diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index ddd132071..d02f5132a 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -29,11 +29,11 @@ jobs: # 1. Check out the current working tree - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 # 2. Setup Java 17 JDK (Adopt) - name: Java 17 setup - uses: actions/setup-java@v2 + uses: actions/setup-java@v4 with: distribution: 'adopt' java-package: jdk @@ -41,7 +41,7 @@ jobs: # 3. Setup local Maven package cache to speed up building - name: Cache Maven packages - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ~/.m2 key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} diff --git a/Changelog.txt b/Changelog.txt index ef92067b1..d50cbbe17 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,3 +1,506 @@ +Version 2.2.041 + Fixed buckets being consumed by furnaces (thanks RunqRun) + Fixed Repair stripping unsafe enchantments from items (thanks Techirion) + Fixed IronGolem causing cast exceptions in rare cases (thanks Techirion) + +Version 2.2.040 + Fixed hover component and action bar messages not working for 1.21.6 and 1.21.7 + Fixed bug where entries of mctop could be duplicated when using FlatFile + Fixed bug where a party leader could leave a party and the party would be left without a party leader + Fixed a bug where EcoEnchants and similar plugins could cause an infinite loop within mcMMO during TreeFeller and other abilities + Added 'Happy_Ghast' to experience.yml for combat XP + Added 'Ghastling' to experience.yml for combat XP + Updated Japanese (ja_JP) translation (Thanks ryota-abe) + Updated Simplified Chinese (zh_CN) locale (Thanks GhostDC) + +Version 2.2.039 + Added StackOverflow safeguards for abilities dealing damage in mcMMO + Improved compatibility with MythicMobs/ModelEngine + Improved compatibility with AdvancedEnchantments + +Version 2.2.038 + Fix potion match failing for non-english locales + FoliaLib Performance improvements (thanks SirSalad) + Fixed situations where Rupture could never end which affected server performance + +Version 2.2.037 + Fixed bug where Alchemy was not matching potions correctly and producing incorrect results (Thanks TheBentoBox) + +Version 2.2.036 + Fixed a bug where Chimaera Wing could cause an exception when used + Fixed bug where Mob Spawners could drop in Blast Mining (thanks TomBock) + Fixed Spectral Arrows not granting XP for Archery or Crossbows (thanks broccolai) + Fixed bug where Trickshot arrows would lose their potion or custom effects + Added locale strings for /mcmmo help command (thanks Griffeng) + +Version 2.2.035 + Support for new additions from Minecraft 1.21.5 + Fixed bug where Blast Mining would not drop deep slate + Swords subskill Stab is now configurable in advanced.yml + Added 'Skills.Swords.Stab.Base_Damage' to advanced.yml + Added 'Skills.Swords.Stab.Per_Rank_Multiplier' to advanced.yml + Added 'Bush' to experience.yml for Herbalism + Added 'Bush' to config.yml Bonus Drops for Herbalism + Added 'Cactus_Flower' to experience.yml for Herbalism + Added 'Cactus_Flower' to config.yml Bonus Drops for Herbalism + Added 'Firefly_Bush' to experience.yml for Herbalism + Added 'Firefly_Bush' to config.yml Bonus Drops for Herbalism + Added 'Leaf_Litter' to experience.yml for Herbalism + Added 'Leaf_Litter' to config.yml Bonus Drops for Herbalism + Added 'Short_Dry_Grass' to experience.yml for Herbalism + Added 'Short_Dry_Grass' to config.yml Bonus Drops for Herbalism + Added 'Tall_Dry_Grass' to experience.yml for Herbalism + Added 'Tall_Dry_Grass' to config.yml Bonus Drops for Herbalism + Added 'Wildflowers' to experience.yml for Herbalism + Added 'Wildflowers' to config.yml Bonus Drops for Herbalism + + + NOTES: + The mob variants will use the "base" mob definition for values for now, such a a warm chicken using chicken values from experience.yml + The new config settings will be added automatically to advanced.yml + +Version 2.2.034 + Fixed bug where mcMMO would drop items in such a way that they get stuck in an adjacent block and float to the surface + Fixed a rare edge case where null entities during chunk unload would cause a NullPointerException and potentially lead to server instability + Fixed bug where arrow would award archery xp after a crossbow trickshot bounce + +Version 2.2.033 + Added Breeze_Rod entries to potions.yml for Awkward potion (see notes) + Added missing TURTLE_HELMET entry to potions.yml for Tier 1 ingredients + Added missing Wind Charging potion entries to potions.yml (see notes) + Fixed bug where mcMMO would attempt to load potions that required ingredients or effects from newer versions of Minecraft + mcMMO is a little more specific during start up of how many potions it loaded, it will now report on incompatible potions from being on an older game version. + + NOTES: + You will have to update your potions.yml manually to receive these changes, it is highly recommended that if you haven't customized this file that you simply just delete it, mcMMO will generate a new one on the next start up and it will contain all the missing entries. + If you have customized this file, you can find the "default" version of this file here on the mcMMO github repo: https://github.com/mcMMO-Dev/mcMMO/blob/master/src/main/resources/potions.yml + You can use this file to compare it to your own and make the manual changes needed to get the new entries. + After making the changes to potions.yml (either via deleting it or not...) mcMMO should now recognize the Wind Charging potion and the Awkward potion created from Breeze Rods + +Version 2.2.032 + Fixed bug where Roll would throw exceptions with certain CMI interactions + Blast Mining no longer drops infested block variants + Reduced bonus drops on Blast Mining and randomized results (see notes) + Added Beetroot to experience.yml for Herbalism + Added Open_Eyeblossom to experience.yml for Herbalism + Addeed Open_Eyeblossom to config.yml Bonus Drops for Herbalism + Added Closed_Eyeblossom to experience.yml for Herbalism + Addeed Closed_Eyeblossom to config.yml Bonus Drops for Herbalism + + NOTES: + A balance pass for Blast Mining is coming, but for now, I've reduced the total bonus drops and clamped the yield ceiling as Blast Mining is a bit too good. + +Version 2.2.031 + Fixed potential NPE when player or blockstate is null for Inventory events on Furnaces + Fixed bug where en_us locale was being set system-wide (thanks BlvckBytes) + Fixed bug where Decimal format would throw exception on non en_us systems (thanks BlvckBytes) + (API) Added McMMOPlayerTameEntityEvent event (thanks Warriorrr) + +Version 2.2.030 + Fixed bug where rupture task could cause an exception (Thanks Wariorrrr) + Fixed bug where Smelting permission was needed for Alchemy XP gain + Fixed material based salvage permissions not functioning (Thanks Momshroom) + +Version 2.2.029 + Fixed bug where block checks at world height would throw IndexOutOfBounds exceptions + Added Eyeblossom to experience.yml for Herbalism xp + Added Bonus_Drops.Herbalism.Eyeblossom to config.yml to enable double/triple drops for Eyeblossom + Added Pale_Hanging_Moss to experience.yml for Herbalism xp + Added Pale_Moss_Block to experience.yml for Herbalism xp + Added Pale_Moss_Carpet to experience.yml for Herbalism xp + Added Pale_Oak_Log to experience.yml for Woodcutting xp + Added Pale_Oak_Wood to experience.yml for Woodcutting xp + Added Stripped_Pale_Oak_Log to experience.yml for Woodcutting xp + Added Stripped_Pale_Oak_Wood to experience.yml for Woodcutting xp + Added Bonus_Drops.Woodcutting.Pale_Oak_Wood to config.yml to enable double/triple drops for Pale Oak Wood + Added Bonus_Drops.Woodcutting.Pale_Oak_Log to config.yml to enable double/triple drops for Pale Oak Log + Temporarily disabled the party item share functionality until it is fixed or potentially removed (see notes) + + Notes: + This update adds support for the new stuff added by the "The Garden Awakens" Minecraft Update + I noticed some issues with the party item share feature, so I've temporarily disabled it until those issues are addressed. + I'm not even sure people like or dislike this feature, I'm personally not a fan.. I'd like to hear what you guys think. + +Version 2.2.028 + Fixed stack overflow during ChunkUnloadEvent + Fixed a bug where you had to wait to summon another COTW summon if one or more of them had died or otherwise expired before their time limit + McMMOItemSpawnEvent#setItemStack being ignored (thanks galacticwarrior9) + (API) Added McMMOPlayerMasterAnglerEvent (thanks bobcat4848) + +Version 2.2.027 + Added Tridents / Crossbows to salvage.vanilla.yml config (see notes) + Fixed an issue where Folia could have all of its threads lock up effectively killing the server + Fixed concurrency issue with Folia regarding locale strings + Fixed concurrency issue with Folia regarding COTW summons + Updated 'Salvage.SubSkill.ScrapCollector.Stat' to no longer mention luck being involved + The amount of materials from salvage are no longer luck-based, you will get a deterministic amount based on damage to the item. + Fixed Ricocheted arrows losing some data after a ricochet + Changed color of locale strings for 'Repair.Listener.Anvil' to be easier to read + Changed color of locale strings for 'Salvage.Listener.Anvil' to be easier to read + + NOTES: + Tridents and Crossbows are now in the salvage.vanilla.yml config, you will need to either delete this config file to regenerate it or add the entries manually. + You can check the default config file after running this mcMMO update at least once in the defaults folder at plugins\mcMMO\defaults to see what you would need to add if you want to take the manual approach + +Version 2.2.026 + Fixed NullPointerException on ChunkUnloadEvent + +Version 2.2.025 + Fixed NullPointerException spam when processing XP for child skills + +Version 2.2.024 + Fixed errors when Fishing or using Shake ability + Significant optimizations made to reading new chunks for mcMMO + Significant optimizations to most block interactions in mcMMO code + Fixed a horrendous edge case where Tree Feller could cause a lot of lag + + Notes: + Part of this update focused on optimization, there's improvements of around 30% in CPU time for most code involving block interactions in mcMMO, which happens to be most code in mcMMO. + One of the optimizations made in this update removes an edge case where Tree Feller could cause a lot of lag, but the optimizations really are across the board in regards to any abilities that interact with blocks. + +Version 2.2.023 + Compatibility with Minecraft 1.21.3 + (API) add causingPlayer to McMMOReplaceVanillaTreasureEvent and update Fish Event to use it (thanks bobcat4848 and Jacob Cuomo) + + Notes: + Tested this version of mcMMO against 1.21.3, 1.21.1, and 1.19.4, which should be full coverage for all the changes, but it is possible you will run into things I didn't catch. + Please report any errors or bugs to GitHub if you find them. + +Version 2.2.022 + Fixed a bug where Roll was always reducing damage (thanks Ineusia) + Fix COTW errors on older versions (thanks Warriorrrr) + Fixed slimes spawning from slime division not inheriting tags. (thanks Ineusia) + +Version 2.2.021 + Fixed issue where Roll wasn't reducing as much damage as it should have been (thanks Ineusia) + Updated locale_es (thanks Devilcasters) + Updated locale_lt_LT (thanks tautuxs) + +Version 2.2.020 + (Codebase) Reworked Roll implementation (See notes) + (Codebase) Added unit test coverage for Roll + Fixed Alchemy error spam in mcMMO potion matching logic (see notes) + Fixed Alchemy NPE when brewing finishes + Fixed a bug where Roll was modifying damage unnecessarily + Fixed blast mining trying to drop non-items (thanks IAISI) + + NOTES: + I'll need to rework Alchemy config logic a bit further to address some issues I've found, for now mcMMO will ignore harmless matching errors in the potion matching logic. + The code for Roll was a bit of a mess, I've rewritten a good chunk of it and added some unit test coverage. + I will likely put out another update for Acrobatics in general, as the code for Acrobatics is whack. + This would be a good time to suggest changes to Acrobatics on discord. + +Version 2.2.019 + Optimized Alchemy code (thanks MrPowerGamerBR) + Fixed an exception that could occur when shooting entities through worlds (thanks Wariorrrr) + Fixes to en_US locale (thanks BlockMasters617) + Maces, Crossbows, and Tridents skill commands don't warn you that they are work in progress anymore. + Fixed IllegalArgumentException when Rupture would trigger on an entity with illegal state + + NOTES: + Maces, Crossbows, and Tridents are still in development, the change to remove the message from the skill command was to reduce the visual noise. + +Version 2.2.018 + Fixed a probability bug where certain skills would max out in chance to succeed well before they were supposed to (such as Dodge) + Blast Mining will no longer drop mob spawners (see notes) + (Codebase) Added more unit tests for Probability and RNG + The Herbalism XP gained when breaking certain plants that can grow unnaturally tall vertically (bamboo, kelp) is now capped to the most it could give when naturally grown, this can be disabled in experience.yml + Added 'ExploitFix.LimitTallPlantFarming' to experience.yml + + NOTES: + This probability bug was a big oopsie and showed a gap in unit test coverage, I've added that coverage and a bug like this in theory shouldn't happen again. + In a future version I will add configuration for admins to control what blocks are not allowed to be dropped by blast mining. + A setting has been added to disable player-created super tall plants from giving full XP, this is on by default, you can tun it off in experience.yml via 'ExploitFix.LimitTallPlantFarming' +Version 2.2.017 + Fixed a bug with default Mace permissions (thanks SrBedrock) + Fixed Blast Mining being almost completely broken + Reworked Blast Mining to drop non-mining related blocks too + Reworked Blast Mining to use your pickaxe when determining drops (will apply Silk Touch) + Fixed shift-clicking ingredients into the brewing stand not working on older versions of Minecraft + Added a setting in advanced.yml to ignore attack cooldowns (see notes) + Updated zh_CN locale (thanks libook) + Updated pt_BR locale (thanks JesusRuescas) + Updated fr locale (thanks Ted-18) + + NOTES: + If Mace skills weren't working for your players before and you were scratching your head wondering why, this should fix it (thanks SrBedrock). + Skills.General.Attack_Cooldown.Adjust_Skills_For_Attack_Cooldown is a new setting in advanced.yml that will allow you to ignore attack cooldowns for the combat skills. + When a player spams an attack, they have a reduced amount of bonus damage from mcMMO and reduced chance for chance-on-hit subskills to activate. + You can have mcMMO ignore this value and apply full bonus damage and full chance to proc abilities by setting this to false. + +Version 2.2.016 + (SQL) Fixed a bug where skill cooldowns were being loaded for players incorrectly + +Version 2.2.015 + Added Maces skill + Added Mace to repair.vanilla.yml (see notes) + Fixed a bug where spamming attacks would still apply full bonus dmg and full chance to proc abilities (see notes) + Fixed some misc missing permissions for crossbows/tridents + + NOTES: + You shouldn't need to update repair.vanilla.yml, it should update automatically + Maces is a new skill that is in early development, feedback is appreciated. + Some ideas I had for the Maces are on hold as they are lacking proper API from Spigot. + This is mostly pertaining to smash attacks, I had some ideas for enhancing them but without the proper API I will hold off for now. + While working on Maces, I noticed a bug where spamming attacks would still apply full bonus damage and full chance to proc abilities, this has been fixed. + When you swing your weapon in Minecraft, you gain an "Attack Strength" value, which is relative to your cooldown, mcMMO was supposed to be making use of this value, but at some point in the past this was broken. + I have fixed this and now mcMMO will use the attack strength value to determine the bonus damage and chance to proc abilities. + For servers modifying Minecraft combat to not have this "cooldown", mcMMO should behave as you would expect, with full damage and full chance to proc abilities even when spamming attacks. + +Version 2.2.014 + Fixed a bug where Luck Of The Sea was being applied for Super Breaker (and other abilities) + +Version 2.2.013 + Added Breeze to experience.yml + Added Bogged to experience.yml + (Locale) Updates to zh_TW (thanks chunkiuu) + (Locale) Updates to zh_CN (thanks haha44444) + Modified the RNG for dropping non-ore blocks from Blast Mining to yield about 50% of what was destroyed + (API) Deprecated com.gmail.nossr50.mcMMO.getPlaceStore + (API) Added com.gmail.nossr50.mcMMO.getUserBlockTracker + (API) Added com.gmail.nossr50.mcMMO.getChunkManager + (API) Added new methods to com.gmail.nossr50.util.blockmeta.UserBlockTracker for easier readability + (API) Deprecated many poorly named methods in UserBlockTracker (see notes) + (Codebase) Cleaned up and organized unit tests relating to UserBlockTracker + Added missing entries for Tridents/Xbows/Maces to config.yml (see notes) + + NOTES: + Some settings such as Hardcore.Death_Stat_Loss.Enabled were missing entries for the new skills, I have added them to the default config. + Missing entries does not mean these things wouldn't work without them present, as default values will be used when config entries are not present. + These missing entries should be added to your config upon start up with this update. + Regarding the API changes, not planning to delete the deprecated methods in UserBlockTracker anytime soon, as nothing has really changed other than the names. + For anyone consuming mcMMO API, I would still recommend switching off these deprecated methods as soon as you can, just for future-proofing. + +Version 2.2.012 + Fixed a bug where Daze would cause an exception in older game versions (1.20.4 and older) + +Version 2.2.011 + Fixed bug where some potions on older versions (1.20.4 and older) were not brewable (night vision extended, etc) + Improved logging for Alchemy potion look up (see notes) + +NOTES: + Added detailed logging when multiple configured potions match an ItemStack. + This will help identify issues with potion configuration. + +Version 2.2.010 + Fixed being unable to load REGEN potion type on new versions of Paper/Spigot 1.20.6 + Fixed some potions not gaining XP when brewed (Level 2 potions, etc) + BrewingStands will now remember who owns them, this persists across restarts (see notes) + Fixed rare NPE in mcMMO events when player data was unable to be retrieved + Fixed a NPE that could happen when damaging armor with Axes + Fixed a bug where Alchemy brewing would be cancelled if the player died + (API) Added getMcMMOPlayer() to McMMOPlayerSkillEvent + (API) Added new ctor McMMOPlayerSkillEvent(@NotNull McMMOPlayer mmoPlayer, @NotNull PrimarySkillType primarySkillType) + (API) Deprecated ctor McMMOPlayerSkillEvent(org.bukkit.entity.Player, com.gmail.nossr50.datatypes.skills.PrimarySkillType) + (API) Added ctor McMMOPlayerAbilityEvent(com.gmail.nossr50.datatypes.player.McMMOPlayer, com.gmail.nossr50.datatypes.skills.PrimarySkillType) + (API) Deprecated ctor McMMOPlayerAbilityEvent(org.bukkit.entity.Player, com.gmail.nossr50.datatypes.skills.PrimarySkillType) + (API) Deprecated ctor McMMOPlayerAbilityActivateEvent(org.bukkit.entity.Player, com.gmail.nossr50.datatypes.skills.PrimarySkillType) + (API) Added ctor McMMOPlayerAbilityActivateEvent(com.gmail.nossr50.datatypes.player.McMMOPlayer, com.gmail.nossr50.datatypes.skills.PrimarySkillType) + (API) Deprecated ctor McMMOPlayerCatalysisEvent(org.bukkit.entity.Player, double) + (API) Added ctor McMMOPlayerCatalysisEvent(com.gmail.nossr50.datatypes.player.McMMOPlayer, double) + (API) Deprecated util method EventUtils.callPlayerAbilityActivateEvent(org.bukkit.entity.Player, com.gmail.nossr50.datatypes.skills.PrimarySkillType) + (API) Added util method EventUtils.callPlayerAbilityActivateEvent(com.gmail.nossr50.datatypes.player.McMMOPlayer, com.gmail.nossr50.datatypes.skills.PrimarySkillType) + (API) Deprecated ctor McMMOPlayerFishingEvent(org.bukkit.entity.Player) + (API) Added ctor McMMOPlayerFishingEvent(com.gmail.nossr50.datatypes.player.McMMOPlayer) + (API) Deprecated ctor McMMOPlayerFishingTreasureEvent.McMMOPlayerFishingTreasureEvent(org.bukkit.entity.Player, org.bukkit.inventory.ItemStack, int) + (API) Added ctor McMMOPlayerFishingTreasureEvent.McMMOPlayerFishingTreasureEvent(com.gmail.nossr50.datatypes.player.McMMOPlayer, org.bukkit.inventory.ItemStack, int) + (API) Deprecated ctor McMMOPlayerMagicHunterEvent(org.bukkit.entity.Player, org.bukkit.inventory.ItemStack, int, java.util.Map) + (API) Added ctor McMMOPlayerMagicHunterEvent(com.gmail.nossr50.datatypes.player.McMMOPlayer, org.bukkit.inventory.ItemStack, int, java.util.Map) + (API) Deprecated ctor McMMOPlayerAbilityDeactivateEvent(org.bukkit.entity.Player, com.gmail.nossr50.datatypes.skills.PrimarySkillType) + (API) Added ctor McMMOPlayerAbilityDeactivateEvent(com.gmail.nossr50.datatypes.player.McMMOPlayer, com.gmail.nossr50.datatypes.skills.PrimarySkillType) + (API) Deprecated util method EventUtils.callAbilityDeactivateEvent(org.bukkit.entity.Player, com.gmail.nossr50.datatypes.skills.SuperAbilityType) + (API) Added util method EventUtils.callAbilityDeactivateEvent(com.gmail.nossr50.datatypes.player.McMMOPlayer, com.gmail.nossr50.datatypes.skills.SuperAbilityType) + (API) Deprecated util EventUtils.callSubSkillEvent(org.bukkit.entity.Player, com.gmail.nossr50.datatypes.skills.SubSkillType) + (API) Added util EventUtils.callSubSkillEvent(com.gmail.nossr50.datatypes.player.McMMOPlayer, com.gmail.nossr50.datatypes.skills.SubSkillType) + (API) Deprecated ctor SubSkillEvent(org.bukkit.entity.Player, com.gmail.nossr50.datatypes.skills.SubSkillType) + (API) Added ctor SubSkillEvent(com.gmail.nossr50.datatypes.player.McMMOPlayer, com.gmail.nossr50.datatypes.skills.SubSkillType) + (API) Deprecated ctor SubSkillEvent(org.bukkit.entity.Player, com.gmail.nossr50.datatypes.skills.SubSkillType, double) + (API) Added ctor SubSkillEvent(com.gmail.nossr50.datatypes.player.McMMOPlayer, com.gmail.nossr50.datatypes.skills.SubSkillType, double) + (API) Deprecated ctor SubSkillEvent(org.bukkit.entity.Player, com.gmail.nossr50.datatypes.skills.subskills.AbstractSubSkill) + (API) Added ctor SubSkillEvent(com.gmail.nossr50.datatypes.player.McMMOPlayer, com.gmail.nossr50.datatypes.skills.subskills.AbstractSubSkill) + (API) Deprecated ctor AlchemyBrewCheckTask(org.bukkit.entity.Player, org.bukkit.block.BrewingStand) + (API) Added ctor AlchemyBrewCheckTask(org.bukkit.block.BrewingStand) + + NOTES: + You can now use hoppers and brewing stands and not have to worry about having to re-interact with the brewing stand over and over again + Ownership of a brewing stand is whoever last interacted with it, this persists across restarts + This is not an exhaustive list of API changes in this update, but most of the important ones should be documented here. + +Version 2.2.009 + Fixed a bug that prevented mcMMO from loading on MC versions older than 1.20.6 + Dramatically increased the base XP for Alchemy again (see notes) + + NOTES: + Alchemy leveling still felt too slow, so I've increased it again. You can either delete experience.yml to get the new values or adjust them manually. + If you haven't updated mcMMO since 2.2.006 or older you don't need to do anything to get these new values. + The new default values are... + Potion_Brewing: + Stage_1: 666 + Stage_2: 1111 + Stage_3: 1750 + Stage_4: 2250 + +Version 2.2.008 + Fixed alchemy potions not upgrading correctly (This will only affect new potions made, see notes) + Fixed a bug where alchemy potions had italicized names + Fixed a bug where messages were not being sent to the action bar in 1.20.6 + (SQL) Fixed bug that broke /mccooldowns and /archery in some circumstances + Fixed some exceptions that could happen with parties disabled (thanks IAISI) + + NOTES: + mcMMO-exclusive Potions (haste, etc) made on version 2.2.007 of mcMMO will not upgrade correctly, you'll just have to make new ones. Sorry for the inconvenience. + Alchemy potions will now be brewed as type "Mundane" behind the scenes, this used to be Uncraftable/Water. This led to some issues. So I've changed it to be Mundane. + +Version 2.2.007 + Compatibility with the 1.20.5 / 1.20.6 MC Update + Fixed bug where Alchemy was not brewing certain potions (haste, etc) + Tree Feller no longer restricts how many saplings can drop + Tree Feller now drops leaves 25% of the time (up from 10%) + Alchemy XP has been DRAMATICALLY increased, it was extremely grindy by default + Alchemy experience values in experience.yml are now found under 'Experience_Values.Alchemy.Potion_Brewing' + Fixed bug where the probability of success of Graceful Roll was not being calculated correctly + Fixed bug where Green Thumb did not replant if seed was in the off hand + Added armadillo to combat experience in experience.yml + + NOTES: + While fixing various Alchemy bugs, I noticed Alchemy leveled SUPER slow, I have increased it dramatically. Feel free to change it back by modifying the new values in experience.yml + I did my best to keep mcMMO compatible with older versions of Minecraft for this update. + This update to MC was quite large, with breaking changes to a lot of code relating to Alchemy, and some other things. + I expect there to be bugs, please report them on GitHub or Discord, but preferably GitHub. + I will be working on fixing these bugs as they come in, so please be patient. +Version 2.2.006 + Added new config custom_item_support.yml + Added support for hex color codes in the locale file, uses the format &#RRGGBB (see notes) + Added setting to disable repair on items with custom models, this is not on by default + Fixed a bug where sometimes the locale name of a skill would get lowercased + Fixed a bug where JSON text components did not get colored properly some of the time + Fixed en_US locale string 'Commands.Skill.Leaderboard' not being colored properly + Fixed skill commands incorrectly telling you to use their locale name, this isn't currently possible + Updated outdated wiki URLs in commands to point to the new wiki + Removed the msg about skills being migrated to a new system when using /mmoinfo command + Added new locale entry 'Anvil.Repair.Reject.CustomModelData' + Added new locale entry 'Anvil.Salvage.Reject.CustomModelData' + Updated en_US locale entry 'JSON.DescriptionHeader' + (API/Codebase) Added some util methods and basic unit tests for LocaleLoader + + NOTES: + Hex Color support in locale files is here! + The hex color code format for the locale files is &#RRGGBB + An example entry applying yellow as a hex color code would look like this: + Axes.SkillName=&#FFFF00Axes + In general, JSON locale entries will either not work with hex color codes or will have the color code stripped out, in the future I will add support for the JSON components to use hex colors from the locale + + Let me know in detail what kind of support you'd like to see in mcMMO regarding custom items, I'm open to suggestions. + This update adds a new config file to allow server owners to disable repair or salvage on items with custom models, + This prevention mechanism is not enabled by default, change the settings in custom_item_support.yml if you want to enable it. + This feature is off by default for now to keep compatibility with existing servers, but it may be enabled by default in the future if feedback suggests it should be. + As a reminder, anyone can update the wiki by clicking on the "edit on github" link on various pages, this will take you to the wiki's source code on GitHub, submit a PR to make changes + +Version 2.2.005 + Fixed a bug where certain skills such as Dodge/Arrow Deflect had no skill cap and would continue improving forever + Reduced messages on startup for SQL DB + (API) Constructor for ProbabilityImpl now takes a raw value between 0 and 1 instead of an inflated percentage + (API) Added some convenience methods to Probability, and ProbabilityUtil classes + (Codebase) Added more unit tests revolving around Probability/RNG + +Version 2.2.004 + Fixed bug where values from Experience_Formula.Skill_Multiplier were not functioning + + NOTES: + A reminder that these values are multipliers and no longer divisors, if you want 10x lower XP, a value of .1 would do the job. + +Version 2.2.003 + (SQLDB) Fixed a bug where lastlogin was using a value that was too large + (SQLDB) Fixed bug where crossbows was not getting added to SQL schema for some users + +Version 2.2.002 + Fixed bug where thrown tridents did not grant XP or benefit from subskills + Fixed bug where trickshot marked bounced arrows as being shot from a bow instead of being shot from a crossbow + +Version 2.2.001 + Fixed Crossbow's Powered shot showing the text for the wrong skill from the locale when using /crossbows command + +Version 2.2.000 + General + Added Crossbows Skill, this skill is an early preview / WIP and feedback on discord is appreciated + Added Tridents Skill, this skill is an early preview / WIP and feedback on discord is appreciated + Added an "endgame" triple drop subskill 'Mother Lode' to Mining + Added an "endgame" triple drop subskill 'Clean Cuts' to Woodcutting + Added an "endgame" triple drop subskill 'Verdant Bounty' to Herbalism + Added /mmopower command which simply shows your power level (aliases /mmopowerlevel /powerlevel) + Quite a few misc bugs were patched relating to random chance, some involving perk permissions + + 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 + Added ExploitFix.PreventArmorStandInteraction to experience.yml to prevent players from triggering mcMMO abilities off armor stands + + Tweaks + Tree Feller now drops 90% less non-wood block rewards (leaves/etc) on average from Knock on Wood. + Treasure drop rate from Shake, Fishing, Hylian, and Excavation now benefit from the Luck perk + Updated advanced.yml with entries for the new skills + + Permission nodes + Added 'mcmmo.commands.mmopower' permission node for the new /mmopower command + Added 'mcmmo.commands.crossbows' permission node + Added 'mcmmo.ability.crossbows.crossbowslimitbreak' permission node + Added 'mcmmo.ability.crossbows.trickshot' permission node + Added 'mcmmo.ability.crossbows.poweredshot' permission node + Added 'mcmmo.commands.tridents' permission node + Added 'mcmmo.ability.tridents.tridentslimitbreak' permission node + Added 'mcmmo.ability.tridents.impale' permission node + Added 'mcmmo.ability.herbalism.verdantbounty' permission node + Added 'mcmmo.ability.mining.motherlode' permission node + Added 'mcmmo.ability.woodcutting.cleancuts' permission node + + Locale + Added locale entries for all the new skills/subskills + + Codebase / Misc + PAPI's '/papi reload' command will no longer unload mcMMO (thanks gecko10000) + Major rewrite for how random chance was handled in the code + Many skills with RNG elements now send out a SubSkillEvent (which can be used to modify probability or cancel the results), some skills without RNG still send out this event when activated, this event is cancellable so it can be used to make a skill fail + A lot of new unit tests were added to help keep mcMMO stable as part of this update, of course, more could always be added. + + NOTES: + One feature of this update is to provide 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. + Tridents especially is very early, I have some ideas but I want to hear what you think about it. + + 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) + Updated korean locale (thanks mangchi57) + Added some unit tests for party creation + +Version 2.1.230 + Fixed an error that could happen when mcMMO was saving when parties were disabled by party.yml (thanks IAISI & L4BORG) + Fixed several exceptions when checking PVP damage when parties were disabled by party.yml (thanks IAISI & L4BORG) + +Version 2.1.229 + Added new party.yml config, which lets admins disable the party system entirely without having to use permissions + Fixed error caused by missing API in McMMOEntityDamageByRuptureEvent + (API) Major API changes to PartyManager + (API) PartyManager is no longer a static singleton class, use mcMMO.getPartyManager() to get the PartyManager + (API) Added com.gmail.nossr50.mcMMO.isPartySystemEnabled to check if the party system is enabled + (API) Added com.gmail.nossr50.api.PartyAPI.isPartySystemEnabled as an alternative, to check if the party system is enabled + (API) Added missing com.gmail.nossr50.events.skills.rupture.McMMOEntityDamageByRuptureEvent.getHandlerList + + NOTES: + Admins can now enable/disable the whole party system with a setting in the new party.yml config + You'll have to start your server one time to generate the config, then change the setting and reboot your server. + Version 2.1.228 Fixed a stack trace due to Spigot API break on EntityDamageEvent and EntityDamageByEntity event (API) - Removed FakeEntityDamageEvent and FakeEntityDamageByEntityEvent @@ -1309,7 +1812,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. @@ -1329,7 +1832,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 @@ -1965,7 +2468,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' @@ -2014,7 +2517,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) @@ -2022,9 +2525,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: @@ -2217,7 +2720,7 @@ Version 2.1.38 Version 2.1.37 Fixed a potential IndexOutOfBoundsException when informing a disconnected player that their Blast Mining was off CD Updated hu_HU locale (thanks andris) - + Version 2.1.36 Updated German locale (Thanks OverCrave) Fixed a bug preventing Villagers from giving combat XP @@ -2295,7 +2798,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. @@ -2757,7 +3260,7 @@ Version 1.5.01 = Fixed bug where pistons would mess with the block tracking = Fixed bug where the Updater was running on the main thread. = Fixed bug when players would use /ptp without being in a party - = Fixed bug where player didn't have a mcMMOPlayer object in AsyncPlayerChatEvent + = Fixed bug where player didn't have a mmoPlayer object in AsyncPlayerChatEvent = Fixed bug where dodge would check the wrong player skill level = Fixed bug which causes /party teleport to stop working = Fixed bug where SaveTimerTask would produce an IndexOutOfBoundsException @@ -3205,7 +3708,7 @@ Version 1.3.13 + Added displaying bonus perks on skill commands + Added config option to disable gaining Acrobatics XP from dodging lightning + Added missing skill guides. They're finally here! - + Added more localization + + Added more localization + Added a very secret easter egg = Fix issue with Sand/Gravel tracking = Fix possible NPE when using the PartyAPI to add a player to a party that doesn't exist. @@ -3302,7 +3805,7 @@ Version 1.3.11 = Fixed bug where mcMMO could throw NPE errors if trees cut down were from a custom mod and had an id of 17 = Fixed dupe bug where mcMMO would ignore other block-protection plugins for various abilities = Fixed NPE with hardcore mode's vampirism - + Version 1.3.10 + Added 1.3.1 compatibility + Added permission node for Iron Grip ability (mcmmo.ability.unarmed.irongrip) @@ -3564,7 +4067,7 @@ Version 1.3.02 Version 1.3.01 = Fixed bug where Tree Feller had no cooldown = Fixed bug with activating Skull Splitter after using Tree Feller - + Version 1.3.00 + Added ability to customize drops for Excavation skill (treasures.yml) + Added ability to customize drops for Fishing skill (treasures.yml) @@ -3628,7 +4131,7 @@ Version 1.3.00 - Removed unused settings from config.yml (HP Regen) - Removed Nether Brick from Mining XP Tables - Removed Stone Brick from Mining XP Tables - + Version 1.2.12 - Fixed issue that caused terrible MySQL performance and negative XP on levelup (Issue #134) - Fixed addxp command taking xprate and skill modifiers into account @@ -3996,7 +4499,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 @@ -4006,7 +4509,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 @@ -4637,7 +5140,7 @@ Version 0.5.9 Version 0.5.8 Fixed bug where players inventories would dupe during combat - + Version 0.5.7 Fixed monsters instant killing players diff --git a/README.md b/README.md index d69bc1143..d3d04067c 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,33 @@ # mcMMO -## The #1 RPG Mod for Minecraft +The #1 RPG Mod for Minecraft -## Website -I'm working on a brand new website for mcMMO - -You can check it out here http://www.mcmmo.org +## Useful URLs +Website: http://www.mcmmo.org Spigot Resource: https://spigot.mcmmo.org -I plan to post links to our new wiki (its still under development), downloads, and dev blogs there. +Polymart Resource: https://polymart.org/product/727/mcmmo +Wiki: https://wiki.mcmmo.org/ + +## API +If you are using maven, you can add mcMMO API to your plugin by adding it to pom.xml like so... + +``` + + neetgames + https://nexus.neetgames.com/repository/maven-releases/ + +``` +``` + + com.gmail.nossr50.mcMMO + mcMMO + 2.2.004 + +``` ### Builds -Currently, you can obtain our builds via the Spigot or Polymart: - +Currently, you can obtain our builds via Spigot or Polymart: http://spigot.mcmmo.org @@ -23,8 +38,6 @@ The goal of mcMMO is to take core Minecraft game mechanics and expand them into ## About the Team In December 2018, the original author and creator of mcMMO (nossr50) returned and took over the role of project lead once again, to develop and improve mcMMO. -#### Project Lead & Founder -[![nossr50](http://www.gravatar.com/avatar/f2ee41eedfd645fb4a3a2c8f6cb1b18c.png)](https://github.com/nossr50) #### Current mcMMO Devs [![nossr50](http://www.gravatar.com/avatar/f2ee41eedfd645fb4a3a2c8f6cb1b18c.png)](https://github.com/nossr50) @@ -56,8 +69,7 @@ The typical command used to build mcMMO is: `mvn clean install` https://spigot.mcmmo.org for more up to date information. -Downloads: - +## Downloads https://www.spigotmc.org/resources/official-mcmmo-original-author-returns.64348/ diff --git a/extras/mods/1.6.x/LOTR.armor.yml b/extras/mods/1.6.x/LOTR.armor.yml deleted file mode 100755 index f4b8880c1..000000000 --- a/extras/mods/1.6.x/LOTR.armor.yml +++ /dev/null @@ -1,439 +0,0 @@ -# Lord of the Rings mod config by Dragyn -# Built against version [1.6.4] The Lord of the Rings Mod Public Beta 11.1 -# -# -# Settings for Boots -### -Boots: - # Bronze - X12015: - Repairable: true - Repair_Material: X12004 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Orc - X12035: - Repairable: true - Repair_Material: X12036 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Gondorian - X12060: - Repairable: true - Repair_Material: IRON_INGOT - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Mithril - X12064: - Repairable: true - Repair_Material: X12006 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Elven - X12088: - Repairable: true - Repair_Material: IRON_INGOT - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Warg - X12098: - Repairable: true - Repair_Material: X12094 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Dwarven - X12129: - Repairable: true - Repair_Material: X12112 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Galven - X12134: - Repairable: true - Repair_Material: X12130 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Uruk - X12161: - Repairable: true - Repair_Material: X12147 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Wood Elf - X12176: - Repairable: true - Repair_Material: LEATHER - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Ancient - X12180: - Repairable: true - Repair_Material: X12179 - Repair_Material_Data_Value: 3 - Repair_Material_Quantity: 2 - Durability: 500 - # Rohirric - X12187: - Repairable: true - Repair_Material: IRON_INGOT - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Rangers - X12206: - Repairable: true - Repair_Material: LEATHER - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Dunlending - X12210: - Repairable: true - Repair_Material: IRON_INGOT - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Morgul - X12222: - Repairable: true - Repair_Material: X12217 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 -# -# Settings for Chestplates -### -Chestplates: - # Bronze - X12013: - Repairable: true - Repair_Material: X12004 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Orc - X12033: - Repairable: true - Repair_Material: X12036 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Gondorian - X12058: - Repairable: true - Repair_Material: IRON_INGOT - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Mithril - X12062: - Repairable: true - Repair_Material: X12006 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Elven - X12086: - Repairable: true - Repair_Material: IRON_INGOT - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Warg - X12096: - Repairable: true - Repair_Material: X12094 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Dwarven - X12127: - Repairable: true - Repair_Material: X12112 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Galven - X12132: - Repairable: true - Repair_Material: X12130 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Uruk - X12159: - Repairable: true - Repair_Material: X12147 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Wood Elf - X12174: - Repairable: true - Repair_Material: LEATHER - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Ancient - X12178: - Repairable: true - Repair_Material: X12179 - Repair_Material_Data_Value: 3 - Repair_Material_Quantity: 2 - Durability: 500 - # Rohirric - X12185: - Repairable: true - Repair_Material: IRON_INGOT - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Rangers - X12204: - Repairable: true - Repair_Material: LEATHER - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Dunlending - X12208: - Repairable: true - Repair_Material: IRON_INGOT - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Morgul - X12220: - Repairable: true - Repair_Material: X12217 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 -# -# Settings for Helmets -### -Helmets: - # Bronze - X12012: - Repairable: true - Repair_Material: X12004 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Orc - X12032: - Repairable: true - Repair_Material: X12036 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Gondorian - X12057: - Repairable: true - Repair_Material: IRON_INGOT - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Mithril - X12061: - Repairable: true - Repair_Material: X12006 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Elven - X12085: - Repairable: true - Repair_Material: IRON_INGOT - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Warg - X12095: - Repairable: true - Repair_Material: X12094 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Dwarven - X12126: - Repairable: true - Repair_Material: X12112 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Galven - X12131: - Repairable: true - Repair_Material: X12130 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Uruk - X12158: - Repairable: true - Repair_Material: X12147 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Wood Elf - X12173: - Repairable: true - Repair_Material: LEATHER - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Ancient - X12177: - Repairable: true - Repair_Material: X12179 - Repair_Material_Data_Value: 3 - Repair_Material_Quantity: 2 - Durability: 500 - # Rohirric - X12184: - Repairable: true - Repair_Material: IRON_INGOT - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Rangers - X12203: - Repairable: true - Repair_Material: LEATHER - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Dunlending - X12207: - Repairable: true - Repair_Material: IRON_INGOT - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Morgul - X12219: - Repairable: true - Repair_Material: X12217 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 -# -# Settings for Leggings -### -Leggings: - # Bronze - X12014: - Repairable: true - Repair_Material: X12004 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Orc - X12034: - Repairable: true - Repair_Material: X12036 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Gondorian - X12059: - Repairable: true - Repair_Material: IRON_INGOT - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Mithril - X12063: - Repairable: true - Repair_Material: X12006 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Elven - X12087: - Repairable: true - Repair_Material: IRON_INGOT - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Warg - X12097: - Repairable: true - Repair_Material: X12094 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Dwarven - X12128: - Repairable: true - Repair_Material: X12112 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Galven - X12133: - Repairable: true - Repair_Material: X12130 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Uruk - X12160: - Repairable: true - Repair_Material: X12147 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Wood Elf - X12175: - Repairable: true - Repair_Material: LEATHER - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Ancient - X12179: - Repairable: true - Repair_Material: X12179 - Repair_Material_Data_Value: 3 - Repair_Material_Quantity: 2 - Durability: 500 - # Rohirric - X12186: - Repairable: true - Repair_Material: IRON_INGOT - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Rangers - X12205: - Repairable: true - Repair_Material: LEATHER - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Dunlending - X12209: - Repairable: true - Repair_Material: IRON_INGOT - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Morgul - X12221: - Repairable: true - Repair_Material: X12217 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 diff --git a/extras/mods/1.6.x/LOTR.blocks.yml b/extras/mods/1.6.x/LOTR.blocks.yml deleted file mode 100755 index 7c555f686..000000000 --- a/extras/mods/1.6.x/LOTR.blocks.yml +++ /dev/null @@ -1,211 +0,0 @@ -# Lord of the Rings mod config by Skuli (Updated by Dragyn) -# Built against version [1.6.4] The Lord of the Rings Mod Public Beta 11.1 -# -# Settings for Custom Excavation Blocks -### -Excavation: - Block_1|0: - XP_Gain: 99 - Double_Drops_Enabled: true - Block_2|0: - XP_Gain: 99 - Double_Drops_Enabled: true - -# -# Settings for Custom Herbalism Blocks -### -Herbalism: - -# Shireheather - X1813: - XP_Gain: 100 - Double_Drops_Enabled: true - -# Simbelmyne - X1805: - XP_Gain: 100 - Double_Drops_Enabled: true - -# Asphodel - X1895: - XP_Gain: 100 - Double_Drops_Enabled: true - -# Bluebell - X1867: - XP_Gain: 100 - Double_Drops_Enabled: true - -# Clover - X1873: - XP_Gain: 10 - Double_Drops_Enabled: false - -# Dead Marsh Plant - X1886: - XP_Gain: 10 - Double_Drops_Enabled: false - -# DwarfWort - X1902: - XP_Gain: 100 - Double_Drops_Enabled: true - -# Elanor - X1833: - XP_Gain: 100 - Double_Drops_Enabled: true - -# Lettuce Crop - X1830: - XP_Gain: 100 - Double_Drops_Enabled: true - -# Morgul Shroom - X1870: - XP_Gain: 100 - Double_Drops_Enabled: true - -# Niphredil - X1834: - XP_Gain: 100 - Double_Drops_Enabled: true - -# Pipeweed Crop - X1823: - XP_Gain: 100 - Double_Drops_Enabled: true - -# Pipeweed Plant - X1822: - XP_Gain: 100 - Double_Drops_Enabled: true - -# -# Settings for Custom Mining Blocks -### -Mining: - -# Mithril - X1803: - XP_Gain: 2000 - Double_Drops_Enabled: false - Is_Ore: true -# Naurite - X1818: - XP_Gain: 150 - Double_Drops_Enabled: false - Is_Ore: false -#Glowstone Ore - X1859: - XP_Gain: 30 - Double_Drops_Enabled: false - Is_Ore: false -# Remains - X1885: - XP_Gain: 1800 - Double_Drops_Enabled: false - Is_Ore: false -# Gulduril - X1887: - XP_Gain: 100 - Double_Drops_Enabled: true - Is_Ore: false - -# Quendite - X1846: - XP_Gain: 150 - Double_Drops_Enabled: false - Is_Ore: false - -# MorgulIron - X1819: - XP_Gain: 25 - Double_Drops_Enabled: true - Is_Ore: false - -# Rohan Rock - X180|2: - XP_Gain: 30 - Double_Drops_Enabled: false - Is_Ore: false - - -#Gondor Stone - X180|1: - XP_Gain: 30 - Double_Drops_Enabled: false - Is_Ore: false - -# Mordor Stone - X180|0: - XP_Gain: 30 - Double_Drops_Enabled: false - Is_Ore: false - -# -# Settings for Custom Woodcutting Blocks -### -Woodcutting: -# Shire Pine - X1806|0: - XP_Gain: 90 - Double_Drops_Enabled: true - Is_Log: true - -# Mallorn - X1806|1: - XP_Gain: 100 - Double_Drops_Enabled: true - Is_Log: true - -# Apple - X1860|0: - XP_Gain: 100 - Double_Drops_Enabled: true - Is_Log: true - -# Pear - X1860|1: - XP_Gain: 100 - Double_Drops_Enabled: true - Is_Log: true - -# Cherry - X1860|2: - XP_Gain: 100 - Double_Drops_Enabled: true - Is_Log: true - -# Mirkwood - X1806|2: - XP_Gain: 100 - Double_Drops_Enabled: true - Is_Log: true - -# Charred - X1806|3: - XP_Gain: 100 - Double_Drops_Enabled: true - Is_Log: true - -# Lebethron - X1896|0: - XP_Gain: 100 - Double_Drops_Enabled: true - Is_Log: true - -# Beech - X1896|1: - XP_Gain: 100 - Double_Drops_Enabled: true - Is_Log: true - - -# -# Settings for Custom Ability Blocks -# (These blocks don't trigger abilities) -### -Ability_Blocks: - Block_1|0: - Block_2|0: diff --git a/extras/mods/1.6.x/LOTR.tools.yml b/extras/mods/1.6.x/LOTR.tools.yml deleted file mode 100755 index 73b0de8ba..000000000 --- a/extras/mods/1.6.x/LOTR.tools.yml +++ /dev/null @@ -1,700 +0,0 @@ -# Lord of the Rings mod config by Skuli (Updated by Dragyn) -# Built against version [1.6.4] The Lord of the Rings Mod Public Beta 11.1 - -Axes: - #DwarvenThrowingAxe - X12146: - XP_Modifer: 1 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X12112 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 3 - Durability: 451 - #UrukWarhammer - X12156: - XP_Modifer: 1 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X12147 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 3 - Durability: 391 - #Gondorian Warhammer - X12140: - XP_Modifer: 1 - Ability_Enabled: true - Tier: 1 - Repairable: false - Repair_Material: X12112 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 3 - Durability: 281 - #UrukBattleaxe - X12155: - XP_Modifer: 1 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X12147 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 3 - Durability: 391 - #MithrilBattleaxe - X12138: - XP_Modifer: 1 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X12006 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 3 - Durability: 2479 - #MithrilWarhamer - X12139: - XP_Modifer: 1 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X12006 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 3 - Durability: 2479 - #OrcWarhammer - X12125: - XP_Modifer: 1 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X12036 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 3 - Durability: 261 - #Dwarven Warhammer - X12120: - XP_Modifer: 1 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X12112 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 3 - Durability: 451 - #DwarvenZbattleaxe - X12119: - XP_Modifer: 1 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X12112 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 3 - Durability: 451 - #BronzeAxe - X12009: - XP_Modifer: 1 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X12004 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 3 - Durability: 197 - #MithrilAxe - X12050: - XP_Modifer: 1 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X12006 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 3 - Durability: 2479 - #MallornAxe - X12075: - XP_Modifer: 1 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X1801 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 3 - Durability: 121 - #Elven Axe - X12080: - XP_Modifer: 2 - Ability_Enabled: true - Tier: 1 - Repairable: false - Repair_Material: X12112 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 3 - Durability: 313 - #DwarvenAxe - X12115: - XP_Modifer: 1 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X12112 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 3 - Durability: 450 - #OrcAxe - X12123: - XP_Modifer: 1 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X12036 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 3 - Durability: 261 - #UrukAxe - X12150: - XP_Modifer: 1 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X12147 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 3 - Durability: 391 -Bows: - #ElvenBow - X12093: - XP_Modifer: 2 - Ability_Enabled: true - Tier: 1 - Repairable: false - Repair_Material: IRON_INGOT - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 9 - Durability: 485 - #mallornbow - X12084: - XP_Modifer: 1 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X1801 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 3 - Durability: 417 - #orcBow - X12099: - XP_Modifer: 1 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X12036 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 3 - Durability: 441 - #UrukCrossbow - X12163: - XP_Modifer: 1 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X12147 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 3 - Durability: 471 - #MithrilCrossbow - X12171: - XP_Modifer: 1 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X12006 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 3 - Durability: 1761 - #IronCrossbow - X12170: - XP_Modifer: 1 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: IRON_INGOT - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 9 - Durability: 357 - #BowofMirkwood - X12177: - XP_Modifer: 1 - Ability_Enabled: true - Tier: 1 - Repairable: false - Repair_Material: X1806 - Repair_Material_Data_Value: 2 - Repair_Material_Quantity: 3 - Durability: 417 -Hoes: - #BronzeHoe - X12011: - XP_Modifer: 1 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X12004 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 197 - #MithrilHoe - X12052: - XP_Modifer: 1 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X12006 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 2479 - #MallornHoe - X12077: - XP_Modifer: 1 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X1801 - Repair_Material_Data_Value: 1 - Repair_Material_Quantity: 2 - Durability: 121 - #CopperHoe - X26511: - XP_Modifer: 1 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X26507 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 180 - #ElvenHoe - X12082: - XP_Modifer: 2 - Ability_Enabled: true - Tier: 1 - Repairable: false - Repair_Material: X12082 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 313 - #DwarvenHoe - X12117: - XP_Modifer: 1 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X26507 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 180 -Pickaxes: - #MEBronzePickaxe - X12008: - XP_Modifer: 1 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X12004 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 3 - Durability: 197 - #MithrilPixkaxe - X12049: - XP_Modifer: 1 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X12006 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 3 - Durability: 2479 - #MallornPickaxe - X12074: - XP_Modifer: 1 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X1801 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 3 - Durability: 121 - #ElvenPickaxe - X12079: - XP_Modifer: 2 - Ability_Enabled: true - Tier: 1 - Repairable: false - Repair_Material: X12006 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 3 - Durability: 313 - #DwarvenPickaxe - X12114: - XP_Modifer: 1 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X12112 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 3 - Durability: 451 - #UrukPickaxe - X12149: - XP_Modifer: 1 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X12147 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 3 - Durability: 391 - #OrcPickaxe - X12122: - XP_Modifer: 1 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X12036 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 3 - Durability: 261 -Shovels: - #BronzeShovel - X12007: - XP_Modifer: 1 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X12004 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 1 - Durability: 197 - #MithrilShovel - X12048: - XP_Modifer: 1 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X12006 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 1 - Durability: 2479 - #MallornShovel - X12073: - XP_Modifer: 1 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X1801 - Repair_Material_Data_Value: 1 - Repair_Material_Quantity: 1 - Durability: 121 - #ElvenShovel - X12078: - XP_Modifer: 2 - Ability_Enabled: true - Tier: 1 - Repairable: false - Repair_Material: X12082 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 1 - Durability: 313 - #DwarvenShovel - X12113: - XP_Modifer: 1 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X12112 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 1 - Durability: 451 - #UrukShovel - X12148: - XP_Modifer: 1 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X12147 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 1 - Durability: 391 - #OrcShovel - X12121: - XP_Modifer: 1 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X12036 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 1 - Durability: 261 - -Swords: - #Uruk Dagger - X12153: - XP_Modifer: 1 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X12147 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 313 - #Poisoned urukd agger - X12154: - XP_Modifer: 1 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X12147 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 313 - #Uruk Spear - X12157: - XP_Modifer: 1 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X12147 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 391 - #Rohirric Sword - X12181: - XP_Modifer: 1 - Ability_Enabled: true - Tier: 1 - Repairable: false - Repair_Material: X12147 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 251 - #Rohirric Dagger - X12182: - XP_Modifer: 1 - Ability_Enabled: true - Tier: 1 - Repairable: false - Repair_Material: X12147 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 201 - #Rohirric Spear - X12183: - XP_Modifer: 1 - Ability_Enabled: true - Tier: 1 - Repairable: false - Repair_Material: X12147 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 251 - #Dunlending Spear - X12212: - XP_Modifer: 1 - Ability_Enabled: true - Tier: 1 - Repairable: false - Repair_Material: X12147 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 251 - #Uruk Scimitar - X12151: - XP_Modifer: 1 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X12147 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 391 - #Mithril Dagger - X12137: - XP_Modifer: 1 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X12006 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 1983 - #Iron Dagger - X12136: - XP_Modifer: 1 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: IRON_INGOT - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 201 - #Dwarven Dagger - X12118: - XP_Modifer: 1 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X12112 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 361 - #Dwarven Sword - X12116: - XP_Modifer: 1 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X12112 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 451 - #Elven Sword - X12081: - XP_Modifer: 1 - Ability_Enabled: true - Tier: 1 - Repairable: false - Repair_Material: X12006 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 313 - #Elven Spear - X12083: - XP_Modifer: 1 - Ability_Enabled: true - Tier: 1 - Repairable: false - Repair_Material: X12006 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 313 - #Anduril - X12070: - XP_Modifer: 1 - Ability_Enabled: true - Tier: 4 - Repairable: false - Repair_Material: X12006 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 313 - #Mallorn Sword - X12076: - XP_Modifer: 1 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X1801 - Repair_Material_Data_Value: 1 - Repair_Material_Quantity: 2 - Durability: 121 - #Mithril Spear - X12069: - XP_Modifer: 1 - Ability_Enabled: true - Tier: 4 - Repairable: true - Repair_Material: X12006 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 2479 - #Iron Spear - X12068: - XP_Modifer: 1 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: IRON_INGOT - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 1 - Durability: 251 - #Orc Spear - X12066: - XP_Modifer: 1 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X12036 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 1 - Durability: 261 - #Bronze Spear - X12067: - XP_Modifer: 1 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X12004 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 1 - Durability: 197 - #Gondor Spear - X12065: - XP_Modifer: 1 - Ability_Enabled: true - Tier: 1 - Repairable: false - Repair_Material: X12006 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 1 - Durability: 281 - #Gondor Sword - X12056: - XP_Modifer: 1 - Ability_Enabled: true - Tier: 1 - Repairable: false - Repair_Material: X12006 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 1 - Durability: 281 - #Orc Scimitar - X12031: - XP_Modifer: 1 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X12036 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 261 - #Steel Sword - X26862: - XP_Modifer: 1 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X26857 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 751 - #Bronze Sword - X12010: - XP_Modifer: 1 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X12004 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 1 - Durability: 197 - #Mithril Sword - X12051: - XP_Modifer: 1 - Ability_Enabled: true - Tier: 4 - Repairable: true - Repair_Material: X12006 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 2479 diff --git a/extras/mods/1.6.x/advancedgenetics.tools.yml b/extras/mods/1.6.x/advancedgenetics.tools.yml deleted file mode 100644 index a0d38b3e7..000000000 --- a/extras/mods/1.6.x/advancedgenetics.tools.yml +++ /dev/null @@ -1,14 +0,0 @@ -# Config wrote by M1cr0man -# Up to date as of Advanced Genetics 1.4.3 -Bows: - # Genetic - X31179: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 3 - Repairable: true - Repair_Material: X31197 - Repair_Material_Pretty_Name: "Cell" - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 3 - Durability: 1501 \ No newline at end of file diff --git a/extras/mods/1.6.x/appliedenergistics.blocks.yml b/extras/mods/1.6.x/appliedenergistics.blocks.yml deleted file mode 100644 index 516a5677d..000000000 --- a/extras/mods/1.6.x/appliedenergistics.blocks.yml +++ /dev/null @@ -1,9 +0,0 @@ -# Config wrote by M1cr0man -# Possibly incomplete. Only covers ores -# Up to date as of Applied Energistics rv14-finale3 -Mining: - # Certus Quartz Ore - X4076|0: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: true \ No newline at end of file diff --git a/extras/mods/1.6.x/appliedenergistics.tools.yml b/extras/mods/1.6.x/appliedenergistics.tools.yml deleted file mode 100644 index 956859c10..000000000 --- a/extras/mods/1.6.x/appliedenergistics.tools.yml +++ /dev/null @@ -1,65 +0,0 @@ -# Config wrote by M1cr0man -# Up to date as of Applied Energistics rv14-finale3 -Axes: - # Quartz - X4365: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 2 - Repairable: true - Repair_Material: X4362 - Repair_Material_Pretty_Name: "Certus Quartz" - Repair_Material_Data_Value: 6 - Repair_Material_Quantity: 3 - Durability: 250 - -Hoes: - # Quartz - X4366: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 2 - Repairable: true - Repair_Material: X4362 - Repair_Material_Pretty_Name: "Certus Quartz" - Repair_Material_Data_Value: 6 - Repair_Material_Quantity: 2 - -Pickaxes: - # Quartz - X4368: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 2 - Repairable: true - Repair_Material: X4362 - Repair_Material_Pretty_Name: "Certus Quartz" - Repair_Material_Data_Value: 6 - Repair_Material_Quantity: 3 - Durability: 250 - -Shovels: - # Quartz - X4367: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 2 - Repairable: true - Repair_Material: X4362 - Repair_Material_Pretty_Name: "Certus Quartz" - Repair_Material_Data_Value: 6 - Repair_Material_Quantity: 1 - Durability: 750 - -Swords: - # Quartz - X4369: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 2 - Repairable: true - Repair_Material: X4362 - Repair_Material_Pretty_Name: "Certus Quartz" - Repair_Material_Data_Value: 6 - Repair_Material_Quantity: 2 - Durability: 250 \ No newline at end of file diff --git a/extras/mods/1.6.x/bigreactors.blocks.yml b/extras/mods/1.6.x/bigreactors.blocks.yml deleted file mode 100644 index 0cde247a1..000000000 --- a/extras/mods/1.6.x/bigreactors.blocks.yml +++ /dev/null @@ -1,9 +0,0 @@ -# Config wrote by M1cr0man -# Possibly incomplete. Only covers ores -# Up to date as of Big Reactors 0.3.4A2 -Mining: - # Yellorite - X1750|0: - XP_Gain: 300 - Double_Drops_Enabled: true - Is_Ore: true \ No newline at end of file diff --git a/extras/mods/1.6.x/biomesoplenty.armor.yml b/extras/mods/1.6.x/biomesoplenty.armor.yml deleted file mode 100644 index 2687ee072..000000000 --- a/extras/mods/1.6.x/biomesoplenty.armor.yml +++ /dev/null @@ -1,77 +0,0 @@ -# Config wrote by M1cr0man -# Up to date as of BoP 1.2.1.434 -Boots: - # Wading - X21269: - Repairable: false - Durability: 9999 - # Muddy - X21283: - Repairable: true - Repair_Material: X21263 - Repair_Material_Pretty_Name: "Mud Ball" - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 4 - Durability: 26 - # Amethyst - X21293: - Repairable: true - Repair_Material: X21264 - Repair_Material_Pretty_Name: "Amethyst" - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 4 - Durability: 520 - -Chestplates: - # Muddy - X21281: - Repairable: true - Repair_Material: X21263 - Repair_Material_Pretty_Name: "Mud Ball" - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 8 - Durability: 32 - # Amethyst - X21291: - Repairable: true - Repair_Material: X21264 - Repair_Material_Pretty_Name: "Amethyst" - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 8 - Durability: 640 - -Helmets: - # Muddy - X21280: - Repairable: true - Repair_Material: X21263 - Repair_Material_Pretty_Name: "Mud Ball" - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 5 - Durability: 22 - # Amethyst - X21290: - Repairable: true - Repair_Material: X21264 - Repair_Material_Pretty_Name: "Amethyst" - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 5 - Durability: 440 - -Leggings: - # Muddy - X21280: - Repairable: true - Repair_Material: X21263 - Repair_Material_Pretty_Name: "Mud Ball" - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 7 - Durability: 30 - # Amethyst - X21290: - Repairable: true - Repair_Material: X21264 - Repair_Material_Pretty_Name: "Amethyst" - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 7 - Durability: 600 \ No newline at end of file diff --git a/extras/mods/1.6.x/biomesoplenty.blocks.yml b/extras/mods/1.6.x/biomesoplenty.blocks.yml deleted file mode 100644 index 60becdc8d..000000000 --- a/extras/mods/1.6.x/biomesoplenty.blocks.yml +++ /dev/null @@ -1,44 +0,0 @@ -# Config wrote by M1cr0man -# Incomplete! Only covers ores -# Up to date as of BoP 1.2.1.434 -Mining: - # Red Rock - X162|0: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - # Amethyst - X1921|0: - XP_Gain: 200 - Double_Drops_Enabled: true - Is_Ore: true - # Ruby - X1921|2: - XP_Gain: 350 - Double_Drops_Enabled: true - Is_Ore: true - # Peridot - X1921|4: - XP_Gain: 350 - Double_Drops_Enabled: true - Is_Ore: true - # Topaz - X1921|6: - XP_Gain: 200 - Double_Drops_Enabled: true - Is_Ore: true - # Tanzanite - X1921|8: - XP_Gain: 200 - Double_Drops_Enabled: true - Is_Ore: true - # Malachite - X1921|10: - XP_Gain: 200 - Double_Drops_Enabled: true - Is_Ore: true - # Sapphire - X1921|12: - XP_Gain: 350 - Double_Drops_Enabled: true - Is_Ore: true \ No newline at end of file diff --git a/extras/mods/1.6.x/biomesoplenty.tools.yml b/extras/mods/1.6.x/biomesoplenty.tools.yml deleted file mode 100644 index 41fb3a74f..000000000 --- a/extras/mods/1.6.x/biomesoplenty.tools.yml +++ /dev/null @@ -1,121 +0,0 @@ -# Config wrote by M1cr0man -# Up to date as of BoP 1.2.1.434 -Axes: - # Amethyst - X21287: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 4 - Repairable: true - Repair_Material: X21264 - Repair_Material_Pretty_Name: "Amethyst" - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 3 - Durability: 2013 - # Muddy - X21277: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X21263 - Repair_Material_Pretty_Name: "Mud Ball" - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 3 - Durability: 32 - -Hoes: - # Amethyst - X21288: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 4 - Repairable: true - Repair_Material: X21264 - Repair_Material_Pretty_Name: "Amethyst" - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 2013 - # Muddy - X21278: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X21263 - Repair_Material_Pretty_Name: "Mud Ball" - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 32 - -Pickaxes: - # Amethyst - X21286: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 4 - Repairable: true - Repair_Material: X21264 - Repair_Material_Pretty_Name: "Amethyst" - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 3 - Durability: 2013 - # Muddy - X21276: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X21263 - Repair_Material_Pretty_Name: "Mud Ball" - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 3 - Durability: 32 - -Shovels: - # Amethyst - X21285: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 4 - Repairable: true - Repair_Material: X21264 - Repair_Material_Pretty_Name: "Amethyst" - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 1 - Durability: 2013 - # Muddy - X21275: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X21263 - Repair_Material_Pretty_Name: "Mud Ball" - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 1 - Durability: 32 - -Swords: - # Amethyst - X21284: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 4 - Repairable: true - Repair_Material: X21264 - Repair_Material_Pretty_Name: "Amethyst" - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 2013 - # Muddy - X21274: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X21263 - Repair_Material_Pretty_Name: "Mud Ball" - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 32 \ No newline at end of file diff --git a/extras/mods/1.6.x/emasher.armor.yml b/extras/mods/1.6.x/emasher.armor.yml deleted file mode 100644 index fa48bb492..000000000 --- a/extras/mods/1.6.x/emasher.armor.yml +++ /dev/null @@ -1,31 +0,0 @@ -# Config wrote by M1cr0man -# Up to date as of Emasher Resource 1.2.3.5 -Boots: - # Hemp - X9301: - Repairable: true - Repair_Material: X9291 - Repair_Material_Pretty_Name: "Hemp" - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 4 - Durability: 65 - -Chestplates: - # Hemp - X9299: - Repairable: true - Repair_Material: X9291 - Repair_Material_Pretty_Name: "Hemp" - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 8 - Durability: 80 - -Leggings: - # Hemp - X9300: - Repairable: true - Repair_Material: X9291 - Repair_Material_Pretty_Name: "Hemp" - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 7 - Durability: 75 \ No newline at end of file diff --git a/extras/mods/1.6.x/emasher.blocks.yml b/extras/mods/1.6.x/emasher.blocks.yml deleted file mode 100644 index 7e74efb11..000000000 --- a/extras/mods/1.6.x/emasher.blocks.yml +++ /dev/null @@ -1,44 +0,0 @@ -# Config wrote by M1cr0man -# Possibly incomplete. Only covers ores -# Up to date as of Emasher Resource 1.2.3.5 -Mining: - # Bauxite - X1565|0: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: true - # Cassiterite - X1565|1: - XP_Gain: 175 - Double_Drops_Enabled: true - Is_Ore: true - # Emery - X1565|2: - XP_Gain: 350 - Double_Drops_Enabled: true - Is_Ore: true - # Galena - X1565|3: - XP_Gain: 300 - Double_Drops_Enabled: true - Is_Ore: true - # Native Copper - X1565|4: - XP_Gain: 175 - Double_Drops_Enabled: true - Is_Ore: true - # Petlandite - X1565|5: - XP_Gain: 300 - Double_Drops_Enabled: true - Is_Ore: true - # Ruby - X1565|6: - XP_Gain: 350 - Double_Drops_Enabled: true - Is_Ore: true - # Sapphire - X1565|7: - XP_Gain: 350 - Double_Drops_Enabled: true - Is_Ore: true \ No newline at end of file diff --git a/extras/mods/1.6.x/extrabiomesxl.blocks.yml b/extras/mods/1.6.x/extrabiomesxl.blocks.yml deleted file mode 100755 index b689b254a..000000000 --- a/extras/mods/1.6.x/extrabiomesxl.blocks.yml +++ /dev/null @@ -1,166 +0,0 @@ -# Config created by Dragyn -# Created For ExtrabiomesXL-universal-1.6.4-3.14.5 - -# -# Settings for Custom Excavation Blocks -### -Excavation: - # Quicksand - X2214|0: - XP_Gain: 40 - Double_Drops_Enabled: true - - -# -# Settings for Custom Herbalism Blocks -### -Herbalism: - # Cattails - X2201|0: - XP_Gain: 30 - Double_Drops_Enabled: true - # Hydrangea - X2202|1: - XP_Gain: 100 - Double_Drops_Enabled: true - # Buttercups - X2202|2: - XP_Gain: 100 - Double_Drops_Enabled: true - # Lavender - X2202|3: - XP_Gain: 100 - Double_Drops_Enabled: true - # Tiny Cactus - X2202|4: - XP_Gain: 30 - Double_Drops_Enabled: true - # Toadstool - X2202|6: - XP_Gain: 150 - Double_Drops_Enabled: true - # Calla Lillies - X2202|7: - XP_Gain: 100 - Double_Drops_Enabled: true -# -# Settings for Custom Mining Blocks -### -Mining: - X254|0: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - - X254|1: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - -# -# Settings for Custom Woodcutting Blocks -### -Woodcutting: - # Fir - X2208|0: - XP_Gain: 80 - Double_Drops_Enabled: true - Is_Log: true - # Acacia - X2208|1: - XP_Gain: 80 - Double_Drops_Enabled: true - Is_Log: true - # Cypress - X2208|2: - XP_Gain: 90 - Double_Drops_Enabled: true - Is_Log: true - # Japanese Maple - X2208|3: - XP_Gain: 100 - Double_Drops_Enabled: true - Is_Log: true - # Redwood Quarter - X2209|0: - XP_Gain: 100 - Double_Drops_Enabled: true - Is_Log: true - X2211|0: - XP_Gain: 100 - Double_Drops_Enabled: true - Is_Log: true - X2212|0: - XP_Gain: 100 - Double_Drops_Enabled: true - Is_Log: true - X2213|0: - XP_Gain: 100 - Double_Drops_Enabled: true - Is_Log: true - # Fir Quarters - X2211|1: - XP_Gain: 100 - Double_Drops_Enabled: true - Is_Log: true - X2212|1: - XP_Gain: 80 - Double_Drops_Enabled: true - Is_Log: true - X2213|1: - XP_Gain: 80 - Double_Drops_Enabled: true - Is_Log: true - # Oak Quarters - X2211|2: - XP_Gain: 100 - Double_Drops_Enabled: true - Is_Log: true - X2212|2: - XP_Gain: 70 - Double_Drops_Enabled: true - Is_Log: true - X2213|2: - XP_Gain: 70 - Double_Drops_Enabled: true - Is_Log: true - # Acacia - # Cypress - # Bald Cypress Quarter - X2225|0: - XP_Gain: 90 - Double_Drops_Enabled: true - Is_Log: true - # Bald Cypress Elbow - X2227|0: - XP_Gain: 90 - Double_Drops_Enabled: true - Is_Log: true - # Bald Cypress Log - X2231|2: - XP_Gain: 90 - Double_Drops_Enabled: true - Is_Log: true - # Rainbow Eucalyptus - X2228|0: - XP_Gain: 100 - Double_Drops_Enabled: true - Is_Log: true - X2229|0: - XP_Gain: 100 - Double_Drops_Enabled: true - Is_Log: true - X2231|0: - XP_Gain: 100 - Double_Drops_Enabled: true - Is_Log: true - # Autumn Log - X2231|1: - XP_Gain: 90 - Double_Drops_Enabled: true - Is_Log: true - # Sakura Log - X2238|0: - XP_Gain: 90 - Double_Drops_Enabled: true - Is_Log: true diff --git a/extras/mods/1.6.x/extrautilities.tools.yml b/extras/mods/1.6.x/extrautilities.tools.yml deleted file mode 100644 index ec705e126..000000000 --- a/extras/mods/1.6.x/extrautilities.tools.yml +++ /dev/null @@ -1,54 +0,0 @@ -# Config wrote by M1cr0man -# Up to date as of Extra Utilities 1.0.3c -Axes: - # Healing - X10264: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 4 - Repairable: true - Repair_Material: X10258 - Repair_Material_Pretty_Name: "Unstable Ingot" - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 3 - Durability: 1561 - -Hoes: - # Reversing - X10265: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 4 - Repairable: true - Repair_Material: X10258 - Repair_Material_Pretty_Name: "Unstable Ingot" - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 1561 - -Pickaxes: - # Destruction - X10263: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 4 - Repairable: false - Durability: 6244 - -Shovels: - # Erosion - X10262: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 4 - Repairable: false - Durability: 6244 - -Swords: - # Etheric - X10261: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 4 - Repairable: false - Durability: 1561 \ No newline at end of file diff --git a/extras/mods/1.6.x/factorization.blocks.yml b/extras/mods/1.6.x/factorization.blocks.yml deleted file mode 100644 index 1db6a5c9f..000000000 --- a/extras/mods/1.6.x/factorization.blocks.yml +++ /dev/null @@ -1,9 +0,0 @@ -# Config wrote by M1cr0man -# Possibly incomplete. Only covers ores -# Up to date as of Factorization 0.8.34 -Mining: - # Dark Iron Ore - X1004|0: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: true \ No newline at end of file diff --git a/extras/mods/1.6.x/forestry.blocks.yml b/extras/mods/1.6.x/forestry.blocks.yml deleted file mode 100644 index 861a285f1..000000000 --- a/extras/mods/1.6.x/forestry.blocks.yml +++ /dev/null @@ -1,19 +0,0 @@ -# Config wrote by M1cr0man -# Possibly incomplete. Only covers ores -# Up to date as of Forestry 2.3.1.1 -Mining: - # Apatite - X1398|0: - XP_Gain: 100 - Double_Drops_Enabled: true - Is_Ore: true - # Copper - X1398|1: - XP_Gain: 175 - Double_Drops_Enabled: true - Is_Ore: true - # Tin - X1398|2: - XP_Gain: 175 - Double_Drops_Enabled: true - Is_Ore: true \ No newline at end of file diff --git a/extras/mods/1.6.x/forestry.tools.yml b/extras/mods/1.6.x/forestry.tools.yml deleted file mode 100644 index ac65bc425..000000000 --- a/extras/mods/1.6.x/forestry.tools.yml +++ /dev/null @@ -1,27 +0,0 @@ -# Config wrote by M1cr0man -# Up to date as of Forestry 2.3.1.1 -Pickaxes: - # Survivalist - X13261: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 2 - Repairable: true - Repair_Material: X5261 - Repair_Material_Pretty_Name: "Bronze Ingot" - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 3 - Durability: 200 - -Shovels: - # Survivalist - X13264: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 2 - Repairable: true - Repair_Material: X5261 - Repair_Material_Pretty_Name: "Bronze Ingot" - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 3 - Durability: 200 \ No newline at end of file diff --git a/extras/mods/1.6.x/galacticraft.armor.yml b/extras/mods/1.6.x/galacticraft.armor.yml deleted file mode 100755 index cddc0ea08..000000000 --- a/extras/mods/1.6.x/galacticraft.armor.yml +++ /dev/null @@ -1,71 +0,0 @@ -# Config created by Dragyn -# Created For Galacticraft-1.6.4-2.0.7.904 and Galacticraft-Planets-1.6.4-2.0.7.904 -# -# Settings for Boots -### -Boots: - # Heavy Duty - X10149: - Repairable: true - Repair_Material: X10150 - Repair_Material_Data_Value: 9 - Repair_Material_Quantity: 2 - Durability: 500 - X10171: - Repairable: true - Repair_Material: X10161 - Repair_Material_Data_Value: 2 - Repair_Material_Quantity: 2 - Durability: 999 -# -# Settings for Chestplates -### -Chestplates: - # Heavy Duty - X10147: - Repairable: true - Repair_Material: X10150 - Repair_Material_Data_Value: 9 - Repair_Material_Quantity: 2 - Durability: 500 - X10169: - Repairable: true - Repair_Material: X10161 - Repair_Material_Data_Value: 2 - Repair_Material_Quantity: 2 - Durability: 999 -# -# Settings for Helmets -### -Helmets: - # Heavy Duty - X10146: - Repairable: true - Repair_Material: X10150 - Repair_Material_Data_Value: 9 - Repair_Material_Quantity: 2 - Durability: 500 - X10168: - Repairable: true - Repair_Material: X10161 - Repair_Material_Data_Value: 2 - Repair_Material_Quantity: 2 - Durability: 999 -# -# Settings for Leggings -### -Leggings: - # Heavy Duty - X10148: - Repairable: true - Repair_Material: X10150 - Repair_Material_Data_Value: 9 - Repair_Material_Quantity: 2 - Durability: 500 - X10170: - Repairable: true - Repair_Material: X10161 - Repair_Material_Data_Value: 2 - Repair_Material_Quantity: 2 - Durability: 999 - \ No newline at end of file diff --git a/extras/mods/1.6.x/galacticraft.blocks.yml b/extras/mods/1.6.x/galacticraft.blocks.yml deleted file mode 100755 index 629383801..000000000 --- a/extras/mods/1.6.x/galacticraft.blocks.yml +++ /dev/null @@ -1,98 +0,0 @@ -# Config created by Dragyn -# Created For Galacticraft-1.6.4-2.0.7.904 and Galacticraft-Planets-1.6.4-2.0.7.904 -# -# Settings for Custom Excavation Blocks -### -Excavation: - # Dirt - X3347|3: - XP_Gain: 40 - Double_Drops_Enabled: true - Block_2|0: - XP_Gain: 99 - Double_Drops_Enabled: true - -# -# Settings for Custom Mining Blocks -### -Mining: - # Copper Ore - X3347|0: - XP_Gain: 350 - Double_Drops_Enabled: true - Is_Ore: true - X3372|5: - XP_Gain: 450 - Double_Drops_Enabled: true - Is_Ore: true - X3390|0: - XP_Gain: 550 - Double_Drops_Enabled: true - Is_Ore: true - # Tin Ore - X3347|1: - XP_Gain: 350 - Double_Drops_Enabled: true - Is_Ore: true - X3372|6: - XP_Gain: 450 - Double_Drops_Enabled: true - Is_Ore: true - X3390|1: - XP_Gain: 550 - Double_Drops_Enabled: true - Is_Ore: true - # Aluminum Ore - X3372|7: - XP_Gain: 450 - Double_Drops_Enabled: true - Is_Ore: true - # Silicon Ore - X3372|8: - XP_Gain: 450 - Double_Drops_Enabled: true - Is_Ore: true - # Cheese Ore - X3347|2: - XP_Gain: 350 - Double_Drops_Enabled: true - Is_Ore: true - # Iron Ore - X3390|3: - XP_Gain: 550 - Double_Drops_Enabled: true - Is_Ore: true - # Desh Ore - X3390|2: - XP_Gain: 600 - Double_Drops_Enabled: true - Is_Ore: true - # Moon Stone - X3347|4: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - # Moon Turf - X3347|5: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - # Mars Cobblestone - X3390|4: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - # Mars Rock/Stone - X3390|5: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - X3390|6: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - X3390|9: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - diff --git a/extras/mods/1.6.x/galacticraft.tools.yml b/extras/mods/1.6.x/galacticraft.tools.yml deleted file mode 100755 index 7a8773fbf..000000000 --- a/extras/mods/1.6.x/galacticraft.tools.yml +++ /dev/null @@ -1,123 +0,0 @@ -# Config created by Dragyn -# Created For Galacticraft-1.6.4-2.0.7.904 and Galacticraft-Planets-1.6.4-2.0.7.904 -# -# Settings for Axes -### -Axes: - # Heavy Duty - X10145: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X10150 - Repair_Material_Data_Value: 9 - Repair_Material_Quantity: 2 - Durability: 500 - # Desh - X10167: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: 10161 - Repair_Material_Data_Value: 2 - Repair_Material_Quantity: 2 - Durability: 1000 - -# -# Settings for Hoes -### -Hoes: - # Heavy Duty - X10144: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X10150 - Repair_Material_Data_Value: 9 - Repair_Material_Quantity: 2 - Durability: 500 - # Desh - X10166: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: 10161 - Repair_Material_Data_Value: 2 - Repair_Material_Quantity: 2 - Durability: 1000 -# -# Settings for Pickaxes -### -Pickaxes: - # Heavy Duty - X10142: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X10150 - Repair_Material_Data_Value: 9 - Repair_Material_Quantity: 2 - Durability: 500 - # Desh - X10164: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: 10161 - Repair_Material_Data_Value: 2 - Repair_Material_Quantity: 2 - Durability: 1000 -# -# Settings for Shovels -### -Shovels: - # Heavy Duty - X10143: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X10150 - Repair_Material_Data_Value: 9 - Repair_Material_Quantity: 2 - Durability: 500 - # Desh - X10165: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: 10161 - Repair_Material_Data_Value: 2 - Repair_Material_Quantity: 2 - Durability: 1000 -# -# Settings for Swords -### -Swords: - # Heavy Duty - X10141: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 4 - Repairable: true - Repair_Material: X10150 - Repair_Material_Data_Value: 9 - Repair_Material_Quantity: 2 - Durability: 500 - # Desh - X10163: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: 10161 - Repair_Material_Data_Value: 2 - Repair_Material_Quantity: 2 - Durability: 1000 \ No newline at end of file diff --git a/extras/mods/1.6.x/metallurgy3.armor.yml b/extras/mods/1.6.x/metallurgy3.armor.yml deleted file mode 100755 index 861f4aef0..000000000 --- a/extras/mods/1.6.x/metallurgy3.armor.yml +++ /dev/null @@ -1,1018 +0,0 @@ -# Config created by Dragyn -# Created For Metallurgy-1.6.4-3.3.1 -# -# Settings for Boots -### -Boots: - # Copper - X26516: - Repairable: true - Repair_Material: X26507 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Bronze - X26666: - Repairable: true - Repair_Material: X26657 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Hepatizon - X26716: - Repairable: true - Repair_Material: X26707 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Damascus - X26766: - Repairable: true - Repair_Material: X26757 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Angmallen - X26816: - Repairable: true - Repair_Material: X26807 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Steel - X26866: - Repairable: true - Repair_Material: X26857 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Silver - X26966: - Repairable: true - Repair_Material: X26957 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Platinum - X27016: - Repairable: true - Repair_Material: X27007 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Brass - X27066: - Repairable: true - Repair_Material: X27057 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Electrum - X27116: - Repairable: true - Repair_Material: X27107 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Ignatius - X27166: - Repairable: true - Repair_Material: X27157 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Shadow Iron - X27216: - Repairable: true - Repair_Material: X27207 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Midasium - X27316: - Repairable: true - Repair_Material: X27307 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Vyroxeres - X27366: - Repairable: true - Repair_Material: X27357 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Ceruclase - X27416: - Repairable: true - Repair_Material: X27407 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Kalendrite - X27516: - Repairable: true - Repair_Material: X27507 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Vulcanite - X27566: - Repairable: true - Repair_Material: X27557 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Sanguinite - X27616: - Repairable: true - Repair_Material: X27607 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Inolashite - X27716: - Repairable: true - Repair_Material: X27707 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Amordrine - X27766: - Repairable: true - Repair_Material: X27757 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Prometheum - X27816: - Repairable: true - Repair_Material: X27757 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Deep Iron - X27866: - Repairable: true - Repair_Material: X27857 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Black Steel - X27966: - Repairable: true - Repair_Material: X27957 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Oureclase - X28016: - Repairable: true - Repair_Material: X28007 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Astral Silver - X28066: - Repairable: true - Repair_Material: X28057 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Carmot - X28116: - Repairable: true - Repair_Material: X28107 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Mithril - X28166: - Repairable: true - Repair_Material: X28107 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Haderoth - X28316: - Repairable: true - Repair_Material: X28307 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Orichalcum - X28366: - Repairable: true - Repair_Material: X28357 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Celenegil - X28416: - Repairable: true - Repair_Material: X28407 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Adamantine - X28466: - Repairable: true - Repair_Material: X28457 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Atlarus - X28516: - Repairable: true - Repair_Material: X28507 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Tartarite - X28566: - Repairable: true - Repair_Material: X28557 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Eximite - X28616: - Repairable: true - Repair_Material: X28607 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Desichalkos - X28716: - Repairable: true - Repair_Material: X28707 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - - -# -# Settings for Chestplates -### -Chestplates: - # Copper - X26514: - Repairable: true - Repair_Material: X26507 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Bronze - X26664: - Repairable: true - Repair_Material: X26657 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Hepatizon - X26714: - Repairable: true - Repair_Material: X26707 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Damascus - X26764: - Repairable: true - Repair_Material: X26757 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Angmallen - X26814: - Repairable: true - Repair_Material: X26807 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Steel - X26864: - Repairable: true - Repair_Material: X26857 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Silver - X26964: - Repairable: true - Repair_Material: X26957 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Platinum - X27014: - Repairable: true - Repair_Material: X27007 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Brass - X27064: - Repairable: true - Repair_Material: X27057 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Electrum - X27114: - Repairable: true - Repair_Material: X27107 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Ignatius - X27164: - Repairable: true - Repair_Material: X27157 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Shadow Iron - X27214: - Repairable: true - Repair_Material: X27207 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Midasium - X27314: - Repairable: true - Repair_Material: X27307 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Vyroxeres - X27364: - Repairable: true - Repair_Material: X27357 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Ceruclase - X27414: - Repairable: true - Repair_Material: X27407 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Kalendrite - X27514: - Repairable: true - Repair_Material: X27507 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Vulcanite - X27564: - Repairable: true - Repair_Material: X27557 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Sanguinite - X27614: - Repairable: true - Repair_Material: X27607 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Inolashite - X27714: - Repairable: true - Repair_Material: X27707 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Amordrine - X27764: - Repairable: true - Repair_Material: X27757 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Prometheum - X27814: - Repairable: true - Repair_Material: X27757 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Deep Iron - X27864: - Repairable: true - Repair_Material: X27857 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Black Steel - X27964: - Repairable: true - Repair_Material: X27957 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Oureclase - X28014: - Repairable: true - Repair_Material: X28007 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Astral Silver - X28064: - Repairable: true - Repair_Material: X28057 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Carmot - X28114: - Repairable: true - Repair_Material: X28107 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Mithril - X28164: - Repairable: true - Repair_Material: X28107 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Haderoth - X28314: - Repairable: true - Repair_Material: X28307 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Orichalcum - X28364: - Repairable: true - Repair_Material: X28357 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Celenegil - X28414: - Repairable: true - Repair_Material: X28407 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Adamantine - X28464: - Repairable: true - Repair_Material: X28457 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Atlarus - X28514: - Repairable: true - Repair_Material: X28507 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Tartarite - X28564: - Repairable: true - Repair_Material: X28557 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Eximite - X28614: - Repairable: true - Repair_Material: X28607 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Desichalkos - X28714: - Repairable: true - Repair_Material: X28707 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - - - - -# -# Settings for Helmets -### -Helmets: - # Copper - X26513: - Repairable: true - Repair_Material: X26507 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Bronze - X26663: - Repairable: true - Repair_Material: X26657 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Hepatizon - X26713: - Repairable: true - Repair_Material: X26707 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Damascus - X26763: - Repairable: true - Repair_Material: X26757 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Angmallen - X26813: - Repairable: true - Repair_Material: X26807 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Steel - X26863: - Repairable: true - Repair_Material: X26857 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Silver - X26963: - Repairable: true - Repair_Material: X26957 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Platinum - X27013: - Repairable: true - Repair_Material: X27007 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Brass - X27063: - Repairable: true - Repair_Material: X27057 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Electrum - X27113: - Repairable: true - Repair_Material: X27107 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Ignatius - X27163: - Repairable: true - Repair_Material: X27157 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Shadow Iron - X27213: - Repairable: true - Repair_Material: X27207 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Midasium - X27313: - Repairable: true - Repair_Material: X27307 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Vyroxeres - X27363: - Repairable: true - Repair_Material: X27357 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Ceruclase - X27413: - Repairable: true - Repair_Material: X27407 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Kalendrite - X27513: - Repairable: true - Repair_Material: X27507 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Vulcanite - X27563: - Repairable: true - Repair_Material: X27557 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Sanguinite - X27613: - Repairable: true - Repair_Material: X27607 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Inolashite - X27713: - Repairable: true - Repair_Material: X27707 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Amordrine - X27763: - Repairable: true - Repair_Material: X27757 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Prometheum - X27813: - Repairable: true - Repair_Material: X27757 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Deep Iron - X27863: - Repairable: true - Repair_Material: X27857 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Black Steel - X27963: - Repairable: true - Repair_Material: X27957 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Oureclase - X28013: - Repairable: true - Repair_Material: X28007 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Astral Silver - X28063: - Repairable: true - Repair_Material: X28057 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Carmot - X28113: - Repairable: true - Repair_Material: X28107 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Mithril - X28163: - Repairable: true - Repair_Material: X28107 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Haderoth - X28313: - Repairable: true - Repair_Material: X28307 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Orichalcum - X28363: - Repairable: true - Repair_Material: X28357 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Celenegil - X28413: - Repairable: true - Repair_Material: X28407 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Adamantine - X28463: - Repairable: true - Repair_Material: X28457 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Atlarus - X28513: - Repairable: true - Repair_Material: X28507 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Tartarite - X28563: - Repairable: true - Repair_Material: X28557 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Eximite - X28613: - Repairable: true - Repair_Material: X28607 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Desichalkos - X28713: - Repairable: true - Repair_Material: X28707 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - - - - -# -# Settings for Leggings -### -Leggings: - # Copper - X26515: - Repairable: true - Repair_Material: X26507 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Bronze - X26665: - Repairable: true - Repair_Material: X26657 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Hepatizon - X26715: - Repairable: true - Repair_Material: X26707 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Damascus - X26765: - Repairable: true - Repair_Material: X26757 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Angmallen - X26815: - Repairable: true - Repair_Material: X26807 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Steel - X26865: - Repairable: true - Repair_Material: X26857 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Silver - X26965: - Repairable: true - Repair_Material: X26957 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Platinum - X27015: - Repairable: true - Repair_Material: X27007 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Brass - X27065: - Repairable: true - Repair_Material: X27057 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Electrum - X27115: - Repairable: true - Repair_Material: X27107 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Ignatius - X27165: - Repairable: true - Repair_Material: X27157 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Shadow Iron - X27215: - Repairable: true - Repair_Material: X27207 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Midasium - X27315: - Repairable: true - Repair_Material: X27307 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Vyroxeres - X27365: - Repairable: true - Repair_Material: X27357 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Ceruclase - X27415: - Repairable: true - Repair_Material: X27407 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Kalendrite - X27515: - Repairable: true - Repair_Material: X27507 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Vulcanite - X27565: - Repairable: true - Repair_Material: X27557 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Sanguinite - X27615: - Repairable: true - Repair_Material: X27607 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Inolashite - X27715: - Repairable: true - Repair_Material: X27707 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Amordrine - X27765: - Repairable: true - Repair_Material: X27757 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Prometheum - X27815: - Repairable: true - Repair_Material: X27757 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Deep Iron - X27865: - Repairable: true - Repair_Material: X27857 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Black Steel - X27965: - Repairable: true - Repair_Material: X27957 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Oureclase - X28015: - Repairable: true - Repair_Material: X28007 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Astral Silver - X28065: - Repairable: true - Repair_Material: X28057 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Carmot - X28115: - Repairable: true - Repair_Material: X28107 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Mithril - X28165: - Repairable: true - Repair_Material: X28107 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Haderoth - X28315: - Repairable: true - Repair_Material: X28307 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Orichalcum - X28365: - Repairable: true - Repair_Material: X28357 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Celenegil - X28415: - Repairable: true - Repair_Material: X28407 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Adamantine - X28465: - Repairable: true - Repair_Material: X28457 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Atlarus - X28515: - Repairable: true - Repair_Material: X28507 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Tartarite - X28565: - Repairable: true - Repair_Material: X28557 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Eximite - X28615: - Repairable: true - Repair_Material: X28607 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Desichalkos - X28715: - Repairable: true - Repair_Material: X28707 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - - - - - - - - - - diff --git a/extras/mods/1.6.x/metallurgy3.blocks.yml b/extras/mods/1.6.x/metallurgy3.blocks.yml deleted file mode 100755 index a7f5ae8d9..000000000 --- a/extras/mods/1.6.x/metallurgy3.blocks.yml +++ /dev/null @@ -1,185 +0,0 @@ -# Config created by Dragyn -# Created For Metallurgy-1.6.4-3.3.1 -# -# -# Settings for Custom Mining Blocks -### -Mining: - # Copper - X900|0: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: true - # Tin - X900|1: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: true - # Zinc - X902|0: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: true - # Silver - X902|1: - XP_Gain: 350 - Double_Drops_Enabled: true - Is_Ore: true - # Platinum - X902|3: - XP_Gain: 350 - Double_Drops_Enabled: true - Is_Ore: true - - # NETHER ORES - # Ignatius - X903|0: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: true - # Shadow Iron - X903|1: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: true - # Lemurite - X903|2: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: true - # Midasium - X903|3: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: true - # Vyroxeres - X903|4: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: true - # Ceruclase - X903|5: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: true - # Alduorite - X903|6: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: true - # Kalendrite - X903|7: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: true - # Vulcanite - X903|8: - XP_Gain: 350 - Double_Drops_Enabled: true - Is_Ore: true - # Sanguinite - X903|9: - XP_Gain: 450 - Double_Drops_Enabled: true - Is_Ore: true - - # Manganese - X900|2: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: true - # Eximite - X900|5: - XP_Gain: 350 - Double_Drops_Enabled: true - Is_Ore: true - # Meutoite - X900|6: - XP_Gain: 350 - Double_Drops_Enabled: true - Is_Ore: true - # Sulfur - X905|7: - XP_Gain: 150 - Double_Drops_Enabled: true - Is_Ore: false - # Phosphorite - X905|8: - XP_Gain: 150 - Double_Drops_Enabled: true - Is_Ore: false - # Saltpeter - X905|9: - XP_Gain: 150 - Double_Drops_Enabled: true - Is_Ore: false - # Magnesium - X905|10: - XP_Gain: 150 - Double_Drops_Enabled: true - Is_Ore: false - # Bitumen - X905|11: - XP_Gain: 100 - Double_Drops_Enabled: true - Is_Ore: false - # Potash - X905|12: - XP_Gain: 150 - Double_Drops_Enabled: true - Is_Ore: false - # Prometheum - X906|0: - XP_Gain: 350 - Double_Drops_Enabled: true - Is_Ore: true - # Deep Iron - X906|1: - XP_Gain: 350 - Double_Drops_Enabled: true - Is_Ore: true - # Infuscolium - X906|2: - XP_Gain: 350 - Double_Drops_Enabled: true - Is_Ore: true - # Oureclase - X906|4: - XP_Gain: 650 - Double_Drops_Enabled: true - Is_Ore: true - # Astral Silver - X906|5: - XP_Gain: 650 - Double_Drops_Enabled: true - Is_Ore: true - # Carmot - X906|6: - XP_Gain: 350 - Double_Drops_Enabled: true - Is_Ore: true - # Mithril - X906|7: - XP_Gain: 750 - Double_Drops_Enabled: true - Is_Ore: true - # Rubracium - X906|8: - XP_Gain: 800 - Double_Drops_Enabled: true - Is_Ore: true - # Orichalcum - X906|11: - XP_Gain: 900 - Double_Drops_Enabled: true - Is_Ore: true - # Adamantine - X906|13: - XP_Gain: 1000 - Double_Drops_Enabled: true - Is_Ore: true - # Atlarus - X906|14: - XP_Gain: 1000 - Double_Drops_Enabled: true - Is_Ore: true diff --git a/extras/mods/1.6.x/metallurgy3.tools.yml b/extras/mods/1.6.x/metallurgy3.tools.yml deleted file mode 100644 index 2e827d221..000000000 --- a/extras/mods/1.6.x/metallurgy3.tools.yml +++ /dev/null @@ -1,1789 +0,0 @@ -# -# mcMMO Mod configuration for use with Metallurgy -# Made for Metallurgy-1.6.4-3.3.1 -# By Skuli, updated by Dragyn -# -### - -# -# Settings for Axes -### -Axes: - #Copper_Axe - X26510: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X26507 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 180 - #Bronze_Axe - X26660: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X26657 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 250 - #Hepatizon_Axe - X26710: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X26707 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 300 - #Damascus_Steel_Axe - X26760: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X26757 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - #Angmallen_Axe - X26810: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X26807 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 300 - #Steel_Axe - X26860: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X26857 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 750 - #Brass_Axe - X27060: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27057 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 15 - #Silver_Axe - X26960: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X26957 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 25 - #Electrum_Axe - X27110: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27107 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 50 - #Platinum_Axe - X27010: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27007 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 100 - #Ignatius_Axe - X27160: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27207 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 200 - #Shadow_Iron_Axe - X27210: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27157 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 300 - #Shadow_Steel_Axe - X27660: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27657 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 400 - #Midasium_Axe - X27310: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27307 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 100 - #Vyroxeres_Axe - X27360: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27357 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 300 - #Ceruclase_Axe - X27410: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27407 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - #Inolashite_Axe - X27710: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27707 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 900 - #Kalendrite_Axe - X27510: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27507 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 1000 - #Amordrine_Axe - X27760: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27757 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - #Vulcanite_Axe - X27560: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27757 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 1500 - #Sanguinite_Axe - X27610: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27607 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 1750 - #Prometheum_Axe - X27810: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27808 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 200 - #Deep_Iron_Axe - X27860: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27857 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 250 - #Black_Steel_Axe - X27960: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27957 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - #Oureclase_Axe - X28010: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X28007 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 750 - #Astral_Silver_Axe - X28060: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X28057 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 35 - #Carmot_Axe - X28110: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X28107 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 50 - #Mithril_Axe - X28160: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X28157 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 1000 - #Quicksilver_Axe - X28260: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X28257 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 1100 - #Haderoth_Axe - X28310: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X28307 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 1250 - #Orichalcum_Axe - X28360: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X28357 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 1350 - #Celenegil_Axe - X28410: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X28407 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 1600 - #Adamantine_Axe - X28460: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X28457 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 1550 - #Atlarus_Axe - X28510: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X28507 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 1750 - #Tartarite_Axe - X28560: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X28557 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 3000 - - -# -# Settings for Bows -### -Bows: - #Bow_1 - #Bow_2 - -# -# Settings for Hoes -### -Hoes: - #Copper_Hoe - X26511: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X26507 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 180 - #Bronze_Hoe - X26661: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X26657 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 250 - #Hepatizon_Hoe - X26711: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X26707 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 300 - #Damascus_Steel_Hoe - X26761: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X26757 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - #Angmallen_Hoe - X26811: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X26807 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 300 - #Steel_Hoe - X26861: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X26857 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 750 - #Brass_Hoe - X27061: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27057 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 15 - #Silver_Hoe - X26961: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X26957 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 25 - #Electrum_Hoe - X27111: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27107 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 50 - #Platinum_Hoe - X27011: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27007 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 100 - #Ignatius_Hoe - X27161: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27207 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 200 - #Shadow_Iron_Hoe - X27211: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27157 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 300 - #Shadow_Steel_Hoe - X27661: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27657 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 400 - #Midasium_Hoe - X27311: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27307 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 100 - #Vyroxeres_Hoe - X27361: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27357 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 300 - #Ceruclase_Hoe - X27411: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27407 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - #Inolashite_Hoe - X27711: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27707 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 900 - #Kalendrite_Hoe - X27511: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27507 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 1000 - #Amordrine_Hoe - X27761: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27757 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - #Vulcanite_Hoe - X27561: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27757 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 1500 - #Sanguinite_Hoe - X27611: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27607 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 1750 - #Prometheum_Hoe - X27811: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27808 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 200 - #Deep_Iron_Hoe - X27861: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27857 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 250 - #Black_Steel_Hoe - X27961: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27957 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - #Oureclase_Hoe - X28011: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X28007 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 750 - #Astral_Silver_Hoe - X28061: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X28057 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 35 - #Carmot_Hoe - X28111: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X28107 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 50 - #Mithril_Hoe - X28161: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X28157 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 1000 - #Quicksilver_Hoe - X28261: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X28257 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 1100 - #Haderoth_Hoe - X28311: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X28307 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 1250 - #Orichalcum_Hoe - X28361: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X28357 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 1350 - #Celenegil_Hoe - X28411: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X28407 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 1600 - #Adamantine_Hoe - X28461: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X28457 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 1550 - #Atlarus_Hoe - X28511: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X28507 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 1750 - #Tartarite_Hoe - X28561: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X28557 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 3000 - - -# -# Settings for Pickaxes -### -Pickaxes: - #Copper_Pickaxe - X26508: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X26507 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 180 - #Bronze_Pickaxe - X26658: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X26657 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 250 - #Hepatizon_Pickaxe - X26708: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X26707 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 300 - #Damascus_Steel_Pickaxe - X26758: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X26757 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - #Angmallen_Pickaxe - X26808: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X26807 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 300 - #Steel_Pickaxe - X26858: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X26857 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 750 - #Brass_Pickaxe - X27058: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27057 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 15 - #Silver_Pickaxe - X26958: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X26957 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 25 - #Electrum_Pickaxe - X27108: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27107 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 50 - #Platinum_Pickaxe - X27008: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27007 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 100 - #Ignatius_Pickaxe - X27158: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27207 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 200 - #Shadow_Iron_Pickaxe - X27208: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27157 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 300 - #Shadow_Steel_Pickaxe - X27658: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27657 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 400 - #Midasium_Pickaxe - X27308: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27307 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 100 - #Vyroxeres_Pickaxe - X27358: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27357 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 300 - #Ceruclase_Pickaxe - X27408: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27407 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - #Inolashite_Pickaxe - X27708: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27707 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 900 - #Kalendrite_Pickaxe - X27508: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27507 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 1000 - #Amordrine_Pickaxe - X27758: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27757 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - #Vulcanite_Pickaxe - X27558: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27757 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 1500 - #Sanguinite_Pickaxe - X27608: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27607 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 1750 - #Prometheum_Pickaxe - X27808: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27808 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 200 - #Deep_Iron_Pickaxe - X27858: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27857 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 250 - #Black_Steel_Pickaxe - X27958: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27957 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - #Oureclase_Pickaxe - X28008: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X28007 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 750 - #Astral_Silver_Pickaxe - X28058: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X28057 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 35 - #Carmot_Pickaxe - X28108: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X28107 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 50 - #Mithril_Pickaxe - X28158: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X28157 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 1000 - #Quicksilver_Pickaxe - X28258: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X28257 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 1100 - #Haderoth_Pickaxe - X28308: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X28307 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 1250 - #Orichalcum_Pickaxe - X28358: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X28357 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 1350 - #Celenegil_Pickaxe - X28408: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X28407 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 1600 - #Adamantine_Pickaxe - X28458: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X28457 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 1550 - #Atlarus_Pickaxe - X28508: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X28507 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 1750 - #Tartarite_Pickaxe - X28558: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X28557 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 3000 - -# -# Settings for Shovels -### -Shovels: - #Copper_Shovel - X26509: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X26507 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 180 - #Bronze_Shovel - X26659: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X26657 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 250 - #Hepatizon_Shovel - X26709: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X26707 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 300 - #Damascus_Steel_Shovel - X26759: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X26757 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - #Angmallen_Shovel - X26809: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X26807 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 300 - #Steel_Shovel - X26859: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X26857 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 750 - #Brass_Shovel - X27059: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27057 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 15 - #Silver_Shovel - X26959: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X26957 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 25 - #Electrum_Shovel - X27109: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27107 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 50 - #Platinum_Shovel - X27009: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27007 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 100 - #Ignatius_Shovel - X27159: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27207 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 200 - #Shadow_Iron_Shovel - X27209: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27157 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 300 - #Shadow_Steel_Shovel - X27659: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27657 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 400 - #Midasium_Shovel - X27309: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27307 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 100 - #Vyroxeres_Shovel - X27359: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27357 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 300 - #Ceruclase_Shovel - X27409: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27407 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - #Inolashite_Shovel - X27709: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27707 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 900 - #Kalendrite_Shovel - X27509: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27507 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 1000 - #Amordrine_Shovel - X27759: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27757 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - #Vulcanite_Shovel - X27559: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27757 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 1500 - #Sanguinite_Shovel - X27609: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27607 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 1750 - #Prometheum_Shovel - X27809: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27808 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 200 - #Deep_Iron_Shovel - X27859: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27857 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 250 - #Black_Steel_Shovel - X27959: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27957 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - #Oureclase_Shovel - X28009: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X28007 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 750 - #Astral_Silver_Shovel - X28059: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X28057 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 35 - #Carmot_Shovel - X28109: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X28107 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 50 - #Mithril_Shovel - X28159: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X28157 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 1000 - #Quicksilver_Shovel - X28259: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X28257 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 1100 - #Haderoth_Shovel - X28309: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X28307 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 1250 - #Orichalcum_Shovel - X28359: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X28357 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 1350 - #Celenegil_Shovel - X28409: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X28407 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 1600 - #Adamantine_Shovel - X28459: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X28457 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 1550 - #Atlarus_Shovel - X28509: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X28507 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 1750 - #Tartarite_Shovel - X28559: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X28557 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 3000 -# -# Settings for Swords -### -Swords: - #Copper_Sword - X26512: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X26507 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 180 - #Bronze_Sword - X26661: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X26657 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 250 - #Hepatizon_Sword - X26712: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X26707 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 300 - #Damascus_Steel_Sword - X26762: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X26757 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - #Angmallen_Sword - X26812: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X26807 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 300 - #Steel_Sword - X26862: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X26857 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 750 - #Brass_Sword - X27062: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27057 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 15 - #Silver_Sword - X26962: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X26957 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 25 - #Electrum_Sword - X27111: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27107 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 50 - #Platinum_Sword - X27012: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27007 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 100 - #Ignatius_Sword - X27162: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27207 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 200 - #Shadow_Iron_Sword - X27212: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27157 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 300 - #Shadow_Steel_Sword - X27662: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27657 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 400 - #Midasium_Sword - X27312: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27307 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 100 - #Vyroxeres_Sword - X27362: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27357 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 300 - #Ceruclase_Sword - X27412: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27407 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - #Inolashite_Sword - X27712: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27707 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 900 - #Kalendrite_Sword - X27512: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27507 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 1000 - #Amordrine_Sword - X27762: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27757 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - #Vulcanite_Sword - X27562: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27757 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 1500 - #Sanguinite_Sword - X27612: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27607 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 1750 - #Prometheum_Sword - X27812: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27808 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 200 - #Deep_Iron_Sword - X27862: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27857 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 250 - #Black_Steel_Sword - X27962: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27957 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - #Oureclase_Sword - X28012: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X28007 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 750 - #Astral_Silver_Sword - X28062: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X28057 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 35 - #Carmot_Sword - X28111: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X28107 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 50 - #Mithril_Sword - X28162: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X28157 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 1000 - #Quicksilver_Sword - X28262: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X28257 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 1100 - #Haderoth_Sword - X28312: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X28307 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 1250 - #Orichalcum_Sword - X28362: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X28357 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 1350 - #Celenegil_Sword - X28412: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X28407 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 1600 - #Adamantine_Sword - X28462: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X28457 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 1550 - #Atlarus_Sword - X28512: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X28507 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 1750 - # Tartarite_Sword - X28562: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X28557 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 3000 \ No newline at end of file diff --git a/extras/mods/1.6.x/minefactoryreloaded.armor.yml b/extras/mods/1.6.x/minefactoryreloaded.armor.yml deleted file mode 100644 index ebaeb91e8..000000000 --- a/extras/mods/1.6.x/minefactoryreloaded.armor.yml +++ /dev/null @@ -1,11 +0,0 @@ -# Config wrote by M1cr0man -# Up to date as of Minefactory Reloaded 2.7.9 Final -Boots: - # Plastic - X12306: - Repairable: true - Repair_Material: X12249 - Repair_Material_Pretty_Name: "Plastic Sheets" - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 4 - Durability: 39 \ No newline at end of file diff --git a/extras/mods/1.6.x/natura.armor.yml b/extras/mods/1.6.x/natura.armor.yml deleted file mode 100644 index ef74a5574..000000000 --- a/extras/mods/1.6.x/natura.armor.yml +++ /dev/null @@ -1,41 +0,0 @@ -# Config wrote by M1cr0man -# Up to date as of Natura 2.1.14 -Boots: - # Impskin - X12712: - Repairable: true - Repair_Material: X12660 - Repair_Material_Pretty_Name: "Imp Leather" - Repair_Material_Data_Value: 6 - Repair_Material_Quantity: 4 - Durability: 429 - -Chestplates: - # Impskin - X12710: - Repairable: true - Repair_Material: X12660 - Repair_Material_Pretty_Name: "Imp Leather" - Repair_Material_Data_Value: 6 - Repair_Material_Quantity: 8 - Durability: 528 - -Helmets: - # Impskin - X12709: - Repairable: true - Repair_Material: X12660 - Repair_Material_Pretty_Name: "Imp Leather" - Repair_Material_Data_Value: 6 - Repair_Material_Quantity: 5 - Durability: 363 - -Leggings: - # Impskin - X12709: - Repairable: true - Repair_Material: X12660 - Repair_Material_Pretty_Name: "Imp Leather" - Repair_Material_Data_Value: 6 - Repair_Material_Quantity: 7 - Durability: 495 \ No newline at end of file diff --git a/extras/mods/1.6.x/natura.tools.yml b/extras/mods/1.6.x/natura.tools.yml deleted file mode 100644 index 67bc07edb..000000000 --- a/extras/mods/1.6.x/natura.tools.yml +++ /dev/null @@ -1,272 +0,0 @@ -# Config wrote by M1cr0man -# Up to date as of Natura 2.1.14 -Axes: - # Bloodwood - X12685: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 2 - Repairable: true - Repair_Material: X3262 - Repair_Material_Pretty_Name: "Bloodwood Planks" - Repair_Material_Data_Value: 4 - Repair_Material_Quantity: 3 - Durability: 350 - # Darkwood - X12689: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 2 - Repairable: true - Repair_Material: X3262 - Repair_Material_Pretty_Name: "Darkwood Planks" - Repair_Material_Data_Value: 11 - Repair_Material_Quantity: 3 - Durability: 131 - # Fusewood - X12693: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 2 - Repairable: true - Repair_Material: X3262 - Repair_Material_Pretty_Name: "Fusewood Planks" - Repair_Material_Data_Value: 12 - Repair_Material_Quantity: 3 - Durability: 250 - # Ghostwood - X12681: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 2 - Repairable: true - Repair_Material: X3262 - Repair_Material_Pretty_Name: "Ghostwood Planks" - Repair_Material_Data_Value: 2 - Repair_Material_Quantity: 3 - Durability: 59 - # Quartz - X12697: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 2 - Repairable: true - Repair_Material: QUARTZ_BLOCK - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 3 - Durability: 131 - -Bows: - # Bloodwood - X12706: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 2 - Repairable: true - Repair_Material: X12677 - Repair_Material_Pretty_Name: "Bloodwood Stick" - Repair_Material_Data_Value: 4 - Repair_Material_Quantity: 3 - Durability: 1501 - # Darkwood - X12707: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 2 - Repairable: true - Repair_Material: X12677 - Repair_Material_Pretty_Name: "Darkwood Stick" - Repair_Material_Data_Value: 11 - Repair_Material_Quantity: 3 - Durability: 162 - # Fusewood - X12708: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 2 - Repairable: true - Repair_Material: X12677 - Repair_Material_Pretty_Name: "Fusewood Stick" - Repair_Material_Data_Value: 12 - Repair_Material_Quantity: 3 - Durability: 28 - # Ghostwood - X12705: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 2 - Repairable: true - Repair_Material: X12677 - Repair_Material_Pretty_Name: "Ghostwood Stick" - Repair_Material_Data_Value: 2 - Repair_Material_Quantity: 3 - Durability: 384 - - -Pickaxes: - # Bloodwood - X12683: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 2 - Repairable: true - Repair_Material: X3262 - Repair_Material_Pretty_Name: "Bloodwood Planks" - Repair_Material_Data_Value: 4 - Repair_Material_Quantity: 3 - Durability: 350 - # Darkwood - X12687: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 2 - Repairable: true - Repair_Material: X3262 - Repair_Material_Pretty_Name: "Darkwood Planks" - Repair_Material_Data_Value: 11 - Repair_Material_Quantity: 3 - Durability: 131 - # Fusewood - X12691: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 2 - Repairable: true - Repair_Material: X3262 - Repair_Material_Pretty_Name: "Fusewood Planks" - Repair_Material_Data_Value: 12 - Repair_Material_Quantity: 3 - Durability: 250 - # Ghostwood - X12679: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 2 - Repairable: true - Repair_Material: X3262 - Repair_Material_Pretty_Name: "Ghostwood Planks" - Repair_Material_Data_Value: 2 - Repair_Material_Quantity: 3 - Durability: 59 - # Quartz - X12695: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 2 - Repairable: true - Repair_Material: QUARTZ_BLOCK - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 3 - Durability: 131 - -Shovels: - # Bloodwood - X12684: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 2 - Repairable: true - Repair_Material: X3262 - Repair_Material_Pretty_Name: "Bloodwood Planks" - Repair_Material_Data_Value: 4 - Repair_Material_Quantity: 1 - Durability: 350 - # Darkwood - X12688: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 2 - Repairable: true - Repair_Material: X3262 - Repair_Material_Pretty_Name: "Darkwood Planks" - Repair_Material_Data_Value: 11 - Repair_Material_Quantity: 1 - Durability: 131 - # Fusewood - X12692: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 2 - Repairable: true - Repair_Material: X3262 - Repair_Material_Pretty_Name: "Fusewood Planks" - Repair_Material_Data_Value: 12 - Repair_Material_Quantity: 1 - Durability: 250 - # Ghostwood - X12680: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 2 - Repairable: true - Repair_Material: X3262 - Repair_Material_Pretty_Name: "Ghostwood Planks" - Repair_Material_Data_Value: 2 - Repair_Material_Quantity: 1 - Durability: 59 - # Quartz - X12696: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 2 - Repairable: true - Repair_Material: QUARTZ_BLOCK - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 1 - Durability: 131 - -Swords: - # Bloodwood - X12682: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 2 - Repairable: true - Repair_Material: X3262 - Repair_Material_Pretty_Name: "Bloodwood Planks" - Repair_Material_Data_Value: 4 - Repair_Material_Quantity: 2 - Durability: 350 - # Darkwood - X12686: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 2 - Repairable: true - Repair_Material: X3262 - Repair_Material_Pretty_Name: "Darkwood Planks" - Repair_Material_Data_Value: 11 - Repair_Material_Quantity: 2 - Durability: 131 - # Fusewood - X12690: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 2 - Repairable: true - Repair_Material: X3262 - Repair_Material_Pretty_Name: "Fusewood Planks" - Repair_Material_Data_Value: 12 - Repair_Material_Quantity: 2 - Durability: 250 - # Ghostwood - X12678: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 2 - Repairable: true - Repair_Material: X3262 - Repair_Material_Pretty_Name: "Ghostwood Planks" - Repair_Material_Data_Value: 2 - Repair_Material_Quantity: 2 - Durability: 59 - # Quartz - X12694: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 2 - Repairable: true - Repair_Material: QUARTZ_BLOCK - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 131 \ No newline at end of file diff --git a/extras/mods/1.6.x/projectred.blocks.yml b/extras/mods/1.6.x/projectred.blocks.yml deleted file mode 100644 index 52a877857..000000000 --- a/extras/mods/1.6.x/projectred.blocks.yml +++ /dev/null @@ -1,29 +0,0 @@ -# Config wrote by M1cr0man -# Possibly incomplete. Only covers ores -# Up to date as of Project Red 4.3.5.30 -Mining: - # Ruby - X2130|0: - XP_Gain: 350 - Double_Drops_Enabled: true - Is_Ore: true - # Sapphire - X2130|1: - XP_Gain: 350 - Double_Drops_Enabled: true - Is_Ore: true - # Peridot - X2130|2: - XP_Gain: 350 - Double_Drops_Enabled: true - Is_Ore: true - # Marble - X2131|0: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - # Basalt - X2131|3: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false \ No newline at end of file diff --git a/extras/mods/1.6.x/projectred.tools.yml b/extras/mods/1.6.x/projectred.tools.yml deleted file mode 100644 index 15220a165..000000000 --- a/extras/mods/1.6.x/projectred.tools.yml +++ /dev/null @@ -1,176 +0,0 @@ -# Config wrote by M1cr0man -# Up to date as of Project Red 4.3.5.30 -Axes: - # Ruby - X9353: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 3 - Repairable: true - Repair_Material: X9281 - Repair_Material_Pretty_Name: "Ruby" - Repair_Material_Data_Value: 37 - Repair_Material_Quantity: 3 - Durability: 500 - # Sapphire - X9354: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 3 - Repairable: true - Repair_Material: X9281 - Repair_Material_Pretty_Name: "Sapphire" - Repair_Material_Data_Value: 38 - Repair_Material_Quantity: 3 - Durability: 500 - # Peridot - X9355: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 3 - Repairable: true - Repair_Material: X9281 - Repair_Material_Pretty_Name: "Peridot" - Repair_Material_Data_Value: 39 - Repair_Material_Quantity: 3 - Durability: 500 - -Hoes: - # Ruby - X9356: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 3 - Repairable: true - Repair_Material: X9281 - Repair_Material_Pretty_Name: "Ruby" - Repair_Material_Data_Value: 37 - Repair_Material_Quantity: 2 - Durability: 500 - # Sapphire - X9357: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 3 - Repairable: true - Repair_Material: X9281 - Repair_Material_Pretty_Name: "Sapphire" - Repair_Material_Data_Value: 38 - Repair_Material_Quantity: 2 - Durability: 500 - # Peridot - X9358: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 3 - Repairable: true - Repair_Material: X9281 - Repair_Material_Pretty_Name: "Peridot" - Repair_Material_Data_Value: 39 - Repair_Material_Quantity: 2 - Durability: 500 - -Pickaxes: - # Ruby - X9359: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 3 - Repairable: true - Repair_Material: X9281 - Repair_Material_Pretty_Name: "Ruby" - Repair_Material_Data_Value: 37 - Repair_Material_Quantity: 3 - Durability: 500 - # Sapphire - X9360: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 3 - Repairable: true - Repair_Material: X9281 - Repair_Material_Pretty_Name: "Sapphire" - Repair_Material_Data_Value: 38 - Repair_Material_Quantity: 3 - Durability: 500 - # Peridot - X9361: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 3 - Repairable: true - Repair_Material: X9281 - Repair_Material_Pretty_Name: "Peridot" - Repair_Material_Data_Value: 39 - Repair_Material_Quantity: 3 - Durability: 500 - -Shovels: - # Ruby - X9362: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 3 - Repairable: true - Repair_Material: X9281 - Repair_Material_Pretty_Name: "Ruby" - Repair_Material_Data_Value: 37 - Repair_Material_Quantity: 1 - Durability: 500 - # Sapphire - X9363: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 3 - Repairable: true - Repair_Material: X9281 - Repair_Material_Pretty_Name: "Sapphire" - Repair_Material_Data_Value: 38 - Repair_Material_Quantity: 1 - Durability: 500 - # Peridot - X9364: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 3 - Repairable: true - Repair_Material: X9281 - Repair_Material_Pretty_Name: "Peridot" - Repair_Material_Data_Value: 39 - Repair_Material_Quantity: 1 - Durability: 500 - -Swords: - # Ruby - X9365: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 3 - Repairable: true - Repair_Material: X9281 - Repair_Material_Pretty_Name: "Ruby" - Repair_Material_Data_Value: 37 - Repair_Material_Quantity: 2 - Durability: 500 - # Sapphire - X9366: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 3 - Repairable: true - Repair_Material: X9281 - Repair_Material_Pretty_Name: "Sapphire" - Repair_Material_Data_Value: 38 - Repair_Material_Quantity: 2 - Durability: 500 - # Peridot - X9368: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 3 - Repairable: true - Repair_Material: X9281 - Repair_Material_Pretty_Name: "Peridot" - Repair_Material_Data_Value: 39 - Repair_Material_Quantity: 2 - Durability: 500 \ No newline at end of file diff --git a/extras/mods/1.6.x/railcraft.armor.yml b/extras/mods/1.6.x/railcraft.armor.yml deleted file mode 100755 index 0aee64ba1..000000000 --- a/extras/mods/1.6.x/railcraft.armor.yml +++ /dev/null @@ -1,49 +0,0 @@ -# Config wrote by Dragyn, updated by M1cr0man -# Up to date as of Railcraft 8.4.0.0 -Boots: - # Steel - X7758: - Repairable: true - Repair_Material: X7796 - Repair_Material_Pretty_Name: "Steel Ingot" - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 4 - Durability: 325 - -Chestplates: - # Steel - X7761: - Repairable: true - Repair_Material: X7796 - Repair_Material_Pretty_Name: "Steel Ingot" - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 8 - Durability: 400 - -Helmets: - # Steel - X7759: - Repairable: true - Repair_Material: X7796 - Repair_Material_Pretty_Name: "Steel Ingot" - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 5 - Durability: 275 - -Leggings: - # Steel - X7760: - Repairable: true - Repair_Material: X7796 - Repair_Material_Pretty_Name: "Steel Ingot" - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 7 - Durability: 375 - # Overalls - X7757: - Repairable: true - Repair_Material: WOOL - Repair_Material_Pretty_Name: "Light Blue Wool" - Repair_Material_Data_Value: 3 - Repair_Material_Quantity: 7 - Durability: 75 \ No newline at end of file diff --git a/extras/mods/1.6.x/railcraft.blocks.yml b/extras/mods/1.6.x/railcraft.blocks.yml deleted file mode 100755 index fc0c06333..000000000 --- a/extras/mods/1.6.x/railcraft.blocks.yml +++ /dev/null @@ -1,103 +0,0 @@ -# Config created by Dragyn -# Created For Railcraft_1.6.2-8.1.0.0 -# -# -# Settings for Custom Mining Blocks -### -Mining: - # Abyssal Stone - X457|6: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - # Quarried Stone - X457|7: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - # Sulfur - X458|0: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: false - # Saltpeter - X458|1: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: false - # Dark Diamond - X458|2: - XP_Gain: 750 - Double_Drops_Enabled: true - Is_Ore: false - # Dark Emerald - X458|3: - XP_Gain: 1000 - Double_Drops_Enabled: true - Is_Ore: false - # Dark Lapis - X458|4: - XP_Gain: 400 - Double_Drops_Enabled: true - Is_Ore: false - # Firestone - X458|5: - XP_Gain: 450 - Double_Drops_Enabled: true - Is_Ore: false - # Infernal Stone - X467|2: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - X467|5: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - # Blood Stained Stone - X468|2: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - X468|5: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - # Sandy Stone - X469|2: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - X469|5: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - # Quarried Stone - X471|2: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - X471|5: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - # Frost Bound Stone - X472|2: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - X472|5: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - # Nether Stone - X475|2: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - X475|5: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - - \ No newline at end of file diff --git a/extras/mods/1.6.x/railcraft.tools.yml b/extras/mods/1.6.x/railcraft.tools.yml deleted file mode 100755 index 77af15498..000000000 --- a/extras/mods/1.6.x/railcraft.tools.yml +++ /dev/null @@ -1,66 +0,0 @@ -# Config wrote by Dragyn, updated by M1cr0man -# Up to date as of Railcraft 8.4.0.0 -Axes: - # Steel - X7819: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X7796 - Repair_Material_Pretty_Name: "Steel Ingot" - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - -Hoes: - # Steel - X7820: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X7796 - Repair_Material_Pretty_Name: "Steel Ingot" - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - -Pickaxes: - # Steel - X7821: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X7796 - Repair_Material_Pretty_Name: "Steel Ingot" - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - -Shovels: - # Steel - X7823: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X7796 - Repair_Material_Pretty_Name: "Steel Ingot" - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - -Swords: - # Steel - X7824: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X7796 - Repair_Material_Pretty_Name: "Steel Ingot" - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 \ No newline at end of file diff --git a/extras/mods/1.6.x/simcraft.blocks.yml b/extras/mods/1.6.x/simcraft.blocks.yml deleted file mode 100755 index 48fe7294a..000000000 --- a/extras/mods/1.6.x/simcraft.blocks.yml +++ /dev/null @@ -1,543 +0,0 @@ -# Config created by Dragyn -# Created For SimCraft 1.6.4 -# -# -# Settings for Custom Herbalism Blocks -### -Herbalism: - X705|0: - XP_Gain: 50 - Double_Drops_Enabled: true - X705|1: - XP_Gain: 50 - Double_Drops_Enabled: true - X705|2: - XP_Gain: 50 - Double_Drops_Enabled: true - X705|3: - XP_Gain: 50 - Double_Drops_Enabled: true - X705|4: - XP_Gain: 50 - Double_Drops_Enabled: true - X705|5: - XP_Gain: 50 - Double_Drops_Enabled: true - X705|6: - XP_Gain: 50 - Double_Drops_Enabled: true - X705|7: - XP_Gain: 50 - Double_Drops_Enabled: true - X705|8: - XP_Gain: 50 - Double_Drops_Enabled: true - X705|9: - XP_Gain: 50 - Double_Drops_Enabled: true - X705|10: - XP_Gain: 50 - Double_Drops_Enabled: true - X705|11: - XP_Gain: 50 - Double_Drops_Enabled: true - X705|12: - XP_Gain: 50 - Double_Drops_Enabled: true - X705|13: - XP_Gain: 50 - Double_Drops_Enabled: true - X705|14: - XP_Gain: 50 - Double_Drops_Enabled: true - X705|15: - XP_Gain: 50 - Double_Drops_Enabled: true - X706|0: - XP_Gain: 50 - Double_Drops_Enabled: true - X706|1: - XP_Gain: 50 - Double_Drops_Enabled: true - X706|2: - XP_Gain: 50 - Double_Drops_Enabled: true - X706|3: - XP_Gain: 50 - Double_Drops_Enabled: true - X706|4: - XP_Gain: 50 - Double_Drops_Enabled: true - X706|5: - XP_Gain: 50 - Double_Drops_Enabled: true - X706|6: - XP_Gain: 50 - Double_Drops_Enabled: true - X706|7: - XP_Gain: 50 - Double_Drops_Enabled: true - X706|8: - XP_Gain: 50 - Double_Drops_Enabled: true - X706|9: - XP_Gain: 50 - Double_Drops_Enabled: true - X706|10: - XP_Gain: 50 - Double_Drops_Enabled: true - X706|11: - XP_Gain: 50 - Double_Drops_Enabled: true - X706|12: - XP_Gain: 50 - Double_Drops_Enabled: true - X706|13: - XP_Gain: 50 - Double_Drops_Enabled: true - X706|14: - XP_Gain: 50 - Double_Drops_Enabled: true - X706|15: - XP_Gain: 50 - Double_Drops_Enabled: true - X707|0: - XP_Gain: 50 - Double_Drops_Enabled: true - X707|1: - XP_Gain: 50 - Double_Drops_Enabled: true - X707|2: - XP_Gain: 50 - Double_Drops_Enabled: true - X707|3: - XP_Gain: 50 - Double_Drops_Enabled: true - X707|4: - XP_Gain: 50 - Double_Drops_Enabled: true - X707|5: - XP_Gain: 50 - Double_Drops_Enabled: true - X707|6: - XP_Gain: 50 - Double_Drops_Enabled: true - X707|7: - XP_Gain: 50 - Double_Drops_Enabled: true - X707|8: - XP_Gain: 50 - Double_Drops_Enabled: true - X707|9: - XP_Gain: 50 - Double_Drops_Enabled: true - X707|10: - XP_Gain: 50 - Double_Drops_Enabled: true - X707|11: - XP_Gain: 50 - Double_Drops_Enabled: true - X707|12: - XP_Gain: 50 - Double_Drops_Enabled: true - X707|13: - XP_Gain: 50 - Double_Drops_Enabled: true - X707|14: - XP_Gain: 50 - Double_Drops_Enabled: true - X707|15: - XP_Gain: 50 - Double_Drops_Enabled: true -# -# Settings for Custom Mining Blocks -### -Mining: - X700|0: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - X700|1: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - X700|2: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - X700|3: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - X700|4: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - X700|5: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - X700|6: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - X700|7: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - X700|8: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - X700|9: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - X700|10: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - X700|11: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - X700|12: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - X700|13: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - X700|14: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - X700|15: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - X701|0: - XP_Gain: 50 - Double_Drops_Enabled: true - Is_Ore: false - X701|1: - XP_Gain: 50 - Double_Drops_Enabled: true - Is_Ore: false - X701|2: - XP_Gain: 50 - Double_Drops_Enabled: true - Is_Ore: false - X701|3: - XP_Gain: 50 - Double_Drops_Enabled: true - Is_Ore: false - X701|4: - XP_Gain: 50 - Double_Drops_Enabled: true - Is_Ore: false - X701|5: - XP_Gain: 50 - Double_Drops_Enabled: true - Is_Ore: false - X701|6: - XP_Gain: 50 - Double_Drops_Enabled: true - Is_Ore: false - X701|7: - XP_Gain: 50 - Double_Drops_Enabled: true - Is_Ore: false - X701|8: - XP_Gain: 50 - Double_Drops_Enabled: true - Is_Ore: false - X701|9: - XP_Gain: 50 - Double_Drops_Enabled: true - Is_Ore: false - X701|10: - XP_Gain: 50 - Double_Drops_Enabled: true - Is_Ore: false - X701|11: - XP_Gain: 50 - Double_Drops_Enabled: true - Is_Ore: false - X701|12: - XP_Gain: 50 - Double_Drops_Enabled: true - Is_Ore: false - X701|13: - XP_Gain: 50 - Double_Drops_Enabled: true - Is_Ore: false - X701|14: - XP_Gain: 50 - Double_Drops_Enabled: true - Is_Ore: false - X701|15: - XP_Gain: 50 - Double_Drops_Enabled: true - Is_Ore: false - X702|0: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: false - X702|1: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: false - X702|2: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: false - X702|3: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: false - X702|4: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: false - X702|5: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: false - X702|6: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: false - X702|7: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: false - X702|8: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: false - X702|9: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: false - X702|10: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: false - X702|11: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: false - X702|12: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: false - X702|13: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: false - X702|14: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: false - X702|15: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: false - X703|0: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: false - X703|1: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: false - X703|2: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: false - X703|3: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: false - X703|4: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: false - X703|5: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: false - X703|6: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: false - X703|7: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: false - X703|8: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: false - X703|9: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: false - X703|10: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: false - X703|11: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: false - X703|12: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: false - X703|13: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: false - X703|14: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: false - X703|15: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: false - X704|0: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: false - X704|1: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: false - X704|2: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: false - X704|3: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: false - X704|4: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: false - X704|5: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: false - X704|6: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: false - X704|7: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: false - X704|8: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: false - X704|9: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: false - X704|10: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: false - X704|11: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: false - X704|12: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: false - X704|13: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: false - X704|14: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: false - X704|15: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: false -# -# Settings for Custom Woodcutting Blocks -### -Woodcutting: - X708|0: - XP_Gain: 80 - Double_Drops_Enabled: true - Is_Log: true - X708|1: - XP_Gain: 80 - Double_Drops_Enabled: true - Is_Log: true - X708|2: - XP_Gain: 80 - Double_Drops_Enabled: true - Is_Log: true - X708|3: - XP_Gain: 80 - Double_Drops_Enabled: true - Is_Log: true - X708|4: - XP_Gain: 80 - Double_Drops_Enabled: true - Is_Log: true - X708|5: - XP_Gain: 80 - Double_Drops_Enabled: true - Is_Log: true - X708|6: - XP_Gain: 80 - Double_Drops_Enabled: true - Is_Log: true - X708|7: - XP_Gain: 80 - Double_Drops_Enabled: true - Is_Log: true - X708|8: - XP_Gain: 80 - Double_Drops_Enabled: true - Is_Log: true - X708|9: - XP_Gain: 80 - Double_Drops_Enabled: true - Is_Log: true - X708|10: - XP_Gain: 80 - Double_Drops_Enabled: true - Is_Log: true - X708|11: - XP_Gain: 80 - Double_Drops_Enabled: true - Is_Log: true - X1095|0: - XP_Gain: 80 - Double_Drops_Enabled: true - Is_Log: true - X1095|1: - XP_Gain: 80 - Double_Drops_Enabled: true - Is_Log: true - X1095|2: - XP_Gain: 80 - Double_Drops_Enabled: true - Is_Log: true - X1095|3: - XP_Gain: 80 - Double_Drops_Enabled: true - Is_Log: true diff --git a/extras/mods/1.6.x/simcraft.tools.yml b/extras/mods/1.6.x/simcraft.tools.yml deleted file mode 100755 index 5243f240d..000000000 --- a/extras/mods/1.6.x/simcraft.tools.yml +++ /dev/null @@ -1,61 +0,0 @@ -# Config created by Dragyn -# Created For Railcraft_1.6.2-8.1.0.0 -# -# -# Settings for Axes -### -Axes: - # Steel - X15787: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X15260 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - - -# -# Settings for Pickaxes -### -Pickaxes: - # Steel - X15788: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X15260 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 -# -# Settings for Shovels -### -Shovels: - # Steel - X15789: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X15260 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 -# -# Settings for Swords -### -Swords: - # Steel - X15786: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X15260 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 diff --git a/extras/mods/1.6.x/stargatetech2.blocks.yml b/extras/mods/1.6.x/stargatetech2.blocks.yml deleted file mode 100644 index 5a63ee227..000000000 --- a/extras/mods/1.6.x/stargatetech2.blocks.yml +++ /dev/null @@ -1,9 +0,0 @@ -# Config wrote by M1cr0man -# Possibly incomplete. Only covers ores -# Up to date as of Stargate Tech 2 Alpha 0.7.3 -Mining: - # Naquadah Ore - X1005|0: - XP_Gain: 300 - Double_Drops_Enabled: true - Is_Ore: true \ No newline at end of file diff --git a/extras/mods/1.6.x/thermalexpansion.armor.yml b/extras/mods/1.6.x/thermalexpansion.armor.yml deleted file mode 100644 index 1688f6c4f..000000000 --- a/extras/mods/1.6.x/thermalexpansion.armor.yml +++ /dev/null @@ -1,41 +0,0 @@ -# Config wrote by M1cr0man -# Up to date as of Thermal Expansion 3.0.0.7 -Boots: - # Invar - X31973: - Repairable: true - Repair_Material: X31978 - Repair_Material_Pretty_Name: "Invar Ingot" - Repair_Material_Data_Value: 71 - Repair_Material_Quantity: 4 - Durability: 325 - -Chestplates: - # Invar - X31975: - Repairable: true - Repair_Material: X31978 - Repair_Material_Pretty_Name: "Invar Ingot" - Repair_Material_Data_Value: 71 - Repair_Material_Quantity: 8 - Durability: 400 - -Helmets: - # Invar - X31976: - Repairable: true - Repair_Material: X31978 - Repair_Material_Pretty_Name: "Invar Ingot" - Repair_Material_Data_Value: 71 - Repair_Material_Quantity: 5 - Durability: 275 - -Leggings: - # Invar - X31976: - Repairable: true - Repair_Material: X31978 - Repair_Material_Pretty_Name: "Invar Ingot" - Repair_Material_Data_Value: 71 - Repair_Material_Quantity: 7 - Durability: 375 \ No newline at end of file diff --git a/extras/mods/1.6.x/thermalexpansion.blocks.yml b/extras/mods/1.6.x/thermalexpansion.blocks.yml deleted file mode 100644 index 33af282cd..000000000 --- a/extras/mods/1.6.x/thermalexpansion.blocks.yml +++ /dev/null @@ -1,29 +0,0 @@ -# Config wrote by M1cr0man -# Possibly incomplete. Only covers ores -# Up to date as of Thermal Expansion 3.0.0.7 -Mining: - # Copper - X4064|0: - XP_Gain: 175 - Double_Drops_Enabled: true - Is_Ore: true - # Tin - X4064|1: - XP_Gain: 175 - Double_Drops_Enabled: true - Is_Ore: true - # Silver - X4064|2: - XP_Gain: 300 - Double_Drops_Enabled: true - Is_Ore: true - # Lead - X4064|3: - XP_Gain: 300 - Double_Drops_Enabled: true - Is_Ore: true - # Ferrous - X4064|4: - XP_Gain: 300 - Double_Drops_Enabled: true - Is_Ore: true \ No newline at end of file diff --git a/extras/mods/1.6.x/thermalexpansion.tools.yml b/extras/mods/1.6.x/thermalexpansion.tools.yml deleted file mode 100644 index e030e72e2..000000000 --- a/extras/mods/1.6.x/thermalexpansion.tools.yml +++ /dev/null @@ -1,66 +0,0 @@ -# Config wrote by M1cr0man -# Up to date as of Thermal Expansion 3.0.0.7 -Axes: - # Invar - X31969: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 3 - Repairable: true - Repair_Material: X31978 - Repair_Material_Pretty_Name: "Invar Ingot" - Repair_Material_Data_Value: 71 - Repair_Material_Quantity: 3 - Durability: 450 - -Hoes: - # Invar - X31968: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 3 - Repairable: true - Repair_Material: X31978 - Repair_Material_Pretty_Name: "Invar Ingot" - Repair_Material_Data_Value: 71 - Repair_Material_Quantity: 2 - Durability: 450 - -Pickaxes: - # Invar - X31970: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 3 - Repairable: true - Repair_Material: X31978 - Repair_Material_Pretty_Name: "Invar Ingot" - Repair_Material_Data_Value: 71 - Repair_Material_Quantity: 3 - Durability: 450 - -Shovels: - # Invar - X31971: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 3 - Repairable: true - Repair_Material: X31978 - Repair_Material_Pretty_Name: "Invar Ingot" - Repair_Material_Data_Value: 71 - Repair_Material_Quantity: 1 - Durability: 450 - -Swords: - # Invar - X31972: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 3 - Repairable: true - Repair_Material: X31978 - Repair_Material_Pretty_Name: "Invar Ingot" - Repair_Material_Data_Value: 71 - Repair_Material_Quantity: 2 - Durability: 450 \ No newline at end of file diff --git a/extras/mods/1.6.x/tinkersconstruct.armor.yml b/extras/mods/1.6.x/tinkersconstruct.armor.yml deleted file mode 100644 index 00dd79b3e..000000000 --- a/extras/mods/1.6.x/tinkersconstruct.armor.yml +++ /dev/null @@ -1,74 +0,0 @@ -# Config wrote by M1cr0man -# Up to date as of Tinker's Construct 1.5.5.7 -# Also covers Tinker's Steelworks 0.0.4.2-fix2 -Boots: - # Wooden (Repaired with Oak Wood) - X14366: - Repairable: true - Repair_Material: LOG - Repair_Material_Pretty_Name: "Oak Wood" - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 4 - Durability: 26 - # Steel - X14771: - Repairable: true - Repair_Material: X14276 - Repair_Material_Pretty_Name: "Steel Ingot" - Repair_Material_Data_Value: 16 - Repair_Material_Quantity: 4 - Durability: 325 - -Chestplates: - # Wooden (Repaired with Oak Wood) - X14364: - Repairable: true - Repair_Material: LOG - Repair_Material_Pretty_Name: "Oak Wood" - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 8 - Durability: 32 - # Steel - X14769: - Repairable: true - Repair_Material: X14276 - Repair_Material_Pretty_Name: "Steel Ingot" - Repair_Material_Data_Value: 16 - Repair_Material_Quantity: 8 - Durability: 400 - -Helmets: - # Wooden (Repaired with Oak Wood) - X14362: - Repairable: true - Repair_Material: LOG - Repair_Material_Pretty_Name: "Oak Wood" - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 5 - Durability: 22 - # Steel - X14768: - Repairable: true - Repair_Material: X14276 - Repair_Material_Pretty_Name: "Steel Ingot" - Repair_Material_Data_Value: 16 - Repair_Material_Quantity: 5 - Durability: 275 - -Leggings: - # Wooden (Repaired with Oak Wood) - X14362: - Repairable: true - Repair_Material: LOG - Repair_Material_Pretty_Name: "Oak Wood" - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 7 - Durability: 30 - # Steel - X14768: - Repairable: true - Repair_Material: X14276 - Repair_Material_Pretty_Name: "Steel Ingot" - Repair_Material_Data_Value: 16 - Repair_Material_Quantity: 7 - Durability: 375 \ No newline at end of file diff --git a/extras/mods/1.6.x/tinkersconstruct.blocks.yml b/extras/mods/1.6.x/tinkersconstruct.blocks.yml deleted file mode 100644 index 0e8a61a28..000000000 --- a/extras/mods/1.6.x/tinkersconstruct.blocks.yml +++ /dev/null @@ -1,55 +0,0 @@ -# Config wrote by M1cr0man -# Possibly incomplete. Only covers ores -# Up to date as of Tinker's Construct 1.5.5.7 -Excavation: - # Iron - X1488|0: - XP_Gain: 250 - Double_Drops_Enabled: true - # Gold - X1488|1: - XP_Gain: 350 - Double_Drops_Enabled: true - # Copper - X1488|2: - XP_Gain: 175 - Double_Drops_Enabled: true - # Tin - X1488|3: - XP_Gain: 175 - Double_Drops_Enabled: true - # Aluminum - X1488|4: - XP_Gain: 250 - Double_Drops_Enabled: true - # Cobalt - X1488|5: - XP_Gain: 500 - Double_Drops_Enabled: true - -Mining: - # Cobalt - X1475|1: - XP_Gain: 500 - Double_Drops_Enabled: true - Is_Ore: true - # Ardite - X1475|2: - XP_Gain: 500 - Double_Drops_Enabled: true - Is_Ore: true - # Copper - X1475|3: - XP_Gain: 175 - Double_Drops_Enabled: true - Is_Ore: true - # Tin - X1475|4: - XP_Gain: 175 - Double_Drops_Enabled: true - Is_Ore: true - # Aluminium - X1475|5: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: true \ No newline at end of file diff --git a/extras/mods/1.6.x/tinkersconstruct.tools.yml b/extras/mods/1.6.x/tinkersconstruct.tools.yml deleted file mode 100644 index 1c0de59af..000000000 --- a/extras/mods/1.6.x/tinkersconstruct.tools.yml +++ /dev/null @@ -1,149 +0,0 @@ -# Config wrote by M1cr0man -# Abilites for Pickaxes and Shovels disabled due to a bug -# Repair disabled as mcMMO does not support NBTTag - based tools -# Up to date as of Tinker's Construct 1.5.5.7 -# Also covers Tinker's Steelworks 0.0.4.2-fix2 -Axes: - # Hatchets - X14309: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 2 - Repairable: false - Durability: 500 - # Mattocks - X14316: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 2 - Repairable: false - Durability: 500 - # Lumber Axes - X14317: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 2 - Repairable: false - Durability: 500 - # Battle Axes - X14327: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 2 - Repairable: false - Durability: 500 - -Bows: - # Shortbows - X14319: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 2 - Repairable: false - Durability: 500 - -Hoes: - # Mattocks - X14316: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 2 - Repairable: false - Durability: 500 - # Scythes - X14323: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 2 - Repairable: false - Durability: 500 - -Pickaxes: - # Pickaxes - X14307: - XP_Modifier: 1.0 - Ability_Enabled: false - Tier: 2 - Repairable: false - Durability: 500 - # Hammers - X14326: - XP_Modifier: 1.0 - Ability_Enabled: false - Tier: 2 - Repairable: false - Durability: 500 - -Shovels: - # Shovels - X14308: - XP_Modifier: 1.0 - Ability_Enabled: false - Tier: 2 - Repairable: false - Durability: 500 - # Mattocks - X14316: - XP_Modifier: 1.0 - Ability_Enabled: false - Tier: 2 - Repairable: false - Durability: 500 - # Excavators - X14325: - XP_Modifier: 1.0 - Ability_Enabled: false - Tier: 2 - Repairable: false - Durability: 500 - -Swords: - # Broadswords - X14311: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 2 - Repairable: false - Durability: 500 - # Longswords - X14312: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 2 - Repairable: false - Durability: 500 - # Rapiers - X14313: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 2 - Repairable: false - Durability: 500 - # Daggers - X14321: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 2 - Repairable: false - Durability: 500 - # Cleavers - X14324: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 2 - Repairable: false - Durability: 500 - # Battle Axes - X14327: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 2 - Repairable: false - Durability: 500 - # Cutlasses - X14328: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 2 - Repairable: false - Durability: 500 \ No newline at end of file diff --git a/extras/mods/1.6.x/twilightforest.armor.yml b/extras/mods/1.6.x/twilightforest.armor.yml deleted file mode 100755 index 18dd80cd2..000000000 --- a/extras/mods/1.6.x/twilightforest.armor.yml +++ /dev/null @@ -1,141 +0,0 @@ -# Config wrote by Dragyn, updated by M1cr0man -# Up to date as of Twilight Forest 1.20.5 -Boots: - # Ironwood - X27978: - Repairable: true - Repair_Material: X27974 - Repair_Material_Pretty_Name: "Ironwood Ingot" - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 4 - Durability: 260 - # Fiery - X27995: - Repairable: true - Repair_Material: X27991 - Repair_Material_Pretty_Name: "Fiery Ingot" - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 4 - Durability: 325 - # Stealeaf - X28002: - Repairable: true - Repair_Material: X27998 - Repair_Material_Pretty_Name: "Steeleaf" - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 4 - Durability: 260 - # Knightmetal - X28037: - Repairable: true - Repair_Material: X28032 - Repair_Material_Pretty_Name: "Knightmetal Ingot" - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 4 - Durability: 260 - -Chestplates: - # Ironwood - X27976: - Repairable: true - Repair_Material: X27974 - Repair_Material_Pretty_Name: "Ironwood Ingot" - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 8 - Durability: 320 - # Naga Scale - X27958: - Repairable: true - Repair_Material: X27957 - Repair_Material_Pretty_Name: "Naga Scale" - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 8 - Durability: 336 - # Fiery - X27993: - Repairable: true - Repair_Material: X27991 - Repair_Material_Pretty_Name: "Fiery Ingot" - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 8 - Durability: 400 - # Stealeaf - X28000: - Repairable: true - Repair_Material: X27998 - Repair_Material_Pretty_Name: "Steeleaf" - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 8 - Durability: 320 - # Knightmetal - # Phantom - -Helmets: - # Ironwood - X27975: - Repairable: true - Repair_Material: X27974 - Repair_Material_Pretty_Name: "Ironwood Ingot" - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 5 - Durability: 220 - # Fiery - X27992: - Repairable: true - Repair_Material: X27991 - Repair_Material_Pretty_Name: "Fiery Ingot" - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 5 - Durability: 275 - # Stealeaf - X27999: - Repairable: true - Repair_Material: X27998 - Repair_Material_Pretty_Name: "Steeleaf" - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 5 - Durability: 220 - # Knightmetal - # Phantom - -Leggings: - # Ironwood - X27977: - Repairable: true - Repair_Material: X27974 - Repair_Material_Pretty_Name: "Ironwood Ingot" - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 7 - Durability: 300 - # Naga Scale - X27959: - Repairable: true - Repair_Material: X27957 - Repair_Material_Pretty_Name: "Naga Scale" - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 7 - Durability: 315 - # Fiery - X27994: - Repairable: true - Repair_Material: X27991 - Repair_Material_Pretty_Name: "Fiery Ingot" - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 7 - Durability: 375 - # Stealeaf - X28001: - Repairable: true - Repair_Material: X27998 - Repair_Material_Pretty_Name: "Steeleaf" - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 7 - Durability: 300 - # Knightmetal - X28036: - Repairable: true - Repair_Material: X28032 - Repair_Material_Pretty_Name: "Knightmetal Ingot" - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 7 - Durability: 300 \ No newline at end of file diff --git a/extras/mods/1.6.x/twilightforest.blocks.yml b/extras/mods/1.6.x/twilightforest.blocks.yml deleted file mode 100755 index f327e5b7e..000000000 --- a/extras/mods/1.6.x/twilightforest.blocks.yml +++ /dev/null @@ -1,117 +0,0 @@ -# Config created by Dragyn -# Created For twilightforest-1.20.3 -# -# -# Settings for Custom Herbalism Blocks -### -Herbalism: - # Mushgloom - X2169|9: - XP_Gain: 150 - Double_Drops_Enabled: true - # Torchberry Plant - X2169|13: - XP_Gain: 20 - Double_Drops_Enabled: true - # Mayapple - X2169|4: - XP_Gain: 30 - Double_Drops_Enabled: true - # Fiddlehead - X2169|8: - XP_Gain: 35 - Double_Drops_Enabled: true - - -# -# Settings for Custom Mining Blocks -### -Mining: - # Mazestone - X2165|0: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: false - X2165|1: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: false - X2165|2: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: false - X2165|3: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: false - X2165|4: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: false - X2165|5: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: false - X2165|6: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: false - X2165|7: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: false - -# -# Settings for Custom Woodcutting Blocks -### -Woodcutting: - # Twilight Oak - X2163|0: - XP_Gain: 70 - Double_Drops_Enabled: true - Is_Log: true - # Canopy - X2163|1: - XP_Gain: 80 - Double_Drops_Enabled: true - Is_Log: true - # Mangrove - X2163|2: - XP_Gain: 90 - Double_Drops_Enabled: true - Is_Log: true - # Darkwood - X2163|3: - XP_Gain: 100 - Double_Drops_Enabled: true - Is_Log: true - # Roots - X2170|0: - XP_Gain: 10 - Double_Drops_Enabled: true - Is_Log: false - X2170|1: - XP_Gain: 10 - Double_Drops_Enabled: true - Is_Log: false - # Timewood - X2176|0: - XP_Gain: 1000 - Double_Drops_Enabled: true - Is_Log: true - # Transwood - X2176|1: - XP_Gain: 1000 - Double_Drops_Enabled: true - Is_Log: true - # Minewood - X2176|2: - XP_Gain: 1000 - Double_Drops_Enabled: true - Is_Log: true - # Sortingwood - X2176|3: - XP_Gain: 1000 - Double_Drops_Enabled: true - Is_Log: true - \ No newline at end of file diff --git a/extras/mods/1.6.x/twilightforest.tools.yml b/extras/mods/1.6.x/twilightforest.tools.yml deleted file mode 100755 index c82fbac78..000000000 --- a/extras/mods/1.6.x/twilightforest.tools.yml +++ /dev/null @@ -1,181 +0,0 @@ -# Config wrote by Dragyn, updated by M1cr0man -# Up to date as of Twilight Forest 1.20.5 -Axes: - # Ironwood - X27982: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27974 - Repair_Material_Pretty_Name: "Ironwood Ingot" - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 512 - # Steeleaf - X28006: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27998 - Repair_Material_Pretty_Name: "Steeleaf" - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 131 - # Knightmetal - X28040: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X28032 - Repair_Material_Pretty_Name: "Knightmetal Ingot" - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 512 - # Minotaur - X28008: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: false - Durability: 1561 - -Hoes: - # Ironwood - X27983: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27974 - Repair_Material_Pretty_Name: "Ironwood Ingot" - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 512 - # Steeleaf - X28007: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27998 - Repair_Material_Pretty_Name: "Steeleaf" - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 131 - -Pickaxes: - # Ironwood - X27981: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27974 - Repair_Material_Pretty_Name: "Ironwood Ingot" - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 512 - # Fiery - X27997: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27991 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 1024 - # Steeleaf - X28005: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27998 - Repair_Material_Pretty_Name: "Steeleaf" - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 131 - # Knightmetal - X28039: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X28032 - Repair_Material_Pretty_Name: "Knightmetal Ingot" - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 512 - -Shovels: - # Ironwood - X27980: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27974 - Repair_Material_Pretty_Name: "Ironwood Ingot" - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 512 - # Steeleaf - X28004: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27998 - Repair_Material_Pretty_Name: "Steeleaf" - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 131 - -Swords: - # Ironwood - X27979: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27974 - Repair_Material_Pretty_Name: "Ironwood Ingot" - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 512 - # Fiery - X27996: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27991 - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 1024 - # Steeleaf - X28003: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X27998 - Repair_Material_Pretty_Name: "Steeleaf" - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 131 - # Knightmetal - X28038: - XP_Modifier: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: X28032 - Repair_Material_Pretty_Name: "Knightmetal Ingot" - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 512 \ No newline at end of file diff --git a/extras/mods/1.6.x/underground_biomes.blocks.yml b/extras/mods/1.6.x/underground_biomes.blocks.yml deleted file mode 100755 index 7abdc794d..000000000 --- a/extras/mods/1.6.x/underground_biomes.blocks.yml +++ /dev/null @@ -1,171 +0,0 @@ -# Config created by Dragyn -# Created For UndergroundBiomes 1.6.x - 0.4.2c -# -# -# Settings for Custom Mining Blocks -### -Mining: - X2000|0: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - X2000|1: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - X2000|2: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - X2000|3: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - X2000|4: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - X2000|5: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - X2000|6: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - X2000|7: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false -# - X2001|0: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - X2001|1: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - X2001|2: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - X2001|3: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - X2001|4: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - X2001|5: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - X2001|6: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - X2001|7: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false -# - X2009|0: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - X2009|1: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - X2009|2: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - X2009|3: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - X2009|4: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - X2009|5: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - X2009|6: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - X2009|7: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false -# - X2010|0: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - X2010|1: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - X2010|2: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - X2010|3: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - X2010|4: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - X2010|5: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - X2010|6: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - X2010|7: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false -# - X2011|0: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - X2011|1: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - X2011|2: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - X2011|3: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - X2011|4: - XP_Gain: 50 - Double_Drops_Enabled: true - Is_Ore: false - X2011|5: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - X2011|6: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false - X2011|7: - XP_Gain: 30 - Double_Drops_Enabled: true - Is_Ore: false \ No newline at end of file diff --git a/extras/mods/1.7.x/twilightforest.armor.yml b/extras/mods/1.7.x/twilightforest.armor.yml deleted file mode 100644 index 89e67a4b3..000000000 --- a/extras/mods/1.7.x/twilightforest.armor.yml +++ /dev/null @@ -1,132 +0,0 @@ -# Config created by joulesbeef -# Created For twilightforest-2.2.3 -# -# -# Settings for Boots -### -Boots: - # Ironwood - TWILIGHTFOREST_ITEM_IRONWOODBOOTS: - Repairable: true - Repair_Material: TWILIGHTFOREST_ITEM_IRONWOODINGOT - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Fiery - TWILIGHTFOREST_ITEM_FIERYBOOTS: - Repairable: true - Repair_Material: TWILIGHTFOREST_ITEM_FIERYINGOT - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Stealeaf - TWILIGHTFOREST_ITEM_STEELEAFBOOTS: - Repairable: true - Repair_Material: TWILIGHTFOREST_ITEM_STEELEAFINGOT - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Knightmetal - TWILIGHTFOREST_ITEM_KNIGHTLYBOOTS: - Repairable: true - Repair_Material: TWILIGHTFOREST_ITEM_KNIGHTMETAL - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - -# -# Settings for Chestplates -### -Chestplates: - # Ironwood - TWILIGHTFOREST_ITEM_IRONWOODPLATE: - Repairable: true - Repair_Material: TWILIGHTFOREST_ITEM_IRONWOODINGOT - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Fiery - TWILIGHTFOREST_ITEM_FIERYPLATE: - Repairable: true - Repair_Material: TWILIGHTFOREST_ITEM_FIERYINGOT - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Stealeaf - TWILIGHTFOREST_ITEM_STEELEAFPLATE: - Repairable: true - Repair_Material: TWILIGHTFOREST_ITEM_STEELEAFINGOT - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Knightmetal - TWILIGHTFOREST_ITEM_KNIGHTLYPLATE: - Repairable: true - Repair_Material: TWILIGHTFOREST_ITEM_KNIGHTMETAL - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - -# -# Settings for Helmets -### -Helmets: - # Ironwood - TWILIGHTFOREST_ITEM_IRONWOODHELM: - Repairable: true - Repair_Material: TWILIGHTFOREST_ITEM_IRONWOODINGOT - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Fiery - TWILIGHTFOREST_ITEM_FIERYHELM: - Repairable: true - Repair_Material: TWILIGHTFOREST_ITEM_FIERYINGOT - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Stealeaf - TWILIGHTFOREST_ITEM_STEELEAFHELM: - Repairable: true - Repair_Material: TWILIGHTFOREST_ITEM_STEELEAFINGOT - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Knightmetal - TWILIGHTFOREST_ITEM_KNIGHTLYHELM: - Repairable: true - Repair_Material: TWILIGHTFOREST_ITEM_KNIGHTMETAL - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 50 -# Settings for Leggings -### -Leggings: - # Ironwood - TWILIGHTFOREST_ITEM_IRONWOODLEGS: - Repairable: true - Repair_Material: TWILIGHTFOREST_ITEM_IRONWOODINGOT - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Fiery - TWILIGHTFOREST_ITEM_FIERYLEGS: - Repairable: true - Repair_Material: TWILIGHTFOREST_ITEM_FIERYINGOT - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Stealeaf - TWILIGHTFOREST_ITEM_STEELEAFLEGS: - Repairable: true - Repair_Material: TWILIGHTFOREST_ITEM_STEELEAFINGOT - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Knightmetal - TWILIGHTFOREST_ITEM_KNIGHTLYLEGS: - Repairable: true - Repair_Material: TWILIGHTFOREST_ITEM_KNIGHTMETAL - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 \ No newline at end of file diff --git a/extras/mods/1.7.x/twilightforest.blocks.yml b/extras/mods/1.7.x/twilightforest.blocks.yml deleted file mode 100644 index 6d108abe2..000000000 --- a/extras/mods/1.7.x/twilightforest.blocks.yml +++ /dev/null @@ -1,116 +0,0 @@ -# Config created by joulesbeef -# Created For twilightforest-2.2.3 -# -# -# Settings for Custom Herbalism Blocks -### -Herbalism: - # Mushgloom - TWILIGHTFOREST_TILE_TFLOG|9: - XP_Gain: 150 - Double_Drops_Enabled: true - # Torchberry Plant - TWILIGHTFOREST_TILE_TFLOG|13: - XP_Gain: 20 - Double_Drops_Enabled: true - # Mayapple - TWILIGHTFOREST_TILE_TFLOG|4: - XP_Gain: 30 - Double_Drops_Enabled: true - # Fiddlehead - TWILIGHTFOREST_TILE_TFLOG|8: - XP_Gain: 35 - Double_Drops_Enabled: true - - -# -# Settings for Custom Mining Blocks -### -Mining: - # Mazestone - TWILIGHTFOREST_TILE_TFMAZESTONE|0: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: false - TWILIGHTFOREST_TILE_TFMAZESTONE|1: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: false - TWILIGHTFOREST_TILE_TFMAZESTONE|2: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: false - TWILIGHTFOREST_TILE_TFMAZESTONE|3: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: false - TWILIGHTFOREST_TILE_TFMAZESTONE|4: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: false - TWILIGHTFOREST_TILE_TFMAZESTONE|5: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: false - TWILIGHTFOREST_TILE_TFMAZESTONE|6: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: false - TWILIGHTFOREST_TILE_TFMAZESTONE|7: - XP_Gain: 250 - Double_Drops_Enabled: true - Is_Ore: false - -# -# Settings for Custom Woodcutting Blocks -### -Woodcutting: - # Twilight Oak - TWILIGHTFOREST_TILE_TFLOG|0: - XP_Gain: 70 - Double_Drops_Enabled: true - Is_Log: true - # Canopy - TWILIGHTFOREST_TILE_TFLOG|1: - XP_Gain: 80 - Double_Drops_Enabled: true - Is_Log: true - # Mangrove - TWILIGHTFOREST_TILE_TFLOG|2: - XP_Gain: 90 - Double_Drops_Enabled: true - Is_Log: true - # Darkwood - TWILIGHTFOREST_TILE_TFLOG|3: - XP_Gain: 100 - Double_Drops_Enabled: true - Is_Log: true - # Roots - TWILIGHTFOREST_TILE_TFROOTS|0: - XP_Gain: 10 - Double_Drops_Enabled: true - Is_Log: false - TWILIGHTFOREST_TILE_TFROOTS|1: - XP_Gain: 10 - Double_Drops_Enabled: true - Is_Log: false - # Timewood - TWILIGHTFOREST_TILE_TFMAGICLOG|0: - XP_Gain: 1000 - Double_Drops_Enabled: true - Is_Log: true - # Transwood - TWILIGHTFOREST_TILE_TFMAGICLOG|1: - XP_Gain: 1000 - Double_Drops_Enabled: true - Is_Log: true - # Minewood - TWILIGHTFOREST_TILE_TFMAGICLOG|2: - XP_Gain: 1000 - Double_Drops_Enabled: true - Is_Log: true - # Sortingwood - TWILIGHTFOREST_TILE_TFMAGICLOG|3: - XP_Gain: 1000 - Double_Drops_Enabled: true - Is_Log: true diff --git a/extras/mods/1.7.x/twilightforest.entities.yml b/extras/mods/1.7.x/twilightforest.entities.yml deleted file mode 100644 index c209f2993..000000000 --- a/extras/mods/1.7.x/twilightforest.entities.yml +++ /dev/null @@ -1,152 +0,0 @@ -# Config created by joulesbeef -# Created For twilightforest-2.2.3 -# -# Settings for Custom Mobs -MoCreatures-Ogre: - Class: Monster - XP_Multiplier: 1.0 - Tameable: false - Taming_XP: 0 - CanBeSummoned: false - COTW_Material: '' - COTW_Material_Data: 0 - COTW_Material_Amount: 0 -TwilightForest-TwilightLich: - Class: Monster - XP_Multiplier: 1.0 - Tameable: false - Taming_XP: 0 - CanBeSummoned: false - COTW_Material: '' - COTW_Material_Data: 0 - COTW_Material_Amount: 0 -TwilightForest-HelmetCrab: - Class: Monster - XP_Multiplier: 1.0 - Tameable: false - Taming_XP: 0 - CanBeSummoned: false - COTW_Material: '' - COTW_Material_Data: 0 - COTW_Material_Amount: 0 -TwilightForest-SlimeBeetle: - Class: Monster - XP_Multiplier: 1.0 - Tameable: false - Taming_XP: 0 - CanBeSummoned: false - COTW_Material: '' - COTW_Material_Data: 0 - COTW_Material_Amount: 0 -TwilightForest-TwilightWraith: - Class: Monster - XP_Multiplier: 1.0 - Tameable: false - Taming_XP: 0 - CanBeSummoned: false - COTW_Material: '' - COTW_Material_Data: 0 - COTW_Material_Amount: 0 -TwilightForest-Naga: - Class: Monster - XP_Multiplier: 1.0 - Tameable: false - Taming_XP: 0 - CanBeSummoned: false - COTW_Material: '' - COTW_Material_Data: 0 - COTW_Material_Amount: 0 -MoCreatures-Shark: - Class: Monster - XP_Multiplier: 1.0 - Tameable: false - Taming_XP: 0 - CanBeSummoned: false - COTW_Material: '' - COTW_Material_Data: 0 - COTW_Material_Amount: 0 -TwilightForest-TowerTermite: - Class: Monster - XP_Multiplier: 1.0 - Tameable: false - Taming_XP: 0 - CanBeSummoned: false - COTW_Material: '' - COTW_Material_Data: 0 - COTW_Material_Amount: 0 -MoCreatures-SmallFish: - Class: Monster - XP_Multiplier: 1.0 - Tameable: false - Taming_XP: 0 - CanBeSummoned: false - COTW_Material: '' - COTW_Material_Data: 0 - COTW_Material_Amount: 0 -TwilightForest-Redcap: - Class: Monster - XP_Multiplier: 1.0 - Tameable: false - Taming_XP: 0 - CanBeSummoned: false - COTW_Material: '' - COTW_Material_Data: 0 - COTW_Material_Amount: 0 -TwilightForest-YetiBoss: - Class: Monster - XP_Multiplier: 1.0 - Tameable: false - Taming_XP: 0 - CanBeSummoned: false - COTW_Material: '' - COTW_Material_Data: 0 - COTW_Material_Amount: 0 -MoCreatures-HellRat: - Class: Monster - XP_Multiplier: 1.0 - Tameable: false - Taming_XP: 0 - CanBeSummoned: false - COTW_Material: '' - COTW_Material_Data: 0 - COTW_Material_Amount: 0 -TwilightForest-Hydra: - XP_Multiplier: 1.0 - Tameable: false - Taming_XP: 0 - CanBeSummoned: false - COTW_Material: '' - COTW_Material_Data: 0 - COTW_Material_Amount: 0 -TwilightForest-Firefly: - XP_Multiplier: 1.0 - Tameable: false - Taming_XP: 0 - CanBeSummoned: false - COTW_Material: '' - COTW_Material_Data: 0 - COTW_Material_Amount: 0 -TwilightForest-KnightPhantom: - XP_Multiplier: 1.0 - Tameable: false - Taming_XP: 0 - CanBeSummoned: false - COTW_Material: '' - COTW_Material_Data: 0 - COTW_Material_Amount: 0 -TwilightForest-TowerGolem: - XP_Multiplier: 1.0 - Tameable: false - Taming_XP: 0 - CanBeSummoned: false - COTW_Material: '' - COTW_Material_Data: 0 - COTW_Material_Amount: 0 -MoCreatures-FishBowl: - XP_Multiplier: 1.0 - Tameable: false - Taming_XP: 0 - CanBeSummoned: false - COTW_Material: '' - COTW_Material_Data: 0 - COTW_Material_Amount: 0 \ No newline at end of file diff --git a/extras/mods/1.7.x/twilightforest.tools.yml b/extras/mods/1.7.x/twilightforest.tools.yml deleted file mode 100644 index e24b8299a..000000000 --- a/extras/mods/1.7.x/twilightforest.tools.yml +++ /dev/null @@ -1,184 +0,0 @@ -# Config created by joulesbeef -# Created For twilightforest-2.2.3 -# -# -# Settings for Axes -### -Axes: - # Ironwood - TWILIGHTFOREST_ITEM_IRONWOODAXE: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: TWILIGHTFOREST_ITEM_IRONWOODINGOT - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Steeleaf - TWILIGHTFOREST_ITEM_STEELEAFAXE: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: TWILIGHTFOREST_ITEM_STEELEAFINGOT - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Knightmetal - TWILIGHTFOREST_ITEM_KNIGHTLYAXE: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: TWILIGHTFOREST_ITEM_KNIGHTMETAL - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Minotaur - TWILIGHTFOREST_ITEM_MINOTAURAXE: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: Diamond - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 -# -# Settings for Hoes -### -Hoes: - # Ironwood - TWILIGHTFOREST_ITEM_IRONWOODHOE: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: TWILIGHTFOREST_ITEM_IRONWOODINGOT - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Steeleaf - TWILIGHTFOREST_ITEM_STEELEAFHOE: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: TWILIGHTFOREST_ITEM_STEELEAFINGOT - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - -# -# Settings for Pickaxes -### -Pickaxes: - # Ironwood - TWILIGHTFOREST_ITEM_IRONWOODPICK: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: TWILIGHTFOREST_ITEM_IRONWOODINGOT - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Fiery - TWILIGHTFOREST_ITEM_FIERYPICK: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: TWILIGHTFOREST_ITEM_FIERYINGOT - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Steeleaf - TWILIGHTFOREST_ITEM_STEELEAFPICK: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: TWILIGHTFOREST_ITEM_STEELEAFINGOT - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Knightmetal - TWILIGHTFOREST_ITEM_KNIGHTLYPICK: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: TWILIGHTFOREST_ITEM_KNIGHTMETAL - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 -# -# Settings for Shovels -### -Shovels: - # Ironwood - TWILIGHTFOREST_ITEM_IRONWOODSHOVEL: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: TWILIGHTFOREST_ITEM_IRONWOODINGOT - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Steeleaf - TWILIGHTFOREST_ITEM_STEELEAFSHOVEL: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: TWILIGHTFOREST_ITEM_STEELEAFINGOT - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 -# -# Settings for Swords -### -Swords: - # Ironwood - TWILIGHTFOREST_ITEM_IRONWOODSWORD: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: TWILIGHTFOREST_ITEM_IRONWOODINGOT - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Fiery - TWILIGHTFOREST_ITEM_FIERYSWORD: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: TWILIGHTFOREST_ITEM_FIERYINGOT - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Steeleaf - TWILIGHTFOREST_ITEM_STEELEAFSWORD: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: TWILIGHTFOREST_ITEM_STEELEAFINGOT - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 - # Knightmetal - TWILIGHTFOREST_ITEM_KNIGHTLYSWORD: - XP_Modifer: 1.0 - Ability_Enabled: true - Tier: 1 - Repairable: true - Repair_Material: TWILIGHTFOREST_ITEM_KNIGHTMETAL - Repair_Material_Data_Value: 0 - Repair_Material_Quantity: 2 - Durability: 500 \ No newline at end of file diff --git a/extras/repair.chain.yml b/extras/repair.chain.yml deleted file mode 100644 index b84a84637..000000000 --- a/extras/repair.chain.yml +++ /dev/null @@ -1,60 +0,0 @@ -# -# Repair configuration -# Last updated on ${project.version}-b${BUILD_NUMBER} -# -# Any file named repair.*.yml in the mcmmmo folder will be loaded as a repair config -# All repair configs have a main section titled "Repairables" -# Afterwards, all sub-items are considered a Repairable to be loaded. The names of each subitem should be the exact material name. -# The bare minimum of a Repairable is that it have a RepairMaterial and a MaximumDurability -# -# ItemType: This is the type of item to be repaired, this is only important to permissions. -## Valid values are ARMOR, TOOL, and OTHER. -## This defaults to OTHER. -# -# MaterialType: This is the type of the material of the item to be repaired, this is only important for permissions. -## Valid values are STRING, LEATHER, WOOD, STONE, IRON, GOLD, DIAMOND, and OTHER -## This defaults to OTHER. -# -# RepairMaterial: This is the material name of the item used to repair this repairable. -## This is required to be set. -# -# RepairMaterialMetadata: This is the metadata of the item used to repair this repairable. -## A value of -1 means to ignore all metadata when repairing. -## This defaults to -1 -# -# MaximumDurability: This is the maximum durability of the item. -## This is required to be set. -# -# MinimumLevel: This is the minimum repair level needed to repair this item. -## Valid values are => 0 -## This defaults to 0 -# -# MinimumQuantity: This is the minimum number of items needed to repair this item ignoring all other repair bonuses. -## This is typically the number of the repair material needed to create a new item, for example for a sword it is 2, for an axe it is 3 -## This defaults to 2 -# -# XpMultiplier: This is the amount to multiply the xp bonus by. -## This defaults to 1 -# -# -# The following is an example of a repair.*.yml config which adds the ability to repair Chainmail armor using fire. -# -# -### -Repairables: - # - # Chainmail repairables - ### - # Armor - CHAINMAIL_HELMET: - RepairMaterial: FIRE - XpMultiplier: 2 - CHAINMAIL_CHESTPLATE: - RepairMaterial: FIRE - XpMultiplier: 2 - CHAINMAIL_LEGGINGS: - RepairMaterial: FIRE - XpMultiplier: 2 - CHAINMAIL_BOOTS: - RepairMaterial: FIRE - XpMultiplier: 2 diff --git a/pom.xml b/pom.xml index e65b832e7..ee77337b7 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 com.gmail.nossr50.mcMMO mcMMO - 2.1.228 + 2.2.041-SNAPSHOT mcMMO https://github.com/mcMMO-Dev/mcMMO @@ -13,10 +13,15 @@ + + 1.21.7-R0.1-SNAPSHOT + 4.23.0 + 4.4.1-SNAPSHOT + 1.1.0 UTF-8 - 16 - 16 - 16 + 17 + 17 + 17 @@ -73,36 +78,44 @@ + + org.apache.maven.plugins + maven-resources-plugin + 3.3.1 + + UTF-8 + UTF-8 + + maven-surefire-plugin - 3.0.0-M7 + 3.2.5 org.junit.jupiter:junit-jupiter false + skip maven-failsafe-plugin - 3.0.0-M7 - + 3.2.5 org.junit.jupiter:junit-jupiter false - org.apache.maven.plugins maven-release-plugin - 3.0.0-M6 + 3.0.1 org.apache.maven.plugins maven-compiler-plugin - 3.10.1 + 3.13.0 - 16 + 17 -parameters @@ -112,6 +125,7 @@ maven-assembly-plugin + 3.7.1 src/main/assembly/package.xml @@ -130,7 +144,7 @@ org.apache.maven.plugins maven-shade-plugin - 3.3.0 + 3.5.3 @@ -140,23 +154,23 @@ org.bstats:bstats-base org.bstats:bstats-bukkit net.kyori:adventure-api - net.kyori:adventure-text-serializer-gson - net.kyori:adventure-platform-bukkit - net.kyori:adventure-platform-api - net.kyori:adventure-platform-viaversion - net.kyori:adventure-platform-facet - net.kyori:adventure-nbt net.kyori:adventure-key + net.kyori:adventure-nbt + net.kyori:adventure-platform-api + net.kyori:adventure-platform-bukkit + net.kyori:adventure-platform-facet + net.kyori:adventure-platform-viaversion + net.kyori:adventure-text-serializer-bungeecord + net.kyori:adventure-text-serializer-commons + net.kyori:adventure-text-serializer-gson + net.kyori:adventure-text-serializer-gson-legacy-impl + net.kyori:adventure-text-serializer-json + net.kyori:adventure-text-serializer-json-legacy-impl + net.kyori:adventure-text-serializer-legacy net.kyori:examination-api net.kyori:examination-string - net.kyori:adventure-text-serializer-legacy - net.kyori:adventure-text-serializer-gson - net.kyori:adventure-text-serializer-json - net.kyori:adventure-text-serializer-bungeecord - net.kyori:adventure-text-serializer-craftbukkit - net.kyori:adventure-text-serializer-gson-legacy-impl - net.kyori:adventure-text-serializer-json-legacy-impl net.kyori:option + net.kyori:adventure-text-serializer-craftbukkit co.aikar:acf-bukkit com.tcoded:FoliaLib @@ -222,6 +236,11 @@ + + + dmulloy2-repo + https://repo.dmulloy2.net/repository/public/ + spigot-repo https://hub.spigotmc.org/nexus/content/repositories/snapshots/ @@ -250,18 +269,44 @@ placeholderapi https://repo.extendedclip.com/content/repositories/placeholderapi/ + - devmart-other - https://nexuslite.gcnt.net/repos/other/ + papermc + https://repo.papermc.io/repository/maven-public/ + + + jitpack + https://jitpack.io + + + tcoded-releases + https://repo.tcoded.com/releases/ - - + + + org.assertj + assertj-core + 3.25.3 + test + + + com.comphenix.protocol + ProtocolLib + 5.3.0 + compile + + + com.h2database + h2 + 2.2.224 + test + me.clip placeholderapi - 2.11.3 + 2.11.6 provided @@ -272,83 +317,88 @@ net.kyori adventure-text-serializer-bungeecord - 4.3.2 + ${kyori.adventure.platform.version} net.kyori adventure-text-serializer-gson - 4.15.0 + ${kyori.adventure.version} net.kyori adventure-text-serializer-gson-legacy-impl - 4.15.0 + ${kyori.adventure.version} net.kyori adventure-text-serializer-json - 4.15.0 + ${kyori.adventure.version} net.kyori adventure-text-serializer-json-legacy-impl - 4.15.0 + ${kyori.adventure.version} net.kyori adventure-api - 4.15.0 + ${kyori.adventure.version} net.kyori adventure-nbt - 4.15.0 + ${kyori.adventure.version} net.kyori adventure-key - 4.15.0 + ${kyori.adventure.version} net.kyori adventure-platform-api - 4.3.2 + ${kyori.adventure.platform.version} net.kyori adventure-platform-bukkit - 4.3.2 + ${kyori.adventure.platform.version} net.kyori adventure-platform-facet - 4.3.2 + ${kyori.adventure.platform.version} net.kyori adventure-platform-viaversion - 4.3.2 + ${kyori.adventure.platform.version} net.kyori option - 1.0.0 + ${kyori.option.version} org.apache.maven.scm maven-scm-provider-gitexe - 2.0.0-M1 + 2.1.0 org.bstats bstats-bukkit - 3.0.0 + 3.0.2 compile + + + + + org.spigotmc spigot-api - 1.20.4-R0.1-SNAPSHOT + ${spigot.version} provided @@ -384,42 +434,42 @@ org.junit.jupiter junit-jupiter - 5.9.0 + 5.11.0-M2 test org.mockito mockito-core - 4.6.1 + 5.12.0 test org.mockito mockito-inline - 4.6.1 + 5.2.0 test org.apache.tomcat tomcat-jdbc - 10.1.0-M17 + 10.1.24 compile org.jetbrains annotations - 23.0.0 + 24.1.0 com.google.guava guava - 32.1.1-jre + 33.2.0-jre compile com.tcoded FoliaLib - 0.3.1 + 0.5.1 compile diff --git a/src/main/java/com/gmail/nossr50/api/AbilityAPI.java b/src/main/java/com/gmail/nossr50/api/AbilityAPI.java index 3ad6d43e7..c2fb9901a 100644 --- a/src/main/java/com/gmail/nossr50/api/AbilityAPI.java +++ b/src/main/java/com/gmail/nossr50/api/AbilityAPI.java @@ -8,7 +8,8 @@ import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; public final class AbilityAPI { - private AbilityAPI() {} + private AbilityAPI() { + } public static boolean berserkEnabled(Player player) { return UserManager.getPlayer(player).getAbilityMode(SuperAbilityType.BERSERK); @@ -39,10 +40,10 @@ public final class AbilityAPI { } public static boolean isAnyAbilityEnabled(Player player) { - McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player); + final McMMOPlayer mmoPlayer = UserManager.getPlayer(player); for (SuperAbilityType ability : SuperAbilityType.values()) { - if (mcMMOPlayer.getAbilityMode(ability)) { + if (mmoPlayer.getAbilityMode(ability)) { return true; } } @@ -83,10 +84,8 @@ public final class AbilityAPI { } public static boolean isBleeding(LivingEntity entity) { - if(entity.isValid()) { - if(entity.hasMetadata(MetadataConstants.METADATA_KEY_RUPTURE)) { - return true; - } + if (entity.isValid()) { + return entity.hasMetadata(MetadataConstants.METADATA_KEY_RUPTURE); } return false; diff --git a/src/main/java/com/gmail/nossr50/api/ChatAPI.java b/src/main/java/com/gmail/nossr50/api/ChatAPI.java index e4d61957a..bfbfb29ba 100644 --- a/src/main/java/com/gmail/nossr50/api/ChatAPI.java +++ b/src/main/java/com/gmail/nossr50/api/ChatAPI.java @@ -6,63 +6,8 @@ import com.gmail.nossr50.util.player.UserManager; import org.bukkit.entity.Player; public final class ChatAPI { - private ChatAPI() {} - -// /** -// * Send a message to all members of a party -// *
-// * This function is designed for API usage. -// * -// * @param plugin The plugin sending the message -// * @param sender The name of the sender -// * @param displayName The display name of the sender -// * @param party The name of the party to send to -// * @param message The message to send -// */ -// public static void sendPartyChat(Plugin plugin, String sender, String displayName, String party, String message) { -// getPartyChatManager(plugin, party).handleChat(sender, displayName, message); -// } -// -// /** -// * Send a message to all members of a party -// *
-// * This function is designed for API usage. -// * -// * @param plugin The plugin sending the message -// * @param sender The name of the sender to display in the chat -// * @param party The name of the party to send to -// * @param message The message to send -// */ -// public static void sendPartyChat(Plugin plugin, String sender, String party, String message) { -// getPartyChatManager(plugin, party).handleChat(sender, message); -// } -// -// /** -// * Send a message to administrators -// *
-// * This function is designed for API usage. -// * -// * @param plugin The plugin sending the message -// * @param sender The name of the sender -// * @param displayName The display name of the sender -// * @param message The message to send -// */ -// public static void sendAdminChat(Plugin plugin, String sender, String displayName, String message) { -// ChatManagerFactory.getChatManager(plugin, ChatChannel.ADMIN).handleChat(sender, displayName, message); -// } -// -// /** -// * Send a message to administrators -// *
-// * This function is designed for API usage. -// * -// * @param plugin The plugin sending the message -// * @param sender The name of the sender to display in the chat -// * @param message The message to send -// */ -// public static void sendAdminChat(Plugin plugin, String sender, String message) { -// ChatManagerFactory.getChatManager(plugin, ChatChannel.ADMIN).handleChat(sender, message); -// } + private ChatAPI() { + } /** * Check if a player is currently talking in party chat. @@ -110,7 +55,8 @@ public final class ChatAPI { * @param player The player to toggle party chat on. */ public static void togglePartyChat(Player player) { - mcMMO.p.getChatManager().setOrToggleChatChannel(UserManager.getPlayer(player), ChatChannel.PARTY); + mcMMO.p.getChatManager() + .setOrToggleChatChannel(UserManager.getPlayer(player), ChatChannel.PARTY); } /** @@ -119,7 +65,8 @@ public final class ChatAPI { * @param playerName The name of the player to toggle party chat on. */ public static void togglePartyChat(String playerName) { - mcMMO.p.getChatManager().setOrToggleChatChannel(UserManager.getPlayer(playerName), ChatChannel.PARTY); + mcMMO.p.getChatManager() + .setOrToggleChatChannel(UserManager.getPlayer(playerName), ChatChannel.PARTY); } /** @@ -128,7 +75,8 @@ public final class ChatAPI { * @param player The player to toggle admin chat on. */ public static void toggleAdminChat(Player player) { - mcMMO.p.getChatManager().setOrToggleChatChannel(UserManager.getPlayer(player), ChatChannel.ADMIN); + mcMMO.p.getChatManager() + .setOrToggleChatChannel(UserManager.getPlayer(player), ChatChannel.ADMIN); } /** @@ -137,6 +85,7 @@ public final class ChatAPI { * @param playerName The name of the player to toggle party chat on. */ public static void toggleAdminChat(String playerName) { - mcMMO.p.getChatManager().setOrToggleChatChannel(UserManager.getPlayer(playerName), ChatChannel.ADMIN); + mcMMO.p.getChatManager() + .setOrToggleChatChannel(UserManager.getPlayer(playerName), ChatChannel.ADMIN); } } diff --git a/src/main/java/com/gmail/nossr50/api/DatabaseAPI.java b/src/main/java/com/gmail/nossr50/api/DatabaseAPI.java index 55f682377..7e4007c0d 100644 --- a/src/main/java/com/gmail/nossr50/api/DatabaseAPI.java +++ b/src/main/java/com/gmail/nossr50/api/DatabaseAPI.java @@ -2,15 +2,17 @@ package com.gmail.nossr50.api; import com.gmail.nossr50.datatypes.player.PlayerProfile; import com.gmail.nossr50.mcMMO; +import java.util.UUID; import org.bukkit.OfflinePlayer; import org.jetbrains.annotations.NotNull; -import java.util.UUID; - public class DatabaseAPI { + private DatabaseAPI() { + } /** * Checks if a player exists in the mcMMO Database + * * @param offlinePlayer target player * @return true if the player exists in the DB, false if they do not */ @@ -22,6 +24,7 @@ public class DatabaseAPI { /** * Checks if a player exists in the mcMMO Database + * * @param uuid target player * @return true if the player exists in the DB, false if they do not */ @@ -38,6 +41,7 @@ public class DatabaseAPI { /** * Checks if a player exists in the mcMMO Database + * * @param playerName target player * @return true if the player exists in the DB, false if they do not */ diff --git a/src/main/java/com/gmail/nossr50/api/ExperienceAPI.java b/src/main/java/com/gmail/nossr50/api/ExperienceAPI.java index 0f1d8eeed..2d10aa8ed 100644 --- a/src/main/java/com/gmail/nossr50/api/ExperienceAPI.java +++ b/src/main/java/com/gmail/nossr50/api/ExperienceAPI.java @@ -1,34 +1,39 @@ package com.gmail.nossr50.api; -import com.gmail.nossr50.api.exceptions.*; +import static com.gmail.nossr50.datatypes.experience.XPGainReason.PVE; +import static com.gmail.nossr50.datatypes.experience.XPGainSource.CUSTOM; +import static com.gmail.nossr50.datatypes.experience.XPGainSource.SELF; + +import com.gmail.nossr50.api.exceptions.InvalidFormulaTypeException; +import com.gmail.nossr50.api.exceptions.InvalidPlayerException; +import com.gmail.nossr50.api.exceptions.InvalidSkillException; +import com.gmail.nossr50.api.exceptions.InvalidXPGainReasonException; +import com.gmail.nossr50.api.exceptions.McMMOPlayerNotFoundException; import com.gmail.nossr50.config.experience.ExperienceConfig; import com.gmail.nossr50.datatypes.experience.FormulaType; 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.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; +import java.util.ArrayList; +import java.util.UUID; import org.bukkit.OfflinePlayer; import org.bukkit.block.BlockState; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; -import java.util.ArrayList; -import java.util.Set; -import java.util.UUID; - public final class ExperienceAPI { - private ExperienceAPI() {} + private ExperienceAPI() { + } /** - * Returns whether given string is a valid type of skill suitable for the - * other API calls in this class. + * Returns whether given string is a valid type of skill suitable for the other API calls in + * this class. *
* This function is designed for API usage. * @@ -40,38 +45,40 @@ public final class ExperienceAPI { } /** - * Start the task that gives combat XP. - * Processes combat XP like mcMMO normally would, so mcMMO will check whether the entity should reward XP when giving out the XP + * Start the task that gives combat 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 mmoPlayer The attacking player * @param target The defending entity * @param primarySkillType The skill being used * @param multiplier final XP result will be multiplied by this * @deprecated Draft API */ @Deprecated - public static void addCombatXP(McMMOPlayer mcMMOPlayer, LivingEntity target, PrimarySkillType primarySkillType, double multiplier) { - CombatUtils.processCombatXP(mcMMOPlayer, target, primarySkillType, multiplier); + public static void addCombatXP(McMMOPlayer mmoPlayer, LivingEntity target, + PrimarySkillType primarySkillType, + double multiplier) { + CombatUtils.processCombatXP(mmoPlayer, target, primarySkillType, multiplier); } /** - * Start the task that gives combat XP. - * Processes combat XP like mcMMO normally would, so mcMMO will check whether the entity should reward XP when giving out the XP + * Start the task that gives combat 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 mmoPlayer The attacking player * @param target The defending entity * @param primarySkillType The skill being used * @deprecated Draft API */ @Deprecated - public static void addCombatXP(McMMOPlayer mcMMOPlayer, LivingEntity target, PrimarySkillType primarySkillType) { - CombatUtils.processCombatXP(mcMMOPlayer, target, primarySkillType); + public static void addCombatXP(McMMOPlayer mmoPlayer, LivingEntity target, + PrimarySkillType primarySkillType) { + CombatUtils.processCombatXP(mmoPlayer, target, primarySkillType); } /** - * Returns whether the given skill type string is both valid and not a - * child skill. (Child skills have no XP of their own, and their level is - * derived from the parent(s).) + * Returns whether the given skill type string is both valid and not a child skill. (Child + * skills have no XP of their own, and their level is derived from the parent(s).) *
* This function is designed for API usage. * @@ -79,7 +86,7 @@ public final class ExperienceAPI { * @return true if this is a valid, non-child mcMMO skill */ public static boolean isNonChildSkill(String skillType) { - PrimarySkillType skill = mcMMO.p.getSkillTools().matchSkill(skillType); + final PrimarySkillType skill = mcMMO.p.getSkillTools().matchSkill(skillType); return skill != null && !SkillTools.isChildSkill(skill); } @@ -97,7 +104,6 @@ public final class ExperienceAPI { * @param player The player to add XP to * @param skillType The skill to add XP to * @param XP The amount of XP to add - * * @throws InvalidSkillException if the given skill is not valid */ @Deprecated @@ -114,7 +120,6 @@ public final class ExperienceAPI { * @param skillType The skill to add XP to * @param XP The amount of XP to add * @param xpGainReason The reason to gain XP - * * @throws InvalidSkillException if the given skill is not valid * @throws InvalidXPGainReasonException if the given xpGainReason is not valid */ @@ -132,17 +137,19 @@ public final class ExperienceAPI { * @param XP The amount of XP to add * @param xpGainReason The reason to gain XP * @param isUnshared true if the XP cannot be shared with party members - * * @throws InvalidSkillException if the given skill is not valid * @throws InvalidXPGainReasonException if the given xpGainReason is not valid */ - public static void addRawXP(Player player, String skillType, float XP, String xpGainReason, boolean isUnshared) { + public static void addRawXP(Player player, String skillType, float XP, String xpGainReason, + boolean isUnshared) { if (isUnshared) { - getPlayer(player).beginUnsharedXpGain(getSkillType(skillType), XP, getXPGainReason(xpGainReason), XPGainSource.CUSTOM); + getPlayer(player).beginUnsharedXpGain(getSkillType(skillType), XP, + getXPGainReason(xpGainReason), CUSTOM); return; } - getPlayer(player).applyXpGain(getSkillType(skillType), XP, getXPGainReason(xpGainReason), XPGainSource.CUSTOM); + getPlayer(player).applyXpGain(getSkillType(skillType), XP, getXPGainReason(xpGainReason), + CUSTOM); } /** @@ -150,8 +157,8 @@ public final class ExperienceAPI { *
* This function is designed for API usage. * - * @deprecated We're using float for our XP values now - * replaced by {@link #addRawXPOffline(String playerName, String skillType, float XP)} + * @deprecated We're using float for our XP values now replaced by + * {@link #addRawXPOffline(String playerName, String skillType, float XP)} */ @Deprecated public static void addRawXPOffline(String playerName, String skillType, int XP) { @@ -163,15 +170,13 @@ public final class ExperienceAPI { *
* This function is designed for API usage. * - * @deprecated We're using uuids to get an offline player - * replaced by {@link #addRawXPOffline(UUID uuid, String skillType, float XP)} - * * @param playerName The player to add XP to * @param skillType The skill to add XP to * @param XP The amount of XP to add - * * @throws InvalidSkillException if the given skill is not valid * @throws InvalidPlayerException if the given player does not exist in the database + * @deprecated We're using uuids to get an offline player replaced by + * {@link #addRawXPOffline(UUID uuid, String skillType, float XP)} */ @Deprecated public static void addRawXPOffline(String playerName, String skillType, float XP) { @@ -186,7 +191,6 @@ public final class ExperienceAPI { * @param uuid The UUID of player to add XP to * @param skillType The skill to add XP to * @param XP The amount of XP to add - * * @throws InvalidSkillException if the given skill is not valid * @throws InvalidPlayerException if the given player does not exist in the database */ @@ -202,7 +206,6 @@ public final class ExperienceAPI { * @param player The player to add XP to * @param skillType The skill to add XP to * @param XP The amount of XP to add - * * @throws InvalidSkillException if the given skill is not valid */ @Deprecated @@ -219,12 +222,15 @@ public final class ExperienceAPI { * @param skillType The skill to add XP to * @param XP The amount of XP to add * @param xpGainReason The reason to gain XP - * * @throws InvalidSkillException if the given skill is not valid * @throws InvalidXPGainReasonException if the given xpGainReason is not valid */ - public static void addMultipliedXP(Player player, String skillType, int XP, String xpGainReason) { - getPlayer(player).applyXpGain(getSkillType(skillType), (int) (XP * ExperienceConfig.getInstance().getExperienceGainsGlobalMultiplier()), getXPGainReason(xpGainReason), XPGainSource.CUSTOM); + public static void addMultipliedXP(Player player, String skillType, int XP, + String xpGainReason) { + getPlayer(player).applyXpGain( + getSkillType(skillType), + (int) (XP * ExperienceConfig.getInstance().getExperienceGainsGlobalMultiplier()), + getXPGainReason(xpGainReason), CUSTOM); } /** @@ -235,13 +241,14 @@ public final class ExperienceAPI { * @param playerName The player to add XP to * @param skillType The skill to add XP to * @param XP The amount of XP to add - * * @throws InvalidSkillException if the given skill is not valid * @throws InvalidPlayerException if the given player does not exist in the database */ @Deprecated public static void addMultipliedXPOffline(String playerName, String skillType, int XP) { - addOfflineXP(playerName, getSkillType(skillType), (int) (XP * ExperienceConfig.getInstance().getExperienceGainsGlobalMultiplier())); + addOfflineXP( + playerName, getSkillType(skillType), + (int) (XP * ExperienceConfig.getInstance().getExperienceGainsGlobalMultiplier())); } /** @@ -252,7 +259,6 @@ public final class ExperienceAPI { * @param player The player to add XP to * @param skillType The skill to add XP to * @param XP The amount of XP to add - * * @throws InvalidSkillException if the given skill is not valid */ @Deprecated @@ -269,7 +275,6 @@ public final class ExperienceAPI { * @param skillType The skill to add XP to * @param XP The amount of XP to add * @param xpGainReason The reason to gain XP - * * @throws InvalidSkillException if the given skill is not valid * @throws InvalidXPGainReasonException if the given xpGainReason is not valid */ @@ -287,20 +292,26 @@ public final class ExperienceAPI { * @param XP The amount of XP to add * @param xpGainReason The reason to gain XP * @param isUnshared true if the XP cannot be shared with party members - * * @throws InvalidSkillException if the given skill is not valid * @throws InvalidXPGainReasonException if the given xpGainReason is not valid */ - public static void addModifiedXP(Player player, String skillType, int XP, String xpGainReason, boolean isUnshared) { - PrimarySkillType skill = getSkillType(skillType); + public static void addModifiedXP(Player player, String skillType, int XP, String xpGainReason, + boolean isUnshared) { + final PrimarySkillType skill = getSkillType(skillType); + final ExperienceConfig expConf = ExperienceConfig.getInstance(); if (isUnshared) { - getPlayer(player).beginUnsharedXpGain(skill, - (int) (XP / ExperienceConfig.getInstance().getFormulaSkillModifier(skill) * ExperienceConfig.getInstance().getExperienceGainsGlobalMultiplier()), getXPGainReason(xpGainReason), XPGainSource.CUSTOM); + getPlayer(player).beginUnsharedXpGain( + skill, (int) (XP / expConf.getFormulaSkillModifier( + skill) * expConf.getExperienceGainsGlobalMultiplier()), + getXPGainReason(xpGainReason), CUSTOM); return; } - getPlayer(player).applyXpGain(skill, (int) (XP / ExperienceConfig.getInstance().getFormulaSkillModifier(skill) * ExperienceConfig.getInstance().getExperienceGainsGlobalMultiplier()), getXPGainReason(xpGainReason), XPGainSource.CUSTOM); + getPlayer(player).applyXpGain( + skill, (int) (XP / expConf.getFormulaSkillModifier( + skill) * expConf.getExperienceGainsGlobalMultiplier()), + getXPGainReason(xpGainReason), CUSTOM); } /** @@ -311,27 +322,29 @@ public final class ExperienceAPI { * @param playerName The player to add XP to * @param skillType The skill to add XP to * @param XP The amount of XP to add - * * @throws InvalidSkillException if the given skill is not valid * @throws InvalidPlayerException if the given player does not exist in the database */ @Deprecated public static void addModifiedXPOffline(String playerName, String skillType, int XP) { - PrimarySkillType skill = getSkillType(skillType); + final PrimarySkillType skill = getSkillType(skillType); - addOfflineXP(playerName, skill, (int) (XP / ExperienceConfig.getInstance().getFormulaSkillModifier(skill) * ExperienceConfig.getInstance().getExperienceGainsGlobalMultiplier())); + addOfflineXP( + playerName, skill, + (int) (XP / ExperienceConfig.getInstance().getFormulaSkillModifier( + skill) * ExperienceConfig.getInstance() + .getExperienceGainsGlobalMultiplier())); } /** - * Adds XP to the player, calculates for XP Rate, skill modifiers, perks, child skills, - * and party sharing. + * Adds XP to the player, calculates for XP Rate, skill modifiers, perks, child skills, and + * party sharing. *
* This function is designed for API usage. * * @param player The player to add XP to * @param skillType The skill to add XP to * @param XP The amount of XP to add - * * @throws InvalidSkillException if the given skill is not valid */ @Deprecated @@ -340,8 +353,8 @@ public final class ExperienceAPI { } /** - * Adds XP to the player, calculates for XP Rate, skill modifiers, perks, child skills, - * and party sharing. + * Adds XP to the player, calculates for XP Rate, skill modifiers, perks, child skills, and + * party sharing. *
* This function is designed for API usage. * @@ -349,7 +362,6 @@ public final class ExperienceAPI { * @param skillType The skill to add XP to * @param XP The amount of XP to add * @param xpGainReason The reason to gain XP - * * @throws InvalidSkillException if the given skill is not valid * @throws InvalidXPGainReasonException if the given xpGainReason is not valid */ @@ -358,8 +370,8 @@ public final class ExperienceAPI { } /** - * Adds XP to the player, calculates for XP Rate, skill modifiers, perks, child skills, - * and party sharing. + * Adds XP to the player, calculates for XP Rate, skill modifiers, perks, child skills, and + * party sharing. *
* This function is designed for API usage. * @@ -368,17 +380,19 @@ public final class ExperienceAPI { * @param XP The amount of XP to add * @param xpGainReason The reason to gain XP * @param isUnshared true if the XP cannot be shared with party members - * * @throws InvalidSkillException if the given skill is not valid * @throws InvalidXPGainReasonException if the given xpGainReason is not valid */ - public static void addXP(Player player, String skillType, int XP, String xpGainReason, boolean isUnshared) { + public static void addXP(Player player, String skillType, int XP, String xpGainReason, + boolean isUnshared) { if (isUnshared) { - getPlayer(player).beginUnsharedXpGain(getSkillType(skillType), XP, getXPGainReason(xpGainReason), XPGainSource.CUSTOM); + getPlayer(player).beginUnsharedXpGain(getSkillType(skillType), XP, + getXPGainReason(xpGainReason), CUSTOM); return; } - getPlayer(player).beginXpGain(getSkillType(skillType), XP, getXPGainReason(xpGainReason), XPGainSource.CUSTOM); + getPlayer(player).beginXpGain(getSkillType(skillType), XP, getXPGainReason(xpGainReason), + CUSTOM); } /** @@ -389,7 +403,6 @@ public final class ExperienceAPI { * @param player The player to get XP for * @param skillType The skill to get XP for * @return the amount of XP in a given skill - * * @throws InvalidSkillException if the given skill is not valid * @throws UnsupportedOperationException if the given skill is a child skill */ @@ -405,7 +418,6 @@ public final class ExperienceAPI { * @param playerName The player to get XP for * @param skillType The skill to get XP for * @return the amount of XP in a given skill - * * @throws InvalidSkillException if the given skill is not valid * @throws InvalidPlayerException if the given player does not exist in the database * @throws UnsupportedOperationException if the given skill is a child skill @@ -423,7 +435,6 @@ public final class ExperienceAPI { * @param uuid The player to get XP for * @param skillType The skill to get XP for * @return the amount of XP in a given skill - * * @throws InvalidSkillException if the given skill is not valid * @throws InvalidPlayerException if the given player does not exist in the database * @throws UnsupportedOperationException if the given skill is a child skill @@ -440,12 +451,12 @@ public final class ExperienceAPI { * @param offlinePlayer The player to get XP for * @param skillType The skill to get XP for * @return the amount of XP in a given skill - * * @throws InvalidSkillException if the given skill is not valid * @throws InvalidPlayerException if the given player does not exist in the database * @throws UnsupportedOperationException if the given skill is a child skill */ - public static int getOfflineXP(@NotNull OfflinePlayer offlinePlayer, @NotNull String skillType) throws InvalidPlayerException { + public static int getOfflineXP(@NotNull OfflinePlayer offlinePlayer, @NotNull String skillType) + throws InvalidPlayerException { return getOfflineProfile(offlinePlayer).getSkillXpLevel(getNonChildSkillType(skillType)); } @@ -457,7 +468,6 @@ public final class ExperienceAPI { * @param player The player to get XP for * @param skillType The skill to get XP for * @return the amount of XP in a given skill - * * @throws InvalidSkillException if the given skill is not valid * @throws UnsupportedOperationException if the given skill is a child skill */ @@ -473,7 +483,6 @@ public final class ExperienceAPI { * @param playerName The player to get XP for * @param skillType The skill to get XP for * @return the amount of XP in a given skill - * * @throws InvalidSkillException if the given skill is not valid * @throws InvalidPlayerException if the given player does not exist in the database * @throws UnsupportedOperationException if the given skill is a child skill @@ -491,7 +500,6 @@ public final class ExperienceAPI { * @param uuid The player to get XP for * @param skillType The skill to get XP for * @return the amount of XP in a given skill - * * @throws InvalidSkillException if the given skill is not valid * @throws InvalidPlayerException if the given player does not exist in the database * @throws UnsupportedOperationException if the given skill is a child skill @@ -508,18 +516,22 @@ public final class ExperienceAPI { * @param offlinePlayer The player to get XP for * @param skillType The skill to get XP for * @return the amount of XP in a given skill - * * @throws InvalidSkillException if the given skill is not valid * @throws InvalidPlayerException if the given player does not exist in the database * @throws UnsupportedOperationException if the given skill is a child skill */ - public static float getOfflineXPRaw(@NotNull OfflinePlayer offlinePlayer, @NotNull String skillType) throws InvalidPlayerException, UnsupportedOperationException, InvalidSkillException { + public static float getOfflineXPRaw(@NotNull OfflinePlayer offlinePlayer, + @NotNull String skillType) + throws InvalidPlayerException, UnsupportedOperationException, InvalidSkillException { return getOfflineProfile(offlinePlayer).getSkillXpLevelRaw(getNonChildSkillType(skillType)); } - public static float getOfflineXPRaw(@NotNull OfflinePlayer offlinePlayer, @NotNull PrimarySkillType skillType) throws InvalidPlayerException, UnsupportedOperationException { - if(SkillTools.isChildSkill(skillType)) + public static float getOfflineXPRaw(@NotNull OfflinePlayer offlinePlayer, + @NotNull PrimarySkillType skillType) + throws InvalidPlayerException, UnsupportedOperationException { + if (SkillTools.isChildSkill(skillType)) { throw new UnsupportedOperationException(); + } return getOfflineProfile(offlinePlayer).getSkillXpLevelRaw(skillType); } @@ -532,7 +544,6 @@ public final class ExperienceAPI { * @param player The player to get the XP amount for * @param skillType The skill to get the XP amount for * @return the total amount of XP needed to reach the next level - * * @throws InvalidSkillException if the given skill is not valid * @throws UnsupportedOperationException if the given skill is a child skill */ @@ -548,7 +559,6 @@ public final class ExperienceAPI { * @param playerName The player to get XP for * @param skillType The skill to get XP for * @return the total amount of XP needed to reach the next level - * * @throws InvalidSkillException if the given skill is not valid * @throws InvalidPlayerException if the given player does not exist in the database * @throws UnsupportedOperationException if the given skill is a child skill @@ -566,7 +576,6 @@ public final class ExperienceAPI { * @param uuid The player to get XP for * @param skillType The skill to get XP for * @return the total amount of XP needed to reach the next level - * * @throws InvalidSkillException if the given skill is not valid * @throws InvalidPlayerException if the given player does not exist in the database * @throws UnsupportedOperationException if the given skill is a child skill @@ -583,12 +592,13 @@ public final class ExperienceAPI { * @param offlinePlayer The player to get XP for * @param skillType The skill to get XP for * @return the total amount of XP needed to reach the next level - * * @throws InvalidSkillException if the given skill is not valid * @throws InvalidPlayerException if the given player does not exist in the database * @throws UnsupportedOperationException if the given skill is a child skill */ - public static int getOfflineXPToNextLevel(@NotNull OfflinePlayer offlinePlayer, @NotNull String skillType) throws UnsupportedOperationException, InvalidSkillException, InvalidPlayerException { + public static int getOfflineXPToNextLevel(@NotNull OfflinePlayer offlinePlayer, + @NotNull String skillType) + throws UnsupportedOperationException, InvalidSkillException, InvalidPlayerException { return getOfflineProfile(offlinePlayer).getXpToLevel(getNonChildSkillType(skillType)); } @@ -600,14 +610,13 @@ public final class ExperienceAPI { * @param player The player to get the XP amount for * @param skillType The skill to get the XP amount for * @return the amount of XP remaining until the next level - * * @throws InvalidSkillException if the given skill is not valid * @throws UnsupportedOperationException if the given skill is a child skill */ public static int getXPRemaining(Player player, String skillType) { - PrimarySkillType skill = getNonChildSkillType(skillType); + final PrimarySkillType skill = getNonChildSkillType(skillType); - PlayerProfile profile = getPlayer(player).getProfile(); + final PlayerProfile profile = getPlayer(player).getProfile(); return profile.getXpToLevel(skill) - profile.getSkillXpLevel(skill); } @@ -620,15 +629,14 @@ public final class ExperienceAPI { * @param playerName The player to get XP for * @param skillType The skill to get XP for * @return the amount of XP needed to reach the next level - * * @throws InvalidSkillException if the given skill is not valid * @throws InvalidPlayerException if the given player does not exist in the database * @throws UnsupportedOperationException if the given skill is a child skill */ @Deprecated public static int getOfflineXPRemaining(String playerName, String skillType) { - PrimarySkillType skill = getNonChildSkillType(skillType); - PlayerProfile profile = getOfflineProfile(playerName); + final PrimarySkillType skill = getNonChildSkillType(skillType); + final PlayerProfile profile = getOfflineProfile(playerName); return profile.getXpToLevel(skill) - profile.getSkillXpLevel(skill); } @@ -641,14 +649,13 @@ public final class ExperienceAPI { * @param uuid The player to get XP for * @param skillType The skill to get XP for * @return the amount of XP needed to reach the next level - * * @throws InvalidSkillException if the given skill is not valid * @throws InvalidPlayerException if the given player does not exist in the database * @throws UnsupportedOperationException if the given skill is a child skill */ public static float getOfflineXPRemaining(UUID uuid, String skillType) { - PrimarySkillType skill = getNonChildSkillType(skillType); - PlayerProfile profile = getOfflineProfile(uuid); + final PrimarySkillType skill = getNonChildSkillType(skillType); + final PlayerProfile profile = getOfflineProfile(uuid); return profile.getXpToLevel(skill) - profile.getSkillXpLevelRaw(skill); } @@ -661,14 +668,14 @@ public final class ExperienceAPI { * @param offlinePlayer The player to get XP for * @param skillType The skill to get XP for * @return the amount of XP needed to reach the next level - * * @throws InvalidSkillException if the given skill is not valid * @throws InvalidPlayerException if the given player does not exist in the database * @throws UnsupportedOperationException if the given skill is a child skill */ - public static float getOfflineXPRemaining(OfflinePlayer offlinePlayer, String skillType) throws InvalidSkillException, InvalidPlayerException, UnsupportedOperationException { - PrimarySkillType skill = getNonChildSkillType(skillType); - PlayerProfile profile = getOfflineProfile(offlinePlayer); + public static float getOfflineXPRemaining(OfflinePlayer offlinePlayer, String skillType) + throws InvalidSkillException, InvalidPlayerException, UnsupportedOperationException { + final PrimarySkillType skill = getNonChildSkillType(skillType); + final PlayerProfile profile = getOfflineProfile(offlinePlayer); return profile.getXpToLevel(skill) - profile.getSkillXpLevelRaw(skill); } @@ -681,7 +688,6 @@ public final class ExperienceAPI { * @param player The player to add levels to * @param skillType Type of skill to add levels to * @param levels Number of levels to add - * * @throws InvalidSkillException if the given skill is not valid */ public static void addLevel(Player player, String skillType, int levels) { @@ -696,17 +702,16 @@ public final class ExperienceAPI { * @param playerName The player to add levels to * @param skillType Type of skill to add levels to * @param levels Number of levels to add - * * @throws InvalidSkillException if the given skill is not valid * @throws InvalidPlayerException if the given player does not exist in the database */ @Deprecated public static void addLevelOffline(String playerName, String skillType, int levels) { - PlayerProfile profile = getOfflineProfile(playerName); - PrimarySkillType skill = getSkillType(skillType); + final PlayerProfile profile = getOfflineProfile(playerName); + final 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())); @@ -728,16 +733,15 @@ public final class ExperienceAPI { * @param uuid The player to add levels to * @param skillType Type of skill to add levels to * @param levels Number of levels to add - * * @throws InvalidSkillException if the given skill is not valid * @throws InvalidPlayerException if the given player does not exist in the database */ public static void addLevelOffline(UUID uuid, String skillType, int levels) { - PlayerProfile profile = getOfflineProfile(uuid); - PrimarySkillType skill = getSkillType(skillType); + final PlayerProfile profile = getOfflineProfile(uuid); + final 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())); @@ -759,7 +763,6 @@ public final class ExperienceAPI { * @param player The player to get the level for * @param skillType The skill to get the level for * @return the level of a given skill - * * @throws InvalidSkillException if the given skill is not valid * @deprecated Use getLevel(Player player, PrimarySkillType skillType) instead */ @@ -776,7 +779,6 @@ public final class ExperienceAPI { * @param player The player to get the level for * @param skillType The skill to get the level for * @return the level of a given skill - * * @throws InvalidSkillException if the given skill is not valid */ public static int getLevel(Player player, PrimarySkillType skillType) { @@ -791,7 +793,6 @@ public final class ExperienceAPI { * @param playerName The player to get the level for * @param skillType The skill to get the level for * @return the level of a given skill - * * @throws InvalidSkillException if the given skill is not valid * @throws InvalidPlayerException if the given player does not exist in the database */ @@ -807,7 +808,6 @@ public final class ExperienceAPI { * @param uuid The player to get the level for * @param skillType The skill to get the level for * @return the level of a given skill - * * @throws InvalidSkillException if the given skill is not valid * @throws InvalidPlayerException if the given player does not exist in the database */ @@ -834,13 +834,12 @@ public final class ExperienceAPI { * * @param playerName The player to get the power level for * @return the power level of the player - * * @throws InvalidPlayerException if the given player does not exist in the database */ @Deprecated public static int getPowerLevelOffline(String playerName) { int powerLevel = 0; - PlayerProfile profile = getOfflineProfile(playerName); + final PlayerProfile profile = getOfflineProfile(playerName); for (PrimarySkillType type : SkillTools.NON_CHILD_SKILLS) { powerLevel += profile.getSkillLevel(type); @@ -856,12 +855,11 @@ public final class ExperienceAPI { * * @param uuid The player to get the power level for * @return the power level of the player - * * @throws InvalidPlayerException if the given player does not exist in the database */ public static int getPowerLevelOffline(UUID uuid) { int powerLevel = 0; - PlayerProfile profile = getOfflineProfile(uuid); + final PlayerProfile profile = getOfflineProfile(uuid); for (PrimarySkillType type : SkillTools.NON_CHILD_SKILLS) { powerLevel += profile.getSkillLevel(type); @@ -877,7 +875,6 @@ public final class ExperienceAPI { * * @param skillType The skill to get the level cap for * @return the level cap of a given skill - * * @throws InvalidSkillException if the given skill is not valid */ public static int getLevelCap(String skillType) { @@ -902,16 +899,16 @@ public final class ExperienceAPI { * * @param playerName The name of the player to check * @param skillType The skill to check - * + * @return the position on the leaderboard * @throws InvalidSkillException if the given skill is not valid * @throws InvalidPlayerException if the given player does not exist in the database * @throws UnsupportedOperationException if the given skill is a child skill - * - * @return the position on the leaderboard */ @Deprecated public static int getPlayerRankSkill(String playerName, String skillType) { - return mcMMO.getDatabaseManager().readRank(mcMMO.p.getServer().getOfflinePlayer(playerName).getName()).get(getNonChildSkillType(skillType)); + return mcMMO.getDatabaseManager() + .readRank(mcMMO.p.getServer().getOfflinePlayer(playerName).getName()).get( + getNonChildSkillType(skillType)); } /** @@ -921,15 +918,15 @@ public final class ExperienceAPI { * * @param uuid The name of the player to check * @param skillType The skill to check - * + * @return the position on the leaderboard * @throws InvalidSkillException if the given skill is not valid * @throws InvalidPlayerException if the given player does not exist in the database * @throws UnsupportedOperationException if the given skill is a child skill - * - * @return the position on the leaderboard */ public static int getPlayerRankSkill(UUID uuid, String skillType) { - return mcMMO.getDatabaseManager().readRank(mcMMO.p.getServer().getOfflinePlayer(uuid).getName()).get(getNonChildSkillType(skillType)); + return mcMMO.getDatabaseManager() + .readRank(mcMMO.p.getServer().getOfflinePlayer(uuid).getName()).get( + getNonChildSkillType(skillType)); } /** @@ -938,14 +935,14 @@ public final class ExperienceAPI { * This function is designed for API usage. * * @param playerName The name of the player to check - * - * @throws InvalidPlayerException if the given player does not exist in the database - * * @return the position on the power level leaderboard + * @throws InvalidPlayerException if the given player does not exist in the database */ @Deprecated public static int getPlayerRankOverall(String playerName) { - return mcMMO.getDatabaseManager().readRank(mcMMO.p.getServer().getOfflinePlayer(playerName).getName()).get(null); + return mcMMO.getDatabaseManager() + .readRank(mcMMO.p.getServer().getOfflinePlayer(playerName).getName()).get( + null); } /** @@ -954,13 +951,12 @@ public final class ExperienceAPI { * This function is designed for API usage. * * @param uuid The name of the player to check - * - * @throws InvalidPlayerException if the given player does not exist in the database - * * @return the position on the power level leaderboard + * @throws InvalidPlayerException if the given player does not exist in the database */ public static int getPlayerRankOverall(UUID uuid) { - return mcMMO.getDatabaseManager().readRank(mcMMO.p.getServer().getOfflinePlayer(uuid).getName()).get(null); + return mcMMO.getDatabaseManager() + .readRank(mcMMO.p.getServer().getOfflinePlayer(uuid).getName()).get(null); } /** @@ -971,7 +967,6 @@ public final class ExperienceAPI { * @param player The player to set the level of * @param skillType The skill to set the level for * @param skillLevel The value to set the level to - * * @throws InvalidSkillException if the given skill is not valid */ public static void setLevel(Player player, String skillType, int skillLevel) { @@ -986,7 +981,6 @@ public final class ExperienceAPI { * @param playerName The player to set the level of * @param skillType The skill to set the level for * @param skillLevel The value to set the level to - * * @throws InvalidSkillException if the given skill is not valid * @throws InvalidPlayerException if the given player does not exist in the database */ @@ -1003,7 +997,6 @@ public final class ExperienceAPI { * @param uuid The player to set the level of * @param skillType The skill to set the level for * @param skillLevel The value to set the level to - * * @throws InvalidSkillException if the given skill is not valid * @throws InvalidPlayerException if the given player does not exist in the database */ @@ -1019,7 +1012,6 @@ public final class ExperienceAPI { * @param player The player to set the XP of * @param skillType The skill to set the XP for * @param newValue The value to set the XP to - * * @throws InvalidSkillException if the given skill is not valid * @throws UnsupportedOperationException if the given skill is a child skill */ @@ -1035,7 +1027,6 @@ public final class ExperienceAPI { * @param playerName The player to set the XP of * @param skillType The skill to set the XP for * @param newValue The value to set the XP to - * * @throws InvalidSkillException if the given skill is not valid * @throws InvalidPlayerException if the given player does not exist in the database * @throws UnsupportedOperationException if the given skill is a child skill @@ -1053,7 +1044,6 @@ public final class ExperienceAPI { * @param uuid The player to set the XP of * @param skillType The skill to set the XP for * @param newValue The value to set the XP to - * * @throws InvalidSkillException if the given skill is not valid * @throws InvalidPlayerException if the given player does not exist in the database * @throws UnsupportedOperationException if the given skill is a child skill @@ -1070,7 +1060,6 @@ public final class ExperienceAPI { * @param player The player to change the XP of * @param skillType The skill to change the XP for * @param xp The amount of XP to remove - * * @throws InvalidSkillException if the given skill is not valid * @throws UnsupportedOperationException if the given skill is a child skill */ @@ -1086,7 +1075,6 @@ public final class ExperienceAPI { * @param playerName The player to change the XP of * @param skillType The skill to change the XP for * @param xp The amount of XP to remove - * * @throws InvalidSkillException if the given skill is not valid * @throws InvalidPlayerException if the given player does not exist in the database * @throws UnsupportedOperationException if the given skill is a child skill @@ -1104,7 +1092,6 @@ public final class ExperienceAPI { * @param uuid The player to change the XP of * @param skillType The skill to change the XP for * @param xp The amount of XP to remove - * * @throws InvalidSkillException if the given skill is not valid * @throws InvalidPlayerException if the given player does not exist in the database * @throws UnsupportedOperationException if the given skill is a child skill @@ -1119,11 +1106,11 @@ public final class ExperienceAPI { * This function is designed for API usage. * * @param level The level to get the amount of XP for - * * @throws InvalidFormulaTypeException if the given formulaType is not valid */ public static int getXpNeededToLevel(int level) { - return mcMMO.p.getFormulaManager().getXPtoNextLevel(level, ExperienceConfig.getInstance().getFormulaType()); + return mcMMO.p.getFormulaManager() + .getXPtoNextLevel(level, ExperienceConfig.getInstance().getFormulaType()); } /** @@ -1133,7 +1120,6 @@ public final class ExperienceAPI { * * @param level The level to get the amount of XP for * @param formulaType The formula type to get the amount of XP for - * * @throws InvalidFormulaTypeException if the given formulaType is not valid */ public static int getXpNeededToLevel(int level, String formulaType) { @@ -1141,88 +1127,102 @@ public final class ExperienceAPI { } /** - * Will add the appropriate type of XP from the block to the player based on the material of the blocks given + * Will add the appropriate type of XP from the block to the player based on the material of the + * blocks given + * * @param blockStates the blocks to reward XP for - * @param mcMMOPlayer the target player + * @param mmoPlayer the target player */ - public static void addXpFromBlocks(ArrayList blockStates, McMMOPlayer mcMMOPlayer) - { - for(BlockState bs : blockStates) - { - for(PrimarySkillType skillType : PrimarySkillType.values()) - { - if(ExperienceConfig.getInstance().getXp(skillType, bs.getType()) > 0) - { - mcMMOPlayer.applyXpGain(skillType, ExperienceConfig.getInstance().getXp(skillType, bs.getType()), XPGainReason.PVE, XPGainSource.SELF); + public static void addXpFromBlocks(ArrayList blockStates, McMMOPlayer mmoPlayer) { + for (BlockState bs : blockStates) { + for (PrimarySkillType skillType : PrimarySkillType.values()) { + if (ExperienceConfig.getInstance().getXp(skillType, bs.getType()) > 0) { + mmoPlayer.applyXpGain( + skillType, + ExperienceConfig.getInstance().getXp(skillType, bs.getType()), PVE, + SELF); } } } } /** - * Will add the appropriate type of XP from the block to the player based on the material of the blocks given if it matches the given skillType + * Will add the appropriate type of XP from the block to the player based on the material of the + * blocks given if it matches the given skillType + * * @param blockStates the blocks to reward XP for - * @param mcMMOPlayer the target player + * @param mmoPlayer the target player * @param skillType target primary skill */ - public static void addXpFromBlocksBySkill(ArrayList blockStates, McMMOPlayer mcMMOPlayer, PrimarySkillType skillType) - { - for(BlockState bs : blockStates) - { - if(ExperienceConfig.getInstance().getXp(skillType, bs.getType()) > 0) - { - mcMMOPlayer.applyXpGain(skillType, ExperienceConfig.getInstance().getXp(skillType, bs.getType()), XPGainReason.PVE, XPGainSource.SELF); + public static void addXpFromBlocksBySkill(ArrayList blockStates, + McMMOPlayer mmoPlayer, + PrimarySkillType skillType) { + for (BlockState bs : blockStates) { + if (ExperienceConfig.getInstance().getXp(skillType, bs.getType()) > 0) { + mmoPlayer.applyXpGain( + skillType, ExperienceConfig.getInstance().getXp(skillType, bs.getType()), + PVE, + SELF); } } } /** - * Will add the appropriate type of XP from the block to the player based on the material of the blocks given + * Will add the appropriate type of XP from the block to the player based on the material of the + * blocks given + * * @param blockState The target blockstate - * @param mcMMOPlayer The target player + * @param mmoPlayer The target player */ - public static void addXpFromBlock(BlockState blockState, McMMOPlayer mcMMOPlayer) - { - for(PrimarySkillType skillType : PrimarySkillType.values()) - { - if(ExperienceConfig.getInstance().getXp(skillType, blockState.getType()) > 0) - { - mcMMOPlayer.applyXpGain(skillType, ExperienceConfig.getInstance().getXp(skillType, blockState.getType()), XPGainReason.PVE, XPGainSource.SELF); + public static void addXpFromBlock(BlockState blockState, McMMOPlayer mmoPlayer) { + for (PrimarySkillType skillType : PrimarySkillType.values()) { + if (ExperienceConfig.getInstance().getXp(skillType, blockState.getType()) > 0) { + mmoPlayer.applyXpGain( + skillType, + ExperienceConfig.getInstance().getXp(skillType, blockState.getType()), + PVE, SELF); } } } /** - * Will add the appropriate type of XP from the block to the player based on the material of the blocks given if it matches the given skillType + * Will add the appropriate type of XP from the block to the player based on the material of the + * blocks given if it matches the given skillType + * * @param blockState The target blockstate - * @param mcMMOPlayer The target player + * @param mmoPlayer The target player * @param skillType target primary skill */ - public static void addXpFromBlockBySkill(BlockState blockState, McMMOPlayer mcMMOPlayer, PrimarySkillType skillType) - { - if(ExperienceConfig.getInstance().getXp(skillType, blockState.getType()) > 0) - { - mcMMOPlayer.applyXpGain(skillType, ExperienceConfig.getInstance().getXp(skillType, blockState.getType()), XPGainReason.PVE, XPGainSource.SELF); + public static void addXpFromBlockBySkill(BlockState blockState, McMMOPlayer mmoPlayer, + PrimarySkillType skillType) { + if (ExperienceConfig.getInstance().getXp(skillType, blockState.getType()) > 0) { + mmoPlayer.applyXpGain( + skillType, + ExperienceConfig.getInstance().getXp(skillType, blockState.getType()), PVE, + SELF); } } // Utility methods follow. - private static void addOfflineXP(@NotNull UUID playerUniqueId, @NotNull PrimarySkillType skill, int XP) { - PlayerProfile profile = getOfflineProfile(playerUniqueId); + private static void addOfflineXP(@NotNull UUID playerUniqueId, @NotNull PrimarySkillType skill, + int XP) { + final PlayerProfile profile = getOfflineProfile(playerUniqueId); profile.addXp(skill, XP); profile.save(true); } - private static void addOfflineXP(@NotNull String playerName, @NotNull PrimarySkillType skill, int XP) { - PlayerProfile profile = getOfflineProfile(playerName); + private static void addOfflineXP(@NotNull String playerName, @NotNull PrimarySkillType skill, + int XP) { + final PlayerProfile profile = getOfflineProfile(playerName); profile.addXp(skill, XP); profile.scheduleAsyncSave(); } - private static @NotNull PlayerProfile getOfflineProfile(@NotNull UUID uuid) throws InvalidPlayerException { - PlayerProfile profile = mcMMO.getDatabaseManager().loadPlayerProfile(uuid); + private static @NotNull PlayerProfile getOfflineProfile(@NotNull UUID uuid) + throws InvalidPlayerException { + final PlayerProfile profile = mcMMO.getDatabaseManager().loadPlayerProfile(uuid); if (!profile.isLoaded()) { throw new InvalidPlayerException(); @@ -1231,8 +1231,9 @@ public final class ExperienceAPI { return profile; } - private static @NotNull PlayerProfile getOfflineProfile(@NotNull OfflinePlayer offlinePlayer) throws InvalidPlayerException { - PlayerProfile profile = mcMMO.getDatabaseManager().loadPlayerProfile(offlinePlayer); + private static @NotNull PlayerProfile getOfflineProfile(@NotNull OfflinePlayer offlinePlayer) + throws InvalidPlayerException { + final PlayerProfile profile = mcMMO.getDatabaseManager().loadPlayerProfile(offlinePlayer); if (!profile.isLoaded()) { throw new InvalidPlayerException(); @@ -1241,8 +1242,9 @@ public final class ExperienceAPI { return profile; } - private static @NotNull PlayerProfile getOfflineProfile(@NotNull String playerName) throws InvalidPlayerException { - PlayerProfile profile = mcMMO.getDatabaseManager().loadPlayerProfile(playerName); + private static @NotNull PlayerProfile getOfflineProfile(@NotNull String playerName) + throws InvalidPlayerException { + final PlayerProfile profile = mcMMO.getDatabaseManager().loadPlayerProfile(playerName); if (!profile.isLoaded()) { throw new InvalidPlayerException(); @@ -1252,7 +1254,7 @@ public final class ExperienceAPI { } private static PrimarySkillType getSkillType(String skillType) throws InvalidSkillException { - PrimarySkillType skill = mcMMO.p.getSkillTools().matchSkill(skillType); + final PrimarySkillType skill = mcMMO.p.getSkillTools().matchSkill(skillType); if (skill == null) { throw new InvalidSkillException(); @@ -1261,8 +1263,9 @@ public final class ExperienceAPI { return skill; } - private static PrimarySkillType getNonChildSkillType(String skillType) throws InvalidSkillException, UnsupportedOperationException { - PrimarySkillType skill = getSkillType(skillType); + private static PrimarySkillType getNonChildSkillType(String skillType) + throws InvalidSkillException, UnsupportedOperationException { + final PrimarySkillType skill = getSkillType(skillType); if (SkillTools.isChildSkill(skill)) { throw new UnsupportedOperationException("Child skills do not have XP"); @@ -1282,7 +1285,7 @@ public final class ExperienceAPI { } private static FormulaType getFormulaType(String formula) throws InvalidFormulaTypeException { - FormulaType formulaType = FormulaType.getFormulaType(formula); + final FormulaType formulaType = FormulaType.getFormulaType(formula); if (formulaType == null) { throw new InvalidFormulaTypeException(); @@ -1292,12 +1295,12 @@ public final class ExperienceAPI { } /** - * @deprecated Use UserManager::getPlayer(Player player) instead * @param player target player * @return McMMOPlayer for that player if the profile is loaded, otherwise null * @throws McMMOPlayerNotFoundException + * @deprecated Use UserManager::getPlayer(Player player) instead */ - @Deprecated + @Deprecated(forRemoval = true) private static McMMOPlayer getPlayer(Player player) throws McMMOPlayerNotFoundException { if (!UserManager.hasPlayerDataKey(player)) { throw new McMMOPlayerNotFoundException(player); diff --git a/src/main/java/com/gmail/nossr50/api/PartyAPI.java b/src/main/java/com/gmail/nossr50/api/PartyAPI.java index 7592df5e6..314d60c43 100644 --- a/src/main/java/com/gmail/nossr50/api/PartyAPI.java +++ b/src/main/java/com/gmail/nossr50/api/PartyAPI.java @@ -3,17 +3,22 @@ package com.gmail.nossr50.api; import com.gmail.nossr50.datatypes.interactions.NotificationType; import com.gmail.nossr50.datatypes.party.Party; 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 java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.UUID; import org.bukkit.OfflinePlayer; import org.bukkit.entity.Player; - -import java.util.*; +import org.jetbrains.annotations.Nullable; public final class PartyAPI { - private PartyAPI() {} + private PartyAPI() { + } /** * Get the name of the party a player is in. @@ -24,13 +29,22 @@ public final class PartyAPI { * @return the name of the player's party, or null if not in a party */ public static String getPartyName(Player player) { - if (!inParty(player)) { + if (!mcMMO.p.getPartyConfig().isPartyEnabled() || !inParty(player)) { return null; } return UserManager.getPlayer(player).getParty().getName(); } + /** + * Check if the party system is enabled. + * + * @return true if the party system is enabled, false otherwise + */ + public static boolean isPartySystemEnabled() { + return mcMMO.p.getPartyConfig().isPartyEnabled(); + } + /** * Checks if a player is in a party. *
@@ -40,8 +54,9 @@ public final class PartyAPI { * @return true if the player is in a party, false otherwise */ public static boolean inParty(Player player) { - if(UserManager.getPlayer(player) == null) + if (!mcMMO.p.getPartyConfig().isPartyEnabled() || UserManager.getPlayer(player) == null) { return false; + } return UserManager.getPlayer(player).inParty(); } @@ -51,12 +66,16 @@ public final class PartyAPI { *
* This function is designed for API usage. * - * @param playera The first player to check - * @param playerb The second player to check + * @param playerA The first player to check + * @param playerB The second player to check * @return true if the two players are in the same party, false otherwise */ - public static boolean inSameParty(Player playera, Player playerb) { - return PartyManager.inSameParty(playera, playerb); + public static boolean inSameParty(Player playerA, Player playerB) { + if (!mcMMO.p.getPartyConfig().isPartyEnabled()) { + return false; + } + + return mcMMO.p.getPartyManager().inSameParty(playerA, playerB); } /** @@ -67,7 +86,7 @@ public final class PartyAPI { * @return the list of parties. */ public static List getParties() { - return PartyManager.getParties(); + return mcMMO.p.getPartyManager().getParties(); } /** @@ -81,32 +100,39 @@ public final class PartyAPI { */ @Deprecated public static void addToParty(Player player, String partyName) { - //Check if player profile is loaded - if(UserManager.getPlayer(player) == null) + if (!mcMMO.p.getPartyConfig().isPartyEnabled()) { return; + } - Party party = PartyManager.getParty(partyName); + //Check if player profile is loaded + final McMMOPlayer mmoPlayer = UserManager.getPlayer(player); + + if (mmoPlayer == null) { + return; + } + + Party party = mcMMO.p.getPartyManager().getParty(partyName); if (party == null) { party = new Party(new PartyLeader(player.getUniqueId(), player.getName()), partyName); } else { - if(PartyManager.isPartyFull(player, party)) - { - NotificationManager.sendPlayerInformation(player, NotificationType.PARTY_MESSAGE, "Commands.Party.PartyFull", party.toString()); + if (mcMMO.p.getPartyManager().isPartyFull(player, party)) { + NotificationManager.sendPlayerInformation( + player, NotificationType.PARTY_MESSAGE, + "Commands.Party.PartyFull", party.toString()); return; } } - PartyManager.addToParty(UserManager.getPlayer(player), party); + mcMMO.p.getPartyManager().addToParty(mmoPlayer, party); } /** - * The max party size of the server - * 0 or less for no size limit + * The max party size of the server 0 or less for no size limit + * * @return the max party size on this server */ - public static int getMaxPartySize() - { + public static int getMaxPartySize() { return mcMMO.p.getGeneralConfig().getPartyMaxSize(); } @@ -119,19 +145,19 @@ public final class PartyAPI { * @param partyName The party to add the player to * @param bypassLimit if true bypasses party size limits */ - //TODO: bypasslimit not used? public static void addToParty(Player player, String partyName, boolean bypassLimit) { //Check if player profile is loaded - if(UserManager.getPlayer(player) == null) + if (!mcMMO.p.getPartyConfig().isPartyEnabled() || UserManager.getPlayer(player) == null) { return; + } - Party party = PartyManager.getParty(partyName); + Party party = mcMMO.p.getPartyManager().getParty(partyName); if (party == null) { party = new Party(new PartyLeader(player.getUniqueId(), player.getName()), partyName); } - PartyManager.addToParty(UserManager.getPlayer(player), party); + mcMMO.p.getPartyManager().addToParty(UserManager.getPlayer(player), party); } /** @@ -143,10 +169,11 @@ public final class PartyAPI { */ public static void removeFromParty(Player player) { //Check if player profile is loaded - if(UserManager.getPlayer(player) == null) + if (!mcMMO.p.getPartyConfig().isPartyEnabled() || UserManager.getPlayer(player) == null) { return; + } - PartyManager.removeFromParty(UserManager.getPlayer(player)); + mcMMO.p.getPartyManager().removeFromParty(UserManager.getPlayer(player)); } /** @@ -157,8 +184,12 @@ public final class PartyAPI { * @param partyName The party name * @return the leader of the party */ - public static String getPartyLeader(String partyName) { - return PartyManager.getPartyLeaderName(partyName); + public static @Nullable String getPartyLeader(String partyName) { + if (!mcMMO.p.getPartyConfig().isPartyEnabled()) { + return null; + } + + return mcMMO.p.getPartyManager().getPartyLeaderName(partyName); } /** @@ -171,7 +202,13 @@ public final class PartyAPI { */ @Deprecated public static void setPartyLeader(String partyName, String playerName) { - PartyManager.setPartyLeader(mcMMO.p.getServer().getOfflinePlayer(playerName).getUniqueId(), PartyManager.getParty(partyName)); + if (!mcMMO.p.getPartyConfig().isPartyEnabled()) { + return; + } + + mcMMO.p.getPartyManager().setPartyLeader( + mcMMO.p.getServer().getOfflinePlayer(playerName).getUniqueId(), + mcMMO.p.getPartyManager().getParty(partyName)); } /** @@ -184,9 +221,12 @@ public final class PartyAPI { */ @Deprecated public static List getOnlineAndOfflineMembers(Player player) { - List members = new ArrayList<>(); + if (!mcMMO.p.getPartyConfig().isPartyEnabled()) { + return null; + } - for (UUID memberUniqueId : PartyManager.getAllMembers(player).keySet()) { + final List members = new ArrayList<>(); + for (UUID memberUniqueId : mcMMO.p.getPartyManager().getAllMembers(player).keySet()) { OfflinePlayer member = mcMMO.p.getServer().getOfflinePlayer(memberUniqueId); members.add(member); } @@ -203,7 +243,11 @@ public final class PartyAPI { */ @Deprecated public static LinkedHashSet getMembers(Player player) { - return (LinkedHashSet) PartyManager.getAllMembers(player).values(); + if (!mcMMO.p.getPartyConfig().isPartyEnabled()) { + return null; + } + + return (LinkedHashSet) mcMMO.p.getPartyManager().getAllMembers(player).values(); } /** @@ -215,7 +259,11 @@ public final class PartyAPI { * @return all the player names and uuids in the player's party */ public static LinkedHashMap getMembersMap(Player player) { - return PartyManager.getAllMembers(player); + if (!mcMMO.p.getPartyConfig().isPartyEnabled()) { + return null; + } + + return mcMMO.p.getPartyManager().getAllMembers(player); } /** @@ -227,7 +275,11 @@ public final class PartyAPI { * @return all online players in this party */ public static List getOnlineMembers(String partyName) { - return PartyManager.getOnlineMembers(partyName); + if (!mcMMO.p.getPartyConfig().isPartyEnabled()) { + return null; + } + + return mcMMO.p.getPartyManager().getOnlineMembers(partyName); } /** @@ -239,7 +291,7 @@ public final class PartyAPI { * @return all online players in the player's party */ public static List getOnlineMembers(Player player) { - return PartyManager.getOnlineMembers(player); + return mcMMO.p.getPartyManager().getOnlineMembers(player); } public static boolean hasAlly(String partyName) { @@ -247,7 +299,7 @@ public final class PartyAPI { } public static String getAllyName(String partyName) { - Party ally = PartyManager.getParty(partyName).getAlly(); + Party ally = mcMMO.p.getPartyManager().getParty(partyName).getAlly(); if (ally != null) { return ally.getName(); } diff --git a/src/main/java/com/gmail/nossr50/api/SkillAPI.java b/src/main/java/com/gmail/nossr50/api/SkillAPI.java index be8315a28..df2bee56e 100644 --- a/src/main/java/com/gmail/nossr50/api/SkillAPI.java +++ b/src/main/java/com/gmail/nossr50/api/SkillAPI.java @@ -3,17 +3,16 @@ package com.gmail.nossr50.api; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.skills.SkillTools; - import java.util.ArrayList; import java.util.Arrays; import java.util.List; public final class SkillAPI { - private SkillAPI() {} + private SkillAPI() { + } /** - * Returns a list of strings with mcMMO's skills - * This includes parent and child skills + * Returns a list of strings with mcMMO's skills This includes parent and child skills *
* This function is designed for API usage. * @@ -24,8 +23,7 @@ public final class SkillAPI { } /** - * Returns a list of strings with mcMMO's skills - * This only includes parent skills + * Returns a list of strings with mcMMO's skills This only includes parent skills *
* This function is designed for API usage. * @@ -36,8 +34,7 @@ public final class SkillAPI { } /** - * Returns a list of strings with mcMMO's skills - * This only includes child skills + * Returns a list of strings with mcMMO's skills This only includes child skills *
* This function is designed for API usage. * @@ -48,8 +45,7 @@ public final class SkillAPI { } /** - * Returns a list of strings with mcMMO's skills - * This only includes combat skills + * Returns a list of strings with mcMMO's skills This only includes combat skills *
* This function is designed for API usage. * @@ -60,8 +56,7 @@ public final class SkillAPI { } /** - * Returns a list of strings with mcMMO's skills - * This only includes gathering skills + * Returns a list of strings with mcMMO's skills This only includes gathering skills *
* This function is designed for API usage. * @@ -72,8 +67,7 @@ public final class SkillAPI { } /** - * Returns a list of strings with mcMMO's skills - * This only includes misc skills + * Returns a list of strings with mcMMO's skills This only includes misc skills *
* This function is designed for API usage. * diff --git a/src/main/java/com/gmail/nossr50/api/exceptions/IncompleteNamespacedKeyRegister.java b/src/main/java/com/gmail/nossr50/api/exceptions/IncompleteNamespacedKeyRegister.java index 5bc8b5c9f..c875ecebe 100644 --- a/src/main/java/com/gmail/nossr50/api/exceptions/IncompleteNamespacedKeyRegister.java +++ b/src/main/java/com/gmail/nossr50/api/exceptions/IncompleteNamespacedKeyRegister.java @@ -1,8 +1,10 @@ package com.gmail.nossr50.api.exceptions; +import java.io.Serial; import org.jetbrains.annotations.NotNull; public class IncompleteNamespacedKeyRegister extends RuntimeException { + @Serial private static final long serialVersionUID = -6905157273569301219L; public IncompleteNamespacedKeyRegister(@NotNull String message) { diff --git a/src/main/java/com/gmail/nossr50/api/exceptions/InvalidFormulaTypeException.java b/src/main/java/com/gmail/nossr50/api/exceptions/InvalidFormulaTypeException.java index c46332b99..169150f04 100644 --- a/src/main/java/com/gmail/nossr50/api/exceptions/InvalidFormulaTypeException.java +++ b/src/main/java/com/gmail/nossr50/api/exceptions/InvalidFormulaTypeException.java @@ -1,6 +1,9 @@ package com.gmail.nossr50.api.exceptions; +import java.io.Serial; + public class InvalidFormulaTypeException extends RuntimeException { + @Serial private static final long serialVersionUID = 3368670229490121886L; public InvalidFormulaTypeException() { diff --git a/src/main/java/com/gmail/nossr50/api/exceptions/InvalidPlayerException.java b/src/main/java/com/gmail/nossr50/api/exceptions/InvalidPlayerException.java index 47d065e4a..ed167c4f3 100644 --- a/src/main/java/com/gmail/nossr50/api/exceptions/InvalidPlayerException.java +++ b/src/main/java/com/gmail/nossr50/api/exceptions/InvalidPlayerException.java @@ -1,6 +1,9 @@ package com.gmail.nossr50.api.exceptions; +import java.io.Serial; + public class InvalidPlayerException extends RuntimeException { + @Serial private static final long serialVersionUID = 907213002618581385L; public InvalidPlayerException() { diff --git a/src/main/java/com/gmail/nossr50/api/exceptions/InvalidSkillException.java b/src/main/java/com/gmail/nossr50/api/exceptions/InvalidSkillException.java index de0f847db..ed8e90941 100644 --- a/src/main/java/com/gmail/nossr50/api/exceptions/InvalidSkillException.java +++ b/src/main/java/com/gmail/nossr50/api/exceptions/InvalidSkillException.java @@ -1,6 +1,9 @@ package com.gmail.nossr50.api.exceptions; +import java.io.Serial; + public class InvalidSkillException extends RuntimeException { + @Serial private static final long serialVersionUID = 942705284195791157L; public InvalidSkillException() { diff --git a/src/main/java/com/gmail/nossr50/api/exceptions/InvalidXPGainReasonException.java b/src/main/java/com/gmail/nossr50/api/exceptions/InvalidXPGainReasonException.java index b2c1232b2..aeb4fd0f0 100644 --- a/src/main/java/com/gmail/nossr50/api/exceptions/InvalidXPGainReasonException.java +++ b/src/main/java/com/gmail/nossr50/api/exceptions/InvalidXPGainReasonException.java @@ -1,6 +1,9 @@ package com.gmail.nossr50.api.exceptions; +import java.io.Serial; + public class InvalidXPGainReasonException extends RuntimeException { + @Serial private static final long serialVersionUID = 4427052841957931157L; public InvalidXPGainReasonException() { diff --git a/src/main/java/com/gmail/nossr50/api/exceptions/McMMOPlayerNotFoundException.java b/src/main/java/com/gmail/nossr50/api/exceptions/McMMOPlayerNotFoundException.java index 374c04a9a..e2506ed36 100644 --- a/src/main/java/com/gmail/nossr50/api/exceptions/McMMOPlayerNotFoundException.java +++ b/src/main/java/com/gmail/nossr50/api/exceptions/McMMOPlayerNotFoundException.java @@ -1,12 +1,15 @@ package com.gmail.nossr50.api.exceptions; +import java.io.Serial; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; public class McMMOPlayerNotFoundException extends RuntimeException { + @Serial private static final long serialVersionUID = 761917904993202836L; public McMMOPlayerNotFoundException(@NotNull Player player) { - super("McMMOPlayer object was not found for [NOTE: This can mean the profile is not loaded yet! : " + player.getName() + " " + player.getUniqueId()); + super("McMMOPlayer object was not found for [NOTE: This can mean the profile is not loaded yet! : " + + player.getName() + " " + player.getUniqueId()); } } diff --git a/src/main/java/com/gmail/nossr50/chat/ChatManager.java b/src/main/java/com/gmail/nossr50/chat/ChatManager.java index 658f4dd16..1d4dd5341 100644 --- a/src/main/java/com/gmail/nossr50/chat/ChatManager.java +++ b/src/main/java/com/gmail/nossr50/chat/ChatManager.java @@ -23,7 +23,6 @@ public class ChatManager { private final @NotNull AdminChatMailer adminChatMailer; private final @NotNull PartyChatMailer partyChatMailer; - private final @NotNull ConsoleAuthor consoleAuthor; private final @NotNull Audience consoleAudience; @@ -34,7 +33,8 @@ public class ChatManager { partyChatMailer = new PartyChatMailer(pluginRef); this.consoleAuthor = new ConsoleAuthor(LocaleLoader.getString("Chat.Identity.Console")); - this.consoleAudience = mcMMO.getAudiences().filter((cs) -> cs instanceof ConsoleCommandSender); + this.consoleAudience = mcMMO.getAudiences() + .filter((cs) -> cs instanceof ConsoleCommandSender); this.isChatEnabled = ChatConfig.getInstance().isChatEnabled(); } @@ -45,7 +45,8 @@ public class ChatManager { * @param rawMessage the raw message from the player as it was typed * @param isAsync whether this is getting processed via async */ - public void processPlayerMessage(@NotNull McMMOPlayer mmoPlayer, @NotNull String rawMessage, boolean isAsync) { + public void processPlayerMessage(@NotNull McMMOPlayer mmoPlayer, @NotNull String rawMessage, + boolean isAsync) { processPlayerMessage(mmoPlayer, mmoPlayer.getChatChannel(), rawMessage, isAsync); } @@ -56,7 +57,8 @@ public class ChatManager { * @param args the raw command arguments from the player * @param chatChannel target channel */ - public void processPlayerMessage(@NotNull McMMOPlayer mmoPlayer, @NotNull String[] args, @NotNull ChatChannel chatChannel) { + public void processPlayerMessage(@NotNull McMMOPlayer mmoPlayer, @NotNull String[] args, + @NotNull ChatChannel chatChannel) { String chatMessageWithoutCommand = buildChatMessage(args); //Commands are never async @@ -71,13 +73,20 @@ public class ChatManager { * @param rawMessage raw chat message as it was typed * @param isAsync whether this is getting processed via async */ - private void processPlayerMessage(@NotNull McMMOPlayer mmoPlayer, @NotNull ChatChannel chatChannel, @NotNull String rawMessage, boolean isAsync) { + private void processPlayerMessage(@NotNull McMMOPlayer mmoPlayer, + @NotNull ChatChannel chatChannel, + @NotNull String rawMessage, boolean isAsync) { switch (chatChannel) { case ADMIN: - adminChatMailer.processChatMessage(mmoPlayer.getPlayerAuthor(), rawMessage, isAsync, Permissions.colorChat(mmoPlayer.getPlayer())); + adminChatMailer.processChatMessage( + mmoPlayer.getPlayerAuthor(), rawMessage, isAsync, + Permissions.colorChat(mmoPlayer.getPlayer())); break; case PARTY: - partyChatMailer.processChatMessage(mmoPlayer.getPlayerAuthor(), rawMessage, mmoPlayer.getParty(), isAsync, Permissions.colorChat(mmoPlayer.getPlayer()), Misc.isPartyLeader(mmoPlayer)); + partyChatMailer.processChatMessage( + mmoPlayer.getPlayerAuthor(), rawMessage, mmoPlayer.getParty(), + isAsync, Permissions.colorChat(mmoPlayer.getPlayer()), + Misc.isPartyLeader(mmoPlayer)); break; case PARTY_OFFICER: case NONE: @@ -87,6 +96,7 @@ public class ChatManager { /** * Handles console messaging to admins + * * @param rawMessage raw message from the console */ public void processConsoleMessage(@NotNull String rawMessage) { @@ -95,6 +105,7 @@ public class ChatManager { /** * Handles console messaging to admins + * * @param args raw command args from the console */ public void processConsoleMessage(@NotNull String[] args) { @@ -103,15 +114,18 @@ public class ChatManager { /** * Handles console messaging to a specific party + * * @param rawMessage raw message from the console * @param party target party */ public void processConsoleMessage(@NotNull String rawMessage, @NotNull Party party) { - partyChatMailer.processChatMessage(getConsoleAuthor(), rawMessage, party, false, true, false); + partyChatMailer.processChatMessage(getConsoleAuthor(), rawMessage, party, false, true, + false); } /** * Gets a console author + * * @return a {@link ConsoleAuthor} */ private @NotNull Author getConsoleAuthor() { @@ -119,32 +133,39 @@ public class ChatManager { } /** - * Change the chat channel of a {@link McMMOPlayer} - * Targeting the channel a player is already in will remove that player from the chat channel + * Change the chat channel of a {@link McMMOPlayer} Targeting the channel a player is already in + * will remove that player from the chat channel + * * @param mmoPlayer target player * @param targetChatChannel target chat channel */ - public void setOrToggleChatChannel(@NotNull McMMOPlayer mmoPlayer, @NotNull ChatChannel targetChatChannel) { - if(targetChatChannel == mmoPlayer.getChatChannel()) { + public void setOrToggleChatChannel(@NotNull McMMOPlayer mmoPlayer, + @NotNull ChatChannel targetChatChannel) { + if (targetChatChannel == mmoPlayer.getChatChannel()) { //Disabled message - mmoPlayer.getPlayer().sendMessage(LocaleLoader.getString("Chat.Channel.Off", StringUtils.getCapitalized(targetChatChannel.toString()))); + mmoPlayer.getPlayer().sendMessage(LocaleLoader.getString( + "Chat.Channel.Off", + StringUtils.getCapitalized(targetChatChannel.toString()))); mmoPlayer.setChatMode(ChatChannel.NONE); } else { mmoPlayer.setChatMode(targetChatChannel); - mmoPlayer.getPlayer().sendMessage(LocaleLoader.getString("Chat.Channel.On", StringUtils.getCapitalized(targetChatChannel.toString()))); + mmoPlayer.getPlayer().sendMessage(LocaleLoader.getString( + "Chat.Channel.On", + StringUtils.getCapitalized(targetChatChannel.toString()))); } } /** * Create a chat message from an array of {@link String} + * * @param args array of {@link String} * @return a String built from the array */ private @NotNull String buildChatMessage(@NotNull String[] args) { StringBuilder stringBuilder = new StringBuilder(); - for(int i = 0; i < args.length; i++) { - if(i + 1 >= args.length) { + for (int i = 0; i < args.length; i++) { + if (i + 1 >= args.length) { stringBuilder.append(args[i]); } else { stringBuilder.append(args[i]).append(" "); @@ -156,18 +177,19 @@ public class ChatManager { /** * 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 */ public boolean isMessageAllowed(@NotNull McMMOPlayer mmoPlayer) { switch (mmoPlayer.getChatChannel()) { case ADMIN: - if(mmoPlayer.getPlayer().isOp() || Permissions.adminChat(mmoPlayer.getPlayer())) { + if (mmoPlayer.getPlayer().isOp() || Permissions.adminChat(mmoPlayer.getPlayer())) { return true; } break; case PARTY: - if(mmoPlayer.getParty() != null && Permissions.partyChat(mmoPlayer.getPlayer())) { + if (mmoPlayer.getParty() != null && Permissions.partyChat(mmoPlayer.getPlayer())) { return true; } break; @@ -181,6 +203,7 @@ public class ChatManager { /** * Sends just the console a message + * * @param author author of the message * @param message message contents in component form */ @@ -190,6 +213,7 @@ public class ChatManager { /** * Whether the mcMMO chat system which handles party and admin chat is enabled or disabled + * * @return true if mcMMO chat processing (for party/admin chat) is enabled */ public boolean isChatEnabled() { @@ -197,28 +221,23 @@ public class ChatManager { } /** - * Whether a specific chat channel is enabled - * ChatChannels are enabled/disabled via user config + * Whether a specific chat channel is enabled ChatChannels are enabled/disabled via user config + *

+ * If chat is disabled, this always returns false If NONE is passed as a {@link ChatChannel} it + * will return true * - * If chat is disabled, this always returns false - * If NONE is passed as a {@link ChatChannel} it will return true * @param chatChannel target chat channel * @return true if the chat channel is enabled */ public boolean isChatChannelEnabled(@NotNull ChatChannel chatChannel) { - if(!isChatEnabled) { + if (!isChatEnabled) { return false; } else { - switch(chatChannel) { - case ADMIN: - case PARTY: - case PARTY_OFFICER: - return ChatConfig.getInstance().isChatChannelEnabled(chatChannel); - case NONE: - return true; - default: - return false; - } + return switch (chatChannel) { + case ADMIN, PARTY, PARTY_OFFICER -> + ChatConfig.getInstance().isChatChannelEnabled(chatChannel); + case NONE -> true; + }; } } diff --git a/src/main/java/com/gmail/nossr50/chat/SamePartyPredicate.java b/src/main/java/com/gmail/nossr50/chat/SamePartyPredicate.java index 226eab83d..055310504 100644 --- a/src/main/java/com/gmail/nossr50/chat/SamePartyPredicate.java +++ b/src/main/java/com/gmail/nossr50/chat/SamePartyPredicate.java @@ -3,12 +3,11 @@ package com.gmail.nossr50.chat; import com.gmail.nossr50.datatypes.party.Party; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.util.player.UserManager; +import java.util.function.Predicate; import org.bukkit.command.CommandSender; import org.bukkit.command.ConsoleCommandSender; import org.bukkit.entity.Player; -import java.util.function.Predicate; - public class SamePartyPredicate implements Predicate { final Party party; @@ -20,13 +19,15 @@ public class SamePartyPredicate implements Predicate @Override public boolean test(T t) { //Include the console in the audience - if(t instanceof ConsoleCommandSender) { - return false; //Party audiences are special, we exclude console from them to avoid double messaging since we send a more verbose version to consoles + if (t instanceof ConsoleCommandSender) { + //Party audiences are special, we exclude console from them to avoid double + // messaging since we send a more verbose version to consoles + return false; } else { - if(t instanceof Player player) { - McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player); - if(mcMMOPlayer != null) { - return mcMMOPlayer.getParty() == party; + if (t instanceof Player player) { + final McMMOPlayer mmoPlayer = UserManager.getPlayer(player); + if (mmoPlayer != null) { + return mmoPlayer.getParty() == party; } } } 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 eb606af6d..d1b4299c1 100644 --- a/src/main/java/com/gmail/nossr50/chat/author/AbstractPlayerAuthor.java +++ b/src/main/java/com/gmail/nossr50/chat/author/AbstractPlayerAuthor.java @@ -3,17 +3,17 @@ package com.gmail.nossr50.chat.author; import com.gmail.nossr50.datatypes.chat.ChatChannel; import com.gmail.nossr50.util.text.TextUtils; import com.google.common.base.Objects; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; import org.bukkit.entity.Player; import org.checkerframework.checker.nullness.qual.NonNull; import org.jetbrains.annotations.NotNull; -import java.util.HashMap; -import java.util.UUID; - public abstract class AbstractPlayerAuthor implements Author { private final @NotNull Player player; + private final @NotNull Map sanitizedNameCache; private @NotNull String lastKnownDisplayName; - private final @NotNull HashMap sanitizedNameCache; public AbstractPlayerAuthor(@NotNull Player player) { this.player = player; @@ -31,32 +31,34 @@ public abstract class AbstractPlayerAuthor implements Author { } /** - * Player display names can change and this method will update the last known display name of this player + * Player display names can change and this method will update the last known display name of + * this player */ private void updateLastKnownDisplayName() { lastKnownDisplayName = player.getDisplayName(); } /** - * Gets a sanitized name for a channel - * Sanitized names are names that are friendly to the {@link net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer} - * Sanitized names for authors are cached by channel and are only created as needed - * Sanitized names will update if a players display name has updated + * Gets a sanitized name for a channel Sanitized names are names that are friendly to the + * {@link net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer} Sanitized names + * for authors are cached by channel and are only created as needed Sanitized names will update + * if a players display name has updated * * @param chatChannel target chat channel * @return the sanitized name for a player */ - protected @NotNull String getSanitizedName(@NotNull ChatChannel chatChannel, boolean useDisplayName) { + protected @NotNull String getSanitizedName(@NotNull ChatChannel chatChannel, + boolean useDisplayName) { //Already in cache - if(sanitizedNameCache.containsKey(chatChannel)) { + if (sanitizedNameCache.containsKey(chatChannel)) { //Update cache - if(useDisplayName && hasPlayerDisplayNameChanged()) { + if (useDisplayName && hasPlayerDisplayNameChanged()) { updateLastKnownDisplayName(); updateSanitizedNameCache(chatChannel, true); } } else { //Update last known display name - if(useDisplayName && hasPlayerDisplayNameChanged()) { + if (useDisplayName && hasPlayerDisplayNameChanged()) { updateLastKnownDisplayName(); } @@ -68,16 +70,18 @@ public abstract class AbstractPlayerAuthor implements Author { } /** - * Update the sanitized name cache - * This will add entries if one didn't exit - * Sanitized names are associated with a {@link ChatChannel} as different chat channels have different chat name settings + * Update the sanitized name cache This will add entries if one didn't exit 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 to use this authors display name */ - private void updateSanitizedNameCache(@NotNull ChatChannel chatChannel, boolean useDisplayName) { - if(useDisplayName) { - sanitizedNameCache.put(chatChannel, TextUtils.sanitizeForSerializer(player.getDisplayName())); + private void updateSanitizedNameCache(@NotNull ChatChannel chatChannel, + boolean useDisplayName) { + if (useDisplayName) { + sanitizedNameCache.put(chatChannel, + TextUtils.sanitizeForSerializer(player.getDisplayName())); } else { //No need to sanitize a basic String sanitizedNameCache.put(chatChannel, player.getName()); @@ -105,12 +109,17 @@ public abstract class AbstractPlayerAuthor implements Author { @Override public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } AbstractPlayerAuthor that = (AbstractPlayerAuthor) o; - return Objects.equal(player, that.player) && - Objects.equal(lastKnownDisplayName, that.lastKnownDisplayName) && - Objects.equal(sanitizedNameCache, that.sanitizedNameCache); + return Objects.equal(player, that.player) && Objects.equal( + lastKnownDisplayName, + that.lastKnownDisplayName) && Objects.equal( + sanitizedNameCache, that.sanitizedNameCache); } @Override 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 c7c35b7e2..feec3d257 100644 --- a/src/main/java/com/gmail/nossr50/chat/author/Author.java +++ b/src/main/java/com/gmail/nossr50/chat/author/Author.java @@ -7,9 +7,9 @@ import org.jetbrains.annotations.NotNull; public interface Author extends Identity { /** - * The name of this author as used in mcMMO chat - * This is the {@link String} representation of the users current chat username - * This can either be the player's display name or the player's official registered nickname with Mojang it depends on the servers chat settings for mcMMO + * The name of this author as used in mcMMO chat This is the {@link String} representation of + * the users current chat username This can either be the player's display name or the player's + * official registered nickname with Mojang it depends on the servers chat settings for mcMMO * * @param chatChannel which chat channel this is going to * @return The name of this author as used in mcMMO chat @@ -25,6 +25,7 @@ public interface Author extends Identity { /** * 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/author/ConsoleAuthor.java b/src/main/java/com/gmail/nossr50/chat/author/ConsoleAuthor.java index 3c6452d32..24bb0cd6e 100644 --- a/src/main/java/com/gmail/nossr50/chat/author/ConsoleAuthor.java +++ b/src/main/java/com/gmail/nossr50/chat/author/ConsoleAuthor.java @@ -2,11 +2,10 @@ package com.gmail.nossr50.chat.author; import com.gmail.nossr50.datatypes.chat.ChatChannel; import com.gmail.nossr50.util.text.TextUtils; +import java.util.UUID; import org.checkerframework.checker.nullness.qual.NonNull; import org.jetbrains.annotations.NotNull; -import java.util.UUID; - public class ConsoleAuthor implements Author { private final UUID uuid; private final @NotNull String name; 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 f798f5d47..a9bc7dc9d 100644 --- a/src/main/java/com/gmail/nossr50/chat/mailer/AdminChatMailer.java +++ b/src/main/java/com/gmail/nossr50/chat/mailer/AdminChatMailer.java @@ -3,12 +3,14 @@ package com.gmail.nossr50.chat.mailer; 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; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.text.TextUtils; +import java.util.function.Predicate; import net.kyori.adventure.audience.Audience; import net.kyori.adventure.text.TextComponent; import org.bukkit.Bukkit; @@ -17,16 +19,14 @@ import org.bukkit.command.ConsoleCommandSender; import org.bukkit.plugin.Plugin; import org.jetbrains.annotations.NotNull; -import java.util.function.Predicate; - public class AdminChatMailer extends AbstractChatMailer { + public static final @NotNull String MCMMO_CHAT_ADMINCHAT_PERMISSION = "mcmmo.chat.adminchat"; + public AdminChatMailer(Plugin pluginRef) { super(pluginRef); } - public static final @NotNull String MCMMO_CHAT_ADMINCHAT_PERMISSION = "mcmmo.chat.adminchat"; - /** * Constructs an audience of admins * @@ -42,9 +42,10 @@ public class AdminChatMailer extends AbstractChatMailer { * @return admin chat audience predicate */ public @NotNull Predicate predicate() { - return (commandSender) -> commandSender.isOp() - || commandSender.hasPermission(MCMMO_CHAT_ADMINCHAT_PERMISSION) - || commandSender instanceof ConsoleCommandSender; + return (commandSender) -> commandSender.isOp() || commandSender.hasPermission( + MCMMO_CHAT_ADMINCHAT_PERMISSION) || ( + ChatConfig.getInstance().isConsoleIncludedInAudience( + ChatChannel.ADMIN) && commandSender instanceof ConsoleCommandSender); } /** @@ -55,11 +56,16 @@ public class AdminChatMailer extends AbstractChatMailer { * @param canColor whether to replace colors codes with colors in the raw message * @return the styled string, based on a locale entry */ - public @NotNull TextComponent addStyle(@NotNull Author author, @NotNull String message, boolean canColor) { - if(canColor) { - return LocaleLoader.getTextComponent("Chat.Style.Admin", author.getAuthoredName(ChatChannel.ADMIN), message); + public @NotNull TextComponent addStyle(@NotNull Author author, @NotNull String message, + boolean canColor) { + if (canColor) { + return LocaleLoader.getTextComponent( + "Chat.Style.Admin", author.getAuthoredName(ChatChannel.ADMIN), + message); } else { - return TextUtils.ofLegacyTextRaw(LocaleLoader.getString("Chat.Style.Admin", author.getAuthoredName(ChatChannel.ADMIN), message)); + return TextUtils.ofLegacyTextRaw( + LocaleLoader.getString("Chat.Style.Admin", + author.getAuthoredName(ChatChannel.ADMIN), message)); } } @@ -76,13 +82,17 @@ public class AdminChatMailer extends AbstractChatMailer { * @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)); + 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)); McMMOChatEvent chatEvent = new McMMOAdminChatEvent(pluginRef, chatMessage, isAsync); Bukkit.getPluginManager().callEvent(chatEvent); - if(!chatEvent.isCancelled()) { + if (!chatEvent.isCancelled()) { sendMail(chatMessage); } } diff --git a/src/main/java/com/gmail/nossr50/chat/mailer/ChatMailer.java b/src/main/java/com/gmail/nossr50/chat/mailer/ChatMailer.java index 77d456b6f..bbd3d9e0c 100644 --- a/src/main/java/com/gmail/nossr50/chat/mailer/ChatMailer.java +++ b/src/main/java/com/gmail/nossr50/chat/mailer/ChatMailer.java @@ -6,6 +6,7 @@ import org.jetbrains.annotations.NotNull; public interface ChatMailer { /** * Send out a chat message + * * @param chatMessage the {@link ChatMessage} */ void sendMail(@NotNull ChatMessage chatMessage); 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 ad8d8992d..34bc560f1 100644 --- a/src/main/java/com/gmail/nossr50/chat/mailer/PartyChatMailer.java +++ b/src/main/java/com/gmail/nossr50/chat/mailer/PartyChatMailer.java @@ -30,13 +30,17 @@ public class PartyChatMailer extends AbstractChatMailer { * @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); + 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); McMMOChatEvent chatEvent = new McMMOPartyChatEvent(pluginRef, chatMessage, party, isAsync); Bukkit.getPluginManager().callEvent(chatEvent); - if(!chatEvent.isCancelled()) { + if (!chatEvent.isCancelled()) { sendMail(chatMessage); } } @@ -59,18 +63,29 @@ public class PartyChatMailer extends AbstractChatMailer { * @param canColor whether to replace colors codes with colors in the raw message * @return the styled string, based on a locale entry */ - public @NotNull TextComponent addStyle(@NotNull Author author, @NotNull String message, boolean canColor, boolean isLeader) { - if(canColor) { - if(isLeader) { - return LocaleLoader.getTextComponent("Chat.Style.Party.Leader", author.getAuthoredName(ChatChannel.PARTY), message); + public @NotNull TextComponent addStyle(@NotNull Author author, @NotNull String message, + boolean canColor, + boolean isLeader) { + if (canColor) { + if (isLeader) { + return LocaleLoader.getTextComponent( + "Chat.Style.Party.Leader", + author.getAuthoredName(ChatChannel.PARTY), message); } else { - return LocaleLoader.getTextComponent("Chat.Style.Party", author.getAuthoredName(ChatChannel.PARTY), message); + return LocaleLoader.getTextComponent( + "Chat.Style.Party", author.getAuthoredName(ChatChannel.PARTY), + message); } } else { - if(isLeader) { - return TextUtils.ofLegacyTextRaw(LocaleLoader.getString("Chat.Style.Party.Leader", author.getAuthoredName(ChatChannel.PARTY), message)); + if (isLeader) { + return TextUtils.ofLegacyTextRaw( + LocaleLoader.getString( + "Chat.Style.Party.Leader", + author.getAuthoredName(ChatChannel.PARTY), message)); } else { - return TextUtils.ofLegacyTextRaw(LocaleLoader.getString("Chat.Style.Party", author.getAuthoredName(ChatChannel.PARTY), message)); + return TextUtils.ofLegacyTextRaw( + LocaleLoader.getString("Chat.Style.Party", + author.getAuthoredName(ChatChannel.PARTY), message)); } } } diff --git a/src/main/java/com/gmail/nossr50/chat/message/AbstractChatMessage.java b/src/main/java/com/gmail/nossr50/chat/message/AbstractChatMessage.java index 5eeb889e4..a1269c334 100644 --- a/src/main/java/com/gmail/nossr50/chat/message/AbstractChatMessage.java +++ b/src/main/java/com/gmail/nossr50/chat/message/AbstractChatMessage.java @@ -15,7 +15,9 @@ public abstract class AbstractChatMessage implements ChatMessage { protected @NotNull TextComponent componentMessage; protected @NotNull Audience audience; - public AbstractChatMessage(@NotNull Plugin pluginRef, @NotNull Author author, @NotNull Audience audience, @NotNull String rawMessage, @NotNull TextComponent componentMessage) { + public AbstractChatMessage(@NotNull Plugin pluginRef, @NotNull Author author, + @NotNull Audience audience, + @NotNull String rawMessage, @NotNull TextComponent componentMessage) { this.pluginRef = pluginRef; this.author = author; this.audience = audience; @@ -38,6 +40,11 @@ public abstract class AbstractChatMessage implements ChatMessage { return audience; } + @Override + public void setAudience(@NotNull Audience newAudience) { + audience = newAudience; + } + @Override public @NotNull TextComponent getChatMessage() { return componentMessage; @@ -48,21 +55,20 @@ public abstract class AbstractChatMessage implements ChatMessage { this.componentMessage = textComponent; } - @Override - public void setAudience(@NotNull Audience newAudience) { - audience = newAudience; - } - @Override public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } AbstractChatMessage that = (AbstractChatMessage) o; - return Objects.equal(pluginRef, that.pluginRef) && - Objects.equal(author, that.author) && - Objects.equal(rawMessage, that.rawMessage) && - Objects.equal(componentMessage, that.componentMessage) && - Objects.equal(audience, that.audience); + return Objects.equal(pluginRef, that.pluginRef) && Objects.equal(author, that.author) + && Objects.equal( + rawMessage, that.rawMessage) && Objects.equal(componentMessage, + that.componentMessage) && Objects.equal( + audience, that.audience); } @Override diff --git a/src/main/java/com/gmail/nossr50/chat/message/AdminChatMessage.java b/src/main/java/com/gmail/nossr50/chat/message/AdminChatMessage.java index 973c0f0c7..1daca02f0 100644 --- a/src/main/java/com/gmail/nossr50/chat/message/AdminChatMessage.java +++ b/src/main/java/com/gmail/nossr50/chat/message/AdminChatMessage.java @@ -8,7 +8,9 @@ import org.bukkit.plugin.Plugin; import org.jetbrains.annotations.NotNull; public class AdminChatMessage extends AbstractChatMessage { - public AdminChatMessage(@NotNull Plugin pluginRef, @NotNull Author author, @NotNull Audience audience, @NotNull String rawMessage, @NotNull TextComponent componentMessage) { + public AdminChatMessage(@NotNull Plugin pluginRef, @NotNull Author author, + @NotNull Audience audience, + @NotNull String rawMessage, @NotNull TextComponent componentMessage) { super(pluginRef, author, audience, rawMessage, componentMessage); } diff --git a/src/main/java/com/gmail/nossr50/chat/message/ChatMessage.java b/src/main/java/com/gmail/nossr50/chat/message/ChatMessage.java index 45bc1ac18..3bcabdd3c 100644 --- a/src/main/java/com/gmail/nossr50/chat/message/ChatMessage.java +++ b/src/main/java/com/gmail/nossr50/chat/message/ChatMessage.java @@ -7,8 +7,8 @@ import org.jetbrains.annotations.NotNull; public interface ChatMessage { /** - * The original message from the {@link Author} - * This is formatted and styled before being sent out to players by mcMMO + * The original message from the {@link Author} This is formatted and styled before being sent + * out to players by mcMMO * * @return the original message without any formatting or alterations * @see #getChatMessage() @@ -18,33 +18,42 @@ public interface ChatMessage { /** * The {@link Author} from which this payload originated * - * @see #getChatMessage() * @return the source of the chat message + * @see #getChatMessage() */ @NotNull Author getAuthor(); /** - * The authors display name which is used in the initial creation of the message payload, it is provided for convenience. - * + * The authors display name which is used in the initial creation of the message payload, it is + * provided for convenience. + *

* This is a name generated by mcMMO during the creation of the {@link ChatMessage} - * + *

* This is used by mcMMO when generating the message payload + *

+ * This method provides the display name for the convenience of plugins constructing their own + * {@link TextComponent payloads} * - * This method provides the display name for the convenience of plugins constructing their own {@link TextComponent payloads} - * - * @see #getChatMessage() * @return the author display name as generated by mcMMO + * @see #getChatMessage() */ @NotNull String getAuthorDisplayName(); /** - * The target audience of this chat message - * Unless modified, this will include the {@link Author} + * The target audience of this chat message Unless modified, this will include the + * {@link Author} * * @return target audience */ @NotNull Audience getAudience(); + /** + * Changes the audience + * + * @param newAudience the replacement audience + */ + void setAudience(@NotNull Audience newAudience); + /** * The {@link TextComponent message} being sent to the audience * @@ -59,13 +68,6 @@ public interface ChatMessage { */ void setChatMessage(@NotNull TextComponent textComponent); - /** - * Changes the audience - * - * @param newAudience the replacement audience - */ - void setAudience(@NotNull Audience newAudience); - /** * Deliver the message to the audience */ 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 4c143ec69..5bbee66d1 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; @@ -18,13 +19,17 @@ public class PartyChatMessage extends AbstractChatMessage { private final @NotNull Party party; - public PartyChatMessage(@NotNull Plugin pluginRef, @NotNull Author author, @NotNull Audience audience, @NotNull String rawMessage, @NotNull TextComponent componentMessage, @NotNull Party party) { + public PartyChatMessage(@NotNull Plugin pluginRef, @NotNull Author author, + @NotNull Audience audience, + @NotNull String rawMessage, @NotNull TextComponent componentMessage, + @NotNull Party party) { super(pluginRef, author, audience, rawMessage, componentMessage); this.party = party; } /** * The party that this chat message was intended for + * * @return the party that this message was intended for */ public @NotNull Party getParty() { @@ -45,31 +50,36 @@ public class PartyChatMessage extends AbstractChatMessage { //Sends to everyone but console audience.sendMessage(author, componentMessage); - TextComponent spyMessage = LocaleLoader.getTextComponent("Chat.Spy.Party", author.getAuthoredName(ChatChannel.PARTY), rawMessage, party.getName()); + final TextComponent spyMessage = LocaleLoader.getTextComponent( + "Chat.Spy.Party", + author.getAuthoredName(ChatChannel.PARTY), rawMessage, party.getName()); //Relay to spies messagePartyChatSpies(spyMessage); //Console message - mcMMO.p.getChatManager().sendConsoleMessage(author, spyMessage); + if (ChatConfig.getInstance().isConsoleIncludedInAudience(ChatChannel.PARTY)) { + mcMMO.p.getChatManager().sendConsoleMessage(author, spyMessage); + } } /** - * Console and Party Chat Spies get a more verbose version of the message - * Party Chat Spies will get a copy of the message as well + * Console and Party Chat Spies get a more verbose version of the message Party Chat Spies will + * get a copy of the message as well + * * @param spyMessage the message to copy to spies */ private void messagePartyChatSpies(@NotNull TextComponent spyMessage) { //Find the people with permissions - for(McMMOPlayer mcMMOPlayer : UserManager.getPlayers()) { - Player player = mcMMOPlayer.getPlayer(); + for (McMMOPlayer mmoPlayer : UserManager.getPlayers()) { + final Player player = mmoPlayer.getPlayer(); //Check for toggled players - if(mcMMOPlayer.isPartyChatSpying()) { - Party adminParty = mcMMOPlayer.getParty(); + if (mmoPlayer.isPartyChatSpying()) { + Party adminParty = mmoPlayer.getParty(); //Only message admins not part of this party - if(adminParty == null || adminParty != getParty()) { + if (adminParty == null || adminParty != getParty()) { //TODO: Hacky, rewrite later Audience audience = mcMMO.getAudiences().player(player); audience.sendMessage(spyMessage); @@ -80,10 +90,16 @@ public class PartyChatMessage extends AbstractChatMessage { @Override public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - if (!super.equals(o)) return false; - PartyChatMessage that = (PartyChatMessage) o; + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + if (!super.equals(o)) { + return false; + } + final PartyChatMessage that = (PartyChatMessage) o; return Objects.equal(party, that.party); } diff --git a/src/main/java/com/gmail/nossr50/commands/CommandManager.java b/src/main/java/com/gmail/nossr50/commands/CommandManager.java index ea72fc2f9..fbb7cf445 100644 --- a/src/main/java/com/gmail/nossr50/commands/CommandManager.java +++ b/src/main/java/com/gmail/nossr50/commands/CommandManager.java @@ -5,6 +5,7 @@ import co.aikar.commands.BukkitCommandManager; 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.datatypes.chat.ChatChannel; import com.gmail.nossr50.datatypes.player.McMMOPlayer; @@ -20,9 +21,14 @@ import org.jetbrains.annotations.NotNull; * 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,29 +42,56 @@ public class CommandManager { } private void registerCommands() { + registerSkillCommands(); //TODO: Implement other skills not just power level registerChatCommands(); } + private void registerSkillCommands() { + if (mcMMO.p.getGeneralConfig().isMasterySystemEnabled()) { + bukkitCommandManager.registerCommand(new PowerLevelCommand(pluginRef)); + } + } + /** * Registers chat commands if the chat system is enabled */ private void registerChatCommands() { - if(ChatConfig.getInstance().isChatEnabled()) { - if(ChatConfig.getInstance().isChatChannelEnabled(ChatChannel.ADMIN)) { + if (ChatConfig.getInstance().isChatEnabled()) { + if (ChatConfig.getInstance().isChatChannelEnabled(ChatChannel.ADMIN)) { bukkitCommandManager.registerCommand(new AdminChatCommand(pluginRef)); } - if(ChatConfig.getInstance().isChatChannelEnabled(ChatChannel.PARTY)) { + if (pluginRef.getPartyConfig().isPartyEnabled() && ChatConfig.getInstance() + .isChatChannelEnabled(ChatChannel.PARTY)) { bukkitCommandManager.registerCommand(new PartyChatCommand(pluginRef)); } } } 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(); - if(issuer.getIssuer() instanceof Player) { + if (issuer.getIssuer() instanceof Player) { validateLoadedData(issuer.getPlayer()); validateAdmin(issuer.getPlayer()); } @@ -67,7 +100,7 @@ public class CommandManager { bukkitCommandManager.getCommandConditions().addCondition(MMO_DATA_LOADED, (context) -> { BukkitCommandIssuer bukkitCommandIssuer = context.getIssuer(); - if(bukkitCommandIssuer.getIssuer() instanceof Player) { + if (bukkitCommandIssuer.getIssuer() instanceof Player) { validateLoadedData(bukkitCommandIssuer.getPlayer()); } }); @@ -75,37 +108,40 @@ public class CommandManager { bukkitCommandManager.getCommandConditions().addCondition(PARTY_CONDITION, (context) -> { BukkitCommandIssuer bukkitCommandIssuer = context.getIssuer(); - if(bukkitCommandIssuer.getIssuer() instanceof Player) { + 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()); } }); } - private void validatePermission(@NotNull String permissionNode, @NotNull Permissible permissible) { - if(!permissible.hasPermission(permissionNode)) { + private void validatePermission(@NotNull String permissionNode, + @NotNull Permissible permissible) { + if (!permissible.hasPermission(permissionNode)) { throw new ConditionFailedException(LocaleLoader.getString("mcMMO.NoPermission")); } } public void validateAdmin(@NotNull Player player) { - if(!player.isOp() && !Permissions.adminChat(player)) { - throw new ConditionFailedException("You are lacking the correct permissions to use this command."); + if (!player.isOp() && !Permissions.adminChat(player)) { + throw new ConditionFailedException( + "You are lacking the correct permissions to use this command."); } } public void validateLoadedData(@NotNull Player player) { - if(UserManager.getPlayer(player) == null) { + if (UserManager.getPlayer(player) == null) { throw new ConditionFailedException(LocaleLoader.getString("Profile.PendingLoad")); } } public void validatePlayerParty(@NotNull Player player) { - McMMOPlayer mmoPlayer = UserManager.getPlayer(player); + final McMMOPlayer mmoPlayer = UserManager.getPlayer(player); - if(mmoPlayer.getParty() == null) { + if (!pluginRef.getPartyConfig().isPartyEnabled() || mmoPlayer.getParty() == null) { throw new ConditionFailedException(LocaleLoader.getString("Commands.Party.None")); } } diff --git a/src/main/java/com/gmail/nossr50/commands/McImportCommand.java b/src/main/java/com/gmail/nossr50/commands/McImportCommand.java deleted file mode 100644 index 3c913ea47..000000000 --- a/src/main/java/com/gmail/nossr50/commands/McImportCommand.java +++ /dev/null @@ -1,336 +0,0 @@ -package com.gmail.nossr50.commands; - -import com.gmail.nossr50.datatypes.skills.ModConfigType; -import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.util.Misc; -import org.bukkit.Material; -import org.bukkit.command.Command; -import org.bukkit.command.CommandExecutor; -import org.bukkit.command.CommandSender; -import org.jetbrains.annotations.NotNull; - -import java.io.*; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Locale; - -public class McImportCommand implements CommandExecutor { - int fileAmount; - - @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { - if (args.length == 0) { - importModConfig(); - return true; - } - return false; - } - - public boolean importModConfig() { - String importFilePath = mcMMO.getModDirectory() + File.separator + "import"; - File importFile = new File(importFilePath, "import.log"); - mcMMO.p.getLogger().info("Starting import of mod materials..."); - fileAmount = 0; - - HashMap> materialNames = new HashMap<>(); - - BufferedReader in = null; - - try { - // Open the file - in = new BufferedReader(new FileReader(importFile)); - - String line; - String materialName; - String modName; - - // While not at the end of the file - while ((line = in.readLine()) != null) { - String[] split1 = line.split("material "); - - if (split1.length != 2) { - continue; - } - - String[] split2 = split1[1].split(" with"); - - if (split2.length != 2) { - continue; - } - - materialName = split2[0]; - - // Categorise each material under a mod config type - ModConfigType type = ModConfigType.getModConfigType(materialName); - - if (!materialNames.containsKey(type)) { - materialNames.put(type, new ArrayList<>()); - } - - materialNames.get(type).add(materialName); - } - } - catch (FileNotFoundException e) { - mcMMO.p.getLogger().warning("Could not find " + importFile.getAbsolutePath() + " ! (No such file or directory)"); - mcMMO.p.getLogger().warning("Copy and paste latest.log to " + importFile.getParentFile().getAbsolutePath() + " and rename it to import.log"); - return false; - } - catch (Exception e) { - e.printStackTrace(); - return false; - } - finally { - tryClose(in); - } - - createOutput(materialNames); - - mcMMO.p.getLogger().info("Import finished! Created " + fileAmount + " files!"); - return true; - } - - private void createOutput(HashMap> materialNames) { - for (ModConfigType modConfigType : materialNames.keySet()) { - HashMap> materialNamesType = new HashMap<>(); - - for (String materialName : materialNames.get(modConfigType)) { - String modName = Misc.getModName(materialName); - - if (!materialNamesType.containsKey(modName)) { - materialNamesType.put(modName, new ArrayList<>()); - } - - materialNamesType.get(modName).add(materialName); - } - - createOutput(modConfigType, materialNamesType); - } - - } - - private void tryClose(Closeable c) { - if (c == null) { - return; - } - try { - c.close(); - } - catch (IOException e) { - e.printStackTrace(); - } - } - - private void createOutput(ModConfigType modConfigType, HashMap> materialNames) { - File outputFilePath = new File(mcMMO.getModDirectory() + File.separator + "output"); - if (!outputFilePath.exists() && !outputFilePath.mkdirs()) { - mcMMO.p.getLogger().severe("Could not create output directory! " + outputFilePath.getAbsolutePath()); - } - - FileWriter out = null; - String type = modConfigType.name().toLowerCase(Locale.ENGLISH); - - for (String modName : materialNames.keySet()) { - File outputFile = new File(outputFilePath, modName + "." + type + ".yml"); - mcMMO.p.getLogger().info("Creating " + outputFile.getName()); - try { - if (outputFile.exists() && !outputFile.delete()) { - mcMMO.p.getLogger().severe("Not able to delete old output file! " + outputFile.getAbsolutePath()); - } - - if (!outputFile.createNewFile()) { - mcMMO.p.getLogger().severe("Could not create output file! " + outputFile.getAbsolutePath()); - continue; - } - - StringBuilder writer = new StringBuilder(); - HashMap> configSections = getConfigSections(modConfigType, modName, materialNames); - - if (configSections == null) { - mcMMO.p.getLogger().severe("Something went wrong!! type is " + type); - return; - } - - // Write the file, go through each skill and write all the materials - for (String configSection : configSections.keySet()) { - if (configSection.equals("UNIDENTIFIED")) { - writer.append("# This isn't a valid config section and all materials in this category need to be").append("\r\n"); - writer.append("# copy and pasted to a valid section of this config file.").append("\r\n"); - } - writer.append(configSection).append(":").append("\r\n"); - - for (String line : configSections.get(configSection)) { - writer.append(line).append("\r\n"); - } - - writer.append("\r\n"); - } - - out = new FileWriter(outputFile); - out.write(writer.toString()); - } catch (Exception e) { - e.printStackTrace(); - return; - } finally { - tryClose(out); - fileAmount++; - } - } - } - - private HashMap> getConfigSections(ModConfigType type, String modName, HashMap> materialNames) { - switch (type) { - case BLOCKS: - return getConfigSectionsBlocks(modName, materialNames); - case TOOLS: - return getConfigSectionsTools(modName, materialNames); - case ARMOR: - return getConfigSectionsArmor(modName, materialNames); - case UNKNOWN: - return getConfigSectionsUnknown(modName, materialNames); - } - - return null; - } - - private HashMap> getConfigSectionsBlocks(String modName, HashMap> materialNames) { - HashMap> configSections = new HashMap<>(); - - // Go through all the materials and categorise them under a skill - for (String materialName : materialNames.get(modName)) { - String skillName = "UNIDENTIFIED"; - if (materialName.contains("ORE")) { - skillName = "Mining"; - } - else if (materialName.contains("LOG") || materialName.contains("LEAVES")) { - skillName = "Woodcutting"; - } - else if (materialName.contains("GRASS") || materialName.contains("SHORT_GRASS") || materialName.contains("FLOWER") || materialName.contains("CROP")) { - skillName = "Herbalism"; - } - else if (materialName.contains("DIRT") || materialName.contains("SAND")) { - skillName = "Excavation"; - } - - if (!configSections.containsKey(skillName)) { - configSections.put(skillName, new ArrayList<>()); - } - - ArrayList skillContents = configSections.get(skillName); - skillContents.add(" " + materialName + "|0:"); - skillContents.add(" " + " " + "XP_Gain: 99"); - skillContents.add(" " + " " + "Double_Drops_Enabled: true"); - - if (skillName.equals("Mining")) { - skillContents.add(" " + " " + "Smelting_XP_Gain: 9"); - } - else if (skillName.equals("Woodcutting")) { - skillContents.add(" " + " " + "Is_Log: " + materialName.contains("LOG")); - } - } - - return configSections; - } - - private HashMap> getConfigSectionsTools(String modName, HashMap> materialNames) { - HashMap> configSections = new HashMap<>(); - - // Go through all the materials and categorise them under a tool type - for (String materialName : materialNames.get(modName)) { - String toolType = "UNIDENTIFIED"; - if (materialName.contains("PICKAXE")) { - toolType = "Pickaxes"; - } - else if (materialName.contains("AXE")) { - toolType = "Axes"; - } - else if (materialName.contains("BOW")) { - toolType = "Bows"; - } - else if (materialName.contains("HOE")) { - toolType = "Hoes"; - } - else if (materialName.contains("SHOVEL") || materialName.contains("SPADE")) { - toolType = "Shovels"; - } - else if (materialName.contains("SWORD")) { - toolType = "Swords"; - } - - if (!configSections.containsKey(toolType)) { - configSections.put(toolType, new ArrayList<>()); - } - - ArrayList skillContents = configSections.get(toolType); - skillContents.add(" " + materialName + ":"); - skillContents.add(" " + " " + "XP_Modifier: 1.0"); - skillContents.add(" " + " " + "Tier: 1"); - skillContents.add(" " + " " + "Ability_Enabled: true"); - addRepairableLines(materialName, skillContents); - } - - return configSections; - } - - private HashMap> getConfigSectionsArmor(String modName, HashMap> materialNames) { - HashMap> configSections = new HashMap<>(); - - // Go through all the materials and categorise them under an armor type - for (String materialName : materialNames.get(modName)) { - String toolType = "UNIDENTIFIED"; - if (materialName.contains("BOOT") || materialName.contains("SHOE")) { - toolType = "Boots"; - } - else if (materialName.contains("CHESTPLATE") || materialName.contains("CHEST")) { - toolType = "Chestplates"; - } - else if (materialName.contains("HELM") || materialName.contains("HAT")) { - toolType = "Helmets"; - } - else if (materialName.contains("LEGGINGS") || materialName.contains("LEGS") || materialName.contains("PANTS")) { - toolType = "Leggings"; - } - - if (!configSections.containsKey(toolType)) { - configSections.put(toolType, new ArrayList<>()); - } - - ArrayList skillContents = configSections.get(toolType); - skillContents.add(" " + materialName + ":"); - addRepairableLines(materialName, skillContents); - } - - return configSections; - } - - private void addRepairableLines(String materialName, ArrayList skillContents) { - skillContents.add(" " + " " + "Repairable: true"); - skillContents.add(" " + " " + "Repair_Material: REPAIR_MATERIAL_NAME"); - skillContents.add(" " + " " + "Repair_Material_Data_Value: 0"); - skillContents.add(" " + " " + "Repair_Material_Quantity: 9"); - skillContents.add(" " + " " + "Repair_Material_Pretty_Name: Repair Item Name"); - skillContents.add(" " + " " + "Repair_MinimumLevel: 0"); - skillContents.add(" " + " " + "Repair_XpMultiplier: 1.0"); - - Material material = Material.matchMaterial(materialName); - short durability = (material == null) ? (short) 9999 : material.getMaxDurability(); - skillContents.add(" " + " " + "Durability: " + ((durability > 0) ? durability : (short) 9999)); - } - - private HashMap> getConfigSectionsUnknown(String modName, HashMap> materialNames) { - HashMap> configSections = new HashMap<>(); - - // Go through all the materials and print them - for (String materialName : materialNames.get(modName)) { - String configKey = "UNIDENTIFIED"; - - if (!configSections.containsKey(configKey)) { - configSections.put(configKey, new ArrayList<>()); - } - - ArrayList skillContents = configSections.get(configKey); - skillContents.add(" " + materialName); - } - - return configSections; - } -} diff --git a/src/main/java/com/gmail/nossr50/commands/McabilityCommand.java b/src/main/java/com/gmail/nossr50/commands/McabilityCommand.java index 0628b9364..c391dc9ff 100644 --- a/src/main/java/com/gmail/nossr50/commands/McabilityCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/McabilityCommand.java @@ -17,9 +17,10 @@ public class McabilityCommand extends ToggleCommand { } @Override - protected void applyCommandAction(McMMOPlayer mcMMOPlayer) { - mcMMOPlayer.getPlayer().sendMessage(LocaleLoader.getString("Commands.Ability." + (mcMMOPlayer.getAbilityUse() ? "Off" : "On"))); - mcMMOPlayer.toggleAbilityUse(); + protected void applyCommandAction(McMMOPlayer mmoPlayer) { + mmoPlayer.getPlayer().sendMessage(LocaleLoader.getString( + "Commands.Ability." + (mmoPlayer.getAbilityUse() ? "Off" : "On"))); + mmoPlayer.toggleAbilityUse(); } @Override diff --git a/src/main/java/com/gmail/nossr50/commands/McconvertCommand.java b/src/main/java/com/gmail/nossr50/commands/McconvertCommand.java index e00510078..5b07e15c2 100644 --- a/src/main/java/com/gmail/nossr50/commands/McconvertCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/McconvertCommand.java @@ -7,6 +7,9 @@ import com.gmail.nossr50.datatypes.database.DatabaseType; import com.gmail.nossr50.datatypes.experience.FormulaType; import com.gmail.nossr50.mcMMO; import com.google.common.collect.ImmutableList; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; @@ -14,10 +17,6 @@ import org.bukkit.command.TabExecutor; import org.bukkit.util.StringUtil; import org.jetbrains.annotations.NotNull; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - public class McconvertCommand implements TabExecutor { private static final List FORMULA_TYPES; private static final List DATABASE_TYPES; @@ -54,11 +53,13 @@ public class McconvertCommand implements TabExecutor { } @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, + @NotNull String label, String[] args) { if (args.length == 2) { if (args[0].equalsIgnoreCase("database") || args[0].equalsIgnoreCase("db")) { return databaseConvertCommand.onCommand(sender, command, label, args); - } else if (args[0].equalsIgnoreCase("experience") || args[0].equalsIgnoreCase("xp") || args[1].equalsIgnoreCase("exp")) { + } else if (args[0].equalsIgnoreCase("experience") || args[0].equalsIgnoreCase("xp") + || args[1].equalsIgnoreCase("exp")) { return experienceConvertCommand.onCommand(sender, command, label, args); } @@ -68,17 +69,22 @@ public class McconvertCommand implements TabExecutor { } @Override - public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, String[] args) { + public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, + @NotNull String alias, String[] args) { switch (args.length) { case 1: - return StringUtil.copyPartialMatches(args[0], SUBCOMMANDS, new ArrayList<>(SUBCOMMANDS.size())); + return StringUtil.copyPartialMatches(args[0], SUBCOMMANDS, + new ArrayList<>(SUBCOMMANDS.size())); case 2: if (args[0].equalsIgnoreCase("database") || args[0].equalsIgnoreCase("db")) { - return StringUtil.copyPartialMatches(args[0], DATABASE_TYPES, new ArrayList<>(DATABASE_TYPES.size())); + return StringUtil.copyPartialMatches(args[0], DATABASE_TYPES, + new ArrayList<>(DATABASE_TYPES.size())); } - if (args[0].equalsIgnoreCase("experience") || args[0].equalsIgnoreCase("xp") || args[0].equalsIgnoreCase("exp")) { - return StringUtil.copyPartialMatches(args[0], FORMULA_TYPES, new ArrayList<>(FORMULA_TYPES.size())); + if (args[0].equalsIgnoreCase("experience") || args[0].equalsIgnoreCase("xp") + || args[0].equalsIgnoreCase("exp")) { + return StringUtil.copyPartialMatches(args[0], FORMULA_TYPES, + new ArrayList<>(FORMULA_TYPES.size())); } return ImmutableList.of(); diff --git a/src/main/java/com/gmail/nossr50/commands/McgodCommand.java b/src/main/java/com/gmail/nossr50/commands/McgodCommand.java index 1867c4672..00fb1c6a1 100644 --- a/src/main/java/com/gmail/nossr50/commands/McgodCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/McgodCommand.java @@ -17,9 +17,10 @@ public class McgodCommand extends ToggleCommand { } @Override - protected void applyCommandAction(McMMOPlayer mcMMOPlayer) { - mcMMOPlayer.getPlayer().sendMessage(LocaleLoader.getString("Commands.GodMode." + (mcMMOPlayer.getGodMode() ? "Disabled" : "Enabled"))); - mcMMOPlayer.toggleGodMode(); + protected void applyCommandAction(McMMOPlayer mmoPlayer) { + mmoPlayer.getPlayer().sendMessage(LocaleLoader.getString( + "Commands.GodMode." + (mmoPlayer.getGodMode() ? "Disabled" : "Enabled"))); + mmoPlayer.toggleGodMode(); } @Override diff --git a/src/main/java/com/gmail/nossr50/commands/McmmoCommand.java b/src/main/java/com/gmail/nossr50/commands/McmmoCommand.java index 838722131..dc3a4a9f5 100644 --- a/src/main/java/com/gmail/nossr50/commands/McmmoCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/McmmoCommand.java @@ -12,7 +12,8 @@ import org.jetbrains.annotations.NotNull; public class McmmoCommand implements CommandExecutor { @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, + @NotNull String label, String[] args) { switch (args.length) { case 0: if (!Permissions.mcmmoDescription(sender)) { @@ -27,18 +28,22 @@ public class McmmoCommand implements CommandExecutor { if (mcMMO.p.getGeneralConfig().getDonateMessageEnabled()) { sender.sendMessage(LocaleLoader.getString("MOTD.Donate")); - sender.sendMessage(ChatColor.GOLD + " - " + ChatColor.GREEN + "nossr50@gmail.com" + ChatColor.GOLD + " Paypal"); + sender.sendMessage( + ChatColor.GOLD + " - " + ChatColor.GREEN + "nossr50@gmail.com" + + ChatColor.GOLD + " Paypal"); } if (Permissions.showversion(sender)) { - sender.sendMessage(LocaleLoader.getString("MOTD.Version", mcMMO.p.getDescription().getVersion())); + sender.sendMessage(LocaleLoader.getString("MOTD.Version", + mcMMO.p.getDescription().getVersion())); } // mcMMO.getHolidayManager().anniversaryCheck(sender); return true; case 1: - if (args[0].equalsIgnoreCase("?") || args[0].equalsIgnoreCase("help") || args[0].equalsIgnoreCase("commands")) { + if (args[0].equalsIgnoreCase("?") || args[0].equalsIgnoreCase("help") + || args[0].equalsIgnoreCase("commands")) { if (!Permissions.mcmmoHelp(sender)) { sender.sendMessage(command.getPermissionMessage()); return true; @@ -57,59 +62,61 @@ public class McmmoCommand implements CommandExecutor { } private void displayGeneralCommands(CommandSender sender) { - sender.sendMessage(ChatColor.DARK_AQUA + " /mcstats " + LocaleLoader.getString("Commands.Stats")); - sender.sendMessage(ChatColor.DARK_AQUA + " /" + LocaleLoader.getString("Commands.SkillInfo")); - sender.sendMessage(ChatColor.DARK_AQUA + " /mctop " + LocaleLoader.getString("Commands.Leaderboards")); + sender.sendMessage(LocaleLoader.getString("Commands.Stats")); + sender.sendMessage(LocaleLoader.getString("Commands.SkillInfo")); + sender.sendMessage(LocaleLoader.getString("Commands.Leaderboards")); if (Permissions.inspect(sender)) { - sender.sendMessage(ChatColor.DARK_AQUA + " /inspect " + LocaleLoader.getString("Commands.Inspect")); + sender.sendMessage(LocaleLoader.getString("Commands.Inspect")); } if (Permissions.mcability(sender)) { - sender.sendMessage(ChatColor.DARK_AQUA + " /mcability " + LocaleLoader.getString("Commands.ToggleAbility")); + sender.sendMessage(LocaleLoader.getString("Commands.ToggleAbility")); } } private void displayOtherCommands(CommandSender sender) { //Don't show them this category if they have none of the permissions - if(!Permissions.skillreset(sender) && !Permissions.mmoedit(sender) && !Permissions.adminChat(sender) && !Permissions.mcgod(sender)) + if (!Permissions.skillreset(sender) && !Permissions.mmoedit(sender) + && !Permissions.adminChat(sender) && !Permissions.mcgod(sender)) { return; + } sender.sendMessage(LocaleLoader.getString("Commands.Other")); if (Permissions.skillreset(sender)) { - sender.sendMessage(ChatColor.DARK_AQUA + " /skillreset " + LocaleLoader.getString("Commands.Reset")); + sender.sendMessage(LocaleLoader.getString("Commands.Reset")); } if (Permissions.mmoedit(sender)) { - sender.sendMessage(ChatColor.DARK_AQUA + " /mmoedit " + LocaleLoader.getString("Commands.mmoedit")); + sender.sendMessage(LocaleLoader.getString("Commands.mmoedit")); } if (Permissions.adminChat(sender)) { - sender.sendMessage(ChatColor.DARK_AQUA + " /adminchat " + LocaleLoader.getString("Commands.AdminToggle")); + sender.sendMessage(LocaleLoader.getString("Commands.AdminToggle")); } if (Permissions.mcgod(sender)) { - sender.sendMessage(ChatColor.DARK_AQUA + " /mcgod " + LocaleLoader.getString("Commands.mcgod")); + sender.sendMessage(LocaleLoader.getString("Commands.mcgod")); } } private void displayPartyCommands(CommandSender sender) { if (Permissions.party(sender)) { sender.sendMessage(LocaleLoader.getString("Commands.Party.Commands")); - sender.sendMessage(ChatColor.DARK_AQUA + " /party create <" + LocaleLoader.getString("Commands.Usage.PartyName") + "> " + LocaleLoader.getString("Commands.Party1")); - sender.sendMessage(ChatColor.DARK_AQUA + " /party join <" + LocaleLoader.getString("Commands.Usage.Player") + "> " + LocaleLoader.getString("Commands.Party2")); - sender.sendMessage(ChatColor.DARK_AQUA + " /party quit " + LocaleLoader.getString("Commands.Party.Quit")); + sender.sendMessage(LocaleLoader.getString("Commands.Party1")); + sender.sendMessage(LocaleLoader.getString("Commands.Party2")); + sender.sendMessage(LocaleLoader.getString("Commands.Party.Quit")); if (Permissions.partyChat(sender)) { - sender.sendMessage(ChatColor.DARK_AQUA + " /party chat " + LocaleLoader.getString("Commands.Party.Toggle")); + sender.sendMessage(LocaleLoader.getString("Commands.Party.Toggle")); } - sender.sendMessage(ChatColor.DARK_AQUA + " /party invite <" + LocaleLoader.getString("Commands.Usage.Player") + "> " + LocaleLoader.getString("Commands.Party.Invite")); - sender.sendMessage(ChatColor.DARK_AQUA + " /party accept " + LocaleLoader.getString("Commands.Party.Accept")); + sender.sendMessage(LocaleLoader.getString("Commands.Party.Invite")); + sender.sendMessage(LocaleLoader.getString("Commands.Party.Accept")); if (Permissions.partySubcommand(sender, PartySubcommandType.TELEPORT)) { - sender.sendMessage(ChatColor.DARK_AQUA + " /party teleport <" + LocaleLoader.getString("Commands.Usage.Player") + "> " + LocaleLoader.getString("Commands.Party.Teleport")); + sender.sendMessage(LocaleLoader.getString("Commands.Party.Teleport")); } } } diff --git a/src/main/java/com/gmail/nossr50/commands/McnotifyCommand.java b/src/main/java/com/gmail/nossr50/commands/McnotifyCommand.java index d693a99c7..289fc8d80 100644 --- a/src/main/java/com/gmail/nossr50/commands/McnotifyCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/McnotifyCommand.java @@ -5,39 +5,41 @@ import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.util.commands.CommandUtils; import com.gmail.nossr50.util.player.UserManager; import com.google.common.collect.ImmutableList; +import java.util.List; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.command.TabExecutor; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; -import java.util.List; - public class McnotifyCommand implements TabExecutor { @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, + @NotNull String label, String[] args) { if (CommandUtils.noConsoleUsage(sender)) { return true; } if (args.length == 0) { - McMMOPlayer mcMMOPlayer = UserManager.getPlayer((Player) sender); + final McMMOPlayer mmoPlayer = UserManager.getPlayer((Player) sender); //Not Loaded yet - if (mcMMOPlayer == null) { + if (mmoPlayer == null) { sender.sendMessage(LocaleLoader.getString("Profile.PendingLoad")); return true; } - sender.sendMessage(LocaleLoader.getString("Commands.Notifications." + (mcMMOPlayer.useChatNotifications() ? "Off" : "On"))); - mcMMOPlayer.toggleChatNotifications(); + sender.sendMessage(LocaleLoader.getString( + "Commands.Notifications." + (mmoPlayer.useChatNotifications() ? "Off" : "On"))); + mmoPlayer.toggleChatNotifications(); return true; } return false; } @Override - public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, String[] args) { + public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, + @NotNull String alias, String[] args) { return ImmutableList.of(); } } diff --git a/src/main/java/com/gmail/nossr50/commands/McrefreshCommand.java b/src/main/java/com/gmail/nossr50/commands/McrefreshCommand.java index 9cc0ed3c1..8d38ac90c 100644 --- a/src/main/java/com/gmail/nossr50/commands/McrefreshCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/McrefreshCommand.java @@ -17,13 +17,13 @@ public class McrefreshCommand extends ToggleCommand { } @Override - protected void applyCommandAction(McMMOPlayer mcMMOPlayer) { - mcMMOPlayer.setRecentlyHurt(0); - mcMMOPlayer.resetCooldowns(); - mcMMOPlayer.resetToolPrepMode(); - mcMMOPlayer.resetAbilityMode(); + protected void applyCommandAction(McMMOPlayer mmoPlayer) { + mmoPlayer.setRecentlyHurt(0); + mmoPlayer.resetCooldowns(); + mmoPlayer.resetToolPrepMode(); + mmoPlayer.resetAbilityMode(); - mcMMOPlayer.getPlayer().sendMessage(LocaleLoader.getString("Ability.Generic.Refresh")); + mmoPlayer.getPlayer().sendMessage(LocaleLoader.getString("Ability.Generic.Refresh")); } @Override diff --git a/src/main/java/com/gmail/nossr50/commands/McscoreboardCommand.java b/src/main/java/com/gmail/nossr50/commands/McscoreboardCommand.java index ff5b4ab2d..074780438 100644 --- a/src/main/java/com/gmail/nossr50/commands/McscoreboardCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/McscoreboardCommand.java @@ -5,30 +5,30 @@ import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.commands.CommandUtils; import com.gmail.nossr50.util.scoreboards.ScoreboardManager; import com.google.common.collect.ImmutableList; +import java.util.ArrayList; +import java.util.List; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.command.TabExecutor; import org.bukkit.util.StringUtil; import org.jetbrains.annotations.NotNull; -import java.util.ArrayList; -import java.util.List; - public class McscoreboardCommand implements TabExecutor { private static final List FIRST_ARGS = ImmutableList.of("keep", "time", "clear"); @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, + @NotNull String label, String[] args) { if (CommandUtils.noConsoleUsage(sender)) { return true; } - if(!mcMMO.p.getGeneralConfig().getScoreboardsEnabled()) { + if (!mcMMO.p.getGeneralConfig().getScoreboardsEnabled()) { sender.sendMessage(LocaleLoader.getString("Scoreboard.Disabled")); return true; } - if(!ScoreboardManager.isPlayerBoardSetup(sender.getName())) { + if (!ScoreboardManager.isPlayerBoardSetup(sender.getName())) { sender.sendMessage(LocaleLoader.getString("Scoreboard.NotSetupYet")); return true; } @@ -42,7 +42,8 @@ public class McscoreboardCommand implements TabExecutor { } if (args[0].equalsIgnoreCase("keep")) { - if (!mcMMO.p.getGeneralConfig().getAllowKeepBoard() || !mcMMO.p.getGeneralConfig().getScoreboardsEnabled()) { + if (!mcMMO.p.getGeneralConfig().getAllowKeepBoard() + || !mcMMO.p.getGeneralConfig().getScoreboardsEnabled()) { sender.sendMessage(LocaleLoader.getString("Commands.Disabled")); return true; } @@ -80,9 +81,11 @@ public class McscoreboardCommand implements TabExecutor { } @Override - public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, String[] args) { + public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, + @NotNull String alias, String[] args) { if (args.length == 1) { - return StringUtil.copyPartialMatches(args[0], FIRST_ARGS, new ArrayList<>(FIRST_ARGS.size())); + return StringUtil.copyPartialMatches(args[0], FIRST_ARGS, + new ArrayList<>(FIRST_ARGS.size())); } return ImmutableList.of(); } diff --git a/src/main/java/com/gmail/nossr50/commands/ToggleCommand.java b/src/main/java/com/gmail/nossr50/commands/ToggleCommand.java index fea470d0e..d73bc0c8a 100644 --- a/src/main/java/com/gmail/nossr50/commands/ToggleCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/ToggleCommand.java @@ -4,18 +4,18 @@ import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.util.commands.CommandUtils; import com.gmail.nossr50.util.player.UserManager; import com.google.common.collect.ImmutableList; +import java.util.ArrayList; +import java.util.List; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.command.TabExecutor; import org.bukkit.util.StringUtil; import org.jetbrains.annotations.NotNull; -import java.util.ArrayList; -import java.util.List; - public abstract class ToggleCommand implements TabExecutor { @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, + @NotNull String label, String[] args) { switch (args.length) { case 0: if (CommandUtils.noConsoleUsage(sender)) { @@ -41,17 +41,17 @@ public abstract class ToggleCommand implements TabExecutor { } String playerName = CommandUtils.getMatchedPlayerName(args[0]); - McMMOPlayer mcMMOPlayer = UserManager.getPlayer(playerName); + final McMMOPlayer mmoPlayer = UserManager.getPlayer(playerName); - if (!CommandUtils.checkPlayerExistence(sender, playerName, mcMMOPlayer)) { + if (!CommandUtils.checkPlayerExistence(sender, playerName, mmoPlayer)) { return true; } - if (CommandUtils.isOffline(sender, mcMMOPlayer.getPlayer())) { + if (CommandUtils.isOffline(sender, mmoPlayer.getPlayer())) { return true; } - applyCommandAction(mcMMOPlayer); + applyCommandAction(mmoPlayer); sendSuccessMessage(sender, playerName); return true; @@ -61,16 +61,21 @@ public abstract class ToggleCommand implements TabExecutor { } @Override - public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, String[] args) { + public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, + @NotNull String alias, String[] args) { if (args.length == 1) { List playerNames = CommandUtils.getOnlinePlayerNames(sender); - return StringUtil.copyPartialMatches(args[0], playerNames, new ArrayList<>(playerNames.size())); + return StringUtil.copyPartialMatches(args[0], playerNames, + new ArrayList<>(playerNames.size())); } return ImmutableList.of(); } protected abstract boolean hasOtherPermission(CommandSender sender); + protected abstract boolean hasSelfPermission(CommandSender sender); - protected abstract void applyCommandAction(McMMOPlayer mcMMOPlayer); + + protected abstract void applyCommandAction(McMMOPlayer mmoPlayer); + protected abstract void sendSuccessMessage(CommandSender sender, String playerName); } diff --git a/src/main/java/com/gmail/nossr50/commands/XprateCommand.java b/src/main/java/com/gmail/nossr50/commands/XprateCommand.java index f5ad2641c..d42be646a 100644 --- a/src/main/java/com/gmail/nossr50/commands/XprateCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/XprateCommand.java @@ -9,6 +9,8 @@ import com.gmail.nossr50.util.commands.CommandUtils; import com.gmail.nossr50.util.player.NotificationManager; import com.gmail.nossr50.util.text.StringUtils; import com.google.common.collect.ImmutableList; +import java.util.ArrayList; +import java.util.List; import org.bukkit.ChatColor; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; @@ -16,17 +18,16 @@ import org.bukkit.command.TabExecutor; import org.bukkit.util.StringUtil; import org.jetbrains.annotations.NotNull; -import java.util.ArrayList; -import java.util.List; - public class XprateCommand implements TabExecutor { - private final double ORIGINAL_XP_RATE = ExperienceConfig.getInstance().getExperienceGainsGlobalMultiplier(); + private final double ORIGINAL_XP_RATE = ExperienceConfig.getInstance() + .getExperienceGainsGlobalMultiplier(); @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, + @NotNull String label, String[] args) { switch (args.length) { case 1: - if (!args[0].equalsIgnoreCase("reset") && !args[0].equalsIgnoreCase("clear")) { + if (!args[0].equalsIgnoreCase("reset") && !args[0].equalsIgnoreCase("clear")) { return false; } @@ -37,22 +38,23 @@ public class XprateCommand implements TabExecutor { if (mcMMO.p.isXPEventEnabled()) { - if(mcMMO.p.getAdvancedConfig().useTitlesForXPEvent()) - { + if (mcMMO.p.getAdvancedConfig().useTitlesForXPEvent()) { NotificationManager.broadcastTitle(mcMMO.p.getServer(), LocaleLoader.getString("Commands.Event.Stop"), LocaleLoader.getString("Commands.Event.Stop.Subtitle"), - 10, 10*20, 20); + 10, 10 * 20, 20); } - if(mcMMO.p.getGeneralConfig().broadcastEventMessages()) - { - mcMMO.p.getServer().broadcastMessage(LocaleLoader.getString("Commands.Event.Stop")); - mcMMO.p.getServer().broadcastMessage(LocaleLoader.getString("Commands.Event.Stop.Subtitle")); + if (mcMMO.p.getGeneralConfig().broadcastEventMessages()) { + mcMMO.p.getServer() + .broadcastMessage(LocaleLoader.getString("Commands.Event.Stop")); + mcMMO.p.getServer().broadcastMessage( + LocaleLoader.getString("Commands.Event.Stop.Subtitle")); } //Admin notification - NotificationManager.processSensitiveCommandNotification(sender, SensitiveCommandType.XPRATE_END); + NotificationManager.processSensitiveCommandNotification(sender, + SensitiveCommandType.XPRATE_END); mcMMO.p.toggleXpEventEnabled(); } @@ -72,40 +74,39 @@ public class XprateCommand implements TabExecutor { if (CommandUtils.shouldDisableToggle(args[1])) { mcMMO.p.setXPEventEnabled(false); - } - else if (CommandUtils.shouldEnableToggle(args[1])) { + } else if (CommandUtils.shouldEnableToggle(args[1])) { mcMMO.p.setXPEventEnabled(true); - } - else { + } else { return false; } int newXpRate = Integer.parseInt(args[0]); - if(newXpRate < 0) - { - sender.sendMessage(ChatColor.RED+LocaleLoader.getString("Commands.NegativeNumberWarn")); + if (newXpRate < 0) { + sender.sendMessage( + ChatColor.RED + LocaleLoader.getString("Commands.NegativeNumberWarn")); return true; } ExperienceConfig.getInstance().setExperienceGainsGlobalMultiplier(newXpRate); - if(mcMMO.p.getAdvancedConfig().useTitlesForXPEvent()) - { + if (mcMMO.p.getAdvancedConfig().useTitlesForXPEvent()) { NotificationManager.broadcastTitle(mcMMO.p.getServer(), LocaleLoader.getString("Commands.Event.Start"), LocaleLoader.getString("Commands.Event.XP", newXpRate), - 10, 10*20, 20); + 10, 10 * 20, 20); } - if(mcMMO.p.getGeneralConfig().broadcastEventMessages()) - { - mcMMO.p.getServer().broadcastMessage(LocaleLoader.getString("Commands.Event.Start")); - mcMMO.p.getServer().broadcastMessage(LocaleLoader.getString("Commands.Event.XP", newXpRate)); + if (mcMMO.p.getGeneralConfig().broadcastEventMessages()) { + mcMMO.p.getServer() + .broadcastMessage(LocaleLoader.getString("Commands.Event.Start")); + mcMMO.p.getServer().broadcastMessage( + LocaleLoader.getString("Commands.Event.XP", newXpRate)); } //Admin notification - NotificationManager.processSensitiveCommandNotification(sender, SensitiveCommandType.XPRATE_MODIFY, String.valueOf(newXpRate)); + NotificationManager.processSensitiveCommandNotification(sender, + SensitiveCommandType.XPRATE_MODIFY, String.valueOf(newXpRate)); return true; @@ -115,16 +116,19 @@ public class XprateCommand implements TabExecutor { } @Override - public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, String[] args) { + public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, + @NotNull String alias, String[] args) { switch (args.length) { case 1: if (StringUtils.isInt(args[0])) { return ImmutableList.of(); } - return StringUtil.copyPartialMatches(args[0], CommandUtils.RESET_OPTIONS, new ArrayList<>(CommandUtils.RESET_OPTIONS.size())); + return StringUtil.copyPartialMatches(args[0], CommandUtils.RESET_OPTIONS, + new ArrayList<>(CommandUtils.RESET_OPTIONS.size())); case 2: - return StringUtil.copyPartialMatches(args[1], CommandUtils.TRUE_FALSE_OPTIONS, new ArrayList<>(CommandUtils.TRUE_FALSE_OPTIONS.size())); + return StringUtil.copyPartialMatches(args[1], CommandUtils.TRUE_FALSE_OPTIONS, + new ArrayList<>(CommandUtils.TRUE_FALSE_OPTIONS.size())); default: return ImmutableList.of(); } diff --git a/src/main/java/com/gmail/nossr50/commands/admin/CompatibilityCommand.java b/src/main/java/com/gmail/nossr50/commands/admin/CompatibilityCommand.java index 89a0f1061..9f153859c 100644 --- a/src/main/java/com/gmail/nossr50/commands/admin/CompatibilityCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/admin/CompatibilityCommand.java @@ -11,8 +11,8 @@ public class CompatibilityCommand implements CommandExecutor { /** * Executes the given command, returning its success. *
- * If false is returned, then the "usage" plugin.yml entry for this command - * (if defined) will be sent to the player. + * If false is returned, then the "usage" plugin.yml entry for this command (if defined) will be + * sent to the player. * * @param commandSender Source of the command * @param command Command which was executed @@ -21,7 +21,9 @@ public class CompatibilityCommand implements CommandExecutor { * @return true if a valid command, otherwise false */ @Override - public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s, @NotNull String[] strings) { + public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, + @NotNull String s, + @NotNull String[] strings) { mcMMO.getCompatibilityManager().reportCompatibilityStatus(commandSender); return true; } diff --git a/src/main/java/com/gmail/nossr50/commands/admin/DropTreasureCommand.java b/src/main/java/com/gmail/nossr50/commands/admin/DropTreasureCommand.java deleted file mode 100644 index 5a60d9bee..000000000 --- a/src/main/java/com/gmail/nossr50/commands/admin/DropTreasureCommand.java +++ /dev/null @@ -1,57 +0,0 @@ -//package com.gmail.nossr50.commands.admin; -// -//import com.gmail.nossr50.config.treasure.FishingTreasureConfig; -//import com.gmail.nossr50.datatypes.player.McMMOPlayer; -//import com.gmail.nossr50.datatypes.treasure.FishingTreasure; -//import com.gmail.nossr50.datatypes.treasure.Rarity; -//import com.gmail.nossr50.mcMMO; -//import com.gmail.nossr50.skills.fishing.FishingManager; -//import com.gmail.nossr50.util.player.UserManager; -//import org.bukkit.Location; -//import org.bukkit.command.Command; -//import org.bukkit.command.CommandExecutor; -//import org.bukkit.command.CommandSender; -//import org.bukkit.entity.Player; -//import org.jetbrains.annotations.NotNull; -// -//public class DropTreasureCommand implements CommandExecutor { -// @Override -// public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { -// if(sender instanceof Player) { -// if(!sender.isOp()) { -// sender.sendMessage("This command is for Operators only"); -// return false; -// } -// -// Player player = (Player) sender; -// Location location = player.getLocation(); -// McMMOPlayer mmoPlayer = UserManager.getPlayer(player); -// -// if(mmoPlayer == null) { -// //TODO: Localize -// player.sendMessage("Your player data is not loaded yet"); -// return false; -// } -// -// if(args.length == 0) { -// mcMMO.p.getLogger().info(player.toString() +" is dropping all mcMMO treasures via admin command at location "+location.toString()); -// for(Rarity rarity : FishingTreasureConfig.getInstance().fishingRewards.keySet()) { -// for(FishingTreasure fishingTreasure : FishingTreasureConfig.getInstance().fishingRewards.get(rarity)) { -// FishingManager fishingManager = mmoPlayer.getFishingManager(); -// } -// } -// //TODO: impl -// } else { -// String targetTreasure = args[1]; -// -// //Drop all treasures matching the name -// //TODO: impl -// } -// -// return true; -// } else { -// sender.sendMessage("No console support for this command"); -// return false; -// } -// } -//} diff --git a/src/main/java/com/gmail/nossr50/commands/admin/McmmoReloadLocaleCommand.java b/src/main/java/com/gmail/nossr50/commands/admin/McmmoReloadLocaleCommand.java index b5a5e22a8..20fb60674 100644 --- a/src/main/java/com/gmail/nossr50/commands/admin/McmmoReloadLocaleCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/admin/McmmoReloadLocaleCommand.java @@ -12,7 +12,9 @@ import org.jetbrains.annotations.NotNull; */ public final class McmmoReloadLocaleCommand implements CommandExecutor { @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, + @NotNull String label, + String[] args) { if (args.length == 0) { if (!Permissions.reloadlocale(sender)) { sender.sendMessage(command.getPermissionMessage()); diff --git a/src/main/java/com/gmail/nossr50/commands/admin/PlayerDebugCommand.java b/src/main/java/com/gmail/nossr50/commands/admin/PlayerDebugCommand.java index 25a87ceb3..5f6c3b63c 100644 --- a/src/main/java/com/gmail/nossr50/commands/admin/PlayerDebugCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/admin/PlayerDebugCommand.java @@ -12,11 +12,14 @@ import org.jetbrains.annotations.NotNull; public class PlayerDebugCommand implements CommandExecutor { @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { - if(sender instanceof Player) { - McMMOPlayer mcMMOPlayer = UserManager.getPlayer((Player) sender); - mcMMOPlayer.toggleDebugMode(); //Toggle debug mode - NotificationManager.sendPlayerInformationChatOnlyPrefixed(mcMMOPlayer.getPlayer(), "Commands.Mmodebug.Toggle", String.valueOf(mcMMOPlayer.isDebugMode())); + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, + @NotNull String label, + String[] args) { + if (sender instanceof Player) { + final McMMOPlayer mmoPlayer = UserManager.getPlayer((Player) sender); + mmoPlayer.toggleDebugMode(); //Toggle debug mode + NotificationManager.sendPlayerInformationChatOnlyPrefixed(mmoPlayer.getPlayer(), + "Commands.Mmodebug.Toggle", String.valueOf(mmoPlayer.isDebugMode())); return true; } else { return false; diff --git a/src/main/java/com/gmail/nossr50/commands/chat/AdminChatCommand.java b/src/main/java/com/gmail/nossr50/commands/chat/AdminChatCommand.java index 3c6f93d11..3feeeacad 100644 --- a/src/main/java/com/gmail/nossr50/commands/chat/AdminChatCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/chat/AdminChatCommand.java @@ -22,24 +22,29 @@ public class AdminChatCommand extends BaseCommand { this.pluginRef = pluginRef; } - @Default @Conditions(CommandManager.ADMIN_CONDITION) + @Default + @Conditions(CommandManager.ADMIN_CONDITION) public void processCommand(String[] args) { - BukkitCommandIssuer bukkitCommandIssuer = (BukkitCommandIssuer) getCurrentCommandIssuer(); - if(args == null || args.length == 0) { + final BukkitCommandIssuer bukkitCommandIssuer = (BukkitCommandIssuer) getCurrentCommandIssuer(); + if (args == null || args.length == 0) { //Process with no arguments - if(bukkitCommandIssuer.isPlayer()) { - McMMOPlayer mmoPlayer = UserManager.getPlayer(bukkitCommandIssuer.getPlayer()); + if (bukkitCommandIssuer.isPlayer()) { + final McMMOPlayer mmoPlayer = UserManager.getPlayer( + bukkitCommandIssuer.getPlayer()); pluginRef.getChatManager().setOrToggleChatChannel(mmoPlayer, ChatChannel.ADMIN); } else { //Not support for console - mcMMO.p.getLogger().info("You cannot switch chat channels as console, please provide full arguments."); + mcMMO.p.getLogger() + .info("You cannot switch chat channels as console, please provide full arguments."); } } else { - if(bukkitCommandIssuer.isPlayer()) { - McMMOPlayer mmoPlayer = UserManager.getPlayer(bukkitCommandIssuer.getPlayer()); + if (bukkitCommandIssuer.isPlayer()) { + final McMMOPlayer mmoPlayer = UserManager.getPlayer( + bukkitCommandIssuer.getPlayer()); - if(mmoPlayer == null) + if (mmoPlayer == null) { return; + } //Message contains the original command so it needs to be passed to this method to trim it pluginRef.getChatManager().processPlayerMessage(mmoPlayer, args, ChatChannel.ADMIN); diff --git a/src/main/java/com/gmail/nossr50/commands/chat/McChatSpy.java b/src/main/java/com/gmail/nossr50/commands/chat/McChatSpy.java index 87ef2285f..f6e861707 100644 --- a/src/main/java/com/gmail/nossr50/commands/chat/McChatSpy.java +++ b/src/main/java/com/gmail/nossr50/commands/chat/McChatSpy.java @@ -18,9 +18,11 @@ public class McChatSpy extends ToggleCommand { } @Override - protected void applyCommandAction(McMMOPlayer mcMMOPlayer) { - mcMMOPlayer.getPlayer().sendMessage(LocaleLoader.getString("Commands.AdminChatSpy." + (mcMMOPlayer.isPartyChatSpying() ? "Disabled" : "Enabled"))); - mcMMOPlayer.togglePartyChatSpying(); + protected void applyCommandAction(McMMOPlayer mmoPlayer) { + mmoPlayer.getPlayer().sendMessage(LocaleLoader.getString( + "Commands.AdminChatSpy." + (mmoPlayer.isPartyChatSpying() ? "Disabled" + : "Enabled"))); + mmoPlayer.togglePartyChatSpying(); } @Override 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 9e420e901..4e174b114 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.chat.ChatChannel; 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; @@ -31,14 +30,16 @@ public class PartyChatCommand extends BaseCommand { public void processCommand(String[] args) { BukkitCommandIssuer bukkitCommandIssuer = (BukkitCommandIssuer) getCurrentCommandIssuer(); - if(args == null || args.length == 0) { + if (args == null || args.length == 0) { //Process with no arguments - if(bukkitCommandIssuer.isPlayer()) { - McMMOPlayer mmoPlayer = UserManager.getPlayer(bukkitCommandIssuer.getPlayer()); + if (bukkitCommandIssuer.isPlayer()) { + final McMMOPlayer mmoPlayer = UserManager.getPlayer( + bukkitCommandIssuer.getPlayer()); pluginRef.getChatManager().setOrToggleChatChannel(mmoPlayer, ChatChannel.PARTY); } else { //Not support for console - mcMMO.p.getLogger().info("You cannot switch chat channels as console, please provide full arguments."); + mcMMO.p.getLogger() + .info("You cannot switch chat channels as console, please provide full arguments."); } } else { //Here we split the logic, consoles need to target a party name and players do not @@ -46,12 +47,13 @@ public class PartyChatCommand extends BaseCommand { /* * Player Logic */ - if(bukkitCommandIssuer.getIssuer() instanceof Player) { - McMMOPlayer mmoPlayer = UserManager.getPlayer(bukkitCommandIssuer.getPlayer()); + if (bukkitCommandIssuer.getIssuer() instanceof Player) { + final McMMOPlayer mmoPlayer = UserManager.getPlayer( + bukkitCommandIssuer.getPlayer()); processCommandArgsPlayer(mmoPlayer, args); - /* - * Console Logic - */ + /* + * Console Logic + */ } else { processCommandArgsConsole(args); } @@ -60,6 +62,7 @@ public class PartyChatCommand extends BaseCommand { /** * Processes the command with arguments for a {@link McMMOPlayer} + * * @param mmoPlayer target player * @param args command arguments */ @@ -69,19 +72,24 @@ public class PartyChatCommand extends BaseCommand { } /** - * Processes the command with arguments for a {@link com.gmail.nossr50.chat.author.ConsoleAuthor} + * Processes the command with arguments for a + * {@link com.gmail.nossr50.chat.author.ConsoleAuthor} + * * @param args command arguments */ private void processCommandArgsConsole(@NotNull String[] args) { - if(args.length <= 1) { + if (args.length <= 1) { //Only specific a party and not the message - mcMMO.p.getLogger().severe("You need to specify a party name and then write a message afterwards."); + mcMMO.p.getLogger() + .severe("You need to specify a party name and then write a message afterwards."); } else { //Grab party - Party targetParty = PartyManager.getParty(args[0]); + Party targetParty = mcMMO.p.getPartyManager().getParty(args[0]); - if(targetParty != null) { - pluginRef.getChatManager().processConsoleMessage(StringUtils.buildStringAfterNthElement(args, 1), targetParty); + if (targetParty != null) { + pluginRef.getChatManager() + .processConsoleMessage(StringUtils.buildStringAfterNthElement(args, 1), + targetParty); } else { mcMMO.p.getLogger().severe("A party with that name doesn't exist!"); } diff --git a/src/main/java/com/gmail/nossr50/commands/database/ConvertDatabaseCommand.java b/src/main/java/com/gmail/nossr50/commands/database/ConvertDatabaseCommand.java index 571f1ae35..e2027bc56 100644 --- a/src/main/java/com/gmail/nossr50/commands/database/ConvertDatabaseCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/database/ConvertDatabaseCommand.java @@ -17,18 +17,26 @@ import org.jetbrains.annotations.NotNull; public class ConvertDatabaseCommand implements CommandExecutor { @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, + @NotNull String label, + String[] args) { if (args.length == 2) { DatabaseType previousType = DatabaseType.getDatabaseType(args[1]); DatabaseType newType = mcMMO.getDatabaseManager().getDatabaseType(); - if (previousType == newType || (newType == DatabaseType.CUSTOM && DatabaseManagerFactory.getCustomDatabaseManagerClass().getSimpleName().equalsIgnoreCase(args[1]))) { - sender.sendMessage(LocaleLoader.getString("Commands.mcconvert.Database.Same", newType.toString())); + if (previousType == newType || (newType == DatabaseType.CUSTOM + && DatabaseManagerFactory.getCustomDatabaseManagerClass() + .getSimpleName() + .equalsIgnoreCase(args[1]))) { + sender.sendMessage(LocaleLoader.getString("Commands.mcconvert.Database.Same", + newType.toString())); return true; } - DatabaseManager oldDatabase = DatabaseManagerFactory.createDatabaseManager(previousType, mcMMO.getUsersFilePath(), mcMMO.p.getLogger(), mcMMO.p.getPurgeTime(), mcMMO.p.getAdvancedConfig().getStartingLevel()); - if(oldDatabase == null) { + DatabaseManager oldDatabase = DatabaseManagerFactory.createDatabaseManager(previousType, + mcMMO.getUsersFilePath(), mcMMO.p.getLogger(), mcMMO.p.getPurgeTime(), + mcMMO.p.getAdvancedConfig().getStartingLevel()); + if (oldDatabase == null) { sender.sendMessage("Unable to load the old database! Check your log for errors."); return true; } @@ -40,19 +48,26 @@ public class ConvertDatabaseCommand implements CommandExecutor { clazz = Class.forName(args[1]); if (!DatabaseManager.class.isAssignableFrom(clazz)) { - sender.sendMessage(LocaleLoader.getString("Commands.mcconvert.Database.InvalidType", args[1])); + sender.sendMessage( + LocaleLoader.getString("Commands.mcconvert.Database.InvalidType", + args[1])); return true; } - oldDatabase = DatabaseManagerFactory.createCustomDatabaseManager((Class) clazz); + oldDatabase = DatabaseManagerFactory.createCustomDatabaseManager( + (Class) clazz); } catch (Throwable e) { e.printStackTrace(); - sender.sendMessage(LocaleLoader.getString("Commands.mcconvert.Database.InvalidType", args[1])); + sender.sendMessage( + LocaleLoader.getString("Commands.mcconvert.Database.InvalidType", + args[1])); return true; } } - sender.sendMessage(LocaleLoader.getString("Commands.mcconvert.Database.Start", previousType.toString(), newType.toString())); + sender.sendMessage(LocaleLoader.getString("Commands.mcconvert.Database.Start", + previousType.toString(), + newType.toString())); UserManager.saveAll(); UserManager.clearAll(); @@ -64,10 +79,14 @@ public class ConvertDatabaseCommand implements CommandExecutor { mcMMO.getDatabaseManager().saveUser(profile); } - mcMMO.p.getFoliaLib().getImpl().runLaterAsync(new PlayerProfileLoadingTask(player), 1); // 1 Tick delay to ensure the player is marked as online before we begin loading + mcMMO.p.getFoliaLib().getScheduler() + .runLaterAsync(new PlayerProfileLoadingTask(player), + 1); // 1 Tick delay to ensure the player is marked as online before we begin loading } - mcMMO.p.getFoliaLib().getImpl().runAsync(new DatabaseConversionTask(oldDatabase, sender, previousType.toString(), newType.toString())); + mcMMO.p.getFoliaLib().getScheduler().runAsync( + new DatabaseConversionTask(oldDatabase, sender, previousType.toString(), + newType.toString())); return true; } return false; diff --git a/src/main/java/com/gmail/nossr50/commands/database/McpurgeCommand.java b/src/main/java/com/gmail/nossr50/commands/database/McpurgeCommand.java index 6f192510f..366ed0c1b 100644 --- a/src/main/java/com/gmail/nossr50/commands/database/McpurgeCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/database/McpurgeCommand.java @@ -3,16 +3,16 @@ package com.gmail.nossr50.commands.database; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; import com.google.common.collect.ImmutableList; +import java.util.List; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.command.TabExecutor; import org.jetbrains.annotations.NotNull; -import java.util.List; - public class McpurgeCommand implements TabExecutor { @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, + @NotNull String label, String[] args) { if (args.length == 0) { mcMMO.getDatabaseManager().purgePowerlessUsers(); @@ -27,7 +27,8 @@ public class McpurgeCommand implements TabExecutor { } @Override - public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, String[] args) { + public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, + @NotNull String alias, String[] args) { return ImmutableList.of(); } } diff --git a/src/main/java/com/gmail/nossr50/commands/database/McremoveCommand.java b/src/main/java/com/gmail/nossr50/commands/database/McremoveCommand.java index 56b817337..c81e88bc9 100644 --- a/src/main/java/com/gmail/nossr50/commands/database/McremoveCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/database/McremoveCommand.java @@ -5,6 +5,9 @@ import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.commands.CommandUtils; import com.gmail.nossr50.util.player.UserManager; import com.google.common.collect.ImmutableList; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; import org.bukkit.Bukkit; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; @@ -12,17 +15,15 @@ import org.bukkit.command.TabExecutor; import org.bukkit.util.StringUtil; import org.jetbrains.annotations.NotNull; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; - public class McremoveCommand implements TabExecutor { @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, + @NotNull String label, String[] args) { if (args.length == 1) { String playerName = CommandUtils.getMatchedPlayerName(args[0]); - if (UserManager.getOfflinePlayer(playerName) == null && CommandUtils.unloadedProfile(sender, mcMMO.getDatabaseManager().loadPlayerProfile(playerName))) { + if (UserManager.getOfflinePlayer(playerName) == null && CommandUtils.unloadedProfile( + sender, mcMMO.getDatabaseManager().loadPlayerProfile(playerName))) { return true; } @@ -35,7 +36,8 @@ public class McremoveCommand implements TabExecutor { if (mcMMO.getDatabaseManager().removeUser(playerName, uuid)) { sender.sendMessage(LocaleLoader.getString("Commands.mcremove.Success", playerName)); } else { - sender.sendMessage(playerName + " could not be removed from the database."); // Pretty sure this should NEVER happen. + sender.sendMessage(playerName + + " could not be removed from the database."); // Pretty sure this should NEVER happen. } return true; @@ -44,10 +46,12 @@ public class McremoveCommand implements TabExecutor { } @Override - public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, String[] args) { + public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, + @NotNull String alias, String[] args) { if (args.length == 1) { List playerNames = CommandUtils.getOnlinePlayerNames(sender); - return StringUtil.copyPartialMatches(args[0], playerNames, new ArrayList<>(playerNames.size())); + return StringUtil.copyPartialMatches(args[0], playerNames, + new ArrayList<>(playerNames.size())); } return ImmutableList.of(); } diff --git a/src/main/java/com/gmail/nossr50/commands/database/MmoshowdbCommand.java b/src/main/java/com/gmail/nossr50/commands/database/MmoshowdbCommand.java index bcb07312d..f314b89f8 100644 --- a/src/main/java/com/gmail/nossr50/commands/database/MmoshowdbCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/database/MmoshowdbCommand.java @@ -4,16 +4,16 @@ import com.gmail.nossr50.database.DatabaseManagerFactory; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; import com.google.common.collect.ImmutableList; +import java.util.List; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.command.TabExecutor; import org.jetbrains.annotations.NotNull; -import java.util.List; - public class MmoshowdbCommand implements TabExecutor { @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, + @NotNull String label, String[] args) { if (args.length == 0) { Class clazz = DatabaseManagerFactory.getCustomDatabaseManagerClass(); @@ -22,14 +22,16 @@ public class MmoshowdbCommand implements TabExecutor { return true; } - sender.sendMessage(LocaleLoader.getString("Commands.mmoshowdb", (mcMMO.p.getGeneralConfig().getUseMySQL() ? "sql" : "flatfile"))); + sender.sendMessage(LocaleLoader.getString("Commands.mmoshowdb", + (mcMMO.p.getGeneralConfig().getUseMySQL() ? "sql" : "flatfile"))); return true; } return false; } @Override - public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, String[] args) { + public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, + @NotNull String alias, String[] args) { return ImmutableList.of(); } } diff --git a/src/main/java/com/gmail/nossr50/commands/experience/AddlevelsCommand.java b/src/main/java/com/gmail/nossr50/commands/experience/AddlevelsCommand.java index ca54d293a..bfa855e85 100644 --- a/src/main/java/com/gmail/nossr50/commands/experience/AddlevelsCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/experience/AddlevelsCommand.java @@ -24,7 +24,8 @@ public class AddlevelsCommand extends ExperienceCommand { } @Override - protected void handleCommand(Player player, PlayerProfile profile, PrimarySkillType skill, int value) { + protected void handleCommand(Player player, PlayerProfile profile, PrimarySkillType skill, + int value) { float xpRemoved = profile.getSkillXpLevelRaw(skill); profile.addLevels(skill, value); @@ -33,29 +34,35 @@ public class AddlevelsCommand extends ExperienceCommand { return; } - McMMOPlayer mmoPlayer = UserManager.getPlayer(player); + final McMMOPlayer mmoPlayer = UserManager.getPlayer(player); - if(mmoPlayer == null) { - EventUtils.tryLevelChangeEvent(player, skill, value, xpRemoved, true, XPGainReason.COMMAND); + if (mmoPlayer == null) { + EventUtils.tryLevelChangeEvent(player, skill, value, xpRemoved, true, + XPGainReason.COMMAND); } else { - EventUtils.tryLevelChangeEvent(mmoPlayer, skill, value, xpRemoved, true, XPGainReason.COMMAND); + EventUtils.tryLevelChangeEvent(mmoPlayer, skill, value, xpRemoved, true, + XPGainReason.COMMAND); } } @Override protected void handlePlayerMessageAll(Player player, int value, boolean isSilent) { - if(isSilent) + if (isSilent) { return; + } player.sendMessage(LocaleLoader.getString("Commands.addlevels.AwardAll.1", value)); } @Override - protected void handlePlayerMessageSkill(Player player, int value, PrimarySkillType skill, boolean isSilent) { - if(isSilent) + protected void handlePlayerMessageSkill(Player player, int value, PrimarySkillType skill, + boolean isSilent) { + if (isSilent) { return; + } - player.sendMessage(LocaleLoader.getString("Commands.addlevels.AwardSkill.1", value, mcMMO.p.getSkillTools().getLocalizedSkillName(skill))); + player.sendMessage(LocaleLoader.getString("Commands.addlevels.AwardSkill.1", value, + mcMMO.p.getSkillTools().getLocalizedSkillName(skill))); } } diff --git a/src/main/java/com/gmail/nossr50/commands/experience/AddxpCommand.java b/src/main/java/com/gmail/nossr50/commands/experience/AddxpCommand.java index 25d77e5c0..d5583a1e1 100644 --- a/src/main/java/com/gmail/nossr50/commands/experience/AddxpCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/experience/AddxpCommand.java @@ -23,15 +23,17 @@ public class AddxpCommand extends ExperienceCommand { } @Override - protected void handleCommand(Player player, PlayerProfile profile, PrimarySkillType skill, int value) { + protected void handleCommand(Player player, PlayerProfile profile, PrimarySkillType skill, + int value) { if (player != null) { //Check if player profile is loaded - if(UserManager.getPlayer(player) == null) + if (UserManager.getPlayer(player) == null) { return; + } - UserManager.getPlayer(player).applyXpGain(skill, value, XPGainReason.COMMAND, XPGainSource.COMMAND); - } - else { + UserManager.getPlayer(player) + .applyXpGain(skill, value, XPGainReason.COMMAND, XPGainSource.COMMAND); + } else { profile.addXp(skill, value); profile.scheduleAsyncSave(); } @@ -39,17 +41,21 @@ public class AddxpCommand extends ExperienceCommand { @Override protected void handlePlayerMessageAll(Player player, int value, boolean isSilent) { - if(isSilent) + if (isSilent) { return; + } player.sendMessage(LocaleLoader.getString("Commands.addxp.AwardAll", value)); } @Override - protected void handlePlayerMessageSkill(Player player, int value, PrimarySkillType skill, boolean isSilent) { - if(isSilent) + protected void handlePlayerMessageSkill(Player player, int value, PrimarySkillType skill, + boolean isSilent) { + if (isSilent) { return; + } - player.sendMessage(LocaleLoader.getString("Commands.addxp.AwardSkill", value, mcMMO.p.getSkillTools().getLocalizedSkillName(skill))); + player.sendMessage(LocaleLoader.getString("Commands.addxp.AwardSkill", value, + mcMMO.p.getSkillTools().getLocalizedSkillName(skill))); } } diff --git a/src/main/java/com/gmail/nossr50/commands/experience/ConvertExperienceCommand.java b/src/main/java/com/gmail/nossr50/commands/experience/ConvertExperienceCommand.java index 9263ebca5..129a1db1e 100644 --- a/src/main/java/com/gmail/nossr50/commands/experience/ConvertExperienceCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/experience/ConvertExperienceCommand.java @@ -6,17 +6,17 @@ import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.runnables.database.FormulaConversionTask; import com.gmail.nossr50.runnables.player.PlayerProfileLoadingTask; import com.gmail.nossr50.util.player.UserManager; +import java.util.Locale; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; -import java.util.Locale; - public class ConvertExperienceCommand implements CommandExecutor { @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, + @NotNull String label, String[] args) { if (args.length == 2) { FormulaType previousType = mcMMO.p.getFormulaManager().getPreviousFormulaType(); FormulaType newType = FormulaType.getFormulaType(args[1].toUpperCase(Locale.ENGLISH)); @@ -27,19 +27,24 @@ public class ConvertExperienceCommand implements CommandExecutor { } if (previousType == newType) { - sender.sendMessage(LocaleLoader.getString("Commands.mcconvert.Experience.Same", newType.toString())); + sender.sendMessage(LocaleLoader.getString("Commands.mcconvert.Experience.Same", + newType.toString())); return true; } - sender.sendMessage(LocaleLoader.getString("Commands.mcconvert.Experience.Start", previousType.toString(), newType.toString())); + sender.sendMessage(LocaleLoader.getString("Commands.mcconvert.Experience.Start", + previousType.toString(), newType.toString())); UserManager.saveAll(); UserManager.clearAll(); - mcMMO.p.getFoliaLib().getImpl().runLater(new FormulaConversionTask(sender, newType), 1); + mcMMO.p.getFoliaLib().getScheduler() + .runLater(new FormulaConversionTask(sender, newType), 1); for (Player player : mcMMO.p.getServer().getOnlinePlayers()) { - mcMMO.p.getFoliaLib().getImpl().runLaterAsync(new PlayerProfileLoadingTask(player), 1); // 1 Tick delay to ensure the player is marked as online before we begin loading + mcMMO.p.getFoliaLib().getScheduler() + .runLaterAsync(new PlayerProfileLoadingTask(player), + 1); // 1 Tick delay to ensure the player is marked as online before we begin loading } return true; diff --git a/src/main/java/com/gmail/nossr50/commands/experience/ExperienceCommand.java b/src/main/java/com/gmail/nossr50/commands/experience/ExperienceCommand.java index 4bd6b4eeb..8d65254a5 100644 --- a/src/main/java/com/gmail/nossr50/commands/experience/ExperienceCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/experience/ExperienceCommand.java @@ -9,6 +9,8 @@ import com.gmail.nossr50.util.commands.CommandUtils; import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.skills.SkillTools; import com.google.common.collect.ImmutableList; +import java.util.ArrayList; +import java.util.List; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.command.TabExecutor; @@ -16,25 +18,24 @@ import org.bukkit.entity.Player; import org.bukkit.util.StringUtil; import org.jetbrains.annotations.NotNull; -import java.util.ArrayList; -import java.util.List; - public abstract class ExperienceCommand implements TabExecutor { @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, + @NotNull String label, String[] args) { PrimarySkillType skill; - if(args.length < 2) { + if (args.length < 2) { return false; } else { - if(args.length == 2 && !isSilent(args) || args.length == 3 && isSilent(args)) { + if (args.length == 2 && !isSilent(args) || args.length == 3 && isSilent(args)) { if (CommandUtils.noConsoleUsage(sender)) { return true; } if (!permissionsCheckSelf(sender)) { - if(command.getPermissionMessage() != null) + if (command.getPermissionMessage() != null) { sender.sendMessage(command.getPermissionMessage()); + } sender.sendMessage("(mcMMO) No permission!"); return true; } @@ -49,23 +50,21 @@ public abstract class ExperienceCommand implements TabExecutor { skill = null; } - if (skill != null && SkillTools.isChildSkill(skill)) - { + if (skill != null && SkillTools.isChildSkill(skill)) { sender.sendMessage(LocaleLoader.getString("Commands.Skill.ChildSkill")); return true; } //Profile not loaded - if(UserManager.getPlayer(sender.getName()) == null) - { + if (UserManager.getPlayer(sender.getName()) == null) { sender.sendMessage(LocaleLoader.getString("Profile.PendingLoad")); return true; } - - editValues((Player) sender, UserManager.getPlayer(sender.getName()).getProfile(), skill, Integer.parseInt(args[1]), isSilent(args)); + editValues((Player) sender, UserManager.getPlayer(sender.getName()).getProfile(), + skill, Integer.parseInt(args[1]), isSilent(args)); return true; - } else if((args.length == 3 && !isSilent(args)) + } else if ((args.length == 3 && !isSilent(args)) || (args.length == 4 && isSilent(args))) { if (!permissionsCheckOthers(sender)) { sender.sendMessage(command.getPermissionMessage()); @@ -82,8 +81,7 @@ public abstract class ExperienceCommand implements TabExecutor { skill = null; } - if (skill != null && SkillTools.isChildSkill(skill)) - { + if (skill != null && SkillTools.isChildSkill(skill)) { sender.sendMessage(LocaleLoader.getString("Commands.Skill.ChildSkill")); return true; } @@ -91,10 +89,10 @@ public abstract class ExperienceCommand implements TabExecutor { int value = Integer.parseInt(args[2]); String playerName = CommandUtils.getMatchedPlayerName(args[0]); - McMMOPlayer mcMMOPlayer = UserManager.getOfflinePlayer(playerName); + final McMMOPlayer mmoPlayer = UserManager.getOfflinePlayer(playerName); - // If the mcMMOPlayer doesn't exist, create a temporary profile and check if it's present in the database. If it's not, abort the process. - if (mcMMOPlayer == null) { + // If the mmoPlayer doesn't exist, create a temporary profile and check if it's present in the database. If it's not, abort the process. + if (mmoPlayer == null) { PlayerProfile profile; profile = mcMMO.getDatabaseManager().loadPlayerProfile(playerName); @@ -104,15 +102,15 @@ public abstract class ExperienceCommand implements TabExecutor { //Check loading by name profile = mcMMO.getDatabaseManager().loadPlayerProfile(playerName); - if(CommandUtils.unloadedProfile(sender, profile)) { + if (CommandUtils.unloadedProfile(sender, profile)) { return true; } } editValues(null, profile, skill, value, isSilent(args)); - } - else { - editValues(mcMMOPlayer.getPlayer(), mcMMOPlayer.getProfile(), skill, value, isSilent(args)); + } else { + editValues(mmoPlayer.getPlayer(), mmoPlayer.getProfile(), skill, value, + isSilent(args)); } handleSenderMessage(sender, playerName, skill); @@ -126,46 +124,60 @@ public abstract class ExperienceCommand implements TabExecutor { private boolean isSilent(String[] args) { int length = args.length; - if(length == 0) + if (length == 0) { return false; + } - return args[length-1].equalsIgnoreCase("-s"); + return args[length - 1].equalsIgnoreCase("-s"); } @Override - public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, String[] args) { + public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, + @NotNull String alias, String[] args) { switch (args.length) { case 1: List playerNames = CommandUtils.getOnlinePlayerNames(sender); - return StringUtil.copyPartialMatches(args[0], playerNames, new ArrayList<>(playerNames.size())); + return StringUtil.copyPartialMatches(args[0], playerNames, + new ArrayList<>(playerNames.size())); case 2: - return StringUtil.copyPartialMatches(args[1], mcMMO.p.getSkillTools().LOCALIZED_SKILL_NAMES, new ArrayList<>(mcMMO.p.getSkillTools().LOCALIZED_SKILL_NAMES.size())); + return StringUtil.copyPartialMatches(args[1], + mcMMO.p.getSkillTools().LOCALIZED_SKILL_NAMES, + new ArrayList<>(mcMMO.p.getSkillTools().LOCALIZED_SKILL_NAMES.size())); default: return ImmutableList.of(); } } protected abstract boolean permissionsCheckSelf(CommandSender sender); + protected abstract boolean permissionsCheckOthers(CommandSender sender); - protected abstract void handleCommand(Player player, PlayerProfile profile, PrimarySkillType skill, int value); + + protected abstract void handleCommand(Player player, PlayerProfile profile, + PrimarySkillType skill, int value); + protected abstract void handlePlayerMessageAll(Player player, int value, boolean isSilent); - protected abstract void handlePlayerMessageSkill(Player player, int value, PrimarySkillType skill, boolean isSilent); + + protected abstract void handlePlayerMessageSkill(Player player, int value, + PrimarySkillType skill, boolean isSilent); private boolean validateArguments(CommandSender sender, String skillName, String value) { - return !(CommandUtils.isInvalidInteger(sender, value) || (!skillName.equalsIgnoreCase("all") && CommandUtils.isInvalidSkill(sender, skillName))); + return !(CommandUtils.isInvalidInteger(sender, value) || (!skillName.equalsIgnoreCase("all") + && CommandUtils.isInvalidSkill(sender, skillName))); } - protected static void handleSenderMessage(CommandSender sender, String playerName, PrimarySkillType skill) { + protected static void handleSenderMessage(CommandSender sender, String playerName, + PrimarySkillType skill) { if (skill == null) { sender.sendMessage(LocaleLoader.getString("Commands.addlevels.AwardAll.2", playerName)); - } - else { - sender.sendMessage(LocaleLoader.getString("Commands.addlevels.AwardSkill.2", mcMMO.p.getSkillTools().getLocalizedSkillName(skill), playerName)); + } else { + sender.sendMessage(LocaleLoader.getString("Commands.addlevels.AwardSkill.2", + mcMMO.p.getSkillTools().getLocalizedSkillName(skill), playerName)); } } - protected void editValues(Player player, PlayerProfile profile, PrimarySkillType skill, int value, boolean isSilent) { + protected void editValues(Player player, PlayerProfile profile, PrimarySkillType skill, + int value, boolean isSilent) { if (skill == null) { for (PrimarySkillType primarySkillType : SkillTools.NON_CHILD_SKILLS) { handleCommand(player, profile, primarySkillType, value); @@ -174,8 +186,7 @@ public abstract class ExperienceCommand implements TabExecutor { if (player != null) { handlePlayerMessageAll(player, value, isSilent); } - } - else { + } else { handleCommand(player, profile, skill, value); if (player != null) { diff --git a/src/main/java/com/gmail/nossr50/commands/experience/MmoeditCommand.java b/src/main/java/com/gmail/nossr50/commands/experience/MmoeditCommand.java index 93089ac69..954e83edd 100644 --- a/src/main/java/com/gmail/nossr50/commands/experience/MmoeditCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/experience/MmoeditCommand.java @@ -24,7 +24,8 @@ public class MmoeditCommand extends ExperienceCommand { } @Override - protected void handleCommand(Player player, PlayerProfile profile, PrimarySkillType skill, int value) { + protected void handleCommand(Player player, PlayerProfile profile, PrimarySkillType skill, + int value) { int skillLevel = profile.getSkillLevel(skill); float xpRemoved = profile.getSkillXpLevelRaw(skill); @@ -39,29 +40,35 @@ public class MmoeditCommand extends ExperienceCommand { return; } - McMMOPlayer mmoPlayer = UserManager.getPlayer(player); + final McMMOPlayer mmoPlayer = UserManager.getPlayer(player); - if(mmoPlayer != null) { - EventUtils.tryLevelEditEvent(mmoPlayer, skill, value, xpRemoved, value > skillLevel, XPGainReason.COMMAND, skillLevel); + if (mmoPlayer != null) { + EventUtils.tryLevelEditEvent(mmoPlayer, skill, value, xpRemoved, value > skillLevel, + XPGainReason.COMMAND, skillLevel); } else { - EventUtils.tryLevelEditEvent(player, skill, value, xpRemoved, value > skillLevel, XPGainReason.COMMAND, skillLevel); + EventUtils.tryLevelEditEvent(player, skill, value, xpRemoved, value > skillLevel, + XPGainReason.COMMAND, skillLevel); } } @Override protected void handlePlayerMessageAll(Player player, int value, boolean isSilent) { - if(isSilent) + if (isSilent) { return; + } player.sendMessage(LocaleLoader.getString("Commands.mmoedit.AllSkills.1", value)); } @Override - protected void handlePlayerMessageSkill(Player player, int value, PrimarySkillType skill, boolean isSilent) { - if(isSilent) + protected void handlePlayerMessageSkill(Player player, int value, PrimarySkillType skill, + boolean isSilent) { + if (isSilent) { return; + } - player.sendMessage(LocaleLoader.getString("Commands.mmoedit.Modified.1", mcMMO.p.getSkillTools().getLocalizedSkillName(skill), value)); + player.sendMessage(LocaleLoader.getString("Commands.mmoedit.Modified.1", + mcMMO.p.getSkillTools().getLocalizedSkillName(skill), value)); } } diff --git a/src/main/java/com/gmail/nossr50/commands/experience/SkillresetCommand.java b/src/main/java/com/gmail/nossr50/commands/experience/SkillresetCommand.java index edc99e2ad..8364f7bfd 100644 --- a/src/main/java/com/gmail/nossr50/commands/experience/SkillresetCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/experience/SkillresetCommand.java @@ -12,6 +12,8 @@ import com.gmail.nossr50.util.commands.CommandUtils; import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.skills.SkillTools; import com.google.common.collect.ImmutableList; +import java.util.ArrayList; +import java.util.List; import org.bukkit.OfflinePlayer; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; @@ -20,16 +22,14 @@ import org.bukkit.entity.Player; import org.bukkit.util.StringUtil; import org.jetbrains.annotations.NotNull; -import java.util.ArrayList; -import java.util.List; - /** - * This class mirrors the structure of ExperienceCommand, except the - * value/quantity argument is removed. + * This class mirrors the structure of ExperienceCommand, except the value/quantity argument is + * removed. */ public class SkillresetCommand implements TabExecutor { @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, + @NotNull String label, String[] args) { PrimarySkillType skill; switch (args.length) { case 1: @@ -48,12 +48,12 @@ public class SkillresetCommand implements TabExecutor { if (args[0].equalsIgnoreCase("all")) { skill = null; - } - else { + } else { skill = mcMMO.p.getSkillTools().matchSkill(args[0]); } - editValues((Player) sender, UserManager.getPlayer(sender.getName()).getProfile(), skill); + editValues((Player) sender, UserManager.getPlayer(sender.getName()).getProfile(), + skill); return true; case 2: @@ -68,18 +68,18 @@ public class SkillresetCommand implements TabExecutor { if (args[1].equalsIgnoreCase("all")) { skill = null; - } - else { + } else { skill = mcMMO.p.getSkillTools().matchSkill(args[1]); } String playerName = CommandUtils.getMatchedPlayerName(args[0]); - McMMOPlayer mcMMOPlayer = UserManager.getOfflinePlayer(playerName); + final McMMOPlayer mmoPlayer = UserManager.getOfflinePlayer(playerName); - // If the mcMMOPlayer doesn't exist, create a temporary profile and check if it's present in the database. If it's not, abort the process. - if (mcMMOPlayer == null) { + // If the mmoPlayer doesn't exist, create a temporary profile and check if it's present in the database. If it's not, abort the process. + if (mmoPlayer == null) { OfflinePlayer offlinePlayer = mcMMO.p.getServer().getOfflinePlayer(playerName); - PlayerProfile profile = mcMMO.getDatabaseManager().loadPlayerProfile(offlinePlayer); + PlayerProfile profile = mcMMO.getDatabaseManager() + .loadPlayerProfile(offlinePlayer); //Check loading by UUID if (CommandUtils.unloadedProfile(sender, profile)) { @@ -87,15 +87,14 @@ public class SkillresetCommand implements TabExecutor { profile = mcMMO.getDatabaseManager().loadPlayerProfile(playerName); //Check if it was present in DB - if(CommandUtils.unloadedProfile(sender, profile)) { + if (CommandUtils.unloadedProfile(sender, profile)) { return true; } } editValues(null, profile, skill); - } - else { - editValues(mcMMOPlayer.getPlayer(), mcMMOPlayer.getProfile(), skill); + } else { + editValues(mmoPlayer.getPlayer(), mmoPlayer.getProfile(), skill); } handleSenderMessage(sender, playerName, skill); @@ -107,13 +106,17 @@ public class SkillresetCommand implements TabExecutor { } @Override - public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, String[] args) { + public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, + @NotNull String alias, String[] args) { switch (args.length) { case 1: List playerNames = CommandUtils.getOnlinePlayerNames(sender); - return StringUtil.copyPartialMatches(args[0], playerNames, new ArrayList<>(playerNames.size())); + return StringUtil.copyPartialMatches(args[0], playerNames, + new ArrayList<>(playerNames.size())); case 2: - return StringUtil.copyPartialMatches(args[1], mcMMO.p.getSkillTools().LOCALIZED_SKILL_NAMES, new ArrayList<>(mcMMO.p.getSkillTools().LOCALIZED_SKILL_NAMES.size())); + return StringUtil.copyPartialMatches(args[1], + mcMMO.p.getSkillTools().LOCALIZED_SKILL_NAMES, + new ArrayList<>(mcMMO.p.getSkillTools().LOCALIZED_SKILL_NAMES.size())); default: return ImmutableList.of(); } @@ -130,7 +133,8 @@ public class SkillresetCommand implements TabExecutor { return; } - EventUtils.tryLevelChangeEvent(player, skill, levelsRemoved, xpRemoved, false, XPGainReason.COMMAND); + EventUtils.tryLevelChangeEvent(player, skill, levelsRemoved, xpRemoved, false, + XPGainReason.COMMAND); } protected boolean permissionsCheckSelf(CommandSender sender) { @@ -146,19 +150,21 @@ public class SkillresetCommand implements TabExecutor { } protected void handlePlayerMessageSkill(Player player, PrimarySkillType skill) { - player.sendMessage(LocaleLoader.getString("Commands.Reset.Single", mcMMO.p.getSkillTools().getLocalizedSkillName(skill))); + player.sendMessage(LocaleLoader.getString("Commands.Reset.Single", + mcMMO.p.getSkillTools().getLocalizedSkillName(skill))); } private boolean validateArguments(CommandSender sender, String skillName) { return skillName.equalsIgnoreCase("all") || !CommandUtils.isInvalidSkill(sender, skillName); } - protected static void handleSenderMessage(CommandSender sender, String playerName, PrimarySkillType skill) { + protected static void handleSenderMessage(CommandSender sender, String playerName, + PrimarySkillType skill) { if (skill == null) { sender.sendMessage(LocaleLoader.getString("Commands.addlevels.AwardAll.2", playerName)); - } - else { - sender.sendMessage(LocaleLoader.getString("Commands.addlevels.AwardSkill.2", mcMMO.p.getSkillTools().getLocalizedSkillName(skill), playerName)); + } else { + sender.sendMessage(LocaleLoader.getString("Commands.addlevels.AwardSkill.2", + mcMMO.p.getSkillTools().getLocalizedSkillName(skill), playerName)); } } @@ -171,8 +177,7 @@ public class SkillresetCommand implements TabExecutor { if (player != null) { handlePlayerMessageAll(player); } - } - else { + } else { handleCommand(player, profile, skill); if (player != null) { diff --git a/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommand.java b/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommand.java index 1e88f8158..fdd93906b 100644 --- a/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommand.java @@ -4,17 +4,16 @@ import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.LogUtils; -import org.bukkit.Bukkit; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.annotations.VisibleForTesting; - import java.util.LinkedList; import java.util.List; import java.util.Objects; import java.util.Set; import java.util.function.BiPredicate; import java.util.function.Predicate; +import org.bukkit.Bukkit; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.VisibleForTesting; public class LevelUpCommand implements CommandsOnLevel { private final @Nullable List> conditions; @@ -23,24 +22,30 @@ public class LevelUpCommand implements CommandsOnLevel { private final @NotNull LinkedList commands; public LevelUpCommand(@Nullable List> conditions, - @Nullable Predicate powerLevelCondition, - @NotNull LinkedList commands, boolean logInfo) { + @Nullable Predicate powerLevelCondition, + @NotNull LinkedList commands, boolean logInfo) { this.conditions = conditions; this.powerLevelCondition = powerLevelCondition; - if (conditions == null && powerLevelCondition == null) + if (conditions == null && powerLevelCondition == null) { throw new IllegalArgumentException("At least one condition must be set"); + } this.commands = commands; this.logInfo = logInfo; } - public void process(@NotNull McMMOPlayer player, @NotNull PrimarySkillType primarySkillType, @NotNull Set levelsGained, - @NotNull Set powerLevelsGained) { + public void process(@NotNull McMMOPlayer player, @NotNull PrimarySkillType primarySkillType, + @NotNull Set levelsGained, + @NotNull Set powerLevelsGained) { // each predicate has to pass at least once // we check the predicates against all levels gained to see if they pass at least once // if all predicates pass at least once, we execute the command - boolean allConditionsPass = (conditions == null) || conditions.stream().allMatch(predicate -> levelsGained.stream().anyMatch(level -> predicate.test(primarySkillType, level))); + boolean allConditionsPass = (conditions == null) || conditions.stream().allMatch( + predicate -> levelsGained.stream() + .anyMatch(level -> predicate.test(primarySkillType, level))); // we also check the power level predicate to see if it passes at least once, if this predicate is null, we mark it as passed - boolean powerLevelConditionPass = (powerLevelCondition == null) || powerLevelsGained.stream().anyMatch(powerLevelCondition); + boolean powerLevelConditionPass = + (powerLevelCondition == null) || powerLevelsGained.stream() + .anyMatch(powerLevelCondition); if (allConditionsPass && powerLevelConditionPass) { executeCommand(player); } @@ -53,7 +58,8 @@ public class LevelUpCommand implements CommandsOnLevel { LogUtils.debug(mcMMO.p.getLogger(), "Executing command: " + command); String injectedCommand = injectedCommand(command, player); if (!injectedCommand.equalsIgnoreCase(command)) { - LogUtils.debug(mcMMO.p.getLogger(), ("Command has been injected with new values: " + injectedCommand)); + LogUtils.debug(mcMMO.p.getLogger(), + ("Command has been injected with new values: " + injectedCommand)); } Bukkit.dispatchCommand(Bukkit.getConsoleSender(), injectedCommand); } @@ -69,7 +75,8 @@ public class LevelUpCommand implements CommandsOnLevel { // Replace each skill level for (PrimarySkillType primarySkillType : PrimarySkillType.values()) { - if (primarySkillType == PrimarySkillType.SMELTING || primarySkillType == PrimarySkillType.SALVAGE) { + if (primarySkillType == PrimarySkillType.SMELTING + || primarySkillType == PrimarySkillType.SALVAGE) { continue; } replaceAll(commandBuilder, "{@" + primarySkillType.name().toLowerCase() + "_level}", @@ -92,10 +99,15 @@ public class LevelUpCommand implements CommandsOnLevel { @Override public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } LevelUpCommand that = (LevelUpCommand) o; - return logInfo == that.logInfo && Objects.equals(conditions, that.conditions) && Objects.equals(commands, that.commands); + return logInfo == that.logInfo && Objects.equals(conditions, that.conditions) + && Objects.equals(commands, that.commands); } @Override diff --git a/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommandBuilder.java b/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommandBuilder.java index d3366e2a8..63e66793c 100644 --- a/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommandBuilder.java +++ b/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommandBuilder.java @@ -1,16 +1,14 @@ package com.gmail.nossr50.commands.levelup; -import com.gmail.nossr50.datatypes.player.McMMOPlayer; -import com.gmail.nossr50.datatypes.skills.PrimarySkillType; -import org.jetbrains.annotations.NotNull; +import static java.util.Objects.requireNonNull; +import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import java.util.Collection; import java.util.LinkedList; import java.util.List; import java.util.function.BiPredicate; import java.util.function.Predicate; - -import static java.util.Objects.requireNonNull; +import org.jetbrains.annotations.NotNull; public class LevelUpCommandBuilder { private LinkedList commands = null; diff --git a/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommandManager.java b/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommandManager.java index 056ec6771..5e70315a9 100644 --- a/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommandManager.java +++ b/src/main/java/com/gmail/nossr50/commands/levelup/LevelUpCommandManager.java @@ -1,16 +1,15 @@ package com.gmail.nossr50.commands.levelup; +import static java.util.Objects.requireNonNull; + import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.LogUtils; -import org.jetbrains.annotations.NotNull; - import java.util.HashSet; import java.util.Objects; import java.util.Set; - -import static java.util.Objects.requireNonNull; +import org.jetbrains.annotations.NotNull; /** * Manages commands to be executed on level up @@ -27,18 +26,20 @@ public class LevelUpCommandManager { public void registerCommand(@NotNull LevelUpCommand levelUpCommand) { requireNonNull(levelUpCommand, "skillLevelUpCommand cannot be null"); levelUpCommands.add(levelUpCommand); - LogUtils.debug(mcMMO.p.getLogger(), "Registered level up command - SkillLevelUpCommand: " + levelUpCommand); + LogUtils.debug(mcMMO.p.getLogger(), + "Registered level up command - SkillLevelUpCommand: " + levelUpCommand); } /** * Apply the level up commands to the player * - * @param mmoPlayer the player - * @param primarySkillType the skill type - * @param levelsGained the levels gained + * @param mmoPlayer the player + * @param primarySkillType the skill type + * @param levelsGained the levels gained */ - public void applySkillLevelUp(@NotNull McMMOPlayer mmoPlayer, @NotNull PrimarySkillType primarySkillType, - Set levelsGained, Set powerLevelsGained) { + public void applySkillLevelUp(@NotNull McMMOPlayer mmoPlayer, + @NotNull PrimarySkillType primarySkillType, + Set levelsGained, Set powerLevelsGained) { if (!mmoPlayer.getPlayer().isOnline()) { return; } @@ -62,10 +63,15 @@ public class LevelUpCommandManager { @Override public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } LevelUpCommandManager that = (LevelUpCommandManager) o; - return Objects.equals(levelUpCommands, that.levelUpCommands) && Objects.equals(plugin, that.plugin); + return Objects.equals(levelUpCommands, that.levelUpCommands) && Objects.equals(plugin, + that.plugin); } @Override 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 09cb1165e..248a72c08 100644 --- a/src/main/java/com/gmail/nossr50/commands/party/PartyAcceptCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/party/PartyAcceptCommand.java @@ -2,7 +2,7 @@ package com.gmail.nossr50.commands.party; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.locale.LocaleLoader; -import com.gmail.nossr50.party.PartyManager; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.player.UserManager; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; @@ -12,9 +12,10 @@ import org.jetbrains.annotations.NotNull; public class PartyAcceptCommand implements CommandExecutor { @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, + @NotNull String label, String[] args) { if (args.length == 1) { - Player player = (Player) sender; + final Player player = (Player) sender; //Check if player profile is loaded if (UserManager.getPlayer(player) == null) { @@ -22,20 +23,20 @@ public class PartyAcceptCommand implements CommandExecutor { return true; } - McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player); + final McMMOPlayer mmoPlayer = UserManager.getPlayer(player); - - if (!mcMMOPlayer.hasPartyInvite()) { + if (!mmoPlayer.hasPartyInvite()) { sender.sendMessage(LocaleLoader.getString("mcMMO.NoInvites")); return true; } // Changing parties - if (!PartyManager.changeOrJoinParty(mcMMOPlayer, mcMMOPlayer.getPartyInvite().getName())) { + if (!mcMMO.p.getPartyManager() + .changeOrJoinParty(mmoPlayer, mmoPlayer.getPartyInvite().getName())) { return true; } - PartyManager.joinInvitedParty(mcMMOPlayer); + mcMMO.p.getPartyManager().joinInvitedParty(mmoPlayer); return true; } sender.sendMessage(LocaleLoader.getString("Commands.Usage.1", "party", "accept")); 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 a918a3ce9..03a35b382 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 @@ package com.gmail.nossr50.commands.party; 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; @@ -15,7 +14,8 @@ import org.jetbrains.annotations.NotNull; public class PartyChangeOwnerCommand implements CommandExecutor { @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, + @NotNull String label, String[] args) { if (args.length == 2) {//Check if player profile is loaded if (UserManager.getPlayer((Player) sender) == null) { sender.sendMessage(LocaleLoader.getString("Profile.PendingLoad")); @@ -31,10 +31,11 @@ public class PartyChangeOwnerCommand implements CommandExecutor { return true; } - PartyManager.setPartyLeader(target.getUniqueId(), playerParty); + mcMMO.p.getPartyManager().setPartyLeader(target.getUniqueId(), playerParty); return true; } - sender.sendMessage(LocaleLoader.getString("Commands.Usage.2", "party", "owner", "<" + LocaleLoader.getString("Commands.Usage.Player") + ">")); + sender.sendMessage(LocaleLoader.getString("Commands.Usage.2", "party", "owner", + "<" + LocaleLoader.getString("Commands.Usage.Player") + ">")); return true; } } diff --git a/src/main/java/com/gmail/nossr50/commands/party/PartyChangePasswordCommand.java b/src/main/java/com/gmail/nossr50/commands/party/PartyChangePasswordCommand.java index b8d835ef3..706342142 100644 --- a/src/main/java/com/gmail/nossr50/commands/party/PartyChangePasswordCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/party/PartyChangePasswordCommand.java @@ -11,9 +11,9 @@ import org.jetbrains.annotations.NotNull; public class PartyChangePasswordCommand implements CommandExecutor { @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { - if(UserManager.getPlayer((Player) sender) == null) - { + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, + @NotNull String label, String[] args) { + if (UserManager.getPlayer((Player) sender) == null) { sender.sendMessage(LocaleLoader.getString("Profile.PendingLoad")); return true; } @@ -35,8 +35,10 @@ public class PartyChangePasswordCommand implements CommandExecutor { return true; default: - sender.sendMessage(LocaleLoader.getString("Commands.Usage.2", "party", "password", "[clear|reset]")); - sender.sendMessage(LocaleLoader.getString("Commands.Usage.2", "party", "password", "<" + LocaleLoader.getString("Commands.Usage.Password") + ">")); + sender.sendMessage(LocaleLoader.getString("Commands.Usage.2", "party", "password", + "[clear|reset]")); + sender.sendMessage(LocaleLoader.getString("Commands.Usage.2", "party", "password", + "<" + LocaleLoader.getString("Commands.Usage.Password") + ">")); return true; } } diff --git a/src/main/java/com/gmail/nossr50/commands/party/PartyCommand.java b/src/main/java/com/gmail/nossr50/commands/party/PartyCommand.java index 752552747..27b1030e6 100644 --- a/src/main/java/com/gmail/nossr50/commands/party/PartyCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/party/PartyCommand.java @@ -9,6 +9,10 @@ import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.commands.CommandUtils; import com.gmail.nossr50.util.player.UserManager; import com.google.common.collect.ImmutableList; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; @@ -17,17 +21,48 @@ import org.bukkit.entity.Player; import org.bukkit.util.StringUtil; import org.jetbrains.annotations.NotNull; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - public class PartyCommand implements TabExecutor { - private static final List PARTY_SUBCOMMANDS; - private static final List XPSHARE_COMPLETIONS = ImmutableList.of("none", "equal"); - private static final List ITEMSHARE_COMPLETIONS = ImmutableList.of("none", "equal", "random", "loot", "mining", "herbalism", "woodcutting", "misc"); + private final List PARTY_SUBCOMMANDS; + private final List XPSHARE_COMPLETIONS = ImmutableList.of("none", "equal"); + private final List ITEMSHARE_COMPLETIONS = ImmutableList.of("none", "equal", "random", + "loot", "mining", "herbalism", "woodcutting", "misc"); + private final CommandExecutor partyJoinCommand; + private final CommandExecutor partyAcceptCommand; + private final CommandExecutor partyCreateCommand; + private final CommandExecutor partyQuitCommand; + private final CommandExecutor partyXpShareCommand; + private final CommandExecutor partyItemShareCommand; + private final CommandExecutor partyInviteCommand; + private final CommandExecutor partyKickCommand; + private final CommandExecutor partyDisbandCommand; + private final CommandExecutor partyChangeOwnerCommand; + private final CommandExecutor partyLockCommand; + private final CommandExecutor partyChangePasswordCommand; + private final CommandExecutor partyRenameCommand; + private final CommandExecutor partyInfoCommand; + private final CommandExecutor partyHelpCommand; + private final CommandExecutor partyTeleportCommand; + private final CommandExecutor partyAllianceCommand; + + public PartyCommand() { + partyJoinCommand = new PartyJoinCommand(); + partyAcceptCommand = new PartyAcceptCommand(); + partyCreateCommand = new PartyCreateCommand(); + partyQuitCommand = new PartyQuitCommand(); + partyXpShareCommand = new PartyXpShareCommand(); + partyItemShareCommand = new PartyItemShareCommand(); + partyInviteCommand = new PartyInviteCommand(); + partyKickCommand = new PartyKickCommand(); + partyDisbandCommand = new PartyDisbandCommand(); + partyChangeOwnerCommand = new PartyChangeOwnerCommand(); + partyLockCommand = new PartyLockCommand(); + partyChangePasswordCommand = new PartyChangePasswordCommand(); + partyRenameCommand = new PartyRenameCommand(); + partyInfoCommand = new PartyInfoCommand(); + partyHelpCommand = new PartyHelpCommand(); + partyTeleportCommand = new PtpCommand(); + partyAllianceCommand = new PartyAllianceCommand(); - static { ArrayList subcommands = new ArrayList<>(); for (PartySubcommandType subcommand : PartySubcommandType.values()) { @@ -38,26 +73,9 @@ public class PartyCommand implements TabExecutor { PARTY_SUBCOMMANDS = ImmutableList.copyOf(subcommands); } - private final CommandExecutor partyJoinCommand = new PartyJoinCommand(); - private final CommandExecutor partyAcceptCommand = new PartyAcceptCommand(); - private final CommandExecutor partyCreateCommand = new PartyCreateCommand(); - private final CommandExecutor partyQuitCommand = new PartyQuitCommand(); - private final CommandExecutor partyXpShareCommand = new PartyXpShareCommand(); - private final CommandExecutor partyItemShareCommand = new PartyItemShareCommand(); - private final CommandExecutor partyInviteCommand = new PartyInviteCommand(); - private final CommandExecutor partyKickCommand = new PartyKickCommand(); - private final CommandExecutor partyDisbandCommand = new PartyDisbandCommand(); - private final CommandExecutor partyChangeOwnerCommand = new PartyChangeOwnerCommand(); - private final CommandExecutor partyLockCommand = new PartyLockCommand(); - private final CommandExecutor partyChangePasswordCommand = new PartyChangePasswordCommand(); - private final CommandExecutor partyRenameCommand = new PartyRenameCommand(); - private final CommandExecutor partyInfoCommand = new PartyInfoCommand(); - private final CommandExecutor partyHelpCommand = new PartyHelpCommand(); - private final CommandExecutor partyTeleportCommand = new PtpCommand(); - private final CommandExecutor partyAllianceCommand = new PartyAllianceCommand(); - @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, + @NotNull String label, String[] args) { if (CommandUtils.noConsoleUsage(sender)) { return true; } @@ -67,22 +85,20 @@ public class PartyCommand implements TabExecutor { return true; } - Player player = (Player) sender; + final Player player = (Player) sender; if (!UserManager.hasPlayerDataKey(player)) { return true; } - if(UserManager.getPlayer(player) == null) - { + final McMMOPlayer mmoPlayer = UserManager.getPlayer(player); + if (mmoPlayer == null) { player.sendMessage(LocaleLoader.getString("Profile.PendingLoad")); return true; } - McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player); - if (args.length < 1) { - if (!mcMMOPlayer.inParty()) { + if (!mmoPlayer.inParty()) { sender.sendMessage(LocaleLoader.getString("Commands.Party.None")); return printUsage(player); } @@ -97,7 +113,8 @@ public class PartyCommand implements TabExecutor { } // Can't use this for lock/unlock since they're handled by the same command - if (subcommand != PartySubcommandType.LOCK && subcommand != PartySubcommandType.UNLOCK && !Permissions.partySubcommand(sender, subcommand)) { + if (subcommand != PartySubcommandType.LOCK && subcommand != PartySubcommandType.UNLOCK + && !Permissions.partySubcommand(sender, subcommand)) { sender.sendMessage(command.getPermissionMessage()); return true; } @@ -116,7 +133,7 @@ public class PartyCommand implements TabExecutor { } // Party member commands - if (!mcMMOPlayer.inParty()) { + if (!mmoPlayer.inParty()) { sender.sendMessage(LocaleLoader.getString("Commands.Party.None")); return printUsage(player); } @@ -135,43 +152,32 @@ public class PartyCommand implements TabExecutor { } // Party leader commands - if (!mcMMOPlayer.getParty().getLeader().getUniqueId().equals(player.getUniqueId())) { + if (!mmoPlayer.getParty().getLeader().getUniqueId().equals(player.getUniqueId())) { sender.sendMessage(LocaleLoader.getString("Party.NotOwner")); return true; } - switch (subcommand) { - case XPSHARE: - return partyXpShareCommand.onCommand(sender, command, label, args); - case ITEMSHARE: - return partyItemShareCommand.onCommand(sender, command, label, args); - case KICK: - return partyKickCommand.onCommand(sender, command, label, args); - case DISBAND: - return partyDisbandCommand.onCommand(sender, command, label, args); - case OWNER: - return partyChangeOwnerCommand.onCommand(sender, command, label, args); - case LOCK: - case UNLOCK: - return partyLockCommand.onCommand(sender, command, label, args); - case PASSWORD: - return partyChangePasswordCommand.onCommand(sender, command, label, args); - case RENAME: - return partyRenameCommand.onCommand(sender, command, label, args); - case ALLIANCE: - return partyAllianceCommand.onCommand(sender, command, label, args); - default: - break; - } - - return true; + return switch (subcommand) { + case XPSHARE -> partyXpShareCommand.onCommand(sender, command, label, args); + case ITEMSHARE -> partyItemShareCommand.onCommand(sender, command, label, args); + case KICK -> partyKickCommand.onCommand(sender, command, label, args); + case DISBAND -> partyDisbandCommand.onCommand(sender, command, label, args); + case OWNER -> partyChangeOwnerCommand.onCommand(sender, command, label, args); + case LOCK, UNLOCK -> partyLockCommand.onCommand(sender, command, label, args); + case PASSWORD -> partyChangePasswordCommand.onCommand(sender, command, label, args); + case RENAME -> partyRenameCommand.onCommand(sender, command, label, args); + case ALLIANCE -> partyAllianceCommand.onCommand(sender, command, label, args); + default -> true; + }; } @Override - public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, String[] args) { + public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, + @NotNull String alias, String[] args) { switch (args.length) { case 1: - return StringUtil.copyPartialMatches(args[0], PARTY_SUBCOMMANDS, new ArrayList<>(PARTY_SUBCOMMANDS.size())); + return StringUtil.copyPartialMatches(args[0], PARTY_SUBCOMMANDS, + new ArrayList<>(PARTY_SUBCOMMANDS.size())); case 2: PartySubcommandType subcommand = PartySubcommandType.getSubcommand(args[0]); @@ -179,43 +185,53 @@ public class PartyCommand implements TabExecutor { return ImmutableList.of(); } + List playerNames = CommandUtils.getOnlinePlayerNames(sender); + switch (subcommand) { case JOIN: case INVITE: case KICK: case OWNER: - List playerNames = CommandUtils.getOnlinePlayerNames(sender); - return StringUtil.copyPartialMatches(args[1], playerNames, new ArrayList<>(playerNames.size())); + return StringUtil.copyPartialMatches(args[1], playerNames, + new ArrayList<>(playerNames.size())); case XPSHARE: - return StringUtil.copyPartialMatches(args[1], XPSHARE_COMPLETIONS, new ArrayList<>(XPSHARE_COMPLETIONS.size())); + return StringUtil.copyPartialMatches(args[1], XPSHARE_COMPLETIONS, + new ArrayList<>(XPSHARE_COMPLETIONS.size())); case ITEMSHARE: - return StringUtil.copyPartialMatches(args[1], ITEMSHARE_COMPLETIONS, new ArrayList<>(ITEMSHARE_COMPLETIONS.size())); + return StringUtil.copyPartialMatches(args[1], ITEMSHARE_COMPLETIONS, + new ArrayList<>(ITEMSHARE_COMPLETIONS.size())); case LOCK: case CHAT: - return StringUtil.copyPartialMatches(args[1], CommandUtils.TRUE_FALSE_OPTIONS, new ArrayList<>(CommandUtils.TRUE_FALSE_OPTIONS.size())); + return StringUtil.copyPartialMatches(args[1], + CommandUtils.TRUE_FALSE_OPTIONS, + new ArrayList<>(CommandUtils.TRUE_FALSE_OPTIONS.size())); case PASSWORD: - return StringUtil.copyPartialMatches(args[1], CommandUtils.RESET_OPTIONS, new ArrayList<>(CommandUtils.RESET_OPTIONS.size())); + return StringUtil.copyPartialMatches(args[1], CommandUtils.RESET_OPTIONS, + new ArrayList<>(CommandUtils.RESET_OPTIONS.size())); case TELEPORT: - List matches = StringUtil.copyPartialMatches(args[1], PtpCommand.TELEPORT_SUBCOMMANDS, new ArrayList<>(PtpCommand.TELEPORT_SUBCOMMANDS.size())); + List matches = StringUtil.copyPartialMatches(args[1], + PtpCommand.TELEPORT_SUBCOMMANDS, + new ArrayList<>(PtpCommand.TELEPORT_SUBCOMMANDS.size())); - if (matches.size() == 0) { - Player player = (Player) sender; - final McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player); + if (matches.isEmpty()) { + final Player player = (Player) sender; + final McMMOPlayer mmoPlayer = UserManager.getPlayer(player); //Not Loaded - if(mcMMOPlayer == null) - { + if (mmoPlayer == null) { sender.sendMessage(LocaleLoader.getString("Profile.PendingLoad")); return ImmutableList.of(); } - if (mcMMOPlayer.getParty() == null) + if (mmoPlayer.getParty() == null) { return ImmutableList.of(); + } - final Party party = mcMMOPlayer.getParty(); + final Party party = mmoPlayer.getParty(); playerNames = party.getOnlinePlayerNames(player); - return StringUtil.copyPartialMatches(args[1], playerNames, new ArrayList<>(playerNames.size())); + return StringUtil.copyPartialMatches(args[1], playerNames, + new ArrayList<>(playerNames.size())); } return matches; @@ -223,8 +239,10 @@ public class PartyCommand implements TabExecutor { return ImmutableList.of(); } case 3: - if (PartySubcommandType.getSubcommand(args[0]) == PartySubcommandType.ITEMSHARE && isItemShareCategory(args[1])) { - return StringUtil.copyPartialMatches(args[2], CommandUtils.TRUE_FALSE_OPTIONS, new ArrayList<>(CommandUtils.TRUE_FALSE_OPTIONS.size())); + if (PartySubcommandType.getSubcommand(args[0]) == PartySubcommandType.ITEMSHARE + && isItemShareCategory(args[1])) { + return StringUtil.copyPartialMatches(args[2], CommandUtils.TRUE_FALSE_OPTIONS, + new ArrayList<>(CommandUtils.TRUE_FALSE_OPTIONS.size())); } return ImmutableList.of(); @@ -245,7 +263,9 @@ public class PartyCommand implements TabExecutor { } private boolean isItemShareCategory(String category) { - return category.equalsIgnoreCase("loot") || category.equalsIgnoreCase("mining") || category.equalsIgnoreCase("herbalism") || category.equalsIgnoreCase("woodcutting") || category.equalsIgnoreCase("misc"); + return category.equalsIgnoreCase("loot") || category.equalsIgnoreCase("mining") + || category.equalsIgnoreCase("herbalism") || category.equalsIgnoreCase( + "woodcutting") || category.equalsIgnoreCase("misc"); } } 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 34daed151..72dcb5094 100644 --- a/src/main/java/com/gmail/nossr50/commands/party/PartyCreateCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/party/PartyCreateCommand.java @@ -2,7 +2,7 @@ package com.gmail.nossr50.commands.party; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.locale.LocaleLoader; -import com.gmail.nossr50.party.PartyManager; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.player.UserManager; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; @@ -12,34 +12,36 @@ import org.jetbrains.annotations.NotNull; public class PartyCreateCommand implements CommandExecutor { @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, + @NotNull String label, String[] args) { switch (args.length) { case 2: case 3: - Player player = (Player) sender; - McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player); + final Player player = (Player) sender; + final McMMOPlayer mmoPlayer = UserManager.getPlayer(player); - if(UserManager.getPlayer(player) == null) - { + if (UserManager.getPlayer(player) == null) { player.sendMessage(LocaleLoader.getString("Profile.PendingLoad")); return true; } // Check to see if the party exists, and if it does cancel creating a new party - if (PartyManager.checkPartyExistence(player, args[1])) { + if (mcMMO.p.getPartyManager().checkPartyExistence(player, args[1])) { return true; } // Changing parties - if (!PartyManager.changeOrJoinParty(mcMMOPlayer, args[1])) { + if (!mcMMO.p.getPartyManager().changeOrJoinParty(mmoPlayer, args[1])) { return true; } - PartyManager.createParty(mcMMOPlayer, args[1], getPassword(args)); + mcMMO.p.getPartyManager().createParty(mmoPlayer, args[1], getPassword(args)); return true; default: - sender.sendMessage(LocaleLoader.getString("Commands.Usage.3", "party", "create", "<" + LocaleLoader.getString("Commands.Usage.PartyName") + ">", "[" + LocaleLoader.getString("Commands.Usage.Password") + "]")); + sender.sendMessage(LocaleLoader.getString("Commands.Usage.3", "party", "create", + "<" + LocaleLoader.getString("Commands.Usage.PartyName") + ">", + "[" + LocaleLoader.getString("Commands.Usage.Password") + "]")); return true; } } 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 e21776370..5016a24bc 100644 --- a/src/main/java/com/gmail/nossr50/commands/party/PartyDisbandCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/party/PartyDisbandCommand.java @@ -4,7 +4,7 @@ import com.gmail.nossr50.datatypes.party.Party; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.events.party.McMMOPartyChangeEvent.EventReason; import com.gmail.nossr50.locale.LocaleLoader; -import com.gmail.nossr50.party.PartyManager; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.player.UserManager; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; @@ -14,26 +14,28 @@ import org.jetbrains.annotations.NotNull; public class PartyDisbandCommand implements CommandExecutor { @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, + @NotNull String label, String[] args) { if (args.length == 1) { - final McMMOPlayer mcMMOPlayer = UserManager.getPlayer((Player) sender); - if (mcMMOPlayer == null) { + final McMMOPlayer mmoPlayer = UserManager.getPlayer((Player) sender); + if (mmoPlayer == null) { sender.sendMessage(LocaleLoader.getString("Profile.PendingLoad")); return true; } - final Party playerParty = mcMMOPlayer.getParty(); + final Party playerParty = mmoPlayer.getParty(); final String partyName = playerParty.getName(); for (Player member : playerParty.getOnlineMembers()) { - if (!PartyManager.handlePartyChangeEvent(member, partyName, null, EventReason.KICKED_FROM_PARTY)) { + if (!mcMMO.p.getPartyManager().handlePartyChangeEvent(member, partyName, null, + EventReason.KICKED_FROM_PARTY)) { return true; } member.sendMessage(LocaleLoader.getString("Party.Disband")); } - PartyManager.disbandParty(mcMMOPlayer, playerParty); + mcMMO.p.getPartyManager().disbandParty(mmoPlayer, playerParty); return true; } sender.sendMessage(LocaleLoader.getString("Commands.Usage.1", "party", "disband")); diff --git a/src/main/java/com/gmail/nossr50/commands/party/PartyHelpCommand.java b/src/main/java/com/gmail/nossr50/commands/party/PartyHelpCommand.java index bbf906a06..1365a6c72 100644 --- a/src/main/java/com/gmail/nossr50/commands/party/PartyHelpCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/party/PartyHelpCommand.java @@ -9,9 +9,11 @@ import org.jetbrains.annotations.NotNull; public class PartyHelpCommand implements CommandExecutor { @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, + @NotNull String label, String[] args) { if (args.length == 1) { - sender.sendMessage(LocaleLoader.getString("Party.Help.3", "/party join", "/party quit")); + sender.sendMessage( + LocaleLoader.getString("Party.Help.3", "/party join", "/party quit")); sender.sendMessage(LocaleLoader.getString("Party.Help.1", "/party create")); sender.sendMessage(LocaleLoader.getString("Party.Help.4", "/party ")); sender.sendMessage(LocaleLoader.getString("Party.Help.5", "/party password")); 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 ab46f14de..52787f628 100644 --- a/src/main/java/com/gmail/nossr50/commands/party/PartyInfoCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/party/PartyInfoCommand.java @@ -6,8 +6,9 @@ import com.gmail.nossr50.datatypes.party.ShareMode; 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 java.util.ArrayList; +import java.util.List; import org.bukkit.ChatColor; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; @@ -15,28 +16,25 @@ import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; -import java.util.ArrayList; -import java.util.List; - public class PartyInfoCommand implements CommandExecutor { @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, + @NotNull String label, String[] args) { switch (args.length) { case 0: case 1: - if(UserManager.getPlayer((Player) sender) == null) - { + if (UserManager.getPlayer((Player) sender) == null) { sender.sendMessage(LocaleLoader.getString("Profile.PendingLoad")); return true; } - Player player = (Player) sender; - McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player); - Party party = mcMMOPlayer.getParty(); + final Player player = (Player) sender; + final McMMOPlayer mmoPlayer = UserManager.getPlayer(player); + Party party = mmoPlayer.getParty(); displayPartyHeader(player, party); displayShareModeInfo(player, party); displayPartyFeatures(player, party); - displayMemberInfo(player, mcMMOPlayer, party); + displayMemberInfo(player, mmoPlayer, party); return true; default: @@ -49,7 +47,10 @@ public class PartyInfoCommand implements CommandExecutor { player.sendMessage(LocaleLoader.getString("Commands.Party.Header")); StringBuilder status = new StringBuilder(); - status.append(LocaleLoader.getString("Commands.Party.Status", party.getName(), LocaleLoader.getString("Party.Status." + (party.isLocked() ? "Locked" : "Unlocked")), party.getLevel())); + status.append(LocaleLoader.getString("Commands.Party.Status", party.getName(), + LocaleLoader.getString( + "Party.Status." + (party.isLocked() ? "Locked" : "Unlocked")), + party.getLevel())); if (!party.hasReachedLevelCap()) { status.append(" (").append(party.getXpToLevelPercentage()).append(")"); @@ -71,13 +72,13 @@ public class PartyInfoCommand implements CommandExecutor { if (isUnlockedFeature(party, partyFeature)) { unlockedPartyFeatures.add(partyFeature.getLocaleString()); - } - else { + } else { lockedPartyFeatures.add(partyFeature.getFeatureLockedLocaleString()); } } - player.sendMessage(LocaleLoader.getString("Commands.Party.UnlockedFeatures", unlockedPartyFeatures.isEmpty() ? "None" : unlockedPartyFeatures)); + player.sendMessage(LocaleLoader.getString("Commands.Party.UnlockedFeatures", + unlockedPartyFeatures.isEmpty() ? "None" : unlockedPartyFeatures)); for (String message : lockedPartyFeatures) { player.sendMessage(message); @@ -85,7 +86,8 @@ public class PartyInfoCommand implements CommandExecutor { } private boolean isUnlockedFeature(Party party, PartyFeature partyFeature) { - return party.getLevel() >= mcMMO.p.getGeneralConfig().getPartyFeatureUnlockLevel(partyFeature); + return party.getLevel() >= mcMMO.p.getGeneralConfig() + .getPartyFeatureUnlockLevel(partyFeature); } private void displayShareModeInfo(Player player, Party party) { @@ -102,34 +104,41 @@ public class PartyInfoCommand implements CommandExecutor { String separator = ""; if (xpShareEnabled) { - expShareInfo = LocaleLoader.getString("Commands.Party.ExpShare", party.getXpShareMode().toString()); + expShareInfo = LocaleLoader.getString("Commands.Party.ExpShare", + party.getXpShareMode().toString()); } if (itemShareEnabled) { - itemShareInfo = LocaleLoader.getString("Commands.Party.ItemShare", party.getItemShareMode().toString()); + itemShareInfo = LocaleLoader.getString("Commands.Party.ItemShare", + party.getItemShareMode().toString()); } if (xpShareEnabled && itemShareEnabled) { separator = ChatColor.DARK_GRAY + " || "; } - player.sendMessage(LocaleLoader.getString("Commands.Party.ShareMode") + expShareInfo + separator + itemShareInfo); + player.sendMessage( + LocaleLoader.getString("Commands.Party.ShareMode") + expShareInfo + separator + + itemShareInfo); if (itemSharingActive) { - player.sendMessage(LocaleLoader.getString("Commands.Party.ItemShareCategories", party.getItemShareCategories())); + player.sendMessage(LocaleLoader.getString("Commands.Party.ItemShareCategories", + party.getItemShareCategories())); } } - private void displayMemberInfo(Player player, McMMOPlayer mcMMOPlayer, Party party) { + private void displayMemberInfo(Player player, McMMOPlayer mmoPlayer, Party party) { /* * Only show members of the party that this member can see */ - List nearMembers = PartyManager.getNearVisibleMembers(mcMMOPlayer); + List nearMembers = mcMMO.p.getPartyManager().getNearVisibleMembers(mmoPlayer); int membersOnline = party.getVisibleMembers(player).size(); player.sendMessage(LocaleLoader.getString("Commands.Party.Members.Header")); - player.sendMessage(LocaleLoader.getString("Commands.Party.MembersNear", nearMembers.size()+1, membersOnline)); + player.sendMessage( + LocaleLoader.getString("Commands.Party.MembersNear", nearMembers.size() + 1, + membersOnline)); player.sendMessage(party.createMembersList(player)); } } 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 7a24a4936..24fdc9c6d 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.party.Party; 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; @@ -15,7 +14,8 @@ import org.jetbrains.annotations.NotNull; public class PartyInviteCommand implements CommandExecutor { @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, + @NotNull String label, String[] args) { if (args.length == 2) { String targetName = CommandUtils.getMatchedPlayerName(args[1]); McMMOPlayer mcMMOTarget = UserManager.getOfflinePlayer(targetName); @@ -31,8 +31,8 @@ public class PartyInviteCommand implements CommandExecutor { return true; } - Player player = (Player) sender; - McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player); + final Player player = (Player) sender; + final McMMOPlayer mmoPlayer = UserManager.getPlayer(player); String playerName = player.getName(); if (player.equals(target)) { @@ -40,31 +40,37 @@ public class PartyInviteCommand implements CommandExecutor { return true; } - if (PartyManager.inSameParty(player, target)) { + if (mcMMO.p.getPartyManager().inSameParty(player, target)) { sender.sendMessage(LocaleLoader.getString("Party.Player.InSameParty", targetName)); return true; } - if (!PartyManager.canInvite(mcMMOPlayer)) { + if (!mcMMO.p.getPartyManager().canInvite(mmoPlayer)) { player.sendMessage(LocaleLoader.getString("Party.Locked")); return true; } - Party playerParty = mcMMOPlayer.getParty(); + Party playerParty = mmoPlayer.getParty(); - if (PartyManager.isPartyFull(target, playerParty)) { - player.sendMessage(LocaleLoader.getString("Commands.Party.PartyFull.Invite", target.getName(), playerParty.toString(), mcMMO.p.getGeneralConfig().getPartyMaxSize())); + if (mcMMO.p.getPartyManager().isPartyFull(target, playerParty)) { + player.sendMessage( + LocaleLoader.getString("Commands.Party.PartyFull.Invite", target.getName(), + playerParty.toString(), + mcMMO.p.getGeneralConfig().getPartyMaxSize())); return true; } mcMMOTarget.setPartyInvite(playerParty); sender.sendMessage(LocaleLoader.getString("Commands.Invite.Success")); - target.sendMessage(LocaleLoader.getString("Commands.Party.Invite.0", playerParty.getName(), playerName)); + target.sendMessage( + LocaleLoader.getString("Commands.Party.Invite.0", playerParty.getName(), + playerName)); target.sendMessage(LocaleLoader.getString("Commands.Party.Invite.1")); return true; } - sender.sendMessage(LocaleLoader.getString("Commands.Usage.2", "party", "invite", "<" + LocaleLoader.getString("Commands.Usage.Player") + ">")); + sender.sendMessage(LocaleLoader.getString("Commands.Usage.2", "party", "invite", + "<" + LocaleLoader.getString("Commands.Usage.Player") + ">")); return true; } } diff --git a/src/main/java/com/gmail/nossr50/commands/party/PartyItemShareCommand.java b/src/main/java/com/gmail/nossr50/commands/party/PartyItemShareCommand.java index 44822d82f..9187abc81 100644 --- a/src/main/java/com/gmail/nossr50/commands/party/PartyItemShareCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/party/PartyItemShareCommand.java @@ -9,26 +9,26 @@ import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.commands.CommandUtils; import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.text.StringUtils; +import java.util.Locale; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; -import java.util.Locale; - public class PartyItemShareCommand implements CommandExecutor { @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { - if(UserManager.getPlayer((Player) sender) == null) - { + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, + @NotNull String label, String[] args) { + if (UserManager.getPlayer((Player) sender) == null) { sender.sendMessage(LocaleLoader.getString("Profile.PendingLoad")); return true; } Party party = UserManager.getPlayer((Player) sender).getParty(); - if (party.getLevel() < mcMMO.p.getGeneralConfig().getPartyFeatureUnlockLevel(PartyFeature.ITEM_SHARE)) { + if (party.getLevel() < mcMMO.p.getGeneralConfig() + .getPartyFeatureUnlockLevel(PartyFeature.ITEM_SHARE)) { sender.sendMessage(LocaleLoader.getString("Party.Feature.Disabled.4")); return true; } @@ -38,7 +38,9 @@ public class PartyItemShareCommand implements CommandExecutor { ShareMode mode = ShareMode.getShareMode(args[1].toUpperCase(Locale.ENGLISH)); if (mode == null) { - sender.sendMessage(LocaleLoader.getString("Commands.Usage.2", "party", "itemshare", "")); + sender.sendMessage( + LocaleLoader.getString("Commands.Usage.2", "party", "itemshare", + "")); return true; } @@ -50,27 +52,31 @@ public class PartyItemShareCommand implements CommandExecutor { if (CommandUtils.shouldEnableToggle(args[2])) { toggle = true; - } - else if (CommandUtils.shouldDisableToggle(args[2])) { + } else if (CommandUtils.shouldDisableToggle(args[2])) { toggle = false; - } - else { - sender.sendMessage(LocaleLoader.getString("Commands.Usage.2", "party", "itemshare", " ")); + } else { + sender.sendMessage( + LocaleLoader.getString("Commands.Usage.2", "party", "itemshare", + " ")); return true; } try { - handleToggleItemShareCategory(party, ItemShareType.valueOf(args[1].toUpperCase(Locale.ENGLISH)), toggle); - } - catch (IllegalArgumentException ex) { - sender.sendMessage(LocaleLoader.getString("Commands.Usage.2", "party", "itemshare", " ")); + handleToggleItemShareCategory(party, + ItemShareType.valueOf(args[1].toUpperCase(Locale.ENGLISH)), toggle); + } catch (IllegalArgumentException ex) { + sender.sendMessage( + LocaleLoader.getString("Commands.Usage.2", "party", "itemshare", + " ")); } return true; default: - sender.sendMessage(LocaleLoader.getString("Commands.Usage.2", "party", "itemshare", "")); - sender.sendMessage(LocaleLoader.getString("Commands.Usage.2", "party", "itemshare", " ")); + sender.sendMessage(LocaleLoader.getString("Commands.Usage.2", "party", "itemshare", + "")); + sender.sendMessage(LocaleLoader.getString("Commands.Usage.2", "party", "itemshare", + " ")); return true; } } @@ -78,7 +84,9 @@ public class PartyItemShareCommand implements CommandExecutor { private void handleChangingShareMode(Party party, ShareMode mode) { party.setItemShareMode(mode); - String changeModeMessage = LocaleLoader.getString("Commands.Party.SetSharing", LocaleLoader.getString("Party.ShareType.Item"), LocaleLoader.getString("Party.ShareMode." + StringUtils.getCapitalized(mode.toString()))); + String changeModeMessage = LocaleLoader.getString("Commands.Party.SetSharing", + LocaleLoader.getString("Party.ShareType.Item"), LocaleLoader.getString( + "Party.ShareMode." + StringUtils.getCapitalized(mode.toString()))); for (Player member : party.getOnlineMembers()) { member.sendMessage(changeModeMessage); @@ -88,7 +96,8 @@ public class PartyItemShareCommand implements CommandExecutor { private void handleToggleItemShareCategory(Party party, ItemShareType type, boolean toggle) { party.setSharingDrops(type, toggle); - String toggleMessage = LocaleLoader.getString("Commands.Party.ToggleShareCategory", StringUtils.getCapitalized(type.toString()), toggle ? "enabled" : "disabled"); + String toggleMessage = LocaleLoader.getString("Commands.Party.ToggleShareCategory", + StringUtils.getCapitalized(type.toString()), toggle ? "enabled" : "disabled"); for (Player member : party.getOnlineMembers()) { member.sendMessage(toggleMessage); 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 8971fc0ed..60c2d4515 100644 --- a/src/main/java/com/gmail/nossr50/commands/party/PartyJoinCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/party/PartyJoinCommand.java @@ -3,7 +3,7 @@ package com.gmail.nossr50.commands.party; import com.gmail.nossr50.datatypes.party.Party; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.locale.LocaleLoader; -import com.gmail.nossr50.party.PartyManager; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.commands.CommandUtils; import com.gmail.nossr50.util.player.UserManager; import org.bukkit.command.Command; @@ -14,7 +14,8 @@ import org.jetbrains.annotations.NotNull; public class PartyJoinCommand implements CommandExecutor { @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, + @NotNull String label, String[] args) { switch (args.length) { case 2: case 3: @@ -28,22 +29,23 @@ public class PartyJoinCommand implements CommandExecutor { Player target = mcMMOTarget.getPlayer(); if (!mcMMOTarget.inParty()) { - sender.sendMessage(LocaleLoader.getString("Party.PlayerNotInParty", targetName)); + sender.sendMessage( + LocaleLoader.getString("Party.PlayerNotInParty", targetName)); return true; } - Player player = (Player) sender; + final Player player = (Player) sender; - if(UserManager.getPlayer((Player) sender) == null) - { + if (UserManager.getPlayer((Player) sender) == null) { sender.sendMessage(LocaleLoader.getString("Profile.PendingLoad")); return true; } - McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player); + final McMMOPlayer mmoPlayer = UserManager.getPlayer(player); Party targetParty = mcMMOTarget.getParty(); - if (player.equals(target) || (mcMMOPlayer.inParty() && mcMMOPlayer.getParty().equals(targetParty))) { + if (player.equals(target) || (mmoPlayer.inParty() && mmoPlayer.getParty() + .equals(targetParty))) { sender.sendMessage(LocaleLoader.getString("Party.Join.Self")); return true; } @@ -51,29 +53,31 @@ public class PartyJoinCommand implements CommandExecutor { String password = getPassword(args); // Make sure party passwords match - if (!PartyManager.checkPartyPassword(player, targetParty, password)) { + if (!mcMMO.p.getPartyManager().checkPartyPassword(player, targetParty, password)) { return true; } String partyName = targetParty.getName(); // Changing parties - if (!PartyManager.changeOrJoinParty(mcMMOPlayer, partyName)) { + if (!mcMMO.p.getPartyManager().changeOrJoinParty(mmoPlayer, partyName)) { return true; } - if(PartyManager.isPartyFull(player, targetParty)) - { - player.sendMessage(LocaleLoader.getString("Commands.Party.PartyFull", targetParty.toString())); + if (mcMMO.p.getPartyManager().isPartyFull(player, targetParty)) { + player.sendMessage(LocaleLoader.getString("Commands.Party.PartyFull", + targetParty.toString())); return true; } player.sendMessage(LocaleLoader.getString("Commands.Party.Join", partyName)); - PartyManager.addToParty(mcMMOPlayer, targetParty); + mcMMO.p.getPartyManager().addToParty(mmoPlayer, targetParty); return true; default: - sender.sendMessage(LocaleLoader.getString("Commands.Usage.3", "party", "join", "<" + LocaleLoader.getString("Commands.Usage.Player") + ">", "[" + LocaleLoader.getString("Commands.Usage.Password") + "]")); + sender.sendMessage(LocaleLoader.getString("Commands.Usage.3", "party", "join", + "<" + LocaleLoader.getString("Commands.Usage.Player") + ">", + "[" + LocaleLoader.getString("Commands.Usage.Password") + "]")); return true; } } 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 fd6b3e495..b864f61d7 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.datatypes.party.Party; 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; @@ -16,7 +15,8 @@ import org.jetbrains.annotations.NotNull; public class PartyKickCommand implements CommandExecutor { @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, + @NotNull String label, String[] args) { if (args.length == 2) { if (UserManager.getPlayer((Player) sender) == null) { sender.sendMessage(LocaleLoader.getString("Profile.PendingLoad")); @@ -37,18 +37,20 @@ public class PartyKickCommand implements CommandExecutor { Player onlineTarget = target.getPlayer(); String partyName = playerParty.getName(); - if (!PartyManager.handlePartyChangeEvent(onlineTarget, partyName, null, EventReason.KICKED_FROM_PARTY)) { + if (!mcMMO.p.getPartyManager().handlePartyChangeEvent(onlineTarget, partyName, null, + EventReason.KICKED_FROM_PARTY)) { return true; } - PartyManager.processPartyLeaving(UserManager.getPlayer(onlineTarget)); + mcMMO.p.getPartyManager().processPartyLeaving(UserManager.getPlayer(onlineTarget)); onlineTarget.sendMessage(LocaleLoader.getString("Commands.Party.Kick", partyName)); } - PartyManager.removeFromParty(target, playerParty); + mcMMO.p.getPartyManager().removeFromParty(target, playerParty); return true; } - sender.sendMessage(LocaleLoader.getString("Commands.Usage.2", "party", "kick", "<" + LocaleLoader.getString("Commands.Usage.Player") + ">")); + sender.sendMessage(LocaleLoader.getString("Commands.Usage.2", "party", "kick", + "<" + LocaleLoader.getString("Commands.Usage.Player") + ">")); return true; } } diff --git a/src/main/java/com/gmail/nossr50/commands/party/PartyLockCommand.java b/src/main/java/com/gmail/nossr50/commands/party/PartyLockCommand.java index eb87e0843..18ac5da15 100644 --- a/src/main/java/com/gmail/nossr50/commands/party/PartyLockCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/party/PartyLockCommand.java @@ -13,13 +13,13 @@ import org.jetbrains.annotations.NotNull; public class PartyLockCommand implements CommandExecutor { @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, + @NotNull String label, String[] args) { switch (args.length) { case 1: if (args[0].equalsIgnoreCase("lock")) { togglePartyLock(sender, true); - } - else if (args[0].equalsIgnoreCase("unlock")) { + } else if (args[0].equalsIgnoreCase("unlock")) { togglePartyLock(sender, false); } @@ -33,11 +33,9 @@ public class PartyLockCommand implements CommandExecutor { if (CommandUtils.shouldEnableToggle(args[1])) { togglePartyLock(sender, true); - } - else if (CommandUtils.shouldDisableToggle(args[1])) { + } else if (CommandUtils.shouldDisableToggle(args[1])) { togglePartyLock(sender, false); - } - else { + } else { sendUsageStrings(sender); } @@ -55,21 +53,22 @@ public class PartyLockCommand implements CommandExecutor { } private void togglePartyLock(CommandSender sender, boolean lock) { - if(UserManager.getPlayer((Player) sender) == null) - { + if (UserManager.getPlayer((Player) sender) == null) { sender.sendMessage(LocaleLoader.getString("Profile.PendingLoad")); return; } Party party = UserManager.getPlayer((Player) sender).getParty(); - if (!Permissions.partySubcommand(sender, lock ? PartySubcommandType.LOCK : PartySubcommandType.UNLOCK)) { + if (!Permissions.partySubcommand(sender, + lock ? PartySubcommandType.LOCK : PartySubcommandType.UNLOCK)) { sender.sendMessage(LocaleLoader.getString("mcMMO.NoPermission")); return; } if (lock == party.isLocked()) { - sender.sendMessage(LocaleLoader.getString("Party." + (lock ? "IsLocked" : "IsntLocked"))); + sender.sendMessage( + LocaleLoader.getString("Party." + (lock ? "IsLocked" : "IsntLocked"))); return; } 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 c450a0757..10685c666 100644 --- a/src/main/java/com/gmail/nossr50/commands/party/PartyQuitCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/party/PartyQuitCommand.java @@ -4,7 +4,7 @@ import com.gmail.nossr50.datatypes.party.Party; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.events.party.McMMOPartyChangeEvent.EventReason; import com.gmail.nossr50.locale.LocaleLoader; -import com.gmail.nossr50.party.PartyManager; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.player.UserManager; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; @@ -14,23 +14,26 @@ import org.jetbrains.annotations.NotNull; public class PartyQuitCommand implements CommandExecutor { @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, + @NotNull String label, String[] args) { if (args.length == 1) { - Player player = (Player) sender; + final Player player = (Player) sender; if (UserManager.getPlayer((Player) sender) == null) { sender.sendMessage(LocaleLoader.getString("Profile.PendingLoad")); return true; } - McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player); - Party playerParty = mcMMOPlayer.getParty(); + final McMMOPlayer mmoPlayer = UserManager.getPlayer(player); + Party playerParty = mmoPlayer.getParty(); - if (!PartyManager.handlePartyChangeEvent(player, playerParty.getName(), null, EventReason.LEFT_PARTY)) { + if (!mcMMO.p.getPartyManager() + .handlePartyChangeEvent(player, playerParty.getName(), null, + EventReason.LEFT_PARTY)) { return true; } - PartyManager.removeFromParty(mcMMOPlayer); + mcMMO.p.getPartyManager().removeFromParty(mmoPlayer); sender.sendMessage(LocaleLoader.getString("Commands.Party.Leave")); return true; } 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 29e35cd4a..c109696d4 100644 --- a/src/main/java/com/gmail/nossr50/commands/party/PartyRenameCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/party/PartyRenameCommand.java @@ -4,7 +4,7 @@ import com.gmail.nossr50.datatypes.party.Party; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.events.party.McMMOPartyChangeEvent.EventReason; import com.gmail.nossr50.locale.LocaleLoader; -import com.gmail.nossr50.party.PartyManager; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.player.UserManager; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; @@ -14,15 +14,16 @@ import org.jetbrains.annotations.NotNull; public class PartyRenameCommand implements CommandExecutor { @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, + @NotNull String label, String[] args) { if (args.length == 2) { if (UserManager.getPlayer((Player) sender) == null) { sender.sendMessage(LocaleLoader.getString("Profile.PendingLoad")); return true; } - McMMOPlayer mcMMOPlayer = UserManager.getPlayer((Player) sender); - Party playerParty = mcMMOPlayer.getParty(); + final McMMOPlayer mmoPlayer = UserManager.getPlayer((Player) sender); + Party playerParty = mmoPlayer.getParty(); String oldPartyName = playerParty.getName(); String newPartyName = args[1].replace(".", ""); @@ -33,22 +34,26 @@ public class PartyRenameCommand implements CommandExecutor { return true; } - Player player = mcMMOPlayer.getPlayer(); + Player player = mmoPlayer.getPlayer(); // Check to see if the party exists, and if it does cancel renaming the party - if (PartyManager.checkPartyExistence(player, newPartyName)) { + if (mcMMO.p.getPartyManager().checkPartyExistence(player, newPartyName)) { return true; } String leaderName = playerParty.getLeader().getPlayerName(); for (Player member : playerParty.getOnlineMembers()) { - if (!PartyManager.handlePartyChangeEvent(member, oldPartyName, newPartyName, EventReason.CHANGED_PARTIES)) { + if (!mcMMO.p.getPartyManager() + .handlePartyChangeEvent(member, oldPartyName, newPartyName, + EventReason.CHANGED_PARTIES)) { return true; } if (!member.getName().equalsIgnoreCase(leaderName)) { - member.sendMessage(LocaleLoader.getString("Party.InformedOnNameChange", leaderName, newPartyName)); + member.sendMessage( + LocaleLoader.getString("Party.InformedOnNameChange", leaderName, + newPartyName)); } } @@ -57,7 +62,8 @@ public class PartyRenameCommand implements CommandExecutor { sender.sendMessage(LocaleLoader.getString("Commands.Party.Rename", newPartyName)); return true; } - sender.sendMessage(LocaleLoader.getString("Commands.Usage.2", "party", "rename", "<" + LocaleLoader.getString("Commands.Usage.PartyName") + ">")); + sender.sendMessage(LocaleLoader.getString("Commands.Usage.2", "party", "rename", + "<" + LocaleLoader.getString("Commands.Usage.PartyName") + ">")); return true; } } diff --git a/src/main/java/com/gmail/nossr50/commands/party/PartySubcommandType.java b/src/main/java/com/gmail/nossr50/commands/party/PartySubcommandType.java index f4ebdb510..5dfb68504 100644 --- a/src/main/java/com/gmail/nossr50/commands/party/PartySubcommandType.java +++ b/src/main/java/com/gmail/nossr50/commands/party/PartySubcommandType.java @@ -30,20 +30,17 @@ public enum PartySubcommandType { if (commandName.equalsIgnoreCase("?")) { return HELP; - } - else if (commandName.equalsIgnoreCase("q") || commandName.equalsIgnoreCase("leave")) { + } else if (commandName.equalsIgnoreCase("q") || commandName.equalsIgnoreCase("leave")) { return QUIT; - } - else if (commandName.equalsIgnoreCase("leader")) { + } else if (commandName.equalsIgnoreCase("leader")) { return OWNER; - } - else if (commandName.equalsIgnoreCase("xpshare") || commandName.equalsIgnoreCase("shareexp") || commandName.equalsIgnoreCase("sharexp")) { + } else if (commandName.equalsIgnoreCase("xpshare") || commandName.equalsIgnoreCase( + "shareexp") || commandName.equalsIgnoreCase("sharexp")) { return XPSHARE; - } - else if (commandName.equalsIgnoreCase("shareitem") || commandName.equalsIgnoreCase("shareitems")) { + } else if (commandName.equalsIgnoreCase("shareitem") || commandName.equalsIgnoreCase( + "shareitems")) { return ITEMSHARE; - } - else if (commandName.equalsIgnoreCase("ally")) { + } else if (commandName.equalsIgnoreCase("ally")) { return ALLIANCE; } diff --git a/src/main/java/com/gmail/nossr50/commands/party/PartyXpShareCommand.java b/src/main/java/com/gmail/nossr50/commands/party/PartyXpShareCommand.java index 8322beecf..66e346ef9 100644 --- a/src/main/java/com/gmail/nossr50/commands/party/PartyXpShareCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/party/PartyXpShareCommand.java @@ -16,16 +16,17 @@ import org.jetbrains.annotations.NotNull; public class PartyXpShareCommand implements CommandExecutor { @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { - if(UserManager.getPlayer((Player) sender) == null) - { + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, + @NotNull String label, String[] args) { + if (UserManager.getPlayer((Player) sender) == null) { sender.sendMessage(LocaleLoader.getString("Profile.PendingLoad")); return true; } Party party = UserManager.getPlayer((Player) sender).getParty(); - if (party.getLevel() < mcMMO.p.getGeneralConfig().getPartyFeatureUnlockLevel(PartyFeature.XP_SHARE)) { + if (party.getLevel() < mcMMO.p.getGeneralConfig() + .getPartyFeatureUnlockLevel(PartyFeature.XP_SHARE)) { sender.sendMessage(LocaleLoader.getString("Party.Feature.Disabled.5")); return true; } @@ -33,22 +34,27 @@ public class PartyXpShareCommand implements CommandExecutor { if (args.length == 2) { if (args[1].equalsIgnoreCase("none") || CommandUtils.shouldDisableToggle(args[1])) { handleChangingShareMode(party, ShareMode.NONE); - } else if (args[1].equalsIgnoreCase("equal") || args[1].equalsIgnoreCase("even") || CommandUtils.shouldEnableToggle(args[1])) { + } else if (args[1].equalsIgnoreCase("equal") || args[1].equalsIgnoreCase("even") + || CommandUtils.shouldEnableToggle(args[1])) { handleChangingShareMode(party, ShareMode.EQUAL); } else { - sender.sendMessage(LocaleLoader.getString("Commands.Usage.2", "party", "xpshare", "")); + sender.sendMessage(LocaleLoader.getString("Commands.Usage.2", "party", "xpshare", + "")); } return true; } - sender.sendMessage(LocaleLoader.getString("Commands.Usage.2", "party", "xpshare", "")); + sender.sendMessage( + LocaleLoader.getString("Commands.Usage.2", "party", "xpshare", "")); return true; } private void handleChangingShareMode(Party party, ShareMode mode) { party.setXpShareMode(mode); - String changeModeMessage = LocaleLoader.getString("Commands.Party.SetSharing", LocaleLoader.getString("Party.ShareType.Xp"), LocaleLoader.getString("Party.ShareMode." + StringUtils.getCapitalized(mode.toString()))); + String changeModeMessage = LocaleLoader.getString("Commands.Party.SetSharing", + LocaleLoader.getString("Party.ShareType.Xp"), LocaleLoader.getString( + "Party.ShareMode." + StringUtils.getCapitalized(mode.toString()))); for (Player member : party.getOnlineMembers()) { member.sendMessage(changeModeMessage); 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 1977ad67b..277defb55 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 @@ -2,7 +2,7 @@ package com.gmail.nossr50.commands.party.alliance; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.locale.LocaleLoader; -import com.gmail.nossr50.party.PartyManager; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.player.UserManager; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; @@ -12,29 +12,31 @@ import org.jetbrains.annotations.NotNull; public class PartyAllianceAcceptCommand implements CommandExecutor { @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, + @NotNull String label, String[] args) { if (args.length == 2) { if (UserManager.getPlayer((Player) sender) == null) { sender.sendMessage(LocaleLoader.getString("Profile.PendingLoad")); return true; } - Player player = (Player) sender; - McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player); + final Player player = (Player) sender; + final McMMOPlayer mmoPlayer = UserManager.getPlayer(player); - if (!mcMMOPlayer.hasPartyAllianceInvite()) { + if (!mmoPlayer.hasPartyAllianceInvite()) { sender.sendMessage(LocaleLoader.getString("mcMMO.NoInvites")); return true; } - if (mcMMOPlayer.getParty().getAlly() != null) { + if (mmoPlayer.getParty().getAlly() != null) { player.sendMessage(LocaleLoader.getString("Commands.Party.Alliance.AlreadyAllies")); return true; } - PartyManager.acceptAllianceInvite(mcMMOPlayer); + mcMMO.p.getPartyManager().acceptAllianceInvite(mmoPlayer); return true; } - sender.sendMessage(LocaleLoader.getString("Commands.Usage.2", "party", "alliance", "accept")); + sender.sendMessage( + LocaleLoader.getString("Commands.Usage.2", "party", "alliance", "accept")); return true; } } 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 27f6e4d21..84faf86e5 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,10 +5,11 @@ import com.gmail.nossr50.datatypes.party.PartyFeature; 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; +import java.util.ArrayList; +import java.util.List; import org.bukkit.ChatColor; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; @@ -18,40 +19,39 @@ import org.bukkit.entity.Player; import org.bukkit.util.StringUtil; import org.jetbrains.annotations.NotNull; -import java.util.ArrayList; -import java.util.List; - public class PartyAllianceCommand implements TabExecutor { private Player player; private Party playerParty; private Party targetParty; - public static final List ALLIANCE_SUBCOMMANDS = ImmutableList.of("invite", "accept", "disband"); + public static final List ALLIANCE_SUBCOMMANDS = ImmutableList.of("invite", "accept", + "disband"); private final CommandExecutor partyAllianceInviteCommand = new PartyAllianceInviteCommand(); private final CommandExecutor partyAllianceAcceptCommand = new PartyAllianceAcceptCommand(); private final CommandExecutor partyAllianceDisbandCommand = new PartyAllianceDisbandCommand(); @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, + @NotNull String label, String[] args) { if (CommandUtils.noConsoleUsage(sender)) { return true; } - if(UserManager.getPlayer((Player) sender) == null) - { + if (UserManager.getPlayer((Player) sender) == null) { sender.sendMessage(LocaleLoader.getString("Profile.PendingLoad")); return true; } player = (Player) sender; - McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player); + final McMMOPlayer mmoPlayer = UserManager.getPlayer(player); - playerParty = mcMMOPlayer.getParty(); + playerParty = mmoPlayer.getParty(); switch (args.length) { case 1: - if (playerParty.getLevel() < mcMMO.p.getGeneralConfig().getPartyFeatureUnlockLevel(PartyFeature.ALLIANCE)) { + if (playerParty.getLevel() < mcMMO.p.getGeneralConfig() + .getPartyFeatureUnlockLevel(PartyFeature.ALLIANCE)) { sender.sendMessage(LocaleLoader.getString("Party.Feature.Disabled.3")); return true; } @@ -64,12 +64,13 @@ public class PartyAllianceCommand implements TabExecutor { targetParty = playerParty.getAlly(); displayPartyHeader(); - displayMemberInfo(mcMMOPlayer); + displayMemberInfo(mmoPlayer); return true; case 2: case 3: - if (playerParty.getLevel() < mcMMO.p.getGeneralConfig().getPartyFeatureUnlockLevel(PartyFeature.ALLIANCE)) { + if (playerParty.getLevel() < mcMMO.p.getGeneralConfig() + .getPartyFeatureUnlockLevel(PartyFeature.ALLIANCE)) { sender.sendMessage(LocaleLoader.getString("Party.Feature.Disabled.3")); return true; } @@ -94,7 +95,7 @@ public class PartyAllianceCommand implements TabExecutor { targetParty = playerParty.getAlly(); displayPartyHeader(); - displayMemberInfo(mcMMOPlayer); + displayMemberInfo(mmoPlayer); return true; default: @@ -109,13 +110,16 @@ public class PartyAllianceCommand implements TabExecutor { } @Override - public List onTabComplete(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String label, String[] args) { + public List onTabComplete(@NotNull CommandSender commandSender, + @NotNull Command command, @NotNull String label, String[] args) { if (args.length == 1) { - List matches = StringUtil.copyPartialMatches(args[0], ALLIANCE_SUBCOMMANDS, new ArrayList<>(ALLIANCE_SUBCOMMANDS.size())); + List matches = StringUtil.copyPartialMatches(args[0], ALLIANCE_SUBCOMMANDS, + new ArrayList<>(ALLIANCE_SUBCOMMANDS.size())); if (matches.size() == 0) { List playerNames = CommandUtils.getOnlinePlayerNames(commandSender); - return StringUtil.copyPartialMatches(args[0], playerNames, new ArrayList<>(playerNames.size())); + return StringUtil.copyPartialMatches(args[0], playerNames, + new ArrayList<>(playerNames.size())); } return matches; @@ -125,11 +129,13 @@ public class PartyAllianceCommand implements TabExecutor { private void displayPartyHeader() { player.sendMessage(LocaleLoader.getString("Commands.Party.Alliance.Header")); - player.sendMessage(LocaleLoader.getString("Commands.Party.Alliance.Ally", playerParty.getName(), targetParty.getName())); + player.sendMessage( + LocaleLoader.getString("Commands.Party.Alliance.Ally", playerParty.getName(), + targetParty.getName())); } - private void displayMemberInfo(McMMOPlayer mcMMOPlayer) { - List nearMembers = PartyManager.getNearMembers(mcMMOPlayer); + private void displayMemberInfo(McMMOPlayer mmoPlayer) { + List nearMembers = mcMMO.p.getPartyManager().getNearMembers(mmoPlayer); player.sendMessage(LocaleLoader.getString("Commands.Party.Alliance.Members.Header")); player.sendMessage(playerParty.createMembersList(player)); player.sendMessage(ChatColor.DARK_GRAY + "----------------------------"); 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 c2cfa666c..bf8f40f96 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 @@ -3,7 +3,7 @@ package com.gmail.nossr50.commands.party.alliance; import com.gmail.nossr50.datatypes.party.Party; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.locale.LocaleLoader; -import com.gmail.nossr50.party.PartyManager; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.player.UserManager; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; @@ -13,25 +13,27 @@ import org.jetbrains.annotations.NotNull; public class PartyAllianceDisbandCommand implements CommandExecutor { @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, + @NotNull String label, String[] args) { if (args.length == 2) { if (UserManager.getPlayer((Player) sender) == null) { sender.sendMessage(LocaleLoader.getString("Profile.PendingLoad")); return true; } - Player player = (Player) sender; - McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player); - Party party = mcMMOPlayer.getParty(); + final Player player = (Player) sender; + final McMMOPlayer mmoPlayer = UserManager.getPlayer(player); + Party party = mmoPlayer.getParty(); if (party.getAlly() == null) { sender.sendMessage(LocaleLoader.getString("Commands.Party.Alliance.None")); return true; } - PartyManager.disbandAlliance(player, party, party.getAlly()); + mcMMO.p.getPartyManager().disbandAlliance(player, party, party.getAlly()); return true; } - sender.sendMessage(LocaleLoader.getString("Commands.Usage.2", "party", "alliance", "disband")); + sender.sendMessage( + LocaleLoader.getString("Commands.Usage.2", "party", "alliance", "disband")); return true; } } 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 408c6136a..4ce9a6242 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 @@ -3,7 +3,7 @@ package com.gmail.nossr50.commands.party.alliance; import com.gmail.nossr50.datatypes.party.Party; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.locale.LocaleLoader; -import com.gmail.nossr50.party.PartyManager; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.commands.CommandUtils; import com.gmail.nossr50.util.player.UserManager; import org.bukkit.command.Command; @@ -14,7 +14,8 @@ import org.jetbrains.annotations.NotNull; public class PartyAllianceInviteCommand implements CommandExecutor { @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, + @NotNull String label, String[] args) { if (args.length == 3) { String targetName = CommandUtils.getMatchedPlayerName(args[2]); McMMOPlayer mcMMOTarget = UserManager.getOfflinePlayer(targetName); @@ -30,8 +31,8 @@ public class PartyAllianceInviteCommand implements CommandExecutor { return true; } - Player player = (Player) sender; - McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player); + final Player player = (Player) sender; + final McMMOPlayer mmoPlayer = UserManager.getPlayer(player); String playerName = player.getName(); if (player.equals(target)) { @@ -44,7 +45,7 @@ public class PartyAllianceInviteCommand implements CommandExecutor { return true; } - if (PartyManager.inSameParty(player, target)) { + if (mcMMO.p.getPartyManager().inSameParty(player, target)) { sender.sendMessage(LocaleLoader.getString("Party.Player.InSameParty", targetName)); return true; } @@ -54,7 +55,7 @@ public class PartyAllianceInviteCommand implements CommandExecutor { return true; } - Party playerParty = mcMMOPlayer.getParty(); + Party playerParty = mmoPlayer.getParty(); if (playerParty.getAlly() != null) { player.sendMessage(LocaleLoader.getString("Commands.Party.Alliance.AlreadyAllies")); @@ -64,11 +65,13 @@ public class PartyAllianceInviteCommand implements CommandExecutor { mcMMOTarget.setPartyAllianceInvite(playerParty); sender.sendMessage(LocaleLoader.getString("Commands.Invite.Success")); - target.sendMessage(LocaleLoader.getString("Commands.Party.Alliance.Invite.0", playerParty.getName(), playerName)); + target.sendMessage(LocaleLoader.getString("Commands.Party.Alliance.Invite.0", + playerParty.getName(), playerName)); target.sendMessage(LocaleLoader.getString("Commands.Party.Alliance.Invite.1")); return true; } - sender.sendMessage(LocaleLoader.getString("Commands.Usage.3", "party", "alliance", "invite", "<" + LocaleLoader.getString("Commands.Usage.Player") + ">")); + sender.sendMessage(LocaleLoader.getString("Commands.Usage.3", "party", "alliance", "invite", + "<" + LocaleLoader.getString("Commands.Usage.Player") + ">")); return true; } } diff --git a/src/main/java/com/gmail/nossr50/commands/party/teleport/PtpAcceptAnyCommand.java b/src/main/java/com/gmail/nossr50/commands/party/teleport/PtpAcceptAnyCommand.java index 9822860f6..445e31fe3 100644 --- a/src/main/java/com/gmail/nossr50/commands/party/teleport/PtpAcceptAnyCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/party/teleport/PtpAcceptAnyCommand.java @@ -11,18 +11,19 @@ import org.jetbrains.annotations.NotNull; public class PtpAcceptAnyCommand implements CommandExecutor { @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, + @NotNull String label, String[] args) { if (!Permissions.partyTeleportAcceptAll(sender)) { sender.sendMessage(command.getPermissionMessage()); return true; } - PartyTeleportRecord ptpRecord = UserManager.getPlayer(sender.getName()).getPartyTeleportRecord(); + PartyTeleportRecord ptpRecord = UserManager.getPlayer(sender.getName()) + .getPartyTeleportRecord(); if (ptpRecord.isConfirmRequired()) { sender.sendMessage(LocaleLoader.getString("Commands.ptp.AcceptAny.Disabled")); - } - else { + } else { sender.sendMessage(LocaleLoader.getString("Commands.ptp.AcceptAny.Enabled")); } diff --git a/src/main/java/com/gmail/nossr50/commands/party/teleport/PtpAcceptCommand.java b/src/main/java/com/gmail/nossr50/commands/party/teleport/PtpAcceptCommand.java index 19c98ad6a..58141563b 100644 --- a/src/main/java/com/gmail/nossr50/commands/party/teleport/PtpAcceptCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/party/teleport/PtpAcceptCommand.java @@ -15,19 +15,19 @@ import org.jetbrains.annotations.NotNull; public class PtpAcceptCommand implements CommandExecutor { @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, + @NotNull String label, String[] args) { if (!Permissions.partyTeleportAccept(sender)) { sender.sendMessage(command.getPermissionMessage()); return true; } - if(UserManager.getPlayer((Player) sender) == null) - { + if (UserManager.getPlayer((Player) sender) == null) { sender.sendMessage(LocaleLoader.getString("Profile.PendingLoad")); return true; } - Player player = (Player) sender; + final Player player = (Player) sender; PartyTeleportRecord ptpRecord = UserManager.getPlayer(player).getPartyTeleportRecord(); if (!ptpRecord.hasRequest()) { @@ -35,7 +35,8 @@ public class PtpAcceptCommand implements CommandExecutor { return true; } - if (SkillUtils.cooldownExpired(ptpRecord.getTimeout(), mcMMO.p.getGeneralConfig().getPTPCommandTimeout())) { + if (SkillUtils.cooldownExpired(ptpRecord.getTimeout(), + mcMMO.p.getGeneralConfig().getPTPCommandTimeout())) { ptpRecord.removeRequest(); player.sendMessage(LocaleLoader.getString("Commands.ptp.RequestExpired")); return true; @@ -54,11 +55,13 @@ public class PtpAcceptCommand implements CommandExecutor { if (!Permissions.partyTeleportAllWorlds(target)) { if (!Permissions.partyTeleportWorld(target, targetWorld)) { - target.sendMessage(LocaleLoader.getString("Commands.ptp.NoWorldPermissions", targetWorld.getName())); + target.sendMessage(LocaleLoader.getString("Commands.ptp.NoWorldPermissions", + targetWorld.getName())); return true; - } - else if (targetWorld != playerWorld && !Permissions.partyTeleportWorld(target, playerWorld)) { - target.sendMessage(LocaleLoader.getString("Commands.ptp.NoWorldPermissions", playerWorld.getName())); + } else if (targetWorld != playerWorld && !Permissions.partyTeleportWorld(target, + playerWorld)) { + target.sendMessage(LocaleLoader.getString("Commands.ptp.NoWorldPermissions", + playerWorld.getName())); return true; } } 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 48276c723..8f80f482f 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.party.PartyTeleportRecord; 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; @@ -18,6 +17,8 @@ import com.gmail.nossr50.util.skills.SkillUtils; import com.gmail.nossr50.worldguard.WorldGuardManager; import com.gmail.nossr50.worldguard.WorldGuardUtils; import com.google.common.collect.ImmutableList; +import java.util.ArrayList; +import java.util.List; import org.bukkit.World; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; @@ -27,18 +28,78 @@ import org.bukkit.entity.Player; import org.bukkit.util.StringUtil; import org.jetbrains.annotations.NotNull; -import java.util.ArrayList; -import java.util.List; - public class PtpCommand implements TabExecutor { - public static final List TELEPORT_SUBCOMMANDS = ImmutableList.of("toggle", "accept", "acceptany", "acceptall"); + public static final List TELEPORT_SUBCOMMANDS = ImmutableList.of("toggle", "accept", + "acceptany", + "acceptall"); private final CommandExecutor ptpToggleCommand = new PtpToggleCommand(); private final CommandExecutor ptpAcceptAnyCommand = new PtpAcceptAnyCommand(); private final CommandExecutor ptpAcceptCommand = new PtpAcceptCommand(); + protected static boolean canTeleport(CommandSender sender, Player player, String targetName) { + McMMOPlayer mcMMOTarget = UserManager.getPlayer(targetName); + + if (!CommandUtils.checkPlayerExistence(sender, targetName, mcMMOTarget)) { + return false; + } + + Player target = mcMMOTarget.getPlayer(); + + if (player.equals(target)) { + player.sendMessage(LocaleLoader.getString("Party.Teleport.Self")); + return false; + } + + if (!mcMMO.p.getPartyManager().inSameParty(player, target)) { + player.sendMessage(LocaleLoader.getString("Party.NotInYourParty", targetName)); + return false; + } + + if (!mcMMOTarget.getPartyTeleportRecord().isEnabled()) { + player.sendMessage(LocaleLoader.getString("Party.Teleport.Disabled", targetName)); + return false; + } + + if (!target.isValid()) { + player.sendMessage(LocaleLoader.getString("Party.Teleport.Dead")); + return false; + } + + return true; + } + + protected static void handleTeleportWarmup(Player teleportingPlayer, Player targetPlayer) { + if (UserManager.getPlayer(targetPlayer) == null) { + targetPlayer.sendMessage(LocaleLoader.getString("Profile.PendingLoad")); + return; + } + + if (UserManager.getPlayer(teleportingPlayer) == null) { + teleportingPlayer.sendMessage(LocaleLoader.getString("Profile.PendingLoad")); + return; + } + + McMMOPlayer mcMMOPlayer = UserManager.getPlayer(teleportingPlayer); + McMMOPlayer mcMMOTarget = UserManager.getPlayer(targetPlayer); + + long warmup = mcMMO.p.getGeneralConfig().getPTPCommandWarmup(); + + mcMMOPlayer.actualizeTeleportCommenceLocation(teleportingPlayer); + + if (warmup > 0) { + teleportingPlayer.sendMessage(LocaleLoader.getString("Teleport.Commencing", warmup)); + mcMMO.p.getFoliaLib().getScheduler().runAtEntityLater(teleportingPlayer, + new TeleportationWarmup(mcMMOPlayer, mcMMOTarget), 20 * warmup); + } else { + EventUtils.handlePartyTeleportEvent(teleportingPlayer, targetPlayer); + } + } + @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, + @NotNull String label, + String[] args) { if (CommandUtils.noConsoleUsage(sender)) { return true; } @@ -46,22 +107,22 @@ public class PtpCommand implements TabExecutor { Player player = (Player) sender; /* WORLD GUARD MAIN FLAG CHECK */ - if(WorldGuardUtils.isWorldGuardLoaded()) - { - if(!WorldGuardManager.getInstance().hasMainFlag(player)) + if (WorldGuardUtils.isWorldGuardLoaded()) { + if (!WorldGuardManager.getInstance().hasMainFlag(player)) { return true; + } } /* WORLD BLACKLIST CHECK */ - if(WorldBlacklist.isWorldBlacklisted(player.getWorld())) + if (WorldBlacklist.isWorldBlacklisted(player.getWorld())) { return true; + } if (!UserManager.hasPlayerDataKey(player)) { return true; } - if(UserManager.getPlayer((Player) sender) == null) - { + if (UserManager.getPlayer((Player) sender) == null) { sender.sendMessage(LocaleLoader.getString("Profile.PendingLoad")); return true; } @@ -75,7 +136,8 @@ public class PtpCommand implements TabExecutor { Party party = mcMMOPlayer.getParty(); - if (party.getLevel() < mcMMO.p.getGeneralConfig().getPartyFeatureUnlockLevel(PartyFeature.TELEPORT)) { + if (party.getLevel() < mcMMO.p.getGeneralConfig() + .getPartyFeatureUnlockLevel(PartyFeature.TELEPORT)) { sender.sendMessage(LocaleLoader.getString("Party.Feature.Disabled.2")); return true; } @@ -93,7 +155,9 @@ public class PtpCommand implements TabExecutor { int hurtCooldown = mcMMO.p.getGeneralConfig().getPTPCommandRecentlyHurtCooldown(); if (hurtCooldown > 0) { - int timeRemaining = SkillUtils.calculateTimeLeft(recentlyHurt * Misc.TIME_CONVERSION_FACTOR, hurtCooldown, player); + int timeRemaining = SkillUtils.calculateTimeLeft( + recentlyHurt * Misc.TIME_CONVERSION_FACTOR, + hurtCooldown, player); if (timeRemaining > 0) { player.sendMessage(LocaleLoader.getString("Item.Injured.Wait", timeRemaining)); @@ -114,7 +178,9 @@ public class PtpCommand implements TabExecutor { long ptpLastUse = mcMMOPlayer.getPartyTeleportRecord().getLastUse(); if (ptpCooldown > 0) { - int timeRemaining = SkillUtils.calculateTimeLeft(ptpLastUse * Misc.TIME_CONVERSION_FACTOR, ptpCooldown, player); + int timeRemaining = SkillUtils.calculateTimeLeft( + ptpLastUse * Misc.TIME_CONVERSION_FACTOR, ptpCooldown, + player); if (timeRemaining > 0) { player.sendMessage(LocaleLoader.getString("Item.Generic.Wait", timeRemaining)); @@ -129,9 +195,12 @@ public class PtpCommand implements TabExecutor { } @Override - public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, String[] args) { + public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, + @NotNull String alias, + String[] args) { if (args.length == 1) { - List matches = StringUtil.copyPartialMatches(args[0], TELEPORT_SUBCOMMANDS, new ArrayList<>(TELEPORT_SUBCOMMANDS.size())); + List matches = StringUtil.copyPartialMatches(args[0], TELEPORT_SUBCOMMANDS, + new ArrayList<>(TELEPORT_SUBCOMMANDS.size())); if (matches.size() == 0) { if (UserManager.getPlayer((Player) sender) == null) { @@ -147,7 +216,8 @@ public class PtpCommand implements TabExecutor { } List playerNames = mcMMOPlayer.getParty().getOnlinePlayerNames(player); - return StringUtil.copyPartialMatches(args[0], playerNames, new ArrayList<>(playerNames.size())); + return StringUtil.copyPartialMatches(args[0], playerNames, + new ArrayList<>(playerNames.size())); } return matches; @@ -163,18 +233,21 @@ public class PtpCommand implements TabExecutor { McMMOPlayer mcMMOTarget = UserManager.getPlayer(targetName); Player target = mcMMOTarget.getPlayer(); - if (mcMMO.p.getGeneralConfig().getPTPCommandWorldPermissions()) { World targetWorld = target.getWorld(); World playerWorld = player.getWorld(); if (!Permissions.partyTeleportAllWorlds(player)) { if (!Permissions.partyTeleportWorld(target, targetWorld)) { - player.sendMessage(LocaleLoader.getString("Commands.ptp.NoWorldPermissions", targetWorld.getName())); + player.sendMessage( + LocaleLoader.getString("Commands.ptp.NoWorldPermissions", + targetWorld.getName())); return; - } - else if (targetWorld != playerWorld && !Permissions.partyTeleportWorld(player, targetWorld)) { - player.sendMessage(LocaleLoader.getString("Commands.ptp.NoWorldPermissions", targetWorld.getName())); + } else if (targetWorld != playerWorld && !Permissions.partyTeleportWorld(player, + targetWorld)) { + player.sendMessage( + LocaleLoader.getString("Commands.ptp.NoWorldPermissions", + targetWorld.getName())); return; } } @@ -193,67 +266,8 @@ public class PtpCommand implements TabExecutor { player.sendMessage(LocaleLoader.getString("Commands.Invite.Success")); target.sendMessage(LocaleLoader.getString("Commands.ptp.Request1", player.getName())); - target.sendMessage(LocaleLoader.getString("Commands.ptp.Request2", mcMMO.p.getGeneralConfig().getPTPCommandTimeout())); - } - - protected static boolean canTeleport(CommandSender sender, Player player, String targetName) { - McMMOPlayer mcMMOTarget = UserManager.getPlayer(targetName); - - if (!CommandUtils.checkPlayerExistence(sender, targetName, mcMMOTarget)) { - return false; - } - - Player target = mcMMOTarget.getPlayer(); - - if (player.equals(target)) { - player.sendMessage(LocaleLoader.getString("Party.Teleport.Self")); - return false; - } - - if (!PartyManager.inSameParty(player, target)) { - player.sendMessage(LocaleLoader.getString("Party.NotInYourParty", targetName)); - return false; - } - - if (!mcMMOTarget.getPartyTeleportRecord().isEnabled()) { - player.sendMessage(LocaleLoader.getString("Party.Teleport.Disabled", targetName)); - return false; - } - - if (!target.isValid()) { - player.sendMessage(LocaleLoader.getString("Party.Teleport.Dead")); - return false; - } - - return true; - } - - protected static void handleTeleportWarmup(Player teleportingPlayer, Player targetPlayer) { - if(UserManager.getPlayer(targetPlayer) == null) - { - targetPlayer.sendMessage(LocaleLoader.getString("Profile.PendingLoad")); - return; - } - - if(UserManager.getPlayer(teleportingPlayer) == null) - { - teleportingPlayer.sendMessage(LocaleLoader.getString("Profile.PendingLoad")); - return; - } - - McMMOPlayer mcMMOPlayer = UserManager.getPlayer(teleportingPlayer); - McMMOPlayer mcMMOTarget = UserManager.getPlayer(targetPlayer); - - long warmup = mcMMO.p.getGeneralConfig().getPTPCommandWarmup(); - - mcMMOPlayer.actualizeTeleportCommenceLocation(teleportingPlayer); - - if (warmup > 0) { - teleportingPlayer.sendMessage(LocaleLoader.getString("Teleport.Commencing", warmup)); - mcMMO.p.getFoliaLib().getImpl().runAtEntityLater(teleportingPlayer, new TeleportationWarmup(mcMMOPlayer, mcMMOTarget), 20 * warmup); - } - else { - EventUtils.handlePartyTeleportEvent(teleportingPlayer, targetPlayer); - } + target.sendMessage( + LocaleLoader.getString("Commands.ptp.Request2", + mcMMO.p.getGeneralConfig().getPTPCommandTimeout())); } } diff --git a/src/main/java/com/gmail/nossr50/commands/party/teleport/PtpToggleCommand.java b/src/main/java/com/gmail/nossr50/commands/party/teleport/PtpToggleCommand.java index aad4df9b9..ec1a1d6cc 100644 --- a/src/main/java/com/gmail/nossr50/commands/party/teleport/PtpToggleCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/party/teleport/PtpToggleCommand.java @@ -11,18 +11,19 @@ import org.jetbrains.annotations.NotNull; public class PtpToggleCommand implements CommandExecutor { @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, + @NotNull String label, String[] args) { if (!Permissions.partyTeleportToggle(sender)) { sender.sendMessage(command.getPermissionMessage()); return true; } - PartyTeleportRecord ptpRecord = UserManager.getPlayer(sender.getName()).getPartyTeleportRecord(); + PartyTeleportRecord ptpRecord = UserManager.getPlayer(sender.getName()) + .getPartyTeleportRecord(); if (ptpRecord.isEnabled()) { sender.sendMessage(LocaleLoader.getString("Commands.ptp.Disabled")); - } - else { + } else { sender.sendMessage(LocaleLoader.getString("Commands.ptp.Enabled")); } diff --git a/src/main/java/com/gmail/nossr50/commands/player/InspectCommand.java b/src/main/java/com/gmail/nossr50/commands/player/InspectCommand.java index ab1047387..2af5265f6 100644 --- a/src/main/java/com/gmail/nossr50/commands/player/InspectCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/player/InspectCommand.java @@ -11,6 +11,8 @@ import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.scoreboards.ScoreboardManager; import com.gmail.nossr50.util.skills.SkillTools; import com.google.common.collect.ImmutableList; +import java.util.ArrayList; +import java.util.List; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.command.TabExecutor; @@ -18,19 +20,18 @@ import org.bukkit.entity.Player; import org.bukkit.util.StringUtil; import org.jetbrains.annotations.NotNull; -import java.util.ArrayList; -import java.util.List; - public class InspectCommand implements TabExecutor { @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, + @NotNull String label, String[] args) { if (args.length == 1) { String playerName = CommandUtils.getMatchedPlayerName(args[0]); - McMMOPlayer mcMMOPlayer = UserManager.getOfflinePlayer(playerName); + final McMMOPlayer mmoPlayer = UserManager.getOfflinePlayer(playerName); - // If the mcMMOPlayer doesn't exist, create a temporary profile and check if it's present in the database. If it's not, abort the process. - if (mcMMOPlayer == null) { - PlayerProfile profile = mcMMO.getDatabaseManager().loadPlayerProfile(playerName); // Temporary Profile + // If the mmoPlayer doesn't exist, create a temporary profile and check if it's present in the database. If it's not, abort the process. + if (mmoPlayer == null) { + PlayerProfile profile = mcMMO.getDatabaseManager() + .loadPlayerProfile(playerName); // Temporary Profile if (!CommandUtils.isLoaded(sender, profile)) { return true; @@ -65,27 +66,26 @@ public class InspectCommand implements TabExecutor { // Sum power level int powerLevel = 0; - for (PrimarySkillType skill : SkillTools.NON_CHILD_SKILLS) + for (PrimarySkillType skill : SkillTools.NON_CHILD_SKILLS) { powerLevel += profile.getSkillLevel(skill); + } sender.sendMessage(LocaleLoader.getString("Commands.PowerLevel", powerLevel)); } else { - Player target = mcMMOPlayer.getPlayer(); - boolean isVanished = false; - - if (CommandUtils.hidden(sender, target, Permissions.inspectHidden(sender))) { - isVanished = true; - } + Player target = mmoPlayer.getPlayer(); + boolean isVanished = CommandUtils.hidden(sender, target, + Permissions.inspectHidden(sender)); //Only distance check players who are online and not vanished - if (!isVanished && CommandUtils.tooFar(sender, target, Permissions.inspectFar(sender))) { + if (!isVanished && CommandUtils.tooFar(sender, target, + Permissions.inspectFar(sender))) { return true; } if (mcMMO.p.getGeneralConfig().getScoreboardsEnabled() && sender instanceof Player && mcMMO.p.getGeneralConfig().getInspectUseBoard()) { - ScoreboardManager.enablePlayerInspectScoreboard((Player) sender, mcMMOPlayer); + ScoreboardManager.enablePlayerInspectScoreboard((Player) sender, mmoPlayer); if (!mcMMO.p.getGeneralConfig().getInspectUseChat()) { return true; @@ -102,7 +102,8 @@ public class InspectCommand implements TabExecutor { CommandUtils.printCombatSkills(target, sender); CommandUtils.printMiscSkills(target, sender); - sender.sendMessage(LocaleLoader.getString("Commands.PowerLevel", mcMMOPlayer.getPowerLevel())); + sender.sendMessage( + LocaleLoader.getString("Commands.PowerLevel", mmoPlayer.getPowerLevel())); } return true; @@ -111,10 +112,12 @@ public class InspectCommand implements TabExecutor { } @Override - public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, String[] args) { + public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, + @NotNull String alias, String[] args) { if (args.length == 1) { List playerNames = CommandUtils.getOnlinePlayerNames(sender); - return StringUtil.copyPartialMatches(args[0], playerNames, new ArrayList<>(playerNames.size())); + return StringUtil.copyPartialMatches(args[0], playerNames, + new ArrayList<>(playerNames.size())); } return ImmutableList.of(); } diff --git a/src/main/java/com/gmail/nossr50/commands/player/McrankCommand.java b/src/main/java/com/gmail/nossr50/commands/player/McRankCommand.java similarity index 67% rename from src/main/java/com/gmail/nossr50/commands/player/McrankCommand.java rename to src/main/java/com/gmail/nossr50/commands/player/McRankCommand.java index dcfcdcdbe..d7124996c 100644 --- a/src/main/java/com/gmail/nossr50/commands/player/McrankCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/player/McRankCommand.java @@ -3,12 +3,14 @@ package com.gmail.nossr50.commands.player; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.runnables.commands.McrankCommandAsyncTask; +import com.gmail.nossr50.runnables.commands.McRankCommandAsyncTask; import com.gmail.nossr50.util.MetadataConstants; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.commands.CommandUtils; import com.gmail.nossr50.util.player.UserManager; import com.google.common.collect.ImmutableList; +import java.util.ArrayList; +import java.util.List; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.command.TabExecutor; @@ -17,12 +19,10 @@ import org.bukkit.metadata.FixedMetadataValue; import org.bukkit.util.StringUtil; import org.jetbrains.annotations.NotNull; -import java.util.ArrayList; -import java.util.List; - -public class McrankCommand implements TabExecutor { +public class McRankCommand implements TabExecutor { @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, + @NotNull String label, String[] args) { switch (args.length) { case 0: if (CommandUtils.noConsoleUsage(sender)) { @@ -53,10 +53,10 @@ public class McrankCommand implements TabExecutor { } String playerName = CommandUtils.getMatchedPlayerName(args[0]); - McMMOPlayer mcMMOPlayer = UserManager.getOfflinePlayer(playerName); + final McMMOPlayer mmoPlayer = UserManager.getOfflinePlayer(playerName); - if (mcMMOPlayer != null) { - Player player = mcMMOPlayer.getPlayer(); + if (mmoPlayer != null) { + Player player = mmoPlayer.getPlayer(); playerName = player.getName(); if (CommandUtils.tooFar(sender, player, Permissions.mcrankFar(sender))) { @@ -73,28 +73,31 @@ public class McrankCommand implements TabExecutor { } @Override - public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, String[] args) { + public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, + @NotNull String alias, String[] args) { if (args.length == 1) { List playerNames = CommandUtils.getOnlinePlayerNames(sender); - return StringUtil.copyPartialMatches(args[0], playerNames, new ArrayList<>(playerNames.size())); + return StringUtil.copyPartialMatches(args[0], playerNames, + new ArrayList<>(playerNames.size())); } return ImmutableList.of(); } private void display(CommandSender sender, String playerName) { if (sender instanceof Player) { - McMMOPlayer mcMMOPlayer = UserManager.getPlayer(sender.getName()); + final McMMOPlayer mmoPlayer = UserManager.getPlayer(sender.getName()); - if(mcMMOPlayer == null) - { + if (mmoPlayer == null) { sender.sendMessage(LocaleLoader.getString("Profile.PendingLoad")); return; } - long cooldownMillis = Math.min(mcMMO.p.getGeneralConfig().getDatabasePlayerCooldown(), 1750); + long cooldownMillis = Math.min(mcMMO.p.getGeneralConfig().getDatabasePlayerCooldown(), + 1750); - if (mcMMOPlayer.getDatabaseATS() + cooldownMillis > System.currentTimeMillis()) { - sender.sendMessage(LocaleLoader.getString("Commands.Database.CooldownMS", getCDSeconds(mcMMOPlayer, cooldownMillis))); + if (mmoPlayer.getDatabaseATS() + cooldownMillis > System.currentTimeMillis()) { + sender.sendMessage(LocaleLoader.getString("Commands.Database.CooldownMS", + getCDSeconds(mmoPlayer, cooldownMillis))); return; } @@ -102,19 +105,23 @@ public class McrankCommand implements TabExecutor { sender.sendMessage(LocaleLoader.getString("Commands.Database.Processing")); return; } else { - ((Player) sender).setMetadata(MetadataConstants.METADATA_KEY_DATABASE_COMMAND, new FixedMetadataValue(mcMMO.p, null)); + ((Player) sender).setMetadata(MetadataConstants.METADATA_KEY_DATABASE_COMMAND, + new FixedMetadataValue(mcMMO.p, null)); } - mcMMOPlayer.actualizeDatabaseATS(); + mmoPlayer.actualizeDatabaseATS(); } - boolean useBoard = mcMMO.p.getGeneralConfig().getScoreboardsEnabled() && (sender instanceof Player) && (mcMMO.p.getGeneralConfig().getRankUseBoard()); + boolean useBoard = + mcMMO.p.getGeneralConfig().getScoreboardsEnabled() && (sender instanceof Player) + && (mcMMO.p.getGeneralConfig().getRankUseBoard()); boolean useChat = !useBoard || mcMMO.p.getGeneralConfig().getRankUseChat(); - mcMMO.p.getFoliaLib().getImpl().runAsync(new McrankCommandAsyncTask(playerName, sender, useBoard, useChat)); + mcMMO.p.getFoliaLib().getScheduler() + .runAsync(new McRankCommandAsyncTask(playerName, sender, useBoard, useChat)); } - private long getCDSeconds(McMMOPlayer mcMMOPlayer, long cooldownMillis) { - return ((mcMMOPlayer.getDatabaseATS() + cooldownMillis) - System.currentTimeMillis()); + private long getCDSeconds(McMMOPlayer mmoPlayer, long cooldownMillis) { + return ((mmoPlayer.getDatabaseATS() + cooldownMillis) - System.currentTimeMillis()); } } diff --git a/src/main/java/com/gmail/nossr50/commands/player/MctopCommand.java b/src/main/java/com/gmail/nossr50/commands/player/McTopCommand.java similarity index 63% rename from src/main/java/com/gmail/nossr50/commands/player/MctopCommand.java rename to src/main/java/com/gmail/nossr50/commands/player/McTopCommand.java index 86b1757e9..c54e4836e 100644 --- a/src/main/java/com/gmail/nossr50/commands/player/MctopCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/player/McTopCommand.java @@ -4,13 +4,15 @@ import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.runnables.commands.MctopCommandAsyncTask; +import com.gmail.nossr50.runnables.commands.McTopCommandAsyncTask; import com.gmail.nossr50.util.MetadataConstants; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.commands.CommandUtils; import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.text.StringUtils; import com.google.common.collect.ImmutableList; +import java.util.ArrayList; +import java.util.List; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.command.TabExecutor; @@ -19,12 +21,10 @@ import org.bukkit.metadata.FixedMetadataValue; import org.bukkit.util.StringUtil; import org.jetbrains.annotations.NotNull; -import java.util.ArrayList; -import java.util.List; - -public class MctopCommand implements TabExecutor { +public class McTopCommand implements TabExecutor { @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, + @NotNull String label, String[] args) { PrimarySkillType skill = null; switch (args.length) { @@ -44,6 +44,13 @@ public class MctopCommand implements TabExecutor { return true; } + // Check if the command is for Maces but the MC version is not correct + if (skill == PrimarySkillType.MACES + && !mcMMO.getCompatibilityManager().getMinecraftGameVersion() + .isAtLeast(1, 21, 0)) { + return true; + } + display(1, skill, sender, command); return true; @@ -58,6 +65,13 @@ public class MctopCommand implements TabExecutor { return true; } + // Check if the command is for Maces but the MC version is not correct + if (skill == PrimarySkillType.MACES + && !mcMMO.getCompatibilityManager().getMinecraftGameVersion() + .isAtLeast(1, 21, 0)) { + return true; + } + display(Math.abs(Integer.parseInt(args[1])), skill, sender, command); return true; @@ -67,9 +81,12 @@ public class MctopCommand implements TabExecutor { } @Override - public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, String[] args) { + public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, + @NotNull String alias, String[] args) { if (args.length == 1) { - return StringUtil.copyPartialMatches(args[0], mcMMO.p.getSkillTools().LOCALIZED_SKILL_NAMES, new ArrayList<>(mcMMO.p.getSkillTools().LOCALIZED_SKILL_NAMES.size())); + return StringUtil.copyPartialMatches(args[0], + mcMMO.p.getSkillTools().LOCALIZED_SKILL_NAMES, + new ArrayList<>(mcMMO.p.getSkillTools().LOCALIZED_SKILL_NAMES.size())); } return ImmutableList.of(); } @@ -85,16 +102,20 @@ public class MctopCommand implements TabExecutor { return; } - McMMOPlayer mcMMOPlayer = UserManager.getPlayer(sender.getName()); - long cooldownMillis = Math.max(mcMMO.p.getGeneralConfig().getDatabasePlayerCooldown(), 1750); + final McMMOPlayer mmoPlayer = UserManager.getPlayer(sender.getName()); + long cooldownMillis = Math.max(mcMMO.p.getGeneralConfig().getDatabasePlayerCooldown(), + 1750); - if (mcMMOPlayer.getDatabaseATS() + cooldownMillis > System.currentTimeMillis()) { - double seconds = ((mcMMOPlayer.getDatabaseATS() + cooldownMillis) - System.currentTimeMillis()) / 1000.0D; + if (mmoPlayer.getDatabaseATS() + cooldownMillis > System.currentTimeMillis()) { + double seconds = + ((mmoPlayer.getDatabaseATS() + cooldownMillis) - System.currentTimeMillis()) + / 1000.0D; if (seconds < 1) { seconds = 1; } - sender.sendMessage(LocaleLoader.formatString(LocaleLoader.getString("Commands.Database.Cooldown"), seconds)); + sender.sendMessage(LocaleLoader.formatString( + LocaleLoader.getString("Commands.Database.Cooldown"), seconds)); return; } @@ -102,20 +123,23 @@ public class MctopCommand implements TabExecutor { sender.sendMessage(LocaleLoader.getString("Commands.Database.Processing")); return; } else { - ((Player) sender).setMetadata(MetadataConstants.METADATA_KEY_DATABASE_COMMAND, new FixedMetadataValue(mcMMO.p, null)); + ((Player) sender).setMetadata(MetadataConstants.METADATA_KEY_DATABASE_COMMAND, + new FixedMetadataValue(mcMMO.p, null)); } - mcMMOPlayer.actualizeDatabaseATS(); + mmoPlayer.actualizeDatabaseATS(); } display(page, skill, sender); } private void display(int page, PrimarySkillType skill, CommandSender sender) { - boolean useBoard = (sender instanceof Player) && (mcMMO.p.getGeneralConfig().getTopUseBoard()); + boolean useBoard = + (sender instanceof Player) && (mcMMO.p.getGeneralConfig().getTopUseBoard()); boolean useChat = !useBoard || mcMMO.p.getGeneralConfig().getTopUseChat(); - mcMMO.p.getFoliaLib().getImpl().runAsync(new MctopCommandAsyncTask(page, skill, sender, useBoard, useChat)); + mcMMO.p.getFoliaLib().getScheduler() + .runAsync(new McTopCommandAsyncTask(page, skill, sender, useBoard, useChat)); } private PrimarySkillType extractSkill(CommandSender sender, String skillName) { diff --git a/src/main/java/com/gmail/nossr50/commands/player/MccooldownCommand.java b/src/main/java/com/gmail/nossr50/commands/player/MccooldownCommand.java index 4475c984a..255f76c1f 100644 --- a/src/main/java/com/gmail/nossr50/commands/player/MccooldownCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/player/MccooldownCommand.java @@ -8,17 +8,17 @@ import com.gmail.nossr50.util.commands.CommandUtils; import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.scoreboards.ScoreboardManager; import com.google.common.collect.ImmutableList; +import java.util.List; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.command.TabExecutor; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; -import java.util.List; - public class MccooldownCommand implements TabExecutor { @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, + @NotNull String label, String[] args) { if (CommandUtils.noConsoleUsage(sender)) { return true; } @@ -28,9 +28,10 @@ public class MccooldownCommand implements TabExecutor { } if (args.length == 0) { - Player player = (Player) sender; + final Player player = (Player) sender; - if (mcMMO.p.getGeneralConfig().getScoreboardsEnabled() && mcMMO.p.getGeneralConfig().getCooldownUseBoard()) { + if (mcMMO.p.getGeneralConfig().getScoreboardsEnabled() && mcMMO.p.getGeneralConfig() + .getCooldownUseBoard()) { ScoreboardManager.enablePlayerCooldownScoreboard(player); if (!mcMMO.p.getGeneralConfig().getCooldownUseChat()) { @@ -43,7 +44,7 @@ public class MccooldownCommand implements TabExecutor { return true; } - McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player); + final McMMOPlayer mmoPlayer = UserManager.getPlayer(player); player.sendMessage(LocaleLoader.getString("Commands.Cooldowns.Header")); player.sendMessage(LocaleLoader.getString("mcMMO.NoSkillNote")); @@ -53,12 +54,14 @@ public class MccooldownCommand implements TabExecutor { continue; } - int seconds = mcMMOPlayer.calculateTimeRemaining(ability); + int seconds = mmoPlayer.calculateTimeRemaining(ability); if (seconds <= 0) { - player.sendMessage(LocaleLoader.getString("Commands.Cooldowns.Row.Y", ability.getLocalizedName())); + player.sendMessage(LocaleLoader.getString("Commands.Cooldowns.Row.Y", + ability.getLocalizedName())); } else { - player.sendMessage(LocaleLoader.getString("Commands.Cooldowns.Row.N", ability.getLocalizedName(), seconds)); + player.sendMessage(LocaleLoader.getString("Commands.Cooldowns.Row.N", + ability.getLocalizedName(), seconds)); } } @@ -68,7 +71,8 @@ public class MccooldownCommand implements TabExecutor { } @Override - public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, String[] args) { + public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, + @NotNull String alias, String[] args) { return ImmutableList.of(); } } diff --git a/src/main/java/com/gmail/nossr50/commands/player/McstatsCommand.java b/src/main/java/com/gmail/nossr50/commands/player/McstatsCommand.java index a9e8cf6e1..3ae8e5fd0 100644 --- a/src/main/java/com/gmail/nossr50/commands/player/McstatsCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/player/McstatsCommand.java @@ -6,17 +6,17 @@ import com.gmail.nossr50.util.commands.CommandUtils; import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.scoreboards.ScoreboardManager; import com.google.common.collect.ImmutableList; +import java.util.List; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.command.TabExecutor; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; -import java.util.List; - public class McstatsCommand implements TabExecutor { @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, + @NotNull String label, String[] args) { if (CommandUtils.noConsoleUsage(sender)) { return true; } @@ -31,9 +31,10 @@ public class McstatsCommand implements TabExecutor { return true; } - Player player = (Player) sender; + final Player player = (Player) sender; - if (mcMMO.p.getGeneralConfig().getStatsUseBoard() && mcMMO.p.getGeneralConfig().getScoreboardsEnabled()) { + if (mcMMO.p.getGeneralConfig().getStatsUseBoard() && mcMMO.p.getGeneralConfig() + .getScoreboardsEnabled()) { ScoreboardManager.enablePlayerStatsScoreboard(player); if (!mcMMO.p.getGeneralConfig().getStatsUseChat()) { @@ -51,9 +52,11 @@ public class McstatsCommand implements TabExecutor { int powerLevelCap = mcMMO.p.getGeneralConfig().getPowerLevelCap(); if (powerLevelCap != Integer.MAX_VALUE) { - player.sendMessage(LocaleLoader.getString("Commands.PowerLevel.Capped", UserManager.getPlayer(player).getPowerLevel(), powerLevelCap)); + player.sendMessage(LocaleLoader.getString("Commands.PowerLevel.Capped", + UserManager.getPlayer(player).getPowerLevel(), powerLevelCap)); } else { - player.sendMessage(LocaleLoader.getString("Commands.PowerLevel", UserManager.getPlayer(player).getPowerLevel())); + player.sendMessage(LocaleLoader.getString("Commands.PowerLevel", + UserManager.getPlayer(player).getPowerLevel())); } return true; @@ -62,7 +65,8 @@ public class McstatsCommand implements TabExecutor { } @Override - public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, String[] args) { + public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, + @NotNull String alias, String[] args) { return ImmutableList.of(); } } diff --git a/src/main/java/com/gmail/nossr50/commands/player/XPBarCommand.java b/src/main/java/com/gmail/nossr50/commands/player/XPBarCommand.java index e780fa19d..371716aac 100644 --- a/src/main/java/com/gmail/nossr50/commands/player/XPBarCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/player/XPBarCommand.java @@ -9,6 +9,8 @@ import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.skills.SkillUtils; import com.gmail.nossr50.util.text.StringUtils; import com.google.common.collect.ImmutableList; +import java.util.ArrayList; +import java.util.List; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.command.TabExecutor; @@ -17,50 +19,56 @@ import org.bukkit.util.StringUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; -import java.util.List; - public class XPBarCommand implements TabExecutor { @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { - if(sender instanceof Player) { - McMMOPlayer mmoPlayer = UserManager.getPlayer((Player) sender); - if(mmoPlayer == null) { - NotificationManager.sendPlayerInformationChatOnlyPrefixed(mmoPlayer.getPlayer(), "Profile.PendingLoad"); + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, + @NotNull String label, @NotNull String[] args) { + if (sender instanceof Player) { + final McMMOPlayer mmoPlayer = UserManager.getPlayer((Player) sender); + if (mmoPlayer == null) { + NotificationManager.sendPlayerInformationChatOnlyPrefixed(mmoPlayer.getPlayer(), + "Profile.PendingLoad"); return false; } - if(args.length == 0) { + if (args.length == 0) { return false; - } else if(args.length < 2) { - String option = args[0]; + } else if (args.length < 2) { + String option = args[0]; - if(option.equalsIgnoreCase(ExperienceBarManager.XPBarSettingTarget.RESET.toString())) { - mmoPlayer.getExperienceBarManager().xpBarSettingToggle(ExperienceBarManager.XPBarSettingTarget.RESET, null); - return true; - } else if(option.equalsIgnoreCase(ExperienceBarManager.XPBarSettingTarget.DISABLE.toString())) { - mmoPlayer.getExperienceBarManager().disableAllBars(); - return true; - } else { - return false; - } + if (option.equalsIgnoreCase( + ExperienceBarManager.XPBarSettingTarget.RESET.toString())) { + mmoPlayer.getExperienceBarManager() + .xpBarSettingToggle(ExperienceBarManager.XPBarSettingTarget.RESET, + null); + return true; + } else if (option.equalsIgnoreCase( + ExperienceBarManager.XPBarSettingTarget.DISABLE.toString())) { + mmoPlayer.getExperienceBarManager().disableAllBars(); + return true; + } else { + return false; + } - //Per skill Settings path + //Per skill Settings path } else if (args.length == 2) { String skillName = args[1]; - if(SkillUtils.isSkill(skillName)) { + if (SkillUtils.isSkill(skillName)) { PrimarySkillType targetSkill = mcMMO.p.getSkillTools().matchSkill(skillName); //Target setting String option = args[0].toLowerCase(); - ExperienceBarManager.XPBarSettingTarget settingTarget = getSettingTarget(option); - if(settingTarget != null && settingTarget != ExperienceBarManager.XPBarSettingTarget.RESET) { + ExperienceBarManager.XPBarSettingTarget settingTarget = getSettingTarget( + option); + if (settingTarget != null + && settingTarget != ExperienceBarManager.XPBarSettingTarget.RESET) { //Change setting - mmoPlayer.getExperienceBarManager().xpBarSettingToggle(settingTarget, targetSkill); + mmoPlayer.getExperienceBarManager() + .xpBarSettingToggle(settingTarget, targetSkill); return true; } else { return false; @@ -92,19 +100,25 @@ public class XPBarCommand implements TabExecutor { } @Override - public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, String[] args) { + public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, + @NotNull String alias, String[] args) { switch (args.length) { case 1: List options = new ArrayList<>(); - for(ExperienceBarManager.XPBarSettingTarget settingTarget : ExperienceBarManager.XPBarSettingTarget.values()) { + for (ExperienceBarManager.XPBarSettingTarget settingTarget : ExperienceBarManager.XPBarSettingTarget.values()) { options.add(StringUtils.getCapitalized(settingTarget.toString())); } - return StringUtil.copyPartialMatches(args[0], options, new ArrayList<>(ExperienceBarManager.XPBarSettingTarget.values().length)); + return StringUtil.copyPartialMatches(args[0], options, + new ArrayList<>(ExperienceBarManager.XPBarSettingTarget.values().length)); case 2: - if(!args[0].equalsIgnoreCase(ExperienceBarManager.XPBarSettingTarget.RESET.toString())) - return StringUtil.copyPartialMatches(args[1], mcMMO.p.getSkillTools().LOCALIZED_SKILL_NAMES, new ArrayList<>(mcMMO.p.getSkillTools().LOCALIZED_SKILL_NAMES.size())); + if (!args[0].equalsIgnoreCase( + ExperienceBarManager.XPBarSettingTarget.RESET.toString())) { + return StringUtil.copyPartialMatches(args[1], + mcMMO.p.getSkillTools().LOCALIZED_SKILL_NAMES, + new ArrayList<>(mcMMO.p.getSkillTools().LOCALIZED_SKILL_NAMES.size())); + } default: return ImmutableList.of(); } diff --git a/src/main/java/com/gmail/nossr50/commands/server/Mcmmoupgrade.java b/src/main/java/com/gmail/nossr50/commands/server/Mcmmoupgrade.java index 77b181e2a..f8469fb63 100644 --- a/src/main/java/com/gmail/nossr50/commands/server/Mcmmoupgrade.java +++ b/src/main/java/com/gmail/nossr50/commands/server/Mcmmoupgrade.java @@ -10,7 +10,8 @@ import org.jetbrains.annotations.NotNull; */ public class Mcmmoupgrade implements CommandExecutor { @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, + @NotNull String label, String[] args) { return false; } } 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 bb963168f..3ce1db82e 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/AcrobaticsCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/AcrobaticsCommand.java @@ -5,15 +5,13 @@ import com.gmail.nossr50.datatypes.skills.SubSkillType; 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.random.RandomChanceSkill; -import com.gmail.nossr50.util.random.RandomChanceUtil; -import com.gmail.nossr50.util.skills.SkillActivationType; +import com.gmail.nossr50.util.Permissions; +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; - import java.util.ArrayList; import java.util.List; +import net.kyori.adventure.text.Component; +import org.bukkit.entity.Player; public class AcrobaticsCommand extends SkillCommand { private String dodgeChance; @@ -30,7 +28,8 @@ public class AcrobaticsCommand extends SkillCommand { 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); + final String[] dodgeStrings = ProbabilityUtil.getRNGDisplayValues(mmoPlayer, + SubSkillType.ACROBATICS_DODGE); dodgeChance = dodgeStrings[0]; dodgeChanceLucky = dodgeStrings[1]; } @@ -38,50 +37,32 @@ public class AcrobaticsCommand extends SkillCommand { @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 - protected List statsDisplay(Player player, float skillValue, boolean hasEndurance, boolean isLucky) { + protected List statsDisplay(Player player, float skillValue, boolean hasEndurance, + boolean isLucky) { List messages = new ArrayList<>(); if (canDodge) { messages.add(getStatMessage(SubSkillType.ACROBATICS_DODGE, dodgeChance) - + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", dodgeChanceLucky) : "")); + + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", dodgeChanceLucky) + : "")); } - + if (canRoll) { AbstractSubSkill abstractSubSkill = InteractionManager.getAbstractByName("Roll"); - if(abstractSubSkill != null) - { - double rollChance, graceChance; - - //Chance to roll at half - RandomChanceSkill roll_rcs = new RandomChanceSkill(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 - - //Chance Stat Calculations - rollChance = RandomChanceUtil.getRandomChanceExecutionChance(roll_rcs); - graceChance = RandomChanceUtil.getRandomChanceExecutionChance(grace_rcs); - //damageThreshold = mcMMO.p.getAdvancedConfig().getRollDamageThreshold(); - - String[] rollStrings = getAbilityDisplayValues(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, player, SubSkillType.ACROBATICS_ROLL); - - //Format - double rollChanceLucky = rollChance * 1.333D; - double graceChanceLucky = graceChance * 1.333D; + if (abstractSubSkill != null) { + String[] rollStrings = ProbabilityUtil.getRNGDisplayValues(mmoPlayer, + SubSkillType.ACROBATICS_ROLL); messages.add(getStatMessage(SubSkillType.ACROBATICS_ROLL, rollStrings[0]) - + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", rollStrings[1]) : "")); - - /*messages.add(getStatMessage(true, false, SubSkillType.ACROBATICS_ROLL, String.valueOf(graceChance)) - + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", String.valueOf(graceChanceLucky)) : ""));*/ + + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", rollStrings[1]) + : "")); } } @@ -92,7 +73,8 @@ public class AcrobaticsCommand extends SkillCommand { protected List getTextComponents(Player player) { List textComponents = new ArrayList<>(); - TextComponentFactory.getSubSkillTextComponents(player, textComponents, PrimarySkillType.ACROBATICS); + TextComponentFactory.getSubSkillTextComponents(player, textComponents, + PrimarySkillType.ACROBATICS); return textComponents; } 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 a8d5fcc8b..cd5570ba8 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/AlchemyCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/AlchemyCommand.java @@ -5,21 +5,19 @@ import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.skills.alchemy.AlchemyManager; 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; -import net.kyori.adventure.text.Component; -import org.bukkit.entity.Player; - import java.util.ArrayList; import java.util.List; +import net.kyori.adventure.text.Component; +import org.bukkit.entity.Player; public class AlchemyCommand extends SkillCommand { private String brewSpeed; private String brewSpeedLucky; - private int tier; - private int ingredientCount; + private int tier; + private int ingredientCount; private String ingredientList; private boolean canCatalysis; @@ -30,20 +28,14 @@ public class AlchemyCommand extends SkillCommand { } protected String[] calculateAbilityDisplayValues(Player player) { - //TODO: Needed? - if(UserManager.getPlayer(player) == null) - { - player.sendMessage(LocaleLoader.getString("Profile.PendingLoad")); - return new String[] {"DATA NOT LOADED", "DATA NOT LOADED"}; - } - - AlchemyManager alchemyManager = UserManager.getPlayer(player).getAlchemyManager(); + AlchemyManager alchemyManager = mmoPlayer.getAlchemyManager(); String[] displayValues = new String[2]; boolean isLucky = Permissions.lucky(player, PrimarySkillType.ALCHEMY); displayValues[0] = decimal.format(alchemyManager.calculateBrewSpeed(false)) + "x"; - displayValues[1] = isLucky ? decimal.format(alchemyManager.calculateBrewSpeed(true)) + "x" : null; + displayValues[1] = + isLucky ? decimal.format(alchemyManager.calculateBrewSpeed(true)) + "x" : null; return displayValues; } @@ -59,7 +51,7 @@ public class AlchemyCommand extends SkillCommand { // ALCHEMY_CONCOCTIONS if (canConcoctions) { - AlchemyManager alchemyManager = UserManager.getPlayer(player).getAlchemyManager(); + AlchemyManager alchemyManager = mmoPlayer.getAlchemyManager(); tier = alchemyManager.getTier(); ingredientCount = alchemyManager.getIngredients().size(); ingredientList = alchemyManager.getIngredientList(); @@ -68,12 +60,13 @@ public class AlchemyCommand extends SkillCommand { @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 - protected List statsDisplay(Player player, float skillValue, boolean hasEndurance, boolean isLucky) { + protected List statsDisplay(Player player, float skillValue, boolean hasEndurance, + boolean isLucky) { List messages = new ArrayList<>(); if (canCatalysis) { @@ -82,8 +75,11 @@ public class AlchemyCommand extends SkillCommand { } if (canConcoctions) { - messages.add(getStatMessage(false, true, SubSkillType.ALCHEMY_CONCOCTIONS, String.valueOf(tier), String.valueOf(RankUtils.getHighestRank(SubSkillType.ALCHEMY_CONCOCTIONS)))); - messages.add(getStatMessage(true, true, SubSkillType.ALCHEMY_CONCOCTIONS, String.valueOf(ingredientCount), ingredientList)); + messages.add(getStatMessage(false, true, SubSkillType.ALCHEMY_CONCOCTIONS, + String.valueOf(tier), + String.valueOf(RankUtils.getHighestRank(SubSkillType.ALCHEMY_CONCOCTIONS)))); + messages.add(getStatMessage(true, true, SubSkillType.ALCHEMY_CONCOCTIONS, + String.valueOf(ingredientCount), ingredientList)); //messages.add(LocaleLoader.getString("Alchemy.Concoctions.Rank", tier, RankUtils.getHighestRank(SubSkillType.ALCHEMY_CONCOCTIONS))); //messages.add(LocaleLoader.getString("Alchemy.Concoctions.Ingredients", ingredientCount, ingredientList)); @@ -96,7 +92,8 @@ public class AlchemyCommand extends SkillCommand { protected List getTextComponents(Player player) { List textComponents = new ArrayList<>(); - TextComponentFactory.getSubSkillTextComponents(player, textComponents, PrimarySkillType.ALCHEMY); + TextComponentFactory.getSubSkillTextComponents(player, textComponents, + PrimarySkillType.ALCHEMY); return textComponents; } diff --git a/src/main/java/com/gmail/nossr50/commands/skills/AprilCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/AprilCommand.java index 5364918ff..cfab931cd 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/AprilCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/AprilCommand.java @@ -31,7 +31,7 @@ // skillName = StringUtils.getCapitalized(label); // // if (args.length == 0) { -// Player player = (Player) sender; +// final Player player = (Player) sender; // FakeSkillType fakeSkillType = FakeSkillType.getByName(skillName); // // float skillValue = Misc.getRandom().nextInt(99); 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 59decaf9f..77eb6706e 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/ArcheryCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/ArcheryCommand.java @@ -4,14 +4,14 @@ 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.random.ProbabilityUtil; 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; - import java.util.ArrayList; import java.util.List; +import net.kyori.adventure.text.Component; +import org.bukkit.entity.Player; public class ArcheryCommand extends SkillCommand { private String skillShotBonus; @@ -32,18 +32,20 @@ public class ArcheryCommand extends SkillCommand { 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 = ProbabilityUtil.getRNGDisplayValues(mmoPlayer, + 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 = ProbabilityUtil.getRNGDisplayValues(mmoPlayer, + SubSkillType.ARCHERY_DAZE); dazeChance = dazeStrings[0]; dazeChanceLucky = dazeStrings[1]; } - + // SKILL SHOT if (canSkillShot) { skillShotBonus = percent.format(Archery.getDamageBonusPercent(player)); @@ -52,32 +54,36 @@ public class ArcheryCommand extends SkillCommand { @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 - protected List statsDisplay(Player player, float skillValue, boolean hasEndurance, boolean isLucky) { + protected List statsDisplay(Player player, float skillValue, boolean hasEndurance, + boolean isLucky) { List messages = new ArrayList<>(); if (canRetrieve) { messages.add(getStatMessage(SubSkillType.ARCHERY_ARROW_RETRIEVAL, retrieveChance) - + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", retrieveChanceLucky) : "")); + + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", retrieveChanceLucky) + : "")); } - + if (canDaze) { messages.add(getStatMessage(SubSkillType.ARCHERY_DAZE, dazeChance) - + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", dazeChanceLucky) : "")); + + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", dazeChanceLucky) + : "")); } - + if (canSkillShot) { 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)))); + String.valueOf(CombatUtils.getLimitBreakDamageAgainstQuality(player, + SubSkillType.ARCHERY_ARCHERY_LIMIT_BREAK, 1000)))); } return messages; @@ -87,7 +93,8 @@ public class ArcheryCommand extends SkillCommand { protected List getTextComponents(Player player) { List textComponents = new ArrayList<>(); - TextComponentFactory.getSubSkillTextComponents(player, textComponents, PrimarySkillType.ARCHERY); + TextComponentFactory.getSubSkillTextComponents(player, textComponents, + PrimarySkillType.ARCHERY); return textComponents; } 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 d6b5c029a..620fd6e17 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/AxesCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/AxesCommand.java @@ -5,16 +5,14 @@ import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.locale.LocaleLoader; 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.SkillActivationType; 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; +import net.kyori.adventure.text.Component; +import org.bukkit.entity.Player; public class AxesCommand extends SkillCommand { private String critChance; @@ -38,21 +36,22 @@ public class AxesCommand extends SkillCommand { protected void dataCalculations(Player player, float skillValue) { // ARMOR IMPACT if (canImpact) { - impactDamage = UserManager.getPlayer(player).getAxesManager().getImpactDurabilityDamage(); + impactDamage = mmoPlayer.getAxesManager().getImpactDurabilityDamage(); } // AXE MASTERY if (canAxeMastery) { axeMasteryDamage = Axes.getAxeMasteryBonusDamage(player); } - + // CRITICAL HIT if (canCritical) { - String[] criticalHitStrings = getAbilityDisplayValues(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, player, SubSkillType.AXES_CRITICAL_STRIKES); + String[] criticalHitStrings = ProbabilityUtil.getRNGDisplayValues(mmoPlayer, + SubSkillType.AXES_CRITICAL_STRIKES); critChance = criticalHitStrings[0]; critChanceLucky = criticalHitStrings[1]; } - + // SKULL SPLITTER if (canSkullSplitter) { String[] skullSplitterStrings = calculateLengthDisplayValues(player, skillValue); @@ -63,42 +62,54 @@ public class AxesCommand extends SkillCommand { @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); + canSkullSplitter = + Permissions.skullSplitter(player) && RankUtils.hasUnlockedSubskill(player, + SubSkillType.AXES_SKULL_SPLITTER); + 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 - protected List statsDisplay(Player player, float skillValue, boolean hasEndurance, boolean isLucky) { + protected List statsDisplay(Player player, float skillValue, boolean hasEndurance, + boolean isLucky) { List messages = new ArrayList<>(); if (canImpact) { - messages.add(LocaleLoader.getString("Ability.Generic.Template", LocaleLoader.getString("Axes.Ability.Bonus.2"), LocaleLoader.getString("Axes.Ability.Bonus.3", impactDamage))); + messages.add(LocaleLoader.getString("Ability.Generic.Template", + LocaleLoader.getString("Axes.Ability.Bonus.2"), + LocaleLoader.getString("Axes.Ability.Bonus.3", impactDamage))); } - + if (canAxeMastery) { - messages.add(LocaleLoader.getString("Ability.Generic.Template", LocaleLoader.getString("Axes.Ability.Bonus.0"), LocaleLoader.getString("Axes.Ability.Bonus.1", axeMasteryDamage))); + messages.add(LocaleLoader.getString("Ability.Generic.Template", + LocaleLoader.getString("Axes.Ability.Bonus.0"), + LocaleLoader.getString("Axes.Ability.Bonus.1", axeMasteryDamage))); } if (canCritical) { messages.add(getStatMessage(SubSkillType.AXES_CRITICAL_STRIKES, critChance) - + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", critChanceLucky) : "")); + + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", critChanceLucky) + : "")); } - + if (canGreaterImpact) { - messages.add(LocaleLoader.getString("Ability.Generic.Template", LocaleLoader.getString("Axes.Ability.Bonus.4"), LocaleLoader.getString("Axes.Ability.Bonus.5", Axes.greaterImpactBonusDamage))); + messages.add(LocaleLoader.getString("Ability.Generic.Template", + LocaleLoader.getString("Axes.Ability.Bonus.4"), + LocaleLoader.getString("Axes.Ability.Bonus.5", Axes.greaterImpactBonusDamage))); } if (canSkullSplitter) { messages.add(getStatMessage(SubSkillType.AXES_SKULL_SPLITTER, skullSplitterLength) - + (hasEndurance ? LocaleLoader.getString("Perks.ActivationTime.Bonus", skullSplitterLengthEndurance) : "")); + + (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)))); + String.valueOf(CombatUtils.getLimitBreakDamageAgainstQuality(player, + SubSkillType.AXES_AXES_LIMIT_BREAK, 1000)))); } return messages; @@ -106,9 +117,10 @@ public class AxesCommand extends SkillCommand { @Override protected List getTextComponents(Player player) { - List textComponents = new ArrayList<>(); + final List textComponents = new ArrayList<>(); - TextComponentFactory.getSubSkillTextComponents(player, textComponents, PrimarySkillType.AXES); + TextComponentFactory.getSubSkillTextComponents(player, textComponents, + PrimarySkillType.AXES); return textComponents; } 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 000000000..fe2a87ec7 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/commands/skills/CrossbowsCommand.java @@ -0,0 +1,76 @@ +package com.gmail.nossr50.commands.skills; + +import static com.gmail.nossr50.datatypes.skills.SubSkillType.CROSSBOWS_CROSSBOWS_LIMIT_BREAK; +import static com.gmail.nossr50.datatypes.skills.SubSkillType.CROSSBOWS_POWERED_SHOT; +import static com.gmail.nossr50.datatypes.skills.SubSkillType.CROSSBOWS_TRICK_SHOT; + +import com.gmail.nossr50.datatypes.skills.PrimarySkillType; +import com.gmail.nossr50.util.Permissions; +import com.gmail.nossr50.util.skills.CombatUtils; +import com.gmail.nossr50.util.skills.RankUtils; +import com.gmail.nossr50.util.text.TextComponentFactory; +import java.util.ArrayList; +import java.util.List; +import net.kyori.adventure.text.Component; +import org.bukkit.entity.Player; + +public class CrossbowsCommand extends SkillCommand { + private boolean canTrickShot; + private boolean canPoweredShot; + + public CrossbowsCommand() { + super(PrimarySkillType.CROSSBOWS); + } + + @Override + protected void dataCalculations(Player player, float skillValue) { + // TODO: Implement data calculations + } + + @Override + protected void permissionsCheck(Player player) { + canTrickShot = RankUtils.hasUnlockedSubskill(player, CROSSBOWS_TRICK_SHOT) + && Permissions.trickShot(player); + + canPoweredShot = RankUtils.hasUnlockedSubskill(player, CROSSBOWS_POWERED_SHOT) + && Permissions.poweredShot(player); + } + + @Override + protected List statsDisplay(Player player, float skillValue, boolean hasEndurance, + boolean isLucky) { + List messages = new ArrayList<>(); + + if (mmoPlayer == null) { + return messages; + } + + if (canPoweredShot) { + messages.add(getStatMessage(CROSSBOWS_POWERED_SHOT, + percent.format(mmoPlayer.getCrossbowsManager().getDamageBonusPercent(player)))); + } + + if (canTrickShot) { + messages.add(getStatMessage(CROSSBOWS_TRICK_SHOT, + String.valueOf(mmoPlayer.getCrossbowsManager().getTrickShotMaxBounceCount()))); + } + + 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; + } + + @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/ExcavationCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/ExcavationCommand.java index de7341e93..d5068bd34 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/ExcavationCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/ExcavationCommand.java @@ -5,14 +5,12 @@ import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.skills.excavation.ExcavationManager; 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; -import net.kyori.adventure.text.Component; -import org.bukkit.entity.Player; - import java.util.ArrayList; import java.util.List; +import net.kyori.adventure.text.Component; +import org.bukkit.entity.Player; public class ExcavationCommand extends SkillCommand { private String gigaDrillBreakerLength; @@ -37,24 +35,28 @@ public class ExcavationCommand extends SkillCommand { @Override protected void permissionsCheck(Player player) { - canGigaDrill = Permissions.gigaDrillBreaker(player) && RankUtils.hasUnlockedSubskill(player, SubSkillType.EXCAVATION_GIGA_DRILL_BREAKER); - canTreasureHunt = canUseSubskill(player, SubSkillType.EXCAVATION_ARCHAEOLOGY); + canGigaDrill = Permissions.gigaDrillBreaker(player) && RankUtils.hasUnlockedSubskill(player, + SubSkillType.EXCAVATION_GIGA_DRILL_BREAKER); + canTreasureHunt = Permissions.canUseSubSkill(player, SubSkillType.EXCAVATION_ARCHAEOLOGY); } @Override - protected List statsDisplay(Player player, float skillValue, boolean hasEndurance, boolean isLucky) { + protected List statsDisplay(Player player, float skillValue, boolean hasEndurance, + boolean isLucky) { List messages = new ArrayList<>(); - ExcavationManager excavationManager = UserManager.getPlayer(player).getExcavationManager(); + ExcavationManager excavationManager = mmoPlayer.getExcavationManager(); if (canGigaDrill) { - messages.add(getStatMessage(SubSkillType.EXCAVATION_GIGA_DRILL_BREAKER, gigaDrillBreakerLength) - + (hasEndurance ? LocaleLoader.getString("Perks.ActivationTime.Bonus", gigaDrillBreakerLengthEndurance) : "")); + messages.add(getStatMessage(SubSkillType.EXCAVATION_GIGA_DRILL_BREAKER, + gigaDrillBreakerLength) + + (hasEndurance ? LocaleLoader.getString("Perks.ActivationTime.Bonus", + gigaDrillBreakerLengthEndurance) : "")); //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, @@ -69,7 +71,8 @@ public class ExcavationCommand extends SkillCommand { protected List getTextComponents(Player player) { List textComponents = new ArrayList<>(); - TextComponentFactory.getSubSkillTextComponents(player, textComponents, PrimarySkillType.EXCAVATION); + TextComponentFactory.getSubSkillTextComponents(player, textComponents, + PrimarySkillType.EXCAVATION); return textComponents; } 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 f22f8399e..d96066c39 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/FishingCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/FishingCommand.java @@ -7,16 +7,16 @@ import com.gmail.nossr50.datatypes.treasure.Rarity; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.skills.fishing.FishingManager; -import com.gmail.nossr50.util.player.UserManager; -import com.gmail.nossr50.util.random.RandomChanceUtil; +import com.gmail.nossr50.util.Permissions; +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.text.StringUtils; 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; +import net.kyori.adventure.text.Component; +import org.bukkit.entity.Player; public class FishingCommand extends SkillCommand { private int lootTier; @@ -48,38 +48,53 @@ public class FishingCommand extends SkillCommand { @Override protected void dataCalculations(Player player, float skillValue) { - FishingManager fishingManager = UserManager.getPlayer(player).getFishingManager(); + FishingManager fishingManager = mmoPlayer.getFishingManager(); // TREASURE HUNTER if (canTreasureHunt) { lootTier = fishingManager.getLootTier(); // Item drop rates - commonTreasure = percent.format(FishingTreasureConfig.getInstance().getItemDropRate(lootTier, Rarity.COMMON) / 100.0); - uncommonTreasure = percent.format(FishingTreasureConfig.getInstance().getItemDropRate(lootTier, Rarity.UNCOMMON) / 100.0); - rareTreasure = percent.format(FishingTreasureConfig.getInstance().getItemDropRate(lootTier, Rarity.RARE) / 100.0); - epicTreasure = percent.format(FishingTreasureConfig.getInstance().getItemDropRate(lootTier, Rarity.EPIC) / 100.0); - legendaryTreasure = percent.format(FishingTreasureConfig.getInstance().getItemDropRate(lootTier, Rarity.LEGENDARY) / 100.0); - mythicTreasure = percent.format(FishingTreasureConfig.getInstance().getItemDropRate(lootTier, Rarity.MYTHIC) / 100.0); + commonTreasure = percent.format( + FishingTreasureConfig.getInstance().getItemDropRate(lootTier, Rarity.COMMON) + / 100.0); + uncommonTreasure = percent.format( + FishingTreasureConfig.getInstance().getItemDropRate(lootTier, Rarity.UNCOMMON) + / 100.0); + rareTreasure = percent.format( + FishingTreasureConfig.getInstance().getItemDropRate(lootTier, Rarity.RARE) + / 100.0); + epicTreasure = percent.format( + FishingTreasureConfig.getInstance().getItemDropRate(lootTier, Rarity.EPIC) + / 100.0); + legendaryTreasure = percent.format( + FishingTreasureConfig.getInstance().getItemDropRate(lootTier, Rarity.LEGENDARY) + / 100.0); + mythicTreasure = percent.format( + FishingTreasureConfig.getInstance().getItemDropRate(lootTier, Rarity.MYTHIC) + / 100.0); // Magic hunter drop rates double totalEnchantChance = 0; for (Rarity rarity : Rarity.values()) { if (rarity != Rarity.MYTHIC) { - totalEnchantChance += FishingTreasureConfig.getInstance().getEnchantmentDropRate(lootTier, rarity); + totalEnchantChance += FishingTreasureConfig.getInstance() + .getEnchantmentDropRate(lootTier, rarity); } } - if(totalEnchantChance >= 1) + if (totalEnchantChance >= 1) { magicChance = percent.format(totalEnchantChance / 100.0); - else + } else { magicChance = percent.format(0); + } } // FISHING_SHAKE if (canShake) { - String[] shakeStrings = RandomChanceUtil.calculateAbilityDisplayValuesStatic(player, PrimarySkillType.FISHING, fishingManager.getShakeChance()); + Probability shakeProbability = Probability.ofPercent(fishingManager.getShakeChance()); + String[] shakeStrings = ProbabilityUtil.getRNGDisplayValues(shakeProbability); shakeChance = shakeStrings[0]; shakeChanceLucky = shakeStrings[1]; } @@ -91,54 +106,69 @@ public class FishingCommand extends SkillCommand { // MASTER ANGLER if (canMasterAngler) { - maMinWaitTime = StringUtils.ticksToSeconds(fishingManager.getMasterAnglerTickMinWaitReduction(RankUtils.getRank(player, SubSkillType.FISHING_MASTER_ANGLER), false)); - maMaxWaitTime = StringUtils.ticksToSeconds(fishingManager.getMasterAnglerTickMaxWaitReduction(RankUtils.getRank(player, SubSkillType.FISHING_MASTER_ANGLER), false, 0)); + maMinWaitTime = StringUtils.ticksToSeconds( + fishingManager.getMasterAnglerTickMinWaitReduction( + RankUtils.getRank(player, SubSkillType.FISHING_MASTER_ANGLER), false)); + maMaxWaitTime = StringUtils.ticksToSeconds( + fishingManager.getMasterAnglerTickMaxWaitReduction( + RankUtils.getRank(player, SubSkillType.FISHING_MASTER_ANGLER), false, + 0)); } } @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 - protected List statsDisplay(Player player, float skillValue, boolean hasEndurance, boolean isLucky) { + protected List statsDisplay(Player player, float skillValue, boolean hasEndurance, + boolean isLucky) { List messages = new ArrayList<>(); - + if (canFishermansDiet) { - messages.add(getStatMessage(false, true, SubSkillType.FISHING_FISHERMANS_DIET, String.valueOf(fishermansDietRank))); + messages.add(getStatMessage(false, true, SubSkillType.FISHING_FISHERMANS_DIET, + String.valueOf(fishermansDietRank))); } - + if (canIceFish) { - messages.add(getStatMessage(SubSkillType.FISHING_ICE_FISHING, SubSkillType.FISHING_ICE_FISHING.getLocaleStatDescription())); + messages.add(getStatMessage(SubSkillType.FISHING_ICE_FISHING, + SubSkillType.FISHING_ICE_FISHING.getLocaleStatDescription())); } - + if (canMagicHunt) { messages.add(getStatMessage(SubSkillType.FISHING_MAGIC_HUNTER, magicChance)); } if (canMasterAngler) { - messages.add(getStatMessage(false,true, + messages.add(getStatMessage(false, true, SubSkillType.FISHING_MASTER_ANGLER, maMinWaitTime)); - messages.add(getStatMessage(true,true, + messages.add(getStatMessage(true, true, SubSkillType.FISHING_MASTER_ANGLER, maMaxWaitTime)); } - + if (canShake) { messages.add(getStatMessage(SubSkillType.FISHING_SHAKE, shakeChance) - + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", shakeChanceLucky) : "")); + + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", shakeChanceLucky) + : "")); } - + if (canTreasureHunt) { - messages.add(getStatMessage(false, true, SubSkillType.FISHING_TREASURE_HUNTER, String.valueOf(lootTier), String.valueOf(RankUtils.getHighestRank(SubSkillType.FISHING_TREASURE_HUNTER)))); + messages.add(getStatMessage(false, true, SubSkillType.FISHING_TREASURE_HUNTER, + String.valueOf(lootTier), String.valueOf( + RankUtils.getHighestRank(SubSkillType.FISHING_TREASURE_HUNTER)))); messages.add(getStatMessage(true, true, SubSkillType.FISHING_TREASURE_HUNTER, String.valueOf(commonTreasure), String.valueOf(uncommonTreasure), @@ -155,7 +185,8 @@ public class FishingCommand extends SkillCommand { protected List getTextComponents(Player player) { List textComponents = new ArrayList<>(); - TextComponentFactory.getSubSkillTextComponents(player, textComponents, PrimarySkillType.FISHING); + TextComponentFactory.getSubSkillTextComponents(player, textComponents, + PrimarySkillType.FISHING); return textComponents; } 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 eba4520a7..4a95874af 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/HerbalismCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/HerbalismCommand.java @@ -5,16 +5,15 @@ import com.gmail.nossr50.datatypes.skills.SubSkillType; 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.SkillActivationType; import com.gmail.nossr50.util.text.TextComponentFactory; +import java.util.ArrayList; +import java.util.List; import net.kyori.adventure.text.Component; import org.bukkit.Material; import org.bukkit.entity.Player; -import java.util.ArrayList; -import java.util.List; - public class HerbalismCommand extends SkillCommand { private String greenTerraLength; private String greenTerraLengthEndurance; @@ -24,6 +23,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; @@ -35,6 +36,7 @@ public class HerbalismCommand extends SkillCommand { private boolean canGreenThumbBlocks; private boolean canFarmersDiet; private boolean canDoubleDrop; + private boolean canTripleDrop; private boolean canShroomThumb; public HerbalismCommand() { @@ -43,19 +45,27 @@ public class HerbalismCommand extends SkillCommand { @Override 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 = ProbabilityUtil.getRNGDisplayValues(mmoPlayer, + SubSkillType.HERBALISM_DOUBLE_DROPS); doubleDropChance = doubleDropStrings[0]; doubleDropChanceLucky = doubleDropStrings[1]; } - + + if (canTripleDrop) { + String[] tripleDropStrings = ProbabilityUtil.getRNGDisplayValues(mmoPlayer, + SubSkillType.HERBALISM_VERDANT_BOUNTY); + tripleDropChance = tripleDropStrings[0]; + tripleDropChanceLucky = tripleDropStrings[1]; + } + // FARMERS DIET if (canFarmersDiet) { farmersDietRank = RankUtils.getRank(player, SubSkillType.HERBALISM_FARMERS_DIET); } - + // GREEN TERRA if (canGreenTerra) { String[] greenTerraStrings = calculateLengthDisplayValues(player, skillValue); @@ -67,21 +77,24 @@ public class HerbalismCommand extends SkillCommand { 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 = ProbabilityUtil.getRNGDisplayValues(mmoPlayer, + 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 = ProbabilityUtil.getRNGDisplayValues(mmoPlayer, + 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 = ProbabilityUtil.getRNGDisplayValues(mmoPlayer, + SubSkillType.HERBALISM_SHROOM_THUMB); shroomThumbChance = shroomThumbStrings[0]; shroomThumbChanceLucky = shroomThumbStrings[1]; } @@ -89,53 +102,82 @@ public class HerbalismCommand extends SkillCommand { @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.BEETROOTS) || 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) && !mcMMO.p.getGeneralConfig().getDoubleDropsDisabled(skill); - canShroomThumb = canUseSubskill(player, SubSkillType.HERBALISM_SHROOM_THUMB); + 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.BEETROOTS) + || 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 = 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); } @Override - protected List statsDisplay(Player player, float skillValue, boolean hasEndurance, boolean isLucky) { + protected List statsDisplay(Player player, float skillValue, boolean hasEndurance, + boolean isLucky) { List messages = new ArrayList<>(); if (canDoubleDrop) { messages.add(getStatMessage(SubSkillType.HERBALISM_DOUBLE_DROPS, doubleDropChance) - + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", doubleDropChanceLucky) : "")); + + (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))); + 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) : "")); + + (hasEndurance ? LocaleLoader.getString("Perks.ActivationTime.Bonus", + greenTerraLengthEndurance) : "")); //messages.add(LocaleLoader.getString("Herbalism.Ability.GTe.Length", greenTerraLength) + (hasEndurance ? LocaleLoader.getString("Perks.ActivationTime.Bonus", greenTerraLengthEndurance) : "")); } if (canGreenThumbBlocks || canGreenThumbPlants) { messages.add(getStatMessage(SubSkillType.HERBALISM_GREEN_THUMB, greenThumbChance) - + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", greenThumbChanceLucky) : "")); + + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", greenThumbChanceLucky) + : "")); //messages.add(LocaleLoader.getString("Herbalism.Ability.GTh.Chance", greenThumbChance) + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", greenThumbChanceLucky) : "")); } if (canGreenThumbPlants) { - messages.add(getStatMessage(true, true,SubSkillType.HERBALISM_GREEN_THUMB, String.valueOf(greenThumbStage))); + messages.add(getStatMessage(true, true, SubSkillType.HERBALISM_GREEN_THUMB, + String.valueOf(greenThumbStage))); } if (hasHylianLuck) { messages.add(getStatMessage(SubSkillType.HERBALISM_HYLIAN_LUCK, hylianLuckChance) - + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", hylianLuckChanceLucky) : "")); + + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", hylianLuckChanceLucky) + : "")); } if (canShroomThumb) { messages.add(getStatMessage(SubSkillType.HERBALISM_SHROOM_THUMB, shroomThumbChance) - + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", shroomThumbChanceLucky) : "")); + + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", shroomThumbChanceLucky) + : "")); } return messages; @@ -145,7 +187,8 @@ public class HerbalismCommand extends SkillCommand { protected List getTextComponents(Player player) { List textComponents = new ArrayList<>(); - TextComponentFactory.getSubSkillTextComponents(player, textComponents, PrimarySkillType.HERBALISM); + TextComponentFactory.getSubSkillTextComponents(player, textComponents, + PrimarySkillType.HERBALISM); return textComponents; } diff --git a/src/main/java/com/gmail/nossr50/commands/skills/MacesCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/MacesCommand.java new file mode 100644 index 000000000..e2c6e3108 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/commands/skills/MacesCommand.java @@ -0,0 +1,85 @@ +package com.gmail.nossr50.commands.skills; + +import static com.gmail.nossr50.datatypes.skills.SubSkillType.MACES_CRIPPLE; +import static com.gmail.nossr50.datatypes.skills.SubSkillType.MACES_MACES_LIMIT_BREAK; + +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; +import com.gmail.nossr50.skills.maces.MacesManager; +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 java.util.ArrayList; +import java.util.List; +import net.kyori.adventure.text.Component; +import org.bukkit.entity.Player; + +public class MacesCommand extends SkillCommand { + + public MacesCommand() { + super(PrimarySkillType.MACES); + } + + String crippleChanceToApply, crippleChanceToApplyLucky, crippleLengthAgainstPlayers, crippleLengthAgainstMobs; + + @Override + protected void dataCalculations(Player player, float skillValue) { + if (SkillUtils.canUseSubskill(player, MACES_CRIPPLE)) { + int crippleRank = RankUtils.getRank(player, MACES_CRIPPLE); + crippleLengthAgainstPlayers = String.valueOf( + MacesManager.getCrippleTickDuration(true) / 20.0D); + crippleLengthAgainstMobs = String.valueOf( + MacesManager.getCrippleTickDuration(false) / 20.0D); + + crippleChanceToApply = + mcMMO.p.getAdvancedConfig().getCrippleChanceToApplyOnHit(crippleRank) + "%"; + crippleChanceToApplyLucky = String.valueOf( + mcMMO.p.getAdvancedConfig().getCrippleChanceToApplyOnHit(crippleRank) * 1.33); + } + } + + @Override + protected void permissionsCheck(Player player) { + } + + @Override + protected List statsDisplay(Player player, float skillValue, boolean hasEndurance, + boolean isLucky) { + final List messages = new ArrayList<>(); + + if (SkillUtils.canUseSubskill(player, MACES_MACES_LIMIT_BREAK)) { + messages.add(getStatMessage(MACES_MACES_LIMIT_BREAK, + String.valueOf(CombatUtils.getLimitBreakDamageAgainstQuality(player, + MACES_MACES_LIMIT_BREAK, 1000)))); + } + + if (SkillUtils.canUseSubskill(player, MACES_CRIPPLE)) { + messages.add(getStatMessage(MACES_CRIPPLE, crippleChanceToApply) + + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", + crippleChanceToApplyLucky) : "")); + messages.add(getStatMessage(true, true, MACES_CRIPPLE, + crippleLengthAgainstPlayers, + crippleLengthAgainstMobs)); + } + + if (SkillUtils.canUseSubskill(player, SubSkillType.MACES_CRUSH)) { + messages.add(getStatMessage(SubSkillType.MACES_CRUSH, + String.valueOf(mmoPlayer.getMacesManager().getCrushDamage()))); + } + + return messages; + } + + @Override + protected List getTextComponents(Player player) { + List textComponents = new ArrayList<>(); + + TextComponentFactory.getSubSkillTextComponents(player, textComponents, + PrimarySkillType.MACES); + + return textComponents; + } +} 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 5e7a14a7a..05af220ea 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/MiningCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/MiningCommand.java @@ -5,19 +5,19 @@ import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.locale.LocaleLoader; 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.SkillActivationType; 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; +import net.kyori.adventure.text.Component; +import org.bukkit.entity.Player; public class MiningCommand extends SkillCommand { private String doubleDropChance; private String doubleDropChanceLucky; + private String tripleDropChance; + private String tripleDropChanceLucky; private String superBreakerLength; private String superBreakerLengthEndurance; @@ -25,11 +25,12 @@ public class MiningCommand extends SkillCommand { private int bonusTNTDrops; private double blastRadiusIncrease; private String oreBonus; -// private String debrisReduction; + // private String debrisReduction; private String blastDamageDecrease; private boolean canSuperBreaker; private boolean canDoubleDrop; + private boolean canTripleDrop; private boolean canBlast; private boolean canBiggerBombs; private boolean canDemoExpert; @@ -42,23 +43,32 @@ public class MiningCommand extends SkillCommand { protected void dataCalculations(Player player, float skillValue) { // BLAST MINING if (canBlast || canDemoExpert || canBiggerBombs) { - MiningManager miningManager = UserManager.getPlayer(player).getMiningManager(); + MiningManager miningManager = mmoPlayer.getMiningManager(); blastMiningRank = miningManager.getBlastMiningTier(); bonusTNTDrops = miningManager.getDropMultiplier(); - oreBonus = percent.format(miningManager.getOreBonus() / 30.0D); // Base received in TNT is 30% + oreBonus = percent.format(miningManager.getOreBonus()); // Base received in TNT is 30% // debrisReduction = percent.format(miningManager.getDebrisReduction() / 30.0D); // Base received in TNT is 30% blastDamageDecrease = percent.format(miningManager.getBlastDamageModifier() / 100.0D); blastRadiusIncrease = miningManager.getBlastRadiusModifier(); } - + + // Mastery TRIPLE DROPS + if (canTripleDrop) { + String[] masteryTripleDropStrings = ProbabilityUtil.getRNGDisplayValues(mmoPlayer, + 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 = ProbabilityUtil.getRNGDisplayValues(mmoPlayer, + SubSkillType.MINING_DOUBLE_DROPS); doubleDropChance = doubleDropStrings[0]; doubleDropChanceLucky = doubleDropStrings[1]; } - + // SUPER BREAKER if (canSuperBreaker) { String[] superBreakerStrings = calculateLengthDisplayValues(player, skillValue); @@ -69,41 +79,61 @@ public class MiningCommand extends SkillCommand { @Override 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); - canSuperBreaker = RankUtils.hasUnlockedSubskill(player, SubSkillType.MINING_SUPER_BREAKER) && Permissions.superBreaker(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 = 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); } @Override - protected List statsDisplay(Player player, float skillValue, boolean hasEndurance, boolean isLucky) { + protected List statsDisplay(Player player, float skillValue, boolean hasEndurance, + boolean isLucky) { List messages = new ArrayList<>(); if (canBiggerBombs) { - messages.add(getStatMessage(true, true, SubSkillType.MINING_BLAST_MINING, String.valueOf(blastRadiusIncrease))); + messages.add(getStatMessage(true, true, SubSkillType.MINING_BLAST_MINING, + String.valueOf(blastRadiusIncrease))); //messages.add(LocaleLoader.getString("Mining.Blast.Radius.Increase", blastRadiusIncrease)); } - + if (canBlast) { - messages.add(getStatMessage(false, true, SubSkillType.MINING_BLAST_MINING, String.valueOf(blastMiningRank), String.valueOf(RankUtils.getHighestRank(SubSkillType.MINING_BLAST_MINING)), LocaleLoader.getString("Mining.Blast.Effect", oreBonus, bonusTNTDrops))); + messages.add(getStatMessage(false, true, SubSkillType.MINING_BLAST_MINING, + String.valueOf(blastMiningRank), + String.valueOf(RankUtils.getHighestRank(SubSkillType.MINING_BLAST_MINING)), + LocaleLoader.getString("Mining.Blast.Effect", oreBonus, bonusTNTDrops))); //messages.add(LocaleLoader.getString("Mining.Blast.Rank", blastMiningRank, RankUtils.getHighestRank(SubSkillType.MINING_BLAST_MINING), LocaleLoader.getString("Mining.Blast.Effect", oreBonus, debrisReduction, bonusTNTDrops))); } - - if (canDemoExpert) { - messages.add(getStatMessage(SubSkillType.MINING_DEMOLITIONS_EXPERTISE, blastDamageDecrease)); + + if (canDemoExpert) { + messages.add( + getStatMessage(SubSkillType.MINING_DEMOLITIONS_EXPERTISE, blastDamageDecrease)); //messages.add(LocaleLoader.getString("Mining.Effect.Decrease", blastDamageDecrease)); } - + if (canDoubleDrop) { messages.add(getStatMessage(SubSkillType.MINING_DOUBLE_DROPS, doubleDropChance) - + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", doubleDropChanceLucky) : "")); + + (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) : "")); + + (hasEndurance ? LocaleLoader.getString("Perks.ActivationTime.Bonus", + superBreakerLengthEndurance) : "")); //messages.add(LocaleLoader.getString("Mining.Ability.Length", superBreakerLength) + (hasEndurance ? LocaleLoader.getString("Perks.ActivationTime.Bonus", superBreakerLengthEndurance) : "")); } @@ -114,7 +144,8 @@ public class MiningCommand extends SkillCommand { protected List getTextComponents(Player player) { List textComponents = new ArrayList<>(); - TextComponentFactory.getSubSkillTextComponents(player, textComponents, PrimarySkillType.MINING); + TextComponentFactory.getSubSkillTextComponents(player, textComponents, + PrimarySkillType.MINING); return textComponents; } diff --git a/src/main/java/com/gmail/nossr50/commands/skills/MmoInfoCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/MmoInfoCommand.java index 0f0a4a710..6300ee0b5 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/MmoInfoCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/MmoInfoCommand.java @@ -1,12 +1,13 @@ package com.gmail.nossr50.commands.skills; import com.gmail.nossr50.datatypes.skills.SubSkillType; -import com.gmail.nossr50.listeners.InteractionManager; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.text.TextComponentFactory; import com.google.common.collect.ImmutableList; +import java.util.ArrayList; +import java.util.List; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.command.TabExecutor; @@ -14,44 +15,39 @@ import org.bukkit.entity.Player; import org.bukkit.util.StringUtil; import org.jetbrains.annotations.NotNull; -import java.util.ArrayList; -import java.util.List; - /** * This is the command that retrieves data about skills from in-game sources */ public class MmoInfoCommand implements TabExecutor { @Override - public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s, String[] args) { + public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, + @NotNull String s, String[] args) { /* * Only allow players to use this command */ - if(commandSender instanceof Player player) - { - if(args.length < 1) + if (commandSender instanceof Player player) { + if (args == null || args.length < 1 || args[0] == null || args[0].isEmpty()) { return false; + } - if(Permissions.mmoinfo(player)) - { - if(args == null || args[0] == null) - return false; - - if(args[0].equalsIgnoreCase( "???")) - { + if (Permissions.mmoinfo(player)) { + if (args[0].equalsIgnoreCase("???")) { player.sendMessage(LocaleLoader.getString("Commands.MmoInfo.Header")); - player.sendMessage(LocaleLoader.getString("Commands.MmoInfo.SubSkillHeader", "???")); + player.sendMessage( + LocaleLoader.getString("Commands.MmoInfo.SubSkillHeader", "???")); player.sendMessage(LocaleLoader.getString("Commands.MmoInfo.DetailsHeader")); player.sendMessage(LocaleLoader.getString("Commands.MmoInfo.Mystery")); return true; - } else if(InteractionManager.getAbstractByName(args[0]) != null || mcMMO.p.getSkillTools().EXACT_SUBSKILL_NAMES.contains(args[0])) - { - displayInfo(player, args[0]); - return true; } - //Not a real skill - player.sendMessage(LocaleLoader.getString("Commands.MmoInfo.NoMatch")); + final SubSkillType subSkillType = matchSubSkill(args[0]); + if (subSkillType != null) { + displayInfo(player, subSkillType); + } else { + //Not a real skill + player.sendMessage(LocaleLoader.getString("Commands.MmoInfo.NoMatch")); + } return true; } } @@ -59,28 +55,35 @@ public class MmoInfoCommand implements TabExecutor { return false; } + public SubSkillType matchSubSkill(String name) { + for (SubSkillType subSkillType : SubSkillType.values()) { + if (subSkillType.getNiceNameNoSpaces(subSkillType).equalsIgnoreCase(name) + || subSkillType.name().equalsIgnoreCase(name)) { + return subSkillType; + } + } + return null; + } + @Override - public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, String[] args) { + public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, + @NotNull String alias, String[] args) { if (args.length == 1) { - return StringUtil.copyPartialMatches(args[0], mcMMO.p.getSkillTools().EXACT_SUBSKILL_NAMES, new ArrayList<>(mcMMO.p.getSkillTools().EXACT_SUBSKILL_NAMES.size())); + return StringUtil.copyPartialMatches(args[0], + mcMMO.p.getSkillTools().EXACT_SUBSKILL_NAMES, + new ArrayList<>(mcMMO.p.getSkillTools().EXACT_SUBSKILL_NAMES.size())); } return ImmutableList.of(); } - private void displayInfo(Player player, String subSkillName) - { + private void displayInfo(Player player, SubSkillType subSkillType) { player.sendMessage(LocaleLoader.getString("Commands.MmoInfo.Header")); - player.sendMessage(LocaleLoader.getString("Commands.MmoInfo.SubSkillHeader", subSkillName)); + player.sendMessage(LocaleLoader.getString("Commands.MmoInfo.SubSkillHeader", + subSkillType.getLocaleName())); player.sendMessage(LocaleLoader.getString("Commands.MmoInfo.DetailsHeader")); - player.sendMessage(LocaleLoader.getString("Commands.MmoInfo.OldSkill")); - - for(SubSkillType subSkillType : SubSkillType.values()) - { - if(subSkillType.getNiceNameNoSpaces(subSkillType).equalsIgnoreCase(subSkillName)) - subSkillName = subSkillType.getWikiName(subSkillType.toString()); - } //Send Player Wiki Link - TextComponentFactory.sendPlayerSubSkillWikiLink(player, subSkillName); + TextComponentFactory.sendPlayerSubSkillWikiLink(player, subSkillType.getLocaleName(), + subSkillType); } } 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 000000000..579b1e419 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/commands/skills/PowerLevelCommand.java @@ -0,0 +1,43 @@ +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.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; + +@CommandPermission("mcmmo.commands.mmopower") +@CommandAlias("mmopower|mmopowerlevel|powerlevel") +public class PowerLevelCommand extends BaseCommand { + private final @NotNull mcMMO pluginRef; + + public PowerLevelCommand(@NotNull mcMMO pluginRef) { + this.pluginRef = pluginRef; + } + + @Default + @Conditions(CommandManager.POWER_LEVEL_CONDITION) + public void processCommand(String[] args) { + BukkitCommandIssuer bukkitCommandIssuer = (BukkitCommandIssuer) getCurrentCommandIssuer(); + Player player = bukkitCommandIssuer.getPlayer(); + final 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(); + + mmoPlayer.getPlayer().sendMessage( + ChatColor.DARK_AQUA + "Your " + ChatColor.GOLD + "[mcMMO]" + ChatColor.DARK_AQUA + + " power level is: " + ChatColor.GREEN + powerLevel); + } +} 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 1941357d0..e56a5e879 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/RepairCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/RepairCommand.java @@ -10,17 +10,15 @@ import com.gmail.nossr50.skills.repair.Repair; import com.gmail.nossr50.skills.repair.RepairManager; 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.SkillActivationType; import com.gmail.nossr50.util.text.TextComponentFactory; +import java.util.ArrayList; +import java.util.List; import net.kyori.adventure.text.Component; import org.bukkit.Material; import org.bukkit.entity.Player; -import java.util.ArrayList; -import java.util.List; - public class RepairCommand extends SkillCommand { private String repairMasteryBonus; private String superRepairChance; @@ -50,10 +48,14 @@ public class RepairCommand extends SkillCommand { @Override protected void dataCalculations(Player player, float skillValue) { // We're using pickaxes here, not the best but it works - Repairable diamondRepairable = mcMMO.getRepairableManager().getRepairable(Material.DIAMOND_PICKAXE); - Repairable goldRepairable = mcMMO.getRepairableManager().getRepairable(Material.GOLDEN_PICKAXE); - Repairable ironRepairable = mcMMO.getRepairableManager().getRepairable(Material.IRON_PICKAXE); - Repairable stoneRepairable = mcMMO.getRepairableManager().getRepairable(Material.STONE_PICKAXE); + Repairable diamondRepairable = mcMMO.getRepairableManager() + .getRepairable(Material.DIAMOND_PICKAXE); + Repairable goldRepairable = mcMMO.getRepairableManager() + .getRepairable(Material.GOLDEN_PICKAXE); + Repairable ironRepairable = mcMMO.getRepairableManager() + .getRepairable(Material.IRON_PICKAXE); + Repairable stoneRepairable = mcMMO.getRepairableManager() + .getRepairable(Material.STONE_PICKAXE); // TODO: This isn't really accurate - if they don't have pickaxes loaded it doesn't always mean the repair level is 0 diamondLevel = (diamondRepairable == null) ? 0 : diamondRepairable.getMinimumLevel(); @@ -63,12 +65,15 @@ public class RepairCommand extends SkillCommand { // REPAIR MASTERY if (canMasterRepair) { - repairMasteryBonus = percent.format(Math.min(((Repair.repairMasteryMaxBonus / Repair.repairMasteryMaxBonusLevel) * skillValue), Repair.repairMasteryMaxBonus) / 100D); + repairMasteryBonus = percent.format(Math.min( + ((Repair.repairMasteryMaxBonus / Repair.repairMasteryMaxBonusLevel) + * skillValue), Repair.repairMasteryMaxBonus) / 100D); } // SUPER REPAIR if (canSuperRepair) { - String[] superRepairStrings = getAbilityDisplayValues(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, player, SubSkillType.REPAIR_SUPER_REPAIR); + String[] superRepairStrings = ProbabilityUtil.getRNGDisplayValues(mmoPlayer, + SubSkillType.REPAIR_SUPER_REPAIR); superRepairChance = superRepairStrings[0]; superRepairChanceLucky = superRepairStrings[1]; } @@ -76,9 +81,9 @@ public class RepairCommand extends SkillCommand { @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); @@ -86,15 +91,17 @@ public class RepairCommand extends SkillCommand { canRepairString = Permissions.repairMaterialType(player, MaterialType.STRING); canRepairLeather = Permissions.repairMaterialType(player, MaterialType.LEATHER); canRepairWood = Permissions.repairMaterialType(player, MaterialType.WOOD); - arcaneBypass = (Permissions.arcaneBypass(player) || Permissions.hasRepairEnchantBypassPerk(player)); + arcaneBypass = (Permissions.arcaneBypass(player) || Permissions.hasRepairEnchantBypassPerk( + player)); } @Override - protected List statsDisplay(Player player, float skillValue, boolean hasEndurance, boolean isLucky) { + protected List statsDisplay(Player player, float skillValue, boolean hasEndurance, + boolean isLucky) { List messages = new ArrayList<>(); if (canArcaneForge) { - RepairManager repairManager = UserManager.getPlayer(player).getRepairManager(); + RepairManager repairManager = mmoPlayer.getRepairManager(); messages.add(getStatMessage(false, true, SubSkillType.REPAIR_ARCANE_FORGING, @@ -104,17 +111,20 @@ public class RepairCommand extends SkillCommand { if (ArcaneForging.arcaneForgingEnchantLoss || ArcaneForging.arcaneForgingDowngrades) { messages.add(getStatMessage(true, true, SubSkillType.REPAIR_ARCANE_FORGING, String.valueOf(arcaneBypass ? 100 : repairManager.getKeepEnchantChance()), - String.valueOf(arcaneBypass ? 0 : repairManager.getDowngradeEnchantChance()))); //Jesus those parentheses + String.valueOf(arcaneBypass ? 0 + : repairManager.getDowngradeEnchantChance()))); //Jesus those parentheses } } - + if (canMasterRepair) { - messages.add(getStatMessage(false, true, SubSkillType.REPAIR_REPAIR_MASTERY, repairMasteryBonus)); + messages.add(getStatMessage(false, true, SubSkillType.REPAIR_REPAIR_MASTERY, + repairMasteryBonus)); } if (canSuperRepair) { messages.add(getStatMessage(SubSkillType.REPAIR_SUPER_REPAIR, superRepairChance) - + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", superRepairChanceLucky) : "")); + + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", superRepairChanceLucky) + : "")); } return messages; @@ -124,7 +134,8 @@ public class RepairCommand extends SkillCommand { protected List getTextComponents(Player player) { List textComponents = new ArrayList<>(); - TextComponentFactory.getSubSkillTextComponents(player, textComponents, PrimarySkillType.REPAIR); + TextComponentFactory.getSubSkillTextComponents(player, textComponents, + PrimarySkillType.REPAIR); return textComponents; } 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 770299951..29a8cd6c0 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/SalvageCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/SalvageCommand.java @@ -5,14 +5,13 @@ import com.gmail.nossr50.datatypes.skills.SubSkillType; 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.player.UserManager; +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; +import net.kyori.adventure.text.Component; +import org.bukkit.entity.Player; public class SalvageCommand extends SkillCommand { private boolean canScrapCollector; @@ -30,19 +29,21 @@ public class SalvageCommand extends SkillCommand { @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 - protected List statsDisplay(Player player, float skillValue, boolean hasEndurance, boolean isLucky) { + protected List statsDisplay(Player player, float skillValue, boolean hasEndurance, + boolean isLucky) { List messages = new ArrayList<>(); - SalvageManager salvageManager = UserManager.getPlayer(player).getSalvageManager(); + SalvageManager salvageManager = mmoPlayer.getSalvageManager(); if (canScrapCollector) { messages.add(getStatMessage(false, true, SubSkillType.SALVAGE_SCRAP_COLLECTOR, - String.valueOf(RankUtils.getRank(player, SubSkillType.SALVAGE_SCRAP_COLLECTOR)), + String.valueOf(SalvageManager.getSalvageLimit(player)), RankUtils.getHighestRankStr(SubSkillType.SALVAGE_SCRAP_COLLECTOR))); } @@ -52,11 +53,15 @@ public class SalvageCommand extends SkillCommand { String.valueOf(RankUtils.getHighestRank(SubSkillType.SALVAGE_ARCANE_SALVAGE)))); if (Salvage.arcaneSalvageEnchantLoss) { - messages.add(LocaleLoader.getString("Ability.Generic.Template", LocaleLoader.getString("Salvage.Arcane.ExtractFull"), percent.format(salvageManager.getExtractFullEnchantChance() / 100))); + messages.add(LocaleLoader.getString("Ability.Generic.Template", + LocaleLoader.getString("Salvage.Arcane.ExtractFull"), + percent.format(salvageManager.getExtractFullEnchantChance() / 100))); } if (Salvage.arcaneSalvageDowngrades) { - messages.add(LocaleLoader.getString("Ability.Generic.Template", LocaleLoader.getString("Salvage.Arcane.ExtractPartial"), percent.format(salvageManager.getExtractPartialEnchantChance() / 100))); + messages.add(LocaleLoader.getString("Ability.Generic.Template", + LocaleLoader.getString("Salvage.Arcane.ExtractPartial"), + percent.format(salvageManager.getExtractPartialEnchantChance() / 100))); } } @@ -67,7 +72,8 @@ public class SalvageCommand extends SkillCommand { protected List getTextComponents(Player player) { List textComponents = new ArrayList<>(); - TextComponentFactory.getSubSkillTextComponents(player, textComponents, PrimarySkillType.SALVAGE); + TextComponentFactory.getSubSkillTextComponents(player, textComponents, + PrimarySkillType.SALVAGE); return textComponents; } 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 df3f8a8a4..87ef5a4a9 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java @@ -5,20 +5,21 @@ 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; -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; 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; import com.google.common.collect.ImmutableList; +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; import net.kyori.adventure.text.Component; import net.md_5.bungee.api.ChatColor; import org.bukkit.command.Command; @@ -28,29 +29,27 @@ import org.bukkit.command.TabExecutor; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; -import java.text.DecimalFormat; -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; -import java.util.Set; - public abstract class SkillCommand implements TabExecutor { + public static final String ABILITY_GENERIC_TEMPLATE_CUSTOM = "Ability.Generic.Template.Custom"; + public static final String ABILITY_GENERIC_TEMPLATE = "Ability.Generic.Template"; protected PrimarySkillType skill; - private final String skillName; - protected DecimalFormat percent = new DecimalFormat("##0.00%"); - protected DecimalFormat decimal = new DecimalFormat("##0.00"); + protected DecimalFormat percent = new DecimalFormat("##0.00%", + DecimalFormatSymbols.getInstance(Locale.US)); + protected DecimalFormat decimal = new DecimalFormat("##0.00", + DecimalFormatSymbols.getInstance(Locale.US)); + protected McMMOPlayer mmoPlayer; private final CommandExecutor skillGuideCommand; public SkillCommand(PrimarySkillType skill) { this.skill = skill; - skillName = mcMMO.p.getSkillTools().getLocalizedSkillName(skill); skillGuideCommand = new SkillGuideCommand(skill); } @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, + @NotNull String label, String[] args) { if (CommandUtils.noConsoleUsage(sender)) { return true; } @@ -59,10 +58,10 @@ public abstract class SkillCommand implements TabExecutor { return true; } - Player player = (Player) sender; - McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player); + final Player player = (Player) sender; + mmoPlayer = UserManager.getPlayer(player); - if (mcMMOPlayer == null) { + if (mmoPlayer == null) { sender.sendMessage(LocaleLoader.getString("Profile.PendingLoad")); return true; } @@ -70,31 +69,33 @@ public abstract class SkillCommand implements TabExecutor { if (args.length == 0) { boolean isLucky = Permissions.lucky(player, skill); boolean hasEndurance = PerksUtils.handleActivationPerks(player, 0, 0) != 0; - float skillValue = mcMMOPlayer.getSkillLevel(skill); + float skillValue = mmoPlayer.getSkillLevel(skill); //Send the players a few blank lines to make finding the top of the skill command easier - if (mcMMO.p.getAdvancedConfig().doesSkillCommandSendBlankLines()) + if (mcMMO.p.getAdvancedConfig().doesSkillCommandSendBlankLines()) { for (int i = 0; i < 2; i++) { player.sendMessage(""); } + } permissionsCheck(player); dataCalculations(player, skillValue); - sendSkillCommandHeader(player, mcMMOPlayer, (int) skillValue); + sendSkillCommandHeader(mcMMO.p.getSkillTools().getLocalizedSkillName(skill), + player, mmoPlayer, (int) skillValue); //Make JSON text components List subskillTextComponents = getTextComponents(player); //Subskills Header - player.sendMessage(LocaleLoader.getString("Skills.Overhaul.Header", LocaleLoader.getString("Effects.SubSkills.Overhaul"))); + player.sendMessage(LocaleLoader.getString("Skills.Overhaul.Header", + LocaleLoader.getString("Effects.SubSkills.Overhaul"))); //Send JSON text components TextComponentFactory.sendPlayerSubSkillList(player, subskillTextComponents); - /*for(TextComponent tc : subskillTextComponents) - { + /*for(TextComponent tc : subskillTextComponents) { player.spigot().sendMessage(new TextComponent[]{tc, new TextComponent(": TESTING")}); }*/ @@ -103,20 +104,19 @@ public abstract class SkillCommand implements TabExecutor { //Header - //Link Header if (mcMMO.p.getGeneralConfig().getUrlLinksEnabled()) { player.sendMessage(LocaleLoader.getString("Overhaul.mcMMO.Header")); TextComponentFactory.sendPlayerUrlHeader(player); } - - if (mcMMO.p.getGeneralConfig().getScoreboardsEnabled() && mcMMO.p.getGeneralConfig().getSkillUseBoard()) { + if (mcMMO.p.getGeneralConfig().getScoreboardsEnabled() && mcMMO.p.getGeneralConfig() + .getSkillUseBoard()) { ScoreboardManager.enablePlayerSkillScoreboard(player, skill); } return true; - } else if ("keep".equals(args[0].toLowerCase())) { + } else if ("keep".equalsIgnoreCase(args[0])) { if (!mcMMO.p.getGeneralConfig().getAllowKeepBoard() || !mcMMO.p.getGeneralConfig().getScoreboardsEnabled() || !mcMMO.p.getGeneralConfig().getSkillUseBoard()) { @@ -133,95 +133,81 @@ public abstract class SkillCommand implements TabExecutor { return skillGuideCommand.onCommand(sender, command, label, args); } - private void getStatMessages(Player player, boolean isLucky, boolean hasEndurance, float skillValue) { + private void getStatMessages(Player player, boolean isLucky, boolean hasEndurance, + float skillValue) { List statsMessages = statsDisplay(player, skillValue, hasEndurance, isLucky); if (!statsMessages.isEmpty()) { - player.sendMessage(LocaleLoader.getString("Skills.Overhaul.Header", LocaleLoader.getString("Commands.Stats.Self.Overhaul"))); + player.sendMessage(LocaleLoader.getString("Skills.Overhaul.Header", + LocaleLoader.getString("Commands.Stats.Self.Overhaul"))); for (String message : statsMessages) { player.sendMessage(message); } } - player.sendMessage(LocaleLoader.getString("Guides.Available", skillName, skillName.toLowerCase(Locale.ENGLISH))); + final String skillName = mcMMO.p.getSkillTools().getLocalizedSkillName(skill); + player.sendMessage(LocaleLoader.getString("Guides.Available", + skillName, + skillName.toLowerCase(Locale.ENGLISH))); } - private void sendSkillCommandHeader(Player player, McMMOPlayer mcMMOPlayer, int skillValue) { - ChatColor hd1 = ChatColor.DARK_AQUA; - ChatColor c1 = ChatColor.GOLD; - ChatColor c2 = ChatColor.RED; - - + private void sendSkillCommandHeader(String skillName, Player player, McMMOPlayer mmoPlayer, + int skillValue) { + // send header player.sendMessage(LocaleLoader.getString("Skills.Overhaul.Header", skillName)); - if(!SkillTools.isChildSkill(skill)) - { + if (!SkillTools.isChildSkill(skill)) { /* * NON-CHILD SKILLS */ //XP GAIN METHOD - player.sendMessage(LocaleLoader.getString("Commands.XPGain.Overhaul", LocaleLoader.getString("Commands.XPGain." + StringUtils.getCapitalized(skill.toString())))); + player.sendMessage(LocaleLoader.getString("Commands.XPGain.Overhaul", + LocaleLoader.getString( + "Commands.XPGain." + StringUtils.getCapitalized(skill.toString())))); //LEVEL - player.sendMessage(LocaleLoader.getString("Effects.Level.Overhaul", skillValue, mcMMOPlayer.getSkillXpLevel(skill), mcMMOPlayer.getXpToLevel(skill))); + player.sendMessage(LocaleLoader.getString("Effects.Level.Overhaul", skillValue, + mmoPlayer.getSkillXpLevel(skill), mmoPlayer.getXpToLevel(skill))); } else { /* * CHILD SKILLS */ - - - 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)))*/ + /*player.sendMessage(parent.getName() + " - " + LocaleLoader.getString("Effects.Level.Overhaul", mmoPlayer.getSkillLevel(parent), mmoPlayer.getSkillXpLevel(parent), mmoPlayer.getXpToLevel(parent)))*/ ArrayList parentList = new ArrayList<>(parents); StringBuilder parentMessage = new StringBuilder(); - for(int i = 0; i < parentList.size(); i++) - { - if(i+1 < parentList.size()) - { - parentMessage.append(LocaleLoader.getString("Effects.Child.ParentList", mcMMO.p.getSkillTools().getLocalizedSkillName(parentList.get(i)), mcMMOPlayer.getSkillLevel(parentList.get(i)))); + for (int i = 0; i < parentList.size(); i++) { + if (i + 1 < parentList.size()) { + parentMessage.append(LocaleLoader.getString("Effects.Child.ParentList", + mcMMO.p.getSkillTools().getLocalizedSkillName(parentList.get(i)), + mmoPlayer.getSkillLevel(parentList.get(i)))); parentMessage.append(ChatColor.GRAY).append(", "); } else { - parentMessage.append(LocaleLoader.getString("Effects.Child.ParentList", mcMMO.p.getSkillTools().getLocalizedSkillName(parentList.get(i)), mcMMOPlayer.getSkillLevel(parentList.get(i)))); + parentMessage.append(LocaleLoader.getString("Effects.Child.ParentList", + mcMMO.p.getSkillTools().getLocalizedSkillName(parentList.get(i)), + mmoPlayer.getSkillLevel(parentList.get(i)))); } } //XP GAIN METHOD - player.sendMessage(LocaleLoader.getString("Commands.XPGain.Overhaul", LocaleLoader.getString("Commands.XPGain.Child"))); - - player.sendMessage(LocaleLoader.getString("Effects.Child.Overhaul", skillValue, parentMessage.toString())); - //LEVEL - //player.sendMessage(LocaleLoader.getString("Effects.Child.Overhaul", skillValue, skillValue)); + player.sendMessage(LocaleLoader.getString("Commands.XPGain.Overhaul", + LocaleLoader.getString("Commands.XPGain.Child"))); + player.sendMessage(LocaleLoader.getString("Effects.Child.Overhaul", skillValue, + parentMessage.toString())); } - /* - if (!SkillTools.isChildSkill(skill)) { - player.sendMessage(LocaleLoader.getString("Skills.Header", skillName)); - player.sendMessage(LocaleLoader.getString("Commands.XPGain", LocaleLoader.getString("Commands.XPGain." + StringUtils.getCapitalized(skill.toString())))); - player.sendMessage(LocaleLoader.getString("Effects.Level", skillValue, mcMMOPlayer.getSkillXpLevel(skill), mcMMOPlayer.getXpToLevel(skill))); - } else { - player.sendMessage(LocaleLoader.getString("Skills.Header", skillName + " " + LocaleLoader.getString("Skills.Child"))); - player.sendMessage(LocaleLoader.getString("Commands.XPGain", LocaleLoader.getString("Commands.XPGain.Child"))); - player.sendMessage(LocaleLoader.getString("Effects.Child", skillValue)); - - player.sendMessage(LocaleLoader.getString("Skills.Header", LocaleLoader.getString("Skills.Parents"))); - Set parents = FamilyTree.getParents(skill); - - for (PrimarySkillType parent : parents) { - player.sendMessage(parent.getName() + " - " + LocaleLoader.getString("Effects.Level", mcMMOPlayer.getSkillLevel(parent), mcMMOPlayer.getSkillXpLevel(parent), mcMMOPlayer.getXpToLevel(parent))); - } - } - */ } @Override - public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, String[] args) { + public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, + @NotNull String alias, String[] args) { if (args.length == 1) { return ImmutableList.of("?", "keep"); } @@ -232,22 +218,17 @@ public abstract class SkillCommand implements TabExecutor { return Math.min((int) skillValue, maxLevel) / rankChangeLevel; } - 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)); + int maxLength = mcMMO.p.getSkillTools() + .getSuperAbilityMaxLength(mcMMO.p.getSkillTools().getSuperAbility(skill)); int abilityLengthVar = mcMMO.p.getAdvancedConfig().getAbilityLength(); int abilityLengthCap = mcMMO.p.getAdvancedConfig().getAbilityLengthCap(); int length; - if(abilityLengthCap <= 0) - { + if (abilityLengthCap <= 0) { length = 2 + (int) (skillValue / abilityLengthVar); - } - else { + } else { length = 2 + (int) (Math.min(abilityLengthCap, skillValue) / abilityLengthVar); } @@ -257,30 +238,34 @@ public abstract class SkillCommand implements TabExecutor { length = Math.min(length, maxLength); } - return new String[] { String.valueOf(length), String.valueOf(enduranceLength) }; + return new String[]{String.valueOf(length), String.valueOf(enduranceLength)}; } - protected String getStatMessage(SubSkillType subSkillType, String... vars) - { + protected String getStatMessage(SubSkillType subSkillType, String... vars) { return getStatMessage(false, false, subSkillType, vars); } - protected String getStatMessage(boolean isExtra, boolean isCustom, SubSkillType subSkillType, String... vars) - { - String templateKey = isCustom ? "Ability.Generic.Template.Custom" : "Ability.Generic.Template"; - String statDescriptionKey = !isExtra ? subSkillType.getLocaleKeyStatDescription() : subSkillType.getLocaleKeyStatExtraDescription(); + protected String getStatMessage(boolean isExtra, boolean isCustom, + @NotNull SubSkillType subSkillType, String... vars) { + final String templateKey = + isCustom ? ABILITY_GENERIC_TEMPLATE_CUSTOM : ABILITY_GENERIC_TEMPLATE; + final String statDescriptionKey = !isExtra + ? subSkillType.getLocaleKeyStatDescription() + : subSkillType.getLocaleKeyStatExtraDescription(); - if(isCustom) - return LocaleLoader.getString(templateKey, LocaleLoader.getString(statDescriptionKey, vars)); - else - { - String[] mergedList = NotificationManager.addItemToFirstPositionOfArray(LocaleLoader.getString(statDescriptionKey), vars); + if (isCustom) { + return LocaleLoader.getString(templateKey, + LocaleLoader.getString(statDescriptionKey, vars)); + } else { + final String[] mergedList + = NotificationManager.addItemToFirstPositionOfArray( + LocaleLoader.getString(statDescriptionKey), vars); return LocaleLoader.getString(templateKey, mergedList); } } protected String getLimitBreakDescriptionParameter() { - if(mcMMO.p.getAdvancedConfig().canApplyLimitBreakPVE()) { + if (mcMMO.p.getAdvancedConfig().canApplyLimitBreakPVE()) { return "(PVP/PVE)"; } else { return "(PVP)"; @@ -291,20 +276,9 @@ public abstract class SkillCommand implements TabExecutor { protected abstract void permissionsCheck(Player player); - //protected abstract List effectsDisplay(); - - protected abstract List statsDisplay(Player player, float skillValue, boolean hasEndurance, boolean isLucky); + protected abstract List statsDisplay(Player player, float skillValue, + boolean hasEndurance, boolean isLucky); 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/SkillGuideCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/SkillGuideCommand.java index ed471f188..13f372061 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/SkillGuideCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/SkillGuideCommand.java @@ -4,14 +4,13 @@ import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.text.StringUtils; +import java.util.ArrayList; +import java.util.Arrays; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; import org.jetbrains.annotations.NotNull; -import java.util.ArrayList; -import java.util.Arrays; - public class SkillGuideCommand implements CommandExecutor { private final String header; private final ArrayList guide; @@ -19,12 +18,14 @@ public class SkillGuideCommand implements CommandExecutor { private final String invalidPage = LocaleLoader.getString("Guides.Page.Invalid"); public SkillGuideCommand(PrimarySkillType skill) { - header = LocaleLoader.getString("Guides.Header", mcMMO.p.getSkillTools().getLocalizedSkillName(skill)); + header = LocaleLoader.getString("Guides.Header", + mcMMO.p.getSkillTools().getLocalizedSkillName(skill)); guide = getGuide(skill); } @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, + @NotNull String label, String[] args) { switch (args.length) { case 1: if (!args[0].equals("?")) { @@ -45,7 +46,8 @@ public class SkillGuideCommand implements CommandExecutor { int pageNumber = Integer.parseInt(args[1]); if (pageNumber > totalPages || pageNumber <= 0) { - sender.sendMessage(LocaleLoader.getString("Guides.Page.OutOfRange", totalPages)); + sender.sendMessage( + LocaleLoader.getString("Guides.Page.OutOfRange", totalPages)); return true; } @@ -77,8 +79,7 @@ public class SkillGuideCommand implements CommandExecutor { while (allStrings.size() < 9) { if (pageIndexStart + allStrings.size() > guide.size()) { allStrings.add(""); - } - else { + } else { allStrings.add(guide.get(pageIndexStart + (allStrings.size() - 1))); } } @@ -91,7 +92,9 @@ public class SkillGuideCommand implements CommandExecutor { ArrayList guide = new ArrayList<>(); for (int i = 0; i < 10; i++) { - String[] section = LocaleLoader.getString("Guides." + StringUtils.getCapitalized(skill.toString()) + ".Section." + i).split("\n"); + String[] section = LocaleLoader.getString( + "Guides." + StringUtils.getCapitalized(skill.toString()) + ".Section." + i) + .split("\n"); if (section[0].startsWith("!")) { break; 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 55544acc2..5b2eec7a1 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/SmeltingCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/SmeltingCommand.java @@ -4,15 +4,13 @@ import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SubSkillType; 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.SkillActivationType; 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; +import net.kyori.adventure.text.Component; +import org.bukkit.entity.Player; public class SmeltingCommand extends SkillCommand { private String burnTimeModifier; @@ -34,19 +32,21 @@ public class SmeltingCommand extends SkillCommand { protected void dataCalculations(Player player, float skillValue) { // FUEL EFFICIENCY if (canFuelEfficiency) { - burnTimeModifier = String.valueOf(UserManager.getPlayer(player).getSmeltingManager().getFuelEfficiencyMultiplier()); + burnTimeModifier = String.valueOf( + mmoPlayer.getSmeltingManager().getFuelEfficiencyMultiplier()); } // FLUX MINING /*if (canFluxMine) { - String[] fluxMiningStrings = getAbilityDisplayValues(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, 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(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, player, SubSkillType.SMELTING_SECOND_SMELT); + String[] secondSmeltStrings = ProbabilityUtil.getRNGDisplayValues(mmoPlayer, + SubSkillType.SMELTING_SECOND_SMELT); str_secondSmeltChance = secondSmeltStrings[0]; str_secondSmeltChanceLucky = secondSmeltStrings[1]; } @@ -54,14 +54,18 @@ public class SmeltingCommand extends SkillCommand { @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); + canUnderstandTheArt = + Permissions.vanillaXpBoost(player, skill) && RankUtils.hasUnlockedSubskill(player, + SubSkillType.SMELTING_UNDERSTANDING_THE_ART); } @Override - protected List statsDisplay(Player player, float skillValue, boolean hasEndurance, boolean isLucky) { + protected List statsDisplay(Player player, float skillValue, boolean hasEndurance, + boolean isLucky) { List messages = new ArrayList<>(); /*if (canFluxMine) { @@ -69,19 +73,21 @@ public class SmeltingCommand extends SkillCommand { + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", str_fluxMiningChanceLucky) : "")); //messages.add(LocaleLoader.getString("Smelting.Ability.FluxMining", str_fluxMiningChance) + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", str_fluxMiningChanceLucky) : "")); }*/ - + if (canFuelEfficiency) { - messages.add(getStatMessage(false, true, SubSkillType.SMELTING_FUEL_EFFICIENCY, burnTimeModifier)); + messages.add(getStatMessage(false, true, SubSkillType.SMELTING_FUEL_EFFICIENCY, + burnTimeModifier)); } if (canSecondSmelt) { messages.add(getStatMessage(SubSkillType.SMELTING_SECOND_SMELT, str_secondSmeltChance) - + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", str_secondSmeltChanceLucky) : "")); + + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", + str_secondSmeltChanceLucky) : "")); } if (canUnderstandTheArt) { messages.add(getStatMessage(false, true, SubSkillType.SMELTING_UNDERSTANDING_THE_ART, - String.valueOf(UserManager.getPlayer(player).getSmeltingManager().getVanillaXpMultiplier()))); + String.valueOf(mmoPlayer.getSmeltingManager().getVanillaXpMultiplier()))); } return messages; @@ -91,7 +97,8 @@ public class SmeltingCommand extends SkillCommand { protected List getTextComponents(Player player) { List textComponents = new ArrayList<>(); - TextComponentFactory.getSubSkillTextComponents(player, textComponents, PrimarySkillType.SMELTING); + TextComponentFactory.getSubSkillTextComponents(player, textComponents, + PrimarySkillType.SMELTING); return textComponents; } 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 954c39024..54359c9df 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/SwordsCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/SwordsCommand.java @@ -5,16 +5,15 @@ import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.locale.LocaleLoader; 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.SkillActivationType; +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; - import java.util.ArrayList; import java.util.List; +import net.kyori.adventure.text.Component; +import org.bukkit.entity.Player; public class SwordsCommand extends SkillCommand { private String counterChance; @@ -38,7 +37,8 @@ public class SwordsCommand extends SkillCommand { 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 = ProbabilityUtil.getRNGDisplayValues(mmoPlayer, + SubSkillType.SWORDS_COUNTER_ATTACK); counterChance = counterStrings[0]; counterChanceLucky = counterStrings[1]; } @@ -46,19 +46,27 @@ public class SwordsCommand extends SkillCommand { // SWORDS_RUPTURE if (canRupture) { int ruptureRank = RankUtils.getRank(player, SubSkillType.SWORDS_RUPTURE); - ruptureLengthSecondsAgainstPlayers = String.valueOf(mcMMO.p.getAdvancedConfig().getRuptureDurationSeconds(true)); - ruptureLengthSecondsAgainstMobs = String.valueOf(mcMMO.p.getAdvancedConfig().getRuptureDurationSeconds(false)); + ruptureLengthSecondsAgainstPlayers = String.valueOf( + mcMMO.p.getAdvancedConfig().getRuptureDurationSeconds(true)); + ruptureLengthSecondsAgainstMobs = String.valueOf( + mcMMO.p.getAdvancedConfig().getRuptureDurationSeconds(false)); - rupturePureTickDamageAgainstPlayers = String.valueOf(mcMMO.p.getAdvancedConfig().getRuptureTickDamage(true, ruptureRank)); - rupturePureTickDamageAgainstMobs = String.valueOf(mcMMO.p.getAdvancedConfig().getRuptureTickDamage(false, ruptureRank)); + rupturePureTickDamageAgainstPlayers = String.valueOf( + mcMMO.p.getAdvancedConfig().getRuptureTickDamage(true, ruptureRank)); + rupturePureTickDamageAgainstMobs = String.valueOf( + mcMMO.p.getAdvancedConfig().getRuptureTickDamage(false, ruptureRank)); - ruptureExplosionDamageAgainstPlayers = String.valueOf(mcMMO.p.getAdvancedConfig().getRuptureExplosionDamage(true, ruptureRank)); - ruptureExplosionDamageAgainstMobs = String.valueOf(mcMMO.p.getAdvancedConfig().getRuptureExplosionDamage(false, ruptureRank)); + ruptureExplosionDamageAgainstPlayers = String.valueOf( + mcMMO.p.getAdvancedConfig().getRuptureExplosionDamage(true, ruptureRank)); + ruptureExplosionDamageAgainstMobs = String.valueOf( + mcMMO.p.getAdvancedConfig().getRuptureExplosionDamage(false, ruptureRank)); - ruptureChanceToApply = String.valueOf(mcMMO.p.getAdvancedConfig().getRuptureChanceToApplyOnHit(ruptureRank) + "%"); - ruptureChanceToApplyLucky = String.valueOf(mcMMO.p.getAdvancedConfig().getRuptureChanceToApplyOnHit(ruptureRank) * 1.33); + ruptureChanceToApply = + mcMMO.p.getAdvancedConfig().getRuptureChanceToApplyOnHit(ruptureRank) + "%"; + ruptureChanceToApplyLucky = String.valueOf( + mcMMO.p.getAdvancedConfig().getRuptureChanceToApplyOnHit(ruptureRank) * 1.33); } - + // SERRATED STRIKES if (canSerratedStrike) { String[] serratedStrikesStrings = calculateLengthDisplayValues(player, skillValue); @@ -69,28 +77,34 @@ public class SwordsCommand extends SkillCommand { @Override protected void permissionsCheck(Player player) { - canRupture = canUseSubskill(player, SubSkillType.SWORDS_RUPTURE); - canCounter = canUseSubskill(player, SubSkillType.SWORDS_COUNTER_ATTACK); - canSerratedStrike = RankUtils.hasUnlockedSubskill(player, SubSkillType.SWORDS_SERRATED_STRIKES) && Permissions.serratedStrikes(player); + 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); } @Override - protected List statsDisplay(Player player, float skillValue, boolean hasEndurance, boolean isLucky) { + protected List statsDisplay(Player player, float skillValue, boolean hasEndurance, + boolean isLucky) { List messages = new ArrayList<>(); if (canCounter) { messages.add(getStatMessage(SubSkillType.SWORDS_COUNTER_ATTACK, counterChance) - + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", counterChanceLucky) : "")); + + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", counterChanceLucky) + : "")); } if (canRupture) { messages.add(getStatMessage(SubSkillType.SWORDS_RUPTURE, ruptureChanceToApply) - + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", ruptureChanceToApplyLucky) : "")); + + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", + ruptureChanceToApplyLucky) : "")); messages.add(getStatMessage(true, true, SubSkillType.SWORDS_RUPTURE, ruptureLengthSecondsAgainstPlayers, ruptureLengthSecondsAgainstMobs)); - messages.add(LocaleLoader.getString("Swords.SubSkill.Rupture.Stat.TickDamage", rupturePureTickDamageAgainstPlayers, rupturePureTickDamageAgainstMobs)); + messages.add(LocaleLoader.getString("Swords.SubSkill.Rupture.Stat.TickDamage", + rupturePureTickDamageAgainstPlayers, rupturePureTickDamageAgainstMobs)); // messages.add(LocaleLoader.getString("Swords.SubSkill.Rupture.Stat.ExplosionDamage", ruptureExplosionDamageAgainstPlayers, ruptureExplosionDamageAgainstMobs)); messages.add(LocaleLoader.getString("Swords.Combat.Rupture.Note.Update.One")); @@ -98,18 +112,19 @@ public class SwordsCommand extends SkillCommand { if (canSerratedStrike) { messages.add(getStatMessage(SubSkillType.SWORDS_SERRATED_STRIKES, serratedStrikesLength) - + (hasEndurance ? LocaleLoader.getString("Perks.ActivationTime.Bonus", serratedStrikesLengthEndurance) : "")); + + (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()))); + String.valueOf(mmoPlayer.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)))); + String.valueOf(CombatUtils.getLimitBreakDamageAgainstQuality(player, + SubSkillType.SWORDS_SWORDS_LIMIT_BREAK, 1000)))); } return messages; @@ -119,7 +134,8 @@ public class SwordsCommand extends SkillCommand { protected List getTextComponents(Player player) { List textComponents = new ArrayList<>(); - TextComponentFactory.getSubSkillTextComponents(player, textComponents, PrimarySkillType.SWORDS); + TextComponentFactory.getSubSkillTextComponents(player, textComponents, + PrimarySkillType.SWORDS); return textComponents; } 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 35f04f5bc..a7db4d82c 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/TamingCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/TamingCommand.java @@ -5,15 +5,14 @@ import com.gmail.nossr50.datatypes.skills.SubSkillType; 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.random.ProbabilityUtil; import com.gmail.nossr50.util.text.TextComponentFactory; +import java.util.ArrayList; +import java.util.List; import net.kyori.adventure.text.Component; import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; -import java.util.ArrayList; -import java.util.List; - public class TamingCommand extends SkillCommand { private String goreChance; private String goreChanceLucky; @@ -35,7 +34,8 @@ public class TamingCommand extends SkillCommand { @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 = ProbabilityUtil.getRNGDisplayValues(mmoPlayer, + SubSkillType.TAMING_GORE); goreChance = goreStrings[0]; goreChanceLucky = goreStrings[1]; } @@ -43,49 +43,69 @@ public class TamingCommand extends SkillCommand { @Override protected void permissionsCheck(Player player) { - canBeastLore = 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); + 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 = 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 - protected List statsDisplay(Player player, float skillValue, boolean hasEndurance, boolean isLucky) { + protected List statsDisplay(Player player, float skillValue, boolean hasEndurance, + boolean isLucky) { List messages = new ArrayList<>(); if (canEnvironmentallyAware) { - messages.add(LocaleLoader.getString("Ability.Generic.Template", LocaleLoader.getString("Taming.Ability.Bonus.0"), LocaleLoader.getString("Taming.Ability.Bonus.1"))); + messages.add(LocaleLoader.getString("Ability.Generic.Template", + LocaleLoader.getString("Taming.Ability.Bonus.0"), + LocaleLoader.getString("Taming.Ability.Bonus.1"))); } - + if (canFastFood) { - messages.add(LocaleLoader.getString("Ability.Generic.Template", LocaleLoader.getString("Taming.Ability.Bonus.8"), LocaleLoader.getString("Taming.Ability.Bonus.9", percent.format(Taming.fastFoodServiceActivationChance / 100D)))); + messages.add(LocaleLoader.getString("Ability.Generic.Template", + LocaleLoader.getString("Taming.Ability.Bonus.8"), + LocaleLoader.getString("Taming.Ability.Bonus.9", + percent.format(Taming.fastFoodServiceActivationChance / 100D)))); } - + if (canGore) { messages.add(LocaleLoader.getString("Ability.Generic.Template", LocaleLoader.getString("Taming.Combat.Chance.Gore"), - goreChance) + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", goreChanceLucky) : "")); + goreChance) + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", + goreChanceLucky) : "")); } - + if (canHolyHound) { - messages.add(LocaleLoader.getString("Ability.Generic.Template", LocaleLoader.getString("Taming.Ability.Bonus.10"), LocaleLoader.getString("Taming.Ability.Bonus.11"))); + messages.add(LocaleLoader.getString("Ability.Generic.Template", + LocaleLoader.getString("Taming.Ability.Bonus.10"), + LocaleLoader.getString("Taming.Ability.Bonus.11"))); } if (canSharpenedClaws) { - messages.add(LocaleLoader.getString("Ability.Generic.Template", LocaleLoader.getString("Taming.Ability.Bonus.6"), LocaleLoader.getString("Taming.Ability.Bonus.7", Taming.sharpenedClawsBonusDamage))); + messages.add(LocaleLoader.getString("Ability.Generic.Template", + LocaleLoader.getString("Taming.Ability.Bonus.6"), + LocaleLoader.getString("Taming.Ability.Bonus.7", + Taming.sharpenedClawsBonusDamage))); } - + if (canShockProof) { - messages.add(LocaleLoader.getString("Ability.Generic.Template", LocaleLoader.getString("Taming.Ability.Bonus.4"), LocaleLoader.getString("Taming.Ability.Bonus.5", Taming.shockProofModifier))); + messages.add(LocaleLoader.getString("Ability.Generic.Template", + LocaleLoader.getString("Taming.Ability.Bonus.4"), + LocaleLoader.getString("Taming.Ability.Bonus.5", Taming.shockProofModifier))); } - + if (canThickFur) { - messages.add(LocaleLoader.getString("Ability.Generic.Template", LocaleLoader.getString("Taming.Ability.Bonus.2"), LocaleLoader.getString("Taming.Ability.Bonus.3", Taming.thickFurModifier))); + messages.add(LocaleLoader.getString("Ability.Generic.Template", + LocaleLoader.getString("Taming.Ability.Bonus.2"), + LocaleLoader.getString("Taming.Ability.Bonus.3", Taming.thickFurModifier))); } return messages; 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 000000000..b01dfdb36 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/commands/skills/TridentsCommand.java @@ -0,0 +1,58 @@ +package com.gmail.nossr50.commands.skills; + +import static com.gmail.nossr50.datatypes.skills.SubSkillType.TRIDENTS_IMPALE; +import static com.gmail.nossr50.datatypes.skills.SubSkillType.TRIDENTS_TRIDENTS_LIMIT_BREAK; + +import com.gmail.nossr50.datatypes.skills.PrimarySkillType; +import com.gmail.nossr50.util.skills.CombatUtils; +import com.gmail.nossr50.util.skills.SkillUtils; +import com.gmail.nossr50.util.text.TextComponentFactory; +import java.util.ArrayList; +import java.util.List; +import net.kyori.adventure.text.Component; +import org.bukkit.entity.Player; + +public class TridentsCommand extends SkillCommand { + + + public TridentsCommand() { + super(PrimarySkillType.TRIDENTS); + } + + @Override + protected void dataCalculations(Player player, float skillValue) { + } + + @Override + protected void permissionsCheck(Player player) { + } + + @Override + protected List statsDisplay(Player player, float skillValue, boolean hasEndurance, + boolean isLucky) { + List messages = new ArrayList<>(); + + 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, TRIDENTS_IMPALE)) { + messages.add(getStatMessage(TRIDENTS_IMPALE, + String.valueOf(mmoPlayer.getTridentsManager().impaleDamageBonus()))); + } + + 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/commands/skills/UnarmedCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/UnarmedCommand.java index 5f9784be7..7ae5c1a7f 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/UnarmedCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/UnarmedCommand.java @@ -4,16 +4,14 @@ import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SubSkillType; 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.SkillActivationType; 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; +import net.kyori.adventure.text.Component; +import org.bukkit.entity.Player; public class UnarmedCommand extends SkillCommand { private String berserkLength; @@ -40,11 +38,12 @@ public class UnarmedCommand extends SkillCommand { 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 = ProbabilityUtil.getRNGDisplayValues(mmoPlayer, + SubSkillType.UNARMED_ARROW_DEFLECT); deflectChance = deflectStrings[0]; deflectChanceLucky = deflectStrings[1]; } - + // BERSERK if (canBerserk) { String[] berserkStrings = calculateLengthDisplayValues(player, skillValue); @@ -54,19 +53,21 @@ public class UnarmedCommand extends SkillCommand { // UNARMED_DISARM if (canDisarm) { - String[] disarmStrings = getAbilityDisplayValues(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, player, SubSkillType.UNARMED_DISARM); + String[] disarmStrings = ProbabilityUtil.getRNGDisplayValues(mmoPlayer, + SubSkillType.UNARMED_DISARM); disarmChance = disarmStrings[0]; disarmChanceLucky = disarmStrings[1]; } // IRON ARM if (canIronArm) { - ironArmBonus = UserManager.getPlayer(player).getUnarmedManager().getSteelArmStyleDamage(); + ironArmBonus = mmoPlayer.getUnarmedManager().getSteelArmStyleDamage(); } // IRON GRIP if (canIronGrip) { - String[] ironGripStrings = getAbilityDisplayValues(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, player, SubSkillType.UNARMED_IRON_GRIP); + String[] ironGripStrings = ProbabilityUtil.getRNGDisplayValues(mmoPlayer, + SubSkillType.UNARMED_IRON_GRIP); ironGripChance = ironGripStrings[0]; ironGripChanceLucky = ironGripStrings[1]; } @@ -74,49 +75,58 @@ public class UnarmedCommand extends SkillCommand { @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); + canBerserk = RankUtils.hasUnlockedSubskill(player, SubSkillType.UNARMED_BERSERK) + && Permissions.berserk(player); + 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? } @Override - protected List statsDisplay(Player player, float skillValue, boolean hasEndurance, boolean isLucky) { + protected List statsDisplay(Player player, float skillValue, boolean hasEndurance, + boolean isLucky) { List messages = new ArrayList<>(); if (canDeflect) { messages.add(getStatMessage(SubSkillType.UNARMED_ARROW_DEFLECT, deflectChance) - + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", deflectChanceLucky) : "")); + + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", deflectChanceLucky) + : "")); //messages.add(LocaleLoader.getString("Unarmed.Ability.Chance.ArrowDeflect", deflectChance) + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", deflectChanceLucky) : "")); } - + if (canBerserk) { messages.add(getStatMessage(SubSkillType.UNARMED_BERSERK, berserkLength) - + (hasEndurance ? LocaleLoader.getString("Perks.ActivationTime.Bonus", berserkLengthEndurance) : "")); + + (hasEndurance ? LocaleLoader.getString("Perks.ActivationTime.Bonus", + berserkLengthEndurance) : "")); //messages.add(LocaleLoader.getString("Unarmed.Ability.Berserk.Length", berserkLength) + (hasEndurance ? LocaleLoader.getString("Perks.ActivationTime.Bonus", berserkLengthEndurance) : "")); } - + if (canDisarm) { messages.add(getStatMessage(SubSkillType.UNARMED_DISARM, disarmChance) - + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", disarmChanceLucky) : "")); + + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", disarmChanceLucky) + : "")); //messages.add(LocaleLoader.getString("Unarmed.Ability.Chance.Disarm", disarmChance) + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", disarmChanceLucky) : "")); } - + if (canIronArm) { - messages.add(LocaleLoader.getString("Ability.Generic.Template", LocaleLoader.getString("Unarmed.Ability.Bonus.0"), LocaleLoader.getString("Unarmed.Ability.Bonus.1", ironArmBonus))); + messages.add(LocaleLoader.getString("Ability.Generic.Template", + LocaleLoader.getString("Unarmed.Ability.Bonus.0"), + LocaleLoader.getString("Unarmed.Ability.Bonus.1", ironArmBonus))); } if (canIronGrip) { messages.add(getStatMessage(SubSkillType.UNARMED_IRON_GRIP, ironGripChance) - + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", ironGripChanceLucky) : "")); + + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", ironGripChanceLucky) + : "")); //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)))); + String.valueOf(CombatUtils.getLimitBreakDamageAgainstQuality(player, + SubSkillType.UNARMED_UNARMED_LIMIT_BREAK, 1000)))); } return messages; @@ -126,7 +136,8 @@ public class UnarmedCommand extends SkillCommand { protected List getTextComponents(Player player) { List textComponents = new ArrayList<>(); - TextComponentFactory.getSubSkillTextComponents(player, textComponents, PrimarySkillType.UNARMED); + TextComponentFactory.getSubSkillTextComponents(player, textComponents, + PrimarySkillType.UNARMED); return textComponents; } 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 08639c27b..9b7f9ed30 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/WoodcuttingCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/WoodcuttingCommand.java @@ -5,28 +5,27 @@ import com.gmail.nossr50.datatypes.skills.SubSkillType; 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.SkillActivationType; 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; +import net.kyori.adventure.text.Component; +import org.bukkit.entity.Player; 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; public WoodcuttingCommand() { super(PrimarySkillType.WOODCUTTING); @@ -38,7 +37,15 @@ public class WoodcuttingCommand extends SkillCommand { if (canDoubleDrop) { setDoubleDropClassicChanceStrings(player); } - + + //Clean Cuts + if (canTripleDrop) { + String[] tripleDropStrings = ProbabilityUtil.getRNGDisplayValues(mmoPlayer, + SubSkillType.WOODCUTTING_CLEAN_CUTS); + tripleDropChance = tripleDropStrings[0]; + tripleDropChanceLucky = tripleDropStrings[1]; + } + // TREE FELLER if (canTreeFell) { String[] treeFellerStrings = calculateLengthDisplayValues(player, skillValue); @@ -48,37 +55,47 @@ public class WoodcuttingCommand extends SkillCommand { } private void setDoubleDropClassicChanceStrings(Player player) { - String[] doubleDropStrings = getAbilityDisplayValues(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, player, SubSkillType.WOODCUTTING_HARVEST_LUMBER); + String[] doubleDropStrings = ProbabilityUtil.getRNGDisplayValues(mmoPlayer, + SubSkillType.WOODCUTTING_HARVEST_LUMBER); doubleDropChance = doubleDropStrings[0]; doubleDropChanceLucky = doubleDropStrings[1]; } @Override protected void permissionsCheck(Player player) { - canTreeFell = RankUtils.hasUnlockedSubskill(player, SubSkillType.WOODCUTTING_TREE_FELLER) && Permissions.treeFeller(player); - canDoubleDrop = canUseSubskill(player, SubSkillType.WOODCUTTING_HARVEST_LUMBER) - && !mcMMO.p.getGeneralConfig().getDoubleDropsDisabled(skill) + canTreeFell = RankUtils.hasUnlockedSubskill(player, SubSkillType.WOODCUTTING_TREE_FELLER) + && Permissions.treeFeller(player); + canDoubleDrop = !mcMMO.p.getGeneralConfig().getDoubleDropsDisabled(skill) + && Permissions.canUseSubSkill(player, SubSkillType.WOODCUTTING_HARVEST_LUMBER) && RankUtils.getRank(player, SubSkillType.WOODCUTTING_HARVEST_LUMBER) >= 1; - canLeafBlow = canUseSubskill(player, SubSkillType.WOODCUTTING_LEAF_BLOWER); - canKnockOnWood = canTreeFell && 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);*/ + canTripleDrop = !mcMMO.p.getGeneralConfig().getDoubleDropsDisabled(skill) + && Permissions.canUseSubSkill(player, SubSkillType.WOODCUTTING_CLEAN_CUTS); + canLeafBlow = Permissions.canUseSubSkill(player, SubSkillType.WOODCUTTING_LEAF_BLOWER); + canKnockOnWood = canTreeFell && Permissions.canUseSubSkill(player, + SubSkillType.WOODCUTTING_KNOCK_ON_WOOD); } @Override - protected List statsDisplay(Player player, float skillValue, boolean hasEndurance, boolean isLucky) { + protected List statsDisplay(Player player, float skillValue, boolean hasEndurance, + boolean isLucky) { List messages = new ArrayList<>(); if (canDoubleDrop) { messages.add(getStatMessage(SubSkillType.WOODCUTTING_HARVEST_LUMBER, doubleDropChance) - + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", doubleDropChanceLucky) : "")); + + (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; - if(RankUtils.hasReachedRank(2, player, SubSkillType.WOODCUTTING_KNOCK_ON_WOOD)) { + if (RankUtils.hasReachedRank(2, player, SubSkillType.WOODCUTTING_KNOCK_ON_WOOD)) { lootNote = LocaleLoader.getString("Woodcutting.SubSkill.KnockOnWood.Loot.Rank2"); } else { lootNote = LocaleLoader.getString("Woodcutting.SubSkill.KnockOnWood.Loot.Normal"); @@ -86,14 +103,17 @@ public class WoodcuttingCommand extends SkillCommand { messages.add(getStatMessage(SubSkillType.WOODCUTTING_KNOCK_ON_WOOD, lootNote)); } - + if (canLeafBlow) { - messages.add(LocaleLoader.getString("Ability.Generic.Template", LocaleLoader.getString("Woodcutting.Ability.0"), LocaleLoader.getString("Woodcutting.Ability.1"))); + messages.add(LocaleLoader.getString("Ability.Generic.Template", + LocaleLoader.getString("Woodcutting.Ability.0"), + LocaleLoader.getString("Woodcutting.Ability.1"))); } if (canTreeFell) { messages.add(getStatMessage(SubSkillType.WOODCUTTING_TREE_FELLER, treeFellerLength) - + (hasEndurance ? LocaleLoader.getString("Perks.ActivationTime.Bonus", treeFellerLengthEndurance) : "")); + + (hasEndurance ? LocaleLoader.getString("Perks.ActivationTime.Bonus", + treeFellerLengthEndurance) : "")); } return messages; @@ -103,7 +123,8 @@ public class WoodcuttingCommand extends SkillCommand { protected List getTextComponents(Player player) { List textComponents = new ArrayList<>(); - TextComponentFactory.getSubSkillTextComponents(player, textComponents, PrimarySkillType.WOODCUTTING); + TextComponentFactory.getSubSkillTextComponents(player, textComponents, + PrimarySkillType.WOODCUTTING); return textComponents; } diff --git a/src/main/java/com/gmail/nossr50/config/AdvancedConfig.java b/src/main/java/com/gmail/nossr50/config/AdvancedConfig.java index 04cca138a..1f44ac78b 100644 --- a/src/main/java/com/gmail/nossr50/config/AdvancedConfig.java +++ b/src/main/java/com/gmail/nossr50/config/AdvancedConfig.java @@ -4,13 +4,13 @@ import com.gmail.nossr50.datatypes.interactions.NotificationType; import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.datatypes.skills.subskills.AbstractSubSkill; import com.gmail.nossr50.mcMMO; -import net.md_5.bungee.api.ChatColor; - import java.io.File; import java.util.ArrayList; import java.util.List; +import net.md_5.bungee.api.ChatColor; public class AdvancedConfig extends BukkitConfig { + int[] defaultCrippleValues = new int[]{10, 15, 20, 25}; public AdvancedConfig(File dataFolder) { super("advanced.yml", dataFolder); @@ -65,7 +65,8 @@ public class AdvancedConfig extends BukkitConfig { } if (getCatalysisMaxSpeed() < getCatalysisMinSpeed()) { - reason.add("Skills.Alchemy.Catalysis.MaxSpeed should be at least Skills.Alchemy.Catalysis.MinSpeed!"); + reason.add( + "Skills.Alchemy.Catalysis.MaxSpeed should be at least Skills.Alchemy.Catalysis.MinSpeed!"); } /* ARCHERY */ @@ -357,7 +358,8 @@ public class AdvancedConfig extends BukkitConfig { } if (getMaxHorseJumpStrength() < 0 || getMaxHorseJumpStrength() > 2) { - reason.add("Skills.Taming.CallOfTheWild.MaxHorseJumpStrength should be between 0 and 2!"); + reason.add( + "Skills.Taming.CallOfTheWild.MaxHorseJumpStrength should be between 0 and 2!"); } /* UNARMED */ @@ -408,6 +410,11 @@ public class AdvancedConfig extends BukkitConfig { /* GENERAL */ + public boolean useAttackCooldown() { + return config.getBoolean("Skills.General.Attack_Cooldown.Adjust_Skills_For_Attack_Cooldown", + true); + } + public boolean canApplyLimitBreakPVE() { return config.getBoolean("Skills.General.LimitBreak.AllowPVE", false); } @@ -421,29 +428,32 @@ public class AdvancedConfig extends BukkitConfig { } /** - * This returns the maximum level at which superabilities will stop lengthening from scaling alongside skill level. - * It returns a different value depending on whether the server is in retro mode + * This returns the maximum level at which superabilities will stop lengthening from scaling + * alongside skill level. It returns a different value depending on whether the server is in + * retro mode * * @return the level at which abilities stop increasing in length */ public int getAbilityLengthCap() { - if (!mcMMO.isRetroModeEnabled()) + if (!mcMMO.isRetroModeEnabled()) { return config.getInt("Skills.General.Ability.Length.Standard.CapLevel", 50); - else + } else { return config.getInt("Skills.General.Ability.Length.RetroMode.CapLevel", 500); + } } /** - * This returns the frequency at which abilities will increase in length - * It returns a different value depending on whether the server is in retro mode + * This returns the frequency at which abilities will increase in length It returns a different + * value depending on whether the server is in retro mode * * @return the number of levels required per ability length increase */ public int getAbilityLength() { - if (!mcMMO.isRetroModeEnabled()) + if (!mcMMO.isRetroModeEnabled()) { return config.getInt("Skills.General.Ability.Length.Standard.IncreaseLevel", 5); - else + } else { return config.getInt("Skills.General.Ability.Length.RetroMode.IncreaseLevel", 50); + } } public int getEnchantBuff() { @@ -451,17 +461,19 @@ public class AdvancedConfig extends BukkitConfig { } /** - * Grabs the max bonus level for a skill used in RNG calculations - * All max level values in the config are multiplied by 10 if the server is in retro mode as the values in the config are based around the new 1-100 skill system scaling - * A value of 10 in the file will be returned as 100 for retro mode servers to accommodate the change in scaling + * Grabs the max bonus level for a skill used in RNG calculations All max level values in the + * config are multiplied by 10 if the server is in retro mode as the values in the config are + * based around the new 1-100 skill system scaling A value of 10 in the file will be returned as + * 100 for retro mode servers to accommodate the change in scaling * * @param subSkillType target subskill - * * @return the level at which this skills max benefits will be reached on the curve */ public int getMaxBonusLevel(SubSkillType subSkillType) { String keyPath = subSkillType.getAdvConfigAddress() + ".MaxBonusLevel."; - return mcMMO.isRetroModeEnabled() ? config.getInt(keyPath + "RetroMode", 1000) : config.getInt(keyPath + "Standard", 100); + return mcMMO.isRetroModeEnabled() ? config.getInt(keyPath + "RetroMode", 1000) + : config.getInt( + keyPath + "Standard", 100); } public int getMaxBonusLevel(AbstractSubSkill abstractSubSkill) { @@ -484,11 +496,15 @@ public class AdvancedConfig extends BukkitConfig { } public boolean doesNotificationUseActionBar(NotificationType notificationType) { - return config.getBoolean("Feedback.ActionBarNotifications." + notificationType.toString() + ".Enabled", true); + return config.getBoolean( + "Feedback.ActionBarNotifications." + notificationType.toString() + ".Enabled", + true); } public boolean doesNotificationSendCopyToChat(NotificationType notificationType) { - return config.getBoolean("Feedback.ActionBarNotifications." + notificationType.toString() + ".SendCopyOfMessageToChat", false); + return config.getBoolean( + "Feedback.ActionBarNotifications." + notificationType.toString() + + ".SendCopyOfMessageToChat", false); } public boolean useTitlesForXPEvent() { @@ -496,73 +512,10 @@ public class AdvancedConfig extends BukkitConfig { } public boolean sendAbilityNotificationToOtherPlayers() { - return config.getBoolean("Feedback.Events.AbilityActivation.SendNotificationToOtherPlayers", true); + return config.getBoolean("Feedback.Events.AbilityActivation.SendNotificationToOtherPlayers", + true); } - /* - * JSON Style Settings - */ - - - /*public ChatColor getJSONStatHoverElementColor(StatType statType, boolean isPrefix) - { - String keyAddress = isPrefix ? "Prefix" : "Value"; - String keyLocation = "Style.JSON.Hover.Details." + StringUtils.getCapitalized(statType.toString()) +"."+keyAddress+".Color"; - - return getChatColorFromKey(keyLocation); - }*/ - - /** - * Used to color our details header in our JSON Hover Object tooltips - * - * @return the ChatColor for this element - */ - /*public ChatColor getJSONStatHoverDetailsColor() - { - String keyLocation = "Style.JSON.Hover.Details.Header.Color"; - return getChatColorFromKey(keyLocation); - } - - public boolean isJSONDetailsHeaderBold() - { - return config.getBoolean("Style.JSON.Hover.Details.Header.Bold"); - } - - public boolean isJSONDetailsHeaderItalic() - { - return config.getBoolean("Style.JSON.Hover.Details.Header.Italics"); - } - - public boolean isJSONDetailsHeaderUnderlined() - { - return config.getBoolean("Style.JSON.Hover.Details.Header.Underlined"); - } - - public ChatColor getJSONStatHoverDescriptionColor() - { - String keyLocation = "Style.JSON.Hover.Details.Description.Color"; - return getChatColorFromKey(keyLocation); - } - - public boolean isJSONDetailsDescriptionBold() - { - return config.getBoolean("Style.JSON.Hover.Details.Description.Bold"); - } - - public boolean isJSONDetailsDescriptionItalic() - { - return config.getBoolean("Style.JSON.Hover.Details.Description.Italics"); - } - - public boolean isJSONDetailsDescriptionUnderlined() - { - return config.getBoolean("Style.JSON.Hover.Details.Description.Underlined"); - } - - public ChatColor getJSONActionBarColor(NotificationType notificationType) - { - return getChatColor(config.getString("Style.JSON.Notification."+notificationType.toString()+".Color")); - }*/ private ChatColor getChatColorFromKey(String keyLocation) { String colorName = config.getString(keyLocation); @@ -571,8 +524,9 @@ public class AdvancedConfig extends BukkitConfig { private ChatColor getChatColor(String configColor) { for (ChatColor chatColor : ChatColor.values()) { - if (configColor.equalsIgnoreCase(chatColor.getName())) + if (configColor.equalsIgnoreCase(chatColor.getName())) { return chatColor; + } } //Invalid Color @@ -580,38 +534,6 @@ public class AdvancedConfig extends BukkitConfig { return ChatColor.WHITE; } - /*public boolean isJSONStatHoverElementBold(StatType statType, boolean isPrefix) - { - String keyAddress = isPrefix ? "Prefix" : "Value"; - String keyLocation = "Style.JSON.Hover.Details." + StringUtils.getCapitalized(statType.toString()) +"."+keyAddress+".Bold"; - return config.getBoolean(keyLocation); - } - - public boolean isJSONStatHoverElementItalic(StatType statType, boolean isPrefix) - { - String keyAddress = isPrefix ? "Prefix" : "Value"; - String keyLocation = "Style.JSON.Hover.Details." + StringUtils.getCapitalized(statType.toString()) +"."+keyAddress+".Italics"; - return config.getBoolean(keyLocation); - } - - public boolean isJSONStatHoverElementUnderlined(StatType statType, boolean isPrefix) - { - String keyAddress = isPrefix ? "Prefix" : "Value"; - String keyLocation = "Style.JSON.Hover.Details." + StringUtils.getCapitalized(statType.toString()) +"."+keyAddress+".Underline"; - return config.getBoolean(keyLocation); - }*/ - - /** - * Some SubSkills have the ability to retain classic functionality - * - * @param subSkillType SubSkillType with classic functionality - * - * @return true if the subskill is in classic mode - */ - public boolean isSubSkillClassic(SubSkillType subSkillType) { - return config.getBoolean(subSkillType.getAdvConfigAddress() + ".Classic"); - } - /* ACROBATICS */ public double getDodgeDamageModifier() { return config.getDouble("Skills.Acrobatics.Dodge.DamageModifier", 2.0D); @@ -627,7 +549,11 @@ public class AdvancedConfig extends BukkitConfig { /* ALCHEMY */ public int getCatalysisMaxBonusLevel() { - return config.getInt("Skills.Alchemy.Catalysis.MaxBonusLevel", 1000); + if (mcMMO.isRetroModeEnabled()) { + return config.getInt("Skills.Alchemy.Catalysis.MaxBonusLevel.RetroMode", 1000); + } else { + return config.getInt("Skills.Alchemy.Catalysis.MaxBonusLevel.Standard", 100); + } } public double getCatalysisMinSpeed() { @@ -693,6 +619,15 @@ public class AdvancedConfig extends BukkitConfig { 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 @@ -835,10 +770,11 @@ public class AdvancedConfig extends BukkitConfig { /* SMELTING */ public int getBurnModifierMaxLevel() { - if (mcMMO.isRetroModeEnabled()) + if (mcMMO.isRetroModeEnabled()) { return config.getInt("Skills.Smelting.FuelEfficiency.RetroMode.MaxBonusLevel", 1000); - else + } else { return config.getInt("Skills.Smelting.FuelEfficiency.Standard.MaxBonusLevel", 100); + } } public double getFluxMiningChance() { @@ -846,6 +782,14 @@ public class AdvancedConfig extends BukkitConfig { } /* SWORDS */ + public double getStabBaseDamage() { + return config.getDouble("Skills.Swords.Stab.Base_Damage", 1.0D); + } + + public double getStabPerRankMultiplier() { + return config.getDouble("Skills.Swords.Stab.Per_Rank_Multiplier", 1.5D); + } + public double getRuptureTickDamage(boolean isTargetPlayer, int rank) { String root = "Skills.Swords.Rupture.Rupture_Mechanics.Tick_Interval_Damage.Against_"; String targetType = isTargetPlayer ? "Players" : "Mobs"; @@ -919,7 +863,6 @@ public class AdvancedConfig extends BukkitConfig { } /* UNARMED */ - public boolean isSteelArmDamageCustom() { return config.getBoolean("Skills.Unarmed.SteelArmStyle.Damage_Override", false); } @@ -935,6 +878,13 @@ public class AdvancedConfig extends BukkitConfig { /* WOODCUTTING */ public boolean isKnockOnWoodXPOrbEnabled() { - return config.getBoolean("Skills.Woodcutting.TreeFeller.Knock_On_Wood.Add_XP_Orbs_To_Drops", true); + return config.getBoolean("Skills.Woodcutting.TreeFeller.Knock_On_Wood.Add_XP_Orbs_To_Drops", + true); + } + + /* MACES */ + public double getCrippleChanceToApplyOnHit(int rank) { + String root = "Skills.Maces.Cripple.Chance_To_Apply_On_Hit.Rank_"; + return config.getDouble(root + rank, defaultCrippleValues[rank - 1]); } } diff --git a/src/main/java/com/gmail/nossr50/config/AutoUpdateLegacyConfigLoader.java b/src/main/java/com/gmail/nossr50/config/AutoUpdateLegacyConfigLoader.java index 600e7f984..d3cd6f1a6 100644 --- a/src/main/java/com/gmail/nossr50/config/AutoUpdateLegacyConfigLoader.java +++ b/src/main/java/com/gmail/nossr50/config/AutoUpdateLegacyConfigLoader.java @@ -2,14 +2,13 @@ package com.gmail.nossr50.config; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.LogUtils; -import org.bukkit.configuration.file.FileConfiguration; -import org.bukkit.configuration.file.YamlConfiguration; -import org.jetbrains.annotations.NotNull; - import java.io.File; import java.io.IOException; import java.util.HashSet; import java.util.Set; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; +import org.jetbrains.annotations.NotNull; public abstract class AutoUpdateLegacyConfigLoader extends LegacyConfigLoader { public AutoUpdateLegacyConfigLoader(String relativePath, String fileName, File dataFolder) { @@ -47,7 +46,8 @@ public abstract class AutoUpdateLegacyConfigLoader extends LegacyConfigLoader { @Override protected void loadFile() { super.loadFile(); - FileConfiguration internalConfig = YamlConfiguration.loadConfiguration(mcMMO.p.getResourceAsReader(fileName)); + FileConfiguration internalConfig = YamlConfiguration.loadConfiguration( + mcMMO.p.getResourceAsReader(fileName)); Set configKeys = config.getKeys(true); Set internalConfigKeys = internalConfig.getKeys(true); @@ -74,7 +74,8 @@ public abstract class AutoUpdateLegacyConfigLoader extends LegacyConfigLoader { } for (String key : newKeys) { - LogUtils.debug(mcMMO.p.getLogger(), "Adding new key: " + key + " = " + internalConfig.get(key)); + LogUtils.debug(mcMMO.p.getLogger(), + "Adding new key: " + key + " = " + internalConfig.get(key)); config.set(key, internalConfig.get(key)); } diff --git a/src/main/java/com/gmail/nossr50/config/BukkitConfig.java b/src/main/java/com/gmail/nossr50/config/BukkitConfig.java index 23d50b6b2..d3b431551 100644 --- a/src/main/java/com/gmail/nossr50/config/BukkitConfig.java +++ b/src/main/java/com/gmail/nossr50/config/BukkitConfig.java @@ -2,16 +2,15 @@ package com.gmail.nossr50.config; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.LogUtils; -import org.bukkit.configuration.InvalidConfigurationException; -import org.bukkit.configuration.file.YamlConfiguration; -import org.jetbrains.annotations.NotNull; - 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; +import org.bukkit.configuration.InvalidConfigurationException; +import org.bukkit.configuration.file.YamlConfiguration; +import org.jetbrains.annotations.NotNull; public abstract class BukkitConfig { boolean copyDefaults = true; @@ -19,7 +18,8 @@ public abstract class BukkitConfig { protected final File configFile; protected YamlConfiguration defaultYamlConfig; protected YamlConfiguration config; - protected @NotNull final File dataFolder; + protected @NotNull + final File dataFolder; private boolean savedDefaults = false; public BukkitConfig(@NotNull String fileName, @NotNull File dataFolder, boolean copyDefaults) { @@ -41,6 +41,7 @@ public abstract class BukkitConfig { public BukkitConfig(@NotNull String fileName) { this(fileName, mcMMO.p.getDataFolder()); } + public BukkitConfig(@NotNull String fileName, boolean copyDefaults) { this(fileName, mcMMO.p.getDataFolder(), copyDefaults); } @@ -52,7 +53,7 @@ public abstract class BukkitConfig { try { config.save(configFile); - if(copyDefaults && !savedDefaults) { + if (copyDefaults && !savedDefaults) { copyMissingDefaultsFromResource(); savedDefaults = true; } @@ -82,9 +83,10 @@ public abstract class BukkitConfig { * Copies the config from the JAR to defaults/ */ YamlConfiguration saveDefaultConfigToDisk() { - LogUtils.debug(mcMMO.p.getLogger(), "Copying default config to disk: " + fileName + " to defaults/" + fileName); - try(InputStream inputStream = mcMMO.p.getResource(fileName)) { - if(inputStream == null) { + LogUtils.debug(mcMMO.p.getLogger(), + "Copying default config to disk: " + fileName + " to defaults/" + fileName); + try (InputStream inputStream = mcMMO.p.getResource(fileName)) { + if (inputStream == null) { mcMMO.p.getLogger().severe("Unable to copy default config: " + fileName); return null; } @@ -110,7 +112,9 @@ public abstract class BukkitConfig { YamlConfiguration initConfig() { if (!configFile.exists()) { - LogUtils.debug(mcMMO.p.getLogger(), "User config file not found, copying a default config to disk: " + fileName); + LogUtils.debug( + mcMMO.p.getLogger(), + "User config file not found, copying a default config to disk: " + fileName); mcMMO.p.saveResource(fileName, false); } @@ -154,15 +158,20 @@ public abstract class BukkitConfig { if (validateKeys()) { LogUtils.debug(mcMMO.p.getLogger(), "No errors found in " + fileName + "!"); } else { - mcMMO.p.getLogger().warning("Errors were found in " + fileName + "! mcMMO was disabled!"); + mcMMO.p.getLogger() + .warning("Errors were found in " + fileName + "! mcMMO was disabled!"); mcMMO.p.getServer().getPluginManager().disablePlugin(mcMMO.p); mcMMO.p.noErrorsInConfigFiles = false; } } public void backup() { - LogUtils.debug(mcMMO.p.getLogger(), "You are using an old version of the " + fileName + " file."); - LogUtils.debug(mcMMO.p.getLogger(), "Your old file has been renamed to " + fileName + ".old and has been replaced by an updated version."); + LogUtils.debug(mcMMO.p.getLogger(), + "You are using an old version of the " + fileName + " file."); + LogUtils.debug( + mcMMO.p.getLogger(), + "Your old file has been renamed to " + fileName + + ".old and has been replaced by an updated version."); configFile.renameTo(new File(configFile.getPath() + ".old")); diff --git a/src/main/java/com/gmail/nossr50/config/ChatConfig.java b/src/main/java/com/gmail/nossr50/config/ChatConfig.java index 0e33d74d1..caff26c03 100644 --- a/src/main/java/com/gmail/nossr50/config/ChatConfig.java +++ b/src/main/java/com/gmail/nossr50/config/ChatConfig.java @@ -35,7 +35,8 @@ public class ChatConfig extends BukkitConfig { } public boolean isChatChannelEnabled(@NotNull ChatChannel chatChannel) { - String key = "Chat.Channels." + StringUtils.getCapitalized(chatChannel.toString()) + ".Enable"; + String key = + "Chat.Channels." + StringUtils.getCapitalized(chatChannel.toString()) + ".Enable"; return config.getBoolean(key, true); } @@ -43,14 +44,21 @@ public class ChatConfig extends BukkitConfig { * Whether to use display names for players in target {@link ChatChannel} * * @param chatChannel target chat channel - * * @return true if display names should be used */ public boolean useDisplayNames(@NotNull ChatChannel chatChannel) { - String key = "Chat.Channels." + StringUtils.getCapitalized(chatChannel.toString()) + ".Use_Display_Names"; + String key = "Chat.Channels." + StringUtils.getCapitalized(chatChannel.toString()) + + ".Use_Display_Names"; 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/java/com/gmail/nossr50/config/CoreSkillsConfig.java b/src/main/java/com/gmail/nossr50/config/CoreSkillsConfig.java index d172e4551..61db52fc6 100644 --- a/src/main/java/com/gmail/nossr50/config/CoreSkillsConfig.java +++ b/src/main/java/com/gmail/nossr50/config/CoreSkillsConfig.java @@ -13,8 +13,9 @@ public class CoreSkillsConfig extends BukkitConfig { } public static CoreSkillsConfig getInstance() { - if (instance == null) + if (instance == null) { instance = new CoreSkillsConfig(); + } return instance; } @@ -35,25 +36,26 @@ public class CoreSkillsConfig extends BukkitConfig { */ /** - * Whether a skill is enabled - * Defaults true + * Whether a skill is enabled Defaults true * * @param abstractSubSkill SubSkill definition to check - * * @return true if subskill is enabled */ public boolean isSkillEnabled(AbstractSubSkill abstractSubSkill) { - return config.getBoolean(StringUtils.getCapitalized(abstractSubSkill.getPrimarySkill().toString()) + "." + abstractSubSkill.getConfigKeyName() + ".Enabled", true); + return config.getBoolean( + StringUtils.getCapitalized(abstractSubSkill.getPrimarySkill() + .toString()) + "." + abstractSubSkill.getConfigKeyName() + ".Enabled", + true); } /** * Whether this primary skill is enabled * * @param primarySkillType target primary skill - * * @return true if enabled */ public boolean isPrimarySkillEnabled(PrimarySkillType primarySkillType) { - return config.getBoolean(StringUtils.getCapitalized(primarySkillType.toString()) + ".Enabled", true); + return config.getBoolean( + StringUtils.getCapitalized(primarySkillType.toString()) + ".Enabled", true); } } diff --git a/src/main/java/com/gmail/nossr50/config/CustomItemSupportConfig.java b/src/main/java/com/gmail/nossr50/config/CustomItemSupportConfig.java new file mode 100644 index 000000000..2c996ec87 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/config/CustomItemSupportConfig.java @@ -0,0 +1,25 @@ +package com.gmail.nossr50.config; + +import java.io.File; + +public class CustomItemSupportConfig extends BukkitConfig { + public CustomItemSupportConfig(File dataFolder) { + super("custom_item_support.yml", dataFolder); + validate(); + } + + @Override + protected void loadKeys() { + + } + + public boolean isCustomRepairAllowed() { + return config.getBoolean( + "Custom_Item_Support.Repair.Allow_Repair_On_Items_With_Custom_Model_Data", true); + } + + public boolean isCustomSalvageAllowed() { + return config.getBoolean( + "Custom_Item_Support.Salvage.Allow_Salvage_On_Items_With_Custom_Model_Data", true); + } +} diff --git a/src/main/java/com/gmail/nossr50/config/GeneralConfig.java b/src/main/java/com/gmail/nossr50/config/GeneralConfig.java index 7a6f766c0..7b44b52aa 100644 --- a/src/main/java/com/gmail/nossr50/config/GeneralConfig.java +++ b/src/main/java/com/gmail/nossr50/config/GeneralConfig.java @@ -1,22 +1,24 @@ package com.gmail.nossr50.config; +import static com.gmail.nossr50.util.text.ConfigStringUtils.getConfigPartyFeatureString; +import static com.gmail.nossr50.util.text.ConfigStringUtils.getMaterialConfigString; + 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.io.File; import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.Set; +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; public class GeneralConfig extends BukkitConfig { @@ -43,16 +45,19 @@ public class GeneralConfig extends BukkitConfig { /* 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!"); + 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!"); + 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."); + reason.add( + "Mob_Healthbar.Display_Time cannot be 0! Set to -1 to disable or set a valid value."); } /* Database Purging */ @@ -65,11 +70,14 @@ public class GeneralConfig extends BukkitConfig { } /* 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 (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) { + if (getHardcoreVampirismStatLeechPercentage() < 0.01 + || getHardcoreVampirismStatLeechPercentage() > 100) { reason.add("Hardcore.Vampirism.Leech_Percentage only accepts values from 0.01 to 100!"); } @@ -122,7 +130,8 @@ public class GeneralConfig extends BukkitConfig { for (PartyFeature partyFeature : PartyFeature.values()) { if (getPartyFeatureUnlockLevel(partyFeature) < 0) { - reason.add("Party.Leveling." + StringUtils.getPrettyPartyFeatureString(partyFeature).replace(" ", "") + "_UnlockLevel should be at least 0!"); + reason.add("Party.Leveling." + getConfigPartyFeatureString( + partyFeature) + "_UnlockLevel should be at least 0!"); } } @@ -228,7 +237,9 @@ public class GeneralConfig extends BukkitConfig { /* Mob Healthbar */ public MobHealthbarType getMobHealthbarDefault() { try { - return MobHealthbarType.valueOf(config.getString("Mob_Healthbar.Display_Type", "HEARTS").toUpperCase(Locale.ENGLISH).trim()); + return MobHealthbarType.valueOf(config.getString("Mob_Healthbar.Display_Type", "HEARTS") + .toUpperCase(Locale.ENGLISH) + .trim()); } catch (IllegalArgumentException ex) { return MobHealthbarType.HEARTS; } @@ -399,11 +410,14 @@ public class GeneralConfig extends BukkitConfig { } public int getMySQLMaxConnections(PoolIdentifier identifier) { - return config.getInt("MySQL.Database.MaxConnections." + StringUtils.getCapitalized(identifier.toString()), 30); + 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); + return config.getInt( + "MySQL.Database.MaxPoolSize." + StringUtils.getCapitalized(identifier.toString()), + 10); } public boolean getMySQLSSL() { @@ -433,11 +447,16 @@ public class GeneralConfig extends BukkitConfig { /* Hardcore Mode */ public boolean getHardcoreStatLossEnabled(PrimarySkillType primarySkillType) { - return config.getBoolean("Hardcore.Death_Stat_Loss.Enabled." + StringUtils.getCapitalized(primarySkillType.toString()), false); + 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); + config.set( + "Hardcore.Death_Stat_Loss.Enabled." + StringUtils.getCapitalized( + primarySkillType.toString()), + enabled); } public double getHardcoreDeathStatPenaltyPercentage() { @@ -453,11 +472,14 @@ public class GeneralConfig extends BukkitConfig { } public boolean getHardcoreVampirismEnabled(PrimarySkillType primarySkillType) { - return config.getBoolean("Hardcore.Vampirism.Enabled." + StringUtils.getCapitalized(primarySkillType.toString()), false); + 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); + config.set("Hardcore.Vampirism.Enabled." + StringUtils.getCapitalized( + primarySkillType.toString()), enabled); } public double getHardcoreVampirismStatLeechPercentage() { @@ -547,6 +569,10 @@ public class GeneralConfig extends BukkitConfig { return config.getBoolean("Particles.Bleed", true); } + public boolean getCrippleEffectEnabled() { + return config.getBoolean("Particles.Cripple", true); + } + public boolean getDodgeEffectEnabled() { return config.getBoolean("Particles.Dodge", true); } @@ -570,7 +596,7 @@ public class GeneralConfig extends BukkitConfig { public int getLevelUpEffectsTier() { return config.getInt("Particles.LevelUp_Tier", 100); } -// public boolean getLargeFireworks() { return config.getBoolean("Particles.LargeFireworks", true); } + // public boolean getLargeFireworks() { return config.getBoolean("Particles.LargeFireworks", true); } /* PARTY SETTINGS */ public boolean getPartyFriendlyFire() { @@ -623,7 +649,8 @@ public class GeneralConfig extends BukkitConfig { } public int getPartyFeatureUnlockLevel(PartyFeature partyFeature) { - return config.getInt("Party.Leveling." + StringUtils.getPrettyPartyFeatureString(partyFeature).replace(" ", "") + "_UnlockLevel", 0); + return config.getInt( + "Party.Leveling." + getConfigPartyFeatureString(partyFeature) + "_UnlockLevel", 0); } /* Party Teleport Settings */ @@ -704,17 +731,22 @@ public class GeneralConfig extends BukkitConfig { */ 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")) + if (material.toString().equalsIgnoreCase("LILY_PAD")) { return false; + } - return config.getBoolean("Bonus_Drops." + StringUtils.getCapitalized(skill.toString()) + "." + StringUtils.getPrettyItemString(material).replace(" ", "_")); + return config.getBoolean( + "Bonus_Drops." + StringUtils.getCapitalized(skill.toString()) + "." + + getMaterialConfigString( + material).replace(" ", "_")); } public boolean getDoubleDropsDisabled(PrimarySkillType skill) { String skillName = StringUtils.getCapitalized(skill.toString()); ConfigurationSection section = config.getConfigurationSection("Bonus_Drops." + skillName); - if (section == null) + if (section == null) { return false; + } Set keys = section.getKeys(false); boolean disabled = true; @@ -774,7 +806,8 @@ public class GeneralConfig extends BukkitConfig { /* Mining */ public Material getDetonatorItem() { - return Material.matchMaterial(config.getString("Skills.Mining.Detonator_Name", "FLINT_AND_STEEL")); + return Material.matchMaterial( + config.getString("Skills.Mining.Detonator_Name", "FLINT_AND_STEEL")); } /* Excavation */ @@ -796,7 +829,8 @@ public class GeneralConfig extends BukkitConfig { } public @Nullable Material getRepairAnvilMaterial() { - return Material.matchMaterial(config.getString("Skills.Repair.Anvil_Material", "IRON_BLOCK")); + return Material.matchMaterial( + config.getString("Skills.Repair.Anvil_Material", "IRON_BLOCK")); } public boolean getRepairConfirmRequired() { @@ -829,7 +863,8 @@ public class GeneralConfig extends BukkitConfig { } public @Nullable Material getSalvageAnvilMaterial() { - return Material.matchMaterial(config.getString("Skills.Salvage.Anvil_Material", "GOLD_BLOCK")); + return Material.matchMaterial( + config.getString("Skills.Salvage.Anvil_Material", "GOLD_BLOCK")); } public boolean getSalvageConfirmRequired() { @@ -859,14 +894,16 @@ public class GeneralConfig extends BukkitConfig { } /* 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(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")); + return Material.matchMaterial( + config.getString( + "Skills.Taming.Call_Of_The_Wild." + cotwEntity + ".Item_Material")); } public int getTamingCOTWCost(String cotwEntity) { @@ -882,12 +919,14 @@ public class GeneralConfig extends BukkitConfig { } public int getTamingCOTWMaxAmount(String cotwEntity) { - return config.getInt("Skills.Taming.Call_Of_The_Wild." + cotwEntity + ".Per_Player_Limit", 1); + 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 getWoodcuttingDoubleDropsEnabled(BlockData blockData) { + return config.getBoolean( + "Bonus_Drops.Woodcutting." + getMaterialConfigString(blockData.getMaterial())); } public boolean getTreeFellerSoundsEnabled() { @@ -910,7 +949,8 @@ public class GeneralConfig extends BukkitConfig { } public int getLevelCap(PrimarySkillType skill) { - int cap = config.getInt("Skills." + StringUtils.getCapitalized(skill.toString()) + ".Level_Cap"); + int cap = config.getInt( + "Skills." + StringUtils.getCapitalized(skill.toString()) + ".Level_Cap"); return (cap <= 0) ? Integer.MAX_VALUE : cap; } @@ -925,11 +965,15 @@ public class GeneralConfig extends BukkitConfig { /* PVP & PVE Settings */ public boolean getPVPEnabled(PrimarySkillType skill) { - return config.getBoolean("Skills." + StringUtils.getCapitalized(skill.toString()) + ".Enabled_For_PVP", true); + 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); + return config.getBoolean( + "Skills." + StringUtils.getCapitalized(skill.toString()) + ".Enabled_For_PVE", + true); } //public float getMasterVolume() { return (float) config.getDouble("Sounds.MasterVolume", 1.0); } @@ -951,23 +995,30 @@ public class GeneralConfig extends BukkitConfig { } public boolean shouldLevelUpBroadcastToConsole() { - return config.getBoolean("General.Level_Up_Chat_Broadcasts.Broadcast_Targets.Send_To_Console", true); + 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); + 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); + 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); + 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); + return config.getInt( + "General.Level_Up_Chat_Broadcasts.Broadcast_Targets.Distance_Restrictions.Restricted_Radius", + 100); } public int getLevelUpBroadcastInterval() { @@ -975,38 +1026,56 @@ public class GeneralConfig extends BukkitConfig { } public boolean shouldPowerLevelUpBroadcasts() { - return config.getBoolean("General.Level_Up_Chat_Broadcasts.Broadcast_Powerlevels.Enabled", true); + 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); + 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); + 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); + 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); + 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); + 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); + return config.getInt( + "General.Level_Up_Chat_Broadcasts.Broadcast_Powerlevels.Milestone_Interval", 100); } public boolean isGreenThumbReplantableCrop(@NotNull Material material) { - return config.getBoolean("Green_Thumb_Replanting_Crops." + StringUtils.getCapitalized(material.toString()), true); + return config.getBoolean( + "Green_Thumb_Replanting_Crops." + StringUtils.getCapitalized(material.toString()), + true); } public boolean useVerboseLogging() { return config.getBoolean("General.Verbose_Logging", false); } + + public boolean isMasterySystemEnabled() { + return config.getBoolean("General.PowerLevel.Skill_Mastery.Enabled"); + } } diff --git a/src/main/java/com/gmail/nossr50/config/HiddenConfig.java b/src/main/java/com/gmail/nossr50/config/HiddenConfig.java index 54cdf0ff0..9fbe00811 100644 --- a/src/main/java/com/gmail/nossr50/config/HiddenConfig.java +++ b/src/main/java/com/gmail/nossr50/config/HiddenConfig.java @@ -1,9 +1,8 @@ package com.gmail.nossr50.config; import com.gmail.nossr50.mcMMO; -import org.bukkit.configuration.file.YamlConfiguration; - import java.io.InputStreamReader; +import org.bukkit.configuration.file.YamlConfiguration; public class HiddenConfig { private static HiddenConfig instance; diff --git a/src/main/java/com/gmail/nossr50/config/LegacyConfigLoader.java b/src/main/java/com/gmail/nossr50/config/LegacyConfigLoader.java index 6a917b3fd..4bd380f96 100644 --- a/src/main/java/com/gmail/nossr50/config/LegacyConfigLoader.java +++ b/src/main/java/com/gmail/nossr50/config/LegacyConfigLoader.java @@ -2,33 +2,42 @@ package com.gmail.nossr50.config; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.LogUtils; -import org.bukkit.configuration.file.YamlConfiguration; -import org.jetbrains.annotations.NotNull; - import java.io.File; import java.util.List; +import org.bukkit.configuration.file.YamlConfiguration; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.VisibleForTesting; @Deprecated public abstract class LegacyConfigLoader { - protected final File configFile; + protected final @NotNull File configFile; protected final @NotNull File dataFolder; - protected String fileName; + protected @NotNull String fileName; protected YamlConfiguration config; - public LegacyConfigLoader(String relativePath, String fileName, @NotNull File dataFolder) { + public LegacyConfigLoader(@NotNull String relativePath, @NotNull String fileName, + @NotNull File dataFolder) { this.fileName = fileName; this.dataFolder = dataFolder; configFile = new File(dataFolder, relativePath + File.separator + fileName); loadFile(); } - public LegacyConfigLoader(String fileName, @NotNull File dataFolder) { + public LegacyConfigLoader(@NotNull String fileName, @NotNull File dataFolder) { this.fileName = fileName; this.dataFolder = dataFolder; configFile = new File(dataFolder, fileName); loadFile(); } + @VisibleForTesting + public LegacyConfigLoader(@NotNull File file) { + this.fileName = file.getName(); + this.dataFolder = file.getParentFile(); + configFile = new File(dataFolder, fileName); + loadFile(); + } + @Deprecated public LegacyConfigLoader(String relativePath, String fileName) { this.fileName = fileName; @@ -52,7 +61,9 @@ public abstract class LegacyConfigLoader { try { mcMMO.p.saveResource(fileName, false); // Normal files } catch (IllegalArgumentException ex) { - mcMMO.p.saveResource(configFile.getParentFile().getName() + File.separator + fileName, false); // Mod files + mcMMO.p.saveResource( + configFile.getParentFile().getName() + File.separator + fileName, + false); // Mod files } } else { LogUtils.debug(mcMMO.p.getLogger(), "Loading mcMMO " + fileName + " File..."); @@ -79,7 +90,8 @@ public abstract class LegacyConfigLoader { if (validateKeys()) { LogUtils.debug(mcMMO.p.getLogger(), "No errors found in " + fileName + "!"); } else { - mcMMO.p.getLogger().warning("Errors were found in " + fileName + "! mcMMO was disabled!"); + mcMMO.p.getLogger() + .warning("Errors were found in " + fileName + "! mcMMO was disabled!"); mcMMO.p.getServer().getPluginManager().disablePlugin(mcMMO.p); mcMMO.p.noErrorsInConfigFiles = false; } @@ -91,7 +103,9 @@ public abstract class LegacyConfigLoader { public void backup() { mcMMO.p.getLogger().warning("You are using an old version of the " + fileName + " file."); - mcMMO.p.getLogger().warning("Your old file has been renamed to " + fileName + ".old and has been replaced by an updated version."); + mcMMO.p.getLogger().warning( + "Your old file has been renamed to " + fileName + + ".old and has been replaced by an updated version."); configFile.renameTo(new File(configFile.getPath() + ".old")); diff --git a/src/main/java/com/gmail/nossr50/config/RankConfig.java b/src/main/java/com/gmail/nossr50/config/RankConfig.java index d892ecda4..f7a2e3000 100644 --- a/src/main/java/com/gmail/nossr50/config/RankConfig.java +++ b/src/main/java/com/gmail/nossr50/config/RankConfig.java @@ -4,11 +4,10 @@ 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.LogUtils; -import org.jetbrains.annotations.NotNull; - import java.util.ArrayList; import java.util.HashSet; import java.util.List; +import org.jetbrains.annotations.NotNull; public class RankConfig extends BukkitConfig { private static RankConfig instance; @@ -20,8 +19,9 @@ public class RankConfig extends BukkitConfig { } public static RankConfig getInstance() { - if (instance == null) + if (instance == null) { return new RankConfig(); + } return instance; } @@ -47,8 +47,7 @@ public class RankConfig extends BukkitConfig { * Returns the unlock level for a subskill depending on the gamemode * * @param subSkillType target subskill - * @param rank the rank we are checking - * + * @param rank the rank we are checking * @return the level requirement for a subskill at this particular rank */ public int getSubSkillUnlockLevel(SubSkillType subSkillType, int rank) { @@ -61,8 +60,7 @@ public class RankConfig extends BukkitConfig { * Returns the unlock level for a subskill depending on the gamemode * * @param subSkillType target subskill - * @param rank the rank we are checking - * + * @param rank the rank we are checking * @return the level requirement for a subskill at this particular rank */ public int getSubSkillUnlockLevel(SubSkillType subSkillType, int rank, boolean retroMode) { @@ -74,12 +72,12 @@ public class RankConfig extends BukkitConfig { * Returns the unlock level for a subskill depending on the gamemode * * @param abstractSubSkill target subskill - * @param rank the rank we are checking - * + * @param rank the rank we are checking * @return the level requirement for a subskill at this particular rank */ public int getSubSkillUnlockLevel(AbstractSubSkill abstractSubSkill, int rank) { - String key = abstractSubSkill.getPrimaryKeyName() + "." + abstractSubSkill.getConfigKeyName(); + String key = + abstractSubSkill.getPrimaryKeyName() + "." + abstractSubSkill.getConfigKeyName(); return findRankByRootAddress(rank, key); } @@ -87,13 +85,13 @@ public class RankConfig extends BukkitConfig { /** * Returns the unlock level for a subskill depending on the gamemode * - * @param key root address of the subskill in the rankskills.yml file + * @param key root address of the subskill in the rankskills.yml file * @param rank the rank we are checking - * * @return the level requirement for a subskill at this particular rank */ private int findRankByRootAddress(int rank, String key) { - String scalingKey = mcMMO.p.getGeneralConfig().getIsRetroMode() ? ".RetroMode." : ".Standard."; + String scalingKey = + mcMMO.p.getGeneralConfig().getIsRetroMode() ? ".RetroMode." : ".Standard."; String targetRank = "Rank_" + rank; @@ -145,18 +143,26 @@ public class RankConfig extends BukkitConfig { checkConfig(reasons, badSkillSetup, false); //Fix bad entries - if (badSkillSetup.isEmpty()) + if (badSkillSetup.isEmpty()) { return; + } - LogUtils.debug(mcMMO.p.getLogger(), "(FIXING CONFIG) mcMMO is correcting a few mistakes found in your skill rank config setup"); + LogUtils.debug( + mcMMO.p.getLogger(), + "(FIXING CONFIG) mcMMO is correcting a few mistakes found in your skill rank config setup"); for (SubSkillType subSkillType : badSkillSetup) { - LogUtils.debug(mcMMO.p.getLogger(), "(FIXING CONFIG) Resetting rank config settings for skill named - " + subSkillType.toString()); + LogUtils.debug( + mcMMO.p.getLogger(), + "(FIXING CONFIG) Resetting rank config settings for skill named - " + + subSkillType.toString()); fixBadEntries(subSkillType); } } - private void checkConfig(@NotNull List reasons, @NotNull HashSet badSkillSetup, boolean retroMode) { + private void checkConfig(@NotNull List reasons, + @NotNull HashSet badSkillSetup, + boolean retroMode) { for (SubSkillType subSkillType : SubSkillType.values()) { //Keeping track of the rank requirements and making sure there are no logical errors int curRank = 0; @@ -165,21 +171,27 @@ public class RankConfig extends BukkitConfig { for (int x = 0; x < subSkillType.getNumRanks(); x++) { int index = x + 1; - if (curRank > 0) + if (curRank > 0) { prevRank = curRank; + } curRank = getSubSkillUnlockLevel(subSkillType, index, retroMode); //Do we really care if its below 0? Probably not if (curRank < 0) { - reasons.add("(CONFIG ISSUE) " + subSkillType + " should not have any ranks that require a negative level!"); + reasons.add( + "(CONFIG ISSUE) " + subSkillType + + " should not have any ranks that require a negative level!"); badSkillSetup.add(subSkillType); continue; } if (prevRank > curRank) { //We're going to allow this but we're going to warn them - LogUtils.debug(mcMMO.p.getLogger(), "(CONFIG ISSUE) You have the ranks for the subskill " + subSkillType + " set up poorly, sequential ranks should have ascending requirements"); + LogUtils.debug( + mcMMO.p.getLogger(), + "(CONFIG ISSUE) You have the ranks for the subskill " + subSkillType + + " set up poorly, sequential ranks should have ascending requirements"); badSkillSetup.add(subSkillType); } } diff --git a/src/main/java/com/gmail/nossr50/config/SoundConfig.java b/src/main/java/com/gmail/nossr50/config/SoundConfig.java index 407b8ef1a..3ad71fa98 100644 --- a/src/main/java/com/gmail/nossr50/config/SoundConfig.java +++ b/src/main/java/com/gmail/nossr50/config/SoundConfig.java @@ -14,8 +14,9 @@ public class SoundConfig extends BukkitConfig { } public static SoundConfig getInstance() { - if (instance == null) + if (instance == null) { return new SoundConfig(); + } return instance; } @@ -29,14 +30,16 @@ public class SoundConfig extends BukkitConfig { protected boolean validateKeys() { for (SoundType soundType : SoundType.values()) { if (config.getDouble("Sounds." + soundType.toString() + ".Volume") < 0) { - LogUtils.debug(mcMMO.p.getLogger(), "[mcMMO] Sound volume cannot be below 0 for " + soundType); + LogUtils.debug(mcMMO.p.getLogger(), + "[mcMMO] Sound volume cannot be below 0 for " + soundType); return false; } //Sounds with custom pitching don't use pitch values if (!soundType.usesCustomPitch()) { if (config.getDouble("Sounds." + soundType + ".Pitch") < 0) { - LogUtils.debug(mcMMO.p.getLogger(), "[mcMMO] Sound pitch cannot be below 0 for " + soundType); + LogUtils.debug(mcMMO.p.getLogger(), + "[mcMMO] Sound pitch cannot be below 0 for " + soundType); return false; } } @@ -50,12 +53,12 @@ public class SoundConfig extends BukkitConfig { public float getVolume(SoundType soundType) { String key = "Sounds." + soundType.toString() + ".Volume"; - return (float) config.getDouble(key); + return (float) config.getDouble(key, 1.0); } public float getPitch(SoundType soundType) { String key = "Sounds." + soundType.toString() + ".Pitch"; - return (float) config.getDouble(key); + return (float) config.getDouble(key, 1.0); } public boolean getIsEnabled(SoundType soundType) { diff --git a/src/main/java/com/gmail/nossr50/config/WorldBlacklist.java b/src/main/java/com/gmail/nossr50/config/WorldBlacklist.java index 7b93ebd89..8899e6964 100644 --- a/src/main/java/com/gmail/nossr50/config/WorldBlacklist.java +++ b/src/main/java/com/gmail/nossr50/config/WorldBlacklist.java @@ -1,10 +1,13 @@ package com.gmail.nossr50.config; import com.gmail.nossr50.mcMMO; -import org.bukkit.World; - -import java.io.*; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.io.Reader; import java.util.ArrayList; +import org.bukkit.World; /** * Blacklist certain features in certain worlds @@ -24,8 +27,9 @@ public class WorldBlacklist { public static boolean isWorldBlacklisted(World world) { for (String s : blacklist) { - if (world.getName().equalsIgnoreCase(s)) + if (world.getName().equalsIgnoreCase(s)) { return true; + } } return false; @@ -36,8 +40,9 @@ public class WorldBlacklist { File blackListFile = new File(plugin.getDataFolder() + File.separator + blackListFileName); try { - if (!blackListFile.exists()) + if (!blackListFile.exists()) { blackListFile.createNewFile(); + } } catch (IOException e) { e.printStackTrace(); } @@ -57,11 +62,13 @@ public class WorldBlacklist { String currentLine; while ((currentLine = bufferedReader.readLine()) != null) { - if (currentLine.length() == 0) + if (currentLine.length() == 0) { continue; + } - if (!blacklist.contains(currentLine)) + if (!blacklist.contains(currentLine)) { blacklist.add(currentLine); + } } @@ -73,8 +80,9 @@ public class WorldBlacklist { closeRead(fileReader); } - if(blacklist.size() > 0) + if (blacklist.size() > 0) { plugin.getLogger().info(blacklist.size() + " entries in mcMMO World Blacklist"); + } } private void closeRead(Reader reader) { 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 cb350ad81..ed926d61d 100644 --- a/src/main/java/com/gmail/nossr50/config/experience/ExperienceConfig.java +++ b/src/main/java/com/gmail/nossr50/config/experience/ExperienceConfig.java @@ -1,11 +1,18 @@ package com.gmail.nossr50.config.experience; +import static com.gmail.nossr50.util.text.ConfigStringUtils.getConfigEntityTypeString; +import static com.gmail.nossr50.util.text.ConfigStringUtils.getMaterialConfigString; + import com.gmail.nossr50.config.BukkitConfig; import com.gmail.nossr50.datatypes.experience.FormulaType; import com.gmail.nossr50.datatypes.skills.MaterialType; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.alchemy.PotionStage; import com.gmail.nossr50.util.text.StringUtils; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.BlockState; @@ -14,11 +21,9 @@ import org.bukkit.boss.BarColor; import org.bukkit.boss.BarStyle; import org.bukkit.entity.EntityType; -import java.util.ArrayList; -import java.util.List; - public class ExperienceConfig extends BukkitConfig { private static ExperienceConfig instance; + final private Map> blockExperienceMap = new HashMap<>(); private ExperienceConfig() { super("experience.yml"); @@ -28,6 +33,18 @@ public class ExperienceConfig extends BukkitConfig { public static ExperienceConfig getInstance() { if (instance == null) { instance = new ExperienceConfig(); + for (PrimarySkillType skill : PrimarySkillType.values()) { + final Map experienceMap = new HashMap<>(); + instance.blockExperienceMap.put(skill, experienceMap); + for (Material material : Material.values()) { + int xp = instance.getConfigXp(skill, material); + + if (xp > 0) { + experienceMap.put(material, xp); + } + } + + } } return instance; @@ -47,7 +64,8 @@ public class ExperienceConfig extends BukkitConfig { /* Curve values */ if (getMultiplier(FormulaType.EXPONENTIAL) <= 0) { - reason.add("Experience_Formula.Exponential_Values.multiplier should be greater than 0!"); + reason.add( + "Experience_Formula.Exponential_Values.multiplier should be greater than 0!"); } if (getMultiplier(FormulaType.LINEAR) <= 0) { @@ -90,7 +108,9 @@ public class ExperienceConfig extends BukkitConfig { /* Alchemy */ for (PotionStage potionStage : PotionStage.values()) { if (getPotionXP(potionStage) < 0) { - reason.add("Experience_Values.Alchemy.Potion_Stage_" + potionStage.toNumerical() + " should be at least 0!"); + reason.add( + "Experience_Values.Alchemy.Potion_Stage_" + potionStage.toNumerical() + + " should be at least 0!"); } } @@ -177,6 +197,10 @@ public class ExperienceConfig extends BukkitConfig { return config.getBoolean("ExploitFix.PreventPluginNPCInteraction", true); } + public boolean isArmorStandInteractionPrevented() { + return config.getBoolean("ExploitFix.PreventArmorStandInteraction", true); + } + public boolean isFishingExploitingPrevented() { return config.getBoolean("ExploitFix.Fishing", true); } @@ -209,16 +233,21 @@ public class ExperienceConfig extends BukkitConfig { /* Curve values */ public double getMultiplier(FormulaType type) { double def = type == FormulaType.LINEAR ? 20D : 0.1D; - return config.getDouble("Experience_Formula." + StringUtils.getCapitalized(type.toString()) + "_Values.multiplier", def); + return config.getDouble( + "Experience_Formula." + StringUtils.getCapitalized(type.toString()) + + "_Values.multiplier", def); } public int getBase(FormulaType type) { int def = type == FormulaType.LINEAR ? 1020 : 2000; - return config.getInt("Experience_Formula." + StringUtils.getCapitalized(type.toString()) + "_Values.base", def); + return config.getInt("Experience_Formula." + StringUtils.getCapitalized(type.toString()) + + "_Values.base", def); } public double getExponent(FormulaType type) { - return config.getDouble("Experience_Formula." + StringUtils.getCapitalized(type.toString()) + "_Values.exponent"); + return config.getDouble( + "Experience_Formula." + StringUtils.getCapitalized(type.toString()) + + "_Values.exponent"); } /* Global modifier */ @@ -258,7 +287,10 @@ public class ExperienceConfig extends BukkitConfig { /* Skill modifiers */ public double getFormulaSkillModifier(PrimarySkillType skill) { - return config.getDouble("Experience_Formula.Modifier." + StringUtils.getCapitalized(skill.toString())); + return config.getDouble( + "Experience_Formula.Skill_Multiplier." + StringUtils.getCapitalized( + skill.toString()), + 1); } /* Custom XP perk */ @@ -276,7 +308,9 @@ public class ExperienceConfig extends BukkitConfig { } public int getDiminishedReturnsThreshold(PrimarySkillType skill) { - return config.getInt("Diminished_Returns.Threshold." + StringUtils.getCapitalized(skill.toString()), 20000); + return config.getInt( + "Diminished_Returns.Threshold." + StringUtils.getCapitalized(skill.toString()), + 20000); } public int getDiminishedReturnsTimeInterval() { @@ -298,12 +332,21 @@ public class ExperienceConfig extends BukkitConfig { } /* 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(" ", "_")); + return config.getDouble( + "Experience_Values.Combat.Multiplier." + getConfigEntityTypeString(entity).replace( + " ", "_")); } public double getAnimalsXP(EntityType entity) { - return config.getDouble("Experience_Values.Combat.Multiplier." + StringUtils.getPrettyEntityTypeString(entity).replace(" ", "_"), getAnimalsXP()); + return config.getDouble( + "Experience_Values.Combat.Multiplier." + getConfigEntityTypeString(entity).replace( + " ", "_"), + getAnimalsXP()); } public double getAnimalsXP() { @@ -311,99 +354,48 @@ public class ExperienceConfig extends BukkitConfig { } public boolean hasCombatXP(EntityType entity) { - return config.contains("Experience_Values.Combat.Multiplier." + StringUtils.getPrettyEntityTypeString(entity).replace(" ", "_")); + return config.contains( + "Experience_Values.Combat.Multiplier." + getConfigEntityTypeString(entity).replace( + " ", "_")); } /* 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")) + private int getConfigXp(PrimarySkillType skill, Material material) { + // prevents exploit + if (material == Material.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; + final String baseString = + "Experience_Values." + StringUtils.getCapitalized(skill.toString()) + "."; + final String configPath = baseString + getMaterialConfigString(material); + return config.getInt(configPath, 0); + } + + public int getXp(PrimarySkillType skill, Material material) { + return blockExperienceMap.get(skill).getOrDefault(material, 0); } - /* 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; + return getXp(skill, blockState.getType()); } - /* 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) { - 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); - return 0; + return getXp(skill, data.getMaterial()); } - 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 getXp(skill, material) > 0; } + @Deprecated(forRemoval = true, since = "2.2.024") public boolean doesBlockGiveSkillXP(PrimarySkillType skill, BlockData data) { - 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); + return getXp(skill, data) > 0; } /* @@ -419,12 +411,17 @@ public class ExperienceConfig extends BukkitConfig { } public boolean getDoExperienceBarsAlwaysUpdateTitle() { - return config.getBoolean("Experience_Bars.ThisMayCauseLag.AlwaysUpdateTitlesWhenXPIsGained.Enable", false) || getAddExtraDetails(); + return config.getBoolean( + "Experience_Bars.ThisMayCauseLag.AlwaysUpdateTitlesWhenXPIsGained.Enable", + false) || getAddExtraDetails(); } public boolean getAddExtraDetails() { - return config.getBoolean("Experience_Bars.ThisMayCauseLag.AlwaysUpdateTitlesWhenXPIsGained.ExtraDetails", false); + return config.getBoolean( + "Experience_Bars.ThisMayCauseLag.AlwaysUpdateTitlesWhenXPIsGained.ExtraDetails", + false); } + public boolean useCombatHPCeiling() { return config.getBoolean("ExploitFix.Combat.XPCeiling.Enabled", true); } @@ -438,15 +435,20 @@ public class ExperienceConfig extends BukkitConfig { } public boolean isExperienceBarEnabled(PrimarySkillType primarySkillType) { - return config.getBoolean("Experience_Bars." + StringUtils.getCapitalized(primarySkillType.toString()) + ".Enable", true); + return config.getBoolean( + "Experience_Bars." + StringUtils.getCapitalized(primarySkillType.toString()) + + ".Enable", true); } public BarColor getExperienceBarColor(PrimarySkillType primarySkillType) { - String colorValueFromConfig = config.getString("Experience_Bars." + StringUtils.getCapitalized(primarySkillType.toString()) + ".Color"); + String colorValueFromConfig = config.getString( + "Experience_Bars." + StringUtils.getCapitalized(primarySkillType.toString()) + + ".Color"); for (BarColor barColor : BarColor.values()) { - if (barColor.toString().equalsIgnoreCase(colorValueFromConfig)) + if (barColor.toString().equalsIgnoreCase(colorValueFromConfig)) { return barColor; + } } //In case the value is invalid @@ -454,11 +456,14 @@ public class ExperienceConfig extends BukkitConfig { } public BarStyle getExperienceBarStyle(PrimarySkillType primarySkillType) { - String colorValueFromConfig = config.getString("Experience_Bars." + StringUtils.getCapitalized(primarySkillType.toString()) + ".BarStyle"); + String colorValueFromConfig = config.getString( + "Experience_Bars." + StringUtils.getCapitalized(primarySkillType.toString()) + + ".BarStyle"); for (BarStyle barStyle : BarStyle.values()) { - if (barStyle.toString().equalsIgnoreCase(colorValueFromConfig)) + if (barStyle.toString().equalsIgnoreCase(colorValueFromConfig)) { return barStyle; + } } //In case the value is invalid @@ -484,7 +489,8 @@ public class ExperienceConfig extends BukkitConfig { /* Alchemy */ public double getPotionXP(PotionStage stage) { - return config.getDouble("Experience_Values.Alchemy.Potion_Stage_" + stage.toNumerical(), 10D); + return config.getDouble( + "Experience_Values.Alchemy.Potion_Brewing.Stage_" + stage.toNumerical(), 10D); } /* Archery */ @@ -502,15 +508,22 @@ public class ExperienceConfig extends BukkitConfig { } public double getRepairXP(MaterialType repairMaterialType) { - return config.getDouble("Experience_Values.Repair." + StringUtils.getCapitalized(repairMaterialType.toString())); + return config.getDouble( + "Experience_Values.Repair." + StringUtils.getCapitalized( + repairMaterialType.toString())); } /* Taming */ public int getTamingXP(EntityType type) { - return config.getInt("Experience_Values.Taming.Animal_Taming." + StringUtils.getPrettyEntityTypeString(type)); + return config.getInt( + "Experience_Values.Taming.Animal_Taming." + getConfigEntityTypeString(type)); } public boolean preventStoneLavaFarming() { return config.getBoolean("ExploitFix.LavaStoneAndCobbleFarming", true); } + + public boolean limitXPOnTallPlants() { + return config.getBoolean("ExploitFix.LimitTallPlantFarming", true); + } } diff --git a/src/main/java/com/gmail/nossr50/config/mods/ArmorConfigManager.java b/src/main/java/com/gmail/nossr50/config/mods/ArmorConfigManager.java deleted file mode 100644 index 66d220d9a..000000000 --- a/src/main/java/com/gmail/nossr50/config/mods/ArmorConfigManager.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.gmail.nossr50.config.mods; - -import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.util.ModManager; - -import java.io.File; -import java.util.regex.Pattern; - -public class ArmorConfigManager { - public ArmorConfigManager(mcMMO plugin) { - Pattern middlePattern = Pattern.compile("armor\\.(?:.+)\\.yml"); - Pattern startPattern = Pattern.compile("(?:.+)\\.armor\\.yml"); - File dataFolder = new File(mcMMO.getModDirectory()); - File vanilla = new File(dataFolder, "armor.default.yml"); - ModManager modManager = mcMMO.getModManager(); - - if (!vanilla.exists()) { - plugin.saveResource(vanilla.getParentFile().getName() + File.separator + "armor.default.yml", false); - } - - for (String fileName : dataFolder.list()) { - if (!middlePattern.matcher(fileName).matches() && !startPattern.matcher(fileName).matches()) { - continue; - } - - File file = new File(dataFolder, fileName); - - if (file.isDirectory()) { - continue; - } - - modManager.registerCustomArmor(new CustomArmorLegacyConfig(fileName)); - } - } -} diff --git a/src/main/java/com/gmail/nossr50/config/mods/BlockConfigManager.java b/src/main/java/com/gmail/nossr50/config/mods/BlockConfigManager.java deleted file mode 100644 index c6df0a1a0..000000000 --- a/src/main/java/com/gmail/nossr50/config/mods/BlockConfigManager.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.gmail.nossr50.config.mods; - -import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.util.ModManager; - -import java.io.File; -import java.util.regex.Pattern; - -public class BlockConfigManager { - public BlockConfigManager(mcMMO plugin) { - Pattern middlePattern = Pattern.compile("blocks\\.(?:.+)\\.yml"); - Pattern startPattern = Pattern.compile("(?:.+)\\.blocks\\.yml"); - File dataFolder = new File(mcMMO.getModDirectory()); - File vanilla = new File(dataFolder, "blocks.default.yml"); - ModManager modManager = mcMMO.getModManager(); - - if (!vanilla.exists()) { - plugin.saveResource(vanilla.getParentFile().getName() + File.separator + "blocks.default.yml", false); - } - - for (String fileName : dataFolder.list()) { - if (!middlePattern.matcher(fileName).matches() && !startPattern.matcher(fileName).matches()) { - continue; - } - - File file = new File(dataFolder, fileName); - - if (file.isDirectory()) { - continue; - } - - modManager.registerCustomBlocks(new CustomBlockLegacyConfig(fileName)); - } - } -} diff --git a/src/main/java/com/gmail/nossr50/config/mods/CustomArmorLegacyConfig.java b/src/main/java/com/gmail/nossr50/config/mods/CustomArmorLegacyConfig.java deleted file mode 100644 index 1369d3026..000000000 --- a/src/main/java/com/gmail/nossr50/config/mods/CustomArmorLegacyConfig.java +++ /dev/null @@ -1,93 +0,0 @@ -package com.gmail.nossr50.config.mods; - -import com.gmail.nossr50.config.LegacyConfigLoader; -import com.gmail.nossr50.datatypes.skills.ItemType; -import com.gmail.nossr50.datatypes.skills.MaterialType; -import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.skills.repair.repairables.Repairable; -import com.gmail.nossr50.skills.repair.repairables.RepairableFactory; -import org.bukkit.Material; -import org.bukkit.configuration.ConfigurationSection; - -import java.util.ArrayList; -import java.util.List; -import java.util.Set; - -public class CustomArmorLegacyConfig extends LegacyConfigLoader { - public List customBoots = new ArrayList<>(); - public List customChestplates = new ArrayList<>(); - public List customHelmets = new ArrayList<>(); - public List customLeggings = new ArrayList<>(); - public List repairables = new ArrayList<>(); - private boolean needsUpdate = false; - - protected CustomArmorLegacyConfig(String fileName) { - super("mods", fileName); - loadKeys(); - } - - @Override - protected void loadKeys() { - loadArmor("Boots", customBoots); - loadArmor("Chestplates", customChestplates); - loadArmor("Helmets", customHelmets); - loadArmor("Leggings", customLeggings); - - if (needsUpdate) { - needsUpdate = false; - backup(); - } - } - - private void loadArmor(String armorType, List materialList) { - if (needsUpdate) { - return; - } - - ConfigurationSection armorSection = config.getConfigurationSection(armorType); - - if (armorSection == null) { - return; - } - - Set armorConfigSet = armorSection.getKeys(false); - - for (String armorName : armorConfigSet) { - if (config.contains(armorType + "." + armorName + "." + ".ID")) { - needsUpdate = true; - return; - } - - Material armorMaterial = Material.matchMaterial(armorName); - - if (armorMaterial == null) { - mcMMO.p.getLogger().warning("Invalid material name. This item will be skipped. - " + armorName); - continue; - } - - boolean repairable = config.getBoolean(armorType + "." + armorName + ".Repairable"); - Material repairMaterial = Material.matchMaterial(config.getString(armorType + "." + armorName + ".Repair_Material", "")); - - if (repairable && (repairMaterial == null)) { - mcMMO.p.getLogger().warning("Incomplete repair information. This item will be unrepairable. - " + armorName); - repairable = false; - } - - if (repairable) { - String repairItemName = config.getString(armorType + "." + armorName + ".Repair_Material_Pretty_Name"); - int repairMinimumLevel = config.getInt(armorType + "." + armorName + ".Repair_MinimumLevel", 0); - double repairXpMultiplier = config.getDouble(armorType + "." + armorName + ".Repair_XpMultiplier", 1); - - short durability = armorMaterial.getMaxDurability(); - - if (durability == 0) { - durability = (short) config.getInt(armorType + "." + armorName + ".Durability", 70); - } - - repairables.add(RepairableFactory.getRepairable(armorMaterial, repairMaterial, repairItemName, repairMinimumLevel, durability, ItemType.ARMOR, MaterialType.OTHER, repairXpMultiplier)); - } - - materialList.add(armorMaterial); - } - } -} diff --git a/src/main/java/com/gmail/nossr50/config/mods/CustomBlockLegacyConfig.java b/src/main/java/com/gmail/nossr50/config/mods/CustomBlockLegacyConfig.java deleted file mode 100644 index 4be1ef44a..000000000 --- a/src/main/java/com/gmail/nossr50/config/mods/CustomBlockLegacyConfig.java +++ /dev/null @@ -1,98 +0,0 @@ -package com.gmail.nossr50.config.mods; - -import com.gmail.nossr50.config.LegacyConfigLoader; -import com.gmail.nossr50.datatypes.mods.CustomBlock; -import com.gmail.nossr50.mcMMO; -import org.bukkit.Material; -import org.bukkit.configuration.ConfigurationSection; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Set; - -public class CustomBlockLegacyConfig extends LegacyConfigLoader { - public List customExcavationBlocks = new ArrayList<>(); - public List customHerbalismBlocks = new ArrayList<>(); - public List customMiningBlocks = new ArrayList<>(); - public List customOres = new ArrayList<>(); - public List customLogs = new ArrayList<>(); - public List customLeaves = new ArrayList<>(); - public List customAbilityBlocks = new ArrayList<>(); - public HashMap customBlockMap = new HashMap<>(); - private boolean needsUpdate = false; - - protected CustomBlockLegacyConfig(String fileName) { - super("mods", fileName); - loadKeys(); - } - - @Override - protected void loadKeys() { - loadBlocks("Excavation", customExcavationBlocks); - loadBlocks("Herbalism", customHerbalismBlocks); - loadBlocks("Mining", customMiningBlocks); - loadBlocks("Woodcutting", null); - loadBlocks("Ability_Blocks", customAbilityBlocks); - - if (needsUpdate) { - needsUpdate = false; - backup(); - } - } - - private void loadBlocks(String skillType, List blockList) { - if (needsUpdate) { - return; - } - - ConfigurationSection skillSection = config.getConfigurationSection(skillType); - - if (skillSection == null) { - return; - } - - Set skillConfigSet = skillSection.getKeys(false); - - for (String blockName : skillConfigSet) { - if (config.contains(skillType + "." + blockName + ".Drop_Item")) { - needsUpdate = true; - return; - } - - String[] blockInfo = blockName.split("[|]"); - - Material blockMaterial = Material.matchMaterial(blockInfo[0]); - - if (blockMaterial == null) { - mcMMO.p.getLogger().warning("Invalid material name. This item will be skipped. - " + blockInfo[0]); - continue; - } - - if (blockList != null) { - blockList.add(blockMaterial); - } - - if (skillType.equals("Ability_Blocks")) { - continue; - } - - int xp = config.getInt(skillType + "." + blockName + ".XP_Gain"); - int smeltingXp = 0; - - if (skillType.equals("Mining") && config.getBoolean(skillType + "." + blockName + ".Is_Ore")) { - customOres.add(blockMaterial); - smeltingXp = config.getInt(skillType + "." + blockName + ".Smelting_XP_Gain", xp / 10); - } else if (skillType.equals("Woodcutting")) { - if (config.getBoolean(skillType + "." + blockName + ".Is_Log")) { - customLogs.add(blockMaterial); - } else { - customLeaves.add(blockMaterial); - xp = 0; // Leaves don't grant XP - } - } - - customBlockMap.put(blockMaterial, new CustomBlock(xp, config.getBoolean(skillType + "." + blockName + ".Double_Drops_Enabled"), smeltingXp)); - } - } -} diff --git a/src/main/java/com/gmail/nossr50/config/mods/CustomEntityLegacyConfig.java b/src/main/java/com/gmail/nossr50/config/mods/CustomEntityLegacyConfig.java deleted file mode 100644 index 37244835c..000000000 --- a/src/main/java/com/gmail/nossr50/config/mods/CustomEntityLegacyConfig.java +++ /dev/null @@ -1,61 +0,0 @@ -package com.gmail.nossr50.config.mods; - -import com.gmail.nossr50.config.LegacyConfigLoader; -import com.gmail.nossr50.datatypes.mods.CustomEntity; -import com.gmail.nossr50.mcMMO; -import org.apache.commons.lang.ClassUtils; -import org.bukkit.Material; -import org.bukkit.inventory.ItemStack; - -import java.util.HashMap; - -public class CustomEntityLegacyConfig extends LegacyConfigLoader { - public HashMap customEntityClassMap = new HashMap<>(); - public HashMap customEntityTypeMap = new HashMap<>(); - - protected CustomEntityLegacyConfig(String fileName) { - super("mods", fileName); - loadKeys(); - } - - @Override - protected void loadKeys() { - if (config.getConfigurationSection("Hostile") != null) { - backup(); - return; - } - - for (String entityName : config.getKeys(false)) { - Class clazz = null; - String className = config.getString(entityName + ".Class", ""); - - try { - clazz = ClassUtils.getClass(className); - } catch (ClassNotFoundException e) { - mcMMO.p.getLogger().warning("Invalid class (" + className + ") detected for " + entityName + "."); - mcMMO.p.getLogger().warning("This custom entity may not function properly."); - } - - String entityTypeName = entityName.replace("_", "."); - double xpMultiplier = config.getDouble(entityName + ".XP_Multiplier", 1.0D); - - boolean canBeTamed = config.getBoolean(entityName + ".Tameable"); - int tamingXp = config.getInt(entityName + ".Taming_XP"); - - boolean canBeSummoned = config.getBoolean(entityName + ".CanBeSummoned"); - Material callOfTheWildMaterial = Material.matchMaterial(config.getString(entityName + ".COTW_Material", "")); - byte callOfTheWildData = (byte) config.getInt(entityName + ".COTW_Material_Data"); - int callOfTheWildAmount = config.getInt(entityName + ".COTW_Material_Amount"); - - if (canBeSummoned && (callOfTheWildMaterial == null || callOfTheWildAmount == 0)) { - mcMMO.p.getLogger().warning("Incomplete Call of the Wild information. This entity will not be able to be summoned by Call of the Wild."); - canBeSummoned = false; - } - - CustomEntity entity = new CustomEntity(xpMultiplier, canBeTamed, tamingXp, canBeSummoned, (canBeSummoned ? new ItemStack(callOfTheWildMaterial) : null), callOfTheWildAmount); - - customEntityTypeMap.put(entityTypeName, entity); - customEntityClassMap.put(clazz == null ? null : clazz.getName(), entity); - } - } -} diff --git a/src/main/java/com/gmail/nossr50/config/mods/CustomToolLegacyConfig.java b/src/main/java/com/gmail/nossr50/config/mods/CustomToolLegacyConfig.java deleted file mode 100644 index ab6630cc7..000000000 --- a/src/main/java/com/gmail/nossr50/config/mods/CustomToolLegacyConfig.java +++ /dev/null @@ -1,107 +0,0 @@ -package com.gmail.nossr50.config.mods; - -import com.gmail.nossr50.config.LegacyConfigLoader; -import com.gmail.nossr50.datatypes.mods.CustomTool; -import com.gmail.nossr50.datatypes.skills.ItemType; -import com.gmail.nossr50.datatypes.skills.MaterialType; -import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.skills.repair.repairables.Repairable; -import com.gmail.nossr50.skills.repair.repairables.RepairableFactory; -import org.bukkit.Material; -import org.bukkit.configuration.ConfigurationSection; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Set; - -public class CustomToolLegacyConfig extends LegacyConfigLoader { - public List customAxes = new ArrayList<>(); - public List customBows = new ArrayList<>(); - public List customHoes = new ArrayList<>(); - public List customPickaxes = new ArrayList<>(); - public List customShovels = new ArrayList<>(); - public List customSwords = new ArrayList<>(); - public HashMap customToolMap = new HashMap<>(); - public List repairables = new ArrayList<>(); - private boolean needsUpdate = false; - - protected CustomToolLegacyConfig(String fileName) { - super("mods", fileName); - loadKeys(); - } - - @Override - protected void loadKeys() { - loadTool("Axes", customAxes); - loadTool("Bows", customBows); - loadTool("Hoes", customHoes); - loadTool("Pickaxes", customPickaxes); - loadTool("Shovels", customShovels); - loadTool("Swords", customSwords); - - if (needsUpdate) { - needsUpdate = false; - backup(); - } - } - - private void loadTool(String toolType, List materialList) { - if (needsUpdate) { - return; - } - - ConfigurationSection toolSection = config.getConfigurationSection(toolType); - - if (toolSection == null) { - return; - } - - Set toolConfigSet = toolSection.getKeys(false); - - for (String toolName : toolConfigSet) { - if (config.contains(toolType + "." + toolName + "." + ".ID")) { - needsUpdate = true; - return; - } - - Material toolMaterial = Material.matchMaterial(toolName); - - if (toolMaterial == null) { - mcMMO.p.getLogger().warning("Invalid material name. This item will be skipped. - " + toolName); - continue; - } - - boolean repairable = config.getBoolean(toolType + "." + toolName + ".Repairable"); - Material repairMaterial = Material.matchMaterial(config.getString(toolType + "." + toolName + ".Repair_Material", "")); - - if (repairable && (repairMaterial == null)) { - mcMMO.p.getLogger().warning("Incomplete repair information. This item will be unrepairable. - " + toolName); - repairable = false; - } - - if (repairable) { - String repairItemName = config.getString(toolType + "." + toolName + ".Repair_Material_Pretty_Name"); - int repairMinimumLevel = config.getInt(toolType + "." + toolName + ".Repair_MinimumLevel", 0); - double repairXpMultiplier = config.getDouble(toolType + "." + toolName + ".Repair_XpMultiplier", 1); - - short durability = toolMaterial.getMaxDurability(); - - if (durability == 0) { - durability = (short) config.getInt(toolType + "." + toolName + ".Durability", 60); - } - - repairables.add(RepairableFactory.getRepairable(toolMaterial, repairMaterial, repairItemName, repairMinimumLevel, durability, ItemType.TOOL, MaterialType.OTHER, repairXpMultiplier)); - } - - double multiplier = config.getDouble(toolType + "." + toolName + ".XP_Modifier", 1.0); - boolean abilityEnabled = config.getBoolean(toolType + "." + toolName + ".Ability_Enabled", true); - int tier = config.getInt(toolType + "." + toolName + ".Tier", 1); - - CustomTool tool = new CustomTool(tier, abilityEnabled, multiplier); - - materialList.add(toolMaterial); - customToolMap.put(toolMaterial, tool); - } - } -} diff --git a/src/main/java/com/gmail/nossr50/config/mods/EntityConfigManager.java b/src/main/java/com/gmail/nossr50/config/mods/EntityConfigManager.java deleted file mode 100644 index 85977bc67..000000000 --- a/src/main/java/com/gmail/nossr50/config/mods/EntityConfigManager.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.gmail.nossr50.config.mods; - -import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.util.ModManager; - -import java.io.File; -import java.util.regex.Pattern; - -public class EntityConfigManager { - public EntityConfigManager(mcMMO plugin) { - Pattern middlePattern = Pattern.compile("entities\\.(?:.+)\\.yml"); - Pattern startPattern = Pattern.compile("(?:.+)\\.entities\\.yml"); - File dataFolder = new File(mcMMO.getModDirectory()); - File vanilla = new File(dataFolder, "entities.default.yml"); - ModManager modManager = mcMMO.getModManager(); - - if (!vanilla.exists()) { - plugin.saveResource(vanilla.getParentFile().getName() + File.separator + "entities.default.yml", false); - } - - for (String fileName : dataFolder.list()) { - if (!middlePattern.matcher(fileName).matches() && !startPattern.matcher(fileName).matches()) { - continue; - } - - File file = new File(dataFolder, fileName); - - if (file.isDirectory()) { - continue; - } - - modManager.registerCustomEntities(new CustomEntityLegacyConfig(fileName)); - } - } -} diff --git a/src/main/java/com/gmail/nossr50/config/mods/ToolConfigManager.java b/src/main/java/com/gmail/nossr50/config/mods/ToolConfigManager.java deleted file mode 100644 index 9b0ac1b87..000000000 --- a/src/main/java/com/gmail/nossr50/config/mods/ToolConfigManager.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.gmail.nossr50.config.mods; - -import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.util.ModManager; - -import java.io.File; -import java.util.regex.Pattern; - -public class ToolConfigManager { - public ToolConfigManager(mcMMO plugin) { - Pattern middlePattern = Pattern.compile("tools\\.(?:.+)\\.yml"); - Pattern startPattern = Pattern.compile("(?:.+)\\.tools\\.yml"); - File dataFolder = new File(mcMMO.getModDirectory()); - File vanilla = new File(dataFolder, "tools.default.yml"); - ModManager modManager = mcMMO.getModManager(); - - if (!vanilla.exists()) { - plugin.saveResource(vanilla.getParentFile().getName() + File.separator + "tools.default.yml", false); - } - - for (String fileName : dataFolder.list()) { - if (!middlePattern.matcher(fileName).matches() && !startPattern.matcher(fileName).matches()) { - continue; - } - - File file = new File(dataFolder, fileName); - - if (file.isDirectory()) { - continue; - } - - modManager.registerCustomTools(new CustomToolLegacyConfig(fileName)); - } - } -} diff --git a/src/main/java/com/gmail/nossr50/config/party/ItemWeightConfig.java b/src/main/java/com/gmail/nossr50/config/party/ItemWeightConfig.java index f36a9d24b..ad5b183f9 100644 --- a/src/main/java/com/gmail/nossr50/config/party/ItemWeightConfig.java +++ b/src/main/java/com/gmail/nossr50/config/party/ItemWeightConfig.java @@ -1,11 +1,11 @@ package com.gmail.nossr50.config.party; -import com.gmail.nossr50.config.BukkitConfig; -import com.gmail.nossr50.util.text.StringUtils; -import org.bukkit.Material; +import static com.gmail.nossr50.util.text.ConfigStringUtils.getMaterialConfigString; +import com.gmail.nossr50.config.BukkitConfig; import java.util.HashSet; import java.util.Locale; +import org.bukkit.Material; public class ItemWeightConfig extends BukkitConfig { private static ItemWeightConfig instance; @@ -23,7 +23,9 @@ public class ItemWeightConfig extends BukkitConfig { } public int getItemWeight(Material material) { - return config.getInt("Item_Weights." + StringUtils.getPrettyItemString(material).replace(" ", "_"), config.getInt("Item_Weights.Default")); + return config.getInt( + "Item_Weights." + getMaterialConfigString(material).replace(" ", "_"), + config.getInt("Item_Weights.Default")); } public HashSet getMiscItems() { diff --git a/src/main/java/com/gmail/nossr50/config/party/PartyConfig.java b/src/main/java/com/gmail/nossr50/config/party/PartyConfig.java new file mode 100644 index 000000000..3d10851e2 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/config/party/PartyConfig.java @@ -0,0 +1,20 @@ +package com.gmail.nossr50.config.party; + +import com.gmail.nossr50.config.BukkitConfig; +import java.io.File; + +public class PartyConfig extends BukkitConfig { + public PartyConfig(File dataFolder) { + super("party.yml", dataFolder); + validate(); + } + + @Override + protected void loadKeys() { + + } + + public boolean isPartyEnabled() { + return config.getBoolean("Party.Enabled", true); + } +} diff --git a/src/main/java/com/gmail/nossr50/config/skills/alchemy/PotionConfig.java b/src/main/java/com/gmail/nossr50/config/skills/alchemy/PotionConfig.java index 3b21589c6..2f03d2623 100644 --- a/src/main/java/com/gmail/nossr50/config/skills/alchemy/PotionConfig.java +++ b/src/main/java/com/gmail/nossr50/config/skills/alchemy/PotionConfig.java @@ -1,23 +1,42 @@ package com.gmail.nossr50.config.skills.alchemy; +import static com.gmail.nossr50.util.ItemUtils.setItemName; +import static com.gmail.nossr50.util.PotionUtil.matchPotionType; +import static com.gmail.nossr50.util.PotionUtil.setBasePotionType; +import static com.gmail.nossr50.util.PotionUtil.setUpgradedAndExtendedProperties; + import com.gmail.nossr50.config.LegacyConfigLoader; import com.gmail.nossr50.datatypes.skills.alchemy.AlchemyPotion; import com.gmail.nossr50.mcMMO; +import com.gmail.nossr50.util.ItemUtils; import com.gmail.nossr50.util.LogUtils; +import java.io.File; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import org.bukkit.ChatColor; import org.bukkit.Color; import org.bukkit.Material; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.inventory.ItemStack; -import org.bukkit.potion.*; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.inventory.meta.PotionMeta; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; +import org.bukkit.potion.PotionType; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.VisibleForTesting; public class PotionConfig extends LegacyConfigLoader { - private static PotionConfig instance; + private static final String BREEZE_ROD_STR = "BREEZE_ROD"; + private static final String INFESTED_EFFECT_STR = "INFESTED"; + private static final String WEAVING_EFFECT_STR = "WEAVING"; + private static final String OOZING_EFFECT_STR = "OOZING"; + private static final String WIND_CHARGED_EFFECT_STR = "WIND_CHARGED"; + private static final String SLIME_BLOCK_STR = "SLIME_BLOCK"; + private static final String COBWEB_STR = "COBWEB"; + private static final String STONE_STR = "STONE"; private final List concoctionsIngredientsTierOne = new ArrayList<>(); private final List concoctionsIngredientsTierTwo = new ArrayList<>(); @@ -27,39 +46,68 @@ public class PotionConfig extends LegacyConfigLoader { private final List concoctionsIngredientsTierSix = new ArrayList<>(); private final List concoctionsIngredientsTierSeven = new ArrayList<>(); private final List concoctionsIngredientsTierEight = new ArrayList<>(); + private final AlchemyPotionConfigResult INCOMPATIBLE_POTION_RESULT = new AlchemyPotionConfigResult( + null, + AlchemyPotionConfigResultType.INCOMPATIBLE); + private final AlchemyPotionConfigResult ERROR_POTION_RESULT = new AlchemyPotionConfigResult( + null, + AlchemyPotionConfigResultType.ERROR); - private final Map potionMap = new HashMap<>(); - - private PotionConfig() { - super("potions.yml"); - loadKeys(); + record AlchemyPotionConfigResult(AlchemyPotion alchemyPotion, + AlchemyPotionConfigResultType resultType) { } - public static PotionConfig getInstance() { - if (instance == null) { - instance = new PotionConfig(); - } + enum AlchemyPotionConfigResultType { + LOADED, + INCOMPATIBLE, + ERROR + } - return instance; + /** + * Map of potion names to AlchemyPotion objects. + */ + private final Map alchemyPotions = new HashMap<>(); + + public PotionConfig() { + super("potions.yml"); + } + + @VisibleForTesting + PotionConfig(File file) { + super(file); } @Override protected void loadKeys() { + } + + public void loadPotions() { loadConcoctions(); loadPotionMap(); } - private void loadConcoctions() { - ConfigurationSection concoctionSection = config.getConfigurationSection("Concoctions"); + @VisibleForTesting + void loadConcoctions() { + final ConfigurationSection concoctionSection = config.getConfigurationSection( + "Concoctions"); - loadConcoctionsTier(concoctionsIngredientsTierOne, concoctionSection.getStringList("Tier_One_Ingredients")); - loadConcoctionsTier(concoctionsIngredientsTierTwo, concoctionSection.getStringList("Tier_Two_Ingredients")); - loadConcoctionsTier(concoctionsIngredientsTierThree, concoctionSection.getStringList("Tier_Three_Ingredients")); - loadConcoctionsTier(concoctionsIngredientsTierFour, concoctionSection.getStringList("Tier_Four_Ingredients")); - loadConcoctionsTier(concoctionsIngredientsTierFive, concoctionSection.getStringList("Tier_Five_Ingredients")); - loadConcoctionsTier(concoctionsIngredientsTierSix, concoctionSection.getStringList("Tier_Six_Ingredients")); - loadConcoctionsTier(concoctionsIngredientsTierSeven, concoctionSection.getStringList("Tier_Seven_Ingredients")); - loadConcoctionsTier(concoctionsIngredientsTierEight, concoctionSection.getStringList("Tier_Eight_Ingredients")); + // Load the ingredients for each tier + loadConcoctionsTier(concoctionsIngredientsTierOne, + concoctionSection.getStringList("Tier_One_Ingredients")); + loadConcoctionsTier(concoctionsIngredientsTierTwo, + concoctionSection.getStringList("Tier_Two_Ingredients")); + loadConcoctionsTier(concoctionsIngredientsTierThree, + concoctionSection.getStringList("Tier_Three_Ingredients")); + loadConcoctionsTier(concoctionsIngredientsTierFour, + concoctionSection.getStringList("Tier_Four_Ingredients")); + loadConcoctionsTier(concoctionsIngredientsTierFive, + concoctionSection.getStringList("Tier_Five_Ingredients")); + loadConcoctionsTier(concoctionsIngredientsTierSix, + concoctionSection.getStringList("Tier_Six_Ingredients")); + loadConcoctionsTier(concoctionsIngredientsTierSeven, + concoctionSection.getStringList("Tier_Seven_Ingredients")); + loadConcoctionsTier(concoctionsIngredientsTierEight, + concoctionSection.getStringList("Tier_Eight_Ingredients")); concoctionsIngredientsTierTwo.addAll(concoctionsIngredientsTierOne); concoctionsIngredientsTierThree.addAll(concoctionsIngredientsTierTwo); @@ -70,8 +118,9 @@ public class PotionConfig extends LegacyConfigLoader { concoctionsIngredientsTierEight.addAll(concoctionsIngredientsTierSeven); } - private void loadConcoctionsTier(List ingredientList, List ingredientStrings) { - if (ingredientStrings != null && ingredientStrings.size() > 0) { + private void loadConcoctionsTier(List ingredientList, + List ingredientStrings) { + if (ingredientStrings != null && !ingredientStrings.isEmpty()) { for (String ingredientString : ingredientStrings) { ItemStack ingredient = loadIngredient(ingredientString); @@ -85,78 +134,149 @@ public class PotionConfig extends LegacyConfigLoader { /** * Find the Potions configuration section and load all defined potions. */ - private void loadPotionMap() { + int loadPotionMap() { ConfigurationSection potionSection = config.getConfigurationSection("Potions"); - int pass = 0; - int fail = 0; + int potionsLoaded = 0; + int incompatible = 0; + int failures = 0; for (String potionName : potionSection.getKeys(false)) { - AlchemyPotion potion = loadPotion(potionSection.getConfigurationSection(potionName)); + AlchemyPotionConfigResult alchemyPotionConfigResult = loadPotion( + potionSection.getConfigurationSection(potionName)); + AlchemyPotion potion = alchemyPotionConfigResult.alchemyPotion; if (potion != null) { - potionMap.put(potionName, potion); - pass++; + alchemyPotions.put(potionName, potion); + potionsLoaded++; } else { - fail++; + if (alchemyPotionConfigResult.resultType + == AlchemyPotionConfigResultType.INCOMPATIBLE) { + incompatible++; + } else { + failures++; + } } } - LogUtils.debug(mcMMO.p.getLogger(), "Loaded " + pass + " Alchemy potions, skipped " + fail + "."); + int totalPotions = potionsLoaded + incompatible + failures; + + mcMMO.p.getLogger() + .info("Loaded " + potionsLoaded + " of " + totalPotions + " Alchemy potions."); + + if (incompatible > 0) { + mcMMO.p.getLogger().info( + "Skipped " + incompatible + " Alchemy potions that require a newer" + + " Minecraft game version."); + } + if (failures > 0) { + mcMMO.p.getLogger().info( + "Failed to load " + failures + + " Alchemy potions that encountered errors while loading."); + } + return potionsLoaded; } - /** - * Parse a ConfigurationSection representing a AlchemyPotion. - * Returns null if input cannot be parsed. - * - * @param potion_section ConfigurationSection to be parsed. - * - * @return Parsed AlchemyPotion. - */ - private AlchemyPotion loadPotion(ConfigurationSection potion_section) { + private @NotNull AlchemyPotionConfigResult loadPotion(ConfigurationSection potion_section) { try { + final String key = potion_section.getName(); + final ConfigurationSection potionData = potion_section.getConfigurationSection( + "PotionData"); + boolean extended = false; + boolean upgraded = false; - String name = potion_section.getString("Name"); - if (name != null) { - name = ChatColor.translateAlternateColorCodes('&', name); + if (potionData != null) { + extended = potionData.getBoolean("Extended", false); + upgraded = potionData.getBoolean("Upgraded", false); } - PotionData data; - if (!potion_section.contains("PotionData")) { // Backwards config compatability - short dataValue = Short.parseShort(potion_section.getName()); - Potion potion = Potion.fromDamage(dataValue); - data = new PotionData(potion.getType(), potion.hasExtendedDuration(), potion.getLevel() == 2); + Material material; + final String materialString = potion_section.getString("Material", null); + if (materialString != null) { + material = ItemUtils.exhaustiveMaterialLookup(materialString); + if (material == null) { + mcMMO.p.getLogger().warning( + "PotionConfig: Failed to parse material for potion " + key + ": " + + materialString); + mcMMO.p.getLogger().warning("PotionConfig: Defaulting to POTION"); + material = Material.POTION; + } } else { - ConfigurationSection potionData = potion_section.getConfigurationSection("PotionData"); - data = new PotionData(PotionType.valueOf(potionData.getString("PotionType", "WATER")), potionData.getBoolean("Extended", false), potionData.getBoolean("Upgraded", false)); + mcMMO.p.getLogger().warning( + "PotionConfig: Missing Material config entry for potion " + key + "," + + " from configuration section: " + potion_section + + ", defaulting to POTION"); + material = Material.POTION; } - Material material = Material.POTION; - String mat = potion_section.getString("Material", null); - if (mat != null) { - material = Material.valueOf(mat); + final ItemStack itemStack = new ItemStack(material, 1); + final PotionMeta potionMeta = (PotionMeta) itemStack.getItemMeta(); + + if (potionMeta == null) { + mcMMO.p.getLogger().severe( + "PotionConfig: Failed to get PotionMeta for " + key + + ", from configuration section:" + " " + potion_section); + return ERROR_POTION_RESULT; } - List lore = new ArrayList<>(); + // extended and upgraded seem to be mutually exclusive + if (extended && upgraded) { + mcMMO.p.getLogger().warning( + "Potion " + key + " has both Extended and Upgraded set to true," + + " defaulting to Extended."); + upgraded = false; + } + + String potionTypeStr = potionData.getString("PotionType", null); + if (potionTypeStr == null) { + mcMMO.p.getLogger().severe( + "PotionConfig: Missing PotionType for " + key + + ", from configuration section:" + " " + potion_section); + return ERROR_POTION_RESULT; + } + + // This works via side effects + // TODO: Redesign later, side effects are stupid + if (!setPotionType(potionMeta, potionTypeStr, upgraded, extended)) { + mcMMO.p.getLogger().severe( + "PotionConfig: Failed to set parameters of potion for " + key + ": " + + potionTypeStr); + return ERROR_POTION_RESULT; + } + + final List lore = new ArrayList<>(); if (potion_section.contains("Lore")) { for (String line : potion_section.getStringList("Lore")) { lore.add(ChatColor.translateAlternateColorCodes('&', line)); } } + potionMeta.setLore(lore); - List effects = new ArrayList<>(); if (potion_section.contains("Effects")) { for (String effect : potion_section.getStringList("Effects")) { String[] parts = effect.split(" "); + if (isTrickyTrialsPotionEffect(parts[0]) && !mcMMO.getCompatibilityManager() + .getMinecraftGameVersion() + .isAtLeast(1, 21, 0)) { + LogUtils.debug( + mcMMO.p.getLogger(), + "Skipping potion effect " + effect + " because it is not" + + " compatible with the current Minecraft game version."); + return INCOMPATIBLE_POTION_RESULT; + } - PotionEffectType type = parts.length > 0 ? PotionEffectType.getByName(parts[0]) : null; + PotionEffectType type = + parts.length > 0 ? PotionEffectType.getByName(parts[0]) : null; int amplifier = parts.length > 1 ? Integer.parseInt(parts[1]) : 0; int duration = parts.length > 2 ? Integer.parseInt(parts[2]) : 0; if (type != null) { - effects.add(new PotionEffect(type, duration, amplifier)); + potionMeta.addCustomEffect(new PotionEffect(type, duration, amplifier), + true); } else { - mcMMO.p.getLogger().warning("Failed to parse effect for potion " + name + ": " + effect); + mcMMO.p.getLogger().severe( + "PotionConfig: Failed to parse effect for potion " + key + ": " + + effect); } } } @@ -165,35 +285,99 @@ public class PotionConfig extends LegacyConfigLoader { if (potion_section.contains("Color")) { color = Color.fromRGB(potion_section.getInt("Color")); } else { - color = this.generateColor(effects); + color = this.generateColor(potionMeta.getCustomEffects()); } + potionMeta.setColor(color); - Map children = new HashMap<>(); + final Map children = new HashMap<>(); if (potion_section.contains("Children")) { - for (String child : potion_section.getConfigurationSection("Children").getKeys(false)) { - ItemStack ingredient = loadIngredient(child); + for (String childIngredient : potion_section.getConfigurationSection("Children") + .getKeys(false)) { + // Breeze Rod was only for potions after 1.21.0 + if (isTrickyTrialsIngredient(childIngredient) + && !mcMMO.getCompatibilityManager() + .getMinecraftGameVersion() + .isAtLeast(1, 21, 0)) { + continue; + } + ItemStack ingredient = loadIngredient(childIngredient); if (ingredient != null) { - children.put(ingredient, potion_section.getConfigurationSection("Children").getString(child)); + children.put( + ingredient, + potion_section.getConfigurationSection("Children") + .getString(childIngredient)); } else { - mcMMO.p.getLogger().warning("Failed to parse child for potion " + name + ": " + child); + mcMMO.p.getLogger().severe( + "PotionConfig: Failed to parse child for potion " + key + ": " + + childIngredient); } } } + // Set the name of the potion + setPotionDisplayName(potion_section, potionMeta); - return new AlchemyPotion(material, data, name, lore, effects, color, children); + // TODO: Might not need to .setItemMeta + itemStack.setItemMeta(potionMeta); + return new AlchemyPotionConfigResult( + new AlchemyPotion(potion_section.getName(), itemStack, children), + AlchemyPotionConfigResultType.LOADED); } catch (Exception e) { - mcMMO.p.getLogger().warning("Failed to load Alchemy potion: " + potion_section.getName()); - return null; + mcMMO.p.getLogger().warning( + "PotionConfig: Failed to load Alchemy potion: " + potion_section.getName()); + e.printStackTrace(); + return ERROR_POTION_RESULT; + } + } + + private static boolean isTrickyTrialsIngredient(String ingredientStr) { + return ingredientStr.equalsIgnoreCase(BREEZE_ROD_STR) || ingredientStr.equalsIgnoreCase( + SLIME_BLOCK_STR) || ingredientStr.equalsIgnoreCase(COBWEB_STR) + || ingredientStr.equalsIgnoreCase( + STONE_STR); + } + + private static boolean isTrickyTrialsPotionEffect(String effectStr) { + return effectStr.equalsIgnoreCase(INFESTED_EFFECT_STR) || effectStr.equalsIgnoreCase( + WEAVING_EFFECT_STR) || effectStr.equalsIgnoreCase(OOZING_EFFECT_STR) + || effectStr.equalsIgnoreCase( + WIND_CHARGED_EFFECT_STR); + } + + private boolean setPotionType(PotionMeta potionMeta, String potionTypeStr, boolean upgraded, + boolean extended) { + final PotionType potionType = matchPotionType(potionTypeStr, upgraded, extended); + + if (potionType == null) { + mcMMO.p.getLogger() + .severe("PotionConfig: Failed to parse potion type for: " + potionTypeStr); + return false; + } + + // set base + setBasePotionType(potionMeta, potionType, extended, upgraded); + + // Legacy only + setUpgradedAndExtendedProperties(potionType, potionMeta, upgraded, extended); + return true; + } + + private void setPotionDisplayName(ConfigurationSection section, PotionMeta potionMeta) { + // If a potion doesn't have any custom effects, there is no reason to override the vanilla name + if (potionMeta.getCustomEffects().isEmpty()) { + return; + } + + final String configuredName = section.getString("Name", null); + if (configuredName != null) { + setItemName(potionMeta, configuredName); } } /** - * Parse a string representation of an ingredient. - * Format: '<MATERIAL>[:data]' - * Returns null if input cannot be parsed. + * Parse a string representation of an ingredient. Format: '<MATERIAL>[:data]' Returns + * null if input cannot be parsed. * * @param ingredient String representing an ingredient. - * * @return Parsed ingredient. */ private ItemStack loadIngredient(String ingredient) { @@ -210,43 +394,62 @@ public class PotionConfig extends LegacyConfigLoader { return null; } + /** + * Get the ingredients for the given tier. + * + * @param tier Tier to get ingredients for. + * @return List of ingredients for the given tier. + */ public List getIngredients(int tier) { - switch (tier) { - case 8: - return concoctionsIngredientsTierEight; - case 7: - return concoctionsIngredientsTierSeven; - case 6: - return concoctionsIngredientsTierSix; - case 5: - return concoctionsIngredientsTierFive; - case 4: - return concoctionsIngredientsTierFour; - case 3: - return concoctionsIngredientsTierThree; - case 2: - return concoctionsIngredientsTierTwo; - case 1: - default: - return concoctionsIngredientsTierOne; - } + return switch (tier) { + case 8 -> concoctionsIngredientsTierEight; + case 7 -> concoctionsIngredientsTierSeven; + case 6 -> concoctionsIngredientsTierSix; + case 5 -> concoctionsIngredientsTierFive; + case 4 -> concoctionsIngredientsTierFour; + case 3 -> concoctionsIngredientsTierThree; + case 2 -> concoctionsIngredientsTierTwo; + default -> concoctionsIngredientsTierOne; + }; } + /** + * Check if the given ItemStack is a valid potion. + * + * @param item ItemStack to be checked. + * @return True if the given ItemStack is a valid potion, false otherwise. + */ public boolean isValidPotion(ItemStack item) { return getPotion(item) != null; } + /** + * Get the AlchemyPotion that corresponds to the given name. + * + * @param name Name of the potion to be checked. + * @return AlchemyPotion that corresponds to the given name. + */ public AlchemyPotion getPotion(String name) { - return potionMap.get(name); + return alchemyPotions.get(name); } + /** + * Get the AlchemyPotion that corresponds to the given ItemStack. + * + * @param item ItemStack to be checked. + * @return AlchemyPotion that corresponds to the given ItemStack. + */ public AlchemyPotion getPotion(ItemStack item) { - for (AlchemyPotion potion : potionMap.values()) { - if (potion.isSimilar(item)) { - return potion; - } + // Fast return if the item does not have any item meta to avoid initializing an unnecessary ItemMeta instance + if (!item.hasItemMeta()) { + return null; } - return null; + + ItemMeta itemMeta = item.getItemMeta(); + final List potionList = alchemyPotions.values().stream().filter( + potion -> potion.isSimilarPotion(item, itemMeta)).toList(); + + return potionList.isEmpty() ? null : potionList.get(0); } public Color generateColor(List effects) { @@ -278,5 +481,4 @@ public class PotionConfig extends LegacyConfigLoader { } return Color.fromRGB(red / colors.size(), green / colors.size(), blue / colors.size()); } - } 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 1df5de82c..e85e369d5 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 @@ -8,12 +8,15 @@ import com.gmail.nossr50.skills.repair.repairables.Repairable; import com.gmail.nossr50.skills.repair.repairables.RepairableFactory; import com.gmail.nossr50.util.ItemUtils; import com.gmail.nossr50.util.LogUtils; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; import org.bukkit.Material; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.inventory.ItemStack; -import java.util.*; - public class RepairConfig extends BukkitConfig { private final HashSet notSupported; private List repairables; @@ -56,7 +59,8 @@ public class RepairConfig extends BukkitConfig { // Repair Material Type MaterialType repairMaterialType = MaterialType.OTHER; - String repairMaterialTypeString = config.getString("Repairables." + key + ".MaterialType", "OTHER"); + String repairMaterialTypeString = config.getString( + "Repairables." + key + ".MaterialType", "OTHER"); if (!config.contains("Repairables." + key + ".MaterialType") && itemMaterial != null) { ItemStack repairItem = new ItemStack(itemMaterial); @@ -73,9 +77,11 @@ public class RepairConfig extends BukkitConfig { repairMaterialType = MaterialType.IRON; } else if (ItemUtils.isGoldArmor(repairItem) || ItemUtils.isGoldTool(repairItem)) { repairMaterialType = MaterialType.GOLD; - } else if (ItemUtils.isDiamondArmor(repairItem) || ItemUtils.isDiamondTool(repairItem)) { + } else if (ItemUtils.isDiamondArmor(repairItem) || ItemUtils.isDiamondTool( + repairItem)) { repairMaterialType = MaterialType.DIAMOND; - } else if (ItemUtils.isNetheriteArmor(repairItem) || ItemUtils.isNetheriteTool(repairItem)) { + } else if (ItemUtils.isNetheriteArmor(repairItem) || ItemUtils.isNetheriteTool( + repairItem)) { repairMaterialType = MaterialType.NETHERITE; } } else { @@ -88,7 +94,9 @@ public class RepairConfig extends BukkitConfig { // Repair Material String repairMaterialName = config.getString("Repairables." + key + ".RepairMaterial"); - Material repairMaterial = (repairMaterialName == null ? repairMaterialType.getDefaultMaterial() : Material.matchMaterial(repairMaterialName)); + Material repairMaterial = (repairMaterialName == null + ? repairMaterialType.getDefaultMaterial() + : Material.matchMaterial(repairMaterialName)); if (repairMaterial == null) { notSupported.add(key); //Collect names of unsupported items @@ -96,10 +104,13 @@ public class RepairConfig extends BukkitConfig { } // Maximum Durability - short maximumDurability = (itemMaterial != null ? itemMaterial.getMaxDurability() : (short) config.getInt("Repairables." + key + ".MaximumDurability")); + short maximumDurability = (itemMaterial != null ? itemMaterial.getMaxDurability() + : (short) config.getInt( + "Repairables." + key + ".MaximumDurability")); if (maximumDurability <= 0) { - maximumDurability = (short) config.getInt("Repairables." + key + ".MaximumDurability"); + maximumDurability = (short) config.getInt( + "Repairables." + key + ".MaximumDurability"); } if (maximumDurability <= 0) { @@ -108,7 +119,8 @@ public class RepairConfig extends BukkitConfig { // Item Type ItemType repairItemType = ItemType.OTHER; - String repairItemTypeString = config.getString("Repairables." + key + ".ItemType", "OTHER"); + String repairItemTypeString = config.getString("Repairables." + key + ".ItemType", + "OTHER"); if (!config.contains("Repairables." + key + ".ItemType") && itemMaterial != null) { ItemStack repairItem = new ItemStack(itemMaterial); @@ -141,7 +153,10 @@ public class RepairConfig extends BukkitConfig { } if (noErrorsInRepairable(reason)) { - Repairable repairable = RepairableFactory.getRepairable(itemMaterial, repairMaterial, null, minimumLevel, maximumDurability, repairItemType, repairMaterialType, xpMultiplier, minimumQuantity); + Repairable repairable = RepairableFactory.getRepairable( + itemMaterial, repairMaterial, null, minimumLevel, maximumDurability, + repairItemType, + repairMaterialType, xpMultiplier, minimumQuantity); repairables.add(repairable); } } @@ -149,7 +164,8 @@ public class RepairConfig extends BukkitConfig { StringBuilder stringBuilder = new StringBuilder(); if (notSupported.size() > 0) { - stringBuilder.append("mcMMO found the following materials in the Repair config that are not supported by the version of Minecraft running on this server: "); + stringBuilder.append( + "mcMMO found the following materials in the Repair config that are not supported by the version of Minecraft running on this server: "); for (Iterator iterator = notSupported.iterator(); iterator.hasNext(); ) { String unsupportedMaterial = iterator.next(); @@ -162,7 +178,8 @@ public class RepairConfig extends BukkitConfig { } LogUtils.debug(mcMMO.p.getLogger(), stringBuilder.toString()); - LogUtils.debug(mcMMO.p.getLogger(), "Items using materials that are not supported will simply be skipped."); + LogUtils.debug(mcMMO.p.getLogger(), + "Items using materials that are not supported will simply be skipped."); } } diff --git a/src/main/java/com/gmail/nossr50/config/skills/repair/RepairConfigManager.java b/src/main/java/com/gmail/nossr50/config/skills/repair/RepairConfigManager.java index 1a54906a7..bab50ce38 100644 --- a/src/main/java/com/gmail/nossr50/config/skills/repair/RepairConfigManager.java +++ b/src/main/java/com/gmail/nossr50/config/skills/repair/RepairConfigManager.java @@ -2,7 +2,6 @@ package com.gmail.nossr50.config.skills.repair; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.skills.repair.repairables.Repairable; - import java.io.File; import java.util.Collection; import java.util.HashSet; @@ -20,8 +19,9 @@ public class RepairConfigManager { repairables.addAll(mainRepairConfig.getLoadedRepairables()); for (String fileName : dataFolder.list()) { - if(fileName.equals(REPAIR_VANILLA_YML)) + if (fileName.equals(REPAIR_VANILLA_YML)) { continue; + } if (!pattern.matcher(fileName).matches()) { continue; diff --git a/src/main/java/com/gmail/nossr50/config/skills/salvage/SalvageConfig.java b/src/main/java/com/gmail/nossr50/config/skills/salvage/SalvageConfig.java index fdcdee3f7..1a91ab504 100644 --- a/src/main/java/com/gmail/nossr50/config/skills/salvage/SalvageConfig.java +++ b/src/main/java/com/gmail/nossr50/config/skills/salvage/SalvageConfig.java @@ -10,14 +10,19 @@ import com.gmail.nossr50.skills.salvage.salvageables.SalvageableFactory; import com.gmail.nossr50.util.ItemUtils; import com.gmail.nossr50.util.LogUtils; import com.gmail.nossr50.util.skills.SkillUtils; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import java.util.Set; +import java.util.logging.Level; import org.bukkit.Material; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.inventory.ItemStack; -import java.io.IOException; -import java.util.*; -import java.util.logging.Level; - public class SalvageConfig extends BukkitConfig { private final HashSet notSupported; private Set salvageables; @@ -41,24 +46,31 @@ public class SalvageConfig extends BukkitConfig { Set keys = section.getKeys(false); //Original version of 1.16 support had maximum quantities that were bad, this fixes it - if (mcMMO.getUpgradeManager().shouldUpgrade(UpgradeType.FIX_NETHERITE_SALVAGE_QUANTITIES)) { - mcMMO.p.getLogger().log(Level.INFO, "Fixing incorrect Salvage quantities on Netherite gear, this will only run once..."); + mcMMO.p.getLogger().log( + Level.INFO, + "Fixing incorrect Salvage quantities on Netherite gear, this will only run once..."); for (String namespacedkey : mcMMO.getMaterialMapStore().getNetheriteArmor()) { - config.set("Salvageables." + namespacedkey.toUpperCase() + ".MaximumQuantity", 4); //TODO: Doesn't make sense to default to 4 for everything + config.set( + "Salvageables." + namespacedkey.toUpperCase(Locale.ENGLISH) + + ".MaximumQuantity", + 4); //TODO: Doesn't make sense to default to 4 for everything } try { config.save(getFile()); - mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.FIX_NETHERITE_SALVAGE_QUANTITIES); - LogUtils.debug(mcMMO.p.getLogger(), "Fixed incorrect Salvage quantities for Netherite gear!"); + mcMMO.getUpgradeManager() + .setUpgradeCompleted(UpgradeType.FIX_NETHERITE_SALVAGE_QUANTITIES); + LogUtils.debug(mcMMO.p.getLogger(), + "Fixed incorrect Salvage quantities for Netherite gear!"); } catch (IOException e) { - LogUtils.debug(mcMMO.p.getLogger(), "Unable to fix Salvage config, please delete the salvage yml file to generate a new one."); + LogUtils.debug( + mcMMO.p.getLogger(), + "Unable to fix Salvage config, please delete the salvage yml file to generate a new one."); e.printStackTrace(); } } - for (String key : keys) { // Validate all the things! List reason = new ArrayList<>(); @@ -73,7 +85,8 @@ public class SalvageConfig extends BukkitConfig { // Salvage Material Type MaterialType salvageMaterialType = MaterialType.OTHER; - String salvageMaterialTypeString = config.getString("Salvageables." + key + ".MaterialType", "OTHER"); + String salvageMaterialTypeString = config.getString( + "Salvageables." + key + ".MaterialType", "OTHER"); if (!config.contains("Salvageables." + key + ".MaterialType") && itemMaterial != null) { ItemStack salvageItem = new ItemStack(itemMaterial); @@ -84,28 +97,40 @@ public class SalvageConfig extends BukkitConfig { salvageMaterialType = MaterialType.STONE; } else if (ItemUtils.isStringTool(salvageItem)) { salvageMaterialType = MaterialType.STRING; + } else if (ItemUtils.isPrismarineTool(salvageItem)) { + salvageMaterialType = MaterialType.PRISMARINE; } else if (ItemUtils.isLeatherArmor(salvageItem)) { salvageMaterialType = MaterialType.LEATHER; - } else if (ItemUtils.isIronArmor(salvageItem) || ItemUtils.isIronTool(salvageItem)) { + } else if (ItemUtils.isIronArmor(salvageItem) || ItemUtils.isIronTool( + salvageItem)) { salvageMaterialType = MaterialType.IRON; - } else if (ItemUtils.isGoldArmor(salvageItem) || ItemUtils.isGoldTool(salvageItem)) { + } else if (ItemUtils.isGoldArmor(salvageItem) || ItemUtils.isGoldTool( + salvageItem)) { salvageMaterialType = MaterialType.GOLD; - } else if (ItemUtils.isDiamondArmor(salvageItem) || ItemUtils.isDiamondTool(salvageItem)) { + } else if (ItemUtils.isDiamondArmor(salvageItem) || ItemUtils.isDiamondTool( + salvageItem)) { salvageMaterialType = MaterialType.DIAMOND; - } else if (ItemUtils.isNetheriteTool(salvageItem) || ItemUtils.isNetheriteArmor(salvageItem)) { + } else if (ItemUtils.isNetheriteTool(salvageItem) || ItemUtils.isNetheriteArmor( + salvageItem)) { salvageMaterialType = MaterialType.NETHERITE; } } else { try { - salvageMaterialType = MaterialType.valueOf(salvageMaterialTypeString.replace(" ", "_").toUpperCase(Locale.ENGLISH)); + salvageMaterialType = MaterialType.valueOf( + salvageMaterialTypeString.replace(" ", "_") + .toUpperCase(Locale.ENGLISH)); } catch (IllegalArgumentException ex) { - reason.add(key + " has an invalid MaterialType of " + salvageMaterialTypeString); + reason.add( + key + " has an invalid MaterialType of " + salvageMaterialTypeString); } } // Salvage Material - String salvageMaterialName = config.getString("Salvageables." + key + ".SalvageMaterial"); - Material salvageMaterial = (salvageMaterialName == null ? salvageMaterialType.getDefaultMaterial() : Material.matchMaterial(salvageMaterialName)); + String salvageMaterialName = config.getString( + "Salvageables." + key + ".SalvageMaterial"); + Material salvageMaterial = (salvageMaterialName == null + ? salvageMaterialType.getDefaultMaterial() + : Material.matchMaterial(salvageMaterialName)); if (salvageMaterial == null) { notSupported.add(key); @@ -113,11 +138,14 @@ public class SalvageConfig extends BukkitConfig { } // Maximum Durability - short maximumDurability = (itemMaterial != null ? itemMaterial.getMaxDurability() : (short) config.getInt("Salvageables." + key + ".MaximumDurability")); + short maximumDurability = (itemMaterial != null ? itemMaterial.getMaxDurability() + : (short) config.getInt( + "Salvageables." + key + ".MaximumDurability")); // Item Type ItemType salvageItemType = ItemType.OTHER; - String salvageItemTypeString = config.getString("Salvageables." + key + ".ItemType", "OTHER"); + String salvageItemTypeString = config.getString("Salvageables." + key + ".ItemType", + "OTHER"); if (!config.contains("Salvageables." + key + ".ItemType") && itemMaterial != null) { ItemStack salvageItem = new ItemStack(itemMaterial); @@ -129,7 +157,8 @@ public class SalvageConfig extends BukkitConfig { } } else { try { - salvageItemType = ItemType.valueOf(salvageItemTypeString.replace(" ", "_").toUpperCase(Locale.ENGLISH)); + salvageItemType = ItemType.valueOf( + salvageItemTypeString.replace(" ", "_").toUpperCase(Locale.ENGLISH)); } catch (IllegalArgumentException ex) { reason.add(key + " has an invalid ItemType of " + salvageItemTypeString); } @@ -143,13 +172,16 @@ public class SalvageConfig extends BukkitConfig { } // Maximum Quantity - int maximumQuantity = (itemMaterial != null ? SkillUtils.getRepairAndSalvageQuantities(itemMaterial, salvageMaterial) : config.getInt("Salvageables." + key + ".MaximumQuantity", 1)); + int maximumQuantity = itemMaterial != null ? SkillUtils.getRepairAndSalvageQuantities( + itemMaterial, + salvageMaterial) : config.getInt("Salvageables." + key + ".MaximumQuantity", 1); if (maximumQuantity <= 0 && itemMaterial != null) { maximumQuantity = config.getInt("Salvageables." + key + ".MaximumQuantity", 1); } - int configMaximumQuantity = config.getInt("Salvageables." + key + ".MaximumQuantity", -1); + int configMaximumQuantity = config.getInt("Salvageables." + key + ".MaximumQuantity", + -1); if (configMaximumQuantity > 0) { maximumQuantity = configMaximumQuantity; @@ -160,7 +192,10 @@ public class SalvageConfig extends BukkitConfig { } if (noErrorsInSalvageable(reason)) { - Salvageable salvageable = SalvageableFactory.getSalvageable(itemMaterial, salvageMaterial, minimumLevel, maximumQuantity, maximumDurability, salvageItemType, salvageMaterialType, xpMultiplier); + Salvageable salvageable = SalvageableFactory.getSalvageable( + itemMaterial, salvageMaterial, minimumLevel, + maximumQuantity, maximumDurability, salvageItemType, salvageMaterialType, + xpMultiplier); salvageables.add(salvageable); } } @@ -168,7 +203,8 @@ public class SalvageConfig extends BukkitConfig { StringBuilder stringBuilder = new StringBuilder(); if (notSupported.size() > 0) { - stringBuilder.append("mcMMO found the following materials in the Salvage config that are not supported by the version of Minecraft running on this server: "); + stringBuilder.append( + "mcMMO found the following materials in the Salvage config that are not supported by the version of Minecraft running on this server: "); for (Iterator iterator = notSupported.iterator(); iterator.hasNext(); ) { String unsupportedMaterial = iterator.next(); @@ -181,7 +217,8 @@ public class SalvageConfig extends BukkitConfig { } LogUtils.debug(mcMMO.p.getLogger(), stringBuilder.toString()); - LogUtils.debug(mcMMO.p.getLogger(), "Items using materials that are not supported will simply be skipped."); + LogUtils.debug(mcMMO.p.getLogger(), + "Items using materials that are not supported will simply be skipped."); } } diff --git a/src/main/java/com/gmail/nossr50/config/skills/salvage/SalvageConfigManager.java b/src/main/java/com/gmail/nossr50/config/skills/salvage/SalvageConfigManager.java index 77348e8d3..08477658a 100644 --- a/src/main/java/com/gmail/nossr50/config/skills/salvage/SalvageConfigManager.java +++ b/src/main/java/com/gmail/nossr50/config/skills/salvage/SalvageConfigManager.java @@ -2,7 +2,6 @@ package com.gmail.nossr50.config.skills.salvage; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.skills.salvage.salvageables.Salvageable; - import java.io.File; import java.util.ArrayList; import java.util.List; @@ -21,8 +20,9 @@ public class SalvageConfigManager { salvageables.addAll(mainSalvageConfig.getLoadedSalvageables()); for (String fileName : dataFolder.list()) { - if(fileName.equals(SALVAGE_VANILLA_YML)) + if (fileName.equals(SALVAGE_VANILLA_YML)) { continue; + } if (!pattern.matcher(fileName).matches()) { continue; 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 a02e0bd3f..2b0261b67 100755 --- a/src/main/java/com/gmail/nossr50/config/treasure/FishingTreasureConfig.java +++ b/src/main/java/com/gmail/nossr50/config/treasure/FishingTreasureConfig.java @@ -1,10 +1,22 @@ package com.gmail.nossr50.config.treasure; +import static com.gmail.nossr50.util.PotionUtil.matchPotionType; + import com.gmail.nossr50.config.BukkitConfig; -import com.gmail.nossr50.datatypes.treasure.*; +import com.gmail.nossr50.datatypes.treasure.EnchantmentTreasure; +import com.gmail.nossr50.datatypes.treasure.FishingTreasure; +import com.gmail.nossr50.datatypes.treasure.FishingTreasureBook; +import com.gmail.nossr50.datatypes.treasure.Rarity; +import com.gmail.nossr50.datatypes.treasure.ShakeTreasure; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.EnchantmentUtils; import com.gmail.nossr50.util.LogUtils; +import com.gmail.nossr50.util.PotionUtil; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Set; import org.bukkit.ChatColor; import org.bukkit.Material; import org.bukkit.configuration.ConfigurationSection; @@ -13,12 +25,9 @@ import org.bukkit.entity.EntityType; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.PotionMeta; -import org.bukkit.potion.PotionData; import org.bukkit.potion.PotionType; import org.jetbrains.annotations.NotNull; -import java.util.*; - public class FishingTreasureConfig extends BukkitConfig { public static final String FILENAME = "fishing_treasures.yml"; @@ -46,23 +55,30 @@ public class FishingTreasureConfig extends BukkitConfig { protected boolean validateKeys() { // Validate all the settings! List reason = new ArrayList<>(); - ConfigurationSection enchantment_drop_rates = config.getConfigurationSection("Enchantment_Drop_Rates"); + ConfigurationSection enchantment_drop_rates = config.getConfigurationSection( + "Enchantment_Drop_Rates"); - if(enchantment_drop_rates != null) { + if (enchantment_drop_rates != null) { for (String tier : enchantment_drop_rates.getKeys(false)) { double totalEnchantDropRate = 0; double totalItemDropRate = 0; for (Rarity rarity : Rarity.values()) { - double enchantDropRate = config.getDouble("Enchantment_Drop_Rates." + tier + "." + rarity.toString()); - double itemDropRate = config.getDouble("Item_Drop_Rates." + tier + "." + rarity); + double enchantDropRate = config.getDouble( + "Enchantment_Drop_Rates." + tier + "." + rarity.toString()); + double itemDropRate = config.getDouble( + "Item_Drop_Rates." + tier + "." + rarity); if ((enchantDropRate < 0.0 || enchantDropRate > 100.0)) { - reason.add("The enchant drop rate for " + tier + " items that are " + rarity + "should be between 0.0 and 100.0!"); + reason.add( + "The enchant drop rate for " + tier + " items that are " + rarity + + "should be between 0.0 and 100.0!"); } if (itemDropRate < 0.0 || itemDropRate > 100.0) { - reason.add("The item drop rate for " + tier + " items that are " + rarity + "should be between 0.0 and 100.0!"); + reason.add( + "The item drop rate for " + tier + " items that are " + rarity + + "should be between 0.0 and 100.0!"); } totalEnchantDropRate += enchantDropRate; @@ -70,15 +86,18 @@ public class FishingTreasureConfig extends BukkitConfig { } if (totalEnchantDropRate < 0 || totalEnchantDropRate > 100.0) { - reason.add("The total enchant drop rate for " + tier + " should be between 0.0 and 100.0!"); + reason.add("The total enchant drop rate for " + tier + + " should be between 0.0 and 100.0!"); } if (totalItemDropRate < 0 || totalItemDropRate > 100.0) { - reason.add("The total item drop rate for " + tier + " should be between 0.0 and 100.0!"); + reason.add("The total item drop rate for " + tier + + " should be between 0.0 and 100.0!"); } } } else { - mcMMO.p.getLogger().warning("Your fishing treasures config is empty, is this intentional? Delete it to regenerate."); + mcMMO.p.getLogger().warning( + "Your fishing treasures config is empty, is this intentional? Delete it to regenerate."); } return noErrorsInConfig(reason); @@ -132,17 +151,24 @@ public class FishingTreasureConfig extends BukkitConfig { if (materialName.contains("INVENTORY")) { // Use magic material BEDROCK to know that we're grabbing something from the inventory and not a normal treasure - addShakeTreasure(new ShakeTreasure(new ItemStack(Material.BEDROCK, 1, (byte) 0), 1, getInventoryStealDropChance(), getInventoryStealDropLevel()), EntityType.PLAYER); + addShakeTreasure( + new ShakeTreasure( + new ItemStack(Material.BEDROCK, 1, (byte) 0), 1, + getInventoryStealDropChance(), getInventoryStealDropLevel()), + EntityType.PLAYER); continue; } else { material = Material.matchMaterial(materialName); } int amount = config.getInt(type + "." + treasureName + ".Amount"); - short data = (treasureInfo.length == 2) ? Short.parseShort(treasureInfo[1]) : (short) config.getInt(type + "." + treasureName + ".Data"); + short data = (treasureInfo.length == 2) ? Short.parseShort(treasureInfo[1]) + : (short) config.getInt( + type + "." + treasureName + ".Data"); if (material == null) { - reason.add("Cannot find matching item type in this version of MC, skipping - " + materialName); + reason.add("Cannot find matching item type in this version of MC, skipping - " + + materialName); continue; } @@ -171,7 +197,8 @@ public class FishingTreasureConfig extends BukkitConfig { } if (dropLevel < 0) { - reason.add("Fishing Config: " + treasureName + " has an invalid Drop_Level: " + dropLevel); + reason.add("Fishing Config: " + treasureName + " has an invalid Drop_Level: " + + dropLevel); } /* @@ -185,8 +212,11 @@ public class FishingTreasureConfig extends BukkitConfig { if (rarityStr != null) { rarity = Rarity.getRarity(rarityStr); } else { - mcMMO.p.getLogger().severe("Please edit your config and add a Rarity definition for - " + treasureName); - mcMMO.p.getLogger().severe("Skipping this treasure until rarity is defined - " + treasureName); + mcMMO.p.getLogger().severe( + "Please edit your config and add a Rarity definition for - " + + treasureName); + mcMMO.p.getLogger().severe("Skipping this treasure until rarity is defined - " + + treasureName); continue; } } @@ -196,7 +226,6 @@ public class FishingTreasureConfig extends BukkitConfig { */ ItemStack item = null; - String customName = null; if (hasCustomName(type, treasureName)) { @@ -204,30 +233,49 @@ public class FishingTreasureConfig extends BukkitConfig { } if (materialName.contains("POTION")) { + // Update for 1.20.5 + Material mat = Material.matchMaterial(materialName); if (mat == null) { reason.add("Potion format for " + FILENAME + " has changed"); + continue; } else { item = new ItemStack(mat, amount, data); - PotionMeta itemMeta = (PotionMeta) item.getItemMeta(); + PotionMeta potionMeta = (PotionMeta) item.getItemMeta(); - if (itemMeta == null) { - mcMMO.p.getLogger().severe("Item meta when adding potion to fishing treasure was null, contact the mcMMO devs!"); + if (potionMeta == null) { + mcMMO.p.getLogger().severe( + "FishingConfig: Item meta when adding potion to fishing treasure was null," + + " contact the mcMMO devs!"); + reason.add( + "FishingConfig: Item meta when adding potion to fishing treasure was null"); continue; } - PotionType potionType = null; - try { - potionType = PotionType.valueOf(config.getString(type + "." + treasureName + ".PotionData.PotionType", "WATER")); - } catch (IllegalArgumentException ex) { - reason.add("Invalid Potion_Type: " + config.getString(type + "." + treasureName + ".PotionData.PotionType", "WATER")); + String potionTypeStr; + potionTypeStr = config.getString( + type + "." + treasureName + ".PotionData.PotionType", "WATER"); + boolean extended = config.getBoolean( + type + "." + treasureName + ".PotionData.Extended", false); + boolean upgraded = config.getBoolean( + type + "." + treasureName + ".PotionData.Upgraded", false); + final PotionType potionType = matchPotionType(potionTypeStr, extended, + upgraded); + + if (potionType == null) { + reason.add( + "FishingConfig: Could not derive potion type from: " + potionTypeStr + + ", " + extended + ", " + upgraded); + continue; } - boolean extended = config.getBoolean(type + "." + treasureName + ".PotionData.Extended", false); - boolean upgraded = config.getBoolean(type + "." + treasureName + ".PotionData.Upgraded", false); - itemMeta.setBasePotionData(new PotionData(potionType, extended, upgraded)); + + // Set the base potion type + // NOTE: Upgraded/Extended are ignored in 1.20.5 and later + PotionUtil.setBasePotionType(potionMeta, potionType, upgraded, extended); if (customName != null) { - itemMeta.setDisplayName(ChatColor.translateAlternateColorCodes('&', customName)); + potionMeta.setDisplayName( + ChatColor.translateAlternateColorCodes('&', customName)); } if (config.contains(type + "." + treasureName + ".Lore")) { @@ -235,17 +283,19 @@ public class FishingTreasureConfig extends BukkitConfig { for (String s : config.getStringList(type + "." + treasureName + ".Lore")) { lore.add(ChatColor.translateAlternateColorCodes('&', s)); } - itemMeta.setLore(lore); + potionMeta.setLore(lore); } - item.setItemMeta(itemMeta); + item.setItemMeta(potionMeta); } } else if (material == Material.ENCHANTED_BOOK) { //If any whitelisted enchants exist we use whitelist-based matching item = new ItemStack(material, 1); ItemMeta itemMeta = item.getItemMeta(); - List allowedEnchantsList = config.getStringList(type + "." + treasureName + ".Enchantments_Whitelist"); - List disallowedEnchantsList = config.getStringList(type + "." + treasureName + ".Enchantments_Blacklist"); + List allowedEnchantsList = config.getStringList( + type + "." + treasureName + ".Enchantments_Whitelist"); + List disallowedEnchantsList = config.getStringList( + type + "." + treasureName + ".Enchantments_Blacklist"); Set blackListedEnchants = new HashSet<>(); Set whiteListedEnchants = new HashSet<>(); @@ -254,11 +304,14 @@ public class FishingTreasureConfig extends BukkitConfig { matchAndFillSet(allowedEnchantsList, whiteListedEnchants); if (customName != null && itemMeta != null) { - itemMeta.setDisplayName(ChatColor.translateAlternateColorCodes('&', customName)); + itemMeta.setDisplayName( + ChatColor.translateAlternateColorCodes('&', customName)); item.setItemMeta(itemMeta); } - FishingTreasureBook fishingTreasureBook = new FishingTreasureBook(item, xp, blackListedEnchants, whiteListedEnchants); + FishingTreasureBook fishingTreasureBook = new FishingTreasureBook( + item, xp, blackListedEnchants, + whiteListedEnchants); addFishingTreasure(rarity, fishingTreasureBook); //TODO: Add book support for shake continue; //The code in this whole file is a disaster, ignore this hacky solution :P @@ -267,7 +320,8 @@ public class FishingTreasureConfig extends BukkitConfig { if (customName != null) { ItemMeta itemMeta = item.getItemMeta(); - itemMeta.setDisplayName(ChatColor.translateAlternateColorCodes('&', customName)); + itemMeta.setDisplayName( + ChatColor.translateAlternateColorCodes('&', customName)); item.setItemMeta(itemMeta); } @@ -282,12 +336,12 @@ public class FishingTreasureConfig extends BukkitConfig { } } - if (noErrorsInConfig(reason)) { if (isFishing) { addFishingTreasure(rarity, new FishingTreasure(item, xp)); } else if (isShake) { - ShakeTreasure shakeTreasure = new ShakeTreasure(item, xp, dropChance, dropLevel); + ShakeTreasure shakeTreasure = new ShakeTreasure(item, xp, dropChance, + dropLevel); EntityType entityType = EntityType.valueOf(type.substring(6)); addShakeTreasure(shakeTreasure, entityType); @@ -296,13 +350,16 @@ public class FishingTreasureConfig extends BukkitConfig { } } - private void addShakeTreasure(@NotNull ShakeTreasure shakeTreasure, @NotNull EntityType entityType) { - if (!shakeMap.containsKey(entityType)) + private void addShakeTreasure(@NotNull ShakeTreasure shakeTreasure, + @NotNull EntityType entityType) { + if (!shakeMap.containsKey(entityType)) { shakeMap.put(entityType, new ArrayList<>()); + } shakeMap.get(entityType).add(shakeTreasure); } - private void addFishingTreasure(@NotNull Rarity rarity, @NotNull FishingTreasure fishingTreasure) { + private void addFishingTreasure(@NotNull Rarity rarity, + @NotNull FishingTreasure fishingTreasure) { fishingRewards.get(rarity).add(fishingTreasure); } @@ -317,7 +374,8 @@ public class FishingTreasureConfig extends BukkitConfig { * @param enchantListStr the users string list of enchantments * @param permissiveList the permissive list of enchantments */ - private void matchAndFillSet(@NotNull List enchantListStr, @NotNull Set permissiveList) { + private void matchAndFillSet(@NotNull List enchantListStr, + @NotNull Set permissiveList) { if (enchantListStr.isEmpty()) { return; } @@ -333,7 +391,10 @@ public class FishingTreasureConfig extends BukkitConfig { } if (!foundMatch) { - LogUtils.debug(mcMMO.p.getLogger(), "[Fishing Treasure Init] Could not find any enchantments which matched the user defined enchantment named: " + str); + LogUtils.debug( + mcMMO.p.getLogger(), + "[Fishing Treasure Init] Could not find any enchantments which matched the user defined enchantment named: " + + str); } } } @@ -344,7 +405,8 @@ public class FishingTreasureConfig extends BukkitConfig { fishingEnchantments.put(rarity, (new ArrayList<>())); } - ConfigurationSection enchantmentSection = config.getConfigurationSection("Enchantments_Rarity." + rarity.toString()); + ConfigurationSection enchantmentSection = config.getConfigurationSection( + "Enchantments_Rarity." + rarity.toString()); if (enchantmentSection == null) { return; @@ -355,7 +417,9 @@ public class FishingTreasureConfig extends BukkitConfig { Enchantment enchantment = EnchantmentUtils.getByName(enchantmentName); if (enchantment == null) { - mcMMO.p.getLogger().warning("Skipping invalid enchantment in " + FILENAME + ": " + enchantmentName); + mcMMO.p.getLogger().info( + "Skipping invalid enchantment in '" + FILENAME + "', named:" + + enchantmentName); continue; } 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 97967a131..707afb92b 100755 --- a/src/main/java/com/gmail/nossr50/config/treasure/TreasureConfig.java +++ b/src/main/java/com/gmail/nossr50/config/treasure/TreasureConfig.java @@ -1,12 +1,18 @@ package com.gmail.nossr50.config.treasure; +import static com.gmail.nossr50.util.text.ConfigStringUtils.getMaterialConfigString; + import com.gmail.nossr50.config.BukkitConfig; import com.gmail.nossr50.datatypes.treasure.ExcavationTreasure; import com.gmail.nossr50.datatypes.treasure.HylianTreasure; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.BlockUtils; import com.gmail.nossr50.util.LogUtils; -import com.gmail.nossr50.util.text.StringUtils; +import com.gmail.nossr50.util.PotionUtil; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; import org.bukkit.ChatColor; import org.bukkit.Material; import org.bukkit.Tag; @@ -14,14 +20,8 @@ import org.bukkit.configuration.ConfigurationSection; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.PotionMeta; -import org.bukkit.potion.PotionData; import org.bukkit.potion.PotionType; -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; - public class TreasureConfig extends BukkitConfig { public static final String FILENAME = "treasures.yml"; @@ -94,7 +94,9 @@ public class TreasureConfig extends BukkitConfig { material = Material.matchMaterial(materialName); int amount = config.getInt(type + "." + treasureName + ".Amount"); - short data = (treasureInfo.length == 2) ? Short.parseShort(treasureInfo[1]) : (short) config.getInt(type + "." + treasureName + ".Data"); + short data = (treasureInfo.length == 2) ? Short.parseShort(treasureInfo[1]) + : (short) config.getInt( + type + "." + treasureName + ".Data"); if (material == null) { reason.add("Invalid material: " + materialName); @@ -119,31 +121,42 @@ public class TreasureConfig extends BukkitConfig { //Check for legacy drop level values and convert if (getWrongKeyValue(type, treasureName, DropLevelKeyConversionType.LEGACY) != -1) { //Legacy Drop level, needs to be converted - shouldWeUpdateFile = processAutomaticKeyConversion(type, shouldWeUpdateFile, treasureName, DropLevelKeyConversionType.LEGACY); + shouldWeUpdateFile = processAutomaticKeyConversion( + type, shouldWeUpdateFile, treasureName, + DropLevelKeyConversionType.LEGACY); } //Check for a bad key that was accidentally shipped out to some users - if (getWrongKeyValue(type, treasureName, DropLevelKeyConversionType.WRONG_KEY_STANDARD) != -1) { + if (getWrongKeyValue(type, treasureName, DropLevelKeyConversionType.WRONG_KEY_STANDARD) + != -1) { //Partially converted to the new system, I had a dyslexic moment so some configs have this - shouldWeUpdateFile = processAutomaticKeyConversion(type, shouldWeUpdateFile, treasureName, DropLevelKeyConversionType.WRONG_KEY_STANDARD); + shouldWeUpdateFile = processAutomaticKeyConversion( + type, shouldWeUpdateFile, treasureName, + DropLevelKeyConversionType.WRONG_KEY_STANDARD); } //Check for a bad key that was accidentally shipped out to some users - if (getWrongKeyValue(type, treasureName, DropLevelKeyConversionType.WRONG_KEY_RETRO) != -1) { + if (getWrongKeyValue(type, treasureName, DropLevelKeyConversionType.WRONG_KEY_RETRO) + != -1) { //Partially converted to the new system, I had a dyslexic moment so some configs have this - shouldWeUpdateFile = processAutomaticKeyConversion(type, shouldWeUpdateFile, treasureName, DropLevelKeyConversionType.WRONG_KEY_RETRO); + shouldWeUpdateFile = processAutomaticKeyConversion( + type, shouldWeUpdateFile, treasureName, + DropLevelKeyConversionType.WRONG_KEY_RETRO); } int dropLevel = -1; if (mcMMO.isRetroModeEnabled()) { - dropLevel = config.getInt(type + "." + treasureName + LEVEL_REQUIREMENT_RETRO_MODE, -1); + dropLevel = config.getInt(type + "." + treasureName + LEVEL_REQUIREMENT_RETRO_MODE, + -1); } else { - dropLevel = config.getInt(type + "." + treasureName + LEVEL_REQUIREMENT_STANDARD_MODE, -1); + dropLevel = config.getInt( + type + "." + treasureName + LEVEL_REQUIREMENT_STANDARD_MODE, -1); } if (dropLevel == -1) { - mcMMO.p.getLogger().severe("Could not find a Level_Requirement entry for treasure " + treasureName); + mcMMO.p.getLogger().severe("Could not find a Level_Requirement entry for treasure " + + treasureName); mcMMO.p.getLogger().severe("Skipping treasure"); continue; } @@ -165,22 +178,43 @@ public class TreasureConfig extends BukkitConfig { Material mat = Material.matchMaterial(materialName); if (mat == null) { reason.add("Potion format for " + FILENAME + " has changed"); + continue; } else { item = new ItemStack(mat, amount, data); - PotionMeta itemMeta = (PotionMeta) item.getItemMeta(); - - PotionType potionType = null; - try { - potionType = PotionType.valueOf(config.getString(type + "." + treasureName + ".PotionData.PotionType", "WATER")); - } catch (IllegalArgumentException ex) { - reason.add("Invalid Potion_Type: " + config.getString(type + "." + treasureName + ".PotionData.PotionType", "WATER")); + PotionMeta potionMeta = (PotionMeta) item.getItemMeta(); + if (potionMeta == null) { + mcMMO.p.getLogger().severe( + "Item meta when adding potion to treasure was null, contact the mcMMO devs!"); + reason.add( + "Item meta when adding potion to treasure was null, contact the mcMMO devs!"); + continue; } - boolean extended = config.getBoolean(type + "." + treasureName + ".PotionData.Extended", false); - boolean upgraded = config.getBoolean(type + "." + treasureName + ".PotionData.Upgraded", false); - itemMeta.setBasePotionData(new PotionData(potionType, extended, upgraded)); + + String potionTypeStr; + potionTypeStr = config.getString( + type + "." + treasureName + ".PotionData.PotionType", "WATER"); + boolean extended = config.getBoolean( + type + "." + treasureName + ".PotionData.Extended", false); + boolean upgraded = config.getBoolean( + type + "." + treasureName + ".PotionData.Upgraded", false); + PotionType potionType = PotionUtil.matchPotionType(potionTypeStr, extended, + upgraded); + + if (potionType == null) { + reason.add( + "Could not derive potion type from: " + potionTypeStr + ", " + + extended + ", " + upgraded); + continue; + } + + // Set the base potion type + // NOTE: extended/upgraded are ignored in 1.20.5 and later + PotionUtil.setBasePotionType(potionMeta, potionType, extended, upgraded); if (config.contains(type + "." + treasureName + ".Custom_Name")) { - itemMeta.setDisplayName(ChatColor.translateAlternateColorCodes('&', config.getString(type + "." + treasureName + ".Custom_Name"))); + potionMeta.setDisplayName(ChatColor.translateAlternateColorCodes( + '&', + config.getString(type + "." + treasureName + ".Custom_Name"))); } if (config.contains(type + "." + treasureName + ".Lore")) { @@ -188,16 +222,18 @@ public class TreasureConfig extends BukkitConfig { for (String s : config.getStringList(type + "." + treasureName + ".Lore")) { lore.add(ChatColor.translateAlternateColorCodes('&', s)); } - itemMeta.setLore(lore); + potionMeta.setLore(lore); } - item.setItemMeta(itemMeta); + item.setItemMeta(potionMeta); } } else if (material != null) { item = new ItemStack(material, amount, data); if (config.contains(type + "." + treasureName + ".Custom_Name")) { ItemMeta itemMeta = item.getItemMeta(); - itemMeta.setDisplayName(ChatColor.translateAlternateColorCodes('&', config.getString(type + "." + treasureName + ".Custom_Name"))); + itemMeta.setDisplayName(ChatColor.translateAlternateColorCodes( + '&', + config.getString(type + "." + treasureName + ".Custom_Name"))); item.setItemMeta(itemMeta); } @@ -214,43 +250,62 @@ public class TreasureConfig extends BukkitConfig { if (noErrorsInConfig(reason)) { if (isExcavation) { - ExcavationTreasure excavationTreasure = new ExcavationTreasure(item, xp, dropChance, dropLevel); - List dropList = config.getStringList(type + "." + treasureName + ".Drops_From"); + ExcavationTreasure excavationTreasure = new ExcavationTreasure(item, xp, + dropChance, dropLevel); + List dropList = config.getStringList( + type + "." + treasureName + ".Drops_From"); for (String blockType : dropList) { - if (!excavationMap.containsKey(blockType)) + if (!excavationMap.containsKey(blockType)) { excavationMap.put(blockType, new ArrayList<>()); + } excavationMap.get(blockType).add(excavationTreasure); } } else if (isHylian) { - HylianTreasure hylianTreasure = new HylianTreasure(item, xp, dropChance, dropLevel); - List dropList = config.getStringList(type + "." + treasureName + ".Drops_From"); + HylianTreasure hylianTreasure = new HylianTreasure(item, xp, dropChance, + dropLevel); + List dropList = config.getStringList( + type + "." + treasureName + ".Drops_From"); for (String dropper : dropList) { if (dropper.equals("Bushes")) { - AddHylianTreasure(StringUtils.getFriendlyConfigMaterialString(Material.FERN), hylianTreasure); - AddHylianTreasure(StringUtils.getFriendlyConfigMaterialString(BlockUtils.getShortGrass()), hylianTreasure); - for (Material species : Tag.SAPLINGS.getValues()) - AddHylianTreasure(StringUtils.getFriendlyConfigMaterialString(species), hylianTreasure); + AddHylianTreasure(getMaterialConfigString(Material.FERN), + hylianTreasure); + AddHylianTreasure(getMaterialConfigString(BlockUtils.getShortGrass()), + hylianTreasure); + for (Material species : Tag.SAPLINGS.getValues()) { + AddHylianTreasure(getMaterialConfigString(species), hylianTreasure); + } - AddHylianTreasure(StringUtils.getFriendlyConfigMaterialString(Material.DEAD_BUSH), hylianTreasure); + AddHylianTreasure(getMaterialConfigString(Material.DEAD_BUSH), + hylianTreasure); continue; } if (dropper.equals("Flowers")) { - AddHylianTreasure(StringUtils.getFriendlyConfigMaterialString(Material.POPPY), hylianTreasure); - AddHylianTreasure(StringUtils.getFriendlyConfigMaterialString(Material.DANDELION), hylianTreasure); - AddHylianTreasure(StringUtils.getFriendlyConfigMaterialString(Material.BLUE_ORCHID), hylianTreasure); - AddHylianTreasure(StringUtils.getFriendlyConfigMaterialString(Material.ALLIUM), hylianTreasure); - AddHylianTreasure(StringUtils.getFriendlyConfigMaterialString(Material.AZURE_BLUET), hylianTreasure); - AddHylianTreasure(StringUtils.getFriendlyConfigMaterialString(Material.ORANGE_TULIP), hylianTreasure); - AddHylianTreasure(StringUtils.getFriendlyConfigMaterialString(Material.PINK_TULIP), hylianTreasure); - AddHylianTreasure(StringUtils.getFriendlyConfigMaterialString(Material.RED_TULIP), hylianTreasure); - AddHylianTreasure(StringUtils.getFriendlyConfigMaterialString(Material.WHITE_TULIP), hylianTreasure); + AddHylianTreasure(getMaterialConfigString(Material.POPPY), + hylianTreasure); + AddHylianTreasure(getMaterialConfigString(Material.DANDELION), + hylianTreasure); + AddHylianTreasure(getMaterialConfigString(Material.BLUE_ORCHID), + hylianTreasure); + AddHylianTreasure(getMaterialConfigString(Material.ALLIUM), + hylianTreasure); + AddHylianTreasure(getMaterialConfigString(Material.AZURE_BLUET), + hylianTreasure); + AddHylianTreasure(getMaterialConfigString(Material.ORANGE_TULIP), + hylianTreasure); + AddHylianTreasure(getMaterialConfigString(Material.PINK_TULIP), + hylianTreasure); + AddHylianTreasure(getMaterialConfigString(Material.RED_TULIP), + hylianTreasure); + AddHylianTreasure(getMaterialConfigString(Material.WHITE_TULIP), + hylianTreasure); continue; } if (dropper.equals("Pots")) { - for (Material species : Tag.FLOWER_POTS.getValues()) - AddHylianTreasure(StringUtils.getFriendlyConfigMaterialString(species), hylianTreasure); + for (Material species : Tag.FLOWER_POTS.getValues()) { + AddHylianTreasure(getMaterialConfigString(species), hylianTreasure); + } continue; } AddHylianTreasure(dropper, hylianTreasure); @@ -269,36 +324,61 @@ public class TreasureConfig extends BukkitConfig { } } - private boolean processAutomaticKeyConversion(String type, boolean shouldWeUpdateTheFile, String treasureName, DropLevelKeyConversionType conversionType) { + private boolean processAutomaticKeyConversion(String type, boolean shouldWeUpdateTheFile, + String treasureName, + DropLevelKeyConversionType conversionType) { switch (conversionType) { case LEGACY: - int legacyDropLevel = getWrongKeyValue(type, treasureName, conversionType); //Legacy only had one value, Retro Mode didn't have a setting + int legacyDropLevel = getWrongKeyValue( + type, treasureName, + conversionType); //Legacy only had one value, Retro Mode didn't have a setting //Config needs to be updated to be more specific - LogUtils.debug(mcMMO.p.getLogger(), "(" + treasureName + ") [Fixing bad address: Legacy] Converting Drop_Level to Level_Requirement in treasures.yml for treasure to match new expected format"); - config.set(type + "." + treasureName + LEGACY_DROP_LEVEL, null); //Remove legacy entry - config.set(type + "." + treasureName + LEVEL_REQUIREMENT_RETRO_MODE, legacyDropLevel * 10); //Multiply by 10 for Retro - config.set(type + "." + treasureName + LEVEL_REQUIREMENT_STANDARD_MODE, legacyDropLevel); + LogUtils.debug( + mcMMO.p.getLogger(), + "(" + treasureName + + ") [Fixing bad address: Legacy] Converting Drop_Level to Level_Requirement in treasures.yml for treasure to match new expected format"); + config.set(type + "." + treasureName + LEGACY_DROP_LEVEL, + null); //Remove legacy entry + config.set( + type + "." + treasureName + LEVEL_REQUIREMENT_RETRO_MODE, + legacyDropLevel * 10); //Multiply by 10 for Retro + config.set(type + "." + treasureName + LEVEL_REQUIREMENT_STANDARD_MODE, + legacyDropLevel); shouldWeUpdateTheFile = true; break; case WRONG_KEY_STANDARD: - LogUtils.debug(mcMMO.p.getLogger(), "(" + treasureName + ") [Fixing bad address: STANDARD] Converting Drop_Level to Level_Requirement in treasures.yml for treasure to match new expected format"); + LogUtils.debug( + mcMMO.p.getLogger(), + "(" + treasureName + + ") [Fixing bad address: STANDARD] Converting Drop_Level to Level_Requirement in treasures.yml for treasure to match new expected format"); int wrongKeyValueStandard = getWrongKeyValue(type, treasureName, conversionType); - config.set(type + "." + treasureName + WRONG_KEY_ROOT, null); //We also kill the Retro key here as we have enough information for setting in values if needed + config.set( + type + "." + treasureName + WRONG_KEY_ROOT, + null); //We also kill the Retro key here as we have enough information for setting in values if needed if (wrongKeyValueStandard != -1) { - config.set(type + "." + treasureName + LEVEL_REQUIREMENT_STANDARD_MODE, wrongKeyValueStandard); - config.set(type + "." + treasureName + LEVEL_REQUIREMENT_RETRO_MODE, wrongKeyValueStandard * 10); //Multiply by 10 for Retro + config.set(type + "." + treasureName + LEVEL_REQUIREMENT_STANDARD_MODE, + wrongKeyValueStandard); + config.set( + type + "." + treasureName + LEVEL_REQUIREMENT_RETRO_MODE, + wrongKeyValueStandard * 10); //Multiply by 10 for Retro } shouldWeUpdateTheFile = true; break; case WRONG_KEY_RETRO: - LogUtils.debug(mcMMO.p.getLogger(), "(" + treasureName + ") [Fixing bad address: RETRO] Converting Drop_Level to Level_Requirement in treasures.yml for treasure to match new expected format"); + LogUtils.debug( + mcMMO.p.getLogger(), + "(" + treasureName + + ") [Fixing bad address: RETRO] Converting Drop_Level to Level_Requirement in treasures.yml for treasure to match new expected format"); int wrongKeyValueRetro = getWrongKeyValue(type, treasureName, conversionType); - config.set(type + "." + treasureName + WRONG_KEY_ROOT, null); //We also kill the Retro key here as we have enough information for setting in values if needed + config.set( + type + "." + treasureName + WRONG_KEY_ROOT, + null); //We also kill the Retro key here as we have enough information for setting in values if needed if (wrongKeyValueRetro != -1) { - config.set(type + "." + treasureName + LEVEL_REQUIREMENT_RETRO_MODE, wrongKeyValueRetro); + config.set(type + "." + treasureName + LEVEL_REQUIREMENT_RETRO_MODE, + wrongKeyValueRetro); } shouldWeUpdateTheFile = true; @@ -307,18 +387,22 @@ public class TreasureConfig extends BukkitConfig { return shouldWeUpdateTheFile; } - private int getWrongKeyValue(String type, String treasureName, DropLevelKeyConversionType dropLevelKeyConversionType) { + private int getWrongKeyValue(String type, String treasureName, + DropLevelKeyConversionType dropLevelKeyConversionType) { return switch (dropLevelKeyConversionType) { case LEGACY -> config.getInt(type + "." + treasureName + LEGACY_DROP_LEVEL, -1); - case WRONG_KEY_STANDARD -> config.getInt(type + "." + treasureName + WRONG_KEY_VALUE_STANDARD, -1); - case WRONG_KEY_RETRO -> config.getInt(type + "." + treasureName + WRONG_KEY_VALUE_RETRO, -1); + case WRONG_KEY_STANDARD -> + config.getInt(type + "." + treasureName + WRONG_KEY_VALUE_STANDARD, -1); + case WRONG_KEY_RETRO -> + config.getInt(type + "." + treasureName + WRONG_KEY_VALUE_RETRO, -1); }; } private void AddHylianTreasure(String dropper, HylianTreasure treasure) { - if (!hylianMap.containsKey(dropper)) + if (!hylianMap.containsKey(dropper)) { hylianMap.put(dropper, new ArrayList<>()); + } hylianMap.get(dropper).add(treasure); } diff --git a/src/main/java/com/gmail/nossr50/database/DatabaseManager.java b/src/main/java/com/gmail/nossr50/database/DatabaseManager.java index 586c8c0b6..a666739e7 100644 --- a/src/main/java/com/gmail/nossr50/database/DatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/DatabaseManager.java @@ -5,15 +5,14 @@ import com.gmail.nossr50.datatypes.database.DatabaseType; import com.gmail.nossr50.datatypes.database.PlayerStat; import com.gmail.nossr50.datatypes.player.PlayerProfile; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; +import java.util.List; +import java.util.Map; +import java.util.UUID; import org.bukkit.OfflinePlayer; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.List; -import java.util.Map; -import java.util.UUID; - public interface DatabaseManager { // During convertUsers, how often to output a status int progressInterval = 200; @@ -38,8 +37,8 @@ public interface DatabaseManager { boolean removeUser(String playerName, UUID uuid); /** - * Removes any cache used for faster lookups - * Currently only used for SQL + * Removes any cache used for faster lookups Currently only used for SQL + * * @param uuid target UUID to cleanup */ void cleanupUser(UUID uuid); @@ -53,21 +52,21 @@ public interface DatabaseManager { boolean saveUser(PlayerProfile profile); /** - * Retrieve leaderboard info. - * Will never be null but it may be empty - * - * @param skill The skill to retrieve info on - * @param pageNumber Which page in the leaderboards to retrieve - * @param statsPerPage The number of stats per page - * @return the requested leaderboard information - */ - @NotNull List readLeaderboard(@Nullable PrimarySkillType skill, int pageNumber, int statsPerPage) throws InvalidSkillException; + * Retrieve leaderboard info. Will never be null but it may be empty + * + * @param skill The skill to retrieve info on + * @param pageNumber Which page in the leaderboards to retrieve + * @param statsPerPage The number of stats per page + * @return the requested leaderboard information + */ + @NotNull List readLeaderboard(@Nullable PrimarySkillType skill, int pageNumber, + int statsPerPage) throws InvalidSkillException; /** * Retrieve rank info into a HashMap from PrimarySkillType to the rank. *

- * The special value null is used to represent the Power - * Level rank (the combination of all skill levels). + * The special value null is used to represent the Power Level rank (the + * combination of all skill levels). * * @param playerName The name of the user to retrieve the rankings for * @return the requested rank information @@ -76,7 +75,8 @@ public interface DatabaseManager { /** * Add a new user to the database. - * @param playerName The name of the player to be added to the database + * + * @param playerName The name of the player to be added to the database * @param uuid The uuid of the player to be added to the database * @return */ @@ -88,8 +88,7 @@ public interface DatabaseManager { * Load a player from the database. * * @param playerName The name of the player to load from the database - * @return The player's data, or an unloaded PlayerProfile if not found - * and createNew is false + * @return The player's data, or an unloaded PlayerProfile if not found and createNew is false */ @NotNull PlayerProfile loadPlayerProfile(@NotNull String playerName); diff --git a/src/main/java/com/gmail/nossr50/database/DatabaseManagerFactory.java b/src/main/java/com/gmail/nossr50/database/DatabaseManagerFactory.java index cb5025f6f..d75952890 100644 --- a/src/main/java/com/gmail/nossr50/database/DatabaseManagerFactory.java +++ b/src/main/java/com/gmail/nossr50/database/DatabaseManagerFactory.java @@ -3,56 +3,55 @@ package com.gmail.nossr50.database; import com.gmail.nossr50.datatypes.database.DatabaseType; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.LogUtils; +import java.util.logging.Logger; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.logging.Logger; - 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) { + public static DatabaseManager getDatabaseManager(@NotNull String userFilePath, + @NotNull Logger logger, long purgeTime, int startingLevel) { if (customManager != null) { try { return createDefaultCustomDatabaseManager(); - } - catch (Exception e) { + } catch (Exception e) { LogUtils.debug(mcMMO.p.getLogger(), "Could not create custom database manager"); e.printStackTrace(); - } - catch (Throwable e) { + } catch (Throwable e) { LogUtils.debug(mcMMO.p.getLogger(), "Failed to create custom database manager"); e.printStackTrace(); } - LogUtils.debug(mcMMO.p.getLogger(), "Falling back on " + (mcMMO.p.getGeneralConfig().getUseMySQL() ? "SQL" : "Flatfile") + " database"); + 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); } /** - * Sets the custom DatabaseManager class for mcMMO to use. This should be - * called prior to mcMMO enabling. + * Sets the custom DatabaseManager class for mcMMO to use. This should be called prior to mcMMO + * enabling. *

- * The provided class must have an empty constructor, which is the one - * that will be used. + * The provided class must have an empty constructor, which is the one that will be used. *

- * This method is intended for API use, but it should not be considered - * stable. This method is subject to change and/or removal in future - * versions. + * This method is intended for API use, but it should not be considered stable. This method is + * subject to change and/or removal in future versions. * * @param clazz the DatabaseManager class to use - * - * @throws IllegalArgumentException if the provided class does not have - * an empty constructor + * @throws IllegalArgumentException if the provided class does not have an empty constructor */ public static void setCustomDatabaseManagerClass(Class clazz) { try { clazz.getConstructor(); customManager = clazz; - } - catch (Throwable e) { - throw new IllegalArgumentException("Provided database manager class must have an empty constructor", e); + } catch (Throwable e) { + throw new IllegalArgumentException( + "Provided database manager class must have an empty constructor", e); } } @@ -60,7 +59,9 @@ public class DatabaseManagerFactory { return customManager; } - public static @Nullable DatabaseManager createDatabaseManager(@NotNull DatabaseType type, @NotNull String userFilePath, @NotNull Logger logger, long purgeTime, int startingLevel) { + public static @Nullable DatabaseManager createDatabaseManager(@NotNull DatabaseType type, + @NotNull String userFilePath, @NotNull Logger logger, long purgeTime, + int startingLevel) { switch (type) { case FLATFILE: LogUtils.debug(mcMMO.p.getLogger(), "Using FlatFile Database"); @@ -68,14 +69,13 @@ public class DatabaseManagerFactory { 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 { LogUtils.debug(mcMMO.p.getLogger(), "Attempting to use Custom Database"); return createDefaultCustomDatabaseManager(); - } - catch (Throwable e) { + } catch (Throwable e) { e.printStackTrace(); } @@ -88,7 +88,8 @@ public class DatabaseManagerFactory { return customManager.getConstructor().newInstance(); } - public static DatabaseManager createCustomDatabaseManager(Class clazz) throws Throwable { + public static DatabaseManager createCustomDatabaseManager( + Class clazz) throws Throwable { return clazz.getConstructor().newInstance(); } } diff --git a/src/main/java/com/gmail/nossr50/database/FlatFileDataProcessor.java b/src/main/java/com/gmail/nossr50/database/FlatFileDataProcessor.java index a232d86cd..2331809af 100644 --- a/src/main/java/com/gmail/nossr50/database/FlatFileDataProcessor.java +++ b/src/main/java/com/gmail/nossr50/database/FlatFileDataProcessor.java @@ -1,16 +1,70 @@ package com.gmail.nossr50.database; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.COOLDOWN_ARCHERY; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.COOLDOWN_BERSERK; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.COOLDOWN_BLAST_MINING; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.COOLDOWN_CHIMAERA_WING; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.COOLDOWN_GIGA_DRILL_BREAKER; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.COOLDOWN_GREEN_TERRA; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.COOLDOWN_MACES; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.COOLDOWN_SERRATED_STRIKES; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.COOLDOWN_SKULL_SPLITTER; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.COOLDOWN_SUPER_BREAKER; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.COOLDOWN_SUPER_SHOTGUN; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.COOLDOWN_TREE_FELLER; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.COOLDOWN_TRIDENTS; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.DATA_ENTRY_COUNT; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.EXP_ACROBATICS; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.EXP_ALCHEMY; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.EXP_ARCHERY; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.EXP_AXES; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.EXP_CROSSBOWS; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.EXP_EXCAVATION; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.EXP_FISHING; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.EXP_HERBALISM; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.EXP_MACES; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.EXP_MINING; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.EXP_REPAIR; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.EXP_SWORDS; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.EXP_TAMING; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.EXP_TRIDENTS; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.EXP_UNARMED; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.EXP_WOODCUTTING; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.HEALTHBAR; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.LEGACY_LAST_LOGIN; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.OVERHAUL_LAST_LOGIN; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.SCOREBOARD_TIPS; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.SKILLS_ACROBATICS; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.SKILLS_ALCHEMY; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.SKILLS_ARCHERY; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.SKILLS_AXES; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.SKILLS_CROSSBOWS; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.SKILLS_EXCAVATION; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.SKILLS_FISHING; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.SKILLS_HERBALISM; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.SKILLS_MACES; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.SKILLS_MINING; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.SKILLS_REPAIR; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.SKILLS_SWORDS; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.SKILLS_TAMING; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.SKILLS_TRIDENTS; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.SKILLS_UNARMED; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.SKILLS_WOODCUTTING; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.USERNAME_INDEX; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.UUID_INDEX; + import com.gmail.nossr50.database.flatfile.FlatFileDataBuilder; import com.gmail.nossr50.database.flatfile.FlatFileDataContainer; import com.gmail.nossr50.database.flatfile.FlatFileDataUtil; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.UUID; +import java.util.logging.Logger; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.*; -import java.util.logging.Logger; - -import static com.gmail.nossr50.database.FlatFileDatabaseManager.*; - public class FlatFileDataProcessor { private final @NotNull List flatFileDataContainers; private final @NotNull List flatFileDataFlags; @@ -33,7 +87,7 @@ public class FlatFileDataProcessor { assert !lineData.isEmpty(); //Make sure the data line is "correct" - if(lineData.charAt(lineData.length() - 1) != ':') { + if (lineData.charAt(lineData.length() - 1) != ':') { // Length checks depend on last rawSplitData being ':' // We add it here if it is missing lineData = lineData.concat(":"); @@ -48,10 +102,11 @@ public class FlatFileDataProcessor { boolean anyBadData = false; //This is the minimum size of the split array needed to be considered proper data - if(splitDataLine.length < getMinimumSplitDataLength()) { + if (splitDataLine.length < getMinimumSplitDataLength()) { //Data is considered junk - if(!corruptDataFound) { - logger.severe("Some corrupt data was found in mcmmo.users and has been repaired, it is possible that some player data has been lost in this process."); + if (!corruptDataFound) { + logger.severe( + "Some corrupt data was found in mcmmo.users and has been repaired, it is possible that some player data has been lost in this process."); corruptDataFound = true; } @@ -59,10 +114,13 @@ public class FlatFileDataProcessor { builder.appendFlag(FlatFileDataFlag.CORRUPTED_OR_UNRECOGNIZABLE); //TODO: This block here is probably pointless - if(splitDataLine.length >= 10 //The value here is kind of arbitrary, it shouldn't be too low to avoid false positives, but also we aren't really going to correctly identify when player data has been corrupted or not with 100% accuracy ever + if (splitDataLine.length >= 10 + //The value here is kind of arbitrary, it shouldn't be too low to avoid false positives, but also we aren't really going to correctly identify when player data has been corrupted or not with 100% accuracy ever && splitDataLine[0] != null && !splitDataLine[0].isEmpty()) { - if(splitDataLine[0].length() <= 16 && splitDataLine[0].length() >= 3) { - logger.severe("Not enough data found to recover corrupted player data for user: "+splitDataLine[0]); + if (splitDataLine[0].length() <= 16 && splitDataLine[0].length() >= 3) { + logger.severe( + "Not enough data found to recover corrupted player data for user: " + + splitDataLine[0]); registerData(builder.appendFlag(FlatFileDataFlag.TOO_INCOMPLETE)); return; } @@ -81,14 +139,14 @@ public class FlatFileDataProcessor { String name = splitDataLine[USERNAME_INDEX]; String strOfUUID = splitDataLine[UUID_INDEX]; - if(name.isEmpty()) { + if (name.isEmpty()) { reportBadDataLine("No name found for data", "[MISSING NAME]", lineData); builder.appendFlag(FlatFileDataFlag.MISSING_NAME); anyBadData = true; badDataValues[USERNAME_INDEX] = true; } - if(strOfUUID.isEmpty() || strOfUUID.equalsIgnoreCase("NULL")) { + if (strOfUUID.isEmpty() || strOfUUID.equalsIgnoreCase("NULL")) { invalidUUID = true; badDataValues[UUID_INDEX] = true; reportBadDataLine("Empty/null UUID for user", "Empty/null", lineData); @@ -110,21 +168,22 @@ public class FlatFileDataProcessor { } //Duplicate UUID is no good, reject them - if(!invalidUUID && uuid != null && uuids.contains(uuid)) { + if (!invalidUUID && uuid != null && uuids.contains(uuid)) { registerData(builder.appendFlag(FlatFileDataFlag.DUPLICATE_UUID)); return; } uuids.add(uuid); - if(names.contains(name)) { + if (names.contains(name)) { builder.appendFlag(FlatFileDataFlag.DUPLICATE_NAME); anyBadData = true; badDataValues[USERNAME_INDEX] = true; } - if(!name.isEmpty()) + if (!name.isEmpty()) { names.add(name); + } //Make sure the data is up to date schema wise, if it isn't we adjust it to the correct size and flag it for repair splitDataLine = isDataSchemaUpToDate(splitDataLine, builder, badDataValues); @@ -135,10 +194,10 @@ public class FlatFileDataProcessor { */ //Check each data for bad values - for(int i = 0; i < DATA_ENTRY_COUNT; i++) { - if(shouldNotBeEmpty(splitDataLine[i], i)) { + for (int i = 0; i < DATA_ENTRY_COUNT; i++) { + if (shouldNotBeEmpty(splitDataLine[i], i)) { - if(i == OVERHAUL_LAST_LOGIN) { + if (i == OVERHAUL_LAST_LOGIN) { builder.appendFlag(FlatFileDataFlag.LAST_LOGIN_SCHEMA_UPGRADE); } @@ -149,13 +208,13 @@ public class FlatFileDataProcessor { boolean isCorrectType = isOfExpectedType(splitDataLine[i], getExpectedValueType(i)); - if(!isCorrectType) { + if (!isCorrectType) { anyBadData = true; badDataValues[i] = true; } } - if(anyBadData) { + if (anyBadData) { builder.appendFlag(FlatFileDataFlag.BAD_VALUES); builder.appendBadDataValues(badDataValues); } @@ -163,16 +222,17 @@ public class FlatFileDataProcessor { registerData(builder); } - public @NotNull String[] isDataSchemaUpToDate(@NotNull String[] splitDataLine, @NotNull FlatFileDataBuilder builder, boolean[] badDataValues) { + public @NotNull String[] isDataSchemaUpToDate(@NotNull String[] splitDataLine, + @NotNull FlatFileDataBuilder builder, boolean[] badDataValues) { assert splitDataLine.length <= DATA_ENTRY_COUNT; //should NEVER be higher - if(splitDataLine.length < DATA_ENTRY_COUNT) { + if (splitDataLine.length < DATA_ENTRY_COUNT) { int oldLength = splitDataLine.length; splitDataLine = Arrays.copyOf(splitDataLine, DATA_ENTRY_COUNT); int newLength = splitDataLine.length; //TODO: Test this - for(int i = oldLength; i < (newLength - 1); i++){ + for (int i = oldLength; i < (newLength - 1); i++) { badDataValues[i] = true; } @@ -184,7 +244,7 @@ public class FlatFileDataProcessor { public boolean shouldNotBeEmpty(@Nullable String data, int index) { - if(getExpectedValueType(index) == ExpectedType.IGNORED) { + if (getExpectedValueType(index) == ExpectedType.IGNORED) { return false; } else { return data == null || data.isEmpty(); @@ -192,7 +252,7 @@ public class FlatFileDataProcessor { } public boolean isOfExpectedType(@NotNull String data, @NotNull ExpectedType expectedType) { - switch(expectedType) { + switch (expectedType) { case STRING: return true; case INTEGER: @@ -226,7 +286,8 @@ public class FlatFileDataProcessor { return false; } case OUT_OF_RANGE: - throw new ArrayIndexOutOfBoundsException("Value matched type OUT_OF_RANGE, this should never happen."); + throw new ArrayIndexOutOfBoundsException( + "Value matched type OUT_OF_RANGE, this should never happen."); case IGNORED: default: return true; @@ -248,66 +309,40 @@ public class FlatFileDataProcessor { FlatFileDataContainer flatFileDataContainer = builder.build(); flatFileDataContainers.add(flatFileDataContainer); - if(flatFileDataContainer.getDataFlags() != null) + if (flatFileDataContainer.getDataFlags() != null) { flatFileDataFlags.addAll(flatFileDataContainer.getDataFlags()); + } } - public static @NotNull ExpectedType getExpectedValueType(int dataIndex) throws IndexOutOfBoundsException { - switch(dataIndex) { - case USERNAME_INDEX: - return ExpectedType.STRING; - case 2: //Assumption: Used to be for something, no longer used - case 3: //Assumption: Used to be for something, no longer used - case 23: //Assumption: Used to be used for something, no longer used - case 33: //Assumption: Used to be used for something, no longer used - case HEALTHBAR: - case LEGACY_LAST_LOGIN: - return ExpectedType.IGNORED; - case SKILLS_MINING: - case SKILLS_REPAIR: - case SKILLS_UNARMED: - case SKILLS_HERBALISM: - case SKILLS_EXCAVATION: - case SKILLS_ARCHERY: - case SKILLS_SWORDS: - case SKILLS_AXES: - case SKILLS_WOODCUTTING: - case SKILLS_ACROBATICS: - case SKILLS_TAMING: - case SKILLS_FISHING: - case SKILLS_ALCHEMY: - case COOLDOWN_BERSERK: - case COOLDOWN_GIGA_DRILL_BREAKER: - case COOLDOWN_TREE_FELLER: - case COOLDOWN_GREEN_TERRA: - case COOLDOWN_SERRATED_STRIKES: - case COOLDOWN_SKULL_SPLITTER: - case COOLDOWN_SUPER_BREAKER: - case COOLDOWN_BLAST_MINING: - case SCOREBOARD_TIPS: - case COOLDOWN_CHIMAERA_WING: - return ExpectedType.INTEGER; - case EXP_MINING: - case EXP_WOODCUTTING: - case EXP_REPAIR: - case EXP_UNARMED: - case EXP_HERBALISM: - case EXP_EXCAVATION: - case EXP_ARCHERY: - case EXP_SWORDS: - case EXP_AXES: - case EXP_ACROBATICS: - case EXP_TAMING: - case EXP_FISHING: - case EXP_ALCHEMY: - return ExpectedType.FLOAT; - case UUID_INDEX: - return ExpectedType.UUID; - case OVERHAUL_LAST_LOGIN: - return ExpectedType.LONG; - } - - throw new IndexOutOfBoundsException(); + public static @NotNull ExpectedType getExpectedValueType(int dataIndex) + throws IndexOutOfBoundsException { + return switch (dataIndex) { + case USERNAME_INDEX -> + ExpectedType.STRING; //Assumption: Used to be for something, no longer used + //Assumption: Used to be for something, no longer used + //Assumption: Used to be used for something, no longer used + //Assumption: Used to be used for something, no longer used + case 2, 3, 23, 33, HEALTHBAR, LEGACY_LAST_LOGIN -> ExpectedType.IGNORED; + case SKILLS_MINING, SKILLS_REPAIR, SKILLS_UNARMED, SKILLS_HERBALISM, SKILLS_EXCAVATION, + SKILLS_ARCHERY, + SKILLS_SWORDS, SKILLS_AXES, SKILLS_WOODCUTTING, SKILLS_ACROBATICS, SKILLS_TAMING, + SKILLS_FISHING, + SKILLS_ALCHEMY, SKILLS_CROSSBOWS, SKILLS_TRIDENTS, SKILLS_MACES, COOLDOWN_BERSERK, + COOLDOWN_GIGA_DRILL_BREAKER, COOLDOWN_TREE_FELLER, COOLDOWN_GREEN_TERRA, + COOLDOWN_SERRATED_STRIKES, + COOLDOWN_SKULL_SPLITTER, COOLDOWN_SUPER_BREAKER, COOLDOWN_BLAST_MINING, + SCOREBOARD_TIPS, + COOLDOWN_CHIMAERA_WING, COOLDOWN_SUPER_SHOTGUN, COOLDOWN_TRIDENTS, + COOLDOWN_ARCHERY, COOLDOWN_MACES -> ExpectedType.INTEGER; + case EXP_MINING, EXP_WOODCUTTING, EXP_REPAIR, EXP_UNARMED, EXP_HERBALISM, + EXP_EXCAVATION, EXP_ARCHERY, + EXP_SWORDS, EXP_AXES, EXP_ACROBATICS, EXP_TAMING, EXP_FISHING, EXP_ALCHEMY, + EXP_CROSSBOWS, + EXP_TRIDENTS, EXP_MACES -> ExpectedType.FLOAT; + case UUID_INDEX -> ExpectedType.UUID; + case OVERHAUL_LAST_LOGIN -> ExpectedType.LONG; + default -> throw new IndexOutOfBoundsException(); + }; } public @NotNull List getFlatFileDataContainers() { @@ -327,15 +362,16 @@ public class FlatFileDataProcessor { //Fix our data if needed and prepare it to be saved - for(FlatFileDataContainer dataContainer : flatFileDataContainers) { + for (FlatFileDataContainer dataContainer : flatFileDataContainers) { String[] splitData = FlatFileDataUtil.getPreparedSaveDataLine(dataContainer); - if(splitData == null) + if (splitData == null) { continue; + } //We add a trailing : as it is needed for some reason (is it?) //TODO: Is the trailing ":" actually necessary? - String fromSplit = org.apache.commons.lang.StringUtils.join(splitData, ":") + ":"; + String fromSplit = org.apache.commons.lang3.StringUtils.join(splitData, ":") + ":"; stringBuilder.append(fromSplit).append("\r\n"); } diff --git a/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java b/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java index 52fa9a330..017a3b554 100644 --- a/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java @@ -12,22 +12,33 @@ import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.LogUtils; import com.gmail.nossr50.util.Misc; import com.gmail.nossr50.util.skills.SkillTools; +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.EnumMap; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.TreeSet; +import java.util.UUID; +import java.util.logging.Logger; import org.bukkit.OfflinePlayer; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.io.*; -import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; -import java.util.*; -import java.util.logging.Logger; - public final class FlatFileDatabaseManager implements DatabaseManager { public static final String IGNORED = "IGNORED"; public static final String LEGACY_INVALID_OLD_USERNAME = "_INVALID_OLD_USERNAME_'"; - private final @NotNull EnumMap> playerStatHash = new EnumMap<>(PrimarySkillType.class); - private final @NotNull List powerLevels = new ArrayList<>(); + private final @NotNull EnumMap> leaderboardMap = new EnumMap<>( + PrimarySkillType.class); + private @NotNull List powerLevels = new ArrayList<>(); private long lastUpdate = 0; private final @NotNull String usersFilePath; private final @NotNull Logger logger; @@ -80,10 +91,21 @@ 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 COOLDOWN_ARCHERY = 51; + public static final int EXP_MACES = 52; + public static final int SKILLS_MACES = 53; + public static final int COOLDOWN_MACES = 54; + //Update this everytime new data is added + public static final int DATA_ENTRY_COUNT = COOLDOWN_MACES + 1; - public static final int DATA_ENTRY_COUNT = OVERHAUL_LAST_LOGIN + 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; @@ -91,16 +113,17 @@ public final class FlatFileDatabaseManager implements DatabaseManager { this.startingLevel = startingLevel; this.testing = testing; - if(!usersFile.exists()) { + if (!usersFile.exists()) { initEmptyDB(); } - if(!testing) { + if (!testing) { List flatFileDataFlags = checkFileHealthAndStructure(); - if(flatFileDataFlags != null) { - if(flatFileDataFlags.size() > 0) { - logger.info("Detected "+flatFileDataFlags.size() + " data entries which need correction."); + if (flatFileDataFlags != null) { + if (!flatFileDataFlags.isEmpty()) { + logger.info("Detected " + flatFileDataFlags.size() + + " data entries which need correction."); } } @@ -108,7 +131,8 @@ public final class FlatFileDatabaseManager implements DatabaseManager { } } - 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); } @@ -142,8 +166,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { // If they're still around, rewrite them to the file. if (!powerless) { writer.append(line).append("\r\n"); - } - else { + } else { purgedUsers++; } } @@ -151,24 +174,21 @@ public final class FlatFileDatabaseManager implements DatabaseManager { // Write the new file out = new FileWriter(usersFilePath); out.write(writer.toString()); - } - catch (IOException e) { - logger.severe("Exception while reading " + usersFilePath + " (Are you sure you formatted it correctly?)" + e); - } - finally { + } catch (IOException e) { + logger.severe("Exception while reading " + usersFilePath + + " (Are you sure you formatted it correctly?)" + e); + } finally { if (in != null) { try { in.close(); - } - catch (IOException e) { + } catch (IOException e) { // Ignore } } if (out != null) { try { out.close(); - } - catch (IOException e) { + } catch (IOException e) { // Ignore } } @@ -212,7 +232,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { if (lastPlayed == -1) { OfflinePlayer player = mcMMO.p.getServer().getOfflinePlayer(uuid); - if(player.getLastPlayed() != 0) { + if (player.getLastPlayed() != 0) { lastPlayed = player.getLastPlayed(); rewrite = true; } @@ -224,7 +244,8 @@ public final class FlatFileDatabaseManager implements DatabaseManager { if (rewrite) { // Rewrite their data with a valid time character[OVERHAUL_LAST_LOGIN] = Long.toString(lastPlayed); - String newLine = org.apache.commons.lang.StringUtils.join(character, ":"); + String newLine = org.apache.commons.lang3.StringUtils.join(character, + ":"); writer.append(newLine).append("\r\n"); } else { writer.append(line).append("\r\n"); @@ -236,27 +257,24 @@ public final class FlatFileDatabaseManager implements DatabaseManager { out = new FileWriter(usersFilePath); out.write(writer.toString()); - if(testing) { - System.out.println(writer.toString()); + if (testing) { + System.out.println(writer); } - } - catch (IOException e) { - logger.severe("Exception while reading " + usersFilePath + " (Are you sure you formatted it correctly?)" + e); - } - finally { + } catch (IOException e) { + logger.severe("Exception while reading " + usersFilePath + + " (Are you sure you formatted it correctly?)" + e); + } finally { if (in != null) { try { in.close(); - } - catch (IOException e) { + } catch (IOException e) { // Ignore } } if (out != null) { try { out.close(); - } - catch (IOException e) { + } catch (IOException e) { // Ignore } } @@ -292,24 +310,21 @@ public final class FlatFileDatabaseManager implements DatabaseManager { out = new FileWriter(usersFilePath); // Write out the new file out.write(writer.toString()); - } - catch (Exception e) { - logger.severe("Exception while reading " + usersFilePath + " (Are you sure you formatted it correctly?)" + e); - } - finally { + } catch (Exception e) { + logger.severe("Exception while reading " + usersFilePath + + " (Are you sure you formatted it correctly?)" + e); + } finally { if (in != null) { try { in.close(); - } - catch (IOException e) { + } catch (IOException e) { // Ignore } } if (out != null) { try { out.close(); - } - catch (IOException e) { + } catch (IOException e) { // Ignore } } @@ -344,16 +359,17 @@ public final class FlatFileDatabaseManager implements DatabaseManager { boolean wroteUser = false; // While not at the end of the file while ((line = in.readLine()) != null) { - if(line.startsWith("#")) { + if (line.startsWith("#")) { writer.append(line).append("\r\n"); continue; } //Check for incomplete or corrupted data - if(!line.contains(":")) { + if (!line.contains(":")) { - if(!corruptDataFound) { - logger.severe("mcMMO found some unexpected or corrupted data in mcmmo.users and is removing it, it is possible some data has been lost."); + if (!corruptDataFound) { + logger.severe( + "mcMMO found some unexpected or corrupted data in mcmmo.users and is removing it, it is possible some data has been lost."); corruptDataFound = true; } @@ -363,10 +379,12 @@ public final class FlatFileDatabaseManager implements DatabaseManager { String[] splitData = line.split(":"); //This would be rare, but check the splitData for having enough entries to contain a UUID - if(splitData.length < UUID_INDEX) { //UUID have been in mcMMO DB for a very long time so any user without + if (splitData.length + < UUID_INDEX) { //UUID have been in mcMMO DB for a very long time so any user without - if(!corruptDataFound) { - logger.severe("mcMMO found some unexpected or corrupted data in mcmmo.users and is removing it, it is possible some data has been lost."); + if (!corruptDataFound) { + logger.severe( + "mcMMO found some unexpected or corrupted data in mcmmo.users and is removing it, it is possible some data has been lost."); corruptDataFound = true; } @@ -374,9 +392,10 @@ public final class FlatFileDatabaseManager implements DatabaseManager { } if (!(uuid != null - && splitData[UUID_INDEX].equalsIgnoreCase(uuid.toString())) - && !splitData[USERNAME_INDEX].equalsIgnoreCase(playerName)) { - writer.append(line).append("\r\n"); //Not the user so write it to file and move on + && splitData[UUID_INDEX].equalsIgnoreCase(uuid.toString())) + && !splitData[USERNAME_INDEX].equalsIgnoreCase(playerName)) { + writer.append(line) + .append("\r\n"); //Not the user so write it to file and move on } else { //User found writeUserToLine(profile, writer); @@ -387,7 +406,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { /* * If we couldn't find the user in the DB we need to add him */ - if(!wroteUser) { + if (!wroteUser) { writeUserToLine(profile, writer); } @@ -395,25 +414,21 @@ public final class FlatFileDatabaseManager implements DatabaseManager { out = new FileWriter(usersFilePath); out.write(writer.toString()); return true; - } - catch (Exception e) { + } catch (Exception e) { e.printStackTrace(); return false; - } - finally { + } finally { if (in != null) { try { in.close(); - } - catch (IOException e) { + } catch (IOException e) { // Ignore } } if (out != null) { try { out.close(); - } - catch (IOException e) { + } catch (IOException e) { // Ignore } } @@ -421,67 +436,137 @@ public final class FlatFileDatabaseManager implements DatabaseManager { } } - public void writeUserToLine(@NotNull PlayerProfile profile, @NotNull Appendable appendable) throws IOException { + public void writeUserToLine(@NotNull PlayerProfile profile, @NotNull Appendable appendable) + throws IOException { appendable.append(profile.getPlayerName()).append(":"); - appendable.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.MINING))).append(":"); + appendable.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.MINING))) + .append(":"); appendable.append(IGNORED).append(":"); appendable.append(IGNORED).append(":"); - appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.MINING))).append(":"); - appendable.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.WOODCUTTING))).append(":"); - appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.WOODCUTTING))).append(":"); - appendable.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.REPAIR))).append(":"); - appendable.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.UNARMED))).append(":"); - appendable.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.HERBALISM))).append(":"); - appendable.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.EXCAVATION))).append(":"); - appendable.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.ARCHERY))).append(":"); - appendable.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.SWORDS))).append(":"); + appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.MINING))) + .append(":"); + appendable.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.WOODCUTTING))) + .append(":"); + appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.WOODCUTTING))) + .append(":"); + appendable.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.REPAIR))) + .append(":"); + appendable.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.UNARMED))) + .append(":"); + appendable.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.HERBALISM))) + .append(":"); + appendable.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.EXCAVATION))) + .append(":"); + appendable.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.ARCHERY))) + .append(":"); + appendable.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.SWORDS))) + .append(":"); appendable.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.AXES))).append(":"); - appendable.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.ACROBATICS))).append(":"); - appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.REPAIR))).append(":"); - appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.UNARMED))).append(":"); - appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.HERBALISM))).append(":"); - appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.EXCAVATION))).append(":"); - appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.ARCHERY))).append(":"); - appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.SWORDS))).append(":"); - appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.AXES))).append(":"); - appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.ACROBATICS))).append(":"); + appendable.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.ACROBATICS))) + .append(":"); + appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.REPAIR))) + .append(":"); + appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.UNARMED))) + .append(":"); + appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.HERBALISM))) + .append(":"); + appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.EXCAVATION))) + .append(":"); + appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.ARCHERY))) + .append(":"); + appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.SWORDS))) + .append(":"); + appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.AXES))) + .append(":"); + appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.ACROBATICS))) + .append(":"); appendable.append(IGNORED).append(":"); - appendable.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.TAMING))).append(":"); - appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.TAMING))).append(":"); - appendable.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.BERSERK))).append(":"); - appendable.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.GIGA_DRILL_BREAKER))).append(":"); - appendable.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.TREE_FELLER))).append(":"); - appendable.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.GREEN_TERRA))).append(":"); - appendable.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.SERRATED_STRIKES))).append(":"); - appendable.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.SKULL_SPLITTER))).append(":"); - appendable.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.SUPER_BREAKER))).append(":"); + appendable.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.TAMING))) + .append(":"); + appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.TAMING))) + .append(":"); + appendable.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.BERSERK))) + .append(":"); + appendable.append( + String.valueOf(profile.getAbilityDATS(SuperAbilityType.GIGA_DRILL_BREAKER))) + .append(":"); + appendable.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.TREE_FELLER))) + .append(":"); + appendable.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.GREEN_TERRA))) + .append(":"); + appendable.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.SERRATED_STRIKES))) + .append(":"); + appendable.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.SKULL_SPLITTER))) + .append(":"); + appendable.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.SUPER_BREAKER))) + .append(":"); appendable.append(IGNORED).append(":"); - appendable.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.FISHING))).append(":"); - appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.FISHING))).append(":"); - appendable.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.BLAST_MINING))).append(":"); + appendable.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.FISHING))) + .append(":"); + appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.FISHING))) + .append(":"); + appendable.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.BLAST_MINING))) + .append(":"); appendable.append(IGNORED).append(":"); //Legacy last login appendable.append(IGNORED).append(":"); //mob health bar - appendable.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.ALCHEMY))).append(":"); - appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.ALCHEMY))).append(":"); - appendable.append(profile.getUniqueId() != null ? profile.getUniqueId().toString() : "NULL").append(":"); + appendable.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.ALCHEMY))) + .append(":"); + appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.ALCHEMY))) + .append(":"); + appendable.append(profile.getUniqueId() != null ? profile.getUniqueId().toString() : "NULL") + .append(":"); appendable.append(String.valueOf(profile.getScoreboardTipsShown())).append(":"); - appendable.append(String.valueOf(profile.getUniqueData(UniqueDataType.CHIMAERA_WING_DATS))).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(":"); + // public static final int COOLDOWN_SUPER_SHOTGUN = 49; + appendable.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.SUPER_SHOTGUN))) + .append(":"); + // public static final int COOLDOWN_TRIDENTS = 50; + appendable.append( + String.valueOf(profile.getAbilityDATS(SuperAbilityType.TRIDENTS_SUPER_ABILITY))) + .append(":"); + // public static final int COOLDOWN_ARCHERY = 51; + appendable.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.EXPLOSIVE_SHOT))) + .append(":"); + // public static final int EXP_MACES = 52; + appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.MACES))) + .append(":"); + // public static final int SKILLS_MACES = 53; + appendable.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.MACES))) + .append(":"); + // public static final int COOLDOWN_MACES = 54; + appendable.append( + String.valueOf(profile.getAbilityDATS(SuperAbilityType.MACES_SUPER_ABILITY))) + .append(":"); appendable.append("\r\n"); } - public @NotNull List readLeaderboard(@Nullable PrimarySkillType primarySkillType, int pageNumber, int statsPerPage) throws InvalidSkillException { + public @NotNull List readLeaderboard(@Nullable PrimarySkillType primarySkillType, + int pageNumber, int statsPerPage) throws InvalidSkillException { //Fix for a plugin that people are using that is throwing SQL errors - if(primarySkillType != null && SkillTools.isChildSkill(primarySkillType)) { - 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!"); + if (primarySkillType != null && SkillTools.isChildSkill(primarySkillType)) { + 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!"); } updateLeaderboards(); - List statsList = primarySkillType == null ? powerLevels : playerStatHash.get(primarySkillType); + List statsList = + primarySkillType == null ? powerLevels : leaderboardMap.get(primarySkillType); int fromIndex = (Math.max(pageNumber, 1) - 1) * statsPerPage; - return statsList.subList(Math.min(fromIndex, statsList.size()), Math.min(fromIndex + statsPerPage, statsList.size())); + return statsList.subList(Math.min(fromIndex, statsList.size()), + Math.min(fromIndex + statsPerPage, statsList.size())); } public @NotNull HashMap readRank(String playerName) { @@ -490,10 +575,9 @@ public final class FlatFileDatabaseManager implements DatabaseManager { HashMap skills = new HashMap<>(); for (PrimarySkillType skill : SkillTools.NON_CHILD_SKILLS) { - skills.put(skill, getPlayerRank(playerName, playerStatHash.get(skill))); + skills.put(skill, getPlayerRank(playerName, leaderboardMap.get(skill))); } - //TODO: Gross skills.put(null, getPlayerRank(playerName, powerLevels)); return skills; @@ -507,13 +591,14 @@ public final class FlatFileDatabaseManager implements DatabaseManager { PlayerProfile playerProfile = new PlayerProfile(playerName, uuid, true, startingLevel); synchronized (fileWritingLock) { - try(BufferedReader bufferedReader = new BufferedReader(new FileReader(usersFilePath))) { + try (BufferedReader bufferedReader = new BufferedReader( + new FileReader(usersFilePath))) { StringBuilder stringBuilder = new StringBuilder(); String line; //Build up the file - while((line = bufferedReader.readLine()) != null) { + while ((line = bufferedReader.readLine()) != null) { stringBuilder.append(line).append("\r\n"); } @@ -543,38 +628,36 @@ public final class FlatFileDatabaseManager implements DatabaseManager { return processUserQuery(getUserQuery(uuid, null)); } - private @NotNull UserQuery getUserQuery(@Nullable UUID uuid, @Nullable String playerName) throws NullPointerException { + private @NotNull UserQuery getUserQuery(@Nullable UUID uuid, @Nullable String playerName) + throws NullPointerException { boolean hasName = playerName != null && !playerName.equalsIgnoreCase("null"); - if(hasName && uuid != null) { + if (hasName && uuid != null) { return new UserQueryFull(playerName, uuid); } else if (uuid != null) { return new UserQueryUUIDImpl(uuid); - } else if(hasName) { + } else if (hasName) { return new UserQueryNameImpl(playerName); } else { - throw new NullPointerException("Both name and UUID cannot be null, at least one must be non-null!"); + throw new NullPointerException( + "Both name and UUID cannot be null, at least one must be non-null!"); } } /** - * Find and load a player by UUID/Name - * If the name isn't null and doesn't match the name in the DB, the players name is then replaced/updated + * Find and load a player by UUID/Name If the name isn't null and doesn't match the name in the + * DB, the players name is then replaced/updated * * @param userQuery the query * @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!"); - } + private @NotNull PlayerProfile processUserQuery(@NotNull UserQuery userQuery) + throws RuntimeException { + 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) { @@ -587,25 +670,22 @@ public final class FlatFileDatabaseManager implements DatabaseManager { in = new BufferedReader(new FileReader(usersFilePath)); String line; - while ((line = in.readLine()) != null) { - if(line.startsWith("#")) { + if (line.startsWith("#")) { continue; } - // Find if the line contains the player we want. String[] rawSplitData = line.split(":"); /* Don't read corrupt data */ - if(rawSplitData.length < (USERNAME_INDEX + 1)) { + if (rawSplitData.length < (USERNAME_INDEX + 1)) { continue; } - - //If we couldn't find anyone - if(playerName.equalsIgnoreCase(rawSplitData[USERNAME_INDEX])) { + // we found the player + if (playerName.equalsIgnoreCase(rawSplitData[USERNAME_INDEX])) { return loadFromLine(rawSplitData); } } @@ -624,7 +704,6 @@ public final class FlatFileDatabaseManager implements DatabaseManager { } } - //Return a new blank profile return new PlayerProfile(playerName, new UUID(0, 0), startingLevel); } @@ -640,24 +719,24 @@ public final class FlatFileDatabaseManager implements DatabaseManager { String line; while ((line = in.readLine()) != null) { - if(line.startsWith("#")) { + if (line.startsWith("#")) { continue; } // Find if the line contains the player we want. String[] rawSplitData = line.split(":"); /* Don't read corrupt data */ - if(rawSplitData.length < (UUID_INDEX + 1)) { + if (rawSplitData.length < (UUID_INDEX + 1)) { continue; } try { UUID fromDataUUID = UUID.fromString(rawSplitData[UUID_INDEX]); - if(fromDataUUID.equals(uuid)) { + if (fromDataUUID.equals(uuid)) { return loadFromLine(rawSplitData); } } catch (Exception e) { - if(testing) { + if (testing) { e.printStackTrace(); } } @@ -681,7 +760,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { * 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) { @@ -696,28 +775,31 @@ public final class FlatFileDatabaseManager implements DatabaseManager { String line; while ((line = in.readLine()) != null) { - if(line.startsWith("#")) { + if (line.startsWith("#")) { continue; } // Find if the line contains the player we want. String[] rawSplitData = line.split(":"); /* Don't read corrupt data */ - if(rawSplitData.length < (UUID_INDEX + 1)) { + if (rawSplitData.length < (UUID_INDEX + 1)) { continue; } try { UUID fromDataUUID = UUID.fromString(rawSplitData[UUID_INDEX]); - if(fromDataUUID.equals(uuid)) { + if (fromDataUUID.equals(uuid)) { //Matched UUID, now check if name matches String dbPlayerName = rawSplitData[USERNAME_INDEX]; boolean matchingName = dbPlayerName.equalsIgnoreCase(playerName); if (!matchingName) { - logger.warning("When loading user: "+playerName +" with UUID of (" + uuid.toString() - +") we found a mismatched name, the name in the DB will be replaced (DB name: "+dbPlayerName+")"); + 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; } @@ -726,7 +808,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { return loadFromLine(rawSplitData); } } catch (Exception e) { - if(testing) { + if (testing) { e.printStackTrace(); } } @@ -753,8 +835,9 @@ public final class FlatFileDatabaseManager implements DatabaseManager { return grabUnloadedProfile(uuid, playerName); //Create an empty new profile and return } - private @NotNull PlayerProfile grabUnloadedProfile(@NotNull UUID uuid, @Nullable String playerName) { - if(playerName == null) { + private @NotNull PlayerProfile grabUnloadedProfile(@NotNull UUID uuid, + @Nullable String playerName) { + if (playerName == null) { playerName = ""; //No name for you boy! } @@ -773,7 +856,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { String line; while ((line = in.readLine()) != null) { - if(line.startsWith("#")) { + if (line.startsWith("#")) { continue; } @@ -787,16 +870,13 @@ public final class FlatFileDatabaseManager implements DatabaseManager { convertedUsers++; Misc.printProgress(convertedUsers, progressInterval, startMillis); } - } - catch (Exception e) { + } catch (Exception e) { e.printStackTrace(); - } - finally { + } finally { if (in != null) { try { in.close(); - } - catch (IOException e) { + } catch (IOException e) { // Ignore } } @@ -836,25 +916,22 @@ public final class FlatFileDatabaseManager implements DatabaseManager { out = new FileWriter(usersFilePath); // Write out the new file out.write(writer.toString()); - } - catch (Exception e) { - logger.severe("Exception while reading " + usersFilePath + " (Are you sure you formatted it correctly?)" + e); - } - finally { + } catch (Exception e) { + logger.severe("Exception while reading " + usersFilePath + + " (Are you sure you formatted it correctly?)" + e); + } finally { LogUtils.debug(logger, i + " entries written while saving UUID for " + userName); if (in != null) { try { in.close(); - } - catch (IOException e) { + } catch (IOException e) { // Ignore } } if (out != null) { try { out.close(); - } - catch (IOException e) { + } catch (IOException e) { // Ignore } } @@ -877,15 +954,18 @@ public final class FlatFileDatabaseManager implements DatabaseManager { while (((line = in.readLine()) != null)) { String[] character = line.split(":"); - if (!fetchedUUIDs.isEmpty() && fetchedUUIDs.containsKey(character[USERNAME_INDEX])) { + if (!fetchedUUIDs.isEmpty() && fetchedUUIDs.containsKey( + character[USERNAME_INDEX])) { if (character.length < 42) { - logger.severe("Could not update UUID for " + character[USERNAME_INDEX] + "!"); + logger.severe( + "Could not update UUID for " + character[USERNAME_INDEX] + "!"); logger.severe("Database entry is invalid."); continue; } - character[UUID_INDEX] = fetchedUUIDs.remove(character[USERNAME_INDEX]).toString(); - line = org.apache.commons.lang.StringUtils.join(character, ":") + ":"; + character[UUID_INDEX] = fetchedUUIDs.remove(character[USERNAME_INDEX]) + .toString(); + line = org.apache.commons.lang3.StringUtils.join(character, ":") + ":"; } i++; @@ -894,25 +974,22 @@ public final class FlatFileDatabaseManager implements DatabaseManager { out = new FileWriter(usersFilePath); // Write out the new file out.write(writer.toString()); - } - catch (Exception e) { - logger.severe("Exception while reading " + usersFilePath + " (Are you sure you formatted it correctly?)" + e); - } - finally { + } catch (Exception e) { + logger.severe("Exception while reading " + usersFilePath + + " (Are you sure you formatted it correctly?)" + e); + } finally { LogUtils.debug(logger, i + " entries written while saving UUID batch"); if (in != null) { try { in.close(); - } - catch (IOException e) { + } catch (IOException e) { // Ignore } } if (out != null) { try { out.close(); - } - catch (IOException e) { + } catch (IOException e) { // Ignore } } @@ -936,16 +1013,13 @@ public final class FlatFileDatabaseManager implements DatabaseManager { String[] character = line.split(":"); users.add(character[USERNAME_INDEX]); } - } - catch (Exception e) { + } catch (Exception e) { e.printStackTrace(); - } - finally { + } finally { if (in != null) { try { in.close(); - } - catch (IOException e) { + } catch (IOException e) { // Ignore } } @@ -964,22 +1038,24 @@ public final class FlatFileDatabaseManager implements DatabaseManager { } lastUpdate = System.currentTimeMillis(); // Log when the last update was run - powerLevels.clear(); // Clear old values from the power levels - // Initialize lists - List mining = new ArrayList<>(); - List woodcutting = new ArrayList<>(); - List herbalism = new ArrayList<>(); - List excavation = new ArrayList<>(); - List acrobatics = new ArrayList<>(); - List repair = new ArrayList<>(); - List swords = new ArrayList<>(); - List axes = new ArrayList<>(); - List archery = new ArrayList<>(); - List unarmed = new ArrayList<>(); - List taming = new ArrayList<>(); - List fishing = new ArrayList<>(); - List alchemy = new ArrayList<>(); + TreeSet powerLevelStats = new TreeSet<>(); + TreeSet mining = new TreeSet<>(); + TreeSet woodcutting = new TreeSet<>(); + TreeSet herbalism = new TreeSet<>(); + TreeSet excavation = new TreeSet<>(); + TreeSet acrobatics = new TreeSet<>(); + TreeSet repair = new TreeSet<>(); + TreeSet swords = new TreeSet<>(); + TreeSet axes = new TreeSet<>(); + TreeSet archery = new TreeSet<>(); + TreeSet unarmed = new TreeSet<>(); + TreeSet taming = new TreeSet<>(); + TreeSet fishing = new TreeSet<>(); + TreeSet alchemy = new TreeSet<>(); + TreeSet crossbows = new TreeSet<>(); + TreeSet tridents = new TreeSet<>(); + TreeSet maces = new TreeSet<>(); BufferedReader in = null; String playerName = null; @@ -991,8 +1067,9 @@ public final class FlatFileDatabaseManager implements DatabaseManager { while ((line = in.readLine()) != null) { - if(line.startsWith("#")) + if (line.startsWith("#")) { continue; + } String[] data = line.split(":"); playerName = data[USERNAME_INDEX]; @@ -1000,32 +1077,45 @@ public final class FlatFileDatabaseManager implements DatabaseManager { Map skills = getSkillMapFromLine(data); - powerLevel += putStat(acrobatics, playerName, skills.get(PrimarySkillType.ACROBATICS)); - powerLevel += putStat(alchemy, playerName, skills.get(PrimarySkillType.ALCHEMY)); - powerLevel += putStat(archery, playerName, skills.get(PrimarySkillType.ARCHERY)); + powerLevel += putStat(acrobatics, playerName, + skills.get(PrimarySkillType.ACROBATICS)); + powerLevel += putStat(alchemy, playerName, + skills.get(PrimarySkillType.ALCHEMY)); + powerLevel += putStat(archery, playerName, + skills.get(PrimarySkillType.ARCHERY)); powerLevel += putStat(axes, playerName, skills.get(PrimarySkillType.AXES)); - powerLevel += putStat(excavation, playerName, skills.get(PrimarySkillType.EXCAVATION)); - powerLevel += putStat(fishing, playerName, skills.get(PrimarySkillType.FISHING)); - powerLevel += putStat(herbalism, playerName, skills.get(PrimarySkillType.HERBALISM)); + powerLevel += putStat(excavation, playerName, + skills.get(PrimarySkillType.EXCAVATION)); + powerLevel += putStat(fishing, playerName, + skills.get(PrimarySkillType.FISHING)); + powerLevel += putStat(herbalism, playerName, + skills.get(PrimarySkillType.HERBALISM)); powerLevel += putStat(mining, playerName, skills.get(PrimarySkillType.MINING)); powerLevel += putStat(repair, playerName, skills.get(PrimarySkillType.REPAIR)); powerLevel += putStat(swords, playerName, skills.get(PrimarySkillType.SWORDS)); 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(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)); + powerLevel += putStat(maces, playerName, skills.get(PrimarySkillType.MACES)); - putStat(powerLevels, playerName, powerLevel); + putStat(powerLevelStats, playerName, powerLevel); } - } - catch (Exception e) { - logger.severe("Exception while reading " + usersFilePath + " during user " + playerName + " (Are you sure you formatted it correctly?) " + e); + } catch (Exception e) { + logger.severe( + "Exception while reading " + usersFilePath + " during user " + playerName + + " (Are you sure you formatted it correctly?) " + e); return LeaderboardStatus.FAILED; } finally { if (in != null) { try { in.close(); - } - catch (IOException e) { + } catch (IOException e) { // Ignore } } @@ -1033,36 +1123,23 @@ public final class FlatFileDatabaseManager implements DatabaseManager { } - SkillComparator c = new SkillComparator(); - - mining.sort(c); - woodcutting.sort(c); - repair.sort(c); - unarmed.sort(c); - herbalism.sort(c); - excavation.sort(c); - archery.sort(c); - swords.sort(c); - axes.sort(c); - acrobatics.sort(c); - taming.sort(c); - fishing.sort(c); - alchemy.sort(c); - powerLevels.sort(c); - - playerStatHash.put(PrimarySkillType.MINING, mining); - playerStatHash.put(PrimarySkillType.WOODCUTTING, woodcutting); - playerStatHash.put(PrimarySkillType.REPAIR, repair); - playerStatHash.put(PrimarySkillType.UNARMED, unarmed); - playerStatHash.put(PrimarySkillType.HERBALISM, herbalism); - playerStatHash.put(PrimarySkillType.EXCAVATION, excavation); - playerStatHash.put(PrimarySkillType.ARCHERY, archery); - playerStatHash.put(PrimarySkillType.SWORDS, swords); - playerStatHash.put(PrimarySkillType.AXES, axes); - playerStatHash.put(PrimarySkillType.ACROBATICS, acrobatics); - playerStatHash.put(PrimarySkillType.TAMING, taming); - playerStatHash.put(PrimarySkillType.FISHING, fishing); - playerStatHash.put(PrimarySkillType.ALCHEMY, alchemy); + powerLevels = List.copyOf(powerLevelStats); + leaderboardMap.put(PrimarySkillType.MINING, List.copyOf(mining)); + leaderboardMap.put(PrimarySkillType.WOODCUTTING, List.copyOf(woodcutting)); + leaderboardMap.put(PrimarySkillType.REPAIR, List.copyOf(repair)); + leaderboardMap.put(PrimarySkillType.UNARMED, List.copyOf(unarmed)); + leaderboardMap.put(PrimarySkillType.HERBALISM, List.copyOf(herbalism)); + leaderboardMap.put(PrimarySkillType.EXCAVATION, List.copyOf(excavation)); + leaderboardMap.put(PrimarySkillType.ARCHERY, List.copyOf(archery)); + leaderboardMap.put(PrimarySkillType.SWORDS, List.copyOf(swords)); + leaderboardMap.put(PrimarySkillType.AXES, List.copyOf(axes)); + leaderboardMap.put(PrimarySkillType.ACROBATICS, List.copyOf(acrobatics)); + leaderboardMap.put(PrimarySkillType.TAMING, List.copyOf(taming)); + leaderboardMap.put(PrimarySkillType.FISHING, List.copyOf(fishing)); + leaderboardMap.put(PrimarySkillType.ALCHEMY, List.copyOf(alchemy)); + leaderboardMap.put(PrimarySkillType.CROSSBOWS, List.copyOf(crossbows)); + leaderboardMap.put(PrimarySkillType.TRIDENTS, List.copyOf(tridents)); + leaderboardMap.put(PrimarySkillType.MACES, List.copyOf(maces)); return LeaderboardStatus.UPDATED; } @@ -1073,17 +1150,19 @@ public final class FlatFileDatabaseManager implements DatabaseManager { try { // Open the file to write the player bufferedWriter = new BufferedWriter(new FileWriter(usersFilePath, true)); - DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("MM/dd/yyyy HH:mm"); + DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern( + "MM/dd/yyyy HH:mm"); LocalDateTime localDateTime = LocalDateTime.now(); - bufferedWriter.append("# mcMMO Database created on ").append(localDateTime.format(dateTimeFormatter)).append("\r\n"); //Empty file + bufferedWriter.append("# mcMMO Database created on ") + .append(localDateTime.format(dateTimeFormatter)) + .append("\r\n"); //Empty file } catch (Exception e) { e.printStackTrace(); } finally { if (bufferedWriter != null) { try { bufferedWriter.close(); - } - catch (IOException e) { + } catch (IOException e) { // Ignore } } @@ -1094,7 +1173,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { 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; @@ -1113,26 +1192,29 @@ public final class FlatFileDatabaseManager implements DatabaseManager { //Analyze the data while ((currentLine = bufferedReader.readLine()) != null) { //Commented lines - if(currentLine.startsWith("#") && dbCommentDate == null) { //The first commented line in the file is likely to be our note about when the file was created + if (currentLine.startsWith("#") && dbCommentDate + == null) { //The first commented line in the file is likely to be our note about when the file was created dbCommentDate = currentLine; continue; } - if(currentLine.isEmpty()) + if (currentLine.isEmpty()) { continue; + } //TODO: We are never passing empty lines, should we remove the flag for them? dataProcessor.processData(currentLine); } //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); //Write data to file - if(dbCommentDate != null) + if (dbCommentDate != null) { fileWriter.write(dbCommentDate + "\r\n"); + } fileWriter.write(dataProcessor.processDataForSave().toString()); } @@ -1144,7 +1226,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { } } - if(flagsFound == null || flagsFound.size() == 0) { + if (flagsFound == null || flagsFound.isEmpty()) { return null; } else { return flagsFound; @@ -1152,11 +1234,10 @@ public final class FlatFileDatabaseManager implements DatabaseManager { } private void closeResources(BufferedReader bufferedReader, FileWriter fileWriter) { - if(bufferedReader != null) { + if (bufferedReader != null) { try { bufferedReader.close(); - } - catch (IOException e) { + } catch (IOException e) { e.printStackTrace(); } } @@ -1164,8 +1245,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { if (fileWriter != null) { try { fileWriter.close(); - } - catch (IOException e) { + } catch (IOException e) { e.printStackTrace(); } } @@ -1179,7 +1259,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { int currentPos = 1; for (PlayerStat stat : statsList) { - if (stat.name.equalsIgnoreCase(playerName)) { + if (stat.playerName().equalsIgnoreCase(playerName)) { return currentPos; } @@ -1189,74 +1269,101 @@ public final class FlatFileDatabaseManager implements DatabaseManager { return null; } - private int putStat(List statList, String playerName, int statValue) { + private int putStat(TreeSet statList, String playerName, int statValue) { statList.add(new PlayerStat(playerName, statValue)); return statValue; } - private static class SkillComparator implements Comparator { - @Override - public int compare(PlayerStat o1, PlayerStat o2) { - return (o2.statVal - o1.statVal); - } - } - private PlayerProfile loadFromLine(@NotNull String[] character) { - Map skills = getSkillMapFromLine(character); // Skill levels - Map skillsXp = new EnumMap<>(PrimarySkillType.class); // Skill & XP - Map skillsDATS = new EnumMap<>(SuperAbilityType.class); // Ability & Cooldown + Map skills = getSkillMapFromLine(character); // Skill levels + Map skillsXp = new EnumMap<>( + PrimarySkillType.class); // Skill & XP + Map skillsDATS = new EnumMap<>( + SuperAbilityType.class); // Ability & Cooldown Map uniquePlayerDataMap = new EnumMap<>(UniqueDataType.class); int scoreboardTipsShown; long lastLogin; String username = character[USERNAME_INDEX]; - tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.TAMING, EXP_TAMING, username); - tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.MINING, EXP_MINING, username); - tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.REPAIR, EXP_REPAIR, username); - tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.WOODCUTTING, EXP_WOODCUTTING, username); - tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.UNARMED, EXP_UNARMED, username); - tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.HERBALISM, EXP_HERBALISM, username); - tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.EXCAVATION, EXP_EXCAVATION, username); - tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.ARCHERY, EXP_ARCHERY, username); - tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.SWORDS, EXP_SWORDS, username); - tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.AXES, EXP_AXES, username); - 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.TAMING, EXP_TAMING, + username); + tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.MINING, EXP_MINING, + username); + tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.REPAIR, EXP_REPAIR, + username); + tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.WOODCUTTING, + EXP_WOODCUTTING, username); + tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.UNARMED, + EXP_UNARMED, username); + tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.HERBALISM, + EXP_HERBALISM, username); + tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.EXCAVATION, + EXP_EXCAVATION, username); + tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.ARCHERY, + EXP_ARCHERY, username); + tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.SWORDS, EXP_SWORDS, + username); + tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.AXES, EXP_AXES, + username); + 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); + tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.MACES, EXP_MACES, + username); // Taming - Unused - tryLoadSkillCooldownFromRawData(skillsDATS, character, SuperAbilityType.SUPER_BREAKER, COOLDOWN_SUPER_BREAKER, username); + tryLoadSkillCooldownFromRawData(skillsDATS, character, SuperAbilityType.SUPER_BREAKER, + COOLDOWN_SUPER_BREAKER, username); // Repair - Unused - tryLoadSkillCooldownFromRawData(skillsDATS, character, SuperAbilityType.TREE_FELLER, COOLDOWN_TREE_FELLER, username); - 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.SERRATED_STRIKES, COOLDOWN_SERRATED_STRIKES, username); - tryLoadSkillCooldownFromRawData(skillsDATS, character, SuperAbilityType.SKULL_SPLITTER, COOLDOWN_SKULL_SPLITTER, username); + tryLoadSkillCooldownFromRawData(skillsDATS, character, SuperAbilityType.TREE_FELLER, + COOLDOWN_TREE_FELLER, username); + 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); + 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 - tryLoadSkillCooldownFromRawData(skillsDATS, character, SuperAbilityType.BLAST_MINING, COOLDOWN_BLAST_MINING, username); + tryLoadSkillCooldownFromRawData(skillsDATS, character, SuperAbilityType.BLAST_MINING, + COOLDOWN_BLAST_MINING, username); + tryLoadSkillCooldownFromRawData(skillsDATS, character, SuperAbilityType.SUPER_SHOTGUN, + COOLDOWN_SUPER_SHOTGUN, username); + tryLoadSkillCooldownFromRawData(skillsDATS, character, + SuperAbilityType.TRIDENTS_SUPER_ABILITY, COOLDOWN_TRIDENTS, username); + tryLoadSkillCooldownFromRawData(skillsDATS, character, SuperAbilityType.MACES_SUPER_ABILITY, + COOLDOWN_MACES, username); UUID uuid; try { uuid = UUID.fromString(character[UUID_INDEX]); - } - catch (Exception e) { + } catch (Exception e) { uuid = null; } try { scoreboardTipsShown = Integer.parseInt(character[SCOREBOARD_TIPS]); - } - catch (Exception e) { + } catch (Exception e) { scoreboardTipsShown = 0; } try { - uniquePlayerDataMap.put(UniqueDataType.CHIMAERA_WING_DATS, Integer.valueOf(character[COOLDOWN_CHIMAERA_WING])); - } - catch (Exception e) { + uniquePlayerDataMap.put(UniqueDataType.CHIMAERA_WING_DATS, + Integer.valueOf(character[COOLDOWN_CHIMAERA_WING])); + } catch (Exception e) { uniquePlayerDataMap.put(UniqueDataType.CHIMAERA_WING_DATS, 0); } @@ -1266,57 +1373,98 @@ public final class FlatFileDatabaseManager implements DatabaseManager { lastLogin = -1; } - return new PlayerProfile(username, uuid, skills, skillsXp, skillsDATS, scoreboardTipsShown, uniquePlayerDataMap, lastLogin); + 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); } } - private void tryLoadSkillFloatValuesFromRawData(@NotNull Map skillMap, @NotNull String[] character, @NotNull PrimarySkillType primarySkillType, int index, @NotNull String userName) { + private void tryLoadSkillFloatValuesFromRawData(@NotNull Map skillMap, + @NotNull String[] character, @NotNull PrimarySkillType primarySkillType, int index, + @NotNull String userName) { try { float valueFromString = Integer.parseInt(character[index]); skillMap.put(primarySkillType, valueFromString); } catch (NumberFormatException e) { skillMap.put(primarySkillType, 0F); - logger.severe("Data corruption when trying to load the value for skill "+primarySkillType+" for player named " + userName+ " setting value to zero"); + logger.severe( + "Data corruption when trying to load the value for skill " + primarySkillType + + " for player named " + userName + " setting value to zero"); e.printStackTrace(); } } - private void tryLoadSkillIntValuesFromRawData(@NotNull Map skillMap, @NotNull String[] character, @NotNull PrimarySkillType primarySkillType, int index, @NotNull String userName) { + private void tryLoadSkillIntValuesFromRawData(@NotNull Map skillMap, + @NotNull String[] character, @NotNull PrimarySkillType primarySkillType, int index, + @NotNull String userName) { try { int valueFromString = Integer.parseInt(character[index]); skillMap.put(primarySkillType, valueFromString); + } catch (ArrayIndexOutOfBoundsException e) { + // TODO: Add debug message + // set to 0 when data not found + skillMap.put(primarySkillType, 0); } catch (NumberFormatException e) { skillMap.put(primarySkillType, 0); - logger.severe("Data corruption when trying to load the value for skill "+primarySkillType+" for player named " + userName+ " setting value to zero"); + logger.severe( + "Data corruption when trying to load the value for skill " + primarySkillType + + " for player named " + userName + " setting value to zero"); e.printStackTrace(); } } - private @NotNull Map getSkillMapFromLine(@NotNull String[] character) { - EnumMap skills = new EnumMap<>(PrimarySkillType.class); // Skill & Level + private @NotNull Map getSkillMapFromLine( + @NotNull String[] character) { + EnumMap skills = new EnumMap<>( + PrimarySkillType.class); // Skill & Level String username = character[USERNAME_INDEX]; - tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.ACROBATICS, SKILLS_ACROBATICS, username); - tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.TAMING, SKILLS_TAMING, username); - tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.MINING, SKILLS_MINING, username); - tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.REPAIR, SKILLS_REPAIR, username); - tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.WOODCUTTING, SKILLS_WOODCUTTING, username); - tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.UNARMED, SKILLS_UNARMED, username); - tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.HERBALISM, SKILLS_HERBALISM, username); - tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.EXCAVATION, SKILLS_EXCAVATION, username); - tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.ARCHERY, SKILLS_ARCHERY, username); - tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.SWORDS, SKILLS_SWORDS, username); - tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.AXES, SKILLS_AXES, username); - tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.FISHING, SKILLS_FISHING, username); - tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.ALCHEMY, SKILLS_ALCHEMY, username); + tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.ACROBATICS, + SKILLS_ACROBATICS, username); + tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.TAMING, SKILLS_TAMING, + username); + tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.MINING, SKILLS_MINING, + username); + tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.REPAIR, SKILLS_REPAIR, + username); + tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.WOODCUTTING, + SKILLS_WOODCUTTING, username); + tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.UNARMED, + SKILLS_UNARMED, username); + tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.HERBALISM, + SKILLS_HERBALISM, username); + tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.EXCAVATION, + SKILLS_EXCAVATION, username); + tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.ARCHERY, + SKILLS_ARCHERY, username); + tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.SWORDS, SKILLS_SWORDS, + username); + tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.AXES, SKILLS_AXES, + username); + tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.FISHING, + SKILLS_FISHING, username); + tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.ALCHEMY, + SKILLS_ALCHEMY, username); + tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.CROSSBOWS, + SKILLS_CROSSBOWS, username); + tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.TRIDENTS, + SKILLS_TRIDENTS, username); + tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.MACES, SKILLS_MACES, + username); return skills; } @@ -1330,5 +1478,6 @@ public final class FlatFileDatabaseManager implements DatabaseManager { } @Override - public void onDisable() { } + public void onDisable() { + } } diff --git a/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java b/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java index 0be013e7e..50866edb1 100644 --- a/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java @@ -14,6 +14,22 @@ import com.gmail.nossr50.runnables.database.UUIDUpdateAsyncTask; import com.gmail.nossr50.util.LogUtils; import com.gmail.nossr50.util.Misc; import com.gmail.nossr50.util.skills.SkillTools; +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.EnumMap; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.locks.ReentrantLock; +import java.util.logging.Logger; import org.apache.tomcat.jdbc.pool.DataSource; import org.apache.tomcat.jdbc.pool.PoolProperties; import org.bukkit.OfflinePlayer; @@ -21,10 +37,6 @@ import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.sql.*; -import java.util.*; -import java.util.concurrent.locks.ReentrantLock; - public final class SQLDatabaseManager implements DatabaseManager { private static final String ALL_QUERY_VERSION = "total"; public static final String MOBHEALTHBAR_VARCHAR = "VARCHAR(50)"; @@ -32,6 +44,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<>(); @@ -45,24 +58,20 @@ 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()) + SQLDatabaseManager(Logger logger, String driverPath, boolean h2) { + this.logger = logger; + this.h2 = h2; + String connectionString = getConnectionString(h2); + + if (!h2 && mcMMO.p.getGeneralConfig().getMySQLPublicKeyRetrieval()) { connectionString += - "?verifyServerCertificate=false"+ - "&useSSL=true"+ - "&requireSSL=true"; - else - connectionString+= - "?useSSL=false"; - - if(mcMMO.p.getGeneralConfig().getMySQLPublicKeyRetrieval()) { - connectionString+= "&allowPublicKeyRetrieval=true"; } @@ -76,7 +85,7 @@ public final class SQLDatabaseManager implements DatabaseManager { } 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. @@ -89,8 +98,10 @@ public final class SQLDatabaseManager implements DatabaseManager { poolProperties.setUrl(connectionString); poolProperties.setUsername(mcMMO.p.getGeneralConfig().getMySQLUserName()); poolProperties.setPassword(mcMMO.p.getGeneralConfig().getMySQLUserPassword()); - poolProperties.setMaxIdle(mcMMO.p.getGeneralConfig().getMySQLMaxPoolSize(PoolIdentifier.MISC)); - poolProperties.setMaxActive(mcMMO.p.getGeneralConfig().getMySQLMaxConnections(PoolIdentifier.MISC)); + poolProperties.setMaxIdle( + mcMMO.p.getGeneralConfig().getMySQLMaxPoolSize(PoolIdentifier.MISC)); + poolProperties.setMaxActive( + mcMMO.p.getGeneralConfig().getMySQLMaxConnections(PoolIdentifier.MISC)); poolProperties.setInitialSize(0); poolProperties.setMaxWait(-1); poolProperties.setRemoveAbandoned(true); @@ -105,8 +116,10 @@ public final class SQLDatabaseManager implements DatabaseManager { poolProperties.setUsername(mcMMO.p.getGeneralConfig().getMySQLUserName()); poolProperties.setPassword(mcMMO.p.getGeneralConfig().getMySQLUserPassword()); poolProperties.setInitialSize(0); - poolProperties.setMaxIdle(mcMMO.p.getGeneralConfig().getMySQLMaxPoolSize(PoolIdentifier.SAVE)); - poolProperties.setMaxActive(mcMMO.p.getGeneralConfig().getMySQLMaxConnections(PoolIdentifier.SAVE)); + poolProperties.setMaxIdle( + mcMMO.p.getGeneralConfig().getMySQLMaxPoolSize(PoolIdentifier.SAVE)); + poolProperties.setMaxActive( + mcMMO.p.getGeneralConfig().getMySQLMaxConnections(PoolIdentifier.SAVE)); poolProperties.setMaxWait(-1); poolProperties.setRemoveAbandoned(true); poolProperties.setRemoveAbandonedTimeout(60); @@ -120,8 +133,10 @@ public final class SQLDatabaseManager implements DatabaseManager { poolProperties.setUsername(mcMMO.p.getGeneralConfig().getMySQLUserName()); poolProperties.setPassword(mcMMO.p.getGeneralConfig().getMySQLUserPassword()); poolProperties.setInitialSize(0); - poolProperties.setMaxIdle(mcMMO.p.getGeneralConfig().getMySQLMaxPoolSize(PoolIdentifier.LOAD)); - poolProperties.setMaxActive(mcMMO.p.getGeneralConfig().getMySQLMaxConnections(PoolIdentifier.LOAD)); + poolProperties.setMaxIdle( + mcMMO.p.getGeneralConfig().getMySQLMaxPoolSize(PoolIdentifier.LOAD)); + poolProperties.setMaxActive( + mcMMO.p.getGeneralConfig().getMySQLMaxConnections(PoolIdentifier.LOAD)); poolProperties.setMaxWait(-1); poolProperties.setRemoveAbandoned(true); poolProperties.setRemoveAbandonedTimeout(60); @@ -133,9 +148,34 @@ public final class SQLDatabaseManager implements DatabaseManager { 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; + } + + // TODO: unit tests public int purgePowerlessUsers() { massUpdateLock.lock(); - mcMMO.p.getLogger().info("Purging powerless users..."); + logger.info("Purging powerless users..."); Connection connection = null; Statement statement = null; @@ -149,29 +189,40 @@ public final class SQLDatabaseManager implements DatabaseManager { + "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 AND maces = 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`)"); - statement.executeUpdate("DELETE FROM `" + tablePrefix + "cooldowns` WHERE NOT EXISTS (SELECT * FROM `" + tablePrefix + "skills` `s` WHERE `" + tablePrefix + "cooldowns`.`user_id` = `s`.`user_id`)"); - statement.executeUpdate("DELETE FROM `" + tablePrefix + "users` WHERE NOT EXISTS (SELECT * FROM `" + tablePrefix + "skills` `s` WHERE `" + tablePrefix + "users`.`id` = `s`.`user_id`)"); - } - catch (SQLException ex) { + 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`)"); + statement.executeUpdate( + "DELETE FROM `" + tablePrefix + "cooldowns` WHERE NOT EXISTS (SELECT * FROM `" + + tablePrefix + "skills` `s` WHERE `" + tablePrefix + + "cooldowns`.`user_id` = `s`.`user_id`)"); + statement.executeUpdate( + "DELETE FROM `" + tablePrefix + "users` WHERE NOT EXISTS (SELECT * FROM `" + + tablePrefix + "skills` `s` WHERE `" + tablePrefix + + "users`.`id` = `s`.`user_id`)"); + } catch (SQLException ex) { printErrors(ex); - } - finally { + } finally { tryClose(statement); tryClose(connection); 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; @@ -181,14 +232,15 @@ public final class SQLDatabaseManager implements DatabaseManager { connection = getConnection(PoolIdentifier.MISC); statement = connection.createStatement(); - purged = statement.executeUpdate("DELETE FROM u, e, h, s, c USING " + tablePrefix + "users u " + - "JOIN " + tablePrefix + "experience e ON (u.id = e.user_id) " + - "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 ((UNIX_TIMESTAMP() - lastlogin) > " + mcMMO.p.getPurgeTime() + ")"); - } - catch (SQLException ex) { + purged = statement.executeUpdate( + "DELETE FROM u, e, h, s, c USING " + tablePrefix + "users u " + + "JOIN " + tablePrefix + "experience e ON (u.id = e.user_id) " + + "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 ((UNIX_TIMESTAMP() - lastlogin) > " + mcMMO.p.getPurgeTime() + + ")"); + } catch (SQLException ex) { printErrors(ex); } finally { tryClose(statement); @@ -196,7 +248,7 @@ public final class SQLDatabaseManager implements DatabaseManager { 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) { @@ -212,23 +264,22 @@ public final class SQLDatabaseManager implements DatabaseManager { "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); success = statement.executeUpdate() != 0; - } - catch (SQLException ex) { + } catch (SQLException ex) { printErrors(ex); - } - finally { + } finally { tryClose(statement); tryClose(connection); } if (success) { - if(uuid != null) + if (uuid != null) { cleanupUser(uuid); + } Misc.profileCleanup(playerName); } @@ -253,17 +304,18 @@ public final class SQLDatabaseManager implements DatabaseManager { 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; } } - statement = connection.prepareStatement("UPDATE " + tablePrefix + "users SET lastlogin = UNIX_TIMESTAMP() WHERE id = ?"); + statement = connection.prepareStatement("UPDATE " + tablePrefix + + "users SET lastlogin = UNIX_TIMESTAMP() WHERE id = ?"); statement.setInt(1, id); 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; } @@ -271,7 +323,7 @@ public final class SQLDatabaseManager implements DatabaseManager { + " taming = ?, mining = ?, repair = ?, woodcutting = ?" + ", unarmed = ?, herbalism = ?, excavation = ?" + ", archery = ?, swords = ?, axes = ?, acrobatics = ?" - + ", fishing = ?, alchemy = ?, total = ? WHERE user_id = ?"); + + ", fishing = ?, alchemy = ?, crossbows = ?, tridents = ?, maces = ?, 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)); @@ -285,15 +337,19 @@ public final class SQLDatabaseManager implements DatabaseManager { 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)); + statement.setInt(16, profile.getSkillLevel(PrimarySkillType.MACES)); int total = 0; - for (PrimarySkillType primarySkillType : SkillTools.NON_CHILD_SKILLS) + for (PrimarySkillType primarySkillType : SkillTools.NON_CHILD_SKILLS) { total += profile.getSkillLevel(primarySkillType); - statement.setInt(14, total); - statement.setInt(15, id); + } + statement.setInt(17, total); + statement.setInt(18, id); 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; } @@ -301,7 +357,7 @@ public final class SQLDatabaseManager implements DatabaseManager { + " taming = ?, mining = ?, repair = ?, woodcutting = ?" + ", unarmed = ?, herbalism = ?, excavation = ?" + ", archery = ?, swords = ?, axes = ?, acrobatics = ?" - + ", fishing = ?, alchemy = ? WHERE user_id = ?"); + + ", fishing = ?, alchemy = ?, crossbows = ?, tridents = ?, maces = ? WHERE user_id = ?"); statement.setInt(1, profile.getSkillXpLevel(PrimarySkillType.TAMING)); statement.setInt(2, profile.getSkillXpLevel(PrimarySkillType.MINING)); statement.setInt(3, profile.getSkillXpLevel(PrimarySkillType.REPAIR)); @@ -315,18 +371,22 @@ public final class SQLDatabaseManager implements DatabaseManager { 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, profile.getSkillXpLevel(PrimarySkillType.MACES)); + statement.setInt(17, id); 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; } 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 = ?, maces = ? 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)); @@ -336,29 +396,31 @@ public final class SQLDatabaseManager implements DatabaseManager { 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.setLong(12, profile.getAbilityDATS(SuperAbilityType.MACES_SUPER_ABILITY)); + statement.setInt(13, id); 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; } - statement = connection.prepareStatement("UPDATE " + tablePrefix + "huds SET mobhealthbar = ?, scoreboardtips = ? WHERE user_id = ?"); + statement = connection.prepareStatement("UPDATE " + tablePrefix + + "huds SET mobhealthbar = ?, scoreboardtips = ? WHERE user_id = ?"); statement.setString(1, MobHealthbarType.HEARTS.name()); statement.setInt(2, profile.getScoreboardTipsShown()); statement.setInt(3, id); 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; } - } - catch (SQLException ex) { + } catch (SQLException ex) { printErrors(ex); - } - finally { + } finally { tryClose(statement); tryClose(connection); } @@ -366,16 +428,18 @@ public final class SQLDatabaseManager implements DatabaseManager { return success; } - public @NotNull List readLeaderboard(@Nullable PrimarySkillType skill, int pageNumber, int statsPerPage) throws InvalidSkillException { + public @NotNull List readLeaderboard(@Nullable PrimarySkillType skill, + int pageNumber, int statsPerPage) throws InvalidSkillException { List stats = new ArrayList<>(); //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!"); - 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!"); + if (skill != null && SkillTools.isChildSkill(skill)) { + 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!"); } - String query = skill == null ? ALL_QUERY_VERSION : skill.name().toLowerCase(Locale.ENGLISH); ResultSet resultSet = null; PreparedStatement statement = null; @@ -383,7 +447,11 @@ public final class SQLDatabaseManager implements DatabaseManager { 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(); @@ -397,11 +465,9 @@ public final class SQLDatabaseManager implements DatabaseManager { stats.add(new PlayerStat(column.get(1), Integer.parseInt(column.get(0)))); } - } - catch (SQLException ex) { + } catch (SQLException ex) { printErrors(ex); - } - finally { + } finally { tryClose(resultSet); tryClose(statement); tryClose(connection); @@ -422,9 +488,11 @@ public final class SQLDatabaseManager implements DatabaseManager { for (PrimarySkillType primarySkillType : SkillTools.NON_CHILD_SKILLS) { String skillName = primarySkillType.name().toLowerCase(Locale.ENGLISH); // 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 = ?)"; + 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` = ?)"; statement = connection.prepareStatement(sql); statement.setString(1, playerName); @@ -435,9 +503,11 @@ public final class SQLDatabaseManager implements DatabaseManager { int rank = resultSet.getInt("rank"); // 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"; + 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"; resultSet.close(); statement.close(); @@ -456,11 +526,14 @@ public final class SQLDatabaseManager implements DatabaseManager { statement.close(); } - String sql = "SELECT COUNT(*) AS 'rank' FROM " + tablePrefix + "users JOIN " + tablePrefix + "skills ON user_id = id " + - "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 = ?)"; + String sql = + "SELECT COUNT(*) AS 'rank' FROM " + tablePrefix + "users JOIN " + tablePrefix + + "skills ON user_id = id " + + "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` = ?)"; statement = connection.prepareStatement(sql); statement.setString(1, playerName); @@ -474,11 +547,13 @@ public final class SQLDatabaseManager implements DatabaseManager { statement.close(); sql = "SELECT user, " + ALL_QUERY_VERSION + " " + - "FROM " + tablePrefix + "users JOIN " + tablePrefix + "skills ON user_id = id " + + "FROM " + tablePrefix + "users JOIN " + tablePrefix + "skills ON user_id = id " + + "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); @@ -493,11 +568,9 @@ public final class SQLDatabaseManager implements DatabaseManager { resultSet.close(); statement.close(); - } - catch (SQLException ex) { + } catch (SQLException ex) { printErrors(ex); - } - finally { + } finally { tryClose(resultSet); tryClose(statement); tryClose(connection); @@ -518,7 +591,8 @@ public final class SQLDatabaseManager implements DatabaseManager { tryClose(connection); } - return new PlayerProfile(playerName, uuid, true, mcMMO.p.getAdvancedConfig().getStartingLevel()); + return new PlayerProfile(playerName, uuid, true, + mcMMO.p.getAdvancedConfig().getStartingLevel()); } @Override @@ -528,7 +602,8 @@ public final class SQLDatabaseManager implements DatabaseManager { int id = newUser(connection, player.getName(), player.getUniqueId()); if (id == -1) { - return new PlayerProfile(player.getName(), player.getUniqueId(), false, mcMMO.p.getAdvancedConfig().getStartingLevel()); + return new PlayerProfile(player.getName(), player.getUniqueId(), false, + mcMMO.p.getAdvancedConfig().getStartingLevel()); } else { return loadPlayerProfile(player); } @@ -536,7 +611,8 @@ public final class SQLDatabaseManager implements DatabaseManager { e.printStackTrace(); } - return new PlayerProfile(player.getName(), player.getUniqueId(), false, mcMMO.p.getAdvancedConfig().getStartingLevel()); + return new PlayerProfile(player.getName(), player.getUniqueId(), false, + mcMMO.p.getAdvancedConfig().getStartingLevel()); } private int newUser(Connection connection, String playerName, UUID uuid) { @@ -546,13 +622,16 @@ public final class SQLDatabaseManager implements DatabaseManager { 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); + + statement = connection.prepareStatement("INSERT INTO " + tablePrefix + + "users (user, uuid, lastlogin) VALUES (?, ?, UNIX_TIMESTAMP())", + Statement.RETURN_GENERATED_KEYS); statement.setString(1, playerName); statement.setString(2, uuid != null ? uuid.toString() : null); statement.executeUpdate(); @@ -560,17 +639,15 @@ public final class SQLDatabaseManager implements DatabaseManager { 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; } writeMissingRows(connection, resultSet.getInt(1)); return resultSet.getInt(1); - } - catch (SQLException ex) { + } catch (SQLException ex) { printErrors(ex); - } - finally { + } finally { tryClose(resultSet); tryClose(statement); } @@ -582,7 +659,8 @@ public final class SQLDatabaseManager implements DatabaseManager { return loadPlayerFromDB(null, playerName); } catch (RuntimeException e) { e.printStackTrace(); - return new PlayerProfile(playerName, false, mcMMO.p.getAdvancedConfig().getStartingLevel()); + return new PlayerProfile(playerName, false, + mcMMO.p.getAdvancedConfig().getStartingLevel()); } } @@ -591,7 +669,8 @@ public final class SQLDatabaseManager implements DatabaseManager { return loadPlayerFromDB(offlinePlayer.getUniqueId(), offlinePlayer.getName()); } - public @NotNull PlayerProfile loadPlayerProfile(@NotNull UUID uuid, @Nullable String playerName) { + public @NotNull PlayerProfile loadPlayerProfile(@NotNull UUID uuid, + @Nullable String playerName) { return loadPlayerFromDB(uuid, playerName); } @@ -600,10 +679,11 @@ public final class SQLDatabaseManager implements DatabaseManager { 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."); + 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."); } PreparedStatement statement = null; @@ -615,24 +695,29 @@ public final class SQLDatabaseManager implements DatabaseManager { int id = getUserID(connection, playerName, uuid); if (id == -1) { - // There is no such user - return new PlayerProfile(playerName, mcMMO.p.getAdvancedConfig().getStartingLevel()); + // There is no such user + return new PlayerProfile(playerName, + mcMMO.p.getAdvancedConfig().getStartingLevel()); } // There is such a user 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 " + "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, s.maces, " + + + "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, e.maces, " + + + "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, c.maces, " + + + "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 = ?"); + + "WHERE u.id = ?" + ); statement.setInt(1, id); resultSet = statement.executeQuery(); @@ -640,7 +725,8 @@ public final class SQLDatabaseManager implements DatabaseManager { 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(); @@ -650,15 +736,15 @@ public final class SQLDatabaseManager implements DatabaseManager { && 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()); @@ -668,17 +754,14 @@ public final class SQLDatabaseManager implements DatabaseManager { } return profile; - } - catch (SQLException e) { + } catch (SQLException e) { printErrors(e); } } resultSet.close(); - } - catch (SQLException ex) { + } catch (SQLException ex) { printErrors(ex); - } - finally { + } finally { tryClose(resultSet); tryClose(statement); tryClose(connection); @@ -706,7 +789,7 @@ public final class SQLDatabaseManager implements DatabaseManager { + "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(); @@ -717,19 +800,16 @@ public final class SQLDatabaseManager implements DatabaseManager { resultSet.next(); destination.saveUser(loadFromResult(playerName, resultSet)); resultSet.close(); - } - catch (SQLException e) { + } catch (SQLException e) { printErrors(e); // Ignore } convertedUsers++; Misc.printProgress(convertedUsers, progressInterval, startMillis); } - } - catch (SQLException e) { + } catch (SQLException e) { printErrors(e); - } - finally { + } finally { tryClose(resultSet); tryClose(statement); tryClose(connection); @@ -745,17 +825,15 @@ public final class SQLDatabaseManager implements DatabaseManager { 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(); return true; - } - catch (SQLException ex) { + } catch (SQLException ex) { printErrors(ex); return false; - } - finally { + } finally { tryClose(statement); tryClose(connection); } @@ -769,7 +847,8 @@ public final class SQLDatabaseManager implements DatabaseManager { 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()); @@ -790,12 +869,10 @@ public final class SQLDatabaseManager implements DatabaseManager { } return true; - } - catch (SQLException ex) { + } catch (SQLException ex) { printErrors(ex); return false; - } - finally { + } finally { tryClose(statement); tryClose(connection); } @@ -811,15 +888,13 @@ public final class SQLDatabaseManager implements DatabaseManager { 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")); } - } - catch (SQLException e) { + } catch (SQLException e) { printErrors(e); - } - finally { + } finally { tryClose(resultSet); tryClose(statement); tryClose(connection); @@ -832,7 +907,6 @@ public final class SQLDatabaseManager implements DatabaseManager { * Checks that the database structure is present and correct */ private void checkStructure() { - PreparedStatement statement = null; Statement createStatement = null; ResultSet resultSet = null; @@ -840,114 +914,143 @@ public final class SQLDatabaseManager implements DatabaseManager { 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(); - createStatement.executeUpdate("CREATE TABLE IF NOT EXISTS `" + tablePrefix + "huds` (" - + "`user_id` int(10) unsigned NOT NULL," - + "`mobhealthbar` varchar(50) NOT NULL DEFAULT '" + mcMMO.p.getGeneralConfig().getMobHealthbarDefault() + "'," - + "`scoreboardtips` int(10) NOT NULL DEFAULT '0'," - + "PRIMARY KEY (`user_id`)) " - + "DEFAULT CHARSET=" + CHARSET_SQL + ";"); + createStatement.executeUpdate( + "CREATE TABLE IF NOT EXISTS `" + tablePrefix + "huds` (" + + "`user_id` int(10) unsigned NOT NULL," + + "`mobhealthbar` varchar(50) NOT NULL DEFAULT '" + + mcMMO.p.getGeneralConfig().getMobHealthbarDefault() + "'," + + "`scoreboardtips` int(10) NOT NULL DEFAULT '0'," + + "PRIMARY KEY (`user_id`)) " + + "DEFAULT CHARSET=" + CHARSET_SQL + ";"); 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(); - createStatement.executeUpdate("CREATE TABLE IF NOT EXISTS `" + tablePrefix + "cooldowns` (" - + "`user_id` int(10) unsigned NOT NULL," - + "`taming` int(32) unsigned NOT NULL DEFAULT '0'," - + "`mining` int(32) unsigned NOT NULL DEFAULT '0'," - + "`woodcutting` int(32) unsigned NOT NULL DEFAULT '0'," - + "`repair` int(32) unsigned NOT NULL DEFAULT '0'," - + "`unarmed` int(32) unsigned NOT NULL DEFAULT '0'," - + "`herbalism` int(32) unsigned NOT NULL DEFAULT '0'," - + "`excavation` int(32) unsigned NOT NULL DEFAULT '0'," - + "`archery` int(32) unsigned NOT NULL DEFAULT '0'," - + "`swords` int(32) unsigned NOT NULL DEFAULT '0'," - + "`axes` int(32) unsigned NOT NULL DEFAULT '0'," - + "`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'," - + "PRIMARY KEY (`user_id`)) " - + "DEFAULT CHARSET=" + CHARSET_SQL + ";"); + createStatement.executeUpdate( + "CREATE TABLE IF NOT EXISTS `" + tablePrefix + "cooldowns` (" + + "`user_id` int(10) unsigned NOT NULL," + + "`taming` int(32) unsigned NOT NULL DEFAULT '0'," + + "`mining` int(32) unsigned NOT NULL DEFAULT '0'," + + "`woodcutting` int(32) unsigned NOT NULL DEFAULT '0'," + + "`repair` int(32) unsigned NOT NULL DEFAULT '0'," + + "`unarmed` int(32) unsigned NOT NULL DEFAULT '0'," + + "`herbalism` int(32) unsigned NOT NULL DEFAULT '0'," + + "`excavation` int(32) unsigned NOT NULL DEFAULT '0'," + + "`archery` int(32) unsigned NOT NULL DEFAULT '0'," + + "`swords` int(32) unsigned NOT NULL DEFAULT '0'," + + "`axes` int(32) unsigned NOT NULL DEFAULT '0'," + + "`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'," + + "`maces` int(32) unsigned NOT NULL DEFAULT '0'," + + "PRIMARY KEY (`user_id`)) " + + "DEFAULT CHARSET=" + CHARSET_SQL + ";"); 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() + "'"; - String totalLevel = "'" + (mcMMO.p.getAdvancedConfig().getStartingLevel() * (PrimarySkillType.values().length - CHILD_SKILLS_SIZE)) + "'"; + String totalLevel = "'" + (mcMMO.p.getAdvancedConfig().getStartingLevel() * ( + PrimarySkillType.values().length - CHILD_SKILLS_SIZE)) + "'"; createStatement = connection.createStatement(); - createStatement.executeUpdate("CREATE TABLE IF NOT EXISTS `" + tablePrefix + "skills` (" - + "`user_id` int(10) unsigned NOT NULL," - + "`taming` int(10) unsigned NOT NULL DEFAULT "+startingLevel+"," - + "`mining` int(10) unsigned NOT NULL DEFAULT "+startingLevel+"," - + "`woodcutting` int(10) unsigned NOT NULL DEFAULT "+startingLevel+"," - + "`repair` int(10) unsigned NOT NULL DEFAULT "+startingLevel+"," - + "`unarmed` int(10) unsigned NOT NULL DEFAULT "+startingLevel+"," - + "`herbalism` int(10) unsigned NOT NULL DEFAULT "+startingLevel+"," - + "`excavation` int(10) unsigned NOT NULL DEFAULT "+startingLevel+"," - + "`archery` int(10) unsigned NOT NULL DEFAULT "+startingLevel+"," - + "`swords` int(10) unsigned NOT NULL DEFAULT "+startingLevel+"," - + "`axes` int(10) unsigned NOT NULL DEFAULT "+startingLevel+"," - + "`acrobatics` int(10) unsigned NOT NULL DEFAULT "+startingLevel+"," - + "`fishing` int(10) unsigned NOT NULL DEFAULT "+startingLevel+"," - + "`alchemy` int(10) unsigned NOT NULL DEFAULT "+startingLevel+"," - + "`total` int(10) unsigned NOT NULL DEFAULT "+totalLevel+"," - + "PRIMARY KEY (`user_id`)) " - + "DEFAULT CHARSET=" + CHARSET_SQL + ";"); + createStatement.executeUpdate( + "CREATE TABLE IF NOT EXISTS `" + tablePrefix + "skills` (" + + "`user_id` int(10) unsigned NOT NULL," + + "`taming` int(10) unsigned NOT NULL DEFAULT " + startingLevel + + "," + + "`mining` int(10) unsigned NOT NULL DEFAULT " + startingLevel + + "," + + "`woodcutting` int(10) unsigned NOT NULL DEFAULT " + startingLevel + + "," + + "`repair` int(10) unsigned NOT NULL DEFAULT " + startingLevel + + "," + + "`unarmed` int(10) unsigned NOT NULL DEFAULT " + startingLevel + + "," + + "`herbalism` int(10) unsigned NOT NULL DEFAULT " + startingLevel + + "," + + "`excavation` int(10) unsigned NOT NULL DEFAULT " + startingLevel + + "," + + "`archery` int(10) unsigned NOT NULL DEFAULT " + startingLevel + + "," + + "`swords` int(10) unsigned NOT NULL DEFAULT " + startingLevel + + "," + + "`axes` int(10) unsigned NOT NULL DEFAULT " + startingLevel + "," + + "`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 + + "," + + "`maces` int(10) unsigned NOT NULL DEFAULT " + startingLevel + "," + + "`total` int(10) unsigned NOT NULL DEFAULT " + totalLevel + "," + + "PRIMARY KEY (`user_id`)) " + + "DEFAULT CHARSET=" + CHARSET_SQL + ";"); 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(); - createStatement.executeUpdate("CREATE TABLE IF NOT EXISTS `" + tablePrefix + "experience` (" - + "`user_id` int(10) unsigned NOT NULL," - + "`taming` int(10) unsigned NOT NULL DEFAULT '0'," - + "`mining` int(10) unsigned NOT NULL DEFAULT '0'," - + "`woodcutting` int(10) unsigned NOT NULL DEFAULT '0'," - + "`repair` int(10) unsigned NOT NULL DEFAULT '0'," - + "`unarmed` int(10) unsigned NOT NULL DEFAULT '0'," - + "`herbalism` int(10) unsigned NOT NULL DEFAULT '0'," - + "`excavation` int(10) unsigned NOT NULL DEFAULT '0'," - + "`archery` int(10) unsigned NOT NULL DEFAULT '0'," - + "`swords` int(10) unsigned NOT NULL DEFAULT '0'," - + "`axes` int(10) unsigned NOT NULL DEFAULT '0'," - + "`acrobatics` int(10) unsigned NOT NULL DEFAULT '0'," - + "`fishing` int(10) unsigned NOT NULL DEFAULT '0'," - + "`alchemy` int(10) unsigned NOT NULL DEFAULT '0'," - + "PRIMARY KEY (`user_id`)) " - + "DEFAULT CHARSET=" + CHARSET_SQL + ";"); + createStatement.executeUpdate( + "CREATE TABLE IF NOT EXISTS `" + tablePrefix + "experience` (" + + "`user_id` int(10) unsigned NOT NULL," + + "`taming` int(10) unsigned NOT NULL DEFAULT '0'," + + "`mining` int(10) unsigned NOT NULL DEFAULT '0'," + + "`woodcutting` int(10) unsigned NOT NULL DEFAULT '0'," + + "`repair` int(10) unsigned NOT NULL DEFAULT '0'," + + "`unarmed` int(10) unsigned NOT NULL DEFAULT '0'," + + "`herbalism` int(10) unsigned NOT NULL DEFAULT '0'," + + "`excavation` int(10) unsigned NOT NULL DEFAULT '0'," + + "`archery` int(10) unsigned NOT NULL DEFAULT '0'," + + "`swords` int(10) unsigned NOT NULL DEFAULT '0'," + + "`axes` int(10) unsigned NOT NULL DEFAULT '0'," + + "`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); } tryClose(resultSet); @@ -961,47 +1064,127 @@ public final class SQLDatabaseManager implements DatabaseManager { for (PrimarySkillType skill : SkillTools.NON_CHILD_SKILLS) { int cap = mcMMO.p.getSkillTools().getLevelCap(skill); if (cap != Integer.MAX_VALUE) { - statement = connection.prepareStatement("UPDATE `" + tablePrefix + "skills` SET `" + skill.name().toLowerCase(Locale.ENGLISH) + "` = " + cap + " WHERE `" + skill.name().toLowerCase(Locale.ENGLISH) + "` > " + cap); + statement = connection.prepareStatement( + "UPDATE `" + tablePrefix + "skills` SET `" + skill.name() + .toLowerCase(Locale.ENGLISH) + "` = " + cap + " WHERE `" + + skill.name().toLowerCase(Locale.ENGLISH) + "` > " + cap); statement.executeUpdate(); tryClose(statement); } } } - mcMMO.p.getLogger().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`)"); - createStatement.executeUpdate("DELETE FROM `" + tablePrefix + "cooldowns` WHERE NOT EXISTS (SELECT * FROM `" + tablePrefix + "users` `u` WHERE `" + tablePrefix + "cooldowns`.`user_id` = `u`.`id`)"); - createStatement.executeUpdate("DELETE FROM `" + tablePrefix + "skills` WHERE NOT EXISTS (SELECT * FROM `" + tablePrefix + "users` `u` WHERE `" + tablePrefix + "skills`.`user_id` = `u`.`id`)"); - } - catch (SQLException ex) { + 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`)"); + createStatement.executeUpdate( + "DELETE FROM `" + tablePrefix + "cooldowns` WHERE NOT EXISTS (SELECT * FROM `" + + tablePrefix + "users` `u` WHERE `" + tablePrefix + + "cooldowns`.`user_id` = `u`.`id`)"); + createStatement.executeUpdate( + "DELETE FROM `" + tablePrefix + "skills` WHERE NOT EXISTS (SELECT * FROM `" + + tablePrefix + "users` `u` WHERE `" + tablePrefix + + "skills`.`user_id` = `u`.`id`)"); + } catch (SQLException ex) { printErrors(ex); - } - finally { + } finally { tryClose(resultSet); tryClose(statement); tryClose(createStatement); tryClose(connection); } + final String skills = "skills"; + final String crossbows = "crossbows"; + final String tridents = "tridents"; + final String maces = "maces"; + final String experience = "experience"; + final String cooldowns = "cooldowns"; + + updateStructure(skills, crossbows, String.valueOf(32)); + updateStructure(skills, tridents, String.valueOf(32)); + updateStructure(skills, maces, String.valueOf(32)); + + updateStructure(experience, crossbows, String.valueOf(10)); + updateStructure(experience, tridents, String.valueOf(10)); + updateStructure(experience, maces, String.valueOf(10)); + + updateStructure(cooldowns, crossbows, String.valueOf(10)); + updateStructure(cooldowns, tridents, String.valueOf(10)); + updateStructure(cooldowns, maces, String.valueOf(10)); } - private 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; + private void updateStructure(String tableName, String columnName, String columnSize) { + try (Connection connection = getConnection(PoolIdentifier.MISC)) { + if (!columnExists(connection, mcMMO.p.getGeneralConfig().getMySQLDatabaseName(), + tablePrefix + tableName, columnName)) { + try (Statement createStatement = connection.createStatement()) { + // logger.info("[SQLDB Check] Adding column '" + columnName + "' to table '" + tablePrefix + tableName + "'..."); + String startingLevel = + "'" + mcMMO.p.getAdvancedConfig().getStartingLevel() + "'"; + createStatement.executeUpdate("ALTER TABLE `" + tablePrefix + tableName + "` " + + "ADD COLUMN `" + columnName + "` int(" + columnSize + + ") unsigned NOT NULL DEFAULT " + startingLevel); + } + } else { + // logger.info("[SQLDB Check] Column '" + columnName + "' already exists in table '" + tablePrefix + tableName + "', looks good!"); + } + } catch (SQLException e) { + e.printStackTrace(); // Consider more robust logging + throw new RuntimeException(e); } + } + + private boolean columnExists(Connection connection, String database, String tableName, + String columnName) throws SQLException { + // logger.info("[SQLDB Check] Checking if column '" + columnName + "' exists in table '" + tableName + "'"); + try (Statement createStatement = connection.createStatement()) { + String sql = "SELECT `COLUMN_NAME`\n" + + "FROM `INFORMATION_SCHEMA`.`COLUMNS`\n" + + "WHERE `TABLE_SCHEMA`='" + database + "'\n" + + " AND `TABLE_NAME`='" + tableName + "'\n" + + " AND `COLUMN_NAME`='" + columnName + "'"; + var resultSet = createStatement.executeQuery(sql); + return resultSet.next(); + } catch (SQLException e) { + logger.info("Failed to check if column exists in table " + tableName + " for column " + + columnName); + e.printStackTrace(); + throw e; + } + } + + + 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 = 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."); + throw new RuntimeException( + "getConnection() for " + identifier.name().toLowerCase(Locale.ENGLISH) + + " pool timed out. Increase max connections settings."); } return connection; } @@ -1012,8 +1195,9 @@ public final class SQLDatabaseManager implements DatabaseManager { * @param upgrade Upgrade to attempt to apply */ private void checkDatabaseStructure(Connection connection, UpgradeType upgrade) { + // TODO: Rewrite / Refactor if (!mcMMO.getUpgradeManager().shouldUpgrade(upgrade)) { - LogUtils.debug(mcMMO.p.getLogger(), "Skipping " + upgrade.name() + " upgrade (unneeded)"); + LogUtils.debug(logger, "Skipping " + upgrade.name() + " upgrade (unneeded)"); return; } @@ -1078,11 +1262,9 @@ public final class SQLDatabaseManager implements DatabaseManager { break; } - } - catch (SQLException ex) { + } catch (SQLException ex) { printErrors(ex); - } - finally { + } finally { tryClose(statement); } } @@ -1091,50 +1273,55 @@ public final class SQLDatabaseManager implements DatabaseManager { PreparedStatement statement = null; try { - statement = connection.prepareStatement("INSERT IGNORE INTO " + tablePrefix + "experience (user_id) VALUES (?)"); + statement = connection.prepareStatement( + "INSERT IGNORE INTO " + tablePrefix + "experience (user_id) VALUES (?)"); statement.setInt(1, id); statement.execute(); statement.close(); - statement = connection.prepareStatement("INSERT IGNORE INTO " + tablePrefix + "skills (user_id) VALUES (?)"); + statement = connection.prepareStatement( + "INSERT IGNORE INTO " + tablePrefix + "skills (user_id) VALUES (?)"); statement.setInt(1, id); statement.execute(); statement.close(); - statement = connection.prepareStatement("INSERT IGNORE INTO " + tablePrefix + "cooldowns (user_id) VALUES (?)"); + statement = connection.prepareStatement( + "INSERT IGNORE INTO " + tablePrefix + "cooldowns (user_id) VALUES (?)"); statement.setInt(1, id); statement.execute(); statement.close(); - statement = connection.prepareStatement("INSERT IGNORE INTO " + tablePrefix + "huds (user_id, mobhealthbar, scoreboardtips) VALUES (?, ?, ?)"); + statement = connection.prepareStatement("INSERT IGNORE INTO " + tablePrefix + + "huds (user_id, mobhealthbar, scoreboardtips) VALUES (?, ?, ?)"); statement.setInt(1, id); statement.setString(2, mcMMO.p.getGeneralConfig().getMobHealthbarDefault().name()); statement.setInt(3, 0); statement.execute(); statement.close(); - } - catch (SQLException ex) { + } catch (SQLException ex) { printErrors(ex); - } - finally { + } finally { tryClose(statement); } } private PlayerProfile loadFromResult(String playerName, ResultSet result) throws SQLException { - Map skills = new EnumMap<>(PrimarySkillType.class); // Skill & Level - Map skillsXp = new EnumMap<>(PrimarySkillType.class); // Skill & XP - Map skillsDATS = new EnumMap<>(SuperAbilityType.class); // Ability & Cooldown - Map uniqueData = new EnumMap<>(UniqueDataType.class); //Chimaera wing cooldown and other misc info - MobHealthbarType mobHealthbarType; + final Map skills = new EnumMap<>( + PrimarySkillType.class); // Skill & Level + final Map skillsXp = new EnumMap<>( + PrimarySkillType.class); // Skill & XP + final Map skillsDATS = new EnumMap<>( + SuperAbilityType.class); // Ability & Cooldown + final Map uniqueData = new EnumMap<>( + UniqueDataType.class); //Chimaera wing cooldown and other misc info UUID uuid; int scoreboardTipsShown; - 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 SKILL_COLUMNS = 16; + final int OFFSET_SKILLS = 0; + final int OFFSET_XP = SKILL_COLUMNS; + final int OFFSET_DATS = OFFSET_XP + SKILL_COLUMNS; + final int OFFSET_OTHER = OFFSET_DATS + SKILL_COLUMNS; skills.put(PrimarySkillType.TAMING, result.getInt(OFFSET_SKILLS + 1)); skills.put(PrimarySkillType.MINING, result.getInt(OFFSET_SKILLS + 2)); @@ -1149,6 +1336,9 @@ public final class SQLDatabaseManager implements DatabaseManager { 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)); + skills.put(PrimarySkillType.MACES, result.getInt(OFFSET_SKILLS + 16)); skillsXp.put(PrimarySkillType.TAMING, result.getFloat(OFFSET_XP + 1)); skillsXp.put(PrimarySkillType.MINING, result.getFloat(OFFSET_XP + 2)); @@ -1163,6 +1353,9 @@ public final class SQLDatabaseManager implements DatabaseManager { 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.CROSSBOWS, result.getFloat(OFFSET_XP + 14)); + skillsXp.put(PrimarySkillType.TRIDENTS, result.getFloat(OFFSET_XP + 15)); + skillsXp.put(PrimarySkillType.MACES, result.getFloat(OFFSET_XP + 16)); // Taming - Unused - result.getInt(OFFSET_DATS + 1) skillsDATS.put(SuperAbilityType.SUPER_BREAKER, result.getInt(OFFSET_DATS + 2)); @@ -1171,42 +1364,58 @@ public final class SQLDatabaseManager implements DatabaseManager { skillsDATS.put(SuperAbilityType.BERSERK, result.getInt(OFFSET_DATS + 5)); skillsDATS.put(SuperAbilityType.GREEN_TERRA, result.getInt(OFFSET_DATS + 6)); skillsDATS.put(SuperAbilityType.GIGA_DRILL_BREAKER, result.getInt(OFFSET_DATS + 7)); + skillsDATS.put(SuperAbilityType.EXPLOSIVE_SHOT, result.getInt(OFFSET_DATS + 8)); // Archery - Unused - result.getInt(OFFSET_DATS + 8) skillsDATS.put(SuperAbilityType.SERRATED_STRIKES, result.getInt(OFFSET_DATS + 9)); skillsDATS.put(SuperAbilityType.SKULL_SPLITTER, result.getInt(OFFSET_DATS + 10)); // 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)); + skillsDATS.put(SuperAbilityType.MACES_SUPER_ABILITY, result.getInt(OFFSET_DATS + 16)); + + // ORDER IS AS FOLLOWS + // MOB HEALTH BAR + // SCOREBOARD TIPS + // UUID + // USER try { + // Mob Health bar is unused, so we add two + // TODO: Why even SELECT the mob health bar? + // Refactor later. scoreboardTipsShown = result.getInt(OFFSET_OTHER + 2); - } - catch (Exception e) { + } catch (Exception e) { scoreboardTipsShown = 0; } try { uuid = UUID.fromString(result.getString(OFFSET_OTHER + 3)); - } - catch (Exception e) { + } catch (Exception e) { uuid = null; } - return new PlayerProfile(playerName, uuid, skills, skillsXp, skillsDATS, scoreboardTipsShown, uniqueData, null); + return new PlayerProfile(playerName, uuid, skills, skillsXp, skillsDATS, + scoreboardTipsShown, uniqueData, null); } private void printErrors(SQLException ex) { - if (debug) { - ex.printStackTrace(); - } + ex.printStackTrace(); - 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,8 +1431,8 @@ public final class SQLDatabaseManager implements DatabaseManager { return; } resultSet.close(); - mcMMO.p.getLogger().info("Updating mcMMO MySQL tables to drop name uniqueness..."); - statement.execute("ALTER TABLE `" + tablePrefix + "users` " + 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)"); mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.DROP_NAME_UNIQUENESS); @@ -1238,33 +1447,36 @@ public final class SQLDatabaseManager implements DatabaseManager { try { statement.executeQuery("SELECT `alchemy` FROM `" + tablePrefix + "skills` LIMIT 1"); mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.ADD_ALCHEMY); - } - catch (SQLException ex) { - mcMMO.p.getLogger().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'"); + } catch (SQLException ex) { + 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'"); } } private void checkUpgradeAddBlastMiningCooldown(final Statement statement) throws SQLException { try { - statement.executeQuery("SELECT `blast_mining` FROM `" + tablePrefix + "cooldowns` LIMIT 1"); + statement.executeQuery( + "SELECT `blast_mining` FROM `" + tablePrefix + "cooldowns` LIMIT 1"); mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.ADD_BLAST_MINING_COOLDOWN); - } - catch (SQLException ex) { - mcMMO.p.getLogger().info("Updating mcMMO MySQL tables for Blast Mining..."); - statement.executeUpdate("ALTER TABLE `" + tablePrefix + "cooldowns` ADD `blast_mining` int(32) NOT NULL DEFAULT '0'"); + } catch (SQLException ex) { + logger.info("Updating mcMMO MySQL tables for Blast Mining..."); + statement.executeUpdate("ALTER TABLE `" + tablePrefix + + "cooldowns` ADD `blast_mining` int(32) NOT NULL DEFAULT '0'"); } } private void checkUpgradeAddUniqueChimaeraWing(final Statement statement) throws SQLException { try { - statement.executeQuery("SELECT `chimaera_wing` FROM `" + tablePrefix + "cooldowns` LIMIT 1"); + statement.executeQuery( + "SELECT `chimaera_wing` FROM `" + tablePrefix + "cooldowns` LIMIT 1"); mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.ADD_UNIQUE_PLAYER_DATA); - } - catch (SQLException ex) { - mcMMO.p.getLogger().info("Updating mcMMO MySQL tables for Chimaera Wing..."); - statement.executeUpdate("ALTER TABLE `" + tablePrefix + "cooldowns` ADD `chimaera_wing` int(32) NOT NULL DEFAULT '0'"); + } catch (SQLException ex) { + logger.info("Updating mcMMO MySQL tables for Chimaera Wing..."); + statement.executeUpdate("ALTER TABLE `" + tablePrefix + + "cooldowns` ADD `chimaera_wing` int(32) NOT NULL DEFAULT '0'"); } } @@ -1272,11 +1484,12 @@ public final class SQLDatabaseManager implements DatabaseManager { try { statement.executeQuery("SELECT `fishing` FROM `" + tablePrefix + "skills` LIMIT 1"); mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.ADD_FISHING); - } - catch (SQLException ex) { - mcMMO.p.getLogger().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'"); + } catch (SQLException ex) { + 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'"); } } @@ -1284,21 +1497,23 @@ public final class SQLDatabaseManager implements DatabaseManager { try { statement.executeQuery("SELECT `mobhealthbar` FROM `" + tablePrefix + "huds` LIMIT 1"); mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.ADD_MOB_HEALTHBARS); - } - catch (SQLException ex) { - mcMMO.p.getLogger().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() + "'"); + } catch (SQLException ex) { + 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() + "'"); } } private void checkUpgradeAddScoreboardTips(final Statement statement) throws SQLException { try { - statement.executeQuery("SELECT `scoreboardtips` FROM `" + tablePrefix + "huds` LIMIT 1"); + statement.executeQuery( + "SELECT `scoreboardtips` FROM `" + tablePrefix + "huds` LIMIT 1"); mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.ADD_SCOREBOARD_TIPS); - } - catch (SQLException ex) { - mcMMO.p.getLogger().info("Updating mcMMO MySQL tables for scoreboard tips..."); - statement.executeUpdate("ALTER TABLE `" + tablePrefix + "huds` ADD `scoreboardtips` int(10) NOT NULL DEFAULT '0' ;"); + } catch (SQLException ex) { + logger.info("Updating mcMMO MySQL tables for scoreboard tips..."); + statement.executeUpdate("ALTER TABLE `" + tablePrefix + + "huds` ADD `scoreboardtips` int(10) NOT NULL DEFAULT '0' ;"); } } @@ -1306,30 +1521,30 @@ public final class SQLDatabaseManager implements DatabaseManager { ResultSet resultSet = null; try { - resultSet = statement.executeQuery("SHOW INDEX FROM `" + tablePrefix + "skills` WHERE `Key_name` LIKE 'idx\\_%'"); + resultSet = statement.executeQuery( + "SHOW INDEX FROM `" + tablePrefix + "skills` WHERE `Key_name` LIKE 'idx\\_%'"); 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); try { - statement.executeUpdate("ALTER TABLE `" + tablePrefix + "skills` ADD INDEX `idx_" + skill_name + "` (`" + skill_name + "`) USING BTREE"); - } - catch (SQLException ex) { + statement.executeUpdate( + "ALTER TABLE `" + tablePrefix + "skills` ADD INDEX `idx_" + + skill_name + "` (`" + skill_name + "`) USING BTREE"); + } catch (SQLException ex) { // Ignore } } } mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.ADD_SQL_INDEXES); - } - catch (SQLException ex) { + } catch (SQLException ex) { printErrors(ex); - } - finally { + } finally { tryClose(resultSet); } } @@ -1351,19 +1566,20 @@ public final class SQLDatabaseManager implements DatabaseManager { } if (!column_exists) { - mcMMO.p.getLogger().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"); + 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"); - mcMMO.p.getFoliaLib().getImpl().runLaterAsync(new GetUUIDUpdatesRequired(), 100); // wait until after first purge + mcMMO.p.getFoliaLib().getScheduler().runLaterAsync(new GetUUIDUpdatesRequired(), + 100); // wait until after first purge } mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.ADD_UUIDS); - } - catch (SQLException ex) { + } catch (SQLException ex) { printErrors(ex); - } - finally { + } finally { tryClose(resultSet); } } @@ -1379,7 +1595,8 @@ public final class SQLDatabaseManager implements DatabaseManager { try { connection = miscPool.getConnection(); statement = connection.createStatement(); - resultSet = statement.executeQuery("SELECT `user` FROM `" + tablePrefix + "users` WHERE `uuid` IS NULL"); + resultSet = statement.executeQuery( + "SELECT `user` FROM `" + tablePrefix + "users` WHERE `uuid` IS NULL"); while (resultSet.next()) { names.add(resultSet.getString("user")); @@ -1420,16 +1637,15 @@ public final class SQLDatabaseManager implements DatabaseManager { } if (column_exists) { - mcMMO.p.getLogger().info("Removing party name from users table..."); - statement.executeUpdate("ALTER TABLE `" + tablePrefix + "users` DROP COLUMN `party`"); + logger.info("Removing party name from users table..."); + statement.executeUpdate( + "ALTER TABLE `" + tablePrefix + "users` DROP COLUMN `party`"); } mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.DROP_SQL_PARTY_NAMES); - } - catch (SQLException ex) { + } catch (SQLException ex) { printErrors(ex); - } - finally { + } finally { tryClose(resultSet); } } @@ -1454,19 +1670,20 @@ public final class SQLDatabaseManager implements DatabaseManager { } if (!column_exists) { - mcMMO.p.getLogger().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"); + 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"); connection.commit(); } mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.ADD_SKILL_TOTAL); - } - catch (SQLException ex) { + } catch (SQLException ex) { printErrors(ex); - } - finally { + } finally { connection.setAutoCommit(true); tryClose(resultSet); tryClose(statement); @@ -1490,32 +1707,34 @@ public final class SQLDatabaseManager implements DatabaseManager { } if (column_exists) { - mcMMO.p.getLogger().info("Removing Spout HUD type from huds table..."); - statement.executeUpdate("ALTER TABLE `" + tablePrefix + "huds` DROP COLUMN `hudtype`"); + logger.info("Removing Spout HUD type from huds table..."); + statement.executeUpdate( + "ALTER TABLE `" + tablePrefix + "huds` DROP COLUMN `hudtype`"); } mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.DROP_SPOUT); - } - catch (SQLException ex) { + } catch (SQLException ex) { printErrors(ex); - } - finally { + } finally { tryClose(resultSet); } } private int getUserID(final Connection connection, final String playerName, final UUID uuid) { - if (uuid == null) + if (uuid == null) { return getUserIDByName(connection, playerName); + } - if (cachedUserIDs.containsKey(uuid)) + if (cachedUserIDs.containsKey(uuid)) { return cachedUserIDs.get(uuid); + } ResultSet resultSet = null; 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(); @@ -1527,11 +1746,9 @@ public final class SQLDatabaseManager implements DatabaseManager { return id; } - } - catch (SQLException ex) { + } catch (SQLException ex) { printErrors(ex); - } - finally { + } finally { tryClose(resultSet); tryClose(statement); } @@ -1544,7 +1761,8 @@ public final class SQLDatabaseManager implements DatabaseManager { 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(); @@ -1552,24 +1770,21 @@ public final class SQLDatabaseManager implements DatabaseManager { return resultSet.getInt("id"); } - } - catch (SQLException ex) { + } catch (SQLException ex) { printErrors(ex); - } - finally { + } finally { tryClose(resultSet); tryClose(statement); } return -1; } - + private void tryClose(AutoCloseable closeable) { if (closeable != null) { try { closeable.close(); - } - catch (Exception e) { + } catch (Exception e) { // Ignore } } @@ -1577,7 +1792,7 @@ public final class SQLDatabaseManager implements DatabaseManager { @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(); @@ -1595,14 +1810,13 @@ public final class SQLDatabaseManager implements DatabaseManager { try { connection = getConnection(PoolIdentifier.MISC); - statement = connection.prepareStatement("UPDATE " + tablePrefix + "huds SET mobhealthbar = ?"); + statement = connection.prepareStatement( + "UPDATE " + tablePrefix + "huds SET mobhealthbar = ?"); statement.setString(1, mcMMO.p.getGeneralConfig().getMobHealthbarDefault().toString()); statement.executeUpdate(); - } - catch (SQLException ex) { + } catch (SQLException ex) { printErrors(ex); - } - finally { + } finally { tryClose(statement); tryClose(connection); } @@ -1619,22 +1833,22 @@ public final class SQLDatabaseManager implements DatabaseManager { */ //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"); - statement.executeUpdate(getUpdateUserInUsersTableSQLQuery()); + logger.info("Updating user column to new encoding"); + statement.executeUpdate(getUpdateUserInUsersTableSQLQuery()); - //Update "uuid" column - mcMMO.p.getLogger().info("Updating user column to new encoding"); - statement.executeUpdate(getUpdateUUIDInUsersTableSQLQuery()); + //Update "uuid" column + logger.info("Updating user column to new encoding"); + statement.executeUpdate(getUpdateUUIDInUsersTableSQLQuery()); - //Update "mobhealthbar" column - mcMMO.p.getLogger().info("Updating mobhealthbar column to new encoding"); - statement.executeUpdate(getUpdateMobHealthBarInHudsTableSQLQuery()); + //Update "mobhealthbar" column + logger.info("Updating mobhealthbar column to new encoding"); + statement.executeUpdate(getUpdateMobHealthBarInHudsTableSQLQuery()); - mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.SQL_CHARSET_UTF8MB4); + mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.SQL_CHARSET_UTF8MB4); } catch (SQLException e) { e.printStackTrace(); @@ -1645,7 +1859,7 @@ public final class SQLDatabaseManager implements DatabaseManager { 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;"; @@ -1670,4 +1884,28 @@ public final class SQLDatabaseManager implements DatabaseManager { " 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/database/UserQueryFull.java b/src/main/java/com/gmail/nossr50/database/UserQueryFull.java index 47a3e965a..d104d3cc0 100644 --- a/src/main/java/com/gmail/nossr50/database/UserQueryFull.java +++ b/src/main/java/com/gmail/nossr50/database/UserQueryFull.java @@ -1,8 +1,7 @@ package com.gmail.nossr50.database; -import org.jetbrains.annotations.NotNull; - import java.util.UUID; +import org.jetbrains.annotations.NotNull; public class UserQueryFull implements UserQueryUUID, UserQueryName { diff --git a/src/main/java/com/gmail/nossr50/database/UserQueryUUID.java b/src/main/java/com/gmail/nossr50/database/UserQueryUUID.java index 192997f90..785c34875 100644 --- a/src/main/java/com/gmail/nossr50/database/UserQueryUUID.java +++ b/src/main/java/com/gmail/nossr50/database/UserQueryUUID.java @@ -1,8 +1,7 @@ package com.gmail.nossr50.database; -import org.jetbrains.annotations.NotNull; - import java.util.UUID; +import org.jetbrains.annotations.NotNull; public interface UserQueryUUID extends UserQuery { diff --git a/src/main/java/com/gmail/nossr50/database/UserQueryUUIDImpl.java b/src/main/java/com/gmail/nossr50/database/UserQueryUUIDImpl.java index 49ad038f5..70a207d8a 100644 --- a/src/main/java/com/gmail/nossr50/database/UserQueryUUIDImpl.java +++ b/src/main/java/com/gmail/nossr50/database/UserQueryUUIDImpl.java @@ -1,8 +1,7 @@ package com.gmail.nossr50.database; -import org.jetbrains.annotations.NotNull; - import java.util.UUID; +import org.jetbrains.annotations.NotNull; public class UserQueryUUIDImpl implements UserQueryUUID { private final @NotNull UUID uuid; diff --git a/src/main/java/com/gmail/nossr50/database/flatfile/BadCategorizedFlatFileData.java b/src/main/java/com/gmail/nossr50/database/flatfile/BadCategorizedFlatFileData.java index fbeaf9c2d..dbc8301e8 100644 --- a/src/main/java/com/gmail/nossr50/database/flatfile/BadCategorizedFlatFileData.java +++ b/src/main/java/com/gmail/nossr50/database/flatfile/BadCategorizedFlatFileData.java @@ -2,15 +2,16 @@ package com.gmail.nossr50.database.flatfile; import com.gmail.nossr50.database.FlatFileDataFlag; import com.google.common.base.Objects; -import org.jetbrains.annotations.NotNull; - import java.util.Arrays; import java.util.HashSet; +import org.jetbrains.annotations.NotNull; public class BadCategorizedFlatFileData extends CategorizedFlatFileData { private final boolean[] badDataIndexes; - protected BadCategorizedFlatFileData(int uniqueProcessingId, @NotNull HashSet dataFlags, @NotNull String[] splitData, boolean[] badDataIndexes) { + protected BadCategorizedFlatFileData(int uniqueProcessingId, + @NotNull HashSet dataFlags, @NotNull String[] splitData, + boolean[] badDataIndexes) { super(uniqueProcessingId, dataFlags, splitData); this.badDataIndexes = badDataIndexes; } @@ -21,9 +22,15 @@ public class BadCategorizedFlatFileData extends CategorizedFlatFileData { @Override public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - if (!super.equals(o)) return false; + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + if (!super.equals(o)) { + return false; + } BadCategorizedFlatFileData that = (BadCategorizedFlatFileData) o; return Objects.equal(badDataIndexes, that.badDataIndexes); } diff --git a/src/main/java/com/gmail/nossr50/database/flatfile/CategorizedFlatFileData.java b/src/main/java/com/gmail/nossr50/database/flatfile/CategorizedFlatFileData.java index 500be9c4f..ceabbb4f1 100644 --- a/src/main/java/com/gmail/nossr50/database/flatfile/CategorizedFlatFileData.java +++ b/src/main/java/com/gmail/nossr50/database/flatfile/CategorizedFlatFileData.java @@ -2,17 +2,17 @@ package com.gmail.nossr50.database.flatfile; import com.gmail.nossr50.database.FlatFileDataFlag; import com.google.common.base.Objects; -import org.jetbrains.annotations.NotNull; - import java.util.HashSet; import java.util.Set; +import org.jetbrains.annotations.NotNull; public class CategorizedFlatFileData implements FlatFileDataContainer { private final @NotNull Set dataFlags; private final @NotNull String[] splitData; private final int uniqueProcessingId; - public CategorizedFlatFileData(int uniqueProcessingId, @NotNull HashSet dataFlags, @NotNull String[] splitData) { + public CategorizedFlatFileData(int uniqueProcessingId, + @NotNull HashSet dataFlags, @NotNull String[] splitData) { this.uniqueProcessingId = uniqueProcessingId; this.dataFlags = dataFlags; this.splitData = splitData; @@ -36,10 +36,15 @@ public class CategorizedFlatFileData implements FlatFileDataContainer { @Override public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } CategorizedFlatFileData that = (CategorizedFlatFileData) o; - return uniqueProcessingId == that.uniqueProcessingId && Objects.equal(dataFlags, that.dataFlags) && Objects.equal(splitData, that.splitData); + return uniqueProcessingId == that.uniqueProcessingId && Objects.equal(dataFlags, + that.dataFlags) && Objects.equal(splitData, that.splitData); } @Override diff --git a/src/main/java/com/gmail/nossr50/database/flatfile/FlatFileDataBuilder.java b/src/main/java/com/gmail/nossr50/database/flatfile/FlatFileDataBuilder.java index ed048d5e1..12fa7c834 100644 --- a/src/main/java/com/gmail/nossr50/database/flatfile/FlatFileDataBuilder.java +++ b/src/main/java/com/gmail/nossr50/database/flatfile/FlatFileDataBuilder.java @@ -1,9 +1,8 @@ package com.gmail.nossr50.database.flatfile; import com.gmail.nossr50.database.FlatFileDataFlag; -import org.jetbrains.annotations.NotNull; - import java.util.HashSet; +import org.jetbrains.annotations.NotNull; public class FlatFileDataBuilder { private final @NotNull HashSet dataFlags; @@ -28,8 +27,9 @@ public class FlatFileDataBuilder { } public @NotNull FlatFileDataContainer build() { - if(dataFlags.contains(FlatFileDataFlag.BAD_VALUES)) { - return new BadCategorizedFlatFileData(uniqueProcessingId, dataFlags, splitStringData, badDataValues); + if (dataFlags.contains(FlatFileDataFlag.BAD_VALUES)) { + return new BadCategorizedFlatFileData(uniqueProcessingId, dataFlags, splitStringData, + badDataValues); } return new CategorizedFlatFileData(uniqueProcessingId, dataFlags, splitStringData); diff --git a/src/main/java/com/gmail/nossr50/database/flatfile/FlatFileDataContainer.java b/src/main/java/com/gmail/nossr50/database/flatfile/FlatFileDataContainer.java index e2fb2336c..461dbbf94 100644 --- a/src/main/java/com/gmail/nossr50/database/flatfile/FlatFileDataContainer.java +++ b/src/main/java/com/gmail/nossr50/database/flatfile/FlatFileDataContainer.java @@ -1,11 +1,10 @@ package com.gmail.nossr50.database.flatfile; import com.gmail.nossr50.database.FlatFileDataFlag; +import java.util.Set; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.Set; - public interface FlatFileDataContainer { default @Nullable Set getDataFlags() { return null; 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 da41a7acc..d6d1750c1 100644 --- a/src/main/java/com/gmail/nossr50/database/flatfile/FlatFileDataUtil.java +++ b/src/main/java/com/gmail/nossr50/database/flatfile/FlatFileDataUtil.java @@ -1,25 +1,79 @@ package com.gmail.nossr50.database.flatfile; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.COOLDOWN_ARCHERY; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.COOLDOWN_BERSERK; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.COOLDOWN_BLAST_MINING; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.COOLDOWN_CHIMAERA_WING; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.COOLDOWN_GIGA_DRILL_BREAKER; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.COOLDOWN_GREEN_TERRA; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.COOLDOWN_MACES; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.COOLDOWN_SERRATED_STRIKES; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.COOLDOWN_SKULL_SPLITTER; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.COOLDOWN_SUPER_BREAKER; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.COOLDOWN_SUPER_SHOTGUN; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.COOLDOWN_TREE_FELLER; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.COOLDOWN_TRIDENTS; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.EXP_ACROBATICS; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.EXP_ALCHEMY; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.EXP_ARCHERY; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.EXP_AXES; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.EXP_CROSSBOWS; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.EXP_EXCAVATION; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.EXP_FISHING; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.EXP_HERBALISM; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.EXP_MACES; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.EXP_MINING; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.EXP_REPAIR; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.EXP_SWORDS; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.EXP_TAMING; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.EXP_TRIDENTS; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.EXP_UNARMED; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.EXP_WOODCUTTING; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.HEALTHBAR; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.LEGACY_INVALID_OLD_USERNAME; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.LEGACY_LAST_LOGIN; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.OVERHAUL_LAST_LOGIN; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.SCOREBOARD_TIPS; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.SKILLS_ACROBATICS; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.SKILLS_ALCHEMY; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.SKILLS_ARCHERY; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.SKILLS_AXES; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.SKILLS_CROSSBOWS; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.SKILLS_EXCAVATION; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.SKILLS_FISHING; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.SKILLS_HERBALISM; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.SKILLS_MACES; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.SKILLS_MINING; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.SKILLS_REPAIR; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.SKILLS_SWORDS; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.SKILLS_TAMING; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.SKILLS_TRIDENTS; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.SKILLS_UNARMED; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.SKILLS_WOODCUTTING; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.USERNAME_INDEX; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.UUID_INDEX; + import com.gmail.nossr50.database.FlatFileDataFlag; import com.gmail.nossr50.database.FlatFileDatabaseManager; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import static com.gmail.nossr50.database.FlatFileDatabaseManager.*; - public class FlatFileDataUtil { - public static @Nullable String[] getPreparedSaveDataLine(@NotNull FlatFileDataContainer dataContainer) { - if(dataContainer.getDataFlags() == null) { + public static @Nullable String[] getPreparedSaveDataLine( + @NotNull FlatFileDataContainer dataContainer) { + if (dataContainer.getDataFlags() == null) { return dataContainer.getSplitData(); } //Data of this type is not salvageable //TODO: Test that we ignore the things we are supposed to ignore //TODO: Should we even keep track of the bad data or just not even build data containers for it? Making containers for it is only really useful for debugging.. well I suppose operations are typically async so it shouldn't matter - if(dataContainer.getDataFlags().contains(FlatFileDataFlag.CORRUPTED_OR_UNRECOGNIZABLE) - || dataContainer.getDataFlags().contains(FlatFileDataFlag.DUPLICATE_UUID) //For now we will not try to fix any issues with UUIDs - || dataContainer.getDataFlags().contains(FlatFileDataFlag.BAD_UUID_DATA) //For now we will not try to fix any issues with UUIDs + if (dataContainer.getDataFlags().contains(FlatFileDataFlag.CORRUPTED_OR_UNRECOGNIZABLE) + || dataContainer.getDataFlags().contains(FlatFileDataFlag.DUPLICATE_UUID) + //For now we will not try to fix any issues with UUIDs + || dataContainer.getDataFlags().contains(FlatFileDataFlag.BAD_UUID_DATA) + //For now we will not try to fix any issues with UUIDs || dataContainer.getDataFlags().contains(FlatFileDataFlag.TOO_INCOMPLETE)) { return null; } @@ -29,7 +83,7 @@ public class FlatFileDataUtil { /* * First fix the bad data values if they exist */ - if(dataContainer instanceof BadCategorizedFlatFileData badData) { + if (dataContainer instanceof BadCategorizedFlatFileData badData) { splitData = repairBadData(dataContainer.getSplitData(), badData.getBadDataIndexes()); } else { splitData = dataContainer.getSplitData(); @@ -40,9 +94,10 @@ public class FlatFileDataUtil { return splitData; } - public static @NotNull String[] repairBadData(@NotNull String[] splitData, boolean[] badDataValues) { - for(int i = 0; i < FlatFileDatabaseManager.DATA_ENTRY_COUNT; i++) { - if(badDataValues[i]) { + public static @NotNull String[] repairBadData(@NotNull String[] splitData, + boolean[] badDataValues) { + for (int i = 0; i < FlatFileDatabaseManager.DATA_ENTRY_COUNT; i++) { + if (badDataValues[i]) { //This data value was marked as bad so we zero initialize it splitData[i] = getZeroInitialisedData(i, 0); } @@ -55,61 +110,39 @@ public class FlatFileDataUtil { * @param index "zero" Initialization will depend on what the index is for * @return the "zero" initialized data corresponding to the index */ - public static @NotNull String getZeroInitialisedData(int index, int startingLevel) throws IndexOutOfBoundsException { - switch(index) { - case USERNAME_INDEX: - return LEGACY_INVALID_OLD_USERNAME; //We'll keep using this value for legacy compatibility reasons (not sure if needed but don't care) - case 2: //Assumption: Used to be for something, no longer used - case 3: //Assumption: Used to be for something, no longer used - case 23: //Assumption: Used to be used for something, no longer used - case 33: //Assumption: Used to be used for something, no longer used - case LEGACY_LAST_LOGIN: - case HEALTHBAR: - return "IGNORED"; - case SKILLS_MINING: - case SKILLS_REPAIR: - case SKILLS_UNARMED: - case SKILLS_HERBALISM: - case SKILLS_EXCAVATION: - case SKILLS_ARCHERY: - case SKILLS_SWORDS: - case SKILLS_AXES: - case SKILLS_WOODCUTTING: - case SKILLS_ACROBATICS: - case SKILLS_TAMING: - case SKILLS_FISHING: - case SKILLS_ALCHEMY: - return String.valueOf(startingLevel); - case OVERHAUL_LAST_LOGIN: - return String.valueOf(-1L); - case COOLDOWN_BERSERK: - case COOLDOWN_GIGA_DRILL_BREAKER: - case COOLDOWN_TREE_FELLER: - case COOLDOWN_GREEN_TERRA: - case COOLDOWN_SERRATED_STRIKES: - case COOLDOWN_SKULL_SPLITTER: - case COOLDOWN_SUPER_BREAKER: - case COOLDOWN_BLAST_MINING: - case SCOREBOARD_TIPS: - case COOLDOWN_CHIMAERA_WING: - case EXP_MINING: - case EXP_WOODCUTTING: - case EXP_REPAIR: - case EXP_UNARMED: - case EXP_HERBALISM: - case EXP_EXCAVATION: - case EXP_ARCHERY: - case EXP_SWORDS: - case EXP_AXES: - case EXP_ACROBATICS: - case EXP_TAMING: - case EXP_FISHING: - case EXP_ALCHEMY: - return "0"; - case UUID_INDEX: - throw new IndexOutOfBoundsException(); //TODO: Add UUID recovery? Might not even be worth it. - } + public static @NotNull String getZeroInitialisedData(int index, int startingLevel) + throws IndexOutOfBoundsException { + //TODO: Add UUID recovery? Might not even be worth it. + return switch (index) { + case USERNAME_INDEX -> + LEGACY_INVALID_OLD_USERNAME; //We'll keep using this value for legacy compatibility reasons (not sure if needed but don't care) + //Assumption: Used to be for something, no longer used + //Assumption: Used to be for something, no longer used + //Assumption: Used to be used for something, no longer used + //Assumption: Used to be used for something, no longer used + case 2, 3, 23, 33, LEGACY_LAST_LOGIN, HEALTHBAR -> "IGNORED"; + case SKILLS_MINING, SKILLS_REPAIR, SKILLS_UNARMED, SKILLS_HERBALISM, SKILLS_EXCAVATION, + SKILLS_ARCHERY, + SKILLS_SWORDS, SKILLS_AXES, SKILLS_WOODCUTTING, SKILLS_ACROBATICS, SKILLS_TAMING, + SKILLS_FISHING, + SKILLS_ALCHEMY, SKILLS_CROSSBOWS, SKILLS_TRIDENTS, SKILLS_MACES -> + String.valueOf(startingLevel); + case OVERHAUL_LAST_LOGIN -> String.valueOf(-1L); + case COOLDOWN_BERSERK, COOLDOWN_GIGA_DRILL_BREAKER, COOLDOWN_TREE_FELLER, + COOLDOWN_GREEN_TERRA, + COOLDOWN_SERRATED_STRIKES, COOLDOWN_SKULL_SPLITTER, COOLDOWN_SUPER_BREAKER, + COOLDOWN_BLAST_MINING, + COOLDOWN_SUPER_SHOTGUN, COOLDOWN_TRIDENTS, COOLDOWN_ARCHERY, COOLDOWN_MACES, + SCOREBOARD_TIPS, COOLDOWN_CHIMAERA_WING, + EXP_MINING, EXP_WOODCUTTING, EXP_REPAIR, EXP_UNARMED, EXP_HERBALISM, + EXP_EXCAVATION, EXP_ARCHERY, + EXP_SWORDS, EXP_AXES, EXP_ACROBATICS, EXP_TAMING, EXP_FISHING, EXP_ALCHEMY, + EXP_CROSSBOWS, + EXP_TRIDENTS, EXP_MACES -> "0"; + case UUID_INDEX -> + throw new IndexOutOfBoundsException(); //TODO: Add UUID recovery? Might not even be worth it. + default -> throw new IndexOutOfBoundsException(); + }; - throw new IndexOutOfBoundsException(); } } diff --git a/src/main/java/com/gmail/nossr50/datatypes/BlockLocationHistory.java b/src/main/java/com/gmail/nossr50/datatypes/BlockLocationHistory.java index 6674cd020..3ccf154fb 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/BlockLocationHistory.java +++ b/src/main/java/com/gmail/nossr50/datatypes/BlockLocationHistory.java @@ -1,12 +1,12 @@ package com.gmail.nossr50.datatypes; import com.google.common.collect.HashMultiset; +import java.util.LinkedList; import org.bukkit.Location; -import java.util.LinkedList; - /** - * This class works with the assumption that you only pass in Block Locations. If locations have differing pitch/yaw, the logic breaks + * This class works with the assumption that you only pass in Block Locations. If locations have + * differing pitch/yaw, the logic breaks */ public class BlockLocationHistory { private final LinkedList limitedSizeOrderedList = new LinkedList<>(); @@ -18,15 +18,17 @@ public class BlockLocationHistory { } /** - * Adds a block location to the history. If the history memory would exceed the max size, it will remove the least recently added block location + * Adds a block location to the history. If the history memory would exceed the max size, it + * will remove the least recently added block location * * @param newItem */ public void add(Location newItem) { limitedSizeOrderedList.addFirst(newItem); lookup.add(newItem); - if (limitedSizeOrderedList.size() > maxSize) + if (limitedSizeOrderedList.size() > maxSize) { lookup.remove(limitedSizeOrderedList.removeLast()); + } } /** diff --git a/src/main/java/com/gmail/nossr50/datatypes/BlockSnapshot.java b/src/main/java/com/gmail/nossr50/datatypes/BlockSnapshot.java index ca60cc4a8..28173a6a5 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/BlockSnapshot.java +++ b/src/main/java/com/gmail/nossr50/datatypes/BlockSnapshot.java @@ -4,8 +4,8 @@ import org.bukkit.Material; import org.bukkit.block.Block; /** - * Contains a snapshot of a block at a specific moment in time - * Used to check before/after type stuff + * Contains a snapshot of a block at a specific moment in time Used to check before/after type + * stuff */ public class BlockSnapshot { private final Material oldType; diff --git a/src/main/java/com/gmail/nossr50/datatypes/LevelUpBroadcastPredicate.java b/src/main/java/com/gmail/nossr50/datatypes/LevelUpBroadcastPredicate.java index f19ec041e..f9aa65277 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/LevelUpBroadcastPredicate.java +++ b/src/main/java/com/gmail/nossr50/datatypes/LevelUpBroadcastPredicate.java @@ -5,12 +5,11 @@ import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.Misc; import com.gmail.nossr50.util.player.UserManager; +import java.util.function.Predicate; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; -import java.util.function.Predicate; - //TODO: Allow for offline players to broadcast public class LevelUpBroadcastPredicate implements Predicate { @@ -25,60 +24,62 @@ public class LevelUpBroadcastPredicate implements Predi Player broadcastingPlayer = (Player) broadcaster; //Always a player no need to check cast //Broadcaster should be online - if(!broadcastingPlayer.isOnline()) { + if (!broadcastingPlayer.isOnline()) { return false; } McMMOPlayer mmoBroadcastingPlayer = UserManager.getPlayer(broadcastingPlayer); - if(mmoBroadcastingPlayer == null) { + if (mmoBroadcastingPlayer == null) { //This should never be null, but just in case... - mcMMO.p.getLogger().severe("McMMOPlayer was null for broadcaster in LevelUpBroadcastPredicate when it should never be null!"); + mcMMO.p.getLogger() + .severe("McMMOPlayer was null for broadcaster in LevelUpBroadcastPredicate when it should never be null!"); return false; } - if(t instanceof Player listeningPlayer) { + if (t instanceof Player listeningPlayer) { //Party Member Check - if(mcMMO.p.getGeneralConfig().isLevelUpBroadcastsPartyMembersOnly()) { + if (mcMMO.p.getGeneralConfig().isLevelUpBroadcastsPartyMembersOnly()) { McMMOPlayer mmoListeningPlayer = UserManager.getPlayer(listeningPlayer); - if(mmoListeningPlayer == null) { + if (mmoListeningPlayer == null) { return false; //No profile so therefor no party } Party playerWhoLeveledParty = mmoBroadcastingPlayer.getParty(); Party broadcastRecipientParty = mmoListeningPlayer.getParty(); - if(playerWhoLeveledParty == null || broadcastRecipientParty == null) { + if (playerWhoLeveledParty == null || broadcastRecipientParty == null) { return false; //No party on either player when being in the same party is required } - if(!playerWhoLeveledParty.equals(broadcastRecipientParty)) { + if (!playerWhoLeveledParty.equals(broadcastRecipientParty)) { return false; //Not in the same party when it is required } } //Same world check - if(isLevelUpBroadcastsSameWorldOnly()) { - if(!mmoBroadcastingPlayer.getPlayer().getWorld().equals(listeningPlayer.getWorld())) { + if (isLevelUpBroadcastsSameWorldOnly()) { + if (!mmoBroadcastingPlayer.getPlayer().getWorld() + .equals(listeningPlayer.getWorld())) { return false; //Not in the same world when its required } //Distance checks - if(mcMMO.p.getGeneralConfig().shouldLevelUpBroadcastsRestrictDistance()) { - if(!Misc.isNear(mmoBroadcastingPlayer.getPlayer().getLocation(), listeningPlayer.getLocation(), mcMMO.p.getGeneralConfig().getLevelUpBroadcastRadius())) { + if (mcMMO.p.getGeneralConfig().shouldLevelUpBroadcastsRestrictDistance()) { + if (!Misc.isNear(mmoBroadcastingPlayer.getPlayer().getLocation(), + listeningPlayer.getLocation(), + mcMMO.p.getGeneralConfig().getLevelUpBroadcastRadius())) { return false; } } } //Visibility checks - if(!listeningPlayer.canSee(mmoBroadcastingPlayer.getPlayer()) && listeningPlayer != mmoBroadcastingPlayer.getPlayer()) { - return false; //Player who leveled should be invisible to this player so don't send the message - } - - return true; + return listeningPlayer.canSee(mmoBroadcastingPlayer.getPlayer()) + || listeningPlayer + == mmoBroadcastingPlayer.getPlayer(); //Player who leveled should be invisible to this player so don't send the message } else { //Send out to console return mcMMO.p.getGeneralConfig().shouldLevelUpBroadcastToConsole(); diff --git a/src/main/java/com/gmail/nossr50/datatypes/PowerLevelUpBroadcastPredicate.java b/src/main/java/com/gmail/nossr50/datatypes/PowerLevelUpBroadcastPredicate.java index 05e7a3a1a..cd472d869 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/PowerLevelUpBroadcastPredicate.java +++ b/src/main/java/com/gmail/nossr50/datatypes/PowerLevelUpBroadcastPredicate.java @@ -5,12 +5,11 @@ import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.Misc; import com.gmail.nossr50.util.player.UserManager; +import java.util.function.Predicate; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; -import java.util.function.Predicate; - //TODO: Allow for offline players to broadcast public class PowerLevelUpBroadcastPredicate implements Predicate { @@ -25,60 +24,62 @@ public class PowerLevelUpBroadcastPredicate implements Player broadcastingPlayer = (Player) broadcaster; //Always a player no need to check cast //Broadcaster should be online - if(!broadcastingPlayer.isOnline()) { + if (!broadcastingPlayer.isOnline()) { return false; } McMMOPlayer mmoBroadcastingPlayer = UserManager.getPlayer(broadcastingPlayer); - if(mmoBroadcastingPlayer == null) { + if (mmoBroadcastingPlayer == null) { //This should never be null, but just in case... - mcMMO.p.getLogger().severe("McMMOPlayer was null for broadcaster in LevelUpBroadcastPredicate when it should never be null!"); + mcMMO.p.getLogger() + .severe("McMMOPlayer was null for broadcaster in LevelUpBroadcastPredicate when it should never be null!"); return false; } - if(t instanceof Player listeningPlayer) { + if (t instanceof Player listeningPlayer) { //Party Member Check - if(mcMMO.p.getGeneralConfig().isPowerLevelUpBroadcastsPartyMembersOnly()) { + if (mcMMO.p.getGeneralConfig().isPowerLevelUpBroadcastsPartyMembersOnly()) { McMMOPlayer mmoListeningPlayer = UserManager.getPlayer(listeningPlayer); - if(mmoListeningPlayer == null) { + if (mmoListeningPlayer == null) { return false; //No profile so therefor no party } Party playerWhoLeveledParty = mmoBroadcastingPlayer.getParty(); Party broadcastRecipientParty = mmoListeningPlayer.getParty(); - if(playerWhoLeveledParty == null || broadcastRecipientParty == null) { + if (playerWhoLeveledParty == null || broadcastRecipientParty == null) { return false; //No party on either player when being in the same party is required } - if(!playerWhoLeveledParty.equals(broadcastRecipientParty)) { + if (!playerWhoLeveledParty.equals(broadcastRecipientParty)) { return false; //Not in the same party when it is required } } //Same world check - if(isPowerLevelUpBroadcastsSameWorldOnly()) { - if(!mmoBroadcastingPlayer.getPlayer().getWorld().equals(listeningPlayer.getWorld())) { + if (isPowerLevelUpBroadcastsSameWorldOnly()) { + if (!mmoBroadcastingPlayer.getPlayer().getWorld() + .equals(listeningPlayer.getWorld())) { return false; //Not in the same world when its required } //Distance checks - if(mcMMO.p.getGeneralConfig().shouldPowerLevelUpBroadcastsRestrictDistance()) { - if(!Misc.isNear(mmoBroadcastingPlayer.getPlayer().getLocation(), listeningPlayer.getLocation(), mcMMO.p.getGeneralConfig().getPowerLevelUpBroadcastRadius())) { + if (mcMMO.p.getGeneralConfig().shouldPowerLevelUpBroadcastsRestrictDistance()) { + if (!Misc.isNear(mmoBroadcastingPlayer.getPlayer().getLocation(), + listeningPlayer.getLocation(), + mcMMO.p.getGeneralConfig().getPowerLevelUpBroadcastRadius())) { return false; } } } //Visibility checks - if(!listeningPlayer.canSee(mmoBroadcastingPlayer.getPlayer()) && listeningPlayer != mmoBroadcastingPlayer.getPlayer()) { - return false; //Player who leveled should be invisible to this player so don't send the message - } - - return true; + return listeningPlayer.canSee(mmoBroadcastingPlayer.getPlayer()) + || listeningPlayer + == mmoBroadcastingPlayer.getPlayer(); //Player who leveled should be invisible to this player so don't send the message } else { //Send out to console return mcMMO.p.getGeneralConfig().shouldPowerLevelUpBroadcastToConsole(); diff --git a/src/main/java/com/gmail/nossr50/datatypes/chat/ChatChannel.java b/src/main/java/com/gmail/nossr50/datatypes/chat/ChatChannel.java index f6edfa5f0..5d1bc29f5 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/chat/ChatChannel.java +++ b/src/main/java/com/gmail/nossr50/datatypes/chat/ChatChannel.java @@ -4,8 +4,10 @@ import com.gmail.nossr50.locale.LocaleLoader; import org.jetbrains.annotations.Nullable; public enum ChatChannel { - ADMIN(LocaleLoader.getString("Commands.AdminChat.On"), LocaleLoader.getString("Commands.AdminChat.Off")), - PARTY(LocaleLoader.getString("Commands.Party.Chat.On"), LocaleLoader.getString("Commands.Party.Chat.Off")), + ADMIN(LocaleLoader.getString("Commands.AdminChat.On"), + LocaleLoader.getString("Commands.AdminChat.Off")), + PARTY(LocaleLoader.getString("Commands.Party.Chat.On"), + LocaleLoader.getString("Commands.Party.Chat.Off")), PARTY_OFFICER(null, null), NONE(null, null); @@ -13,7 +15,7 @@ public enum ChatChannel { private final String disabledMessage; ChatChannel(@Nullable String enabledMessage, @Nullable String disabledMessage) { - this.enabledMessage = enabledMessage; + this.enabledMessage = enabledMessage; this.disabledMessage = disabledMessage; } diff --git a/src/main/java/com/gmail/nossr50/datatypes/database/DatabaseType.java b/src/main/java/com/gmail/nossr50/datatypes/database/DatabaseType.java index c8e089ab6..11a01cdec 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/database/DatabaseType.java +++ b/src/main/java/com/gmail/nossr50/datatypes/database/DatabaseType.java @@ -14,8 +14,7 @@ public enum DatabaseType { if (typeName.equalsIgnoreCase("file")) { return FLATFILE; - } - else if (typeName.equalsIgnoreCase("mysql")) { + } else if (typeName.equalsIgnoreCase("mysql")) { return SQL; } diff --git a/src/main/java/com/gmail/nossr50/datatypes/database/PlayerStat.java b/src/main/java/com/gmail/nossr50/datatypes/database/PlayerStat.java index 825be52ba..a6b0e7665 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/database/PlayerStat.java +++ b/src/main/java/com/gmail/nossr50/datatypes/database/PlayerStat.java @@ -1,11 +1,14 @@ package com.gmail.nossr50.datatypes.database; -public class PlayerStat { - public String name; - public int statVal = 0; +import org.jetbrains.annotations.NotNull; - public PlayerStat(String name, int value) { - this.name = name; - this.statVal = value; +public record PlayerStat(String playerName, int value) implements Comparable { + @Override + public int compareTo(@NotNull PlayerStat o) { + // Descending order + int cmp = Integer.compare(o.value, this.value); + if (cmp != 0) return cmp; + // Tie-breaker + return this.playerName.compareTo(o.playerName); } } diff --git a/src/main/java/com/gmail/nossr50/datatypes/experience/FormulaType.java b/src/main/java/com/gmail/nossr50/datatypes/experience/FormulaType.java index ea428d812..9637fe014 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/experience/FormulaType.java +++ b/src/main/java/com/gmail/nossr50/datatypes/experience/FormulaType.java @@ -8,8 +8,7 @@ public enum FormulaType { public static FormulaType getFormulaType(String string) { try { return valueOf(string); - } - catch (IllegalArgumentException ex) { + } catch (IllegalArgumentException ex) { return UNKNOWN; } } diff --git a/src/main/java/com/gmail/nossr50/datatypes/experience/SkillXpGain.java b/src/main/java/com/gmail/nossr50/datatypes/experience/SkillXpGain.java index 3ffb1cd94..c166ae10a 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/experience/SkillXpGain.java +++ b/src/main/java/com/gmail/nossr50/datatypes/experience/SkillXpGain.java @@ -2,10 +2,9 @@ package com.gmail.nossr50.datatypes.experience; import com.gmail.nossr50.config.experience.ExperienceConfig; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; -import org.jetbrains.annotations.NotNull; - import java.util.concurrent.Delayed; import java.util.concurrent.TimeUnit; +import org.jetbrains.annotations.NotNull; public class SkillXpGain implements Delayed { private final long expiryTime; @@ -27,14 +26,14 @@ public class SkillXpGain implements Delayed { } private static long getDuration() { - return TimeUnit.MINUTES.toMillis(ExperienceConfig.getInstance().getDiminishedReturnsTimeInterval()); + return TimeUnit.MINUTES.toMillis( + ExperienceConfig.getInstance().getDiminishedReturnsTimeInterval()); } public int compareTo(SkillXpGain other) { if (this.expiryTime < other.expiryTime) { return -1; - } - else if (this.expiryTime > other.expiryTime) { + } else if (this.expiryTime > other.expiryTime) { return 1; } return 0; diff --git a/src/main/java/com/gmail/nossr50/datatypes/json/McMMOUrl.java b/src/main/java/com/gmail/nossr50/datatypes/json/McMMOUrl.java index 4cac6d1e5..f8120730a 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/json/McMMOUrl.java +++ b/src/main/java/com/gmail/nossr50/datatypes/json/McMMOUrl.java @@ -1,17 +1,15 @@ package com.gmail.nossr50.datatypes.json; public class McMMOUrl { - public static final String urlWebsite = "https://www.mcmmo.org"; - public static final String urlDiscord = "https://discord.gg/bJ7pFS9"; - public static final String urlPatreon = "https://www.patreon.com/nossr50"; - public static final String urlWiki = "https://wiki.mcmmo.org/"; - public static final String urlSpigot = "https://spigot.mcmmo.org"; + public static final String urlWebsite = "https://www.mcmmo.org"; + public static final String urlDiscord = "https://discord.gg/bJ7pFS9"; + public static final String urlPatreon = "https://www.patreon.com/nossr50"; + public static final String urlWiki = "https://wiki.mcmmo.org/"; + public static final String urlSpigot = "https://spigot.mcmmo.org"; public static final String urlTranslate = "https://translate.mcmmo.org/"; - public static String getUrl(McMMOWebLinks webLinks) - { - switch(webLinks) - { + public static String getUrl(McMMOWebLinks webLinks) { + switch (webLinks) { case WIKI: return urlWiki; case PATREON: diff --git a/src/main/java/com/gmail/nossr50/datatypes/json/McMMOWebLinks.java b/src/main/java/com/gmail/nossr50/datatypes/json/McMMOWebLinks.java index 9648883fb..e27aac8eb 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/json/McMMOWebLinks.java +++ b/src/main/java/com/gmail/nossr50/datatypes/json/McMMOWebLinks.java @@ -11,28 +11,24 @@ public enum McMMOWebLinks { HELP_TRANSLATE, WIKI; - public String getUrl() - { + public String getUrl() { return McMMOUrl.getUrl(this); } - public String getNiceTitle() - { + public String getNiceTitle() { return StringUtils.getCapitalized(toString()); } - public String getLocaleDescription() - { - switch (this) - { + public String getLocaleDescription() { + switch (this) { case WEBSITE: - return LocaleLoader.getString( "JSON.URL.Website"); + return LocaleLoader.getString("JSON.URL.Website"); case DISCORD: - return LocaleLoader.getString( "JSON.URL.Discord"); + return LocaleLoader.getString("JSON.URL.Discord"); case PATREON: - return LocaleLoader.getString( "JSON.URL.Patreon"); + return LocaleLoader.getString("JSON.URL.Patreon"); case HELP_TRANSLATE: - return LocaleLoader.getString( "JSON.URL.Translation"); + return LocaleLoader.getString("JSON.URL.Translation"); case SPIGOT: return LocaleLoader.getString("JSON.URL.Spigot"); case WIKI: diff --git a/src/main/java/com/gmail/nossr50/datatypes/meta/OldName.java b/src/main/java/com/gmail/nossr50/datatypes/meta/OldName.java index 137399009..9aac9b224 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/meta/OldName.java +++ b/src/main/java/com/gmail/nossr50/datatypes/meta/OldName.java @@ -8,8 +8,7 @@ import org.bukkit.metadata.FixedMetadataValue; */ public class OldName extends FixedMetadataValue { - public OldName(String oldName, mcMMO plugin) - { + public OldName(String oldName, mcMMO plugin) { super(plugin, oldName); } diff --git a/src/main/java/com/gmail/nossr50/datatypes/meta/RuptureTaskMeta.java b/src/main/java/com/gmail/nossr50/datatypes/meta/RuptureTaskMeta.java index b484ce8cd..9563449af 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/meta/RuptureTaskMeta.java +++ b/src/main/java/com/gmail/nossr50/datatypes/meta/RuptureTaskMeta.java @@ -8,11 +8,12 @@ import org.jetbrains.annotations.NotNull; public class RuptureTaskMeta extends FixedMetadataValue { private final @NotNull RuptureTask ruptureTask; + /** * Initializes a FixedMetadataValue with an Object * * @param owningPlugin the {@link Plugin} that created this metadata value - * @param ruptureTask the value assigned to this metadata value + * @param ruptureTask the value assigned to this metadata value */ public RuptureTaskMeta(@NotNull Plugin owningPlugin, @NotNull RuptureTask ruptureTask) { super(owningPlugin, ruptureTask); diff --git a/src/main/java/com/gmail/nossr50/datatypes/meta/UUIDMeta.java b/src/main/java/com/gmail/nossr50/datatypes/meta/UUIDMeta.java index 3ba795def..4174a8d68 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/meta/UUIDMeta.java +++ b/src/main/java/com/gmail/nossr50/datatypes/meta/UUIDMeta.java @@ -1,18 +1,17 @@ package com.gmail.nossr50.datatypes.meta; +import java.util.UUID; import org.bukkit.metadata.FixedMetadataValue; import org.bukkit.plugin.Plugin; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.UUID; - public class UUIDMeta extends FixedMetadataValue { /** * Initializes a FixedMetadataValue with an Object * * @param owningPlugin the {@link Plugin} that created this metadata value - * @param value the value assigned to this metadata value + * @param value the value assigned to this metadata value */ public UUIDMeta(@NotNull Plugin owningPlugin, @Nullable UUID value) { super(owningPlugin, value); diff --git a/src/main/java/com/gmail/nossr50/datatypes/mods/CustomEntity.java b/src/main/java/com/gmail/nossr50/datatypes/mods/CustomEntity.java index c1b8fc118..88846f364 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/mods/CustomEntity.java +++ b/src/main/java/com/gmail/nossr50/datatypes/mods/CustomEntity.java @@ -10,7 +10,8 @@ public class CustomEntity { private final ItemStack callOfTheWildItem; private final int callOfTheWildAmount; - public CustomEntity(double xpMultiplier, boolean canBeTamed, int tamingXP, boolean canBeSummoned, ItemStack callOfTheWildItem, int callOfTheWildAmount) { + public CustomEntity(double xpMultiplier, boolean canBeTamed, int tamingXP, + boolean canBeSummoned, ItemStack callOfTheWildItem, int callOfTheWildAmount) { this.xpMultiplier = xpMultiplier; this.canBeTamed = canBeTamed; this.tamingXP = tamingXP; diff --git a/src/main/java/com/gmail/nossr50/datatypes/party/ItemShareType.java b/src/main/java/com/gmail/nossr50/datatypes/party/ItemShareType.java index 270421f14..5f744c093 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/party/ItemShareType.java +++ b/src/main/java/com/gmail/nossr50/datatypes/party/ItemShareType.java @@ -15,17 +15,13 @@ public enum ItemShareType { public static ItemShareType getShareType(ItemStack itemStack) { if (ItemUtils.isMobDrop(itemStack)) { return LOOT; - } - else if (ItemUtils.isMiningDrop(itemStack)) { + } else if (ItemUtils.isMiningDrop(itemStack)) { return MINING; - } - else if (ItemUtils.isHerbalismDrop(itemStack)) { + } else if (ItemUtils.isHerbalismDrop(itemStack)) { return HERBALISM; - } - else if (ItemUtils.isWoodcuttingDrop(itemStack)) { + } else if (ItemUtils.isWoodcuttingDrop(itemStack)) { return WOODCUTTING; - } - else if (ItemUtils.isMiscDrop(itemStack)) { + } else if (ItemUtils.isMiscDrop(itemStack)) { return MISC; } @@ -33,6 +29,7 @@ public enum ItemShareType { } public String getLocaleString() { - return LocaleLoader.getString("Party.ItemShare.Category." + StringUtils.getCapitalized(this.toString())); + return LocaleLoader.getString( + "Party.ItemShare.Category." + StringUtils.getCapitalized(this.toString())); } } 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 af5aa7b74..44dfe328c 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/party/Party.java +++ b/src/main/java/com/gmail/nossr50/datatypes/party/Party.java @@ -6,11 +6,18 @@ import com.gmail.nossr50.datatypes.experience.FormulaType; 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; import com.gmail.nossr50.util.sounds.SoundType; +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Locale; +import java.util.UUID; +import java.util.function.Predicate; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.OfflinePlayer; @@ -18,14 +25,11 @@ import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; -import java.text.DecimalFormat; -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.UUID; -import java.util.function.Predicate; - public class Party { + + private static final DecimalFormat percent = new DecimalFormat("##0.00%", + DecimalFormatSymbols.getInstance(Locale.US)); + private final @NotNull Predicate samePartyPredicate; private final LinkedHashMap members = new LinkedHashMap<>(); private final List onlineMembers = new ArrayList<>(); @@ -38,14 +42,14 @@ public class Party { private int level; private float xp; - private ShareMode xpShareMode = ShareMode.NONE; + private ShareMode xpShareMode = ShareMode.NONE; private ShareMode itemShareMode = ShareMode.NONE; - private boolean shareLootDrops = true; - private boolean shareMiningDrops = true; - private boolean shareHerbalismDrops = true; + private boolean shareLootDrops = true; + private boolean shareMiningDrops = true; + private boolean shareHerbalismDrops = true; private boolean shareWoodcuttingDrops = true; - private boolean shareMiscDrops = true; + private boolean shareMiscDrops = true; public Party(String name) { this.name = name; @@ -86,14 +90,13 @@ public class Party { return onlineMembers; } - public List getVisibleMembers(Player player) - { + public List getVisibleMembers(Player player) { ArrayList visibleMembers = new ArrayList<>(); - for(Player p : onlineMembers) - { - if(player.canSee(p)) + for (Player p : getOnlineMembers()) { + if (player.canSee(p)) { visibleMembers.add(p); + } } return visibleMembers; @@ -113,11 +116,11 @@ public class Party { } public boolean addOnlineMember(Player player) { - return onlineMembers.add(player); + return getOnlineMembers().add(player); } public boolean removeOnlineMember(Player player) { - return onlineMembers.remove(player); + return getOnlineMembers().remove(player); } public String getName() { @@ -203,11 +206,11 @@ public class Party { public int getXpToLevel() { FormulaType formulaType = ExperienceConfig.getInstance().getFormulaType(); - return (mcMMO.p.getFormulaManager().getXPtoNextLevel(level, formulaType)) * (getOnlineMembers().size() + mcMMO.p.getGeneralConfig().getPartyXpCurveMultiplier()); + return (mcMMO.p.getFormulaManager().getXPtoNextLevel(level, formulaType)) * ( + getOnlineMembers().size() + mcMMO.p.getGeneralConfig().getPartyXpCurveMultiplier()); } public String getXpToLevelPercentage() { - DecimalFormat percent = new DecimalFormat("##0.00%"); return percent.format(this.getXp() / getXpToLevel()); } @@ -246,14 +249,15 @@ public class Party { Player leader = mcMMO.p.getServer().getPlayer(this.leader.getUniqueId()); if (leader != null) { - leader.sendMessage(LocaleLoader.getString("Party.LevelUp", levelsGained, getLevel())); + leader.sendMessage( + LocaleLoader.getString("Party.LevelUp", levelsGained, getLevel())); if (mcMMO.p.getGeneralConfig().getLevelUpSoundsEnabled()) { SoundManager.sendSound(leader, leader.getLocation(), SoundType.LEVEL_UP); } } } else { - PartyManager.informPartyMembersLevelUp(this, levelsGained, getLevel()); + mcMMO.p.getPartyManager().informPartyMembersLevelUp(this, levelsGained, getLevel()); } } @@ -335,9 +339,10 @@ public class Party { } /** - * Makes a formatted list of party members based on the perspective of a target player - * Players that are hidden will be shown as offline (formatted in the same way) - * Party leader will be formatted a specific way as well + * Makes a formatted list of party members based on the perspective of a target player Players + * that are hidden will be shown as offline (formatted in the same way) Party leader will be + * formatted a specific way as well + * * @param player target player to use as POV * @return formatted list of party members from the POV of a player */ @@ -345,11 +350,12 @@ public class Party { StringBuilder memberList = new StringBuilder(); List coloredNames = new ArrayList<>(); - for(UUID playerUUID : members.keySet()) { + for (UUID playerUUID : members.keySet()) { OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(playerUUID); - if(offlinePlayer.isOnline() && player.canSee((Player) offlinePlayer)) { - ChatColor onlineColor = leader.getUniqueId().equals(playerUUID) ? ChatColor.GOLD : ChatColor.GREEN; + if (offlinePlayer.isOnline() && player.canSee((Player) offlinePlayer)) { + ChatColor onlineColor = + leader.getUniqueId().equals(playerUUID) ? ChatColor.GOLD : ChatColor.GREEN; coloredNames.add(onlineColor + offlinePlayer.getName()); } else { coloredNames.add(ChatColor.DARK_GRAY + members.get(playerUUID)); @@ -361,8 +367,8 @@ public class Party { } private void buildChatMessage(@NotNull StringBuilder stringBuilder, String @NotNull [] names) { - for(int i = 0; i < names.length; i++) { - if(i + 1 >= names.length) { + for (int i = 0; i < names.length; i++) { + if (i + 1 >= names.length) { stringBuilder .append(names[i]); } else { @@ -376,19 +382,20 @@ public class Party { /** * Get the near party members. * - * @param mcMMOPlayer The player to check + * @param mmoPlayer The player to check * @return the near party members */ - public List getNearMembers(McMMOPlayer mcMMOPlayer) { + public List getNearMembers(McMMOPlayer mmoPlayer) { List nearMembers = new ArrayList<>(); - Party party = mcMMOPlayer.getParty(); + Party party = mmoPlayer.getParty(); if (party != null) { - Player player = mcMMOPlayer.getPlayer(); + Player player = mmoPlayer.getPlayer(); double range = mcMMO.p.getGeneralConfig().getPartyShareRange(); for (Player member : party.getOnlineMembers()) { - if (!player.equals(member) && member.isValid() && Misc.isNear(player.getLocation(), member.getLocation(), range)) { + if (!player.equals(member) && member.isValid() && Misc.isNear(player.getLocation(), + member.getLocation(), range)) { nearMembers.add(member); } } diff --git a/src/main/java/com/gmail/nossr50/datatypes/party/PartyFeature.java b/src/main/java/com/gmail/nossr50/datatypes/party/PartyFeature.java index b50bfe852..8acc68306 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/party/PartyFeature.java +++ b/src/main/java/com/gmail/nossr50/datatypes/party/PartyFeature.java @@ -1,10 +1,11 @@ package com.gmail.nossr50.datatypes.party; +import static com.gmail.nossr50.util.text.ConfigStringUtils.getConfigPartyFeatureString; + import com.gmail.nossr50.commands.party.PartySubcommandType; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.Permissions; -import com.gmail.nossr50.util.text.StringUtils; import org.bukkit.entity.Player; public enum PartyFeature { @@ -15,11 +16,13 @@ public enum PartyFeature { XP_SHARE; public String getLocaleString() { - return LocaleLoader.getString("Party.Feature." + StringUtils.getPrettyPartyFeatureString(this).replace(" ", "")); + return LocaleLoader.getString("Party.Feature." + getConfigPartyFeatureString(this)); } public String getFeatureLockedLocaleString() { - return LocaleLoader.getString("Ability.Generic.Template.Lock", LocaleLoader.getString("Party.Feature.Locked." + StringUtils.getPrettyPartyFeatureString(this).replace(" ", ""), mcMMO.p.getGeneralConfig().getPartyFeatureUnlockLevel(this))); + return LocaleLoader.getString("Ability.Generic.Template.Lock", + LocaleLoader.getString("Party.Feature.Locked." + getConfigPartyFeatureString(this), + mcMMO.p.getGeneralConfig().getPartyFeatureUnlockLevel(this))); } public boolean hasPermission(Player player) { @@ -44,7 +47,6 @@ public enum PartyFeature { return false; } - return Permissions.partySubcommand(player, partySubCommandType); } } diff --git a/src/main/java/com/gmail/nossr50/datatypes/party/PartyTeleportRecord.java b/src/main/java/com/gmail/nossr50/datatypes/party/PartyTeleportRecord.java index 17d815a6b..7c79d9cec 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/party/PartyTeleportRecord.java +++ b/src/main/java/com/gmail/nossr50/datatypes/party/PartyTeleportRecord.java @@ -5,9 +5,9 @@ import com.gmail.nossr50.util.Misc; import org.bukkit.entity.Player; public class PartyTeleportRecord { - private Player requestor; + private Player requestor; private boolean enabled, confirmRequired; - private int timeout, lastUse; + private int timeout, lastUse; public PartyTeleportRecord() { requestor = null; diff --git a/src/main/java/com/gmail/nossr50/datatypes/party/ShareMode.java b/src/main/java/com/gmail/nossr50/datatypes/party/ShareMode.java index 778ed08e6..33d64e51b 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/party/ShareMode.java +++ b/src/main/java/com/gmail/nossr50/datatypes/party/ShareMode.java @@ -10,12 +10,10 @@ public enum ShareMode { public static ShareMode getShareMode(String string) { try { return valueOf(string); - } - catch (IllegalArgumentException ex) { + } catch (IllegalArgumentException ex) { if (string.equalsIgnoreCase("even")) { return EQUAL; - } - else if (CommandUtils.shouldDisableToggle(string)) { + } else if (CommandUtils.shouldDisableToggle(string)) { return NONE; } 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 91dfe17e5..12a24cd5c 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java +++ b/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java @@ -1,5 +1,8 @@ package com.gmail.nossr50.datatypes.player; +import static com.gmail.nossr50.util.EventUtils.callPlayerAbilityActivateEvent; +import static java.util.Objects.requireNonNull; + import com.gmail.nossr50.api.exceptions.InvalidSkillException; import com.gmail.nossr50.chat.author.PlayerAuthor; import com.gmail.nossr50.config.ChatConfig; @@ -10,7 +13,6 @@ import com.gmail.nossr50.datatypes.experience.XPGainReason; import com.gmail.nossr50.datatypes.experience.XPGainSource; import com.gmail.nossr50.datatypes.interactions.NotificationType; import com.gmail.nossr50.datatypes.meta.RuptureTaskMeta; -import com.gmail.nossr50.datatypes.mods.CustomTool; import com.gmail.nossr50.datatypes.party.Party; import com.gmail.nossr50.datatypes.party.PartyTeleportRecord; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; @@ -20,28 +22,34 @@ import com.gmail.nossr50.datatypes.skills.ToolType; 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.AbilityDisableTask; +import com.gmail.nossr50.runnables.skills.RuptureTask; import com.gmail.nossr50.runnables.skills.ToolLowerTask; import com.gmail.nossr50.skills.SkillManager; import com.gmail.nossr50.skills.acrobatics.AcrobaticsManager; 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; import com.gmail.nossr50.skills.herbalism.HerbalismManager; +import com.gmail.nossr50.skills.maces.MacesManager; import com.gmail.nossr50.skills.mining.MiningManager; import com.gmail.nossr50.skills.repair.RepairManager; import com.gmail.nossr50.skills.salvage.SalvageManager; import com.gmail.nossr50.skills.smelting.SmeltingManager; 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.skills.woodcutting.WoodcuttingManager; -import com.gmail.nossr50.util.*; +import com.gmail.nossr50.util.BlockUtils; +import com.gmail.nossr50.util.EventUtils; +import com.gmail.nossr50.util.MetadataConstants; +import com.gmail.nossr50.util.Misc; +import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.experience.ExperienceBarManager; import com.gmail.nossr50.util.player.NotificationManager; import com.gmail.nossr50.util.player.UserManager; @@ -52,6 +60,9 @@ import com.gmail.nossr50.util.skills.SkillTools; import com.gmail.nossr50.util.skills.SkillUtils; import com.gmail.nossr50.util.sounds.SoundManager; import com.gmail.nossr50.util.sounds.SoundType; +import java.util.EnumMap; +import java.util.Map; +import java.util.UUID; import net.kyori.adventure.identity.Identified; import net.kyori.adventure.identity.Identity; import org.bukkit.GameMode; @@ -63,11 +74,8 @@ import org.bukkit.metadata.FixedMetadataValue; import org.bukkit.plugin.Plugin; import org.checkerframework.checker.nullness.qual.NonNull; import org.jetbrains.annotations.NotNull; - -import java.util.EnumMap; -import java.util.Map; -import java.util.Set; -import java.util.UUID; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.VisibleForTesting; public class McMMOPlayer implements Identified { private final @NotNull Identity identity; @@ -75,16 +83,17 @@ public class McMMOPlayer implements Identified { //Hacky fix for now, redesign later private final @NotNull PlayerAuthor playerAuthor; - private final Player player; + private final Player player; private final PlayerProfile profile; - private final Map skillManagers = new EnumMap<>(PrimarySkillType.class); + private final Map skillManagers = new EnumMap<>( + PrimarySkillType.class); private final ExperienceBarManager experienceBarManager; - private Party party; - private Party invite; - private Party allianceInvite; - private int itemShareModifier; + private Party party; + private Party invite; + private Party allianceInvite; + private int itemShareModifier; private PartyTeleportRecord ptpRecord; @@ -97,8 +106,10 @@ public class McMMOPlayer implements Identified { private ChatChannel chatChannel; - private final Map abilityMode = new EnumMap<>(SuperAbilityType.class); - private final Map abilityInformed = new EnumMap<>(SuperAbilityType.class); + private final Map abilityMode = new EnumMap<>( + SuperAbilityType.class); + private final Map abilityInformed = new EnumMap<>( + SuperAbilityType.class); private final Map toolMode = new EnumMap<>(ToolType.class); @@ -106,7 +117,6 @@ public class McMMOPlayer implements Identified { private int respawnATS; private int teleportATS; private long databaseATS; - private double attackStrength; //captured during arm swing events //private int chimeraWingLastUse; private Location teleportCommence; @@ -117,6 +127,8 @@ public class McMMOPlayer implements Identified { private PrimarySkillType lastSkillShownScoreboard = PrimarySkillType.values()[0]; public McMMOPlayer(Player player, PlayerProfile profile) { + requireNonNull(player, "player cannot be null"); + requireNonNull(profile, "profile cannot be null"); this.playerName = player.getName(); UUID uuid = player.getUniqueId(); identity = Identity.identity(uuid); @@ -143,19 +155,18 @@ public class McMMOPlayer implements Identified { experienceBarManager = new ExperienceBarManager(this); debugMode = false; //Debug mode helps solve support issues, players can toggle it on or off - attackStrength = 1.0D; this.playerAuthor = new PlayerAuthor(player); this.chatChannel = ChatChannel.NONE; - if(ChatConfig.getInstance().isSpyingAutomatic() && Permissions.adminChatSpy(getPlayer())) { + if (ChatConfig.getInstance().isSpyingAutomatic() && Permissions.adminChatSpy(getPlayer())) { chatSpy = true; } } private void initSkillManagers() { - for(PrimarySkillType primarySkillType : PrimarySkillType.values()) { + for (PrimarySkillType primarySkillType : PrimarySkillType.values()) { try { initManager(primarySkillType); } catch (InvalidSkillException e) { @@ -166,7 +177,7 @@ public class McMMOPlayer implements Identified { //TODO: Add test private void initManager(PrimarySkillType primarySkillType) throws InvalidSkillException { - switch(primarySkillType) { + switch (primarySkillType) { case ACROBATICS: skillManagers.put(primarySkillType, new AcrobaticsManager(this)); break; @@ -179,6 +190,9 @@ public class McMMOPlayer implements Identified { case AXES: skillManagers.put(primarySkillType, new AxesManager(this)); break; + case CROSSBOWS: + skillManagers.put(primarySkillType, new CrossbowsManager(this)); + break; case EXCAVATION: skillManagers.put(primarySkillType, new ExcavationManager(this)); break; @@ -206,14 +220,23 @@ public class McMMOPlayer implements Identified { case TAMING: skillManagers.put(primarySkillType, new TamingManager(this)); break; + case TRIDENTS: + skillManagers.put(primarySkillType, new TridentsManager(this)); + break; case UNARMED: skillManagers.put(primarySkillType, new UnarmedManager(this)); break; case WOODCUTTING: skillManagers.put(primarySkillType, new WoodcuttingManager(this)); break; + case MACES: + if (mcMMO.getCompatibilityManager().getMinecraftGameVersion().isAtLeast(1, 21, 0)) { + skillManagers.put(primarySkillType, new MacesManager(this)); + } + break; default: - throw new InvalidSkillException("The skill named has no manager! Contact the devs!"); + throw new InvalidSkillException( + "The skill named has no manager! Contact the devs!"); } } @@ -222,18 +245,13 @@ public class McMMOPlayer implements Identified { } public double getAttackStrength() { - return attackStrength; + if (mcMMO.p.getAdvancedConfig().useAttackCooldown()) { + return player.getAttackCooldown(); + } else { + return 1.0D; + } } -// public void setAttackStrength(double attackStrength) { -// this.attackStrength = attackStrength; -// } - - /*public void hideXpBar(PrimarySkillType primarySkillType) - { - experienceBarManager.hideExperienceBar(primarySkillType); - }*/ - public @NotNull PrimarySkillType getLastSkillShownScoreboard() { return lastSkillShownScoreboard; } @@ -242,42 +260,45 @@ public class McMMOPlayer implements Identified { this.lastSkillShownScoreboard = primarySkillType; } - public void processPostXpEvent(PrimarySkillType primarySkillType, Plugin plugin, XPGainSource xpGainSource) - { + public void processPostXpEvent(PrimarySkillType primarySkillType, Plugin plugin, + XPGainSource xpGainSource) { //Check if they've reached the power level cap just now - if(hasReachedPowerLevelCap()) { - NotificationManager.sendPlayerInformationChatOnly(player, "LevelCap.PowerLevel", String.valueOf(mcMMO.p.getGeneralConfig().getPowerLevelCap())); - } else if(hasReachedLevelCap(primarySkillType)) { + if (hasReachedPowerLevelCap()) { + NotificationManager.sendPlayerInformationChatOnly(player, "LevelCap.PowerLevel", + String.valueOf(mcMMO.p.getGeneralConfig().getPowerLevelCap())); + } else if (hasReachedLevelCap(primarySkillType)) { NotificationManager.sendPlayerInformationChatOnly(player, "LevelCap.Skill", String.valueOf(mcMMO.p.getSkillTools().getLevelCap(primarySkillType)), mcMMO.p.getSkillTools().getLocalizedSkillName(primarySkillType)); } //Updates from Party sources - if(xpGainSource == XPGainSource.PARTY_MEMBERS && !ExperienceConfig.getInstance().isPartyExperienceBarsEnabled()) + if (xpGainSource == XPGainSource.PARTY_MEMBERS && !ExperienceConfig.getInstance() + .isPartyExperienceBarsEnabled()) { return; + } //Updates from passive sources (Alchemy, Smelting, etc...) - if(xpGainSource == XPGainSource.PASSIVE && !ExperienceConfig.getInstance().isPassiveGainsExperienceBarsEnabled()) + if (xpGainSource == XPGainSource.PASSIVE && !ExperienceConfig.getInstance() + .isPassiveGainsExperienceBarsEnabled()) { return; + } updateXPBar(primarySkillType, plugin); } - public void processUnlockNotifications(mcMMO plugin, PrimarySkillType primarySkillType, int skillLevel) - { + public void processUnlockNotifications(mcMMO plugin, PrimarySkillType primarySkillType, + int skillLevel) { RankUtils.executeSkillUnlockNotifications(plugin, this, primarySkillType, skillLevel); } - public void updateXPBar(PrimarySkillType primarySkillType, Plugin plugin) - { + public void updateXPBar(PrimarySkillType primarySkillType, Plugin plugin) { //XP BAR UPDATES experienceBarManager.updateExperienceBar(primarySkillType, plugin); } - public double getProgressInCurrentSkillLevel(PrimarySkillType primarySkillType) - { - if(SkillTools.isChildSkill(primarySkillType)) { + public double getProgressInCurrentSkillLevel(PrimarySkillType primarySkillType) { + if (SkillTools.isChildSkill(primarySkillType)) { return 1.0D; } @@ -307,6 +328,18 @@ public class McMMOPlayer implements Identified { 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 MacesManager getMacesManager() { + return (MacesManager) skillManagers.get(PrimarySkillType.MACES); + } + public ExcavationManager getExcavationManager() { return (ExcavationManager) skillManagers.get(PrimarySkillType.EXCAVATION); } @@ -366,13 +399,14 @@ public class McMMOPlayer implements Identified { } /** - * Get the mode of an ability. + * Get the mode of a superAbilityType. * - * @param ability The ability to check - * @return true if the ability is enabled, false otherwise + * @param superAbilityType The superAbilityType to check + * @return true if the superAbilityType is enabled, false otherwise */ - public boolean getAbilityMode(SuperAbilityType ability) { - return abilityMode.get(ability); + public boolean getAbilityMode(@NotNull SuperAbilityType superAbilityType) { + requireNonNull(superAbilityType, "superAbilityType cannot be null"); + return abilityMode.get(superAbilityType); } /** @@ -382,6 +416,7 @@ public class McMMOPlayer implements Identified { * @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); } @@ -471,7 +506,8 @@ public class McMMOPlayer implements Identified { } public void actualizeChimeraWingLastUse() { - profile.setChimaeraWingDATS((int) (System.currentTimeMillis() / Misc.TIME_CONVERSION_FACTOR)); + profile.setChimaeraWingDATS( + (int) (System.currentTimeMillis() / Misc.TIME_CONVERSION_FACTOR)); } public Location getTeleportCommenceLocation() { @@ -530,9 +566,13 @@ public class McMMOPlayer implements Identified { * Party Chat Spy */ - public boolean isPartyChatSpying() { return chatSpy; } + public boolean isPartyChatSpying() { + return chatSpy; + } - public void togglePartyChatSpying() { chatSpy = !chatSpy;} + public void togglePartyChatSpying() { + chatSpy = !chatSpy; + } /* * Debug Mode Flags @@ -576,21 +616,25 @@ public class McMMOPlayer implements Identified { } /** - * Whether a player is level capped - * If they are at the power level cap, this will return true, otherwise it checks their skill level + * 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 */ public boolean hasReachedLevelCap(PrimarySkillType primarySkillType) { - if(hasReachedPowerLevelCap()) + if (hasReachedPowerLevelCap()) { return true; + } - return getSkillLevel(primarySkillType) >= mcMMO.p.getSkillTools().getLevelCap(primarySkillType); + return getSkillLevel(primarySkillType) >= mcMMO.p.getSkillTools() + .getLevelCap(primarySkillType); } /** - * Whether a player is power level capped - * Compares their power level total to the current set limit + * 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 */ public boolean hasReachedPowerLevelCap() { @@ -598,18 +642,20 @@ public class McMMOPlayer implements Identified { } /** - * Begins an experience gain. The amount will be affected by skill modifiers, global rate, perks, and may be shared with the party + * Begins an experience gain. The amount will be affected by skill modifiers, global rate, + * perks, and may be shared with the party * * @param skill Skill being used * @param xp Experience amount to process */ - public void beginXpGain(PrimarySkillType skill, float xp, XPGainReason xpGainReason, XPGainSource xpGainSource) { - if(xp <= 0) { + public void beginXpGain(PrimarySkillType skill, float xp, XPGainReason xpGainReason, + XPGainSource xpGainSource) { + if (xp <= 0) { return; } 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) { @@ -622,7 +668,8 @@ public class McMMOPlayer implements Identified { } // Return if the experience has been shared - if (party != null && ShareHandler.handleXpShare(xp, this, skill, ShareHandler.getSharedXpGainReason(xpGainReason))) { + if (party != null && ShareHandler.handleXpShare(xp, this, skill, + ShareHandler.getSharedXpGainReason(xpGainReason))) { return; } @@ -630,22 +677,27 @@ public class McMMOPlayer implements Identified { } /** - * Begins an experience gain. The amount will be affected by skill modifiers, global rate and perks + * Begins an experience gain. The amount will be affected by skill modifiers, global rate and + * perks * * @param skill Skill being used * @param xp Experience amount to process */ - public void beginUnsharedXpGain(PrimarySkillType skill, float xp, XPGainReason xpGainReason, XPGainSource xpGainSource) { - if(player.getGameMode() == GameMode.CREATIVE) - return; - - applyXpGain(skill, modifyXpGain(skill, xp), xpGainReason, xpGainSource); - - if (party == null || party.hasReachedLevelCap()) { + public void beginUnsharedXpGain(PrimarySkillType skill, float xp, XPGainReason xpGainReason, + XPGainSource xpGainSource) { + if (player.getGameMode() == GameMode.CREATIVE) { return; } - if (!mcMMO.p.getGeneralConfig().getPartyXpNearMembersNeeded() || !PartyManager.getNearMembers(this).isEmpty()) { + applyXpGain(skill, modifyXpGain(skill, xp), xpGainReason, xpGainSource); + + if (!mcMMO.p.getPartyConfig().isPartyEnabled() || party == null + || party.hasReachedLevelCap()) { + return; + } + + if (!mcMMO.p.getGeneralConfig().getPartyXpNearMembersNeeded() || !mcMMO.p.getPartyManager() + .getNearMembers(this).isEmpty()) { party.applyXpGain(modifyXpGain(skill, xp)); } } @@ -656,17 +708,19 @@ public class McMMOPlayer implements Identified { * @param primarySkillType Skill being used * @param xp Experience amount to add */ - public void applyXpGain(PrimarySkillType primarySkillType, float xp, XPGainReason xpGainReason, XPGainSource xpGainSource) { + public void applyXpGain(PrimarySkillType primarySkillType, float xp, XPGainReason xpGainReason, + XPGainSource xpGainSource) { if (!mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, primarySkillType)) { return; } - final McMMOPlayerPreXpGainEvent mcMMOPlayerPreXpGainEvent = new McMMOPlayerPreXpGainEvent(player, primarySkillType, xp, xpGainReason); - mcMMO.p.getServer().getPluginManager().callEvent(mcMMOPlayerPreXpGainEvent); - xp = mcMMOPlayerPreXpGainEvent.getXpGained(); + final McMMOPlayerPreXpGainEvent mmoPlayerPreXpGainEvent = new McMMOPlayerPreXpGainEvent( + player, primarySkillType, xp, xpGainReason); + mcMMO.p.getServer().getPluginManager().callEvent(mmoPlayerPreXpGainEvent); + xp = mmoPlayerPreXpGainEvent.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); @@ -688,9 +742,11 @@ public class McMMOPlayer implements Identified { * * @param primarySkillType The skill to check */ - private void checkXp(PrimarySkillType primarySkillType, XPGainReason xpGainReason, XPGainSource xpGainSource) { - if(hasReachedLevelCap(primarySkillType)) + private void checkXp(PrimarySkillType primarySkillType, XPGainReason xpGainReason, + XPGainSource xpGainSource) { + if (hasReachedLevelCap(primarySkillType)) { return; + } if (getSkillXpLevelRaw(primarySkillType) < getXpToLevel(primarySkillType)) { processPostXpEvent(primarySkillType, mcMMO.p, xpGainSource); @@ -710,7 +766,8 @@ public class McMMOPlayer implements Identified { levelsGained++; } - if (EventUtils.tryLevelChangeEvent(this, primarySkillType, levelsGained, xpRemoved, true, xpGainReason)) { + if (EventUtils.tryLevelChangeEvent(this, primarySkillType, levelsGained, xpRemoved, true, + xpGainReason)) { return; } @@ -722,7 +779,8 @@ public class McMMOPlayer implements Identified { * Check to see if the player unlocked any new skills */ - NotificationManager.sendPlayerLevelUpNotification(this, primarySkillType, levelsGained, profile.getSkillLevel(primarySkillType)); + NotificationManager.sendPlayerLevelUpNotification(this, primarySkillType, levelsGained, + profile.getSkillLevel(primarySkillType)); //UPDATE XP BARS processPostXpEvent(primarySkillType, mcMMO.p, xpGainSource); @@ -732,11 +790,11 @@ public class McMMOPlayer implements Identified { * Players & Profiles */ - public Player getPlayer() { + public @NotNull Player getPlayer() { return player; } - public PlayerProfile getProfile() { + public @NotNull PlayerProfile getProfile() { return profile; } @@ -745,11 +803,14 @@ public class McMMOPlayer implements Identified { */ public void setupPartyData() { - party = PartyManager.getPlayerParty(player.getName(), player.getUniqueId()); - ptpRecord = new PartyTeleportRecord(); + if (mcMMO.p.isPartySystemEnabled()) { + party = mcMMO.p.getPartyManager() + .getPlayerParty(player.getName(), player.getUniqueId()); + ptpRecord = new PartyTeleportRecord(); - if (inParty()) { - loginParty(); + if (inParty()) { + loginParty(); + } } } @@ -769,7 +830,7 @@ public class McMMOPlayer implements Identified { this.party = party; } - public Party getParty() { + public @Nullable Party getParty() { return party; } @@ -785,7 +846,7 @@ public class McMMOPlayer implements Identified { invite = null; } - public PartyTeleportRecord getPartyTeleportRecord() { + public @Nullable PartyTeleportRecord getPartyTeleportRecord() { return ptpRecord; } @@ -832,29 +893,25 @@ public class McMMOPlayer implements Identified { * @param xp Experience amount to process * @return Modified experience */ - private float modifyXpGain(PrimarySkillType primarySkillType, float xp) { + @VisibleForTesting + float modifyXpGain(PrimarySkillType primarySkillType, float xp) { //TODO: A rare situation can occur where the default Power Level cap can prevent a player with one skill edited to something silly like Integer.MAX_VALUE from gaining XP in any skill, we may need to represent power level with another data type - if ((mcMMO.p.getSkillTools().getLevelCap(primarySkillType) <= getSkillLevel(primarySkillType)) + if ((mcMMO.p.getSkillTools().getLevelCap(primarySkillType) <= getSkillLevel( + primarySkillType)) || (mcMMO.p.getGeneralConfig().getPowerLevelCap() <= getPowerLevel())) { return 0; } - xp = (float) (xp / ExperienceConfig.getInstance().getFormulaSkillModifier(primarySkillType) * ExperienceConfig.getInstance().getExperienceGainsGlobalMultiplier()); - - if (mcMMO.p.getGeneralConfig().getToolModsEnabled()) { - CustomTool tool = mcMMO.getModManager().getTool(player.getInventory().getItemInMainHand()); - - if (tool != null) { - xp *= tool.getXpMultiplier(); - } - } + xp = (float) ( + (xp * ExperienceConfig.getInstance().getFormulaSkillModifier(primarySkillType)) + * ExperienceConfig.getInstance().getExperienceGainsGlobalMultiplier()); return PerksUtils.handleXpPerks(player, xp, primarySkillType); } public void checkGodMode() { if (godMode && !Permissions.mcgod(player) - || godMode && WorldBlacklist.isWorldBlacklisted(player.getWorld())) { + || godMode && WorldBlacklist.isWorldBlacklisted(player.getWorld())) { toggleGodMode(); player.sendMessage(LocaleLoader.getString("Commands.GodMode.Forbidden")); } @@ -874,7 +931,8 @@ public class McMMOPlayer implements Identified { */ public void checkAbilityActivation(PrimarySkillType primarySkillType) { ToolType tool = mcMMO.p.getSkillTools().getPrimarySkillToolType(primarySkillType); - SuperAbilityType superAbilityType = mcMMO.p.getSkillTools().getSuperAbility(primarySkillType); + SuperAbilityType superAbilityType = mcMMO.p.getSkillTools() + .getSuperAbility(primarySkillType); SubSkillType subSkillType = superAbilityType.getSubSkillTypeDefinition(); if (getAbilityMode(superAbilityType) || !superAbilityType.getPermissions(player)) { @@ -883,12 +941,14 @@ public class McMMOPlayer implements Identified { //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); + 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)); + NotificationManager.sendPlayerInformation(player, NotificationType.ABILITY_COOLDOWN, + "Skills.AbilityGateRequirementFail", String.valueOf(diff), + mcMMO.p.getSkillTools().getLocalizedSkillName(primarySkillType)); return; } @@ -899,15 +959,17 @@ public class McMMOPlayer implements Identified { * Axes and Woodcutting are odd because they share the same tool. * We show them the too tired message when they take action. */ - if (primarySkillType == PrimarySkillType.WOODCUTTING || primarySkillType == PrimarySkillType.AXES) { - NotificationManager.sendPlayerInformation(player, NotificationType.ABILITY_COOLDOWN, "Skills.TooTired", String.valueOf(timeRemaining)); + if (primarySkillType == PrimarySkillType.WOODCUTTING + || primarySkillType == PrimarySkillType.AXES) { + NotificationManager.sendPlayerInformation(player, NotificationType.ABILITY_COOLDOWN, + "Skills.TooTired", String.valueOf(timeRemaining)); //SoundManager.sendSound(player, player.getLocation(), SoundType.TIRED); } return; } - if (EventUtils.callPlayerAbilityActivateEvent(player, primarySkillType).isCancelled()) { + if (callPlayerAbilityActivateEvent(this, primarySkillType).isCancelled()) { return; } @@ -918,39 +980,51 @@ public class McMMOPlayer implements Identified { int ticks; //Ability cap of 0 or below means no cap - if(abilityLengthCap > 0) - { - ticks = PerksUtils.handleActivationPerks(player, 2 + (Math.min(abilityLengthCap, getSkillLevel(primarySkillType)) / abilityLengthVar), superAbilityType.getMaxLength()); + if (abilityLengthCap > 0) { + ticks = PerksUtils.handleActivationPerks(player, + 2 + (Math.min(abilityLengthCap, getSkillLevel(primarySkillType)) + / abilityLengthVar), superAbilityType.getMaxLength()); } else { - ticks = PerksUtils.handleActivationPerks(player, 2 + (getSkillLevel(primarySkillType) / abilityLengthVar), superAbilityType.getMaxLength()); + ticks = PerksUtils.handleActivationPerks(player, + 2 + (getSkillLevel(primarySkillType) / abilityLengthVar), + superAbilityType.getMaxLength()); } if (useChatNotifications()) { - NotificationManager.sendPlayerInformation(player, NotificationType.SUPER_ABILITY, superAbilityType.getAbilityOn()); + NotificationManager.sendPlayerInformation(player, NotificationType.SUPER_ABILITY, + superAbilityType.getAbilityOn()); //player.sendMessage(ability.getAbilityOn()); } if (mcMMO.p.getAdvancedConfig().sendAbilityNotificationToOtherPlayers()) { - SkillUtils.sendSkillMessage(player, NotificationType.SUPER_ABILITY_ALERT_OTHERS, superAbilityType.getAbilityPlayer()); + SkillUtils.sendSkillMessage(player, NotificationType.SUPER_ABILITY_ALERT_OTHERS, + superAbilityType.getAbilityPlayer()); } //Sounds - SoundManager.worldSendSound(player.getWorld(), player.getLocation(), SoundType.ABILITY_ACTIVATED_GENERIC); + SoundManager.worldSendSound(player.getWorld(), player.getLocation(), + SoundType.ABILITY_ACTIVATED_GENERIC); //If the current item is still buffed somehow, remove it to prevent enchantments from stacking. - if (superAbilityType == SuperAbilityType.SUPER_BREAKER || superAbilityType == SuperAbilityType.GIGA_DRILL_BREAKER) + if (superAbilityType == SuperAbilityType.SUPER_BREAKER + || superAbilityType == SuperAbilityType.GIGA_DRILL_BREAKER) { SkillUtils.removeAbilityBuff(player.getInventory().getItemInMainHand()); + } // Enable the ability - profile.setAbilityDATS(superAbilityType, System.currentTimeMillis() + ((long) ticks * Misc.TIME_CONVERSION_FACTOR)); + profile.setAbilityDATS(superAbilityType, + System.currentTimeMillis() + ((long) ticks * Misc.TIME_CONVERSION_FACTOR)); setAbilityMode(superAbilityType, true); - if (superAbilityType == SuperAbilityType.SUPER_BREAKER || superAbilityType == SuperAbilityType.GIGA_DRILL_BREAKER) { + if (superAbilityType == SuperAbilityType.SUPER_BREAKER + || superAbilityType == SuperAbilityType.GIGA_DRILL_BREAKER) { SkillUtils.handleAbilitySpeedIncrease(player); } setToolPreparationMode(tool, false); - mcMMO.p.getFoliaLib().getImpl().runAtEntityLater(player, new AbilityDisableTask(this, superAbilityType), (long) ticks * Misc.TICK_CONVERSION_FACTOR); + mcMMO.p.getFoliaLib().getScheduler() + .runAtEntityLater(player, new AbilityDisableTask(this, superAbilityType), + (long) ticks * Misc.TICK_CONVERSION_FACTOR); } public void processAbilityActivation(@NotNull PrimarySkillType primarySkillType) { @@ -958,16 +1032,13 @@ public class McMMOPlayer implements Identified { return; } - if (mcMMO.p.getGeneralConfig().getAbilitiesOnlyActivateWhenSneaking() && !player.isSneaking()) { + if (mcMMO.p.getGeneralConfig().getAbilitiesOnlyActivateWhenSneaking() + && !player.isSneaking()) { return; } ItemStack inHand = player.getInventory().getItemInMainHand(); - if (mcMMO.getModManager().isCustomTool(inHand) && !mcMMO.getModManager().getTool(inHand).isAbilityEnabled()) { - return; - } - if (!getAbilityUse()) { return; } @@ -986,11 +1057,14 @@ public class McMMOPlayer implements Identified { * Basically the tool always needs to ready and we check to see if the cooldown is over when the user takes action */ if (tool.inHand(inHand) && !getToolPreparationMode(tool)) { - if (primarySkillType != PrimarySkillType.WOODCUTTING && primarySkillType != PrimarySkillType.AXES) { + if (primarySkillType != PrimarySkillType.WOODCUTTING + && primarySkillType != PrimarySkillType.AXES) { int timeRemaining = calculateTimeRemaining(ability); if (isAbilityOnCooldown(ability)) { - NotificationManager.sendPlayerInformation(player, NotificationType.ABILITY_COOLDOWN, "Skills.TooTired", String.valueOf(timeRemaining)); + NotificationManager.sendPlayerInformation(player, + NotificationType.ABILITY_COOLDOWN, "Skills.TooTired", + String.valueOf(timeRemaining)); return; } } @@ -1001,10 +1075,11 @@ public class McMMOPlayer implements Identified { * IF THE TOOL IS AN AXE * */ - if(tool == ToolType.AXE) { + if (tool == ToolType.AXE) { processAxeToolMessages(); } else { - NotificationManager.sendPlayerInformation(player, NotificationType.TOOL, tool.getRaiseTool()); + NotificationManager.sendPlayerInformation(player, NotificationType.TOOL, + tool.getRaiseTool()); } //Send Sound @@ -1012,7 +1087,9 @@ public class McMMOPlayer implements Identified { } setToolPreparationMode(tool, true); - mcMMO.p.getFoliaLib().getImpl().runAtEntityLater(player, new ToolLowerTask(this, tool), 4 * Misc.TICK_CONVERSION_FACTOR); + mcMMO.p.getFoliaLib().getScheduler() + .runAtEntityLater(player, new ToolLowerTask(this, tool), + 4 * Misc.TICK_CONVERSION_FACTOR); } } @@ -1022,37 +1099,51 @@ public class McMMOPlayer implements Identified { /* * IF BOTH TREE FELLER & SKULL SPLITTER ARE ON CD */ - if(isAbilityOnCooldown(SuperAbilityType.TREE_FELLER) && isAbilityOnCooldown(SuperAbilityType.SKULL_SPLITTER)) { - tooTiredMultiple(PrimarySkillType.WOODCUTTING, SubSkillType.WOODCUTTING_TREE_FELLER, SuperAbilityType.TREE_FELLER, SubSkillType.AXES_SKULL_SPLITTER, SuperAbilityType.SKULL_SPLITTER); - /* - * IF TREE FELLER IS ON CD - * AND PLAYER IS LOOKING AT TREE - */ - } else if(isAbilityOnCooldown(SuperAbilityType.TREE_FELLER) + if (isAbilityOnCooldown(SuperAbilityType.TREE_FELLER) && isAbilityOnCooldown( + SuperAbilityType.SKULL_SPLITTER)) { + tooTiredMultiple(PrimarySkillType.WOODCUTTING, SubSkillType.WOODCUTTING_TREE_FELLER, + SuperAbilityType.TREE_FELLER, SubSkillType.AXES_SKULL_SPLITTER, + SuperAbilityType.SKULL_SPLITTER); + /* + * IF TREE FELLER IS ON CD + * AND PLAYER IS LOOKING AT TREE + */ + } else if (isAbilityOnCooldown(SuperAbilityType.TREE_FELLER) && BlockUtils.isPartOfTree(rayCast)) { - raiseToolWithCooldowns(SubSkillType.WOODCUTTING_TREE_FELLER, SuperAbilityType.TREE_FELLER); + raiseToolWithCooldowns(SubSkillType.WOODCUTTING_TREE_FELLER, + SuperAbilityType.TREE_FELLER); - /* - * IF SKULL SPLITTER IS ON CD - */ - } else if(isAbilityOnCooldown(SuperAbilityType.SKULL_SPLITTER)) { - raiseToolWithCooldowns(SubSkillType.AXES_SKULL_SPLITTER, SuperAbilityType.SKULL_SPLITTER); + /* + * IF SKULL SPLITTER IS ON CD + */ + } else if (isAbilityOnCooldown(SuperAbilityType.SKULL_SPLITTER)) { + raiseToolWithCooldowns(SubSkillType.AXES_SKULL_SPLITTER, + SuperAbilityType.SKULL_SPLITTER); } else { - NotificationManager.sendPlayerInformation(player, NotificationType.TOOL, ToolType.AXE.getRaiseTool()); + NotificationManager.sendPlayerInformation(player, NotificationType.TOOL, + ToolType.AXE.getRaiseTool()); } } - private void tooTiredMultiple(PrimarySkillType primarySkillType, SubSkillType aSubSkill, SuperAbilityType aSuperAbility, SubSkillType bSubSkill, SuperAbilityType bSuperAbility) { - String aSuperAbilityCD = LocaleLoader.getString("Skills.TooTired.Named", aSubSkill.getLocaleName(), String.valueOf(calculateTimeRemaining(aSuperAbility))); - String bSuperAbilityCD = LocaleLoader.getString("Skills.TooTired.Named", bSubSkill.getLocaleName(), String.valueOf(calculateTimeRemaining(bSuperAbility))); + private void tooTiredMultiple(PrimarySkillType primarySkillType, SubSkillType aSubSkill, + SuperAbilityType aSuperAbility, SubSkillType bSubSkill, + SuperAbilityType bSuperAbility) { + String aSuperAbilityCD = LocaleLoader.getString("Skills.TooTired.Named", + aSubSkill.getLocaleName(), + String.valueOf(calculateTimeRemaining(aSuperAbility))); + String bSuperAbilityCD = LocaleLoader.getString("Skills.TooTired.Named", + bSubSkill.getLocaleName(), + String.valueOf(calculateTimeRemaining(bSuperAbility))); String allCDStr = aSuperAbilityCD + ", " + bSuperAbilityCD; - NotificationManager.sendPlayerInformation(player, NotificationType.TOOL, "Skills.TooTired.Extra", + NotificationManager.sendPlayerInformation(player, NotificationType.TOOL, + "Skills.TooTired.Extra", mcMMO.p.getSkillTools().getLocalizedSkillName(primarySkillType), allCDStr); } - private void raiseToolWithCooldowns(SubSkillType subSkillType, SuperAbilityType superAbilityType) { + private void raiseToolWithCooldowns(SubSkillType subSkillType, + SuperAbilityType superAbilityType) { NotificationManager.sendPlayerInformation(player, NotificationType.TOOL, "Axes.Ability.Ready.Extra", subSkillType.getLocaleName(), @@ -1067,12 +1158,14 @@ public class McMMOPlayer implements Identified { * Calculate the time remaining until the ability's cooldown expires. * * @param ability SuperAbilityType whose cooldown to check - * * @return the number of seconds remaining before the cooldown expires */ public int calculateTimeRemaining(SuperAbilityType ability) { long deactivatedTimestamp = profile.getAbilityDATS(ability) * Misc.TIME_CONVERSION_FACTOR; - return (int) (((deactivatedTimestamp + (PerksUtils.handleCooldownPerks(player, ability.getCooldown()) * Misc.TIME_CONVERSION_FACTOR)) - System.currentTimeMillis()) / Misc.TIME_CONVERSION_FACTOR); + return (int) (((deactivatedTimestamp + ( + PerksUtils.handleCooldownPerks(player, ability.getCooldown()) + * Misc.TIME_CONVERSION_FACTOR)) - System.currentTimeMillis()) + / Misc.TIME_CONVERSION_FACTOR); } /* @@ -1127,19 +1220,24 @@ public class McMMOPlayer implements Identified { } /** - * This method is called by PlayerQuitEvent to tear down the mcMMOPlayer. + * This method is called by PlayerQuitEvent to tear down the mmoPlayer. * * @param syncSave if true, data is saved synchronously */ public void logout(boolean syncSave) { - Player thisPlayer = getPlayer(); - if(getPlayer().hasMetadata(MetadataConstants.METADATA_KEY_RUPTURE)) { - RuptureTaskMeta ruptureTaskMeta = (RuptureTaskMeta) getPlayer().getMetadata(MetadataConstants.METADATA_KEY_RUPTURE).get(0); - - //Punish a logout - ruptureTaskMeta.getRuptureTimerTask().endRupture(); - ruptureTaskMeta.getRuptureTimerTask().endRupture(); - ruptureTaskMeta.getRuptureTimerTask().endRupture(); + final Player thisPlayer = getPlayer(); + if (getPlayer() != null && getPlayer().hasMetadata( + MetadataConstants.METADATA_KEY_RUPTURE)) { + final RuptureTaskMeta ruptureTaskMeta + = (RuptureTaskMeta) getPlayer().getMetadata( + MetadataConstants.METADATA_KEY_RUPTURE).get(0); + if (ruptureTaskMeta != null) { + final RuptureTask ruptureTimerTask = ruptureTaskMeta.getRuptureTimerTask(); + if (ruptureTimerTask != null) { + ruptureTimerTask.cancel(); + } + getPlayer().removeMetadata(MetadataConstants.METADATA_KEY_RUPTURE, mcMMO.p); + } } cleanup(); @@ -1152,8 +1250,9 @@ public class McMMOPlayer implements Identified { UserManager.remove(thisPlayer); - if(mcMMO.p.getGeneralConfig().getScoreboardsEnabled()) + if (mcMMO.p.getGeneralConfig().getScoreboardsEnabled()) { ScoreboardManager.teardownPlayer(thisPlayer); + } if (inParty()) { party.removeOnlineMember(thisPlayer); @@ -1164,10 +1263,8 @@ public class McMMOPlayer implements Identified { } /** - * Cleanup various things related to this player - * Such as temporary summons.. - * Turning off abilities... - * Etc... + * Cleanup various things related to this player Such as temporary summons.. Turning off + * abilities... Etc... */ public void cleanup() { resetAbilityMode(); @@ -1176,6 +1273,7 @@ public class McMMOPlayer implements Identified { /** * For use with Adventure API (Kyori lib) + * * @return this players identity */ @Override @@ -1186,6 +1284,7 @@ public class McMMOPlayer implements Identified { /** * The {@link com.gmail.nossr50.chat.author.Author} for this player, used by mcMMO chat + * * @return the {@link com.gmail.nossr50.chat.author.Author} for this player */ public @NotNull PlayerAuthor getPlayerAuthor() { @@ -1197,8 +1296,8 @@ public class McMMOPlayer implements Identified { } /** - * Change the chat channel for a player - * This does not inform the player + * Change the chat channel for a player This does not inform the player + * * @param chatChannel new chat channel */ public void setChatMode(@NotNull ChatChannel chatChannel) { 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 387172c6d..783b8133e 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/player/PlayerProfile.java +++ b/src/main/java/com/gmail/nossr50/datatypes/player/PlayerProfile.java @@ -7,16 +7,18 @@ import com.gmail.nossr50.datatypes.skills.PrimarySkillType; 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 java.util.EnumMap; +import java.util.Map; +import java.util.Objects; +import java.util.UUID; +import java.util.concurrent.DelayQueue; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.*; -import java.util.concurrent.DelayQueue; - public class PlayerProfile { private final String playerName; private @Nullable UUID uuid; @@ -30,14 +32,19 @@ public class PlayerProfile { private @Nullable Long lastLogin; /* Skill Data */ - private final Map skills = new EnumMap<>(PrimarySkillType.class); // Skill & Level - private final Map skillsXp = new EnumMap<>(PrimarySkillType.class); // Skill & XP - private final Map abilityDATS = new EnumMap<>(SuperAbilityType.class); // Ability & Cooldown - private final Map uniquePlayerData = new EnumMap<>(UniqueDataType.class); //Misc data that doesn't fit into other categories (chimaera wing, etc..) + private final Map skills = new EnumMap<>( + PrimarySkillType.class); // Skill & Level + private final Map skillsXp = new EnumMap<>( + PrimarySkillType.class); // Skill & XP + private final Map abilityDATS = new EnumMap<>( + SuperAbilityType.class); // Ability & Cooldown + private final Map uniquePlayerData = new EnumMap<>( + UniqueDataType.class); //Misc data that doesn't fit into other categories (chimaera wing, etc..) // Store previous XP gains for diminished returns private final DelayQueue gainedSkillsXp = new DelayQueue<>(); - private final Map rollingSkillsXp = new EnumMap<>(PrimarySkillType.class); + private final Map rollingSkillsXp = new EnumMap<>( + PrimarySkillType.class); @Deprecated public PlayerProfile(String playerName) { @@ -85,7 +92,10 @@ public class PlayerProfile { this.loaded = isLoaded; } - public PlayerProfile(@NotNull String playerName, @Nullable UUID uuid, Map levelData, Map xpData, Map cooldownData, int scoreboardTipsShown, Map uniqueProfileData, @Nullable Long lastLogin) { + public PlayerProfile(@NotNull String playerName, @Nullable UUID uuid, + Map levelData, Map xpData, + Map cooldownData, int scoreboardTipsShown, + Map uniqueProfileData, @Nullable Long lastLogin) { this.playerName = playerName; this.uuid = uuid; this.scoreboardTipsShown = scoreboardTipsShown; @@ -97,21 +107,23 @@ public class PlayerProfile { loaded = true; - if(lastLogin != null) + if (lastLogin != null) { this.lastLogin = lastLogin; + } } public void scheduleAsyncSave() { - mcMMO.p.getFoliaLib().getImpl().runAsync(new PlayerProfileSaveTask(this, false)); + mcMMO.p.getFoliaLib().getScheduler().runAsync(new PlayerProfileSaveTask(this, false)); } public void scheduleAsyncSaveDelay() { - mcMMO.p.getFoliaLib().getImpl().runLaterAsync(new PlayerProfileSaveTask(this, false), 20); + mcMMO.p.getFoliaLib().getScheduler() + .runLaterAsync(new PlayerProfileSaveTask(this, false), 20); } @Deprecated public void scheduleSyncSaveDelay() { - mcMMO.p.getFoliaLib().getImpl().runLater(new PlayerProfileSaveTask(this, true), 20); + mcMMO.p.getFoliaLib().getScheduler().runLater(new PlayerProfileSaveTask(this, true), 20); } public void save(boolean useSync) { @@ -121,30 +133,34 @@ public class PlayerProfile { } // TODO should this part be synchronized? - PlayerProfile profileCopy = new PlayerProfile(playerName, uuid, ImmutableMap.copyOf(skills), ImmutableMap.copyOf(skillsXp), ImmutableMap.copyOf(abilityDATS), scoreboardTipsShown, ImmutableMap.copyOf(uniquePlayerData), lastLogin); + PlayerProfile profileCopy = new PlayerProfile(playerName, uuid, ImmutableMap.copyOf(skills), + ImmutableMap.copyOf(skillsXp), ImmutableMap.copyOf(abilityDATS), + scoreboardTipsShown, ImmutableMap.copyOf(uniquePlayerData), lastLogin); changed = !mcMMO.getDatabaseManager().saveUser(profileCopy); if (changed) { - mcMMO.p.getLogger().severe("PlayerProfile saving failed for player: " + playerName + " " + uuid); + mcMMO.p.getLogger() + .severe("PlayerProfile saving failed for player: " + playerName + " " + uuid); - if(saveAttempts > 0) { - mcMMO.p.getLogger().severe("Attempted to save profile for player "+getPlayerName() - + " resulted in failure. "+saveAttempts+" have been made so far."); + if (saveAttempts > 0) { + mcMMO.p.getLogger().severe("Attempted to save profile for player " + getPlayerName() + + " resulted in failure. " + saveAttempts + " have been made so far."); } - if(saveAttempts < 10) - { + if (saveAttempts < 10) { saveAttempts++; //Back out of async saving if we detect a server shutdown, this is not always going to be caught - if(mcMMO.isServerShutdownExecuted() || useSync) - mcMMO.p.getFoliaLib().getImpl().runNextTick(new PlayerProfileSaveTask(this, true)); - else + if (mcMMO.isServerShutdownExecuted() || useSync) { + mcMMO.p.getFoliaLib().getScheduler() + .runNextTick(new PlayerProfileSaveTask(this, true)); + } else { scheduleAsyncSave(); + } } else { mcMMO.p.getLogger().severe("mcMMO has failed to save the profile for " - +getPlayerName()+" numerous times." + + + getPlayerName() + " numerous times." + " mcMMO will now stop attempting to save this profile." + " Check your console for errors and inspect your DB for issues."); } @@ -155,9 +171,12 @@ public class PlayerProfile { } /** - * Get this users last login, will return current java.lang.System#currentTimeMillis() if it doesn't exist + * Get this users last login, will return current java.lang.System#currentTimeMillis() if it + * doesn't exist + * * @return the last login - * @deprecated This is only function for FlatFileDB atm, and it's only here for unit testing right now + * @deprecated This is only function for FlatFileDB atm, and it's only here for unit testing + * right now */ public @NotNull Long getLastLogin() { return Objects.requireNonNullElse(lastLogin, -1L); @@ -210,7 +229,9 @@ public class PlayerProfile { * Cooldowns */ - public int getChimaerWingDATS() { return uniquePlayerData.get(UniqueDataType.CHIMAERA_WING_DATS);} + public int getChimaerWingDATS() { + return uniquePlayerData.get(UniqueDataType.CHIMAERA_WING_DATS); + } protected void setChimaeraWingDATS(int DATS) { markProfileDirty(); @@ -222,7 +243,9 @@ public class PlayerProfile { uniquePlayerData.put(uniqueDataType, newData); } - public long getUniqueData(UniqueDataType uniqueDataType) { return uniquePlayerData.get(uniqueDataType); } + public long getUniqueData(UniqueDataType uniqueDataType) { + return uniquePlayerData.get(uniqueDataType); + } /** * Get the current deactivation timestamp of an ability. @@ -268,7 +291,7 @@ public class PlayerProfile { } public int getSkillXpLevel(PrimarySkillType skill) { - if(SkillTools.isChildSkill(skill)) { + if (SkillTools.isChildSkill(skill)) { return 0; } @@ -336,8 +359,9 @@ public class PlayerProfile { markProfileDirty(); //Don't allow levels to be negative - if(level < 0) + if (level < 0) { level = 0; + } skills.put(skill, level); skillsXp.put(skill, 0F); @@ -363,21 +387,19 @@ public class PlayerProfile { 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) { skillsXp.put(parentSkill, skillsXp.get(parentSkill) + dividedXP); } - } - else { + } else { skillsXp.put(skill, skillsXp.get(skill) + xp); } } /** - * Get the registered amount of experience gained - * This is used for diminished XP returns + * Get the registered amount of experience gained This is used for diminished XP returns * * @return xp Experience amount registered */ @@ -392,8 +414,7 @@ public class PlayerProfile { } /** - * Register an experience gain - * This is used for diminished XP returns + * Register an experience gain This is used for diminished XP returns * * @param primarySkillType Skill being used * @param xp Experience amount to add @@ -404,13 +425,13 @@ public class PlayerProfile { } /** - * Remove experience gains older than a given time - * This is used for diminished XP returns + * Remove experience gains older than a given time This is used for diminished XP returns */ public void purgeExpiredXpGains() { SkillXpGain gain; while ((gain = gainedSkillsXp.poll()) != null) { - rollingSkillsXp.put(gain.getSkill(), getRegisteredXpGain(gain.getSkill()) - gain.getXp()); + rollingSkillsXp.put(gain.getSkill(), + getRegisteredXpGain(gain.getSkill()) - gain.getXp()); } } @@ -421,18 +442,25 @@ public class PlayerProfile { * @return the total amount of Xp until next level */ public int getXpToLevel(PrimarySkillType primarySkillType) { - if(SkillTools.isChildSkill(primarySkillType)) { + if (SkillTools.isChildSkill(primarySkillType)) { return 0; } - int level = (ExperienceConfig.getInstance().getCumulativeCurveEnabled()) ? UserManager.getPlayer(playerName).getPowerLevel() : skills.get(primarySkillType); + int level = (ExperienceConfig.getInstance().getCumulativeCurveEnabled()) + ? UserManager.getPlayer(playerName).getPowerLevel() : skills.get(primarySkillType); FormulaType formulaType = ExperienceConfig.getInstance().getFormulaType(); return mcMMO.p.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/datatypes/skills/MaterialType.java b/src/main/java/com/gmail/nossr50/datatypes/skills/MaterialType.java index 26e0f17d9..f66798be9 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/MaterialType.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/MaterialType.java @@ -11,6 +11,7 @@ public enum MaterialType { GOLD, DIAMOND, NETHERITE, + PRISMARINE, OTHER; public Material getDefaultMaterial() { @@ -37,10 +38,13 @@ public enum MaterialType { return Material.DIAMOND; case NETHERITE: - if(Material.getMaterial("NETHERITE_SCRAP") != null) + if (Material.getMaterial("NETHERITE_SCRAP") != null) { return Material.getMaterial("NETHERITE_SCRAP"); - else + } else { return Material.DIAMOND; + } + case PRISMARINE: + return Material.PRISMARINE_CRYSTALS; case OTHER: default: diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/ModConfigType.java b/src/main/java/com/gmail/nossr50/datatypes/skills/ModConfigType.java deleted file mode 100644 index df951d783..000000000 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/ModConfigType.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.gmail.nossr50.datatypes.skills; - -public enum ModConfigType { - BLOCKS, - TOOLS, - ARMOR, - UNKNOWN; - - public static ModConfigType getModConfigType(String materialName) { - if (materialName.contains("HELM") || (materialName.contains("CHEST") && !materialName.contains("CHESTNUT")) || materialName.contains("LEGS") || materialName.contains("LEGGINGS") || materialName.contains("BOOT")) { - return ARMOR; - } - else if (materialName.contains("PICKAXE") || materialName.contains("AXE") || (materialName.contains("BOW") && !materialName.contains("BOWL")) || materialName.contains("HOE") || materialName.contains("SHOVEL") || materialName.contains("SWORD")) { - return TOOLS; - } - else if (materialName.contains("LOG") || materialName.contains("LEAVES") || materialName.contains("FLOWER") || materialName.contains("PLANT") || materialName.contains("CROP") || materialName.contains("ORE") || materialName.contains("DIRT") || materialName.contains("SAND") || materialName.contains("GRASS")) { - return BLOCKS; - } - - return UNKNOWN; - } -} 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 9fa39bd5d..411c977c0 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java @@ -4,6 +4,8 @@ import com.gmail.nossr50.config.GeneralConfig; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.skills.SkillTools; +import java.util.ArrayList; +import java.util.List; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; @@ -18,23 +20,29 @@ public enum PrimarySkillType { ALCHEMY, ARCHERY, AXES, + CROSSBOWS, EXCAVATION, FISHING, HERBALISM, + MACES, MINING, REPAIR, SALVAGE, SMELTING, SWORDS, TAMING, + TRIDENTS, UNARMED, WOODCUTTING; /** - * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() + * instead + * * @return the max level of this skill * @see SkillTools#getLevelCap(com.gmail.nossr50.datatypes.skills.PrimarySkillType) - * @deprecated this is being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + * @deprecated this is being removed in an upcoming update, you should be using + * mcMMO.getSkillTools() instead */ @Deprecated public int getMaxLevel() { @@ -42,10 +50,14 @@ public enum PrimarySkillType { } /** - * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() + * instead + * * @return the max level of this skill - * @see SkillTools#isSuperAbilityUnlocked(com.gmail.nossr50.datatypes.skills.PrimarySkillType, org.bukkit.entity.Player) - * @deprecated this is being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + * @see SkillTools#isSuperAbilityUnlocked(com.gmail.nossr50.datatypes.skills.PrimarySkillType, + * org.bukkit.entity.Player) + * @deprecated this is being removed in an upcoming update, you should be using + * mcMMO.getSkillTools() instead */ @Deprecated public boolean isSuperAbilityUnlocked(@NotNull Player player) { @@ -53,10 +65,13 @@ public enum PrimarySkillType { } /** - * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() + * instead + * * @return the max level of this skill * @see SkillTools#getPVPEnabled(com.gmail.nossr50.datatypes.skills.PrimarySkillType) - * @deprecated this is being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + * @deprecated this is being removed in an upcoming update, you should be using + * mcMMO.getSkillTools() instead */ @Deprecated public boolean getPVPEnabled() { @@ -64,10 +79,13 @@ public enum PrimarySkillType { } /** - * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() + * instead + * * @return the max level of this skill * @see SkillTools#getPVEEnabled(com.gmail.nossr50.datatypes.skills.PrimarySkillType) - * @deprecated this is being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + * @deprecated this is being removed in an upcoming update, you should be using + * mcMMO.getSkillTools() instead */ @Deprecated public boolean getPVEEnabled() { @@ -75,10 +93,13 @@ public enum PrimarySkillType { } /** - * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() + * instead + * * @return the max level of this skill * @see GeneralConfig#getDoubleDropsDisabled(com.gmail.nossr50.datatypes.skills.PrimarySkillType) - * @deprecated this is being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + * @deprecated this is being removed in an upcoming update, you should be using + * mcMMO.getSkillTools() instead */ @Deprecated public boolean getDoubleDropsDisabled() { @@ -86,10 +107,13 @@ public enum PrimarySkillType { } /** - * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() + * instead + * * @return the max level of this skill * @see SkillTools#getHardcoreStatLossEnabled(com.gmail.nossr50.datatypes.skills.PrimarySkillType) - * @deprecated this is being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + * @deprecated this is being removed in an upcoming update, you should be using + * mcMMO.getSkillTools() instead */ @Deprecated public boolean getHardcoreStatLossEnabled() { @@ -97,10 +121,13 @@ public enum PrimarySkillType { } /** - * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() + * instead + * * @return the max level of this skill * @see SkillTools#getHardcoreVampirismEnabled(com.gmail.nossr50.datatypes.skills.PrimarySkillType) - * @deprecated this is being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + * @deprecated this is being removed in an upcoming update, you should be using + * mcMMO.getSkillTools() instead */ @Deprecated public boolean getHardcoreVampirismEnabled() { @@ -108,10 +135,13 @@ public enum PrimarySkillType { } /** - * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() + * instead + * * @return the max level of this skill * @see SkillTools#getPrimarySkillToolType(com.gmail.nossr50.datatypes.skills.PrimarySkillType) - * @deprecated this is being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + * @deprecated this is being removed in an upcoming update, you should be using + * mcMMO.getSkillTools() instead */ @Deprecated public ToolType getTool() { @@ -119,10 +149,13 @@ public enum PrimarySkillType { } /** - * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() + * instead + * * @return the max level of this skill * @see SkillTools#getSubSkills(com.gmail.nossr50.datatypes.skills.PrimarySkillType) - * @deprecated this is being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + * @deprecated this is being removed in an upcoming update, you should be using + * mcMMO.getSkillTools() instead */ @Deprecated public List getSkillAbilities() { @@ -130,20 +163,27 @@ public enum PrimarySkillType { } /** - * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() + * instead + * * @return the max level of this skill - * @see SkillTools#getXpModifier(com.gmail.nossr50.datatypes.skills.PrimarySkillType) - * @deprecated this is being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + * @see SkillTools#getXpMultiplier(com.gmail.nossr50.datatypes.skills.PrimarySkillType) + * @deprecated this is being removed in an upcoming update, you should be using + * mcMMO.getSkillTools() instead */ @Deprecated public double getXpModifier() { - return mcMMO.p.getSkillTools().getXpModifier(this); + return mcMMO.p.getSkillTools().getXpMultiplier(this); } /** - * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() + * instead + * + * @return the max level of this skill * @see SkillTools#matchSkill(java.lang.String) - * @deprecated this is being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + * @deprecated this is being removed in an upcoming update, you should be using + * mcMMO.getSkillTools() instead */ @Deprecated public static PrimarySkillType getSkill(String skillName) { @@ -161,10 +201,13 @@ public enum PrimarySkillType { } /** - * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() + * instead + * * @return the max level of this skill * @see SkillTools#isChildSkill(com.gmail.nossr50.datatypes.skills.PrimarySkillType) - * @deprecated this is being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + * @deprecated this is being removed in an upcoming update, you should be using + * mcMMO.getSkillTools() instead */ @Deprecated public boolean isChildSkill() { @@ -172,10 +215,13 @@ public enum PrimarySkillType { } /** - * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() + * instead + * * @return the max level of this skill * @see SkillTools#getPrimarySkillBySubSkill(com.gmail.nossr50.datatypes.skills.SubSkillType) - * @deprecated this is being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + * @deprecated this is being removed in an upcoming update, you should be using + * mcMMO.getSkillTools() instead */ @Deprecated public static PrimarySkillType bySecondaryAbility(SubSkillType subSkillType) { @@ -183,10 +229,13 @@ public enum PrimarySkillType { } /** - * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() + * instead + * * @return the max level of this skill * @see SkillTools#getPrimarySkillBySuperAbility(com.gmail.nossr50.datatypes.skills.SuperAbilityType) - * @deprecated this is being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + * @deprecated this is being removed in an upcoming update, you should be using + * mcMMO.getSkillTools() instead */ @Deprecated public static PrimarySkillType byAbility(SuperAbilityType superAbilityType) { @@ -194,10 +243,13 @@ public enum PrimarySkillType { } /** - * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() + * instead + * * @return the max level of this skill * @see SkillTools#getLocalizedSkillName(com.gmail.nossr50.datatypes.skills.PrimarySkillType) - * @deprecated this is being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + * @deprecated this is being removed in an upcoming update, you should be using + * mcMMO.getSkillTools() instead */ @Deprecated public String getName() { @@ -205,9 +257,12 @@ public enum PrimarySkillType { } /** - * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() + * instead + * * @return the max level of this skill - * @see Permissions#skillEnabled(org.bukkit.permissions.Permissible, com.gmail.nossr50.datatypes.skills.PrimarySkillType) + * @see Permissions#skillEnabled(org.bukkit.permissions.Permissible, + * com.gmail.nossr50.datatypes.skills.PrimarySkillType) * @deprecated this is being removed in an upcoming update */ @Deprecated @@ -216,10 +271,14 @@ public enum PrimarySkillType { } /** - * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() + * instead + * * @return the max level of this skill - * @see SkillTools#canCombatSkillsTrigger(com.gmail.nossr50.datatypes.skills.PrimarySkillType, org.bukkit.entity.Entity) - * @deprecated this is being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + * @see SkillTools#canCombatSkillsTrigger(com.gmail.nossr50.datatypes.skills.PrimarySkillType, + * org.bukkit.entity.Entity) + * @deprecated this is being removed in an upcoming update, you should be using + * mcMMO.getSkillTools() instead */ @Deprecated public boolean shouldProcess(Entity target) { diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillFlags.java b/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillFlags.java index ed4626935..47a5edcca 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillFlags.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillFlags.java @@ -6,14 +6,14 @@ public class SubSkillFlags { * These are so I can flag properties for subskills * Flags are in the power of 2 because binary is a base-2 system */ - public static final int ACTIVE = 1; //Active subskills are ones that aren't passive - public static final int SUPERABILITY = 2; // Super abilities are redundantly active - public static final int RNG = 4; //If the subskill makes use of RNG - public static final int PVP = 8; //If the subskill has properties that change in PVP conditions - public static final int TIMED = 16; //If the subskill has a duration or time component - public static final int TARGET_COLLECTION = 32; //If the subskill has multiple target types - public static final int REWARD_COLLECTION = 64; //If the subskill has multiple reward types - public static final int CHARGES = 128; - public static final int LIMITED = 256; + public static final int ACTIVE = 1; //Active subskills are ones that aren't passive + public static final int SUPERABILITY = 2; // Super abilities are redundantly active + public static final int RNG = 4; //If the subskill makes use of RNG + public static final int PVP = 8; //If the subskill has properties that change in PVP conditions + public static final int TIMED = 16; //If the subskill has a duration or time component + public static final int TARGET_COLLECTION = 32; //If the subskill has multiple target types + public static final int REWARD_COLLECTION = 64; //If the subskill has multiple reward types + public static final int CHARGES = 128; + public static final int LIMITED = 256; //public static final int RANDOM_ACTIVATION = 128; //If the subskill has random activation } 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 a11b98eb2..210653077 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java @@ -3,7 +3,6 @@ package com.gmail.nossr50.datatypes.skills; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.text.StringUtils; - import java.util.Locale; public enum SubSkillType { @@ -31,6 +30,11 @@ public enum SubSkillType { AXES_GREATER_IMPACT(1), AXES_SKULL_SPLITTER(1), + /* CROSSBOWS */ + CROSSBOWS_CROSSBOWS_LIMIT_BREAK(10), + CROSSBOWS_TRICK_SHOT(3), + CROSSBOWS_POWERED_SHOT(20), + /* Excavation */ EXCAVATION_ARCHAEOLOGY(8), EXCAVATION_GIGA_DRILL_BREAKER(1), @@ -45,18 +49,25 @@ public enum SubSkillType { /* Herbalism */ HERBALISM_DOUBLE_DROPS(1), + HERBALISM_VERDANT_BOUNTY(1), HERBALISM_FARMERS_DIET(5), HERBALISM_GREEN_TERRA(1), HERBALISM_GREEN_THUMB(4), HERBALISM_HYLIAN_LUCK, HERBALISM_SHROOM_THUMB, + /* Maces */ + MACES_MACES_LIMIT_BREAK(10), + MACES_CRUSH(4), + MACES_CRIPPLE(4), + /* Mining */ MINING_BIGGER_BOMBS(1), MINING_BLAST_MINING(8), MINING_DEMOLITIONS_EXPERTISE(1), MINING_DOUBLE_DROPS(1), MINING_SUPER_BREAKER(1), + MINING_MOTHER_LODE(1), /* Repair */ REPAIR_ARCANE_FORGING(8), @@ -91,6 +102,10 @@ public enum SubSkillType { TAMING_SHOCK_PROOF(1), TAMING_THICK_FUR(1), + /* Tridents */ + TRIDENTS_IMPALE(10), + TRIDENTS_TRIDENTS_LIMIT_BREAK(10), + /* Unarmed */ UNARMED_ARROW_DEFLECT(1), UNARMED_BERSERK(1), @@ -101,71 +116,76 @@ public enum SubSkillType { UNARMED_UNARMED_LIMIT_BREAK(10), /* 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_TREE_FELLER(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. /** * If our SubSkillType has more than 1 rank define it + * * @param numRanks The number of ranks our SubSkillType has */ - SubSkillType(int numRanks) - { + SubSkillType(int numRanks) { this.numRanks = numRanks; } - SubSkillType() - { + SubSkillType() { this.numRanks = 0; } - public int getNumRanks() - { + public int getNumRanks() { return numRanks; } /** - * !!! This relies on the immutable lists in PrimarySkillType being populated !!! - * If we add skills, those immutable lists need to be updated - * @return + * !!! This relies on the immutable lists in PrimarySkillType being populated !!! If we add + * skills, those immutable lists need to be updated + * + * @return the parent skill of this subskill */ - public PrimarySkillType getParentSkill() { return mcMMO.p.getSkillTools().getPrimarySkillBySubSkill(this); } + public PrimarySkillType getParentSkill() { + return mcMMO.p.getSkillTools().getPrimarySkillBySubSkill(this); + } /** * Returns the root address for this skill in the advanced.yml file + * * @return the root address for this skill in advanced.yml */ public String getAdvConfigAddress() { - return "Skills." + StringUtils.getCapitalized(getParentSkill().toString()) + "." + getConfigName(toString()); + return "Skills." + StringUtils.getCapitalized(getParentSkill().toString()) + "." + + getConfigName(toString()); } /** * Returns the root address for this skill in the rankskills.yml file + * * @return the root address for this skill in rankskills.yml */ public String getRankConfigAddress() { - return StringUtils.getCapitalized(getParentSkill().toString()) + "." + getConfigName(toString()); + return StringUtils.getCapitalized(getParentSkill().toString()) + "." + getConfigName( + toString()); } /** * Get the string representation of the permission node for this subskill + * * @return the permission node for this subskill */ - public String getPermissionNodeAddress() - { + public String getPermissionNodeAddress() { //TODO: This could be optimized - return "mcmmo.ability." + getParentSkill().toString().toLowerCase(Locale.ENGLISH) + "." + getConfigName(toString()).toLowerCase(Locale.ENGLISH); + return "mcmmo.ability." + getParentSkill().toString().toLowerCase(Locale.ENGLISH) + "." + + getConfigName(toString()).toLowerCase(Locale.ENGLISH); } /** * Returns the name of the skill as it is used in advanced.yml and other config files + * * @return the yaml identifier for this skill */ private String getConfigName(String subSkillName) { @@ -189,12 +209,10 @@ public enum SubSkillType { * Split the string up so we can capitalize each part */ String subskillNameWithoutPrefix = subSkillName.substring(subStringIndex); - if(subskillNameWithoutPrefix.contains("_")) - { + if (subskillNameWithoutPrefix.contains("_")) { String[] splitStrings = subskillNameWithoutPrefix.split("_"); - for(String string : splitStrings) - { + for (String string : splitStrings) { endResult.append(StringUtils.getCapitalized(string)); } } else { @@ -204,58 +222,37 @@ public enum SubSkillType { return endResult.toString(); } - public String getWikiName(String subSkillName) { - /* - * Find where to begin our substring (after the prefix) - */ - StringBuilder endResult = new StringBuilder(); - int subStringIndex = getSubStringIndex(subSkillName); - - /* - * Split the string up so we can capitalize each part - */ - String subskillNameWithoutPrefix = subSkillName.substring(subStringIndex); - if(subskillNameWithoutPrefix.contains("_")) - { - String[] splitStrings = subskillNameWithoutPrefix.split("_"); - - for(int i = 0; i < splitStrings.length; i++) - { - if(i+1 >= splitStrings.length) - endResult.append(StringUtils.getCapitalized(splitStrings[i])); - else { - endResult.append(StringUtils.getCapitalized(splitStrings[i])); - endResult.append("_"); - } - } - } else { - endResult.append(StringUtils.getCapitalized(subskillNameWithoutPrefix)); - } - - return endResult.toString(); + public String getWikiUrl() { + // remove the text before the first underscore + int subStringIndex = getSubStringIndex(name()); + String afterPrefix = name().substring(subStringIndex); + // replace _ or spaces with - + return afterPrefix.replace("_", "-").replace(" ", "-").toLowerCase(Locale.ENGLISH); } /** * Returns the name of the parent skill from the Locale file + * * @return The parent skill as defined in the locale */ - public String getParentNiceNameLocale() - { - return LocaleLoader.getString(StringUtils.getCapitalized(getParentSkill().toString())+".SkillName"); + public String getParentNiceNameLocale() { + return LocaleLoader.getString( + StringUtils.getCapitalized(getParentSkill().toString()) + ".SkillName"); } /** * Gets the "nice" name of the subskill without spaces + * * @param subSkillType target subskill * @return the "nice" name without spaces */ - public String getNiceNameNoSpaces(SubSkillType subSkillType) - { + public String getNiceNameNoSpaces(SubSkillType subSkillType) { return getConfigName(subSkillType.toString()); } /** * This finds the substring index for our SubSkillType's name after its parent name prefix + * * @param subSkillName The name to process * @return The value of the substring index after our parent's prefix */ @@ -274,34 +271,40 @@ public enum SubSkillType { return subStringIndex; } - public String getLocaleKeyRoot() - { - return StringUtils.getCapitalized(getParentSkill().toString())+".SubSkill."+getConfigName(toString()); + public String getLocaleKeyRoot() { + return StringUtils.getCapitalized(getParentSkill().toString()) + ".SubSkill." + + getConfigName(toString()); } - public String getLocaleName() - { + public String getLocaleName() { return getFromLocaleSubAddress(".Name"); } - public String getLocaleDescription() - { + public String getLocaleDescription() { return getFromLocaleSubAddress(".Description"); } - public String getLocaleStatDescription() { return getFromLocaleSubAddress(".Stat"); } - public String getLocaleKeyStatDescription() { return getLocaleKeyFromSubAddress(".Stat"); } + public String getLocaleStatDescription() { + return getFromLocaleSubAddress(".Stat"); + } - public String getLocaleStatExtraDescription() { return getFromLocaleSubAddress(".Stat.Extra"); } - public String getLocaleKeyStatExtraDescription() { return getLocaleKeyFromSubAddress(".Stat.Extra"); } + public String getLocaleKeyStatDescription() { + return getLocaleKeyFromSubAddress(".Stat"); + } - public String getLocaleStat(String... vars) - { + public String getLocaleStatExtraDescription() { + return getFromLocaleSubAddress(".Stat.Extra"); + } + + public String getLocaleKeyStatExtraDescription() { + return getLocaleKeyFromSubAddress(".Stat.Extra"); + } + + public String getLocaleStat(String... vars) { return LocaleLoader.getString("Ability.Generic.Template", (Object[]) vars); } - public String getCustomLocaleStat(String... vars) - { + public String getCustomLocaleStat(String... vars) { return LocaleLoader.getString("Ability.Generic.Template.Custom", (Object[]) vars); } @@ -309,8 +312,7 @@ public enum SubSkillType { return LocaleLoader.getString(getLocaleKeyRoot() + s); } - private String getLocaleKeyFromSubAddress(String s) - { + private String getLocaleKeyFromSubAddress(String s) { return getLocaleKeyRoot() + s; } } 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 6e4de8d78..04dd1baea 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/SuperAbilityType.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/SuperAbilityType.java @@ -6,10 +6,17 @@ import com.gmail.nossr50.util.BlockUtils; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.text.StringUtils; import org.bukkit.Material; -import org.bukkit.block.BlockState; +import org.bukkit.block.Block; import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; 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", @@ -65,6 +72,27 @@ public enum SuperAbilityType { "Swords.Skills.SS.Refresh", "Swords.Skills.SS.Other.Off", "Swords.SubSkill.SerratedStrikes.Name"), + SUPER_SHOTGUN( + "Placeholder", + "Placeholder", + "Placeholder", + "Placeholder", + "Placeholder", + "Placeholder"), + TRIDENTS_SUPER_ABILITY( + "Placeholder", + "Placeholder", + "Placeholder", + "Placeholder", + "Placeholder", + "Placeholder"), + MACES_SUPER_ABILITY( + "Placeholder", + "Placeholder", + "Placeholder", + "Placeholder", + "Placeholder", + "Placeholder"), /** * Has cooldown - but has to share a skill with Super Breaker, so needs special treatment @@ -82,15 +110,16 @@ 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; - GIGA_DRILL_BREAKER.subSkillTypeDefinition = SubSkillType.EXCAVATION_GIGA_DRILL_BREAKER; - GREEN_TERRA.subSkillTypeDefinition = SubSkillType.HERBALISM_GREEN_TERRA; - SKULL_SPLITTER.subSkillTypeDefinition = SubSkillType.AXES_SKULL_SPLITTER; - TREE_FELLER.subSkillTypeDefinition = SubSkillType.WOODCUTTING_TREE_FELLER; - SERRATED_STRIKES.subSkillTypeDefinition = SubSkillType.SWORDS_SERRATED_STRIKES; - BLAST_MINING.subSkillTypeDefinition = SubSkillType.MINING_BLAST_MINING; + BERSERK.subSkillTypeDefinition = SubSkillType.UNARMED_BERSERK; + SUPER_BREAKER.subSkillTypeDefinition = SubSkillType.MINING_SUPER_BREAKER; + GIGA_DRILL_BREAKER.subSkillTypeDefinition = SubSkillType.EXCAVATION_GIGA_DRILL_BREAKER; + GREEN_TERRA.subSkillTypeDefinition = SubSkillType.HERBALISM_GREEN_TERRA; + SKULL_SPLITTER.subSkillTypeDefinition = SubSkillType.AXES_SKULL_SPLITTER; + TREE_FELLER.subSkillTypeDefinition = SubSkillType.WOODCUTTING_TREE_FELLER; + SERRATED_STRIKES.subSkillTypeDefinition = SubSkillType.SWORDS_SERRATED_STRIKES; + BLAST_MINING.subSkillTypeDefinition = SubSkillType.MINING_BLAST_MINING; } private final String abilityOn; @@ -101,7 +130,8 @@ public enum SuperAbilityType { private SubSkillType subSkillTypeDefinition; private final String localizedName; - SuperAbilityType(String abilityOn, String abilityOff, String abilityPlayer, String abilityRefresh, String abilityPlayerOff, String localizedName) { + SuperAbilityType(String abilityOn, String abilityOff, String abilityPlayer, + String abilityRefresh, String abilityPlayerOff, String localizedName) { this.abilityOn = abilityOn; this.abilityOff = abilityOff; this.abilityPlayer = abilityPlayer; @@ -139,7 +169,7 @@ public enum SuperAbilityType { } public String getName() { - return StringUtils.getPrettyAbilityString(this); + return StringUtils.getPrettySuperAbilityString(this); } public String getLocalizedName() { @@ -173,67 +203,40 @@ public enum SuperAbilityType { * @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) { - 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 TREE_FELLER -> Permissions.treeFeller(player); + // TODO: once implemented, return permissions for the following abilities + case EXPLOSIVE_SHOT, TRIDENTS_SUPER_ABILITY, SUPER_SHOTGUN, MACES_SUPER_ABILITY -> + false; + }; } - /** - * Check if a block is affected by this ability. - * - * @param blockState the block to check - * @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; - } + public boolean blockCheck(@NotNull Block block) { + return switch (this) { + case BERSERK -> (BlockUtils.affectedByGigaDrillBreaker(block) + || block.getType() == Material.SNOW + || mcMMO.getMaterialMapStore().isGlass(block.getType())); + case GIGA_DRILL_BREAKER -> BlockUtils.affectedByGigaDrillBreaker(block); + case GREEN_TERRA -> BlockUtils.canMakeMossy(block); + case SUPER_BREAKER -> BlockUtils.affectedBySuperBreaker(block); + case TREE_FELLER -> BlockUtils.hasWoodcuttingXP(block); + default -> false; + }; } /** * Grabs the associated SubSkillType definition for this SuperAbilityType + * * @return the matching SubSkillType definition for this SuperAbilityType */ public SubSkillType getSubSkillTypeDefinition() { 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 9fdb444e9..69422c1a2 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/ToolType.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/ToolType.java @@ -10,7 +10,11 @@ public enum ToolType { HOE("Herbalism.Ability.Lower", "Herbalism.Ability.Ready"), PICKAXE("Mining.Ability.Lower", "Mining.Ability.Ready"), SHOVEL("Excavation.Ability.Lower", "Excavation.Ability.Ready"), - SWORD("Swords.Ability.Lower", "Swords.Ability.Ready"); + SWORD("Swords.Ability.Lower", "Swords.Ability.Ready"), + CROSSBOW("Crossbows.Ability.Lower", "Crossbows.Ability.Ready"), + BOW("Archery.Ability.Lower", "Archery.Ability.Ready"), + TRIDENTS("Tridents.Ability.Lower", "Tridents.Ability.Ready"), + MACES("Maces.Ability.Lower", "Maces.Ability.Ready"); private final String lowerTool; private final String raiseTool; @@ -38,6 +42,12 @@ public enum ToolType { switch (this) { case AXE: return ItemUtils.isAxe(itemStack); + case CROSSBOW: + return ItemUtils.isCrossbow(itemStack); + case TRIDENTS: + return ItemUtils.isTrident(itemStack); + case MACES: + return ItemUtils.isMace(itemStack); case FISTS: return itemStack.getType() == Material.AIR; diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/alchemy/AlchemyPotion.java b/src/main/java/com/gmail/nossr50/datatypes/skills/alchemy/AlchemyPotion.java index c767004df..9ab8411ba 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/alchemy/AlchemyPotion.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/alchemy/AlchemyPotion.java @@ -1,167 +1,164 @@ package com.gmail.nossr50.datatypes.skills.alchemy; -import com.gmail.nossr50.config.skills.alchemy.PotionConfig; -import org.bukkit.Color; -import org.bukkit.Material; -import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.meta.PotionMeta; -import org.bukkit.potion.Potion; -import org.bukkit.potion.PotionData; -import org.bukkit.potion.PotionEffect; +import static com.gmail.nossr50.util.PotionUtil.samePotionType; +import static java.util.Objects.requireNonNull; -import java.util.List; +import com.gmail.nossr50.mcMMO; +import com.gmail.nossr50.util.PotionUtil; import java.util.Map; import java.util.Map.Entry; +import java.util.Objects; +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.inventory.meta.PotionMeta; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; public class AlchemyPotion { - private final Material material; - private PotionData data; - private String name; - private List lore; - private List effects; - private Color color; - private Map children; + private final @NotNull String potionConfigName; + private final @NotNull ItemStack potionItemStack; + private final @NotNull ItemMeta potionItemMeta; + private final @NotNull Map alchemyPotionChildren; - public AlchemyPotion(Material material, PotionData data, String name, List lore, List effects, Color color, Map children) { - this.material = material; - this.data = data; - this.lore = lore; - this.name = name; - this.effects = effects; - this.children = children; - this.color = color; + public AlchemyPotion(@NotNull String potionConfigName, @NotNull ItemStack potionItemStack, + @NotNull Map alchemyPotionChildren) { + this.potionConfigName = requireNonNull(potionConfigName, "potionConfigName cannot be null"); + this.potionItemStack = requireNonNull(potionItemStack, "potionItemStack cannot be null"); + this.alchemyPotionChildren = requireNonNull(alchemyPotionChildren, + "alchemyPotionChildren cannot be null"); + this.potionItemMeta = requireNonNull(potionItemStack.getItemMeta(), + "potionItemMeta cannot be null"); // The potion item meta should never be null because it is a potion, but if it is null, then something went terribly wrong } - public String toString() { - return "AlchemyPotion{" + data + ", " + name + ", Effects[" + effects.size() + "], Children[" + children.size() + "]}"; + public @NotNull ItemStack toItemStack(int amount) { + final ItemStack clone = potionItemStack.clone(); + clone.setAmount(Math.max(1, amount)); + return clone; } - public ItemStack toItemStack(int amount) { - ItemStack potion = new ItemStack(material, amount); - PotionMeta meta = (PotionMeta) potion.getItemMeta(); - - meta.setBasePotionData(data); - if (this.getName() != null) { - meta.setDisplayName(this.getName()); - } - - if (this.getLore() != null && !this.getLore().isEmpty()) { - meta.setLore(this.getLore()); - } - - if (!this.getEffects().isEmpty()) { - for (PotionEffect effect : this.getEffects()) { - meta.addCustomEffect(effect, true); - } - } - - if (this.getColor() != null) { - meta.setColor(this.getColor()); - } - - potion.setItemMeta(meta); - return potion; + public @NotNull Map getAlchemyPotionChildren() { + return alchemyPotionChildren; } - public Material getMaterial() { - return material; - } - - public Potion toPotion(int amount) { - return Potion.fromItemStack(this.toItemStack(amount)); - } - - public PotionData getData() { - return data; - } - - public void setData(PotionData data) { - this.data = data; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public List getLore() { - return lore; - } - - public void setLore(List lore) { - this.lore = lore; - } - - public List getEffects() { - return effects; - } - - public void setEffects(List effects) { - this.effects = effects; - } - - public Color getColor() { - return color; - } - - public void setColor(Color color) { - this.color = color; - } - - public Map getChildren() { - return children; - } - - public void setChildren(Map children) { - this.children = children; - } - - public AlchemyPotion getChild(ItemStack ingredient) { - if (!children.isEmpty()) { - for (Entry child : children.entrySet()) { + public @Nullable AlchemyPotion getChild(@NotNull ItemStack ingredient) { + if (!alchemyPotionChildren.isEmpty()) { + for (Entry child : alchemyPotionChildren.entrySet()) { if (ingredient.isSimilar(child.getKey())) { - return PotionConfig.getInstance().getPotion(child.getValue()); + return mcMMO.p.getPotionConfig().getPotion(child.getValue()); } } } return null; } - public boolean isSimilar(ItemStack item) { - if (item.getType() != material) { + public boolean isSimilarPotion(@NotNull ItemStack otherPotion) { + return isSimilarPotion(otherPotion, otherPotion.getItemMeta()); + } + + public boolean isSimilarPotion(@NotNull ItemStack otherPotion, @Nullable ItemMeta otherMeta) { + requireNonNull(otherPotion, "otherPotion cannot be null"); + + if (otherPotion.getType() != potionItemStack.getType()) { return false; } - if (!item.hasItemMeta()) { + + // no potion meta, no match + if (otherMeta == null) { return false; } - PotionMeta meta = (PotionMeta) item.getItemMeta(); - PotionData that = meta.getBasePotionData(); - if (data.getType() != that.getType()) { + + /* + * Compare custom effects on both potions. + */ + + final PotionMeta otherPotionMeta = (PotionMeta) otherMeta; + // compare custom effects on both potions, this has to be done in two traversals + // comparing thisPotionMeta -> otherPotionMeta and otherPotionMeta -> thisPotionMeta + if (hasDifferingCustomEffects(getAlchemyPotionMeta(), otherPotionMeta) + || hasDifferingCustomEffects(otherPotionMeta, getAlchemyPotionMeta())) { return false; } - if (data.isExtended() != that.isExtended()) { + + if (!samePotionType(getAlchemyPotionMeta(), otherPotionMeta)) { return false; } - if (data.isUpgraded() != that.isUpgraded()) { + + // Legacy only comparison, compare PotionData + if (!PotionUtil.isPotionDataEqual(getAlchemyPotionMeta(), otherPotionMeta)) { return false; } - for (PotionEffect effect : effects) { - if (!meta.hasCustomEffect(effect.getType())) { - return false; + + /* + * If one potion has lore and the other does not, then they are not the same potion. + * If both have lore, compare the lore. + * If neither have lore, they may be the same potion. + */ + if (!otherPotionMeta.hasLore() && getAlchemyPotionMeta().hasLore() + || !getAlchemyPotionMeta().hasLore() && otherPotionMeta.hasLore()) { + return false; + } + + return !otherPotionMeta.hasLore() || !getAlchemyPotionMeta().hasLore() + || otherPotionMeta.getLore().equals(getAlchemyPotionMeta().getLore()); + } + + private boolean hasDifferingCustomEffects(PotionMeta potionMeta, PotionMeta otherPotionMeta) { + for (int i = 0; i < potionMeta.getCustomEffects().size(); i++) { + var effect = potionMeta.getCustomEffects().get(i); + + // One has an effect the other does not, they are not the same potion + if (!otherPotionMeta.hasCustomEffect(effect.getType())) { + return true; + } + + var otherEffect = otherPotionMeta.getCustomEffects().get(i); + // Amplifier or duration are not equal, they are not the same potion + if (effect.getAmplifier() != otherEffect.getAmplifier() + || effect.getDuration() != otherEffect.getDuration()) { + return true; } } - if (!meta.hasLore() && !lore.isEmpty()) { + return false; + } + + public PotionMeta getAlchemyPotionMeta() { + return (PotionMeta) potionItemMeta; + } + + public boolean isSplash() { + return potionItemStack.getType() == Material.SPLASH_POTION; + } + + public boolean isLingering() { + return potionItemStack.getType() == Material.LINGERING_POTION; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { return false; } - if (!(lore.isEmpty() && !meta.hasLore()) && !meta.getLore().equals(lore)) { - return false; - } - if (!meta.hasDisplayName() && name != null) { - return false; - } - return (name == null && !meta.hasDisplayName()) || meta.getDisplayName().equals(name); + AlchemyPotion that = (AlchemyPotion) o; + return Objects.equals(potionConfigName, that.potionConfigName) && Objects.equals( + potionItemStack, that.potionItemStack) && Objects.equals(alchemyPotionChildren, + that.alchemyPotionChildren); + } + + @Override + public int hashCode() { + return Objects.hash(potionConfigName, potionItemStack, alchemyPotionChildren); + } + + @Override + public String toString() { + return "AlchemyPotion{" + + "potionConfigName='" + potionConfigName + '\'' + + ", potionItemStack=" + potionItemStack + + ", alchemyPotionChildren=" + alchemyPotionChildren + + '}'; } } diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/alchemy/PotionStage.java b/src/main/java/com/gmail/nossr50/datatypes/skills/alchemy/PotionStage.java index fe2778eed..471320190 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/alchemy/PotionStage.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/alchemy/PotionStage.java @@ -1,11 +1,12 @@ package com.gmail.nossr50.datatypes.skills.alchemy; -import org.bukkit.Material; -import org.bukkit.potion.PotionData; -import org.bukkit.potion.PotionEffect; -import org.bukkit.potion.PotionType; +import static com.gmail.nossr50.util.PotionUtil.isLong; +import static com.gmail.nossr50.util.PotionUtil.isPotionTypeWater; +import static com.gmail.nossr50.util.PotionUtil.isStrong; -import java.util.List; +import com.gmail.nossr50.util.PotionUtil; +import org.bukkit.inventory.meta.PotionMeta; +import org.bukkit.potion.PotionEffect; public enum PotionStage { FIVE(5), @@ -35,36 +36,37 @@ public enum PotionStage { } public static PotionStage getPotionStage(AlchemyPotion input, AlchemyPotion output) { - PotionStage potionStage = getPotionStage(output); - if (!isWaterBottle(input) && getPotionStage(input) == potionStage) { - potionStage = PotionStage.FIVE; + PotionStage outputPotionStage = getPotionStage(output); + PotionStage inputPotionStage = getPotionStage(input); + if (!isWaterBottle(input) && inputPotionStage == outputPotionStage) { + outputPotionStage = PotionStage.FIVE; } - return potionStage; + return outputPotionStage; } - private static boolean isWaterBottle(AlchemyPotion input) { - return input.getData().getType() == PotionType.WATER; + private static boolean isWaterBottle(AlchemyPotion alchemyPotion) { + return isPotionTypeWater(alchemyPotion.getAlchemyPotionMeta()); } public static PotionStage getPotionStage(AlchemyPotion alchemyPotion) { - PotionData data = alchemyPotion.getData(); - List effects = alchemyPotion.getEffects(); + final PotionMeta potionMeta = alchemyPotion.getAlchemyPotionMeta(); int stage = 1; // Check if potion has an effect of any sort - if (data.getType().getEffectType() != null || !effects.isEmpty()) { + if (!potionMeta.getCustomEffects().isEmpty() + || PotionUtil.hasBasePotionEffects(potionMeta)) { stage++; } // Check if potion has a glowstone dust amplifier // Else check if the potion has a custom effect with an amplifier added by mcMMO - if (data.isUpgraded()) { + if (isStrong(potionMeta)) { stage++; - } else if(!effects.isEmpty()) { - for (PotionEffect effect : effects){ - if(effect.getAmplifier() > 0){ + } else if (!potionMeta.getCustomEffects().isEmpty()) { + for (PotionEffect effect : potionMeta.getCustomEffects()) { + if (effect.getAmplifier() > 0) { stage++; break; } @@ -72,12 +74,12 @@ public enum PotionStage { } // Check if potion has a redstone dust amplifier - if (data.isExtended()) { + if (isLong(potionMeta)) { stage++; } // Check if potion has a gunpowder amplifier - if (alchemyPotion.getMaterial() == Material.SPLASH_POTION || alchemyPotion.getMaterial() == Material.LINGERING_POTION) { + if (alchemyPotion.isSplash() || alchemyPotion.isLingering()) { stage++; } diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/interfaces/ChildSkill.java b/src/main/java/com/gmail/nossr50/datatypes/skills/interfaces/ChildSkill.java index 0bfee0108..603bffa03 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/interfaces/ChildSkill.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/interfaces/ChildSkill.java @@ -5,6 +5,7 @@ import com.gmail.nossr50.datatypes.skills.PrimarySkillType; public interface ChildSkill extends Skill { /** * Get's the other parent for this Skill + * * @return the other parent */ PrimarySkillType getSecondParent(); diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/interfaces/CoreSkill.java b/src/main/java/com/gmail/nossr50/datatypes/skills/interfaces/CoreSkill.java index 51d4913ce..dff03f7da 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/interfaces/CoreSkill.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/interfaces/CoreSkill.java @@ -3,14 +3,15 @@ package com.gmail.nossr50.datatypes.skills.interfaces; import com.gmail.nossr50.datatypes.skills.SubSkillType; /** - * This interface is mostly here to maintain backwards compatibility with other mcMMO plugins - * Only Core Skills will make use of this - * Previously in mcMMO subskills were basically defined by the SecondaryAbility ENUM - * In the new system which I'm gradually converting all the existing skills to, skills instead are unique instances of AbstractSubSkill + * This interface is mostly here to maintain backwards compatibility with other mcMMO plugins Only + * Core Skills will make use of this Previously in mcMMO subskills were basically defined by the + * SecondaryAbility ENUM In the new system which I'm gradually converting all the existing skills + * to, skills instead are unique instances of AbstractSubSkill */ public interface CoreSkill { /** * Gets the associated SubSkillType for this subskill + * * @return the associated SubSkillType ENUM definition */ SubSkillType getSubSkillType(); diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/interfaces/Localized.java b/src/main/java/com/gmail/nossr50/datatypes/skills/interfaces/Localized.java index 468e19c1d..8498a9c79 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/interfaces/Localized.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/interfaces/Localized.java @@ -1,18 +1,20 @@ package com.gmail.nossr50.datatypes.skills.interfaces; /** - * Localized interface represents skills which have localizations - * Skills with localizations will use their localization names/descriptions when being printed + * Localized interface represents skills which have localizations Skills with localizations will use + * their localization names/descriptions when being printed */ public interface Localized { /** * The translated name for this locale + * * @return the translated name for this locale */ String getLocaleName(); /** * The translated name for this subskill description + * * @return */ String getLocaleDescription(); diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/interfaces/Skill.java b/src/main/java/com/gmail/nossr50/datatypes/skills/interfaces/Skill.java index 68cf7180e..280960c3c 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/interfaces/Skill.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/interfaces/Skill.java @@ -5,12 +5,14 @@ import com.gmail.nossr50.datatypes.skills.PrimarySkillType; public interface Skill { /** * The primary skill + * * @return this primary skill */ PrimarySkillType getPrimarySkill(); /** * Returns the key name used for this skill in conjunction with config files + * * @return config file key name */ String getPrimaryKeyName(); 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 e3a448eb0..37cc115a6 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 @@ -1,19 +1,19 @@ package com.gmail.nossr50.datatypes.skills.interfaces; -import org.bukkit.inventory.ItemStack; - import java.util.Collection; +import org.bukkit.inventory.ItemStack; public interface Toolable { /** - * Whether this Skill requires a tool - * Not all skills will require a tool + * Whether this Skill requires a tool Not all skills will require a tool + * * @return true if tool is required */ - boolean requiresTool(); + boolean requiresTool(); /** * The tools associated with this Skill + * * @return the tools */ Collection getTools(); diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/progression/Progression.java b/src/main/java/com/gmail/nossr50/datatypes/skills/progression/Progression.java index 30f00e0aa..191db9854 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/progression/Progression.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/progression/Progression.java @@ -6,6 +6,7 @@ import org.bukkit.event.Event; public interface Progression { /** * The interaction vector for gaining XP + * * @return the interaction vector for gaining XP */ InteractType getXpGainInteractType(); 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 109ece783..a4c277824 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 @@ -1,6 +1,7 @@ package com.gmail.nossr50.datatypes.skills.subskills; import com.gmail.nossr50.config.CoreSkillsConfig; +import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.datatypes.skills.subskills.interfaces.Interaction; import com.gmail.nossr50.datatypes.skills.subskills.interfaces.Rank; @@ -17,8 +18,8 @@ public abstract class AbstractSubSkill implements SubSkill, Interaction, Rank, S protected String configKeyPrimary; protected SubSkillType subSkillType; - public AbstractSubSkill(String configKeySubSkill, String configKeyPrimary, SubSkillType subSkillType) - { + public AbstractSubSkill(String configKeySubSkill, String configKeyPrimary, + SubSkillType subSkillType) { this.configKeySubSkill = configKeySubSkill; this.configKeyPrimary = configKeyPrimary; this.subSkillType = subSkillType; @@ -31,7 +32,8 @@ public abstract class AbstractSubSkill implements SubSkill, Interaction, Rank, S */ @Override public String getDescription() { - return LocaleLoader.getString(getPrimaryKeyName()+".SubSkill."+getConfigKeyName()+".Description"); + return LocaleLoader.getString( + getPrimaryKeyName() + ".SubSkill." + getConfigKeyName() + ".Description"); } /** @@ -39,7 +41,8 @@ public abstract class AbstractSubSkill implements SubSkill, Interaction, Rank, S * * @return true if enabled */ - @Override @Deprecated + @Override + @Deprecated public boolean isEnabled() { //TODO: This might be troublesome... return CoreSkillsConfig.getInstance().isSkillEnabled(this); @@ -48,15 +51,16 @@ public abstract class AbstractSubSkill implements SubSkill, Interaction, Rank, S /** * Prints detailed info about this subskill to the player * - * @param player the target player + * @param mmoPlayer the target player */ @Override - public void printInfo(Player player) { + public void printInfo(McMMOPlayer mmoPlayer) { /* DEFAULT SETTINGS PRINT THE BARE MINIMUM */ - //TextComponentFactory.sendPlayerUrlHeader(player); + final Player player = mmoPlayer.getPlayer(); player.sendMessage(LocaleLoader.getString("Commands.MmoInfo.Header")); - player.sendMessage(LocaleLoader.getString("Commands.MmoInfo.SubSkillHeader", getConfigKeyName())); + player.sendMessage( + LocaleLoader.getString("Commands.MmoInfo.SubSkillHeader", getConfigKeyName())); player.sendMessage(LocaleLoader.getString("Commands.MmoInfo.DetailsHeader")); } diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/AcrobaticsSubSkill.java b/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/AcrobaticsSubSkill.java index df479bb53..7d1848c02 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/AcrobaticsSubSkill.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/AcrobaticsSubSkill.java @@ -14,21 +14,22 @@ public abstract class AcrobaticsSubSkill extends AbstractSubSkill { protected EventPriority interactionPriority; - public AcrobaticsSubSkill(String configKeySub, EventPriority interactionPriority, SubSkillType subSkillType) { + public AcrobaticsSubSkill(String configKeySub, EventPriority interactionPriority, + SubSkillType subSkillType) { super(configKeySub, "Acrobatics", subSkillType); this.interactionPriority = interactionPriority; } /** - * The name of this subskill - * Core mcMMO skills will pull the name from Locale with this method + * The name of this subskill Core mcMMO skills will pull the name from Locale with this method * * @return the subskill name */ @Override public String getNiceName() { - return LocaleLoader.getString(getPrimaryKeyName()+".SubSkill."+getConfigKeyName()+".Name"); + return LocaleLoader.getString( + getPrimaryKeyName() + ".SubSkill." + getConfigKeyName() + ".Name"); } /** @@ -48,7 +49,9 @@ public abstract class AcrobaticsSubSkill extends AbstractSubSkill { */ @Override public String getTips() { - return LocaleLoader.getString("JSON."+StringUtils.getCapitalized(getPrimarySkill().toString())+".SubSkill."+getConfigKeyName()+".Details.Tips"); + return LocaleLoader.getString( + "JSON." + StringUtils.getCapitalized(getPrimarySkill().toString()) + ".SubSkill." + + getConfigKeyName() + ".Details.Tips"); } /** @@ -84,7 +87,7 @@ public abstract class AcrobaticsSubSkill extends AbstractSubSkill { /** * Executes the interaction between this subskill and Minecraft * - * @param event the vector of interaction + * @param event the vector of interaction * @param plugin the mcMMO plugin instance * @return true if interaction wasn't cancelled */ 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 64a3a14fb..4b64a8ad1 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 @@ -1,10 +1,14 @@ package com.gmail.nossr50.datatypes.skills.subskills.acrobatics; +import static com.gmail.nossr50.util.player.NotificationManager.sendPlayerInformation; +import static com.gmail.nossr50.util.random.ProbabilityUtil.getSubSkillProbability; +import static com.gmail.nossr50.util.skills.SkillUtils.applyXpGain; +import static com.gmail.nossr50.util.sounds.SoundManager.sendCategorizedSound; + import com.gmail.nossr50.config.experience.ExperienceConfig; import com.gmail.nossr50.datatypes.experience.XPGainReason; 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; @@ -12,33 +16,30 @@ import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.EventUtils; import com.gmail.nossr50.util.ItemUtils; 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.skills.PerksUtils; +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.SkillActivationType; -import com.gmail.nossr50.util.skills.SkillUtils; -import com.gmail.nossr50.util.sounds.SoundManager; import com.gmail.nossr50.util.sounds.SoundType; +import java.util.Locale; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.TextComponent; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.SoundCategory; -import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.Player; import org.bukkit.event.Event; import org.bukkit.event.EventPriority; import org.bukkit.event.entity.EntityDamageEvent; import org.bukkit.inventory.ItemStack; - -import java.util.Locale; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.VisibleForTesting; public class Roll extends AcrobaticsSubSkill { + public static final String GRACEFUL_ROLL_ACTIVATED_LOCALE_STR_KEY = "Acrobatics.Ability.Proc"; + public static final String ROLL_ACTIVATED_LOCALE_KEY = "Acrobatics.Roll.Text"; + public Roll() { super("Roll", EventPriority.HIGHEST, SubSkillType.ACROBATICS_ROLL); } @@ -51,41 +52,70 @@ public class Roll extends AcrobaticsSubSkill { */ @Override public boolean doInteraction(Event event, mcMMO plugin) { - //TODO: Go through and API this up - - /* - * Roll is a SubSkill which allows players to negate fall damage from certain heights with sufficient Acrobatics skill and luck - * Roll is activated when a player takes damage from a fall - * If a player holds shift, they double their odds at a successful roll and upon success are told they did a graceful roll. - */ - - //Casting - EntityDamageEvent entityDamageEvent = (EntityDamageEvent) event; + final EntityDamageEvent entityDamageEvent = (EntityDamageEvent) event; //Make sure a real player was damaged in this event - if(!EventUtils.isRealPlayerDamaged(entityDamageEvent)) + if (!EventUtils.isRealPlayerDamaged(entityDamageEvent) + || !entityDamageEvent.isApplicable(EntityDamageEvent.DamageModifier.MAGIC)) { return false; + } - if (entityDamageEvent.getCause() == EntityDamageEvent.DamageCause.FALL) {//Grab the player - McMMOPlayer mcMMOPlayer = EventUtils.getMcMMOPlayer(entityDamageEvent.getEntity()); + if (entityDamageEvent.getCause() == EntityDamageEvent.DamageCause.FALL) { + final McMMOPlayer mmoPlayer = EventUtils.getMcMMOPlayer(entityDamageEvent.getEntity()); - if (mcMMOPlayer == null) + if (mmoPlayer == null) { return false; + } /* * Check for success */ - Player player = (Player) ((EntityDamageEvent) event).getEntity(); - if (canRoll(player)) { - entityDamageEvent.setDamage(rollCheck(player, mcMMOPlayer, entityDamageEvent.getFinalDamage())); - if (entityDamageEvent.getFinalDamage() == 0) { - entityDamageEvent.setCancelled(true); - return true; + if (canRoll(mmoPlayer)) { + final RollResult rollResult + = rollCheck(mmoPlayer, entityDamageEvent); + if (rollResult == null) { + // no-op - fall was fatal or otherwise did not get processed + return false; } - } else if(mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, PrimarySkillType.ACROBATICS)) { - //Give XP Anyways - SkillUtils.applyXpGain(mcMMOPlayer, getPrimarySkill(), calculateRollXP(player, ((EntityDamageEvent) event).getFinalDamage(), false), XPGainReason.PVE); + + // Roll happened, reduce damage, send messages and XP + if (rollResult.isRollSuccess()) { + // Clear out the damage from falling so that way our modified damage doesn't get re-reduced by protection/feather falling + entityDamageEvent.setDamage(0); + // Send the damage is MAGIC so that it cuts through all resistances + // This is fine because we considered protection/featherfalling in the rollCheck method + entityDamageEvent.setDamage(EntityDamageEvent.DamageModifier.MAGIC, + rollResult.getModifiedDamage()); + + if (entityDamageEvent.getFinalDamage() == 0) { + entityDamageEvent.setCancelled(true); + } + + final String key + = rollResult.isGraceful() ? GRACEFUL_ROLL_ACTIVATED_LOCALE_STR_KEY + : ROLL_ACTIVATED_LOCALE_KEY; + sendPlayerInformation(mmoPlayer.getPlayer(), NotificationType.SUBSKILL_MESSAGE, + key); + sendCategorizedSound(mmoPlayer.getPlayer(), mmoPlayer.getPlayer().getLocation(), + SoundType.ROLL_ACTIVATED, SoundCategory.PLAYERS, 0.5F); + } + + if (!rollResult.isExploiting() && rollResult.getXpGain() > 0) { + applyXpGain(mmoPlayer, getPrimarySkill(), rollResult.getXpGain(), + XPGainReason.PVE); + } + + // Player didn't die, so add the location to the list + addFallLocation(mmoPlayer); + return true; + // We give Acrobatics XP for fall damage even if they haven't unlocked roll + } else if (mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(mmoPlayer.getPlayer(), + PrimarySkillType.ACROBATICS)) { + //Give XP + applyXpGain(mmoPlayer, getPrimarySkill(), + calculateRollXP(mmoPlayer, ((EntityDamageEvent) event).getFinalDamage(), + false), XPGainReason.PVE); } } @@ -99,7 +129,8 @@ public class Roll extends AcrobaticsSubSkill { */ @Override public String getPermissionNode() { - return ("mcmmo.ability."+getPrimaryKeyName()+"."+getConfigKeyName()).toLowerCase(Locale.ENGLISH); + return ("mcmmo.ability." + getPrimaryKeyName() + "." + getConfigKeyName()).toLowerCase( + Locale.ENGLISH); } /** @@ -110,32 +141,34 @@ public class Roll extends AcrobaticsSubSkill { */ @Override public boolean hasPermission(Player player) { - return Permissions.isSubSkillEnabled(player, this); + return Permissions.isSubSkillEnabled(player, getSubSkillType()); } /** * Adds detailed stats specific to this skill * * @param componentBuilder target component builder - * @param player target player + * @param mmoPlayer target player */ @Override - public void addStats(TextComponent.Builder componentBuilder, Player player) { + public void addStats(TextComponent.Builder componentBuilder, McMMOPlayer mmoPlayer) { String rollChance, rollChanceLucky, gracefulRollChance, gracefulRollChanceLucky; /* Values related to the player */ - PlayerProfile playerProfile = UserManager.getPlayer(player).getProfile(); - float skillValue = playerProfile.getSkillLevel(getPrimarySkill()); - boolean isLucky = Permissions.lucky(player, getPrimarySkill()); + float skillValue = mmoPlayer.getSkillLevel(getPrimarySkill()); + boolean isLucky = Permissions.lucky(mmoPlayer.getPlayer(), getPrimarySkill()); - String[] rollStrings = RandomChanceUtil.calculateAbilityDisplayValues(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, player, SubSkillType.ACROBATICS_ROLL); + String[] rollStrings = ProbabilityUtil.getRNGDisplayValues(mmoPlayer, + 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); + Probability probability = getRollProbability(mmoPlayer); + Probability gracefulProbability = Probability.ofValue(probability.getValue() * 2); + String[] gracefulRollStrings = ProbabilityUtil.getRNGDisplayValues(gracefulProbability); gracefulRollChance = gracefulRollStrings[0]; gracefulRollChanceLucky = gracefulRollStrings[1]; @@ -147,25 +180,38 @@ public class Roll extends AcrobaticsSubSkill { componentBuilder.append("\n");*/ //Acrobatics.SubSkill.Roll.Chance - componentBuilder.append(Component.text(LocaleLoader.getString("Acrobatics.SubSkill.Roll.Chance", rollChance) + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", rollChanceLucky) : ""))); + componentBuilder.append(Component.text( + LocaleLoader.getString("Acrobatics.SubSkill.Roll.Chance", rollChance) + (isLucky + ? LocaleLoader.getString("Perks.Lucky.Bonus", rollChanceLucky) : ""))); componentBuilder.append(Component.newline()); - componentBuilder.append(Component.text(LocaleLoader.getString("Acrobatics.SubSkill.Roll.GraceChance", gracefulRollChance) + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", gracefulRollChanceLucky) : ""))); + componentBuilder.append(Component.text( + LocaleLoader.getString("Acrobatics.SubSkill.Roll.GraceChance", gracefulRollChance) + + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", + gracefulRollChanceLucky) : ""))); //Activation Tips - componentBuilder.append(Component.newline()).append(Component.text(LocaleLoader.getString("JSON.Hover.Tips"))).append(Component.newline()); + componentBuilder.append(Component.newline()) + .append(Component.text(LocaleLoader.getString("JSON.Hover.Tips"))) + .append(Component.newline()); componentBuilder.append(Component.text(getTips())); componentBuilder.append(Component.newline()); //Advanced //Lucky Notice - if(isLucky) - { - componentBuilder.append(Component.text(LocaleLoader.getString("JSON.JWrapper.Perks.Header"))); + if (isLucky) { + componentBuilder.append( + Component.text(LocaleLoader.getString("JSON.JWrapper.Perks.Header"))); componentBuilder.append(Component.newline()); - componentBuilder.append(Component.text(LocaleLoader.getString("JSON.JWrapper.Perks.Lucky", "33"))); + componentBuilder.append( + Component.text(LocaleLoader.getString("JSON.JWrapper.Perks.Lucky", "33"))); } } + @NotNull + private Probability getRollProbability(McMMOPlayer mmoPlayer) { + return getSubSkillProbability(SubSkillType.ACROBATICS_ROLL, mmoPlayer); + } + @Override public boolean isSuperAbility() { return false; @@ -181,112 +227,100 @@ public class Roll extends AcrobaticsSubSkill { return true; } - private boolean canRoll(Player player) { - return RankUtils.hasUnlockedSubskill(player, SubSkillType.ACROBATICS_ROLL) && Permissions.isSubSkillEnabled(player, SubSkillType.ACROBATICS_ROLL); + @VisibleForTesting + public boolean canRoll(McMMOPlayer mmoPlayer) { + return RankUtils.hasUnlockedSubskill(mmoPlayer.getPlayer(), SubSkillType.ACROBATICS_ROLL) + && Permissions.isSubSkillEnabled(mmoPlayer.getPlayer(), + SubSkillType.ACROBATICS_ROLL); } /** - * Handle the damage reduction and XP gain from the Roll ability + * Handle the damage reduction and XP gain from the Roll / Graceful Roll ability * - * @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 + * @param entityDamageEvent the event to modify in the event of roll success + * @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 RollResult rollCheck(McMMOPlayer mmoPlayer, EntityDamageEvent entityDamageEvent) { + double baseDamage = entityDamageEvent.getFinalDamage(); + final boolean isGraceful = mmoPlayer.getPlayer().isSneaking(); + final RollResult.Builder rollResultBuilder + = new RollResult.Builder(entityDamageEvent, isGraceful); + final Probability probability + = isGraceful ? getGracefulProbability(mmoPlayer) + : getNonGracefulProbability(mmoPlayer); - int skillLevel = mcMMOPlayer.getSkillLevel(getPrimarySkill()); + double modifiedDamage = calculateModifiedRollDamage(baseDamage, + mcMMO.p.getAdvancedConfig().getRollDamageThreshold() * 2); + rollResultBuilder.modifiedDamage(modifiedDamage); - if (player.isSneaking()) { - return gracefulRollCheck(player, mcMMOPlayer, damage, skillLevel); + boolean isExploiting = isPlayerExploitingAcrobatics(mmoPlayer); + rollResultBuilder.exploiting(isExploiting); + // They Rolled + if (!isFatal(mmoPlayer, modifiedDamage) + && ProbabilityUtil.isStaticSkillRNGSuccessful(PrimarySkillType.ACROBATICS, + mmoPlayer, probability)) { + rollResultBuilder.rollSuccess(true); + rollResultBuilder.exploiting(isExploiting); + final boolean canGainXp = mmoPlayer.getAcrobaticsManager().canGainRollXP(); + + if (!isExploiting && canGainXp) { + rollResultBuilder.xpGain((int) calculateRollXP(mmoPlayer, baseDamage, true)); + } + + return rollResultBuilder.build(); + // They did not roll, but they also did not die so reward XP as appropriate + } else if (!isFatal(mmoPlayer, baseDamage)) { + rollResultBuilder.rollSuccess(false); + final boolean canGainXp = mmoPlayer.getAcrobaticsManager().canGainRollXP(); + if (!isExploiting && canGainXp) { + rollResultBuilder.xpGain((int) calculateRollXP(mmoPlayer, baseDamage, false)); + } + + return rollResultBuilder.build(); } - - double modifiedDamage = calculateModifiedRollDamage(damage, mcMMO.p.getAdvancedConfig().getRollDamageThreshold()); - - if (!isFatal(player, modifiedDamage) - && RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, 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")); - - //if (!SkillUtils.cooldownExpired((long) mcMMOPlayer.getTeleportATS(), Config.getInstance().getXPAfterTeleportCooldown())) { - if(!isExploiting(player) && mcMMOPlayer.getAcrobaticsManager().canGainRollXP()) - SkillUtils.applyXpGain(mcMMOPlayer, getPrimarySkill(), calculateRollXP(player, damage, true), XPGainReason.PVE); - //} - - addFallLocation(player); - return modifiedDamage; - } - else if (!isFatal(player, damage)) { - //if (!SkillUtils.cooldownExpired((long) mcMMOPlayer.getTeleportATS(), Config.getInstance().getXPAfterTeleportCooldown())) { - if(!isExploiting(player) && mcMMOPlayer.getAcrobaticsManager().canGainRollXP()) - SkillUtils.applyXpGain(mcMMOPlayer, getPrimarySkill(), calculateRollXP(player, damage, false), XPGainReason.PVE); - //} - } - - addFallLocation(player); - return damage; + // Fall was fatal return null + return null; } - private int getActivationChance(McMMOPlayer mcMMOPlayer) { - return PerksUtils.handleLuckyPerks(mcMMOPlayer.getPlayer(), getPrimarySkill()); + @NotNull + public static Probability getGracefulProbability(McMMOPlayer mmoPlayer) { + double gracefulOdds = + getSubSkillProbability(SubSkillType.ACROBATICS_ROLL, mmoPlayer).getValue() * 2; + return Probability.ofValue(gracefulOdds); + } + + public static Probability getNonGracefulProbability(McMMOPlayer mmoPlayer) { + double gracefulOdds = getSubSkillProbability(SubSkillType.ACROBATICS_ROLL, + mmoPlayer).getValue(); + return Probability.ofValue(gracefulOdds); } /** - * Handle the damage reduction and XP gain from the Graceful Roll ability - * - * @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 gracefulRollCheck(Player player, McMMOPlayer mcMMOPlayer, double damage, int skillLevel) { - double modifiedDamage = calculateModifiedRollDamage(damage, mcMMO.p.getAdvancedConfig().getRollDamageThreshold() * 2); - - RandomChanceSkill rcs = new RandomChanceSkill(player, subSkillType); - rcs.setSkillLevel(rcs.getSkillLevel() * 2); //Double the effective odds - - if (!isFatal(player, modifiedDamage) - && RandomChanceUtil.checkRandomChanceExecutionSuccess(rcs)) - { - NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE, "Acrobatics.Ability.Proc"); - SoundManager.sendCategorizedSound(player, player.getLocation(), SoundType.ROLL_ACTIVATED, SoundCategory.PLAYERS,0.5F); - if(!isExploiting(player) && mcMMOPlayer.getAcrobaticsManager().canGainRollXP()) - SkillUtils.applyXpGain(mcMMOPlayer, getPrimarySkill(), calculateRollXP(player, damage, true), XPGainReason.PVE); - - addFallLocation(player); - return modifiedDamage; - } - else if (!isFatal(player, damage)) { - if(!isExploiting(player) && mcMMOPlayer.getAcrobaticsManager().canGainRollXP()) - SkillUtils.applyXpGain(mcMMOPlayer, getPrimarySkill(), calculateRollXP(player, damage, false), XPGainReason.PVE); - - addFallLocation(player); - } - - return damage; - } - - /** - * Check if the player is "farming" Acrobatics XP using - * exploits in the game. + * Check if the player is "farming" Acrobatics XP using exploits in the game. * * @return true if exploits are detected, false otherwise */ - private boolean isExploiting(Player player) { + private boolean isPlayerExploitingAcrobatics(McMMOPlayer mmoPlayer) { if (!ExperienceConfig.getInstance().isAcrobaticsExploitingPrevented()) { return false; } - McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player); - - if (ItemUtils.hasItemInEitherHand(player, Material.ENDER_PEARL) || player.isInsideVehicle()) { - if(mcMMOPlayer.isDebugMode()) { - mcMMOPlayer.getPlayer().sendMessage("Acrobatics XP Prevented: Ender Pearl or Inside Vehicle"); + if (ItemUtils.hasItemInEitherHand(mmoPlayer.getPlayer(), Material.ENDER_PEARL) + || mmoPlayer.getPlayer().isInsideVehicle()) { + if (mmoPlayer.isDebugMode()) { + mmoPlayer.getPlayer() + .sendMessage("Acrobatics XP Prevented: Ender Pearl or Inside Vehicle"); } return true; } - if(UserManager.getPlayer(player).getAcrobaticsManager().hasFallenInLocationBefore(getBlockLocation(player))) - { - if(mcMMOPlayer.isDebugMode()) { - mcMMOPlayer.getPlayer().sendMessage("Acrobatics XP Prevented: Fallen in location before"); + if (mmoPlayer.getAcrobaticsManager() + .hasFallenInLocationBefore(getBlockLocation(mmoPlayer))) { + if (mmoPlayer.isDebugMode()) { + mmoPlayer.getPlayer() + .sendMessage("Acrobatics XP Prevented: Fallen in location before"); } return true; @@ -295,14 +329,16 @@ public class Roll extends AcrobaticsSubSkill { return false; //NOT EXPLOITING } - private float calculateRollXP(Player player, double damage, boolean isRoll) { + private float calculateRollXP(McMMOPlayer mmoPlayer, double damage, boolean isRoll) { //Clamp Damage to account for insane DRs damage = Math.min(20, damage); - ItemStack boots = player.getInventory().getBoots(); - float xp = (float) (damage * (isRoll ? ExperienceConfig.getInstance().getRollXPModifier() : ExperienceConfig.getInstance().getFallXPModifier())); + ItemStack boots = mmoPlayer.getPlayer().getInventory().getBoots(); + float xp = (float) (damage * (isRoll ? ExperienceConfig.getInstance().getRollXPModifier() + : ExperienceConfig.getInstance().getFallXPModifier())); - if (boots != null && boots.containsEnchantment(Enchantment.PROTECTION_FALL)) { + if (boots != null && boots.containsEnchantment( + mcMMO.p.getEnchantmentMapper().getFeatherFalling())) { xp *= ExperienceConfig.getInstance().getFeatherFallXPModifier(); } @@ -313,8 +349,8 @@ public class Roll extends AcrobaticsSubSkill { return Math.max(damage - damageThreshold, 0.0); } - private boolean isFatal(Player player, double damage) { - return player.getHealth() - damage <= 0; + private boolean isFatal(McMMOPlayer mmoPlayer, double damage) { + return mmoPlayer.getPlayer().getHealth() - damage <= 0; } /** @@ -330,110 +366,48 @@ public class Roll extends AcrobaticsSubSkill { /** * Prints detailed info about this subskill to the player * - * @param player the target player + * @param mmoPlayer the target player */ @Override - public void printInfo(Player player) { + public void printInfo(McMMOPlayer mmoPlayer) { //Header - super.printInfo(player); + super.printInfo(mmoPlayer); //Start the description string. //player.sendMessage(getDescription()); //Player stats - player.sendMessage(LocaleLoader.getString("Commands.MmoInfo.Stats", - LocaleLoader.getString("Acrobatics.SubSkill.Roll.Stats", getStats(player)))); + mmoPlayer.getPlayer().sendMessage(LocaleLoader.getString("Commands.MmoInfo.Stats", + LocaleLoader.getString("Acrobatics.SubSkill.Roll.Stats", getStats(mmoPlayer)))); //Mechanics - player.sendMessage(LocaleLoader.getString("Commands.MmoInfo.Mechanics")); - player.sendMessage(getMechanics()); + mmoPlayer.getPlayer().sendMessage(LocaleLoader.getString("Commands.MmoInfo.Mechanics")); + mmoPlayer.getPlayer().sendMessage(getMechanics()); } - /** - * Returns a collection of strings about how a skill works - * Used in the MMO Info command - * - * @return - */ @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 - */ - return "Under Construction: This will work in a future update."; -// -// double rollChanceHalfMax, graceChanceHalfMax, damageThreshold, chancePerLevel; -// -// //Chance to roll at half max skill -// RandomChanceSkill rollHalfMaxSkill = new RandomChanceSkill(null, subSkillType); -// int halfMaxSkillValue = mcMMO.p.getAdvancedConfig().getMaxBonusLevel(SubSkillType.ACROBATICS_ROLL)/2; -// rollHalfMaxSkill.setSkillLevel(halfMaxSkillValue); -// -// //Chance to graceful roll at full skill -// RandomChanceSkill rollGraceHalfMaxSkill = new RandomChanceSkill(null, subSkillType); -// rollGraceHalfMaxSkill.setSkillLevel(halfMaxSkillValue * 2); //Double the effective odds -// -// //Chance to roll per level -// RandomChanceSkill rollOneSkillLevel = new RandomChanceSkill(null, subSkillType); -// rollGraceHalfMaxSkill.setSkillLevel(1); //Level 1 skill -// -// //Chance Stat Calculations -// rollChanceHalfMax = RandomChanceUtil.getRandomChanceExecutionChance(rollHalfMaxSkill); -// graceChanceHalfMax = RandomChanceUtil.getRandomChanceExecutionChance(rollGraceHalfMaxSkill); -// damageThreshold = mcMMO.p.getAdvancedConfig().getRollDamageThreshold(); -// -// chancePerLevel = RandomChanceUtil.getRandomChanceExecutionChance(rollOneSkillLevel); -// -// double maxLevel = mcMMO.p.getAdvancedConfig().getMaxBonusLevel(SubSkillType.ACROBATICS_ROLL); -// -// return LocaleLoader.getString("Acrobatics.SubSkill.Roll.Mechanics", rollChanceHalfMax, graceChanceHalfMax, maxLevel, chancePerLevel, damageThreshold, damageThreshold * 2,halfMaxSkillValue); } /** * Get an array of various stats for a player * - * @param player target player + * @param mmoPlayer target player * @return stat array for target player for this skill */ @Override - public Double[] getStats(Player player) - { - double playerChanceRoll, playerChanceGrace; + public Double[] getStats(McMMOPlayer mmoPlayer) { + double playerChanceRoll = getSubSkillProbability(subSkillType, mmoPlayer).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); - - return new Double[]{ playerChanceRoll, playerChanceGrace }; + return new Double[]{playerChanceRoll, playerChanceGrace}; } - public void addFallLocation(Player player) - { - UserManager.getPlayer(player).getAcrobaticsManager().addLocationToFallMap(getBlockLocation(player)); + public void addFallLocation(@NotNull McMMOPlayer mmoPlayer) { + mmoPlayer.getAcrobaticsManager().addLocationToFallMap(getBlockLocation(mmoPlayer)); } - public Location getBlockLocation(Player player) - { - return player.getLocation().getBlock().getLocation(); + public @NotNull Location getBlockLocation(@NotNull McMMOPlayer mmoPlayer) { + return mmoPlayer.getPlayer().getLocation().getBlock().getLocation(); } - } diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/RollResult.java b/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/RollResult.java new file mode 100644 index 000000000..b1742d35f --- /dev/null +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/RollResult.java @@ -0,0 +1,115 @@ +package com.gmail.nossr50.datatypes.skills.subskills.acrobatics; + +import static java.util.Objects.requireNonNull; + +import org.bukkit.event.entity.EntityDamageEvent; + +/** + * Immutable class representing the result of a roll action in acrobatics. + */ +public class RollResult { + private final boolean rollSuccess; + private final boolean isGraceful; + private final double eventDamage; + private final double modifiedDamage; + private final boolean isFatal; + private final boolean isExploiting; + private final float xpGain; + + private RollResult(Builder builder) { + this.rollSuccess = builder.rollSuccess; + this.isGraceful = builder.isGraceful; + this.eventDamage = builder.eventDamage; + this.modifiedDamage = builder.modifiedDamage; + this.isFatal = builder.isFatal; + this.isExploiting = builder.isExploiting; + this.xpGain = builder.xpGain; + } + + public boolean isRollSuccess() { + return rollSuccess; + } + + public boolean isGraceful() { + return isGraceful; + } + + public double getEventDamage() { + return eventDamage; + } + + public double getModifiedDamage() { + return modifiedDamage; + } + + public boolean isFatal() { + return isFatal; + } + + public boolean isExploiting() { + return isExploiting; + } + + public float getXpGain() { + return xpGain; + } + + /** + * Builder class for constructing {@code RollResult} instances. + */ + public static class Builder { + private final boolean isGraceful; + private final double eventDamage; + private double modifiedDamage; + private boolean isFatal; + private boolean rollSuccess; + private boolean isExploiting; + private float xpGain; + + /** + * Constructs a new {@code Builder} with required parameters. + * + * @param entityDamageEvent the damage event, must not be null + * @param isGracefulRoll whether the roll is graceful + */ + public Builder(EntityDamageEvent entityDamageEvent, boolean isGracefulRoll) { + requireNonNull(entityDamageEvent, "EntityDamageEvent cannot be null"); + this.eventDamage = entityDamageEvent.getDamage(); + this.isGraceful = isGracefulRoll; + } + + public Builder modifiedDamage(double modifiedDamage) { + this.modifiedDamage = modifiedDamage; + return this; + } + + public Builder fatal(boolean isFatal) { + this.isFatal = isFatal; + return this; + } + + public Builder rollSuccess(boolean rollSuccess) { + this.rollSuccess = rollSuccess; + return this; + } + + public Builder exploiting(boolean isExploiting) { + this.isExploiting = isExploiting; + return this; + } + + public Builder xpGain(float xpGain) { + this.xpGain = xpGain; + return this; + } + + /** + * Builds and returns a {@code RollResult} instance. + * + * @return a new {@code RollResult} + */ + public RollResult build() { + return new RollResult(this); + } + } +} diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/interfaces/Interaction.java b/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/interfaces/Interaction.java index 1e0357c7a..fed55dca4 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/interfaces/Interaction.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/interfaces/Interaction.java @@ -7,12 +7,14 @@ import org.bukkit.event.EventPriority; public interface Interaction { /** * The type of interaction this subskill has with Minecraft + * * @return the interaction type */ InteractType getInteractType(); /** * Executes the interaction between this subskill and Minecraft + * * @param event the vector of interaction * @param plugin the mcMMO plugin instance * @return true if interaction wasn't cancelled @@ -21,6 +23,7 @@ public interface Interaction { /** * The priority for this interaction + * * @return the priority for interaction */ EventPriority getEventPriority(); diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/interfaces/Rank.java b/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/interfaces/Rank.java index 4729ae454..4bb0c6d33 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/interfaces/Rank.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/interfaces/Rank.java @@ -3,12 +3,14 @@ package com.gmail.nossr50.datatypes.skills.subskills.interfaces; public interface Rank { /** * Gets the number of ranks for this subskill, 0 for no ranks + * * @return the number of ranks for this subskill, 0 for no ranks */ int getNumRanks(); /** * Not all skills have ranks + * * @return true if the skill has ranks */ boolean hasRanks(); 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 33d0e9874..2da1dda84 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 @@ -1,5 +1,6 @@ package com.gmail.nossr50.datatypes.skills.subskills.interfaces; +import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.skills.interfaces.Skill; import net.kyori.adventure.text.TextComponent; import org.bukkit.entity.Player; @@ -7,71 +8,81 @@ import org.bukkit.entity.Player; public interface SubSkill extends Skill { /** * Grabs the permission node for this skill + * * @return permission node address */ String getPermissionNode(); /** * Returns a collection of strings about how a skill works + * * @return */ String getMechanics(); /** * Get an array of various stats for a player - * @param player target player + * + * @param mmoPlayer target player * @return stat array for target player for this skill */ - Double[] getStats(Player player); + Double[] getStats(McMMOPlayer mmoPlayer); /** * Checks if a player has permission to use this skill + * * @param player target player * @return true if player has permission */ boolean hasPermission(Player player); /** - * The name of this subskill - * It's a good idea for this to return the localized name + * The name of this subskill It's a good idea for this to return the localized name + * * @return the subskill name */ String getNiceName(); /** * This is the name that represents our subskill in the config + * * @return the config key name */ String getConfigKeyName(); /** * Returns the simple description of this subskill + * * @return the simple description of this subskill */ String getDescription(); /** * Grabs tips for the subskill + * * @return tips for the subskill */ String getTips(); /** * Adds detailed stats specific to this skill + * * @param componentBuilder target component builder - * @param player owner of this skill + * @param mmoPlayer owner of this skill */ - void addStats(TextComponent.Builder componentBuilder, Player player); + void addStats(TextComponent.Builder componentBuilder, McMMOPlayer mmoPlayer); /** * Whether this subskill is enabled + * * @return true if enabled */ boolean isEnabled(); /** * Prints detailed info about this subskill to the player - * @param player the target player + * + * @param mmoPlayer the target player */ - void printInfo(Player player); + void printInfo(McMMOPlayer mmoPlayer); } diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/taming/CallOfTheWildType.java b/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/taming/CallOfTheWildType.java index 9e1749adc..4794fd0ac 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/taming/CallOfTheWildType.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/taming/CallOfTheWildType.java @@ -11,9 +11,10 @@ public enum CallOfTheWildType { //TODO: This is a hacky fix to make the COTW code in 2.1 more bearable, this will be removed upon the rework planned for COTW public String getConfigEntityTypeEntry() { - switch(this) { + switch (this) { case CAT: - return StringUtils.getPrettyEntityTypeString(EntityType.OCELOT); //Even though cats will be summoned in 1.14, we specify Ocelot here. This will be gone in 2.2 + return StringUtils.getPrettyEntityTypeString( + EntityType.OCELOT); //Even though cats will be summoned in 1.14, we specify Ocelot here. This will be gone in 2.2 case WOLF: return StringUtils.getPrettyEntityTypeString(EntityType.WOLF); case HORSE: diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/taming/TamingSummon.java b/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/taming/TamingSummon.java index f92155a6a..fb0cfc159 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/taming/TamingSummon.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/taming/TamingSummon.java @@ -16,7 +16,8 @@ public class TamingSummon { private final CallOfTheWildType callOfTheWildType; private EntityType entityType; - public TamingSummon(CallOfTheWildType callOfTheWildType, Material itemType, int itemAmountRequired, int entitiesSummoned, int summonLifespan, int summonCap) { + public TamingSummon(CallOfTheWildType callOfTheWildType, Material itemType, + int itemAmountRequired, int entitiesSummoned, int summonLifespan, int summonCap) { this.callOfTheWildType = callOfTheWildType; this.itemType = itemType; this.itemAmountRequired = Math.max(itemAmountRequired, 1); @@ -28,7 +29,7 @@ public class TamingSummon { } private void initEntityType() { - switch(callOfTheWildType) { + switch (callOfTheWildType) { case WOLF: entityType = EntityType.WOLF; break; @@ -36,7 +37,7 @@ public class TamingSummon { entityType = EntityType.HORSE; break; case CAT: - if(shouldSpawnCatInsteadOfOcelot()) { + if (shouldSpawnCatInsteadOfOcelot()) { //Server is on 1.14 or above entityType = EntityType.CAT; } else { diff --git a/src/main/java/com/gmail/nossr50/datatypes/treasure/EnchantmentWrapper.java b/src/main/java/com/gmail/nossr50/datatypes/treasure/EnchantmentWrapper.java index c442b4179..f283f2b61 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/treasure/EnchantmentWrapper.java +++ b/src/main/java/com/gmail/nossr50/datatypes/treasure/EnchantmentWrapper.java @@ -31,10 +31,15 @@ public class EnchantmentWrapper { @Override public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } EnchantmentWrapper that = (EnchantmentWrapper) o; - return enchantmentLevel == that.enchantmentLevel && Objects.equal(enchantment, that.enchantment); + return enchantmentLevel == that.enchantmentLevel && Objects.equal(enchantment, + that.enchantment); } @Override diff --git a/src/main/java/com/gmail/nossr50/datatypes/treasure/FishingTreasureBook.java b/src/main/java/com/gmail/nossr50/datatypes/treasure/FishingTreasureBook.java index 69feb7b9b..c797a9815 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/treasure/FishingTreasureBook.java +++ b/src/main/java/com/gmail/nossr50/datatypes/treasure/FishingTreasureBook.java @@ -2,21 +2,22 @@ package com.gmail.nossr50.datatypes.treasure; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.LogUtils; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; import org.bukkit.enchantments.Enchantment; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; - public class FishingTreasureBook extends FishingTreasure { private final @Nullable Set blackListedEnchantments; private final @Nullable Set whiteListedEnchantments; private final @NotNull List legalEnchantments; //TODO: Make immutable - public FishingTreasureBook(@NotNull ItemStack enchantedBook, int xp, @Nullable Set blackListedEnchantments, @Nullable Set whiteListedEnchantments) { + public FishingTreasureBook(@NotNull ItemStack enchantedBook, int xp, + @Nullable Set blackListedEnchantments, + @Nullable Set whiteListedEnchantments) { super(enchantedBook, xp); this.blackListedEnchantments = blackListedEnchantments; @@ -29,16 +30,16 @@ public class FishingTreasureBook extends FishingTreasure { private void initLegalEnchantments() { LogUtils.debug(mcMMO.p.getLogger(), "Registering enchantments for Fishing Book..."); - for(Enchantment enchantment : Enchantment.values()) { - if(isEnchantAllowed(enchantment)) { + for (Enchantment enchantment : Enchantment.values()) { + if (isEnchantAllowed(enchantment)) { addAllLegalEnchants(enchantment); } } } /** - * Get all the enchantments which can drop for this book - * This list can be empty, but should in practice never be empty... + * Get all the enchantments which can drop for this book This list can be empty, but should in + * practice never be empty... * * @return all the enchantments that can drop for this book */ @@ -57,18 +58,19 @@ public class FishingTreasureBook extends FishingTreasure { private void addAllLegalEnchants(@NotNull Enchantment enchantment) { int legalEnchantCap = enchantment.getMaxLevel(); - for(int i = 0; i < legalEnchantCap; i++) { - int enchantLevel = i+1; - EnchantmentWrapper enchantmentWrapper = new EnchantmentWrapper(enchantment, enchantLevel); + for (int i = 0; i < legalEnchantCap; i++) { + int enchantLevel = i + 1; + EnchantmentWrapper enchantmentWrapper = new EnchantmentWrapper(enchantment, + enchantLevel); legalEnchantments.add(enchantmentWrapper); // mcMMO.p.getLogger().info("Fishing treasure book enchantment added: " + enchantmentWrapper); } } private boolean isEnchantAllowed(@NotNull Enchantment enchantment) { - if(whiteListedEnchantments != null && !whiteListedEnchantments.isEmpty()) { + if (whiteListedEnchantments != null && !whiteListedEnchantments.isEmpty()) { return whiteListedEnchantments.contains(enchantment); - } else if(blackListedEnchantments != null && !blackListedEnchantments.isEmpty()) { + } else if (blackListedEnchantments != null && !blackListedEnchantments.isEmpty()) { return !blackListedEnchantments.contains(enchantment); } else { return true; diff --git a/src/main/java/com/gmail/nossr50/datatypes/treasure/Rarity.java b/src/main/java/com/gmail/nossr50/datatypes/treasure/Rarity.java index 4666b32b1..f21cda3b8 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/treasure/Rarity.java +++ b/src/main/java/com/gmail/nossr50/datatypes/treasure/Rarity.java @@ -12,14 +12,14 @@ public enum Rarity { COMMON; public static @NotNull Rarity getRarity(@NotNull String string) { - if(string.equalsIgnoreCase("Records")) { - mcMMO.p.getLogger().severe("Entries in fishing treasures have Records set as rarity, however Records was renamed to Mythic. Please update your treasures to read MYTHIC instead of RECORDS for rarity, or delete the config file to regenerate a new one."); + if (string.equalsIgnoreCase("Records")) { + mcMMO.p.getLogger() + .severe("Entries in fishing treasures have Records set as rarity, however Records was renamed to Mythic. Please update your treasures to read MYTHIC instead of RECORDS for rarity, or delete the config file to regenerate a new one."); return Rarity.MYTHIC; //People that copy paste their configs will have Records interpretted as Mythic } try { return valueOf(string); - } - catch (IllegalArgumentException ex) { + } catch (IllegalArgumentException ex) { return COMMON; } } 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 013849de2..cc1660548 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/treasure/Treasure.java +++ b/src/main/java/com/gmail/nossr50/datatypes/treasure/Treasure.java @@ -1,25 +1,34 @@ package com.gmail.nossr50.datatypes.treasure; +import com.gmail.nossr50.util.random.Probability; +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 = Probability.ofPercent(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; } @@ -35,8 +44,9 @@ public abstract class Treasure { return dropChance; } - public void setDropChance(Double dropChance) { + public void setDropChance(double dropChance) { this.dropChance = dropChance; + this.dropProbability = Probability.ofPercent(dropChance); } public int getDropLevel() { @@ -46,4 +56,34 @@ public abstract class Treasure { 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/events/McMMOReplaceVanillaTreasureEvent.java b/src/main/java/com/gmail/nossr50/events/McMMOReplaceVanillaTreasureEvent.java index 6553bf1c1..80aa0a2f2 100644 --- a/src/main/java/com/gmail/nossr50/events/McMMOReplaceVanillaTreasureEvent.java +++ b/src/main/java/com/gmail/nossr50/events/McMMOReplaceVanillaTreasureEvent.java @@ -1,21 +1,33 @@ package com.gmail.nossr50.events; import org.bukkit.entity.Item; +import org.bukkit.entity.Player; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; public class McMMOReplaceVanillaTreasureEvent extends Event { private @NotNull ItemStack replacementItemStack; private final @NotNull Item originalItem; + private final @Nullable Player causingPlayer; - public McMMOReplaceVanillaTreasureEvent(@NotNull Item originalItem, @NotNull ItemStack replacementItemStack) { - this.originalItem = originalItem; - this.replacementItemStack = replacementItemStack; + public McMMOReplaceVanillaTreasureEvent(@NotNull Item originalItem, + @NotNull ItemStack replacementItemStack) { + this(originalItem, replacementItemStack, null); } - /** Rest of file is required boilerplate for custom events **/ + public McMMOReplaceVanillaTreasureEvent(@NotNull Item originalItem, + @NotNull ItemStack replacementItemStack, @Nullable Player causingPlayer) { + this.originalItem = originalItem; + this.replacementItemStack = replacementItemStack; + this.causingPlayer = causingPlayer; + } + + /** + * Rest of file is required boilerplate for custom events + **/ private static final @NotNull HandlerList handlers = new HandlerList(); @Override @@ -31,6 +43,10 @@ public class McMMOReplaceVanillaTreasureEvent extends Event { return replacementItemStack; } + public @Nullable Player getCausingPlayer() { + return causingPlayer; + } + public void setReplacementItemStack(@NotNull ItemStack replacementItemStack) { this.replacementItemStack = replacementItemStack; } diff --git a/src/main/java/com/gmail/nossr50/events/chat/McMMOAdminChatEvent.java b/src/main/java/com/gmail/nossr50/events/chat/McMMOAdminChatEvent.java index 921fdd7fa..190df18ee 100644 --- a/src/main/java/com/gmail/nossr50/events/chat/McMMOAdminChatEvent.java +++ b/src/main/java/com/gmail/nossr50/events/chat/McMMOAdminChatEvent.java @@ -8,7 +8,8 @@ import org.jetbrains.annotations.NotNull; * Called when a chat is sent to the admin chat channel */ public class McMMOAdminChatEvent extends McMMOChatEvent { - public McMMOAdminChatEvent(@NotNull Plugin plugin, @NotNull AbstractChatMessage chatMessage, boolean isAsync) { + public McMMOAdminChatEvent(@NotNull Plugin plugin, @NotNull AbstractChatMessage chatMessage, + boolean isAsync) { super(plugin, chatMessage, isAsync); } } diff --git a/src/main/java/com/gmail/nossr50/events/chat/McMMOChatEvent.java b/src/main/java/com/gmail/nossr50/events/chat/McMMOChatEvent.java index 5f9980398..85b8e677d 100644 --- a/src/main/java/com/gmail/nossr50/events/chat/McMMOChatEvent.java +++ b/src/main/java/com/gmail/nossr50/events/chat/McMMOChatEvent.java @@ -18,7 +18,8 @@ public abstract class McMMOChatEvent extends Event implements Cancellable { protected final @NotNull Plugin plugin; protected final @NotNull AbstractChatMessage chatMessage; - protected McMMOChatEvent(@NotNull Plugin plugin, @NotNull AbstractChatMessage chatMessage, boolean isAsync) { + protected McMMOChatEvent(@NotNull Plugin plugin, @NotNull AbstractChatMessage chatMessage, + boolean isAsync) { super(isAsync); this.plugin = plugin; this.chatMessage = chatMessage; @@ -59,8 +60,9 @@ public abstract class McMMOChatEvent extends Event implements Cancellable { } /** - * The name of the author - * Will return the display name if mcMMO chat config is set to, otherwise returns the players Mojang registered nickname + * The name of the author Will return the display name if mcMMO chat config is set to, otherwise + * returns the players Mojang registered nickname + * * @return the author's name */ public @NotNull String getDisplayName(ChatChannel chatChannel) { @@ -79,8 +81,7 @@ public abstract class McMMOChatEvent extends Event implements Cancellable { } /** - * The original message typed by the player before any formatting - * The raw message is immutable + * The original message typed by the player before any formatting The raw message is immutable * * @return the message as it was typed by the player, this is before any formatting */ @@ -89,7 +90,8 @@ public abstract class McMMOChatEvent extends Event implements Cancellable { } /** - * The {@link TextComponent} as it will be sent to all players which should include formatting such as adding chat prefixes, player names, etc + * The {@link TextComponent} as it will be sent to all players which should include formatting + * such as adding chat prefixes, player names, etc * * @return the message that will be sent to the {@link Audience} */ @@ -98,7 +100,8 @@ public abstract class McMMOChatEvent extends Event implements Cancellable { } /** - * This will be the final message sent to the audience, this should be the message after its been formatted and has had player names added to it etc + * This will be the final message sent to the audience, this should be the message after its + * been formatted and has had player names added to it etc * * @param chatMessage the new chat message */ @@ -108,7 +111,6 @@ public abstract class McMMOChatEvent extends Event implements Cancellable { /** * @param message Adjusts the final message sent to players in the party - * * @deprecated use {{@link #setMessagePayload(TextComponent)}} */ @Deprecated @@ -116,7 +118,9 @@ public abstract class McMMOChatEvent extends Event implements Cancellable { chatMessage.setChatMessage(Component.text(message)); } - /** Following are required for Cancellable **/ + /** + * Following are required for Cancellable + **/ @Override public boolean isCancelled() { return cancelled; @@ -127,7 +131,9 @@ public abstract class McMMOChatEvent extends Event implements Cancellable { this.cancelled = cancelled; } - /** Rest of file is required boilerplate for custom events **/ + /** + * Rest of file is required boilerplate for custom events + **/ private static final @NotNull HandlerList handlers = new HandlerList(); @Override @@ -141,6 +147,7 @@ public abstract class McMMOChatEvent extends Event implements Cancellable { /** * The {@link ChatMessage} + * * @return the chat message */ public @NotNull ChatMessage getChatMessage() { diff --git a/src/main/java/com/gmail/nossr50/events/chat/McMMOPartyChatEvent.java b/src/main/java/com/gmail/nossr50/events/chat/McMMOPartyChatEvent.java index 1f00c6763..46d897014 100644 --- a/src/main/java/com/gmail/nossr50/events/chat/McMMOPartyChatEvent.java +++ b/src/main/java/com/gmail/nossr50/events/chat/McMMOPartyChatEvent.java @@ -12,7 +12,8 @@ public class McMMOPartyChatEvent extends McMMOChatEvent { private final @NotNull String party; //Not going to break the API to rename this for now private final @NotNull Party targetParty; - public McMMOPartyChatEvent(@NotNull Plugin pluginRef, @NotNull PartyChatMessage chatMessage, @NotNull Party party, boolean isAsync) { + public McMMOPartyChatEvent(@NotNull Plugin pluginRef, @NotNull PartyChatMessage chatMessage, + @NotNull Party party, boolean isAsync) { super(pluginRef, chatMessage, isAsync); this.party = party.getName(); this.targetParty = party; @@ -20,7 +21,6 @@ public class McMMOPartyChatEvent extends McMMOChatEvent { /** * @return String name of the party the message will be sent to - * * @deprecated this will be removed in the future */ @Deprecated diff --git a/src/main/java/com/gmail/nossr50/events/experience/McMMOPlayerExperienceEvent.java b/src/main/java/com/gmail/nossr50/events/experience/McMMOPlayerExperienceEvent.java index 44ad7d078..fc84e7884 100644 --- a/src/main/java/com/gmail/nossr50/events/experience/McMMOPlayerExperienceEvent.java +++ b/src/main/java/com/gmail/nossr50/events/experience/McMMOPlayerExperienceEvent.java @@ -26,11 +26,12 @@ public abstract class McMMOPlayerExperienceEvent extends PlayerEvent implements this.xpGainReason = XPGainReason.UNKNOWN; } - protected McMMOPlayerExperienceEvent(Player player, PrimarySkillType skill, XPGainReason xpGainReason) { + protected McMMOPlayerExperienceEvent(Player player, PrimarySkillType skill, + XPGainReason xpGainReason) { super(player); this.skill = skill; - if(UserManager.getPlayer(player) != null) { + if (UserManager.getPlayer(player) != null) { this.skillLevel = UserManager.getPlayer(player).getSkillLevel(skill); } else { this.skillLevel = 0; @@ -60,7 +61,9 @@ public abstract class McMMOPlayerExperienceEvent extends PlayerEvent implements return xpGainReason; } - /** Following are required for Cancellable **/ + /** + * Following are required for Cancellable + **/ @Override public boolean isCancelled() { return cancelled; @@ -70,7 +73,7 @@ public abstract class McMMOPlayerExperienceEvent extends PlayerEvent implements public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } - + private static final HandlerList handlers = new HandlerList(); @Override diff --git a/src/main/java/com/gmail/nossr50/events/experience/McMMOPlayerLevelChangeEvent.java b/src/main/java/com/gmail/nossr50/events/experience/McMMOPlayerLevelChangeEvent.java index bf23d4443..8b0dc62da 100644 --- a/src/main/java/com/gmail/nossr50/events/experience/McMMOPlayerLevelChangeEvent.java +++ b/src/main/java/com/gmail/nossr50/events/experience/McMMOPlayerLevelChangeEvent.java @@ -13,7 +13,8 @@ public abstract class McMMOPlayerLevelChangeEvent extends McMMOPlayerExperienceE super(player, skill, XPGainReason.UNKNOWN); } - public McMMOPlayerLevelChangeEvent(Player player, PrimarySkillType skill, XPGainReason xpGainReason) { + public McMMOPlayerLevelChangeEvent(Player player, PrimarySkillType skill, + XPGainReason xpGainReason) { super(player, skill, xpGainReason); } } diff --git a/src/main/java/com/gmail/nossr50/events/experience/McMMOPlayerLevelDownEvent.java b/src/main/java/com/gmail/nossr50/events/experience/McMMOPlayerLevelDownEvent.java index 6e512b338..01a5530aa 100644 --- a/src/main/java/com/gmail/nossr50/events/experience/McMMOPlayerLevelDownEvent.java +++ b/src/main/java/com/gmail/nossr50/events/experience/McMMOPlayerLevelDownEvent.java @@ -24,12 +24,14 @@ public class McMMOPlayerLevelDownEvent extends McMMOPlayerLevelChangeEvent { this.levelsLost = levelsLost; } - public McMMOPlayerLevelDownEvent(Player player, PrimarySkillType skill, XPGainReason xpGainReason) { + public McMMOPlayerLevelDownEvent(Player player, PrimarySkillType skill, + XPGainReason xpGainReason) { super(player, skill, xpGainReason); this.levelsLost = 1; } - public McMMOPlayerLevelDownEvent(Player player, PrimarySkillType skill, int levelsLost, XPGainReason xpGainReason) { + public McMMOPlayerLevelDownEvent(Player player, PrimarySkillType skill, int levelsLost, + XPGainReason xpGainReason) { super(player, skill, xpGainReason); this.levelsLost = levelsLost; } diff --git a/src/main/java/com/gmail/nossr50/events/experience/McMMOPlayerLevelUpEvent.java b/src/main/java/com/gmail/nossr50/events/experience/McMMOPlayerLevelUpEvent.java index 20badcf7c..ed269e41c 100644 --- a/src/main/java/com/gmail/nossr50/events/experience/McMMOPlayerLevelUpEvent.java +++ b/src/main/java/com/gmail/nossr50/events/experience/McMMOPlayerLevelUpEvent.java @@ -24,12 +24,14 @@ public class McMMOPlayerLevelUpEvent extends McMMOPlayerLevelChangeEvent { this.levelsGained = levelsGained; } - public McMMOPlayerLevelUpEvent(Player player, PrimarySkillType skill, XPGainReason xpGainReason) { + public McMMOPlayerLevelUpEvent(Player player, PrimarySkillType skill, + XPGainReason xpGainReason) { super(player, skill, xpGainReason); this.levelsGained = 1; } - public McMMOPlayerLevelUpEvent(Player player, PrimarySkillType skill, int levelsGained, XPGainReason xpGainReason) { + public McMMOPlayerLevelUpEvent(Player player, PrimarySkillType skill, int levelsGained, + XPGainReason xpGainReason) { super(player, skill, xpGainReason); this.levelsGained = levelsGained; } diff --git a/src/main/java/com/gmail/nossr50/events/experience/McMMOPlayerPreXpGainEvent.java b/src/main/java/com/gmail/nossr50/events/experience/McMMOPlayerPreXpGainEvent.java index 849d7ab48..a9eb3505b 100644 --- a/src/main/java/com/gmail/nossr50/events/experience/McMMOPlayerPreXpGainEvent.java +++ b/src/main/java/com/gmail/nossr50/events/experience/McMMOPlayerPreXpGainEvent.java @@ -18,7 +18,8 @@ public class McMMOPlayerPreXpGainEvent extends McMMOPlayerExperienceEvent { this.xpGained = xpGained; } - public McMMOPlayerPreXpGainEvent(Player player, PrimarySkillType skill, float xpGained, XPGainReason xpGainReason) { + public McMMOPlayerPreXpGainEvent(Player player, PrimarySkillType skill, float xpGained, + XPGainReason xpGainReason) { super(player, skill, xpGainReason); this.xpGained = xpGained; } diff --git a/src/main/java/com/gmail/nossr50/events/experience/McMMOPlayerXpGainEvent.java b/src/main/java/com/gmail/nossr50/events/experience/McMMOPlayerXpGainEvent.java index 5cd0c73fa..1cfcef292 100644 --- a/src/main/java/com/gmail/nossr50/events/experience/McMMOPlayerXpGainEvent.java +++ b/src/main/java/com/gmail/nossr50/events/experience/McMMOPlayerXpGainEvent.java @@ -18,7 +18,8 @@ public class McMMOPlayerXpGainEvent extends McMMOPlayerExperienceEvent { this.xpGained = xpGained; } - public McMMOPlayerXpGainEvent(Player player, PrimarySkillType skill, float xpGained, XPGainReason xpGainReason) { + public McMMOPlayerXpGainEvent(Player player, PrimarySkillType skill, float xpGained, + XPGainReason xpGainReason) { super(player, skill, xpGainReason); this.xpGained = xpGained; } diff --git a/src/main/java/com/gmail/nossr50/events/fake/FakeBlockDamageEvent.java b/src/main/java/com/gmail/nossr50/events/fake/FakeBlockDamageEvent.java index 0e32ce00c..d756a5653 100644 --- a/src/main/java/com/gmail/nossr50/events/fake/FakeBlockDamageEvent.java +++ b/src/main/java/com/gmail/nossr50/events/fake/FakeBlockDamageEvent.java @@ -9,7 +9,8 @@ import org.bukkit.inventory.ItemStack; * Called when mcMMO damages a block due to a special ability. */ public class FakeBlockDamageEvent extends BlockDamageEvent implements FakeEvent { - public FakeBlockDamageEvent(Player player, Block block, ItemStack itemInHand, boolean instaBreak) { + public FakeBlockDamageEvent(Player player, Block block, ItemStack itemInHand, + boolean instaBreak) { super(player, block, itemInHand, instaBreak); } } diff --git a/src/main/java/com/gmail/nossr50/events/fake/FakeBrewEvent.java b/src/main/java/com/gmail/nossr50/events/fake/FakeBrewEvent.java index ea44f355a..4ba86c465 100644 --- a/src/main/java/com/gmail/nossr50/events/fake/FakeBrewEvent.java +++ b/src/main/java/com/gmail/nossr50/events/fake/FakeBrewEvent.java @@ -1,14 +1,14 @@ package com.gmail.nossr50.events.fake; +import java.util.List; import org.bukkit.block.Block; import org.bukkit.event.inventory.BrewEvent; import org.bukkit.inventory.BrewerInventory; import org.bukkit.inventory.ItemStack; -import java.util.List; - public class FakeBrewEvent extends BrewEvent implements FakeEvent { - public FakeBrewEvent(Block brewer, BrewerInventory contents, List results, int fuelLevel) { + public FakeBrewEvent(Block brewer, BrewerInventory contents, List results, + int fuelLevel) { super(brewer, contents, results, fuelLevel); } } diff --git a/src/main/java/com/gmail/nossr50/events/fake/FakeEvent.java b/src/main/java/com/gmail/nossr50/events/fake/FakeEvent.java index 62e989326..b15fed073 100644 --- a/src/main/java/com/gmail/nossr50/events/fake/FakeEvent.java +++ b/src/main/java/com/gmail/nossr50/events/fake/FakeEvent.java @@ -3,9 +3,8 @@ package com.gmail.nossr50.events.fake; import org.bukkit.event.Event; /** - * This interface marks an {@link Event} as "fake". - * This is just a handy way of checking if an {@link Event} is fake or not, maybe there - * will be methods suitable for this in the future. - * + * This interface marks an {@link Event} as "fake". This is just a handy way of checking if an + * {@link Event} is fake or not, maybe there will be methods suitable for this in the future. */ -public interface FakeEvent {} +public interface FakeEvent { +} diff --git a/src/main/java/com/gmail/nossr50/events/fake/FakePlayerAnimationEvent.java b/src/main/java/com/gmail/nossr50/events/fake/FakePlayerAnimationEvent.java index e4eb1ec88..ce89f20e1 100644 --- a/src/main/java/com/gmail/nossr50/events/fake/FakePlayerAnimationEvent.java +++ b/src/main/java/com/gmail/nossr50/events/fake/FakePlayerAnimationEvent.java @@ -4,7 +4,7 @@ //import org.bukkit.event.player.PlayerAnimationEvent; //import org.bukkit.event.player.PlayerAnimationType; // -///** +/// ** // * Called when handling extra drops to avoid issues with NoCheat. // */ //public class FakePlayerAnimationEvent extends PlayerAnimationEvent implements FakeEvent { diff --git a/src/main/java/com/gmail/nossr50/events/hardcore/McMMOPlayerDeathPenaltyEvent.java b/src/main/java/com/gmail/nossr50/events/hardcore/McMMOPlayerDeathPenaltyEvent.java index 7c4d3f08a..77814aa37 100644 --- a/src/main/java/com/gmail/nossr50/events/hardcore/McMMOPlayerDeathPenaltyEvent.java +++ b/src/main/java/com/gmail/nossr50/events/hardcore/McMMOPlayerDeathPenaltyEvent.java @@ -1,20 +1,20 @@ package com.gmail.nossr50.events.hardcore; +import java.util.HashMap; import org.bukkit.entity.Player; import org.bukkit.event.Cancellable; import org.bukkit.event.HandlerList; import org.bukkit.event.player.PlayerEvent; import org.jetbrains.annotations.NotNull; -import java.util.HashMap; - public class McMMOPlayerDeathPenaltyEvent extends PlayerEvent implements Cancellable { private HashMap levelChanged; private HashMap experienceChanged; private boolean cancelled; - public McMMOPlayerDeathPenaltyEvent(Player player, HashMap levelChanged, HashMap experienceChanged) { + public McMMOPlayerDeathPenaltyEvent(Player player, HashMap levelChanged, + HashMap experienceChanged) { super(player); this.levelChanged = levelChanged; this.experienceChanged = experienceChanged; @@ -43,7 +43,9 @@ public class McMMOPlayerDeathPenaltyEvent extends PlayerEvent implements Cancell this.experienceChanged = experienceChanged; } - /** Following are required for Cancellable **/ + /** + * Following are required for Cancellable + **/ @Override public boolean isCancelled() { return cancelled; @@ -54,7 +56,9 @@ public class McMMOPlayerDeathPenaltyEvent extends PlayerEvent implements Cancell this.cancelled = cancelled; } - /** Rest of file is required boilerplate for custom events **/ + /** + * Rest of file is required boilerplate for custom events + **/ private static final HandlerList handlers = new HandlerList(); @Override diff --git a/src/main/java/com/gmail/nossr50/events/hardcore/McMMOPlayerPreDeathPenaltyEvent.java b/src/main/java/com/gmail/nossr50/events/hardcore/McMMOPlayerPreDeathPenaltyEvent.java index 7bf355da0..5c7301cba 100644 --- a/src/main/java/com/gmail/nossr50/events/hardcore/McMMOPlayerPreDeathPenaltyEvent.java +++ b/src/main/java/com/gmail/nossr50/events/hardcore/McMMOPlayerPreDeathPenaltyEvent.java @@ -14,7 +14,9 @@ public class McMMOPlayerPreDeathPenaltyEvent extends PlayerEvent implements Canc this.cancelled = false; } - /** Following are required for Cancellable **/ + /** + * Following are required for Cancellable + **/ @Override public boolean isCancelled() { return cancelled; @@ -25,7 +27,9 @@ public class McMMOPlayerPreDeathPenaltyEvent extends PlayerEvent implements Canc this.cancelled = cancelled; } - /** Rest of file is required boilerplate for custom events **/ + /** + * Rest of file is required boilerplate for custom events + **/ private static final HandlerList handlers = new HandlerList(); @Override diff --git a/src/main/java/com/gmail/nossr50/events/hardcore/McMMOPlayerStatLossEvent.java b/src/main/java/com/gmail/nossr50/events/hardcore/McMMOPlayerStatLossEvent.java index 414ffdac5..e204b1014 100644 --- a/src/main/java/com/gmail/nossr50/events/hardcore/McMMOPlayerStatLossEvent.java +++ b/src/main/java/com/gmail/nossr50/events/hardcore/McMMOPlayerStatLossEvent.java @@ -1,12 +1,12 @@ package com.gmail.nossr50.events.hardcore; -import org.bukkit.entity.Player; - import java.util.HashMap; +import org.bukkit.entity.Player; public class McMMOPlayerStatLossEvent extends McMMOPlayerDeathPenaltyEvent { - public McMMOPlayerStatLossEvent(Player player, HashMap levelChanged, HashMap experienceChanged) { + public McMMOPlayerStatLossEvent(Player player, HashMap levelChanged, + HashMap experienceChanged) { super(player, levelChanged, experienceChanged); } } diff --git a/src/main/java/com/gmail/nossr50/events/hardcore/McMMOPlayerVampirismEvent.java b/src/main/java/com/gmail/nossr50/events/hardcore/McMMOPlayerVampirismEvent.java index 8aa59d521..3f42a7148 100644 --- a/src/main/java/com/gmail/nossr50/events/hardcore/McMMOPlayerVampirismEvent.java +++ b/src/main/java/com/gmail/nossr50/events/hardcore/McMMOPlayerVampirismEvent.java @@ -1,13 +1,13 @@ package com.gmail.nossr50.events.hardcore; -import org.bukkit.entity.Player; - import java.util.HashMap; +import org.bukkit.entity.Player; public class McMMOPlayerVampirismEvent extends McMMOPlayerDeathPenaltyEvent { private final boolean isVictim; - public McMMOPlayerVampirismEvent(Player player, boolean isVictim, HashMap levelChanged, HashMap experienceChanged) { + public McMMOPlayerVampirismEvent(Player player, boolean isVictim, + HashMap levelChanged, HashMap experienceChanged) { super(player, levelChanged, experienceChanged); this.isVictim = isVictim; } diff --git a/src/main/java/com/gmail/nossr50/events/items/McMMOItemSpawnEvent.java b/src/main/java/com/gmail/nossr50/events/items/McMMOItemSpawnEvent.java index 1249476d4..f333da5b0 100644 --- a/src/main/java/com/gmail/nossr50/events/items/McMMOItemSpawnEvent.java +++ b/src/main/java/com/gmail/nossr50/events/items/McMMOItemSpawnEvent.java @@ -20,7 +20,8 @@ public class McMMOItemSpawnEvent extends Event implements Cancellable { private final ItemSpawnReason itemSpawnReason; private final Player player; - public McMMOItemSpawnEvent(@NotNull Location location, @NotNull ItemStack itemStack, @NotNull ItemSpawnReason itemSpawnReason, @Nullable Player player) { + public McMMOItemSpawnEvent(@NotNull Location location, @NotNull ItemStack itemStack, + @NotNull ItemSpawnReason itemSpawnReason, @Nullable Player player) { this.location = location; this.itemStack = itemStack; this.itemSpawnReason = itemSpawnReason; @@ -29,8 +30,8 @@ public class McMMOItemSpawnEvent extends Event implements Cancellable { } /** - * Get the associated player - * This can be null + * Get the associated player This can be null + * * @return the associated player if one exists null otherwise */ public @Nullable Player getPlayer() { @@ -39,8 +40,9 @@ public class McMMOItemSpawnEvent extends Event implements Cancellable { /** * The reason an item is being spawned by mcMMO - * @see ItemSpawnReason + * * @return the item drop reason + * @see ItemSpawnReason */ public ItemSpawnReason getItemSpawnReason() { return itemSpawnReason; @@ -74,7 +76,9 @@ public class McMMOItemSpawnEvent extends Event implements Cancellable { this.itemStack = itemStack; } - /** Following are required for Cancellable **/ + /** + * Following are required for Cancellable + **/ @Override public boolean isCancelled() { return cancelled; @@ -85,7 +89,9 @@ public class McMMOItemSpawnEvent extends Event implements Cancellable { this.cancelled = cancelled; } - /** Rest of file is required boilerplate for custom events **/ + /** + * Rest of file is required boilerplate for custom events + **/ private static final @NotNull HandlerList handlers = new HandlerList(); @Override diff --git a/src/main/java/com/gmail/nossr50/events/party/McMMOPartyAllianceChangeEvent.java b/src/main/java/com/gmail/nossr50/events/party/McMMOPartyAllianceChangeEvent.java index 68fc2db6f..1d8fdd7d9 100644 --- a/src/main/java/com/gmail/nossr50/events/party/McMMOPartyAllianceChangeEvent.java +++ b/src/main/java/com/gmail/nossr50/events/party/McMMOPartyAllianceChangeEvent.java @@ -12,7 +12,8 @@ public class McMMOPartyAllianceChangeEvent extends PlayerEvent implements Cancel private final EventReason reason; private boolean cancelled; - public McMMOPartyAllianceChangeEvent(Player player, String oldAlly, String newAlly, EventReason reason) { + public McMMOPartyAllianceChangeEvent(Player player, String oldAlly, String newAlly, + EventReason reason) { super(player); if (newAlly != null) { @@ -66,7 +67,9 @@ public class McMMOPartyAllianceChangeEvent extends PlayerEvent implements Cancel CUSTOM } - /** Following are required for Cancellable **/ + /** + * Following are required for Cancellable + **/ @Override public boolean isCancelled() { return cancelled; @@ -77,7 +80,9 @@ public class McMMOPartyAllianceChangeEvent extends PlayerEvent implements Cancel this.cancelled = cancelled; } - /** Rest of file is required boilerplate for custom events **/ + /** + * Rest of file is required boilerplate for custom events + **/ private static final HandlerList handlers = new HandlerList(); @Override diff --git a/src/main/java/com/gmail/nossr50/events/party/McMMOPartyChangeEvent.java b/src/main/java/com/gmail/nossr50/events/party/McMMOPartyChangeEvent.java index 1f9b30696..46f0e6365 100644 --- a/src/main/java/com/gmail/nossr50/events/party/McMMOPartyChangeEvent.java +++ b/src/main/java/com/gmail/nossr50/events/party/McMMOPartyChangeEvent.java @@ -15,7 +15,8 @@ public class McMMOPartyChangeEvent extends PlayerEvent implements Cancellable { private final EventReason reason; private boolean cancelled; - public McMMOPartyChangeEvent(Player player, String oldParty, String newParty, EventReason reason) { + public McMMOPartyChangeEvent(Player player, String oldParty, String newParty, + EventReason reason) { super(player); if (newParty != null) { @@ -89,7 +90,9 @@ public class McMMOPartyChangeEvent extends PlayerEvent implements Cancellable { CUSTOM } - /** Following are required for Cancellable **/ + /** + * Following are required for Cancellable + **/ @Override public boolean isCancelled() { return cancelled; @@ -100,7 +103,9 @@ public class McMMOPartyChangeEvent extends PlayerEvent implements Cancellable { this.cancelled = cancelled; } - /** Rest of file is required boilerplate for custom events **/ + /** + * Rest of file is required boilerplate for custom events + **/ private static final HandlerList handlers = new HandlerList(); @Override diff --git a/src/main/java/com/gmail/nossr50/events/party/McMMOPartyLevelUpEvent.java b/src/main/java/com/gmail/nossr50/events/party/McMMOPartyLevelUpEvent.java index ed42bf028..e676d18aa 100644 --- a/src/main/java/com/gmail/nossr50/events/party/McMMOPartyLevelUpEvent.java +++ b/src/main/java/com/gmail/nossr50/events/party/McMMOPartyLevelUpEvent.java @@ -29,7 +29,9 @@ public class McMMOPartyLevelUpEvent extends Event implements Cancellable { this.levelsChanged = levelsChanged; } - /** Following are required for Cancellable **/ + /** + * Following are required for Cancellable + **/ @Override public boolean isCancelled() { return cancelled; @@ -40,7 +42,9 @@ public class McMMOPartyLevelUpEvent extends Event implements Cancellable { this.cancelled = cancelled; } - /** Rest of file is required boilerplate for custom events **/ + /** + * Rest of file is required boilerplate for custom events + **/ private static final HandlerList handlers = new HandlerList(); @Override diff --git a/src/main/java/com/gmail/nossr50/events/party/McMMOPartyTeleportEvent.java b/src/main/java/com/gmail/nossr50/events/party/McMMOPartyTeleportEvent.java index 322833de1..0e2e108b2 100644 --- a/src/main/java/com/gmail/nossr50/events/party/McMMOPartyTeleportEvent.java +++ b/src/main/java/com/gmail/nossr50/events/party/McMMOPartyTeleportEvent.java @@ -32,7 +32,9 @@ public class McMMOPartyTeleportEvent extends PlayerTeleportEvent { return target; } - /** Rest of file is required boilerplate for custom events **/ + /** + * Rest of file is required boilerplate for custom events + **/ private static final HandlerList handlers = new HandlerList(); @Override diff --git a/src/main/java/com/gmail/nossr50/events/party/McMMOPartyXpGainEvent.java b/src/main/java/com/gmail/nossr50/events/party/McMMOPartyXpGainEvent.java index 926588dcc..1d6b7cce7 100644 --- a/src/main/java/com/gmail/nossr50/events/party/McMMOPartyXpGainEvent.java +++ b/src/main/java/com/gmail/nossr50/events/party/McMMOPartyXpGainEvent.java @@ -51,7 +51,9 @@ public class McMMOPartyXpGainEvent extends Event implements Cancellable { this.xpGained = xpGained; } - /** Following are required for Cancellable **/ + /** + * Following are required for Cancellable + **/ @Override public boolean isCancelled() { return cancelled; @@ -62,7 +64,9 @@ public class McMMOPartyXpGainEvent extends Event implements Cancellable { this.cancelled = cancelled; } - /** Rest of file is required boilerplate for custom events **/ + /** + * Rest of file is required boilerplate for custom events + **/ private static final HandlerList handlers = new HandlerList(); @Override diff --git a/src/main/java/com/gmail/nossr50/events/players/McMMOPlayerProfileLoadEvent.java b/src/main/java/com/gmail/nossr50/events/players/McMMOPlayerProfileLoadEvent.java index c16a520a8..84347fb66 100644 --- a/src/main/java/com/gmail/nossr50/events/players/McMMOPlayerProfileLoadEvent.java +++ b/src/main/java/com/gmail/nossr50/events/players/McMMOPlayerProfileLoadEvent.java @@ -12,13 +12,15 @@ public class McMMOPlayerProfileLoadEvent extends Event implements Cancellable { private boolean cancelled; private final PlayerProfile profile; private final Player player; - public McMMOPlayerProfileLoadEvent(Player player, PlayerProfile profile){ + + public McMMOPlayerProfileLoadEvent(Player player, PlayerProfile profile) { super(!Bukkit.isPrimaryThread()); this.cancelled = false; this.profile = profile; this.player = player; } + @Override public boolean isCancelled() { return this.cancelled; @@ -29,7 +31,10 @@ public class McMMOPlayerProfileLoadEvent extends Event implements Cancellable { this.cancelled = cancelled; } - public PlayerProfile getProfile(){return this.profile;} + public PlayerProfile getProfile() { + return this.profile; + } + private static final HandlerList handlers = new HandlerList(); @Override @@ -41,5 +46,7 @@ public class McMMOPlayerProfileLoadEvent extends Event implements Cancellable { return handlers; } - public Player getPlayer() {return player;} + public Player getPlayer() { + return player; + } } diff --git a/src/main/java/com/gmail/nossr50/events/scoreboard/McMMOScoreboardEvent.java b/src/main/java/com/gmail/nossr50/events/scoreboard/McMMOScoreboardEvent.java index e03a8a4f7..249edd304 100644 --- a/src/main/java/com/gmail/nossr50/events/scoreboard/McMMOScoreboardEvent.java +++ b/src/main/java/com/gmail/nossr50/events/scoreboard/McMMOScoreboardEvent.java @@ -7,8 +7,7 @@ import org.bukkit.scoreboard.Scoreboard; import org.jetbrains.annotations.NotNull; /** - * The parent class of all mcMMO scoreboard events - * All scoreboard events will extend from this + * The parent class of all mcMMO scoreboard events All scoreboard events will extend from this */ abstract public class McMMOScoreboardEvent extends Event { @@ -18,8 +17,8 @@ abstract public class McMMOScoreboardEvent extends Event { private final ScoreboardEventReason scoreboardEventReason; - public McMMOScoreboardEvent(Scoreboard targetBoard, Scoreboard currentBoard, Player targetPlayer, ScoreboardEventReason scoreboardEventReason) - { + public McMMOScoreboardEvent(Scoreboard targetBoard, Scoreboard currentBoard, + Player targetPlayer, ScoreboardEventReason scoreboardEventReason) { this.scoreboardEventReason = scoreboardEventReason; this.targetBoard = targetBoard; this.currentBoard = currentBoard; @@ -30,6 +29,7 @@ abstract public class McMMOScoreboardEvent extends Event { /** * This is the scoreboard the player will be assigned to after this event + * * @return the target board to assign the player after this event fires */ public Scoreboard getTargetBoard() { @@ -38,6 +38,7 @@ abstract public class McMMOScoreboardEvent extends Event { /** * Change the scoreboard that the player will be assigned to after this event fires + * * @param targetBoard the new board to assign the player to */ public void setTargetBoard(Scoreboard targetBoard) { @@ -46,6 +47,7 @@ abstract public class McMMOScoreboardEvent extends Event { /** * The player involved in this event (this can be changed) + * * @return the player involved in this event */ public Player getTargetPlayer() { @@ -55,6 +57,7 @@ abstract public class McMMOScoreboardEvent extends Event { /** * This is the scoreboard the player is currently assigned to at the time the event was fired * Grabbed via player.getScoreboard() + * * @return players current scoreboard */ public Scoreboard getCurrentBoard() { @@ -63,6 +66,7 @@ abstract public class McMMOScoreboardEvent extends Event { /** * The ENUM defining the reason for this event + * * @return the reason for this event */ public ScoreboardEventReason getScoreboardEventReason() { @@ -71,13 +75,16 @@ abstract public class McMMOScoreboardEvent extends Event { /** * Change the target player for this event + * * @param targetPlayer the new target for this event */ public void setTargetPlayer(Player targetPlayer) { this.targetPlayer = targetPlayer; } - /** Rest of file is required boilerplate for custom events **/ + /** + * Rest of file is required boilerplate for custom events + **/ private static final HandlerList handlers = new HandlerList(); @Override diff --git a/src/main/java/com/gmail/nossr50/events/scoreboard/McMMOScoreboardMakeboardEvent.java b/src/main/java/com/gmail/nossr50/events/scoreboard/McMMOScoreboardMakeboardEvent.java index 8418e0ad8..63f3a4e83 100644 --- a/src/main/java/com/gmail/nossr50/events/scoreboard/McMMOScoreboardMakeboardEvent.java +++ b/src/main/java/com/gmail/nossr50/events/scoreboard/McMMOScoreboardMakeboardEvent.java @@ -4,12 +4,13 @@ import org.bukkit.entity.Player; import org.bukkit.scoreboard.Scoreboard; /** - * This event is called when mcMMO creates its custom boards - * You should not interfere with this event unless you understand our board code thoroughly - * mcMMO relies on using new scoreboards to show players individually catered boards with stats specific to them + * This event is called when mcMMO creates its custom boards You should not interfere with this + * event unless you understand our board code thoroughly mcMMO relies on using new scoreboards to + * show players individually catered boards with stats specific to them */ public class McMMOScoreboardMakeboardEvent extends McMMOScoreboardEvent { - public McMMOScoreboardMakeboardEvent(Scoreboard targetBoard, Scoreboard currentBoard, Player targetPlayer, ScoreboardEventReason scoreboardEventReason) { + public McMMOScoreboardMakeboardEvent(Scoreboard targetBoard, Scoreboard currentBoard, + Player targetPlayer, ScoreboardEventReason scoreboardEventReason) { super(targetBoard, currentBoard, targetPlayer, scoreboardEventReason); } } diff --git a/src/main/java/com/gmail/nossr50/events/scoreboard/McMMOScoreboardObjectiveEvent.java b/src/main/java/com/gmail/nossr50/events/scoreboard/McMMOScoreboardObjectiveEvent.java index 2f883f19e..bfa6d2478 100644 --- a/src/main/java/com/gmail/nossr50/events/scoreboard/McMMOScoreboardObjectiveEvent.java +++ b/src/main/java/com/gmail/nossr50/events/scoreboard/McMMOScoreboardObjectiveEvent.java @@ -11,7 +11,9 @@ public class McMMOScoreboardObjectiveEvent extends McMMOScoreboardEvent implemen protected Objective targetObjective; protected final ScoreboardObjectiveEventReason objectiveEventReason; - public McMMOScoreboardObjectiveEvent(Objective targetObjective, ScoreboardObjectiveEventReason objectiveEventReason, Scoreboard scoreboard, Scoreboard oldboard, Player targetPlayer, ScoreboardEventReason scoreboardEventReason) { + public McMMOScoreboardObjectiveEvent(Objective targetObjective, + ScoreboardObjectiveEventReason objectiveEventReason, Scoreboard scoreboard, + Scoreboard oldboard, Player targetPlayer, ScoreboardEventReason scoreboardEventReason) { super(scoreboard, oldboard, targetPlayer, scoreboardEventReason); this.objectiveEventReason = objectiveEventReason; this.targetObjective = targetObjective; @@ -20,6 +22,7 @@ public class McMMOScoreboardObjectiveEvent extends McMMOScoreboardEvent implemen /** * The objective that will be modified by this event + * * @return */ public Objective getTargetObjective() { @@ -28,6 +31,7 @@ public class McMMOScoreboardObjectiveEvent extends McMMOScoreboardEvent implemen /** * Change the target objective for this event + * * @param newObjective new target objective */ public void setTargetObjective(Objective newObjective) { diff --git a/src/main/java/com/gmail/nossr50/events/scoreboard/McMMOScoreboardRevertEvent.java b/src/main/java/com/gmail/nossr50/events/scoreboard/McMMOScoreboardRevertEvent.java index 000a19a54..0d4f0c738 100644 --- a/src/main/java/com/gmail/nossr50/events/scoreboard/McMMOScoreboardRevertEvent.java +++ b/src/main/java/com/gmail/nossr50/events/scoreboard/McMMOScoreboardRevertEvent.java @@ -4,11 +4,14 @@ import org.bukkit.entity.Player; import org.bukkit.scoreboard.Scoreboard; /** - * This event is called when mcMMO is attempting to change a players targetBoard back to their previous board - * This is used when an mcMMO board is cleared (removed from the screen), changing back from a temporary board (usually from a delayed scheduled task or our mcscoreboard time command) + * This event is called when mcMMO is attempting to change a players targetBoard back to their + * previous board This is used when an mcMMO board is cleared (removed from the screen), changing + * back from a temporary board (usually from a delayed scheduled task or our mcscoreboard time + * command) */ public class McMMOScoreboardRevertEvent extends McMMOScoreboardEvent { - public McMMOScoreboardRevertEvent(Scoreboard targetBoard, Scoreboard currentBoard, Player targetPlayer, ScoreboardEventReason scoreboardEventReason) { + public McMMOScoreboardRevertEvent(Scoreboard targetBoard, Scoreboard currentBoard, + Player targetPlayer, ScoreboardEventReason scoreboardEventReason) { super(targetBoard, currentBoard, targetPlayer, scoreboardEventReason); } } diff --git a/src/main/java/com/gmail/nossr50/events/skills/McMMOPlayerNotificationEvent.java b/src/main/java/com/gmail/nossr50/events/skills/McMMOPlayerNotificationEvent.java index 75d8eae83..5d7261d48 100644 --- a/src/main/java/com/gmail/nossr50/events/skills/McMMOPlayerNotificationEvent.java +++ b/src/main/java/com/gmail/nossr50/events/skills/McMMOPlayerNotificationEvent.java @@ -30,8 +30,8 @@ public class McMMOPlayerNotificationEvent extends Event implements Cancellable { protected final Player player; public McMMOPlayerNotificationEvent(Player player, NotificationType notificationType, - Component notificationTextComponent, McMMOMessageType chatMessageType, - boolean isMessageAlsoBeingSentToChat) { + Component notificationTextComponent, McMMOMessageType chatMessageType, + boolean isMessageAlsoBeingSentToChat) { super(false); this.player = player; this.notificationType = notificationType; @@ -75,6 +75,7 @@ public class McMMOPlayerNotificationEvent extends Event implements Cancellable { /** * The notification type for this event + * * @return this event's notification type */ public NotificationType getEventNotificationType() { 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 e899ea528..c44765b7a 100644 --- a/src/main/java/com/gmail/nossr50/events/skills/McMMOPlayerSkillEvent.java +++ b/src/main/java/com/gmail/nossr50/events/skills/McMMOPlayerSkillEvent.java @@ -1,5 +1,8 @@ package com.gmail.nossr50.events.skills; +import static java.util.Objects.requireNonNull; + +import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.util.player.UserManager; import org.bukkit.entity.Player; @@ -11,19 +14,34 @@ import org.jetbrains.annotations.NotNull; * Generic event for mcMMO skill handling. */ public abstract class McMMOPlayerSkillEvent extends PlayerEvent { - protected PrimarySkillType skill; + protected @NotNull PrimarySkillType skill; protected int skillLevel; + protected McMMOPlayer mmoPlayer; - protected McMMOPlayerSkillEvent(Player player, PrimarySkillType skill) { + @Deprecated(forRemoval = true, since = "2.2.010") + protected McMMOPlayerSkillEvent(@NotNull Player player, @NotNull PrimarySkillType skill) { super(player); + final McMMOPlayer mmoPlayer = UserManager.getPlayer(player); + requireNonNull(mmoPlayer, "Player not found in UserManager," + + "contact the dev and tell them to use the constructor for" + + " McMMOPlayerSkillEvent(McMMOPlayer, PrimarySkillType) instead"); this.skill = skill; this.skillLevel = UserManager.getPlayer(player).getSkillLevel(skill); } + protected McMMOPlayerSkillEvent(@NotNull McMMOPlayer mmoPlayer, + @NotNull PrimarySkillType primarySkillType) { + super(mmoPlayer.getPlayer()); + requireNonNull(mmoPlayer, "mmoPlayer cannot be null"); + requireNonNull(primarySkillType, "primarySkillType cannot be null"); + this.skill = primarySkillType; + this.skillLevel = mmoPlayer.getSkillLevel(primarySkillType); + } + /** * @return The skill involved in this event */ - public PrimarySkillType getSkill() { + public @NotNull PrimarySkillType getSkill() { return skill; } @@ -34,9 +52,20 @@ public abstract class McMMOPlayerSkillEvent extends PlayerEvent { return skillLevel; } - /** Rest of file is required boilerplate for custom events **/ + /** + * Rest of file is required boilerplate for custom events + **/ private static final HandlerList handlers = new HandlerList(); + /** + * Returns the {@link McMMOPlayer} associated with this event. + * + * @return The {@link McMMOPlayer} associated with this event. + */ + public @NotNull McMMOPlayer getMcMMOPlayer() { + return mmoPlayer; + } + @Override public @NotNull HandlerList getHandlers() { return handlers; diff --git a/src/main/java/com/gmail/nossr50/events/skills/SkillActivationPerkEvent.java b/src/main/java/com/gmail/nossr50/events/skills/SkillActivationPerkEvent.java index 36848e6fa..8e88147ef 100644 --- a/src/main/java/com/gmail/nossr50/events/skills/SkillActivationPerkEvent.java +++ b/src/main/java/com/gmail/nossr50/events/skills/SkillActivationPerkEvent.java @@ -9,8 +9,6 @@ import org.jetbrains.annotations.NotNull; public class SkillActivationPerkEvent extends Event { - - private static final HandlerList handlers = new HandlerList(); private final Player player; private int ticks; diff --git a/src/main/java/com/gmail/nossr50/events/skills/abilities/McMMOPlayerAbilityActivateEvent.java b/src/main/java/com/gmail/nossr50/events/skills/abilities/McMMOPlayerAbilityActivateEvent.java index 7b0db958b..c8f8cbb86 100644 --- a/src/main/java/com/gmail/nossr50/events/skills/abilities/McMMOPlayerAbilityActivateEvent.java +++ b/src/main/java/com/gmail/nossr50/events/skills/abilities/McMMOPlayerAbilityActivateEvent.java @@ -1,14 +1,24 @@ package com.gmail.nossr50.events.skills.abilities; +import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; +import com.gmail.nossr50.util.player.UserManager; +import java.util.Objects; import org.bukkit.entity.Player; import org.bukkit.event.Cancellable; -public class McMMOPlayerAbilityActivateEvent extends McMMOPlayerAbilityEvent implements Cancellable { +public class McMMOPlayerAbilityActivateEvent extends McMMOPlayerAbilityEvent implements + Cancellable { private boolean cancelled; + @Deprecated(forRemoval = true, since = "2.2.010") public McMMOPlayerAbilityActivateEvent(Player player, PrimarySkillType skill) { - super(player, skill); + super(Objects.requireNonNull(UserManager.getPlayer(player)), skill); + cancelled = false; + } + + public McMMOPlayerAbilityActivateEvent(McMMOPlayer mmoPlayer, PrimarySkillType skill) { + super(mmoPlayer, skill); cancelled = false; } diff --git a/src/main/java/com/gmail/nossr50/events/skills/abilities/McMMOPlayerAbilityDeactivateEvent.java b/src/main/java/com/gmail/nossr50/events/skills/abilities/McMMOPlayerAbilityDeactivateEvent.java index 384b61c92..7883d19c0 100644 --- a/src/main/java/com/gmail/nossr50/events/skills/abilities/McMMOPlayerAbilityDeactivateEvent.java +++ b/src/main/java/com/gmail/nossr50/events/skills/abilities/McMMOPlayerAbilityDeactivateEvent.java @@ -1,10 +1,22 @@ package com.gmail.nossr50.events.skills.abilities; +import static java.util.Objects.requireNonNull; + +import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; +import com.gmail.nossr50.util.player.UserManager; import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; public class McMMOPlayerAbilityDeactivateEvent extends McMMOPlayerAbilityEvent { - public McMMOPlayerAbilityDeactivateEvent(Player player, PrimarySkillType skill) { - super(player, skill); + @Deprecated(forRemoval = true, since = "2.2.010") + public McMMOPlayerAbilityDeactivateEvent(@NotNull Player player, + @NotNull PrimarySkillType skill) { + this(requireNonNull(UserManager.getPlayer(player)), skill); + } + + public McMMOPlayerAbilityDeactivateEvent(@NotNull McMMOPlayer mmoPlayer, + @NotNull PrimarySkillType skill) { + super(mmoPlayer, skill); } } diff --git a/src/main/java/com/gmail/nossr50/events/skills/abilities/McMMOPlayerAbilityEvent.java b/src/main/java/com/gmail/nossr50/events/skills/abilities/McMMOPlayerAbilityEvent.java index 08d7dc2b2..183af3540 100644 --- a/src/main/java/com/gmail/nossr50/events/skills/abilities/McMMOPlayerAbilityEvent.java +++ b/src/main/java/com/gmail/nossr50/events/skills/abilities/McMMOPlayerAbilityEvent.java @@ -1,16 +1,38 @@ package com.gmail.nossr50.events.skills.abilities; +import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SuperAbilityType; import com.gmail.nossr50.events.skills.McMMOPlayerSkillEvent; import com.gmail.nossr50.mcMMO; +import com.gmail.nossr50.util.player.UserManager; +import java.util.Objects; import org.bukkit.entity.Player; public class McMMOPlayerAbilityEvent extends McMMOPlayerSkillEvent { private final SuperAbilityType ability; + /** + * Create a new McMMOPlayerAbilityEvent. + * + * @param player The player involved in this event + * @param skill The skill involved in this event + * @deprecated Use {@link #McMMOPlayerAbilityEvent(McMMOPlayer, PrimarySkillType)} instead + */ + @Deprecated(forRemoval = true, since = "2.2.010") protected McMMOPlayerAbilityEvent(Player player, PrimarySkillType skill) { - super(player, skill); + super(Objects.requireNonNull(UserManager.getPlayer(player)), skill); + ability = mcMMO.p.getSkillTools().getSuperAbility(skill); + } + + /** + * Create a new McMMOPlayerAbilityEvent. + * + * @param mmoPlayer The McMMOPlayer involved in this event + * @param skill The skill involved in this event + */ + protected McMMOPlayerAbilityEvent(McMMOPlayer mmoPlayer, PrimarySkillType skill) { + super(mmoPlayer, skill); ability = mcMMO.p.getSkillTools().getSuperAbility(skill); } diff --git a/src/main/java/com/gmail/nossr50/events/skills/alchemy/McMMOPlayerBrewEvent.java b/src/main/java/com/gmail/nossr50/events/skills/alchemy/McMMOPlayerBrewEvent.java index ca62829cb..4b98769da 100644 --- a/src/main/java/com/gmail/nossr50/events/skills/alchemy/McMMOPlayerBrewEvent.java +++ b/src/main/java/com/gmail/nossr50/events/skills/alchemy/McMMOPlayerBrewEvent.java @@ -1,24 +1,36 @@ package com.gmail.nossr50.events.skills.alchemy; +import static java.util.Objects.requireNonNull; + +import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.events.skills.McMMOPlayerSkillEvent; +import com.gmail.nossr50.util.player.UserManager; import org.bukkit.block.Block; import org.bukkit.block.BlockState; import org.bukkit.block.BrewingStand; import org.bukkit.entity.Player; import org.bukkit.event.Cancellable; +import org.jetbrains.annotations.NotNull; public class McMMOPlayerBrewEvent extends McMMOPlayerSkillEvent implements Cancellable { private final BlockState brewingStand; private boolean cancelled; + @Deprecated(forRemoval = true, since = "2.2.010") public McMMOPlayerBrewEvent(Player player, BlockState brewingStand) { - super(player, PrimarySkillType.ALCHEMY); + super(requireNonNull(UserManager.getPlayer(player)), PrimarySkillType.ALCHEMY); this.brewingStand = brewingStand; cancelled = false; } + public McMMOPlayerBrewEvent(@NotNull McMMOPlayer mmoPlayer, @NotNull BlockState brewingStand) { + super(mmoPlayer, PrimarySkillType.ALCHEMY); + this.brewingStand = requireNonNull(brewingStand); + cancelled = false; + } + public boolean isCancelled() { return cancelled; } diff --git a/src/main/java/com/gmail/nossr50/events/skills/alchemy/McMMOPlayerCatalysisEvent.java b/src/main/java/com/gmail/nossr50/events/skills/alchemy/McMMOPlayerCatalysisEvent.java index c4dbcc7d3..0a5dfe19e 100644 --- a/src/main/java/com/gmail/nossr50/events/skills/alchemy/McMMOPlayerCatalysisEvent.java +++ b/src/main/java/com/gmail/nossr50/events/skills/alchemy/McMMOPlayerCatalysisEvent.java @@ -1,7 +1,11 @@ package com.gmail.nossr50.events.skills.alchemy; +import static java.util.Objects.requireNonNull; + +import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.events.skills.McMMOPlayerSkillEvent; +import com.gmail.nossr50.util.player.UserManager; import org.bukkit.entity.Player; import org.bukkit.event.Cancellable; @@ -10,8 +14,15 @@ public class McMMOPlayerCatalysisEvent extends McMMOPlayerSkillEvent implements private boolean cancelled; + @Deprecated(forRemoval = true, since = "2.2.010") public McMMOPlayerCatalysisEvent(Player player, double speed) { - super(player, PrimarySkillType.ALCHEMY); + super(requireNonNull(UserManager.getPlayer(player)), PrimarySkillType.ALCHEMY); + this.speed = speed; + cancelled = false; + } + + public McMMOPlayerCatalysisEvent(McMMOPlayer mmoPlayer, double speed) { + super(mmoPlayer, PrimarySkillType.ALCHEMY); this.speed = speed; cancelled = false; } diff --git a/src/main/java/com/gmail/nossr50/events/skills/fishing/McMMOPlayerFishingEvent.java b/src/main/java/com/gmail/nossr50/events/skills/fishing/McMMOPlayerFishingEvent.java index 96cde8b6b..363b10927 100644 --- a/src/main/java/com/gmail/nossr50/events/skills/fishing/McMMOPlayerFishingEvent.java +++ b/src/main/java/com/gmail/nossr50/events/skills/fishing/McMMOPlayerFishingEvent.java @@ -1,15 +1,23 @@ package com.gmail.nossr50.events.skills.fishing; +import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.events.skills.McMMOPlayerSkillEvent; +import com.gmail.nossr50.util.player.UserManager; import org.bukkit.entity.Player; import org.bukkit.event.Cancellable; public class McMMOPlayerFishingEvent extends McMMOPlayerSkillEvent implements Cancellable { private boolean cancelled; + @Deprecated(forRemoval = true, since = "2.2.010") protected McMMOPlayerFishingEvent(Player player) { - super(player, PrimarySkillType.FISHING); + super(UserManager.getPlayer(player), PrimarySkillType.FISHING); + cancelled = false; + } + + protected McMMOPlayerFishingEvent(McMMOPlayer mmoPlayer) { + super(mmoPlayer, PrimarySkillType.FISHING); cancelled = false; } diff --git a/src/main/java/com/gmail/nossr50/events/skills/fishing/McMMOPlayerFishingTreasureEvent.java b/src/main/java/com/gmail/nossr50/events/skills/fishing/McMMOPlayerFishingTreasureEvent.java index dba01b751..e43d4e6e3 100644 --- a/src/main/java/com/gmail/nossr50/events/skills/fishing/McMMOPlayerFishingTreasureEvent.java +++ b/src/main/java/com/gmail/nossr50/events/skills/fishing/McMMOPlayerFishingTreasureEvent.java @@ -1,23 +1,35 @@ package com.gmail.nossr50.events.skills.fishing; +import static java.util.Objects.requireNonNull; + +import com.gmail.nossr50.datatypes.player.McMMOPlayer; +import com.gmail.nossr50.util.player.UserManager; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; public class McMMOPlayerFishingTreasureEvent extends McMMOPlayerFishingEvent { private ItemStack treasure; private int xp; + @Deprecated(forRemoval = true, since = "2.2.010") public McMMOPlayerFishingTreasureEvent(Player player, ItemStack treasure, int xp) { - super(player); + this(requireNonNull(UserManager.getPlayer(player)), treasure, xp); + } + + public McMMOPlayerFishingTreasureEvent(@NotNull McMMOPlayer mmoPlayer, + @Nullable ItemStack treasure, int xp) { + super(mmoPlayer); this.treasure = treasure; this.xp = xp; } - public ItemStack getTreasure() { + public @Nullable ItemStack getTreasure() { return treasure; } - public void setTreasure(ItemStack item) { + public void setTreasure(@Nullable ItemStack item) { this.treasure = item; } diff --git a/src/main/java/com/gmail/nossr50/events/skills/fishing/McMMOPlayerMagicHunterEvent.java b/src/main/java/com/gmail/nossr50/events/skills/fishing/McMMOPlayerMagicHunterEvent.java index decd27ad5..b98dc2015 100644 --- a/src/main/java/com/gmail/nossr50/events/skills/fishing/McMMOPlayerMagicHunterEvent.java +++ b/src/main/java/com/gmail/nossr50/events/skills/fishing/McMMOPlayerMagicHunterEvent.java @@ -1,20 +1,33 @@ package com.gmail.nossr50.events.skills.fishing; +import static java.util.Objects.requireNonNull; + +import com.gmail.nossr50.datatypes.player.McMMOPlayer; +import com.gmail.nossr50.util.player.UserManager; +import java.util.HashMap; +import java.util.Map; import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; - -import java.util.Map; +import org.jetbrains.annotations.NotNull; public class McMMOPlayerMagicHunterEvent extends McMMOPlayerFishingTreasureEvent { - private final Map enchants; + private final Map enchants = new HashMap<>(); - public McMMOPlayerMagicHunterEvent(Player player, ItemStack treasure, int xp, Map enchants) { - super(player, treasure, xp); - this.enchants = enchants; + @Deprecated(forRemoval = true, since = "2.2.010") + public McMMOPlayerMagicHunterEvent(@NotNull Player player, @NotNull ItemStack treasure, int xp, + @NotNull Map enchants) { + this(requireNonNull(UserManager.getPlayer(player)), treasure, xp, enchants); } - public Map getEnchantments() { + public McMMOPlayerMagicHunterEvent(@NotNull McMMOPlayer mmoPlayer, @NotNull ItemStack treasure, + int xp, @NotNull Map enchants) { + super(mmoPlayer, treasure, xp); + requireNonNull(enchants, "enchants cannot be null"); + this.enchants.putAll(enchants); + } + + public @NotNull Map getEnchantments() { return enchants; } } diff --git a/src/main/java/com/gmail/nossr50/events/skills/fishing/McMMOPlayerMasterAnglerEvent.java b/src/main/java/com/gmail/nossr50/events/skills/fishing/McMMOPlayerMasterAnglerEvent.java new file mode 100644 index 000000000..db4e19cae --- /dev/null +++ b/src/main/java/com/gmail/nossr50/events/skills/fishing/McMMOPlayerMasterAnglerEvent.java @@ -0,0 +1,55 @@ +package com.gmail.nossr50.events.skills.fishing; + +import com.gmail.nossr50.datatypes.player.McMMOPlayer; +import com.gmail.nossr50.skills.fishing.FishingManager; +import org.jetbrains.annotations.NotNull; + +public class McMMOPlayerMasterAnglerEvent extends McMMOPlayerFishingEvent { + private int reducedMinWaitTime; + private int reducedMaxWaitTime; + private final FishingManager fishingManager; + + public McMMOPlayerMasterAnglerEvent(@NotNull McMMOPlayer mmoPlayer, + int reducedMinWaitTime, + int reducedMaxWaitTime, + FishingManager fishingManager) { + super(mmoPlayer); + this.fishingManager = fishingManager; + this.reducedMinWaitTime = Math.max(reducedMinWaitTime, getReducedMinWaitTimeLowerBound()); + this.reducedMaxWaitTime = Math.max(reducedMaxWaitTime, getReducedMaxWaitTimeLowerBound()); + } + + public int getReducedMinWaitTime() { + return reducedMinWaitTime; + } + + public void setReducedMinWaitTime(int reducedMinWaitTime) { + if (reducedMinWaitTime < 0 || reducedMinWaitTime > reducedMaxWaitTime) { + throw new IllegalArgumentException( + "Reduced min wait time must be greater than or equal to 0" + + " and less than reduced max wait time."); + } + this.reducedMinWaitTime = Math.max(reducedMinWaitTime, getReducedMinWaitTimeLowerBound()); + } + + public int getReducedMaxWaitTime() { + return reducedMaxWaitTime; + } + + public void setReducedMaxWaitTime(int reducedMaxWaitTime) { + if (reducedMaxWaitTime < 0 || reducedMaxWaitTime < reducedMinWaitTime) { + throw new IllegalArgumentException( + "Reduced max wait time must be greater than or equal to 0" + + " and greater than reduced min wait time."); + } + this.reducedMaxWaitTime = Math.max(reducedMaxWaitTime, getReducedMaxWaitTimeLowerBound()); + } + + public int getReducedMinWaitTimeLowerBound() { + return fishingManager.getMasterAnglerMinWaitLowerBound(); + } + + public int getReducedMaxWaitTimeLowerBound() { + return fishingManager.getMasterAnglerMaxWaitLowerBound(); + } +} \ No newline at end of file diff --git a/src/main/java/com/gmail/nossr50/events/skills/repair/McMMOPlayerRepairCheckEvent.java b/src/main/java/com/gmail/nossr50/events/skills/repair/McMMOPlayerRepairCheckEvent.java index fd4a02754..d0baf6beb 100644 --- a/src/main/java/com/gmail/nossr50/events/skills/repair/McMMOPlayerRepairCheckEvent.java +++ b/src/main/java/com/gmail/nossr50/events/skills/repair/McMMOPlayerRepairCheckEvent.java @@ -15,7 +15,8 @@ public class McMMOPlayerRepairCheckEvent extends McMMOPlayerSkillEvent implement private final ItemStack repairedObject; private boolean cancelled; - public McMMOPlayerRepairCheckEvent(Player player, short repairAmount, ItemStack repairMaterial, ItemStack repairedObject) { + public McMMOPlayerRepairCheckEvent(Player player, short repairAmount, ItemStack repairMaterial, + ItemStack repairedObject) { super(player, PrimarySkillType.REPAIR); this.repairAmount = repairAmount; this.repairMaterial = repairMaterial; @@ -44,7 +45,9 @@ public class McMMOPlayerRepairCheckEvent extends McMMOPlayerSkillEvent implement return repairedObject; } - /** Following are required for Cancellable **/ + /** + * Following are required for Cancellable + **/ @Override public boolean isCancelled() { return cancelled; diff --git a/src/main/java/com/gmail/nossr50/events/skills/rupture/McMMOEntityDamageByRuptureEvent.java b/src/main/java/com/gmail/nossr50/events/skills/rupture/McMMOEntityDamageByRuptureEvent.java index 6612af381..8f27fde3d 100644 --- a/src/main/java/com/gmail/nossr50/events/skills/rupture/McMMOEntityDamageByRuptureEvent.java +++ b/src/main/java/com/gmail/nossr50/events/skills/rupture/McMMOEntityDamageByRuptureEvent.java @@ -8,24 +8,25 @@ import org.bukkit.event.entity.EntityEvent; import org.jetbrains.annotations.NotNull; public class McMMOEntityDamageByRuptureEvent extends EntityEvent implements Cancellable { - private final McMMOPlayer damager; + private final McMMOPlayer damager; private final Entity damagee; private double damage; private boolean isCancelled = false; private static final HandlerList handlers = new HandlerList(); - public McMMOEntityDamageByRuptureEvent(@NotNull McMMOPlayer damager, @NotNull Entity damagee, double damage) { + public McMMOEntityDamageByRuptureEvent(@NotNull McMMOPlayer damager, @NotNull Entity damagee, + double damage) { super(damagee); - this.damager = damager; + this.damager = damager; this.damagee = damagee; this.damage = damage; - } + } - @NotNull + @NotNull @Deprecated - public McMMOPlayer getMcMMODamager() { - return damager; - } + public McMMOPlayer getMcMMODamager() { + return damager; + } public McMMOPlayer getDamager() { return damager; @@ -54,4 +55,8 @@ public class McMMOEntityDamageByRuptureEvent extends EntityEvent implements Canc public HandlerList getHandlers() { return handlers; } + + public static @NotNull HandlerList getHandlerList() { + return handlers; + } } diff --git a/src/main/java/com/gmail/nossr50/events/skills/salvage/McMMOPlayerSalvageCheckEvent.java b/src/main/java/com/gmail/nossr50/events/skills/salvage/McMMOPlayerSalvageCheckEvent.java index 6a8061763..ca1f9b0a4 100644 --- a/src/main/java/com/gmail/nossr50/events/skills/salvage/McMMOPlayerSalvageCheckEvent.java +++ b/src/main/java/com/gmail/nossr50/events/skills/salvage/McMMOPlayerSalvageCheckEvent.java @@ -15,7 +15,8 @@ public class McMMOPlayerSalvageCheckEvent extends McMMOPlayerSkillEvent implemen private final ItemStack enchantedBook; private boolean cancelled; - public McMMOPlayerSalvageCheckEvent(Player player, ItemStack salvageItem, ItemStack salvageResults, ItemStack enchantedBook) { + public McMMOPlayerSalvageCheckEvent(Player player, ItemStack salvageItem, + ItemStack salvageResults, ItemStack enchantedBook) { super(player, PrimarySkillType.SALVAGE); this.salvageItem = salvageItem; this.salvageResults = salvageResults; @@ -38,13 +39,16 @@ public class McMMOPlayerSalvageCheckEvent extends McMMOPlayerSkillEvent implemen } /** - * @return The enchanted book that should drop after salvaging or null if no book should be dropped. + * @return The enchanted book that should drop after salvaging or null if no book should be + * dropped. */ public ItemStack getEnchantedBook() { return enchantedBook; } - /** Following are required for Cancellable **/ + /** + * Following are required for Cancellable + **/ @Override public boolean isCancelled() { return cancelled; diff --git a/src/main/java/com/gmail/nossr50/events/skills/secondaryabilities/SubSkillBlockEvent.java b/src/main/java/com/gmail/nossr50/events/skills/secondaryabilities/SubSkillBlockEvent.java index 69b730af5..76a553b4f 100644 --- a/src/main/java/com/gmail/nossr50/events/skills/secondaryabilities/SubSkillBlockEvent.java +++ b/src/main/java/com/gmail/nossr50/events/skills/secondaryabilities/SubSkillBlockEvent.java @@ -8,13 +8,15 @@ import org.jetbrains.annotations.NotNull; public class SubSkillBlockEvent extends SubSkillEvent { private final @NotNull Block block; - public SubSkillBlockEvent(@NotNull Player player, @NotNull SubSkillType subSkillType, @NotNull Block block) { + public SubSkillBlockEvent(@NotNull Player player, @NotNull SubSkillType subSkillType, + @NotNull Block block) { super(player, subSkillType); this.block = block; } /** * Get the block associated with this event + * * @return the block associated with this event */ public @NotNull Block getBlock() { 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 7aefb003e..49e6ab588 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,11 +1,16 @@ package com.gmail.nossr50.events.skills.secondaryabilities; +import static java.util.Objects.requireNonNull; + +import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.datatypes.skills.subskills.AbstractSubSkill; import com.gmail.nossr50.events.skills.McMMOPlayerSkillEvent; import com.gmail.nossr50.mcMMO; +import com.gmail.nossr50.util.player.UserManager; 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; @@ -14,33 +19,64 @@ public class SubSkillEvent extends McMMOPlayerSkillEvent implements Cancellable /** * 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 Use {@link #SubSkillEvent(McMMOPlayer, SubSkillType)} instead */ - @Deprecated - public SubSkillEvent(Player player, SubSkillType subSkillType) { - super(player, mcMMO.p.getSkillTools().getPrimarySkillBySubSkill(subSkillType)); + @Deprecated(forRemoval = true, since = "2.2.010") + public SubSkillEvent(@NotNull Player player, @NotNull SubSkillType subSkillType) { + this(requireNonNull(UserManager.getPlayer(player)), subSkillType); + } + + /** + * Only skills using the old system will fire this event + * + * @param mmoPlayer target player + * @param subSkillType target subskill + */ + public SubSkillEvent(@NotNull McMMOPlayer mmoPlayer, @NotNull SubSkillType subSkillType) { + super(mmoPlayer, mcMMO.p.getSkillTools().getPrimarySkillBySubSkill(subSkillType)); 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 final result of the dice roll, typically + * between 0-1.0 */ - @Deprecated - public SubSkillEvent(Player player, SubSkillType subSkillType, double resultModifier) { + @Deprecated(forRemoval = true, since = "2.2.010") + public SubSkillEvent(@NotNull Player player, @NotNull SubSkillType subSkillType, + double resultModifier) { + this(requireNonNull(UserManager.getPlayer(player)), subSkillType, resultModifier); + } + + /** + * 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 + */ + public SubSkillEvent(@NotNull McMMOPlayer player, @NotNull SubSkillType subSkillType, + double resultModifier) { super(player, mcMMO.p.getSkillTools().getPrimarySkillBySubSkill(subSkillType)); - this.subSkillType = subSkillType; + this.subSkillType = requireNonNull(subSkillType, "subSkillType cannot be null"); this.resultModifier = resultModifier; } - public SubSkillEvent(Player player, AbstractSubSkill abstractSubSkill) - { - super(player, abstractSubSkill.getPrimarySkill()); + @Deprecated(forRemoval = true, since = "2.2.010") + public SubSkillEvent(@NotNull Player player, @NotNull AbstractSubSkill abstractSubSkill) { + this(requireNonNull(UserManager.getPlayer(player)), abstractSubSkill); + } + + public SubSkillEvent(@NotNull McMMOPlayer mmoPlayer, + @NotNull AbstractSubSkill abstractSubSkill) { + super(mmoPlayer, abstractSubSkill.getPrimarySkill()); } public double getResultModifier() { @@ -53,6 +89,7 @@ public class SubSkillEvent extends McMMOPlayerSkillEvent implements Cancellable /** * Gets the SubSkillType involved in the event + * * @return the SubSkillType */ public SubSkillType getSubSkillType() { 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 c1a90a425..3756c6cdd 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/events/skills/taming/McMMOPlayerTameEntityEvent.java b/src/main/java/com/gmail/nossr50/events/skills/taming/McMMOPlayerTameEntityEvent.java new file mode 100644 index 000000000..a81f9f2d5 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/events/skills/taming/McMMOPlayerTameEntityEvent.java @@ -0,0 +1,78 @@ +package com.gmail.nossr50.events.skills.taming; + +import com.gmail.nossr50.datatypes.experience.XPGainReason; +import com.gmail.nossr50.datatypes.player.McMMOPlayer; +import com.gmail.nossr50.datatypes.skills.PrimarySkillType; +import com.gmail.nossr50.events.experience.McMMOPlayerExperienceEvent; +import com.google.common.base.Preconditions; +import org.bukkit.entity.Entity; +import org.bukkit.event.HandlerList; +import org.jetbrains.annotations.NotNull; + +/** + * Called when a player has tamed an entity, and we are about to award them experience for it. + */ +public class McMMOPlayerTameEntityEvent extends McMMOPlayerExperienceEvent { + private static final HandlerList HANDLER_LIST = new HandlerList(); + + private final McMMOPlayer mmoPlayer; + private float xpGained; + private final Entity tamedEntity; + + public McMMOPlayerTameEntityEvent(@NotNull McMMOPlayer mmoPlayer, float xp, + @NotNull Entity tamedEntity) { + super(mmoPlayer.getPlayer(), PrimarySkillType.TAMING, XPGainReason.PVE); + this.mmoPlayer = mmoPlayer; + this.xpGained = xp; + this.tamedEntity = tamedEntity; + } + + /** + * @return The {@link McMMOPlayer} associated with this event. + */ + @NotNull + public McMMOPlayer getMcMMOPlayer() { + return mmoPlayer; + } + + /** + * @return The raw experience that the player will receive. + */ + public float getXpGained() { + return this.xpGained; + } + + /** + * @param xpGained The raw experience that the player will receive. + * @throws IllegalArgumentException if xpGained is NaN, infinite, or not positive. + */ + public void setXpGained(float xpGained) { + Preconditions.checkArgument(Float.isFinite(xpGained), "new gained xp must be a number"); + Preconditions.checkArgument(xpGained > 0, "new gained xp must be a positive number"); + + this.xpGained = xpGained; + } + + @NotNull + public Entity getTamedEntity() { + return tamedEntity; + } + + /** + * @apiNote Cancelling this event prevents experience from being awarded, but the entity will + * remain tamed. + */ + @Override + public void setCancelled(boolean cancelled) { + super.setCancelled(cancelled); + } + + public static HandlerList getHandlerList() { + return HANDLER_LIST; + } + + @Override + public @NotNull HandlerList getHandlers() { + return HANDLER_LIST; + } +} diff --git a/src/main/java/com/gmail/nossr50/events/skills/unarmed/McMMOPlayerDisarmEvent.java b/src/main/java/com/gmail/nossr50/events/skills/unarmed/McMMOPlayerDisarmEvent.java index 7404aaa22..a0c535f8d 100644 --- a/src/main/java/com/gmail/nossr50/events/skills/unarmed/McMMOPlayerDisarmEvent.java +++ b/src/main/java/com/gmail/nossr50/events/skills/unarmed/McMMOPlayerDisarmEvent.java @@ -18,7 +18,9 @@ public class McMMOPlayerDisarmEvent extends McMMOPlayerSkillEvent implements Can return defender; } - /** Following are required for Cancellable **/ + /** + * Following are required for Cancellable + **/ @Override public boolean isCancelled() { return cancelled; diff --git a/src/main/java/com/gmail/nossr50/listeners/BlockListener.java b/src/main/java/com/gmail/nossr50/listeners/BlockListener.java index c49c759c9..272609395 100644 --- a/src/main/java/com/gmail/nossr50/listeners/BlockListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/BlockListener.java @@ -1,5 +1,7 @@ package com.gmail.nossr50.listeners; +import static com.gmail.nossr50.util.Misc.getBlockCenter; + import com.gmail.nossr50.api.ItemSpawnReason; import com.gmail.nossr50.config.HiddenConfig; import com.gmail.nossr50.config.WorldBlacklist; @@ -20,25 +22,47 @@ import com.gmail.nossr50.skills.mining.MiningManager; import com.gmail.nossr50.skills.repair.Repair; import com.gmail.nossr50.skills.salvage.Salvage; import com.gmail.nossr50.skills.woodcutting.WoodcuttingManager; -import com.gmail.nossr50.util.*; +import com.gmail.nossr50.util.BlockUtils; +import com.gmail.nossr50.util.ContainerMetadataUtils; +import com.gmail.nossr50.util.EventUtils; +import com.gmail.nossr50.util.ItemUtils; +import com.gmail.nossr50.util.MetadataConstants; +import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.player.UserManager; 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.worldguard.WorldGuardManager; import com.gmail.nossr50.worldguard.WorldGuardUtils; -import org.bukkit.*; -import org.bukkit.block.*; +import java.util.HashSet; +import org.bukkit.ChatColor; +import org.bukkit.GameMode; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.OfflinePlayer; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.block.BlockState; +import org.bukkit.block.BrewingStand; +import org.bukkit.block.Furnace; import org.bukkit.entity.Item; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; -import org.bukkit.event.block.*; +import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.event.block.BlockDamageEvent; +import org.bukkit.event.block.BlockDropItemEvent; +import org.bukkit.event.block.BlockFormEvent; +import org.bukkit.event.block.BlockGrowEvent; +import org.bukkit.event.block.BlockMultiPlaceEvent; +import org.bukkit.event.block.BlockPistonExtendEvent; +import org.bukkit.event.block.BlockPistonRetractEvent; +import org.bukkit.event.block.BlockPlaceEvent; +import org.bukkit.event.block.EntityBlockFormEvent; import org.bukkit.inventory.ItemStack; -import java.util.HashSet; - public class BlockListener implements Listener { private final mcMMO plugin; @@ -47,76 +71,88 @@ public class BlockListener implements Listener { } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = false) - public void onBlockDropItemEvent(BlockDropItemEvent event) - { + public void onBlockDropItemEvent(BlockDropItemEvent event) { //Make sure we clean up metadata on these blocks - if(event.isCancelled()) { - if(event.getBlock().hasMetadata(MetadataConstants.METADATA_KEY_BONUS_DROPS)) + if (event.isCancelled()) { + if (event.getBlock().hasMetadata(MetadataConstants.METADATA_KEY_BONUS_DROPS)) { event.getBlock().removeMetadata(MetadataConstants.METADATA_KEY_BONUS_DROPS, plugin); + } return; } int tileEntityTolerance = 1; // beetroot hotfix, potentially other plants may need this fix - if(event.getBlockState().getType() == Material.BEETROOTS) + if (event.getBlock().getType() == Material.BEETROOTS) { tileEntityTolerance = 2; + } //Track how many "things" are being dropped HashSet uniqueMaterials = new HashSet<>(); boolean dontRewardTE = false; //If we suspect TEs are mixed in with other things don't reward bonus drops for anything that isn't a block int blockCount = 0; - for(Item item : event.getItems()) { + for (Item item : event.getItems()) { //Track unique materials uniqueMaterials.add(item.getItemStack().getType()); //Count blocks as a second failsafe - if(item.getItemStack().getType().isBlock()) + if (item.getItemStack().getType().isBlock()) { blockCount++; + } } - if(uniqueMaterials.size() > tileEntityTolerance) { + if (uniqueMaterials.size() > tileEntityTolerance) { //Too many things are dropping, assume tile entities might be duped //Technically this would also prevent something like coal from being bonus dropped if you placed a TE above a coal ore when mining it but that's pretty edge case and this is a good solution for now dontRewardTE = true; } //If there are more than one block in the item list we can't really trust it and will back out of rewarding bonus drops - if(blockCount <= 1) { - for(Item item : event.getItems()) - { + if (blockCount <= 1) { + for (Item item : event.getItems()) { ItemStack is = new ItemStack(item.getItemStack()); - if(is.getAmount() <= 0) + if (is.getAmount() <= 0) { continue; + } //TODO: Ignore this abomination its rewritten in 2.2 - if(!mcMMO.p.getGeneralConfig().getDoubleDropsEnabled(PrimarySkillType.MINING, is.getType()) - && !mcMMO.p.getGeneralConfig().getDoubleDropsEnabled(PrimarySkillType.HERBALISM, is.getType()) - && !mcMMO.p.getGeneralConfig().getDoubleDropsEnabled(PrimarySkillType.WOODCUTTING, is.getType())) + if (!mcMMO.p.getGeneralConfig() + .getDoubleDropsEnabled(PrimarySkillType.MINING, is.getType()) + && !mcMMO.p.getGeneralConfig() + .getDoubleDropsEnabled(PrimarySkillType.HERBALISM, is.getType()) + && !mcMMO.p.getGeneralConfig() + .getDoubleDropsEnabled(PrimarySkillType.WOODCUTTING, is.getType())) { continue; + } //If we suspect TEs might be duped only reward block - if(dontRewardTE) { - if(!is.getType().isBlock()) { + if (dontRewardTE) { + if (!is.getType().isBlock()) { continue; } } - if (event.getBlock().getMetadata(MetadataConstants.METADATA_KEY_BONUS_DROPS).size() > 0) { - BonusDropMeta bonusDropMeta = (BonusDropMeta) event.getBlock().getMetadata(MetadataConstants.METADATA_KEY_BONUS_DROPS).get(0); + if (event.getBlock().getMetadata(MetadataConstants.METADATA_KEY_BONUS_DROPS).size() + > 0) { + final BonusDropMeta bonusDropMeta = + (BonusDropMeta) event.getBlock().getMetadata( + MetadataConstants.METADATA_KEY_BONUS_DROPS).get(0); int bonusCount = bonusDropMeta.asInt(); - + final Location centeredLocation = getBlockCenter(event.getBlock()); for (int i = 0; i < bonusCount; i++) { - Misc.spawnItemNaturally(event.getPlayer(), event.getBlockState().getLocation(), is, ItemSpawnReason.BONUS_DROPS); + + ItemUtils.spawnItemNaturally(event.getPlayer(), + centeredLocation, is, ItemSpawnReason.BONUS_DROPS); } } } } - if(event.getBlock().hasMetadata(MetadataConstants.METADATA_KEY_BONUS_DROPS)) + if (event.getBlock().hasMetadata(MetadataConstants.METADATA_KEY_BONUS_DROPS)) { event.getBlock().removeMetadata(MetadataConstants.METADATA_KEY_BONUS_DROPS, plugin); + } } /** @@ -127,17 +163,18 @@ public class BlockListener implements Listener { @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onBlockPistonExtend(BlockPistonExtendEvent event) { /* WORLD BLACKLIST CHECK */ - if(WorldBlacklist.isWorldBlacklisted(event.getBlock().getWorld())) + if (WorldBlacklist.isWorldBlacklisted(event.getBlock().getWorld())) { return; + } - if(!ExperienceConfig.getInstance().isPistonCheatingPrevented()) { + if (!ExperienceConfig.getInstance().isPistonCheatingPrevented()) { return; } final BlockFace direction = event.getDirection(); for (final Block block : event.getBlocks()) { - mcMMO.p.getFoliaLib().getImpl().runAtLocation(block.getLocation(), t -> { + mcMMO.p.getFoliaLib().getScheduler().runAtLocation(block.getLocation(), t -> { final Block movedBlock = block.getRelative(direction); if (BlockUtils.isWithinWorldBounds(movedBlock)) { @@ -155,10 +192,11 @@ public class BlockListener implements Listener { @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onBlockPistonRetract(BlockPistonRetractEvent event) { /* WORLD BLACKLIST CHECK */ - if(WorldBlacklist.isWorldBlacklisted(event.getBlock().getWorld())) + if (WorldBlacklist.isWorldBlacklisted(event.getBlock().getWorld())) { return; + } - if(!ExperienceConfig.getInstance().isPistonCheatingPrevented()) { + if (!ExperienceConfig.getInstance().isPistonCheatingPrevented()) { return; } @@ -167,12 +205,13 @@ public class BlockListener implements Listener { Block movedBlock = event.getBlock().getRelative(direction); //Spigot makes bad things happen in its API - if(BlockUtils.isWithinWorldBounds(movedBlock)) { + if (BlockUtils.isWithinWorldBounds(movedBlock)) { BlockUtils.setUnnaturalBlock(movedBlock); } for (Block block : event.getBlocks()) { - if(BlockUtils.isWithinWorldBounds(block) && BlockUtils.isWithinWorldBounds(block.getRelative(direction))) { + if (BlockUtils.isWithinWorldBounds(block) && BlockUtils.isWithinWorldBounds( + block.getRelative(direction))) { Block relativeBlock = block.getRelative(direction); BlockUtils.setUnnaturalBlock(relativeBlock); } @@ -180,24 +219,25 @@ public class BlockListener implements Listener { } /** - * Monitor blocks formed by entities (snowmen) - * Does not seem to monitor stuff like a falling block creating a new block + * Monitor blocks formed by entities (snowmen) Does not seem to monitor stuff like a falling + * block creating a new block * * @param event The event to watch */ @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - public void onEntityBlockFormEvent(EntityBlockFormEvent event) - { + public void onEntityBlockFormEvent(EntityBlockFormEvent event) { /* WORLD BLACKLIST CHECK */ - if(WorldBlacklist.isWorldBlacklisted(event.getBlock().getWorld())) + if (WorldBlacklist.isWorldBlacklisted(event.getBlock().getWorld())) { return; + } BlockState blockState = event.getNewState(); - if(ExperienceConfig.getInstance().isSnowExploitPrevented() && BlockUtils.shouldBeWatched(blockState)) { + if (ExperienceConfig.getInstance().isSnowExploitPrevented() && BlockUtils.shouldBeWatched( + blockState)) { Block block = blockState.getBlock(); - if(BlockUtils.isWithinWorldBounds(block)) { + if (BlockUtils.isWithinWorldBounds(block)) { BlockUtils.setUnnaturalBlock(block); } } @@ -207,20 +247,22 @@ public class BlockListener implements Listener { * Does not monitor stuff like a falling block replacing a liquid */ @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - public void onBlockFormEvent(BlockFormEvent event) - { + public void onBlockFormEvent(BlockFormEvent event) { World world = event.getBlock().getWorld(); /* WORLD BLACKLIST CHECK */ - if(WorldBlacklist.isWorldBlacklisted(world)) + if (WorldBlacklist.isWorldBlacklisted(world)) { return; + } - if(ExperienceConfig.getInstance().preventStoneLavaFarming()) { + if (ExperienceConfig.getInstance().preventStoneLavaFarming()) { BlockState newState = event.getNewState(); - if(newState.getType() != Material.OBSIDIAN && ExperienceConfig.getInstance().doesBlockGiveSkillXP(PrimarySkillType.MINING, newState.getBlockData())) { + if (newState.getType() != Material.OBSIDIAN + && ExperienceConfig.getInstance().doesBlockGiveSkillXP( + PrimarySkillType.MINING, newState.getType())) { Block block = newState.getBlock(); - if(BlockUtils.isWithinWorldBounds(block)) { + if (BlockUtils.isWithinWorldBounds(block)) { BlockUtils.setUnnaturalBlock(block); } } @@ -241,34 +283,35 @@ public class BlockListener implements Listener { // if (!Tag.LOGS.isTagged(event.getBlockReplacedState().getType()) || !Tag.LOGS.isTagged(event.getBlockPlaced().getType())) /* WORLD BLACKLIST CHECK */ - if(WorldBlacklist.isWorldBlacklisted(block.getWorld())) { + if (WorldBlacklist.isWorldBlacklisted(block.getWorld())) { return; } - if(BlockUtils.isWithinWorldBounds(block)) { + if (BlockUtils.isWithinWorldBounds(block)) { //NOTE: BlockMultiPlace has its own logic so don't handle anything that would overlap if (!(event instanceof BlockMultiPlaceEvent)) { BlockUtils.setUnnaturalBlock(block); } } - Player player = event.getPlayer(); if (!UserManager.hasPlayerDataKey(player)) { return; } - McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player); + final McMMOPlayer mmoPlayer = UserManager.getPlayer(player); - if(mcMMOPlayer == null) + if (mmoPlayer == null) { return; - - if (blockState.getType() == Repair.anvilMaterial && mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, PrimarySkillType.REPAIR)) { - mcMMOPlayer.getRepairManager().placedAnvilCheck(); } - else if (blockState.getType() == Salvage.anvilMaterial && mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, PrimarySkillType.SALVAGE)) { - mcMMOPlayer.getSalvageManager().placedAnvilCheck(); + + if (blockState.getType() == Repair.anvilMaterial && mcMMO.p.getSkillTools() + .doesPlayerHaveSkillPermission(player, PrimarySkillType.REPAIR)) { + mmoPlayer.getRepairManager().placedAnvilCheck(); + } else if (blockState.getType() == Salvage.anvilMaterial && mcMMO.p.getSkillTools() + .doesPlayerHaveSkillPermission(player, PrimarySkillType.SALVAGE)) { + mmoPlayer.getSalvageManager().placedAnvilCheck(); } } @@ -284,15 +327,15 @@ public class BlockListener implements Listener { Block block = blockState.getBlock(); /* Check if the blocks placed should be monitored so they do not give out XP in the future */ - if(BlockUtils.isWithinWorldBounds(block)) { + if (BlockUtils.isWithinWorldBounds(block)) { //Updated: 10/5/2021 //Note: For some reason Azalea trees trigger this event but no other tree does (as of 10/5/2021) but if this changes in the future we may need to update this - if(BlockUtils.isPartOfTree(event.getBlockPlaced())) { + if (BlockUtils.isPartOfTree(event.getBlockPlaced())) { return; } //Track unnatural blocks - for(BlockState replacedState : event.getReplacedBlockStates()) { + for (BlockState replacedState : event.getReplacedBlockStates()) { BlockUtils.setUnnaturalBlock(replacedState.getBlock()); } } @@ -305,12 +348,13 @@ public class BlockListener implements Listener { World world = block.getWorld(); /* WORLD BLACKLIST CHECK */ - if(WorldBlacklist.isWorldBlacklisted(world)) + if (WorldBlacklist.isWorldBlacklisted(world)) { return; + } // Minecraft is dumb, the events still throw when a plant "grows" higher than the max block height. Even though no new block is created - if(BlockUtils.isWithinWorldBounds(block)) { - mcMMO.getPlaceStore().setFalse(block); + if (BlockUtils.isWithinWorldBounds(block)) { + mcMMO.getUserBlockTracker().setEligible(block); } } @@ -322,36 +366,34 @@ public class BlockListener implements Listener { @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onBlockBreak(BlockBreakEvent event) { /* WORLD BLACKLIST CHECK */ - Block block = event.getBlock(); + final Block block = event.getBlock(); if (event instanceof FakeBlockBreakEvent) { return; } - if(WorldBlacklist.isWorldBlacklisted(block.getWorld())) { + if (WorldBlacklist.isWorldBlacklisted(block.getWorld())) { BlockUtils.cleanupBlockMetadata(block); return; } /* WORLD GUARD MAIN FLAG CHECK */ - if(WorldGuardUtils.isWorldGuardLoaded()) - { - if(!WorldGuardManager.getInstance().hasMainFlag(event.getPlayer())) { + if (WorldGuardUtils.isWorldGuardLoaded()) { + if (!WorldGuardManager.getInstance().hasMainFlag(event.getPlayer())) { BlockUtils.cleanupBlockMetadata(block); return; } } - BlockState blockState = block.getState(); - Location location = blockState.getLocation(); - -// if (!BlockUtils.shouldBeWatched(blockState)) { -// return; -// } + final Location location = block.getLocation(); /* ALCHEMY - Cancel any brew in progress for that BrewingStand */ - if (blockState instanceof BrewingStand && Alchemy.brewingStandMap.containsKey(location)) { - Alchemy.brewingStandMap.get(location).cancelBrew(); + if (block.getType() == Material.BREWING_STAND) { + final BlockState blockState = block.getState(); + if (blockState instanceof BrewingStand && Alchemy.brewingStandMap.containsKey( + location)) { + Alchemy.brewingStandMap.get(location).cancelBrew(); + } } Player player = event.getPlayer(); @@ -361,10 +403,10 @@ public class BlockListener implements Listener { return; } - McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player); + final McMMOPlayer mmoPlayer = UserManager.getPlayer(player); //Check if profile is loaded - if(mcMMOPlayer == null) { + if (mmoPlayer == null) { /* Remove metadata from placed watched blocks */ BlockUtils.cleanupBlockMetadata(block); @@ -374,19 +416,20 @@ public class BlockListener implements Listener { ItemStack heldItem = player.getInventory().getItemInMainHand(); /* HERBALISM */ - if (BlockUtils.affectedByGreenTerra(blockState)) { - HerbalismManager herbalismManager = mcMMOPlayer.getHerbalismManager(); + if (BlockUtils.affectedByGreenTerra(block)) { + HerbalismManager herbalismManager = mmoPlayer.getHerbalismManager(); /* Green Terra */ if (herbalismManager.canActivateAbility()) { - mcMMOPlayer.checkAbilityActivation(PrimarySkillType.HERBALISM); + mmoPlayer.checkAbilityActivation(PrimarySkillType.HERBALISM); } /* * We don't check the block store here because herbalism has too many unusual edge cases. * Instead, we check it inside the drops handler. */ - if (mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, PrimarySkillType.HERBALISM)) { + if (mcMMO.p.getSkillTools() + .doesPlayerHaveSkillPermission(player, PrimarySkillType.HERBALISM)) { herbalismManager.processHerbalismBlockBreakEvent(event); } /* @@ -397,37 +440,43 @@ public class BlockListener implements Listener { } /* MINING */ - else if (BlockUtils.affectedBySuperBreaker(blockState) + else if (BlockUtils.affectedBySuperBreaker(block) && (ItemUtils.isPickaxe(heldItem) || ItemUtils.isHoe(heldItem)) - && mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, PrimarySkillType.MINING) - && !mcMMO.getPlaceStore().isTrue(blockState)) { - MiningManager miningManager = mcMMOPlayer.getMiningManager(); - miningManager.miningBlockCheck(blockState); + && mcMMO.p.getSkillTools() + .doesPlayerHaveSkillPermission(player, PrimarySkillType.MINING) + && !mcMMO.getUserBlockTracker().isIneligible(block)) { + MiningManager miningManager = mmoPlayer.getMiningManager(); + miningManager.miningBlockCheck(block); } /* WOOD CUTTING */ - else if (BlockUtils.hasWoodcuttingXP(blockState) && ItemUtils.isAxe(heldItem) - && mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, PrimarySkillType.WOODCUTTING) && !mcMMO.getPlaceStore().isTrue(blockState)) { - WoodcuttingManager woodcuttingManager = mcMMOPlayer.getWoodcuttingManager(); + else if (BlockUtils.hasWoodcuttingXP(block) && ItemUtils.isAxe(heldItem) + && mcMMO.p.getSkillTools() + .doesPlayerHaveSkillPermission(player, PrimarySkillType.WOODCUTTING) + && !mcMMO.getUserBlockTracker().isIneligible(block)) { + WoodcuttingManager woodcuttingManager = mmoPlayer.getWoodcuttingManager(); if (woodcuttingManager.canUseTreeFeller(heldItem)) { - woodcuttingManager.processTreeFeller(blockState); - } - else { + woodcuttingManager.processTreeFeller(block); + } else { //Check for XP - woodcuttingManager.processWoodcuttingBlockXP(blockState); + woodcuttingManager.processWoodcuttingBlockXP(block); //Check for bonus drops - woodcuttingManager.processHarvestLumber(blockState); + woodcuttingManager.processBonusDropCheck(block); } } /* EXCAVATION */ - else if (BlockUtils.affectedByGigaDrillBreaker(blockState) && ItemUtils.isShovel(heldItem) && mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, PrimarySkillType.EXCAVATION) && !mcMMO.getPlaceStore().isTrue(blockState)) { - ExcavationManager excavationManager = mcMMOPlayer.getExcavationManager(); - excavationManager.excavationBlockCheck(blockState); + else if (BlockUtils.affectedByGigaDrillBreaker(block) + && ItemUtils.isShovel(heldItem) + && mcMMO.p.getSkillTools() + .doesPlayerHaveSkillPermission(player, PrimarySkillType.EXCAVATION) + && !mcMMO.getUserBlockTracker().isIneligible(block)) { + final ExcavationManager excavationManager = mmoPlayer.getExcavationManager(); + excavationManager.excavationBlockCheck(block); - if (mcMMOPlayer.getAbilityMode(SuperAbilityType.GIGA_DRILL_BREAKER)) { - excavationManager.gigaDrillBreaker(blockState); + if (mmoPlayer.getAbilityMode(SuperAbilityType.GIGA_DRILL_BREAKER)) { + excavationManager.gigaDrillBreaker(block); } } @@ -442,18 +491,20 @@ public class BlockListener implements Listener { */ @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void onBlockBreakHigher(BlockBreakEvent event) { - if(event instanceof FakeEvent) + if (event instanceof FakeEvent) { return; + } /* WORLD BLACKLIST CHECK */ - if(WorldBlacklist.isWorldBlacklisted(event.getBlock().getWorld())) + if (WorldBlacklist.isWorldBlacklisted(event.getBlock().getWorld())) { return; + } /* WORLD GUARD MAIN FLAG CHECK */ - if(WorldGuardUtils.isWorldGuardLoaded()) - { - if(!WorldGuardManager.getInstance().hasMainFlag(event.getPlayer())) + if (WorldGuardUtils.isWorldGuardLoaded()) { + if (!WorldGuardManager.getInstance().hasMainFlag(event.getPlayer())) { return; + } } Player player = event.getPlayer(); @@ -463,8 +514,7 @@ public class BlockListener implements Listener { } //Profile not loaded - if(UserManager.getPlayer(player) == null) - { + if (UserManager.getPlayer(player) == null) { return; } @@ -478,8 +528,7 @@ public class BlockListener implements Listener { if (herbalismManager.processHylianLuck(blockState)) { blockState.update(true); event.setCancelled(true); - } - else if (blockState.getType() == Material.FLOWER_POT) { + } else if (blockState.getType() == Material.FLOWER_POT) { blockState.setType(Material.AIR); blockState.update(true); event.setCancelled(true); @@ -505,18 +554,19 @@ public class BlockListener implements Listener { */ @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onBlockDamage(BlockDamageEvent event) { - Player player = event.getPlayer(); - BlockState blockState = event.getBlock().getState(); + final Player player = event.getPlayer(); + final Block block = event.getBlock(); /* WORLD BLACKLIST CHECK */ - if(WorldBlacklist.isWorldBlacklisted(event.getBlock().getWorld())) + if (WorldBlacklist.isWorldBlacklisted(event.getBlock().getWorld())) { return; + } /* WORLD GUARD MAIN FLAG CHECK */ - if(WorldGuardUtils.isWorldGuardLoaded()) - { - if(!WorldGuardManager.getInstance().hasMainFlag(event.getPlayer())) + if (WorldGuardUtils.isWorldGuardLoaded()) { + if (!WorldGuardManager.getInstance().hasMainFlag(event.getPlayer())) { return; + } } if (event instanceof FakeBlockDamageEvent) { @@ -526,11 +576,10 @@ public class BlockListener implements Listener { return; } - McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player); + final McMMOPlayer mmoPlayer = UserManager.getPlayer(player); //Profile not loaded - if(mcMMOPlayer == null) - { + if (mmoPlayer == null) { return; } @@ -539,35 +588,45 @@ public class BlockListener implements Listener { * * We check permissions here before processing activation. */ - if (BlockUtils.canActivateAbilities(blockState)) { + if (BlockUtils.canActivateAbilities(block)) { ItemStack heldItem = player.getInventory().getItemInMainHand(); - if (mcMMOPlayer.getToolPreparationMode(ToolType.HOE) && ItemUtils.isHoe(heldItem) && (BlockUtils.affectedByGreenTerra(blockState) || BlockUtils.canMakeMossy(blockState)) && Permissions.greenTerra(player)) { - mcMMOPlayer.checkAbilityActivation(PrimarySkillType.HERBALISM); - } - else if (mcMMOPlayer.getToolPreparationMode(ToolType.AXE) && ItemUtils.isAxe(heldItem) && BlockUtils.hasWoodcuttingXP(blockState) && Permissions.treeFeller(player)) { - mcMMOPlayer.checkAbilityActivation(PrimarySkillType.WOODCUTTING); - } - else if (mcMMOPlayer.getToolPreparationMode(ToolType.PICKAXE) && ItemUtils.isPickaxe(heldItem) && BlockUtils.affectedBySuperBreaker(blockState) && Permissions.superBreaker(player)) { - mcMMOPlayer.checkAbilityActivation(PrimarySkillType.MINING); - } - else if (mcMMOPlayer.getToolPreparationMode(ToolType.SHOVEL) && ItemUtils.isShovel(heldItem) && BlockUtils.affectedByGigaDrillBreaker(blockState) && Permissions.gigaDrillBreaker(player)) { - mcMMOPlayer.checkAbilityActivation(PrimarySkillType.EXCAVATION); - } - else if (mcMMOPlayer.getToolPreparationMode(ToolType.FISTS) && heldItem.getType() == Material.AIR && (BlockUtils.affectedByGigaDrillBreaker(blockState) - || mcMMO.getMaterialMapStore().isGlass(blockState.getType()) - || blockState.getType() == Material.SNOW - || BlockUtils.affectedByBlockCracker(blockState) && Permissions.berserk(player))) { - mcMMOPlayer.checkAbilityActivation(PrimarySkillType.UNARMED); + if (mmoPlayer.getToolPreparationMode(ToolType.HOE) + && ItemUtils.isHoe(heldItem) + && (BlockUtils.affectedByGreenTerra(block) + || BlockUtils.canMakeMossy(block)) + && Permissions.greenTerra(player)) { + mmoPlayer.checkAbilityActivation(PrimarySkillType.HERBALISM); + } else if (mmoPlayer.getToolPreparationMode(ToolType.AXE) && ItemUtils.isAxe(heldItem) + && BlockUtils.hasWoodcuttingXP(block) && Permissions.treeFeller(player)) { + mmoPlayer.checkAbilityActivation(PrimarySkillType.WOODCUTTING); + } else if (mmoPlayer.getToolPreparationMode(ToolType.PICKAXE) && ItemUtils.isPickaxe( + heldItem) && BlockUtils.affectedBySuperBreaker(block) + && Permissions.superBreaker(player)) { + mmoPlayer.checkAbilityActivation(PrimarySkillType.MINING); + } else if (mmoPlayer.getToolPreparationMode(ToolType.SHOVEL) && ItemUtils.isShovel( + heldItem) && BlockUtils.affectedByGigaDrillBreaker(block) + && Permissions.gigaDrillBreaker(player)) { + mmoPlayer.checkAbilityActivation(PrimarySkillType.EXCAVATION); + } else if (mmoPlayer.getToolPreparationMode(ToolType.FISTS) + && heldItem.getType() == Material.AIR && ( + BlockUtils.affectedByGigaDrillBreaker(block) + || mcMMO.getMaterialMapStore().isGlass(block.getType()) + || block.getType() == Material.SNOW + || BlockUtils.affectedByBlockCracker(block) && Permissions.berserk( + player))) { + mmoPlayer.checkAbilityActivation(PrimarySkillType.UNARMED); - if(mcMMOPlayer.getAbilityMode(SuperAbilityType.BERSERK)) { - if (SuperAbilityType.BERSERK.blockCheck(blockState) && EventUtils.simulateBlockBreak(blockState.getBlock(), player)) { + if (mmoPlayer.getAbilityMode(SuperAbilityType.BERSERK)) { + if (SuperAbilityType.BERSERK.blockCheck(block) && EventUtils.simulateBlockBreak( + block, player)) { event.setInstaBreak(true); - if(blockState.getType().getKey().getKey().contains("glass")) { - SoundManager.worldSendSound(player.getWorld(), blockState.getLocation(), SoundType.GLASS); + if (block.getType().getKey().getKey().contains("glass")) { + SoundManager.worldSendSound(player.getWorld(), block.getLocation(), + SoundType.GLASS); } else { - SoundManager.sendSound(player, blockState.getLocation(), SoundType.POP); + SoundManager.sendSound(player, block.getLocation(), SoundType.POP); } } } @@ -579,8 +638,9 @@ public class BlockListener implements Listener { * * We don't need to check permissions here because they've already been checked for the ability to even activate. */ - if (mcMMOPlayer.getAbilityMode(SuperAbilityType.TREE_FELLER) && BlockUtils.hasWoodcuttingXP(blockState) && mcMMO.p.getGeneralConfig().getTreeFellerSoundsEnabled()) { - SoundManager.sendSound(player, blockState.getLocation(), SoundType.FIZZ); + if (mmoPlayer.getAbilityMode(SuperAbilityType.TREE_FELLER) && BlockUtils.hasWoodcuttingXP( + block) && mcMMO.p.getGeneralConfig().getTreeFellerSoundsEnabled()) { + SoundManager.sendSound(player, block.getLocation(), SoundType.FIZZ); } } @@ -592,14 +652,15 @@ public class BlockListener implements Listener { @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void onBlockDamageHigher(BlockDamageEvent event) { /* WORLD BLACKLIST CHECK */ - if(WorldBlacklist.isWorldBlacklisted(event.getBlock().getWorld())) + if (WorldBlacklist.isWorldBlacklisted(event.getBlock().getWorld())) { return; + } /* WORLD GUARD MAIN FLAG CHECK */ - if(WorldGuardUtils.isWorldGuardLoaded()) - { - if(!WorldGuardManager.getInstance().hasMainFlag(event.getPlayer())) + if (WorldGuardUtils.isWorldGuardLoaded()) { + if (!WorldGuardManager.getInstance().hasMainFlag(event.getPlayer())) { return; + } } if (event instanceof FakeBlockDamageEvent) { @@ -612,45 +673,45 @@ public class BlockListener implements Listener { return; } - McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player); + final McMMOPlayer mmoPlayer = UserManager.getPlayer(player); - //Profile not loaded - if(UserManager.getPlayer(player) == null) - { + if (mmoPlayer == null) { return; } ItemStack heldItem = player.getInventory().getItemInMainHand(); Block block = event.getBlock(); - BlockState blockState = block.getState(); /* * ABILITY TRIGGER CHECKS * * We don't need to check permissions here because they've already been checked for the ability to even activate. */ - if (mcMMOPlayer.getAbilityMode(SuperAbilityType.GREEN_TERRA) && BlockUtils.canMakeMossy(blockState)) { - if (mcMMOPlayer.getHerbalismManager().processGreenTerraBlockConversion(blockState)) { - blockState.update(true); - } - } - else if (mcMMOPlayer.getAbilityMode(SuperAbilityType.BERSERK) && (heldItem.getType() == Material.AIR || mcMMO.p.getGeneralConfig().getUnarmedItemsAsUnarmed())) { - if (mcMMOPlayer.getUnarmedManager().canUseBlockCracker() && BlockUtils.affectedByBlockCracker(blockState)) { - if (EventUtils.simulateBlockBreak(block, player) && mcMMOPlayer.getUnarmedManager().blockCrackerCheck(blockState)) { - blockState.update(); + if (mmoPlayer.getAbilityMode(SuperAbilityType.GREEN_TERRA) && BlockUtils.canMakeMossy( + block)) { + mmoPlayer.getHerbalismManager().processGreenTerraBlockConversion(block); + } else if (mmoPlayer.getAbilityMode(SuperAbilityType.BERSERK) && ( + heldItem.getType() == Material.AIR || mcMMO.p.getGeneralConfig() + .getUnarmedItemsAsUnarmed())) { + if (mmoPlayer.getUnarmedManager().canUseBlockCracker() + && BlockUtils.affectedByBlockCracker(block)) { + if (EventUtils.simulateBlockBreak(block, player)) { + mmoPlayer.getUnarmedManager().blockCrackerCheck(block.getState()); } - } - else if (!event.getInstaBreak() && SuperAbilityType.BERSERK.blockCheck(blockState) && EventUtils.simulateBlockBreak(block, player)) { + } else if (!event.getInstaBreak() && SuperAbilityType.BERSERK.blockCheck(block) + && EventUtils.simulateBlockBreak(block, player)) { event.setInstaBreak(true); - if(blockState.getType().getKey().getKey().contains("glass")) { - SoundManager.worldSendSound(player.getWorld(), block.getLocation(), SoundType.GLASS); + if (block.getType().getKey().getKey().contains("glass")) { + SoundManager.worldSendSound(player.getWorld(), block.getLocation(), + SoundType.GLASS); } else { SoundManager.sendSound(player, block.getLocation(), SoundType.POP); } } - } - else if (mcMMOPlayer.getWoodcuttingManager().canUseLeafBlower(heldItem) && BlockUtils.isNonWoodPartOfTree(blockState) && EventUtils.simulateBlockBreak(block, player)) { + } else if (mmoPlayer.getWoodcuttingManager().canUseLeafBlower(heldItem) + && BlockUtils.isNonWoodPartOfTree(block) && EventUtils.simulateBlockBreak(block, + player)) { event.setInstaBreak(true); SoundManager.sendSound(player, block.getLocation(), SoundType.POP); } @@ -659,85 +720,105 @@ public class BlockListener implements Listener { @EventHandler(priority = EventPriority.MONITOR) public void onBlockDamageCleanup(BlockDamageEvent event) { Player player = event.getPlayer(); - McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player); + final McMMOPlayer mmoPlayer = UserManager.getPlayer(player); //Profile not loaded - if(UserManager.getPlayer(player) == null) - { + if (UserManager.getPlayer(player) == null) { return; } - BlockState blockState = event.getBlock().getState(); - ItemStack heldItem = player.getInventory().getItemInMainHand(); - cleanupAbilityTools(player, mcMMOPlayer, blockState, heldItem); + cleanupAbilityTools(mmoPlayer, event.getBlock(), heldItem); - debugStickDump(player, blockState); + debugStickDump(player, event.getBlock()); } //TODO: Rewrite this //TODO: Convert into locale strings - private void debugStickDump(Player player, BlockState blockState) { + private void debugStickDump(Player player, Block block) { //Profile not loaded - if(UserManager.getPlayer(player) == null) - { + final McMMOPlayer mmoPlayer = UserManager.getPlayer(player); + if (mmoPlayer == null) { return; } - if(UserManager.getPlayer(player).isDebugMode()) - { - if(mcMMO.getPlaceStore().isTrue(blockState)) - player.sendMessage("[mcMMO DEBUG] This block is not natural and does not reward treasures/XP"); - else - { + final BlockState blockState = block.getState(); + + if (mmoPlayer.isDebugMode()) { + if (mcMMO.getUserBlockTracker().isIneligible(blockState)) { + player.sendMessage( + "[mcMMO DEBUG] This block is not natural and does not reward treasures/XP"); + } else { player.sendMessage("[mcMMO DEBUG] This block is considered natural by mcMMO"); - UserManager.getPlayer(player).getExcavationManager().printExcavationDebug(player, blockState); + mmoPlayer.getExcavationManager().printExcavationDebug(player, block); } - if(WorldGuardUtils.isWorldGuardLoaded()) - { - if(WorldGuardManager.getInstance().hasMainFlag(player)) - player.sendMessage("[mcMMO DEBUG] World Guard main flag is permitted for this player in this region"); - else - player.sendMessage("[mcMMO DEBUG] World Guard main flag is DENIED for this player in this region"); - - if(WorldGuardManager.getInstance().hasXPFlag(player)) - player.sendMessage("[mcMMO DEBUG] World Guard xp flag is permitted for this player in this region"); - else - player.sendMessage("[mcMMO DEBUG] World Guard xp flag is not permitted for this player in this region"); - } - - if(blockState instanceof Furnace furnace) - { - if(mcMMO.getSmeltingTracker().isFurnaceOwned(furnace)) - { - player.sendMessage("[mcMMO DEBUG] This furnace has a registered owner"); - OfflinePlayer furnacePlayer = mcMMO.getSmeltingTracker().getFurnaceOwner(furnace); - if(furnacePlayer != null) - { - player.sendMessage("[mcMMO DEBUG] This furnace is owned by player "+furnacePlayer.getName()); - } + if (WorldGuardUtils.isWorldGuardLoaded()) { + if (WorldGuardManager.getInstance().hasMainFlag(player)) { + player.sendMessage( + "[mcMMO DEBUG] World Guard main flag is permitted for this player in this region"); + } else { + player.sendMessage( + "[mcMMO DEBUG] World Guard main flag is DENIED for this player in this region"); + } + + if (WorldGuardManager.getInstance().hasXPFlag(player)) { + player.sendMessage( + "[mcMMO DEBUG] World Guard xp flag is permitted for this player in this region"); + } else { + player.sendMessage( + "[mcMMO DEBUG] World Guard xp flag is not permitted for this player in this region"); } - else - player.sendMessage("[mcMMO DEBUG] This furnace does not have a registered owner"); } - if(ExperienceConfig.getInstance().isExperienceBarsEnabled()) - player.sendMessage("[mcMMO DEBUG] XP bars are enabled, however you should check per-skill settings to make sure those are enabled."); + if (blockState instanceof Furnace || blockState instanceof BrewingStand) { + if (ContainerMetadataUtils.isContainerOwned(blockState)) { + player.sendMessage("[mcMMO DEBUG] This container has a registered owner"); + final OfflinePlayer furnacePlayer = ContainerMetadataUtils.getContainerOwner( + blockState); + if (furnacePlayer != null) { + player.sendMessage("[mcMMO DEBUG] This container is owned by player " + + furnacePlayer.getName()); + } + } else { + player.sendMessage( + "[mcMMO DEBUG] This container does not have a registered owner"); + } + } - player.sendMessage(ChatColor.RED+"You can turn this debug info off by typing "+ChatColor.GOLD+"/mmodebug"); + if (ExperienceConfig.getInstance().isExperienceBarsEnabled()) { + player.sendMessage( + "[mcMMO DEBUG] XP bars are enabled, however you should check per-skill settings to make sure those are enabled."); + } + + player.sendMessage( + ChatColor.RED + "You can turn this debug info off by typing " + ChatColor.GOLD + + "/mmodebug"); } } - private void cleanupAbilityTools(Player player, McMMOPlayer mcMMOPlayer, BlockState blockState, ItemStack heldItem) { + /** + * Clean up ability tools after a block break event. + * + * @param mmoPlayer The player + * @param block The block + * @param heldItem The item in the player's hand + */ + private void cleanupAbilityTools(McMMOPlayer mmoPlayer, Block block, ItemStack heldItem) { if (HiddenConfig.getInstance().useEnchantmentBuffs()) { - if ((ItemUtils.isPickaxe(heldItem) && !mcMMOPlayer.getAbilityMode(SuperAbilityType.SUPER_BREAKER)) || (ItemUtils.isShovel(heldItem) && !mcMMOPlayer.getAbilityMode(SuperAbilityType.GIGA_DRILL_BREAKER))) { + if ((ItemUtils.isPickaxe(heldItem) + && !mmoPlayer.getAbilityMode(SuperAbilityType.SUPER_BREAKER)) + || (ItemUtils.isShovel(heldItem) + && !mmoPlayer.getAbilityMode(SuperAbilityType.GIGA_DRILL_BREAKER))) { SkillUtils.removeAbilityBuff(heldItem); } } else { - if ((mcMMOPlayer.getAbilityMode(SuperAbilityType.SUPER_BREAKER) && !BlockUtils.affectedBySuperBreaker(blockState)) || (mcMMOPlayer.getAbilityMode(SuperAbilityType.GIGA_DRILL_BREAKER) && !BlockUtils.affectedByGigaDrillBreaker(blockState))) { - SkillUtils.removeAbilityBoostsFromInventory(player); + if ((mmoPlayer.getAbilityMode(SuperAbilityType.SUPER_BREAKER) + && !BlockUtils.affectedBySuperBreaker(block)) + || (mmoPlayer.getAbilityMode(SuperAbilityType.GIGA_DRILL_BREAKER) + && !BlockUtils.affectedByGigaDrillBreaker(block))) { + SkillUtils.removeAbilityBoostsFromInventory(mmoPlayer.getPlayer()); } } } diff --git a/src/main/java/com/gmail/nossr50/listeners/ChunkListener.java b/src/main/java/com/gmail/nossr50/listeners/ChunkListener.java index 761516deb..56580ece8 100644 --- a/src/main/java/com/gmail/nossr50/listeners/ChunkListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/ChunkListener.java @@ -1,20 +1,34 @@ package com.gmail.nossr50.listeners; import com.gmail.nossr50.mcMMO; +import java.util.Arrays; +import org.bukkit.Chunk; import org.bukkit.entity.LivingEntity; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.world.ChunkUnloadEvent; -import java.util.List; - public class ChunkListener implements Listener { - @EventHandler(ignoreCancelled = true) + @EventHandler(ignoreCancelled = true, priority = org.bukkit.event.EventPriority.MONITOR) public void onChunkUnload(ChunkUnloadEvent event) { - List matchingEntities = mcMMO.getTransientEntityTracker().getAllTransientEntitiesInChunk(event.getChunk()); - for(LivingEntity livingEntity : matchingEntities) { - mcMMO.getTransientEntityTracker().removeSummon(livingEntity, null, false); + final Chunk unloadingChunk = event.getChunk(); + + // Avoid processing if chunk is null or unloaded + if (unloadingChunk == null || !unloadingChunk.isLoaded() + || unloadingChunk.getEntities() == null) { + return; + } + + try { + Arrays.stream(unloadingChunk.getEntities()) + .filter(entity -> entity instanceof LivingEntity) + .map(entity -> (LivingEntity) entity) + .forEach(livingEntity -> mcMMO.getTransientEntityTracker() + .removeTrackedEntity(livingEntity)); + } catch (Exception ex) { + mcMMO.p.getLogger().warning( + "Caught exception during chunk unload event processing: " + ex.getMessage()); } } } 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 484faa5bb..000000000 --- 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/listeners/EntityListener.java b/src/main/java/com/gmail/nossr50/listeners/EntityListener.java index e3ac46c5c..34c53367f 100644 --- a/src/main/java/com/gmail/nossr50/listeners/EntityListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/EntityListener.java @@ -1,5 +1,11 @@ package com.gmail.nossr50.listeners; +import static com.gmail.nossr50.util.AttributeMapper.MAPPED_MAX_HEALTH; +import static com.gmail.nossr50.util.MobMetadataUtils.addMobFlags; +import static com.gmail.nossr50.util.MobMetadataUtils.flagMetadata; +import static com.gmail.nossr50.util.MobMetadataUtils.hasMobFlag; +import static com.gmail.nossr50.util.MobMetadataUtils.hasMobFlags; + import com.gmail.nossr50.config.WorldBlacklist; import com.gmail.nossr50.config.experience.ExperienceConfig; import com.gmail.nossr50.datatypes.player.McMMOPlayer; @@ -8,37 +14,72 @@ import com.gmail.nossr50.datatypes.skills.subskills.interfaces.InteractType; import com.gmail.nossr50.events.fake.FakeEntityTameEvent; 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.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; import com.gmail.nossr50.skills.taming.TamingManager; import com.gmail.nossr50.skills.unarmed.UnarmedManager; -import com.gmail.nossr50.util.*; +import com.gmail.nossr50.util.BlockUtils; +import com.gmail.nossr50.util.ItemUtils; +import com.gmail.nossr50.util.MetadataConstants; +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.RandomChanceUtil; +import com.gmail.nossr50.util.random.ProbabilityUtil; import com.gmail.nossr50.util.skills.CombatUtils; -import com.gmail.nossr50.util.skills.SkillActivationType; +import com.gmail.nossr50.util.skills.ProjectileUtils; import com.gmail.nossr50.worldguard.WorldGuardManager; import com.gmail.nossr50.worldguard.WorldGuardUtils; +import java.util.Set; 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; -import org.bukkit.entity.*; +import org.bukkit.entity.AnimalTamer; +import org.bukkit.entity.Animals; +import org.bukkit.entity.ArmorStand; +import org.bukkit.entity.Arrow; +import org.bukkit.entity.Enderman; +import org.bukkit.entity.Endermite; +import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.FallingBlock; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.entity.Projectile; +import org.bukkit.entity.TNTPrimed; +import org.bukkit.entity.Tameable; +import org.bukkit.entity.Trident; +import org.bukkit.entity.Wolf; import org.bukkit.event.Cancellable; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; -import org.bukkit.event.entity.*; +import org.bukkit.event.entity.CreatureSpawnEvent; +import org.bukkit.event.entity.EntityBreedEvent; +import org.bukkit.event.entity.EntityChangeBlockEvent; +import org.bukkit.event.entity.EntityCombustByEntityEvent; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.event.entity.EntityDamageEvent; import org.bukkit.event.entity.EntityDamageEvent.DamageCause; +import org.bukkit.event.entity.EntityDeathEvent; +import org.bukkit.event.entity.EntityExplodeEvent; +import org.bukkit.event.entity.EntityShootBowEvent; +import org.bukkit.event.entity.EntityTameEvent; +import org.bukkit.event.entity.EntityTargetEvent; +import org.bukkit.event.entity.EntityTargetLivingEntityEvent; +import org.bukkit.event.entity.EntityTransformEvent; +import org.bukkit.event.entity.ExplosionPrimeEvent; +import org.bukkit.event.entity.FoodLevelChangeEvent; +import org.bukkit.event.entity.PotionSplashEvent; +import org.bukkit.event.entity.ProjectileHitEvent; +import org.bukkit.event.entity.ProjectileLaunchEvent; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.PotionMeta; @@ -46,156 +87,148 @@ import org.bukkit.metadata.FixedMetadataValue; import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffectType; import org.bukkit.projectiles.ProjectileSource; -import org.jetbrains.annotations.NotNull; public class EntityListener implements Listener { private final mcMMO pluginRef; - private final @NotNull MobMetadataService mobMetadataService; /** - * We can use this {@link NamespacedKey} for {@link Enchantment} comparisons to - * check if a {@link Player} has a {@link Trident} enchanted with "Piercing". + * We can use this {@link NamespacedKey} for {@link Enchantment} comparisons to check if a + * {@link Player} has a {@link Trident} enchanted with "Piercing". */ private final NamespacedKey piercingEnchantment = NamespacedKey.minecraft("piercing"); + private final static Set TRANSFORMABLE_ENTITIES + = Set.of(EntityType.SLIME, EntityType.MAGMA_CUBE); public EntityListener(final mcMMO pluginRef) { this.pluginRef = 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) { + if (event.getEntity() instanceof LivingEntity livingEntity) { //Transfer metadata keys from mob-spawned mobs to new mobs - if(mobMetadataService.hasMobFlags(livingEntity)) { - for(Entity entity : event.getTransformedEntities()) { - if(entity instanceof LivingEntity transformedEntity) { - mobMetadataService.addMobFlags(livingEntity, transformedEntity); + if (hasMobFlags(livingEntity)) { + for (Entity entity : event.getTransformedEntities()) { + if (entity instanceof LivingEntity transformedEntity) { + addMobFlags(livingEntity, transformedEntity); } } } + + // Clear the original slime/magma cubes metadata - it's dead. + if (TRANSFORMABLE_ENTITIES.contains(livingEntity.getType())) { + mcMMO.getTransientMetadataTools().cleanLivingEntityMetadata(livingEntity); + } } } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onEntityTargetEntity(EntityTargetLivingEntityEvent event) { - if(!ExperienceConfig.getInstance().isEndermanEndermiteFarmingPrevented()) + if (!ExperienceConfig.getInstance().isEndermanEndermiteFarmingPrevented()) { return; + } //It's rare but targets can be null sometimes - if(event.getTarget() == null) - { + if (event.getTarget() == null) { return; } //Prevent entities from giving XP if they target endermite - if(event.getTarget() instanceof Endermite) - { - if(event.getEntity() instanceof Enderman enderman) { + if (event.getTarget() instanceof Endermite) { + if (event.getEntity() instanceof Enderman enderman) { - if(!mobMetadataService.hasMobFlag(MobMetaFlagType.EXPLOITED_ENDERMEN, enderman)) { - mobMetadataService.flagMetadata(MobMetaFlagType.EXPLOITED_ENDERMEN, enderman); + if (!hasMobFlag(MobMetaFlagType.EXPLOITED_ENDERMEN, enderman)) { + flagMetadata(MobMetaFlagType.EXPLOITED_ENDERMEN, enderman); } } } } - @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())) + if (WorldBlacklist.isWorldBlacklisted(event.getEntity().getWorld())) { return; + } - if(event.getEntity() instanceof Player player) - { - - /* WORLD GUARD MAIN FLAG CHECK */ - if(WorldGuardUtils.isWorldGuardLoaded()) - { - if(!WorldGuardManager.getInstance().hasMainFlag(player)) - return; - } - + if (event.getEntity() instanceof Player player) { 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; } ItemStack bow = event.getBow(); - if (bow != null - && bow.containsEnchantment(Enchantment.ARROW_INFINITE)) { - projectile.setMetadata(MetadataConstants.METADATA_KEY_INF_ARROW, MetadataConstants.MCMMO_METADATA_VALUE); + if (bow == null) { + return; } - 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())); + if (bow.containsEnchantment(mcMMO.p.getEnchantmentMapper().getInfinity())) { + projectile.setMetadata(MetadataConstants.METADATA_KEY_INF_ARROW, + MetadataConstants.MCMMO_METADATA_VALUE); + } + + // Set BowType, Force, and Distance metadata + 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, arrow.getLocation())); + //Cleanup metadata in 1 minute in case normal collection falls through - CombatUtils.delayArrowMetaCleanup((Projectile) projectile); + CombatUtils.delayArrowMetaCleanup(arrow); } } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onProjectileLaunch(ProjectileLaunchEvent event) { /* WORLD BLACKLIST CHECK */ - if(WorldBlacklist.isWorldBlacklisted(event.getEntity().getWorld())) + if (WorldBlacklist.isWorldBlacklisted(event.getEntity().getWorld())) { return; + } - if(event.getEntity().getShooter() instanceof Player player) - { + if (event.getEntity().getShooter() instanceof Player player) { /* WORLD GUARD MAIN FLAG CHECK */ - if(WorldGuardUtils.isWorldGuardLoaded()) { - if(!WorldGuardManager.getInstance().hasMainFlag(player)) + if (WorldGuardUtils.isWorldGuardLoaded()) { + if (!WorldGuardManager.getInstance().hasMainFlag(player)) { 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(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 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, projectile.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")) { + if (ItemUtils.doesPlayerHaveEnchantmentInHands(player, "piercing")) { return; } - if (RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.ARCHERY_ARROW_RETRIEVAL, player)) { - projectile.setMetadata(MetadataConstants.METADATA_KEY_TRACKED_ARROW, MetadataConstants.MCMMO_METADATA_VALUE); + if (ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.ARCHERY_ARROW_RETRIEVAL, + UserManager.getPlayer(player))) { + arrow.setMetadata(MetadataConstants.METADATA_KEY_TRACKED_ARROW, + MetadataConstants.MCMMO_METADATA_VALUE); } } } @@ -204,18 +237,19 @@ public class EntityListener implements Listener { /** * Monitor EntityChangeBlock events. * - * @param event - * The event to watch + * @param event The event to watch */ @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onEntityChangeBlock(EntityChangeBlockEvent event) { /* WORLD BLACKLIST CHECK */ - if(WorldBlacklist.isWorldBlacklisted(event.getEntity().getWorld())) + if (WorldBlacklist.isWorldBlacklisted(event.getEntity().getWorld())) { return; + } Block block = event.getBlock(); Entity entity = event.getEntity(); - Material notYetReplacedType = block.getState().getType(); //because its from getState() this is the block that hasn't been changed yet, which is likely air/lava/water etc + Material notYetReplacedType = block.getState() + .getType(); //because its from getState() this is the block that hasn't been changed yet, which is likely air/lava/water etc // When the event is fired for the falling block that changes back to a // normal block @@ -234,23 +268,25 @@ public class EntityListener implements Listener { if (entity instanceof FallingBlock || entity instanceof Enderman) { boolean isTracked = entity.hasMetadata(MetadataConstants.METADATA_KEY_TRAVELING_BLOCK); - if (mcMMO.getPlaceStore().isTrue(block) && !isTracked) { - mcMMO.getPlaceStore().setFalse(block); + if (mcMMO.getUserBlockTracker().isIneligible(block) && !isTracked) { + mcMMO.getUserBlockTracker().setEligible(block); - entity.setMetadata(MetadataConstants.METADATA_KEY_TRAVELING_BLOCK, MetadataConstants.MCMMO_METADATA_VALUE); - TravelingBlockMetaCleanup metaCleanupTask = new TravelingBlockMetaCleanup(entity, pluginRef); - mcMMO.p.getFoliaLib().getImpl().runAtEntityTimer(entity, metaCleanupTask, 20, 20*60); //6000 ticks is 5 minutes - } - else if (isTracked) { + entity.setMetadata(MetadataConstants.METADATA_KEY_TRAVELING_BLOCK, + MetadataConstants.MCMMO_METADATA_VALUE); + TravelingBlockMetaCleanup metaCleanupTask = new TravelingBlockMetaCleanup(entity, + pluginRef); + mcMMO.p.getFoliaLib().getScheduler().runAtEntityTimer(entity, metaCleanupTask, 20, + 20 * 60); //6000 ticks is 5 minutes + } else if (isTracked) { BlockUtils.setUnnaturalBlock(block); entity.removeMetadata(MetadataConstants.METADATA_KEY_TRAVELING_BLOCK, pluginRef); } - } else if ((block.getType() == Material.REDSTONE_ORE || block.getType().getKey().getKey().equalsIgnoreCase("deepslate_redstone_ore"))) { + } else if ((block.getType() == Material.REDSTONE_ORE || block.getType().getKey().getKey() + .equalsIgnoreCase("deepslate_redstone_ore"))) { //Redstone ore fire this event and should be ignored - } - else { - if (mcMMO.getPlaceStore().isTrue(block)) { - mcMMO.getPlaceStore().setFalse(block); + } else { + if (mcMMO.getUserBlockTracker().isIneligible(block)) { + mcMMO.getUserBlockTracker().setEligible(block); } } } @@ -259,16 +295,16 @@ public class EntityListener implements Listener { @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void onEntityCombustByEntityEvent(EntityCombustByEntityEvent event) { //Prevent players from setting fire to each other if they are in the same party - if(event.getEntity() instanceof Player defender) { + if (event.getEntity() instanceof Player defender) { - if(event.getCombuster() instanceof Projectile projectile) { - if(projectile.getShooter() instanceof Player attacker) { - if(checkParties(event, defender, attacker)) { + if (event.getCombuster() instanceof Projectile projectile) { + if (projectile.getShooter() instanceof Player attacker) { + if (checkIfInPartyOrSamePlayer(event, defender, attacker)) { event.setCancelled(true); } } - } else if(event.getCombuster() instanceof Player attacker) { - if(checkParties(event, defender, attacker)) { + } else if (event.getCombuster() instanceof Player attacker) { + if (checkIfInPartyOrSamePlayer(event, defender, attacker)) { event.setCancelled(true); } } @@ -278,8 +314,7 @@ public class EntityListener implements Listener { /** * Handle EntityDamageByEntity events that involve modifying the event. * - * @param event - * The event to watch + * @param event The event to watch */ @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void onEntityDamageByEntity(EntityDamageByEntityEvent event) { @@ -293,18 +328,18 @@ public class EntityListener implements Listener { Entity defender = event.getEntity(); Entity attacker = event.getDamager(); - if(WorldGuardUtils.isWorldGuardLoaded()) - { - if(attacker instanceof Player) { + if (WorldGuardUtils.isWorldGuardLoaded()) { + if (attacker instanceof Player) { - if(!WorldGuardManager.getInstance().hasMainFlag((Player) attacker)) { + if (!WorldGuardManager.getInstance().hasMainFlag((Player) attacker)) { return; } - } else if(attacker instanceof Projectile projectile) { + } else if (attacker instanceof Projectile projectile) { - if(projectile.getShooter() instanceof Player) { - if(!WorldGuardManager.getInstance().hasMainFlag((Player) projectile.getShooter())) { + if (projectile.getShooter() instanceof Player) { + if (!WorldGuardManager.getInstance() + .hasMainFlag((Player) projectile.getShooter())) { return; } } @@ -313,7 +348,7 @@ public class EntityListener implements Listener { } /* WORLD BLACKLIST CHECK */ - if(WorldBlacklist.isWorldBlacklisted(event.getEntity().getWorld())) { + if (WorldBlacklist.isWorldBlacklisted(event.getEntity().getWorld())) { return; } @@ -321,16 +356,13 @@ public class EntityListener implements Listener { // However, for entities, we do not wanna cancel this event to allow plugins to observe changes // properly - if (CombatUtils.isProcessingNoInvulnDamage()) { - return; - } - if (event.getEntity() instanceof ArmorStand) { return; } - - if ((ExperienceConfig.getInstance().isNPCInteractionPrevented() && Misc.isNPCEntityExcludingVillagers(defender)) || !defender.isValid() || !(defender instanceof LivingEntity target)) { + if ((ExperienceConfig.getInstance().isNPCInteractionPrevented() + && Misc.isNPCEntityExcludingVillagers(defender)) || !defender.isValid() + || !(defender instanceof LivingEntity target)) { return; } @@ -338,7 +370,8 @@ public class EntityListener implements Listener { return; } - if (ExperienceConfig.getInstance().isNPCInteractionPrevented() && Misc.isNPCEntityExcludingVillagers(attacker)) { + if (ExperienceConfig.getInstance().isNPCInteractionPrevented() + && Misc.isNPCEntityExcludingVillagers(attacker)) { return; } @@ -352,9 +385,9 @@ public class EntityListener implements Listener { if (animalTamer != null && ((OfflinePlayer) animalTamer).isOnline()) { attacker = (Entity) animalTamer; } - } - else if (attacker instanceof TNTPrimed && defender instanceof Player) { - if (BlastMining.processBlastMiningExplosion(event, (TNTPrimed) attacker, (Player) defender)) { + } else if (attacker instanceof TNTPrimed && defender instanceof Player) { + if (BlastMining.processBlastMiningExplosion(event, (TNTPrimed) attacker, + (Player) defender)) { return; } } @@ -362,18 +395,19 @@ public class EntityListener implements Listener { //Friendly fire checks if (defender instanceof Player defendingPlayer) { //If the attacker is a Player or a projectile belonging to a player - if(attacker instanceof Projectile projectile) { - if(projectile.getShooter() instanceof Player attackingPlayer && !attackingPlayer.equals(defendingPlayer)) { - //Check for party friendly fire and cancel the event - if (checkParties(event, defendingPlayer, attackingPlayer)) { + if (attacker instanceof Projectile projectile) { + if (projectile.getShooter() instanceof Player attackingPlayer + && !attackingPlayer.equals(defendingPlayer)) { + //Check for friendly fire and cancel the event + if (checkIfInPartyOrSamePlayer(event, defendingPlayer, attackingPlayer)) { return; } } //Deflect checks - final McMMOPlayer mcMMOPlayer = UserManager.getPlayer(defendingPlayer); - if (mcMMOPlayer != null) { - UnarmedManager unarmedManager = mcMMOPlayer.getUnarmedManager(); + final McMMOPlayer mmoPlayer = UserManager.getPlayer(defendingPlayer); + if (mmoPlayer != null) { + UnarmedManager unarmedManager = mmoPlayer.getUnarmedManager(); if (unarmedManager.canDeflect()) { if (projectile instanceof Arrow && unarmedManager.deflectCheck()) { @@ -382,16 +416,17 @@ public class EntityListener implements Listener { } } } - } else if (attacker instanceof Player attackingPlayer){ - if (checkParties(event, defendingPlayer, attackingPlayer)) + } else if (attacker instanceof Player attackingPlayer) { + if (checkIfInPartyOrSamePlayer(event, defendingPlayer, attackingPlayer)) { return; + } } } //Required setup for processCombatAttack - if(attacker instanceof Projectile) { + if (attacker instanceof Projectile) { ProjectileSource shooter = ((Projectile) attacker).getShooter(); - if(shooter instanceof LivingEntity) { + if (shooter instanceof LivingEntity) { attacker = (LivingEntity) shooter; } } @@ -405,8 +440,8 @@ public class EntityListener implements Listener { * Surprising this kind of thing * */ - if(mcMMO.isProjectKorraEnabled()) { - if(event.getFinalDamage() == 0) { + if (mcMMO.isProjectKorraEnabled()) { + if (event.getFinalDamage() == 0) { return; } } @@ -415,39 +450,45 @@ public class EntityListener implements Listener { CombatUtils.handleHealthbars(attacker, target, event.getFinalDamage(), pluginRef); } - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = false) + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = false) public void onEntityDamageMonitor(EntityDamageByEntityEvent entityDamageEvent) { - if(entityDamageEvent.getEntity() instanceof LivingEntity livingEntity) { + if (entityDamageEvent.getEntity() instanceof LivingEntity livingEntity) { - if(entityDamageEvent.getFinalDamage() >= livingEntity.getHealth()) { + if (entityDamageEvent.getFinalDamage() >= livingEntity.getHealth()) { //This sets entity names back to whatever they are supposed to be CombatUtils.fixNames(livingEntity); } } - if(entityDamageEvent.getDamager() instanceof Projectile) { - CombatUtils.cleanupArrowMetadata((Projectile) entityDamageEvent.getDamager()); + if (entityDamageEvent.getDamager() instanceof Arrow arrow) { + CombatUtils.delayArrowMetaCleanup(arrow); } - if(entityDamageEvent.getEntity() instanceof Player player && entityDamageEvent.getDamager() instanceof Player) { - McMMOPlayer mmoPlayer = UserManager.getPlayer(player); - if(mmoPlayer != null) { - if(mmoPlayer.isDebugMode()) { - player.sendMessage(ChatColor.GOLD + "(mmodebug start of combat report) EntityDamageByEntityEvent DEBUG Info:"); + if (entityDamageEvent.getEntity() instanceof Player player + && entityDamageEvent.getDamager() instanceof Player) { + final McMMOPlayer mmoPlayer = UserManager.getPlayer(player); + if (mmoPlayer != null) { + if (mmoPlayer.isDebugMode()) { + player.sendMessage(ChatColor.GOLD + + "(mmodebug start of combat report) EntityDamageByEntityEvent DEBUG Info:"); player.sendMessage("You are being damaged by another player in this event"); player.sendMessage("Raw Damage: " + entityDamageEvent.getDamage()); - player.sendMessage("Your max health: "+player.getAttribute(Attribute.GENERIC_MAX_HEALTH).getValue()); - player.sendMessage("Your current health: "+player.getHealth()); + player.sendMessage("Your max health: " + player.getAttribute(MAPPED_MAX_HEALTH) + .getValue()); + player.sendMessage("Your current health: " + player.getHealth()); player.sendMessage(ChatColor.GREEN + "Damage Modifiers (final damage)"); for (EntityDamageEvent.DamageModifier modifier : EntityDamageEvent.DamageModifier.values()) { - player.sendMessage("Modifier "+modifier.name()+": " + entityDamageEvent.getDamage(modifier)); + player.sendMessage( + "Modifier " + modifier.name() + ": " + entityDamageEvent.getDamage( + modifier)); } player.sendMessage("Final damage: " + entityDamageEvent.getFinalDamage()); - if(entityDamageEvent.isCancelled()) { - player.sendMessage("Event was cancelled, which means no damage should be done."); + if (entityDamageEvent.isCancelled()) { + player.sendMessage( + "Event was cancelled, which means no damage should be done."); } player.sendMessage(ChatColor.RED + "(mmodebug end of combat report)"); @@ -455,25 +496,31 @@ public class EntityListener implements Listener { } } - if(entityDamageEvent.getDamager() instanceof Player player && entityDamageEvent.getEntity() instanceof Player otherPlayer) { - McMMOPlayer mmoPlayer = UserManager.getPlayer(player); - if(mmoPlayer != null) { - if(mmoPlayer.isDebugMode()) { - player.sendMessage(ChatColor.GOLD + "(mmodebug start of combat report) EntityDamageByEntityEvent DEBUG Info:"); + if (entityDamageEvent.getDamager() instanceof Player player + && entityDamageEvent.getEntity() instanceof Player otherPlayer) { + final McMMOPlayer mmoPlayer = UserManager.getPlayer(player); + if (mmoPlayer != null) { + if (mmoPlayer.isDebugMode()) { + player.sendMessage(ChatColor.GOLD + + "(mmodebug start of combat report) EntityDamageByEntityEvent DEBUG Info:"); player.sendMessage("You are dealing damage to another player in this event"); player.sendMessage("Raw Damage: " + entityDamageEvent.getDamage()); player.sendMessage(ChatColor.GREEN + "Damage Modifiers (final damage)"); for (EntityDamageEvent.DamageModifier modifier : EntityDamageEvent.DamageModifier.values()) { - player.sendMessage("Modifier "+modifier.name()+": " + entityDamageEvent.getDamage(modifier)); + player.sendMessage( + "Modifier " + modifier.name() + ": " + entityDamageEvent.getDamage( + modifier)); } player.sendMessage("Final damage: " + entityDamageEvent.getFinalDamage()); - player.sendMessage("Target players max health: "+otherPlayer.getAttribute(Attribute.GENERIC_MAX_HEALTH).getValue()); - player.sendMessage("Target players current health: "+otherPlayer.getHealth()); + player.sendMessage("Target players max health: " + otherPlayer.getAttribute( + MAPPED_MAX_HEALTH).getValue()); + player.sendMessage("Target players current health: " + otherPlayer.getHealth()); - if(entityDamageEvent.isCancelled()) { - player.sendMessage("Event was cancelled, which means no damage should be done."); + if (entityDamageEvent.isCancelled()) { + player.sendMessage( + "Event was cancelled, which means no damage should be done."); } player.sendMessage(ChatColor.RED + "(mmodebug end of combat report)"); @@ -482,52 +529,58 @@ public class EntityListener implements Listener { } } - public boolean checkParties(Cancellable event, Player defendingPlayer, Player attackingPlayer) { - if (!UserManager.hasPlayerDataKey(defendingPlayer) || !UserManager.hasPlayerDataKey(attackingPlayer)) { - return true; - } - - // We want to make sure we're not gaining XP or applying abilities - // when we hit ourselves + public boolean checkIfInPartyOrSamePlayer(Cancellable event, Player defendingPlayer, + Player attackingPlayer) { + // This check is probably necessary outside of the party system if (defendingPlayer.equals(attackingPlayer)) { return true; } + if (!pluginRef.isPartySystemEnabled()) { + return false; + } + + if (!UserManager.hasPlayerDataKey(defendingPlayer) || !UserManager.hasPlayerDataKey( + attackingPlayer)) { + return true; + } + //Party Friendly Fire - if(!mcMMO.p.getGeneralConfig().getPartyFriendlyFire()) - if ((PartyManager.inSameParty(defendingPlayer, attackingPlayer) - || PartyManager.areAllies(defendingPlayer, attackingPlayer)) + if (!mcMMO.p.getGeneralConfig().getPartyFriendlyFire()) { + if ((mcMMO.p.getPartyManager().inSameParty(defendingPlayer, attackingPlayer) + || mcMMO.p.getPartyManager().areAllies(defendingPlayer, attackingPlayer)) && !(Permissions.friendlyFire(attackingPlayer) && Permissions.friendlyFire(defendingPlayer))) { event.setCancelled(true); return true; } + } return false; } /** * Handle EntityDamage events that involve modifying the event. * - * @param event - * The event to modify + * @param event The event to modify */ @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void onEntityDamage(EntityDamageEvent event) { /* WORLD BLACKLIST CHECK */ - if(WorldBlacklist.isWorldBlacklisted(event.getEntity().getWorld())) + if (WorldBlacklist.isWorldBlacklisted(event.getEntity().getWorld())) { return; - - if(event.getEntity().hasMetadata(MetadataConstants.METADATA_KEY_EXPLOSION_FROM_RUPTURE)) { - event.getEntity().removeMetadata(MetadataConstants.METADATA_KEY_EXPLOSION_FROM_RUPTURE, mcMMO.p); } - if(event.getEntity() instanceof Player player) - { + if (event.getEntity().hasMetadata(MetadataConstants.METADATA_KEY_EXPLOSION_FROM_RUPTURE)) { + event.getEntity() + .removeMetadata(MetadataConstants.METADATA_KEY_EXPLOSION_FROM_RUPTURE, mcMMO.p); + } + + if (event.getEntity() instanceof Player player) { /* WORLD GUARD MAIN FLAG CHECK */ - if(WorldGuardUtils.isWorldGuardLoaded()) - { - if(!WorldGuardManager.getInstance().hasMainFlag(player)) + if (WorldGuardUtils.isWorldGuardLoaded()) { + if (!WorldGuardManager.getInstance().hasMainFlag(player)) { return; + } } } @@ -563,7 +616,9 @@ public class EntityListener implements Listener { } */ - if ((ExperienceConfig.getInstance().isNPCInteractionPrevented() && Misc.isNPCEntityExcludingVillagers(entity)) || !entity.isValid() || !(entity instanceof LivingEntity livingEntity)) { + if ((ExperienceConfig.getInstance().isNPCInteractionPrevented() + && Misc.isNPCEntityExcludingVillagers(entity)) || !entity.isValid() + || !(entity instanceof LivingEntity livingEntity)) { return; } @@ -574,50 +629,47 @@ public class EntityListener implements Listener { DamageCause cause = event.getCause(); if (livingEntity instanceof Player) { - Player player = (Player) entity; + final Player player = (Player) entity; if (!UserManager.hasPlayerDataKey(player)) { return; } - McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player); + final McMMOPlayer mmoPlayer = UserManager.getPlayer(player); //Profile not loaded - if(mcMMOPlayer == null) + if (mmoPlayer == null) { return; + } /* Check for invincibility */ - if (mcMMOPlayer.getGodMode()) { + if (mmoPlayer.getGodMode()) { event.setCancelled(true); return; } if (event.getFinalDamage() >= 1) { - mcMMOPlayer.actualizeRecentlyHurt(); + mmoPlayer.actualizeRecentlyHurt(); } - } - - else if (livingEntity instanceof Tameable pet) { + } else if (livingEntity instanceof Tameable pet) { AnimalTamer owner = pet.getOwner(); - if(owner instanceof Player player) - { + if (owner instanceof Player player) { /* WORLD GUARD MAIN FLAG CHECK */ - if(WorldGuardUtils.isWorldGuardLoaded()) - { - if(!WorldGuardManager.getInstance().hasMainFlag(player)) + if (WorldGuardUtils.isWorldGuardLoaded()) { + if (!WorldGuardManager.getInstance().hasMainFlag(player)) { return; + } } } if (Taming.canPreventDamage(pet, owner)) { - Player player = (Player) owner; + final Player player = (Player) owner; Wolf wolf = (Wolf) pet; //Profile not loaded - if(UserManager.getPlayer(player) == null) - { + if (UserManager.getPlayer(player) == null) { return; } @@ -685,34 +737,40 @@ public class EntityListener implements Listener { /** * Monitor EntityDeath events. * - * @param event - * The event to watch + * @param event The event to watch */ @EventHandler(priority = EventPriority.LOWEST) public void onEntityDeathLowest(EntityDeathEvent event) { - mcMMO.getTransientMetadataTools().cleanLivingEntityMetadata(event.getEntity()); + final LivingEntity entity = event.getEntity(); + + // Clear metadata for Slimes/Magma Cubes after transformation events take place, otherwise small spawned slimes will not have any tags + if (TRANSFORMABLE_ENTITIES.contains(entity.getType())) { + return; + } + + mcMMO.getTransientMetadataTools().cleanLivingEntityMetadata(entity); } /** * Monitor EntityDeath events. * - * @param event - * The event to watch + * @param event The event to watch */ @EventHandler(ignoreCancelled = true) public void onEntityDeath(EntityDeathEvent event) { - LivingEntity entity = event.getEntity(); + final LivingEntity entity = event.getEntity(); - if(mcMMO.getTransientEntityTracker().isTransientSummon(entity)) { - mcMMO.getTransientEntityTracker().removeSummon(entity, null, false); + if (mcMMO.getTransientEntityTracker().isTransient(entity)) { + mcMMO.getTransientEntityTracker().killSummonAndCleanMobFlags(entity, null, false); } /* WORLD BLACKLIST CHECK */ - if(WorldBlacklist.isWorldBlacklisted(event.getEntity().getWorld())) { + if (WorldBlacklist.isWorldBlacklisted(event.getEntity().getWorld())) { return; } - if (ExperienceConfig.getInstance().isNPCInteractionPrevented() && Misc.isNPCEntityExcludingVillagers(entity)) { + if (ExperienceConfig.getInstance().isNPCInteractionPrevented() + && Misc.isNPCEntityExcludingVillagers(entity)) { return; } @@ -722,14 +780,14 @@ public class EntityListener implements Listener { /** * Monitor CreatureSpawn events. * - * @param event - * The event to watch + * @param event The event to watch */ @EventHandler(priority = EventPriority.MONITOR) public void onCreatureSpawn(CreatureSpawnEvent event) { /* WORLD BLACKLIST CHECK */ - if(WorldBlacklist.isWorldBlacklisted(event.getEntity().getWorld())) + if (WorldBlacklist.isWorldBlacklisted(event.getEntity().getWorld())) { return; + } LivingEntity livingEntity = event.getEntity(); @@ -752,20 +810,22 @@ public class EntityListener implements Listener { } } - private void trackSpawnedAndPassengers(LivingEntity livingEntity, MobMetaFlagType mobMetaFlagType) { - mobMetadataService.flagMetadata(mobMetaFlagType, livingEntity); + private void trackSpawnedAndPassengers(LivingEntity livingEntity, + MobMetaFlagType mobMetaFlagType) { + flagMetadata(mobMetaFlagType, livingEntity); - for(Entity passenger : livingEntity.getPassengers()) { - if(passenger != null) { - mobMetadataService.flagMetadata(mobMetaFlagType, livingEntity); + for (Entity passenger : livingEntity.getPassengers()) { + if (passenger != null) { + flagMetadata(mobMetaFlagType, livingEntity); } } } @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) public void onEntityBreed(EntityBreedEvent event) { - if(ExperienceConfig.getInstance().isCOTWBreedingPrevented()) { - if(mobMetadataService.hasMobFlag(MobMetaFlagType.COTW_SUMMONED_MOB, event.getFather()) || mobMetadataService.hasMobFlag(MobMetaFlagType.COTW_SUMMONED_MOB, event.getMother())) { + if (ExperienceConfig.getInstance().isCOTWBreedingPrevented()) { + if (hasMobFlag(MobMetaFlagType.COTW_SUMMONED_MOB, event.getFather()) || hasMobFlag( + MobMetaFlagType.COTW_SUMMONED_MOB, event.getMother())) { event.setCancelled(true); Animals mom = (Animals) event.getMother(); Animals father = (Animals) event.getFather(); @@ -775,8 +835,9 @@ public class EntityListener implements Listener { father.setLoveModeTicks(0); //Inform the player - if(event.getBreeder() instanceof Player player) { - NotificationManager.sendPlayerInformationChatOnly(player, "Taming.Summon.COTW.BreedingDisallowed"); + if (event.getBreeder() instanceof Player player) { + NotificationManager.sendPlayerInformationChatOnly(player, + "Taming.Summon.COTW.BreedingDisallowed"); } } } @@ -785,43 +846,44 @@ public class EntityListener implements Listener { /** * Handle ExplosionPrime events that involve modifying the event. * - * @param event - * The event to modify + * @param event The event to modify */ @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void onExplosionPrime(ExplosionPrimeEvent event) { /* WORLD BLACKLIST CHECK */ - if(WorldBlacklist.isWorldBlacklisted(event.getEntity().getWorld())) + if (WorldBlacklist.isWorldBlacklisted(event.getEntity().getWorld())) { return; + } - Entity entity = event.getEntity(); + final Entity entity = event.getEntity(); - if (!(entity instanceof TNTPrimed) || !entity.hasMetadata(MetadataConstants.METADATA_KEY_TRACKED_TNT)) { + if (!(entity instanceof TNTPrimed) || !entity.hasMetadata( + MetadataConstants.METADATA_KEY_TRACKED_TNT)) { return; } // We can make this assumption because we (should) be the only ones // using this exact metadata - Player player = pluginRef.getServer().getPlayerExact(entity.getMetadata(MetadataConstants.METADATA_KEY_TRACKED_TNT).get(0).asString()); + final Player player = pluginRef.getServer().getPlayerExact( + entity.getMetadata(MetadataConstants.METADATA_KEY_TRACKED_TNT).get(0).asString()); if (!UserManager.hasPlayerDataKey(player)) { return; } - //Profile not loaded - if(UserManager.getPlayer(player) == null) - { + // Profile is not loaded + if (UserManager.getPlayer(player) == null) { return; } /* WORLD GUARD MAIN FLAG CHECK */ - if(WorldGuardUtils.isWorldGuardLoaded()) - { - if(!WorldGuardManager.getInstance().hasMainFlag(player)) + if (WorldGuardUtils.isWorldGuardLoaded()) { + if (!WorldGuardManager.getInstance().hasMainFlag(player)) { return; + } } - MiningManager miningManager = UserManager.getPlayer(player).getMiningManager(); + final MiningManager miningManager = UserManager.getPlayer(player).getMiningManager(); if (miningManager.canUseBiggerBombs()) { event.setRadius(miningManager.biggerBombs(event.getRadius())); @@ -831,39 +893,40 @@ public class EntityListener implements Listener { /** * Handle EntityExplode events that involve modifying the event. * - * @param event - * The event to modify + * @param event The event to modify */ @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void onEnitityExplode(EntityExplodeEvent event) { /* WORLD BLACKLIST CHECK */ - if(WorldBlacklist.isWorldBlacklisted(event.getEntity().getWorld())) + if (WorldBlacklist.isWorldBlacklisted(event.getEntity().getWorld())) { return; + } Entity entity = event.getEntity(); - if (!(entity instanceof TNTPrimed) || !entity.hasMetadata(MetadataConstants.METADATA_KEY_TRACKED_TNT)) { + if (!(entity instanceof TNTPrimed) || !entity.hasMetadata( + MetadataConstants.METADATA_KEY_TRACKED_TNT)) { return; } // We can make this assumption because we (should) be the only ones // using this exact metadata - Player player = pluginRef.getServer().getPlayerExact(entity.getMetadata(MetadataConstants.METADATA_KEY_TRACKED_TNT).get(0).asString()); + Player player = pluginRef.getServer().getPlayerExact( + entity.getMetadata(MetadataConstants.METADATA_KEY_TRACKED_TNT).get(0).asString()); if (!UserManager.hasPlayerDataKey(player)) { return; } /* WORLD GUARD MAIN FLAG CHECK */ - if(WorldGuardUtils.isWorldGuardLoaded()) - { - if(!WorldGuardManager.getInstance().hasMainFlag(player)) + if (WorldGuardUtils.isWorldGuardLoaded()) { + if (!WorldGuardManager.getInstance().hasMainFlag(player)) { return; + } } //Profile not loaded - if(UserManager.getPlayer(player) == null) - { + if (UserManager.getPlayer(player) == null) { return; } @@ -878,14 +941,14 @@ public class EntityListener implements Listener { /** * Handle FoodLevelChange events that involve modifying the event. * - * @param event - * The event to modify + * @param event The event to modify */ @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) public void onFoodLevelChange(FoodLevelChangeEvent event) { /* WORLD BLACKLIST CHECK */ - if(WorldBlacklist.isWorldBlacklisted(event.getEntity().getWorld())) + if (WorldBlacklist.isWorldBlacklisted(event.getEntity().getWorld())) { return; + } Entity entity = event.getEntity(); @@ -894,16 +957,15 @@ public class EntityListener implements Listener { } //Profile not loaded - if(UserManager.getPlayer(player) == null) - { + if (UserManager.getPlayer(player) == null) { return; } /* WORLD GUARD MAIN FLAG CHECK */ - if(WorldGuardUtils.isWorldGuardLoaded()) - { - if(!WorldGuardManager.getInstance().hasMainFlag(player)) + if (WorldGuardUtils.isWorldGuardLoaded()) { + if (!WorldGuardManager.getInstance().hasMainFlag(player)) { return; + } } if (!UserManager.hasPlayerDataKey(player)) { @@ -922,9 +984,11 @@ public class EntityListener implements Listener { //The main hand is used over the off hand if they both have food, so check the main hand first Material foodInHand; - if(mcMMO.getMaterialMapStore().isFood(player.getInventory().getItemInMainHand().getType())) { + if (mcMMO.getMaterialMapStore() + .isFood(player.getInventory().getItemInMainHand().getType())) { foodInHand = player.getInventory().getItemInMainHand().getType(); - } else if(mcMMO.getMaterialMapStore().isFood(player.getInventory().getItemInOffHand().getType())) { + } else if (mcMMO.getMaterialMapStore() + .isFood(player.getInventory().getItemInOffHand().getType())) { foodInHand = player.getInventory().getItemInOffHand().getType(); } else { return; //Not Food @@ -937,9 +1001,10 @@ public class EntityListener implements Listener { */ //Hacky 1.17 support - if(foodInHand.getKey().getKey().equalsIgnoreCase("glow_berries")) { + if (foodInHand.getKey().getKey().equalsIgnoreCase("glow_berries")) { if (Permissions.isSubSkillEnabled(player, SubSkillType.HERBALISM_FARMERS_DIET)) { - event.setFoodLevel(UserManager.getPlayer(player).getHerbalismManager().farmersDiet(newFoodLevel)); + event.setFoodLevel(UserManager.getPlayer(player).getHerbalismManager() + .farmersDiet(newFoodLevel)); } return; @@ -947,41 +1012,43 @@ public class EntityListener implements Listener { switch (foodInHand) { case BAKED_POTATO: /* - * RESTORES 3 HUNGER - RESTORES 5 1/2 HUNGER @ - * 1000 - */ + * RESTORES 3 HUNGER - RESTORES 5 1/2 HUNGER @ + * 1000 + */ case BEETROOT: case BREAD: /* RESTORES 2 1/2 HUNGER - RESTORES 5 HUNGER @ 1000 */ case CARROT: /* - * RESTORES 2 HUNGER - RESTORES 4 1/2 HUNGER @ - * 1000 - */ + * RESTORES 2 HUNGER - RESTORES 4 1/2 HUNGER @ + * 1000 + */ case GOLDEN_CARROT: /* - * RESTORES 3 HUNGER - RESTORES 5 1/2 HUNGER @ - * 1000 - */ + * RESTORES 3 HUNGER - RESTORES 5 1/2 HUNGER @ + * 1000 + */ case MUSHROOM_STEW: /* - * RESTORES 4 HUNGER - RESTORES 6 1/2 HUNGER @ - * 1000 - */ + * RESTORES 4 HUNGER - RESTORES 6 1/2 HUNGER @ + * 1000 + */ case PUMPKIN_PIE: /* - * RESTORES 4 HUNGER - RESTORES 6 1/2 HUNGER @ - * 1000 - */ + * RESTORES 4 HUNGER - RESTORES 6 1/2 HUNGER @ + * 1000 + */ if (Permissions.isSubSkillEnabled(player, SubSkillType.HERBALISM_FARMERS_DIET)) { - event.setFoodLevel(UserManager.getPlayer(player).getHerbalismManager().farmersDiet(newFoodLevel)); + event.setFoodLevel(UserManager.getPlayer(player).getHerbalismManager() + .farmersDiet(newFoodLevel)); } return; case COOKIE: /* RESTORES 1/2 HUNGER - RESTORES 2 HUNGER @ 1000 */ case MELON_SLICE: /* RESTORES 1 HUNGER - RESTORES 2 1/2 HUNGER @ 1000 */ case POISONOUS_POTATO: /* - * RESTORES 1 HUNGER - RESTORES 2 1/2 HUNGER - * @ 1000 - */ + * RESTORES 1 HUNGER - RESTORES 2 1/2 HUNGER + * @ 1000 + */ case POTATO: /* RESTORES 1/2 HUNGER - RESTORES 2 HUNGER @ 1000 */ if (Permissions.isSubSkillEnabled(player, SubSkillType.HERBALISM_FARMERS_DIET)) { - event.setFoodLevel(UserManager.getPlayer(player).getHerbalismManager().farmersDiet(newFoodLevel)); + event.setFoodLevel(UserManager.getPlayer(player).getHerbalismManager() + .farmersDiet(newFoodLevel)); } return; case COD: @@ -991,7 +1058,8 @@ public class EntityListener implements Listener { case COOKED_SALMON: if (Permissions.isSubSkillEnabled(player, SubSkillType.FISHING_FISHERMANS_DIET)) { - event.setFoodLevel(UserManager.getPlayer(player).getFishingManager().handleFishermanDiet(newFoodLevel)); + event.setFoodLevel(UserManager.getPlayer(player).getFishingManager() + .handleFishermanDiet(newFoodLevel)); } return; @@ -1002,42 +1070,42 @@ public class EntityListener implements Listener { /** * Monitor EntityTame events. * - * @param event - * The event to watch + * @param event The event to watch */ @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onEntityTame(EntityTameEvent event) { /* WORLD BLACKLIST CHECK */ - if(WorldBlacklist.isWorldBlacklisted(event.getEntity().getWorld())) + if (WorldBlacklist.isWorldBlacklisted(event.getEntity().getWorld())) { return; + } if (event instanceof FakeEntityTameEvent) { return; } - Player player = (Player) event.getOwner(); + final Player player = (Player) event.getOwner(); /* WORLD GUARD MAIN FLAG CHECK */ - if(WorldGuardUtils.isWorldGuardLoaded()) - { - if(!WorldGuardManager.getInstance().hasMainFlag(player)) + if (WorldGuardUtils.isWorldGuardLoaded()) { + if (!WorldGuardManager.getInstance().hasMainFlag(player)) { return; + } } LivingEntity livingEntity = event.getEntity(); if (!UserManager.hasPlayerDataKey(player) - || (ExperienceConfig.getInstance().isNPCInteractionPrevented() && Misc.isNPCEntityExcludingVillagers(livingEntity)) - || mobMetadataService.hasMobFlag(MobMetaFlagType.EGG_MOB, livingEntity) - || mobMetadataService.hasMobFlag(MobMetaFlagType.MOB_SPAWNER_MOB, livingEntity)) { + || (ExperienceConfig.getInstance().isNPCInteractionPrevented() + && Misc.isNPCEntityExcludingVillagers(livingEntity)) + || hasMobFlag(MobMetaFlagType.EGG_MOB, livingEntity) + || hasMobFlag(MobMetaFlagType.MOB_SPAWNER_MOB, livingEntity)) { return; } - mobMetadataService.flagMetadata(MobMetaFlagType.PLAYER_TAMED_MOB, livingEntity); + flagMetadata(MobMetaFlagType.PLAYER_TAMED_MOB, livingEntity); //Profile not loaded - if(UserManager.getPlayer(player) == null) - { + if (UserManager.getPlayer(player) == null) { return; } @@ -1047,14 +1115,14 @@ public class EntityListener implements Listener { /** * Handle EntityTarget events. * - * @param event - * The event to process + * @param event The event to process */ @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void onEntityTarget(EntityTargetEvent event) { /* WORLD BLACKLIST CHECK */ - if(WorldBlacklist.isWorldBlacklisted(event.getEntity().getWorld())) + if (WorldBlacklist.isWorldBlacklisted(event.getEntity().getWorld())) { return; + } Entity entity = event.getEntity(); Entity target = event.getTarget(); @@ -1064,10 +1132,10 @@ public class EntityListener implements Listener { } /* WORLD GUARD MAIN FLAG CHECK */ - if(WorldGuardUtils.isWorldGuardLoaded()) - { - if(!WorldGuardManager.getInstance().hasMainFlag(player)) + if (WorldGuardUtils.isWorldGuardLoaded()) { + if (!WorldGuardManager.getInstance().hasMainFlag(player)) { return; + } } if (!UserManager.hasPlayerDataKey(player) || !CombatUtils.isFriendlyPet(player, tameable)) { @@ -1077,23 +1145,23 @@ public class EntityListener implements Listener { // isFriendlyPet ensures that the Tameable is: Tamed, owned by a player, // and the owner is in the same party // So we can make some assumptions here, about our casting and our check - if (!(Permissions.friendlyFire(player) && Permissions.friendlyFire((Player) tameable.getOwner()))) { + if (!(Permissions.friendlyFire(player) && Permissions.friendlyFire( + (Player) tameable.getOwner()))) { event.setCancelled(true); } } /** - * Handle PotionSplash events in order to fix broken Splash Potion of - * Saturation. + * Handle PotionSplash events in order to fix broken Splash Potion of Saturation. * - * @param event - * The event to process + * @param event The event to process */ @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onPotionSplash(PotionSplashEvent event) { /* WORLD BLACKLIST CHECK */ - if(WorldBlacklist.isWorldBlacklisted(event.getEntity().getWorld())) + if (WorldBlacklist.isWorldBlacklisted(event.getEntity().getWorld())) { return; + } ItemMeta meta = event.getPotion().getItem().getItemMeta(); @@ -1108,10 +1176,24 @@ public class EntityListener implements Listener { for (LivingEntity entity : event.getAffectedEntities()) { int duration = (int) (effect.getDuration() * event.getIntensity(entity)); - entity.addPotionEffect(new PotionEffect(effect.getType(), duration, effect.getAmplifier(), effect.isAmbient())); + entity.addPotionEffect( + new PotionEffect(effect.getType(), duration, effect.getAmplifier(), + effect.isAmbient())); } } } + @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 arrow) { + if (ProjectileUtils.isCrossbowProjectile(arrow)) { + Crossbows.processCrossbows(event, pluginRef, arrow); + } + } + } } diff --git a/src/main/java/com/gmail/nossr50/listeners/InteractionManager.java b/src/main/java/com/gmail/nossr50/listeners/InteractionManager.java index 348ba2af0..b16fa538e 100644 --- a/src/main/java/com/gmail/nossr50/listeners/InteractionManager.java +++ b/src/main/java/com/gmail/nossr50/listeners/InteractionManager.java @@ -6,11 +6,10 @@ import com.gmail.nossr50.datatypes.skills.subskills.interfaces.InteractType; import com.gmail.nossr50.datatypes.skills.subskills.interfaces.Interaction; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.LogUtils; -import org.bukkit.event.Event; - import java.util.ArrayList; import java.util.HashMap; import java.util.Locale; +import org.bukkit.event.Event; public class InteractionManager { private static HashMap> interactRegister; @@ -19,28 +18,33 @@ public class InteractionManager { public static void initMaps() { /* INIT MAPS */ - if(interactRegister == null) + if (interactRegister == null) { interactRegister = new HashMap<>(); + } - if(subSkillList == null) + if (subSkillList == null) { subSkillList = new ArrayList<>(); + } - if(subSkillNameMap == null) + if (subSkillNameMap == null) { subSkillNameMap = new HashMap<>(); + } } /** * Registers subskills with the Interaction registration + * * @param abstractSubSkill the target subskill to register */ - public static void registerSubSkill(AbstractSubSkill abstractSubSkill) - { + public static void registerSubSkill(AbstractSubSkill abstractSubSkill) { //Store a unique copy of each subskill - if(!subSkillList.contains(abstractSubSkill)) + if (!subSkillList.contains(abstractSubSkill)) { subSkillList.add(abstractSubSkill); + } //Init ArrayList - interactRegister.computeIfAbsent(abstractSubSkill.getInteractType(), k -> new ArrayList<>()); + interactRegister.computeIfAbsent(abstractSubSkill.getInteractType(), + k -> new ArrayList<>()); //Registration array reference ArrayList arrayRef = interactRegister.get(abstractSubSkill.getInteractType()); @@ -53,59 +57,59 @@ public class InteractionManager { //Register in name map subSkillNameMap.putIfAbsent(lowerCaseName, abstractSubSkill); - LogUtils.debug(mcMMO.p.getLogger(), "Registered subskill: "+ abstractSubSkill.getConfigKeyName()); + LogUtils.debug(mcMMO.p.getLogger(), + "Registered subskill: " + abstractSubSkill.getConfigKeyName()); } /** - * Grabs the registered abstract skill by its name - * Is not case sensitive + * Grabs the registered abstract skill by its name Is not case sensitive + * * @param name name of subskill, not case sensitive * @return null if the subskill is not registered */ - public static AbstractSubSkill getAbstractByName(String name) - { + public static AbstractSubSkill getAbstractByName(String name) { return subSkillNameMap.get(name.toLowerCase(Locale.ENGLISH)); } /** * Processes the associated Interactions for this event + * * @param event target event * @param plugin instance of mcMMO plugin * @param curInteractType the associated interaction type */ - public static void processEvent(Event event, mcMMO plugin, InteractType curInteractType) - { - if(interactRegister.get(curInteractType) == null) + public static void processEvent(Event event, mcMMO plugin, InteractType curInteractType) { + if (interactRegister.get(curInteractType) == null) { return; + } - for(Interaction interaction : interactRegister.get(curInteractType)) - { + for (Interaction interaction : interactRegister.get(curInteractType)) { interaction.doInteraction(event, plugin); } } /** * Returns the list that contains all unique instances of registered Interaction classes - * Interactions are extensions of abstract classes that represent modifying behaviours in Minecraft through events + * Interactions are extensions of abstract classes that represent modifying behaviours in + * Minecraft through events + * * @return the unique collection of all registered Interaction classes */ - public static ArrayList getSubSkillList() - { + public static ArrayList getSubSkillList() { return subSkillList; } - public static boolean hasSubSkill(String name) - { + public static boolean hasSubSkill(String name) { return getAbstractByName(name) != null; } - public static boolean hasSubSkill(SubSkillType subSkillType) - { + public static boolean hasSubSkill(SubSkillType subSkillType) { return hasSubSkill(subSkillType.getNiceNameNoSpaces(subSkillType)); } /** * Returns the associative map which contains all registered interactions + * * @return the interact register */ public static HashMap> getInteractRegister() { diff --git a/src/main/java/com/gmail/nossr50/listeners/InventoryListener.java b/src/main/java/com/gmail/nossr50/listeners/InventoryListener.java index 4467ff723..4374f74da 100644 --- a/src/main/java/com/gmail/nossr50/listeners/InventoryListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/InventoryListener.java @@ -9,6 +9,7 @@ import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.runnables.player.PlayerUpdateInventoryTask; import com.gmail.nossr50.skills.alchemy.Alchemy; import com.gmail.nossr50.skills.alchemy.AlchemyPotionBrewer; +import com.gmail.nossr50.util.ContainerMetadataUtils; import com.gmail.nossr50.util.ItemUtils; import com.gmail.nossr50.util.MetadataConstants; import com.gmail.nossr50.util.Permissions; @@ -28,8 +29,24 @@ import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; -import org.bukkit.event.inventory.*; -import org.bukkit.inventory.*; +import org.bukkit.event.inventory.BrewEvent; +import org.bukkit.event.inventory.ClickType; +import org.bukkit.event.inventory.CraftItemEvent; +import org.bukkit.event.inventory.FurnaceBurnEvent; +import org.bukkit.event.inventory.FurnaceExtractEvent; +import org.bukkit.event.inventory.FurnaceSmeltEvent; +import org.bukkit.event.inventory.InventoryAction; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.InventoryDragEvent; +import org.bukkit.event.inventory.InventoryMoveItemEvent; +import org.bukkit.event.inventory.InventoryOpenEvent; +import org.bukkit.event.inventory.InventoryType; +import org.bukkit.inventory.BrewerInventory; +import org.bukkit.inventory.FurnaceInventory; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.InventoryHolder; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.PlayerInventory; public class InventoryListener implements Listener { private final mcMMO plugin; @@ -41,44 +58,50 @@ public class InventoryListener implements Listener { @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void onFurnaceBurnEvent(FurnaceBurnEvent event) { /* WORLD BLACKLIST CHECK */ - if(WorldBlacklist.isWorldBlacklisted(event.getBlock().getWorld())) + if (WorldBlacklist.isWorldBlacklisted(event.getBlock().getWorld())) { return; + } Block furnaceBlock = event.getBlock(); BlockState furnaceState = furnaceBlock.getState(); - ItemStack smelting = furnaceState instanceof Furnace ? ((Furnace) furnaceState).getInventory().getSmelting() : null; + ItemStack smelting = + furnaceState instanceof Furnace ? ((Furnace) furnaceState).getInventory() + .getSmelting() : null; - if (!ItemUtils.isSmeltable(smelting)) { + if (!ItemUtils.isSmeltable(smelting) || event.getBurnTime() <= 0) { return; } Furnace furnace = (Furnace) furnaceState; - OfflinePlayer offlinePlayer = mcMMO.getSmeltingTracker().getFurnaceOwner(furnace); + OfflinePlayer offlinePlayer = ContainerMetadataUtils.getContainerOwner(furnace); Player player; - if(offlinePlayer != null && offlinePlayer.isOnline() && offlinePlayer instanceof Player) { + if (offlinePlayer != null && offlinePlayer.isOnline() && offlinePlayer instanceof Player) { player = (Player) offlinePlayer; if (!Permissions.isSubSkillEnabled(player, SubSkillType.SMELTING_FUEL_EFFICIENCY)) { return; } - McMMOPlayer mmoPlayer = UserManager.getPlayer(player); + final McMMOPlayer mmoPlayer = UserManager.getPlayer(player); - if(mmoPlayer != null) { + if (mmoPlayer != null) { boolean debugMode = mmoPlayer.isDebugMode(); - if(debugMode) { + if (debugMode) { player.sendMessage("FURNACE FUEL EFFICIENCY DEBUG REPORT"); - player.sendMessage("Furnace - "+furnace.hashCode()); - player.sendMessage("Furnace Type: "+furnaceBlock.getType()); - player.sendMessage("Burn Length before Fuel Efficiency is applied - "+event.getBurnTime()); + player.sendMessage("Furnace - " + furnace.hashCode()); + player.sendMessage("Furnace Type: " + furnaceBlock.getType()); + player.sendMessage("Burn Length before Fuel Efficiency is applied - " + + event.getBurnTime()); } - event.setBurnTime(mmoPlayer.getSmeltingManager().fuelEfficiency(event.getBurnTime())); + event.setBurnTime( + mmoPlayer.getSmeltingManager().fuelEfficiency(event.getBurnTime())); - if(debugMode) { - player.sendMessage("New Furnace Burn Length (after applying fuel efficiency) "+event.getBurnTime()); + if (debugMode) { + player.sendMessage("New Furnace Burn Length (after applying fuel efficiency) " + + event.getBurnTime()); player.sendMessage(""); } } @@ -88,25 +111,27 @@ public class InventoryListener implements Listener { @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void onFurnaceSmeltEvent(FurnaceSmeltEvent event) { /* WORLD BLACKLIST CHECK */ - if(WorldBlacklist.isWorldBlacklisted(event.getBlock().getWorld())) + if (WorldBlacklist.isWorldBlacklisted(event.getBlock().getWorld())) { return; + } - BlockState blockState = event.getBlock().getState(); //Furnaces can only be cast from a BlockState not a Block + BlockState blockState = event.getBlock() + .getState(); //Furnaces can only be cast from a BlockState not a Block ItemStack smelting = event.getSource(); if (!ItemUtils.isSmeltable(smelting)) { return; } - if(blockState instanceof Furnace furnace) { - OfflinePlayer offlinePlayer = mcMMO.getSmeltingTracker().getFurnaceOwner(furnace); + if (blockState instanceof Furnace furnace) { + OfflinePlayer offlinePlayer = ContainerMetadataUtils.getContainerOwner(furnace); - if(offlinePlayer != null) { + if (offlinePlayer != null) { McMMOPlayer offlineProfile = UserManager.getOfflinePlayer(offlinePlayer); //Profile doesn't exist - if(offlineProfile != null) { + if (offlineProfile != null) { //Process smelting offlineProfile.getSmeltingManager().smeltProcessing(event, furnace); } @@ -117,8 +142,9 @@ public class InventoryListener implements Listener { @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void onFurnaceExtractEvent(FurnaceExtractEvent event) { /* WORLD BLACKLIST CHECK */ - if(WorldBlacklist.isWorldBlacklisted(event.getPlayer().getWorld())) + if (WorldBlacklist.isWorldBlacklisted(event.getPlayer().getWorld())) { return; + } BlockState furnaceBlock = event.getBlock().getState(); @@ -128,21 +154,21 @@ public class InventoryListener implements Listener { Player player = event.getPlayer(); - if(furnaceBlock instanceof Furnace) { + if (furnaceBlock instanceof Furnace) { /* WORLD GUARD MAIN FLAG CHECK */ - if(WorldGuardUtils.isWorldGuardLoaded()) - { - if(!WorldGuardManager.getInstance().hasMainFlag(player)) + if (WorldGuardUtils.isWorldGuardLoaded()) { + if (!WorldGuardManager.getInstance().hasMainFlag(player)) { return; + } } - if (!UserManager.hasPlayerDataKey(player) || !Permissions.vanillaXpBoost(player, PrimarySkillType.SMELTING)) { + if (!UserManager.hasPlayerDataKey(player) || !Permissions.vanillaXpBoost(player, + PrimarySkillType.SMELTING)) { return; } //Profile not loaded - if(UserManager.getPlayer(player) == null) - { + if (UserManager.getPlayer(player) == null) { return; } @@ -155,26 +181,35 @@ public class InventoryListener implements Listener { @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) public void onInventoryClickEventNormal(InventoryClickEvent event) { /* WORLD BLACKLIST CHECK */ - if(WorldBlacklist.isWorldBlacklisted(event.getWhoClicked().getWorld())) + if (WorldBlacklist.isWorldBlacklisted(event.getWhoClicked().getWorld())) { return; + } //We should never care to do processing if the player clicks outside the window -// if(isOutsideWindowClick(event)) +// if (isOutsideWindowClick(event)) // return; Inventory inventory = event.getInventory(); Player player = ((Player) event.getWhoClicked()).getPlayer(); + final McMMOPlayer mmoPlayer = UserManager.getPlayer(player); - if(event.getInventory() instanceof FurnaceInventory) - { - Furnace furnace = mcMMO.getSmeltingTracker().getFurnaceFromInventory(event.getInventory()); - - if (furnace != null) - { - //Switch owners - mcMMO.getSmeltingTracker().processFurnaceOwnership(furnace, player); + if (event.getInventory() instanceof FurnaceInventory furnaceInventory) { + if (!mcMMO.p.getSkillTools() + .doesPlayerHaveSkillPermission(player, PrimarySkillType.SMELTING)) { + return; } + //Switch owners + ContainerMetadataUtils.processContainerOwnership(furnaceInventory.getHolder(), player); + } + + if (event.getInventory() instanceof BrewerInventory brewerInventory) { + if (!mcMMO.p.getSkillTools() + .doesPlayerHaveSkillPermission(player, PrimarySkillType.ALCHEMY)) { + return; + } + // switch owners + ContainerMetadataUtils.processContainerOwnership(brewerInventory.getHolder(), player); } if (!(inventory instanceof BrewerInventory)) { @@ -189,22 +224,29 @@ public class InventoryListener implements Listener { HumanEntity whoClicked = event.getWhoClicked(); - if (!UserManager.hasPlayerDataKey(event.getWhoClicked()) || !Permissions.isSubSkillEnabled(whoClicked, SubSkillType.ALCHEMY_CONCOCTIONS)) { + if (mmoPlayer == null || !Permissions.isSubSkillEnabled(whoClicked, + SubSkillType.ALCHEMY_CONCOCTIONS)) { return; } + // TODO: Investigate why this WG check is all the way down here? /* WORLD GUARD MAIN FLAG CHECK */ - if(WorldGuardUtils.isWorldGuardLoaded()) - { - if(!WorldGuardManager.getInstance().hasMainFlag(player)) + if (WorldGuardUtils.isWorldGuardLoaded()) { + if (!WorldGuardManager.getInstance().hasMainFlag(player)) { return; + } } - ItemStack clicked = event.getCurrentItem(); - ItemStack cursor = event.getCursor(); + final ItemStack clicked = event.getCurrentItem(); + final ItemStack cursor = event.getCursor(); - if ((clicked != null && (clicked.getType() == Material.POTION || clicked.getType() == Material.SPLASH_POTION || clicked.getType() == Material.LINGERING_POTION)) || (cursor != null && (cursor.getType() == Material.POTION || cursor.getType() == Material.SPLASH_POTION || cursor.getType() == Material.LINGERING_POTION))) { - AlchemyPotionBrewer.scheduleCheck(player, stand); + if ((clicked != null && (clicked.getType() == Material.POTION + || clicked.getType() == Material.SPLASH_POTION + || clicked.getType() == Material.LINGERING_POTION)) + || (cursor != null && (cursor.getType() == Material.POTION + || cursor.getType() == Material.SPLASH_POTION + || cursor.getType() == Material.LINGERING_POTION))) { + AlchemyPotionBrewer.scheduleCheck(stand); return; } @@ -214,38 +256,37 @@ public class InventoryListener implements Listener { if (click.isShiftClick()) { switch (slot) { case FUEL: - AlchemyPotionBrewer.scheduleCheck(player, stand); + AlchemyPotionBrewer.scheduleCheck(stand); return; case CONTAINER: case QUICKBAR: - if (!AlchemyPotionBrewer.isValidIngredient(player, clicked)) { + if (!AlchemyPotionBrewer.isValidIngredientByPlayer(player, clicked)) { return; } - if (!AlchemyPotionBrewer.transferItems(event.getView(), event.getRawSlot(), click)) { + if (!AlchemyPotionBrewer.transferItems(event.getView(), event.getRawSlot(), + click)) { return; } event.setCancelled(true); AlchemyPotionBrewer.scheduleUpdate(inventory); - AlchemyPotionBrewer.scheduleCheck(player, stand); + AlchemyPotionBrewer.scheduleCheck(stand); return; default: } - } - else if (slot == InventoryType.SlotType.FUEL) { + } else if (slot == InventoryType.SlotType.FUEL) { boolean emptyClicked = AlchemyPotionBrewer.isEmpty(clicked); if (AlchemyPotionBrewer.isEmpty(cursor)) { if (emptyClicked && click == ClickType.NUMBER_KEY) { - AlchemyPotionBrewer.scheduleCheck(player, stand); + AlchemyPotionBrewer.scheduleCheck(stand); return; } - AlchemyPotionBrewer.scheduleCheck(player, stand); - } - else if (emptyClicked) { - if (AlchemyPotionBrewer.isValidIngredient(player, cursor)) { + AlchemyPotionBrewer.scheduleCheck(stand); + } else if (emptyClicked) { + if (AlchemyPotionBrewer.isValidIngredientByPlayer(player, cursor)) { int amount = cursor.getAmount(); if (click == ClickType.LEFT || (click == ClickType.RIGHT && amount == 1)) { @@ -254,9 +295,8 @@ public class InventoryListener implements Listener { event.setCursor(null); AlchemyPotionBrewer.scheduleUpdate(inventory); - AlchemyPotionBrewer.scheduleCheck(player, stand); - } - else if (click == ClickType.RIGHT) { + AlchemyPotionBrewer.scheduleCheck(stand); + } else if (click == ClickType.RIGHT) { event.setCancelled(true); ItemStack one = cursor.clone(); @@ -269,7 +309,7 @@ public class InventoryListener implements Listener { event.setCursor(rest); AlchemyPotionBrewer.scheduleUpdate(inventory); - AlchemyPotionBrewer.scheduleCheck(player, stand); + AlchemyPotionBrewer.scheduleCheck(stand); } } } @@ -284,8 +324,9 @@ public class InventoryListener implements Listener { @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) public void onInventoryDragEvent(InventoryDragEvent event) { /* WORLD BLACKLIST CHECK */ - if(WorldBlacklist.isWorldBlacklisted(event.getWhoClicked().getWorld())) + if (WorldBlacklist.isWorldBlacklisted(event.getWhoClicked().getWorld())) { return; + } Inventory inventory = event.getInventory(); @@ -301,7 +342,8 @@ public class InventoryListener implements Listener { HumanEntity whoClicked = event.getWhoClicked(); - if (!UserManager.hasPlayerDataKey(event.getWhoClicked()) || !Permissions.isSubSkillEnabled(whoClicked, SubSkillType.ALCHEMY_CONCOCTIONS)) { + if (!UserManager.hasPlayerDataKey(event.getWhoClicked()) || !Permissions.isSubSkillEnabled( + whoClicked, SubSkillType.ALCHEMY_CONCOCTIONS)) { return; } @@ -313,18 +355,18 @@ public class InventoryListener implements Listener { ItemStack ingredient = ((BrewerInventory) inventory).getIngredient(); if (AlchemyPotionBrewer.isEmpty(ingredient) || ingredient.isSimilar(cursor)) { - Player player = (Player) whoClicked; + final Player player = (Player) whoClicked; /* WORLD GUARD MAIN FLAG CHECK */ - if(WorldGuardUtils.isWorldGuardLoaded()) - { - if(!WorldGuardManager.getInstance().hasMainFlag(player)) + if (WorldGuardUtils.isWorldGuardLoaded()) { + if (!WorldGuardManager.getInstance().hasMainFlag(player)) { return; + } } - if (AlchemyPotionBrewer.isValidIngredient(player, cursor)) { + if (AlchemyPotionBrewer.isValidIngredientByPlayer(player, cursor)) { // Not handled: dragging custom ingredients over ingredient slot (does not trigger any event) - AlchemyPotionBrewer.scheduleCheck(player, (BrewingStand) holder); + AlchemyPotionBrewer.scheduleCheck((BrewingStand) holder); return; } @@ -335,14 +377,16 @@ public class InventoryListener implements Listener { // Apparently sometimes vanilla brewing beats our task listener to the actual brew. We handle this by cancelling the vanilla event and finishing our brew ourselves. @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) - public void onBrew(BrewEvent event) - { + public void onBrew(BrewEvent event) { /* WORLD BLACKLIST CHECK */ - if(WorldBlacklist.isWorldBlacklisted(event.getBlock().getWorld())) + if (WorldBlacklist.isWorldBlacklisted(event.getBlock().getWorld())) { return; + } - if (event instanceof FakeBrewEvent) + if (event instanceof FakeBrewEvent) { return; + } + Location location = event.getBlock().getLocation(); if (Alchemy.brewingStandMap.containsKey(location)) { Alchemy.brewingStandMap.get(location).finishImmediately(); @@ -350,59 +394,86 @@ public class InventoryListener implements Listener { } } +// @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) +// public void onBrewStart(BrewingStartEvent event) { +// /* WORLD BLACKLIST CHECK */ +// if (WorldBlacklist.isWorldBlacklisted(event.getBlock().getWorld())) +// return; +// +// if (event instanceof FakeEvent) +// return; +// } + @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) public void onInventoryMoveItemEvent(InventoryMoveItemEvent event) { /* WORLD BLACKLIST CHECK */ - if(event.getSource().getLocation() != null) - if(WorldBlacklist.isWorldBlacklisted(event.getSource().getLocation().getWorld())) + if (event.getSource().getLocation() != null) { + if (WorldBlacklist.isWorldBlacklisted(event.getSource().getLocation().getWorld())) { return; + } + } - Inventory inventory = event.getDestination(); + final Inventory inventory = event.getDestination(); if (!(inventory instanceof BrewerInventory)) { return; } - InventoryHolder holder = inventory.getHolder(); + final InventoryHolder holder = inventory.getHolder(); - if (!(holder instanceof BrewingStand)) { - return; - } + if (holder instanceof BrewingStand brewingStand) { - ItemStack item = event.getItem(); + ItemStack item = event.getItem(); - if (mcMMO.p.getGeneralConfig().getPreventHopperTransferIngredients() && item.getType() != Material.POTION && item.getType() != Material.SPLASH_POTION && item.getType() != Material.LINGERING_POTION) { - event.setCancelled(true); - return; - } + if (mcMMO.p.getGeneralConfig().getPreventHopperTransferIngredients() + && item.getType() != Material.POTION && item.getType() != Material.SPLASH_POTION + && item.getType() != Material.LINGERING_POTION) { + event.setCancelled(true); + return; + } - if (mcMMO.p.getGeneralConfig().getPreventHopperTransferBottles() && (item.getType() == Material.POTION || item.getType() == Material.SPLASH_POTION || item.getType() == Material.LINGERING_POTION)) { - event.setCancelled(true); - return; - } + if (mcMMO.p.getGeneralConfig().getPreventHopperTransferBottles() && ( + item.getType() == Material.POTION || item.getType() == Material.SPLASH_POTION + || item.getType() == Material.LINGERING_POTION)) { + event.setCancelled(true); + return; + } + int ingredientLevel = 1; - if (mcMMO.p.getGeneralConfig().getEnabledForHoppers() && AlchemyPotionBrewer.isValidIngredient(null, item)) { - AlchemyPotionBrewer.scheduleCheck(null, (BrewingStand) holder); + OfflinePlayer offlinePlayer = ContainerMetadataUtils.getContainerOwner(brewingStand); + if (offlinePlayer != null && offlinePlayer.isOnline()) { + final McMMOPlayer mmoPlayer = UserManager.getPlayer(offlinePlayer.getPlayer()); + if (mmoPlayer != null) { + ingredientLevel = mmoPlayer.getAlchemyManager().getTier(); + } + } + + if (mcMMO.p.getGeneralConfig().getEnabledForHoppers() + && AlchemyPotionBrewer.isValidIngredientByLevel(ingredientLevel, item)) { + AlchemyPotionBrewer.scheduleCheck(brewingStand); + } } } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onInventoryClickEvent(InventoryClickEvent event) { - if(event.getCurrentItem() == null) { + if (event.getCurrentItem() == null) { return; } SkillUtils.removeAbilityBuff(event.getCurrentItem()); if (event.getAction() == InventoryAction.HOTBAR_SWAP) { - if(isOutsideWindowClick(event)) + if (isOutsideWindowClick(event)) { return; + } PlayerInventory playerInventory = event.getWhoClicked().getInventory(); - if(playerInventory.getItem(event.getHotbarButton()) != null) + if (playerInventory.getItem(event.getHotbarButton()) != null) { SkillUtils.removeAbilityBuff(playerInventory.getItem(event.getHotbarButton())); + } } } @@ -414,8 +485,9 @@ public class InventoryListener implements Listener { @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onCraftItem(CraftItemEvent event) { /* WORLD BLACKLIST CHECK */ - if(WorldBlacklist.isWorldBlacklisted(event.getWhoClicked().getWorld())) + if (WorldBlacklist.isWorldBlacklisted(event.getWhoClicked().getWorld())) { return; + } final HumanEntity whoClicked = event.getWhoClicked(); @@ -425,21 +497,22 @@ public class InventoryListener implements Listener { ItemStack result = event.getRecipe().getResult(); - //TODO: what is the point of this + //TODO: Used for Chimaera Wing, but not sure it is still necessary if (!ItemUtils.isMcMMOItem(result)) { return; } - Player player = (Player) whoClicked; + final Player player = (Player) whoClicked; /* WORLD GUARD MAIN FLAG CHECK */ - if(WorldGuardUtils.isWorldGuardLoaded()) - { - if(!WorldGuardManager.getInstance().hasMainFlag(player)) + if (WorldGuardUtils.isWorldGuardLoaded()) { + if (!WorldGuardManager.getInstance().hasMainFlag(player)) { return; + } } - mcMMO.p.getFoliaLib().getImpl().runAtEntity(whoClicked, new PlayerUpdateInventoryTask((Player) whoClicked)); + mcMMO.p.getFoliaLib().getScheduler() + .runAtEntity(whoClicked, new PlayerUpdateInventoryTask((Player) whoClicked)); } } diff --git a/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java b/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java index a63b7650e..821bd8b66 100644 --- a/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java @@ -10,7 +10,6 @@ import com.gmail.nossr50.datatypes.skills.subskills.taming.CallOfTheWildType; import com.gmail.nossr50.events.McMMOReplaceVanillaTreasureEvent; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.party.ShareHandler; import com.gmail.nossr50.runnables.MobHealthDisplayUpdaterTask; import com.gmail.nossr50.runnables.player.PlayerProfileLoadingTask; import com.gmail.nossr50.skills.fishing.FishingManager; @@ -21,22 +20,39 @@ import com.gmail.nossr50.skills.repair.RepairManager; import com.gmail.nossr50.skills.salvage.Salvage; import com.gmail.nossr50.skills.salvage.SalvageManager; import com.gmail.nossr50.skills.taming.TamingManager; -import com.gmail.nossr50.util.*; +import com.gmail.nossr50.util.BlockUtils; +import com.gmail.nossr50.util.ChimaeraWing; +import com.gmail.nossr50.util.EventUtils; +import com.gmail.nossr50.util.HardcoreManager; +import com.gmail.nossr50.util.LogUtils; +import com.gmail.nossr50.util.MetadataConstants; +import com.gmail.nossr50.util.Misc; +import com.gmail.nossr50.util.MobHealthbarUtils; +import com.gmail.nossr50.util.Motd; +import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.scoreboards.ScoreboardManager; 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.worldguard.WorldGuardManager; import com.gmail.nossr50.worldguard.WorldGuardUtils; +import java.util.Locale; import org.bukkit.Bukkit; import org.bukkit.GameMode; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.BlockState; import org.bukkit.enchantments.Enchantment; -import org.bukkit.entity.*; +import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.ExperienceOrb; +import org.bukkit.entity.HumanEntity; +import org.bukkit.entity.Item; +import org.bukkit.entity.ItemFrame; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Minecart; +import org.bukkit.entity.Player; +import org.bukkit.entity.Projectile; import org.bukkit.entity.minecart.PoweredMinecart; import org.bukkit.event.Event; import org.bukkit.event.EventHandler; @@ -46,12 +62,21 @@ import org.bukkit.event.block.Action; import org.bukkit.event.entity.EntityDamageByEntityEvent; import org.bukkit.event.entity.EntityPickupItemEvent; import org.bukkit.event.entity.PlayerDeathEvent; -import org.bukkit.event.player.*; +import org.bukkit.event.player.AsyncPlayerChatEvent; +import org.bukkit.event.player.PlayerChangedWorldEvent; +import org.bukkit.event.player.PlayerCommandPreprocessEvent; +import org.bukkit.event.player.PlayerDropItemEvent; +import org.bukkit.event.player.PlayerFishEvent; +import org.bukkit.event.player.PlayerInteractEntityEvent; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.event.player.PlayerRespawnEvent; +import org.bukkit.event.player.PlayerSwapHandItemsEvent; +import org.bukkit.event.player.PlayerTeleportEvent; import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemStack; -import java.util.Locale; - public class PlayerListener implements Listener { private final mcMMO plugin; @@ -62,22 +87,22 @@ public class PlayerListener implements Listener { /** * Monitor PlayerTeleportEvents. *

- * These events are monitored for the purpose of setting the - * player's last teleportation timestamp, in order to prevent - * possible Acrobatics exploitation. + * These events are monitored for the purpose of setting the player's last teleportation + * timestamp, in order to prevent possible Acrobatics exploitation. * * @param event The event to monitor */ @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onPlayerTeleport(PlayerTeleportEvent event) { /* WORLD BLACKLIST CHECK */ - if(WorldBlacklist.isWorldBlacklisted(event.getPlayer().getWorld())) { + if (WorldBlacklist.isWorldBlacklisted(event.getPlayer().getWorld())) { //Remove scoreboards - if(mcMMO.p.getGeneralConfig().getScoreboardsEnabled()) { + if (mcMMO.p.getGeneralConfig().getScoreboardsEnabled()) { ScoreboardManager.teardownPlayer(event.getPlayer()); } return; - } else if(WorldBlacklist.isWorldBlacklisted(event.getFrom().getWorld()) && mcMMO.p.getGeneralConfig().getScoreboardsEnabled()) { + } else if (WorldBlacklist.isWorldBlacklisted(event.getFrom().getWorld()) + && mcMMO.p.getGeneralConfig().getScoreboardsEnabled()) { //This only fires if they are travelling to a non-blacklisted world from a blacklisted world //Setup scoreboards @@ -87,19 +112,20 @@ public class PlayerListener implements Listener { Player player = event.getPlayer(); /* WORLD GUARD MAIN FLAG CHECK */ - if(WorldGuardUtils.isWorldGuardLoaded()) - { - if(!WorldGuardManager.getInstance().hasMainFlag(player)) + if (WorldGuardUtils.isWorldGuardLoaded()) { + if (!WorldGuardManager.getInstance().hasMainFlag(player)) { return; + } } - if (!UserManager.hasPlayerDataKey(player) || mcMMO.p.getGeneralConfig().getXPAfterTeleportCooldown() <= 0 || event.getFrom().equals(event.getTo())) { + if (!UserManager.hasPlayerDataKey(player) + || mcMMO.p.getGeneralConfig().getXPAfterTeleportCooldown() <= 0 || event.getFrom() + .equals(event.getTo())) { return; } //Profile not loaded - if(UserManager.getPlayer(player) == null) - { + if (UserManager.getPlayer(player) == null) { return; } @@ -109,63 +135,73 @@ public class PlayerListener implements Listener { /** * Handle {@link EntityDamageByEntityEvent} at the highest priority. *

- * This handler is used to clear the names of mobs with health bars to - * fix death messages showing mob health bars on death. + * This handler is used to clear the names of mobs with health bars to fix death messages + * showing mob health bars on death. * * @param event the event to listen to */ @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void onEntityDamageByEntityHighest(EntityDamageByEntityEvent event) { // we only care about players as this is for fixing player death messages - if (!(event.getEntity() instanceof Player player)) + if (!(event.getEntity() instanceof Player player)) { return; + } // get the attacker LivingEntity attacker; - if (event.getDamager() instanceof LivingEntity) + if (event.getDamager() instanceof LivingEntity) { attacker = (LivingEntity) event.getDamager(); + } // attempt to find creator of a projectile - else if (event.getDamager() instanceof Projectile && ((Projectile) event.getDamager()).getShooter() instanceof LivingEntity) + else if (event.getDamager() instanceof Projectile + && ((Projectile) event.getDamager()).getShooter() instanceof LivingEntity) { attacker = (LivingEntity) ((Projectile) event.getDamager()).getShooter(); - else + } else { return; + } - if (attacker instanceof HumanEntity) + if (attacker instanceof HumanEntity) { return; + } // world blacklist check - if (WorldBlacklist.isWorldBlacklisted(event.getEntity().getWorld())) + if (WorldBlacklist.isWorldBlacklisted(event.getEntity().getWorld())) { return; + } // world guard main flag check - if (WorldGuardUtils.isWorldGuardLoaded() && !WorldGuardManager.getInstance().hasMainFlag((Player) event.getEntity())) + if (WorldGuardUtils.isWorldGuardLoaded() && !WorldGuardManager.getInstance() + .hasMainFlag((Player) event.getEntity())) { return; + } // we only want to handle player deaths - if ((player.getHealth() - event.getFinalDamage()) > 0) + if ((player.getHealth() - event.getFinalDamage()) > 0) { return; + } // temporarily clear the mob's name new MobHealthDisplayUpdaterTask(attacker).run(); // set the name back - mcMMO.p.getFoliaLib().getImpl().runAtEntityLater(attacker, () -> MobHealthbarUtils.handleMobHealthbars(attacker, 0, mcMMO.p), 1); + mcMMO.p.getFoliaLib().getScheduler().runAtEntityLater(attacker, + () -> MobHealthbarUtils.handleMobHealthbars(attacker, 0, mcMMO.p), 1); } /** * Monitor PlayerDeathEvents. *

- * These events are monitored for the purpose of dealing the penalties - * associated with hardcore and vampirism modes. If neither of these - * modes are enabled, or if the player who died has hardcore bypass - * permissions, this handler does nothing. + * These events are monitored for the purpose of dealing the penalties associated with hardcore + * and vampirism modes. If neither of these modes are enabled, or if the player who died has + * hardcore bypass permissions, this handler does nothing. * * @param event The event to monitor */ @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onPlayerDeathMonitor(PlayerDeathEvent event) { /* WORLD BLACKLIST CHECK */ - if(WorldBlacklist.isWorldBlacklisted(event.getEntity().getWorld())) + if (WorldBlacklist.isWorldBlacklisted(event.getEntity().getWorld())) { return; + } boolean statLossEnabled = HardcoreManager.isStatLossEnabled(); boolean vampirismEnabled = HardcoreManager.isVampirismEnabled(); @@ -176,17 +212,18 @@ public class PlayerListener implements Listener { Player killedPlayer = event.getEntity(); - if (!killedPlayer.hasMetadata(MetadataConstants.METADATA_KEY_PLAYER_DATA) || Permissions.hardcoreBypass(killedPlayer)) { + if (!killedPlayer.hasMetadata(MetadataConstants.METADATA_KEY_PLAYER_DATA) + || Permissions.hardcoreBypass(killedPlayer)) { return; } Player killer = killedPlayer.getKiller(); /* WORLD GUARD MAIN FLAG CHECK */ - if(WorldGuardUtils.isWorldGuardLoaded()) - { - if(!WorldGuardManager.getInstance().hasMainFlag(killedPlayer)) + if (WorldGuardUtils.isWorldGuardLoaded()) { + if (!WorldGuardManager.getInstance().hasMainFlag(killedPlayer)) { return; + } } if (statLossEnabled || (killer != null && vampirismEnabled)) { @@ -212,9 +249,8 @@ public class PlayerListener implements Listener { /** * Monitor PlayerChangedWorldEvents. *

- * These events are monitored for the purpose of removing god mode or - * player parties if they are not allowed on the world the player has - * changed to. + * These events are monitored for the purpose of removing god mode or player parties if they are + * not allowed on the world the player has changed to. * * @param event The event to monitor */ @@ -227,79 +263,79 @@ public class PlayerListener implements Listener { } //Profile not loaded - if(UserManager.getPlayer(player) == null) - { + if (UserManager.getPlayer(player) == null) { return; } - McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player); + final McMMOPlayer mmoPlayer = UserManager.getPlayer(player); - mcMMOPlayer.checkGodMode(); - mcMMOPlayer.checkParty(); + mmoPlayer.checkGodMode(); + mmoPlayer.checkParty(); } /** * Monitor PlayerDropItemEvents. *

- * These events are monitored for the purpose of flagging sharable - * dropped items, as well as removing ability buffs from pickaxes - * and shovels. + * These events are monitored for the purpose of flagging sharable dropped items, as well as + * removing ability buffs from pickaxes and shovels. * * @param event The event to monitor */ @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onPlayerDropItem(PlayerDropItemEvent event) { /* WORLD BLACKLIST CHECK */ - if(WorldBlacklist.isWorldBlacklisted(event.getPlayer().getWorld())) + if (WorldBlacklist.isWorldBlacklisted(event.getPlayer().getWorld())) { return; + } /* WORLD GUARD MAIN FLAG CHECK */ - if(WorldGuardUtils.isWorldGuardLoaded()) - { - if(!WorldGuardManager.getInstance().hasMainFlag(event.getPlayer())) + if (WorldGuardUtils.isWorldGuardLoaded()) { + if (!WorldGuardManager.getInstance().hasMainFlag(event.getPlayer())) { return; + } } - Item drop = event.getItemDrop(); - ItemStack dropStack = drop.getItemStack(); + // TODO: This sharing item system seems very unoptimized, temporarily disabling + /*if (ItemUtils.isSharable(event.getItemDrop().getItemStack())) { + event.getItemDrop().getItemStack().setMetadata( + MetadataConstants.METADATA_KEY_TRACKED_ITEM, + MetadataConstants.MCMMO_METADATA_VALUE); + }*/ - if (ItemUtils.isSharable(dropStack)) { - drop.setMetadata(MetadataConstants.METADATA_KEY_TRACKED_ITEM, MetadataConstants.MCMMO_METADATA_VALUE); - } - - SkillUtils.removeAbilityBuff(dropStack); + SkillUtils.removeAbilityBuff(event.getItemDrop().getItemStack()); } /** * Handle PlayerFishEvents at the highest priority. *

- * These events are used for the purpose of handling our anti-exploit - * code, as well as dealing with ice fishing. + * These events are used for the purpose of handling our anti-exploit code, as well as dealing + * with ice fishing. * * @param event The event to modify */ @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) public void onPlayerFishHighest(PlayerFishEvent event) { /* WORLD BLACKLIST CHECK */ - if(WorldBlacklist.isWorldBlacklisted(event.getPlayer().getWorld())) + if (WorldBlacklist.isWorldBlacklisted(event.getPlayer().getWorld())) { return; + } Player player = event.getPlayer(); /* WORLD GUARD MAIN FLAG CHECK */ - if(WorldGuardUtils.isWorldGuardLoaded()) - { - if(!WorldGuardManager.getInstance().hasMainFlag(player)) + if (WorldGuardUtils.isWorldGuardLoaded()) { + if (!WorldGuardManager.getInstance().hasMainFlag(player)) { return; + } } - if (!UserManager.hasPlayerDataKey(player) || !mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, PrimarySkillType.FISHING)) { + if (!UserManager.hasPlayerDataKey(player) || !mcMMO.p.getSkillTools() + .doesPlayerHaveSkillPermission(player, PrimarySkillType.FISHING)) { return; } //Profile not loaded - if(UserManager.getPlayer(player) == null) - { + if (UserManager.getPlayer(player) == null) { return; } @@ -308,7 +344,7 @@ public class PlayerListener implements Listener { switch (event.getState()) { case CAUGHT_FISH: //TODO Update to new API once available! Waiting for case CAUGHT_TREASURE - if(event.getCaught() != null) { + if (event.getCaught() != null) { Item fishingCatch = (Item) event.getCaught(); if (mcMMO.p.getGeneralConfig().getFishingOverrideTreasures() && @@ -319,7 +355,8 @@ public class PlayerListener implements Listener { ItemStack replacementCatch = new ItemStack(Material.SALMON, 1); - McMMOReplaceVanillaTreasureEvent replaceVanillaTreasureEvent = new McMMOReplaceVanillaTreasureEvent(fishingCatch, replacementCatch); + McMMOReplaceVanillaTreasureEvent replaceVanillaTreasureEvent = new McMMOReplaceVanillaTreasureEvent( + fishingCatch, replacementCatch, player); Bukkit.getPluginManager().callEvent(replaceVanillaTreasureEvent); //Replace @@ -329,8 +366,10 @@ public class PlayerListener implements Listener { if (Permissions.vanillaXpBoost(player, PrimarySkillType.FISHING)) { //Don't modify XP below vanilla values - if(fishingManager.handleVanillaXpBoost(event.getExpToDrop()) > 1) - event.setExpToDrop(fishingManager.handleVanillaXpBoost(event.getExpToDrop())); + if (fishingManager.handleVanillaXpBoost(event.getExpToDrop()) > 1) { + event.setExpToDrop( + fishingManager.handleVanillaXpBoost(event.getExpToDrop())); + } } } return; @@ -352,40 +391,42 @@ public class PlayerListener implements Listener { private void cancelFishingEventAndDropXp(PlayerFishEvent event, Player player) { event.setCancelled(true); - ExperienceOrb experienceOrb = (ExperienceOrb) player.getWorld().spawnEntity(player.getEyeLocation(), EntityType.EXPERIENCE_ORB); + ExperienceOrb experienceOrb = (ExperienceOrb) player.getWorld() + .spawnEntity(player.getEyeLocation(), EntityType.EXPERIENCE_ORB); experienceOrb.setExperience(event.getExpToDrop()); } /** * Monitor PlayerFishEvents. *

- * These events are monitored for the purpose of handling the various - * Fishing skills and abilities. + * These events are monitored for the purpose of handling the various Fishing skills and + * abilities. * * @param event The event to monitor */ @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onPlayerFishMonitor(PlayerFishEvent event) { /* WORLD BLACKLIST CHECK */ - if(WorldBlacklist.isWorldBlacklisted(event.getPlayer().getWorld())) + if (WorldBlacklist.isWorldBlacklisted(event.getPlayer().getWorld())) { return; + } Player player = event.getPlayer(); /* WORLD GUARD MAIN FLAG CHECK */ - if(WorldGuardUtils.isWorldGuardLoaded()) - { - if(!WorldGuardManager.getInstance().hasMainFlag(player)) + if (WorldGuardUtils.isWorldGuardLoaded()) { + if (!WorldGuardManager.getInstance().hasMainFlag(player)) { return; + } } - if (!UserManager.hasPlayerDataKey(player) || !mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, PrimarySkillType.FISHING)) { + if (!UserManager.hasPlayerDataKey(player) || !mcMMO.p.getSkillTools() + .doesPlayerHaveSkillPermission(player, PrimarySkillType.FISHING)) { return; } //Profile not loaded - if(UserManager.getPlayer(player) == null) - { + if (UserManager.getPlayer(player) == null) { return; } @@ -393,20 +434,18 @@ public class PlayerListener implements Listener { FishingManager fishingManager = UserManager.getPlayer(player).getFishingManager(); //Track the hook - if(ExperienceConfig.getInstance().isFishingExploitingPrevented()) - { - if(event.getHook().getMetadata(MetadataConstants.METADATA_KEY_FISH_HOOK_REF).size() == 0) - { + if (ExperienceConfig.getInstance().isFishingExploitingPrevented()) { + if (event.getHook().getMetadata(MetadataConstants.METADATA_KEY_FISH_HOOK_REF).size() + == 0) { fishingManager.setFishHookReference(event.getHook()); } //Spam Fishing - if(event.getState() == PlayerFishEvent.State.CAUGHT_FISH && fishingManager.isFishingTooOften()) - { + if (event.getState() == PlayerFishEvent.State.CAUGHT_FISH + && fishingManager.isFishingTooOften()) { event.setExpToDrop(0); - if(caught instanceof Item caughtItem) - { + if (caught instanceof Item caughtItem) { caughtItem.remove(); } @@ -421,43 +460,47 @@ public class PlayerListener implements Listener { ItemStack inHand = player.getInventory().getItemInMainHand(); //Grab lure level - if(inHand != null + if (inHand != null && inHand.getItemMeta() != null && inHand.getType().getKey().getKey().equalsIgnoreCase("fishing_rod")) { - if(inHand.getItemMeta().hasEnchants()) { - for(Enchantment enchantment : inHand.getItemMeta().getEnchants().keySet()) { - if(enchantment.toString().toLowerCase().contains("lure")) { + if (inHand.getItemMeta().hasEnchants()) { + for (Enchantment enchantment : inHand.getItemMeta().getEnchants() + .keySet()) { + if (enchantment.toString().toLowerCase().contains("lure")) { lureLevel = inHand.getEnchantmentLevel(enchantment); } } } - // Prevent any potential odd behavior by only processing if no offhand fishing rod is present - if(!player.getInventory().getItemInOffHand().getType().getKey().getKey().equalsIgnoreCase("fishing_rod")) { - // In case of offhand fishing rod, don't process anything - fishingManager.masterAngler(event.getHook(), lureLevel); - fishingManager.setFishingTarget(); + // Prevent any potential odd behavior by only processing if no offhand fishing rod is present + if (!player.getInventory().getItemInOffHand().getType().getKey().getKey() + .equalsIgnoreCase("fishing_rod")) { + // In case of offhand fishing rod, don't process anything + fishingManager.masterAngler(event.getHook(), lureLevel); + fishingManager.setFishingTarget(); + } } } - } return; case CAUGHT_FISH: - if(caught instanceof Item) { - if(ExperienceConfig.getInstance().isFishingExploitingPrevented()) { + if (caught instanceof Item caughtItem) { + if (ExperienceConfig.getInstance().isFishingExploitingPrevented()) { fishingManager.processExploiting(event.getHook().getLocation().toVector()); - if (fishingManager.isExploitingFishing(event.getHook().getLocation().toVector())) { - player.sendMessage(LocaleLoader.getString("Fishing.ScarcityTip", ExperienceConfig.getInstance().getFishingExploitingOptionMoveRange())); + if (fishingManager.isExploitingFishing( + event.getHook().getLocation().toVector())) { + player.sendMessage(LocaleLoader.getString("Fishing.ScarcityTip", + ExperienceConfig.getInstance() + .getFishingExploitingOptionMoveRange())); event.setExpToDrop(0); - Item caughtItem = (Item) caught; caughtItem.remove(); return; } } - fishingManager.processFishing((Item) caught); + fishingManager.processFishing(caughtItem); fishingManager.setFishingTarget(); } return; @@ -474,29 +517,29 @@ public class PlayerListener implements Listener { /** * Handle PlayerPickupItemEvents at the highest priority. *

- * These events are used to handle item sharing between party members and - * are also used to handle item pickup for the Unarmed skill. + * These events are used to handle item sharing between party members and are also used to + * handle item pickup for the Unarmed skill. * * @param event The event to modify */ @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void onPlayerPickupItem(EntityPickupItemEvent event) { /* WORLD BLACKLIST CHECK */ - if(WorldBlacklist.isWorldBlacklisted(event.getEntity().getWorld())) - return; - - if(Misc.isNPCEntityExcludingVillagers(event.getEntity())) { + if (WorldBlacklist.isWorldBlacklisted(event.getEntity().getWorld())) { return; } - if(event.getEntity() instanceof Player player) - { + if (Misc.isNPCEntityExcludingVillagers(event.getEntity())) { + return; + } + + if (event.getEntity() instanceof Player player) { /* WORLD GUARD MAIN FLAG CHECK */ - if(WorldGuardUtils.isWorldGuardLoaded()) - { - if(!WorldGuardManager.getInstance().hasMainFlag(player)) + if (WorldGuardUtils.isWorldGuardLoaded()) { + if (!WorldGuardManager.getInstance().hasMainFlag(player)) { return; + } } if (!UserManager.hasPlayerDataKey(player)) { @@ -504,34 +547,35 @@ public class PlayerListener implements Listener { } //Profile not loaded - McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player); - if(mcMMOPlayer == null) { + final McMMOPlayer mmoPlayer = UserManager.getPlayer(player); + if (mmoPlayer == null) { return; } - Item drop = event.getItem(); - ItemStack dropStack = drop.getItemStack(); + final Item drop = event.getItem(); //Remove tracking - if(drop.hasMetadata(MetadataConstants.METADATA_KEY_TRACKED_ARROW)) { + if (drop.hasMetadata(MetadataConstants.METADATA_KEY_TRACKED_ARROW)) { drop.removeMetadata(MetadataConstants.METADATA_KEY_TRACKED_ARROW, mcMMO.p); } if (drop.hasMetadata(MetadataConstants.METADATA_KEY_DISARMED_ITEM)) { - if (!player.getName().equals(drop.getMetadata(MetadataConstants.METADATA_KEY_DISARMED_ITEM).get(0).asString())) { + if (!player.getName() + .equals(drop.getMetadata(MetadataConstants.METADATA_KEY_DISARMED_ITEM) + .get(0).asString())) { event.setCancelled(true); } - return; } - if (!drop.hasMetadata(MetadataConstants.METADATA_KEY_TRACKED_ITEM) && mcMMOPlayer.inParty() && ItemUtils.isSharable(dropStack)) { - event.setCancelled(ShareHandler.handleItemShare(drop, mcMMOPlayer)); + // TODO: Temporarily disabling sharing items... + /*if (!drop.hasMetadata(MetadataConstants.METADATA_KEY_TRACKED_ITEM) && mmoPlayer.inParty() && ItemUtils.isSharable(dropStack)) { + event.setCancelled(ShareHandler.handleItemShare(drop, mmoPlayer)); if (event.isCancelled()) { SoundManager.sendSound(player, player.getLocation(), SoundType.POP); } - } + }*/ /*if (player.getInventory().getItemInMainHand().getType() == Material.AIR) { Unarmed.handleItemPickup(player, event); @@ -549,9 +593,8 @@ public class PlayerListener implements Listener { /** * Monitor PlayerQuitEvents. *

- * These events are monitored for the purpose of resetting player - * variables and other garbage collection tasks that must take place when - * a player exits the server. + * These events are monitored for the purpose of resetting player variables and other garbage + * collection tasks that must take place when a player exits the server. * * @param event The event to monitor */ @@ -563,24 +606,23 @@ public class PlayerListener implements Listener { return; } - McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player); + final McMMOPlayer mmoPlayer = UserManager.getPlayer(player); //Profile not loaded - if(mcMMOPlayer == null) { + if (mmoPlayer == null) { return; } //Use a sync save if the server is shutting down to avoid race conditions - mcMMOPlayer.logout(mcMMO.isServerShutdownExecuted()); + mmoPlayer.logout(mcMMO.isServerShutdownExecuted()); mcMMO.getTransientMetadataTools().cleanLivingEntityMetadata(event.getPlayer()); } /** * Monitor PlayerJoinEvents. *

- * These events are monitored for the purpose of initializing player - * variables, as well as handling the MOTD display and other important - * join messages. + * These events are monitored for the purpose of initializing player variables, as well as + * handling the MOTD display and other important join messages. * * @param event The event to monitor */ @@ -589,23 +631,24 @@ public class PlayerListener implements Listener { Player player = event.getPlayer(); //Delay loading for 3 seconds in case the player has a save task running, its hacky but it should do the trick - mcMMO.p.getFoliaLib().getImpl().runLaterAsync(new PlayerProfileLoadingTask(player), 60); + mcMMO.p.getFoliaLib().getScheduler() + .runLaterAsync(new PlayerProfileLoadingTask(player), 60); if (mcMMO.p.getGeneralConfig().getMOTDEnabled() && Permissions.motd(player)) { Motd.displayAll(player); } if (plugin.isXPEventEnabled() && mcMMO.p.getGeneralConfig().playerJoinEventInfo()) { - player.sendMessage(LocaleLoader.getString("XPRate.Event", ExperienceConfig.getInstance().getExperienceGainsGlobalMultiplier())); + player.sendMessage(LocaleLoader.getString("XPRate.Event", + ExperienceConfig.getInstance().getExperienceGainsGlobalMultiplier())); } } /** * Monitor PlayerRespawnEvents. *

- * These events are monitored for the purpose of setting the - * player's last respawn timestamp, in order to prevent - * possible exploitation. + * These events are monitored for the purpose of setting the player's last respawn timestamp, in + * order to prevent possible exploitation. * * @param event The event to monitor */ @@ -618,8 +661,7 @@ public class PlayerListener implements Listener { } //Profile not loaded - if(UserManager.getPlayer(player) == null) - { + if (UserManager.getPlayer(player) == null) { return; } @@ -634,57 +676,62 @@ public class PlayerListener implements Listener { @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) public void onPlayerInteractLowest(PlayerInteractEvent event) { /* WORLD BLACKLIST CHECK */ - if(WorldBlacklist.isWorldBlacklisted(event.getPlayer().getWorld())) + if (WorldBlacklist.isWorldBlacklisted(event.getPlayer().getWorld())) { return; + } Player player = event.getPlayer(); /* WORLD GUARD MAIN FLAG CHECK */ - if(WorldGuardUtils.isWorldGuardLoaded()) - { - if(!WorldGuardManager.getInstance().hasMainFlag(player)) + if (WorldGuardUtils.isWorldGuardLoaded()) { + if (!WorldGuardManager.getInstance().hasMainFlag(player)) { return; + } } - if(event.getClickedBlock() == null) + if (event.getClickedBlock() == null) { return; + } Block clickedBlock = event.getClickedBlock(); Material clickedBlockType = clickedBlock.getType(); //The blacklist contains interactable blocks so its a convenient filter - if(clickedBlockType == Repair.anvilMaterial || clickedBlockType == Salvage.anvilMaterial) { + if (clickedBlockType == Repair.anvilMaterial || clickedBlockType == Salvage.anvilMaterial) { event.setUseItemInHand(Event.Result.ALLOW); - if(!event.getPlayer().isSneaking() && mcMMO.getMaterialMapStore().isToolActivationBlackListed(clickedBlockType)) { + if (!event.getPlayer().isSneaking() && mcMMO.getMaterialMapStore() + .isToolActivationBlackListed(clickedBlockType)) { event.setUseInteractedBlock(Event.Result.DENY); } } - if (event.getHand() != EquipmentSlot.HAND || !UserManager.hasPlayerDataKey(player) || player.getGameMode() == GameMode.CREATIVE) { + if (event.getHand() != EquipmentSlot.HAND || !UserManager.hasPlayerDataKey(player) + || player.getGameMode() == GameMode.CREATIVE) { return; } //Profile not loaded - if(UserManager.getPlayer(player) == null) - { + if (UserManager.getPlayer(player) == null) { return; } - McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player); - MiningManager miningManager = mcMMOPlayer.getMiningManager(); + final McMMOPlayer mmoPlayer = UserManager.getPlayer(player); + MiningManager miningManager = mmoPlayer.getMiningManager(); ItemStack heldItem = player.getInventory().getItemInMainHand(); switch (event.getAction()) { case RIGHT_CLICK_BLOCK: Material type = clickedBlock.getType(); - if (!mcMMO.p.getGeneralConfig().getAbilitiesOnlyActivateWhenSneaking() || player.isSneaking()) { + if (!mcMMO.p.getGeneralConfig().getAbilitiesOnlyActivateWhenSneaking() + || player.isSneaking()) { /* REPAIR CHECKS */ if (type == Repair.anvilMaterial - && mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, PrimarySkillType.REPAIR) + && mcMMO.p.getSkillTools() + .doesPlayerHaveSkillPermission(player, PrimarySkillType.REPAIR) && mcMMO.getRepairableManager().isRepairable(heldItem) && heldItem.getAmount() <= 1) { - RepairManager repairManager = mcMMOPlayer.getRepairManager(); + RepairManager repairManager = mmoPlayer.getRepairManager(); event.setCancelled(true); // Make sure the player knows what he's doing when trying to repair an enchanted item @@ -695,19 +742,22 @@ public class PlayerListener implements Listener { } /* SALVAGE CHECKS */ else if (type == Salvage.anvilMaterial - && mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, PrimarySkillType.SALVAGE) - && RankUtils.hasUnlockedSubskill(player, SubSkillType.SALVAGE_SCRAP_COLLECTOR) + && mcMMO.p.getSkillTools() + .doesPlayerHaveSkillPermission(player, PrimarySkillType.SALVAGE) + && RankUtils.hasUnlockedSubskill(player, + SubSkillType.SALVAGE_SCRAP_COLLECTOR) && mcMMO.getSalvageableManager().isSalvageable(heldItem) && heldItem.getAmount() <= 1) { - SalvageManager salvageManager = UserManager.getPlayer(player).getSalvageManager(); - event.setCancelled(true); + SalvageManager salvageManager = UserManager.getPlayer(player) + .getSalvageManager(); + event.setCancelled(true); - // Make sure the player knows what he's doing when trying to salvage an enchanted item - if (salvageManager.checkConfirmation(true)) { - SkillUtils.removeAbilityBoostsFromInventory(player); - salvageManager.handleSalvage(clickedBlock.getLocation(), heldItem); - player.updateInventory(); - } + // Make sure the player knows what he's doing when trying to salvage an enchanted item + if (salvageManager.checkConfirmation(true)) { + SkillUtils.removeAbilityBoostsFromInventory(player); + salvageManager.handleSalvage(clickedBlock.getLocation(), heldItem); + player.updateInventory(); + } } } @@ -715,8 +765,7 @@ public class PlayerListener implements Listener { else if (miningManager.canDetonate()) { if (type == Material.TNT) { event.setCancelled(true); // Don't detonate the TNT if they're too close - } - else { + } else { miningManager.remoteDetonation(); } } @@ -726,25 +775,32 @@ public class PlayerListener implements Listener { case LEFT_CLICK_BLOCK: type = clickedBlock.getType(); - if (!mcMMO.p.getGeneralConfig().getAbilitiesOnlyActivateWhenSneaking() || player.isSneaking()) { + if (!mcMMO.p.getGeneralConfig().getAbilitiesOnlyActivateWhenSneaking() + || player.isSneaking()) { /* REPAIR CHECKS */ - if (type == Repair.anvilMaterial && mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, PrimarySkillType.REPAIR) && mcMMO.getRepairableManager().isRepairable(heldItem)) { - RepairManager repairManager = mcMMOPlayer.getRepairManager(); + if (type == Repair.anvilMaterial && mcMMO.p.getSkillTools() + .doesPlayerHaveSkillPermission(player, PrimarySkillType.REPAIR) + && mcMMO.getRepairableManager().isRepairable(heldItem)) { + RepairManager repairManager = mmoPlayer.getRepairManager(); // Cancel repairing an enchanted item if (repairManager.checkConfirmation(false)) { repairManager.setLastAnvilUse(0); - player.sendMessage(LocaleLoader.getString("Skills.Cancelled", LocaleLoader.getString("Repair.Pretty.Name"))); + player.sendMessage(LocaleLoader.getString("Skills.Cancelled", + LocaleLoader.getString("Repair.Pretty.Name"))); } } /* SALVAGE CHECKS */ - else if (type == Salvage.anvilMaterial && mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, PrimarySkillType.SALVAGE) && mcMMO.getSalvageableManager().isSalvageable(heldItem)) { - SalvageManager salvageManager = mcMMOPlayer.getSalvageManager(); + else if (type == Salvage.anvilMaterial && mcMMO.p.getSkillTools() + .doesPlayerHaveSkillPermission(player, PrimarySkillType.SALVAGE) + && mcMMO.getSalvageableManager().isSalvageable(heldItem)) { + SalvageManager salvageManager = mmoPlayer.getSalvageManager(); // Cancel salvaging an enchanted item if (salvageManager.checkConfirmation(false)) { salvageManager.setLastAnvilUse(0); - player.sendMessage(LocaleLoader.getString("Skills.Cancelled", LocaleLoader.getString("Salvage.Pretty.Name"))); + player.sendMessage(LocaleLoader.getString("Skills.Cancelled", + LocaleLoader.getString("Salvage.Pretty.Name"))); } } } @@ -764,55 +820,64 @@ public class PlayerListener implements Listener { @EventHandler(priority = EventPriority.MONITOR) public void onPlayerInteractMonitor(PlayerInteractEvent event) { /* WORLD BLACKLIST CHECK */ - if(WorldBlacklist.isWorldBlacklisted(event.getPlayer().getWorld())) + if (WorldBlacklist.isWorldBlacklisted(event.getPlayer().getWorld())) { return; + } Player player = event.getPlayer(); /* WORLD GUARD MAIN FLAG CHECK */ - if(WorldGuardUtils.isWorldGuardLoaded()) - { - if(!WorldGuardManager.getInstance().hasMainFlag(player)) + if (WorldGuardUtils.isWorldGuardLoaded()) { + if (!WorldGuardManager.getInstance().hasMainFlag(player)) { return; + } } - if (event.getHand() != EquipmentSlot.HAND || !UserManager.hasPlayerDataKey(player) || player.getGameMode() == GameMode.CREATIVE) { + if (event.getHand() != EquipmentSlot.HAND + || !UserManager.hasPlayerDataKey(player) + || player.getGameMode() == GameMode.CREATIVE) { return; } //Profile not loaded - if(UserManager.getPlayer(player) == null) - { + if (UserManager.getPlayer(player) == null) { + return; + } + + final McMMOPlayer mmoPlayer = UserManager.getPlayer(player); + if (mmoPlayer == null) { return; } - McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player); ItemStack heldItem = player.getInventory().getItemInMainHand(); //Spam Fishing Detection - if(event.getAction() == Action.RIGHT_CLICK_BLOCK || event.getAction() == Action.RIGHT_CLICK_AIR) - { - if(ExperienceConfig.getInstance().isFishingExploitingPrevented() - && (heldItem.getType() == Material.FISHING_ROD || player.getInventory().getItemInOffHand().getType() == Material.FISHING_ROD)) - { - if(player.isInsideVehicle() && (player.getVehicle() instanceof Minecart || player.getVehicle() instanceof PoweredMinecart)) - { + if (event.getAction() == Action.RIGHT_CLICK_BLOCK + || event.getAction() == Action.RIGHT_CLICK_AIR) { + if (ExperienceConfig.getInstance().isFishingExploitingPrevented() + && (heldItem.getType() == Material.FISHING_ROD + || player.getInventory().getItemInOffHand().getType() + == Material.FISHING_ROD)) { + if (player.isInsideVehicle() && (player.getVehicle() instanceof Minecart + || player.getVehicle() instanceof PoweredMinecart)) { player.getVehicle().eject(); } - //mcMMOPlayer.getFishingManager().setFishingRodCastTimestamp(); + //mmoPlayer.getFishingManager().setFishingRodCastTimestamp(); } } switch (event.getAction()) { case RIGHT_CLICK_BLOCK: - if(player.getInventory().getItemInOffHand().getType() != Material.AIR && !player.isInsideVehicle() && !player.isSneaking()) { + if (player.getInventory().getItemInOffHand().getType() != Material.AIR + && !player.isInsideVehicle() && !player.isSneaking()) { break; } //Hmm - if(event.getClickedBlock() == null) + if (event.getClickedBlock() == null) { return; + } Block block = event.getClickedBlock(); BlockState blockState = block.getState(); @@ -821,24 +886,24 @@ public class PlayerListener implements Listener { if (BlockUtils.canActivateTools(blockState)) { if (mcMMO.p.getGeneralConfig().getAbilitiesEnabled()) { if (BlockUtils.canActivateHerbalism(blockState)) { - mcMMOPlayer.processAbilityActivation(PrimarySkillType.HERBALISM); + mmoPlayer.processAbilityActivation(PrimarySkillType.HERBALISM); } - mcMMOPlayer.processAbilityActivation(PrimarySkillType.AXES); - mcMMOPlayer.processAbilityActivation(PrimarySkillType.EXCAVATION); - mcMMOPlayer.processAbilityActivation(PrimarySkillType.MINING); - mcMMOPlayer.processAbilityActivation(PrimarySkillType.SWORDS); - mcMMOPlayer.processAbilityActivation(PrimarySkillType.UNARMED); - mcMMOPlayer.processAbilityActivation(PrimarySkillType.WOODCUTTING); + mmoPlayer.processAbilityActivation(PrimarySkillType.AXES); + mmoPlayer.processAbilityActivation(PrimarySkillType.EXCAVATION); + mmoPlayer.processAbilityActivation(PrimarySkillType.MINING); + mmoPlayer.processAbilityActivation(PrimarySkillType.SWORDS); + mmoPlayer.processAbilityActivation(PrimarySkillType.UNARMED); + mmoPlayer.processAbilityActivation(PrimarySkillType.WOODCUTTING); } ChimaeraWing.activationCheck(player); } - HerbalismManager herbalismManager = mcMMOPlayer.getHerbalismManager(); + HerbalismManager herbalismManager = mmoPlayer.getHerbalismManager(); // FakePlayerAnimationEvent fakeSwing = new FakePlayerAnimationEvent(event.getPlayer(), PlayerAnimationType.ARM_SWING); //PlayerAnimationEvent compat - if(!event.isCancelled() || event.useInteractedBlock() != Event.Result.DENY) { + if (!event.isCancelled() || event.useInteractedBlock() != Event.Result.DENY) { //TODO: Is this code to set false from bone meal even needed? I'll have to double check later. if (heldItem.getType() == Material.BONE_MEAL) { switch (blockState.getType().toString()) { @@ -849,25 +914,29 @@ public class PlayerListener implements Listener { case "NETHER_WART_BLOCK": case "POTATO": case "MANGROVE_PROPAGULE": - mcMMO.getPlaceStore().setFalse(blockState); + mcMMO.getUserBlockTracker().setEligible(blockState); break; } } if (herbalismManager.canGreenThumbBlock(blockState)) { //call event for Green Thumb Block - if(!EventUtils.callSubSkillBlockEvent(player, SubSkillType.HERBALISM_GREEN_THUMB, block).isCancelled()) { + if (!EventUtils.callSubSkillBlockEvent(player, + SubSkillType.HERBALISM_GREEN_THUMB, block).isCancelled()) { // Bukkit.getPluginManager().callEvent(fakeSwing); - player.getInventory().getItemInMainHand().setAmount(heldItem.getAmount() - 1); + player.getInventory().getItemInMainHand() + .setAmount(heldItem.getAmount() - 1); player.updateInventory(); - if (herbalismManager.processGreenThumbBlocks(blockState) && EventUtils.simulateBlockBreak(block, player)) { + if (herbalismManager.processGreenThumbBlocks(blockState) + && EventUtils.simulateBlockBreak(block, player)) { blockState.update(true); } } } /* SHROOM THUMB CHECK */ else if (herbalismManager.canUseShroomThumb(blockState)) { - if(!EventUtils.callSubSkillBlockEvent(player, SubSkillType.HERBALISM_SHROOM_THUMB, block).isCancelled()) { + if (!EventUtils.callSubSkillBlockEvent(player, + SubSkillType.HERBALISM_SHROOM_THUMB, block).isCancelled()) { // Bukkit.getPluginManager().callEvent(fakeSwing); event.setCancelled(true); if (herbalismManager.processShroomThumb(blockState) @@ -882,26 +951,27 @@ public class PlayerListener implements Listener { break; case RIGHT_CLICK_AIR: - if(player.getInventory().getItemInOffHand().getType() != Material.AIR && !player.isInsideVehicle() && !player.isSneaking()) { + if (player.getInventory().getItemInOffHand().getType() != Material.AIR + && !player.isInsideVehicle() && !player.isSneaking()) { break; } /* ACTIVATION CHECKS */ if (mcMMO.p.getGeneralConfig().getAbilitiesEnabled()) { - mcMMOPlayer.processAbilityActivation(PrimarySkillType.AXES); - mcMMOPlayer.processAbilityActivation(PrimarySkillType.EXCAVATION); - mcMMOPlayer.processAbilityActivation(PrimarySkillType.HERBALISM); - mcMMOPlayer.processAbilityActivation(PrimarySkillType.MINING); - mcMMOPlayer.processAbilityActivation(PrimarySkillType.SWORDS); - mcMMOPlayer.processAbilityActivation(PrimarySkillType.UNARMED); - mcMMOPlayer.processAbilityActivation(PrimarySkillType.WOODCUTTING); + mmoPlayer.processAbilityActivation(PrimarySkillType.AXES); + mmoPlayer.processAbilityActivation(PrimarySkillType.EXCAVATION); + mmoPlayer.processAbilityActivation(PrimarySkillType.HERBALISM); + mmoPlayer.processAbilityActivation(PrimarySkillType.MINING); + mmoPlayer.processAbilityActivation(PrimarySkillType.SWORDS); + mmoPlayer.processAbilityActivation(PrimarySkillType.UNARMED); + mmoPlayer.processAbilityActivation(PrimarySkillType.WOODCUTTING); } /* ITEM CHECKS */ ChimaeraWing.activationCheck(player); /* BLAST MINING CHECK */ - MiningManager miningManager = mcMMOPlayer.getMiningManager(); + MiningManager miningManager = mmoPlayer.getMiningManager(); if (miningManager.canDetonate()) { miningManager.remoteDetonation(); } @@ -917,15 +987,16 @@ public class PlayerListener implements Listener { /* CALL OF THE WILD CHECKS */ Material type = heldItem.getType(); - TamingManager tamingManager = mcMMOPlayer.getTamingManager(); + TamingManager tamingManager = mmoPlayer.getTamingManager(); - if (type == mcMMO.p.getGeneralConfig().getTamingCOTWMaterial(CallOfTheWildType.WOLF.getConfigEntityTypeEntry())) { + if (type == mcMMO.p.getGeneralConfig() + .getTamingCOTWMaterial(CallOfTheWildType.WOLF.getConfigEntityTypeEntry())) { tamingManager.summonWolf(); - } - else if (type == mcMMO.p.getGeneralConfig().getTamingCOTWMaterial(CallOfTheWildType.CAT.getConfigEntityTypeEntry())) { + } else if (type == mcMMO.p.getGeneralConfig() + .getTamingCOTWMaterial(CallOfTheWildType.CAT.getConfigEntityTypeEntry())) { tamingManager.summonOcelot(); - } - else if (type == mcMMO.p.getGeneralConfig().getTamingCOTWMaterial(CallOfTheWildType.HORSE.getConfigEntityTypeEntry())) { + } else if (type == mcMMO.p.getGeneralConfig().getTamingCOTWMaterial( + CallOfTheWildType.HORSE.getConfigEntityTypeEntry())) { tamingManager.summonHorse(); } @@ -945,27 +1016,33 @@ public class PlayerListener implements Listener { public void onPlayerChat(AsyncPlayerChatEvent event) { Player player = event.getPlayer(); - if ((ExperienceConfig.getInstance().isNPCInteractionPrevented() && Misc.isNPCEntityExcludingVillagers(player)) || !UserManager.hasPlayerDataKey(player)) { + if ((ExperienceConfig.getInstance().isNPCInteractionPrevented() + && Misc.isNPCEntityExcludingVillagers(player)) || !UserManager.hasPlayerDataKey( + player)) { return; } - McMMOPlayer mcMMOPlayer = UserManager.getOfflinePlayer(player); + final McMMOPlayer mmoPlayer = UserManager.getOfflinePlayer(player); - if (mcMMOPlayer == null) { - LogUtils.debug(mcMMO.p.getLogger(), player.getName() + "is chatting, but is currently not logged in to the server."); - LogUtils.debug(mcMMO.p.getLogger(), "Party & Admin chat will not work properly for this player."); + if (mmoPlayer == null) { + LogUtils.debug(mcMMO.p.getLogger(), player.getName() + + "is chatting, but is currently not logged in to the server."); + LogUtils.debug(mcMMO.p.getLogger(), + "Party & Admin chat will not work properly for this player."); return; } - if(plugin.getChatManager().isChatChannelEnabled(mcMMOPlayer.getChatChannel())) { - if(mcMMOPlayer.getChatChannel() != ChatChannel.NONE) { - if(plugin.getChatManager().isMessageAllowed(mcMMOPlayer)) { + if (plugin.getChatManager().isChatChannelEnabled(mmoPlayer.getChatChannel())) { + if (mmoPlayer.getChatChannel() != ChatChannel.NONE) { + if (plugin.getChatManager().isMessageAllowed(mmoPlayer)) { //If the message is allowed we cancel this event to avoid double sending messages - plugin.getChatManager().processPlayerMessage(mcMMOPlayer, event.getMessage(), event.isAsynchronous()); + plugin.getChatManager().processPlayerMessage(mmoPlayer, event.getMessage(), + event.isAsynchronous()); event.setCancelled(true); } else { //Message wasn't allowed, remove the player from their channel - plugin.getChatManager().setOrToggleChatChannel(mcMMOPlayer, mcMMOPlayer.getChatChannel()); + plugin.getChatManager() + .setOrToggleChatChannel(mmoPlayer, mmoPlayer.getChatChannel()); } } } @@ -986,7 +1063,8 @@ public class PlayerListener implements Listener { // Do these ACTUALLY have to be lower case to work properly? for (PrimarySkillType skill : PrimarySkillType.values()) { String skillName = skill.toString().toLowerCase(Locale.ENGLISH); - String localizedName = mcMMO.p.getSkillTools().getLocalizedSkillName(skill).toLowerCase(Locale.ENGLISH); + String localizedName = mcMMO.p.getSkillTools().getLocalizedSkillName(skill) + .toLowerCase(Locale.ENGLISH); if (lowerCaseCommand.equals(localizedName)) { event.setMessage(message.replace(command, skillName)); @@ -1001,9 +1079,8 @@ public class PlayerListener implements Listener { } /** - * When a {@link Player} attempts to place an {@link ItemStack} - * into an {@link ItemFrame}, we want to make sure to remove any - * Ability buffs from that item. + * When a {@link Player} attempts to place an {@link ItemStack} into an {@link ItemFrame}, we + * want to make sure to remove any Ability buffs from that item. * * @param event The {@link PlayerInteractEntityEvent} to handle */ @@ -1025,8 +1102,7 @@ public class PlayerListener implements Listener { if (event.getHand() == EquipmentSlot.OFF_HAND) { itemInHand = event.getPlayer().getInventory().getItemInOffHand(); - } - else { + } else { itemInHand = event.getPlayer().getInventory().getItemInMainHand(); } diff --git a/src/main/java/com/gmail/nossr50/listeners/SelfListener.java b/src/main/java/com/gmail/nossr50/listeners/SelfListener.java index 7c7f98de3..a6349e0dd 100644 --- a/src/main/java/com/gmail/nossr50/listeners/SelfListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/SelfListener.java @@ -27,8 +27,7 @@ public class SelfListener implements Listener { //Used in task scheduling and other things private final mcMMO plugin; - public SelfListener(mcMMO plugin) - { + public SelfListener(mcMMO plugin) { this.plugin = plugin; } @@ -37,26 +36,28 @@ public class SelfListener implements Listener { final Player player = event.getPlayer(); final PrimarySkillType skill = event.getSkill(); - final McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player); + final McMMOPlayer mmoPlayer = UserManager.getPlayer(player); //TODO: Handle proper validation at the event level - if(mcMMOPlayer == null || !mcMMOPlayer.getProfile().isLoaded()) + if (mmoPlayer == null || !mmoPlayer.getProfile().isLoaded()) { return; + } - if(player.isOnline()) { + if (player.isOnline()) { //Players can gain multiple levels especially during xprate events - for(int i = 0; i < event.getLevelsGained(); i++) - { + for (int i = 0; i < event.getLevelsGained(); i++) { int previousLevelGained = event.getSkillLevel() - i; //Send player skill unlock notifications - UserManager.getPlayer(player).processUnlockNotifications(plugin, event.getSkill(), previousLevelGained); + UserManager.getPlayer(player) + .processUnlockNotifications(plugin, event.getSkill(), previousLevelGained); } //Reset the delay timer RankUtils.resetUnlockDelayTimer(); - if(mcMMO.p.getGeneralConfig().getScoreboardsEnabled()) + if (mcMMO.p.getGeneralConfig().getScoreboardsEnabled()) { ScoreboardManager.handleLevelUp(player, skill); + } } final Set levelsAchieved = new LinkedHashSet<>(); @@ -77,80 +78,79 @@ public class SelfListener implements Listener { public void onPlayerXp(McMMOPlayerXpGainEvent event) { Player player = event.getPlayer(); - if(player.isOnline()) { - if(mcMMO.p.getGeneralConfig().getScoreboardsEnabled()) + if (player.isOnline()) { + if (mcMMO.p.getGeneralConfig().getScoreboardsEnabled()) { ScoreboardManager.handleXp(player, event.getSkill()); + } } } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onAbility(McMMOPlayerAbilityActivateEvent event) { Player player = event.getPlayer(); - if(player.isOnline()) { - if(mcMMO.p.getGeneralConfig().getScoreboardsEnabled()) + if (player.isOnline()) { + if (mcMMO.p.getGeneralConfig().getScoreboardsEnabled()) { ScoreboardManager.cooldownUpdate(event.getPlayer(), event.getSkill()); + } } } @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) public void onPlayerXpGain(McMMOPlayerXpGainEvent event) { Player player = event.getPlayer(); - McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player); + final McMMOPlayer mmoPlayer = UserManager.getPlayer(player); //TODO: Handle proper validation at the event level - if(mcMMOPlayer == null || !mcMMOPlayer.getProfile().isLoaded()) + if (mmoPlayer == null || !mmoPlayer.getProfile().isLoaded()) { return; + } PrimarySkillType primarySkillType = event.getSkill(); - if(mcMMOPlayer.isDebugMode()) { - mcMMOPlayer.getPlayer().sendMessage(event.getSkill().toString() + " XP Gained"); - mcMMOPlayer.getPlayer().sendMessage("Incoming Raw XP: "+event.getRawXpGained()); + if (mmoPlayer.isDebugMode()) { + mmoPlayer.getPlayer().sendMessage(event.getSkill().toString() + " XP Gained"); + mmoPlayer.getPlayer().sendMessage("Incoming Raw XP: " + event.getRawXpGained()); } //WorldGuard XP Check - if(event.getXpGainReason() == XPGainReason.PVE || + if (event.getXpGainReason() == XPGainReason.PVE || event.getXpGainReason() == XPGainReason.PVP || event.getXpGainReason() == XPGainReason.SHARED_PVE || - event.getXpGainReason() == XPGainReason.SHARED_PVP) - { - if(WorldGuardUtils.isWorldGuardLoaded()) - { - if(!WorldGuardManager.getInstance().hasXPFlag(player)) - { + event.getXpGainReason() == XPGainReason.SHARED_PVP) { + if (WorldGuardUtils.isWorldGuardLoaded()) { + if (!WorldGuardManager.getInstance().hasXPFlag(player)) { event.setRawXpGained(0); event.setCancelled(true); - if(mcMMOPlayer.isDebugMode()) { - mcMMOPlayer.getPlayer().sendMessage("No WG XP Flag - New Raw XP: "+event.getRawXpGained()); + if (mmoPlayer.isDebugMode()) { + mmoPlayer.getPlayer().sendMessage( + "No WG XP Flag - New Raw XP: " + event.getRawXpGained()); } } } } - if (event.getXpGainReason() == XPGainReason.COMMAND) - { + if (event.getXpGainReason() == XPGainReason.COMMAND) { return; } - if(ExperienceConfig.getInstance().isEarlyGameBoostEnabled()) - { + if (ExperienceConfig.getInstance().isEarlyGameBoostEnabled()) { int earlyGameBonusXP = 0; //Give some bonus XP for low levels - if(PlayerLevelUtils.qualifiesForEarlyGameBoost(mcMMOPlayer, primarySkillType)) - { - earlyGameBonusXP += (mcMMOPlayer.getXpToLevel(primarySkillType) * 0.05); + if (PlayerLevelUtils.qualifiesForEarlyGameBoost(mmoPlayer, primarySkillType)) { + earlyGameBonusXP += (mmoPlayer.getXpToLevel(primarySkillType) * 0.05); event.setRawXpGained(event.getRawXpGained() + earlyGameBonusXP); } } - int threshold = ExperienceConfig.getInstance().getDiminishedReturnsThreshold(primarySkillType); + int threshold = ExperienceConfig.getInstance() + .getDiminishedReturnsThreshold(primarySkillType); if (threshold <= 0 || !ExperienceConfig.getInstance().getDiminishedReturnsEnabled()) { - if(mcMMOPlayer.isDebugMode()) { - mcMMOPlayer.getPlayer().sendMessage("Final Raw XP: "+event.getRawXpGained()); + if (mmoPlayer.isDebugMode()) { + mmoPlayer.getPlayer().sendMessage("Final Raw XP: " + event.getRawXpGained()); } // Diminished returns is turned off return; @@ -169,11 +169,15 @@ public class SelfListener implements Listener { float guaranteedMinimum = ExperienceConfig.getInstance().getDiminishedReturnsCap() * rawXp; - float modifiedThreshold = (float) (threshold / ExperienceConfig.getInstance().getFormulaSkillModifier(primarySkillType) * ExperienceConfig.getInstance().getExperienceGainsGlobalMultiplier()); - float difference = (mcMMOPlayer.getProfile().getRegisteredXpGain(primarySkillType) - modifiedThreshold) / modifiedThreshold; + float modifiedThreshold = (float) ( + threshold / ExperienceConfig.getInstance().getFormulaSkillModifier(primarySkillType) + * ExperienceConfig.getInstance().getExperienceGainsGlobalMultiplier()); + float difference = + (mmoPlayer.getProfile().getRegisteredXpGain(primarySkillType) - modifiedThreshold) + / modifiedThreshold; if (difference > 0) { -// System.out.println("Total XP Earned: " + mcMMOPlayer.getProfile().getRegisteredXpGain(primarySkillType) + " / Threshold value: " + threshold); +// System.out.println("Total XP Earned: " + mmoPlayer.getProfile().getRegisteredXpGain(primarySkillType) + " / Threshold value: " + threshold); // System.out.println(difference * 100 + "% over the threshold!"); // System.out.println("Previous: " + event.getRawXpGained()); // System.out.println("Adjusted XP " + (event.getRawXpGained() - (event.getRawXpGained() * difference))); @@ -183,12 +187,10 @@ public class SelfListener implements Listener { * Make sure players get a guaranteed minimum of XP */ //If there is no guaranteed minimum proceed, otherwise only proceed if newValue would be higher than our guaranteed minimum - if(guaranteedMinimum <= 0 || newValue > guaranteedMinimum) - { + if (guaranteedMinimum <= 0 || newValue > guaranteedMinimum) { if (newValue > 0) { event.setRawXpGained(newValue); - } - else { + } else { event.setCancelled(true); } } else { @@ -197,8 +199,8 @@ public class SelfListener implements Listener { } - if(mcMMOPlayer.isDebugMode()) { - mcMMOPlayer.getPlayer().sendMessage("Final Raw XP: "+event.getRawXpGained()); + if (mmoPlayer.isDebugMode()) { + mmoPlayer.getPlayer().sendMessage("Final Raw XP: " + event.getRawXpGained()); } } diff --git a/src/main/java/com/gmail/nossr50/listeners/WorldListener.java b/src/main/java/com/gmail/nossr50/listeners/WorldListener.java index 4c24930c6..ef2286e8d 100644 --- a/src/main/java/com/gmail/nossr50/listeners/WorldListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/WorldListener.java @@ -26,13 +26,14 @@ public class WorldListener implements Listener { @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onStructureGrow(StructureGrowEvent event) { /* WORLD BLACKLIST CHECK */ - if(WorldBlacklist.isWorldBlacklisted(event.getWorld())) + if (WorldBlacklist.isWorldBlacklisted(event.getWorld())) { return; + } // Using 50 ms later as I do not know of a way to run one tick later (safely) - plugin.getFoliaLib().getImpl().runLater(() -> { + plugin.getFoliaLib().getScheduler().runLater(() -> { for (BlockState blockState : event.getBlocks()) { - mcMMO.getPlaceStore().setFalse(blockState); + mcMMO.getUserBlockTracker().setEligible(blockState); } }, 1); } @@ -45,10 +46,11 @@ public class WorldListener implements Listener { @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onWorldUnload(WorldUnloadEvent event) { /* WORLD BLACKLIST CHECK */ - if(WorldBlacklist.isWorldBlacklisted(event.getWorld())) + if (WorldBlacklist.isWorldBlacklisted(event.getWorld())) { return; + } - mcMMO.getPlaceStore().unloadWorld(event.getWorld()); + mcMMO.getChunkManager().unloadWorld(event.getWorld()); } /** @@ -59,11 +61,12 @@ public class WorldListener implements Listener { @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onChunkUnload(ChunkUnloadEvent event) { /* WORLD BLACKLIST CHECK */ - if(WorldBlacklist.isWorldBlacklisted(event.getWorld())) + if (WorldBlacklist.isWorldBlacklisted(event.getWorld())) { return; + } Chunk chunk = event.getChunk(); - mcMMO.getPlaceStore().chunkUnloaded(chunk.getX(), chunk.getZ(), event.getWorld()); + mcMMO.getChunkManager().chunkUnloaded(chunk.getX(), chunk.getZ(), event.getWorld()); } } diff --git a/src/main/java/com/gmail/nossr50/locale/LocaleLoader.java b/src/main/java/com/gmail/nossr50/locale/LocaleLoader.java index 20b5e2631..80de6fc0d 100644 --- a/src/main/java/com/gmail/nossr50/locale/LocaleLoader.java +++ b/src/main/java/com/gmail/nossr50/locale/LocaleLoader.java @@ -3,29 +3,48 @@ package com.gmail.nossr50.locale; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.LogUtils; import com.gmail.nossr50.util.text.TextUtils; -import net.kyori.adventure.text.TextComponent; -import org.bukkit.ChatColor; -import org.jetbrains.annotations.NotNull; - -import java.io.*; +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.Reader; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.text.MessageFormat; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; -import java.util.*; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.MissingResourceException; +import java.util.PropertyResourceBundle; +import java.util.ResourceBundle; +import java.util.concurrent.ConcurrentHashMap; import java.util.logging.Level; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import net.kyori.adventure.text.TextComponent; +import org.bukkit.ChatColor; +import org.jetbrains.annotations.NotNull; public final class LocaleLoader { private static final String BUNDLE_ROOT = "com.gmail.nossr50.locale.locale"; private static final String OVERRIDE_FILE_NAME = "locale_override.properties"; - private static Map bundleCache = new HashMap<>(); + // Must be concurrent to accomodate Folia + private static Map bundleCache = new ConcurrentHashMap<>(); private static ResourceBundle bundle = null; private static ResourceBundle filesystemBundle = null; private static ResourceBundle enBundle = null; + // Matches the pattern &#RRGGBB + private static final Pattern hexPattern = Pattern.compile("&#([A-Fa-f0-9]{6})"); + private static final Pattern minecraftHexPattern = Pattern.compile( + "§x(§[A-Fa-f0-9])(§[A-Fa-f0-9])(§[A-Fa-f0-9])(§[A-Fa-f0-9])(§[A-Fa-f0-9])(§[A-Fa-f0-9])"); - private LocaleLoader() {} + private LocaleLoader() { + } public static String getString(String key) { return getString(key, (Object[]) null); @@ -34,9 +53,8 @@ public final class LocaleLoader { /** * Gets the appropriate string from the Locale files. * - * @param key The key to look up the string with + * @param key The key to look up the string with * @param messageArguments Any arguments to be added to the string - * * @return The properly formatted locale string */ public static String getString(String key, Object... messageArguments) { @@ -48,17 +66,16 @@ public final class LocaleLoader { return formatString(rawMessage, messageArguments); } - //TODO: Remove this hacky crap with something better later - /** - * Gets the appropriate TextComponent representation of a formatted string from the Locale files. + * Gets the appropriate TextComponent representation of a formatted string from the Locale + * files. * - * @param key The key to look up the string with + * @param key The key to look up the string with * @param messageArguments Any arguments to be added to the text component - * * @return The properly formatted text component */ - public static @NotNull TextComponent getTextComponent(@NotNull String key, Object... messageArguments) { + public static @NotNull TextComponent getTextComponent(@NotNull String key, + Object... messageArguments) { if (bundle == null) { initialize(); } @@ -104,7 +121,7 @@ public final class LocaleLoader { public static String formatString(String string, Object... messageArguments) { if (messageArguments != null) { - MessageFormat formatter = new MessageFormat(""); + MessageFormat formatter = new MessageFormat("", Locale.US); formatter.applyPattern(string.replace("'", "''")); string = formatter.format(messageArguments); } @@ -114,9 +131,10 @@ public final class LocaleLoader { return string; } - public static @NotNull TextComponent formatComponent(@NotNull String string, Object... messageArguments) { + public static @NotNull TextComponent formatComponent(@NotNull String string, + Object... messageArguments) { if (messageArguments != null) { - MessageFormat formatter = new MessageFormat(""); + MessageFormat formatter = new MessageFormat("", Locale.US); formatter.applyPattern(string.replace("'", "''")); string = formatter.format(messageArguments); } @@ -133,7 +151,6 @@ public final class LocaleLoader { private static void initialize() { if (bundle == null) { - Locale.setDefault(new Locale("en", "US")); Locale locale = null; String[] myLocale = mcMMO.p.getGeneralConfig().getLocale().split("[-_ ]"); @@ -145,10 +162,13 @@ public final class LocaleLoader { } if (locale == null) { - throw new IllegalStateException("Failed to parse locale string '" + mcMMO.p.getGeneralConfig().getLocale() + "'"); + throw new IllegalStateException( + "Failed to parse locale string '" + mcMMO.p.getGeneralConfig().getLocale() + + "'"); } - Path localePath = Paths.get(mcMMO.getLocalesDirectory() + "locale_" + locale.toString() + ".properties"); + Path localePath = Paths.get( + mcMMO.getLocalesDirectory() + "locale_" + locale + ".properties"); Path overridePath = Paths.get(mcMMO.getLocalesDirectory() + OVERRIDE_FILE_NAME); File overrideFile = overridePath.toFile(); @@ -165,13 +185,18 @@ public final class LocaleLoader { //Insert our helpful text StringBuilder stringBuilder = new StringBuilder(); - try(BufferedReader bufferedReader = new BufferedReader(new FileReader(overrideFile.getPath()))) { + try (BufferedReader bufferedReader = new BufferedReader( + new FileReader(overrideFile.getPath()))) { // Open the file String line; - DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("MM/dd/yyyy HH:mm"); + DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern( + "MM/dd/yyyy HH:mm"); LocalDateTime localDateTime = LocalDateTime.now(); - stringBuilder.append("# mcMMO Locale Override File created on ").append(localDateTime.format(dateTimeFormatter)).append("\r\n"); //Empty file - stringBuilder.append(getLocaleHelpTextWithoutExamples()); //Add our helpful text + stringBuilder.append("# mcMMO Locale Override File created on ") + .append(localDateTime.format(dateTimeFormatter)) + .append("\r\n"); //Empty file + stringBuilder.append( + getLocaleHelpTextWithoutExamples()); //Add our helpful text while ((line = bufferedReader.readLine()) != null) { stringBuilder.append(line).append("\r\n"); } @@ -179,7 +204,7 @@ public final class LocaleLoader { e.printStackTrace(); } - try(FileWriter fileWriter = new FileWriter(overrideFile.getPath())) { + try (FileWriter fileWriter = new FileWriter(overrideFile.getPath())) { fileWriter.write(stringBuilder.toString()); } catch (IOException e) { e.printStackTrace(); @@ -193,18 +218,24 @@ public final class LocaleLoader { //Use the new locale file if (Files.exists(overridePath) && Files.isRegularFile(overridePath)) { try (Reader localeReader = Files.newBufferedReader(overridePath)) { - LogUtils.debug(mcMMO.p.getLogger(), "Loading locale from " + overridePath.toString()); + LogUtils.debug(mcMMO.p.getLogger(), + "Loading locale from " + overridePath); filesystemBundle = new PropertyResourceBundle(localeReader); } catch (IOException e) { - mcMMO.p.getLogger().log(Level.WARNING, "Failed to load locale from " + overridePath, e); + mcMMO.p.getLogger() + .log(Level.WARNING, "Failed to load locale from " + overridePath, e); } } else { //Create a blank file and fill it in with some helpful text - try (BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(overrideFile, true))) { + try (BufferedWriter bufferedWriter = new BufferedWriter( + new FileWriter(overrideFile, true))) { // Open the file to write the player - DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("MM/dd/yyyy HH:mm"); + DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern( + "MM/dd/yyyy HH:mm"); LocalDateTime localDateTime = LocalDateTime.now(); - bufferedWriter.append("# mcMMO Locale Override File created on ").append(localDateTime.format(dateTimeFormatter)).append("\r\n"); //Empty file + bufferedWriter.append("# mcMMO Locale Override File created on ") + .append(localDateTime.format(dateTimeFormatter)) + .append("\r\n"); //Empty file String localeExplanation = getLocaleHelpText(); bufferedWriter.append(localeExplanation); } catch (Exception e) { @@ -221,35 +252,52 @@ public final class LocaleLoader { @NotNull private static String getLocaleHelpText() { String localeExplanation = - "# -- Are you looking to change the language of mcMMO but without editing it yourself? --\n" + + "# -- Are you looking to change the language of mcMMO but without editing it yourself? --\n" + + "\n" + - "# mcMMO has quite a few built in translations, you can choose which translation by editing config.yml with the appropriate locale code. The setting is `General.Locale` in config.yml\n" + - "# Odds are, if you speak a popular language on earth we already have a translation for it.\n" + - "# However our translations are done by the community, and update infrequently. (Please help us out <3)\n" + - "# We would love more people to help update our locales, submit any updated translation file to our GitHub or email it to me at business@neetgames.com\n" + - "# For a list of built in translations, view this link: https://github.com/mcMMO-Dev/mcMMO/tree/master/src/main/resources/locale\n" + + "# mcMMO has quite a few built in translations, you can choose which translation by editing config.yml with the appropriate locale code. The setting is `General.Locale` in config.yml\n" + + + "# Odds are, if you speak a popular language on earth we already have a translation for it.\n" + + + "# However our translations are done by the community, and update infrequently. (Please help us out <3)\n" + + + "# We would love more people to help update our locales, submit any updated translation file to our GitHub or email it to me at business@neetgames.com\n" + + + "# For a list of built in translations, view this link: https://github.com/mcMMO-Dev/mcMMO/tree/master/src/main/resources/locale\n" + + "\n" + "\n" + "# -- Using a built in translation -- \n" + - "# Assuming you read the above section, edit config.yml's General.Locale from en_US to the locale code that we support (see the above link), then reboot your server\n" + + "# Assuming you read the above section, edit config.yml's General.Locale from en_US to the locale code that we support (see the above link), then reboot your server\n" + + "\n" + "\n" + - "# -- Do you want to change the text in mcMMO? Including adding colors? ( Locale Override ) -- \n" + + "# -- Do you want to change the text in mcMMO? Including adding colors? ( Locale Override ) -- \n" + + "# First, a brief explanation.\n" + - "# Locales are the language files used by mcMMO, they also contain color codes and most of the styling used by mcMMO.\n" + - "# You can customize a locale outside of the JAR in version 2.1.51 and up.\n" + + "# Locales are the language files used by mcMMO, they also contain color codes and most of the styling used by mcMMO.\n" + + + "# You can customize a locale outside of the JAR in version 2.1.51 and up.\n" + + "#\n" + "# Locales can be overridden by editing this file\n" + - "# You can find the up to date current locale files here https://github.com/mcMMO-Dev/mcMMO/tree/master/src/main/resources/locale\n" + - "# The master file is en_US, if a translation is missing entries (as they often are) it will pull from the en_US file https://github.com/mcMMO-Dev/mcMMO/blob/master/src/main/resources/locale/locale_en_US.properties\n" + + "# You can find the up to date current locale files here https://github.com/mcMMO-Dev/mcMMO/tree/master/src/main/resources/locale\n" + + + "# The master file is en_US, if a translation is missing entries (as they often are) it will pull from the en_US file https://github.com/mcMMO-Dev/mcMMO/blob/master/src/main/resources/locale/locale_en_US.properties\n" + + "#\n" + - "# To override a locale, add entries to this file and copy ** only ** the strings you want to replace, otherwise you will not see any updated strings when mcMMO updates and will have to manually change them and read patch notes carefully.\n" + - "# If you wish to replace every line in some way, feel free to copy the entire contents of this file, just be advised that you will need to be on top of locale updates in mcMMO and follow our changelog closely.\n" + + "# To override a locale, add entries to this file and copy ** only ** the strings you want to replace, otherwise you will not see any updated strings when mcMMO updates and will have to manually change them and read patch notes carefully.\n" + + + "# If you wish to replace every line in some way, feel free to copy the entire contents of this file, just be advised that you will need to be on top of locale updates in mcMMO and follow our changelog closely.\n" + + "\n" + "\n" + - "# FIND KEYS HERE: On our github repo (en_US is our master file and has ALL the keys) -> https://github.com/mcMMO-Dev/mcMMO/tree/master/src/main/resources/locale\n" + - "# WARNING: Some keys in our master file are unused, make gratuitous use of Ctrl+F\n" + - "# HOW TO APPLY: You can either restart the server for these changes to take effect or run /mcreloadlocale.\n" + + "# FIND KEYS HERE: On our github repo (en_US is our master file and has ALL the keys) -> https://github.com/mcMMO-Dev/mcMMO/tree/master/src/main/resources/locale\n" + + + "# WARNING: Some keys in our master file are unused, make gratuitous use of Ctrl+F\n" + + + "# HOW TO APPLY: You can either restart the server for these changes to take effect or run /mcreloadlocale.\n" + + "# -- Add Keys Below --\n" + getExamples(); return localeExplanation; @@ -258,9 +306,14 @@ public final class LocaleLoader { @NotNull private static String getExamples() { return """ - This.Is.An.Example.Put.Locale.Keys.Here.One=&aExample text using hex color codes + This.Is.An.Example.Put.Locale.Keys.Here.One=&aExample text using simplified minecraft color codes This.Is.An.Example.Put.Locale.Keys.Here.Two=[[DARK_AQUA]]Example text using our own color codes This.Is.An.Example.Put.Locale.Keys.Here.Three=Example text with no colors + This.Is.An.Example.Put.Locale.Keys.Here.Four=&#FF0000Example text with red color hex code + This.Is.An.Example.Put.Locale.Keys.Here.Five=�FF00Example text with green color hex code + This.Is.An.Example.Put.Locale.Keys.Here.Six=�FFExample text with blue color hex code + This.Is.An.Example.Put.Locale.Keys.Here.Seven=&#FFFF00Example text with yellow color hex code + This.Is.An.Example.Put.Locale.Keys.Here.Eight=&lExample text with bold using simplified minecraft color codes """; } @@ -269,18 +322,18 @@ public final class LocaleLoader { String localeExplanation = """ # -- Are you looking to change the language of mcMMO but without editing it yourself? -- - + # mcMMO has quite a few built in translations, you can choose which translation by editing config.yml with the appropriate locale code. The setting is `General.Locale` in config.yml # Odds are, if you speak a popular language on earth we already have a translation for it. # However our translations are done by the community, and update infrequently. (Please help us out <3) # We would love more people to help update our locales, submit any updated translation file to our GitHub or email it to me at business@neetgames.com # For a list of built in translations, view this link: https://github.com/mcMMO-Dev/mcMMO/tree/master/src/main/resources/locale - - + + # -- Using a built in translation --\s # Assuming you read the above section, edit config.yml's General.Locale from en_US to the locale code that we support (see the above link), then reboot your server - - + + # -- Do you want to change the text in mcMMO? Including adding colors? ( Locale Override ) --\s # First, a brief explanation. # Locales are the language files used by mcMMO, they also contain color codes and most of the styling used by mcMMO. @@ -292,8 +345,8 @@ public final class LocaleLoader { # # To override a locale, add entries to this file and copy ** only ** the strings you want to replace, otherwise you will not see any updated strings when mcMMO updates and will have to manually change them and read patch notes carefully. # If you wish to replace every line in some way, feel free to copy the entire contents of this file, just be advised that you will need to be on top of locale updates in mcMMO and follow our changelog closely. - - + + # WARNING: Locales only support ASCII and UTF16 characters at the moment, so you'll need to run special characters through a UTF16 converter (google it) to get them to work. This will be fixed in the future! # FIND KEYS HERE: On our github repo (en_US is our master file and has ALL the keys) -> https://github.com/mcMMO-Dev/mcMMO/tree/master/src/main/resources/locale # WARNING: Some keys in our master file are unused, make gratuitous use of Ctrl+F @@ -304,6 +357,10 @@ public final class LocaleLoader { } public static String addColors(String input) { + // First check for hex color codes and insert them + input = translateHexColorCodes(input); + + // Then check for our own color codes input = input.replaceAll("\\Q[[BLACK]]\\E", ChatColor.BLACK.toString()); input = input.replaceAll("\\Q[[DARK_BLUE]]\\E", ChatColor.DARK_BLUE.toString()); input = input.replaceAll("\\Q[[DARK_GREEN]]\\E", ChatColor.DARK_GREEN.toString()); @@ -327,6 +384,7 @@ public final class LocaleLoader { input = input.replaceAll("\\Q[[MAGIC]]\\E", ChatColor.MAGIC.toString()); input = input.replaceAll("\\Q[[RESET]]\\E", ChatColor.RESET.toString()); + // Then check for the typical color codes input = input.replaceAll("\\Q&0\\E", ChatColor.BLACK.toString()); input = input.replaceAll("\\Q&1\\E", ChatColor.DARK_BLUE.toString()); input = input.replaceAll("\\Q&2\\E", ChatColor.DARK_GREEN.toString()); @@ -352,4 +410,52 @@ public final class LocaleLoader { return input; } + + /** + * Translates hex color codes to the appropriate Minecraft color codes. + *

+ * Hex color codes are in the format of &#RRGGBB Minecraft color codes are in the format of + * §x§R§R§G§G§B§B Where R, G, and B are the red, green, and blue values respectively. The §x is + * a special character that tells Minecraft to use the following color codes as hex values. The + * §R§R is the red value, the §G§G is the green value, and the §B§B is the blue value. Example: + * §x§R§R§G§G§B§B is the equivalent of the hex color code &#RRGGBB + *

+ * + * @param messageWithHex The message with hex color codes to translate + * @return The message with the hex color codes translated to Minecraft color codes + */ + public static String translateHexColorCodes(String messageWithHex) { + if (messageWithHex == null) { + return null; + } + + final Matcher matcher = hexPattern.matcher(messageWithHex); + final StringBuilder buffer = new StringBuilder(messageWithHex.length() + 4 * 8); + while (matcher.find()) { + String group = matcher.group(1); + String hexEquivalent = "§x" + + "§" + group.charAt(0) + "§" + group.charAt(1) + + "§" + group.charAt(2) + "§" + group.charAt(3) + + "§" + group.charAt(4) + "§" + group.charAt(5); + matcher.appendReplacement(buffer, hexEquivalent); + } + return matcher.appendTail(buffer).toString(); + } + + // Method to reverse the transformation from Minecraft color codes to hex codes + public static String reverseTranslateHexColorCodes(String minecraftColorString) { + // Matches the Minecraft color pattern: §x§R§R§G§G§B§B + Matcher matcher = minecraftHexPattern.matcher(minecraftColorString); + StringBuilder buffer = new StringBuilder(); + + while (matcher.find()) { + String hexColor = "#" + + matcher.group(1).substring(1) + matcher.group(2).substring(1) + + matcher.group(3).substring(1) + matcher.group(4).substring(1) + + matcher.group(5).substring(1) + matcher.group(6).substring(1); + matcher.appendReplacement(buffer, "&" + hexColor); + } + matcher.appendTail(buffer); + return buffer.toString(); + } } diff --git a/src/main/java/com/gmail/nossr50/mcMMO.java b/src/main/java/com/gmail/nossr50/mcMMO.java index 52fb4b4cd..5c048899b 100644 --- a/src/main/java/com/gmail/nossr50/mcMMO.java +++ b/src/main/java/com/gmail/nossr50/mcMMO.java @@ -3,12 +3,16 @@ package com.gmail.nossr50; import com.gmail.nossr50.chat.ChatManager; import com.gmail.nossr50.commands.CommandManager; import com.gmail.nossr50.commands.levelup.LevelUpCommandManager; -import com.gmail.nossr50.config.*; +import com.gmail.nossr50.config.AdvancedConfig; +import com.gmail.nossr50.config.CoreSkillsConfig; +import com.gmail.nossr50.config.CustomItemSupportConfig; +import com.gmail.nossr50.config.GeneralConfig; +import com.gmail.nossr50.config.HiddenConfig; +import com.gmail.nossr50.config.RankConfig; +import com.gmail.nossr50.config.SoundConfig; +import com.gmail.nossr50.config.WorldBlacklist; import com.gmail.nossr50.config.experience.ExperienceConfig; -import com.gmail.nossr50.config.mods.ArmorConfigManager; -import com.gmail.nossr50.config.mods.BlockConfigManager; -import com.gmail.nossr50.config.mods.EntityConfigManager; -import com.gmail.nossr50.config.mods.ToolConfigManager; +import com.gmail.nossr50.config.party.PartyConfig; import com.gmail.nossr50.config.skills.alchemy.PotionConfig; import com.gmail.nossr50.config.skills.repair.RepairConfigManager; import com.gmail.nossr50.config.skills.salvage.SalvageConfigManager; @@ -18,8 +22,14 @@ import com.gmail.nossr50.database.DatabaseManager; import com.gmail.nossr50.database.DatabaseManagerFactory; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.subskills.acrobatics.Roll; -import com.gmail.nossr50.listeners.*; -import com.gmail.nossr50.metadata.MetadataService; +import com.gmail.nossr50.listeners.BlockListener; +import com.gmail.nossr50.listeners.ChunkListener; +import com.gmail.nossr50.listeners.EntityListener; +import com.gmail.nossr50.listeners.InteractionManager; +import com.gmail.nossr50.listeners.InventoryListener; +import com.gmail.nossr50.listeners.PlayerListener; +import com.gmail.nossr50.listeners.SelfListener; +import com.gmail.nossr50.listeners.WorldListener; import com.gmail.nossr50.party.PartyManager; import com.gmail.nossr50.placeholders.PapiExpansion; import com.gmail.nossr50.runnables.SaveTimerTask; @@ -31,16 +41,25 @@ import com.gmail.nossr50.runnables.player.ClearRegisteredXPGainTask; 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; import com.gmail.nossr50.skills.salvage.salvageables.Salvageable; import com.gmail.nossr50.skills.salvage.salvageables.SalvageableManager; import com.gmail.nossr50.skills.salvage.salvageables.SimpleSalvageableManager; -import com.gmail.nossr50.util.*; +import com.gmail.nossr50.util.ChimaeraWing; +import com.gmail.nossr50.util.EnchantmentMapper; +import com.gmail.nossr50.util.LogFilter; +import com.gmail.nossr50.util.LogUtils; +import com.gmail.nossr50.util.MaterialMapStore; +import com.gmail.nossr50.util.MetadataConstants; +import com.gmail.nossr50.util.Misc; +import com.gmail.nossr50.util.Permissions; +import com.gmail.nossr50.util.TransientEntityTracker; +import com.gmail.nossr50.util.TransientMetadataTools; import com.gmail.nossr50.util.blockmeta.ChunkManager; import com.gmail.nossr50.util.blockmeta.ChunkManagerFactory; +import com.gmail.nossr50.util.blockmeta.UserBlockTracker; import com.gmail.nossr50.util.commands.CommandRegistrationManager; import com.gmail.nossr50.util.compat.CompatibilityManager; import com.gmail.nossr50.util.experience.FormulaManager; @@ -51,11 +70,15 @@ import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.scoreboards.ScoreboardManager; import com.gmail.nossr50.util.skills.RankUtils; import com.gmail.nossr50.util.skills.SkillTools; -import com.gmail.nossr50.util.skills.SmeltingTracker; import com.gmail.nossr50.util.upgrade.UpgradeManager; import com.gmail.nossr50.worldguard.WorldGuardManager; import com.tcoded.folialib.FoliaLib; -import com.tcoded.folialib.util.InvalidTickDelayNotifier; +import java.io.File; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; import net.kyori.adventure.platform.bukkit.BukkitAudiences; import net.shatteredlands.shatt.backup.ZipLibrary; import org.bstats.bukkit.Metrics; @@ -71,36 +94,24 @@ import org.bukkit.plugin.java.JavaPluginLoader; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.io.File; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.List; - public class mcMMO extends JavaPlugin { - - /* Managers & Services */ private static PlatformManager platformManager; - private static MetadataService metadataService; - private static ChunkManager placeStore; - private static RepairableManager repairableManager; + private static ChunkManager chunkManager; + private static RepairableManager repairableManager; private static SalvageableManager salvageableManager; - private static ModManager modManager; - private static DatabaseManager databaseManager; + private static DatabaseManager databaseManager; private FormulaManager formulaManager; - private static UpgradeManager upgradeManager; + private static UpgradeManager upgradeManager; private static LevelUpCommandManager levelUpCommandManager; private static MaterialMapStore materialMapStore; private static PlayerLevelUtils playerLevelUtils; - private static SmeltingTracker smeltingTracker; private static TransientMetadataTools transientMetadataTools; private static ChatManager chatManager; private static CommandManager commandManager; //ACF private static TransientEntityTracker transientEntityTracker; - private @NotNull SkillTools skillTools; + private SkillTools skillTools; private static boolean serverShutdownExecuted = false; @@ -141,18 +152,13 @@ public class mcMMO extends JavaPlugin { private GeneralConfig generalConfig; private AdvancedConfig advancedConfig; + private PartyConfig partyConfig; + private PotionConfig potionConfig; + private CustomItemSupportConfig customItemSupportConfig; + private EnchantmentMapper enchantmentMapper; private FoliaLib foliaLib; - -// private RepairConfig repairConfig; -// private SalvageConfig salvageConfig; -// private PersistentDataConfig persistentDataConfig; -// private ChatConfig chatConfig; -// private CoreSkillsConfig coreSkillsConfig; -// private RankConfig rankConfig; -// private TreasureConfig treasureConfig; -// private FishingTreasureConfig fishingTreasureConfig; -// private SoundConfig soundConfig; + private PartyManager partyManager; private CommandOnLevelUpConfig commandOnLevelUpConfig; @@ -160,13 +166,6 @@ public class mcMMO extends JavaPlugin { p = this; } - - protected mcMMO(JavaPluginLoader loader, PluginDescriptionFile description, File dataFolder, File file) - { - super(loader, description, dataFolder, file); - } - - /** * Things to be run when the plugin is enabled. */ @@ -176,9 +175,15 @@ public class mcMMO extends JavaPlugin { //Filter out any debug messages (if debug/verbose logging is not enabled) getLogger().setFilter(new LogFilter(this)); + //Platform Manager + platformManager = new PlatformManager(); + //Folia lib plugin instance foliaLib = new FoliaLib(this); - InvalidTickDelayNotifier.disableNotifications = true; + foliaLib.getOptions().disableNotifications(); + // Performance optimization + // This makes the scheduler behave differently between Spigot/Legacy-Paper & Folia/Modern-Paper + foliaLib.getOptions().disableIsValidOnNonFolia(); setupFilePaths(); generalConfig = new GeneralConfig(getDataFolder()); //Load before skillTools @@ -188,16 +193,12 @@ public class mcMMO extends JavaPlugin { levelUpCommandManager = new LevelUpCommandManager(this); advancedConfig = new AdvancedConfig(getDataFolder()); commandOnLevelUpConfig = new CommandOnLevelUpConfig(getDataFolder()); + partyConfig = new PartyConfig(getDataFolder()); + customItemSupportConfig = new CustomItemSupportConfig(getDataFolder()); //Store this value so other plugins can check it isRetroModeEnabled = generalConfig.getIsRetroMode(); - //Platform Manager - platformManager = new PlatformManager(); - - //metadata service - metadataService = new MetadataService(this); - MetadataConstants.MCMMO_METADATA_VALUE = new FixedMetadataValue(this, true); PluginManager pluginManager = getServer().getPluginManager(); @@ -206,11 +207,10 @@ public class mcMMO extends JavaPlugin { upgradeManager = new UpgradeManager(); - modManager = new ModManager(); - - //Init Material Maps + // Init Material Maps materialMapStore = new MaterialMapStore(); - + // Init compatibility mappers + enchantmentMapper = new EnchantmentMapper(this); loadConfigFiles(); if (!noErrorsInConfigFiles) { @@ -221,64 +221,73 @@ public class mcMMO extends JavaPlugin { checkModConfigs(); } - if(projectKorraEnabled) { - getLogger().info("ProjectKorra was detected, this can cause some issues with weakness potions and combat skills for mcMMO"); + if (projectKorraEnabled) { + getLogger().info( + "ProjectKorra was detected, this can cause some issues with weakness potions and combat skills for mcMMO"); } if (healthBarPluginEnabled) { - getLogger().info("HealthBar plugin found, mcMMO's healthbars are automatically disabled."); + getLogger().info( + "HealthBar plugin found, mcMMO's healthbars are automatically disabled."); } - if (pluginManager.getPlugin("NoCheatPlus") != null && pluginManager.getPlugin("CompatNoCheatPlus") == null) { - getLogger().warning("NoCheatPlus plugin found, but CompatNoCheatPlus was not found!"); - getLogger().warning("mcMMO will not work properly alongside NoCheatPlus without CompatNoCheatPlus"); + if (pluginManager.getPlugin("NoCheatPlus") != null && pluginManager.getPlugin( + "CompatNoCheatPlus") == null) { + getLogger().warning( + "NoCheatPlus plugin found, but CompatNoCheatPlus was not found!"); + getLogger().warning( + "mcMMO will not work properly alongside NoCheatPlus without CompatNoCheatPlus"); } // One month in milliseconds this.purgeTime = 2630000000L * generalConfig.getOldUsersCutoff(); - databaseManager = DatabaseManagerFactory.getDatabaseManager(mcMMO.getUsersFilePath(), getLogger(), purgeTime, mcMMO.p.getAdvancedConfig().getStartingLevel()); + databaseManager = DatabaseManagerFactory.getDatabaseManager( + mcMMO.getUsersFilePath(), getLogger(), + purgeTime, mcMMO.p.getAdvancedConfig().getStartingLevel()); //Check for the newer API and tell them what to do if its missing checkForOutdatedAPI(); - if(serverAPIOutdated) - { - foliaLib - .getImpl() - .runTimer( - () -> getLogger().severe("You are running an outdated version of "+platformManager.getServerSoftware()+", mcMMO will not work unless you update to a newer version!"), - 20, 20*60*30 - ); + if (serverAPIOutdated) { + foliaLib.getImpl().runTimer( + () -> getLogger().severe( + "You are running an outdated version of " + + platformManager.getServerSoftware() + + ", mcMMO will not work unless you update to a newer version!"), + 20, 20 * 60 * 30); - if(platformManager.getServerSoftware() == ServerSoftwareType.CRAFT_BUKKIT) - { - foliaLib - .getImpl() - .runTimer( - () -> getLogger().severe("We have detected you are using incompatible server software, our best guess is that you are using CraftBukkit. mcMMO requires Spigot or Paper, if you are not using CraftBukkit, you will still need to update your custom server software before mcMMO will work."), - 20, 20*60*30 - ); + if (platformManager.getServerSoftware() == ServerSoftwareType.CRAFT_BUKKIT) { + foliaLib.getImpl().runTimer( + () -> getLogger().severe( + "We have detected you are using incompatible server software, our best guess is that you are using CraftBukkit. mcMMO requires Spigot or Paper, if you are not using CraftBukkit, you will still need to update your custom server software before mcMMO will work."), + 20, 20 * 60 * 30); } } else { registerEvents(); registerCoreSkills(); registerCustomRecipes(); - PartyManager.loadParties(); + if (partyConfig.isPartyEnabled()) { + partyManager = new PartyManager(this); + partyManager.loadParties(); + } formulaManager = new FormulaManager(); for (Player player : getServer().getOnlinePlayers()) { - getFoliaLib().getImpl().runLaterAsync(new PlayerProfileLoadingTask(player), 1); // 1 Tick delay to ensure the player is marked as online before we begin loading + getFoliaLib().getScheduler().runLaterAsync( + new PlayerProfileLoadingTask(player), + 1); // 1 Tick delay to ensure the player is marked as online before we begin loading } - LogUtils.debug(mcMMO.p.getLogger(), "Version " + getDescription().getVersion() + " is enabled!"); + LogUtils.debug(mcMMO.p.getLogger(), + "Version " + getDescription().getVersion() + " is enabled!"); scheduleTasks(); CommandRegistrationManager.registerCommands(); - placeStore = ChunkManagerFactory.getChunkManager(); // Get our ChunkletManager + chunkManager = ChunkManagerFactory.getChunkManager(); // Get our ChunkletManager if (generalConfig.getPTPCommandWorldPermissions()) { Permissions.generateWorldTeleportPermissions(); @@ -291,23 +300,25 @@ public class mcMMO extends JavaPlugin { //If anonymous statistics are enabled then use them Metrics metrics; - if(generalConfig.getIsMetricsEnabled()) { + if (generalConfig.getIsMetricsEnabled()) { metrics = new Metrics(this, 3894); - metrics.addCustomChart(new SimplePie("version", () -> getDescription().getVersion())); + metrics.addCustomChart( + new SimplePie("version", () -> getDescription().getVersion())); - if(generalConfig.getIsRetroMode()) + if (generalConfig.getIsRetroMode()) { metrics.addCustomChart(new SimplePie("leveling_system", () -> "Retro")); - else + } else { metrics.addCustomChart(new SimplePie("leveling_system", () -> "Standard")); + } } } catch (Throwable t) { getLogger().severe("There was an error while enabling mcMMO!"); if (!(t instanceof ExceptionInInitializerError)) { t.printStackTrace(); - } - else { - getLogger().info("Please do not replace the mcMMO jar while the server is running."); + } else { + getLogger().info( + "Please do not replace the mcMMO jar while the server is running."); } getServer().getPluginManager().disablePlugin(this); @@ -322,9 +333,6 @@ public class mcMMO extends JavaPlugin { //Init the blacklist worldBlacklist = new WorldBlacklist(this); - //Init smelting tracker - smeltingTracker = new SmeltingTracker(); - //Set up Adventure's audiences audiences = BukkitAudiences.create(this); @@ -337,7 +345,7 @@ public class mcMMO extends JavaPlugin { transientEntityTracker = new TransientEntityTracker(); setServerShutdown(false); //Reset flag, used to make decisions about async saves - if(Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null) { + if (Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null) { new PapiExpansion().register(); } } @@ -358,14 +366,15 @@ public class mcMMO extends JavaPlugin { } catch (ClassNotFoundException | NoSuchMethodException e) { serverAPIOutdated = true; String software = platformManager.getServerSoftwareStr(); - getLogger().severe("You are running an older version of " + software + " that is not compatible with mcMMO, update your server software!"); + getLogger().severe( + "You are running an older version of " + software + + " that is not compatible with mcMMO, update your server software!"); } } @Override - public void onLoad() - { - if(getServer().getPluginManager().getPlugin("WorldGuard") != null) { + public void onLoad() { + if (getServer().getPluginManager().getPlugin("WorldGuard") != null) { WorldGuardManager.getInstance().registerFlags(); } } @@ -377,22 +386,25 @@ public class mcMMO extends JavaPlugin { public void onDisable() { setServerShutdown(true); //TODO: Write code to catch unfinished async save tasks, for now we just hope they finish in time, which they should in most cases - mcMMO.p.getLogger().info("Server shutdown has been executed, saving and cleaning up data..."); + mcMMO.p.getLogger() + .info("Server shutdown has been executed, saving and cleaning up data..."); try { UserManager.saveAll(); // Make sure to save player information if the server shuts down UserManager.clearAll(); Alchemy.finishAllBrews(); // Finish all partially complete AlchemyBrewTasks to prevent vanilla brewing continuation on restart - PartyManager.saveParties(); // Save our parties + if (partyConfig.isPartyEnabled()) { + getPartyManager().saveParties(); // Save our parties + } //TODO: Needed? - if(generalConfig.getScoreboardsEnabled()) + if (generalConfig.getScoreboardsEnabled()) { ScoreboardManager.teardownAll(); + } formulaManager.saveFormula(); - placeStore.closeAll(); - } - catch (Exception e) { + chunkManager.closeAll(); + } catch (Exception e) { e.printStackTrace(); } @@ -400,16 +412,17 @@ public class mcMMO extends JavaPlugin { // Remove other tasks BEFORE starting the Backup, or we just cancel it straight away. try { ZipLibrary.mcMMOBackup(); - } catch(NoClassDefFoundError e) { + } catch (NoClassDefFoundError e) { getLogger().severe("Backup class not found!"); - getLogger().info("Please do not replace the mcMMO jar while the server is running."); + getLogger().info( + "Please do not replace the mcMMO jar while the server is running."); } catch (Throwable e) { getLogger().severe(e.toString()); } } LogUtils.debug(mcMMO.p.getLogger(), "Canceling all tasks..."); - getFoliaLib().getImpl().cancelAllTasks(); // This removes our tasks + getFoliaLib().getScheduler().cancelAllTasks(); // This removes our tasks LogUtils.debug(mcMMO.p.getLogger(), "Unregister all events..."); HandlerList.unregisterAll(this); // Cancel event registrations @@ -453,8 +466,33 @@ public class mcMMO extends JavaPlugin { return formulaManager; } + /** + * Get the {@link UserBlockTracker}. + * + * @return the {@link UserBlockTracker} + */ + public static UserBlockTracker getUserBlockTracker() { + return chunkManager; + } + + /** + * Get the chunk manager. + * + * @return the chunk manager + */ + public static ChunkManager getChunkManager() { + return chunkManager; + } + + /** + * Get the chunk manager. + * + * @return the chunk manager + * @deprecated Use {@link #getChunkManager()} or {@link #getUserBlockTracker()} instead. + */ + @Deprecated(since = "2.2.013", forRemoval = true) public static ChunkManager getPlaceStore() { - return placeStore; + return chunkManager; } public static RepairableManager getRepairableManager() { @@ -469,10 +507,6 @@ public class mcMMO extends JavaPlugin { return databaseManager; } - public static ModManager getModManager() { - return modManager; - } - public static UpgradeManager getUpgradeManager() { return upgradeManager; } @@ -481,10 +515,6 @@ public class mcMMO extends JavaPlugin { return platformManager.getCompatibilityManager(); } - public static MetadataService getMetadataService() { - return metadataService; - } - @Deprecated public static void setDatabaseManager(DatabaseManager databaseManager) { mcMMO.databaseManager = databaseManager; @@ -523,10 +553,10 @@ public class mcMMO extends JavaPlugin { } } - File oldArmorFile = new File(modDirectory + "armor.yml"); - File oldBlocksFile = new File(modDirectory + "blocks.yml"); + File oldArmorFile = new File(modDirectory + "armor.yml"); + File oldBlocksFile = new File(modDirectory + "blocks.yml"); File oldEntitiesFile = new File(modDirectory + "entities.yml"); - File oldToolsFile = new File(modDirectory + "tools.yml"); + File oldToolsFile = new File(modDirectory + "tools.yml"); if (oldArmorFile.exists()) { if (!oldArmorFile.renameTo(new File(modDirectory + "armor.default.yml"))) { @@ -564,34 +594,19 @@ public class mcMMO extends JavaPlugin { FishingTreasureConfig.getInstance(); HiddenConfig.getInstance(); mcMMO.p.getAdvancedConfig(); - PotionConfig.getInstance(); + + // init potion config + potionConfig = new PotionConfig(); + potionConfig.loadPotions(); + CoreSkillsConfig.getInstance(); SoundConfig.getInstance(); RankConfig.getInstance(); - new ChildConfig(); - List repairables = new ArrayList<>(); - if (generalConfig.getToolModsEnabled()) { - new ToolConfigManager(this); - } - - if (generalConfig.getArmorModsEnabled()) { - new ArmorConfigManager(this); - } - - if (generalConfig.getBlockModsEnabled()) { - new BlockConfigManager(this); - } - - if (generalConfig.getEntityModsEnabled()) { - new EntityConfigManager(this); - } - // Load repair configs, make manager, and register them at this time repairables.addAll(new RepairConfigManager(this).getLoadedRepairables()); - repairables.addAll(modManager.getLoadedRepairables()); repairableManager = new SimpleRepairableManager(repairables.size()); repairableManager.registerRepairables(repairables); @@ -613,12 +628,11 @@ public class mcMMO extends JavaPlugin { pluginManager.registerEvents(new SelfListener(this), this); pluginManager.registerEvents(new WorldListener(this), this); pluginManager.registerEvents(new ChunkListener(), this); -// pluginManager.registerEvents(new CommandListener(this), this); + // pluginManager.registerEvents(new CommandListener(this), this); } /** - * Registers core skills - * This enables the skills in the new skill system + * Registers core skills This enables the skills in the new skill system */ private void registerCoreSkills() { /* @@ -627,8 +641,7 @@ public class mcMMO extends JavaPlugin { InteractionManager.initMaps(); //Init maps - if(CoreSkillsConfig.getInstance().isPrimarySkillEnabled(PrimarySkillType.ACROBATICS)) - { + if (CoreSkillsConfig.getInstance().isPrimarySkillEnabled(PrimarySkillType.ACROBATICS)) { LogUtils.debug(mcMMO.p.getLogger(), "Enabling Acrobatics Skills"); //TODO: Should do this differently @@ -639,11 +652,12 @@ public class mcMMO extends JavaPlugin { } private void registerCustomRecipes() { - getFoliaLib().getImpl().runLater(() -> { - if (generalConfig.getChimaeraEnabled()) { - getServer().addRecipe(ChimaeraWing.getChimaeraWingRecipe()); - } - }, 40); + getFoliaLib().getScheduler().runLater( + () -> { + if (generalConfig.getChimaeraEnabled()) { + getServer().addRecipe(ChimaeraWing.getChimaeraWingRecipe()); + } + }, 40); } private void scheduleTasks() { @@ -653,63 +667,78 @@ public class mcMMO extends JavaPlugin { long saveIntervalTicks = Math.max(minute, generalConfig.getSaveInterval() * minute); - getFoliaLib().getImpl().runTimer(new SaveTimerTask(), saveIntervalTicks, saveIntervalTicks); + getFoliaLib().getScheduler() + .runTimer(new SaveTimerTask(), saveIntervalTicks, saveIntervalTicks); // Cleanup the backups folder - getFoliaLib().getImpl().runAsync(new CleanBackupsTask()); + getFoliaLib().getScheduler().runAsync(new CleanBackupsTask()); // Old & Powerless User remover - long purgeIntervalTicks = generalConfig.getPurgeInterval() * 60L * 60L * Misc.TICK_CONVERSION_FACTOR; + long purgeIntervalTicks = + generalConfig.getPurgeInterval() * 60L * 60L * Misc.TICK_CONVERSION_FACTOR; if (purgeIntervalTicks == 0) { - getFoliaLib().getImpl().runLaterAsync(new UserPurgeTask(), 2 * Misc.TICK_CONVERSION_FACTOR); // Start 2 seconds after startup. - } - else if (purgeIntervalTicks > 0) { - getFoliaLib().getImpl().runTimerAsync(new UserPurgeTask(), purgeIntervalTicks, purgeIntervalTicks); + getFoliaLib().getScheduler().runLaterAsync( + new UserPurgeTask(), + 2 * Misc.TICK_CONVERSION_FACTOR); // Start 2 seconds after startup. + } else if (purgeIntervalTicks > 0) { + getFoliaLib().getScheduler() + .runTimerAsync(new UserPurgeTask(), purgeIntervalTicks, purgeIntervalTicks); } // Automatically remove old members from parties - long kickIntervalTicks = generalConfig.getAutoPartyKickInterval() * 60L * 60L * Misc.TICK_CONVERSION_FACTOR; + if (partyConfig.isPartyEnabled()) { + long kickIntervalTicks = generalConfig.getAutoPartyKickInterval() * 60L * 60L + * Misc.TICK_CONVERSION_FACTOR; - if (kickIntervalTicks == 0) { - getFoliaLib().getImpl().runLater(new PartyAutoKickTask(), 2 * Misc.TICK_CONVERSION_FACTOR); // Start 2 seconds after startup. - } - else if (kickIntervalTicks > 0) { - getFoliaLib().getImpl().runTimer(new PartyAutoKickTask(), kickIntervalTicks, kickIntervalTicks); + if (kickIntervalTicks == 0) { + getFoliaLib().getScheduler().runLater( + new PartyAutoKickTask(), + 2 * Misc.TICK_CONVERSION_FACTOR); // Start 2 seconds after startup. + } else if (kickIntervalTicks > 0) { + getFoliaLib().getScheduler() + .runTimer(new PartyAutoKickTask(), kickIntervalTicks, kickIntervalTicks); + } } // Update power level tag scoreboards - getFoliaLib().getImpl().runTimer(new PowerLevelUpdatingTask(), 2 * Misc.TICK_CONVERSION_FACTOR, 2 * Misc.TICK_CONVERSION_FACTOR); + getFoliaLib().getScheduler().runTimer( + new PowerLevelUpdatingTask(), 2 * Misc.TICK_CONVERSION_FACTOR, + 2 * Misc.TICK_CONVERSION_FACTOR); // Clear the registered XP data so players can earn XP again if (ExperienceConfig.getInstance().getDiminishedReturnsEnabled()) { - getFoliaLib().getImpl().runTimer(new ClearRegisteredXPGainTask(), 60, 60); + getFoliaLib().getScheduler().runTimer(new ClearRegisteredXPGainTask(), 60, 60); } - if(mcMMO.p.getAdvancedConfig().allowPlayerTips()) - { - getFoliaLib().getImpl().runTimer(new NotifySquelchReminderTask(), 60, ((20 * 60) * 60)); + if (mcMMO.p.getAdvancedConfig().allowPlayerTips()) { + getFoliaLib().getScheduler() + .runTimer(new NotifySquelchReminderTask(), 60, ((20 * 60) * 60)); } } private void checkModConfigs() { if (!generalConfig.getToolModsEnabled()) { - getLogger().warning("Cauldron implementation found, but the custom tool config for mcMMO is disabled!"); + getLogger().warning( + "Cauldron implementation found, but the custom tool config for mcMMO is disabled!"); getLogger().info("To enable, set Mods.Tool_Mods_Enabled to TRUE in config.yml."); } if (!generalConfig.getArmorModsEnabled()) { - getLogger().warning("Cauldron implementation found, but the custom armor config for mcMMO is disabled!"); + getLogger().warning( + "Cauldron implementation found, but the custom armor config for mcMMO is disabled!"); getLogger().info("To enable, set Mods.Armor_Mods_Enabled to TRUE in config.yml."); } if (!generalConfig.getBlockModsEnabled()) { - getLogger().warning("Cauldron implementation found, but the custom block config for mcMMO is disabled!"); + getLogger().warning( + "Cauldron implementation found, but the custom block config for mcMMO is disabled!"); getLogger().info("To enable, set Mods.Block_Mods_Enabled to TRUE in config.yml."); } if (!generalConfig.getEntityModsEnabled()) { - getLogger().warning("Cauldron implementation found, but the custom entity config for mcMMO is disabled!"); + getLogger().warning( + "Cauldron implementation found, but the custom entity config for mcMMO is disabled!"); getLogger().info("To enable, set Mods.Entity_Mods_Enabled to TRUE in config.yml."); } } @@ -720,9 +749,9 @@ public class mcMMO extends JavaPlugin { } /** - * Checks if this plugin is using retro mode - * Retro mode is a 0-1000 skill system - * Standard mode is scaled for 1-100 + * Checks if this plugin is using retro mode Retro mode is a 0-1000 skill system Standard mode + * is scaled for 1-100 + * * @return true if retro mode is enabled */ public static boolean isRetroModeEnabled() { @@ -737,10 +766,6 @@ public class mcMMO extends JavaPlugin { return platformManager; } - public static SmeltingTracker getSmeltingTracker() { - return smeltingTracker; - } - public static BukkitAudiences getAudiences() { return audiences; } @@ -789,6 +814,35 @@ public class mcMMO extends JavaPlugin { return advancedConfig; } + public @NotNull PartyConfig getPartyConfig() { + return partyConfig; + } + + /** + * Check if the party system is enabled + * + * @return true if the party system is enabled, false otherwise + */ + public boolean isPartySystemEnabled() { + return partyConfig.isPartyEnabled(); + } + + public PartyManager getPartyManager() { + return partyManager; + } + + public CustomItemSupportConfig getCustomItemSupportConfig() { + return customItemSupportConfig; + } + + public PotionConfig getPotionConfig() { + return potionConfig; + } + + public EnchantmentMapper getEnchantmentMapper() { + return enchantmentMapper; + } + public @NotNull FoliaLib getFoliaLib() { return foliaLib; } diff --git a/src/main/java/com/gmail/nossr50/metadata/BlockMetadataService.java b/src/main/java/com/gmail/nossr50/metadata/BlockMetadataService.java deleted file mode 100644 index 1545cd608..000000000 --- a/src/main/java/com/gmail/nossr50/metadata/BlockMetadataService.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.gmail.nossr50.metadata; - -import com.gmail.nossr50.mcMMO; -import org.bukkit.block.Furnace; -import org.bukkit.persistence.PersistentDataContainer; -import org.bukkit.persistence.PersistentDataHolder; -import org.bukkit.persistence.PersistentDataType; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.UUID; - -import static com.gmail.nossr50.metadata.MetadataService.NSK_FURNACE_UUID_LEAST_SIG; -import static com.gmail.nossr50.metadata.MetadataService.NSK_FURNACE_UUID_MOST_SIG; - -public class BlockMetadataService { - - private final @NotNull mcMMO pluginRef; - - public BlockMetadataService(@NotNull mcMMO pluginRef) { - this.pluginRef = pluginRef; - } - - public @Nullable UUID getFurnaceOwner(@NotNull Furnace furnace) { - //Get container from entity - PersistentDataContainer dataContainer = ((PersistentDataHolder) furnace).getPersistentDataContainer(); - - //Too lazy to make a custom data type for this stuff - Long mostSigBits = dataContainer.get(NSK_FURNACE_UUID_MOST_SIG, PersistentDataType.LONG); - Long leastSigBits = dataContainer.get(NSK_FURNACE_UUID_LEAST_SIG, PersistentDataType.LONG); - - if (mostSigBits != null && leastSigBits != null) { - return new UUID(mostSigBits, leastSigBits); - } else { - return null; - } - } - - public void setFurnaceOwner(@NotNull Furnace furnace, @NotNull UUID uuid) { - PersistentDataContainer dataContainer = ((PersistentDataHolder) furnace).getPersistentDataContainer(); - - dataContainer.set(NSK_FURNACE_UUID_MOST_SIG, PersistentDataType.LONG, uuid.getMostSignificantBits()); - dataContainer.set(NSK_FURNACE_UUID_LEAST_SIG, PersistentDataType.LONG, uuid.getLeastSignificantBits()); - - furnace.update(); - } - - -} diff --git a/src/main/java/com/gmail/nossr50/metadata/MetadataService.java b/src/main/java/com/gmail/nossr50/metadata/MetadataService.java deleted file mode 100644 index d38726737..000000000 --- a/src/main/java/com/gmail/nossr50/metadata/MetadataService.java +++ /dev/null @@ -1,71 +0,0 @@ -package com.gmail.nossr50.metadata; - -import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.util.MetadataConstants; -import org.bukkit.NamespacedKey; -import org.jetbrains.annotations.NotNull; - -public class MetadataService { - private final @NotNull mcMMO pluginRef; - - protected static final @NotNull NamespacedKey NSK_SUPER_ABILITY_BOOSTED_ITEM; - protected static final @NotNull NamespacedKey NSK_MOB_SPAWNER_MOB; - protected static final @NotNull NamespacedKey NSK_EGG_MOB; - protected static final @NotNull NamespacedKey NSK_NETHER_GATE_MOB; - protected static final @NotNull NamespacedKey NSK_COTW_SUMMONED_MOB; - protected static final @NotNull NamespacedKey NSK_PLAYER_BRED_MOB; - protected static final @NotNull NamespacedKey NSK_PLAYER_TAMED_MOB; - protected static final @NotNull NamespacedKey NSK_VILLAGER_TRADE_ORIGIN_ITEM; - protected static final @NotNull NamespacedKey NSK_EXPLOITED_ENDERMEN; - protected static final @NotNull NamespacedKey NSK_FURNACE_UUID_MOST_SIG; - protected static final @NotNull NamespacedKey NSK_FURNACE_UUID_LEAST_SIG; - - static { - NSK_SUPER_ABILITY_BOOSTED_ITEM = getNamespacedKey(MetadataConstants.METADATA_KEY_SUPER_ABILITY_BOOSTED_ITEM); - NSK_MOB_SPAWNER_MOB = getNamespacedKey(MetadataConstants.METADATA_KEY_MOB_SPAWNER_MOB); - NSK_EGG_MOB = getNamespacedKey(MetadataConstants.METADATA_KEY_EGG_MOB); - NSK_NETHER_GATE_MOB = getNamespacedKey(MetadataConstants.METADATA_KEY_NETHER_PORTAL_MOB); - NSK_COTW_SUMMONED_MOB = getNamespacedKey(MetadataConstants.METADATA_KEY_COTW_SUMMONED_MOB); - NSK_PLAYER_BRED_MOB = getNamespacedKey(MetadataConstants.METADATA_KEY_PLAYER_BRED_MOB); - NSK_PLAYER_TAMED_MOB = getNamespacedKey(MetadataConstants.METADATA_KEY_PLAYER_TAMED_MOB); - NSK_VILLAGER_TRADE_ORIGIN_ITEM = getNamespacedKey(MetadataConstants.METADATA_KEY_VILLAGER_TRADE_ORIGIN_ITEM); - NSK_EXPLOITED_ENDERMEN = getNamespacedKey(MetadataConstants.METADATA_KEY_EXPLOITED_ENDERMEN); - NSK_FURNACE_UUID_MOST_SIG = getNamespacedKey(MetadataConstants.METADATA_KEY_FURNACE_UUID_MOST_SIG); - NSK_FURNACE_UUID_LEAST_SIG = getNamespacedKey(MetadataConstants.METADATA_KEY_FURNACE_UUID_LEAST_SIG); - } - - private final @NotNull ItemMetadataService itemMetadataService; - private final @NotNull MobMetadataService mobMetadataService; - private final @NotNull BlockMetadataService blockMetadataService; - - public MetadataService(@NotNull mcMMO pluginRef) { - this.pluginRef = pluginRef; - - blockMetadataService = new BlockMetadataService(pluginRef); - mobMetadataService = new MobMetadataService(pluginRef); - itemMetadataService = new ItemMetadataService(pluginRef); - } - - /** - * Helper method to simplify generating namespaced keys - * - * @param key the {@link String} value of the key - * - * @return the generated {@link NamespacedKey} - */ - public static @NotNull NamespacedKey getNamespacedKey(@NotNull String key) { - return new NamespacedKey(mcMMO.p, key); - } - - public @NotNull ItemMetadataService getItemMetadataService() { - return itemMetadataService; - } - - public @NotNull MobMetadataService getMobMetadataService() { - return mobMetadataService; - } - - public @NotNull BlockMetadataService getBlockMetadataService() { - return blockMetadataService; - } -} diff --git a/src/main/java/com/gmail/nossr50/metadata/MobMetadataService.java b/src/main/java/com/gmail/nossr50/metadata/MobMetadataService.java deleted file mode 100644 index e78b056c9..000000000 --- a/src/main/java/com/gmail/nossr50/metadata/MobMetadataService.java +++ /dev/null @@ -1,177 +0,0 @@ -package com.gmail.nossr50.metadata; - -import com.gmail.nossr50.api.exceptions.IncompleteNamespacedKeyRegister; -import com.gmail.nossr50.config.PersistentDataConfig; -import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.util.MetadataConstants; -import org.bukkit.NamespacedKey; -import org.bukkit.entity.Entity; -import org.bukkit.entity.LivingEntity; -import org.bukkit.persistence.PersistentDataContainer; -import org.bukkit.persistence.PersistentDataType; -import org.jetbrains.annotations.NotNull; - -import java.util.EnumMap; -import java.util.HashSet; -import java.util.WeakHashMap; - -import static com.gmail.nossr50.metadata.MetadataService.*; - -//TODO: Use SpawnReason where appropriate instead of MobMetaFlagType -public class MobMetadataService { - private final @NotNull WeakHashMap> mobRegistry; //transient data - private final @NotNull EnumMap mobFlagKeyMap; //used for persistent data - private final @NotNull mcMMO pluginRef; - private boolean isUsingPersistentData = false; - - public MobMetadataService(@NotNull mcMMO pluginRef) { - this.pluginRef = pluginRef; - mobFlagKeyMap = new EnumMap<>(MobMetaFlagType.class); - mobRegistry = new WeakHashMap<>(); - initMobFlagKeyMap(); - - for (MobMetaFlagType metaFlagType : MobMetaFlagType.values()) { - if (PersistentDataConfig.getInstance().isMobPersistent(metaFlagType)) - isUsingPersistentData = true; - } - } - - /** - * Registers the namespaced keys required by the API (CB/Spigot) - * Used primarily for persistent data - */ - private void initMobFlagKeyMap() throws IncompleteNamespacedKeyRegister { - for (MobMetaFlagType mobMetaFlagType : MobMetaFlagType.values()) { - switch (mobMetaFlagType) { - case MOB_SPAWNER_MOB -> mobFlagKeyMap.put(mobMetaFlagType, NSK_MOB_SPAWNER_MOB); - case EGG_MOB -> mobFlagKeyMap.put(mobMetaFlagType, NSK_EGG_MOB); - case NETHER_PORTAL_MOB -> mobFlagKeyMap.put(mobMetaFlagType, NSK_NETHER_GATE_MOB); - case COTW_SUMMONED_MOB -> mobFlagKeyMap.put(mobMetaFlagType, NSK_COTW_SUMMONED_MOB); - case PLAYER_BRED_MOB -> mobFlagKeyMap.put(mobMetaFlagType, NSK_PLAYER_BRED_MOB); - case EXPLOITED_ENDERMEN -> mobFlagKeyMap.put(mobMetaFlagType, NSK_EXPLOITED_ENDERMEN); - case PLAYER_TAMED_MOB -> mobFlagKeyMap.put(mobMetaFlagType, NSK_PLAYER_TAMED_MOB); - default -> throw new IncompleteNamespacedKeyRegister("missing namespaced key register for type: " + mobMetaFlagType); - } - } - } - - /** - * 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 - * - * @return true if the mob has metadata values for target {@link MobMetaFlagType} - */ - public boolean hasMobFlag(@NotNull MobMetaFlagType flag, @NotNull LivingEntity livingEntity) { - if (PersistentDataConfig.getInstance().isMobPersistent(flag)) { - return livingEntity.getPersistentDataContainer().has(mobFlagKeyMap.get(flag), PersistentDataType.BYTE); - } else { - if (mobRegistry.containsKey(livingEntity)) { - return mobRegistry.get(livingEntity).contains(flag); - } - - return false; - } - } - - /** - * Whether a target {@link LivingEntity} has any mcMMO mob flags - * - * @param livingEntity the living entity to check for metadata - * - * @return true if the mob has any mcMMO mob related metadata values - */ - public boolean hasMobFlags(@NotNull LivingEntity livingEntity) { - if (isUsingPersistentData) { - for (MobMetaFlagType metaFlagType : MobMetaFlagType.values()) { - if (hasMobFlag(metaFlagType, livingEntity)) - return true; - } - - return false; - } else { - return mobRegistry.containsKey(livingEntity) && mobRegistry.get(livingEntity).size() > 0; - } - } - - /** - * Copies all mcMMO mob flags from one {@link LivingEntity} to another {@link LivingEntity} - * This does not clear existing mcMMO mob flags on the target - * - * @param sourceEntity entity to copy from - * @param targetEntity entity to copy to - */ - public void addMobFlags(@NotNull LivingEntity sourceEntity, @NotNull LivingEntity targetEntity) { - if (!hasMobFlags(sourceEntity)) - return; - - if (isUsingPersistentData) { - for (MobMetaFlagType flag : MobMetaFlagType.values()) { - if (hasMobFlag(flag, sourceEntity)) { - flagMetadata(flag, targetEntity); - } - } - } else { - HashSet flags = new HashSet<>(mobRegistry.get(sourceEntity)); - mobRegistry.put(targetEntity, flags); - } - } - - /** - * Adds a mob flag to a {@link LivingEntity} which effectively acts a true/false boolean - * Existence of the flag can be considered a true value, non-existence can be considered false for all intents and purposes - * - * @param flag the desired flag to assign - * @param livingEntity the target living entity - */ - public void flagMetadata(@NotNull MobMetaFlagType flag, @NotNull LivingEntity livingEntity) { - if (PersistentDataConfig.getInstance().isMobPersistent(flag)) { - if (!hasMobFlag(flag, livingEntity)) { - PersistentDataContainer persistentDataContainer = livingEntity.getPersistentDataContainer(); - persistentDataContainer.set(mobFlagKeyMap.get(flag), PersistentDataType.BYTE, MetadataConstants.SIMPLE_FLAG_VALUE); - } - } else { - HashSet flags = mobRegistry.getOrDefault(livingEntity, new HashSet<>()); - flags.add(flag); // add the new flag - mobRegistry.put(livingEntity, flags); //update registry - } - } - - /** - * Removes a specific mob flag from target {@link LivingEntity} - * - * @param flag desired flag to remove - * @param livingEntity the target living entity - */ - public void removeMobFlag(@NotNull MobMetaFlagType flag, @NotNull LivingEntity livingEntity) { - if (PersistentDataConfig.getInstance().isMobPersistent(flag)) { - if (hasMobFlag(flag, livingEntity)) { - PersistentDataContainer persistentDataContainer = livingEntity.getPersistentDataContainer(); - persistentDataContainer.remove(mobFlagKeyMap.get(flag)); - } - } else { - if (mobRegistry.containsKey(livingEntity)) { - mobRegistry.get(livingEntity).remove(flag); - - if (mobRegistry.get(livingEntity).size() == 0) - mobRegistry.remove(livingEntity); - } - } - } - - /** - * Remove all mcMMO related mob flags from the target {@link LivingEntity} - * - * @param livingEntity target entity - */ - public void removeMobFlags(@NotNull LivingEntity livingEntity) { - if (isUsingPersistentData) { - for (MobMetaFlagType flag : MobMetaFlagType.values()) { - removeMobFlag(flag, livingEntity); - } - } else { - mobRegistry.remove(livingEntity); - } - } -} diff --git a/src/main/java/com/gmail/nossr50/party/PartyManager.java b/src/main/java/com/gmail/nossr50/party/PartyManager.java index 7bc3afe9b..53e355cef 100644 --- a/src/main/java/com/gmail/nossr50/party/PartyManager.java +++ b/src/main/java/com/gmail/nossr50/party/PartyManager.java @@ -1,5 +1,7 @@ package com.gmail.nossr50.party; +import static java.util.Objects.requireNonNull; + import com.gmail.nossr50.datatypes.chat.ChatChannel; import com.gmail.nossr50.datatypes.interactions.NotificationType; import com.gmail.nossr50.datatypes.party.ItemShareType; @@ -19,10 +21,6 @@ import com.gmail.nossr50.util.player.NotificationManager; import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.sounds.SoundManager; import com.gmail.nossr50.util.sounds.SoundType; -import org.bukkit.OfflinePlayer; -import org.bukkit.configuration.file.YamlConfiguration; -import org.bukkit.entity.Player; - import java.io.File; import java.util.ArrayList; import java.util.LinkedHashMap; @@ -30,112 +28,60 @@ import java.util.List; import java.util.Map.Entry; import java.util.UUID; import java.util.logging.Level; +import org.bukkit.OfflinePlayer; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; public final class PartyManager { - private static final String partiesFilePath = mcMMO.getFlatFileDirectory() + "parties.yml"; - private static final List parties = new ArrayList<>(); - private static final File partyFile = new File(partiesFilePath); + private final @NotNull List parties; + private final @NotNull File partyFile; + private final @NotNull mcMMO pluginRef; - private PartyManager() {} - - /** - * Check if a party with a given name already exists. - * - * @param player The player to notify - * @param partyName The name of the party to check - * @return true if a party with that name exists, false otherwise - */ - public static boolean checkPartyExistence(Player player, String partyName) { - if (getParty(partyName) == null) { - return false; - } - - player.sendMessage(LocaleLoader.getString("Commands.Party.AlreadyExists", partyName)); - return true; + public PartyManager(@NotNull mcMMO pluginRef) { + this.pluginRef = pluginRef; + final String partiesFilePath = mcMMO.getFlatFileDirectory() + "parties.yml"; + this.partyFile = new File(partiesFilePath); + this.parties = new ArrayList<>(); } /** - * Checks if the player can join a party, parties can have a size limit, although there is a permission to bypass this + * Checks if the player can join a party, parties can have a size limit, although there is a + * permission to bypass this + * * @param player player who is attempting to join the party * @param targetParty the target party * @return true if party is full and cannot be joined */ - public static boolean isPartyFull(Player player, Party targetParty) - { - return !Permissions.partySizeBypass(player) && mcMMO.p.getGeneralConfig().getPartyMaxSize() >= 1 && targetParty.getOnlineMembers().size() >= mcMMO.p.getGeneralConfig().getPartyMaxSize(); + 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(); } - /** - * Attempt to change parties or join a new party. - * - * @param mcMMOPlayer The player changing or joining parties - * @param newPartyName The name of the party being joined - * @return true if the party was joined successfully, false otherwise - */ - public static boolean changeOrJoinParty(McMMOPlayer mcMMOPlayer, String newPartyName) { - Player player = mcMMOPlayer.getPlayer(); + public boolean areAllies(@NotNull Player firstPlayer, @NotNull Player secondPlayer) { + requireNonNull(firstPlayer, "firstPlayer cannot be null!"); + requireNonNull(secondPlayer, "secondPlayer cannot be null!"); - if (mcMMOPlayer.inParty()) { - Party oldParty = mcMMOPlayer.getParty(); - - if (!handlePartyChangeEvent(player, oldParty.getName(), newPartyName, EventReason.CHANGED_PARTIES)) { - return false; - } - - removeFromParty(mcMMOPlayer); - } - else return handlePartyChangeEvent(player, null, newPartyName, EventReason.JOINED_PARTY); - - return true; - } - - /** - * Check if two online players are in the same party. - * - * @param firstPlayer The first player - * @param secondPlayer The second player - * @return true if they are in the same party, false otherwise - */ - public static boolean inSameParty(Player firstPlayer, Player secondPlayer) { //Profile not loaded - if(UserManager.getPlayer(firstPlayer) == null) - { + if (UserManager.getPlayer(firstPlayer) == null) { return false; } //Profile not loaded - if(UserManager.getPlayer(secondPlayer) == null) - { + if (UserManager.getPlayer(secondPlayer) == null) { return false; } Party firstParty = UserManager.getPlayer(firstPlayer).getParty(); Party secondParty = UserManager.getPlayer(secondPlayer).getParty(); - if (firstParty == null || secondParty == null) { - return false; - } - - return firstParty.equals(secondParty); - } - - public static boolean areAllies(Player firstPlayer, Player secondPlayer) { - //Profile not loaded - if(UserManager.getPlayer(firstPlayer) == null) - { - return false; - } - - //Profile not loaded - if(UserManager.getPlayer(secondPlayer) == null) - { - return false; - } - - Party firstParty = UserManager.getPlayer(firstPlayer).getParty(); - Party secondParty = UserManager.getPlayer(secondPlayer).getParty(); - - if (firstParty == null || secondParty == null || firstParty.getAlly() == null || secondParty.getAlly() == null) { + if (firstParty == null || secondParty == null || firstParty.getAlly() == null + || secondParty.getAlly() == null) { return false; } @@ -145,19 +91,21 @@ public final class PartyManager { /** * Get the near party members. * - * @param mcMMOPlayer The player to check + * @param mmoPlayer The player to check * @return the near party members */ - public static List getNearMembers(McMMOPlayer mcMMOPlayer) { + public @NotNull List getNearMembers(@NotNull McMMOPlayer mmoPlayer) { + requireNonNull(mmoPlayer, "mmoPlayer cannot be null!"); List nearMembers = new ArrayList<>(); - Party party = mcMMOPlayer.getParty(); + Party party = mmoPlayer.getParty(); if (party != null) { - Player player = mcMMOPlayer.getPlayer(); - double range = mcMMO.p.getGeneralConfig().getPartyShareRange(); + Player player = mmoPlayer.getPlayer(); + double range = pluginRef.getGeneralConfig().getPartyShareRange(); for (Player member : party.getOnlineMembers()) { - if (!player.equals(member) && member.isValid() && Misc.isNear(player.getLocation(), member.getLocation(), range)) { + if (!player.equals(member) && member.isValid() && Misc.isNear(player.getLocation(), + member.getLocation(), range)) { nearMembers.add(member); } } @@ -166,18 +114,18 @@ public final class PartyManager { return nearMembers; } - public static List getNearVisibleMembers(McMMOPlayer mcMMOPlayer) { + public @NotNull List getNearVisibleMembers(@NotNull McMMOPlayer mmoPlayer) { + requireNonNull(mmoPlayer, "mmoPlayer cannot be null!"); List nearMembers = new ArrayList<>(); - Party party = mcMMOPlayer.getParty(); + Party party = mmoPlayer.getParty(); if (party != null) { - Player player = mcMMOPlayer.getPlayer(); - double range = mcMMO.p.getGeneralConfig().getPartyShareRange(); + Player player = mmoPlayer.getPlayer(); + double range = pluginRef.getGeneralConfig().getPartyShareRange(); for (Player member : party.getVisibleMembers(player)) { - if (!player.equals(member) - && member.isValid() - && Misc.isNear(player.getLocation(), member.getLocation(), range)) { + if (!player.equals(member) && member.isValid() && Misc.isNear(player.getLocation(), + member.getLocation(), range)) { nearMembers.add(member); } } @@ -186,14 +134,14 @@ public final class PartyManager { return nearMembers; } - /** * Get a list of all players in this player's party. * * @param player The player to check * @return all the players in the player's party */ - public static LinkedHashMap getAllMembers(Player player) { + public @NotNull LinkedHashMap getAllMembers(@NotNull Player player) { + requireNonNull(player, "player cannot be null!"); Party party = getParty(player); return party == null ? new LinkedHashMap<>() : party.getMembers(); @@ -205,7 +153,8 @@ public final class PartyManager { * @param partyName The party to check * @return all online players in this party */ - public static List getOnlineMembers(String partyName) { + public @NotNull List getOnlineMembers(@NotNull String partyName) { + requireNonNull(partyName, "partyName cannot be null!"); return getOnlineMembers(getParty(partyName)); } @@ -215,11 +164,12 @@ public final class PartyManager { * @param player The player to check * @return all online players in this party */ - public static List getOnlineMembers(Player player) { + public @NotNull List getOnlineMembers(@NotNull Player player) { + requireNonNull(player, "player cannot be null!"); return getOnlineMembers(getParty(player)); } - private static List getOnlineMembers(Party party) { + private List getOnlineMembers(@Nullable Party party) { return party == null ? new ArrayList<>() : party.getOnlineMembers(); } @@ -229,7 +179,8 @@ public final class PartyManager { * @param partyName The party name * @return the existing party, null otherwise */ - public static Party getParty(String partyName) { + public @Nullable Party getParty(@NotNull String partyName) { + requireNonNull(partyName, "partyName cannot be null!"); for (Party party : parties) { if (party.getName().equalsIgnoreCase(partyName)) { return party; @@ -246,9 +197,10 @@ public final class PartyManager { * @return the existing party, null otherwise */ @Deprecated - public static Party getPlayerParty(String playerName) { + public @Nullable Party getPlayerParty(@NotNull String playerName) { + requireNonNull(playerName, "playerName cannot be null!"); for (Party party : parties) { - if (party.getMembers().containsKey(playerName)) { + if (party.getMembers().containsValue(playerName)) { return party; } } @@ -262,7 +214,9 @@ public final class PartyManager { * @param uuid The members uuid * @return the existing party, null otherwise */ - public static Party getPlayerParty(String playerName, UUID uuid) { + 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)) { @@ -285,16 +239,19 @@ public final class PartyManager { * @param player The member * @return the existing party, null otherwise */ - public static Party getParty(Player player) { + public @Nullable Party getParty(@NotNull Player player) { + requireNonNull(player, "player cannot be null!"); //Profile not loaded - if(UserManager.getPlayer(player) == null) - { + if (UserManager.getPlayer(player) == null) { return null; } - McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player); + final McMMOPlayer mmoPlayer = UserManager.getPlayer(player); + if (mmoPlayer == null) { + return null; + } - return mcMMOPlayer.getParty(); + return mmoPlayer.getParty(); } /** @@ -302,7 +259,7 @@ public final class PartyManager { * * @return the list of parties. */ - public static List getParties() { + public @NotNull List getParties() { return parties; } @@ -312,11 +269,29 @@ public final class PartyManager { * @param player The player to remove * @param party The party */ - public static void removeFromParty(OfflinePlayer player, Party party) { - LinkedHashMap members = party.getMembers(); - String playerName = player.getName(); + public void removeFromParty(@NotNull OfflinePlayer player, @NotNull Party party) { + requireNonNull(player, "player cannot be null!"); + requireNonNull(party, "party cannot be null!"); - members.remove(player.getUniqueId()); + final LinkedHashMap members = party.getMembers(); + final String playerName = player.getName(); + + if (party.getLeader().getUniqueId().equals(player.getUniqueId())) { + members.remove(player.getUniqueId()); + if (!members.isEmpty()) { + for (Entry entry : members.entrySet()) { + final UUID memberUUID = entry.getKey(); + final String memberName = entry.getValue(); + if (!memberUUID.equals(party.getLeader().getUniqueId())) { + party.setLeader(new PartyLeader(memberUUID, memberName)); + break; + } + } + } + + } else { + members.remove(player.getUniqueId()); + } if (player.isOnline()) { party.getOnlineMembers().remove(player.getPlayer()); @@ -324,13 +299,7 @@ public final class PartyManager { if (members.isEmpty()) { parties.remove(party); - } - else { - // If the leaving player was the party leader, appoint a new leader from the party members - if (party.getLeader().getUniqueId().equals(player.getUniqueId())) { - setPartyLeader(members.keySet().iterator().next(), party); - } - + } else { informPartyMembersQuit(party, playerName); } } @@ -338,11 +307,16 @@ public final class PartyManager { /** * Remove a player from a party. * - * @param mcMMOPlayer The player to remove + * @param mmoPlayer The player to remove */ - public static void removeFromParty(McMMOPlayer mcMMOPlayer) { - removeFromParty(mcMMOPlayer.getPlayer(), mcMMOPlayer.getParty()); - processPartyLeaving(mcMMOPlayer); + public void removeFromParty(@NotNull McMMOPlayer mmoPlayer) { + requireNonNull(mmoPlayer, "mmoPlayer cannot be null!"); + if (mmoPlayer.getParty() == null) { + return; + } + + removeFromParty(mmoPlayer.getPlayer(), mmoPlayer.getParty()); + processPartyLeaving(mmoPlayer); } /** @@ -351,21 +325,24 @@ public final class PartyManager { * @param party The party to remove * @deprecated Use {@link #disbandParty(McMMOPlayer, Party)} */ - public static void disbandParty(Party party) { + @Deprecated + public void disbandParty(@NotNull Party party) { + requireNonNull(party, "party cannot be null!"); disbandParty(null, party); } /** * Disband a party. Kicks out all members and removes the party. * + * @param mmoPlayer The player to remove (can be null? lol) * @param party The party to remove */ - public static void disbandParty(McMMOPlayer mcMMOPlayer, Party party) { + public void disbandParty(@Nullable McMMOPlayer mmoPlayer, @NotNull Party party) { + requireNonNull(party, "party cannot be null!"); //TODO: Potential issues with unloaded profile? for (final Player member : party.getOnlineMembers()) { //Profile not loaded - if(UserManager.getPlayer(member) == null) - { + if (UserManager.getPlayer(member) == null) { continue; } @@ -378,22 +355,26 @@ public final class PartyManager { } parties.remove(party); - if (mcMMOPlayer != null) { - handlePartyChangeEvent(mcMMOPlayer.getPlayer(), party.getName(), null, EventReason.DISBANDED_PARTY); + if (mmoPlayer != null) { + handlePartyChangeEvent(mmoPlayer.getPlayer(), party.getName(), null, + EventReason.DISBANDED_PARTY); } } /** * Create a new party * - * @param mcMMOPlayer The player to add to the party + * @param mmoPlayer The player to add to the party * @param partyName The party to add the player to * @param password The password for this party, null if there was no password */ - public static void createParty(McMMOPlayer mcMMOPlayer, String partyName, String password) { - Player player = mcMMOPlayer.getPlayer(); + public void createParty(@NotNull McMMOPlayer mmoPlayer, @NotNull String partyName, + @Nullable String password) { + Player player = mmoPlayer.getPlayer(); - Party party = new Party(new PartyLeader(player.getUniqueId(), player.getName()), partyName.replace(".", ""), password); + Party party = new Party(new PartyLeader(player.getUniqueId(), player.getName()), + partyName.replace(".", ""), + password); if (password != null) { player.sendMessage(LocaleLoader.getString("Party.Password.Set", password)); @@ -402,7 +383,7 @@ public final class PartyManager { parties.add(party); player.sendMessage(LocaleLoader.getString("Commands.Party.Create", party.getName())); - addToParty(mcMMOPlayer, party); + addToParty(mmoPlayer, party); handlePartyChangeEvent(player, null, partyName, EventReason.CREATED_PARTY); } @@ -414,7 +395,8 @@ public final class PartyManager { * @param password The password provided by the player * @return true if the player can join the party */ - public static boolean checkPartyPassword(Player player, Party party, String password) { + public boolean checkPartyPassword(@NotNull Player player, @NotNull Party party, + @Nullable String password) { if (party.isLocked()) { String partyPassword = party.getPassword(); @@ -440,39 +422,48 @@ public final class PartyManager { /** * Accept a party invitation * - * @param mcMMOPlayer The player to add to the party + * @param mmoPlayer The player to add to the party */ - public static void joinInvitedParty(McMMOPlayer mcMMOPlayer) { - Party invite = mcMMOPlayer.getPartyInvite(); + public void joinInvitedParty(@NotNull McMMOPlayer mmoPlayer) { + requireNonNull(mmoPlayer, "mmoPlayer cannot be null!"); + Party invite = mmoPlayer.getPartyInvite(); // Check if the party still exists, it might have been disbanded if (!parties.contains(invite)) { - NotificationManager.sendPlayerInformation(mcMMOPlayer.getPlayer(), NotificationType.PARTY_MESSAGE, "Party.Disband"); + NotificationManager.sendPlayerInformation(mmoPlayer.getPlayer(), + NotificationType.PARTY_MESSAGE, + "Party.Disband"); return; } /* * Don't let players join a full party */ - if(mcMMO.p.getGeneralConfig().getPartyMaxSize() > 0 && invite.getMembers().size() >= mcMMO.p.getGeneralConfig().getPartyMaxSize()) - { - NotificationManager.sendPlayerInformation(mcMMOPlayer.getPlayer(), NotificationType.PARTY_MESSAGE, "Commands.Party.PartyFull.InviteAccept", invite.getName(), String.valueOf(mcMMO.p.getGeneralConfig().getPartyMaxSize())); + if (pluginRef.getGeneralConfig().getPartyMaxSize() > 0 && invite.getMembers() + .size() >= pluginRef.getGeneralConfig().getPartyMaxSize()) { + NotificationManager.sendPlayerInformation(mmoPlayer.getPlayer(), + NotificationType.PARTY_MESSAGE, + "Commands.Party.PartyFull.InviteAccept", invite.getName(), + String.valueOf(pluginRef.getGeneralConfig().getPartyMaxSize())); return; } - NotificationManager.sendPlayerInformation(mcMMOPlayer.getPlayer(), NotificationType.PARTY_MESSAGE, "Commands.Party.Invite.Accepted", invite.getName()); - mcMMOPlayer.removePartyInvite(); - addToParty(mcMMOPlayer, invite); + NotificationManager.sendPlayerInformation(mmoPlayer.getPlayer(), + NotificationType.PARTY_MESSAGE, + "Commands.Party.Invite.Accepted", invite.getName()); + mmoPlayer.removePartyInvite(); + addToParty(mmoPlayer, invite); } /** * Accept a party alliance invitation * - * @param mcMMOPlayer The player who accepts the alliance invite + * @param mmoPlayer The player who accepts the alliance invite */ - public static void acceptAllianceInvite(McMMOPlayer mcMMOPlayer) { - Party invite = mcMMOPlayer.getPartyAllianceInvite(); - Player player = mcMMOPlayer.getPlayer(); + public void acceptAllianceInvite(@NotNull McMMOPlayer mmoPlayer) { + requireNonNull(mmoPlayer, "mmoPlayer cannot be null!"); + Party invite = mmoPlayer.getPartyAllianceInvite(); + Player player = mmoPlayer.getPlayer(); // Check if the party still exists, it might have been disbanded if (!parties.contains(invite)) { @@ -480,63 +471,84 @@ public final class PartyManager { return; } - if (!handlePartyChangeAllianceEvent(player, mcMMOPlayer.getParty().getName(), invite.getName(), McMMOPartyAllianceChangeEvent.EventReason.FORMED_ALLIANCE)) { + if (!handlePartyChangeAllianceEvent(player, mmoPlayer.getParty().getName(), + invite.getName(), + McMMOPartyAllianceChangeEvent.EventReason.FORMED_ALLIANCE)) { return; } - player.sendMessage(LocaleLoader.getString("Commands.Party.Alliance.Invite.Accepted", invite.getName())); - mcMMOPlayer.removePartyAllianceInvite(); + player.sendMessage(LocaleLoader.getString("Commands.Party.Alliance.Invite.Accepted", + invite.getName())); + mmoPlayer.removePartyAllianceInvite(); - createAlliance(mcMMOPlayer.getParty(), invite); + createAlliance(mmoPlayer.getParty(), invite); } - public static void createAlliance(Party firstParty, Party secondParty) { + 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); for (Player member : firstParty.getOnlineMembers()) { - member.sendMessage(LocaleLoader.getString("Party.Alliance.Formed", secondParty.getName())); + member.sendMessage( + LocaleLoader.getString("Party.Alliance.Formed", secondParty.getName())); } for (Player member : secondParty.getOnlineMembers()) { - member.sendMessage(LocaleLoader.getString("Party.Alliance.Formed", firstParty.getName())); + member.sendMessage( + LocaleLoader.getString("Party.Alliance.Formed", firstParty.getName())); } } - public static boolean disbandAlliance(Player player, Party firstParty, Party secondParty){ - if (!handlePartyChangeAllianceEvent(player, firstParty.getName(), secondParty.getName(), McMMOPartyAllianceChangeEvent.EventReason.DISBAND_ALLIANCE)) { + 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; } - PartyManager.disbandAlliance(firstParty, secondParty); + disbandAlliance(firstParty, secondParty); return true; } - private static void disbandAlliance(Party firstParty, Party secondParty) { + 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); for (Player member : firstParty.getOnlineMembers()) { - member.sendMessage(LocaleLoader.getString("Party.Alliance.Disband", secondParty.getName())); + member.sendMessage( + LocaleLoader.getString("Party.Alliance.Disband", secondParty.getName())); } for (Player member : secondParty.getOnlineMembers()) { - member.sendMessage(LocaleLoader.getString("Party.Alliance.Disband", firstParty.getName())); + member.sendMessage( + LocaleLoader.getString("Party.Alliance.Disband", firstParty.getName())); } } /** * Add a player to a party * - * @param mcMMOPlayer The player to add to the party + * @param mmoPlayer The player to add to the party * @param party The party */ - public static void addToParty(McMMOPlayer mcMMOPlayer, Party party) { - Player player = mcMMOPlayer.getPlayer(); + public void addToParty(@NotNull McMMOPlayer mmoPlayer, @NotNull Party party) { + requireNonNull(mmoPlayer, "mmoPlayer cannot be null!"); + requireNonNull(party, "party cannot be null!"); + + Player player = mmoPlayer.getPlayer(); String playerName = player.getName(); informPartyMembersJoin(party, playerName); - mcMMOPlayer.setParty(party); + mmoPlayer.setParty(party); party.getMembers().put(player.getUniqueId(), player.getName()); party.getOnlineMembers().add(player); } @@ -547,7 +559,8 @@ public final class PartyManager { * @param partyName The party name * @return the leader of the party */ - public static String getPartyLeaderName(String partyName) { + public @Nullable String getPartyLeaderName(@NotNull String partyName) { + requireNonNull(partyName, "partyName cannot be null!"); Party party = getParty(partyName); return party == null ? null : party.getLeader().getPlayerName(); @@ -559,8 +572,10 @@ public final class PartyManager { * @param uuid The uuid of the player to set as leader * @param party The party */ - public static void setPartyLeader(UUID uuid, Party party) { - OfflinePlayer player = mcMMO.p.getServer().getOfflinePlayer(uuid); + 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(); for (Player member : party.getOnlineMembers()) { @@ -568,11 +583,9 @@ public final class PartyManager { if (memberUniqueId.equals(player.getUniqueId())) { member.sendMessage(LocaleLoader.getString("Party.Owner.Player")); - } - else if (memberUniqueId.equals(leaderUniqueId)) { + } else if (memberUniqueId.equals(leaderUniqueId)) { member.sendMessage(LocaleLoader.getString("Party.Owner.NotLeader")); - } - else { + } else { member.sendMessage(LocaleLoader.getString("Party.Owner.New", player.getName())); } } @@ -585,25 +598,101 @@ public final class PartyManager { * * @return true if the player can invite */ - public static boolean canInvite(McMMOPlayer mcMMOPlayer) { - Party party = mcMMOPlayer.getParty(); + public boolean canInvite(@NotNull McMMOPlayer mmoPlayer) { + requireNonNull(mmoPlayer, "mmoPlayer cannot be null!"); + Party party = mmoPlayer.getParty(); - return !party.isLocked() || party.getLeader().getUniqueId().equals(mcMMOPlayer.getPlayer().getUniqueId()); + return !party.isLocked() || party.getLeader().getUniqueId() + .equals(mmoPlayer.getPlayer().getUniqueId()); + } + + /** + * Check if a party with a given name already exists. + * + * @param player The player to notify + * @param partyName The name of the party to check + * @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; + } + + player.sendMessage(LocaleLoader.getString("Commands.Party.AlreadyExists", partyName)); + return true; + } + + /** + * Attempt to change parties or join a new party. + * + * @param mmoPlayer The player changing or joining parties + * @param newPartyName The name of the party being joined + * @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()) { + final Party oldParty = mmoPlayer.getParty(); + + if (!handlePartyChangeEvent(player, oldParty.getName(), newPartyName, + EventReason.CHANGED_PARTIES)) { + return false; + } + + removeFromParty(mmoPlayer); + } else { + return handlePartyChangeEvent(player, null, newPartyName, EventReason.JOINED_PARTY); + } + + return true; + } + + /** + * Check if two online players are in the same party. + * + * @param firstPlayer The first player + * @param secondPlayer The second player + * @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; + } + + //Profile not loaded + if (UserManager.getPlayer(secondPlayer) == null) { + return false; + } + + Party firstParty = UserManager.getPlayer(firstPlayer).getParty(); + Party secondParty = UserManager.getPlayer(secondPlayer).getParty(); + + if (firstParty == null || secondParty == null) { + return false; + } + + return firstParty.equals(secondParty); } /** * Load party file. */ - public static void loadParties() { - if (!partyFile.exists()) { + public void loadParties() { + if (!pluginRef.getPartyConfig().isPartyEnabled() || !partyFile.exists()) { return; } -// if (mcMMO.getUpgradeManager().shouldUpgrade(UpgradeType.ADD_UUIDS_PARTY)) { -// loadAndUpgradeParties(); -// return; -// } - try { YamlConfiguration partiesFile; partiesFile = YamlConfiguration.loadConfiguration(partyFile); @@ -614,8 +703,10 @@ public final class PartyManager { try { Party party = new Party(partyName); - String[] leaderSplit = partiesFile.getString(partyName + ".Leader").split("[|]"); - party.setLeader(new PartyLeader(UUID.fromString(leaderSplit[0]), leaderSplit[1])); + String[] leaderSplit = partiesFile.getString(partyName + ".Leader") + .split("[|]"); + party.setLeader( + new PartyLeader(UUID.fromString(leaderSplit[0]), leaderSplit[1])); party.setPassword(partiesFile.getString(partyName + ".Password")); party.setLocked(partiesFile.getBoolean(partyName + ".Locked")); party.setLevel(partiesFile.getInt(partyName + ".Level")); @@ -625,11 +716,18 @@ public final class PartyManager { hasAlly.add(party); } - party.setXpShareMode(ShareMode.getShareMode(partiesFile.getString(partyName + ".ExpShareMode", "NONE"))); - party.setItemShareMode(ShareMode.getShareMode(partiesFile.getString(partyName + ".ItemShareMode", "NONE"))); + party.setXpShareMode( + ShareMode.getShareMode( + partiesFile.getString(partyName + ".ExpShareMode", "NONE"))); + party.setItemShareMode( + ShareMode.getShareMode( + partiesFile.getString(partyName + ".ItemShareMode", "NONE"))); for (ItemShareType itemShareType : ItemShareType.values()) { - party.setSharingDrops(itemShareType, partiesFile.getBoolean(partyName + ".ItemShareType." + itemShareType.toString(), true)); + party.setSharingDrops(itemShareType, + partiesFile.getBoolean( + partyName + ".ItemShareType." + itemShareType, + true)); } LinkedHashMap members = party.getMembers(); @@ -641,31 +739,33 @@ public final class PartyManager { parties.add(party); } catch (Exception e) { - mcMMO.p.getLogger().log(Level.WARNING, "An exception occurred while loading a party with name '" + partyName + "'. Skipped loading party.", e); + pluginRef.getLogger().log(Level.WARNING, + "An exception occurred while loading a party with name '" + partyName + + "'. Skipped loading party.", + e); } } - LogUtils.debug(mcMMO.p.getLogger(), "Loaded (" + parties.size() + ") Parties..."); + LogUtils.debug(pluginRef.getLogger(), "Loaded (" + parties.size() + ") Parties..."); for (Party party : hasAlly) { - party.setAlly(PartyManager.getParty(partiesFile.getString(party.getName() + ".Ally"))); + party.setAlly(getParty(partiesFile.getString(party.getName() + ".Ally"))); } } catch (Exception e) { e.printStackTrace(); } - } /** * Save party file. */ - public static void saveParties() { - LogUtils.debug(mcMMO.p.getLogger(), "[Party Data] Saving..."); + public void saveParties() { + LogUtils.debug(pluginRef.getLogger(), "[Party Data] Saving..."); if (partyFile.exists()) { if (!partyFile.delete()) { - mcMMO.p.getLogger().warning("Could not delete party file. Party saving failed!"); + pluginRef.getLogger().warning("Could not delete party file. Party saving failed!"); return; } } @@ -676,23 +776,27 @@ public final class PartyManager { String partyName = party.getName(); PartyLeader leader = party.getLeader(); - partiesFile.set(partyName + ".Leader", leader.getUniqueId().toString() + "|" + leader.getPlayerName()); + partiesFile.set(partyName + ".Leader", + leader.getUniqueId().toString() + "|" + leader.getPlayerName()); partiesFile.set(partyName + ".Password", party.getPassword()); partiesFile.set(partyName + ".Locked", party.isLocked()); partiesFile.set(partyName + ".Level", party.getLevel()); partiesFile.set(partyName + ".Xp", (int) party.getXp()); - partiesFile.set(partyName + ".Ally", (party.getAlly() != null) ? party.getAlly().getName() : ""); + partiesFile.set(partyName + ".Ally", + (party.getAlly() != null) ? party.getAlly().getName() : ""); partiesFile.set(partyName + ".ExpShareMode", party.getXpShareMode().toString()); partiesFile.set(partyName + ".ItemShareMode", party.getItemShareMode().toString()); for (ItemShareType itemShareType : ItemShareType.values()) { - partiesFile.set(partyName + ".ItemShareType." + itemShareType.toString(), party.sharingDrops(itemShareType)); + partiesFile.set(partyName + ".ItemShareType." + itemShareType.toString(), + party.sharingDrops(itemShareType)); } List members = new ArrayList<>(); for (Entry memberEntry : party.getMembers().entrySet()) { - String memberUniqueId = memberEntry.getKey() == null ? "" : memberEntry.getKey().toString(); + String memberUniqueId = + memberEntry.getKey() == null ? "" : memberEntry.getKey().toString(); String memberName = memberEntry.getValue(); if (!members.contains(memberName)) { @@ -705,79 +809,11 @@ public final class PartyManager { try { partiesFile.save(partyFile); - } - catch (Exception e) { + } catch (Exception e) { e.printStackTrace(); } } -// private static void loadAndUpgradeParties() { -// YamlConfiguration partiesFile = YamlConfiguration.loadConfiguration(partyFile); -// -// if (!partyFile.renameTo(new File(mcMMO.getFlatFileDirectory() + "parties.yml.converted"))) { -// mcMMO.p.getLogger().severe("Could not rename parties.yml to parties.yml.converted!"); -// return; -// } -// -// ArrayList hasAlly = new ArrayList<>(); -// -// for (String partyName : partiesFile.getConfigurationSection("").getKeys(false)) { -// Party party = new Party(partyName); -// -// String leaderName = partiesFile.getString(partyName + ".Leader"); -// PlayerProfile profile = mcMMO.getDatabaseManager().loadPlayerProfile(leaderName, false); -// -// if (!profile.isLoaded()) { -// mcMMO.p.getLogger().warning("Could not find UUID in database for party leader " + leaderName + " in party " + partyName); -// continue; -// } -// -// UUID leaderUniqueId = profile.getUniqueId(); -// -// party.setLeader(new PartyLeader(leaderUniqueId, leaderName)); -// party.setPassword(partiesFile.getString(partyName + ".Password")); -// party.setLocked(partiesFile.getBoolean(partyName + ".Locked")); -// party.setLevel(partiesFile.getInt(partyName + ".Level")); -// party.setXp(partiesFile.getInt(partyName + ".Xp")); -// -// if (partiesFile.getString(partyName + ".Ally") != null) { -// hasAlly.add(party); -// } -// -// party.setXpShareMode(ShareMode.getShareMode(partiesFile.getString(partyName + ".ExpShareMode", "NONE"))); -// party.setItemShareMode(ShareMode.getShareMode(partiesFile.getString(partyName + ".ItemShareMode", "NONE"))); -// -// for (ItemShareType itemShareType : ItemShareType.values()) { -// party.setSharingDrops(itemShareType, partiesFile.getBoolean(partyName + ".ItemShareType." + itemShareType.toString(), true)); -// } -// -// LinkedHashMap members = party.getMembers(); -// -// for (String memberName : partiesFile.getStringList(partyName + ".Members")) { -// PlayerProfile memberProfile = mcMMO.getDatabaseManager().loadPlayerProfile(memberName, false); -// -// if (!memberProfile.isLoaded()) { -// mcMMO.p.getLogger().warning("Could not find UUID in database for party member " + memberName + " in party " + partyName); -// continue; -// } -// -// UUID memberUniqueId = memberProfile.getUniqueId(); -// -// members.put(memberUniqueId, memberName); -// } -// -// parties.add(party); -// } -// -// LogUtils.debug(mcMMO.p.getLogger(), "Loaded (" + parties.size() + ") Parties..."); -// -// for (Party party : hasAlly) { -// party.setAlly(PartyManager.getParty(partiesFile.getString(party.getName() + ".Ally"))); -// } -// -// mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.ADD_UUIDS_PARTY); -// } - /** * Handle party change event. * @@ -787,9 +823,11 @@ public final class PartyManager { * @param reason The reason for changing parties * @return true if the change event was successful, false otherwise */ - public static boolean handlePartyChangeEvent(Player player, String oldPartyName, String newPartyName, EventReason reason) { - McMMOPartyChangeEvent event = new McMMOPartyChangeEvent(player, oldPartyName, newPartyName, reason); - mcMMO.p.getServer().getPluginManager().callEvent(event); + public boolean handlePartyChangeEvent(Player player, String oldPartyName, String newPartyName, + EventReason reason) { + McMMOPartyChangeEvent event = new McMMOPartyChangeEvent(player, oldPartyName, newPartyName, + reason); + pluginRef.getServer().getPluginManager().callEvent(event); return !event.isCancelled(); } @@ -803,22 +841,26 @@ public final class PartyManager { * @param reason The reason for changing allies * @return true if the change event was successful, false otherwise */ - public static boolean handlePartyChangeAllianceEvent(Player player, String oldAllyName, String newAllyName, McMMOPartyAllianceChangeEvent.EventReason reason) { - McMMOPartyAllianceChangeEvent event = new McMMOPartyAllianceChangeEvent(player, oldAllyName, newAllyName, reason); - mcMMO.p.getServer().getPluginManager().callEvent(event); + public boolean handlePartyChangeAllianceEvent(Player player, String oldAllyName, + String newAllyName, + McMMOPartyAllianceChangeEvent.EventReason reason) { + McMMOPartyAllianceChangeEvent event = new McMMOPartyAllianceChangeEvent(player, oldAllyName, + newAllyName, + reason); + pluginRef.getServer().getPluginManager().callEvent(event); return !event.isCancelled(); } /** - * Remove party data from the mcMMOPlayer. + * Remove party data from the mmoPlayer. * - * @param mcMMOPlayer The player to remove party data from. + * @param mmoPlayer The player to remove party data from. */ - public static void processPartyLeaving(McMMOPlayer mcMMOPlayer) { - mcMMOPlayer.removeParty(); - mcMMOPlayer.setChatMode(ChatChannel.NONE); - mcMMOPlayer.setItemShareModifier(10); + public void processPartyLeaving(@NotNull McMMOPlayer mmoPlayer) { + mmoPlayer.removeParty(); + mmoPlayer.setChatMode(ChatChannel.NONE); + mmoPlayer.setItemShareModifier(10); } /** @@ -828,8 +870,8 @@ public final class PartyManager { * @param levelsGained The amount of levels gained * @param level The current party level */ - public static void informPartyMembersLevelUp(Party party, int levelsGained, int level) { - boolean levelUpSoundsEnabled = mcMMO.p.getGeneralConfig().getLevelUpSoundsEnabled(); + public void informPartyMembersLevelUp(Party party, int levelsGained, int level) { + boolean levelUpSoundsEnabled = pluginRef.getGeneralConfig().getLevelUpSoundsEnabled(); for (Player member : party.getOnlineMembers()) { member.sendMessage(LocaleLoader.getString("Party.LevelUp", levelsGained, level)); @@ -845,7 +887,7 @@ public final class PartyManager { * @param party The concerned party * @param playerName The name of the player that joined */ - private static void informPartyMembersJoin(Party party, String playerName) { + private void informPartyMembersJoin(Party party, String playerName) { for (Player member : party.getOnlineMembers()) { member.sendMessage(LocaleLoader.getString("Party.InformedOnJoin", playerName)); } @@ -857,7 +899,7 @@ public final class PartyManager { * @param party The concerned party * @param playerName The name of the player that left */ - private static void informPartyMembersQuit(Party party, String playerName) { + private void informPartyMembersQuit(Party party, String playerName) { for (Player member : party.getOnlineMembers()) { member.sendMessage(LocaleLoader.getString("Party.InformedOnQuit", playerName)); } diff --git a/src/main/java/com/gmail/nossr50/party/ShareHandler.java b/src/main/java/com/gmail/nossr50/party/ShareHandler.java index cc991104d..a9c38d6e4 100644 --- a/src/main/java/com/gmail/nossr50/party/ShareHandler.java +++ b/src/main/java/com/gmail/nossr50/party/ShareHandler.java @@ -11,50 +11,54 @@ import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.Misc; import com.gmail.nossr50.util.player.UserManager; +import java.util.List; import org.bukkit.entity.Item; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; -import java.util.List; - public final class ShareHandler { - private ShareHandler() {} + private ShareHandler() { + } /** * Distribute Xp amongst party members. * * @param xp Xp without party sharing - * @param mcMMOPlayer Player initiating the Xp gain + * @param mmoPlayer Player initiating the Xp gain * @param primarySkillType Skill being used * @return True is the xp has been shared */ - public static boolean handleXpShare(float xp, McMMOPlayer mcMMOPlayer, PrimarySkillType primarySkillType, XPGainReason xpGainReason) { - Party party = mcMMOPlayer.getParty(); + public static boolean handleXpShare(float xp, McMMOPlayer mmoPlayer, + PrimarySkillType primarySkillType, XPGainReason xpGainReason) { + Party party = mmoPlayer.getParty(); if (party.getXpShareMode() != ShareMode.EQUAL) { return false; } - List nearMembers = PartyManager.getNearVisibleMembers(mcMMOPlayer); + List nearMembers = mcMMO.p.getPartyManager().getNearVisibleMembers(mmoPlayer); if (nearMembers.isEmpty()) { return false; } - nearMembers.add(mcMMOPlayer.getPlayer()); + nearMembers.add(mmoPlayer.getPlayer()); int partySize = nearMembers.size(); - double shareBonus = Math.min(mcMMO.p.getGeneralConfig().getPartyShareBonusBase() + (partySize * mcMMO.p.getGeneralConfig().getPartyShareBonusIncrease()), mcMMO.p.getGeneralConfig().getPartyShareBonusCap()); + double shareBonus = Math.min(mcMMO.p.getGeneralConfig().getPartyShareBonusBase() + + (partySize * mcMMO.p.getGeneralConfig().getPartyShareBonusIncrease()), + mcMMO.p.getGeneralConfig().getPartyShareBonusCap()); float splitXp = (float) (xp / partySize * shareBonus); for (Player member : nearMembers) { //Profile not loaded - if(UserManager.getPlayer(member) == null) - { + if (UserManager.getPlayer(member) == null) { continue; } - UserManager.getPlayer(member).beginUnsharedXpGain(primarySkillType, splitXp, xpGainReason, XPGainSource.PARTY_MEMBERS); + UserManager.getPlayer(member) + .beginUnsharedXpGain(primarySkillType, splitXp, xpGainReason, + XPGainSource.PARTY_MEMBERS); } return true; @@ -64,10 +68,10 @@ public final class ShareHandler { * Distribute Items amongst party members. * * @param drop Item that will get shared - * @param mcMMOPlayer Player who picked up the item + * @param mmoPlayer Player who picked up the item * @return True if the item has been shared */ - public static boolean handleItemShare(Item drop, McMMOPlayer mcMMOPlayer) { + public static boolean handleItemShare(Item drop, McMMOPlayer mmoPlayer) { ItemStack itemStack = drop.getItemStack(); ItemShareType dropType = ItemShareType.getShareType(itemStack); @@ -75,7 +79,7 @@ public final class ShareHandler { return false; } - Party party = mcMMOPlayer.getParty(); + Party party = mmoPlayer.getParty(); if (!party.sharingDrops(dropType)) { return false; @@ -87,7 +91,7 @@ public final class ShareHandler { return false; } - List nearMembers = PartyManager.getNearMembers(mcMMOPlayer); + List nearMembers = mcMMO.p.getPartyManager().getNearMembers(mmoPlayer); if (nearMembers.isEmpty()) { return false; @@ -96,7 +100,7 @@ public final class ShareHandler { Player winningPlayer = null; ItemStack newStack = itemStack.clone(); - nearMembers.add(mcMMOPlayer.getPlayer()); + nearMembers.add(mmoPlayer.getPlayer()); int partySize = nearMembers.size(); drop.remove(); @@ -113,8 +117,7 @@ public final class ShareHandler { McMMOPlayer mcMMOMember = UserManager.getPlayer(member); //Profile not loaded - if(UserManager.getPlayer(member) == null) - { + if (UserManager.getPlayer(member) == null) { continue; } @@ -130,14 +133,16 @@ public final class ShareHandler { if (winningPlayer != null) { McMMOPlayer mcMMOWinning = UserManager.getPlayer(winningPlayer); - mcMMOWinning.setItemShareModifier(mcMMOWinning.getItemShareModifier() + itemWeight); + mcMMOWinning.setItemShareModifier( + mcMMOWinning.getItemShareModifier() + itemWeight); } winningPlayer = member; } McMMOPlayer mcMMOTarget = UserManager.getPlayer(winningPlayer); - mcMMOTarget.setItemShareModifier(mcMMOTarget.getItemShareModifier() - itemWeight); + mcMMOTarget.setItemShareModifier( + mcMMOTarget.getItemShareModifier() - itemWeight); awardDrop(winningPlayer, newStack); } @@ -159,11 +164,9 @@ public final class ShareHandler { public static XPGainReason getSharedXpGainReason(XPGainReason xpGainReason) { if (xpGainReason == XPGainReason.PVE) { return XPGainReason.SHARED_PVE; - } - else if (xpGainReason == XPGainReason.PVP) { + } else if (xpGainReason == XPGainReason.PVP) { return XPGainReason.SHARED_PVP; - } - else { + } else { return xpGainReason; } } diff --git a/src/main/java/com/gmail/nossr50/placeholders/PapiExpansion.java b/src/main/java/com/gmail/nossr50/placeholders/PapiExpansion.java index ff7a90cea..06ad1b25b 100644 --- a/src/main/java/com/gmail/nossr50/placeholders/PapiExpansion.java +++ b/src/main/java/com/gmail/nossr50/placeholders/PapiExpansion.java @@ -9,17 +9,17 @@ import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.text.StringUtils; +import java.util.Map; +import java.util.TreeMap; import me.clip.placeholderapi.PlaceholderAPIPlugin; import me.clip.placeholderapi.expansion.PlaceholderExpansion; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.Map; -import java.util.TreeMap; - public class PapiExpansion extends PlaceholderExpansion { - private final Map placeholders = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); + private final Map placeholders = new TreeMap<>( + String.CASE_INSENSITIVE_ORDER); public PapiExpansion() { init(); @@ -41,6 +41,11 @@ public class PapiExpansion extends PlaceholderExpansion { return "1.0,0"; } + @Override + public boolean persist() { + return true; + } + @Override public String getRequiredPlugin() { return "mcMMO"; @@ -71,19 +76,25 @@ public class PapiExpansion extends PlaceholderExpansion { public Integer getSkillLevel(PrimarySkillType skill, Player player) { final McMMOPlayer user = UserManager.getPlayer(player); - if (user == null) return null; + if (user == null) { + return null; + } return user.getSkillLevel(skill); } public Integer getExpNeeded(PrimarySkillType skill, Player player) { final McMMOPlayer user = UserManager.getPlayer(player); - if (user == null) return null; + if (user == null) { + return null; + } return user.getXpToLevel(skill); } public Integer getExp(PrimarySkillType skill, Player player) { final McMMOPlayer user = UserManager.getPlayer(player); - if (user == null) return null; + if (user == null) { + return null; + } return user.getSkillXpLevel(skill); } @@ -91,7 +102,9 @@ public class PapiExpansion extends PlaceholderExpansion { public Integer getExpRemaining(PrimarySkillType skill, Player player) { final McMMOPlayer user = UserManager.getPlayer(player); - if (user == null) return null; + if (user == null) { + return null; + } int current = user.getSkillXpLevel(skill); int needed = user.getXpToLevel(skill); @@ -100,7 +113,8 @@ public class PapiExpansion extends PlaceholderExpansion { public Integer getRank(PrimarySkillType skill, Player player) { try { - return ExperienceAPI.getPlayerRankSkill(player.getUniqueId(), StringUtils.getCapitalized(skill.toString())); + return ExperienceAPI.getPlayerRankSkill(player.getUniqueId(), + StringUtils.getCapitalized(skill.toString())); } catch (Exception ex) { return null; } @@ -108,7 +122,9 @@ public class PapiExpansion extends PlaceholderExpansion { public Integer getPowerLevel(Player player) { final McMMOPlayer user = UserManager.getPlayer(player); - if (user == null) return null; + if (user == null) { + return null; + } return user.getPowerLevel(); } @@ -118,7 +134,9 @@ public class PapiExpansion extends PlaceholderExpansion { public String getPartyName(Player player) { final McMMOPlayer user = UserManager.getPlayer(player); - if (user == null) return null; + if (user == null) { + return null; + } final Party party = user.getParty(); return (party == null) ? null : party.getName(); @@ -126,14 +144,18 @@ public class PapiExpansion extends PlaceholderExpansion { public String getPartyLeader(Player player) { final McMMOPlayer user = UserManager.getPlayer(player); - if (user == null) return null; + if (user == null) { + return null; + } final Party party = user.getParty(); return (party == null) ? null : party.getLeader().getPlayerName(); } public Integer getPartySize(Player player) { final McMMOPlayer user = UserManager.getPlayer(player); - if (user == null) return null; + if (user == null) { + return null; + } final Party party = user.getParty(); return (party == null) ? null : party.getMembers().size(); } @@ -144,36 +166,42 @@ public class PapiExpansion extends PlaceholderExpansion { public String getSkillXpRate(PrimarySkillType skill, Player player) { final McMMOPlayer user = UserManager.getPlayer(player); - if (user == null) return null; + if (user == null) { + return null; + } double modifier = 1.0F; - if (Permissions.customXpBoost(player, skill)) + if (Permissions.customXpBoost(player, skill)) { modifier = ExperienceConfig.getInstance().getCustomXpPerkBoost(); - else if (Permissions.quadrupleXp(player, skill)) + } else if (Permissions.quadrupleXp(player, skill)) { modifier = 4; - else if (Permissions.tripleXp(player, skill)) + } else if (Permissions.tripleXp(player, skill)) { modifier = 3; - else if (Permissions.doubleAndOneHalfXp(player, skill)) + } else if (Permissions.doubleAndOneHalfXp(player, skill)) { modifier = 2.5; - else if (Permissions.doubleXp(player, skill)) + } else if (Permissions.doubleXp(player, skill)) { modifier = 2; - else if (Permissions.oneAndOneHalfXp(player, skill)) + } else if (Permissions.oneAndOneHalfXp(player, skill)) { modifier = 1.5; - else if (Permissions.oneAndOneTenthXp(player, skill)) + } else if (Permissions.oneAndOneTenthXp(player, skill)) { modifier = 1.1; + } return String.valueOf(modifier); } public String isExpEventActive(Player player) { - return mcMMO.p.isXPEventEnabled() ? PlaceholderAPIPlugin.booleanTrue() : PlaceholderAPIPlugin.booleanFalse(); + return mcMMO.p.isXPEventEnabled() ? PlaceholderAPIPlugin.booleanTrue() + : PlaceholderAPIPlugin.booleanFalse(); } public void registerPlaceholder(Placeholder placeholder) { final Placeholder registered = placeholders.get(placeholder.getName()); - if (registered != null) - throw new IllegalStateException("Placeholder " + placeholder.getName() + " is already registered!"); + if (registered != null) { + throw new IllegalStateException( + "Placeholder " + placeholder.getName() + " is already registered!"); + } placeholders.put(placeholder.getName(), placeholder); } @@ -200,7 +228,6 @@ public class PapiExpansion extends PlaceholderExpansion { registerPlaceholder(new SkillXpRatePlaceholder(this, skill)); } - //%mcmmo_power_level% registerPlaceholder(new PowerLevelPlaceholder(this)); @@ -226,5 +253,6 @@ public class PapiExpansion extends PlaceholderExpansion { registerPlaceholder(new XpEventActivePlaceholder(this)); // %mcmmo_xprate% registerPlaceholder(new XpRatePlaceholder(this)); - }; + } + } diff --git a/src/main/java/com/gmail/nossr50/placeholders/PartyIsMemberPlaceholder.java b/src/main/java/com/gmail/nossr50/placeholders/PartyIsMemberPlaceholder.java index ac385a4ba..a57666628 100644 --- a/src/main/java/com/gmail/nossr50/placeholders/PartyIsMemberPlaceholder.java +++ b/src/main/java/com/gmail/nossr50/placeholders/PartyIsMemberPlaceholder.java @@ -5,6 +5,7 @@ import org.bukkit.entity.Player; public class PartyIsMemberPlaceholder implements Placeholder { private final PapiExpansion papiExpansion; + public PartyIsMemberPlaceholder(PapiExpansion papiExpansion) { this.papiExpansion = papiExpansion; } diff --git a/src/main/java/com/gmail/nossr50/placeholders/PartyLeaderPlaceholder.java b/src/main/java/com/gmail/nossr50/placeholders/PartyLeaderPlaceholder.java index 3f753bed9..bd301b52d 100644 --- a/src/main/java/com/gmail/nossr50/placeholders/PartyLeaderPlaceholder.java +++ b/src/main/java/com/gmail/nossr50/placeholders/PartyLeaderPlaceholder.java @@ -1,6 +1,6 @@ package com.gmail.nossr50.placeholders; -import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang3.StringUtils; import org.bukkit.entity.Player; public class PartyLeaderPlaceholder implements Placeholder { @@ -12,7 +12,7 @@ public class PartyLeaderPlaceholder implements Placeholder { @Override public String process(Player player, String params) { - return StringUtils.stripToEmpty(papiExpansion.getPartyLeader(player)); + return StringUtils.trimToEmpty(papiExpansion.getPartyLeader(player)); } @Override diff --git a/src/main/java/com/gmail/nossr50/placeholders/PartyNamePlaceholder.java b/src/main/java/com/gmail/nossr50/placeholders/PartyNamePlaceholder.java index 2cec030d6..e35346887 100644 --- a/src/main/java/com/gmail/nossr50/placeholders/PartyNamePlaceholder.java +++ b/src/main/java/com/gmail/nossr50/placeholders/PartyNamePlaceholder.java @@ -1,6 +1,6 @@ package com.gmail.nossr50.placeholders; -import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang3.StringUtils; import org.bukkit.entity.Player; public class PartyNamePlaceholder implements Placeholder { @@ -12,7 +12,7 @@ public class PartyNamePlaceholder implements Placeholder { @Override public String process(Player player, String params) { - return StringUtils.stripToEmpty(papiExpansion.getPartyName(player)); + return StringUtils.trimToEmpty(papiExpansion.getPartyName(player)); } @Override diff --git a/src/main/java/com/gmail/nossr50/runnables/MobDodgeMetaCleanup.java b/src/main/java/com/gmail/nossr50/runnables/MobDodgeMetaCleanup.java index 8087d3c65..cc0682910 100644 --- a/src/main/java/com/gmail/nossr50/runnables/MobDodgeMetaCleanup.java +++ b/src/main/java/com/gmail/nossr50/runnables/MobDodgeMetaCleanup.java @@ -17,7 +17,7 @@ public class MobDodgeMetaCleanup extends CancellableRunnable { @Override public void run() { - if(!mob.isValid() || mob.getTarget() == null) { + if (!mob.isValid() || mob.getTarget() == null) { mob.removeMetadata(MetadataConstants.METADATA_KEY_DODGE_TRACKER, pluginRef); this.cancel(); } else if (!mob.hasMetadata(MetadataConstants.METADATA_KEY_DODGE_TRACKER)) { diff --git a/src/main/java/com/gmail/nossr50/runnables/MobHealthDisplayUpdaterTask.java b/src/main/java/com/gmail/nossr50/runnables/MobHealthDisplayUpdaterTask.java index 8e59fcb5b..45d28c557 100644 --- a/src/main/java/com/gmail/nossr50/runnables/MobHealthDisplayUpdaterTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/MobHealthDisplayUpdaterTask.java @@ -15,12 +15,16 @@ public class MobHealthDisplayUpdaterTask extends CancellableRunnable { @Override public void run() { if (target.hasMetadata(MetadataConstants.METADATA_KEY_CUSTOM_NAME)) { - target.setCustomName(target.getMetadata(MetadataConstants.METADATA_KEY_CUSTOM_NAME).get(0).asString()); + target.setCustomName( + target.getMetadata(MetadataConstants.METADATA_KEY_CUSTOM_NAME).get(0) + .asString()); target.removeMetadata(MetadataConstants.METADATA_KEY_CUSTOM_NAME, mcMMO.p); } if (target.hasMetadata(MetadataConstants.METADATA_KEY_NAME_VISIBILITY)) { - target.setCustomNameVisible(target.getMetadata(MetadataConstants.METADATA_KEY_NAME_VISIBILITY).get(0).asBoolean()); + target.setCustomNameVisible( + target.getMetadata(MetadataConstants.METADATA_KEY_NAME_VISIBILITY).get(0) + .asBoolean()); target.removeMetadata(MetadataConstants.METADATA_KEY_NAME_VISIBILITY, mcMMO.p); } } diff --git a/src/main/java/com/gmail/nossr50/runnables/PistonTrackerTask.java b/src/main/java/com/gmail/nossr50/runnables/PistonTrackerTask.java deleted file mode 100644 index d4e69c5bc..000000000 --- a/src/main/java/com/gmail/nossr50/runnables/PistonTrackerTask.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.gmail.nossr50.runnables; - -import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.util.BlockUtils; -import com.gmail.nossr50.util.CancellableRunnable; -import com.gmail.nossr50.util.MetadataConstants; -import org.bukkit.block.Block; -import org.bukkit.block.BlockFace; - -import java.util.List; - -public class PistonTrackerTask extends CancellableRunnable { - private final List blocks; - private final BlockFace direction; - private final Block futureEmptyBlock; - - public PistonTrackerTask(List blocks, BlockFace direction, Block futureEmptyBlock) { - this.blocks = blocks; - this.direction = direction; - this.futureEmptyBlock = futureEmptyBlock; - } - - @Override - public void run() { - // Check to see if futureEmptyBlock is empty - if it isn't; the blocks didn't move - if (!BlockUtils.isPistonPiece(futureEmptyBlock.getState())) { - return; - } - - if (mcMMO.getPlaceStore().isTrue(futureEmptyBlock)) { - mcMMO.getPlaceStore().setFalse(futureEmptyBlock); - } - - for (Block b : blocks) { - Block nextBlock = b.getRelative(direction); - - if (nextBlock.hasMetadata(MetadataConstants.METADATA_KEY_PISTON_TRACKING)) { - BlockUtils.setUnnaturalBlock(nextBlock); - nextBlock.removeMetadata(MetadataConstants.METADATA_KEY_PISTON_TRACKING, mcMMO.p); - } - else if (mcMMO.getPlaceStore().isTrue(nextBlock)) { - // Block doesn't have metadatakey but isTrue - set it to false - mcMMO.getPlaceStore().setFalse(nextBlock); - } - } - } -} diff --git a/src/main/java/com/gmail/nossr50/runnables/SaveTimerTask.java b/src/main/java/com/gmail/nossr50/runnables/SaveTimerTask.java index e109cce98..6fba23714 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 @@ package com.gmail.nossr50.runnables; 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; @@ -15,12 +14,14 @@ public class SaveTimerTask extends CancellableRunnable { // All player data will be saved periodically through this int count = 1; - for (McMMOPlayer mcMMOPlayer : UserManager.getPlayers()) { - mcMMO.p.getFoliaLib().getImpl().runLaterAsync(new PlayerProfileSaveTask(mcMMOPlayer.getProfile(), false), count); + for (McMMOPlayer mmoPlayer : UserManager.getPlayers()) { + mcMMO.p.getFoliaLib().getScheduler() + .runLaterAsync(new PlayerProfileSaveTask(mmoPlayer.getProfile(), false), count); count++; } - - PartyManager.saveParties(); + if (mcMMO.p.getPartyConfig().isPartyEnabled()) { + mcMMO.p.getPartyManager().saveParties(); + } } } diff --git a/src/main/java/com/gmail/nossr50/runnables/StickyPistonTrackerTask.java b/src/main/java/com/gmail/nossr50/runnables/StickyPistonTrackerTask.java index d8f52ae30..bf5c77269 100644 --- a/src/main/java/com/gmail/nossr50/runnables/StickyPistonTrackerTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/StickyPistonTrackerTask.java @@ -19,7 +19,7 @@ public class StickyPistonTrackerTask extends CancellableRunnable { @Override public void run() { - if (!mcMMO.getPlaceStore().isTrue(movedBlock.getRelative(direction))) { + if (!mcMMO.getUserBlockTracker().isIneligible(movedBlock.getRelative(direction))) { return; } @@ -29,7 +29,7 @@ public class StickyPistonTrackerTask extends CancellableRunnable { } // The sticky piston actually pulled the block so move the PlaceStore data - mcMMO.getPlaceStore().setFalse(movedBlock.getRelative(direction)); + mcMMO.getUserBlockTracker().setEligible(movedBlock.getRelative(direction)); BlockUtils.setUnnaturalBlock(movedBlock); } } diff --git a/src/main/java/com/gmail/nossr50/runnables/TravelingBlockMetaCleanup.java b/src/main/java/com/gmail/nossr50/runnables/TravelingBlockMetaCleanup.java index 366fb2967..e982201dc 100644 --- a/src/main/java/com/gmail/nossr50/runnables/TravelingBlockMetaCleanup.java +++ b/src/main/java/com/gmail/nossr50/runnables/TravelingBlockMetaCleanup.java @@ -17,7 +17,7 @@ public class TravelingBlockMetaCleanup extends CancellableRunnable { @Override public void run() { - if(!entity.isValid()) { + if (!entity.isValid()) { entity.removeMetadata(MetadataConstants.METADATA_KEY_TRAVELING_BLOCK, pluginRef); this.cancel(); } else if (!entity.hasMetadata(MetadataConstants.METADATA_KEY_TRAVELING_BLOCK)) { diff --git a/src/main/java/com/gmail/nossr50/runnables/backups/CleanBackupsTask.java b/src/main/java/com/gmail/nossr50/runnables/backups/CleanBackupsTask.java index c4de1183d..78df232e2 100644 --- a/src/main/java/com/gmail/nossr50/runnables/backups/CleanBackupsTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/backups/CleanBackupsTask.java @@ -3,15 +3,20 @@ package com.gmail.nossr50.runnables.backups; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.CancellableRunnable; import com.gmail.nossr50.util.LogUtils; - import java.io.File; import java.text.ParseException; import java.text.SimpleDateFormat; -import java.util.*; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; import java.util.concurrent.TimeUnit; public class CleanBackupsTask extends CancellableRunnable { - private static final String BACKUP_DIRECTORY = mcMMO.getMainDirectory() + "backup" + File.separator; + private static final String BACKUP_DIRECTORY = + mcMMO.getMainDirectory() + "backup" + File.separator; private static final File BACKUP_DIR = new File(BACKUP_DIRECTORY); @Override @@ -38,7 +43,8 @@ public class CleanBackupsTask extends CancellableRunnable { Date date = getDate(fileName.split("[.]")[0]); if (!fileName.contains(".zip") || date == null) { - LogUtils.debug(mcMMO.p.getLogger(), "Could not determine date for file: " + fileName); + LogUtils.debug(mcMMO.p.getLogger(), + "Could not determine date for file: " + fileName); continue; } @@ -51,16 +57,17 @@ public class CleanBackupsTask extends CancellableRunnable { if (isPast24Hours(date) && mcMMO.p.getGeneralConfig().getKeepLast24Hours()) { // Keep all files from the last 24 hours continue; - } - else if (isLastWeek(date) && !savedDays.contains(dayOfWeek) && mcMMO.p.getGeneralConfig().getKeepDailyLastWeek()) { + } else if (isLastWeek(date) && !savedDays.contains(dayOfWeek) + && mcMMO.p.getGeneralConfig().getKeepDailyLastWeek()) { // Keep daily backups of the past week savedDays.add(dayOfWeek); continue; - } - else { - List savedWeeks = savedYearsWeeks.computeIfAbsent(year, k -> new ArrayList<>()); + } else { + List savedWeeks = savedYearsWeeks.computeIfAbsent(year, + k -> new ArrayList<>()); - if (!savedWeeks.contains(weekOfYear) && mcMMO.p.getGeneralConfig().getKeepWeeklyPastMonth()) { + if (!savedWeeks.contains(weekOfYear) && mcMMO.p.getGeneralConfig() + .getKeepWeeklyPastMonth()) { // Keep one backup of each week savedWeeks.add(weekOfYear); continue; @@ -75,7 +82,9 @@ public class CleanBackupsTask extends CancellableRunnable { return; } - LogUtils.debug(mcMMO.p.getLogger(), "Cleaned backup files. Deleted " + amountDeleted + " of " + amountTotal + " files."); + LogUtils.debug(mcMMO.p.getLogger(), + "Cleaned backup files. Deleted " + amountDeleted + " of " + amountTotal + + " files."); for (File file : toDelete) { if (file.delete()) { @@ -88,11 +97,11 @@ public class CleanBackupsTask extends CancellableRunnable { * Check if date is within last 24 hours * * @param date date to check - * * @return true is date is within last 24 hours, false if otherwise */ private boolean isPast24Hours(Date date) { - Date modifiedDate = new Date(System.currentTimeMillis() - TimeUnit.MILLISECONDS.convert(24, TimeUnit.HOURS)); + Date modifiedDate = new Date( + System.currentTimeMillis() - TimeUnit.MILLISECONDS.convert(24, TimeUnit.HOURS)); return date.after(modifiedDate); } @@ -100,22 +109,21 @@ public class CleanBackupsTask extends CancellableRunnable { * Check if date is within the last week * * @param date date to check - * * @return true is date is within the last week, false if otherwise */ private boolean isLastWeek(Date date) { - Date modifiedDate = new Date(System.currentTimeMillis() - TimeUnit.MILLISECONDS.convert(7, TimeUnit.DAYS)); + Date modifiedDate = new Date( + System.currentTimeMillis() - TimeUnit.MILLISECONDS.convert(7, TimeUnit.DAYS)); return date.after(modifiedDate); } private Date getDate(String fileName) { - SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss"); + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss", Locale.US); Date date; try { date = dateFormat.parse(fileName); - } - catch (ParseException e) { + } catch (ParseException e) { return null; } diff --git a/src/main/java/com/gmail/nossr50/runnables/commands/McrankCommandAsyncTask.java b/src/main/java/com/gmail/nossr50/runnables/commands/McRankCommandAsyncTask.java similarity index 55% rename from src/main/java/com/gmail/nossr50/runnables/commands/McrankCommandAsyncTask.java rename to src/main/java/com/gmail/nossr50/runnables/commands/McRankCommandAsyncTask.java index 2897b4388..4148cd6cd 100644 --- a/src/main/java/com/gmail/nossr50/runnables/commands/McrankCommandAsyncTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/commands/McRankCommandAsyncTask.java @@ -3,23 +3,25 @@ package com.gmail.nossr50.runnables.commands; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.CancellableRunnable; -import org.apache.commons.lang.Validate; +import java.util.Map; +import org.apache.commons.lang3.Validate; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; -import java.util.Map; - -public class McrankCommandAsyncTask extends CancellableRunnable { +public class McRankCommandAsyncTask extends CancellableRunnable { private final String playerName; private final CommandSender sender; private final boolean useBoard, useChat; - public McrankCommandAsyncTask(String playerName, CommandSender sender, boolean useBoard, boolean useChat) { - Validate.isTrue(useBoard || useChat, "Attempted to start a rank retrieval with both board and chat off"); + public McRankCommandAsyncTask(String playerName, CommandSender sender, boolean useBoard, + boolean useChat) { + Validate.isTrue(useBoard || useChat, + "Attempted to start a rank retrieval with both board and chat off"); Validate.notNull(sender, "Attempted to start a rank retrieval with no recipient"); if (useBoard) { - Validate.isTrue(sender instanceof Player, "Attempted to start a rank retrieval displaying scoreboard to a non-player"); + Validate.isTrue(sender instanceof Player, + "Attempted to start a rank retrieval displaying scoreboard to a non-player"); } this.playerName = playerName; @@ -32,7 +34,8 @@ public class McrankCommandAsyncTask extends CancellableRunnable { public void run() { Map skills = mcMMO.getDatabaseManager().readRank(playerName); - mcMMO.p.getFoliaLib().getImpl().runNextTick(new McrankCommandDisplayTask(skills, sender, playerName, useBoard, useChat)); + mcMMO.p.getFoliaLib().getScheduler().runNextTick( + new McRankCommandDisplayTask(skills, sender, playerName, useBoard, useChat)); } } diff --git a/src/main/java/com/gmail/nossr50/runnables/commands/McrankCommandDisplayTask.java b/src/main/java/com/gmail/nossr50/runnables/commands/McRankCommandDisplayTask.java similarity index 70% rename from src/main/java/com/gmail/nossr50/runnables/commands/McrankCommandDisplayTask.java rename to src/main/java/com/gmail/nossr50/runnables/commands/McRankCommandDisplayTask.java index c1067ecf1..08c7a9abd 100644 --- a/src/main/java/com/gmail/nossr50/runnables/commands/McrankCommandDisplayTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/commands/McRankCommandDisplayTask.java @@ -7,21 +7,22 @@ import com.gmail.nossr50.util.CancellableRunnable; import com.gmail.nossr50.util.MetadataConstants; import com.gmail.nossr50.util.scoreboards.ScoreboardManager; import com.gmail.nossr50.util.skills.SkillTools; +import java.util.Map; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; -import java.util.Map; - /** * Display the results of McrankCommandAsyncTask to the sender. */ -public class McrankCommandDisplayTask extends CancellableRunnable { +public class McRankCommandDisplayTask extends CancellableRunnable { private final Map skills; private final CommandSender sender; private final String playerName; private final boolean useBoard, useChat; - McrankCommandDisplayTask(Map skills, CommandSender sender, String playerName, boolean useBoard, boolean useChat) { + McRankCommandDisplayTask(Map skills, CommandSender sender, + String playerName, + boolean useBoard, boolean useChat) { this.skills = skills; this.sender = sender; this.playerName = playerName; @@ -42,30 +43,33 @@ public class McrankCommandDisplayTask extends CancellableRunnable { } private void displayChat() { -// Player player = mcMMO.p.getServer().getPlayerExact(playerName); Integer rank; sender.sendMessage(LocaleLoader.getString("Commands.mcrank.Heading")); sender.sendMessage(LocaleLoader.getString("Commands.mcrank.Player", playerName)); for (PrimarySkillType skill : SkillTools.NON_CHILD_SKILLS) { -// if (!mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, skill)) { -// continue; -// } - + // Check if the command is for Maces but the MC version is not correct + if (skill == PrimarySkillType.MACES + && !mcMMO.getCompatibilityManager().getMinecraftGameVersion() + .isAtLeast(1, 21, 0)) { + continue; + } rank = skills.get(skill); - sender.sendMessage(LocaleLoader.getString("Commands.mcrank.Skill", mcMMO.p.getSkillTools().getLocalizedSkillName(skill), (rank == null ? LocaleLoader.getString("Commands.mcrank.Unranked") : rank))); + sender.sendMessage(LocaleLoader.getString("Commands.mcrank.Skill", + mcMMO.p.getSkillTools().getLocalizedSkillName(skill), + (rank == null ? LocaleLoader.getString("Commands.mcrank.Unranked") : rank))); } rank = skills.get(null); - sender.sendMessage(LocaleLoader.getString("Commands.mcrank.Overall", (rank == null ? LocaleLoader.getString("Commands.mcrank.Unranked") : rank))); + sender.sendMessage(LocaleLoader.getString("Commands.mcrank.Overall", + (rank == null ? LocaleLoader.getString("Commands.mcrank.Unranked") : rank))); } public void displayBoard() { if (sender.getName().equalsIgnoreCase(playerName)) { ScoreboardManager.showPlayerRankScoreboard((Player) sender, skills); - } - else { + } else { ScoreboardManager.showPlayerRankScoreboardOthers((Player) sender, playerName, skills); } } diff --git a/src/main/java/com/gmail/nossr50/runnables/commands/MctopCommandAsyncTask.java b/src/main/java/com/gmail/nossr50/runnables/commands/McTopCommandAsyncTask.java similarity index 54% rename from src/main/java/com/gmail/nossr50/runnables/commands/MctopCommandAsyncTask.java rename to src/main/java/com/gmail/nossr50/runnables/commands/McTopCommandAsyncTask.java index a343bc810..c8da44146 100644 --- a/src/main/java/com/gmail/nossr50/runnables/commands/MctopCommandAsyncTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/commands/McTopCommandAsyncTask.java @@ -4,24 +4,26 @@ import com.gmail.nossr50.datatypes.database.PlayerStat; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.CancellableRunnable; -import org.apache.commons.lang.Validate; +import java.util.List; +import org.apache.commons.lang3.Validate; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; -import java.util.List; - -public class MctopCommandAsyncTask extends CancellableRunnable { +public class McTopCommandAsyncTask extends CancellableRunnable { private final CommandSender sender; private final PrimarySkillType skill; private final int page; private final boolean useBoard, useChat; - public MctopCommandAsyncTask(int page, PrimarySkillType skill, CommandSender sender, boolean useBoard, boolean useChat) { - Validate.isTrue(useBoard || useChat, "Attempted to start a rank retrieval with both board and chat off"); + public McTopCommandAsyncTask(int page, PrimarySkillType skill, CommandSender sender, + boolean useBoard, boolean useChat) { + Validate.isTrue(useBoard || useChat, + "Attempted to start a rank retrieval with both board and chat off"); Validate.notNull(sender, "Attempted to start a rank retrieval with no recipient"); if (useBoard) { - Validate.isTrue(sender instanceof Player, "Attempted to start a rank retrieval displaying scoreboard to a non-player"); + Validate.isTrue(sender instanceof Player, + "Attempted to start a rank retrieval displaying scoreboard to a non-player"); } this.page = page; @@ -33,8 +35,10 @@ public class MctopCommandAsyncTask extends CancellableRunnable { @Override public void run() { - final List userStats = mcMMO.getDatabaseManager().readLeaderboard(skill, page, 10); + final List userStats = mcMMO.getDatabaseManager() + .readLeaderboard(skill, page, 10); - mcMMO.p.getFoliaLib().getImpl().runNextTick(new MctopCommandDisplayTask(userStats, page, skill, sender, useBoard, useChat)); + mcMMO.p.getFoliaLib().getScheduler().runNextTick( + new MctopCommandDisplayTask(userStats, page, skill, sender, useBoard, useChat)); } } diff --git a/src/main/java/com/gmail/nossr50/runnables/commands/MctopCommandDisplayTask.java b/src/main/java/com/gmail/nossr50/runnables/commands/MctopCommandDisplayTask.java index ed1a2f73c..255d1168f 100644 --- a/src/main/java/com/gmail/nossr50/runnables/commands/MctopCommandDisplayTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/commands/MctopCommandDisplayTask.java @@ -7,14 +7,13 @@ import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.CancellableRunnable; import com.gmail.nossr50.util.MetadataConstants; import com.gmail.nossr50.util.scoreboards.ScoreboardManager; +import java.util.List; import org.bukkit.ChatColor; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; -import java.util.List; - /** - * Display the results of {@link MctopCommandAsyncTask} to the sender. + * Display the results of {@link McTopCommandAsyncTask} to the sender. */ public class MctopCommandDisplayTask extends CancellableRunnable { private final List userStats; @@ -23,7 +22,8 @@ public class MctopCommandDisplayTask extends CancellableRunnable { private final int page; private final boolean useBoard, useChat; - MctopCommandDisplayTask(List userStats, int page, PrimarySkillType skill, CommandSender sender, boolean useBoard, boolean useChat) { + MctopCommandDisplayTask(List userStats, int page, PrimarySkillType skill, + CommandSender sender, boolean useBoard, boolean useChat) { this.userStats = userStats; this.page = page; this.skill = skill; @@ -43,28 +43,31 @@ public class MctopCommandDisplayTask extends CancellableRunnable { } if (sender instanceof Player) { - ((Player) sender).removeMetadata(MetadataConstants.METADATA_KEY_DATABASE_COMMAND, mcMMO.p); + ((Player) sender).removeMetadata(MetadataConstants.METADATA_KEY_DATABASE_COMMAND, + mcMMO.p); } - if(sender instanceof Player) + if (sender instanceof Player) { sender.sendMessage(LocaleLoader.getString("Commands.mctop.Tip")); + } } private void displayChat() { if (skill == null) { - if(sender instanceof Player) { + if (sender instanceof Player) { sender.sendMessage(LocaleLoader.getString("Commands.PowerLevel.Leaderboard")); + } else { + sender.sendMessage(ChatColor.stripColor( + LocaleLoader.getString("Commands.PowerLevel.Leaderboard"))); } - else { - sender.sendMessage(ChatColor.stripColor(LocaleLoader.getString("Commands.PowerLevel.Leaderboard"))); - } - } - else { - if(sender instanceof Player) { - sender.sendMessage(LocaleLoader.getString("Commands.Skill.Leaderboard", mcMMO.p.getSkillTools().getLocalizedSkillName(skill))); - } - else { - sender.sendMessage(ChatColor.stripColor(LocaleLoader.getString("Commands.Skill.Leaderboard", mcMMO.p.getSkillTools().getLocalizedSkillName(skill)))); + } else { + if (sender instanceof Player) { + sender.sendMessage(LocaleLoader.getString("Commands.Skill.Leaderboard", + mcMMO.p.getSkillTools().getLocalizedSkillName(skill))); + } else { + sender.sendMessage(ChatColor.stripColor( + LocaleLoader.getString("Commands.Skill.Leaderboard", + mcMMO.p.getSkillTools().getLocalizedSkillName(skill)))); } } @@ -74,13 +77,15 @@ public class MctopCommandDisplayTask extends CancellableRunnable { // Format: // 01. Playername - skill value // 12. Playername - skill value - if(sender instanceof Player) { - sender.sendMessage(String.format("%2d. %s%s - %s%s", place, ChatColor.GREEN, stat.name, ChatColor.WHITE, stat.statVal)); + if (sender instanceof Player) { + sender.sendMessage( + String.format("%2d. %s%s - %s%s", place, ChatColor.GREEN, stat.playerName(), + ChatColor.WHITE, stat.value())); + } else { + sender.sendMessage(String.format("%2d. %s - %s", place, stat.playerName(), + stat.value())); } - else { - sender.sendMessage(String.format("%2d. %s - %s", place, stat.name, stat.statVal)); - } - + place++; } } @@ -88,8 +93,7 @@ public class MctopCommandDisplayTask extends CancellableRunnable { private void displayBoard() { if (skill == null) { ScoreboardManager.showTopPowerScoreboard((Player) sender, page, userStats); - } - else { + } else { ScoreboardManager.showTopScoreboard((Player) sender, skill, page, userStats); } } diff --git a/src/main/java/com/gmail/nossr50/runnables/commands/NotifySquelchReminderTask.java b/src/main/java/com/gmail/nossr50/runnables/commands/NotifySquelchReminderTask.java index 9b9fcd6fe..83faca3dd 100644 --- a/src/main/java/com/gmail/nossr50/runnables/commands/NotifySquelchReminderTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/commands/NotifySquelchReminderTask.java @@ -11,10 +11,8 @@ public class NotifySquelchReminderTask extends CancellableRunnable { @Override public void run() { for (Player player : Bukkit.getOnlinePlayers()) { - if(UserManager.getPlayer(player) != null) - { - if(!UserManager.getPlayer(player).useChatNotifications()) - { + if (UserManager.getPlayer(player) != null) { + if (!UserManager.getPlayer(player).useChatNotifications()) { player.sendMessage(LocaleLoader.getString("Reminder.Squelched")); } } diff --git a/src/main/java/com/gmail/nossr50/runnables/database/DatabaseConversionTask.java b/src/main/java/com/gmail/nossr50/runnables/database/DatabaseConversionTask.java index 4e59a01fb..8d2e1cb4b 100644 --- a/src/main/java/com/gmail/nossr50/runnables/database/DatabaseConversionTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/database/DatabaseConversionTask.java @@ -11,7 +11,8 @@ public class DatabaseConversionTask extends CancellableRunnable { private final CommandSender sender; private final String message; - public DatabaseConversionTask(DatabaseManager sourceDatabase, CommandSender sender, String oldType, String newType) { + public DatabaseConversionTask(DatabaseManager sourceDatabase, CommandSender sender, + String oldType, String newType) { this.sourceDatabase = sourceDatabase; this.sender = sender; message = LocaleLoader.getString("Commands.mcconvert.Database.Finish", oldType, newType); @@ -21,6 +22,6 @@ public class DatabaseConversionTask extends CancellableRunnable { public void run() { sourceDatabase.convertUsers(mcMMO.getDatabaseManager()); - mcMMO.p.getFoliaLib().getImpl().runNextTick(t -> sender.sendMessage(message)); + mcMMO.p.getFoliaLib().getScheduler().runNextTick(t -> sender.sendMessage(message)); } } diff --git a/src/main/java/com/gmail/nossr50/runnables/database/FormulaConversionTask.java b/src/main/java/com/gmail/nossr50/runnables/database/FormulaConversionTask.java index 68adf8e7f..007238728 100644 --- a/src/main/java/com/gmail/nossr50/runnables/database/FormulaConversionTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/database/FormulaConversionTask.java @@ -29,11 +29,11 @@ public class FormulaConversionTask extends CancellableRunnable { int convertedUsers = 0; long startMillis = System.currentTimeMillis(); for (String playerName : mcMMO.getDatabaseManager().getStoredUsers()) { - McMMOPlayer mcMMOPlayer = UserManager.getOfflinePlayer(playerName); + final McMMOPlayer mmoPlayer = UserManager.getOfflinePlayer(playerName); PlayerProfile profile; - // If the mcMMOPlayer doesn't exist, create a temporary profile and check if it's present in the database. If it's not, abort the process. - if (mcMMOPlayer == null) { + // If the mmoPlayer doesn't exist, create a temporary profile and check if it's present in the database. If it's not, abort the process. + if (mmoPlayer == null) { profile = mcMMO.getDatabaseManager().loadPlayerProfile(playerName); if (!profile.isLoaded()) { @@ -44,9 +44,8 @@ public class FormulaConversionTask extends CancellableRunnable { editValues(profile); // Since this is a temporary profile, we save it here. profile.scheduleAsyncSave(); - } - else { - profile = mcMMOPlayer.getProfile(); + } else { + profile = mmoPlayer.getProfile(); editValues(profile); } convertedUsers++; @@ -54,22 +53,29 @@ public class FormulaConversionTask extends CancellableRunnable { } mcMMO.p.getFormulaManager().setPreviousFormulaType(formulaType); - sender.sendMessage(LocaleLoader.getString("Commands.mcconvert.Experience.Finish", formulaType.toString())); + sender.sendMessage(LocaleLoader.getString("Commands.mcconvert.Experience.Finish", + formulaType.toString())); } private void editValues(PlayerProfile profile) { - LogUtils.debug(mcMMO.p.getLogger(), "========================================================================"); - LogUtils.debug(mcMMO.p.getLogger(), "Conversion report for " + profile.getPlayerName() + ":"); + LogUtils.debug(mcMMO.p.getLogger(), + "========================================================================"); + LogUtils.debug(mcMMO.p.getLogger(), + "Conversion report for " + profile.getPlayerName() + ":"); for (PrimarySkillType primarySkillType : SkillTools.NON_CHILD_SKILLS) { int oldLevel = profile.getSkillLevel(primarySkillType); int oldXPLevel = profile.getSkillXpLevel(primarySkillType); - int totalOldXP = mcMMO.p.getFormulaManager().calculateTotalExperience(oldLevel, oldXPLevel); + int totalOldXP = mcMMO.p.getFormulaManager() + .calculateTotalExperience(oldLevel, oldXPLevel); if (totalOldXP == 0) { continue; } - int[] newExperienceValues = mcMMO.p.getFormulaManager().calculateNewLevel(primarySkillType, (int) Math.floor(totalOldXP / ExperienceConfig.getInstance().getExpModifier()), formulaType); + int[] newExperienceValues = mcMMO.p.getFormulaManager() + .calculateNewLevel(primarySkillType, (int) Math.floor( + totalOldXP / ExperienceConfig.getInstance().getExpModifier()), + formulaType); int newLevel = newExperienceValues[0]; int newXPlevel = newExperienceValues[1]; @@ -83,7 +89,8 @@ public class FormulaConversionTask extends CancellableRunnable { LogUtils.debug(mcMMO.p.getLogger(), " NEW:"); LogUtils.debug(mcMMO.p.getLogger(), " Level " + newLevel); LogUtils.debug(mcMMO.p.getLogger(), " XP " + newXPlevel); - LogUtils.debug(mcMMO.p.getLogger(), "------------------------------------------------------------------------"); + LogUtils.debug(mcMMO.p.getLogger(), + "------------------------------------------------------------------------"); profile.modifySkill(primarySkillType, newLevel); profile.setSkillXpLevel(primarySkillType, newXPlevel); diff --git a/src/main/java/com/gmail/nossr50/runnables/database/UUIDUpdateAsyncTask.java b/src/main/java/com/gmail/nossr50/runnables/database/UUIDUpdateAsyncTask.java index 44b7cf36f..7075eb722 100644 --- a/src/main/java/com/gmail/nossr50/runnables/database/UUIDUpdateAsyncTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/database/UUIDUpdateAsyncTask.java @@ -7,7 +7,6 @@ import com.gmail.nossr50.util.Misc; import com.google.common.collect.ImmutableList; import com.google.gson.Gson; import com.google.gson.JsonObject; - import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; @@ -44,10 +43,13 @@ public class UUIDUpdateAsyncTask extends CancellableRunnable { @Override public void run() { // First iteration - if (position == 0) - plugin.getLogger().info("Starting to check and update UUIDs, total amount of users: " + userNames.size()); + if (position == 0) { + plugin.getLogger().info("Starting to check and update UUIDs, total amount of users: " + + userNames.size()); + } - List batch = userNames.subList(position, Math.min(userNames.size(), position + BATCH_SIZE)); + List batch = userNames.subList(position, + Math.min(userNames.size(), position + BATCH_SIZE)); Map fetchedUUIDs = new HashMap<>(); HttpURLConnection connection; @@ -71,16 +73,18 @@ public class UUIDUpdateAsyncTask extends CancellableRunnable { case HttpURLConnection.HTTP_BAD_REQUEST: case HttpURLConnection.HTTP_FORBIDDEN: // Rejected, probably rate limit, just wait it out - this.runTaskLaterAsynchronously(plugin, Misc.TICK_CONVERSION_FACTOR * HARD_LIMIT_PERIOD); + this.runTaskLaterAsynchronously(plugin, + Misc.TICK_CONVERSION_FACTOR * HARD_LIMIT_PERIOD); return; default: // Unknown failure - this.runTaskLaterAsynchronously(plugin, Misc.TICK_CONVERSION_FACTOR * RETRY_PERIOD); + this.runTaskLaterAsynchronously(plugin, + Misc.TICK_CONVERSION_FACTOR * RETRY_PERIOD); return; } try (InputStream input = connection.getInputStream(); - InputStreamReader reader = new InputStreamReader(input)) { + InputStreamReader reader = new InputStreamReader(input)) { for (JsonObject jsonProfile : GSON.fromJson(reader, JsonObject[].class)) { UUID id = toUUID(jsonProfile.get("id").getAsString()); String name = jsonProfile.get("name").getAsString(); @@ -94,31 +98,37 @@ public class UUIDUpdateAsyncTask extends CancellableRunnable { return; } - if (fetchedUUIDs.size() != 0) + if (fetchedUUIDs.size() != 0) { mcMMO.getDatabaseManager().saveUserUUIDs(fetchedUUIDs); + } position += batch.size(); - plugin.getLogger().info(String.format("Conversion progress: %d/%d users", position, userNames.size())); + plugin.getLogger().info(String.format("Conversion progress: %d/%d users", position, + userNames.size())); - if (position +1 >= userNames.size()) { + if (position + 1 >= userNames.size()) { mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.ADD_UUIDS); awaiter.countDown(); plugin.getLogger().info("UUID checks completed"); - } else - this.runTaskLaterAsynchronously(plugin, Misc.TICK_CONVERSION_FACTOR * DELAY_PERIOD); // Schedule next batch + } else { + this.runTaskLaterAsynchronously(plugin, + Misc.TICK_CONVERSION_FACTOR * DELAY_PERIOD); // Schedule next batch + } } // Bukkit runnables don't let themselves reschedule themselves, so we are a pseudo bukkit runnable. private void runTaskLaterAsynchronously(mcMMO plugin, int delay) { - plugin.getFoliaLib().getImpl().runLaterAsync(this, delay); + plugin.getFoliaLib().getScheduler().runLaterAsync(this, delay); } public void start() { - plugin.getFoliaLib().getImpl().runAsync(this); + plugin.getFoliaLib().getScheduler().runAsync(this); } private static UUID toUUID(String id) { - return UUID.fromString(id.substring(0, 8) + "-" + id.substring(8, 12) + "-" + id.substring(12, 16) + "-" + id.substring(16, 20) + "-" + id.substring(20, 32)); + return UUID.fromString( + id.substring(0, 8) + "-" + id.substring(8, 12) + "-" + id.substring(12, 16) + "-" + + id.substring(16, 20) + "-" + id.substring(20, 32)); } public void waitUntilFinished() { diff --git a/src/main/java/com/gmail/nossr50/runnables/database/UserPurgeTask.java b/src/main/java/com/gmail/nossr50/runnables/database/UserPurgeTask.java index ab2b4cbea..64bcbf8be 100644 --- a/src/main/java/com/gmail/nossr50/runnables/database/UserPurgeTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/database/UserPurgeTask.java @@ -2,11 +2,11 @@ package com.gmail.nossr50.runnables.database; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.CancellableRunnable; - import java.util.concurrent.locks.ReentrantLock; public class UserPurgeTask extends CancellableRunnable { private final ReentrantLock lock = new ReentrantLock(); + @Override public void run() { lock.lock(); diff --git a/src/main/java/com/gmail/nossr50/runnables/items/ChimaeraWingWarmup.java b/src/main/java/com/gmail/nossr50/runnables/items/ChimaeraWingWarmup.java index bb0996b50..abe3b338e 100644 --- a/src/main/java/com/gmail/nossr50/runnables/items/ChimaeraWingWarmup.java +++ b/src/main/java/com/gmail/nossr50/runnables/items/ChimaeraWingWarmup.java @@ -1,5 +1,8 @@ package com.gmail.nossr50.runnables.items; +import static com.gmail.nossr50.util.ChimaeraWing.expendChimaeraWing; + +import com.gmail.nossr50.datatypes.interactions.NotificationType; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; @@ -7,16 +10,22 @@ import com.gmail.nossr50.util.CancellableRunnable; import com.gmail.nossr50.util.ChimaeraWing; import com.gmail.nossr50.util.ItemUtils; import com.gmail.nossr50.util.Misc; +import com.gmail.nossr50.util.player.NotificationManager; import com.gmail.nossr50.util.skills.SkillUtils; +import com.gmail.nossr50.util.sounds.SoundManager; +import com.gmail.nossr50.util.sounds.SoundType; import org.bukkit.Location; +import org.bukkit.Material; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; public class ChimaeraWingWarmup extends CancellableRunnable { - private final McMMOPlayer mcMMOPlayer; + private final McMMOPlayer mmoPlayer; + private final Location location; - public ChimaeraWingWarmup(McMMOPlayer mcMMOPlayer) { - this.mcMMOPlayer = mcMMOPlayer; + public ChimaeraWingWarmup(McMMOPlayer mmoPlayer, Location location) { + this.mmoPlayer = mmoPlayer; + this.location = location; } @Override @@ -25,27 +34,31 @@ public class ChimaeraWingWarmup extends CancellableRunnable { } private void checkChimaeraWingTeleport() { - Player player = mcMMOPlayer.getPlayer(); - Location previousLocation = mcMMOPlayer.getTeleportCommenceLocation(); + final Player player = mmoPlayer.getPlayer(); + final Location previousLocation = mmoPlayer.getTeleportCommenceLocation(); - if (player.getLocation().distanceSquared(previousLocation) > 1.0 || !player.getInventory().containsAtLeast(ChimaeraWing.getChimaeraWing(0), 1)) { + if (player.getLocation().distanceSquared(previousLocation) > 1.0 + || !player.getInventory().containsAtLeast(ChimaeraWing.getChimaeraWing(1), 1)) { player.sendMessage(LocaleLoader.getString("Teleport.Cancelled")); - mcMMOPlayer.setTeleportCommenceLocation(null); + mmoPlayer.setTeleportCommenceLocation(null); return; } - ItemStack inHand = player.getInventory().getItemInMainHand(); + final ItemStack inHand = player.getInventory().getItemInMainHand(); - if (!ItemUtils.isChimaeraWing(inHand) || inHand.getAmount() < mcMMO.p.getGeneralConfig().getChimaeraUseCost()) { - player.sendMessage(LocaleLoader.getString("Skills.NeedMore", LocaleLoader.getString("Item.ChimaeraWing.Name"))); + if (!ItemUtils.isChimaeraWing(inHand) || inHand.getAmount() < mcMMO.p.getGeneralConfig() + .getChimaeraUseCost()) { + player.sendMessage(LocaleLoader.getString("Skills.NeedMore", + LocaleLoader.getString("Item.ChimaeraWing.Name"))); return; } - long recentlyHurt = mcMMOPlayer.getRecentlyHurt(); + long recentlyHurt = mmoPlayer.getRecentlyHurt(); int hurtCooldown = mcMMO.p.getGeneralConfig().getChimaeraRecentlyHurtCooldown(); if (hurtCooldown > 0) { - int timeRemaining = SkillUtils.calculateTimeLeft(recentlyHurt * Misc.TIME_CONVERSION_FACTOR, hurtCooldown, player); + int timeRemaining = SkillUtils.calculateTimeLeft( + recentlyHurt * Misc.TIME_CONVERSION_FACTOR, hurtCooldown, player); if (timeRemaining > 0) { player.sendMessage(LocaleLoader.getString("Item.Injured.Wait", timeRemaining)); @@ -53,6 +66,36 @@ public class ChimaeraWingWarmup extends CancellableRunnable { } } - ChimaeraWing.chimaeraExecuteTeleport(); + chimaeraExecuteTeleport(); + } + + private void chimaeraExecuteTeleport() { + final Player player = mmoPlayer.getPlayer(); + + if (mcMMO.p.getGeneralConfig().getChimaeraUseBedSpawn() + && player.getBedSpawnLocation() != null) { + mcMMO.p.getFoliaLib().getScheduler() + .teleportAsync(player, player.getBedSpawnLocation()); + } else { + final Location spawnLocation = player.getWorld().getSpawnLocation(); + if (spawnLocation.getBlock().getType() == Material.AIR) { + mcMMO.p.getFoliaLib().getScheduler().teleportAsync(player, spawnLocation); + } else { + mcMMO.p.getFoliaLib().getScheduler().teleportAsync( + player, player.getWorld().getHighestBlockAt(spawnLocation).getLocation()); + } + } + + expendChimaeraWing(player, mcMMO.p.getGeneralConfig().getChimaeraUseCost(), + player.getInventory().getItemInMainHand()); + mmoPlayer.actualizeChimeraWingLastUse(); + mmoPlayer.setTeleportCommenceLocation(null); + + if (mcMMO.p.getGeneralConfig().getChimaeraSoundEnabled()) { + SoundManager.sendSound(player, location, SoundType.CHIMAERA_WING); + } + + NotificationManager.sendPlayerInformation(player, NotificationType.ITEM_MESSAGE, + "Item.ChimaeraWing.Pass"); } } 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 52d245227..f3f5d38c6 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 @@ package com.gmail.nossr50.runnables.items; 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; @@ -14,26 +13,27 @@ import org.bukkit.World; import org.bukkit.entity.Player; public class TeleportationWarmup extends CancellableRunnable { - private final McMMOPlayer mcMMOPlayer; + private final McMMOPlayer mmoPlayer; private final McMMOPlayer mcMMOTarget; - public TeleportationWarmup(McMMOPlayer mcMMOPlayer, McMMOPlayer mcMMOTarget) { - this.mcMMOPlayer = mcMMOPlayer; + public TeleportationWarmup(McMMOPlayer mmoPlayer, McMMOPlayer mcMMOTarget) { + this.mmoPlayer = mmoPlayer; this.mcMMOTarget = mcMMOTarget; } @Override public void run() { - Player teleportingPlayer = mcMMOPlayer.getPlayer(); + Player teleportingPlayer = mmoPlayer.getPlayer(); Player targetPlayer = mcMMOTarget.getPlayer(); - Location previousLocation = mcMMOPlayer.getTeleportCommenceLocation(); - Location newLocation = mcMMOPlayer.getPlayer().getLocation(); - long recentlyHurt = mcMMOPlayer.getRecentlyHurt(); + Location previousLocation = mmoPlayer.getTeleportCommenceLocation(); + Location newLocation = mmoPlayer.getPlayer().getLocation(); + long recentlyHurt = mmoPlayer.getRecentlyHurt(); - mcMMOPlayer.setTeleportCommenceLocation(null); + mmoPlayer.setTeleportCommenceLocation(null); - if (!PartyManager.inSameParty(teleportingPlayer, targetPlayer)) { - teleportingPlayer.sendMessage(LocaleLoader.getString("Party.NotInYourParty", targetPlayer.getName())); + if (!mcMMO.p.getPartyManager().inSameParty(teleportingPlayer, targetPlayer)) { + teleportingPlayer.sendMessage( + LocaleLoader.getString("Party.NotInYourParty", targetPlayer.getName())); return; } @@ -45,10 +45,12 @@ public class TeleportationWarmup extends CancellableRunnable { int hurtCooldown = mcMMO.p.getGeneralConfig().getPTPCommandRecentlyHurtCooldown(); if (hurtCooldown > 0) { - int timeRemaining = SkillUtils.calculateTimeLeft(recentlyHurt * Misc.TIME_CONVERSION_FACTOR, hurtCooldown, teleportingPlayer); + int timeRemaining = SkillUtils.calculateTimeLeft( + recentlyHurt * Misc.TIME_CONVERSION_FACTOR, hurtCooldown, teleportingPlayer); if (timeRemaining > 0) { - teleportingPlayer.sendMessage(LocaleLoader.getString("Item.Injured.Wait", timeRemaining)); + teleportingPlayer.sendMessage( + LocaleLoader.getString("Item.Injured.Wait", timeRemaining)); return; } } @@ -59,17 +61,20 @@ public class TeleportationWarmup extends CancellableRunnable { if (!Permissions.partyTeleportAllWorlds(teleportingPlayer)) { if (!Permissions.partyTeleportWorld(targetPlayer, targetWorld)) { - teleportingPlayer.sendMessage(LocaleLoader.getString("Commands.ptp.NoWorldPermissions", targetWorld.getName())); + teleportingPlayer.sendMessage( + LocaleLoader.getString("Commands.ptp.NoWorldPermissions", + targetWorld.getName())); return; - } - else if (targetWorld != playerWorld && !Permissions.partyTeleportWorld(teleportingPlayer, targetWorld)) { - teleportingPlayer.sendMessage(LocaleLoader.getString("Commands.ptp.NoWorldPermissions", targetWorld.getName())); + } else if (targetWorld != playerWorld && !Permissions.partyTeleportWorld( + teleportingPlayer, targetWorld)) { + teleportingPlayer.sendMessage( + LocaleLoader.getString("Commands.ptp.NoWorldPermissions", + targetWorld.getName())); return; } } } - EventUtils.handlePartyTeleportEvent(teleportingPlayer, targetPlayer); } } 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 18891155c..133ef88b8 100644 --- a/src/main/java/com/gmail/nossr50/runnables/party/PartyAutoKickTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/party/PartyAutoKickTask.java @@ -2,18 +2,17 @@ package com.gmail.nossr50.runnables.party; 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; - import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map.Entry; import java.util.UUID; +import org.bukkit.OfflinePlayer; public class PartyAutoKickTask extends CancellableRunnable { - private final static long KICK_TIME = 24L * 60L * 60L * 1000L * mcMMO.p.getGeneralConfig().getAutoPartyKickTime(); + private final static long KICK_TIME = + 24L * 60L * 60L * 1000L * mcMMO.p.getGeneralConfig().getAutoPartyKickTime(); @Override public void run() { @@ -22,12 +21,13 @@ public class PartyAutoKickTask extends CancellableRunnable { long currentTime = System.currentTimeMillis(); - for (Party party : PartyManager.getParties()) { + for (Party party : mcMMO.p.getPartyManager().getParties()) { for (UUID memberUniqueId : party.getMembers().keySet()) { OfflinePlayer member = mcMMO.p.getServer().getOfflinePlayer(memberUniqueId); boolean isProcessed = processedPlayers.contains(memberUniqueId); - if ((!member.isOnline() && (currentTime - member.getLastPlayed() > KICK_TIME)) || isProcessed) { + if ((!member.isOnline() && (currentTime - member.getLastPlayed() > KICK_TIME)) + || isProcessed) { toRemove.put(member, party); } @@ -38,7 +38,7 @@ public class PartyAutoKickTask extends CancellableRunnable { } for (Entry entry : toRemove.entrySet()) { - PartyManager.removeFromParty(entry.getKey(), entry.getValue()); + mcMMO.p.getPartyManager().removeFromParty(entry.getKey(), entry.getValue()); } } } diff --git a/src/main/java/com/gmail/nossr50/runnables/player/ClearRegisteredXPGainTask.java b/src/main/java/com/gmail/nossr50/runnables/player/ClearRegisteredXPGainTask.java index 47923c7a4..f4ba32d16 100644 --- a/src/main/java/com/gmail/nossr50/runnables/player/ClearRegisteredXPGainTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/player/ClearRegisteredXPGainTask.java @@ -7,8 +7,8 @@ import com.gmail.nossr50.util.player.UserManager; public class ClearRegisteredXPGainTask extends CancellableRunnable { @Override public void run() { - for (McMMOPlayer mcMMOPlayer : UserManager.getPlayers()) { - mcMMOPlayer.getProfile().purgeExpiredXpGains(); + for (McMMOPlayer mmoPlayer : UserManager.getPlayers()) { + mmoPlayer.getProfile().purgeExpiredXpGains(); } } } diff --git a/src/main/java/com/gmail/nossr50/runnables/player/PlayerProfileLoadingTask.java b/src/main/java/com/gmail/nossr50/runnables/player/PlayerProfileLoadingTask.java index 6cd865055..3417e14f5 100644 --- a/src/main/java/com/gmail/nossr50/runnables/player/PlayerProfileLoadingTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/player/PlayerProfileLoadingTask.java @@ -38,50 +38,59 @@ public class PlayerProfileLoadingTask extends CancellableRunnable { // Quit if they logged out if (!player.isOnline()) { - LogUtils.debug(mcMMO.p.getLogger(), "Aborting profile loading recovery for " + player.getName() + " - player logged out"); + LogUtils.debug(mcMMO.p.getLogger(), + "Aborting profile loading recovery for " + player.getName() + + " - player logged out"); return; } PlayerProfile profile = mcMMO.getDatabaseManager().loadPlayerProfile(player); - if(!profile.isLoaded()) { - LogUtils.debug(mcMMO.p.getLogger(), "Creating new data for player: "+player.getName()); + if (!profile.isLoaded()) { + LogUtils.debug(mcMMO.p.getLogger(), + "Creating new data for player: " + player.getName()); //Profile isn't loaded so add as new user profile = mcMMO.getDatabaseManager().newUser(player); } // If successful, schedule the apply if (profile.isLoaded()) { - mcMMO.p.getFoliaLib().getImpl().runAtEntity(player, new ApplySuccessfulProfile(new McMMOPlayer(player, profile))); + mcMMO.p.getFoliaLib().getScheduler().runAtEntity(player, + new ApplySuccessfulProfile(new McMMOPlayer(player, profile))); EventUtils.callPlayerProfileLoadEvent(player, profile); return; } // Print errors to console/logs if we're failing at least 2 times in a row to load the profile - if (attempt >= 3) - { + if (attempt >= 3) { //Log the error mcMMO.p.getLogger().severe(LocaleLoader.getString("Profile.Loading.FailureNotice", player.getName(), String.valueOf(attempt))); //Notify the admins - mcMMO.p.getServer().broadcast(LocaleLoader.getString("Profile.Loading.FailureNotice", player.getName()), Server.BROADCAST_CHANNEL_ADMINISTRATIVE); + mcMMO.p.getServer().broadcast( + LocaleLoader.getString("Profile.Loading.FailureNotice", player.getName()), + Server.BROADCAST_CHANNEL_ADMINISTRATIVE); //Notify the player - player.sendMessage(LocaleLoader.getString("Profile.Loading.FailurePlayer", String.valueOf(attempt)).split("\n")); + player.sendMessage( + LocaleLoader.getString("Profile.Loading.FailurePlayer", String.valueOf(attempt)) + .split("\n")); } // Increment attempt counter and try attempt++; - mcMMO.p.getFoliaLib().getImpl().runLaterAsync(new PlayerProfileLoadingTask(player, attempt), (100 + (attempt * 100L))); + mcMMO.p.getFoliaLib().getScheduler() + .runLaterAsync(new PlayerProfileLoadingTask(player, attempt), + (100 + (attempt * 100L))); } private class ApplySuccessfulProfile extends CancellableRunnable { - private final McMMOPlayer mcMMOPlayer; + private final McMMOPlayer mmoPlayer; - private ApplySuccessfulProfile(McMMOPlayer mcMMOPlayer) { - this.mcMMOPlayer = mcMMOPlayer; + private ApplySuccessfulProfile(McMMOPlayer mmoPlayer) { + this.mmoPlayer = mmoPlayer; } // Synchronized task @@ -89,22 +98,25 @@ public class PlayerProfileLoadingTask extends CancellableRunnable { @Override public void run() { if (!player.isOnline()) { - mcMMO.p.getLogger().info("Aborting profile loading recovery for " + player.getName() + " - player logged out"); + mcMMO.p.getLogger().info("Aborting profile loading recovery for " + player.getName() + + " - player logged out"); return; } - mcMMOPlayer.getProfile().updateLastLogin(); + mmoPlayer.getProfile().updateLastLogin(); - mcMMOPlayer.setupPartyData(); - UserManager.track(mcMMOPlayer); - mcMMOPlayer.actualizeRespawnATS(); + mmoPlayer.setupPartyData(); + UserManager.track(mmoPlayer); + mmoPlayer.actualizeRespawnATS(); if (mcMMO.p.getGeneralConfig().getScoreboardsEnabled()) { ScoreboardManager.setupPlayer(player); if (mcMMO.p.getGeneralConfig().getShowStatsAfterLogin()) { ScoreboardManager.enablePlayerStatsScoreboard(player); - mcMMO.p.getFoliaLib().getImpl().runAtEntityLater(player, new McScoreboardKeepTask(player), Misc.TICK_CONVERSION_FACTOR); + mcMMO.p.getFoliaLib().getScheduler() + .runAtEntityLater(player, new McScoreboardKeepTask(player), + Misc.TICK_CONVERSION_FACTOR); } } 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 69e080972..98779d6bf 100644 --- a/src/main/java/com/gmail/nossr50/runnables/skills/AbilityCooldownTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/skills/AbilityCooldownTask.java @@ -7,23 +7,22 @@ import com.gmail.nossr50.util.CancellableRunnable; import com.gmail.nossr50.util.player.NotificationManager; public class AbilityCooldownTask extends CancellableRunnable { - private final McMMOPlayer mcMMOPlayer; + private final McMMOPlayer mmoPlayer; private final SuperAbilityType ability; - public AbilityCooldownTask(McMMOPlayer mcMMOPlayer, SuperAbilityType ability) { - this.mcMMOPlayer = mcMMOPlayer; + public AbilityCooldownTask(McMMOPlayer mmoPlayer, SuperAbilityType ability) { + this.mmoPlayer = mmoPlayer; this.ability = ability; } @Override public void run() { - if (!mcMMOPlayer.getPlayer().isOnline() || mcMMOPlayer.getAbilityInformed(ability)) { + if (!mmoPlayer.getPlayer().isOnline() || mmoPlayer.getAbilityInformed(ability)) { return; } - mcMMOPlayer.setAbilityInformed(ability, true); - - NotificationManager.sendPlayerInformation(mcMMOPlayer.getPlayer(), NotificationType.ABILITY_REFRESHED, ability.getAbilityRefresh()); - //mcMMOPlayer.getPlayer().sendMessage(ability.getAbilityRefresh()); + mmoPlayer.setAbilityInformed(ability, true); // TODO: ?? What does this do again? + NotificationManager.sendPlayerInformation(mmoPlayer.getPlayer(), + NotificationType.ABILITY_REFRESHED, ability.getAbilityRefresh()); } } diff --git a/src/main/java/com/gmail/nossr50/runnables/skills/AbilityDisableTask.java b/src/main/java/com/gmail/nossr50/runnables/skills/AbilityDisableTask.java index a789171e0..2d613f935 100644 --- a/src/main/java/com/gmail/nossr50/runnables/skills/AbilityDisableTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/skills/AbilityDisableTask.java @@ -15,21 +15,21 @@ import org.bukkit.World; import org.bukkit.entity.Player; public class AbilityDisableTask extends CancellableRunnable { - private final McMMOPlayer mcMMOPlayer; + private final McMMOPlayer mmoPlayer; private final SuperAbilityType ability; - public AbilityDisableTask(McMMOPlayer mcMMOPlayer, SuperAbilityType ability) { - this.mcMMOPlayer = mcMMOPlayer; + public AbilityDisableTask(McMMOPlayer mmoPlayer, SuperAbilityType ability) { + this.mmoPlayer = mmoPlayer; this.ability = ability; } @Override public void run() { - if (!mcMMOPlayer.getAbilityMode(ability)) { + if (!mmoPlayer.getAbilityMode(ability)) { return; } - Player player = mcMMOPlayer.getPlayer(); + Player player = mmoPlayer.getPlayer(); switch (ability) { case SUPER_BREAKER: @@ -49,21 +49,26 @@ public class AbilityDisableTask extends CancellableRunnable { EventUtils.callAbilityDeactivateEvent(player, ability); - mcMMOPlayer.setAbilityMode(ability, false); - mcMMOPlayer.setAbilityInformed(ability, false); + mmoPlayer.setAbilityMode(ability, false); + mmoPlayer.setAbilityInformed(ability, false); // ParticleEffectUtils.playAbilityDisabledEffect(player); - if (mcMMOPlayer.useChatNotifications()) { + if (mmoPlayer.useChatNotifications()) { //player.sendMessage(ability.getAbilityOff()); - NotificationManager.sendPlayerInformation(player, NotificationType.ABILITY_OFF, ability.getAbilityOff()); + NotificationManager.sendPlayerInformation(player, NotificationType.ABILITY_OFF, + ability.getAbilityOff()); } if (mcMMO.p.getAdvancedConfig().sendAbilityNotificationToOtherPlayers()) { - SkillUtils.sendSkillMessage(player, NotificationType.SUPER_ABILITY_ALERT_OTHERS, ability.getAbilityPlayerOff()); + SkillUtils.sendSkillMessage(player, NotificationType.SUPER_ABILITY_ALERT_OTHERS, + ability.getAbilityPlayerOff()); } - if(!mcMMO.isServerShutdownExecuted()) { - mcMMO.p.getFoliaLib().getImpl().runAtEntityLater(player, new AbilityCooldownTask(mcMMOPlayer, ability), (long) PerksUtils.handleCooldownPerks(player, ability.getCooldown()) * Misc.TICK_CONVERSION_FACTOR); + if (!mcMMO.isServerShutdownExecuted()) { + mcMMO.p.getFoliaLib().getScheduler() + .runAtEntityLater(player, new AbilityCooldownTask(mmoPlayer, ability), + (long) PerksUtils.handleCooldownPerks(player, ability.getCooldown()) + * Misc.TICK_CONVERSION_FACTOR); } } diff --git a/src/main/java/com/gmail/nossr50/runnables/skills/AlchemyBrewCheckTask.java b/src/main/java/com/gmail/nossr50/runnables/skills/AlchemyBrewCheckTask.java index 68de298f5..630d05bce 100644 --- a/src/main/java/com/gmail/nossr50/runnables/skills/AlchemyBrewCheckTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/skills/AlchemyBrewCheckTask.java @@ -1,39 +1,61 @@ package com.gmail.nossr50.runnables.skills; +import static com.gmail.nossr50.skills.alchemy.AlchemyPotionBrewer.isValidBrew; + +import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.skills.alchemy.Alchemy; -import com.gmail.nossr50.skills.alchemy.AlchemyPotionBrewer; import com.gmail.nossr50.util.CancellableRunnable; +import com.gmail.nossr50.util.ContainerMetadataUtils; +import com.gmail.nossr50.util.player.UserManager; +import java.util.Arrays; import org.bukkit.Location; +import org.bukkit.OfflinePlayer; import org.bukkit.block.BrewingStand; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; - -import java.util.Arrays; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; public class AlchemyBrewCheckTask extends CancellableRunnable { - private final Player player; private final BrewingStand brewingStand; private final ItemStack[] oldInventory; - public AlchemyBrewCheckTask(Player player, BrewingStand brewingStand) { - this.player = player; + @Deprecated(forRemoval = true, since = "2.2.010") + public AlchemyBrewCheckTask(@Nullable Player ignored, BrewingStand brewingStand) { + this(brewingStand); + } + + public AlchemyBrewCheckTask(@NotNull BrewingStand brewingStand) { this.brewingStand = brewingStand; this.oldInventory = Arrays.copyOfRange(brewingStand.getInventory().getContents(), 0, 4); } @Override public void run() { - Location location = brewingStand.getLocation(); - ItemStack[] newInventory = Arrays.copyOfRange(brewingStand.getInventory().getContents(), 0, 4); - boolean validBrew = brewingStand.getFuelLevel() > 0 && AlchemyPotionBrewer.isValidBrew(player, newInventory); - - if (Alchemy.brewingStandMap.containsKey(location)) { - if (oldInventory[Alchemy.INGREDIENT_SLOT] == null || newInventory[Alchemy.INGREDIENT_SLOT] == null || !oldInventory[Alchemy.INGREDIENT_SLOT].isSimilar(newInventory[Alchemy.INGREDIENT_SLOT]) || !validBrew) { - Alchemy.brewingStandMap.get(location).cancelBrew(); + OfflinePlayer offlinePlayer = ContainerMetadataUtils.getContainerOwner(brewingStand); + int ingredientLevel = 1; + if (offlinePlayer != null && offlinePlayer.isOnline()) { + final McMMOPlayer mmoPlayer = UserManager.getPlayer(offlinePlayer.getPlayer()); + if (mmoPlayer != null) { + ingredientLevel = mmoPlayer.getAlchemyManager().getTier(); } } - else if (validBrew) { - Alchemy.brewingStandMap.put(location, new AlchemyBrewTask(brewingStand, player)); + final Location location = brewingStand.getLocation(); + final ItemStack[] newInventory = Arrays.copyOfRange( + brewingStand.getInventory().getContents(), 0, 4); + boolean validBrew = + brewingStand.getFuelLevel() > 0 && isValidBrew(ingredientLevel, newInventory); + + if (Alchemy.brewingStandMap.containsKey(location)) { + if (oldInventory[Alchemy.INGREDIENT_SLOT] == null + || newInventory[Alchemy.INGREDIENT_SLOT] == null + || !oldInventory[Alchemy.INGREDIENT_SLOT].isSimilar( + newInventory[Alchemy.INGREDIENT_SLOT]) + || !validBrew) { + Alchemy.brewingStandMap.get(location).cancelBrew(); + } + } else if (validBrew) { + Alchemy.brewingStandMap.put(location, new AlchemyBrewTask(brewingStand)); } } } diff --git a/src/main/java/com/gmail/nossr50/runnables/skills/AlchemyBrewTask.java b/src/main/java/com/gmail/nossr50/runnables/skills/AlchemyBrewTask.java index de5ea2adb..2bc6a073f 100644 --- a/src/main/java/com/gmail/nossr50/runnables/skills/AlchemyBrewTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/skills/AlchemyBrewTask.java @@ -1,5 +1,6 @@ package com.gmail.nossr50.runnables.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.events.skills.alchemy.McMMOPlayerBrewEvent; @@ -8,43 +9,58 @@ import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.skills.alchemy.Alchemy; import com.gmail.nossr50.skills.alchemy.AlchemyPotionBrewer; import com.gmail.nossr50.util.CancellableRunnable; +import com.gmail.nossr50.util.ContainerMetadataUtils; import com.gmail.nossr50.util.Misc; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.player.UserManager; -import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.OfflinePlayer; import org.bukkit.block.BlockState; import org.bukkit.block.BrewingStand; import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; public class AlchemyBrewTask extends CancellableRunnable { private static final double DEFAULT_BREW_SPEED = 1.0; - private static final int DEFAULT_BREW_TICKS = 400; + private static final int DEFAULT_BREW_TICKS = 400; private final BlockState brewingStand; - private final Location location; + private final OfflinePlayer offlinePlayer; + private McMMOPlayer mmoPlayer; private double brewSpeed; private double brewTimer; - private final Player player; private int fuel; private boolean firstRun = true; + private int ingredientLevel = 1; + + @Deprecated(forRemoval = true, since = "2.2.010") + public AlchemyBrewTask(@NotNull BlockState brewingStand, Player ignored) { + this(brewingStand); + } + + public AlchemyBrewTask(@NotNull BlockState brewingStand) { + offlinePlayer = ContainerMetadataUtils.getContainerOwner(brewingStand); + McMMOPlayer mmoPlayer = null; + if (offlinePlayer != null && offlinePlayer.isOnline()) { + mmoPlayer = UserManager.getPlayer(offlinePlayer.getPlayer()); + } - public AlchemyBrewTask(BlockState brewingStand, Player player) { this.brewingStand = brewingStand; - this.location = brewingStand.getLocation(); - this.player = player; brewSpeed = DEFAULT_BREW_SPEED; brewTimer = DEFAULT_BREW_TICKS; - if (player != null - && !Misc.isNPCEntityExcludingVillagers(player) - && Permissions.isSubSkillEnabled(player, SubSkillType.ALCHEMY_CATALYSIS) - && UserManager.getPlayer(player) != null) { + if (mmoPlayer != null + && !Misc.isNPCEntityExcludingVillagers(mmoPlayer.getPlayer()) + && Permissions.isSubSkillEnabled(mmoPlayer.getPlayer(), + SubSkillType.ALCHEMY_CATALYSIS)) { + ingredientLevel = mmoPlayer.getAlchemyManager().getTier(); - double catalysis = UserManager.getPlayer(player).getAlchemyManager().calculateBrewSpeed(Permissions.lucky(player, PrimarySkillType.ALCHEMY)); + double catalysis = mmoPlayer.getAlchemyManager() + .calculateBrewSpeed(Permissions.lucky(mmoPlayer.getPlayer(), + PrimarySkillType.ALCHEMY)); - McMMOPlayerCatalysisEvent event = new McMMOPlayerCatalysisEvent(player, catalysis); + McMMOPlayerCatalysisEvent event = new McMMOPlayerCatalysisEvent(mmoPlayer, catalysis); mcMMO.p.getServer().getPluginManager().callEvent(event); if (!event.isCancelled()) { @@ -52,70 +68,121 @@ public class AlchemyBrewTask extends CancellableRunnable { } } - if (Alchemy.brewingStandMap.containsKey(location)) { - Alchemy.brewingStandMap.get(location).cancel(); + if (Alchemy.brewingStandMap.containsKey(brewingStand.getLocation())) { + Alchemy.brewingStandMap.get(brewingStand.getLocation()).cancel(); } fuel = ((BrewingStand) brewingStand).getFuelLevel(); - if (((BrewingStand) brewingStand).getBrewingTime() == -1) // Only decrement on our end if it isn't a vanilla ingredient. + if (((BrewingStand) brewingStand).getBrewingTime() + == -1) // Only decrement on our end if it isn't a vanilla ingredient. + { fuel--; + } - Alchemy.brewingStandMap.put(location, this); - mcMMO.p.getFoliaLib().getImpl().runAtLocationTimer(location, this, 1, 1); + Alchemy.brewingStandMap.put(brewingStand.getLocation(), this); + mcMMO.p.getFoliaLib().getScheduler() + .runAtLocationTimer(brewingStand.getLocation(), this, 1, 1); } @Override public void run() { - if (player == null || !player.isValid() || brewingStand == null || brewingStand.getType() != Material.BREWING_STAND || !AlchemyPotionBrewer.isValidIngredient(player, ((BrewingStand) brewingStand).getInventory().getContents()[Alchemy.INGREDIENT_SLOT])) { - if (Alchemy.brewingStandMap.containsKey(location)) { - Alchemy.brewingStandMap.remove(location); - } - + // Check if preconditions for brewing are not met + if (shouldCancelBrewing()) { + Alchemy.brewingStandMap.remove(brewingStand.getLocation()); this.cancel(); - return; } + // Initialize the brewing stand on the first run + initializeBrewing(); + + // Update the brewing process timer + brewTimer -= brewSpeed; + + // Check if the brewing process should finish + if (isBrewingComplete()) { + this.cancel(); + finish(); + } else { + updateBrewingTime(); + } + } + + private boolean shouldCancelBrewing() { + if (offlinePlayer == null) { + return true; + } + if (brewingStand == null) { + return true; + } + if (brewingStand.getType() != Material.BREWING_STAND) { + return true; + } + return !AlchemyPotionBrewer.isValidIngredientByLevel( + getIngredientLevelUpdated(), ((BrewingStand) brewingStand).getInventory() + .getContents()[Alchemy.INGREDIENT_SLOT]); + } + + private int getIngredientLevelUpdated() { + if (mmoPlayer != null) { + ingredientLevel = mmoPlayer.getAlchemyManager().getTier(); + return ingredientLevel; + } else if (offlinePlayer.isOnline() && mmoPlayer == null) { + final McMMOPlayer fetchedMMOPlayer = UserManager.getPlayer(offlinePlayer.getPlayer()); + if (fetchedMMOPlayer != null) { + this.mmoPlayer = fetchedMMOPlayer; + ingredientLevel = mmoPlayer.getAlchemyManager().getTier(); + } + return ingredientLevel; + } else { + return ingredientLevel; + } + } + + private void initializeBrewing() { if (firstRun) { firstRun = false; ((BrewingStand) brewingStand).setFuelLevel(fuel); } - - brewTimer -= brewSpeed; - - // Vanilla potion brewing completes when BrewingTime == 1 - if (brewTimer < Math.max(brewSpeed, 2)) { - this.cancel(); - finish(); - } - else { - ((BrewingStand) brewingStand).setBrewingTime((int) brewTimer); - } } - private void finish() { - McMMOPlayerBrewEvent event = new McMMOPlayerBrewEvent(player, brewingStand); - mcMMO.p.getServer().getPluginManager().callEvent(event); + private boolean isBrewingComplete() { + return brewTimer < Math.max(brewSpeed, 2); + } - if (!event.isCancelled()) { - AlchemyPotionBrewer.finishBrewing(brewingStand, player, false); + private void updateBrewingTime() { + ((BrewingStand) brewingStand).setBrewingTime((int) brewTimer); + } + + + private void finish() { + if (mmoPlayer == null) { + // Still need to finish brewing if the player is null + AlchemyPotionBrewer.finishBrewing(brewingStand, null, false); + } else { + final McMMOPlayerBrewEvent event = new McMMOPlayerBrewEvent(mmoPlayer, brewingStand); + mcMMO.p.getServer().getPluginManager().callEvent(event); + + if (!event.isCancelled()) { + AlchemyPotionBrewer.finishBrewing(brewingStand, mmoPlayer, false); + } } - Alchemy.brewingStandMap.remove(location); + Alchemy.brewingStandMap.remove(brewingStand.getLocation()); } public void finishImmediately() { this.cancel(); - AlchemyPotionBrewer.finishBrewing(brewingStand, player, true); - Alchemy.brewingStandMap.remove(location); + AlchemyPotionBrewer.finishBrewing(brewingStand, mmoPlayer, true); + Alchemy.brewingStandMap.remove(brewingStand.getLocation()); } public void cancelBrew() { this.cancel(); ((BrewingStand) brewingStand).setBrewingTime(-1); - Alchemy.brewingStandMap.remove(location); + Alchemy.brewingStandMap.remove(brewingStand.getLocation()); } } diff --git a/src/main/java/com/gmail/nossr50/runnables/skills/AprilTask.java b/src/main/java/com/gmail/nossr50/runnables/skills/AprilTask.java index 9b4aa61a4..079a86750 100644 --- a/src/main/java/com/gmail/nossr50/runnables/skills/AprilTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/skills/AprilTask.java @@ -25,7 +25,7 @@ // if (betterRandom == 0) { // SoundManager.sendSound(player, player.getLocation(), SoundType.LEVEL_UP); // player.sendMessage(unknown("superskill") + " skill increased by 1. Total (" + unknown("12") + ")"); -//// fireworksShow(player); +/// / fireworksShow(player); // } // // for (Statistic statistic : mcMMO.getHolidayManager().movementStatistics) { diff --git a/src/main/java/com/gmail/nossr50/runnables/skills/AwardCombatXpTask.java b/src/main/java/com/gmail/nossr50/runnables/skills/AwardCombatXpTask.java index 6ced4c66a..8ea83dbf6 100644 --- a/src/main/java/com/gmail/nossr50/runnables/skills/AwardCombatXpTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/skills/AwardCombatXpTask.java @@ -5,19 +5,21 @@ 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.mcMMO; import com.gmail.nossr50.util.CancellableRunnable; import org.bukkit.entity.LivingEntity; public class AwardCombatXpTask extends CancellableRunnable { - private final McMMOPlayer mcMMOPlayer; + private final McMMOPlayer mmoPlayer; private final double baseXp; private final PrimarySkillType primarySkillType; private final LivingEntity target; private final XPGainReason xpGainReason; private final double baseHealth; - public AwardCombatXpTask(McMMOPlayer mcMMOPlayer, PrimarySkillType primarySkillType, double baseXp, LivingEntity target, XPGainReason xpGainReason) { - this.mcMMOPlayer = mcMMOPlayer; + public AwardCombatXpTask(McMMOPlayer mmoPlayer, PrimarySkillType primarySkillType, + double baseXp, LivingEntity target, XPGainReason xpGainReason) { + this.mmoPlayer = mmoPlayer; this.primarySkillType = primarySkillType; this.baseXp = baseXp; this.target = target; @@ -40,10 +42,13 @@ public class AwardCombatXpTask extends CancellableRunnable { damage += health; } - if(ExperienceConfig.getInstance().useCombatHPCeiling()) { + if (ExperienceConfig.getInstance().useCombatHPCeiling()) { damage = Math.min(damage, ExperienceConfig.getInstance().getCombatHPCeiling()); } - mcMMOPlayer.beginXpGain(primarySkillType, (int) (damage * baseXp), xpGainReason, XPGainSource.SELF); + final double finalDamage = damage; + mcMMO.p.getFoliaLib().getScheduler().runAtEntity(mmoPlayer.getPlayer(), + task -> mmoPlayer.beginXpGain(primarySkillType, (int) (finalDamage * baseXp), + xpGainReason, XPGainSource.SELF)); } } diff --git a/src/main/java/com/gmail/nossr50/runnables/skills/BleedContainer.java b/src/main/java/com/gmail/nossr50/runnables/skills/BleedContainer.java index 32b4b9eca..4a49e14ae 100644 --- a/src/main/java/com/gmail/nossr50/runnables/skills/BleedContainer.java +++ b/src/main/java/com/gmail/nossr50/runnables/skills/BleedContainer.java @@ -9,12 +9,12 @@ public class BleedContainer { public LivingEntity target; public LivingEntity damageSource; - public BleedContainer(LivingEntity target, int bleedTicks, int bleedRank, int toolTier, LivingEntity damageSource) - { - this.target = target; - this.bleedTicks = bleedTicks; - this.bleedRank = bleedRank; - this.toolTier = toolTier; - this.damageSource = damageSource; + public BleedContainer(LivingEntity target, int bleedTicks, int bleedRank, int toolTier, + LivingEntity damageSource) { + this.target = target; + this.bleedTicks = bleedTicks; + this.bleedRank = bleedRank; + this.toolTier = toolTier; + this.damageSource = damageSource; } } diff --git a/src/main/java/com/gmail/nossr50/runnables/skills/BleedTimerTask.java b/src/main/java/com/gmail/nossr50/runnables/skills/BleedTimerTask.java deleted file mode 100644 index 0cb4d3d13..000000000 --- a/src/main/java/com/gmail/nossr50/runnables/skills/BleedTimerTask.java +++ /dev/null @@ -1,214 +0,0 @@ -//package com.gmail.nossr50.runnables.skills; -// -//import com.gmail.nossr50.config.AdvancedConfig; -//import com.gmail.nossr50.datatypes.interactions.NotificationType; -//import com.gmail.nossr50.events.fake.FakeEntityDamageByEntityEvent; -//import com.gmail.nossr50.mcMMO; -//import com.gmail.nossr50.util.MobHealthbarUtils; -//import com.gmail.nossr50.util.player.NotificationManager; -//import com.gmail.nossr50.util.skills.CombatUtils; -//import com.gmail.nossr50.util.skills.ParticleEffectUtils; -//import com.gmail.nossr50.util.sounds.SoundManager; -//import com.gmail.nossr50.util.sounds.SoundType; -//import org.bukkit.Bukkit; -//import org.bukkit.entity.LivingEntity; -//import org.bukkit.entity.Player; -//import org.bukkit.event.entity.EntityDamageEvent; -//import org.bukkit.inventory.ItemStack; -//import com.gmail.nossr50.util.CancellableRunnable; -//import org.jetbrains.annotations.NotNull; -// -//import java.util.HashMap; -//import java.util.Iterator; -//import java.util.Map; -//import java.util.Map.Entry; -// -//public class BleedTimerTask extends CancellableRunnable { -// private static final @NotNull Map bleedList = new HashMap<>(); -// private static boolean isIterating = false; -// -// @Override -// public void run() { -// isIterating = true; -// Iterator> bleedIterator = bleedList.entrySet().iterator(); -// -// while (bleedIterator.hasNext()) { -// Entry containerEntry = bleedIterator.next(); -// LivingEntity target = containerEntry.getKey(); -// int toolTier = containerEntry.getValue().toolTier; -// -//// String debugMessage = ""; -//// debugMessage += ChatColor.GOLD + "Target ["+target.getName()+"]: " + ChatColor.RESET; -// -//// debugMessage+="RemainingTicks=["+containerEntry.getValue().bleedTicks+"], "; -// -// if (containerEntry.getValue().bleedTicks <= 0 || !target.isValid()) { -// if(target instanceof Player) -// { -// NotificationManager.sendPlayerInformation((Player) target, NotificationType.SUBSKILL_MESSAGE, "Swords.Combat.Bleeding.Stopped"); -// } -// -// bleedIterator.remove(); -// continue; -// } -// -// int armorCount = 0; -// -// double damage; -// -// if (target instanceof Player) { -// damage = mcMMO.p.getAdvancedConfig().getRuptureDamagePlayer(); -// -// //Above Bleed Rank 3 deals 50% more damage -// if (containerEntry.getValue().toolTier >= 4 && containerEntry.getValue().bleedRank >= 3) -// damage = damage * 1.5; -// -// Player player = (Player) target; -// -// if (!player.isOnline()) { -// continue; -// } -// -// //Count Armor -// for (ItemStack armorPiece : ((Player) target).getInventory().getArmorContents()) { -// //We only want to count slots that contain armor. -// if (armorPiece != null) { -// armorCount++; -// } -// } -// -// } else { -// damage = mcMMO.p.getAdvancedConfig().getRuptureDamageMobs(); -// -//// debugMessage+="BaseDMG=["+damage+"], "; -// -// //Above Bleed Rank 3 deals 50% more damage -// if (containerEntry.getValue().bleedRank >= 3) -// { -// damage = damage * 1.5; -// } -// -//// debugMessage+="Rank4Bonus=["+String.valueOf(containerEntry.getValue().bleedRank >= 3)+"], "; -// -// -// MobHealthbarUtils.handleMobHealthbars(target, damage, mcMMO.p); //Update health bars -// } -// -//// debugMessage+="FullArmor=["+String.valueOf(armorCount > 3)+"], "; -// -// if(armorCount > 3) -// { -// damage = damage * .75; -// } -// -//// debugMessage+="AfterRankAndArmorChecks["+damage+"], "; -// -// //Weapons below Diamond get damage cut in half -// if(toolTier < 4) -// damage = damage / 2; -// -//// debugMessage+="AfterDiamondCheck=["+String.valueOf(damage)+"], "; -// -// //Wood weapons get damage cut in half again -// if(toolTier < 2) -// damage = damage / 2; -// -//// debugMessage+="AfterWoodenCheck=["+String.valueOf(damage)+"], "; -// -// double victimHealth = target.getHealth(); -// -//// debugMessage+="TargetHealthBeforeDMG=["+String.valueOf(target.getHealth())+"], "; -// -// //Fire a fake event -// FakeEntityDamageByEntityEvent fakeEntityDamageByEntityEvent = (FakeEntityDamageByEntityEvent) CombatUtils.sendEntityDamageEvent(containerEntry.getValue().damageSource, target, EntityDamageEvent.DamageCause.CUSTOM, damage); -// Bukkit.getPluginManager().callEvent(fakeEntityDamageByEntityEvent); -// -// CombatUtils.dealNoInvulnerabilityTickDamageRupture(target, damage, containerEntry.getValue().damageSource, toolTier); -// -// double victimHealthAftermath = target.getHealth(); -// -//// debugMessage+="TargetHealthAfterDMG=["+String.valueOf(target.getHealth())+"], "; -// -// if(victimHealthAftermath <= 0 || victimHealth != victimHealthAftermath) -// { -// //Play Bleed Sound -// SoundManager.worldSendSound(target.getWorld(), target.getLocation(), SoundType.BLEED); -// -// ParticleEffectUtils.playBleedEffect(target); -// } -// -// //Lower Bleed Ticks -// BleedContainer loweredBleedContainer = copyContainer(containerEntry.getValue()); -// loweredBleedContainer.bleedTicks -= 1; -// -//// debugMessage+="RemainingTicks=["+loweredBleedContainer.bleedTicks+"]"; -// containerEntry.setValue(loweredBleedContainer); -// -//// Bukkit.broadcastMessage(debugMessage); -// } -// isIterating = false; -// } -// -// public static @NotNull BleedContainer copyContainer(@NotNull BleedContainer container) -// { -// LivingEntity target = container.target; -// LivingEntity source = container.damageSource; -// int bleedTicks = container.bleedTicks; -// int bleedRank = container.bleedRank; -// int toolTier = container.toolTier; -// -// return new BleedContainer(target, bleedTicks, bleedRank, toolTier, source); -// } -// -// /** -// * Instantly Bleed out a LivingEntity -// * -// * @param entity LivingEntity to bleed out -// */ -// public static void bleedOut(@NotNull LivingEntity entity) { -// /* -// * Don't remove anything from the list outside of run() -// */ -// -// if (bleedList.containsKey(entity)) { -// CombatUtils.dealNoInvulnerabilityTickDamage(entity, bleedList.get(entity).bleedTicks * 2, bleedList.get(entity).damageSource); -// } -// } -// -// /** -// * Add a LivingEntity to the bleedList if it is not in it. -// * -// * @param entity LivingEntity to add -// * @param attacker source of the bleed/rupture -// * @param ticks Number of bleeding ticks -// */ -// public static void add(@NotNull LivingEntity entity, @NotNull LivingEntity attacker, int ticks, int bleedRank, int toolTier) { -// if (!Bukkit.isPrimaryThread()) { -// throw new IllegalStateException("Cannot add bleed task async!"); -// } -// -// if(isIterating) { -// //Used to throw an error here, but in reality all we are really doing is preventing concurrency issues from other plugins being naughty and its not really needed -// //I'm not really a fan of silent errors, but I'm sick of seeing people using crazy enchantments come in and report this "bug" -// return; -// } -// -//// if (isIterating) throw new IllegalStateException("Cannot add task while iterating timers!"); -// -// if(toolTier < 4) -// ticks = Math.max(1, (ticks / 3)); -// -// ticks+=1; -// -// BleedContainer newBleedContainer = new BleedContainer(entity, ticks, bleedRank, toolTier, attacker); -// bleedList.put(entity, newBleedContainer); -// } -// -// public static boolean isBleedOperationAllowed() { -// return !isIterating && Bukkit.isPrimaryThread(); -// } -// -// public static boolean isBleeding(@NotNull LivingEntity entity) { -// return bleedList.containsKey(entity); -// } -//} diff --git a/src/main/java/com/gmail/nossr50/runnables/skills/DelayedCropReplant.java b/src/main/java/com/gmail/nossr50/runnables/skills/DelayedCropReplant.java index 927e9a3f8..b04ad0578 100644 --- a/src/main/java/com/gmail/nossr50/runnables/skills/DelayedCropReplant.java +++ b/src/main/java/com/gmail/nossr50/runnables/skills/DelayedCropReplant.java @@ -29,13 +29,15 @@ public class DelayedCropReplant extends CancellableRunnable { /** * Replants a crop after a delay setting the age to desiredCropAge + * * @param cropState target {@link BlockState} * @param desiredCropAge desired age of the crop */ - public DelayedCropReplant(BlockBreakEvent blockBreakEvent, BlockState cropState, int desiredCropAge, boolean wasImmaturePlant) { + public DelayedCropReplant(BlockBreakEvent blockBreakEvent, BlockState cropState, + int desiredCropAge, boolean wasImmaturePlant) { BlockData cropData = cropState.getBlockData(); - if(cropData instanceof Directional cropDir) { + if (cropData instanceof Directional cropDir) { cropFace = cropDir.getFacing(); } @@ -54,19 +56,21 @@ public class DelayedCropReplant extends CancellableRunnable { PlantAnchorType plantAnchorType = PlantAnchorType.NORMAL; //Remove the metadata marking the block as recently replanted - mcMMO.p.getFoliaLib().getImpl().runAtLocationLater(blockBreakEvent.getBlock().getLocation(), new markPlantAsOld(blockBreakEvent.getBlock().getLocation()), 10); + mcMMO.p.getFoliaLib().getScheduler() + .runAtLocationLater(blockBreakEvent.getBlock().getLocation(), + new markPlantAsOld(blockBreakEvent.getBlock().getLocation()), 10); - if(blockBreakEvent.isCancelled()) { + if (blockBreakEvent.isCancelled()) { wasImmaturePlant = true; } //Two kinds of air in Minecraft - if(currentState.getType().equals(cropMaterial) || currentState.getType().equals(Material.AIR) || currentState.getType().equals(Material.CAVE_AIR)) { -// if(currentState.getBlock().getRelative(BlockFace.DOWN)) + if (currentState.getType().equals(cropMaterial) || currentState.getType() + .equals(Material.AIR) || currentState.getType().equals(Material.CAVE_AIR)) { +// if (currentState.getBlock().getRelative(BlockFace.DOWN)) //The space is not currently occupied by a block so we can fill it cropBlock.setType(cropMaterial); - //Get new state (necessary?) BlockState newState = cropBlock.getState(); BlockData newData = newState.getBlockData(); @@ -74,19 +78,19 @@ public class DelayedCropReplant extends CancellableRunnable { int age = 0; //Crop age should always be 0 if the plant was immature - if(!wasImmaturePlant) { + if (!wasImmaturePlant) { age = desiredCropAge; //Otherwise make the plant the desired age } - if(newData instanceof Directional) { + if (newData instanceof Directional) { //Cocoa Version Directional directional = (Directional) newState.getBlockData(); directional.setFacing(cropFace); newState.setBlockData(directional); - if(newData instanceof Cocoa) { + if (newData instanceof Cocoa) { plantAnchorType = PlantAnchorType.COCOA; } } @@ -96,12 +100,12 @@ public class DelayedCropReplant extends CancellableRunnable { ageable.setAge(age); newState.setBlockData(ageable); - newState.update(true, true); //Play an effect ParticleEffectUtils.playGreenThumbEffect(cropLocation); - mcMMO.p.getFoliaLib().getImpl().runAtLocationLater(newState.getLocation(), new PhysicsBlockUpdate(newState.getBlock(), cropFace, plantAnchorType), 1); + mcMMO.p.getFoliaLib().getScheduler().runAtLocationLater(newState.getLocation(), + new PhysicsBlockUpdate(newState.getBlock(), cropFace, plantAnchorType), 1); } } @@ -115,11 +119,12 @@ public class DelayedCropReplant extends CancellableRunnable { private final PlantAnchorType plantAnchorType; private BlockFace plantFace; - private PhysicsBlockUpdate(@NotNull Block plantBlock, @Nullable BlockFace plantFace, @NotNull PlantAnchorType plantAnchorType) { + private PhysicsBlockUpdate(@NotNull Block plantBlock, @Nullable BlockFace plantFace, + @NotNull PlantAnchorType plantAnchorType) { this.plantBlock = plantBlock; this.plantAnchorType = plantAnchorType; - if(plantFace != null) { + if (plantFace != null) { this.plantFace = plantFace; } } @@ -140,8 +145,8 @@ public class DelayedCropReplant extends CancellableRunnable { private void checkPlantIntegrity(@NotNull BlockFace blockFace) { Block neighbor = plantBlock.getRelative(blockFace); - if(plantAnchorType == PlantAnchorType.COCOA) { - if(!neighbor.getType().toString().toLowerCase().contains("jungle")) { + if (plantAnchorType == PlantAnchorType.COCOA) { + if (!neighbor.getType().toString().toLowerCase().contains("jungle")) { plantBlock.breakNaturally(); } } else { @@ -159,7 +164,6 @@ public class DelayedCropReplant extends CancellableRunnable { } - private static class markPlantAsOld extends CancellableRunnable { private final Location cropLoc; @@ -171,8 +175,10 @@ public class DelayedCropReplant extends CancellableRunnable { @Override public void run() { Block cropBlock = cropLoc.getBlock(); - if(cropBlock.getMetadata(MetadataConstants.METADATA_KEY_REPLANT).size() > 0) - cropBlock.setMetadata(MetadataConstants.METADATA_KEY_REPLANT, new RecentlyReplantedCropMeta(mcMMO.p, false)); + if (cropBlock.getMetadata(MetadataConstants.METADATA_KEY_REPLANT).size() > 0) { + cropBlock.setMetadata(MetadataConstants.METADATA_KEY_REPLANT, + new RecentlyReplantedCropMeta(mcMMO.p, false)); + } } } diff --git a/src/main/java/com/gmail/nossr50/runnables/skills/DelayedHerbalismXPCheckTask.java b/src/main/java/com/gmail/nossr50/runnables/skills/DelayedHerbalismXPCheckTask.java index dcc583f02..f992b4439 100644 --- a/src/main/java/com/gmail/nossr50/runnables/skills/DelayedHerbalismXPCheckTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/skills/DelayedHerbalismXPCheckTask.java @@ -3,21 +3,21 @@ package com.gmail.nossr50.runnables.skills; import com.gmail.nossr50.datatypes.BlockSnapshot; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.util.CancellableRunnable; - import java.util.ArrayList; public class DelayedHerbalismXPCheckTask extends CancellableRunnable { - private final McMMOPlayer mcMMOPlayer; + private final McMMOPlayer mmoPlayer; private final ArrayList chorusBlocks; - public DelayedHerbalismXPCheckTask(McMMOPlayer mcMMOPlayer, ArrayList chorusBlocks) { - this.mcMMOPlayer = mcMMOPlayer; + public DelayedHerbalismXPCheckTask(McMMOPlayer mmoPlayer, + ArrayList chorusBlocks) { + this.mmoPlayer = mmoPlayer; this.chorusBlocks = chorusBlocks; } @Override public void run() { - mcMMOPlayer.getHerbalismManager().awardXPForBlockSnapshots(chorusBlocks); + mmoPlayer.getHerbalismManager().awardXPForBlockSnapshots(chorusBlocks); } } diff --git a/src/main/java/com/gmail/nossr50/runnables/skills/ExperienceBarHideTask.java b/src/main/java/com/gmail/nossr50/runnables/skills/ExperienceBarHideTask.java index 34c87b0d4..035fbf02c 100644 --- a/src/main/java/com/gmail/nossr50/runnables/skills/ExperienceBarHideTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/skills/ExperienceBarHideTask.java @@ -6,32 +6,33 @@ import com.gmail.nossr50.util.CancellableRunnable; import com.gmail.nossr50.util.experience.ExperienceBarManager; public class ExperienceBarHideTask extends CancellableRunnable { - public final McMMOPlayer mcMMOPlayer; + public final McMMOPlayer mmoPlayer; public final PrimarySkillType primarySkillType; public final ExperienceBarManager experienceBarManagerRef; - public ExperienceBarHideTask(ExperienceBarManager experienceBarManagerRef, McMMOPlayer mcMMOPlayer, PrimarySkillType primarySkillType) - { + public ExperienceBarHideTask(ExperienceBarManager experienceBarManagerRef, + McMMOPlayer mmoPlayer, PrimarySkillType primarySkillType) { this.experienceBarManagerRef = experienceBarManagerRef; - this.mcMMOPlayer = mcMMOPlayer; + this.mmoPlayer = mmoPlayer; this.primarySkillType = primarySkillType; } /** - * When an object implementing interface Runnable is used - * to create a thread, starting the thread causes the object's + * When an object implementing interface Runnable is used to create a thread, + * starting the thread causes the object's * run method to be called in that separately executing * thread. *

- * The general contract of the method run is that it may - * take any action whatsoever. + * The general contract of the method run is that it may take any action + * whatsoever. * * @see Thread#run() */ @Override public void run() { - if(experienceBarManagerRef == null || mcMMOPlayer == null) + if (experienceBarManagerRef == null || mmoPlayer == null) { return; + } experienceBarManagerRef.hideExperienceBar(primarySkillType); experienceBarManagerRef.clearTask(primarySkillType); diff --git a/src/main/java/com/gmail/nossr50/runnables/skills/MasterAnglerTask.java b/src/main/java/com/gmail/nossr50/runnables/skills/MasterAnglerTask.java index 39a6c01b4..81f64fbb3 100644 --- a/src/main/java/com/gmail/nossr50/runnables/skills/MasterAnglerTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/skills/MasterAnglerTask.java @@ -10,7 +10,8 @@ public class MasterAnglerTask extends CancellableRunnable { private final @NotNull FishingManager fishingManager; private final int lureLevel; - public MasterAnglerTask(@NotNull FishHook fishHook, @NotNull FishingManager fishingManager, int lureLevel) { + public MasterAnglerTask(@NotNull FishHook fishHook, @NotNull FishingManager fishingManager, + int lureLevel) { this.fishHook = fishHook; this.fishingManager = fishingManager; this.lureLevel = lureLevel; 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 f2e9c608f..d9445c273 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,7 @@ package com.gmail.nossr50.runnables.skills; -import com.gmail.nossr50.datatypes.MobHealthbarType; +import static com.gmail.nossr50.util.AttributeMapper.MAPPED_MAX_HEALTH; + import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.events.skills.rupture.McMMOEntityDamageByRuptureEvent; import com.gmail.nossr50.mcMMO; @@ -8,7 +9,7 @@ import com.gmail.nossr50.util.CancellableRunnable; import com.gmail.nossr50.util.MetadataConstants; import com.gmail.nossr50.util.MobHealthbarUtils; import com.gmail.nossr50.util.skills.ParticleEffectUtils; -import com.google.common.base.Objects; +import org.bukkit.attribute.AttributeInstance; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; @@ -26,53 +27,89 @@ public class RuptureTask extends CancellableRunnable { private int damageTickTracker; private int animationTick; private final double pureTickDamage; - private final double explosionDamage; + // failsafe to ensure Rupture always exits and does not run forever + private int totalTicks = 0; + private final int totalTickCeiling; - public RuptureTask(@NotNull McMMOPlayer ruptureSource, @NotNull LivingEntity targetEntity, double pureTickDamage, double explosionDamage) { + /** + * Constructor for the RuptureTask class. + * + * @param ruptureSource The McMMOPlayer who is the source of the rupture. + * @param targetEntity The LivingEntity that is the target of the rupture. + * @param pureTickDamage The amount of damage to be applied per tick. + */ + public RuptureTask(@NotNull McMMOPlayer ruptureSource, @NotNull LivingEntity targetEntity, + double pureTickDamage) { this.ruptureSource = ruptureSource; this.targetEntity = targetEntity; - this.expireTick = mcMMO.p.getAdvancedConfig().getRuptureDurationSeconds(targetEntity instanceof Player) * 20; - + this.expireTick = mcMMO.p.getAdvancedConfig() + .getRuptureDurationSeconds(targetEntity instanceof Player) * 20; + this.totalTickCeiling = Math.min(this.expireTick, 200); this.ruptureTick = 0; this.damageTickTracker = 0; this.animationTick = ANIMATION_TICK_INTERVAL; //Play an animation right away this.pureTickDamage = pureTickDamage; - this.explosionDamage = explosionDamage; + } + + /** + * Deprecated constructor for the RuptureTask class. + * + * @param ruptureSource The McMMOPlayer who is the source of the rupture. + * @param targetEntity The LivingEntity that is the target of the rupture. + * @param pureTickDamage The amount of damage to be applied per tick. + * @param ignored This parameter is ignored and should not be used. + * @since 2.2.023 + * @deprecated This constructor is deprecated and will be removed in future versions. Use + * {@link #RuptureTask(McMMOPlayer, LivingEntity, double)} instead. + */ + @Deprecated(forRemoval = true, since = "2.2.023") + public RuptureTask(@NotNull McMMOPlayer ruptureSource, @NotNull LivingEntity targetEntity, + double pureTickDamage, double ignored) { + this(ruptureSource, targetEntity, pureTickDamage); } @Override public void run() { + // always increment the fail-safe + totalTicks++; + + if (totalTicks >= totalTickCeiling) { + this.cancel(); + return; + } + //Check validity - if(targetEntity.isValid()) { + if (targetEntity.isValid()) { ruptureTick += 1; //Advance rupture tick by 1. damageTickTracker += 1; //Increment damage tick tracker //TODO: Clean this code up, applyRupture() is a confusing name for something that returns boolean //Rupture hasn't ended yet - if(ruptureTick < expireTick) { + if (ruptureTick < expireTick) { //Is it time to damage? - if(damageTickTracker >= DAMAGE_TICK_INTERVAL) { - + if (damageTickTracker >= DAMAGE_TICK_INTERVAL) { damageTickTracker = 0; //Reset timer - if (applyRupture()) return; + if (applyRupture()) { + return; + } playAnimation(); } } else { - if(!applyRupture()) { + if (!applyRupture()) { playAnimation(); } endRupture(); } } else { - targetEntity.removeMetadata(MetadataConstants.METADATA_KEY_RUPTURE, mcMMO.p); this.cancel(); //Task no longer needed + targetEntity.removeMetadata(MetadataConstants.METADATA_KEY_RUPTURE, mcMMO.p); } } private void playAnimation() { - if(animationTick >= ANIMATION_TICK_INTERVAL) { + if (animationTick >= ANIMATION_TICK_INTERVAL) { ParticleEffectUtils.playBleedEffect(targetEntity); //Animate animationTick = 0; } else { @@ -83,22 +120,46 @@ public class RuptureTask extends CancellableRunnable { private boolean applyRupture() { double healthBeforeRuptureIsApplied = targetEntity.getHealth(); - //Ensure victim has health + // Ensure victim has health if (healthBeforeRuptureIsApplied > 0.01) { //Send a fake damage event McMMOEntityDamageByRuptureEvent event = - new McMMOEntityDamageByRuptureEvent(ruptureSource, targetEntity, calculateAdjustedTickDamage()); + new McMMOEntityDamageByRuptureEvent(ruptureSource, targetEntity, + calculateAdjustedTickDamage()); mcMMO.p.getServer().getPluginManager().callEvent(event); - //Ensure the event wasn't cancelled and damage is still greater than 0 + //Ensure the event wasn't canceled and damage is still greater than 0 double damage = event.getDamage(); //Use raw damage for Rupture - if (event.isCancelled() || damage <= 0 || healthBeforeRuptureIsApplied - damage <= 0) + if (event.isCancelled() || damage <= 0 || healthBeforeRuptureIsApplied - damage <= 0) { return true; + } - double damagedHealth = healthBeforeRuptureIsApplied - damage; + final double damagedHealth = healthBeforeRuptureIsApplied - damage; - targetEntity.setHealth(damagedHealth); //Hurt entity without the unwanted side effects of damage()} + final AttributeInstance maxHealthAttribute = targetEntity.getAttribute( + MAPPED_MAX_HEALTH); + if (maxHealthAttribute == null) { + // Can't remove health if max health is null + mcMMO.p.getLogger() + .info("RuptureTask: Target entity has an illegal state for its health." + + " Cancelling Rupture. Target has null " + MAPPED_MAX_HEALTH + + " attribute."); + return true; + } + + if (damagedHealth > maxHealthAttribute.getValue()) { + // Something went very wrong here, target has an illegal state for its health + mcMMO.p.getLogger() + .info("RuptureTask: Target entity has an illegal state for its health." + + " Cancelling Rupture. Target has " + targetEntity.getHealth() + + " health," + + " but max health is " + maxHealthAttribute.getValue()); + return true; + } + + targetEntity.setHealth( + damagedHealth); //Hurt entity without the unwanted side effects of damage()} MobHealthbarUtils.handleMobHealthbars(targetEntity, damage, mcMMO.p); } @@ -110,19 +171,7 @@ public class RuptureTask extends CancellableRunnable { ruptureTick = 0; } - public void endRupture() { -// targetEntity.setMetadata(mcMMO.EXPLOSION_FROM_RUPTURE, new FixedMetadataValue(mcMMO.p, "null")); -// -// ParticleEffectUtils.playGreaterImpactEffect(targetEntity); //Animate -// -// if(ruptureSource.getPlayer() != null && ruptureSource.getPlayer().isValid()) { -// targetEntity.damage(getExplosionDamage(), ruptureSource.getPlayer()); -// } else { -// targetEntity.damage(getExplosionDamage(), null); -// } -// -// targetEntity.removeMetadata(mcMMO.RUPTURE_META_KEY, mcMMO.p); - + private void endRupture() { targetEntity.removeMetadata(MetadataConstants.METADATA_KEY_RUPTURE, mcMMO.p); this.cancel(); //Task no longer needed } @@ -130,10 +179,10 @@ public class RuptureTask extends CancellableRunnable { private double calculateAdjustedTickDamage() { double tickDamage = pureTickDamage; - if(targetEntity.getHealth() <= tickDamage) { + if (targetEntity.getHealth() <= tickDamage) { tickDamage = targetEntity.getHealth() - 0.01; - if(tickDamage <= 0) { + if (tickDamage <= 0) { tickDamage = 0; } } @@ -141,8 +190,20 @@ public class RuptureTask extends CancellableRunnable { return tickDamage; } - private double getExplosionDamage() { - return explosionDamage; + @Override + public final boolean equals(Object o) { + if (!(o instanceof RuptureTask that)) { + return false; + } + + return ruptureSource.equals(that.ruptureSource) && targetEntity.equals(that.targetEntity); + } + + @Override + public int hashCode() { + int result = ruptureSource.hashCode(); + result = 31 * result + targetEntity.hashCode(); + return result; } @Override @@ -153,21 +214,10 @@ public class RuptureTask extends CancellableRunnable { ", expireTick=" + expireTick + ", ruptureTick=" + ruptureTick + ", damageTickTracker=" + damageTickTracker + + ", animationTick=" + animationTick + ", pureTickDamage=" + pureTickDamage + - ", explosionDamage=" + explosionDamage + + ", totalTicks=" + totalTicks + + ", totalTickCeiling=" + totalTickCeiling + '}'; } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - RuptureTask that = (RuptureTask) o; - return expireTick == that.expireTick && ruptureTick == that.ruptureTick && damageTickTracker == that.damageTickTracker && Double.compare(that.pureTickDamage, pureTickDamage) == 0 && Double.compare(that.explosionDamage, explosionDamage) == 0 && Objects.equal(ruptureSource, that.ruptureSource) && Objects.equal(targetEntity, that.targetEntity); - } - - @Override - public int hashCode() { - return Objects.hashCode(ruptureSource, targetEntity, expireTick, ruptureTick, damageTickTracker, pureTickDamage, explosionDamage); - } } diff --git a/src/main/java/com/gmail/nossr50/runnables/skills/SkillUnlockNotificationTask.java b/src/main/java/com/gmail/nossr50/runnables/skills/SkillUnlockNotificationTask.java index c9b6d87a5..3360149ef 100644 --- a/src/main/java/com/gmail/nossr50/runnables/skills/SkillUnlockNotificationTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/skills/SkillUnlockNotificationTask.java @@ -7,35 +7,37 @@ import com.gmail.nossr50.util.player.NotificationManager; public class SkillUnlockNotificationTask extends CancellableRunnable { - private final McMMOPlayer mcMMOPlayer; + private final McMMOPlayer mmoPlayer; private final SubSkillType subSkillType; private final int rank; + /** * Notify a player about a newly unlocked subskill - * @param mcMMOPlayer target player + * + * @param mmoPlayer target player * @param subSkillType the subskill that they just unlocked * @param rank the rank of the subskill */ - public SkillUnlockNotificationTask(McMMOPlayer mcMMOPlayer, SubSkillType subSkillType, int rank) - { - this.mcMMOPlayer = mcMMOPlayer; + public SkillUnlockNotificationTask(McMMOPlayer mmoPlayer, SubSkillType subSkillType, int rank) { + this.mmoPlayer = mmoPlayer; this.subSkillType = subSkillType; this.rank = rank; } + /** - * When an object implementing interface Runnable is used - * to create a thread, starting the thread causes the object's + * When an object implementing interface Runnable is used to create a thread, + * starting the thread causes the object's * run method to be called in that separately executing * thread. *

- * The general contract of the method run is that it may - * take any action whatsoever. + * The general contract of the method run is that it may take any action + * whatsoever. * * @see Thread#run() */ @Override public void run() { - //mcMMOPlayer.getPlayer().sendTitle(subSkillType.getLocaleName(), "Rank "+rank, 7, 20, 7); - NotificationManager.sendPlayerUnlockNotification(mcMMOPlayer, subSkillType); + //mmoPlayer.getPlayer().sendTitle(subSkillType.getLocaleName(), "Rank "+rank, 7, 20, 7); + NotificationManager.sendPlayerUnlockNotification(mmoPlayer, subSkillType); } } diff --git a/src/main/java/com/gmail/nossr50/runnables/skills/ToolLowerTask.java b/src/main/java/com/gmail/nossr50/runnables/skills/ToolLowerTask.java index 98f336e84..1494101f0 100644 --- a/src/main/java/com/gmail/nossr50/runnables/skills/ToolLowerTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/skills/ToolLowerTask.java @@ -8,24 +8,25 @@ import com.gmail.nossr50.util.CancellableRunnable; import com.gmail.nossr50.util.player.NotificationManager; public class ToolLowerTask extends CancellableRunnable { - private final McMMOPlayer mcMMOPlayer; + private final McMMOPlayer mmoPlayer; private final ToolType tool; - public ToolLowerTask(McMMOPlayer mcMMOPlayer, ToolType tool) { - this.mcMMOPlayer = mcMMOPlayer; + public ToolLowerTask(McMMOPlayer mmoPlayer, ToolType tool) { + this.mmoPlayer = mmoPlayer; this.tool = tool; } @Override public void run() { - if (!mcMMOPlayer.getToolPreparationMode(tool)) { + if (!mmoPlayer.getToolPreparationMode(tool)) { return; } - mcMMOPlayer.setToolPreparationMode(tool, false); + mmoPlayer.setToolPreparationMode(tool, false); if (mcMMO.p.getGeneralConfig().getAbilityMessagesEnabled()) { - NotificationManager.sendPlayerInformation(mcMMOPlayer.getPlayer(), NotificationType.TOOL, tool.getLowerTool()); + NotificationManager.sendPlayerInformation(mmoPlayer.getPlayer(), NotificationType.TOOL, + tool.getLowerTool()); } } } diff --git a/src/main/java/com/gmail/nossr50/skills/SkillManager.java b/src/main/java/com/gmail/nossr50/skills/SkillManager.java index cc18c9b32..a3c826022 100644 --- a/src/main/java/com/gmail/nossr50/skills/SkillManager.java +++ b/src/main/java/com/gmail/nossr50/skills/SkillManager.java @@ -27,6 +27,7 @@ public abstract class SkillManager { /** * Applies XP to a player, provides SELF as an XpGainSource source + * * @param xp amount of XP to apply * @param xpGainReason the reason for the XP gain * @deprecated use applyXpGain(float, XPGainReason, XPGainSource) @@ -38,6 +39,7 @@ public abstract class SkillManager { /** * Applies XP to a player + * * @param xp amount of XP to apply * @param xpGainReason the reason for the XP gain * @param xpGainSource the source of the XP @@ -47,6 +49,7 @@ public abstract class SkillManager { } public XPGainReason getXPGainReason(LivingEntity target, Entity damager) { - return (damager instanceof Player && target instanceof Player) ? XPGainReason.PVP : XPGainReason.PVE; + return (damager instanceof Player && target instanceof Player) ? XPGainReason.PVP + : XPGainReason.PVE; } } diff --git a/src/main/java/com/gmail/nossr50/skills/acrobatics/Acrobatics.java b/src/main/java/com/gmail/nossr50/skills/acrobatics/Acrobatics.java index 60f948d90..ef4a0024a 100644 --- a/src/main/java/com/gmail/nossr50/skills/acrobatics/Acrobatics.java +++ b/src/main/java/com/gmail/nossr50/skills/acrobatics/Acrobatics.java @@ -4,13 +4,15 @@ import com.gmail.nossr50.config.experience.ExperienceConfig; import com.gmail.nossr50.mcMMO; public final class Acrobatics { - public static double dodgeDamageModifier = mcMMO.p.getAdvancedConfig().getDodgeDamageModifier(); + public static double dodgeDamageModifier = mcMMO.p.getAdvancedConfig().getDodgeDamageModifier(); public static int dodgeXpModifier = ExperienceConfig.getInstance().getDodgeXPModifier(); - public static boolean dodgeLightningDisabled = mcMMO.p.getGeneralConfig().getDodgeLightningDisabled(); + public static boolean dodgeLightningDisabled = mcMMO.p.getGeneralConfig() + .getDodgeLightningDisabled(); - private Acrobatics() {} + private Acrobatics() { + } - protected static double calculateModifiedDodgeDamage(double damage, double damageModifier) { + static double calculateModifiedDodgeDamage(double damage, double damageModifier) { return Math.max(damage / damageModifier, 1.0); } } 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 a0758bacc..daeefcbdc 100644 --- a/src/main/java/com/gmail/nossr50/skills/acrobatics/AcrobaticsManager.java +++ b/src/main/java/com/gmail/nossr50/skills/acrobatics/AcrobaticsManager.java @@ -14,10 +14,10 @@ import com.gmail.nossr50.util.MetadataConstants; 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.player.UserManager; +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.SkillActivationType; import com.gmail.nossr50.util.skills.SkillUtils; import org.bukkit.Location; import org.bukkit.entity.Entity; @@ -29,8 +29,8 @@ import org.bukkit.metadata.MetadataValue; public class AcrobaticsManager extends SkillManager { - public AcrobaticsManager(McMMOPlayer mcMMOPlayer) { - super(mcMMOPlayer, PrimarySkillType.ACROBATICS); + public AcrobaticsManager(McMMOPlayer mmoPlayer) { + super(mmoPlayer, PrimarySkillType.ACROBATICS); fallLocationMap = new BlockLocationHistory(50); } @@ -39,23 +39,20 @@ public class AcrobaticsManager extends SkillManager { private long rollXPIntervalLengthen = (1000 * 10); //10 Seconds private final BlockLocationHistory fallLocationMap; - public boolean hasFallenInLocationBefore(Location location) - { + public boolean hasFallenInLocationBefore(Location location) { return fallLocationMap.contains(location); } - public void addLocationToFallMap(Location location) - { + public void addLocationToFallMap(Location location) { fallLocationMap.add(location); } - public boolean canGainRollXP() - { - if(!ExperienceConfig.getInstance().isAcrobaticsExploitingPrevented()) + public boolean canGainRollXP() { + if (!ExperienceConfig.getInstance().isAcrobaticsExploitingPrevented()) { return true; + } - if(System.currentTimeMillis() >= rollXPCooldown) - { + if (System.currentTimeMillis() >= rollXPCooldown) { rollXPCooldown = System.currentTimeMillis() + rollXPInterval; rollXPIntervalLengthen = (1000 * 10); //5 Seconds return true; @@ -67,11 +64,13 @@ public class AcrobaticsManager extends SkillManager { } public boolean canDodge(Entity damager) { - if(getPlayer().isBlocking()) + if (getPlayer().isBlocking()) { return false; + } - if(!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.ACROBATICS_DODGE)) + if (!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.ACROBATICS_DODGE)) { return false; + } if (Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.ACROBATICS_DODGE)) { if (damager instanceof LightningStrike && Acrobatics.dodgeLightningDisabled) { @@ -88,35 +87,49 @@ public class AcrobaticsManager extends SkillManager { * Handle the damage reduction and XP gain from the Dodge ability * * @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 + * @return the modified event damage if the ability was successful, the original event damage + * otherwise */ public double dodgeCheck(Entity attacker, double damage) { - double modifiedDamage = Acrobatics.calculateModifiedDodgeDamage(damage, Acrobatics.dodgeDamageModifier); + 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) + && ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.ACROBATICS_DODGE, + UserManager.getPlayer(player))) { ParticleEffectUtils.playDodgeEffect(player); if (mmoPlayer.useChatNotifications()) { - NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE, "Acrobatics.Combat.Proc"); + NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE, + "Acrobatics.Combat.Proc"); } - if (SkillUtils.cooldownExpired(mmoPlayer.getRespawnATS(), Misc.PLAYER_RESPAWN_COOLDOWN_SECONDS)) { - if(attacker instanceof Mob mob) { + if (SkillUtils.cooldownExpired(mmoPlayer.getRespawnATS(), + Misc.PLAYER_RESPAWN_COOLDOWN_SECONDS)) { + if (attacker instanceof Mob mob) { //Check to see how many dodge XP rewards this mob has handed out - if(mob.hasMetadata(MetadataConstants.METADATA_KEY_DODGE_TRACKER) && ExperienceConfig.getInstance().isAcrobaticsExploitingPrevented()) { + if (mob.hasMetadata(MetadataConstants.METADATA_KEY_DODGE_TRACKER) + && ExperienceConfig.getInstance().isAcrobaticsExploitingPrevented()) { //If Dodge XP has been handed out 5 times then consider it being exploited - MetadataValue metadataValue = mob.getMetadata(MetadataConstants.METADATA_KEY_DODGE_TRACKER).get(0); + MetadataValue metadataValue = mob.getMetadata( + MetadataConstants.METADATA_KEY_DODGE_TRACKER).get(0); int count = metadataValue.asInt(); - if(count <= 5) { - applyXpGain((float) (damage * Acrobatics.dodgeXpModifier), XPGainReason.PVE); - mob.setMetadata(MetadataConstants.METADATA_KEY_DODGE_TRACKER, new FixedMetadataValue(mcMMO.p, count + 1)); - MobDodgeMetaCleanup metaCleanupTask = new MobDodgeMetaCleanup(mob, mcMMO.p); - mcMMO.p.getFoliaLib().getImpl().runAtEntityTimer(mob, metaCleanupTask, 20, 20*60); //one minute + if (count <= 5) { + applyXpGain((float) (damage * Acrobatics.dodgeXpModifier), + XPGainReason.PVE); + mob.setMetadata(MetadataConstants.METADATA_KEY_DODGE_TRACKER, + new FixedMetadataValue(mcMMO.p, count + 1)); + MobDodgeMetaCleanup metaCleanupTask = new MobDodgeMetaCleanup(mob, + mcMMO.p); + mcMMO.p.getFoliaLib().getScheduler() + .runAtEntityTimer(mob, metaCleanupTask, 20, + 20 * 60); //one minute } } else { - applyXpGain((float) (damage * Acrobatics.dodgeXpModifier), XPGainReason.PVE); + applyXpGain((float) (damage * Acrobatics.dodgeXpModifier), + XPGainReason.PVE); } } } diff --git a/src/main/java/com/gmail/nossr50/skills/alchemy/Alchemy.java b/src/main/java/com/gmail/nossr50/skills/alchemy/Alchemy.java index c6c5470a3..5281ab762 100644 --- a/src/main/java/com/gmail/nossr50/skills/alchemy/Alchemy.java +++ b/src/main/java/com/gmail/nossr50/skills/alchemy/Alchemy.java @@ -3,63 +3,32 @@ package com.gmail.nossr50.skills.alchemy; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.runnables.skills.AlchemyBrewTask; import com.gmail.nossr50.util.LogUtils; -import org.bukkit.Location; - import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import org.bukkit.Location; public final class Alchemy { - /*public enum Tier { - EIGHT(8), - SEVEN(7), - SIX(6), - FIVE(5), - FOUR(4), - THREE(3), - TWO(2), - ONE(1); - - int numerical; - - private Tier(int numerical) { - this.numerical = numerical; - } - - public int toNumerical() { - return numerical; - } - - public static Tier fromNumerical(int numerical) { - for (Tier tier : Tier.values()) { - if (tier.toNumerical() == numerical) { - return tier; - } - } - return null; - } - - protected int getLevel() { - return mcMMO.p.getAdvancedConfig().getConcoctionsTierLevel(this); - } - }*/ - public static final int INGREDIENT_SLOT = 3; - public static int catalysisMaxBonusLevel = mcMMO.p.getAdvancedConfig().getCatalysisMaxBonusLevel(); - public static double catalysisMinSpeed = mcMMO.p.getAdvancedConfig().getCatalysisMinSpeed(); - public static double catalysisMaxSpeed = mcMMO.p.getAdvancedConfig().getCatalysisMaxSpeed(); + public static int catalysisMaxBonusLevel = mcMMO.p.getAdvancedConfig() + .getCatalysisMaxBonusLevel(); + public static double catalysisMinSpeed = mcMMO.p.getAdvancedConfig().getCatalysisMinSpeed(); + public static double catalysisMaxSpeed = mcMMO.p.getAdvancedConfig().getCatalysisMaxSpeed(); public static Map brewingStandMap = new HashMap<>(); - private Alchemy() {} + private Alchemy() { + } /** - * Finish all active brews. Used upon Disable to prevent vanilla potions from being brewed upon next Enable. + * Finish all active brews. Used upon Disable to prevent vanilla potions from being brewed upon + * next Enable. */ public static void finishAllBrews() { - LogUtils.debug(mcMMO.p.getLogger(), "Completing " + brewingStandMap.size() + " unfinished Alchemy brews."); + LogUtils.debug(mcMMO.p.getLogger(), + "Completing " + brewingStandMap.size() + " unfinished Alchemy brews."); List toFinish = new ArrayList<>(brewingStandMap.values()); diff --git a/src/main/java/com/gmail/nossr50/skills/alchemy/AlchemyManager.java b/src/main/java/com/gmail/nossr50/skills/alchemy/AlchemyManager.java index 16b1dd2ac..801473b90 100644 --- a/src/main/java/com/gmail/nossr50/skills/alchemy/AlchemyManager.java +++ b/src/main/java/com/gmail/nossr50/skills/alchemy/AlchemyManager.java @@ -1,25 +1,25 @@ package com.gmail.nossr50.skills.alchemy; +import static com.gmail.nossr50.util.text.ConfigStringUtils.getMaterialConfigString; + import com.gmail.nossr50.config.experience.ExperienceConfig; -import com.gmail.nossr50.config.skills.alchemy.PotionConfig; 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; import com.gmail.nossr50.datatypes.skills.alchemy.PotionStage; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.skills.SkillManager; import com.gmail.nossr50.util.skills.RankUtils; -import com.gmail.nossr50.util.text.StringUtils; -import org.bukkit.inventory.ItemStack; - import java.util.List; +import org.bukkit.inventory.ItemStack; public class AlchemyManager extends SkillManager { private final double LUCKY_MODIFIER = 4.0 / 3.0; - public AlchemyManager(McMMOPlayer mcMMOPlayer) { - super(mcMMOPlayer, PrimarySkillType.ALCHEMY); + public AlchemyManager(McMMOPlayer mmoPlayer) { + super(mmoPlayer, PrimarySkillType.ALCHEMY); } public int getTier() { @@ -27,14 +27,14 @@ public class AlchemyManager extends SkillManager { } public List getIngredients() { - return PotionConfig.getInstance().getIngredients(getTier()); + return mcMMO.p.getPotionConfig().getIngredients(getTier()); } public String getIngredientList() { StringBuilder list = new StringBuilder(); for (ItemStack ingredient : getIngredients()) { - String string = StringUtils.getPrettyItemString(ingredient.getType()); + String string = getMaterialConfigString(ingredient.getType()); list.append(", ").append(string); } @@ -49,10 +49,22 @@ public class AlchemyManager extends SkillManager { return Alchemy.catalysisMinSpeed; } - return Math.min(Alchemy.catalysisMaxSpeed, Alchemy.catalysisMinSpeed + (Alchemy.catalysisMaxSpeed - Alchemy.catalysisMinSpeed) * (skillLevel - RankUtils.getUnlockLevel(SubSkillType.ALCHEMY_CATALYSIS)) / (Alchemy.catalysisMaxBonusLevel - RankUtils.getUnlockLevel(SubSkillType.ALCHEMY_CATALYSIS))) * (isLucky ? LUCKY_MODIFIER : 1.0); + return Math.min(Alchemy.catalysisMaxSpeed, Alchemy.catalysisMinSpeed + + (Alchemy.catalysisMaxSpeed - Alchemy.catalysisMinSpeed) * (skillLevel + - RankUtils.getUnlockLevel(SubSkillType.ALCHEMY_CATALYSIS)) / ( + Alchemy.catalysisMaxBonusLevel - RankUtils.getUnlockLevel( + SubSkillType.ALCHEMY_CATALYSIS))) * (isLucky ? LUCKY_MODIFIER + : 1.0); } + /** + * Handle the XP gain for a successful potion brew. + * + * @param potionStage The potion stage, this is used to determine the XP gain. + * @param amount The amount of potions brewed. + */ public void handlePotionBrewSuccesses(PotionStage potionStage, int amount) { - applyXpGain((float) (ExperienceConfig.getInstance().getPotionXP(potionStage) * amount), XPGainReason.PVE, XPGainSource.PASSIVE); + applyXpGain((float) (ExperienceConfig.getInstance().getPotionXP(potionStage) * amount), + XPGainReason.PVE, XPGainSource.PASSIVE); } } \ No newline at end of file diff --git a/src/main/java/com/gmail/nossr50/skills/alchemy/AlchemyPotionBrewer.java b/src/main/java/com/gmail/nossr50/skills/alchemy/AlchemyPotionBrewer.java index 2a11b0159..20f241e1d 100644 --- a/src/main/java/com/gmail/nossr50/skills/alchemy/AlchemyPotionBrewer.java +++ b/src/main/java/com/gmail/nossr50/skills/alchemy/AlchemyPotionBrewer.java @@ -1,6 +1,6 @@ package com.gmail.nossr50.skills.alchemy; -import com.gmail.nossr50.config.skills.alchemy.PotionConfig; +import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.datatypes.skills.alchemy.AlchemyPotion; import com.gmail.nossr50.datatypes.skills.alchemy.PotionStage; @@ -10,6 +10,11 @@ import com.gmail.nossr50.runnables.player.PlayerUpdateInventoryTask; import com.gmail.nossr50.runnables.skills.AlchemyBrewCheckTask; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.player.UserManager; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import org.bukkit.Material; import org.bukkit.block.BlockState; import org.bukkit.block.BrewingStand; @@ -20,23 +25,63 @@ import org.bukkit.inventory.BrewerInventory; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.InventoryView; import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - +// TODO: Update to use McMMOPlayer public final class AlchemyPotionBrewer { + /* + * Compatibility with older versions where InventoryView used to be an abstract class and became an interface. + * This was introduced in Minecraft 1.21 if we drop support for versions older than 1.21 this can be removed. + */ + private static final Method getItem, setItem; + + static { + try { + final Class clazz = Class.forName("org.bukkit.inventory.InventoryView"); + getItem = clazz.getDeclaredMethod("getItem", int.class); + setItem = clazz.getDeclaredMethod("setItem", int.class, ItemStack.class); + } catch (NoSuchMethodException | ClassNotFoundException e) { + throw new RuntimeException(e); + } + } + + @Deprecated(forRemoval = true, since = "2.2.010") public static boolean isValidBrew(Player player, ItemStack[] contents) { - if (!isValidIngredient(player, contents[Alchemy.INGREDIENT_SLOT])) { + if (!isValidIngredientByPlayer(player, contents[Alchemy.INGREDIENT_SLOT])) { return false; } for (int i = 0; i < 3; i++) { - if (contents[i] == null || contents[i].getType() != Material.POTION && contents[i].getType() != Material.SPLASH_POTION && contents[i].getType() != Material.LINGERING_POTION) { + if (contents[i] == null || contents[i].getType() != Material.POTION + && contents[i].getType() != Material.SPLASH_POTION + && contents[i].getType() != Material.LINGERING_POTION) { continue; } - if (getChildPotion(PotionConfig.getInstance().getPotion(contents[i]), contents[Alchemy.INGREDIENT_SLOT]) != null) { + final AlchemyPotion potion = mcMMO.p.getPotionConfig().getPotion(contents[i]); + if (getChildPotion(potion, contents[Alchemy.INGREDIENT_SLOT]) != null) { + return true; + } + } + + return false; + } + + public static boolean isValidBrew(int ingredientLevel, ItemStack[] contents) { + if (!isValidIngredientByLevel(ingredientLevel, contents[Alchemy.INGREDIENT_SLOT])) { + return false; + } + + for (int i = 0; i < 3; i++) { + if (contents[i] == null || contents[i].getType() != Material.POTION + && contents[i].getType() != Material.SPLASH_POTION + && contents[i].getType() != Material.LINGERING_POTION) { + continue; + } + + final AlchemyPotion potion = mcMMO.p.getPotionConfig().getPotion(contents[i]); + if (getChildPotion(potion, contents[Alchemy.INGREDIENT_SLOT]) != null) { return true; } } @@ -57,16 +102,16 @@ public final class AlchemyPotionBrewer { } private static void removeIngredient(BrewerInventory inventory, Player player) { - if(inventory.getIngredient() == null) + if (inventory.getIngredient() == null) { return; + } ItemStack ingredient = inventory.getIngredient().clone(); - if (!isEmpty(ingredient) && isValidIngredient(player, ingredient)) { + if (!isEmpty(ingredient) && isValidIngredientByPlayer(player, ingredient)) { if (ingredient.getAmount() <= 1) { inventory.setIngredient(null); - } - else { + } else { ingredient.setAmount(ingredient.getAmount() - 1); inventory.setIngredient(ingredient); } @@ -74,17 +119,18 @@ public final class AlchemyPotionBrewer { } private static boolean hasIngredient(BrewerInventory inventory, Player player) { - ItemStack ingredient = inventory.getIngredient() == null ? null : inventory.getIngredient().clone(); + ItemStack ingredient = + inventory.getIngredient() == null ? null : inventory.getIngredient().clone(); - return !isEmpty(ingredient) && isValidIngredient(player, ingredient); + return !isEmpty(ingredient) && isValidIngredientByPlayer(player, ingredient); } - public static boolean isValidIngredient(Player player, ItemStack item) { + public static boolean isValidIngredientByPlayer(Player player, ItemStack item) { if (isEmpty(item)) { return false; } - for (ItemStack ingredient : getValidIngredients(player)) { + for (ItemStack ingredient : getValidIngredients(UserManager.getPlayer(player))) { if (item.isSimilar(ingredient)) { return true; } @@ -93,77 +139,126 @@ public final class AlchemyPotionBrewer { return false; } - private static List getValidIngredients(Player player) { - if(player == null || UserManager.getPlayer(player) == null) - { - return PotionConfig.getInstance().getIngredients(1); + public static boolean isValidIngredientByLevel(int ingredientLevel, ItemStack item) { + if (isEmpty(item)) { + return false; } - return PotionConfig.getInstance().getIngredients(!Permissions.isSubSkillEnabled(player, SubSkillType.ALCHEMY_CONCOCTIONS) ? 1 : UserManager.getPlayer(player).getAlchemyManager().getTier()); + // TODO: Update this when we fix loading from hoppers + for (ItemStack ingredient : mcMMO.p.getPotionConfig().getIngredients(ingredientLevel)) { + if (item.isSimilar(ingredient)) { + return true; + } + } + + return false; } - public static void finishBrewing(BlockState brewingStand, Player player, boolean forced) { + private static List getValidIngredients(@Nullable McMMOPlayer mmoPlayer) { + if (mmoPlayer == null) { + return mcMMO.p.getPotionConfig().getIngredients(1); + } + + return mcMMO.p.getPotionConfig().getIngredients( + !Permissions.isSubSkillEnabled(mmoPlayer, SubSkillType.ALCHEMY_CONCOCTIONS) + ? 1 : mmoPlayer.getAlchemyManager().getTier()); + } + + public static void finishBrewing(BlockState brewingStand, @Nullable McMMOPlayer mmoPlayer, + boolean forced) { + // Check if the brewing stand block state is an actual brewing stand if (!(brewingStand instanceof BrewingStand)) { return; } - BrewerInventory inventory = ((BrewingStand) brewingStand).getInventory(); - ItemStack ingredient = inventory.getIngredient() == null ? null : inventory.getIngredient().clone(); + // Retrieve the inventory of the brewing stand and clone the current ingredient for safe manipulation + final BrewerInventory inventory = ((BrewingStand) brewingStand).getInventory(); + final ItemStack ingredient = + inventory.getIngredient() == null ? null : inventory.getIngredient().clone(); + Player player = mmoPlayer != null ? mmoPlayer.getPlayer() : null; - if (!hasIngredient(inventory, player)) { + if (ingredient == null) { return; } + // Check if the brewing stand has a valid ingredient; if not, exit the method + if (player == null + || !hasIngredient(inventory, player)) { + // debug + return; + } + + // Initialize lists to hold the potions before and after brewing, initially setting them to null List inputList = new ArrayList<>(Collections.nCopies(3, null)); List outputList = new ArrayList<>(Collections.nCopies(3, null)); + // Process each of the three slots in the brewing stand for (int i = 0; i < 3; i++) { - ItemStack item = inventory.getItem(i); + final ItemStack potionInBrewStandInputSlot = inventory.getItem(i); - if (isEmpty(item) || item.getType() == Material.GLASS_BOTTLE || !PotionConfig.getInstance().isValidPotion(item)) { + // Skip the slot if it's empty, contains a glass bottle, or holds an invalid potion + if (isEmpty(potionInBrewStandInputSlot) + || potionInBrewStandInputSlot.getType() == Material.GLASS_BOTTLE + || !mcMMO.p.getPotionConfig().isValidPotion(potionInBrewStandInputSlot)) { + // debug continue; } - AlchemyPotion input = PotionConfig.getInstance().getPotion(item); + // Retrieve the potion configurations for the input and resulting output potion + AlchemyPotion input = mcMMO.p.getPotionConfig().getPotion(potionInBrewStandInputSlot); AlchemyPotion output = input.getChild(ingredient); + // Update the input list with the current potion inputList.set(i, input); + // If there is a valid output potion, add it to the output list if (output != null) { - outputList.set(i, output.toItemStack(item.getAmount()).clone()); + outputList.set(i, + output.toItemStack(potionInBrewStandInputSlot.getAmount()).clone()); } } - FakeBrewEvent event = new FakeBrewEvent(brewingStand.getBlock(), inventory, outputList, ((BrewingStand) brewingStand).getFuelLevel()); + // Create a fake brewing event and pass it to the plugin's event system + FakeBrewEvent event = new FakeBrewEvent(brewingStand.getBlock(), inventory, outputList, + ((BrewingStand) brewingStand).getFuelLevel()); mcMMO.p.getServer().getPluginManager().callEvent(event); + // If the event is cancelled or there are no potions processed, exit the method if (event.isCancelled() || inputList.isEmpty()) { + // debug return; } + // Update the brewing inventory with the new potions for (int i = 0; i < 3; i++) { - if(outputList.get(i) != null) { + if (outputList.get(i) != null) { inventory.setItem(i, outputList.get(i)); } } + // Remove the used ingredient from the brewing inventory removeIngredient(inventory, player); + // Handle potion brewing success and related effects for each potion processed for (AlchemyPotion input : inputList) { - if (input == null) continue; + if (input == null) { + continue; + } AlchemyPotion output = input.getChild(ingredient); if (output != null && player != null) { PotionStage potionStage = PotionStage.getPotionStage(input, output); - //TODO: hmm - if (UserManager.hasPlayerDataKey(player)) { - UserManager.getPlayer(player).getAlchemyManager().handlePotionBrewSuccesses(potionStage, 1); + // Update player alchemy skills or effects based on brewing success + if (UserManager.getPlayer(player) != null) { + UserManager.getPlayer(player).getAlchemyManager() + .handlePotionBrewSuccesses(potionStage, 1); } } } + // If the brewing was not forced by external conditions, schedule a new update if (!forced) { scheduleUpdate(inventory); } @@ -172,19 +267,23 @@ public final class AlchemyPotionBrewer { public static boolean transferItems(InventoryView view, int fromSlot, ClickType click) { boolean success = false; - if (click.isLeftClick()) { - success = transferItems(view, fromSlot); - } - else if (click.isRightClick()) { - success = transferOneItem(view, fromSlot); + try { + if (click.isLeftClick()) { + success = transferItems(view, fromSlot); + } else if (click.isRightClick()) { + success = transferOneItem(view, fromSlot); + } + } catch (InvocationTargetException | IllegalAccessException e) { + throw new RuntimeException(e); } return success; } - private static boolean transferOneItem(InventoryView view, int fromSlot) { - ItemStack from = view.getItem(fromSlot).clone(); - ItemStack to = view.getItem(Alchemy.INGREDIENT_SLOT).clone(); + private static boolean transferOneItem(InventoryView view, int fromSlot) + throws InvocationTargetException, IllegalAccessException { + final ItemStack from = ((ItemStack) getItem.invoke(view, fromSlot)).clone(); + ItemStack to = ((ItemStack) getItem.invoke(view, Alchemy.INGREDIENT_SLOT)).clone(); if (isEmpty(from)) { return false; @@ -195,19 +294,17 @@ public final class AlchemyPotionBrewer { if (!emptyTo && fromAmount >= from.getType().getMaxStackSize()) { return false; - } - else if (emptyTo || from.isSimilar(to)) { + } else if (emptyTo || from.isSimilar(to)) { if (emptyTo) { to = from.clone(); to.setAmount(1); - } - else { + } else { to.setAmount(to.getAmount() + 1); } from.setAmount(fromAmount - 1); - view.setItem(Alchemy.INGREDIENT_SLOT, to); - view.setItem(fromSlot, from); + setItem.invoke(view, Alchemy.INGREDIENT_SLOT, to); + setItem.invoke(view, fromSlot, from); return true; } @@ -218,20 +315,17 @@ public final class AlchemyPotionBrewer { /** * Transfer items between two ItemStacks, returning the leftover status */ - private static boolean transferItems(InventoryView view, int fromSlot) { - ItemStack from = view.getItem(fromSlot).clone(); - ItemStack to = view.getItem(Alchemy.INGREDIENT_SLOT).clone(); - + private static boolean transferItems(InventoryView view, int fromSlot) + throws InvocationTargetException, IllegalAccessException { + final ItemStack from = ((ItemStack) getItem.invoke(view, fromSlot)).clone(); + final ItemStack to = ((ItemStack) getItem.invoke(view, Alchemy.INGREDIENT_SLOT)).clone(); if (isEmpty(from)) { return false; - } - else if (isEmpty(to)) { - view.setItem(Alchemy.INGREDIENT_SLOT, from); - view.setItem(fromSlot, null); - + } else if (isEmpty(to)) { + setItem.invoke(view, Alchemy.INGREDIENT_SLOT, from); + setItem.invoke(view, fromSlot, null); return true; - } - else if (from.isSimilar(to)) { + } else if (from.isSimilar(to)) { int fromAmount = from.getAmount(); int toAmount = to.getAmount(); int maxSize = to.getType().getMaxStackSize(); @@ -240,17 +334,17 @@ public final class AlchemyPotionBrewer { int left = fromAmount + toAmount - maxSize; to.setAmount(maxSize); - view.setItem(Alchemy.INGREDIENT_SLOT, to); + setItem.invoke(view, Alchemy.INGREDIENT_SLOT, to); from.setAmount(left); - view.setItem(fromSlot, from); + setItem.invoke(view, fromSlot, from); return true; } to.setAmount(fromAmount + toAmount); - view.setItem(fromSlot, null); - view.setItem(Alchemy.INGREDIENT_SLOT, to); + setItem.invoke(view, fromSlot, null); + setItem.invoke(view, Alchemy.INGREDIENT_SLOT, to); return true; } @@ -258,14 +352,16 @@ public final class AlchemyPotionBrewer { return false; } - public static void scheduleCheck(Player player, BrewingStand brewingStand) { - mcMMO.p.getFoliaLib().getImpl().runAtEntity(player, new AlchemyBrewCheckTask(player, brewingStand)); + public static void scheduleCheck(@NotNull BrewingStand brewingStand) { + mcMMO.p.getFoliaLib().getScheduler().runAtLocation( + brewingStand.getLocation(), new AlchemyBrewCheckTask(brewingStand)); } public static void scheduleUpdate(Inventory inventory) { for (HumanEntity humanEntity : inventory.getViewers()) { if (humanEntity instanceof Player) { - mcMMO.p.getFoliaLib().getImpl().runAtEntity(humanEntity, new PlayerUpdateInventoryTask((Player) humanEntity)); + mcMMO.p.getFoliaLib().getScheduler().runAtEntity(humanEntity, + new PlayerUpdateInventoryTask((Player) humanEntity)); } } } diff --git a/src/main/java/com/gmail/nossr50/skills/archery/Archery.java b/src/main/java/com/gmail/nossr50/skills/archery/Archery.java index 3ad317287..b5e2c5737 100644 --- a/src/main/java/com/gmail/nossr50/skills/archery/Archery.java +++ b/src/main/java/com/gmail/nossr50/skills/archery/Archery.java @@ -4,26 +4,27 @@ import com.gmail.nossr50.api.ItemSpawnReason; import com.gmail.nossr50.config.experience.ExperienceConfig; import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.util.Misc; +import com.gmail.nossr50.util.ItemUtils; import com.gmail.nossr50.util.skills.RankUtils; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; import org.bukkit.Material; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - public class Archery { private static final List trackedEntities = new ArrayList<>(); - public static double skillShotMaxBonusDamage = mcMMO.p.getAdvancedConfig().getSkillShotDamageMax(); + public static double skillShotMaxBonusDamage = mcMMO.p.getAdvancedConfig() + .getSkillShotDamageMax(); public static double dazeBonusDamage = mcMMO.p.getAdvancedConfig().getDazeBonusDamage(); - public static final double DISTANCE_XP_MULTIPLIER = ExperienceConfig.getInstance().getArcheryDistanceMultiplier(); + public static final double DISTANCE_XP_MULTIPLIER = ExperienceConfig.getInstance() + .getArcheryDistanceMultiplier(); protected static void incrementTrackerValue(LivingEntity livingEntity) { for (TrackedEntity trackedEntity : trackedEntities) { @@ -53,25 +54,28 @@ public class Archery { * @param livingEntity The entity hit by the arrows */ public static void arrowRetrievalCheck(@NotNull LivingEntity livingEntity) { - for (Iterator entityIterator = trackedEntities.iterator(); entityIterator.hasNext();) { + for (Iterator entityIterator = trackedEntities.iterator(); + entityIterator.hasNext(); ) { TrackedEntity trackedEntity = entityIterator.next(); if (trackedEntity.getID() == livingEntity.getUniqueId()) { - Misc.spawnItems(null, livingEntity.getLocation(), new ItemStack(Material.ARROW), trackedEntity.getArrowCount(), ItemSpawnReason.ARROW_RETRIEVAL_ACTIVATED); + ItemUtils.spawnItems(null, livingEntity.getLocation(), + new ItemStack(Material.ARROW), trackedEntity.getArrowCount(), + ItemSpawnReason.ARROW_RETRIEVAL_ACTIVATED); entityIterator.remove(); return; } } } - public static double getSkillShotBonusDamage(Player player, double oldDamage) - { + public static double getSkillShotBonusDamage(Player player, double oldDamage) { double damageBonusPercent = getDamageBonusPercent(player); double newDamage = oldDamage + (oldDamage * damageBonusPercent); return Math.min(newDamage, (oldDamage + Archery.skillShotMaxBonusDamage)); } public static double getDamageBonusPercent(Player player) { - return ((RankUtils.getRank(player, SubSkillType.ARCHERY_SKILL_SHOT)) * (mcMMO.p.getAdvancedConfig().getSkillShotRankDamageMultiplier()) / 100.0D); + return ((RankUtils.getRank(player, SubSkillType.ARCHERY_SKILL_SHOT)) + * (mcMMO.p.getAdvancedConfig().getSkillShotRankDamageMultiplier()) / 100.0D); } } 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 56dd26aaa..ee41e3ff0 100644 --- a/src/main/java/com/gmail/nossr50/skills/archery/ArcheryManager.java +++ b/src/main/java/com/gmail/nossr50/skills/archery/ArcheryManager.java @@ -1,5 +1,7 @@ package com.gmail.nossr50.skills.archery; +import static com.gmail.nossr50.util.PotionEffectUtil.getNauseaPotionEffectType; + import com.gmail.nossr50.datatypes.interactions.NotificationType; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; @@ -10,39 +12,41 @@ import com.gmail.nossr50.util.MetadataConstants; 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.random.ProbabilityUtil; import com.gmail.nossr50.util.skills.RankUtils; -import com.gmail.nossr50.util.skills.SkillActivationType; import org.bukkit.Location; import org.bukkit.entity.Entity; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; import org.bukkit.entity.Projectile; import org.bukkit.potion.PotionEffect; -import org.bukkit.potion.PotionEffectType; public class ArcheryManager extends SkillManager { - public ArcheryManager(McMMOPlayer mcMMOPlayer) { - super(mcMMOPlayer, PrimarySkillType.ARCHERY); + public ArcheryManager(McMMOPlayer mmoPlayer) { + super(mmoPlayer, PrimarySkillType.ARCHERY); } public boolean canDaze(LivingEntity target) { - if(!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.ARCHERY_DAZE)) + if (!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.ARCHERY_DAZE)) { return false; + } - return target instanceof Player && Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.ARCHERY_DAZE); + return target instanceof Player && Permissions.isSubSkillEnabled(getPlayer(), + SubSkillType.ARCHERY_DAZE); } public boolean canSkillShot() { - if(!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.ARCHERY_SKILL_SHOT)) + if (!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.ARCHERY_SKILL_SHOT)) { return false; + } return Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.ARCHERY_SKILL_SHOT); } public boolean canRetrieveArrows() { - if(!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.ARCHERY_ARROW_RETRIEVAL)) + if (!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.ARCHERY_ARROW_RETRIEVAL)) { return false; + } return Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.ARCHERY_ARROW_RETRIEVAL); } @@ -53,22 +57,26 @@ public class ArcheryManager extends SkillManager { * @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)) + if (!arrow.hasMetadata(MetadataConstants.METADATA_KEY_ARROW_DISTANCE)) { return 1; + } - Location firedLocation = (Location) arrow.getMetadata(MetadataConstants.METADATA_KEY_ARROW_DISTANCE).get(0).value(); + Location firedLocation = (Location) arrow.getMetadata( + MetadataConstants.METADATA_KEY_ARROW_DISTANCE).get(0).value(); Location targetLocation = target.getLocation(); - if(firedLocation == null || firedLocation.getWorld() == null) + if (firedLocation == null || firedLocation.getWorld() == null) { return 1; + } if (firedLocation.getWorld() != targetLocation.getWorld()) { return 1; } - return 1 + Math.min(firedLocation.distance(targetLocation), 50) * Archery.DISTANCE_XP_MULTIPLIER; + return 1 + Math.min(firedLocation.distance(targetLocation), 50) + * Archery.DISTANCE_XP_MULTIPLIER; } /** @@ -77,9 +85,10 @@ public class ArcheryManager extends SkillManager { * @param target The {@link LivingEntity} damaged by the arrow */ public void retrieveArrows(LivingEntity target, Projectile projectile) { - if(projectile.hasMetadata(MetadataConstants.METADATA_KEY_TRACKED_ARROW)) { + if (projectile.hasMetadata(MetadataConstants.METADATA_KEY_TRACKED_ARROW)) { Archery.incrementTrackerValue(target); - projectile.removeMetadata(MetadataConstants.METADATA_KEY_TRACKED_ARROW, mcMMO.p); //Only 1 entity per projectile + projectile.removeMetadata(MetadataConstants.METADATA_KEY_TRACKED_ARROW, + mcMMO.p); //Only 1 entity per projectile } } @@ -89,24 +98,24 @@ public class ArcheryManager extends SkillManager { * @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 (!ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.ARCHERY_DAZE, mmoPlayer)) { return 0; } Location dazedLocation = defender.getLocation(); dazedLocation.setPitch(90 - Misc.getRandom().nextInt(181)); -// defender.teleport(dazedLocation); - mcMMO.p.getFoliaLib().getImpl().teleportAsync(defender, dazedLocation); - defender.addPotionEffect(new PotionEffect(PotionEffectType.CONFUSION, 20 * 10, 10)); - + mcMMO.p.getFoliaLib().getScheduler().teleportAsync(defender, dazedLocation); + defender.addPotionEffect(new PotionEffect(getNauseaPotionEffectType(), 20 * 10, 10)); if (NotificationManager.doesPlayerUseNotifications(defender)) { - NotificationManager.sendPlayerInformation(defender, NotificationType.SUBSKILL_MESSAGE, "Combat.TouchedFuzzy"); + NotificationManager.sendPlayerInformation(defender, NotificationType.SUBSKILL_MESSAGE, + "Combat.TouchedFuzzy"); } if (mmoPlayer.useChatNotifications()) { - NotificationManager.sendPlayerInformation(getPlayer(), NotificationType.SUBSKILL_MESSAGE, "Combat.TargetDazed"); + NotificationManager.sendPlayerInformation(getPlayer(), + NotificationType.SUBSKILL_MESSAGE, "Combat.TargetDazed"); } return Archery.dazeBonusDamage; @@ -118,10 +127,11 @@ public class ArcheryManager extends SkillManager { * @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 (ProbabilityUtil.isNonRNGSkillActivationSuccessful(SubSkillType.ARCHERY_SKILL_SHOT, + mmoPlayer)) { + return Archery.getSkillShotBonusDamage(getPlayer(), oldDamage); + } else { return oldDamage; } - - return Archery.getSkillShotBonusDamage(getPlayer(), oldDamage); } } diff --git a/src/main/java/com/gmail/nossr50/skills/archery/TrackedEntity.java b/src/main/java/com/gmail/nossr50/skills/archery/TrackedEntity.java index 613ddaf70..bc0a283f9 100644 --- a/src/main/java/com/gmail/nossr50/skills/archery/TrackedEntity.java +++ b/src/main/java/com/gmail/nossr50/skills/archery/TrackedEntity.java @@ -2,9 +2,8 @@ package com.gmail.nossr50.skills.archery; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.CancellableRunnable; -import org.bukkit.entity.LivingEntity; - import java.util.UUID; +import org.bukkit.entity.LivingEntity; public class TrackedEntity extends CancellableRunnable { private final LivingEntity livingEntity; @@ -15,7 +14,7 @@ public class TrackedEntity extends CancellableRunnable { this.livingEntity = livingEntity; this.id = livingEntity.getUniqueId(); - mcMMO.p.getFoliaLib().getImpl().runAtEntityTimer(livingEntity, this, 12000, 12000); + mcMMO.p.getFoliaLib().getScheduler().runAtEntityTimer(livingEntity, this, 12000, 12000); } @Override diff --git a/src/main/java/com/gmail/nossr50/skills/axes/Axes.java b/src/main/java/com/gmail/nossr50/skills/axes/Axes.java index 47d95be3f..a3fbfd7c3 100644 --- a/src/main/java/com/gmail/nossr50/skills/axes/Axes.java +++ b/src/main/java/com/gmail/nossr50/skills/axes/Axes.java @@ -9,26 +9,34 @@ import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; public class Axes { - public static double axeMasteryRankDamageMultiplier = mcMMO.p.getAdvancedConfig().getAxeMasteryRankDamageMultiplier(); + public static double axeMasteryRankDamageMultiplier = mcMMO.p.getAdvancedConfig() + .getAxeMasteryRankDamageMultiplier(); - public static double criticalHitPVPModifier = mcMMO.p.getAdvancedConfig().getCriticalStrikesPVPModifier(); - public static double criticalHitPVEModifier = mcMMO.p.getAdvancedConfig().getCriticalStrikesPVEModifier(); + public static double criticalHitPVPModifier = mcMMO.p.getAdvancedConfig() + .getCriticalStrikesPVPModifier(); + public static double criticalHitPVEModifier = mcMMO.p.getAdvancedConfig() + .getCriticalStrikesPVEModifier(); - public static double impactChance = mcMMO.p.getAdvancedConfig().getImpactChance(); + public static double impactChance = mcMMO.p.getAdvancedConfig().getImpactChance(); - public static double greaterImpactBonusDamage = mcMMO.p.getAdvancedConfig().getGreaterImpactBonusDamage(); - public static double greaterImpactChance = mcMMO.p.getAdvancedConfig().getGreaterImpactChance(); - public static double greaterImpactKnockbackMultiplier = mcMMO.p.getAdvancedConfig().getGreaterImpactModifier(); + public static double greaterImpactBonusDamage = mcMMO.p.getAdvancedConfig() + .getGreaterImpactBonusDamage(); + public static double greaterImpactChance = mcMMO.p.getAdvancedConfig().getGreaterImpactChance(); + public static double greaterImpactKnockbackMultiplier = mcMMO.p.getAdvancedConfig() + .getGreaterImpactModifier(); - public static double skullSplitterModifier = mcMMO.p.getAdvancedConfig().getSkullSplitterModifier(); + public static double skullSplitterModifier = mcMMO.p.getAdvancedConfig() + .getSkullSplitterModifier(); protected static boolean hasArmor(LivingEntity target) { - if(target == null || !target.isValid() || target.getEquipment() == null) + if (target == null || !target.isValid() || target.getEquipment() == null) { return false; + } for (ItemStack itemStack : target.getEquipment().getArmorContents()) { - if(itemStack == null) + if (itemStack == null) { continue; + } if (ItemUtils.isArmor(itemStack)) { return true; @@ -39,12 +47,14 @@ public class Axes { } /** - * For every rank in Axe Mastery we add RankDamageMultiplier to get the total bonus damage from Axe Mastery + * For every rank in Axe Mastery we add RankDamageMultiplier to get the total bonus damage from + * Axe Mastery + * * @param player The target player * @return The axe mastery bonus damage which will be added to their attack */ - public static double getAxeMasteryBonusDamage(Player player) - { - return RankUtils.getRank(player, SubSkillType.AXES_AXE_MASTERY) * Axes.axeMasteryRankDamageMultiplier; + public static double getAxeMasteryBonusDamage(Player player) { + return RankUtils.getRank(player, SubSkillType.AXES_AXE_MASTERY) + * Axes.axeMasteryRankDamageMultiplier; } } 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 d7ce592d8..61df4f015 100644 --- a/src/main/java/com/gmail/nossr50/skills/axes/AxesManager.java +++ b/src/main/java/com/gmail/nossr50/skills/axes/AxesManager.java @@ -1,5 +1,8 @@ package com.gmail.nossr50.skills.axes; +import static com.gmail.nossr50.util.random.ProbabilityUtil.isSkillRNGSuccessful; +import static com.gmail.nossr50.util.skills.SkillUtils.handleArmorDurabilityChange; + import com.gmail.nossr50.datatypes.interactions.NotificationType; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; @@ -11,66 +14,80 @@ import com.gmail.nossr50.skills.SkillManager; 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.*; +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; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; +import org.bukkit.inventory.EntityEquipment; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; public class AxesManager extends SkillManager { - public AxesManager(McMMOPlayer mcMMOPlayer) { - super(mcMMOPlayer, PrimarySkillType.AXES); + public AxesManager(McMMOPlayer mmoPlayer) { + super(mmoPlayer, PrimarySkillType.AXES); } public boolean canUseAxeMastery() { - if(!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.AXES_AXE_MASTERY)) + if (!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.AXES_AXE_MASTERY)) { return false; + } return Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.AXES_AXE_MASTERY); } public boolean canCriticalHit(@NotNull LivingEntity target) { - if(!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.AXES_CRITICAL_STRIKES)) + if (!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.AXES_CRITICAL_STRIKES)) { return false; + } - return target.isValid() && Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.AXES_CRITICAL_STRIKES); + return target.isValid() && Permissions.isSubSkillEnabled(getPlayer(), + SubSkillType.AXES_CRITICAL_STRIKES); } public boolean canImpact(@NotNull LivingEntity target) { - if(!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.AXES_ARMOR_IMPACT)) + if (!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.AXES_ARMOR_IMPACT)) { return false; + } - return target.isValid() && Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.AXES_ARMOR_IMPACT) && Axes.hasArmor(target); + return target.isValid() && Permissions.isSubSkillEnabled(getPlayer(), + SubSkillType.AXES_ARMOR_IMPACT) && Axes.hasArmor(target); } public boolean canGreaterImpact(@NotNull LivingEntity target) { - if(!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.AXES_GREATER_IMPACT)) + if (!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.AXES_GREATER_IMPACT)) { return false; + } - return target.isValid() && Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.AXES_GREATER_IMPACT) && !Axes.hasArmor(target); + return target.isValid() && Permissions.isSubSkillEnabled(getPlayer(), + SubSkillType.AXES_GREATER_IMPACT) && !Axes.hasArmor(target); } public boolean canUseSkullSplitter(@NotNull LivingEntity target) { - if(!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.AXES_SKULL_SPLITTER)) + if (!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.AXES_SKULL_SPLITTER)) { return false; + } - return target.isValid() && mmoPlayer.getAbilityMode(SuperAbilityType.SKULL_SPLITTER) && Permissions.skullSplitter(getPlayer()); + return target.isValid() && mmoPlayer.getAbilityMode(SuperAbilityType.SKULL_SPLITTER) + && Permissions.skullSplitter(getPlayer()); } public boolean canActivateAbility() { - return mmoPlayer.getToolPreparationMode(ToolType.AXE) && Permissions.skullSplitter(getPlayer()); + return mmoPlayer.getToolPreparationMode(ToolType.AXE) && Permissions.skullSplitter( + getPlayer()); } /** * Handle the effects of the Axe Mastery ability */ public double axeMastery() { - if (!RandomChanceUtil.isActivationSuccessful(SkillActivationType.ALWAYS_FIRES, SubSkillType.AXES_AXE_MASTERY, getPlayer())) { - return 0; + if (ProbabilityUtil.isNonRNGSkillActivationSuccessful(SubSkillType.AXES_AXE_MASTERY, + mmoPlayer)) { + return Axes.getAxeMasteryBonusDamage(getPlayer()); } - return Axes.getAxeMasteryBonusDamage(getPlayer()); + return 0; } /** @@ -80,25 +97,27 @@ public class AxesManager extends SkillManager { * @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 (!isSkillRNGSuccessful(SubSkillType.AXES_CRITICAL_STRIKES, mmoPlayer, + mmoPlayer.getAttackStrength())) { return 0; } Player player = getPlayer(); if (mmoPlayer.useChatNotifications()) { - NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE, "Axes.Combat.CriticalHit"); + NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE, + "Axes.Combat.CriticalHit"); } if (target instanceof Player defender) { if (NotificationManager.doesPlayerUseNotifications(defender)) { - NotificationManager.sendPlayerInformation(defender, NotificationType.SUBSKILL_MESSAGE, "Axes.Combat.CritStruck"); + NotificationManager.sendPlayerInformation(defender, + NotificationType.SUBSKILL_MESSAGE, "Axes.Combat.CritStruck"); } damage = (damage * Axes.criticalHitPVPModifier) - damage; - } - else { + } else { damage = (damage * Axes.criticalHitPVEModifier) - damage; } @@ -112,18 +131,25 @@ public class AxesManager extends SkillManager { */ public void impactCheck(@NotNull LivingEntity target) { double durabilityDamage = getImpactDurabilityDamage(); + final EntityEquipment equipment = target.getEquipment(); - for (ItemStack armor : target.getEquipment().getArmorContents()) { + if (equipment == null) { + return; + } + + for (ItemStack armor : equipment.getArmorContents()) { if (armor != null && ItemUtils.isArmor(armor)) { - if (RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_STATIC_CHANCE, SubSkillType.AXES_ARMOR_IMPACT, getPlayer())) { - SkillUtils.handleArmorDurabilityChange(armor, durabilityDamage, 1); + if (isSkillRNGSuccessful(SubSkillType.AXES_ARMOR_IMPACT, mmoPlayer, + mmoPlayer.getAttackStrength())) { + handleArmorDurabilityChange(armor, durabilityDamage, 1); } } } } public double getImpactDurabilityDamage() { - return mcMMO.p.getAdvancedConfig().getImpactDurabilityDamageMultiplier() * RankUtils.getRank(getPlayer(), SubSkillType.AXES_ARMOR_IMPACT); + return mcMMO.p.getAdvancedConfig().getImpactDurabilityDamageMultiplier() + * RankUtils.getRank(getPlayer(), SubSkillType.AXES_ARMOR_IMPACT); } /** @@ -132,24 +158,28 @@ public class AxesManager extends SkillManager { * @param target The {@link LivingEntity} being affected by the ability */ public double greaterImpact(@NotNull LivingEntity target) { - //static chance (3rd param) - if (!RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_STATIC_CHANCE, SubSkillType.AXES_GREATER_IMPACT, getPlayer())) { + if (!isSkillRNGSuccessful(SubSkillType.AXES_GREATER_IMPACT, mmoPlayer, + mmoPlayer.getAttackStrength())) { return 0; } Player player = getPlayer(); ParticleEffectUtils.playGreaterImpactEffect(target); - target.setVelocity(player.getLocation().getDirection().normalize().multiply(Axes.greaterImpactKnockbackMultiplier)); + target.setVelocity( + player.getLocation().getDirection().normalize() + .multiply(Axes.greaterImpactKnockbackMultiplier)); if (mmoPlayer.useChatNotifications()) { - NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE, "Axes.Combat.GI.Proc"); + NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE, + "Axes.Combat.GI.Proc"); } if (target instanceof Player defender) { if (NotificationManager.doesPlayerUseNotifications(defender)) { - NotificationManager.sendPlayerInformation(defender, NotificationType.SUBSKILL_MESSAGE, "Axes.Combat.GI.Struck"); + NotificationManager.sendPlayerInformation(defender, + NotificationType.SUBSKILL_MESSAGE, "Axes.Combat.GI.Struck"); } } @@ -158,10 +188,12 @@ public class AxesManager extends SkillManager { /** * Handle the effects of the Skull Splitter ability - * @param target The {@link LivingEntity} being affected by the ability + * + * @param target The {@link LivingEntity} being affected by the ability * @param damage The amount of damage initially dealt by the event */ public void skullSplitterCheck(@NotNull LivingEntity target, double damage) { - CombatUtils.applyAbilityAoE(getPlayer(), target, damage / Axes.skullSplitterModifier, skill); + CombatUtils.applyAbilityAoE(getPlayer(), target, + (damage / Axes.skullSplitterModifier) * mmoPlayer.getAttackStrength(), skill); } } 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 0e200bafa..000000000 --- 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 0be533600..000000000 --- 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/skills/crossbows/Crossbows.java b/src/main/java/com/gmail/nossr50/skills/crossbows/Crossbows.java new file mode 100644 index 000000000..867ecca7d --- /dev/null +++ b/src/main/java/com/gmail/nossr50/skills/crossbows/Crossbows.java @@ -0,0 +1,43 @@ +package com.gmail.nossr50.skills.crossbows; + +import static com.gmail.nossr50.util.skills.ProjectileUtils.getNormal; + +import com.gmail.nossr50.datatypes.player.McMMOPlayer; +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; + +/** + * 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) { + final 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) { + 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 new file mode 100644 index 000000000..41d079906 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/skills/crossbows/CrossbowsManager.java @@ -0,0 +1,143 @@ +package com.gmail.nossr50.skills.crossbows; + +import static com.gmail.nossr50.util.MetadataConstants.MCMMO_METADATA_VALUE; +import static com.gmail.nossr50.util.MetadataConstants.METADATA_KEY_CROSSBOW_PROJECTILE; +import static com.gmail.nossr50.util.skills.CombatUtils.delayArrowMetaCleanup; +import static com.gmail.nossr50.util.skills.ProjectileUtils.isCrossbowProjectile; + +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.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; +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 arrow, + @NotNull Vector hitBlockNormal) { + if (!isCrossbowProjectile(arrow)) { + return; + } + + // Check player permission + if (!Permissions.trickShot(mmoPlayer.getPlayer())) { + return; + } + + // TODO: Add an event for this for plugins to hook into + spawnReflectedArrow(pluginRef, arrow, arrow.getLocation(), hitBlockNormal); + } + + private 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))); + 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) { + return; + } + + // Spawn new arrow with the reflected direction + final Arrow spawnedArrow = originalArrow.getWorld() + .spawnArrow(origin, reflectedDirection, 1, 1); + // copy some properties from the old arrow + spawnedArrow.setShooter(originalArrowShooter); + spawnedArrow.setCritical(originalArrow.isCritical()); + spawnedArrow.setPierceLevel(originalArrow.getPierceLevel()); + spawnedArrow.setPickupStatus(originalArrow.getPickupStatus()); + spawnedArrow.setKnockbackStrength(originalArrow.getKnockbackStrength()); + + if (originalArrow.getBasePotionType() != null) { + spawnedArrow.setBasePotionType(originalArrow.getBasePotionType()); + } + + if (originalArrow.hasCustomEffects()) { + for (var effect : originalArrow.getCustomEffects()) { + spawnedArrow.addCustomEffect(effect, true); + } + } + + // copy metadata from old arrow + ProjectileUtils.copyArrowMetadata(pluginRef, originalArrow, spawnedArrow); + originalArrow.remove(); + // add important metadata to new arrow + spawnedArrow.setMetadata(MetadataConstants.METADATA_KEY_BOUNCE_COUNT, + new FixedMetadataValue(pluginRef, bounceCount + 1)); + spawnedArrow.setMetadata(MetadataConstants.METADATA_KEY_SPAWNED_ARROW, + new FixedMetadataValue(pluginRef, originalArrowShooter)); + // Easy fix to recognize the arrow as a crossbow projectile + // TODO: Replace the hack with the new API for setting weapon on projectiles + if (!spawnedArrow.hasMetadata(METADATA_KEY_CROSSBOW_PROJECTILE)) { + spawnedArrow.setMetadata(MetadataConstants.METADATA_KEY_CROSSBOW_PROJECTILE, + MCMMO_METADATA_VALUE); + } + // There are reasons to keep this despite using the metadata values above + spawnedArrow.setShotFromCrossbow(true); + + // 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() { + 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, + mmoPlayer)) { + return getPoweredShotBonusDamage(getPlayer(), oldDamage); + } else { + return oldDamage; + } + } +} diff --git a/src/main/java/com/gmail/nossr50/skills/excavation/Excavation.java b/src/main/java/com/gmail/nossr50/skills/excavation/Excavation.java index aa6209e80..47b69955b 100644 --- a/src/main/java/com/gmail/nossr50/skills/excavation/Excavation.java +++ b/src/main/java/com/gmail/nossr50/skills/excavation/Excavation.java @@ -1,37 +1,26 @@ package com.gmail.nossr50.skills.excavation; -import com.gmail.nossr50.config.experience.ExperienceConfig; -import com.gmail.nossr50.config.treasure.TreasureConfig; -import com.gmail.nossr50.datatypes.skills.PrimarySkillType; -import com.gmail.nossr50.datatypes.treasure.ExcavationTreasure; -import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.util.text.StringUtils; -import org.bukkit.block.BlockState; +import static com.gmail.nossr50.util.text.ConfigStringUtils.getMaterialConfigString; +import com.gmail.nossr50.config.treasure.TreasureConfig; +import com.gmail.nossr50.datatypes.treasure.ExcavationTreasure; import java.util.ArrayList; import java.util.List; +import org.bukkit.block.Block; public class Excavation { /** - * Get the list of possible {@link ExcavationTreasure|ExcavationTreasures} obtained from a given block. + * Get the list of possible {@link ExcavationTreasure|ExcavationTreasures} obtained from a given + * block. * - * @param blockState The {@link BlockState} of the block to check. + * @param block The {@link Block} to check for treasures * @return the list of treasures that could be found */ - protected static List getTreasures(BlockState blockState) { - String friendly = StringUtils.getFriendlyConfigBlockDataString(blockState.getBlockData()); - if (TreasureConfig.getInstance().excavationMap.containsKey(friendly)) + protected static List getTreasures(Block block) { + String friendly = getMaterialConfigString(block.getBlockData().getMaterial()); + if (TreasureConfig.getInstance().excavationMap.containsKey(friendly)) { return TreasureConfig.getInstance().excavationMap.get(friendly); + } return new ArrayList<>(); } - - protected static int getBlockXP(BlockState blockState) { - int xp = ExperienceConfig.getInstance().getXp(PrimarySkillType.EXCAVATION, blockState.getType()); - - if (xp == 0 && mcMMO.getModManager().isCustomExcavationBlock(blockState)) { - xp = mcMMO.getModManager().getBlock(blockState).getXpGain(); - } - - return xp; - } } 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 876634b46..e47f2b57e 100644 --- a/src/main/java/com/gmail/nossr50/skills/excavation/ExcavationManager.java +++ b/src/main/java/com/gmail/nossr50/skills/excavation/ExcavationManager.java @@ -1,27 +1,34 @@ package com.gmail.nossr50.skills.excavation; +import static java.util.Objects.requireNonNull; + import com.gmail.nossr50.api.ItemSpawnReason; +import com.gmail.nossr50.config.experience.ExperienceConfig; 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; import com.gmail.nossr50.datatypes.treasure.ExcavationTreasure; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.skills.SkillManager; +import com.gmail.nossr50.util.ItemUtils; import com.gmail.nossr50.util.Misc; import com.gmail.nossr50.util.Permissions; -import com.gmail.nossr50.util.random.RandomChanceUtil; +import com.gmail.nossr50.util.random.ProbabilityUtil; import com.gmail.nossr50.util.skills.RankUtils; import com.gmail.nossr50.util.skills.SkillUtils; +import java.util.List; import org.bukkit.Location; +import org.bukkit.block.Block; import org.bukkit.block.BlockState; import org.bukkit.entity.Player; - -import java.util.List; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.VisibleForTesting; public class ExcavationManager extends SkillManager { - public ExcavationManager(McMMOPlayer mcMMOPlayer) { - super(mcMMOPlayer, PrimarySkillType.EXCAVATION); + public ExcavationManager(McMMOPlayer mmoPlayer) { + super(mmoPlayer, PrimarySkillType.EXCAVATION); } /** @@ -29,33 +36,67 @@ public class ExcavationManager extends SkillManager { * * @param blockState The {@link BlockState} to check ability activation for */ + @Deprecated(forRemoval = true, since = "2.2.024") public void excavationBlockCheck(BlockState blockState) { - int xp = Excavation.getBlockXP(blockState); + excavationBlockCheck(blockState.getBlock()); + } + public void excavationBlockCheck(Block block) { + int xp = ExperienceConfig.getInstance().getXp(PrimarySkillType.EXCAVATION, block.getType()); + requireNonNull(block, "excavationBlockCheck: block cannot be null"); if (Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.EXCAVATION_ARCHAEOLOGY)) { - List treasures = Excavation.getTreasures(blockState); + List treasures = getTreasures(block); if (!treasures.isEmpty()) { int skillLevel = getSkillLevel(); - Location location = Misc.getBlockCenter(blockState); + final Location centerOfBlock = Misc.getBlockCenter(block); for (ExcavationTreasure treasure : treasures) { if (skillLevel >= treasure.getDropLevel() - && RandomChanceUtil.checkRandomChanceExecutionSuccess(getPlayer(), PrimarySkillType.EXCAVATION, treasure.getDropChance())) { - - //Spawn Vanilla XP orbs if a dice roll succeeds - if(RandomChanceUtil.rollDice(getArchaelogyExperienceOrbChance(), 100)) { - Misc.spawnExperienceOrb(location, getExperienceOrbsReward()); - } - - xp += treasure.getXp(); - Misc.spawnItem(getPlayer(), location, treasure.getDrop(), ItemSpawnReason.EXCAVATION_TREASURE); + && ProbabilityUtil.isStaticSkillRNGSuccessful( + PrimarySkillType.EXCAVATION, mmoPlayer, + treasure.getDropProbability())) { + processExcavationBonusesOnBlock(treasure, centerOfBlock); } } } } - applyXpGain(xp, XPGainReason.PVE); + applyXpGain(xp, XPGainReason.PVE, XPGainSource.SELF); + } + + @Deprecated(forRemoval = true, since = "2.2.024") + public List getTreasures(@NotNull BlockState blockState) { + requireNonNull(blockState, "blockState cannot be null"); + return getTreasures(blockState.getBlock()); + } + + public List getTreasures(@NotNull Block block) { + requireNonNull(block, "block cannot be null"); + return Excavation.getTreasures(block); + } + + @VisibleForTesting + @Deprecated(forRemoval = true, since = "2.2.024") + public void processExcavationBonusesOnBlock(BlockState ignored, ExcavationTreasure treasure, + Location location) { + processExcavationBonusesOnBlock(treasure, location); + } + + public void processExcavationBonusesOnBlock(ExcavationTreasure treasure, Location location) { + //Spawn Vanilla XP orbs if a dice roll succeeds + if (ProbabilityUtil.isStaticSkillRNGSuccessful( + PrimarySkillType.EXCAVATION, mmoPlayer, getArchaelogyExperienceOrbChance())) { + Misc.spawnExperienceOrb(location, getExperienceOrbsReward()); + } + + int xp = 0; + xp += treasure.getXp(); + ItemUtils.spawnItem(getPlayer(), location, treasure.getDrop(), + ItemSpawnReason.EXCAVATION_TREASURE); + if (xp > 0) { + applyXpGain(xp, XPGainReason.PVE, XPGainSource.SELF); + } } public int getExperienceOrbsReward() { @@ -70,18 +111,20 @@ public class ExcavationManager extends SkillManager { return RankUtils.getRank(getPlayer(), SubSkillType.EXCAVATION_ARCHAEOLOGY); } - public void printExcavationDebug(Player player, BlockState blockState) - { + public void printExcavationDebug(Player player, Block block) { if (Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.EXCAVATION_ARCHAEOLOGY)) { - List treasures = Excavation.getTreasures(blockState); + List treasures = Excavation.getTreasures(block); if (!treasures.isEmpty()) { for (ExcavationTreasure treasure : treasures) { player.sendMessage("|||||||||||||||||||||||||||||||||"); - player.sendMessage("[mcMMO DEBUG] Treasure found: ("+treasure.getDrop().getType().toString()+")"); - player.sendMessage("[mcMMO DEBUG] Drop Chance for Treasure: "+treasure.getDropChance()); - player.sendMessage("[mcMMO DEBUG] Skill Level Required: "+treasure.getDropLevel()); - player.sendMessage("[mcMMO DEBUG] XP for Treasure: "+treasure.getXp()); + player.sendMessage( + "[mcMMO DEBUG] Treasure found: (" + treasure.getDrop().getType() + ")"); + player.sendMessage( + "[mcMMO DEBUG] Drop Chance for Treasure: " + treasure.getDropChance()); + player.sendMessage( + "[mcMMO DEBUG] Skill Level Required: " + treasure.getDropLevel()); + player.sendMessage("[mcMMO DEBUG] XP for Treasure: " + treasure.getXp()); } } else { player.sendMessage("[mcMMO DEBUG] No treasures found for this block."); @@ -92,12 +135,13 @@ public class ExcavationManager extends SkillManager { /** * Process the Giga Drill Breaker ability. * - * @param blockState The {@link BlockState} to check ability activation for + * @param block The {@link Block} to check ability activation for */ - public void gigaDrillBreaker(BlockState blockState) { - excavationBlockCheck(blockState); - excavationBlockCheck(blockState); + public void gigaDrillBreaker(Block block) { + excavationBlockCheck(block); + excavationBlockCheck(block); - SkillUtils.handleDurabilityChange(getPlayer().getInventory().getItemInMainHand(), mcMMO.p.getGeneralConfig().getAbilityToolDamage()); + SkillUtils.handleDurabilityChange(getPlayer().getInventory().getItemInMainHand(), + mcMMO.p.getGeneralConfig().getAbilityToolDamage()); } } diff --git a/src/main/java/com/gmail/nossr50/skills/fishing/Fishing.java b/src/main/java/com/gmail/nossr50/skills/fishing/Fishing.java index 965b9c924..e4f752d56 100644 --- a/src/main/java/com/gmail/nossr50/skills/fishing/Fishing.java +++ b/src/main/java/com/gmail/nossr50/skills/fishing/Fishing.java @@ -3,36 +3,30 @@ package com.gmail.nossr50.skills.fishing; import com.gmail.nossr50.config.treasure.FishingTreasureConfig; import com.gmail.nossr50.datatypes.treasure.ShakeTreasure; import com.gmail.nossr50.util.Misc; -import com.gmail.nossr50.util.adapter.BiomeAdapter; +import java.util.HashMap; +import java.util.List; import org.bukkit.Material; -import org.bukkit.block.Biome; import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.LivingEntity; import org.bukkit.inventory.ItemStack; -import java.util.HashMap; -import java.util.List; -import java.util.Set; - public final class Fishing { - protected static final HashMap> ENCHANTABLE_CACHE = new HashMap<>(); + static final HashMap> ENCHANTABLE_CACHE = new HashMap<>(); - public static Set masterAnglerBiomes = BiomeAdapter.WATER_BIOMES; - public static Set iceFishingBiomes = BiomeAdapter.ICE_BIOMES; - - private Fishing() {} + private Fishing() { + } /** * Finds the possible drops of an entity * - * @param target - * Targeted entity + * @param target Targeted entity * @return possibleDrops List of ItemStack that can be dropped */ - protected static List findPossibleDrops(LivingEntity target) { - if (FishingTreasureConfig.getInstance().shakeMap.containsKey(target.getType())) + static List findPossibleDrops(LivingEntity target) { + if (FishingTreasureConfig.getInstance().shakeMap.containsKey(target.getType())) { return FishingTreasureConfig.getInstance().shakeMap.get(target.getType()); + } return null; } @@ -40,11 +34,10 @@ public final class Fishing { /** * Randomly chooses a drop among the list * - * @param possibleDrops - * List of ItemStack that can be dropped + * @param possibleDrops List of ItemStack that can be dropped * @return Chosen ItemStack */ - protected static ItemStack chooseDrop(List possibleDrops) { + static ItemStack chooseDrop(List possibleDrops) { int dropProbability = Misc.getRandom().nextInt(100); double cumulatedProbability = 0; 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 7f3767986..7a5845e81 100644 --- a/src/main/java/com/gmail/nossr50/skills/fishing/FishingManager.java +++ b/src/main/java/com/gmail/nossr50/skills/fishing/FishingManager.java @@ -8,29 +8,49 @@ import com.gmail.nossr50.datatypes.interactions.NotificationType; 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.treasure.*; +import com.gmail.nossr50.datatypes.treasure.EnchantmentTreasure; +import com.gmail.nossr50.datatypes.treasure.FishingTreasure; +import com.gmail.nossr50.datatypes.treasure.FishingTreasureBook; +import com.gmail.nossr50.datatypes.treasure.Rarity; +import com.gmail.nossr50.datatypes.treasure.ShakeTreasure; import com.gmail.nossr50.events.skills.fishing.McMMOPlayerFishingTreasureEvent; +import com.gmail.nossr50.events.skills.fishing.McMMOPlayerMasterAnglerEvent; import com.gmail.nossr50.events.skills.fishing.McMMOPlayerShakeEvent; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.runnables.skills.MasterAnglerTask; import com.gmail.nossr50.skills.SkillManager; -import com.gmail.nossr50.util.*; +import com.gmail.nossr50.util.BlockUtils; +import com.gmail.nossr50.util.EventUtils; +import com.gmail.nossr50.util.ItemUtils; +import com.gmail.nossr50.util.MetadataConstants; +import com.gmail.nossr50.util.Misc; +import com.gmail.nossr50.util.Permissions; +import com.gmail.nossr50.util.adapter.BiomeAdapter; 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.random.ProbabilityUtil; import com.gmail.nossr50.util.skills.CombatUtils; import com.gmail.nossr50.util.skills.RankUtils; import com.gmail.nossr50.util.skills.SkillUtils; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import org.bukkit.ChatColor; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.enchantments.Enchantment; -import org.bukkit.entity.*; -import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.entity.Boat; +import org.bukkit.entity.Entity; +import org.bukkit.entity.FishHook; +import org.bukkit.entity.Item; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.entity.Sheep; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.PlayerInventory; import org.bukkit.inventory.meta.SkullMeta; @@ -39,8 +59,6 @@ import org.bukkit.util.Vector; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.*; - public class FishingManager extends SkillManager { public static final int FISHING_ROD_CAST_CD_MILLISECONDS = 100; private final long FISHING_COOLDOWN_SECONDS = 1000L; @@ -48,39 +66,52 @@ public class FishingManager extends SkillManager { private long fishingRodCastTimestamp = 0L; private long fishHookSpawnTimestamp = 0L; private long lastWarned = 0L; - private long lastWarnedExhaust = 0L; + private final long lastWarnedExhaust = 0L; private FishHook fishHookReference; private BoundingBox lastFishingBoundingBox; private boolean sameTarget; private Item fishingCatch; private Location hookLocation; private int fishCaughtCounter = 1; + private final int masterAnglerMinWaitLowerBound; + private final int masterAnglerMaxWaitLowerBound; - public FishingManager(McMMOPlayer mcMMOPlayer) { - super(mcMMOPlayer, PrimarySkillType.FISHING); + public FishingManager(McMMOPlayer mmoPlayer) { + super(mmoPlayer, PrimarySkillType.FISHING); + //Ticks for minWait and maxWait never go below this value + int bonusCapMin = mcMMO.p.getAdvancedConfig().getFishingReductionMinWaitCap(); + int bonusCapMax = mcMMO.p.getAdvancedConfig().getFishingReductionMaxWaitCap(); + + this.masterAnglerMinWaitLowerBound = Math.max(bonusCapMin, 0); + this.masterAnglerMaxWaitLowerBound = Math.max(bonusCapMax, + masterAnglerMinWaitLowerBound + 40); } 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() // { // long currentTime = System.currentTimeMillis(); // //Only track spam casting if the fishing hook is fresh -// if(currentTime > fishHookSpawnTimestamp + 1000) +// if (currentTime > fishHookSpawnTimestamp + 1000) // return; // -// if(currentTime < fishingRodCastTimestamp + FISHING_ROD_CAST_CD_MILLISECONDS) +// if (currentTime < fishingRodCastTimestamp + FISHING_ROD_CAST_CD_MILLISECONDS) // { // ItemStack fishingRod = getPlayer().getInventory().getItemInMainHand(); // // //Ensure correct hand item is damaged -// if(fishingRod.getType() != Material.FISHING_ROD) { +// if (fishingRod.getType() != Material.FISHING_ROD) { // fishingRod = getPlayer().getInventory().getItemInOffHand(); // } // @@ -88,7 +119,7 @@ public class FishingManager extends SkillManager { // fishingRod.setDurability((short) (fishingRod.getDurability() + 5)); // getPlayer().updateInventory(); // -// if(lastWarnedExhaust + (1000) < currentTime) +// if (lastWarnedExhaust + (1000) < currentTime) // { // getPlayer().sendMessage(LocaleLoader.getString("Fishing.Exhausting")); // lastWarnedExhaust = currentTime; @@ -99,26 +130,25 @@ public class FishingManager extends SkillManager { // fishingRodCastTimestamp = System.currentTimeMillis(); // } - public void setFishHookReference(FishHook fishHook) - { - if(fishHook.getMetadata(MetadataConstants.METADATA_KEY_FISH_HOOK_REF).size() > 0) + public void setFishHookReference(FishHook fishHook) { + if (fishHook.getMetadata(MetadataConstants.METADATA_KEY_FISH_HOOK_REF).size() > 0) { return; + } - fishHook.setMetadata(MetadataConstants.METADATA_KEY_FISH_HOOK_REF, MetadataConstants.MCMMO_METADATA_VALUE); + fishHook.setMetadata(MetadataConstants.METADATA_KEY_FISH_HOOK_REF, + MetadataConstants.MCMMO_METADATA_VALUE); this.fishHookReference = fishHook; fishHookSpawnTimestamp = System.currentTimeMillis(); fishingRodCastTimestamp = System.currentTimeMillis(); } - public boolean isFishingTooOften() - { + public boolean isFishingTooOften() { long currentTime = System.currentTimeMillis(); long fishHookSpawnCD = fishHookSpawnTimestamp + 1000; boolean hasFished = (currentTime < fishHookSpawnCD); - if(hasFished && (lastWarned + (1000) < currentTime)) - { + if (hasFished && (lastWarned + (1000) < currentTime)) { getPlayer().sendMessage(LocaleLoader.getString("Fishing.Scared")); lastWarned = System.currentTimeMillis(); } @@ -128,20 +158,24 @@ public class FishingManager extends SkillManager { public void processExploiting(Vector centerOfCastVector) { BoundingBox newCastBoundingBox = makeBoundingBox(centerOfCastVector); - this.sameTarget = lastFishingBoundingBox != null && lastFishingBoundingBox.overlaps(newCastBoundingBox); + this.sameTarget = lastFishingBoundingBox != null && lastFishingBoundingBox.overlaps( + newCastBoundingBox); if (this.sameTarget) { fishCaughtCounter++; - } - else { + } else { fishCaughtCounter = 1; } //If the new bounding box does not intersect with the old one, then update our bounding box reference - if (!this.sameTarget) lastFishingBoundingBox = newCastBoundingBox; + if (!this.sameTarget) { + lastFishingBoundingBox = newCastBoundingBox; + } - if (fishCaughtCounter + 1 == ExperienceConfig.getInstance().getFishingExploitingOptionOverFishLimit()) { - getPlayer().sendMessage(LocaleLoader.getString("Fishing.LowResourcesTip", ExperienceConfig.getInstance().getFishingExploitingOptionMoveRange())); + if (fishCaughtCounter + 1 == ExperienceConfig.getInstance() + .getFishingExploitingOptionOverFishLimit()) { + getPlayer().sendMessage(LocaleLoader.getString("Fishing.LowResourcesTip", + ExperienceConfig.getInstance().getFishingExploitingOptionMoveRange())); } } @@ -153,7 +187,8 @@ public class FishingManager extends SkillManager { return false; }*/ - return this.sameTarget && fishCaughtCounter >= ExperienceConfig.getInstance().getFishingExploitingOptionOverFishLimit(); + return this.sameTarget && fishCaughtCounter >= ExperienceConfig.getInstance() + .getFishingExploitingOptionOverFishLimit(); } public static BoundingBox makeBoundingBox(Vector centerOfCastVector) { @@ -175,7 +210,8 @@ public class FishingManager extends SkillManager { } // Make sure this is a body of water, not just a block of ice. - if (!Fishing.iceFishingBiomes.contains(block.getBiome()) && (block.getRelative(BlockFace.DOWN, 3).getType() != Material.WATER)) { + if (!BiomeAdapter.ICE_BIOMES.contains(block.getBiome()) + && (block.getRelative(BlockFace.DOWN, 3).getType() != Material.WATER)) { return false; } @@ -198,7 +234,8 @@ public class FishingManager extends SkillManager { } public double getShakeChance() { - return mcMMO.p.getAdvancedConfig().getShakeChance(RankUtils.getRank(mmoPlayer.getPlayer(), SubSkillType.FISHING_SHAKE)); + return mcMMO.p.getAdvancedConfig().getShakeChance( + RankUtils.getRank(mmoPlayer.getPlayer(), SubSkillType.FISHING_SHAKE)); } protected int getVanillaXPBoostModifier() { @@ -218,11 +255,11 @@ public class FishingManager extends SkillManager { * Handle the Fisherman's Diet ability * * @param eventFoodLevel The initial change in hunger from the event - * * @return the modified change in hunger for the event */ public int handleFishermanDiet(int eventFoodLevel) { - return SkillUtils.handleFoodSkills(getPlayer(), eventFoodLevel, SubSkillType.FISHING_FISHERMANS_DIET); + return SkillUtils.handleFoodSkills(getPlayer(), eventFoodLevel, + SubSkillType.FISHING_FISHERMANS_DIET); } public void iceFishing(FishHook hook, Block block) { @@ -244,18 +281,21 @@ public class FishingManager extends SkillManager { } public void masterAngler(@NotNull FishHook hook, int lureLevel) { - mcMMO.p.getFoliaLib().getImpl().runAtEntityLater(hook, new MasterAnglerTask(hook, this, lureLevel), 1); //We run later to get the lure bonus applied + mcMMO.p.getFoliaLib().getScheduler() + .runAtEntityLater(hook, new MasterAnglerTask(hook, this, lureLevel), + 1); //We run later to get the lure bonus applied } /** - * Processes master angler - * Reduced tick time on fish hook, etc + * Processes master angler Reduced tick time on fish hook, etc + * * @param fishHook target fish hook */ public void processMasterAngler(@NotNull FishHook fishHook, int lureLevel) { - MasterAnglerCompatibilityLayer masterAnglerCompatibilityLayer = (MasterAnglerCompatibilityLayer) mcMMO.getCompatibilityManager().getMasterAnglerCompatibilityLayer(); + MasterAnglerCompatibilityLayer masterAnglerCompatibilityLayer = (MasterAnglerCompatibilityLayer) mcMMO.getCompatibilityManager() + .getMasterAnglerCompatibilityLayer(); - if(masterAnglerCompatibilityLayer != null) { + if (masterAnglerCompatibilityLayer != null) { int maxWaitTicks = masterAnglerCompatibilityLayer.getMaxWaitTime(fishHook); int minWaitTicks = masterAnglerCompatibilityLayer.getMinWaitTime(fishHook); @@ -263,63 +303,85 @@ public class FishingManager extends SkillManager { int convertedLureBonus = 0; //This avoids a Minecraft bug where lure levels above 3 break fishing - if(lureLevel > 0) { + if (lureLevel > 0) { masterAnglerCompatibilityLayer.setApplyLure(fishHook, false); convertedLureBonus = lureLevel * 100; } boolean boatBonus = isInBoat(); int minWaitReduction = getMasterAnglerTickMinWaitReduction(masterAnglerRank, boatBonus); - int maxWaitReduction = getMasterAnglerTickMaxWaitReduction(masterAnglerRank, boatBonus, convertedLureBonus); + int maxWaitReduction = getMasterAnglerTickMaxWaitReduction(masterAnglerRank, boatBonus, + convertedLureBonus); - //Ticks for minWait and maxWait never go below this value - int bonusCapMin = mcMMO.p.getAdvancedConfig().getFishingReductionMinWaitCap(); - int bonusCapMax = mcMMO.p.getAdvancedConfig().getFishingReductionMaxWaitCap(); - - int reducedMinWaitTime = getReducedTicks(minWaitTicks, minWaitReduction, bonusCapMin); - int reducedMaxWaitTime = getReducedTicks(maxWaitTicks, maxWaitReduction, bonusCapMax); + int reducedMinWaitTime = getReducedTicks(minWaitTicks, minWaitReduction, + masterAnglerMinWaitLowerBound); + int reducedMaxWaitTime = getReducedTicks(maxWaitTicks, maxWaitReduction, + masterAnglerMaxWaitLowerBound); boolean badValuesFix = false; //If we find bad values correct it - if(reducedMaxWaitTime < reducedMinWaitTime) { + if (reducedMaxWaitTime < reducedMinWaitTime) { reducedMaxWaitTime = reducedMinWaitTime + 100; badValuesFix = true; } - if(mmoPlayer.isDebugMode()) { + final McMMOPlayerMasterAnglerEvent event = + new McMMOPlayerMasterAnglerEvent(mmoPlayer, reducedMinWaitTime, + reducedMaxWaitTime, this); + mcMMO.p.getServer().getPluginManager().callEvent(event); + + if (event.isCancelled()) { + return; + } + + reducedMaxWaitTime = event.getReducedMaxWaitTime(); + reducedMinWaitTime = event.getReducedMinWaitTime(); + + if (mmoPlayer.isDebugMode()) { mmoPlayer.getPlayer().sendMessage(ChatColor.GOLD + "Master Angler Debug"); - if(badValuesFix) { - mmoPlayer.getPlayer().sendMessage(ChatColor.RED + "Bad values were applied and corrected, check your configs, max wait should never be lower than min wait."); + if (badValuesFix) { + mmoPlayer.getPlayer() + .sendMessage(ChatColor.RED + "Bad values were applied and corrected," + + " check your configs, minWaitLowerBound wait should never be lower than min wait."); } - mmoPlayer.getPlayer().sendMessage("ALLOW STACK WITH LURE: " + masterAnglerCompatibilityLayer.getApplyLure(fishHook)); + mmoPlayer.getPlayer().sendMessage( + "ALLOW STACK WITH LURE: " + masterAnglerCompatibilityLayer.getApplyLure( + fishHook)); mmoPlayer.getPlayer().sendMessage("MIN TICK REDUCTION: " + minWaitReduction); mmoPlayer.getPlayer().sendMessage("MAX TICK REDUCTION: " + maxWaitReduction); mmoPlayer.getPlayer().sendMessage("BOAT BONUS: " + boatBonus); - if(boatBonus) { - mmoPlayer.getPlayer().sendMessage("BOAT MAX TICK REDUCTION: " + maxWaitReduction); - mmoPlayer.getPlayer().sendMessage("BOAT MIN TICK REDUCTION: " + maxWaitReduction); + if (boatBonus) { + mmoPlayer.getPlayer() + .sendMessage("BOAT MAX TICK REDUCTION: " + maxWaitReduction); + mmoPlayer.getPlayer() + .sendMessage("BOAT MIN TICK REDUCTION: " + maxWaitReduction); } mmoPlayer.getPlayer().sendMessage(""); - mmoPlayer.getPlayer().sendMessage(ChatColor.DARK_AQUA + "BEFORE MASTER ANGLER WAS APPLIED"); + mmoPlayer.getPlayer() + .sendMessage(ChatColor.DARK_AQUA + "BEFORE MASTER ANGLER WAS APPLIED"); mmoPlayer.getPlayer().sendMessage("Original Max Wait Ticks: " + maxWaitTicks); mmoPlayer.getPlayer().sendMessage("Original Min Wait Ticks: " + minWaitTicks); mmoPlayer.getPlayer().sendMessage(""); - mmoPlayer.getPlayer().sendMessage(ChatColor.DARK_AQUA + "AFTER MASTER ANGLER WAS APPLIED"); + mmoPlayer.getPlayer() + .sendMessage(ChatColor.DARK_AQUA + "AFTER MASTER ANGLER WAS APPLIED"); mmoPlayer.getPlayer().sendMessage("Current Max Wait Ticks: " + reducedMaxWaitTime); mmoPlayer.getPlayer().sendMessage("Current Min Wait Ticks: " + reducedMinWaitTime); mmoPlayer.getPlayer().sendMessage(""); - mmoPlayer.getPlayer().sendMessage(ChatColor.DARK_AQUA + "Caps / Limits (edit in advanced.yml)"); - mmoPlayer.getPlayer().sendMessage("Lowest possible max wait ticks " + bonusCapMax); - mmoPlayer.getPlayer().sendMessage("Lowest possible min wait ticks " + bonusCapMin); + mmoPlayer.getPlayer() + .sendMessage(ChatColor.DARK_AQUA + "Caps / Limits (edit in advanced.yml)"); + mmoPlayer.getPlayer().sendMessage("Lowest possible minWaitLowerBound wait ticks " + + masterAnglerMinWaitLowerBound); + mmoPlayer.getPlayer().sendMessage( + "Lowest possible min wait ticks " + masterAnglerMaxWaitLowerBound); } masterAnglerCompatibilityLayer.setMaxWaitTime(fishHook, reducedMaxWaitTime); @@ -333,13 +395,16 @@ public class FishingManager extends SkillManager { } public boolean isInBoat() { - return mmoPlayer.getPlayer().isInsideVehicle() && mmoPlayer.getPlayer().getVehicle() instanceof Boat; + return mmoPlayer.getPlayer().isInsideVehicle() && mmoPlayer.getPlayer() + .getVehicle() instanceof Boat; } - public int getMasterAnglerTickMaxWaitReduction(int masterAnglerRank, boolean boatBonus, int emulatedLureBonus) { - int totalBonus = mcMMO.p.getAdvancedConfig().getFishingReductionMaxWaitTicks() * masterAnglerRank; + public int getMasterAnglerTickMaxWaitReduction(int masterAnglerRank, boolean boatBonus, + int emulatedLureBonus) { + int totalBonus = + mcMMO.p.getAdvancedConfig().getFishingReductionMaxWaitTicks() * masterAnglerRank; - if(boatBonus) { + if (boatBonus) { totalBonus += getFishingBoatMaxWaitReduction(); } @@ -349,9 +414,10 @@ public class FishingManager extends SkillManager { } public int getMasterAnglerTickMinWaitReduction(int masterAnglerRank, boolean boatBonus) { - int totalBonus = mcMMO.p.getAdvancedConfig().getFishingReductionMinWaitTicks() * masterAnglerRank; + int totalBonus = + mcMMO.p.getAdvancedConfig().getFishingReductionMinWaitTicks() * masterAnglerRank; - if(boatBonus) { + if (boatBonus) { totalBonus += getFishingBoatMinWaitReduction(); } @@ -379,20 +445,22 @@ public class FishingManager extends SkillManager { */ public void processFishing(@NotNull Item fishingCatch) { this.fishingCatch = fishingCatch; - int fishXp = ExperienceConfig.getInstance().getXp(PrimarySkillType.FISHING, fishingCatch.getItemStack().getType()); + int fishXp = ExperienceConfig.getInstance() + .getXp(PrimarySkillType.FISHING, fishingCatch.getItemStack().getType()); int treasureXp = 0; ItemStack treasureDrop = null; Player player = getPlayer(); FishingTreasure treasure = null; boolean fishingSucceeds = false; - if (mcMMO.p.getGeneralConfig().getFishingDropsEnabled() && Permissions.isSubSkillEnabled(player, SubSkillType.FISHING_TREASURE_HUNTER)) { + if (mcMMO.p.getGeneralConfig().getFishingDropsEnabled() && Permissions.isSubSkillEnabled( + player, SubSkillType.FISHING_TREASURE_HUNTER)) { treasure = getFishingTreasure(); this.fishingCatch = null; } if (treasure != null) { - if(treasure instanceof FishingTreasureBook) { + if (treasure instanceof FishingTreasureBook) { treasureDrop = ItemUtils.createEnchantBook((FishingTreasureBook) treasure); } else { treasureDrop = treasure.getDrop().clone(); // Not cloning is bad, m'kay? @@ -404,19 +472,21 @@ public class FishingManager extends SkillManager { /* * Books get some special treatment */ - if(treasure instanceof FishingTreasureBook) { + if (treasure instanceof FishingTreasureBook) { //Skip the magic hunter stuff - if(treasureDrop.getItemMeta() != null) { + if (treasureDrop.getItemMeta() != null) { enchants.putAll(treasureDrop.getItemMeta().getEnchants()); } - event = EventUtils.callFishingTreasureEvent(player, treasureDrop, treasure.getXp(), enchants); + event = EventUtils.callFishingTreasureEvent(mmoPlayer, treasureDrop, + treasure.getXp(), enchants); } else { if (isMagicHunterEnabled() && ItemUtils.isEnchantable(treasureDrop)) { enchants = processMagicHunter(treasureDrop); } - event = EventUtils.callFishingTreasureEvent(player, treasureDrop, treasure.getXp(), enchants); + event = EventUtils.callFishingTreasureEvent(mmoPlayer, treasureDrop, + treasure.getXp(), enchants); } if (!event.isCancelled()) { @@ -428,7 +498,7 @@ public class FishingManager extends SkillManager { fishingSucceeds = true; boolean enchanted = false; - if(treasure instanceof FishingTreasureBook) { + if (treasure instanceof FishingTreasureBook) { enchanted = true; } else if (!enchants.isEmpty()) { treasureDrop.addUnsafeEnchantments(enchants); @@ -436,7 +506,8 @@ public class FishingManager extends SkillManager { } if (enchanted) { - NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE, "Fishing.Ability.TH.MagicFound"); + NotificationManager.sendPlayerInformation(player, + NotificationType.SUBSKILL_MESSAGE, "Fishing.Ability.TH.MagicFound"); } } @@ -446,9 +517,10 @@ public class FishingManager extends SkillManager { } } - if(fishingSucceeds) { + if (fishingSucceeds) { if (mcMMO.p.getGeneralConfig().getFishingExtraFish()) { - Misc.spawnItem(getPlayer(), player.getEyeLocation(), fishingCatch.getItemStack(), ItemSpawnReason.FISHING_EXTRA_FISH); + ItemUtils.spawnItem(getPlayer(), player.getEyeLocation(), + fishingCatch.getItemStack(), ItemSpawnReason.FISHING_EXTRA_FISH); } fishingCatch.setItemStack(treasureDrop); @@ -461,7 +533,6 @@ public class FishingManager extends SkillManager { * Handle the vanilla XP boost for Fishing * * @param experience The amount of experience initially awarded by the event - * * @return the modified event damage */ public int handleVanillaXpBoost(int experience) { @@ -477,8 +548,9 @@ public class FishingManager extends SkillManager { * * @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 (ProbabilityUtil.isStaticSkillRNGSuccessful(PrimarySkillType.FISHING, mmoPlayer, + getShakeChance())) { List possibleDrops = Fishing.findPossibleDrops(target); if (possibleDrops == null || possibleDrops.isEmpty()) { @@ -518,9 +590,10 @@ public class FishingManager extends SkillManager { if (FishingTreasureConfig.getInstance().getInventoryStealStacks()) { inventory.setItem(slot, null); - } - else { - inventory.setItem(slot, (drop.getAmount() > 1) ? new ItemStack(drop.getType(), drop.getAmount() - 1) : null); + } else { + inventory.setItem(slot, + (drop.getAmount() > 1) ? new ItemStack(drop.getType(), + drop.getAmount() - 1) : null); drop.setAmount(1); } @@ -555,8 +628,11 @@ public class FishingManager extends SkillManager { return; } - Misc.spawnItem(getPlayer(), target.getLocation(), drop, ItemSpawnReason.FISHING_SHAKE_TREASURE); - CombatUtils.dealDamage(target, Math.min(Math.max(target.getMaxHealth() / 4, 1), 10), EntityDamageEvent.DamageCause.CUSTOM, getPlayer()); // Make it so you can shake a mob no more than 4 times. + ItemUtils.spawnItem(getPlayer(), target.getLocation(), drop, + ItemSpawnReason.FISHING_SHAKE_TREASURE); + // Make it so you can shake a mob no more than 4 times. + double dmg = Math.min(Math.max(target.getMaxHealth() / 4, 1), 10); + CombatUtils.safeDealDamage(target, dmg, getPlayer()); applyXpGain(ExperienceConfig.getInstance().getFishingShakeXP(), XPGainReason.PVE); } } @@ -571,11 +647,12 @@ public class FishingManager extends SkillManager { int luck; if (getPlayer().getInventory().getItemInMainHand().getType() == Material.FISHING_ROD) { - luck = getPlayer().getInventory().getItemInMainHand().getEnchantmentLevel(Enchantment.LUCK); - } - else { + luck = getPlayer().getInventory().getItemInMainHand().getEnchantmentLevel( + mcMMO.p.getEnchantmentMapper().getLuckOfTheSea()); + } else { // We know something was caught, so if the rod wasn't in the main hand it must be in the offhand - luck = getPlayer().getInventory().getItemInOffHand().getEnchantmentLevel(Enchantment.LUCK); + luck = getPlayer().getInventory().getItemInOffHand().getEnchantmentLevel( + mcMMO.p.getEnchantmentMapper().getLuckOfTheSea()); } // Rather than subtracting luck (and causing a minimum 3% chance for every drop), scale by luck. @@ -584,11 +661,13 @@ public class FishingManager extends SkillManager { FishingTreasure treasure = null; for (Rarity rarity : Rarity.values()) { - double dropRate = FishingTreasureConfig.getInstance().getItemDropRate(getLootTier(), rarity); + double dropRate = FishingTreasureConfig.getInstance() + .getItemDropRate(getLootTier(), rarity); if (diceRoll <= dropRate) { - List fishingTreasures = FishingTreasureConfig.getInstance().fishingRewards.get(rarity); + List fishingTreasures = FishingTreasureConfig.getInstance().fishingRewards.get( + rarity); if (fishingTreasures.isEmpty()) { return null; @@ -635,7 +714,8 @@ public class FishingManager extends SkillManager { for (Rarity rarity : Rarity.values()) { - double dropRate = FishingTreasureConfig.getInstance().getEnchantmentDropRate(getLootTier(), rarity); + double dropRate = FishingTreasureConfig.getInstance() + .getEnchantmentDropRate(getLootTier(), rarity); if (diceRoll <= dropRate) { // Make sure enchanted books always get some kind of enchantment. --hoorigan @@ -644,7 +724,8 @@ public class FishingManager extends SkillManager { continue; } - fishingEnchantments = FishingTreasureConfig.getInstance().fishingEnchantments.get(rarity); + fishingEnchantments = FishingTreasureConfig.getInstance().fishingEnchantments.get( + rarity); break; } @@ -676,7 +757,8 @@ public class FishingManager extends SkillManager { for (EnchantmentTreasure enchantmentTreasure : possibleEnchants) { Enchantment possibleEnchantment = enchantmentTreasure.getEnchantment(); - if (treasureDrop.getItemMeta().hasConflictingEnchant(possibleEnchantment) || Misc.getRandom().nextInt(specificChance) != 0) { + if (treasureDrop.getItemMeta().hasConflictingEnchant(possibleEnchantment) + || Misc.getRandom().nextInt(specificChance) != 0) { continue; } @@ -715,4 +797,12 @@ public class FishingManager extends SkillManager { private int getVanillaXpMultiplier() { return getVanillaXPBoostModifier(); } + + public int getMasterAnglerMinWaitLowerBound() { + return masterAnglerMinWaitLowerBound; + } + + public int getMasterAnglerMaxWaitLowerBound() { + return masterAnglerMaxWaitLowerBound; + } } \ No newline at end of file diff --git a/src/main/java/com/gmail/nossr50/skills/herbalism/Herbalism.java b/src/main/java/com/gmail/nossr50/skills/herbalism/Herbalism.java index 00c05d20e..452219280 100644 --- a/src/main/java/com/gmail/nossr50/skills/herbalism/Herbalism.java +++ b/src/main/java/com/gmail/nossr50/skills/herbalism/Herbalism.java @@ -9,7 +9,6 @@ public class Herbalism { * Convert blocks affected by the Green Thumb & Green Terra abilities. * * @param blockState The {@link BlockState} to check ability activation for - * * @return true if the ability was successful, false otherwise */ protected static boolean convertGreenTerraBlocks(BlockState blockState) { @@ -40,7 +39,6 @@ public class Herbalism { * Convert blocks affected by the Green Thumb & Green Terra abilities. * * @param blockState The {@link BlockState} to check ability activation for - * * @return true if the ability was successful, false otherwise */ protected static boolean convertShroomThumb(BlockState blockState) { 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 d97b12db8..30314b5a7 100644 --- a/src/main/java/com/gmail/nossr50/skills/herbalism/HerbalismManager.java +++ b/src/main/java/com/gmail/nossr50/skills/herbalism/HerbalismManager.java @@ -1,5 +1,11 @@ package com.gmail.nossr50.skills.herbalism; +import static com.gmail.nossr50.util.ItemUtils.hasItemIncludingOffHand; +import static com.gmail.nossr50.util.ItemUtils.removeItemIncludingOffHand; +import static com.gmail.nossr50.util.Misc.getBlockCenter; +import static com.gmail.nossr50.util.text.ConfigStringUtils.getMaterialConfigString; +import static java.util.Objects.requireNonNull; + import com.gmail.nossr50.api.ItemSpawnReason; import com.gmail.nossr50.config.experience.ExperienceConfig; import com.gmail.nossr50.config.treasure.TreasureConfig; @@ -18,16 +24,27 @@ import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.runnables.skills.DelayedCropReplant; import com.gmail.nossr50.runnables.skills.DelayedHerbalismXPCheckTask; import com.gmail.nossr50.skills.SkillManager; -import com.gmail.nossr50.util.*; +import com.gmail.nossr50.util.BlockUtils; +import com.gmail.nossr50.util.CancellableRunnable; +import com.gmail.nossr50.util.EventUtils; +import com.gmail.nossr50.util.ItemUtils; +import com.gmail.nossr50.util.MetadataConstants; +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.random.ProbabilityUtil; 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; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Locale; +import java.util.Set; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Block; @@ -41,30 +58,48 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.PlayerInventory; import org.jetbrains.annotations.NotNull; -import java.util.*; - public class HerbalismManager extends SkillManager { - public HerbalismManager(McMMOPlayer mcMMOPlayer) { - super(mcMMOPlayer, PrimarySkillType.HERBALISM); + private final static HashMap plantBreakLimits; + + private static final String CACTUS_STR = "cactus"; + private static final String CACTUS_FLOWER_STR = "cactus_flower"; + + static { + plantBreakLimits = new HashMap<>(); + plantBreakLimits.put(CACTUS_STR, 3); + plantBreakLimits.put("bamboo", 20); + plantBreakLimits.put("sugar_cane", 3); + plantBreakLimits.put("kelp", 26); + plantBreakLimits.put("kelp_plant", 26); + plantBreakLimits.put("chorus_plant", 22); + } + + public HerbalismManager(McMMOPlayer mmoPlayer) { + super(mmoPlayer, PrimarySkillType.HERBALISM); } public boolean canGreenThumbBlock(BlockState blockState) { - if(!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.HERBALISM_GREEN_THUMB)) - return false; - - Player player = getPlayer(); - ItemStack item = player.getInventory().getItemInMainHand(); - - return item.getAmount() > 0 && item.getType() == Material.WHEAT_SEEDS && BlockUtils.canMakeMossy(blockState) && Permissions.greenThumbBlock(player, blockState.getType()); - } - - public boolean canUseShroomThumb(BlockState blockState) { - if(!BlockUtils.canMakeShroomy(blockState)) { + if (!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.HERBALISM_GREEN_THUMB)) { return false; } - if(!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.HERBALISM_SHROOM_THUMB)) + final Player player = getPlayer(); + final ItemStack item = player.getInventory().getItemInMainHand(); + + return item.getAmount() > 0 + && item.getType() == Material.WHEAT_SEEDS + && BlockUtils.canMakeMossy(blockState.getBlock()) + && Permissions.greenThumbBlock(player, blockState.getType()); + } + + public boolean canUseShroomThumb(BlockState blockState) { + if (!BlockUtils.canMakeShroomy(blockState)) { return false; + } + + if (!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.HERBALISM_SHROOM_THUMB)) { + return false; + } Player player = getPlayer(); PlayerInventory inventory = player.getInventory(); @@ -79,34 +114,38 @@ public class HerbalismManager extends SkillManager { public void processBerryBushHarvesting(@NotNull BlockState blockState) { /* Check if the player is harvesting a berry bush */ - if(blockState.getType().toString().equalsIgnoreCase("sweet_berry_bush")) { - if(mmoPlayer.isDebugMode()) { + if (blockState.getType().toString().equalsIgnoreCase("sweet_berry_bush")) { + if (mmoPlayer.isDebugMode()) { mmoPlayer.getPlayer().sendMessage("Processing sweet berry bush rewards"); } //Check the age - if(blockState.getBlockData() instanceof Ageable ageable) { + if (blockState.getBlockData() instanceof Ageable ageable) { int rewardByAge = 0; - if(ageable.getAge() == 2) { + if (ageable.getAge() == 2) { rewardByAge = 1; //Normal XP - } else if(ageable.getAge() == 3) { + } else if (ageable.getAge() == 3) { rewardByAge = 2; //Double XP } else { return; //Not old enough, back out of processing } - if(mmoPlayer.isDebugMode()) { + if (mmoPlayer.isDebugMode()) { mmoPlayer.getPlayer().sendMessage("Bush Reward Multiplier: " + rewardByAge); } - int xpReward = ExperienceConfig.getInstance().getXp(PrimarySkillType.HERBALISM, blockState) * rewardByAge; + int xpReward = ExperienceConfig.getInstance() + .getXp(PrimarySkillType.HERBALISM, blockState.getType()) + * rewardByAge; - if(mmoPlayer.isDebugMode()) { + if (mmoPlayer.isDebugMode()) { mmoPlayer.getPlayer().sendMessage("Bush XP: " + xpReward); } - CheckBushAge checkBushAge = new CheckBushAge(blockState.getBlock(), mmoPlayer, xpReward); - mcMMO.p.getFoliaLib().getImpl().runAtLocationLater(blockState.getLocation(), checkBushAge, 1); + CheckBushAge checkBushAge = new CheckBushAge(blockState.getBlock(), mmoPlayer, + xpReward); + mcMMO.p.getFoliaLib().getScheduler() + .runAtLocationLater(blockState.getLocation(), checkBushAge, 1); } } } @@ -127,10 +166,10 @@ public class HerbalismManager extends SkillManager { public void run() { BlockState blockState = block.getState(); - if(blockState.getType().toString().equalsIgnoreCase("sweet_berry_bush")) { - if(blockState.getBlockData() instanceof Ageable ageable) { + if (blockState.getType().toString().equalsIgnoreCase("sweet_berry_bush")) { + if (blockState.getBlockData() instanceof Ageable ageable) { - if(ageable.getAge() <= 1) { + if (ageable.getAge() <= 1) { applyXpGain(xpReward, XPGainReason.PVE, XPGainSource.SELF); } } @@ -140,18 +179,16 @@ public class HerbalismManager extends SkillManager { public boolean canUseHylianLuck() { - if(!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.HERBALISM_HYLIAN_LUCK)) + if (!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.HERBALISM_HYLIAN_LUCK)) { return false; + } return Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.HERBALISM_HYLIAN_LUCK); } - public boolean canGreenTerraBlock(BlockState blockState) { - return mmoPlayer.getAbilityMode(SuperAbilityType.GREEN_TERRA) && BlockUtils.canMakeMossy(blockState); - } - public boolean canActivateAbility() { - return mmoPlayer.getToolPreparationMode(ToolType.HOE) && Permissions.greenTerra(getPlayer()); + return mmoPlayer.getToolPreparationMode(ToolType.HOE) && Permissions.greenTerra( + getPlayer()); } public boolean isGreenTerraActive() { @@ -165,57 +202,64 @@ public class HerbalismManager extends SkillManager { * @return the modified change in hunger for the event */ public int farmersDiet(int eventFoodLevel) { - return SkillUtils.handleFoodSkills(getPlayer(), eventFoodLevel, SubSkillType.HERBALISM_FARMERS_DIET); + return SkillUtils.handleFoodSkills(getPlayer(), eventFoodLevel, + SubSkillType.HERBALISM_FARMERS_DIET); } - /** - * Process the Green Terra ability. - * - * @param blockState The {@link BlockState} to check ability activation for - * @return true if the ability was successful, false otherwise - */ - public boolean processGreenTerraBlockConversion(BlockState blockState) { - Player player = getPlayer(); + public void processGreenTerraBlockConversion(BlockState blockState) { + final Player player = getPlayer(); if (!Permissions.greenThumbBlock(player, blockState.getType())) { - return false; + return; } PlayerInventory playerInventory = player.getInventory(); ItemStack seed = new ItemStack(Material.WHEAT_SEEDS); if (!playerInventory.containsAtLeast(seed, 1)) { - NotificationManager.sendPlayerInformation(player, NotificationType.REQUIREMENTS_NOT_MET, "Herbalism.Ability.GTe.NeedMore"); - return false; + NotificationManager.sendPlayerInformation(player, + NotificationType.REQUIREMENTS_NOT_MET, "Herbalism.Ability.GTe.NeedMore"); + return; } playerInventory.removeItem(seed); - player.updateInventory(); // Needed until replacement available + // player.updateInventory(); - return Herbalism.convertGreenTerraBlocks(blockState); + Herbalism.convertGreenTerraBlocks(blockState); + blockState.update(true); + } + + /** + * Process the Green Terra ability. + * + * @param block The {@link Block} to check ability activation for + */ + public void processGreenTerraBlockConversion(Block block) { + processGreenTerraBlockConversion(block.getState()); } /** * Handles herbalism abilities and XP rewards from a BlockBreakEvent + * * @param blockBreakEvent The Block Break Event to process */ public void processHerbalismBlockBreakEvent(BlockBreakEvent blockBreakEvent) { - Player player = getPlayer(); + final Player player = getPlayer(); - Block block = blockBreakEvent.getBlock(); + final Block block = blockBreakEvent.getBlock(); if (mcMMO.p.getGeneralConfig().getHerbalismPreventAFK() && player.isInsideVehicle()) { - if(block.hasMetadata(MetadataConstants.METADATA_KEY_REPLANT)) { + if (block.hasMetadata(MetadataConstants.METADATA_KEY_REPLANT)) { block.removeMetadata(MetadataConstants.METADATA_KEY_REPLANT, mcMMO.p); } return; } //Check if the plant was recently replanted - if(block.getBlockData() instanceof Ageable ageableCrop) { - if(block.getMetadata(MetadataConstants.METADATA_KEY_REPLANT).size() >= 1) { - if(block.getMetadata(MetadataConstants.METADATA_KEY_REPLANT).get(0).asBoolean()) { - if(isAgeableMature(ageableCrop)) { + if (block.getBlockData() instanceof Ageable ageableCrop) { + if (!block.getMetadata(MetadataConstants.METADATA_KEY_REPLANT).isEmpty()) { + if (block.getMetadata(MetadataConstants.METADATA_KEY_REPLANT).get(0).asBoolean()) { + if (isAgeableMature(ageableCrop)) { block.removeMetadata(MetadataConstants.METADATA_KEY_REPLANT, mcMMO.p); } else { //Crop is recently replanted to back out of destroying it @@ -232,10 +276,11 @@ public class HerbalismManager extends SkillManager { */ //Grab all broken blocks - HashSet brokenBlocks = getBrokenHerbalismBlocks(blockBreakEvent); + final HashSet brokenBlocks = getBrokenHerbalismBlocks(blockBreakEvent); - if(brokenBlocks.size() == 0) + if (brokenBlocks.isEmpty()) { return; + } //Handle rewards, xp, ability interactions, etc processHerbalismOnBlocksBroken(blockBreakEvent, brokenBlocks); @@ -243,21 +288,26 @@ public class HerbalismManager extends SkillManager { /** * Process rewards for a set of plant blocks for Herbalism + * * @param blockBreakEvent the block break event * @param brokenPlants plant blocks to process */ - private void processHerbalismOnBlocksBroken(BlockBreakEvent blockBreakEvent, HashSet brokenPlants) { - if(blockBreakEvent.isCancelled()) + private void processHerbalismOnBlocksBroken(BlockBreakEvent blockBreakEvent, + HashSet brokenPlants) { + if (blockBreakEvent.isCancelled()) { return; + } - BlockState originalBreak = blockBreakEvent.getBlock().getState(); + final BlockState originalBreak = blockBreakEvent.getBlock().getState(); + // TODO: Storing this boolean for no reason, refactor boolean greenThumbActivated = false; //TODO: The design of Green Terra needs to change, this is a mess - if(Permissions.greenThumbPlant(getPlayer(), originalBreak.getType())) { - if(mcMMO.p.getGeneralConfig().isGreenThumbReplantableCrop(originalBreak.getType())) { - if(!getPlayer().isSneaking()) { - greenThumbActivated = processGreenThumbPlants(originalBreak, blockBreakEvent, isGreenTerraActive()); + if (Permissions.greenThumbPlant(getPlayer(), originalBreak.getType())) { + if (mcMMO.p.getGeneralConfig().isGreenThumbReplantableCrop(originalBreak.getType())) { + if (!getPlayer().isSneaking()) { + greenThumbActivated = processGreenThumbPlants(originalBreak, blockBreakEvent, + isGreenTerraActive()); } } } @@ -273,25 +323,27 @@ public class HerbalismManager extends SkillManager { ArrayList delayedChorusBlocks = new ArrayList<>(); //Blocks that will be checked in future ticks HashSet noDelayPlantBlocks = new HashSet<>(); //Blocks that will be checked immediately - for(Block brokenPlant : brokenPlants) { + for (Block brokenPlant : brokenPlants) { /* * This check is to make XP bars appear to work properly with Chorus Trees by giving XP for the originalBreak immediately instead of later */ - if(brokenPlant.getLocation().equals(originalBreak.getBlock().getLocation())) { + if (brokenPlant.getLocation().equals(originalBreak.getBlock().getLocation())) { //If its the same block as the original, we are going to directly check it for being a valid XP gain and add it to the nonChorusBlocks list even if its a chorus block //This stops a delay from happening when bringing up the XP bar for chorus trees - if(!mcMMO.getPlaceStore().isTrue(originalBreak)) { + if (!mcMMO.getUserBlockTracker().isIneligible(originalBreak)) { //Even if its a chorus block, the original break will be moved to nonChorusBlocks for immediate XP rewards noDelayPlantBlocks.add(brokenPlant); } else { - if(isChorusTree(brokenPlant.getType())) { + if (isChorusTree(brokenPlant.getType())) { //If its a chorus tree AND it was marked as true in the placestore then we add this block to the list of chorus blocks - delayedChorusBlocks.add(new BlockSnapshot(brokenPlant.getType(), brokenPlant)); + delayedChorusBlocks.add( + new BlockSnapshot(brokenPlant.getType(), brokenPlant)); } else { - noDelayPlantBlocks.add(brokenPlant); //If its not a chorus plant that was marked as unnatural but it was marked unnatural, put it in the nodelay list to be handled + noDelayPlantBlocks.add( + brokenPlant); //If its not a chorus plant that was marked as unnatural but it was marked unnatural, put it in the nodelay list to be handled } } - } else if(isChorusTree(brokenPlant.getType())) { + } else if (isChorusTree(brokenPlant.getType())) { //Chorus Blocks get checked for XP several ticks later to avoid expensive calculations delayedChorusBlocks.add(new BlockSnapshot(brokenPlant.getType(), brokenPlant)); } else { @@ -300,23 +352,26 @@ public class HerbalismManager extends SkillManager { } //Give out XP to the non-chorus blocks - if(noDelayPlantBlocks.size() > 0) { + if (!noDelayPlantBlocks.isEmpty()) { //Note: Will contain 1 chorus block if the original block was a chorus block, this is to prevent delays for the XP bar awardXPForPlantBlocks(noDelayPlantBlocks); } - if(delayedChorusBlocks.size() > 0) { + if (!delayedChorusBlocks.isEmpty()) { //Check XP for chorus blocks - DelayedHerbalismXPCheckTask delayedHerbalismXPCheckTask = new DelayedHerbalismXPCheckTask(mmoPlayer, delayedChorusBlocks); + DelayedHerbalismXPCheckTask delayedHerbalismXPCheckTask = new DelayedHerbalismXPCheckTask( + mmoPlayer, delayedChorusBlocks); //Large delay because the tree takes a while to break - mcMMO.p.getFoliaLib().getImpl().runAtEntity(mmoPlayer.getPlayer(), delayedHerbalismXPCheckTask); //Calculate Chorus XP + Bonus Drops 1 tick later + mcMMO.p.getFoliaLib().getScheduler().runAtEntity(mmoPlayer.getPlayer(), + delayedHerbalismXPCheckTask); //Calculate Chorus XP + Bonus Drops 1 tick later } } /** - * Check for double drops on a collection of broken blocks - * If a double drop has occurred, it will be marked here for bonus drops + * Check for double drops on a collection of broken blocks If a double drop has occurred, it + * will be marked here for bonus drops + * * @param player player who broke the blocks * @param brokenPlants the collection of broken plants */ @@ -328,58 +383,50 @@ public class HerbalismManager extends SkillManager { return; } - for(Block brokenPlant : brokenPlants) { + for (Block brokenPlant : brokenPlants) { BlockState brokenPlantState = brokenPlant.getState(); BlockData plantData = brokenPlantState.getBlockData(); //Check for double drops - if(!mcMMO.getPlaceStore().isTrue(brokenPlant)) { - + if (!mcMMO.getUserBlockTracker().isIneligible(brokenPlant)) { /* - * * Natural Blocks - * - * - * */ - //Not all things that are natural should give double drops, make sure its fully mature as well - if(plantData instanceof Ageable ageable) { + if (plantData instanceof Ageable ageable) { - if(isAgeableMature(ageable) || isBizarreAgeable(plantData)) { - if(checkDoubleDrop(brokenPlantState)) { - markForBonusDrops(brokenPlantState); + if (isAgeableMature(ageable) || isBizarreAgeable(plantData)) { + if (checkDoubleDrop(brokenPlant)) { + markForBonusDrops(brokenPlant); } } - } else if(checkDoubleDrop(brokenPlantState)) { + } else if (checkDoubleDrop(brokenPlant)) { //Add metadata to mark this block for double or triple drops - markForBonusDrops(brokenPlantState); + markForBonusDrops(brokenPlant); } } else { - /* - * * Unnatural Blocks - * */ - - //If it's a Crop we need to reward XP when its fully grown - if(isAgeableAndFullyMature(plantData) && !isBizarreAgeable(plantData)) { + //If it's a crop, we need to reward XP when its fully grown + if (isAgeableAndFullyMature(plantData) && !isBizarreAgeable(plantData)) { //Add metadata to mark this block for double or triple drops - markForBonusDrops(brokenPlantState); + markForBonusDrops(brokenPlant); } } } } /** - * Checks if BlockData is bizarre ageable, and we cannot trust that age for Herbalism rewards/XP reasons + * Checks if BlockData is bizarre ageable, and we cannot trust that age for Herbalism rewards/XP + * reasons + * * @param blockData target BlockData * @return returns true if the BlockData is a bizarre ageable for Herbalism XP / Rewards */ public boolean isBizarreAgeable(BlockData blockData) { - if(blockData instanceof Ageable) { - //Catcus and Sugar Canes cannot be trusted + if (blockData instanceof Ageable) { + // Cactus and Sugar Canes cannot be trusted return switch (blockData.getMaterial()) { case CACTUS, KELP, SUGAR_CANE, BAMBOO -> true; default -> false; @@ -389,14 +436,20 @@ public class HerbalismManager extends SkillManager { return false; } - public void markForBonusDrops(BlockState brokenPlantState) { + /** + * Mark a block for bonus drops. + * + * @param block the block to mark + */ + public void markForBonusDrops(Block block) { //Add metadata to mark this block for double or triple drops boolean awardTriple = mmoPlayer.getAbilityMode(SuperAbilityType.GREEN_TERRA); - BlockUtils.markDropsAsBonus(brokenPlantState, awardTriple); + BlockUtils.markDropsAsBonus(block, awardTriple); } /** * Checks if a block is an ageable and if that ageable is fully mature + * * @param plantData target plant * @return returns true if the block is both an ageable and fully mature */ @@ -406,54 +459,70 @@ public class HerbalismManager extends SkillManager { public void awardXPForPlantBlocks(HashSet brokenPlants) { int xpToReward = 0; + int firstXpReward = -1; - for(Block brokenPlantBlock : brokenPlants) { + for (Block brokenPlantBlock : brokenPlants) { BlockState brokenBlockNewState = brokenPlantBlock.getState(); BlockData plantData = brokenBlockNewState.getBlockData(); - if(mcMMO.getPlaceStore().isTrue(brokenBlockNewState)) { + if (mcMMO.getUserBlockTracker().isIneligible(brokenBlockNewState)) { /* - * * Unnatural Blocks - * - * */ - //If its a Crop we need to reward XP when its fully grown - if(isAgeableAndFullyMature(plantData) && !isBizarreAgeable(plantData)) { - xpToReward += ExperienceConfig.getInstance().getXp(PrimarySkillType.HERBALISM, brokenBlockNewState.getType()); + if (isAgeableAndFullyMature(plantData) && !isBizarreAgeable(plantData)) { + xpToReward += ExperienceConfig.getInstance() + .getXp(PrimarySkillType.HERBALISM, brokenBlockNewState.getType()); + if (firstXpReward == -1) { + firstXpReward = xpToReward; + } } //Mark it as natural again as it is being broken - mcMMO.getPlaceStore().setFalse(brokenBlockNewState); + mcMMO.getUserBlockTracker().setEligible(brokenBlockNewState); } else { /* - * * Natural Blocks - * - * */ + // Calculate XP + if (plantData instanceof Ageable plantAgeable) { - //Calculate XP - if(plantData instanceof Ageable plantAgeable) { - - if(isAgeableMature(plantAgeable) || isBizarreAgeable(plantData)) { - xpToReward += ExperienceConfig.getInstance().getXp(PrimarySkillType.HERBALISM, brokenBlockNewState.getType()); + if (isAgeableMature(plantAgeable) || isBizarreAgeable(plantData)) { + xpToReward += ExperienceConfig.getInstance() + .getXp(PrimarySkillType.HERBALISM, brokenBlockNewState.getType()); + if (firstXpReward == -1) { + firstXpReward = xpToReward; + } } } else { - xpToReward += ExperienceConfig.getInstance().getXp(PrimarySkillType.HERBALISM, brokenPlantBlock.getType()); + xpToReward += ExperienceConfig.getInstance() + .getXp(PrimarySkillType.HERBALISM, brokenPlantBlock.getType()); + if (firstXpReward == -1) { + firstXpReward = xpToReward; + } } } } - if(mmoPlayer.isDebugMode()) { - mmoPlayer.getPlayer().sendMessage("Plants processed: "+brokenPlants.size()); + if (mmoPlayer.isDebugMode()) { + mmoPlayer.getPlayer().sendMessage("Plants processed: " + brokenPlants.size()); } //Reward XP - if(xpToReward > 0) { - applyXpGain(xpToReward, XPGainReason.PVE, XPGainSource.SELF); + if (xpToReward > 0) { + // get first block from hash set using stream API + final Block firstBlock = brokenPlants.stream().findFirst().orElse(null); + if (firstBlock != null + && ExperienceConfig.getInstance().limitXPOnTallPlants() + && plantBreakLimits.containsKey(firstBlock.getType().getKey().getKey())) { + int limit = plantBreakLimits.get(firstBlock.getType().getKey().getKey()) + * firstXpReward; + // Plant may be unnaturally tall, limit XP + applyXpGain(Math.min(xpToReward, limit), XPGainReason.PVE, XPGainSource.SELF); + } else { + applyXpGain(xpToReward, XPGainReason.PVE, XPGainSource.SELF); + } } } @@ -464,6 +533,7 @@ public class HerbalismManager extends SkillManager { /** * Award XP for any blocks that used to be something else but are now AIR + * * @param brokenPlants snapshot of broken blocks */ public void awardXPForBlockSnapshots(ArrayList brokenPlants) { @@ -474,106 +544,123 @@ public class HerbalismManager extends SkillManager { int xpToReward = 0; int blocksGivingXP = 0; - for(BlockSnapshot blockSnapshot : brokenPlants) { - BlockState brokenBlockNewState = blockSnapshot.getBlockRef().getState(); + for (BlockSnapshot blockSnapshot : brokenPlants) { + final BlockState brokenBlockNewState = blockSnapshot.getBlockRef().getState(); //Remove metadata from the snapshot of blocks - if(brokenBlockNewState.hasMetadata(MetadataConstants.METADATA_KEY_BONUS_DROPS)) { - brokenBlockNewState.removeMetadata(MetadataConstants.METADATA_KEY_BONUS_DROPS, mcMMO.p); + if (brokenBlockNewState.hasMetadata(MetadataConstants.METADATA_KEY_BONUS_DROPS)) { + brokenBlockNewState.removeMetadata(MetadataConstants.METADATA_KEY_BONUS_DROPS, + mcMMO.p); } //If the block is not AIR that means it wasn't broken - if(brokenBlockNewState.getType() != Material.AIR) { + if (brokenBlockNewState.getType() != Material.AIR) { continue; } - if(mcMMO.getPlaceStore().isTrue(brokenBlockNewState)) { + if (mcMMO.getUserBlockTracker().isIneligible(brokenBlockNewState)) { //Mark it as natural again as it is being broken - mcMMO.getPlaceStore().setFalse(brokenBlockNewState); + mcMMO.getUserBlockTracker().setEligible(brokenBlockNewState); } else { //TODO: Do we care about chorus flower age? //Calculate XP for the old type - xpToReward += ExperienceConfig.getInstance().getXp(PrimarySkillType.HERBALISM, blockSnapshot.getOldType()); + xpToReward += ExperienceConfig.getInstance() + .getXp(PrimarySkillType.HERBALISM, blockSnapshot.getOldType()); blocksGivingXP++; } } - if(mmoPlayer.isDebugMode()) { - mmoPlayer.getPlayer().sendMessage("Chorus Plants checked for XP: "+brokenPlants.size()); - mmoPlayer.getPlayer().sendMessage("Valid Chorus Plant XP Gains: "+blocksGivingXP); + if (mmoPlayer.isDebugMode()) { + mmoPlayer.getPlayer() + .sendMessage("Chorus Plants checked for XP: " + brokenPlants.size()); + mmoPlayer.getPlayer().sendMessage("Valid Chorus Plant XP Gains: " + blocksGivingXP); } //Reward XP - if(xpToReward > 0) { + if (xpToReward > 0) { applyXpGain(xpToReward, XPGainReason.PVE, XPGainSource.SELF); } } /** * Process and return plant blocks from a BlockBreakEvent + * * @param blockBreakEvent target event * @return a set of plant-blocks that were broken as a result of this event */ private HashSet getBrokenHerbalismBlocks(@NotNull BlockBreakEvent blockBreakEvent) { //Get an updated capture of this block - BlockState originBlockState = blockBreakEvent.getBlock().getState(); - Material originBlockMaterial = originBlockState.getType(); - HashSet blocksBroken = new HashSet<>(); //Blocks broken + final BlockState originBlockState = blockBreakEvent.getBlock().getState(); + final Material originBlockMaterial = originBlockState.getType(); + final HashSet blocksBroken = new HashSet<>(); //Blocks broken //Add the initial block blocksBroken.add(originBlockState.getBlock()); - if(!isOneBlockPlant(originBlockMaterial)) { + if (!isOneBlockPlant(originBlockMaterial)) { //If the block is a multi-block structure, capture a set of all blocks broken and return that - blocksBroken = getBrokenBlocksMultiBlockPlants(originBlockState); + addBrokenBlocksMultiBlockPlants(originBlockState, blocksBroken); } //Return all broken plant-blocks return blocksBroken; } - private HashSet getBrokenChorusBlocks(BlockState originalBreak) { - return grabChorusTreeBrokenBlocksRecursive(originalBreak.getBlock(), new HashSet<>()); - } - - private HashSet grabChorusTreeBrokenBlocksRecursive(Block currentBlock, HashSet traversed) { - if (!isChorusTree(currentBlock.getType())) - return traversed; - - // Prevent any infinite loops, who needs more than 256 chorus anyways - if (traversed.size() > 256) - return traversed; - - if (!traversed.add(currentBlock)) - return traversed; - - //Grab all Blocks in the Tree - for (BlockFace blockFace : new BlockFace[] { BlockFace.UP, BlockFace.NORTH, BlockFace.SOUTH, BlockFace.EAST ,BlockFace.WEST}) - grabChorusTreeBrokenBlocksRecursive(currentBlock.getRelative(blockFace, 1), traversed); - - traversed.add(currentBlock); - - return traversed; - } - - /** - * Grab a set of all plant blocks that are broken as a result of this event - * The method to grab these blocks is a bit hacky and does not hook into the API - * Basically we expect the blocks to be broken if this event is not cancelled and we determine which block are broken on our end rather than any event state captures - * - * @return a set of plant-blocks broken from this event - */ - protected HashSet getBrokenBlocksMultiBlockPlants(BlockState brokenBlock) { - //Track the broken blocks - HashSet brokenBlocks; - - if (isChorusBranch(brokenBlock.getType())) { - brokenBlocks = getBrokenChorusBlocks(brokenBlock); - } else { - brokenBlocks = getBlocksBrokenAboveOrBelow(brokenBlock, false, mcMMO.getMaterialMapStore().isMultiBlockHangingPlant(brokenBlock.getType())); + private void addChorusTreeBrokenBlocks(Block currentBlock, Set traversed) { + if (!isChorusTree(currentBlock.getType())) { + return; } - return brokenBlocks; + // Prevent any infinite loops, who needs more than 256 chorus anyways + if (traversed.size() > 256) { + return; + } + + if (!traversed.add(currentBlock)) { + return; + } + + //Grab all Blocks in the Tree + for (BlockFace blockFace : new BlockFace[]{BlockFace.UP, BlockFace.NORTH, BlockFace.SOUTH, + BlockFace.EAST, BlockFace.WEST}) { + addChorusTreeBrokenBlocks(currentBlock.getRelative(blockFace, 1), traversed); + } + } + + + protected void addBrokenBlocksMultiBlockPlants(BlockState brokenBlock, + Set brokenBlocks) { + if (isChorusBranch(brokenBlock.getType())) { + addChorusTreeBrokenBlocks(brokenBlock.getBlock(), brokenBlocks); + } else if (isCactus(brokenBlock.getType())) { + addCactusBlocks(brokenBlock.getBlock(), brokenBlocks); + } else { + addBlocksBrokenAboveOrBelow(brokenBlock.getBlock(), brokenBlocks, + mcMMO.getMaterialMapStore().isMultiBlockHangingPlant(brokenBlock.getType())); + } + } + + private void addCactusBlocks(Block currentBlock, Set traversed) { + if (!isCactus(currentBlock.getType())) { + return; + } + + if (traversed.size() > 4) // Max size 3 cactus + flower + { + return; + } + + if (!traversed.add(currentBlock)) { + return; + } + + addCactusBlocks(currentBlock.getRelative(BlockFace.UP), traversed); + addCactusBlocks(currentBlock.getRelative(BlockFace.DOWN), traversed); + } + + private boolean isCactus(Material material) { + return material.getKey().getKey().equalsIgnoreCase(CACTUS_STR) + || material.getKey().getKey().equalsIgnoreCase(CACTUS_FLOWER_STR); } private boolean isChorusBranch(Material blockType) { @@ -584,25 +671,8 @@ public class HerbalismManager extends SkillManager { return blockType == Material.CHORUS_PLANT || blockType == Material.CHORUS_FLOWER; } - /** - * Grabs blocks upwards from a target block - * A lot of Plants/Crops in Herbalism only break vertically from a broken block - * The vertical search returns early if it runs into anything that is not a multi-block plant - * Multi-block plants are hard-coded and kept in {@link MaterialMapStore} - * - * @param originBlock The point of the "break" - * @param inclusive Whether to include the origin block - * @param below Whether to search down instead of up. - * @return A set of blocks above the target block which can be assumed to be broken - */ - private HashSet getBlocksBrokenAboveOrBelow(BlockState originBlock, boolean inclusive, boolean below) { - HashSet brokenBlocks = new HashSet<>(); - Block block = originBlock.getBlock(); - - //Add the initial block to the set - if(inclusive) - brokenBlocks.add(block); - + private void addBlocksBrokenAboveOrBelow(Block originBlock, Set brokenBlocks, + boolean below) { //Limit our search int maxHeight = 512; @@ -610,37 +680,38 @@ public class HerbalismManager extends SkillManager { // Search vertically for multi-block plants, exit early if any non-multi block plants for (int y = 0; y < maxHeight; y++) { - //TODO: Should this grab state? It would be more expensive.. - Block relativeBlock = block.getRelative(relativeFace, y); + final Block relativeBlock = originBlock.getRelative(relativeFace, y); //Abandon our search if the block isn't multi - if (isOneBlockPlant(relativeBlock.getType())) + if (isOneBlockPlant(relativeBlock.getType())) { break; + } brokenBlocks.add(relativeBlock); } - - return brokenBlocks; } /** - * If the plant is considered a one block plant - * This is determined by seeing if it exists in a hard-coded collection of Multi-Block plants + * If the plant is considered a one block plant This is determined by seeing if it exists in a + * hard-coded collection of Multi-Block plants + * * @param material target plant material * @return true if the block is not contained in the collection of multi-block plants */ private boolean isOneBlockPlant(Material material) { - return !mcMMO.getMaterialMapStore().isMultiBlockPlant(material) && !mcMMO.getMaterialMapStore().isMultiBlockHangingPlant(material); + return !mcMMO.getMaterialMapStore().isMultiBlockPlant(material) + && !mcMMO.getMaterialMapStore().isMultiBlockHangingPlant(material); } /** * Check for success on herbalism double drops - * @param blockState target block state - * @return true if double drop succeeds + * + * @param block target block state + * @return true if the double drop succeeds */ - private boolean checkDoubleDrop(BlockState blockState) - { - return BlockUtils.checkDoubleDrops(getPlayer(), blockState, skill, SubSkillType.HERBALISM_DOUBLE_DROPS); + private boolean checkDoubleDrop(@NotNull Block block) { + requireNonNull(block, "BlockState cannot be null"); + return BlockUtils.checkDoubleDrops(mmoPlayer, block, SubSkillType.HERBALISM_DOUBLE_DROPS); } /** @@ -650,8 +721,9 @@ public class HerbalismManager extends SkillManager { * @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())) { - NotificationManager.sendPlayerInformation(getPlayer(), NotificationType.SUBSKILL_MESSAGE_FAILED, "Herbalism.Ability.GTh.Fail"); + if (!ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.HERBALISM_GREEN_THUMB, mmoPlayer)) { + NotificationManager.sendPlayerInformation(getPlayer(), + NotificationType.SUBSKILL_MESSAGE_FAILED, "Herbalism.Ability.GTh.Fail"); return false; } @@ -665,32 +737,36 @@ public class HerbalismManager extends SkillManager { * @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 (!ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.HERBALISM_HYLIAN_LUCK, mmoPlayer)) { return false; } - String friendly = StringUtils.getFriendlyConfigBlockDataString(blockState.getBlockData()); - if (!TreasureConfig.getInstance().hylianMap.containsKey(friendly)) + final String materialConfigString = getMaterialConfigString( + blockState.getBlockData().getMaterial()); + if (!TreasureConfig.getInstance().hylianMap.containsKey(materialConfigString)) { return false; - List treasures = TreasureConfig.getInstance().hylianMap.get(friendly); - - Player player = getPlayer(); + } + List treasures = TreasureConfig.getInstance().hylianMap.get( + materialConfigString); if (treasures.isEmpty()) { return false; } int skillLevel = getSkillLevel(); - Location location = Misc.getBlockCenter(blockState); + final Location centerOfBlock = getBlockCenter(blockState); for (HylianTreasure treasure : treasures) { if (skillLevel >= treasure.getDropLevel() - && RandomChanceUtil.checkRandomChanceExecutionSuccess(new RandomChanceSkillStatic(treasure.getDropChance(), getPlayer(), SubSkillType.HERBALISM_HYLIAN_LUCK))) { - if (!EventUtils.simulateBlockBreak(blockState.getBlock(), player)) { + && ProbabilityUtil.isStaticSkillRNGSuccessful(PrimarySkillType.HERBALISM, + mmoPlayer, treasure.getDropChance())) { + if (!EventUtils.simulateBlockBreak(blockState.getBlock(), mmoPlayer.getPlayer())) { return false; } blockState.setType(Material.AIR); - Misc.spawnItem(getPlayer(), location, treasure.getDrop(), ItemSpawnReason.HYLIAN_LUCK_TREASURE); - NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE, "Herbalism.HylianLuck"); + ItemUtils.spawnItem(getPlayer(), centerOfBlock, treasure.getDrop(), + ItemSpawnReason.HYLIAN_LUCK_TREASURE); + NotificationManager.sendPlayerInformation(mmoPlayer.getPlayer(), + NotificationType.SUBSKILL_MESSAGE, "Herbalism.HylianLuck"); return true; } } @@ -704,25 +780,29 @@ public class HerbalismManager extends SkillManager { * @return true if the ability was successful, false otherwise */ public boolean processShroomThumb(BlockState blockState) { - Player player = getPlayer(); - PlayerInventory playerInventory = player.getInventory(); - + PlayerInventory playerInventory = getPlayer().getInventory(); + if (!playerInventory.contains(Material.BROWN_MUSHROOM, 1)) { - NotificationManager.sendPlayerInformation(player, NotificationType.REQUIREMENTS_NOT_MET, "Skills.NeedMore", StringUtils.getPrettyItemString(Material.BROWN_MUSHROOM)); + NotificationManager.sendPlayerInformation(getPlayer(), + NotificationType.REQUIREMENTS_NOT_MET, "Skills.NeedMore", + StringUtils.getPrettyMaterialString(Material.BROWN_MUSHROOM)); return false; } if (!playerInventory.contains(Material.RED_MUSHROOM, 1)) { - NotificationManager.sendPlayerInformation(player, NotificationType.REQUIREMENTS_NOT_MET, "Skills.NeedMore", StringUtils.getPrettyItemString(Material.RED_MUSHROOM)); + NotificationManager.sendPlayerInformation(getPlayer(), + NotificationType.REQUIREMENTS_NOT_MET, "Skills.NeedMore", + StringUtils.getPrettyMaterialString(Material.RED_MUSHROOM)); return false; } playerInventory.removeItem(new ItemStack(Material.BROWN_MUSHROOM)); playerInventory.removeItem(new ItemStack(Material.RED_MUSHROOM)); - player.updateInventory(); + getPlayer().updateInventory(); - if (!RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.HERBALISM_SHROOM_THUMB, player)) { - NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE_FAILED, "Herbalism.Ability.ShroomThumb.Fail"); + if (!ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.HERBALISM_SHROOM_THUMB, mmoPlayer)) { + NotificationManager.sendPlayerInformation(getPlayer(), + NotificationType.SUBSKILL_MESSAGE_FAILED, "Herbalism.Ability.ShroomThumb.Fail"); return false; } @@ -731,14 +811,20 @@ public class HerbalismManager extends SkillManager { /** * Starts the delayed replant task and turns + * * @param desiredCropAge the desired age of the crop * @param blockBreakEvent the {@link BlockBreakEvent} this crop was involved in * @param cropState the {@link BlockState} of the crop */ - private void startReplantTask(int desiredCropAge, BlockBreakEvent blockBreakEvent, BlockState cropState, boolean isImmature) { + private void startReplantTask(int desiredCropAge, BlockBreakEvent blockBreakEvent, + BlockState cropState, boolean isImmature) { //Mark the plant as recently replanted to avoid accidental breakage - mcMMO.p.getFoliaLib().getImpl().runAtLocationLater(blockBreakEvent.getBlock().getLocation(), new DelayedCropReplant(blockBreakEvent, cropState, desiredCropAge, isImmature), 2 * Misc.TICK_CONVERSION_FACTOR); - blockBreakEvent.getBlock().setMetadata(MetadataConstants.METADATA_KEY_REPLANT, new RecentlyReplantedCropMeta(mcMMO.p, true)); + mcMMO.p.getFoliaLib().getScheduler() + .runAtLocationLater(blockBreakEvent.getBlock().getLocation(), + new DelayedCropReplant(blockBreakEvent, cropState, desiredCropAge, + isImmature), 2 * Misc.TICK_CONVERSION_FACTOR); + blockBreakEvent.getBlock().setMetadata(MetadataConstants.METADATA_KEY_REPLANT, + new RecentlyReplantedCropMeta(mcMMO.p, true)); } /** @@ -747,13 +833,16 @@ public class HerbalismManager extends SkillManager { * @param blockState The {@link BlockState} to check ability activation for * @param greenTerra boolean to determine if greenTerra is active or not */ - private boolean processGreenThumbPlants(BlockState blockState, BlockBreakEvent blockBreakEvent, boolean greenTerra) { + private boolean processGreenThumbPlants(@NotNull BlockState blockState, + @NotNull BlockBreakEvent blockBreakEvent, + boolean greenTerra) { if (!ItemUtils.isHoe(blockBreakEvent.getPlayer().getInventory().getItemInMainHand()) - && !ItemUtils.isAxe(blockBreakEvent.getPlayer().getInventory().getItemInMainHand())) { + && !ItemUtils.isAxe( + blockBreakEvent.getPlayer().getInventory().getItemInMainHand())) { return false; } - BlockData blockData = blockState.getBlockData(); + final BlockData blockData = blockState.getBlockData(); if (!(blockData instanceof Ageable ageable)) { return false; @@ -761,78 +850,62 @@ public class HerbalismManager extends SkillManager { //If the ageable is NOT mature and the player is NOT using a hoe, abort - Player player = getPlayer(); - PlayerInventory playerInventory = player.getInventory(); - Material seed; + final Player player = getPlayer(); + final Material replantMaterial; - switch (blockState.getType().getKey().getKey().toLowerCase(Locale.ROOT)) { - case "carrots": - seed = Material.matchMaterial("CARROT"); - break; - - case "wheat": - seed = Material.matchMaterial("WHEAT_SEEDS"); - break; - - case "nether_wart": - seed = Material.getMaterial("NETHER_WART"); - break; - - case "potatoes": - seed = Material.matchMaterial("POTATO"); - break; - - case "beetroots": - seed = Material.matchMaterial("BEETROOT_SEEDS"); - break; - - case "cocoa": - seed = Material.matchMaterial("COCOA_BEANS"); - break; - - case "torchflower": - seed = Material.matchMaterial("TORCHFLOWER_SEEDS"); - break; - default: + switch (blockState.getType().getKey().getKey().toLowerCase(Locale.ENGLISH)) { + case "carrots" -> replantMaterial = Material.matchMaterial("CARROT"); + case "wheat" -> replantMaterial = Material.matchMaterial("WHEAT_SEEDS"); + case "nether_wart" -> replantMaterial = Material.getMaterial("NETHER_WART"); + case "potatoes" -> replantMaterial = Material.matchMaterial("POTATO"); + case "beetroots" -> replantMaterial = Material.matchMaterial("BEETROOT_SEEDS"); + case "cocoa" -> replantMaterial = Material.matchMaterial("COCOA_BEANS"); + case "torchflower" -> replantMaterial = Material.matchMaterial("TORCHFLOWER_SEEDS"); + default -> { return false; + } } - - ItemStack seedStack = new ItemStack(seed); + if (replantMaterial == null) { + return false; + } if (ItemUtils.isAxe(blockBreakEvent.getPlayer().getInventory().getItemInMainHand()) - && blockState.getType() != Material.COCOA) { + && blockState.getType() != Material.COCOA) { return false; } - if (!greenTerra && !RandomChanceUtil.checkRandomChanceExecutionSuccess(player, SubSkillType.HERBALISM_GREEN_THUMB, true)) { + if (!greenTerra && !ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.HERBALISM_GREEN_THUMB, + mmoPlayer)) { return false; } - if (!playerInventory.containsAtLeast(seedStack, 1)) { + if (!hasItemIncludingOffHand(player, replantMaterial)) { return false; } - if (!processGrowingPlants(blockState, ageable, blockBreakEvent, greenTerra)) { - return false; - } - - if(EventUtils.callSubSkillBlockEvent(player, SubSkillType.HERBALISM_GREEN_THUMB, blockState.getBlock()).isCancelled()) { + if (EventUtils.callSubSkillBlockEvent(player, SubSkillType.HERBALISM_GREEN_THUMB, + blockState.getBlock()) + .isCancelled()) { return false; } else { - playerInventory.removeItem(seedStack); - player.updateInventory(); // Needed until replacement available + if (!processGrowingPlants(blockState, ageable, blockBreakEvent, greenTerra)) { + return false; + } + // remove the item from the player's inventory + removeItemIncludingOffHand(player, replantMaterial, 1); + // player.updateInventory(); // Needed until replacement available + //Play sound SoundManager.sendSound(player, player.getLocation(), SoundType.ITEM_CONSUMED); return true; } - -// new HerbalismBlockUpdaterTask(blockState).runTaskLater(mcMMO.p, 0); } - private boolean processGrowingPlants(BlockState blockState, Ageable ageable, BlockBreakEvent blockBreakEvent, boolean greenTerra) { + private boolean processGrowingPlants(BlockState blockState, Ageable ageable, + BlockBreakEvent blockBreakEvent, boolean greenTerra) { //This check is needed - if(isBizarreAgeable(ageable)) { + if (isBizarreAgeable(ageable)) { return false; } @@ -840,7 +913,7 @@ public class HerbalismManager extends SkillManager { int greenThumbStage = getGreenThumbStage(greenTerra); //Immature plants will start over at 0 - if(!isAgeableMature(ageable)) { + if (!isAgeableMature(ageable)) { // blockBreakEvent.setCancelled(true); startReplantTask(0, blockBreakEvent, blockState, true); // blockState.setType(Material.AIR); @@ -854,7 +927,7 @@ public class HerbalismManager extends SkillManager { case "carrots": case "wheat": - finalAge = getGreenThumbStage(greenTerra); + finalAge = getGreenThumbStage(greenTerra); break; case "beetroots": @@ -862,11 +935,9 @@ public class HerbalismManager extends SkillManager { if (greenTerra || greenThumbStage > 2) { finalAge = 2; - } - else if (greenThumbStage == 2) { + } else if (greenThumbStage == 2) { finalAge = 1; - } - else { + } else { finalAge = 0; } break; @@ -875,8 +946,7 @@ public class HerbalismManager extends SkillManager { if (getGreenThumbStage(greenTerra) >= 2) { finalAge = 1; - } - else { + } else { finalAge = 0; } break; @@ -885,16 +955,16 @@ public class HerbalismManager extends SkillManager { return false; } - //Start the delayed replant startReplantTask(finalAge, blockBreakEvent, blockState, false); return true; } private int getGreenThumbStage(boolean greenTerraActive) { - if(greenTerraActive) + if (greenTerraActive) { return Math.min(RankUtils.getHighestRank(SubSkillType.HERBALISM_GREEN_THUMB), RankUtils.getRank(getPlayer(), SubSkillType.HERBALISM_GREEN_THUMB) + 1); + } return RankUtils.getRank(getPlayer(), SubSkillType.HERBALISM_GREEN_THUMB); } diff --git a/src/main/java/com/gmail/nossr50/skills/maces/MacesManager.java b/src/main/java/com/gmail/nossr50/skills/maces/MacesManager.java new file mode 100644 index 000000000..0dbade619 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/skills/maces/MacesManager.java @@ -0,0 +1,115 @@ +package com.gmail.nossr50.skills.maces; + +import com.gmail.nossr50.datatypes.interactions.NotificationType; +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.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 java.util.Locale; +import org.bukkit.NamespacedKey; +import org.bukkit.Registry; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.potion.PotionEffectType; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class MacesManager extends SkillManager { + private static @Nullable PotionEffectType slowEffectType; + + public MacesManager(McMMOPlayer mmoPlayer) { + super(mmoPlayer, PrimarySkillType.MACES); + } + + private static @Nullable PotionEffectType mockSpigotMatch(@NotNull String input) { + // Replicates match() behaviour for older versions lacking this API + final String filtered = input.toLowerCase(Locale.ROOT).replaceAll("\\s+", "_"); + final NamespacedKey namespacedKey = NamespacedKey.fromString(filtered); + return (namespacedKey != null) ? Registry.EFFECT.get(namespacedKey) : null; + } + + /** + * Get the Crush damage bonus. + * + * @return the Crush damage bonus. + */ + public double getCrushDamage() { + if (!Permissions.canUseSubSkill(mmoPlayer.getPlayer(), SubSkillType.MACES_CRUSH)) { + return 0; + } + + int rank = RankUtils.getRank(getPlayer(), SubSkillType.MACES_CRUSH); + + if (rank > 0) { + return (0.5D + (rank * 1.D)); + } + + return 0; + } + + /** + * Process Cripple attack. + * + * @param target The defending entity + */ + public void processCripple(@NotNull LivingEntity target) { + // Lazy initialized to avoid some backwards compatibility issues + if (slowEffectType == null) { + if (mockSpigotMatch("slowness") == null) { + mcMMO.p.getLogger().severe("Unable to find the Slowness PotionEffectType, " + + "mcMMO will not function properly."); + throw new IllegalStateException("Unable to find the Slowness PotionEffectType!"); + } else { + slowEffectType = mockSpigotMatch("slowness"); + } + } + + boolean isPlayerTarget = target instanceof Player; + // Don't apply Cripple if the target is already Slowed + if (slowEffectType == null || target.getPotionEffect(slowEffectType) != null) { + return; + } + + if (!Permissions.canUseSubSkill(mmoPlayer.getPlayer(), SubSkillType.MACES_CRIPPLE)) { + return; + } + + int crippleRank = RankUtils.getRank(getPlayer(), SubSkillType.MACES_CRIPPLE); + double crippleOdds = (mcMMO.p.getAdvancedConfig().getCrippleChanceToApplyOnHit(crippleRank) + * mmoPlayer.getAttackStrength()); + + if (ProbabilityUtil.isStaticSkillRNGSuccessful(PrimarySkillType.MACES, mmoPlayer, + crippleOdds)) { + if (mmoPlayer.useChatNotifications()) { + NotificationManager.sendPlayerInformation(mmoPlayer.getPlayer(), + NotificationType.SUBSKILL_MESSAGE, "Maces.SubSkill.Cripple.Activated"); + } + + // Cripple is success, Cripple the target + target.addPotionEffect(slowEffectType.createEffect( + getCrippleTickDuration(isPlayerTarget), + getCrippleStrength(isPlayerTarget))); + ParticleEffectUtils.playCrippleEffect(target); + } + } + + public static int getCrippleTickDuration(boolean isPlayerTarget) { + // TODO: Make configurable + if (isPlayerTarget) { + return 20; + } else { + return 30; + } + } + + public static int getCrippleStrength(boolean isPlayerTarget) { + // TODO: Make configurable + return isPlayerTarget ? 1 : 2; + } +} diff --git a/src/main/java/com/gmail/nossr50/skills/mining/BlastMining.java b/src/main/java/com/gmail/nossr50/skills/mining/BlastMining.java index 98b8cf8b6..c4f8a18b4 100644 --- a/src/main/java/com/gmail/nossr50/skills/mining/BlastMining.java +++ b/src/main/java/com/gmail/nossr50/skills/mining/BlastMining.java @@ -10,104 +10,56 @@ import org.bukkit.entity.TNTPrimed; import org.bukkit.event.entity.EntityDamageByEntityEvent; public class BlastMining { - // The order of the values is extremely important, a few methods depend on it to work properly - /* public enum Tier { - EIGHT(8), - SEVEN(7), - SIX(6), - FIVE(5), - FOUR(4), - THREE(3), - TWO(2), - ONE(1); - - int numerical; - - private Tier(int numerical) { - this.numerical = numerical; - } - - public int toNumerical() { - return numerical; - } - - protected int getLevel() { - return mcMMO.p.getAdvancedConfig().getBlastMiningRankLevel(this); - } - - - }*/ - public final static int MAXIMUM_REMOTE_DETONATION_DISTANCE = 100; public static double getBlastRadiusModifier(int rank) { return mcMMO.p.getAdvancedConfig().getBlastRadiusModifier(rank); } - - public static double getBlastDamageDecrease(int rank) { return mcMMO.p.getAdvancedConfig().getBlastDamageDecrease(rank); } - - public static int getDemolitionExpertUnlockLevel() { - /*List tierList = Arrays.asList(Tier.values()); - for (Tier tier : tierList) { - if (tier.getBlastDamageDecrease() > 0) { - continue; + for (int i = 0; i < SubSkillType.MINING_BLAST_MINING.getNumRanks() - 1; i++) { + if (getBlastDamageDecrease(i + 1) > 0) { + return RankUtils.getRankUnlockLevel(SubSkillType.MINING_BLAST_MINING, i + 1); } - - return tier == Tier.EIGHT ? tier.getLevel() : tierList.get(tierList.indexOf(tier) - 1).getLevel(); - }*/ - - for(int i = 0; i < SubSkillType.MINING_BLAST_MINING.getNumRanks()-1; i++) - { - if(getBlastDamageDecrease(i+1) > 0) - return RankUtils.getRankUnlockLevel(SubSkillType.MINING_BLAST_MINING, i+1); } return 0; } public static int getBiggerBombsUnlockLevel() { - /*List tierList = Arrays.asList(Tier.values()); - for (Tier tier : tierList) { - if (tier.getBlastRadiusModifier() > 1.0) { - continue; + for (int i = 0; i < SubSkillType.MINING_BLAST_MINING.getNumRanks() - 1; i++) { + if (getBlastRadiusModifier(i + 1) > 0) { + return RankUtils.getRankUnlockLevel(SubSkillType.MINING_BLAST_MINING, i + 1); } - - return tier == Tier.EIGHT ? tier.getLevel() : tierList.get(tierList.indexOf(tier) - 1).getLevel(); - }*/ - - for(int i = 0; i < SubSkillType.MINING_BLAST_MINING.getNumRanks()-1; i++) - { - if(getBlastRadiusModifier(i+1) > 0) - return RankUtils.getRankUnlockLevel(SubSkillType.MINING_BLAST_MINING, i+1); } return 0; } - public static boolean processBlastMiningExplosion(EntityDamageByEntityEvent event, TNTPrimed tnt, Player defender) { - if (!tnt.hasMetadata(MetadataConstants.METADATA_KEY_TRACKED_TNT) || !UserManager.hasPlayerDataKey(defender)) { + public static boolean processBlastMiningExplosion(EntityDamageByEntityEvent event, + TNTPrimed tnt, Player defender) { + if (!tnt.hasMetadata(MetadataConstants.METADATA_KEY_TRACKED_TNT) + || !UserManager.hasPlayerDataKey(defender)) { return false; } // We can make this assumption because we (should) be the only ones using this exact metadata - Player player = mcMMO.p.getServer().getPlayerExact(tnt.getMetadata(MetadataConstants.METADATA_KEY_TRACKED_TNT).get(0).asString()); + Player player = mcMMO.p.getServer().getPlayerExact( + tnt.getMetadata(MetadataConstants.METADATA_KEY_TRACKED_TNT).get(0).asString()); if (!(player != null && player.equals(defender))) { return false; } - if(UserManager.getPlayer(defender) == null) - { + if (UserManager.getPlayer(defender) == null) { return false; } - MiningManager miningManager = UserManager.getPlayer(defender).getMiningManager(); + final MiningManager miningManager = UserManager.getPlayer(defender).getMiningManager(); if (!miningManager.canUseDemolitionsExpertise()) { return false; diff --git a/src/main/java/com/gmail/nossr50/skills/mining/Mining.java b/src/main/java/com/gmail/nossr50/skills/mining/Mining.java deleted file mode 100644 index 0c301752c..000000000 --- a/src/main/java/com/gmail/nossr50/skills/mining/Mining.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.gmail.nossr50.skills.mining; - -import com.gmail.nossr50.config.experience.ExperienceConfig; -import com.gmail.nossr50.datatypes.skills.PrimarySkillType; -import com.gmail.nossr50.mcMMO; -import org.bukkit.block.BlockState; - -public class Mining { - - /** - * Calculate XP gain for Mining. - * - * @param blockState The {@link BlockState} to check ability activation for - */ - public static int getBlockXp(BlockState blockState) { - int xp = ExperienceConfig.getInstance().getXp(PrimarySkillType.MINING, blockState.getType()); - - if (xp == 0 && mcMMO.getModManager().isCustomMiningBlock(blockState)) { - xp = mcMMO.getModManager().getBlock(blockState).getXpGain(); - } - - return xp; - } -} 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 030104d4f..3044d87c4 100644 --- a/src/main/java/com/gmail/nossr50/skills/mining/MiningManager.java +++ b/src/main/java/com/gmail/nossr50/skills/mining/MiningManager.java @@ -1,8 +1,12 @@ package com.gmail.nossr50.skills.mining; +import static com.gmail.nossr50.util.ItemUtils.isPickaxe; +import static com.gmail.nossr50.util.Misc.getBlockCenter; + import com.gmail.nossr50.api.ItemSpawnReason; import com.gmail.nossr50.config.experience.ExperienceConfig; import com.gmail.nossr50.datatypes.experience.XPGainReason; +import com.gmail.nossr50.datatypes.experience.XPGainSource; import com.gmail.nossr50.datatypes.interactions.NotificationType; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; @@ -11,12 +15,22 @@ import com.gmail.nossr50.datatypes.skills.SuperAbilityType; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.runnables.skills.AbilityCooldownTask; import com.gmail.nossr50.skills.SkillManager; -import com.gmail.nossr50.util.*; +import com.gmail.nossr50.util.BlockUtils; +import com.gmail.nossr50.util.EventUtils; +import com.gmail.nossr50.util.ItemUtils; +import com.gmail.nossr50.util.MetadataConstants; +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.random.Probability; +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; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Locale; +import java.util.Set; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.BlockState; @@ -28,78 +42,137 @@ import org.bukkit.event.entity.EntityExplodeEvent; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; -import java.util.ArrayList; -import java.util.List; - public class MiningManager extends SkillManager { - public static final String BUDDING_AMETHYST = "budding_amethyst"; + private static final String BUDDING_AMETHYST = "budding_amethyst"; + private static final Collection BLAST_MINING_BLACKLIST = Set.of(Material.SPAWNER, + Material.INFESTED_COBBLESTONE, Material.INFESTED_DEEPSLATE, Material.INFESTED_STONE, + Material.INFESTED_STONE_BRICKS, Material.INFESTED_CRACKED_STONE_BRICKS, + Material.INFESTED_CHISELED_STONE_BRICKS, Material.INFESTED_MOSSY_STONE_BRICKS); + private final static Set INFESTED_BLOCKS = Set.of("infested_stone", + "infested_cobblestone", + "infested_stone_bricks", "infested_cracked_stone_bricks", "infested_mossy_stone_bricks", + "infested_chiseled_stone_bricks", "infested_deepslate"); - public MiningManager(McMMOPlayer mcMMOPlayer) { - super(mcMMOPlayer, PrimarySkillType.MINING); + public MiningManager(@NotNull McMMOPlayer mmoPlayer) { + super(mmoPlayer, PrimarySkillType.MINING); } public boolean canUseDemolitionsExpertise() { - if(!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.MINING_DEMOLITIONS_EXPERTISE)) + if (!RankUtils.hasUnlockedSubskill(getPlayer(), + SubSkillType.MINING_DEMOLITIONS_EXPERTISE)) { return false; + } - return getSkillLevel() >= BlastMining.getDemolitionExpertUnlockLevel() && Permissions.demolitionsExpertise(getPlayer()); + return getSkillLevel() >= BlastMining.getDemolitionExpertUnlockLevel() + && Permissions.demolitionsExpertise(getPlayer()); } public boolean canDetonate() { Player player = getPlayer(); - return canUseBlastMining() && player.isSneaking() - && (ItemUtils.isPickaxe(getPlayer().getInventory().getItemInMainHand()) || player.getInventory().getItemInMainHand().getType() == mcMMO.p.getGeneralConfig().getDetonatorItem()) + return canUseBlastMining() + && player.isSneaking() + && (isPickaxe(getPlayer().getInventory().getItemInMainHand()) || isDetonatorInHand( + player)) && Permissions.remoteDetonation(player); } + private static boolean isDetonatorInHand(Player player) { + return player.getInventory().getItemInMainHand().getType() == mcMMO.p.getGeneralConfig() + .getDetonatorItem(); + } + public boolean canUseBlastMining() { //Not checking permissions? return RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.MINING_BLAST_MINING); } public boolean canUseBiggerBombs() { - if(!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.MINING_BIGGER_BOMBS)) + if (!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.MINING_BIGGER_BOMBS)) { return false; + } - return getSkillLevel() >= BlastMining.getBiggerBombsUnlockLevel() && Permissions.biggerBombs(getPlayer()); + return getSkillLevel() >= BlastMining.getBiggerBombsUnlockLevel() + && Permissions.biggerBombs(getPlayer()); } public boolean canDoubleDrop() { - return RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.MINING_DOUBLE_DROPS) && Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.MINING_DOUBLE_DROPS); + return RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.MINING_DOUBLE_DROPS) + && Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.MINING_DOUBLE_DROPS); } + public boolean canMotherLode() { + return Permissions.canUseSubSkill(getPlayer(), SubSkillType.MINING_MOTHER_LODE); + } + + /** * Process double drops & XP gain for Mining. * * @param blockState The {@link BlockState} to check ability activation for */ + @Deprecated(since = "2.2.024", forRemoval = true) public void miningBlockCheck(BlockState blockState) { + miningBlockCheck(blockState.getBlock()); + } + + public void miningBlockCheck(Block block) { Player player = getPlayer(); - applyXpGain(Mining.getBlockXp(blockState), XPGainReason.PVE); + applyXpGain(ExperienceConfig.getInstance().getXp(PrimarySkillType.MINING, block), + XPGainReason.PVE); if (!Permissions.isSubSkillEnabled(player, SubSkillType.MINING_DOUBLE_DROPS)) { return; } if (mmoPlayer.getAbilityMode(mcMMO.p.getSkillTools().getSuperAbility(skill))) { - SkillUtils.handleDurabilityChange(getPlayer().getInventory().getItemInMainHand(), mcMMO.p.getGeneralConfig().getAbilityToolDamage()); + SkillUtils.handleDurabilityChange(getPlayer().getInventory().getItemInMainHand(), + mcMMO.p.getGeneralConfig().getAbilityToolDamage()); } - if(!mcMMO.p.getGeneralConfig().getDoubleDropsEnabled(PrimarySkillType.MINING, blockState.getType()) || !canDoubleDrop()) + if (!mcMMO.p.getGeneralConfig() + .getDoubleDropsEnabled(PrimarySkillType.MINING, block.getType()) + || !canDoubleDrop()) { return; + } - boolean silkTouch = player.getInventory().getItemInMainHand().containsEnchantment(Enchantment.SILK_TOUCH); + boolean silkTouch = player.getInventory().getItemInMainHand() + .containsEnchantment(Enchantment.SILK_TOUCH); - if(silkTouch && !mcMMO.p.getAdvancedConfig().getDoubleDropSilkTouchEnabled()) + if (silkTouch && !mcMMO.p.getAdvancedConfig().getDoubleDropSilkTouchEnabled()) { return; + } + //Mining mastery allows for a chance of triple drops + if (canMotherLode()) { + //Triple Drops failed so do a normal double drops check + if (!processTripleDrops(block)) { + processDoubleDrops(block); + } + } else { + //If the user has no mastery, proceed with normal double drop routine + processDoubleDrops(block); + } + } + + private boolean processTripleDrops(@NotNull Block block) { //TODO: Make this readable - if (RandomChanceUtil.checkRandomChanceExecutionSuccess(getPlayer(), SubSkillType.MINING_DOUBLE_DROPS, true)) { - boolean useTriple = mmoPlayer.getAbilityMode(mcMMO.p.getSkillTools().getSuperAbility(skill)) && mcMMO.p.getAdvancedConfig().getAllowMiningTripleDrops(); - BlockUtils.markDropsAsBonus(blockState, useTriple); + if (ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.MINING_MOTHER_LODE, mmoPlayer)) { + BlockUtils.markDropsAsBonus(block, 2); + return true; + } else { + return false; + } + } + + private void processDoubleDrops(@NotNull Block block) { + //TODO: Make this readable + if (ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.MINING_DOUBLE_DROPS, mmoPlayer)) { + boolean useTriple = mmoPlayer.getAbilityMode(SuperAbilityType.SUPER_BREAKER) + && mcMMO.p.getAdvancedConfig().getAllowMiningTripleDrops(); + BlockUtils.markDropsAsBonus(block, useTriple); } } @@ -107,30 +180,36 @@ public class MiningManager extends SkillManager { * Detonate TNT for Blast Mining */ public void remoteDetonation() { - Player player = getPlayer(); - Block targetBlock = player.getTargetBlock(BlockUtils.getTransparentBlocks(), BlastMining.MAXIMUM_REMOTE_DETONATION_DISTANCE); + final Player player = getPlayer(); + final Block targetBlock = player.getTargetBlock(BlockUtils.getTransparentBlocks(), + BlastMining.MAXIMUM_REMOTE_DETONATION_DISTANCE); //Blast mining cooldown check needs to be first so the player can be messaged - if (!blastMiningCooldownOver() || targetBlock.getType() != Material.TNT || !EventUtils.simulateBlockBreak(targetBlock, player)) { + if (!blastMiningCooldownOver() + || targetBlock.getType() != Material.TNT + || !EventUtils.simulateBlockBreak(targetBlock, player)) { return; } - TNTPrimed tnt = player.getWorld().spawn(targetBlock.getLocation(), TNTPrimed.class); + final TNTPrimed tnt = player.getWorld().spawn(targetBlock.getLocation(), TNTPrimed.class); - //SkillUtils.sendSkillMessage(player, SuperAbilityType.BLAST_MINING.getAbilityPlayer(player)); - NotificationManager.sendPlayerInformation(player, NotificationType.SUPER_ABILITY, "Mining.Blast.Boom"); - //player.sendMessage(LocaleLoader.getString("Mining.Blast.Boom")); + NotificationManager.sendPlayerInformation(player, NotificationType.SUPER_ABILITY, + "Mining.Blast.Boom"); tnt.setMetadata(MetadataConstants.METADATA_KEY_TRACKED_TNT, mmoPlayer.getPlayerMetadata()); tnt.setFuseTicks(0); - if (mcMMO.getCompatibilityManager().getMinecraftGameVersion().isAtLeast(1, 16, 4)) { - tnt.setSource(player); - } + tnt.setSource(player); targetBlock.setType(Material.AIR); mmoPlayer.setAbilityDATS(SuperAbilityType.BLAST_MINING, System.currentTimeMillis()); mmoPlayer.setAbilityInformed(SuperAbilityType.BLAST_MINING, false); - mcMMO.p.getFoliaLib().getImpl().runAtEntityLater(mmoPlayer.getPlayer(), new AbilityCooldownTask(mmoPlayer, SuperAbilityType.BLAST_MINING), (long) SuperAbilityType.BLAST_MINING.getCooldown() * Misc.TICK_CONVERSION_FACTOR); + mcMMO.p.getFoliaLib().getScheduler().runAtEntityLater(mmoPlayer.getPlayer(), + new AbilityCooldownTask(mmoPlayer, SuperAbilityType.BLAST_MINING), + (long) SuperAbilityType.BLAST_MINING.getCooldown() * Misc.TICK_CONVERSION_FACTOR); + } + + private boolean isInfestedBlock(String material) { + return INFESTED_BLOCKS.contains(material.toLowerCase(Locale.ENGLISH)); } /** @@ -139,81 +218,100 @@ public class MiningManager extends SkillManager { * @param yield The % of blocks to drop * @param event The {@link EntityExplodeEvent} */ - //TODO: Rewrite this garbage public void blastMiningDropProcessing(float yield, EntityExplodeEvent event) { - if (yield == 0) + if (yield == 0) { return; + } - //Strip out only stuff that gives mining XP - List ores = new ArrayList<>(); - - List notOres = new ArrayList<>(); + var increasedYieldFromBonuses = yield + (yield * getOreBonus()); + // Strip out only stuff that gives mining XP + final List ores = new ArrayList<>(); + final List notOres = new ArrayList<>(); for (Block targetBlock : event.blockList()) { - BlockState blockState = targetBlock.getState(); - //Containers usually have 0 XP unless someone edited their config in a very strange way - if (ExperienceConfig.getInstance().getXp(PrimarySkillType.MINING, targetBlock) != 0 - && !(targetBlock instanceof Container) - && !mcMMO.getPlaceStore().isTrue(targetBlock)) { - if(BlockUtils.isOre(blockState)) { - ores.add(blockState); + + if (mcMMO.getUserBlockTracker().isIneligible(targetBlock)) { + continue; + } + + if (ExperienceConfig.getInstance().getXp(PrimarySkillType.MINING, targetBlock) != 0) { + if (BlockUtils.isOre(targetBlock) && !(targetBlock instanceof Container)) { + ores.add(targetBlock); } else { - notOres.add(blockState); + notOres.add(targetBlock); } + } else { + notOres.add(targetBlock); } } int xp = 0; - - float oreBonus = (float) (getOreBonus() / 100); - float debrisReduction = (float) (getDebrisReduction() / 100); int dropMultiplier = getDropMultiplier(); - float debrisYield = yield - debrisReduction; - //Drop "debris" based on skill modifiers - for(BlockState blockState : notOres) { - if(isDropIllegal(blockState.getType())) + for (Block block : notOres) { + if (isDropIllegal(block.getType())) { continue; + } - if(RandomUtils.nextFloat() < debrisYield) { - Misc.spawnItem(getPlayer(), Misc.getBlockCenter(blockState), new ItemStack(blockState.getType()), ItemSpawnReason.BLAST_MINING_DEBRIS_NON_ORES); // Initial block that would have been dropped + if (block.getType().isItem() && Probability.ofPercent(10).evaluate()) { + ItemUtils.spawnItem(getPlayer(), + getBlockCenter(block), + new ItemStack(block.getType()), + ItemSpawnReason.BLAST_MINING_DEBRIS_NON_ORES); // Initial block that would have been dropped } } - for (BlockState blockState : ores) { - if(isDropIllegal(blockState.getType())) + for (Block block : ores) { + // currentOreYield only used for drop calculations for ores + float currentOreYield = Math.min(increasedYieldFromBonuses, 3F); + + if (isDropIllegal(block.getType())) { continue; + } - if (RandomUtils.nextFloat() < (yield + oreBonus)) { - xp += Mining.getBlockXp(blockState); + // Always give XP for every ore destroyed + xp += ExperienceConfig.getInstance().getXp(PrimarySkillType.MINING, block); + while (currentOreYield > 0) { + if (Probability.ofValue(currentOreYield).evaluate()) { + Collection oreDrops = + isPickaxe(mmoPlayer.getPlayer().getInventory().getItemInMainHand()) + ? block.getDrops( + mmoPlayer.getPlayer().getInventory().getItemInMainHand()) + : List.of(new ItemStack(block.getType())); + ItemUtils.spawnItems(getPlayer(), getBlockCenter(block), + oreDrops, BLAST_MINING_BLACKLIST, ItemSpawnReason.BLAST_MINING_ORES); - Misc.spawnItem(getPlayer(), Misc.getBlockCenter(blockState), new ItemStack(blockState.getType()), ItemSpawnReason.BLAST_MINING_ORES); // Initial block that would have been dropped - - if (mcMMO.p.getAdvancedConfig().isBlastMiningBonusDropsEnabled() && !mcMMO.getPlaceStore().isTrue(blockState)) { - for (int i = 1; i < dropMultiplier; i++) { -// Bukkit.broadcastMessage("Bonus Drop on Ore: "+blockState.getType().toString()); - Misc.spawnItem(getPlayer(), Misc.getBlockCenter(blockState), new ItemStack(blockState.getType()), ItemSpawnReason.BLAST_MINING_ORES_BONUS_DROP); // Initial block that would have been dropped + if (mcMMO.p.getAdvancedConfig().isBlastMiningBonusDropsEnabled()) { + if (Probability.ofValue(0.5F).evaluate()) { + for (int i = 1; i < dropMultiplier; i++) { + ItemUtils.spawnItems(getPlayer(), + getBlockCenter(block), + oreDrops, + BLAST_MINING_BLACKLIST, + ItemSpawnReason.BLAST_MINING_ORES_BONUS_DROP); + } + } } } + currentOreYield = Math.max(currentOreYield - 1, 0); } } - //Replace the event blocklist with the newYield list + // Replace the event blocklist with the newYield list event.setYield(0F); -// event.blockList().clear(); -// event.blockList().addAll(notOres); - - applyXpGain(xp, XPGainReason.PVE); + applyXpGain(xp, XPGainReason.PVE, XPGainSource.SELF); } /** - * Checks if it would be illegal (in vanilla) to obtain the block - * Certain things should never drop ( such as budding_amethyst ) + * Checks if it would be illegal (in vanilla) to obtain the block Certain things should never + * drop (such as budding_amethyst, infested blocks or spawners) * * @param material target material - * @return true if it's not legal to obtain the block through normal gameplay + * @return true if it's not legal to get the block through normal gameplay */ public boolean isDropIllegal(@NotNull Material material) { - return material.getKey().getKey().equalsIgnoreCase(BUDDING_AMETHYST); + return isInfestedBlock(material.getKey().getKey()) + || material.getKey().getKey().equalsIgnoreCase(BUDDING_AMETHYST) + || material == Material.SPAWNER; } /** @@ -244,10 +342,11 @@ public class MiningManager extends SkillManager { * * @return the Blast Mining tier */ - public double getOreBonus() { - return getOreBonus(getBlastMiningTier()); + public float getOreBonus() { + return (float) (mcMMO.p.getAdvancedConfig().getOreBonus(getBlastMiningTier()) / 100F); } + @Deprecated(since = "2.2.017", forRemoval = true) public static double getOreBonus(int rank) { return mcMMO.p.getAdvancedConfig().getOreBonus(rank); } @@ -310,7 +409,9 @@ public class MiningManager extends SkillManager { if (timeRemaining > 0) { //getPlayer().sendMessage(LocaleLoader.getString("Skills.TooTired", timeRemaining)); - NotificationManager.sendPlayerInformation(getPlayer(), NotificationType.ABILITY_COOLDOWN, "Skills.TooTired", String.valueOf(timeRemaining)); + NotificationManager.sendPlayerInformation(getPlayer(), + NotificationType.ABILITY_COOLDOWN, "Skills.TooTired", + String.valueOf(timeRemaining)); return false; } diff --git a/src/main/java/com/gmail/nossr50/skills/repair/ArcaneForging.java b/src/main/java/com/gmail/nossr50/skills/repair/ArcaneForging.java index 05bcfb160..1729627c8 100644 --- a/src/main/java/com/gmail/nossr50/skills/repair/ArcaneForging.java +++ b/src/main/java/com/gmail/nossr50/skills/repair/ArcaneForging.java @@ -4,6 +4,8 @@ import com.gmail.nossr50.mcMMO; public class ArcaneForging { - public static boolean arcaneForgingDowngrades = mcMMO.p.getAdvancedConfig().getArcaneForgingDowngradeEnabled(); - public static boolean arcaneForgingEnchantLoss = mcMMO.p.getAdvancedConfig().getArcaneForgingEnchantLossEnabled(); + public static boolean arcaneForgingDowngrades = mcMMO.p.getAdvancedConfig() + .getArcaneForgingDowngradeEnabled(); + public static boolean arcaneForgingEnchantLoss = mcMMO.p.getAdvancedConfig() + .getArcaneForgingEnchantLossEnabled(); } diff --git a/src/main/java/com/gmail/nossr50/skills/repair/Repair.java b/src/main/java/com/gmail/nossr50/skills/repair/Repair.java index 36ba8cdc5..b8d86ca59 100644 --- a/src/main/java/com/gmail/nossr50/skills/repair/Repair.java +++ b/src/main/java/com/gmail/nossr50/skills/repair/Repair.java @@ -5,8 +5,10 @@ import com.gmail.nossr50.mcMMO; import org.bukkit.Material; public class Repair { - public static int repairMasteryMaxBonusLevel = mcMMO.p.getAdvancedConfig().getMaxBonusLevel(SubSkillType.REPAIR_REPAIR_MASTERY); - public static double repairMasteryMaxBonus = mcMMO.p.getAdvancedConfig().getRepairMasteryMaxBonus(); + public static int repairMasteryMaxBonusLevel = mcMMO.p.getAdvancedConfig() + .getMaxBonusLevel(SubSkillType.REPAIR_REPAIR_MASTERY); + public static double repairMasteryMaxBonus = mcMMO.p.getAdvancedConfig() + .getRepairMasteryMaxBonus(); - public static Material anvilMaterial = mcMMO.p.getGeneralConfig().getRepairAnvilMaterial(); + public static Material anvilMaterial = mcMMO.p.getGeneralConfig().getRepairAnvilMaterial(); } 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 284f875c6..9051a8872 100644 --- a/src/main/java/com/gmail/nossr50/skills/repair/RepairManager.java +++ b/src/main/java/com/gmail/nossr50/skills/repair/RepairManager.java @@ -14,14 +14,17 @@ import com.gmail.nossr50.util.EventUtils; 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.random.ProbabilityUtil; 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; +import java.util.Arrays; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Objects; +import java.util.Optional; import org.bukkit.Material; import org.bukkit.SoundCategory; import org.bukkit.enchantments.Enchantment; @@ -29,18 +32,12 @@ import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.PlayerInventory; -import java.util.Arrays; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Objects; -import java.util.Optional; - public class RepairManager extends SkillManager { private boolean placedAnvil; - private int lastClick; + private int lastClick; - public RepairManager(McMMOPlayer mcMMOPlayer) { - super(mcMMOPlayer, PrimarySkillType.REPAIR); + public RepairManager(McMMOPlayer mmoPlayer) { + super(mmoPlayer, PrimarySkillType.REPAIR); } /** @@ -54,11 +51,13 @@ public class RepairManager extends SkillManager { } if (mcMMO.p.getGeneralConfig().getRepairAnvilMessagesEnabled()) { - NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE, "Repair.Listener.Anvil"); + NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE, + "Repair.Listener.Anvil"); } if (mcMMO.p.getGeneralConfig().getRepairAnvilPlaceSoundsEnabled()) { - SoundManager.sendCategorizedSound(player, player.getLocation(), SoundType.ANVIL, SoundCategory.BLOCKS); + SoundManager.sendCategorizedSound(player, player.getLocation(), SoundType.ANVIL, + SoundCategory.BLOCKS); } togglePlacedAnvil(); @@ -67,20 +66,33 @@ public class RepairManager extends SkillManager { public void handleRepair(ItemStack item) { Player player = getPlayer(); Repairable repairable = mcMMO.getRepairableManager().getRepairable(item.getType()); + if (item.getItemMeta() != null) { + if (item.getItemMeta().hasCustomModelData()) { + if (!mcMMO.p.getCustomItemSupportConfig().isCustomRepairAllowed()) { + NotificationManager.sendPlayerInformation(player, + NotificationType.SUBSKILL_MESSAGE_FAILED, + "Anvil.Repair.Reject.CustomModelData"); + return; + } + } - if (item.getItemMeta().isUnbreakable()) { - NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE_FAILED, "Anvil.Unbreakable"); - return; + if (item.getItemMeta().isUnbreakable()) { + NotificationManager.sendPlayerInformation(player, + NotificationType.SUBSKILL_MESSAGE_FAILED, "Anvil.Unbreakable"); + return; + } } // Permissions checks on material and item types if (!Permissions.repairMaterialType(player, repairable.getRepairMaterialType())) { - NotificationManager.sendPlayerInformation(player, NotificationType.NO_PERMISSION, "mcMMO.NoPermission"); + NotificationManager.sendPlayerInformation(player, NotificationType.NO_PERMISSION, + "mcMMO.NoPermission"); return; } if (!Permissions.repairItemType(player, repairable.getRepairItemType())) { - NotificationManager.sendPlayerInformation(player, NotificationType.NO_PERMISSION, "mcMMO.NoPermission"); + NotificationManager.sendPlayerInformation(player, NotificationType.NO_PERMISSION, + "mcMMO.NoPermission"); return; } @@ -89,7 +101,10 @@ public class RepairManager extends SkillManager { // Level check if (skillLevel < minimumRepairableLevel) { - NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE_FAILED, "Repair.Skills.Adept", String.valueOf(minimumRepairableLevel), StringUtils.getPrettyItemString(item.getType())); + NotificationManager.sendPlayerInformation(player, + NotificationType.SUBSKILL_MESSAGE_FAILED, "Repair.Skills.Adept", + String.valueOf(minimumRepairableLevel), + StringUtils.getPrettyMaterialString(item.getType())); return; } @@ -102,23 +117,29 @@ public class RepairManager extends SkillManager { // Do not repair if at full durability if (startDurability <= 0) { - NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE_FAILED, "Repair.Skills.FullDurability"); + NotificationManager.sendPlayerInformation(player, + NotificationType.SUBSKILL_MESSAGE_FAILED, "Repair.Skills.FullDurability"); return; } // Check if they have the proper material to repair with if (!inventory.contains(repairMaterial)) { - String prettyName = repairable.getRepairMaterialPrettyName() == null ? StringUtils.getPrettyItemString(repairMaterial) : repairable.getRepairMaterialPrettyName(); + String prettyName = repairable.getRepairMaterialPrettyName() == null + ? StringUtils.getPrettyMaterialString(repairMaterial) + : repairable.getRepairMaterialPrettyName(); String materialsNeeded = ""; - NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE_FAILED, "Skills.NeedMore.Extra", prettyName, materialsNeeded); + NotificationManager.sendPlayerInformation(player, + NotificationType.SUBSKILL_MESSAGE_FAILED, "Skills.NeedMore.Extra", prettyName, + materialsNeeded); return; } // Do not repair stacked items if (item.getAmount() != 1) { - NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE_FAILED, "Repair.Skills.StackedItems"); + NotificationManager.sendPlayerInformation(player, + NotificationType.SUBSKILL_MESSAGE_FAILED, "Repair.Skills.StackedItems"); return; } @@ -127,8 +148,10 @@ public class RepairManager extends SkillManager { // Lets get down to business, // To defeat, the huns. - int baseRepairAmount = repairable.getBaseRepairDurability(item); // Did they send me daughters? - short newDurability = repairCalculate(startDurability, baseRepairAmount); // When I asked for sons? + int baseRepairAmount = repairable.getBaseRepairDurability( + item); // Did they send me daughters? + short newDurability = repairCalculate(startDurability, + baseRepairAmount); // When I asked for sons? // toRemove should be refreshed before the event call. toRemove = inventory.getItem(inventory.first(repairMaterial)).clone(); @@ -149,11 +172,15 @@ public class RepairManager extends SkillManager { // Fail out with "you need material" if we don't find a suitable alternative. if (possibleMaterial.isEmpty()) { - String prettyName = repairable.getRepairMaterialPrettyName() == null ? StringUtils.getPrettyItemString(repairMaterial) : repairable.getRepairMaterialPrettyName(); + String prettyName = repairable.getRepairMaterialPrettyName() == null + ? StringUtils.getPrettyMaterialString(repairMaterial) + : repairable.getRepairMaterialPrettyName(); String materialsNeeded = ""; - NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE_FAILED, "Skills.NeedMore.Extra", prettyName, materialsNeeded); + NotificationManager.sendPlayerInformation(player, + NotificationType.SUBSKILL_MESSAGE_FAILED, "Skills.NeedMore.Extra", + prettyName, materialsNeeded); return; } @@ -163,12 +190,14 @@ public class RepairManager extends SkillManager { } // Call event - if (EventUtils.callRepairCheckEvent(player, (short) (startDurability - newDurability), toRemove, item).isCancelled()) { + if (EventUtils.callRepairCheckEvent(player, (short) (startDurability - newDurability), + toRemove, item).isCancelled()) { return; } // Handle the enchants - if (ArcaneForging.arcaneForgingEnchantLoss && !Permissions.hasRepairEnchantBypassPerk(player)) { + if (ArcaneForging.arcaneForgingEnchantLoss && !Permissions.hasRepairEnchantBypassPerk( + player)) { addEnchants(item); } @@ -178,22 +207,27 @@ public class RepairManager extends SkillManager { inventory.removeItem(toRemove); // Give out XP like candy - applyXpGain((float) ((getPercentageRepaired(startDurability, newDurability, repairable.getMaximumDurability()) - * repairable.getXpMultiplier()) - * ExperienceConfig.getInstance().getRepairXPBase() - * ExperienceConfig.getInstance().getRepairXP(repairable.getRepairMaterialType())), XPGainReason.PVE); + applyXpGain((float) ((getPercentageRepaired(startDurability, newDurability, + repairable.getMaximumDurability()) + * repairable.getXpMultiplier()) + * ExperienceConfig.getInstance().getRepairXPBase() + * ExperienceConfig.getInstance().getRepairXP(repairable.getRepairMaterialType())), + XPGainReason.PVE); // BWONG BWONG BWONG if (mcMMO.p.getGeneralConfig().getRepairAnvilUseSoundsEnabled()) { - SoundManager.sendCategorizedSound(player, player.getLocation(), SoundType.ANVIL, SoundCategory.BLOCKS); - SoundManager.sendCategorizedSound(player, player.getLocation(), SoundType.ITEM_BREAK, SoundCategory.PLAYERS); + SoundManager.sendCategorizedSound(player, player.getLocation(), SoundType.ANVIL, + SoundCategory.BLOCKS); + SoundManager.sendCategorizedSound(player, player.getLocation(), SoundType.ITEM_BREAK, + SoundCategory.PLAYERS); } // Repair the item! item.setDurability(newDurability); } - private float getPercentageRepaired(short startDurability, short newDurability, short totalDurability) { + private float getPercentageRepaired(short startDurability, short newDurability, + short totalDurability) { return ((startDurability - newDurability) / (float) totalDurability); } @@ -206,7 +240,8 @@ public class RepairManager extends SkillManager { Player player = getPlayer(); long lastUse = getLastAnvilUse(); - if (!SkillUtils.cooldownExpired(lastUse, 3) || !mcMMO.p.getGeneralConfig().getRepairConfirmRequired()) { + if (!SkillUtils.cooldownExpired(lastUse, 3) || !mcMMO.p.getGeneralConfig() + .getRepairConfirmRequired()) { return true; } @@ -215,7 +250,8 @@ public class RepairManager extends SkillManager { } actualizeLastAnvilUse(); - NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE, "Skills.ConfirmOrCancel", LocaleLoader.getString("Repair.Pretty.Name")); + NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE, + "Skills.ConfirmOrCancel", LocaleLoader.getString("Repair.Pretty.Name")); return false; } @@ -235,7 +271,8 @@ public class RepairManager extends SkillManager { * @return The chance of keeping the enchantment */ public double getKeepEnchantChance() { - return mcMMO.p.getAdvancedConfig().getArcaneForgingKeepEnchantsChance(getArcaneForgingRank()); + return mcMMO.p.getAdvancedConfig() + .getArcaneForgingKeepEnchantsChance(getArcaneForgingRank()); } /** @@ -295,14 +332,16 @@ public class RepairManager extends SkillManager { && RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.REPAIR_REPAIR_MASTERY)) { double maxBonusCalc = Repair.repairMasteryMaxBonus / 100.0D; - double skillLevelBonusCalc = (Repair.repairMasteryMaxBonus / Repair.repairMasteryMaxBonusLevel) * (getSkillLevel() / 100.0D); + double skillLevelBonusCalc = + (Repair.repairMasteryMaxBonus / Repair.repairMasteryMaxBonusLevel) * ( + getSkillLevel() / 100.0D); double bonus = repairAmount * Math.min(skillLevelBonusCalc, maxBonusCalc); - repairAmount += bonus; } - if (Permissions.isSubSkillEnabled(player, SubSkillType.REPAIR_SUPER_REPAIR) && checkPlayerProcRepair()) { + if (Permissions.isSubSkillEnabled(player, SubSkillType.REPAIR_SUPER_REPAIR) + && checkPlayerProcRepair()) { repairAmount *= 2.0D; } @@ -319,11 +358,13 @@ public class RepairManager extends SkillManager { * @return true if bonus granted, false otherwise */ private boolean checkPlayerProcRepair() { - if(!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.REPAIR_SUPER_REPAIR)) + 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())) { - NotificationManager.sendPlayerInformation(getPlayer(), NotificationType.SUBSKILL_MESSAGE, "Repair.Skills.FeltEasy"); + if (ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.REPAIR_SUPER_REPAIR, mmoPlayer)) { + NotificationManager.sendPlayerInformation(getPlayer(), + NotificationType.SUBSKILL_MESSAGE, "Repair.Skills.FeltEasy"); return true; } @@ -345,16 +386,19 @@ public class RepairManager extends SkillManager { } if (Permissions.arcaneBypass(player)) { - NotificationManager.sendPlayerInformation(getPlayer(), NotificationType.SUBSKILL_MESSAGE, "Repair.Arcane.Perfect"); + NotificationManager.sendPlayerInformation(getPlayer(), + NotificationType.SUBSKILL_MESSAGE, "Repair.Arcane.Perfect"); return; } - if (getArcaneForgingRank() == 0 || !Permissions.isSubSkillEnabled(player, SubSkillType.REPAIR_ARCANE_FORGING)) { + if (getArcaneForgingRank() == 0 || !Permissions.isSubSkillEnabled(player, + SubSkillType.REPAIR_ARCANE_FORGING)) { for (Enchantment enchant : enchants.keySet()) { item.removeEnchantment(enchant); } - NotificationManager.sendPlayerInformation(getPlayer(), NotificationType.SUBSKILL_MESSAGE_FAILED, "Repair.Arcane.Lost"); + NotificationManager.sendPlayerInformation(getPlayer(), + NotificationType.SUBSKILL_MESSAGE_FAILED, "Repair.Arcane.Lost"); return; } @@ -363,25 +407,26 @@ public class RepairManager extends SkillManager { for (Entry enchant : enchants.entrySet()) { int enchantLevel = enchant.getValue(); - if(!ExperienceConfig.getInstance().allowUnsafeEnchantments()) { - if(enchantLevel > enchant.getKey().getMaxLevel()) { + if (!ExperienceConfig.getInstance().allowUnsafeEnchantments()) { + if (enchantLevel > enchant.getKey().getMaxLevel()) { enchantLevel = enchant.getKey().getMaxLevel(); - item.addEnchantment(enchant.getKey(), enchantLevel); + item.addUnsafeEnchantment(enchant.getKey(), enchantLevel); } } Enchantment enchantment = enchant.getKey(); - if (RandomChanceUtil.checkRandomChanceExecutionSuccess(new RandomChanceSkillStatic(getKeepEnchantChance(), getPlayer(), SubSkillType.REPAIR_ARCANE_FORGING))) { + if (ProbabilityUtil.isStaticSkillRNGSuccessful(PrimarySkillType.REPAIR, mmoPlayer, + getKeepEnchantChance())) { if (ArcaneForging.arcaneForgingDowngrades && enchantLevel > 1 - && (!RandomChanceUtil.checkRandomChanceExecutionSuccess(new RandomChanceSkillStatic(100 - getDowngradeEnchantChance(), getPlayer(), SubSkillType.REPAIR_ARCANE_FORGING)))) { + && (!ProbabilityUtil.isStaticSkillRNGSuccessful(PrimarySkillType.REPAIR, + mmoPlayer, 100 - getDowngradeEnchantChance()))) { item.addUnsafeEnchantment(enchantment, enchantLevel - 1); downgraded = true; } - } - else { + } else { item.removeEnchantment(enchantment); } } @@ -389,13 +434,12 @@ public class RepairManager extends SkillManager { Map newEnchants = item.getEnchantments(); if (newEnchants.isEmpty()) { - NotificationManager.sendPlayerInformationChatOnly(getPlayer(), "Repair.Arcane.Fail"); - } - else if (downgraded || newEnchants.size() < enchants.size()) { - NotificationManager.sendPlayerInformationChatOnly(getPlayer(), "Repair.Arcane.Downgrade"); - } - else { - NotificationManager.sendPlayerInformationChatOnly(getPlayer(), "Repair.Arcane.Perfect"); + NotificationManager.sendPlayerInformationChatOnly(getPlayer(), "Repair.Arcane.Fail"); + } else if (downgraded || newEnchants.size() < enchants.size()) { + NotificationManager.sendPlayerInformationChatOnly(getPlayer(), + "Repair.Arcane.Downgrade"); + } else { + NotificationManager.sendPlayerInformationChatOnly(getPlayer(), "Repair.Arcane.Perfect"); } } diff --git a/src/main/java/com/gmail/nossr50/skills/repair/repairables/Repairable.java b/src/main/java/com/gmail/nossr50/skills/repair/repairables/Repairable.java index b59333f9d..4a3a00947 100644 --- a/src/main/java/com/gmail/nossr50/skills/repair/repairables/Repairable.java +++ b/src/main/java/com/gmail/nossr50/skills/repair/repairables/Repairable.java @@ -44,8 +44,9 @@ public interface Repairable { /** * Gets the minimum quantity of repair materials ignoring all other repair bonuses - * - * This is typically set to the number of items needed to create that item, for example 5 for helmets or 2 for swords + *

+ * This is typically set to the number of items needed to create that item, for example 5 for + * helmets or 2 for swords * * @return the minimum number of items */ @@ -60,7 +61,7 @@ public interface Repairable { /** * Gets the base repair durability on which to calculate bonuses. - * + *

* This is actually the maximum durability divided by the minimum quantity * * @return the base repair durability diff --git a/src/main/java/com/gmail/nossr50/skills/repair/repairables/RepairableFactory.java b/src/main/java/com/gmail/nossr50/skills/repair/repairables/RepairableFactory.java index 85ed7d8ae..a6826cc91 100644 --- a/src/main/java/com/gmail/nossr50/skills/repair/repairables/RepairableFactory.java +++ b/src/main/java/com/gmail/nossr50/skills/repair/repairables/RepairableFactory.java @@ -6,23 +6,35 @@ import org.bukkit.Material; public class RepairableFactory { - public static Repairable getRepairable(Material itemMaterial, Material repairMaterial, short maximumDurability) { - return getRepairable(itemMaterial, repairMaterial, null, 0, maximumDurability, ItemType.OTHER, MaterialType.OTHER, 1); + public static Repairable getRepairable(Material itemMaterial, Material repairMaterial, + short maximumDurability) { + return getRepairable(itemMaterial, repairMaterial, null, 0, maximumDurability, + ItemType.OTHER, MaterialType.OTHER, 1); } - public static Repairable getRepairable(Material itemMaterial, Material repairMaterial, int minimumLevel, short maximumDurability, ItemType repairItemType, MaterialType repairMaterialType, double xpMultiplier) { - return getRepairable(itemMaterial, repairMaterial, null, minimumLevel, maximumDurability, repairItemType, repairMaterialType, xpMultiplier); + public static Repairable getRepairable(Material itemMaterial, Material repairMaterial, + int minimumLevel, short maximumDurability, ItemType repairItemType, + MaterialType repairMaterialType, double xpMultiplier) { + return getRepairable(itemMaterial, repairMaterial, null, minimumLevel, maximumDurability, + repairItemType, repairMaterialType, xpMultiplier); } - public static Repairable getRepairable(Material itemMaterial, Material repairMaterial, String repairMaterialPrettyName, - int minimumLevel, short maximumDurability, ItemType repairItemType, MaterialType repairMaterialType, double xpMultiplier) { + public static Repairable getRepairable(Material itemMaterial, Material repairMaterial, + String repairMaterialPrettyName, + int minimumLevel, short maximumDurability, ItemType repairItemType, + MaterialType repairMaterialType, double xpMultiplier) { // TODO: Add in loading from config what type of repairable we want. - return new SimpleRepairable(itemMaterial, repairMaterial, repairMaterialPrettyName, minimumLevel, maximumDurability, repairItemType, repairMaterialType, xpMultiplier); + return new SimpleRepairable(itemMaterial, repairMaterial, repairMaterialPrettyName, + minimumLevel, maximumDurability, repairItemType, repairMaterialType, xpMultiplier); } - public static Repairable getRepairable(Material itemMaterial, Material repairMaterial, String repairMaterialPrettyName, - int minimumLevel, short maximumDurability, ItemType repairItemType, MaterialType repairMaterialType, double xpMultiplier, int minQuantity) { + public static Repairable getRepairable(Material itemMaterial, Material repairMaterial, + String repairMaterialPrettyName, + int minimumLevel, short maximumDurability, ItemType repairItemType, + MaterialType repairMaterialType, double xpMultiplier, int minQuantity) { // TODO: Add in loading from config what type of repairable we want. - return new SimpleRepairable(itemMaterial, repairMaterial, repairMaterialPrettyName, minimumLevel, maximumDurability, repairItemType, repairMaterialType, xpMultiplier, minQuantity); + return new SimpleRepairable(itemMaterial, repairMaterial, repairMaterialPrettyName, + minimumLevel, maximumDurability, repairItemType, repairMaterialType, xpMultiplier, + minQuantity); } } diff --git a/src/main/java/com/gmail/nossr50/skills/repair/repairables/RepairableManager.java b/src/main/java/com/gmail/nossr50/skills/repair/repairables/RepairableManager.java index fbfe46019..bfb744f33 100644 --- a/src/main/java/com/gmail/nossr50/skills/repair/repairables/RepairableManager.java +++ b/src/main/java/com/gmail/nossr50/skills/repair/repairables/RepairableManager.java @@ -1,10 +1,9 @@ package com.gmail.nossr50.skills.repair.repairables; +import java.util.List; import org.bukkit.Material; import org.bukkit.inventory.ItemStack; -import java.util.List; - public interface RepairableManager { /** * Register a repairable with the RepairManager @@ -24,7 +23,6 @@ public interface RepairableManager { * Checks if an item is repairable * * @param type Material to check if repairable - * * @return true if repairable, false if not */ boolean isRepairable(Material type); @@ -33,7 +31,6 @@ public interface RepairableManager { * Checks if an item is repairable * * @param itemStack Item to check if repairable - * * @return true if repairable, false if not */ boolean isRepairable(ItemStack itemStack); @@ -42,7 +39,6 @@ public interface RepairableManager { * Gets the repairable with this type * * @param type Material of the repairable to look for - * * @return the repairable, can be null */ Repairable getRepairable(Material type); diff --git a/src/main/java/com/gmail/nossr50/skills/repair/repairables/SimpleRepairable.java b/src/main/java/com/gmail/nossr50/skills/repair/repairables/SimpleRepairable.java index de201456d..af1913962 100644 --- a/src/main/java/com/gmail/nossr50/skills/repair/repairables/SimpleRepairable.java +++ b/src/main/java/com/gmail/nossr50/skills/repair/repairables/SimpleRepairable.java @@ -17,7 +17,9 @@ public class SimpleRepairable implements Repairable { private final double xpMultiplier; private int minQuantity = -1; - protected SimpleRepairable(Material type, Material repairMaterial, String repairMaterialPrettyName, int minimumLevel, short maximumDurability, ItemType repairItemType, MaterialType repairMaterialType, double xpMultiplier) { + protected SimpleRepairable(Material type, Material repairMaterial, + String repairMaterialPrettyName, int minimumLevel, short maximumDurability, + ItemType repairItemType, MaterialType repairMaterialType, double xpMultiplier) { this.itemMaterial = type; this.repairMaterial = repairMaterial; this.repairMaterialPrettyName = repairMaterialPrettyName; @@ -28,7 +30,10 @@ public class SimpleRepairable implements Repairable { this.xpMultiplier = xpMultiplier; } - protected SimpleRepairable(Material type, Material repairMaterial, String repairMaterialPrettyName, int minimumLevel, short maximumDurability, ItemType repairItemType, MaterialType repairMaterialType, double xpMultiplier, int minQuantity) { + protected SimpleRepairable(Material type, Material repairMaterial, + String repairMaterialPrettyName, int minimumLevel, short maximumDurability, + ItemType repairItemType, MaterialType repairMaterialType, double xpMultiplier, + int minQuantity) { this.itemMaterial = type; this.repairMaterial = repairMaterial; this.repairMaterialPrettyName = repairMaterialPrettyName; @@ -67,10 +72,12 @@ public class SimpleRepairable implements Repairable { @Override public int getMinimumQuantity() { - if(minQuantity == -1) - return Math.max(SkillUtils.getRepairAndSalvageQuantities(itemMaterial, repairMaterial), 1); - else + if (minQuantity == -1) { + return Math.max(SkillUtils.getRepairAndSalvageQuantities(itemMaterial, repairMaterial), + 1); + } else { return minQuantity; + } } @Override diff --git a/src/main/java/com/gmail/nossr50/skills/repair/repairables/SimpleRepairableManager.java b/src/main/java/com/gmail/nossr50/skills/repair/repairables/SimpleRepairableManager.java index dd7a74f36..f437e9511 100644 --- a/src/main/java/com/gmail/nossr50/skills/repair/repairables/SimpleRepairableManager.java +++ b/src/main/java/com/gmail/nossr50/skills/repair/repairables/SimpleRepairableManager.java @@ -1,10 +1,9 @@ package com.gmail.nossr50.skills.repair.repairables; -import org.bukkit.Material; -import org.bukkit.inventory.ItemStack; - import java.util.HashMap; import java.util.List; +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; public class SimpleRepairableManager implements RepairableManager { private final HashMap repairables; diff --git a/src/main/java/com/gmail/nossr50/skills/salvage/Salvage.java b/src/main/java/com/gmail/nossr50/skills/salvage/Salvage.java index 4f510f909..92f1937bb 100644 --- a/src/main/java/com/gmail/nossr50/skills/salvage/Salvage.java +++ b/src/main/java/com/gmail/nossr50/skills/salvage/Salvage.java @@ -6,11 +6,12 @@ import org.bukkit.Material; public final class Salvage { /** - * This is a static utility class, therefore we don't want any instances of - * this class. Making the constructor private prevents accidents like that. + * This is a static utility class, therefore we don't want any instances of this class. Making + * the constructor private prevents accidents like that. */ - private Salvage() {} - + private Salvage() { + } + public static Material anvilMaterial = mcMMO.p.getGeneralConfig().getSalvageAnvilMaterial(); /*public static int salvageMaxPercentageLevel = mcMMO.p.getAdvancedConfig().getSalvageMaxPercentageLevel(); @@ -18,11 +19,15 @@ public final class Salvage { public static int advancedSalvageUnlockLevel = RankUtils.getRankUnlockLevel(SubSkillType.SALVAGE_SCRAP_COLLECTOR, 1);*/ - public static boolean arcaneSalvageDowngrades = mcMMO.p.getAdvancedConfig().getArcaneSalvageEnchantDowngradeEnabled(); - public static boolean arcaneSalvageEnchantLoss = mcMMO.p.getAdvancedConfig().getArcaneSalvageEnchantLossEnabled(); + public static boolean arcaneSalvageDowngrades = mcMMO.p.getAdvancedConfig() + .getArcaneSalvageEnchantDowngradeEnabled(); + public static boolean arcaneSalvageEnchantLoss = mcMMO.p.getAdvancedConfig() + .getArcaneSalvageEnchantLossEnabled(); - static int calculateSalvageableAmount(int currentDurability, short maxDurability, int baseAmount) { - double percentDamaged = (maxDurability <= 0) ? 1D : (double) (maxDurability - currentDurability) / maxDurability; + static int calculateSalvageableAmount(int currentDurability, short maxDurability, + int baseAmount) { + double percentDamaged = (maxDurability <= 0) ? 1D + : (double) (maxDurability - currentDurability) / maxDurability; return (int) Math.floor(baseAmount * percentDamaged); } 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 4e4c04ff3..5fd5f05bb 100644 --- a/src/main/java/com/gmail/nossr50/skills/salvage/SalvageManager.java +++ b/src/main/java/com/gmail/nossr50/skills/salvage/SalvageManager.java @@ -11,16 +11,18 @@ import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.skills.SkillManager; import com.gmail.nossr50.skills.salvage.salvageables.Salvageable; 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.random.RandomChanceSkillStatic; -import com.gmail.nossr50.util.random.RandomChanceUtil; +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; import com.gmail.nossr50.util.sounds.SoundType; import com.gmail.nossr50.util.text.StringUtils; +import java.util.Map; +import java.util.Map.Entry; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.enchantments.Enchantment; @@ -30,15 +32,12 @@ import org.bukkit.inventory.meta.Damageable; import org.bukkit.inventory.meta.EnchantmentStorageMeta; import org.bukkit.inventory.meta.ItemMeta; -import java.util.Map; -import java.util.Map.Entry; - public class SalvageManager extends SkillManager { private boolean placedAnvil; - private int lastClick; + private int lastClick; - public SalvageManager(McMMOPlayer mcMMOPlayer) { - super(mcMMOPlayer, PrimarySkillType.SALVAGE); + public SalvageManager(McMMOPlayer mmoPlayer) { + super(mmoPlayer, PrimarySkillType.SALVAGE); } /** @@ -52,7 +51,8 @@ public class SalvageManager extends SkillManager { } if (mcMMO.p.getGeneralConfig().getSalvageAnvilMessagesEnabled()) { - NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE, "Salvage.Listener.Anvil"); + NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE, + "Salvage.Listener.Anvil"); } if (mcMMO.p.getGeneralConfig().getSalvageAnvilPlaceSoundsEnabled()) { @@ -63,24 +63,36 @@ public class SalvageManager extends SkillManager { } public void handleSalvage(Location location, ItemStack item) { - Player player = getPlayer(); + final Player player = getPlayer(); - Salvageable salvageable = mcMMO.getSalvageableManager().getSalvageable(item.getType()); - ItemMeta meta = item.getItemMeta(); - - if (meta != null && meta.isUnbreakable()) { - NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE_FAILED, "Anvil.Unbreakable"); - return; + final Salvageable salvageable = mcMMO.getSalvageableManager() + .getSalvageable(item.getType()); + final ItemMeta meta = item.getItemMeta(); + if (meta != null) { + if (meta.hasCustomModelData() && !mcMMO.p.getCustomItemSupportConfig() + .isCustomSalvageAllowed()) { + NotificationManager.sendPlayerInformation(player, + NotificationType.SUBSKILL_MESSAGE_FAILED, + "Anvil.Salvage.Reject.CustomModelData"); + return; + } + if (meta.isUnbreakable()) { + NotificationManager.sendPlayerInformation(player, + NotificationType.SUBSKILL_MESSAGE_FAILED, "Anvil.Unbreakable"); + return; + } } // Permissions checks on material and item types if (!Permissions.salvageItemType(player, salvageable.getSalvageItemType())) { - NotificationManager.sendPlayerInformation(player, NotificationType.NO_PERMISSION, "mcMMO.NoPermission"); + NotificationManager.sendPlayerInformation(player, NotificationType.NO_PERMISSION, + "mcMMO.NoPermission"); return; } if (!Permissions.salvageMaterialType(player, salvageable.getSalvageMaterialType())) { - NotificationManager.sendPlayerInformation(player, NotificationType.NO_PERMISSION, "mcMMO.NoPermission"); + NotificationManager.sendPlayerInformation(player, NotificationType.NO_PERMISSION, + "mcMMO.NoPermission"); return; } @@ -91,19 +103,23 @@ public class SalvageManager extends SkillManager { if (getSkillLevel() < minimumSalvageableLevel) { NotificationManager.sendPlayerInformation(player, NotificationType.REQUIREMENTS_NOT_MET, "Salvage.Skills.Adept.Level", - String.valueOf(minimumSalvageableLevel), StringUtils.getPrettyItemString(item.getType())); + String.valueOf(minimumSalvageableLevel), + StringUtils.getPrettyMaterialString(item.getType())); return; } - int durability = meta instanceof Damageable ? ((Damageable) meta).getDamage(): 0; - int potentialSalvageYield = Salvage.calculateSalvageableAmount(durability, salvageable.getMaximumDurability(), salvageable.getMaximumQuantity()); + int durability = meta instanceof Damageable ? ((Damageable) meta).getDamage() : 0; + int potentialSalvageYield = Salvage.calculateSalvageableAmount(durability, + salvageable.getMaximumDurability(), salvageable.getMaximumQuantity()); if (potentialSalvageYield <= 0) { - NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE_FAILED, "Salvage.Skills.TooDamaged"); + NotificationManager.sendPlayerInformation(player, + NotificationType.SUBSKILL_MESSAGE_FAILED, "Salvage.Skills.TooDamaged"); return; } - potentialSalvageYield = Math.min(potentialSalvageYield, getSalvageLimit()); // Always get at least something back, if you're capable of salvaging it. + potentialSalvageYield = Math.min(potentialSalvageYield, getSalvageLimit( + getPlayer())); // Always get at least something back, if you're capable of salvaging it. location.add(0.5, 1, 0.5); @@ -114,36 +130,18 @@ public class SalvageManager extends SkillManager { enchantBook = arcaneSalvageCheck(enchants); } - //Lottery on Salvageable Amount - - int lotteryResults = 1; - int chanceOfSuccess = 99; - - for(int x = 0; x < potentialSalvageYield-1; x++) { - - if(RandomChanceUtil.rollDice(chanceOfSuccess, 100)) { - chanceOfSuccess-=3; - chanceOfSuccess = Math.max(chanceOfSuccess, 90); - - lotteryResults+=1; - } - } - - ItemStack salvageResults = new ItemStack(salvageable.getSalvageMaterial(), lotteryResults); + ItemStack salvageResults = new ItemStack(salvageable.getSalvageMaterial(), + potentialSalvageYield); //Call event - if (EventUtils.callSalvageCheckEvent(player, item, salvageResults, enchantBook).isCancelled()) { + if (EventUtils.callSalvageCheckEvent(player, item, salvageResults, enchantBook) + .isCancelled()) { return; } - // We only send a confirmation message after processing the event (fixes #4694) - if (lotteryResults == potentialSalvageYield && potentialSalvageYield != 1 && RankUtils.isPlayerMaxRankInSubSkill(player, SubSkillType.SALVAGE_ARCANE_SALVAGE)) { - NotificationManager.sendPlayerInformationChatOnly(player, "Salvage.Skills.Lottery.Perfect", String.valueOf(lotteryResults), StringUtils.getPrettyItemString(item.getType())); - } else if (salvageable.getMaximumQuantity() == 1 || getSalvageLimit() >= salvageable.getMaximumQuantity()) { - NotificationManager.sendPlayerInformationChatOnly(player, "Salvage.Skills.Lottery.Normal", String.valueOf(lotteryResults), StringUtils.getPrettyItemString(item.getType())); - } else { - NotificationManager.sendPlayerInformationChatOnly(player, "Salvage.Skills.Lottery.Untrained", String.valueOf(lotteryResults), StringUtils.getPrettyItemString(item.getType())); - } + NotificationManager.sendPlayerInformationChatOnly(player, "Salvage.Skills.Lottery.Normal", + String.valueOf(potentialSalvageYield), + StringUtils.getPrettyMaterialString(item.getType())); player.getInventory().setItemInMainHand(new ItemStack(Material.AIR)); @@ -161,25 +159,33 @@ public class SalvageManager extends SkillManager { anvilLoc.add(0, .1, 0); if (enchantBook != null) { - Misc.spawnItemTowardsLocation(getPlayer(), anvilLoc.clone(), playerLoc.clone(), enchantBook, vectorSpeed, ItemSpawnReason.SALVAGE_ENCHANTMENT_BOOK); + ItemUtils.spawnItemTowardsLocation(getPlayer(), anvilLoc.clone(), playerLoc.clone(), + enchantBook, vectorSpeed, ItemSpawnReason.SALVAGE_ENCHANTMENT_BOOK); } - Misc.spawnItemTowardsLocation(getPlayer(), anvilLoc.clone(), playerLoc.clone(), salvageResults, vectorSpeed, ItemSpawnReason.SALVAGE_MATERIALS); + ItemUtils.spawnItemTowardsLocation(getPlayer(), anvilLoc.clone(), playerLoc.clone(), + salvageResults, vectorSpeed, ItemSpawnReason.SALVAGE_MATERIALS); // BWONG BWONG BWONG - CLUNK! if (mcMMO.p.getGeneralConfig().getSalvageAnvilUseSoundsEnabled()) { SoundManager.sendSound(player, player.getLocation(), SoundType.ITEM_BREAK); } - NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE, "Salvage.Skills.Success"); + NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE, + "Salvage.Skills.Success"); } /*public double getMaxSalvagePercentage() { return Math.min((((Salvage.salvageMaxPercentage / Salvage.salvageMaxPercentageLevel) * getSkillLevel()) / 100.0D), Salvage.salvageMaxPercentage / 100.0D); }*/ - public int getSalvageLimit() { - return (RankUtils.getRank(getPlayer(), SubSkillType.SALVAGE_SCRAP_COLLECTOR)); + public static int getSalvageLimit(Player player) { + if (RankUtils.getRank(player, SubSkillType.SALVAGE_SCRAP_COLLECTOR) == 1) { + return 1; + } else { + var curRank = RankUtils.getRank(player, SubSkillType.SALVAGE_SCRAP_COLLECTOR); + return curRank * 2; + } } /** @@ -191,46 +197,27 @@ public class SalvageManager extends SkillManager { return RankUtils.getRank(getPlayer(), SubSkillType.SALVAGE_ARCANE_SALVAGE); } - /*public double getExtractFullEnchantChance() { - int skillLevel = getSkillLevel(); - - for (Tier tier : Tier.values()) { - if (skillLevel >= tier.getLevel()) { - return tier.getExtractFullEnchantChance(); - } - } - - return 0; - } - - public double getExtractPartialEnchantChance() { - int skillLevel = getSkillLevel(); - - for (Tier tier : Tier.values()) { - if (skillLevel >= tier.getLevel()) { - return tier.getExtractPartialEnchantChance(); - } - } - - return 0; - }*/ - public double getExtractFullEnchantChance() { - if(Permissions.hasSalvageEnchantBypassPerk(getPlayer())) + if (Permissions.hasSalvageEnchantBypassPerk(getPlayer())) { return 100.0D; + } - return mcMMO.p.getAdvancedConfig().getArcaneSalvageExtractFullEnchantsChance(getArcaneSalvageRank()); + return mcMMO.p.getAdvancedConfig() + .getArcaneSalvageExtractFullEnchantsChance(getArcaneSalvageRank()); } public double getExtractPartialEnchantChance() { - return mcMMO.p.getAdvancedConfig().getArcaneSalvageExtractPartialEnchantsChance(getArcaneSalvageRank()); + return mcMMO.p.getAdvancedConfig() + .getArcaneSalvageExtractPartialEnchantsChance(getArcaneSalvageRank()); } private ItemStack arcaneSalvageCheck(Map enchants) { Player player = getPlayer(); - if (!RankUtils.hasUnlockedSubskill(player, SubSkillType.SALVAGE_ARCANE_SALVAGE) || !Permissions.arcaneSalvage(player)) { - NotificationManager.sendPlayerInformationChatOnly(player, "Salvage.Skills.ArcaneFailed"); + if (!RankUtils.hasUnlockedSubskill(player, SubSkillType.SALVAGE_ARCANE_SALVAGE) + || !Permissions.arcaneSalvage(player)) { + NotificationManager.sendPlayerInformationChatOnly(player, + "Salvage.Skills.ArcaneFailed"); return null; } @@ -244,20 +231,21 @@ public class SalvageManager extends SkillManager { int enchantLevel = enchant.getValue(); - if(!ExperienceConfig.getInstance().allowUnsafeEnchantments()) { - if(enchantLevel > enchant.getKey().getMaxLevel()) { + if (!ExperienceConfig.getInstance().allowUnsafeEnchantments()) { + if (enchantLevel > enchant.getKey().getMaxLevel()) { enchantLevel = enchant.getKey().getMaxLevel(); } } if (!Salvage.arcaneSalvageEnchantLoss || Permissions.hasSalvageEnchantBypassPerk(player) - || RandomChanceUtil.checkRandomChanceExecutionSuccess(new RandomChanceSkillStatic(getExtractFullEnchantChance(), getPlayer(), SubSkillType.SALVAGE_ARCANE_SALVAGE))) { + || ProbabilityUtil.isStaticSkillRNGSuccessful( + PrimarySkillType.SALVAGE, mmoPlayer, getExtractFullEnchantChance())) { enchantMeta.addStoredEnchant(enchant.getKey(), enchantLevel, true); - } - else if (enchantLevel > 1 + } else if (enchantLevel > 1 && Salvage.arcaneSalvageDowngrades - && RandomChanceUtil.checkRandomChanceExecutionSuccess(new RandomChanceSkillStatic(getExtractPartialEnchantChance(), getPlayer(), SubSkillType.SALVAGE_ARCANE_SALVAGE))) { + && ProbabilityUtil.isStaticSkillRNGSuccessful( + PrimarySkillType.SALVAGE, mmoPlayer, getExtractPartialEnchantChance())) { enchantMeta.addStoredEnchant(enchant.getKey(), enchantLevel - 1, true); downgraded = true; } else { @@ -265,13 +253,13 @@ public class SalvageManager extends SkillManager { } } - if(failedAllEnchants(arcaneFailureCount, enchants.entrySet().size())) - { - NotificationManager.sendPlayerInformationChatOnly(player, "Salvage.Skills.ArcaneFailed"); + if (failedAllEnchants(arcaneFailureCount, enchants.size())) { + NotificationManager.sendPlayerInformationChatOnly(player, + "Salvage.Skills.ArcaneFailed"); return null; - } else if(downgraded) - { - NotificationManager.sendPlayerInformationChatOnly(player, "Salvage.Skills.ArcanePartial"); + } else if (downgraded) { + NotificationManager.sendPlayerInformationChatOnly(player, + "Salvage.Skills.ArcanePartial"); } book.setItemMeta(enchantMeta); @@ -284,15 +272,16 @@ public class SalvageManager extends SkillManager { /** * Check if the player has tried to use an Anvil before. - * @param actualize * + * @param actualize * @return true if the player has confirmed using an Anvil */ public boolean checkConfirmation(boolean actualize) { Player player = getPlayer(); long lastUse = getLastAnvilUse(); - if (!SkillUtils.cooldownExpired(lastUse, 3) || !mcMMO.p.getGeneralConfig().getSalvageConfirmRequired()) { + if (!SkillUtils.cooldownExpired(lastUse, 3) || !mcMMO.p.getGeneralConfig() + .getSalvageConfirmRequired()) { return true; } @@ -302,7 +291,8 @@ public class SalvageManager extends SkillManager { actualizeLastAnvilUse(); - NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE, "Skills.ConfirmOrCancel", LocaleLoader.getString("Salvage.Pretty.Name")); + NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE, + "Skills.ConfirmOrCancel", LocaleLoader.getString("Salvage.Pretty.Name")); return false; } diff --git a/src/main/java/com/gmail/nossr50/skills/salvage/salvageables/Salvageable.java b/src/main/java/com/gmail/nossr50/skills/salvage/salvageables/Salvageable.java index 1d9ac26a9..bcf46e866 100644 --- a/src/main/java/com/gmail/nossr50/skills/salvage/salvageables/Salvageable.java +++ b/src/main/java/com/gmail/nossr50/skills/salvage/salvageables/Salvageable.java @@ -35,8 +35,9 @@ public interface Salvageable { /** * Gets the maximum quantity of salvage materials ignoring all other salvage bonuses - * - * This is typically set to the number of items needed to create that item, for example 5 for helmets or 2 for swords + *

+ * This is typically set to the number of items needed to create that item, for example 5 for + * helmets or 2 for swords * * @return the maximum number of items */ @@ -51,7 +52,7 @@ public interface Salvageable { /** * Gets the base salvage durability on which to calculate bonuses. - * + *

* This is actually the maximum durability divided by the minimum quantity * * @return the base salvage durability diff --git a/src/main/java/com/gmail/nossr50/skills/salvage/salvageables/SalvageableFactory.java b/src/main/java/com/gmail/nossr50/skills/salvage/salvageables/SalvageableFactory.java index d408b1992..cb59884d8 100644 --- a/src/main/java/com/gmail/nossr50/skills/salvage/salvageables/SalvageableFactory.java +++ b/src/main/java/com/gmail/nossr50/skills/salvage/salvageables/SalvageableFactory.java @@ -6,17 +6,23 @@ import org.bukkit.Material; public final class SalvageableFactory { /** - * This is a static utility class, therefore we don't want any instances of - * this class. Making the constructor private prevents accidents like that. + * This is a static utility class, therefore we don't want any instances of this class. Making + * the constructor private prevents accidents like that. */ - private SalvageableFactory() {} - - public static Salvageable getSalvageable(Material itemMaterial, Material recipeMaterial, int maximumQuantity, short maximumDurability) { - return getSalvageable(itemMaterial, recipeMaterial, 0, maximumQuantity, maximumDurability, ItemType.OTHER, MaterialType.OTHER, 1); + private SalvageableFactory() { } - public static Salvageable getSalvageable(Material itemMaterial, Material recipeMaterial, int minimumLevel, int maximumQuantity, short maximumDurability, ItemType repairItemType, MaterialType repairMaterialType, double xpMultiplier) { + public static Salvageable getSalvageable(Material itemMaterial, Material recipeMaterial, + int maximumQuantity, short maximumDurability) { + return getSalvageable(itemMaterial, recipeMaterial, 0, maximumQuantity, maximumDurability, + ItemType.OTHER, MaterialType.OTHER, 1); + } + + public static Salvageable getSalvageable(Material itemMaterial, Material recipeMaterial, + int minimumLevel, int maximumQuantity, short maximumDurability, ItemType repairItemType, + MaterialType repairMaterialType, double xpMultiplier) { // TODO: Add in loading from config what type of repairable we want. - return new SimpleSalvageable(itemMaterial, recipeMaterial, minimumLevel, maximumQuantity, maximumDurability, repairItemType, repairMaterialType, xpMultiplier); + return new SimpleSalvageable(itemMaterial, recipeMaterial, minimumLevel, maximumQuantity, + maximumDurability, repairItemType, repairMaterialType, xpMultiplier); } } diff --git a/src/main/java/com/gmail/nossr50/skills/salvage/salvageables/SalvageableManager.java b/src/main/java/com/gmail/nossr50/skills/salvage/salvageables/SalvageableManager.java index 24add9b40..7d2a1bc79 100644 --- a/src/main/java/com/gmail/nossr50/skills/salvage/salvageables/SalvageableManager.java +++ b/src/main/java/com/gmail/nossr50/skills/salvage/salvageables/SalvageableManager.java @@ -1,10 +1,9 @@ package com.gmail.nossr50.skills.salvage.salvageables; +import java.util.List; import org.bukkit.Material; import org.bukkit.inventory.ItemStack; -import java.util.List; - public interface SalvageableManager { /** * Register a salvageable with the SalvageManager @@ -24,7 +23,6 @@ public interface SalvageableManager { * Checks if an item is salvageable * * @param type Material to check if salvageable - * * @return true if salvageable, false if not */ boolean isSalvageable(Material type); @@ -33,7 +31,6 @@ public interface SalvageableManager { * Checks if an item is salvageable * * @param itemStack Item to check if salvageable - * * @return true if salvageable, false if not */ boolean isSalvageable(ItemStack itemStack); @@ -42,7 +39,6 @@ public interface SalvageableManager { * Gets the salvageable with this type * * @param type Material of the salvageable to look for - * * @return the salvageable, can be null */ Salvageable getSalvageable(Material type); diff --git a/src/main/java/com/gmail/nossr50/skills/salvage/salvageables/SimpleSalvageable.java b/src/main/java/com/gmail/nossr50/skills/salvage/salvageables/SimpleSalvageable.java index d7484425c..7978d2b6b 100644 --- a/src/main/java/com/gmail/nossr50/skills/salvage/salvageables/SimpleSalvageable.java +++ b/src/main/java/com/gmail/nossr50/skills/salvage/salvageables/SimpleSalvageable.java @@ -13,7 +13,9 @@ public class SimpleSalvageable implements Salvageable { private final MaterialType salvageMaterialType; private final double xpMultiplier; - protected SimpleSalvageable(Material type, Material salvageMaterial, int minimumLevel, int maximumQuantity, short maximumDurability, ItemType salvageItemType, MaterialType salvageMaterialType, double xpMultiplier) { + protected SimpleSalvageable(Material type, Material salvageMaterial, int minimumLevel, + int maximumQuantity, short maximumDurability, ItemType salvageItemType, + MaterialType salvageMaterialType, double xpMultiplier) { this.itemMaterial = type; this.salvageMaterial = salvageMaterial; this.salvageItemType = salvageItemType; diff --git a/src/main/java/com/gmail/nossr50/skills/salvage/salvageables/SimpleSalvageableManager.java b/src/main/java/com/gmail/nossr50/skills/salvage/salvageables/SimpleSalvageableManager.java index 1a6d8a1f3..6a9d70ff0 100644 --- a/src/main/java/com/gmail/nossr50/skills/salvage/salvageables/SimpleSalvageableManager.java +++ b/src/main/java/com/gmail/nossr50/skills/salvage/salvageables/SimpleSalvageableManager.java @@ -1,11 +1,10 @@ package com.gmail.nossr50.skills.salvage.salvageables; -import org.bukkit.Material; -import org.bukkit.inventory.ItemStack; - import java.util.HashMap; import java.util.List; import java.util.Map; +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; public class SimpleSalvageableManager implements SalvageableManager { private final Map salvageables; 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 98d5a5a6f..c66527afd 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.mcMMO; import com.gmail.nossr50.skills.SkillManager; import com.gmail.nossr50.util.Permissions; -import com.gmail.nossr50.util.random.RandomChanceUtil; +import com.gmail.nossr50.util.random.ProbabilityUtil; import com.gmail.nossr50.util.skills.RankUtils; -import com.gmail.nossr50.util.skills.SkillActivationType; import org.bukkit.block.Furnace; import org.bukkit.event.inventory.FurnaceBurnEvent; import org.bukkit.event.inventory.FurnaceSmeltEvent; @@ -19,13 +18,14 @@ import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; public class SmeltingManager extends SkillManager { - public SmeltingManager(McMMOPlayer mcMMOPlayer) { - super(mcMMOPlayer, PrimarySkillType.SMELTING); + public SmeltingManager(McMMOPlayer mmoPlayer) { + super(mmoPlayer, PrimarySkillType.SMELTING); } 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()); + && ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.SMELTING_SECOND_SMELT, + mmoPlayer); } /** @@ -34,11 +34,11 @@ public class SmeltingManager extends SkillManager { * @param burnTime The initial burn time from the {@link FurnaceBurnEvent} */ public int fuelEfficiency(int burnTime) { + if (burnTime <= 0) return 0; return Math.min(Short.MAX_VALUE, Math.max(1, burnTime * getFuelEfficiencyMultiplier())); } - public int getFuelEfficiencyMultiplier() - { + public int getFuelEfficiencyMultiplier() { return switch (RankUtils.getRank(getPlayer(), SubSkillType.SMELTING_FUEL_EFFICIENCY)) { case 1 -> 2; case 2 -> 3; @@ -47,20 +47,24 @@ public class SmeltingManager extends SkillManager { }; } - public void smeltProcessing(@NotNull FurnaceSmeltEvent furnaceSmeltEvent, @NotNull Furnace furnace) { - applyXpGain(Smelting.getSmeltXP(furnaceSmeltEvent.getSource()), XPGainReason.PVE, XPGainSource.PASSIVE); //Add XP + public void smeltProcessing(@NotNull FurnaceSmeltEvent furnaceSmeltEvent, + @NotNull Furnace furnace) { + applyXpGain(Smelting.getSmeltXP(furnaceSmeltEvent.getSource()), XPGainReason.PVE, + XPGainSource.PASSIVE); //Add XP processDoubleSmelt(furnaceSmeltEvent, furnace); } - private void processDoubleSmelt(@NotNull FurnaceSmeltEvent furnaceSmeltEvent, @NotNull Furnace furnace) { + private void processDoubleSmelt(@NotNull FurnaceSmeltEvent furnaceSmeltEvent, + @NotNull Furnace furnace) { ItemStack resultItemStack = furnaceSmeltEvent.getResult(); /* doubleSmeltCondition should be equal to the max */ //Process double smelt - if (mcMMO.p.getGeneralConfig().getDoubleDropsEnabled(PrimarySkillType.SMELTING, resultItemStack.getType()) + if (mcMMO.p.getGeneralConfig() + .getDoubleDropsEnabled(PrimarySkillType.SMELTING, resultItemStack.getType()) && canDoubleSmeltItemStack(furnace) //Effectively two less than max stack size && isSecondSmeltSuccessful()) { @@ -74,12 +78,14 @@ public class SmeltingManager extends SkillManager { FurnaceInventory furnaceInventory = furnace.getInventory(); ItemStack furnaceResult = furnaceInventory.getResult(); - if(furnaceResult == null) + if (furnaceResult == null) { return true; //This actually means there is nothing yet in the resulting item slot, which means it should always be okay to double smelt + } int resultAmount = furnaceResult.getAmount(); //Amount before double smelt int itemLimit = furnaceResult.getMaxStackSize(); - int doubleSmeltCondition = itemLimit - 2; //Don't double smelt if it would cause an illegal stack size + int doubleSmeltCondition = + itemLimit - 2; //Don't double smelt if it would cause an illegal stack size return resultAmount <= doubleSmeltCondition; } @@ -94,6 +100,7 @@ public class SmeltingManager extends SkillManager { * @return the vanilla XP multiplier */ public int getVanillaXpMultiplier() { - return Math.max(1, RankUtils.getRank(getPlayer(), SubSkillType.SMELTING_UNDERSTANDING_THE_ART)); + return Math.max(1, + RankUtils.getRank(getPlayer(), SubSkillType.SMELTING_UNDERSTANDING_THE_ART)); } } \ No newline at end of file diff --git a/src/main/java/com/gmail/nossr50/skills/swords/Swords.java b/src/main/java/com/gmail/nossr50/skills/swords/Swords.java index 7dda504ea..7db420921 100644 --- a/src/main/java/com/gmail/nossr50/skills/swords/Swords.java +++ b/src/main/java/com/gmail/nossr50/skills/swords/Swords.java @@ -3,7 +3,8 @@ package com.gmail.nossr50.skills.swords; import com.gmail.nossr50.mcMMO; public class Swords { - public static double counterAttackModifier = mcMMO.p.getAdvancedConfig().getCounterModifier(); + public static double counterAttackModifier = mcMMO.p.getAdvancedConfig().getCounterModifier(); - public static double serratedStrikesModifier = mcMMO.p.getAdvancedConfig().getSerratedStrikesModifier(); + public static double serratedStrikesModifier = mcMMO.p.getAdvancedConfig() + .getSerratedStrikesModifier(); } 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 a95f1b9a4..23810d5b9 100644 --- a/src/main/java/com/gmail/nossr50/skills/swords/SwordsManager.java +++ b/src/main/java/com/gmail/nossr50/skills/swords/SwordsManager.java @@ -10,47 +10,50 @@ import com.gmail.nossr50.datatypes.skills.ToolType; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.runnables.skills.RuptureTask; import com.gmail.nossr50.skills.SkillManager; -import com.gmail.nossr50.util.ItemUtils; 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 org.bukkit.entity.Entity; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; public class SwordsManager extends SkillManager { - public SwordsManager(McMMOPlayer mcMMOPlayer) { - super(mcMMOPlayer, PrimarySkillType.SWORDS); + public SwordsManager(McMMOPlayer mmoPlayer) { + super(mmoPlayer, PrimarySkillType.SWORDS); } public boolean canActivateAbility() { - return mmoPlayer.getToolPreparationMode(ToolType.SWORD) && Permissions.serratedStrikes(getPlayer()); + return mmoPlayer.getToolPreparationMode(ToolType.SWORD) && Permissions.serratedStrikes( + getPlayer()); } public boolean canUseStab() { - return Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.SWORDS_STAB) && RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.SWORDS_STAB); + return Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.SWORDS_STAB) + && RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.SWORDS_STAB); } public boolean canUseRupture() { - return Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.SWORDS_RUPTURE) && RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.SWORDS_RUPTURE); + return Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.SWORDS_RUPTURE) + && RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.SWORDS_RUPTURE); } public boolean canUseCounterAttack(Entity target) { - if(!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.SWORDS_COUNTER_ATTACK)) + if (!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.SWORDS_COUNTER_ATTACK)) { return false; + } - return target instanceof LivingEntity && Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.SWORDS_COUNTER_ATTACK); + return target instanceof LivingEntity && Permissions.isSubSkillEnabled(getPlayer(), + SubSkillType.SWORDS_COUNTER_ATTACK); } public boolean canUseSerratedStrike() { - if(!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.SWORDS_SERRATED_STRIKES)) + if (!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.SWORDS_SERRATED_STRIKES)) { return false; + } return mmoPlayer.getAbilityMode(SuperAbilityType.SERRATED_STRIKES); } @@ -61,14 +64,17 @@ public class SwordsManager extends SkillManager { * @param target The defending entity */ public void processRupture(@NotNull LivingEntity target) { - if(!canUseRupture()) + if (!canUseRupture()) { return; + } - if(target.hasMetadata(MetadataConstants.METADATA_KEY_RUPTURE)) { - RuptureTaskMeta ruptureTaskMeta = (RuptureTaskMeta) target.getMetadata(MetadataConstants.METADATA_KEY_RUPTURE).get(0); + if (target.hasMetadata(MetadataConstants.METADATA_KEY_RUPTURE)) { + RuptureTaskMeta ruptureTaskMeta = (RuptureTaskMeta) target.getMetadata( + MetadataConstants.METADATA_KEY_RUPTURE).get(0); - if(mmoPlayer.isDebugMode()) { - mmoPlayer.getPlayer().sendMessage("Rupture task ongoing for target " + target.toString()); + if (mmoPlayer.isDebugMode()) { + mmoPlayer.getPlayer() + .sendMessage("Rupture task ongoing for target " + target); mmoPlayer.getPlayer().sendMessage(ruptureTaskMeta.getRuptureTimerTask().toString()); } @@ -76,31 +82,33 @@ public class SwordsManager extends SkillManager { return; //Don't apply bleed } - if (RandomChanceUtil.rollDice(mcMMO.p.getAdvancedConfig().getRuptureChanceToApplyOnHit(getRuptureRank()), 100)) { + double ruptureOdds = + mcMMO.p.getAdvancedConfig().getRuptureChanceToApplyOnHit(getRuptureRank()) + * mmoPlayer.getAttackStrength(); + if (ProbabilityUtil.isStaticSkillRNGSuccessful(PrimarySkillType.SWORDS, mmoPlayer, + ruptureOdds)) { if (target instanceof Player defender) { //Don't start or add to a bleed if they are blocking - if(defender.isBlocking()) + if (defender.isBlocking()) { return; + } if (NotificationManager.doesPlayerUseNotifications(defender)) { - NotificationManager.sendPlayerInformation(defender, NotificationType.SUBSKILL_MESSAGE, "Swords.Combat.Bleeding.Started"); + NotificationManager.sendPlayerInformation(defender, + NotificationType.SUBSKILL_MESSAGE, "Swords.Combat.Bleeding.Started"); } } - RuptureTask ruptureTask = new RuptureTask(mmoPlayer, target, - mcMMO.p.getAdvancedConfig().getRuptureTickDamage(target instanceof Player, getRuptureRank()), - mcMMO.p.getAdvancedConfig().getRuptureExplosionDamage(target instanceof Player, getRuptureRank())); + final RuptureTask ruptureTask = new RuptureTask(mmoPlayer, target, + mcMMO.p.getAdvancedConfig() + .getRuptureTickDamage(target instanceof Player, getRuptureRank())); - RuptureTaskMeta ruptureTaskMeta = new RuptureTaskMeta(mcMMO.p, ruptureTask); + final RuptureTaskMeta ruptureTaskMeta = new RuptureTaskMeta(mcMMO.p, ruptureTask); - mcMMO.p.getFoliaLib().getImpl().runAtEntityTimer(mmoPlayer.getPlayer(), ruptureTask, 1, 1); + mcMMO.p.getFoliaLib().getScheduler().runAtEntityTimer(target, ruptureTask, 1, 1); target.setMetadata(MetadataConstants.METADATA_KEY_RUPTURE, ruptureTaskMeta); - -// if (mmoPlayer.useChatNotifications()) { -// NotificationManager.sendPlayerInformation(getPlayer(), NotificationType.SUBSKILL_MESSAGE, "Swords.Combat.Bleeding"); -// } } } @@ -108,32 +116,18 @@ public class SwordsManager extends SkillManager { return RankUtils.getRank(getPlayer(), SubSkillType.SWORDS_RUPTURE); } - public double getStabDamage() - { + public double getStabDamage() { int rank = RankUtils.getRank(getPlayer(), SubSkillType.SWORDS_STAB); - if(rank > 0) - { - return (1.0D + (rank * 1.5)); + if (rank > 0) { + double baseDamage = mcMMO.p.getAdvancedConfig().getStabBaseDamage(); + double rankMultiplier = mcMMO.p.getAdvancedConfig().getStabPerRankMultiplier(); + return (baseDamage + (rank * rankMultiplier)); } return 0; } - public int getToolTier(@NotNull ItemStack itemStack) - { - if(ItemUtils.isNetheriteTool(itemStack)) - return 5; - if(ItemUtils.isDiamondTool(itemStack)) - return 4; - else if(ItemUtils.isIronTool(itemStack) || ItemUtils.isGoldTool(itemStack)) - return 3; - else if(ItemUtils.isStoneTool(itemStack)) - return 2; - else - return 1; - } - /** * Handle the effects of the Counter Attack ability * @@ -141,23 +135,28 @@ public class SwordsManager extends SkillManager { * @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())) { - CombatUtils.dealDamage(attacker, damage / Swords.counterAttackModifier, getPlayer()); + if (ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.SWORDS_COUNTER_ATTACK, mmoPlayer)) { + CombatUtils.safeDealDamage(attacker, damage / Swords.counterAttackModifier, + getPlayer()); - NotificationManager.sendPlayerInformation(getPlayer(), NotificationType.SUBSKILL_MESSAGE, "Swords.Combat.Countered"); + NotificationManager.sendPlayerInformation(getPlayer(), + NotificationType.SUBSKILL_MESSAGE, "Swords.Combat.Countered"); if (attacker instanceof Player) { - NotificationManager.sendPlayerInformation((Player)attacker, NotificationType.SUBSKILL_MESSAGE, "Swords.Combat.Counter.Hit"); + NotificationManager.sendPlayerInformation((Player) attacker, + NotificationType.SUBSKILL_MESSAGE, "Swords.Combat.Counter.Hit"); } } } /** * Handle the effects of the Serrated Strikes ability - * @param target The {@link LivingEntity} being affected by the ability + * + * @param target The {@link LivingEntity} being affected by the ability * @param damage The amount of damage initially dealt by the event */ public void serratedStrikes(@NotNull LivingEntity target, double damage) { - CombatUtils.applyAbilityAoE(getPlayer(), target, damage / Swords.serratedStrikesModifier, skill); + CombatUtils.applyAbilityAoE(getPlayer(), target, damage / Swords.serratedStrikesModifier, + skill); } } diff --git a/src/main/java/com/gmail/nossr50/skills/taming/Taming.java b/src/main/java/com/gmail/nossr50/skills/taming/Taming.java index 26ee15a67..edfce6813 100644 --- a/src/main/java/com/gmail/nossr50/skills/taming/Taming.java +++ b/src/main/java/com/gmail/nossr50/skills/taming/Taming.java @@ -2,19 +2,25 @@ package com.gmail.nossr50.skills.taming; import com.gmail.nossr50.mcMMO; import org.bukkit.EntityEffect; -import org.bukkit.entity.*; +import org.bukkit.entity.AnimalTamer; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Player; +import org.bukkit.entity.Tameable; +import org.bukkit.entity.Wolf; public class Taming { - public static double fastFoodServiceActivationChance = mcMMO.p.getAdvancedConfig().getFastFoodChance(); + public static double fastFoodServiceActivationChance = mcMMO.p.getAdvancedConfig() + .getFastFoodChance(); - public static int goreBleedTicks = 2; //Equivalent to rank 1 in Rupture - public static double goreModifier = mcMMO.p.getAdvancedConfig().getGoreModifier(); + public static int goreBleedTicks = 2; //Equivalent to rank 1 in Rupture + public static double goreModifier = mcMMO.p.getAdvancedConfig().getGoreModifier(); - public static double sharpenedClawsBonusDamage = mcMMO.p.getAdvancedConfig().getSharpenedClawsBonus(); + public static double sharpenedClawsBonusDamage = mcMMO.p.getAdvancedConfig() + .getSharpenedClawsBonus(); - public static double shockProofModifier = mcMMO.p.getAdvancedConfig().getShockProofModifier(); + public static double shockProofModifier = mcMMO.p.getAdvancedConfig().getShockProofModifier(); - public static double thickFurModifier = mcMMO.p.getAdvancedConfig().getThickFurModifier(); + public static double thickFurModifier = mcMMO.p.getAdvancedConfig().getThickFurModifier(); public static boolean canPreventDamage(Tameable pet, AnimalTamer owner) { return pet.isTamed() && owner instanceof Player && pet instanceof Wolf; 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 1359a041b..d16444715 100644 --- a/src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java +++ b/src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java @@ -1,13 +1,19 @@ package com.gmail.nossr50.skills.taming; +import static com.gmail.nossr50.util.AttributeMapper.MAPPED_JUMP_STRENGTH; +import static com.gmail.nossr50.util.AttributeMapper.MAPPED_MOVEMENT_SPEED; +import static com.gmail.nossr50.util.MobMetadataUtils.flagMetadata; + import com.gmail.nossr50.config.experience.ExperienceConfig; import com.gmail.nossr50.datatypes.experience.XPGainReason; +import com.gmail.nossr50.datatypes.experience.XPGainSource; import com.gmail.nossr50.datatypes.interactions.NotificationType; 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.subskills.taming.CallOfTheWildType; import com.gmail.nossr50.datatypes.skills.subskills.taming.TamingSummon; +import com.gmail.nossr50.events.skills.taming.McMMOPlayerTameEntityEvent; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.metadata.MobMetaFlagType; @@ -15,32 +21,38 @@ import com.gmail.nossr50.skills.SkillManager; 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.random.ProbabilityUtil; 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.sounds.SoundManager; import com.gmail.nossr50.util.sounds.SoundType; import com.gmail.nossr50.util.text.StringUtils; +import java.util.HashMap; import org.bukkit.Location; import org.bukkit.Material; -import org.bukkit.attribute.Attribute; import org.bukkit.attribute.AttributeInstance; -import org.bukkit.entity.*; +import org.bukkit.entity.AbstractHorse; +import org.bukkit.entity.Ageable; +import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Horse; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Llama; +import org.bukkit.entity.Ocelot; +import org.bukkit.entity.Player; +import org.bukkit.entity.Tameable; +import org.bukkit.entity.Wolf; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; -import java.util.HashMap; - public class TamingManager extends SkillManager { //TODO: Temporary static cache, will be changed in 2.2 private static HashMap summoningItems; private static HashMap cotwSummonDataProperties; private long lastSummonTimeStamp; - public TamingManager(@NotNull McMMOPlayer mcMMOPlayer) { - super(mcMMOPlayer, PrimarySkillType.TAMING); + public TamingManager(@NotNull McMMOPlayer mmoPlayer) { + super(mmoPlayer, PrimarySkillType.TAMING); init(); } @@ -59,27 +71,40 @@ public class TamingManager extends SkillManager { private void initStaticCaches() { //TODO: Temporary static cache, will be changed in 2.2 //This is shared between instances of TamingManager - if(summoningItems == null) { + if (summoningItems == null) { summoningItems = new HashMap<>(); - summoningItems.put(mcMMO.p.getGeneralConfig().getTamingCOTWMaterial(CallOfTheWildType.CAT.getConfigEntityTypeEntry()), CallOfTheWildType.CAT); - summoningItems.put(mcMMO.p.getGeneralConfig().getTamingCOTWMaterial(CallOfTheWildType.WOLF.getConfigEntityTypeEntry()), CallOfTheWildType.WOLF); - summoningItems.put(mcMMO.p.getGeneralConfig().getTamingCOTWMaterial(CallOfTheWildType.HORSE.getConfigEntityTypeEntry()), CallOfTheWildType.HORSE); + summoningItems.put(mcMMO.p.getGeneralConfig() + .getTamingCOTWMaterial(CallOfTheWildType.CAT.getConfigEntityTypeEntry()), + CallOfTheWildType.CAT); + summoningItems.put(mcMMO.p.getGeneralConfig() + .getTamingCOTWMaterial(CallOfTheWildType.WOLF.getConfigEntityTypeEntry()), + CallOfTheWildType.WOLF); + summoningItems.put(mcMMO.p.getGeneralConfig() + .getTamingCOTWMaterial(CallOfTheWildType.HORSE.getConfigEntityTypeEntry()), + CallOfTheWildType.HORSE); } //TODO: Temporary static cache, will be changed in 2.2 //This is shared between instances of TamingManager - if(cotwSummonDataProperties == null) { + if (cotwSummonDataProperties == null) { cotwSummonDataProperties = new HashMap<>(); - for(CallOfTheWildType callOfTheWildType : CallOfTheWildType.values()) { - Material itemSummonMaterial = mcMMO.p.getGeneralConfig().getTamingCOTWMaterial(callOfTheWildType.getConfigEntityTypeEntry()); - int itemAmountRequired = mcMMO.p.getGeneralConfig().getTamingCOTWCost(callOfTheWildType.getConfigEntityTypeEntry()); - int entitiesSummonedPerCOTW = mcMMO.p.getGeneralConfig().getTamingCOTWAmount(callOfTheWildType.getConfigEntityTypeEntry()); - int summonLifespanSeconds = mcMMO.p.getGeneralConfig().getTamingCOTWLength(callOfTheWildType.getConfigEntityTypeEntry()); - int perPlayerMaxAmount = mcMMO.p.getGeneralConfig().getTamingCOTWMaxAmount(callOfTheWildType.getConfigEntityTypeEntry()); + for (CallOfTheWildType callOfTheWildType : CallOfTheWildType.values()) { + Material itemSummonMaterial = mcMMO.p.getGeneralConfig() + .getTamingCOTWMaterial(callOfTheWildType.getConfigEntityTypeEntry()); + int itemAmountRequired = mcMMO.p.getGeneralConfig() + .getTamingCOTWCost(callOfTheWildType.getConfigEntityTypeEntry()); + int entitiesSummonedPerCOTW = mcMMO.p.getGeneralConfig() + .getTamingCOTWAmount(callOfTheWildType.getConfigEntityTypeEntry()); + int summonLifespanSeconds = mcMMO.p.getGeneralConfig() + .getTamingCOTWLength(callOfTheWildType.getConfigEntityTypeEntry()); + int perPlayerMaxAmount = mcMMO.p.getGeneralConfig() + .getTamingCOTWMaxAmount(callOfTheWildType.getConfigEntityTypeEntry()); - TamingSummon tamingSummon = new TamingSummon(callOfTheWildType, itemSummonMaterial, itemAmountRequired, entitiesSummonedPerCOTW, summonLifespanSeconds, perPlayerMaxAmount); + TamingSummon tamingSummon = new TamingSummon(callOfTheWildType, itemSummonMaterial, + itemAmountRequired, entitiesSummonedPerCOTW, summonLifespanSeconds, + perPlayerMaxAmount); cotwSummonDataProperties.put(callOfTheWildType, tamingSummon); } } @@ -92,7 +117,8 @@ public class TamingManager extends SkillManager { public boolean canUseEnvironmentallyAware() { return RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.TAMING_ENVIRONMENTALLY_AWARE) - && Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.TAMING_ENVIRONMENTALLY_AWARE); + && Permissions.isSubSkillEnabled(getPlayer(), + SubSkillType.TAMING_ENVIRONMENTALLY_AWARE); } public boolean canUseShockProof() { @@ -107,7 +133,8 @@ public class TamingManager extends SkillManager { public boolean canUseFastFoodService() { return RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.TAMING_FAST_FOOD_SERVICE) - && Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.TAMING_FAST_FOOD_SERVICE); + && Permissions.isSubSkillEnabled(getPlayer(), + SubSkillType.TAMING_FAST_FOOD_SERVICE); } public boolean canUseSharpenedClaws() { @@ -116,15 +143,17 @@ public class TamingManager extends SkillManager { } public boolean canUseGore() { - if(!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.TAMING_GORE)) + if (!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.TAMING_GORE)) { return false; + } return Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.TAMING_GORE); } public boolean canUseBeastLore() { - if(!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.TAMING_BEAST_LORE)) + if (!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.TAMING_BEAST_LORE)) { return false; + } return Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.TAMING_BEAST_LORE); } @@ -135,7 +164,15 @@ public class TamingManager extends SkillManager { * @param entity The LivingEntity to award XP for */ public void awardTamingXP(@NotNull LivingEntity entity) { - applyXpGain(ExperienceConfig.getInstance().getTamingXP(entity.getType()), XPGainReason.PVE); + int xp = ExperienceConfig.getInstance().getTamingXP(entity.getType()); + + final McMMOPlayerTameEntityEvent event = new McMMOPlayerTameEntityEvent(mmoPlayer, xp, + entity); + mcMMO.p.getServer().getPluginManager().callEvent(event); + + if (!event.isCancelled()) { + applyXpGain(event.getXpGained(), XPGainReason.PVE, XPGainSource.SELF); + } } /** @@ -145,7 +182,8 @@ public class TamingManager extends SkillManager { * @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 (!ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.TAMING_FAST_FOOD_SERVICE, + mmoPlayer)) { return; } @@ -165,12 +203,6 @@ public class TamingManager extends SkillManager { * @param damage The initial damage */ public double gore(@NotNull LivingEntity target, double damage) { -// if (target instanceof Player) { -// NotificationManager.sendPlayerInformation((Player)target, NotificationType.SUBSKILL_MESSAGE, "Combat.StruckByGore"); -// } -// -// NotificationManager.sendPlayerInformation(getPlayer(), NotificationType.SUBSKILL_MESSAGE, "Combat.Gore"); - damage = (damage * Taming.goreModifier) - damage; return damage; @@ -184,8 +216,9 @@ public class TamingManager extends SkillManager { * Summon an ocelot to your side. */ public void summonOcelot() { - if(!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.TAMING_CALL_OF_THE_WILD)) + if (!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.TAMING_CALL_OF_THE_WILD)) { return; + } if (!Permissions.callOfTheWild(getPlayer(), EntityType.OCELOT)) { return; @@ -198,8 +231,9 @@ public class TamingManager extends SkillManager { * Summon a wolf to your side. */ public void summonWolf() { - if(!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.TAMING_CALL_OF_THE_WILD)) + if (!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.TAMING_CALL_OF_THE_WILD)) { return; + } if (!Permissions.callOfTheWild(getPlayer(), EntityType.WOLF)) { return; @@ -212,8 +246,9 @@ public class TamingManager extends SkillManager { * Summon a horse to your side. */ public void summonHorse() { - if(!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.TAMING_CALL_OF_THE_WILD)) + if (!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.TAMING_CALL_OF_THE_WILD)) { return; + } if (!Permissions.callOfTheWild(getPlayer(), EntityType.HORSE)) { return; @@ -234,21 +269,28 @@ public class TamingManager extends SkillManager { String message = LocaleLoader.getString("Combat.BeastLore") + " "; if (beast.isTamed() && beast.getOwner() != null) { - message = message.concat(LocaleLoader.getString("Combat.BeastLoreOwner", beast.getOwner().getName()) + " "); + message = message.concat( + LocaleLoader.getString("Combat.BeastLoreOwner", beast.getOwner().getName()) + + " "); } - message = message.concat(LocaleLoader.getString("Combat.BeastLoreHealth", target.getHealth(), target.getMaxHealth())); + message = message.concat( + LocaleLoader.getString("Combat.BeastLoreHealth", target.getHealth(), + target.getMaxHealth())); // Bred mules & donkeys can actually have horse-like stats, but llamas cannot. if (beast instanceof AbstractHorse horseLikeCreature && !(beast instanceof Llama)) { - AttributeInstance jumpAttribute = horseLikeCreature.getAttribute(Attribute.HORSE_JUMP_STRENGTH); + AttributeInstance jumpAttribute = horseLikeCreature.getAttribute(MAPPED_JUMP_STRENGTH); - if(jumpAttribute != null) { + if (jumpAttribute != null) { double jumpStrength = jumpAttribute.getValue(); // Taken from https://minecraft.wiki/w/Horse#Jump_strength - jumpStrength = -0.1817584952 * Math.pow(jumpStrength, 3) + 3.689713992 * Math.pow(jumpStrength, 2) + 2.128599134 * jumpStrength - 0.343930367; - message = message.concat("\n" + LocaleLoader.getString("Combat.BeastLoreHorseSpeed", horseLikeCreature.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED).getValue() * 43)) - .concat("\n" + LocaleLoader.getString("Combat.BeastLoreHorseJumpStrength", jumpStrength)); + jumpStrength = -0.1817584952 * Math.pow(jumpStrength, 3) + 3.689713992 * Math.pow( + jumpStrength, 2) + 2.128599134 * jumpStrength - 0.343930367; + message = message.concat("\n" + LocaleLoader.getString("Combat.BeastLoreHorseSpeed", + horseLikeCreature.getAttribute(MAPPED_MOVEMENT_SPEED).getValue() * 43)) + .concat("\n" + LocaleLoader.getString("Combat.BeastLoreHorseJumpStrength", + jumpStrength)); } } @@ -263,15 +305,19 @@ public class TamingManager extends SkillManager { Player owner = getPlayer(); wolf.teleport(owner); - NotificationManager.sendPlayerInformation(owner, NotificationType.SUBSKILL_MESSAGE, "Taming.Listener.Wolf"); + NotificationManager.sendPlayerInformation(owner, NotificationType.SUBSKILL_MESSAGE, + "Taming.Listener.Wolf"); } public void pummel(LivingEntity target, Wolf wolf) { - if(!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.TAMING_PUMMEL)) + if (!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.TAMING_PUMMEL)) { return; + } - if(!RandomChanceUtil.checkRandomChanceExecutionSuccess(new RandomChanceSkillStatic(mcMMO.p.getAdvancedConfig().getPummelChance(), getPlayer(), SubSkillType.TAMING_PUMMEL))) + if (!ProbabilityUtil.isStaticSkillRNGSuccessful(PrimarySkillType.TAMING, mmoPlayer, + mcMMO.p.getAdvancedConfig().getPummelChance())) { return; + } ParticleEffectUtils.playGreaterImpactEffect(target); target.setVelocity(wolf.getLocation().getDirection().normalize().multiply(1.5D)); @@ -279,22 +325,25 @@ public class TamingManager extends SkillManager { if (target instanceof Player defender) { if (NotificationManager.doesPlayerUseNotifications(defender)) { - NotificationManager.sendPlayerInformation(defender, NotificationType.SUBSKILL_MESSAGE, "Taming.SubSkill.Pummel.TargetMessage"); + NotificationManager.sendPlayerInformation(defender, + NotificationType.SUBSKILL_MESSAGE, "Taming.SubSkill.Pummel.TargetMessage"); } } } public void attackTarget(LivingEntity target) { - if(target instanceof Tameable tameable) - { - if(tameable.getOwner() == getPlayer()) - { + if (target instanceof Tameable tameable) { + if (tameable.getOwner() == getPlayer()) { return; } } double range = 5; Player player = getPlayer(); + if (!target.getWorld().equals(player.getWorld())) { + return; + } + for (Entity entity : player.getNearbyEntities(range, range, range)) { if (entity.getType() != EntityType.WOLF) { continue; @@ -313,7 +362,7 @@ public class TamingManager extends SkillManager { private void processCallOfTheWild() { //Prevent summoning too many things accidentally if a player holds down the button - if(lastSummonTimeStamp + 150 > System.currentTimeMillis()) { + if (lastSummonTimeStamp + 150 > System.currentTimeMillis()) { return; } else { lastSummonTimeStamp = System.currentTimeMillis(); @@ -323,7 +372,7 @@ public class TamingManager extends SkillManager { ItemStack itemInMainHand = player.getInventory().getItemInMainHand(); //Check if the item the player is currently holding is a COTW item - if(isCOTWItem(itemInMainHand)) { + if (isCOTWItem(itemInMainHand)) { //Get the summoning type CallOfTheWildType callOfTheWildType = summoningItems.get(itemInMainHand.getType()); TamingSummon tamingSummon = cotwSummonDataProperties.get(callOfTheWildType); @@ -332,15 +381,17 @@ public class TamingManager extends SkillManager { int amountSummoned = 0; //Check to see if players have the correct amount of the item required to summon - if(itemInMainHand.getAmount() >= tamingSummon.getItemAmountRequired()) { + if (itemInMainHand.getAmount() >= tamingSummon.getItemAmountRequired()) { //Initial Spawn location Location spawnLocation = Misc.getLocationOffset(player.getLocation(), 1); //COTW can summon multiple entities per usage for (int i = 0; i < tamingSummon.getEntitiesSummoned(); i++) { - if (getAmountCurrentlySummoned(callOfTheWildType) >= tamingSummon.getSummonCap()) { - NotificationManager.sendPlayerInformationChatOnly(player, "Taming.Summon.COTW.Limit", + if (getAmountCurrentlySummoned(callOfTheWildType) + >= tamingSummon.getSummonCap()) { + NotificationManager.sendPlayerInformationChatOnly(player, + "Taming.Summon.COTW.Limit", String.valueOf(tamingSummon.getSummonCap()), StringUtils.getCapitalized(callOfTheWildType.toString())); break; @@ -351,22 +402,28 @@ public class TamingManager extends SkillManager { //Inform the player about what they have just done if (tamingSummon.getSummonLifespan() > 0) { - NotificationManager.sendPlayerInformationChatOnly(player, "Taming.Summon.COTW.Success.WithLifespan", - StringUtils.getCapitalized(callOfTheWildType.toString()), String.valueOf(tamingSummon.getSummonLifespan())); + NotificationManager.sendPlayerInformationChatOnly(player, + "Taming.Summon.COTW.Success.WithLifespan", + StringUtils.getCapitalized(callOfTheWildType.toString()), + String.valueOf(tamingSummon.getSummonLifespan())); } else { - NotificationManager.sendPlayerInformationChatOnly(player, "Taming.Summon.COTW.Success.WithoutLifespan", StringUtils.getCapitalized(callOfTheWildType.toString())); + NotificationManager.sendPlayerInformationChatOnly(player, + "Taming.Summon.COTW.Success.WithoutLifespan", + StringUtils.getCapitalized(callOfTheWildType.toString())); } //Send Sound - SoundManager.sendSound(player, player.getLocation(), SoundType.ABILITY_ACTIVATED_GENERIC); + SoundManager.sendSound(player, player.getLocation(), + SoundType.ABILITY_ACTIVATED_GENERIC); amountSummoned++; } //Remove items from the player if they had at least one entity summoned successfully - if(amountSummoned >= 1) { + if (amountSummoned >= 1) { //Remove the items used to summon - int itemAmountAfterPayingCost = itemInMainHand.getAmount() - tamingSummon.getItemAmountRequired(); + int itemAmountAfterPayingCost = + itemInMainHand.getAmount() - tamingSummon.getItemAmountRequired(); itemInMainHand.setAmount(itemAmountAfterPayingCost); player.updateInventory(); } @@ -374,28 +431,27 @@ public class TamingManager extends SkillManager { } else { //Player did not have enough of the item in their main hand int difference = tamingSummon.getItemAmountRequired() - itemInMainHand.getAmount(); - NotificationManager.sendPlayerInformationChatOnly(player, "Taming.Summon.COTW.NeedMoreItems", String.valueOf(difference), StringUtils.getPrettyItemString(itemInMainHand.getType())); + NotificationManager.sendPlayerInformationChatOnly(player, + "Taming.Summon.COTW.NeedMoreItems", String.valueOf(difference), + StringUtils.getPrettyMaterialString(itemInMainHand.getType())); } } } - private void spawnCOTWEntity(CallOfTheWildType callOfTheWildType, Location spawnLocation, EntityType entityType) { - switch(callOfTheWildType) { - case CAT: + private void spawnCOTWEntity(CallOfTheWildType callOfTheWildType, Location spawnLocation, + EntityType entityType) { + 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); } } private void spawnWolf(Location spawnLocation) { - LivingEntity callOfWildEntity = (LivingEntity) getPlayer().getWorld().spawnEntity(spawnLocation, EntityType.WOLF); + LivingEntity callOfWildEntity = (LivingEntity) getPlayer().getWorld() + .spawnEntity(spawnLocation, EntityType.WOLF); //This is used to prevent XP gains for damaging this entity applyMetaDataToCOTWEntity(callOfWildEntity); @@ -409,11 +465,15 @@ public class TamingManager extends SkillManager { callOfWildEntity.setMaxHealth(20.0); callOfWildEntity.setHealth(callOfWildEntity.getMaxHealth()); - callOfWildEntity.setCustomName(LocaleLoader.getString("Taming.Summon.Name.Format", getPlayer().getName(), StringUtils.getPrettyEntityTypeString(EntityType.WOLF))); + callOfWildEntity.setCustomName( + LocaleLoader.getString("Taming.Summon.Name.Format", getPlayer().getName(), + StringUtils.getPrettyEntityTypeString(EntityType.WOLF))); } + @SuppressWarnings("deprecation") private void spawnCat(Location spawnLocation, EntityType entityType) { - LivingEntity callOfWildEntity = (LivingEntity) getPlayer().getWorld().spawnEntity(spawnLocation, entityType); + LivingEntity callOfWildEntity = (LivingEntity) getPlayer().getWorld() + .spawnEntity(spawnLocation, entityType); //This is used to prevent XP gains for damaging this entity applyMetaDataToCOTWEntity(callOfWildEntity); @@ -423,24 +483,26 @@ public class TamingManager extends SkillManager { addToTracker(callOfWildEntity, CallOfTheWildType.CAT); //Randomize the cat - if(callOfWildEntity instanceof Ocelot) { + if (callOfWildEntity instanceof Ocelot) { + // Ocelot.Type is deprecated, but that's fine since this only runs on 1.13 int numberOfTypes = Ocelot.Type.values().length; - ((Ocelot) callOfWildEntity).setCatType(Ocelot.Type.values()[Misc.getRandom().nextInt(numberOfTypes)]); - ((Ocelot) callOfWildEntity).setAdult(); - } else if(callOfWildEntity instanceof Cat) { - int numberOfTypes = Cat.Type.values().length; - ((Cat) callOfWildEntity).setCatType(Cat.Type.values()[Misc.getRandom().nextInt(numberOfTypes)]); - ((Cat) callOfWildEntity).setAdult(); + ((Ocelot) callOfWildEntity).setCatType( + Ocelot.Type.values()[Misc.getRandom().nextInt(numberOfTypes)]); } - callOfWildEntity.setCustomName(LocaleLoader.getString("Taming.Summon.Name.Format", getPlayer().getName(), StringUtils.getPrettyEntityTypeString(entityType))); + ((Ageable) callOfWildEntity).setAdult(); + + callOfWildEntity.setCustomName( + LocaleLoader.getString("Taming.Summon.Name.Format", getPlayer().getName(), + StringUtils.getPrettyEntityTypeString(entityType))); //Particle effect ParticleEffectUtils.playCallOfTheWildEffect(callOfWildEntity); } private void spawnHorse(Location spawnLocation) { - LivingEntity callOfWildEntity = (LivingEntity) getPlayer().getWorld().spawnEntity(spawnLocation, EntityType.HORSE); + LivingEntity callOfWildEntity = (LivingEntity) getPlayer().getWorld() + .spawnEntity(spawnLocation, EntityType.HORSE); applyMetaDataToCOTWEntity(callOfWildEntity); setBaseCOTWEntityProperties(callOfWildEntity); @@ -454,12 +516,16 @@ public class TamingManager extends SkillManager { callOfWildEntity.setHealth(callOfWildEntity.getMaxHealth()); horse.setColor(Horse.Color.values()[Misc.getRandom().nextInt(Horse.Color.values().length)]); horse.setStyle(Horse.Style.values()[Misc.getRandom().nextInt(Horse.Style.values().length)]); - horse.setJumpStrength(Math.max(mcMMO.p.getAdvancedConfig().getMinHorseJumpStrength(), Math.min(Math.min(Misc.getRandom().nextDouble(), Misc.getRandom().nextDouble()) * 2, mcMMO.p.getAdvancedConfig().getMaxHorseJumpStrength()))); + horse.setJumpStrength(Math.max(mcMMO.p.getAdvancedConfig().getMinHorseJumpStrength(), + Math.min(Math.min(Misc.getRandom().nextDouble(), Misc.getRandom().nextDouble()) * 2, + mcMMO.p.getAdvancedConfig().getMaxHorseJumpStrength()))); horse.setAdult(); //TODO: setSpeed, once available - callOfWildEntity.setCustomName(LocaleLoader.getString("Taming.Summon.Name.Format", getPlayer().getName(), StringUtils.getPrettyEntityTypeString(EntityType.HORSE))); + callOfWildEntity.setCustomName( + LocaleLoader.getString("Taming.Summon.Name.Format", getPlayer().getName(), + StringUtils.getPrettyEntityTypeString(EntityType.HORSE))); //Particle effect ParticleEffectUtils.playCallOfTheWildEffect(callOfWildEntity); @@ -472,11 +538,12 @@ public class TamingManager extends SkillManager { private void applyMetaDataToCOTWEntity(LivingEntity summonedEntity) { //This helps identify the entity as being summoned by COTW - mcMMO.getMetadataService().getMobMetadataService().flagMetadata(MobMetaFlagType.COTW_SUMMONED_MOB, summonedEntity); + flagMetadata(MobMetaFlagType.COTW_SUMMONED_MOB, summonedEntity); } /** * Whether the itemstack is used for COTW + * * @param itemStack target ItemStack * @return true if it is used for any COTW */ @@ -485,16 +552,19 @@ public class TamingManager extends SkillManager { } private int getAmountCurrentlySummoned(@NotNull CallOfTheWildType callOfTheWildType) { - return mcMMO.getTransientEntityTracker().getAmountCurrentlySummoned(getPlayer().getUniqueId(), callOfTheWildType); + return mcMMO.getTransientEntityTracker() + .getActiveSummonsForPlayerOfType(getPlayer().getUniqueId(), callOfTheWildType); } - private void addToTracker(@NotNull LivingEntity livingEntity, @NotNull CallOfTheWildType callOfTheWildType) { - mcMMO.getTransientEntityTracker().registerEntity(getPlayer().getUniqueId(), new TrackedTamingEntity(livingEntity, callOfTheWildType, getPlayer())); + private void addToTracker(@NotNull LivingEntity livingEntity, + @NotNull CallOfTheWildType callOfTheWildType) { + mcMMO.getTransientEntityTracker().addSummon(getPlayer().getUniqueId(), + new TrackedTamingEntity(livingEntity, callOfTheWildType, getPlayer())); } /** - * Remove all tracked entities from existence if they currently exist - * Clear the tracked entity lists afterwards + * Remove all tracked entities from existence if they currently exist Clear the tracked entity + * lists afterwards */ //TODO: The way this tracker was written is garbo, I should just rewrite it, I'll save that for a future update public void cleanupAllSummons() { diff --git a/src/main/java/com/gmail/nossr50/skills/taming/TrackedTamingEntity.java b/src/main/java/com/gmail/nossr50/skills/taming/TrackedTamingEntity.java index 8af370b9e..e004a5e7a 100644 --- a/src/main/java/com/gmail/nossr50/skills/taming/TrackedTamingEntity.java +++ b/src/main/java/com/gmail/nossr50/skills/taming/TrackedTamingEntity.java @@ -4,6 +4,7 @@ import com.gmail.nossr50.datatypes.skills.subskills.taming.CallOfTheWildType; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.CancellableRunnable; import com.gmail.nossr50.util.Misc; +import java.util.UUID; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; @@ -12,23 +13,30 @@ public class TrackedTamingEntity extends CancellableRunnable { private final @NotNull LivingEntity livingEntity; private final @NotNull CallOfTheWildType callOfTheWildType; private final @NotNull Player player; + private final @NotNull UUID playerUUID; - protected TrackedTamingEntity(@NotNull LivingEntity livingEntity, @NotNull CallOfTheWildType callOfTheWildType, @NotNull Player player) { + public TrackedTamingEntity(@NotNull LivingEntity livingEntity, + @NotNull CallOfTheWildType callOfTheWildType, + @NotNull Player player) { this.player = player; + this.playerUUID = player.getUniqueId(); this.callOfTheWildType = callOfTheWildType; this.livingEntity = livingEntity; - int tamingCOTWLength = mcMMO.p.getGeneralConfig().getTamingCOTWLength(callOfTheWildType.getConfigEntityTypeEntry()); + int tamingCOTWLength = mcMMO.p.getGeneralConfig() + .getTamingCOTWLength(callOfTheWildType.getConfigEntityTypeEntry()); if (tamingCOTWLength > 0) { int length = tamingCOTWLength * Misc.TICK_CONVERSION_FACTOR; - mcMMO.p.getFoliaLib().getImpl().runAtEntityLater(livingEntity, this, length); + mcMMO.p.getFoliaLib().getScheduler().runAtEntityLater(livingEntity, this, length); } } @Override public void run() { - mcMMO.getTransientEntityTracker().removeSummon(this.getLivingEntity(), player, true); + mcMMO.getTransientEntityTracker() + .killSummonAndCleanMobFlags(this.getLivingEntity(), player, true); + mcMMO.getTransientEntityTracker().removeSummonFromTracker(playerUUID, this); this.cancel(); } diff --git a/src/main/java/com/gmail/nossr50/skills/tridents/TridentsManager.java b/src/main/java/com/gmail/nossr50/skills/tridents/TridentsManager.java new file mode 100644 index 000000000..fcacc014c --- /dev/null +++ b/src/main/java/com/gmail/nossr50/skills/tridents/TridentsManager.java @@ -0,0 +1,25 @@ +package com.gmail.nossr50.skills.tridents; + +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.skills.RankUtils; + +public class TridentsManager extends SkillManager { + public TridentsManager(McMMOPlayer mmoPlayer) { + super(mmoPlayer, PrimarySkillType.TRIDENTS); + } + + 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/skills/unarmed/Unarmed.java b/src/main/java/com/gmail/nossr50/skills/unarmed/Unarmed.java index cb1124dd4..407e20a8c 100644 --- a/src/main/java/com/gmail/nossr50/skills/unarmed/Unarmed.java +++ b/src/main/java/com/gmail/nossr50/skills/unarmed/Unarmed.java @@ -8,7 +8,8 @@ import org.bukkit.event.entity.EntityPickupItemEvent; import org.bukkit.inventory.ItemStack; public class Unarmed { - public static boolean blockCrackerSmoothBrick = mcMMO.p.getGeneralConfig().getUnarmedBlockCrackerSmoothbrickToCracked(); + public static boolean blockCrackerSmoothBrick = mcMMO.p.getGeneralConfig() + .getUnarmedBlockCrackerSmoothbrickToCracked(); public static double berserkDamageModifier = 1.5; public static void handleItemPickup(Player player, EntityPickupItemEvent event) { @@ -19,27 +20,26 @@ public class Unarmed { int amount = itemDrop.getAmount(); boolean grabbedItem = false; - for(int i = 0; i <= storageContents.length-1; i++) - { - if(amount <= 0) + for (int i = 0; i <= storageContents.length - 1; i++) { + if (amount <= 0) { break; + } - if(i == heldItemSlotID) + if (i == heldItemSlotID) { continue; + } //EMPTY SLOT! - if(storageContents[i] == null) - { + if (storageContents[i] == null) { player.getInventory().setItem(i, itemDrop); amount = 0; grabbedItem = true; break; - } - else if(itemDrop.isSimilar(storageContents[i]) && storageContents[i].getAmount() < storageContents[i].getMaxStackSize()) - { + } else if (itemDrop.isSimilar(storageContents[i]) + && storageContents[i].getAmount() < storageContents[i].getMaxStackSize()) { //If we can fit this whole itemstack into this item - if(amount + storageContents[i].getAmount() <= storageContents[i].getMaxStackSize()) - { + if (amount + storageContents[i].getAmount() + <= storageContents[i].getMaxStackSize()) { ItemStack modifiedAmount = storageContents[i]; modifiedAmount.setAmount(amount + storageContents[i].getAmount()); @@ -49,7 +49,8 @@ public class Unarmed { } else { //Add what we can from this stack ItemStack modifiedAmount = storageContents[i]; - int amountThatCanFit = storageContents[i].getMaxStackSize() - storageContents[i].getAmount(); + int amountThatCanFit = + storageContents[i].getMaxStackSize() - storageContents[i].getAmount(); modifiedAmount.setAmount(amountThatCanFit); player.getInventory().setItem(i, modifiedAmount); @@ -61,15 +62,15 @@ public class Unarmed { } } - if(amount <= 0) + if (amount <= 0) { event.getItem().remove(); //Cleanup Item - else + } else { event.getItem().getItemStack().setAmount(amount); + } event.setCancelled(true); - if(grabbedItem) - { + if (grabbedItem) { SoundManager.sendSound(player, player.getLocation(), SoundType.POP); player.updateInventory(); } 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 93dc5eef5..6cc57ab88 100644 --- a/src/main/java/com/gmail/nossr50/skills/unarmed/UnarmedManager.java +++ b/src/main/java/com/gmail/nossr50/skills/unarmed/UnarmedManager.java @@ -1,5 +1,7 @@ package com.gmail.nossr50.skills.unarmed; +import static com.gmail.nossr50.util.random.ProbabilityUtil.isSkillRNGSuccessful; + import com.gmail.nossr50.api.ItemSpawnReason; import com.gmail.nossr50.datatypes.interactions.NotificationType; import com.gmail.nossr50.datatypes.player.McMMOPlayer; @@ -9,12 +11,15 @@ import com.gmail.nossr50.datatypes.skills.SuperAbilityType; import com.gmail.nossr50.datatypes.skills.ToolType; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.skills.SkillManager; -import com.gmail.nossr50.util.*; +import com.gmail.nossr50.util.EventUtils; +import com.gmail.nossr50.util.ItemUtils; +import com.gmail.nossr50.util.MetadataConstants; +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.RandomChanceUtil; +import com.gmail.nossr50.util.random.ProbabilityUtil; import com.gmail.nossr50.util.skills.RankUtils; -import com.gmail.nossr50.util.skills.SkillActivationType; import org.bukkit.Material; import org.bukkit.block.BlockState; import org.bukkit.entity.Item; @@ -25,8 +30,8 @@ import org.jetbrains.annotations.NotNull; public class UnarmedManager extends SkillManager { - public UnarmedManager(McMMOPlayer mcMMOPlayer) { - super(mcMMOPlayer, PrimarySkillType.UNARMED); + public UnarmedManager(McMMOPlayer mmoPlayer) { + super(mmoPlayer, PrimarySkillType.UNARMED); } public boolean canActivateAbility() { @@ -34,8 +39,9 @@ public class UnarmedManager extends SkillManager { } public boolean canUseSteelArm() { - if(!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.UNARMED_STEEL_ARM_STYLE)) + if (!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.UNARMED_STEEL_ARM_STYLE)) { return false; + } return Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.UNARMED_STEEL_ARM_STYLE); } @@ -45,51 +51,58 @@ public class UnarmedManager extends SkillManager { } public boolean canDisarm(LivingEntity target) { - if(!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.UNARMED_DISARM)) + if (!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.UNARMED_DISARM)) { return false; + } - return target instanceof Player && ((Player) target).getInventory().getItemInMainHand().getType() != Material.AIR && Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.UNARMED_DISARM); + return target instanceof Player + && ((Player) target).getInventory().getItemInMainHand().getType() != Material.AIR + && Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.UNARMED_DISARM); } public boolean canDeflect() { - if(!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.UNARMED_ARROW_DEFLECT)) + if (!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.UNARMED_ARROW_DEFLECT)) { return false; + } Player player = getPlayer(); - return ItemUtils.isUnarmed(player.getInventory().getItemInMainHand()) && Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.UNARMED_ARROW_DEFLECT); + return ItemUtils.isUnarmed(player.getInventory().getItemInMainHand()) + && Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.UNARMED_ARROW_DEFLECT); } public boolean canUseBlockCracker() { - if(!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.UNARMED_BLOCK_CRACKER)) + if (!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.UNARMED_BLOCK_CRACKER)) { return false; + } return Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.UNARMED_BLOCK_CRACKER); } - public boolean blockCrackerCheck(@NotNull BlockState blockState) { - if (!RandomChanceUtil.isActivationSuccessful(SkillActivationType.ALWAYS_FIRES, SubSkillType.UNARMED_BLOCK_CRACKER, getPlayer())) { - return false; + public void blockCrackerCheck(@NotNull BlockState blockState) { + if (!ProbabilityUtil.isNonRNGSkillActivationSuccessful(SubSkillType.UNARMED_BLOCK_CRACKER, + mmoPlayer)) { + return; } switch (blockState.getType()) { case STONE_BRICKS: if (!Unarmed.blockCrackerSmoothBrick) { - return false; + return; } blockState.getBlock().setType(Material.CRACKED_STONE_BRICKS); - return true; + blockState.update(true); + return; case INFESTED_STONE_BRICKS: if (!Unarmed.blockCrackerSmoothBrick) { - return false; + return; } blockState.getBlock().setType(Material.INFESTED_CRACKED_STONE_BRICKS); - return true; - + blockState.update(true); + return; default: - return false; } } @@ -99,22 +112,29 @@ public class UnarmedManager extends SkillManager { * @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 (isSkillRNGSuccessful(SubSkillType.UNARMED_DISARM, mmoPlayer, + mmoPlayer.getAttackStrength()) + && !hasIronGrip(defender)) { if (EventUtils.callDisarmEvent(defender).isCancelled()) { return; } - if(UserManager.getPlayer(defender) == null) + if (UserManager.getPlayer(defender) == null) { return; + } - Item item = Misc.spawnItem(getPlayer(), defender.getLocation(), defender.getInventory().getItemInMainHand(), ItemSpawnReason.UNARMED_DISARMED_ITEM); + final Item item = ItemUtils.spawnItem(getPlayer(), defender.getLocation(), + defender.getInventory().getItemInMainHand(), + ItemSpawnReason.UNARMED_DISARMED_ITEM); if (item != null && mcMMO.p.getAdvancedConfig().getDisarmProtected()) { - item.setMetadata(MetadataConstants.METADATA_KEY_DISARMED_ITEM, UserManager.getPlayer(defender).getPlayerMetadata()); + item.setMetadata(MetadataConstants.METADATA_KEY_DISARMED_ITEM, + UserManager.getPlayer(defender).getPlayerMetadata()); } defender.getInventory().setItemInMainHand(new ItemStack(Material.AIR)); - NotificationManager.sendPlayerInformation(defender, NotificationType.SUBSKILL_MESSAGE, "Skills.Disarmed"); + NotificationManager.sendPlayerInformation(defender, NotificationType.SUBSKILL_MESSAGE, + "Skills.Disarmed"); } } @@ -122,8 +142,9 @@ public class UnarmedManager extends SkillManager { * Check for arrow deflection. */ public boolean deflectCheck() { - if (RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.UNARMED_ARROW_DEFLECT, getPlayer())) { - NotificationManager.sendPlayerInformation(getPlayer(), NotificationType.SUBSKILL_MESSAGE, "Combat.ArrowDeflect"); + if (isSkillRNGSuccessful(SubSkillType.UNARMED_ARROW_DEFLECT, mmoPlayer)) { + NotificationManager.sendPlayerInformation(getPlayer(), + NotificationType.SUBSKILL_MESSAGE, "Combat.ArrowDeflect"); return true; } @@ -136,7 +157,8 @@ public class UnarmedManager extends SkillManager { * @param damage The amount of damage initially dealt by the event */ public double berserkDamage(double damage) { - damage = ((damage * Unarmed.berserkDamageModifier) * mmoPlayer.getAttackStrength()) - damage; + damage = + ((damage * Unarmed.berserkDamageModifier) * mmoPlayer.getAttackStrength()) - damage; return damage; } @@ -145,11 +167,12 @@ public class UnarmedManager extends SkillManager { * Handle the effects of the Iron Arm ability */ public double calculateSteelArmStyleDamage() { - if (!RandomChanceUtil.isActivationSuccessful(SkillActivationType.ALWAYS_FIRES, SubSkillType.UNARMED_STEEL_ARM_STYLE, getPlayer())) { - return 0; + if (ProbabilityUtil.isNonRNGSkillActivationSuccessful(SubSkillType.UNARMED_STEEL_ARM_STYLE, + mmoPlayer)) { + return getSteelArmStyleDamage(); } - return getSteelArmStyleDamage(); + return 0; } public double getSteelArmStyleDamage() { @@ -157,14 +180,16 @@ public class UnarmedManager extends SkillManager { double bonus = 0; - if(rank >= 18) + if (rank >= 18) { bonus = 1 + rank - 18; + } double finalBonus = bonus + 0.5 + (rank / 2); - - if(mcMMO.p.getAdvancedConfig().isSteelArmDamageCustom()) { - return mcMMO.p.getAdvancedConfig().getSteelArmOverride(RankUtils.getRank(getPlayer(), SubSkillType.UNARMED_STEEL_ARM_STYLE), finalBonus); + if (mcMMO.p.getAdvancedConfig().isSteelArmDamageCustom()) { + return mcMMO.p.getAdvancedConfig().getSteelArmOverride( + RankUtils.getRank(getPlayer(), SubSkillType.UNARMED_STEEL_ARM_STYLE), + finalBonus); } else { return finalBonus; } @@ -179,9 +204,12 @@ public class UnarmedManager extends SkillManager { 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)) { - NotificationManager.sendPlayerInformation(defender, NotificationType.SUBSKILL_MESSAGE, "Unarmed.Ability.IronGrip.Defender"); - NotificationManager.sendPlayerInformation(getPlayer(), NotificationType.SUBSKILL_MESSAGE, "Unarmed.Ability.IronGrip.Attacker"); + && isSkillRNGSuccessful(SubSkillType.UNARMED_IRON_GRIP, + UserManager.getPlayer(defender))) { + NotificationManager.sendPlayerInformation(defender, NotificationType.SUBSKILL_MESSAGE, + "Unarmed.Ability.IronGrip.Defender"); + NotificationManager.sendPlayerInformation(getPlayer(), + NotificationType.SUBSKILL_MESSAGE, "Unarmed.Ability.IronGrip.Attacker"); return true; } 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 c59a7e7ac..d3a05828f 100644 --- a/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java +++ b/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java @@ -1,5 +1,9 @@ package com.gmail.nossr50.skills.woodcutting; +import static com.gmail.nossr50.util.ItemUtils.spawnItemsFromCollection; +import static com.gmail.nossr50.util.Misc.getBlockCenter; +import static com.gmail.nossr50.util.skills.RankUtils.hasUnlockedSubskill; + import com.gmail.nossr50.api.FakeBlockBreakEventType; import com.gmail.nossr50.api.ItemSpawnReason; import com.gmail.nossr50.config.experience.ExperienceConfig; @@ -12,13 +16,22 @@ import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.datatypes.skills.SuperAbilityType; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.skills.SkillManager; -import com.gmail.nossr50.util.*; +import com.gmail.nossr50.util.BlockUtils; +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.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 java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.ThreadLocalRandom; +import java.util.function.Predicate; import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.block.Block; @@ -30,36 +43,38 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.Damageable; import org.bukkit.inventory.meta.ItemMeta; import org.jetbrains.annotations.NotNull; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; +import org.jetbrains.annotations.VisibleForTesting; public class WoodcuttingManager extends SkillManager { + public static final String SAPLING = "sapling"; + public static final String PROPAGULE = "propagule"; + private static final Predicate IS_SAPLING_OR_PROPAGULE = + p -> p.getType().getKey().getKey().toLowerCase().contains(SAPLING) + || p.getType().getKey().getKey().toLowerCase().contains(PROPAGULE); private boolean treeFellerReachedThreshold = false; - private static int treeFellerThreshold; //TODO: Shared setting, will be removed in 2.2 + private static int treeFellerThreshold; /** - * The x/y differences to the blocks in a flat cylinder around the center - * block, which is excluded. + * The x/y differences to the blocks in a flat cylinder around the center block, which is + * excluded. */ private static final int[][] directions = { - new int[] {-2, -1}, new int[] {-2, 0}, new int[] {-2, 1}, - new int[] {-1, -2}, new int[] {-1, -1}, new int[] {-1, 0}, new int[] {-1, 1}, new int[] {-1, 2}, - new int[] { 0, -2}, new int[] { 0, -1}, new int[] { 0, 1}, new int[] { 0, 2}, - new int[] { 1, -2}, new int[] { 1, -1}, new int[] { 1, 0}, new int[] { 1, 1}, new int[] { 1, 2}, - new int[] { 2, -1}, new int[] { 2, 0}, new int[] { 2, 1}, + new int[]{-2, -1}, new int[]{-2, 0}, new int[]{-2, 1}, + new int[]{-1, -2}, new int[]{-1, -1}, new int[]{-1, 0}, new int[]{-1, 1}, + new int[]{-1, 2}, + new int[]{0, -2}, new int[]{0, -1}, new int[]{0, 1}, new int[]{0, 2}, + new int[]{1, -2}, new int[]{1, -1}, new int[]{1, 0}, new int[]{1, 1}, new int[]{1, 2}, + new int[]{2, -1}, new int[]{2, 0}, new int[]{2, 1}, }; - public WoodcuttingManager(McMMOPlayer mcMMOPlayer) { - super(mcMMOPlayer, PrimarySkillType.WOODCUTTING); + public WoodcuttingManager(McMMOPlayer mmoPlayer) { + super(mmoPlayer, PrimarySkillType.WOODCUTTING); treeFellerThreshold = mcMMO.p.getGeneralConfig().getTreeFellerThreshold(); } public boolean canUseLeafBlower(ItemStack heldItem) { return Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.WOODCUTTING_LEAF_BLOWER) - && RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.WOODCUTTING_LEAF_BLOWER) + && hasUnlockedSubskill(getPlayer(), SubSkillType.WOODCUTTING_LEAF_BLOWER) && ItemUtils.isAxe(heldItem); } @@ -68,53 +83,99 @@ public class WoodcuttingManager extends SkillManager { && ItemUtils.isAxe(heldItem); } - private boolean checkHarvestLumberActivation(@NotNull Material material) { + private boolean checkHarvestLumberActivation(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()) - && mcMMO.p.getGeneralConfig().getDoubleDropsEnabled(PrimarySkillType.WOODCUTTING, material); + && ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.WOODCUTTING_HARVEST_LUMBER, + mmoPlayer) + && 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) + && ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.WOODCUTTING_CLEAN_CUTS, + mmoPlayer) + && mcMMO.p.getGeneralConfig() + .getDoubleDropsEnabled(PrimarySkillType.WOODCUTTING, material); } /** - * 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); + @Deprecated(forRemoval = true, since = "2.2.024") + public void processBonusDropCheck(@NotNull BlockState blockState) { + processBonusDropCheck(blockState.getBlock()); + } + + public void processBonusDropCheck(@NotNull Block block) { + //TODO: Why isn't this using the item drop event? Potentially because of Tree Feller? This should be adjusted either way. + if (mcMMO.p.getGeneralConfig() + .getDoubleDropsEnabled(PrimarySkillType.WOODCUTTING, block.getType())) { + //Mastery enabled for player + if (Permissions.canUseSubSkill(getPlayer(), SubSkillType.WOODCUTTING_CLEAN_CUTS)) { + if (checkCleanCutsActivation(block.getType())) { + //Triple drops + spawnHarvestLumberBonusDrops(block); + spawnHarvestLumberBonusDrops(block); + } else { + //Harvest Lumber Check + if (checkHarvestLumberActivation(block.getType())) { + spawnHarvestLumberBonusDrops(block); + } + } + //No Mastery (no Clean Cuts) + } else if (Permissions.canUseSubSkill(getPlayer(), + SubSkillType.WOODCUTTING_HARVEST_LUMBER)) { + if (checkHarvestLumberActivation(block.getType())) { + spawnHarvestLumberBonusDrops(block); + } + } } } + @Deprecated(forRemoval = true, since = "2.2.024") public void processWoodcuttingBlockXP(@NotNull BlockState blockState) { - if(mcMMO.getPlaceStore().isTrue(blockState)) - return; + processWoodcuttingBlockXP(blockState.getBlock()); + } - int xp = getExperienceFromLog(blockState); - applyXpGain(xp, XPGainReason.PVE); + public void processWoodcuttingBlockXP(@NotNull Block block) { + if (mcMMO.getUserBlockTracker().isIneligible(block)) { + return; + } + + int xp = getExperienceFromLog(block); + applyXpGain(xp, XPGainReason.PVE, XPGainSource.SELF); } /** * Begins Tree Feller * - * @param blockState Block being broken + * @param startingBlock The first startingBlock broken */ - public void processTreeFeller(BlockState blockState) { - Player player = getPlayer(); - Set treeFellerBlocks = new HashSet<>(); + public void processTreeFeller(Block startingBlock) { + final Player player = getPlayer(); + Set treeFellerBlocks = new HashSet<>(); treeFellerReachedThreshold = false; - processTree(blockState, treeFellerBlocks); + processTree(startingBlock, treeFellerBlocks); // If the tool can't sustain the durability loss - if (!handleDurabilityLoss(treeFellerBlocks, player.getInventory().getItemInMainHand(), player)) { - NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE_FAILED, "Woodcutting.Skills.TreeFeller.Splinter"); + if (!handleDurabilityLoss(treeFellerBlocks, player.getInventory().getItemInMainHand(), + player)) { + NotificationManager.sendPlayerInformation(player, + NotificationType.SUBSKILL_MESSAGE_FAILED, + "Woodcutting.Skills.TreeFeller.Splinter"); double health = player.getHealth(); if (health > 1) { - CombatUtils.dealDamage(player, Misc.getRandom().nextInt((int) (health - 1))); + int dmg = Misc.getRandom().nextInt((int) (health - 1)); + CombatUtils.safeDealDamage(player, dmg); } return; @@ -125,54 +186,51 @@ public class WoodcuttingManager extends SkillManager { } /** - * Processes Tree Feller in a recursive manner - * - * @param blockState Block being checked - * @param treeFellerBlocks List of blocks to be removed - */ - /* - * Algorithm: An int[][] of X/Z directions is created on static class - * initialization, representing a cylinder with radius of about 2 - the - * (0,0) center and all (+-2, +-2) corners are omitted. - * + * Process the tree feller ability. + *

+ * Algorithm: An int[][] of X/Z directions is created on static class initialization, + * representing a cylinder with radius of about 2 - the (0,0) center and all (+-2, +-2) corners + * are omitted. + *

* processTreeFellerTargetBlock() returns a boolean, which is used for the sole purpose of * switching between these two behaviors: - * + *

* (Call blockState "this log" for the below explanation.) - * - * [A] There is another log above this log (TRUNK) - * Only the flat cylinder in the directions array is searched. - * [B] There is not another log above this log (BRANCH AND TOP) - * The cylinder in the directions array is extended up and down by 1 - * block in the Y-axis, and the block below this log is checked as - * well. Due to the fact that the directions array will catch all - * blocks on a red mushroom, the special method for it is eliminated. - * - * This algorithm has been shown to achieve a performance of 2-5 - * milliseconds on regular trees and 10-15 milliseconds on jungle trees - * once the JIT has optimized the function (use the ability about 4 times - * before taking measurements). + *

+ * [A] There is another log above this log (TRUNK) Only the flat cylinder in the directions + * array is searched. [B] There is not another log above this log (BRANCH AND TOP) The cylinder + * in the directions array is extended up and down by 1 block in the Y-axis, and the block below + * this log is checked as well. Due to the fact that the directions array will catch all blocks + * on a red mushroom, the special method for it is eliminated. + *

+ * This algorithm has been shown to achieve a performance of 2-5 milliseconds on regular trees + * and 10-15 milliseconds on jungle trees once the JIT has optimized the function (use the + * ability about 4 times before taking measurements). */ - private void processTree(BlockState blockState, Set treeFellerBlocks) { - List futureCenterBlocks = new ArrayList<>(); + @VisibleForTesting + void processTree(Block block, Set treeFellerBlocks) { + List futureCenterBlocks = new ArrayList<>(); // Check the block up and take different behavior (smaller search) if it's a log - if (processTreeFellerTargetBlock(blockState.getBlock().getRelative(BlockFace.UP).getState(), futureCenterBlocks, treeFellerBlocks)) { + if (processTreeFellerTargetBlock(block.getRelative(BlockFace.UP), futureCenterBlocks, + treeFellerBlocks)) { for (int[] dir : directions) { - processTreeFellerTargetBlock(blockState.getBlock().getRelative(dir[0], 0, dir[1]).getState(), futureCenterBlocks, treeFellerBlocks); + processTreeFellerTargetBlock(block.getRelative(dir[0], 0, dir[1]), + futureCenterBlocks, treeFellerBlocks); if (treeFellerReachedThreshold) { return; } } - } - else { + } else { // Cover DOWN - processTreeFellerTargetBlock(blockState.getBlock().getRelative(BlockFace.DOWN).getState(), futureCenterBlocks, treeFellerBlocks); + processTreeFellerTargetBlock(block.getRelative(BlockFace.DOWN), futureCenterBlocks, + treeFellerBlocks); // Search in a cube for (int y = -1; y <= 1; y++) { for (int[] dir : directions) { - processTreeFellerTargetBlock(blockState.getBlock().getRelative(dir[0], y, dir[1]).getState(), futureCenterBlocks, treeFellerBlocks); + processTreeFellerTargetBlock(block.getRelative(dir[0], y, dir[1]), + futureCenterBlocks, treeFellerBlocks); if (treeFellerReachedThreshold) { return; @@ -182,7 +240,7 @@ public class WoodcuttingManager extends SkillManager { } // Recursive call for each log found - for (BlockState futureCenterBlock : futureCenterBlocks) { + for (Block futureCenterBlock : futureCenterBlocks) { if (treeFellerReachedThreshold) { return; } @@ -199,7 +257,8 @@ public class WoodcuttingManager extends SkillManager { * @param player the player holding the item * @return True if the tool can sustain the durability loss */ - private static boolean handleDurabilityLoss(@NotNull Set treeFellerBlocks, @NotNull ItemStack inHand, @NotNull Player player) { + private static boolean handleDurabilityLoss(@NotNull Set treeFellerBlocks, + @NotNull ItemStack inHand, @NotNull Player player) { //Treat the NBT tag for unbreakable and the durability enchant differently ItemMeta meta = inHand.getItemMeta(); @@ -210,15 +269,16 @@ public class WoodcuttingManager extends SkillManager { int durabilityLoss = 0; Material type = inHand.getType(); - for (BlockState blockState : treeFellerBlocks) { - if (BlockUtils.hasWoodcuttingXP(blockState)) { + for (Block block : treeFellerBlocks) { + if (BlockUtils.hasWoodcuttingXP(block)) { durabilityLoss += mcMMO.p.getGeneralConfig().getAbilityToolDamage(); } } // Call PlayerItemDamageEvent first to make sure it's not cancelled //TODO: Put this event stuff in handleDurabilityChange - final PlayerItemDamageEvent event = new PlayerItemDamageEvent(player, inHand, durabilityLoss); + final PlayerItemDamageEvent event = new PlayerItemDamageEvent(player, inHand, + durabilityLoss); Bukkit.getPluginManager().callEvent(event); if (event.isCancelled()) { @@ -226,24 +286,25 @@ public class WoodcuttingManager extends SkillManager { } SkillUtils.handleDurabilityChange(inHand, durabilityLoss); - int durability = meta instanceof Damageable ? ((Damageable) meta).getDamage(): 0; - return (durability < (mcMMO.getRepairableManager().isRepairable(type) ? mcMMO.getRepairableManager().getRepairable(type).getMaximumDurability() : type.getMaxDurability())); + int durability = meta instanceof Damageable ? ((Damageable) meta).getDamage() : 0; + return (durability < (mcMMO.getRepairableManager().isRepairable(type) + ? mcMMO.getRepairableManager().getRepairable(type).getMaximumDurability() + : type.getMaxDurability())); } /** - * Handle a block addition to the list of blocks to be removed and to the - * list of blocks used for future recursive calls of - * 'processTree()' + * Handle a block addition to the list of blocks to be removed and to the list of blocks used + * for future recursive calls of 'processTree()' * - * @param blockState Block to be added - * @param futureCenterBlocks List of blocks that will be used to call - * 'processTree()' + * @param block Block to be added + * @param futureCenterBlocks List of blocks that will be used to call 'processTree()' * @param treeFellerBlocks List of blocks to be removed - * @return true if and only if the given blockState was a Log not already - * in treeFellerBlocks. + * @return true if and only if the given block was a Log not already in treeFellerBlocks. */ - private boolean processTreeFellerTargetBlock(@NotNull BlockState blockState, @NotNull List futureCenterBlocks, @NotNull Set treeFellerBlocks) { - if (treeFellerBlocks.contains(blockState) || mcMMO.getPlaceStore().isTrue(blockState)) { + private boolean processTreeFellerTargetBlock(@NotNull Block block, + @NotNull List futureCenterBlocks, + @NotNull Set treeFellerBlocks) { + if (treeFellerBlocks.contains(block) || mcMMO.getUserBlockTracker().isIneligible(block)) { return false; } @@ -252,13 +313,12 @@ public class WoodcuttingManager extends SkillManager { treeFellerReachedThreshold = true; } - if (BlockUtils.hasWoodcuttingXP(blockState)) { - treeFellerBlocks.add(blockState); - futureCenterBlocks.add(blockState); + if (BlockUtils.hasWoodcuttingXP(block)) { + treeFellerBlocks.add(block); + futureCenterBlocks.add(block); return true; - } - else if (BlockUtils.isNonWoodPartOfTree(blockState)) { - treeFellerBlocks.add(blockState); + } else if (BlockUtils.isNonWoodPartOfTree(block)) { + treeFellerBlocks.add(block); return false; } return false; @@ -269,17 +329,17 @@ public class WoodcuttingManager extends SkillManager { * * @param treeFellerBlocks List of blocks to be dropped */ - private void dropTreeFellerLootFromBlocks(@NotNull Set treeFellerBlocks) { + private void dropTreeFellerLootFromBlocks(@NotNull Set treeFellerBlocks) { Player player = getPlayer(); int xp = 0; int processedLogCount = 0; ItemStack itemStack = player.getInventory().getItemInMainHand(); - for (BlockState blockState : treeFellerBlocks) { + for (Block block : treeFellerBlocks) { int beforeXP = xp; - Block block = blockState.getBlock(); - if (!EventUtils.simulateBlockBreak(block, player, FakeBlockBreakEventType.TREE_FELLER)) { + if (!EventUtils.simulateBlockBreak(block, player, + FakeBlockBreakEventType.TREE_FELLER)) { continue; } @@ -287,37 +347,50 @@ public class WoodcuttingManager extends SkillManager { * Handle Drops & XP */ - if (BlockUtils.hasWoodcuttingXP(blockState)) { + if (BlockUtils.hasWoodcuttingXP(block)) { //Add XP - xp += processTreeFellerXPGains(blockState, processedLogCount); + xp += processTreeFellerXPGains(block, processedLogCount); //Drop displaced block - Misc.spawnItemsFromCollection(getPlayer(), Misc.getBlockCenter(blockState), block.getDrops(itemStack), ItemSpawnReason.TREE_FELLER_DISPLACED_BLOCK); + spawnItemsFromCollection(player, getBlockCenter(block), + block.getDrops(itemStack), ItemSpawnReason.TREE_FELLER_DISPLACED_BLOCK); //Bonus Drops / Harvest lumber checks - processHarvestLumber(blockState); - } else if (BlockUtils.isNonWoodPartOfTree(blockState)) { + processBonusDropCheck(block); + } else if (BlockUtils.isNonWoodPartOfTree(block)) { + // 75% of the time do not drop leaf blocks + if (ThreadLocalRandom.current().nextInt(100) > 75) { + spawnItemsFromCollection(player, + getBlockCenter(block), + block.getDrops(itemStack), + ItemSpawnReason.TREE_FELLER_DISPLACED_BLOCK); + } else if (hasUnlockedSubskill(player, SubSkillType.WOODCUTTING_KNOCK_ON_WOOD)) { + // if KnockOnWood is unlocked, then drop any saplings from the remaining blocks + ItemUtils.spawnItemsConditionally(block.getDrops(itemStack), + IS_SAPLING_OR_PROPAGULE, + ItemSpawnReason.TREE_FELLER_DISPLACED_BLOCK, + getBlockCenter(block), + // only spawn saplings + player + ); + } + //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()) { - if(RandomChanceUtil.rollDice(10, 100)) { + if (hasUnlockedSubskill(player, SubSkillType.WOODCUTTING_KNOCK_ON_WOOD)) { + if (RankUtils.hasReachedRank(2, player, + SubSkillType.WOODCUTTING_KNOCK_ON_WOOD)) { + if (mcMMO.p.getAdvancedConfig().isKnockOnWoodXPOrbEnabled()) { + if (ProbabilityUtil.isStaticSkillRNGSuccessful( + PrimarySkillType.WOODCUTTING, mmoPlayer, 10)) { int randOrbCount = Math.max(1, Misc.getRandom().nextInt(100)); - Misc.spawnExperienceOrb(blockState.getLocation(), randOrbCount); + Misc.spawnExperienceOrb(block.getLocation(), randOrbCount); } } } - - } else { - Misc.spawnItemsFromCollection(getPlayer(), Misc.getBlockCenter(blockState), block.getDrops(itemStack), ItemSpawnReason.TREE_FELLER_DISPLACED_BLOCK, 1); } } - blockState.setType(Material.AIR); - blockState.update(true); + block.setType(Material.AIR); //Update only when XP changes processedLogCount = updateProcessedLogCount(xp, processedLogCount, beforeXP); @@ -327,37 +400,42 @@ public class WoodcuttingManager extends SkillManager { } private int updateProcessedLogCount(int xp, int processedLogCount, int beforeXP) { - if(beforeXP != xp) - processedLogCount+=1; + if (beforeXP != xp) { + processedLogCount += 1; + } return processedLogCount; } /** - * Retrieves the experience reward from logging via Tree Feller - * Experience is reduced per log processed so far - * Experience is only reduced if the config option to reduce Tree Feller XP is set - * Experience per log will not fall below 1 unless the experience for that log is set to 0 in the config + * Retrieves the experience reward from logging via Tree Feller Experience is reduced per log + * processed so far Experience is only reduced if the config option to reduce Tree Feller XP is + * set Experience per log will not fall below 1 unless the experience for that log is set to 0 + * in the config * - * @param blockState Log being broken + * @param block Log being broken * @param woodCount how many logs have given out XP for this tree feller so far * @return Amount of experience */ - private static int processTreeFellerXPGains(BlockState blockState, int woodCount) { - if(mcMMO.getPlaceStore().isTrue(blockState)) + private static int processTreeFellerXPGains(Block block, int woodCount) { + if (mcMMO.getUserBlockTracker().isIneligible(block)) { return 0; + } - int rawXP = ExperienceConfig.getInstance().getXp(PrimarySkillType.WOODCUTTING, blockState.getType()); + int rawXP = ExperienceConfig.getInstance() + .getXp(PrimarySkillType.WOODCUTTING, block.getType()); - if(rawXP <= 0) + if (rawXP <= 0) { return 0; + } - if(ExperienceConfig.getInstance().isTreeFellerXPReduced()) { + if (ExperienceConfig.getInstance().isTreeFellerXPReduced()) { int reducedXP = rawXP - (woodCount * 5); rawXP = Math.max(1, reducedXP); return rawXP; } else { - return ExperienceConfig.getInstance().getXp(PrimarySkillType.WOODCUTTING, blockState.getType()); + return ExperienceConfig.getInstance() + .getXp(PrimarySkillType.WOODCUTTING, block.getType()); } } @@ -367,12 +445,19 @@ public class WoodcuttingManager extends SkillManager { * @param blockState Log being broken * @return Amount of experience */ + @Deprecated(forRemoval = true, since = "2.2.024") protected static int getExperienceFromLog(BlockState blockState) { - if (mcMMO.getModManager().isCustomLog(blockState)) { - return mcMMO.getModManager().getBlock(blockState).getXpGain(); - } + return getExperienceFromLog(blockState.getBlock()); + } - return ExperienceConfig.getInstance().getXp(PrimarySkillType.WOODCUTTING, blockState.getType()); + /** + * Retrieves the experience reward from a log + * + * @param block Log being broken + * @return Amount of experience + */ + protected static int getExperienceFromLog(Block block) { + return ExperienceConfig.getInstance().getXp(PrimarySkillType.WOODCUTTING, block.getType()); } /** @@ -380,7 +465,16 @@ public class WoodcuttingManager extends SkillManager { * * @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); + @Deprecated(forRemoval = true, since = "2.2.024") + void spawnHarvestLumberBonusDrops(@NotNull BlockState blockState) { + spawnHarvestLumberBonusDrops(blockState.getBlock()); + } + + void spawnHarvestLumberBonusDrops(@NotNull Block block) { + spawnItemsFromCollection( + getPlayer(), + getBlockCenter(block), + block.getDrops(getPlayer().getInventory().getItemInMainHand()), + ItemSpawnReason.BONUS_DROPS); } } diff --git a/src/main/java/com/gmail/nossr50/util/AttributeMapper.java b/src/main/java/com/gmail/nossr50/util/AttributeMapper.java new file mode 100644 index 000000000..c1388c15f --- /dev/null +++ b/src/main/java/com/gmail/nossr50/util/AttributeMapper.java @@ -0,0 +1,201 @@ +package com.gmail.nossr50.util; + +import com.gmail.nossr50.mcMMO; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.Optional; +import java.util.stream.Stream; +import org.bukkit.attribute.Attribute; + +public class AttributeMapper { + + public static final String ATTRIBUTE = "ATTRIBUTE"; + public static final String ORG_BUKKIT_REGISTRY = "org.bukkit.Registry"; + + // Prevent instantiation + private AttributeMapper() { + } + + // Define constants for attribute keys and their legacy counterparts + private static final String MAX_HEALTH_1_21_3_STR = "max_health"; + private static final String MAX_HEALTH_1_18_2_STR = "generic.max_health"; + public static final Attribute MAPPED_MAX_HEALTH; + + private static final String JUMP_STRENGTH_1_23_1 = "jump_strength"; + private static final String JUMP_STRENGTH_1_21_1 = "generic.jump_strength"; + private static final String JUMP_STR_1_18_2 = "horse.jump_strength"; + public static final Attribute MAPPED_JUMP_STRENGTH; + + public static final Attribute MAPPED_MOVEMENT_SPEED; + private static final String MOVEMENT_SPEED_1_18_2 = "generic.movement_speed"; + private static final String MOVEMENT_SPEED_1_21_1 = "generic.movement_speed"; + private static final String MOVEMENT_SPEED_1_21_3 = "movement_speed"; + + // Add other attributes similarly... + // For brevity, only key attributes are shown + + static { + MAPPED_MAX_HEALTH = findAttribute(MAX_HEALTH_1_21_3_STR, MAX_HEALTH_1_18_2_STR); + MAPPED_JUMP_STRENGTH = findAttribute(JUMP_STRENGTH_1_23_1, JUMP_STRENGTH_1_21_1, + JUMP_STR_1_18_2); + MAPPED_MOVEMENT_SPEED = findAttribute(MOVEMENT_SPEED_1_18_2, MOVEMENT_SPEED_1_21_1, + MOVEMENT_SPEED_1_21_3); + } + + private static Attribute findAttribute(String... keys) { + Stream attributeStream; + try { + // Try to get Registry.ATTRIBUTE using reflection + Class registryClass = Class.forName(ORG_BUKKIT_REGISTRY); + Field attributeField = registryClass.getField(ATTRIBUTE); + Object attributeRegistry = attributeField.get(null); + + // Get the stream() method of the attribute registry + Method streamMethod = attributeRegistry.getClass().getMethod("stream"); + attributeStream = (Stream) streamMethod.invoke(attributeRegistry); + } catch (ClassNotFoundException | NoSuchFieldException | IllegalAccessException | + NoSuchMethodException | + InvocationTargetException e) { + // Fallback to older versions where Attribute is an enum + Object[] enumConstants = Attribute.class.getEnumConstants(); + attributeStream = Arrays.stream(enumConstants); + } + + Optional optionalAttribute = attributeStream + .filter(attr -> { + try { + String attrKey = null; + String attrName = null; + + // Try to get attr.getKey().getKey() + Method getKeyMethod = attr.getClass().getMethod("getKey"); + Object namespacedKey = getKeyMethod.invoke(attr); + + if (namespacedKey != null) { + Method getKeyStringMethod = namespacedKey.getClass() + .getMethod("getKey"); + attrKey = (String) getKeyStringMethod.invoke(namespacedKey); + } + + // Try to get attr.name() + Method nameMethod; + try { + nameMethod = attr.getClass().getMethod("name"); + attrName = (String) nameMethod.invoke(attr); + } catch (NoSuchMethodException e) { + // name() method doesn't exist in newer versions + attrName = null; + } + + // Compare with provided keys + for (String key : keys) { + if ((attrKey != null && attrKey.equalsIgnoreCase(key)) || + (attrName != null && attrName.equalsIgnoreCase(key))) { + return true; + } + } + } catch (Exception e) { + mcMMO.p.getLogger() + .severe("Unable to find the attribute with possible keys: " + + Arrays.toString(keys) + + ", mcMMO will not function properly."); + throw new RuntimeException(e); + } + return false; + }) + .findFirst(); + + if (optionalAttribute.isPresent()) { + return (Attribute) optionalAttribute.get(); + } else { + mcMMO.p.getLogger().severe("Unable to find the attribute with possible keys: " + + Arrays.toString(keys) + ", mcMMO will not function properly."); + throw new IllegalStateException("Unable to find the attribute with possible keys: " + + Arrays.toString(keys)); + } + } + + /* + For easy reference... + List of 1.18 Attributes by name... + GENERIC_MAX_HEALTH("generic.max_health"), + GENERIC_FOLLOW_RANGE("generic.follow_range"), + GENERIC_KNOCKBACK_RESISTANCE("generic.knockback_resistance"), + GENERIC_MOVEMENT_SPEED("generic.movement_speed"), + GENERIC_FLYING_SPEED("generic.flying_speed"), + GENERIC_ATTACK_DAMAGE("generic.attack_damage"), + GENERIC_ATTACK_KNOCKBACK("generic.attack_knockback"), + GENERIC_ATTACK_SPEED("generic.attack_speed"), + GENERIC_ARMOR("generic.armor"), + GENERIC_ARMOR_TOUGHNESS("generic.armor_toughness"), + GENERIC_LUCK("generic.luck"), + HORSE_JUMP_STRENGTH("horse.jump_strength"), + ZOMBIE_SPAWN_REINFORCEMENTS("zombie.spawn_reinforcements"); + List of 1.21.1 Attributes by name... + GENERIC_MAX_HEALTH("generic.max_health"), + GENERIC_FOLLOW_RANGE("generic.follow_range"), + GENERIC_KNOCKBACK_RESISTANCE("generic.knockback_resistance"), + GENERIC_MOVEMENT_SPEED("generic.movement_speed"), + GENERIC_FLYING_SPEED("generic.flying_speed"), + GENERIC_ATTACK_DAMAGE("generic.attack_damage"), + GENERIC_ATTACK_KNOCKBACK("generic.attack_knockback"), + GENERIC_ATTACK_SPEED("generic.attack_speed"), + GENERIC_ARMOR("generic.armor"), + GENERIC_ARMOR_TOUGHNESS("generic.armor_toughness"), + GENERIC_FALL_DAMAGE_MULTIPLIER("generic.fall_damage_multiplier"), + GENERIC_LUCK("generic.luck"), + GENERIC_MAX_ABSORPTION("generic.max_absorption"), + GENERIC_SAFE_FALL_DISTANCE("generic.safe_fall_distance"), + GENERIC_SCALE("generic.scale"), + GENERIC_STEP_HEIGHT("generic.step_height"), + GENERIC_GRAVITY("generic.gravity"), + GENERIC_JUMP_STRENGTH("generic.jump_strength"), + GENERIC_EXPLOSION_KNOCKBACK_RESISTANCE("generic.explosion_knockback_resistance"), + GENERIC_MOVEMENT_EFFICIENCY("generic.movement_efficiency"), + GENERIC_OXYGEN_BONUS("generic.oxygen_bonus"), + GENERIC_WATER_MOVEMENT_EFFICIENCY("generic.water_movement_efficiency"), + PLAYER_BLOCK_INTERACTION_RANGE("player.block_interaction_range"), + PLAYER_ENTITY_INTERACTION_RANGE("player.entity_interaction_range"), + PLAYER_BLOCK_BREAK_SPEED("player.block_break_speed"), + PLAYER_MINING_EFFICIENCY("player.mining_efficiency"), + PLAYER_SNEAKING_SPEED("player.sneaking_speed"), + PLAYER_SUBMERGED_MINING_SPEED("player.submerged_mining_speed"), + PLAYER_SWEEPING_DAMAGE_RATIO("player.sweeping_damage_ratio"), + ZOMBIE_SPAWN_REINFORCEMENTS("zombie.spawn_reinforcements"); + List of 1.21.3 Attributes... + Attribute MAX_HEALTH = getAttribute("max_health"); + Attribute FOLLOW_RANGE = getAttribute("follow_range"); + Attribute KNOCKBACK_RESISTANCE = getAttribute("knockback_resistance"); + Attribute MOVEMENT_SPEED = getAttribute("movement_speed"); + Attribute FLYING_SPEED = getAttribute("flying_speed"); + Attribute ATTACK_DAMAGE = getAttribute("attack_damage"); + Attribute ATTACK_KNOCKBACK = getAttribute("attack_knockback"); + Attribute ATTACK_SPEED = getAttribute("attack_speed"); + Attribute ARMOR = getAttribute("armor"); + Attribute ARMOR_TOUGHNESS = getAttribute("armor_toughness"); + Attribute FALL_DAMAGE_MULTIPLIER = getAttribute("fall_damage_multiplier"); + Attribute LUCK = getAttribute("luck"); + Attribute MAX_ABSORPTION = getAttribute("max_absorption"); + Attribute SAFE_FALL_DISTANCE = getAttribute("safe_fall_distance"); + Attribute SCALE = getAttribute("scale"); + Attribute STEP_HEIGHT = getAttribute("step_height"); + Attribute GRAVITY = getAttribute("gravity"); + Attribute JUMP_STRENGTH = getAttribute("jump_strength"); + Attribute BURNING_TIME = getAttribute("burning_time"); + Attribute EXPLOSION_KNOCKBACK_RESISTANCE = getAttribute("explosion_knockback_resistance"); + Attribute MOVEMENT_EFFICIENCY = getAttribute("movement_efficiency"); + Attribute OXYGEN_BONUS = getAttribute("oxygen_bonus"); + Attribute WATER_MOVEMENT_EFFICIENCY = getAttribute("water_movement_efficiency"); + Attribute TEMPT_RANGE = getAttribute("tempt_range"); + Attribute BLOCK_INTERACTION_RANGE = getAttribute("block_interaction_range"); + Attribute ENTITY_INTERACTION_RANGE = getAttribute("entity_interaction_range"); + Attribute BLOCK_BREAK_SPEED = getAttribute("block_break_speed"); + Attribute MINING_EFFICIENCY = getAttribute("mining_efficiency"); + Attribute SNEAKING_SPEED = getAttribute("sneaking_speed"); + Attribute SUBMERGED_MINING_SPEED = getAttribute("submerged_mining_speed"); + Attribute SWEEPING_DAMAGE_RATIO = getAttribute("sweeping_damage_ratio"); + Attribute SPAWN_REINFORCEMENTS = getAttribute("spawn_reinforcements"); + */ +} diff --git a/src/main/java/com/gmail/nossr50/util/BlockUtils.java b/src/main/java/com/gmail/nossr50/util/BlockUtils.java index 7ef3cbc81..174a83fb9 100644 --- a/src/main/java/com/gmail/nossr50/util/BlockUtils.java +++ b/src/main/java/com/gmail/nossr50/util/BlockUtils.java @@ -1,14 +1,18 @@ package com.gmail.nossr50.util; +import static java.util.Objects.requireNonNull; + import com.gmail.nossr50.config.experience.ExperienceConfig; import com.gmail.nossr50.datatypes.meta.BonusDropMeta; +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.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.player.UserManager; +import com.gmail.nossr50.util.random.ProbabilityUtil; +import java.util.HashSet; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Block; @@ -17,8 +21,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; +import org.jetbrains.annotations.Nullable; public final class BlockUtils { @@ -32,17 +35,32 @@ public final class BlockUtils { * Mark a block for giving bonus drops, double drops are used if triple is false * * @param blockState target blockstate - * @param triple marks the block to give triple drops + * @param triple marks the block to give triple drops */ + @Deprecated(forRemoval = true, since = "2.2.024") public static void markDropsAsBonus(BlockState blockState, boolean triple) { - if (triple) - blockState.setMetadata(MetadataConstants.METADATA_KEY_BONUS_DROPS, new BonusDropMeta(2, mcMMO.p)); - else - blockState.setMetadata(MetadataConstants.METADATA_KEY_BONUS_DROPS, new BonusDropMeta(1, mcMMO.p)); + if (triple) { + blockState.getBlock().setMetadata(MetadataConstants.METADATA_KEY_BONUS_DROPS, + new BonusDropMeta(2, mcMMO.p)); + } else { + blockState.getBlock().setMetadata(MetadataConstants.METADATA_KEY_BONUS_DROPS, + new BonusDropMeta(1, mcMMO.p)); + } + } + + public static void markDropsAsBonus(Block block, boolean triple) { + if (triple) { + block.setMetadata(MetadataConstants.METADATA_KEY_BONUS_DROPS, + new BonusDropMeta(2, mcMMO.p)); + } else { + block.setMetadata(MetadataConstants.METADATA_KEY_BONUS_DROPS, + new BonusDropMeta(1, mcMMO.p)); + } } /** - * Util method for compatibility across Minecraft versions, grabs the {@link Material} enum for short_grass + * Util method for compatibility across Minecraft versions, grabs the {@link Material} enum for + * short_grass * * @return the {@link Material} enum for short_grass */ @@ -57,37 +75,55 @@ public final class BlockUtils { } /** - * Set up the state for a block to be seen as unnatural and cleanup any unwanted metadata from the block + * Set up the state for a block to be seen as unnatural and cleanup any unwanted metadata from + * the block + * * @param block target block */ public static void setUnnaturalBlock(@NotNull Block block) { - mcMMO.getPlaceStore().setTrue(block); + mcMMO.getUserBlockTracker().setIneligible(block); // Failsafe against lingering metadata - if(block.hasMetadata(MetadataConstants.METADATA_KEY_BONUS_DROPS)) + if (block.hasMetadata(MetadataConstants.METADATA_KEY_BONUS_DROPS)) { block.removeMetadata(MetadataConstants.METADATA_KEY_BONUS_DROPS, mcMMO.p); + } } /** - * Cleans up some block metadata when a block breaks and the metadata is no longer needed - * This also sets the blocks coords to false in our chunk store + * Cleans up some block metadata when a block breaks and the metadata is no longer needed This + * also sets the blocks coords to false in our chunk store + * * @param block target block */ public static void cleanupBlockMetadata(Block block) { - if(block.hasMetadata(MetadataConstants.METADATA_KEY_REPLANT)) { + if (block.hasMetadata(MetadataConstants.METADATA_KEY_REPLANT)) { block.removeMetadata(MetadataConstants.METADATA_KEY_REPLANT, mcMMO.p); } - mcMMO.getPlaceStore().setFalse(block); + mcMMO.getUserBlockTracker().setEligible(block); } /** * Marks a block to drop extra copies of items + * * @param blockState target blockstate * @param amount amount of extra items to drop */ + @Deprecated(forRemoval = true, since = "2.2.024") public static void markDropsAsBonus(BlockState blockState, int amount) { - blockState.setMetadata(MetadataConstants.METADATA_KEY_BONUS_DROPS, new BonusDropMeta(amount, mcMMO.p)); + blockState.setMetadata(MetadataConstants.METADATA_KEY_BONUS_DROPS, + new BonusDropMeta(amount, mcMMO.p)); + } + + /** + * Marks a block to drop extra copies of items + * + * @param block target block + * @param amount the number of extra items to drop + */ + public static void markDropsAsBonus(Block block, int amount) { + block.setMetadata(MetadataConstants.METADATA_KEY_BONUS_DROPS, + new BonusDropMeta(amount, mcMMO.p)); } /** @@ -95,10 +131,53 @@ public final class BlockUtils { * * @param blockState the blockstate * @return true if the player succeeded in the check + * @deprecated Use {@link #checkDoubleDrops(McMMOPlayer, BlockState, SubSkillType)} instead */ - 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)); + @Deprecated(forRemoval = true, since = "2.2.010") + public static boolean checkDoubleDrops(Player player, BlockState blockState, + PrimarySkillType ignored, SubSkillType subSkillType) { + return checkDoubleDrops(UserManager.getPlayer(player), blockState, subSkillType); + } + + /** + * Checks if a player successfully passed the double drop check + * + * @param mmoPlayer the player involved in the check + * @param blockState the blockstate of the block + * @param subSkillType the subskill involved + * @return true if the player succeeded in the check + */ + @Deprecated(forRemoval = true, since = "2.2.024") + public static boolean checkDoubleDrops(@Nullable McMMOPlayer mmoPlayer, + @NotNull BlockState blockState, + @NotNull SubSkillType subSkillType) { + requireNonNull(blockState, "blockState cannot be null"); + requireNonNull(subSkillType, "subSkillType cannot be null"); + if (mcMMO.p.getGeneralConfig() + .getDoubleDropsEnabled(subSkillType.getParentSkill(), blockState.getType()) + && Permissions.isSubSkillEnabled(mmoPlayer, subSkillType)) { + return ProbabilityUtil.isSkillRNGSuccessful(subSkillType, mmoPlayer); + } + + return false; + } + + /** + * Checks if a player successfully passed the double drop check + * + * @param mmoPlayer the player involved in the check + * @param block the block + * @param subSkillType the subskill involved + * @return true if the player succeeded in the check + */ + public static boolean checkDoubleDrops(@Nullable McMMOPlayer mmoPlayer, @NotNull Block block, + @NotNull SubSkillType subSkillType) { + requireNonNull(block, "block cannot be null"); + requireNonNull(subSkillType, "subSkillType cannot be null"); + if (mcMMO.p.getGeneralConfig() + .getDoubleDropsEnabled(subSkillType.getParentSkill(), block.getType()) + && Permissions.isSubSkillEnabled(mmoPlayer, subSkillType)) { + return ProbabilityUtil.isSkillRNGSuccessful(subSkillType, mmoPlayer); } return false; @@ -111,31 +190,45 @@ public final class BlockUtils { * @return true if the block awards XP, false otherwise */ public static boolean shouldBeWatched(BlockState blockState) { - return affectedByGigaDrillBreaker(blockState) || affectedByGreenTerra(blockState) || affectedBySuperBreaker(blockState) || hasWoodcuttingXP(blockState) - || mcMMO.p.getGeneralConfig().getDoubleDropsEnabled(PrimarySkillType.MINING, blockState.getType()) - || mcMMO.p.getGeneralConfig().getDoubleDropsEnabled(PrimarySkillType.EXCAVATION, blockState.getType()) - || mcMMO.p.getGeneralConfig().getDoubleDropsEnabled(PrimarySkillType.WOODCUTTING, blockState.getType()) - || mcMMO.p.getGeneralConfig().getDoubleDropsEnabled(PrimarySkillType.SMELTING, blockState.getType()); + return shouldBeWatched(blockState.getType()); + } + + public static boolean shouldBeWatched(Material material) { + return affectedByGigaDrillBreaker(material) + || affectedByGreenTerra(material) + || affectedBySuperBreaker(material) + || hasWoodcuttingXP(material) + || mcMMO.p.getGeneralConfig() + .getDoubleDropsEnabled(PrimarySkillType.MINING, material) + || mcMMO.p.getGeneralConfig() + .getDoubleDropsEnabled(PrimarySkillType.EXCAVATION, material) + || mcMMO.p.getGeneralConfig() + .getDoubleDropsEnabled(PrimarySkillType.WOODCUTTING, material) + || mcMMO.p.getGeneralConfig() + .getDoubleDropsEnabled(PrimarySkillType.SMELTING, material); } /** * Check if a given block should allow for the activation of abilities * * @param blockState The {@link BlockState} of the block to check - * @return true if the block should allow ability activation, false - * otherwise + * @return true if the block should allow ability activation, false otherwise */ + @Deprecated(forRemoval = true, since = "2.2.024") public static boolean canActivateAbilities(BlockState blockState) { return !mcMMO.getMaterialMapStore().isAbilityActivationBlackListed(blockState.getType()); } + public static boolean canActivateAbilities(Block block) { + return !mcMMO.getMaterialMapStore().isAbilityActivationBlackListed(block.getType()); + } + /** - * Check if a given block should allow for the activation of tools - * Activating a tool is step 1 of a 2 step process for super ability activation + * Check if a given block should allow for the activation of tools Activating a tool is step 1 + * of a 2 step process for super ability activation * * @param blockState The {@link BlockState} of the block to check - * @return true if the block should allow ability activation, false - * otherwise + * @return true if the block should allow ability activation, false otherwise */ public static boolean canActivateTools(BlockState blockState) { return !mcMMO.getMaterialMapStore().isToolActivationBlackListed(blockState.getType()) @@ -150,7 +243,27 @@ public final class BlockUtils { * @return true if the block is an ore, false otherwise */ public static boolean isOre(BlockState blockState) { - return MaterialUtils.isOre(blockState.getType()); + return isOre(blockState.getType()); + } + + /** + * Check if a given block is an ore + * + * @param block The {@link Block} to check + * @return true if the block is an ore, false otherwise + */ + public static boolean isOre(Block block) { + return isOre(block.getType()); + } + + /** + * Check if a given material is an ore + * + * @param material The {@link Material} to check + * @return true if the material is an ore, false otherwise + */ + public static boolean isOre(Material material) { + return MaterialUtils.isOre(material); } /** @@ -159,10 +272,15 @@ public final class BlockUtils { * @param blockState The {@link BlockState} of the block to check * @return true if the block can be made mossy, false otherwise */ + @Deprecated(since = "2.2.024") public static boolean canMakeMossy(BlockState blockState) { return mcMMO.getMaterialMapStore().isMossyWhiteListed(blockState.getType()); } + public static boolean canMakeMossy(Block block) { + return mcMMO.getMaterialMapStore().isMossyWhiteListed(block.getType()); + } + /** * Determine if a given block should be affected by Green Terra * @@ -170,41 +288,58 @@ public final class BlockUtils { * @return true if the block should affected by Green Terra, false otherwise */ public static boolean affectedByGreenTerra(BlockState blockState) { - if (ExperienceConfig.getInstance().doesBlockGiveSkillXP(PrimarySkillType.HERBALISM, blockState.getBlockData())) { - return true; - } + return affectedByGreenTerra(blockState.getType()); + } - return mcMMO.getModManager().isCustomHerbalismBlock(blockState); + public static boolean affectedByGreenTerra(Block block) { + return affectedByGreenTerra(block.getType()); + } + + public static boolean affectedByGreenTerra(Material material) { + return ExperienceConfig.getInstance() + .doesBlockGiveSkillXP(PrimarySkillType.HERBALISM, material); + } + + public static boolean affectedBySuperBreaker(BlockState blockState) { + return affectedBySuperBreaker(blockState.getType()); } /** * Determine if a given block should be affected by Super Breaker * - * @param blockState The {@link BlockState} of the block to check - * @return true if the block should affected by Super Breaker, false - * otherwise + * @param block The {@link Block} to check + * @return true if the block should affected by Super Breaker, false otherwise */ - public static boolean affectedBySuperBreaker(BlockState blockState) { - if(mcMMO.getMaterialMapStore().isIntendedToolPickaxe(blockState.getType())) - return true; + public static boolean affectedBySuperBreaker(Block block) { + return affectedBySuperBreaker(block.getType()); + } - if (ExperienceConfig.getInstance().doesBlockGiveSkillXP(PrimarySkillType.MINING, blockState.getBlockData())) + public static boolean affectedBySuperBreaker(Material material) { + if (mcMMO.getMaterialMapStore().isIntendedToolPickaxe(material)) { return true; + } - return mcMMO.getModManager().isCustomMiningBlock(blockState); + return ExperienceConfig.getInstance() + .doesBlockGiveSkillXP(PrimarySkillType.MINING, material); } /** * Determine if a given block should be affected by Giga Drill Breaker * * @param blockState The {@link BlockState} of the block to check - * @return true if the block should affected by Giga Drill Breaker, false - * otherwise + * @return true if the block should be affected by Giga Drill Breaker, false otherwise */ public static boolean affectedByGigaDrillBreaker(@NotNull BlockState blockState) { - if (ExperienceConfig.getInstance().doesBlockGiveSkillXP(PrimarySkillType.EXCAVATION, blockState.getBlockData())) - return true; - return mcMMO.getModManager().isCustomExcavationBlock(blockState); + return affectedByGigaDrillBreaker(blockState.getType()); + } + + public static boolean affectedByGigaDrillBreaker(@NotNull Block block) { + return affectedByGigaDrillBreaker(block.getType()); + } + + public static boolean affectedByGigaDrillBreaker(@NotNull Material material) { + return ExperienceConfig.getInstance() + .doesBlockGiveSkillXP(PrimarySkillType.EXCAVATION, material); } /** @@ -214,7 +349,16 @@ public final class BlockUtils { * @return true if the block is a log, false otherwise */ public static boolean hasWoodcuttingXP(@NotNull BlockState blockState) { - return ExperienceConfig.getInstance().doesBlockGiveSkillXP(PrimarySkillType.WOODCUTTING, blockState.getBlockData()); + return hasWoodcuttingXP(blockState.getType()); + } + + public static boolean hasWoodcuttingXP(@NotNull Block block) { + return hasWoodcuttingXP(block.getType()); + } + + public static boolean hasWoodcuttingXP(@NotNull Material material) { + return ExperienceConfig.getInstance() + .doesBlockGiveSkillXP(PrimarySkillType.WOODCUTTING, material); } /** @@ -224,36 +368,39 @@ public final class BlockUtils { * @return true if the block is a leaf, false otherwise */ public static boolean isNonWoodPartOfTree(@NotNull BlockState blockState) { - return mcMMO.getMaterialMapStore().isTreeFellerDestructible(blockState.getType()); + return isNonWoodPartOfTree(blockState.getType()); + } + + public static boolean isNonWoodPartOfTree(@NotNull Block block) { + return isNonWoodPartOfTree(block.getType()); } 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 * * @param blockState The {@link BlockState} of the block to check - * @return true if the block can be activate Herbalism abilities, false - * otherwise + * @return true if the block can be activate Herbalism abilities, false otherwise */ public static boolean canActivateHerbalism(BlockState blockState) { return mcMMO.getMaterialMapStore().isHerbalismAbilityWhiteListed(blockState.getType()); @@ -263,11 +410,18 @@ public final class BlockUtils { * Determine if a given block should be affected by Block Cracker * * @param blockState The {@link BlockState} of the block to check - * @return true if the block should affected by Block Cracker, false - * otherwise + * @return true if the block should affected by Block Cracker, false otherwise */ public static boolean affectedByBlockCracker(BlockState blockState) { - return mcMMO.getMaterialMapStore().isBlockCrackerWhiteListed(blockState.getType()); + return affectedByBlockCracker(blockState.getType()); + } + + public static boolean affectedByBlockCracker(Block block) { + return affectedByBlockCracker(block.getType()); + } + + public static boolean affectedByBlockCracker(Material material) { + return mcMMO.getMaterialMapStore().isBlockCrackerWhiteListed(material); } /** @@ -331,8 +485,10 @@ public final class BlockUtils { } /** - * Checks to see if a Block is within the world bounds - * Prevent processing blocks from other plugins (or perhaps odd spigot anomalies) from sending blocks that can't exist within the world + * Checks to see if a Block is within the world bounds Prevent processing blocks from other + * plugins (or perhaps odd spigot anomalies) from sending blocks that can't exist within the + * world + * * @param block * @return */ diff --git a/src/main/java/com/gmail/nossr50/util/CancellableRunnable.java b/src/main/java/com/gmail/nossr50/util/CancellableRunnable.java index a47cdcda3..23f9eaeaa 100644 --- a/src/main/java/com/gmail/nossr50/util/CancellableRunnable.java +++ b/src/main/java/com/gmail/nossr50/util/CancellableRunnable.java @@ -1,7 +1,6 @@ package com.gmail.nossr50.util; import com.tcoded.folialib.wrapper.task.WrappedTask; - import java.util.function.Consumer; public abstract class CancellableRunnable implements Consumer { diff --git a/src/main/java/com/gmail/nossr50/util/ChimaeraWing.java b/src/main/java/com/gmail/nossr50/util/ChimaeraWing.java index e6ea0582c..3f9e9b28b 100644 --- a/src/main/java/com/gmail/nossr50/util/ChimaeraWing.java +++ b/src/main/java/com/gmail/nossr50/util/ChimaeraWing.java @@ -9,8 +9,8 @@ import com.gmail.nossr50.util.player.NotificationManager; 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.sounds.SoundManager; -import com.gmail.nossr50.util.sounds.SoundType; +import java.util.ArrayList; +import java.util.List; import org.bukkit.ChatColor; import org.bukkit.Location; import org.bukkit.Material; @@ -21,14 +21,9 @@ import org.bukkit.inventory.ShapelessRecipe; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.util.Vector; -import java.util.ArrayList; -import java.util.List; - public final class ChimaeraWing { - private static McMMOPlayer mcMMOPlayer; - private static Location location; - - private ChimaeraWing() {} + private ChimaeraWing() { + } /** * Check for item usage. @@ -40,114 +35,104 @@ public final class ChimaeraWing { return; } - ItemStack inHand = player.getInventory().getItemInMainHand(); + final ItemStack inHand = player.getInventory().getItemInMainHand(); if (!ItemUtils.isChimaeraWing(inHand)) { return; } if (!Permissions.chimaeraWing(player)) { - NotificationManager.sendPlayerInformation(player, NotificationType.NO_PERMISSION, "mcMMO.NoPermission"); + NotificationManager.sendPlayerInformation(player, NotificationType.NO_PERMISSION, + "mcMMO.NoPermission"); return; } - mcMMOPlayer = UserManager.getPlayer(player); + final McMMOPlayer mmoPlayer = UserManager.getPlayer(player); //Not loaded - if(mcMMOPlayer == null) - return; - - if (mcMMOPlayer.getTeleportCommenceLocation() != null) { + if (mmoPlayer == null) { return; } - int amount = inHand.getAmount(); - - if (amount < mcMMO.p.getGeneralConfig().getChimaeraUseCost()) { - NotificationManager.sendPlayerInformation(player, NotificationType.REQUIREMENTS_NOT_MET, "Item.ChimaeraWing.NotEnough",String.valueOf(mcMMO.p.getGeneralConfig().getChimaeraUseCost() - amount), "Item.ChimaeraWing.Name"); + if (mmoPlayer.getTeleportCommenceLocation() != null) { return; } - long lastTeleport = mcMMOPlayer.getChimeraWingLastUse(); + int amountInHand = inHand.getAmount(); + + if (amountInHand < mcMMO.p.getGeneralConfig().getChimaeraUseCost()) { + NotificationManager.sendPlayerInformation(player, NotificationType.REQUIREMENTS_NOT_MET, + "Item.ChimaeraWing.NotEnough", + String.valueOf(mcMMO.p.getGeneralConfig().getChimaeraUseCost() - amountInHand), + "Item.ChimaeraWing.Name"); + return; + } + + long lastTeleport = mmoPlayer.getChimeraWingLastUse(); int cooldown = mcMMO.p.getGeneralConfig().getChimaeraCooldown(); if (cooldown > 0) { - int timeRemaining = SkillUtils.calculateTimeLeft(lastTeleport * Misc.TIME_CONVERSION_FACTOR, cooldown, player); + int timeRemaining = SkillUtils.calculateTimeLeft( + lastTeleport * Misc.TIME_CONVERSION_FACTOR, cooldown, player); if (timeRemaining > 0) { - NotificationManager.sendPlayerInformation(player, NotificationType.ABILITY_COOLDOWN, "Item.Generic.Wait", String.valueOf(timeRemaining)); + NotificationManager.sendPlayerInformation(player, NotificationType.ABILITY_COOLDOWN, + "Item.Generic.Wait", String.valueOf(timeRemaining)); return; } } - long recentlyHurt = mcMMOPlayer.getRecentlyHurt(); + long recentlyHurt = mmoPlayer.getRecentlyHurt(); int hurtCooldown = mcMMO.p.getGeneralConfig().getChimaeraRecentlyHurtCooldown(); if (hurtCooldown > 0) { - int timeRemaining = SkillUtils.calculateTimeLeft(recentlyHurt * Misc.TIME_CONVERSION_FACTOR, hurtCooldown, player); + int timeRemaining = SkillUtils.calculateTimeLeft( + recentlyHurt * Misc.TIME_CONVERSION_FACTOR, hurtCooldown, player); if (timeRemaining > 0) { - NotificationManager.sendPlayerInformation(player, NotificationType.ITEM_MESSAGE, "Item.Injured.Wait", String.valueOf(timeRemaining)); + NotificationManager.sendPlayerInformation(player, NotificationType.ITEM_MESSAGE, + "Item.Injured.Wait", String.valueOf(timeRemaining)); return; } } - location = player.getLocation(); + final Location playerLocation = player.getLocation(); if (mcMMO.p.getGeneralConfig().getChimaeraPreventUseUnderground()) { - if (location.getY() < player.getWorld().getHighestBlockYAt(location)) { - player.getInventory().setItemInMainHand(new ItemStack(getChimaeraWing(amount - mcMMO.p.getGeneralConfig().getChimaeraUseCost()))); - NotificationManager.sendPlayerInformation(player, NotificationType.REQUIREMENTS_NOT_MET, "Item.ChimaeraWing.Fail"); - player.updateInventory(); + if (playerLocation.getY() < player.getWorld().getHighestBlockYAt(playerLocation)) { + expendChimaeraWing(player, amountInHand, inHand); + NotificationManager.sendPlayerInformation(player, + NotificationType.REQUIREMENTS_NOT_MET, "Item.ChimaeraWing.Fail"); player.setVelocity(new Vector(0, 0.5D, 0)); - CombatUtils.dealDamage(player, Misc.getRandom().nextInt((int) (player.getHealth() - 10))); - mcMMOPlayer.actualizeChimeraWingLastUse(); + final int dmg = Misc.getRandom().nextInt((int) (player.getHealth() - 10)); + CombatUtils.safeDealDamage(player, dmg); + mmoPlayer.actualizeChimeraWingLastUse(); return; } } - mcMMOPlayer.actualizeTeleportCommenceLocation(player); - - long warmup = mcMMO.p.getGeneralConfig().getChimaeraWarmup(); - - if (warmup > 0) { - NotificationManager.sendPlayerInformation(player, NotificationType.ITEM_MESSAGE, "Teleport.Commencing", String.valueOf(warmup)); - mcMMO.p.getFoliaLib().getImpl().runAtEntityLater(player, new ChimaeraWingWarmup(mcMMOPlayer), 20 * warmup); - } - else { - chimaeraExecuteTeleport(); + mmoPlayer.actualizeTeleportCommenceLocation(player); + long teleportDelay = mcMMO.p.getGeneralConfig().getChimaeraWarmup(); + if (teleportDelay > 0) { + NotificationManager.sendPlayerInformation(player, NotificationType.ITEM_MESSAGE, + "Teleport.Commencing", String.valueOf(teleportDelay)); + mcMMO.p.getFoliaLib().getScheduler() + .runAtEntityLater(player, new ChimaeraWingWarmup(mmoPlayer, playerLocation), + 20 * teleportDelay); + } else { + mcMMO.p.getFoliaLib().getScheduler() + .runAtEntityLater(player, new ChimaeraWingWarmup(mmoPlayer, playerLocation), 0); } } - public static void chimaeraExecuteTeleport() { - Player player = mcMMOPlayer.getPlayer(); - - if (mcMMO.p.getGeneralConfig().getChimaeraUseBedSpawn() && player.getBedSpawnLocation() != null) { -// player.teleport(player.getBedSpawnLocation()); - mcMMO.p.getFoliaLib().getImpl().teleportAsync(player, player.getBedSpawnLocation()); + public static void expendChimaeraWing(Player player, int amountInHand, ItemStack inHand) { + int amountAfterUse = amountInHand - mcMMO.p.getGeneralConfig().getChimaeraUseCost(); + if (amountAfterUse >= 1) { + inHand.setAmount(amountAfterUse); + player.getInventory().setItemInMainHand(inHand); + } else { + player.getInventory().removeItem(inHand); } - else { - Location spawnLocation = player.getWorld().getSpawnLocation(); - if (spawnLocation.getBlock().getType() == Material.AIR) { -// player.teleport(spawnLocation); - mcMMO.p.getFoliaLib().getImpl().teleportAsync(player, spawnLocation); - } - else { -// player.teleport(player.getWorld().getHighestBlockAt(spawnLocation).getLocation()); - mcMMO.p.getFoliaLib().getImpl().teleportAsync(player, player.getWorld().getHighestBlockAt(spawnLocation).getLocation()); - } - } - - player.getInventory().setItemInMainHand(new ItemStack(getChimaeraWing(player.getInventory().getItemInMainHand().getAmount() - mcMMO.p.getGeneralConfig().getChimaeraUseCost()))); - player.updateInventory(); - mcMMOPlayer.actualizeChimeraWingLastUse(); - mcMMOPlayer.setTeleportCommenceLocation(null); - - if (mcMMO.p.getGeneralConfig().getChimaeraSoundEnabled()) { - SoundManager.sendSound(player, location, SoundType.CHIMAERA_WING); - } - - NotificationManager.sendPlayerInformation(player, NotificationType.ITEM_MESSAGE, "Item.ChimaeraWing.Pass"); } public static ItemStack getChimaeraWing(int amount) { @@ -170,7 +155,8 @@ public final class ChimaeraWing { Material ingredient = mcMMO.p.getGeneralConfig().getChimaeraItem(); int amount = mcMMO.p.getGeneralConfig().getChimaeraRecipeCost(); - ShapelessRecipe chimeraWing = new ShapelessRecipe(new NamespacedKey(mcMMO.p, "Chimera"), getChimaeraWing(1)); + ShapelessRecipe chimeraWing = new ShapelessRecipe(new NamespacedKey(mcMMO.p, "Chimera"), + getChimaeraWing(1)); chimeraWing.addIngredient(amount, ingredient); return chimeraWing; } diff --git a/src/main/java/com/gmail/nossr50/util/ContainerMetadataUtils.java b/src/main/java/com/gmail/nossr50/util/ContainerMetadataUtils.java new file mode 100644 index 000000000..b36b9e682 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/util/ContainerMetadataUtils.java @@ -0,0 +1,123 @@ +package com.gmail.nossr50.util; + +import static com.gmail.nossr50.util.MetadataService.NSK_CONTAINER_UUID_LEAST_SIG; +import static com.gmail.nossr50.util.MetadataService.NSK_CONTAINER_UUID_MOST_SIG; + +import com.gmail.nossr50.datatypes.player.McMMOPlayer; +import com.gmail.nossr50.util.player.UserManager; +import java.util.UUID; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.OfflinePlayer; +import org.bukkit.block.BlockState; +import org.bukkit.entity.Player; +import org.bukkit.persistence.PersistentDataContainer; +import org.bukkit.persistence.PersistentDataHolder; +import org.bukkit.persistence.PersistentDataType; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class ContainerMetadataUtils { + + public static void changeContainerOwnership(@Nullable BlockState blockState, + @Nullable Player player) { + // no-op when the blockState is null or player is null + if (blockState == null || player == null) { + return; + } + + final McMMOPlayer mmoPlayer = UserManager.getPlayer(player); + + /* + Debug output + */ + printOwnershipGainDebug(blockState, mmoPlayer); + printOwnershipLossDebug(blockState); + setOwner(blockState, player.getUniqueId()); + } + + public static void printOwnershipGainDebug(@NotNull BlockState blockState, + @Nullable McMMOPlayer mmoPlayer) { + if (mmoPlayer != null && mmoPlayer.isDebugMode()) { + mmoPlayer.getPlayer().sendMessage("Container ownership " + + ChatColor.GREEN + "gained " + ChatColor.RESET + + "at location: " + blockState.getLocation()); + } + } + + public static void printOwnershipLossDebug(BlockState blockState) { + OfflinePlayer containerOwner = getContainerOwner(blockState); + + if (containerOwner != null && containerOwner.isOnline()) { + final McMMOPlayer mmoContainerOwner = UserManager.getPlayer(containerOwner.getPlayer()); + + if (mmoContainerOwner != null) { + if (mmoContainerOwner.isDebugMode()) { + mmoContainerOwner.getPlayer().sendMessage("Container ownership " + + ChatColor.RED + "lost " + ChatColor.RESET + + "at location: " + blockState.getLocation()); + } + } + } + } + + public static @Nullable OfflinePlayer getContainerOwner(BlockState container) { + if (container instanceof PersistentDataHolder persistentDataHolder) { + final UUID uuid = getOwner(persistentDataHolder); + + if (uuid != null) { + return Bukkit.getOfflinePlayer(uuid); + } + } + + return null; + } + + + public static boolean isContainerOwned(BlockState blockState) { + return getContainerOwner(blockState) != null; + } + + public static void processContainerOwnership(BlockState blockState, Player player) { + // no-op when the blockState is null or player is null + if (blockState == null || player == null) { + return; + } + + if (getContainerOwner(blockState) != null) { + if (getContainerOwner(blockState).getUniqueId().equals(player.getUniqueId())) { + return; + } + } + + changeContainerOwnership(blockState, player); + } + + public static @Nullable UUID getOwner(@NotNull PersistentDataHolder persistentDataHolder) { + //Get container from entity + final PersistentDataContainer dataContainer = persistentDataHolder.getPersistentDataContainer(); + + //Too lazy to make a custom data type for this stuff + final Long mostSigBits = dataContainer.get(NSK_CONTAINER_UUID_MOST_SIG, + PersistentDataType.LONG); + final Long leastSigBits = dataContainer.get(NSK_CONTAINER_UUID_LEAST_SIG, + PersistentDataType.LONG); + + if (mostSigBits != null && leastSigBits != null) { + return new UUID(mostSigBits, leastSigBits); + } else { + return null; + } + } + + public static void setOwner(@NotNull BlockState blockState, @NotNull UUID uuid) { + PersistentDataContainer dataContainer = ((PersistentDataHolder) blockState).getPersistentDataContainer(); + + dataContainer.set(NSK_CONTAINER_UUID_MOST_SIG, PersistentDataType.LONG, + uuid.getMostSignificantBits()); + dataContainer.set(NSK_CONTAINER_UUID_LEAST_SIG, PersistentDataType.LONG, + uuid.getLeastSignificantBits()); + + blockState.update(); + } +} diff --git a/src/main/java/com/gmail/nossr50/util/EnchantmentMapper.java b/src/main/java/com/gmail/nossr50/util/EnchantmentMapper.java new file mode 100644 index 000000000..474912b1e --- /dev/null +++ b/src/main/java/com/gmail/nossr50/util/EnchantmentMapper.java @@ -0,0 +1,159 @@ +package com.gmail.nossr50.util; + +import com.gmail.nossr50.mcMMO; +import java.util.Locale; +import org.bukkit.NamespacedKey; +import org.bukkit.Registry; +import org.bukkit.enchantments.Enchantment; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class EnchantmentMapper { + private final mcMMO pluginRef; + private final Enchantment efficiency; + private final Enchantment unbreaking; + private final Enchantment infinity; + private final Enchantment featherFalling; + private final Enchantment luckOfTheSea; + + public EnchantmentMapper(mcMMO pluginRef) { + this.pluginRef = pluginRef; + this.efficiency = initEfficiency(); + this.unbreaking = initUnbreaking(); + this.infinity = initInfinity(); + this.featherFalling = initFeatherFalling(); + this.luckOfTheSea = initLuckOfTheSea(); + } + + private static @Nullable Enchantment mockSpigotMatch(@NotNull String input) { + // Replicates match() behaviour for older versions lacking this API + final String filtered = input.toLowerCase(Locale.ROOT).replaceAll("\\s+", "_"); + final NamespacedKey namespacedKey = NamespacedKey.fromString(filtered); + return (namespacedKey != null) ? Registry.ENCHANTMENT.get(namespacedKey) : null; + } + + private Enchantment initLuckOfTheSea() { + if (mockSpigotMatch("luck_of_the_sea") != null) { + return mockSpigotMatch("luck_of_the_sea"); + } + + // Look for the enchantment by name + for (Enchantment enchantment : Registry.ENCHANTMENT) { + if (enchantment.getKey().getKey().equalsIgnoreCase("LUCK_OF_THE_SEA") + || enchantment.getKey().getKey().equalsIgnoreCase("LUCK") + || enchantment.getName().equalsIgnoreCase("LUCK_OF_THE_SEA") + || enchantment.getName().equalsIgnoreCase("LUCK")) { + return enchantment; + } + } + + pluginRef.getLogger().severe("Unable to find the Luck of the Sea enchantment, " + + "mcMMO will not function properly."); + throw new IllegalStateException("Unable to find the Luck of the Sea enchantment"); + } + + private Enchantment initFeatherFalling() { + if (mockSpigotMatch("feather_falling") != null) { + return mockSpigotMatch("feather_falling"); + } + + // Look for the enchantment by name + for (Enchantment enchantment : Registry.ENCHANTMENT) { + if (enchantment.getKey().getKey().equalsIgnoreCase("FEATHER_FALLING") + || enchantment.getKey().getKey().equalsIgnoreCase("PROTECTION_FALL") + || enchantment.getName().equalsIgnoreCase("FEATHER_FALLING") + || enchantment.getName().equalsIgnoreCase("PROTECTION_FALL")) { + return enchantment; + } + } + + pluginRef.getLogger().severe("Unable to find the Feather Falling enchantment, " + + "mcMMO will not function properly."); + throw new IllegalStateException("Unable to find the Feather Falling enchantment"); + } + + private Enchantment initInfinity() { + if (mockSpigotMatch("infinity") != null) { + return mockSpigotMatch("infinity"); + } + + // Look for the enchantment by name + for (Enchantment enchantment : Registry.ENCHANTMENT) { + if (enchantment.getKey().getKey().equalsIgnoreCase("INFINITY") + || enchantment.getKey().getKey().equalsIgnoreCase("ARROW_INFINITE") + || enchantment.getName().equalsIgnoreCase("INFINITY") + || enchantment.getName().equalsIgnoreCase("ARROW_INFINITE")) { + return enchantment; + } + } + + pluginRef.getLogger().severe("Unable to find the Infinity enchantment, " + + "mcMMO will not function properly."); + throw new IllegalStateException("Unable to find the Infinity enchantment"); + } + + private Enchantment initEfficiency() { + if (mockSpigotMatch("efficiency") != null) { + return mockSpigotMatch("efficiency"); + } + + // Look for the enchantment by name + for (Enchantment enchantment : Registry.ENCHANTMENT) { + if (enchantment.getKey().getKey().equalsIgnoreCase("EFFICIENCY") + || enchantment.getKey().getKey().equalsIgnoreCase("DIG_SPEED") + || enchantment.getName().equalsIgnoreCase("EFFICIENCY") + || enchantment.getName().equalsIgnoreCase("DIG_SPEED")) { + return enchantment; + } + } + + pluginRef.getLogger().severe("Unable to find the Efficiency enchantment, " + + "mcMMO will not function properly."); + throw new IllegalStateException("Unable to find the Efficiency enchantment"); + } + + private Enchantment initUnbreaking() { + if (mockSpigotMatch("unbreaking") != null) { + return mockSpigotMatch("unbreaking"); + } + + // Look for the enchantment by name + for (Enchantment enchantment : Registry.ENCHANTMENT) { + if (enchantment.getKey().getKey().equalsIgnoreCase("UNBREAKING") + || enchantment.getKey().getKey().equalsIgnoreCase("DURABILITY") + || enchantment.getName().equalsIgnoreCase("UNBREAKING") + || enchantment.getName().equalsIgnoreCase("DURABILITY")) { + return enchantment; + } + } + + pluginRef.getLogger().severe("Unable to find the Unbreaking enchantment, " + + "mcMMO will not function properly."); + throw new IllegalStateException("Unable to find the Unbreaking enchantment"); + } + + /** + * Get the efficiency enchantment + * + * @return The efficiency enchantment + */ + public Enchantment getEfficiency() { + return efficiency; + } + + public Enchantment getUnbreaking() { + return unbreaking; + } + + public Enchantment getInfinity() { + return infinity; + } + + public Enchantment getFeatherFalling() { + return featherFalling; + } + + public Enchantment getLuckOfTheSea() { + return luckOfTheSea; + } +} diff --git a/src/main/java/com/gmail/nossr50/util/EnchantmentUtils.java b/src/main/java/com/gmail/nossr50/util/EnchantmentUtils.java index 6aab49b3d..17034f6be 100644 --- a/src/main/java/com/gmail/nossr50/util/EnchantmentUtils.java +++ b/src/main/java/com/gmail/nossr50/util/EnchantmentUtils.java @@ -1,53 +1,55 @@ package com.gmail.nossr50.util; -import org.bukkit.enchantments.Enchantment; - import java.util.HashMap; +import org.bukkit.enchantments.Enchantment; +import org.jetbrains.annotations.Nullable; public class EnchantmentUtils { - private static final HashMap enchants = new HashMap<>(); + private static final HashMap legacyEnchantments = new HashMap<>(); static { - enchants.put("SHARPNESS", Enchantment.DAMAGE_ALL); - enchants.put("POWER", Enchantment.ARROW_DAMAGE); - enchants.put("FIRE_PROTECTION", Enchantment.PROTECTION_FIRE); - enchants.put("FEATHER_FALLING", Enchantment.PROTECTION_FALL); - enchants.put("PROTECTION", Enchantment.PROTECTION_ENVIRONMENTAL); - enchants.put("BLAST_PROTECTION", Enchantment.PROTECTION_EXPLOSIONS); - enchants.put("PROJECTILE_PROTECTION", Enchantment.PROTECTION_PROJECTILE); - enchants.put("RESPIRATION", Enchantment.OXYGEN); - enchants.put("INFINITY", Enchantment.ARROW_INFINITE); - enchants.put("AQUA_AFFINITY", Enchantment.WATER_WORKER); - enchants.put("UNBREAKING", Enchantment.DURABILITY); - enchants.put("SMITE", Enchantment.DAMAGE_UNDEAD); - enchants.put("BANE_OF_ARTHROPODS", Enchantment.DAMAGE_ARTHROPODS); - enchants.put("EFFICIENCY", Enchantment.DIG_SPEED); - enchants.put("FIRE_ASPECT", Enchantment.FIRE_ASPECT); - enchants.put("SILK_TOUCH", Enchantment.SILK_TOUCH); - enchants.put("FORTUNE", Enchantment.LOOT_BONUS_BLOCKS); - enchants.put("LOOTING", Enchantment.LOOT_BONUS_MOBS); - enchants.put("PUNCH", Enchantment.ARROW_KNOCKBACK); - enchants.put("FLAME", Enchantment.ARROW_FIRE); - enchants.put("KNOCKBACK", Enchantment.KNOCKBACK); - enchants.put("THORNS", Enchantment.THORNS); - enchants.put("MENDING", Enchantment.MENDING); - enchants.put("DEPTH_STRIDER", Enchantment.DEPTH_STRIDER); - enchants.put("FROST_WALKER", Enchantment.FROST_WALKER); + // backwards compatibility for looking up legacy bukkit enums + addLegacyEnchantmentLookup("SHARPNESS", "DAMAGE_ALL"); + addLegacyEnchantmentLookup("POWER", "ARROW_DAMAGE"); + addLegacyEnchantmentLookup("FIRE_PROTECTION", "PROTECTION_FIRE"); + addLegacyEnchantmentLookup("FEATHER_FALLING", "PROTECTION_FALL"); + addLegacyEnchantmentLookup("PROTECTION", "PROTECTION_ENVIRONMENTAL"); + addLegacyEnchantmentLookup("BLAST_PROTECTION", "PROTECTION_EXPLOSIONS"); + addLegacyEnchantmentLookup("PROJECTILE_PROTECTION", "PROTECTION_PROJECTILE"); + addLegacyEnchantmentLookup("RESPIRATION", "OXYGEN"); + addLegacyEnchantmentLookup("INFINITY", "ARROW_INFINITE"); + addLegacyEnchantmentLookup("AQUA_AFFINITY", "WATER_WORKER"); + addLegacyEnchantmentLookup("UNBREAKING", "DURABILITY"); + addLegacyEnchantmentLookup("SMITE", "DAMAGE_UNDEAD"); + addLegacyEnchantmentLookup("BANE_OF_ARTHROPODS", "DAMAGE_ARTHROPODS"); + addLegacyEnchantmentLookup("EFFICIENCY", "DIG_SPEED"); + addLegacyEnchantmentLookup("FORTUNE", "LOOT_BONUS_BLOCKS"); + addLegacyEnchantmentLookup("LOOTING", "LOOT_BONUS_MOBS"); + addLegacyEnchantmentLookup("PUNCH", "ARROW_KNOCKBACK"); + addLegacyEnchantmentLookup("FLAME", "ARROW_FIRE"); } /** * Method to get an {@link Enchantment} using it's Vanilla Minecraft name or Bukkit enum name * * @param enchantmentName Vanilla or Bukkit name of enchantment - * * @return Enchantment or null if no enchantment was found */ - public static Enchantment getByName(String enchantmentName) { - if (enchants.containsKey(enchantmentName)) { - return enchants.get(enchantmentName); + @SuppressWarnings("deprecation") + public static @Nullable Enchantment getByName(String enchantmentName) { + if (legacyEnchantments.containsKey(enchantmentName)) { + return legacyEnchantments.get(enchantmentName); } return Enchantment.getByName(enchantmentName); } + + @SuppressWarnings("deprecation") + private static void addLegacyEnchantmentLookup(String enchantmentName, + String legacyBukkitName) { + if (Enchantment.getByName(legacyBukkitName) != null) { + legacyEnchantments.put(enchantmentName, Enchantment.getByName(legacyBukkitName)); + } + } } diff --git a/src/main/java/com/gmail/nossr50/util/EventUtils.java b/src/main/java/com/gmail/nossr50/util/EventUtils.java index 68179e24b..7cff9b931 100644 --- a/src/main/java/com/gmail/nossr50/util/EventUtils.java +++ b/src/main/java/com/gmail/nossr50/util/EventUtils.java @@ -1,5 +1,7 @@ package com.gmail.nossr50.util; +import static java.util.Objects.requireNonNull; + import com.gmail.nossr50.api.FakeBlockBreakEventType; import com.gmail.nossr50.api.TreeFellerBlockBreakEvent; import com.gmail.nossr50.datatypes.experience.XPGainReason; @@ -10,7 +12,6 @@ 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.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; @@ -41,6 +42,8 @@ import com.gmail.nossr50.util.player.NotificationManager; import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.skills.CombatUtils; import com.gmail.nossr50.util.skills.SkillTools; +import java.util.HashMap; +import java.util.Map; import org.bukkit.block.Block; import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.Entity; @@ -56,19 +59,24 @@ import org.bukkit.plugin.Plugin; import org.bukkit.plugin.PluginManager; import org.jetbrains.annotations.NotNull; -import java.util.HashMap; -import java.util.Map; - /** * This class is meant to help make event related code less boilerplate */ public final class EventUtils { /** - * This is a static utility class, therefore we don't want any instances of - * this class. Making the constructor private prevents accidents like that. + * True when the current thread is already executing simulateBlockBreak(). + * Thread-local so parallel Folia regions / async tasks are isolated. */ - private EventUtils() {} + private static final ThreadLocal IN_FAKE_BREAK = + ThreadLocal.withInitial(() -> false); + + /** + * This is a static utility class, therefore we don't want any instances of this class. Making + * the constructor private prevents accidents like that. + */ + private EventUtils() { + } /* * Quality of Life methods @@ -76,11 +84,12 @@ public final class EventUtils { /** * This is a simple check to see if an {@link Event} is fake or not. - * {@link FakeEvent FakeEvents} should not be processed like normally and maybe even - * be ignored by other {@link Plugin plugins} completely. - * + * {@link FakeEvent FakeEvents} should not be processed like normally and maybe even be ignored + * by other {@link Plugin plugins} completely. + * * @param event The {@link Event} in question - * @return Whether this {@link Event} has been faked by mcMMO and should not be processed normally. + * @return Whether this {@link Event} has been faked by mcMMO and should not be processed + * normally. */ public static boolean isFakeEvent(@NotNull Event event) { return event instanceof FakeEvent; @@ -88,30 +97,26 @@ public final class EventUtils { /** * This little method is just to make the code more readable - * + * * @param entity target entity * @return the associated McMMOPlayer for this entity */ - public static McMMOPlayer getMcMMOPlayer(@NotNull Entity entity) - { - return UserManager.getPlayer((Player)entity); + public static McMMOPlayer getMcMMOPlayer(@NotNull Entity entity) { + return UserManager.getPlayer((Player) entity); } /** * Checks to see if a Player was damaged in this EntityDamageEvent - * + *

* This method checks for the following things and if they are all true it returns true - * - * 1) The player is real and not an NPC - * 2) The player is not in god mode - * 3) The damage dealt is above 0 - * 4) The player is loaded into our mcMMO user profiles + *

+ * 1) The player is real and not an NPC 2) The player is not in god mode 3) The damage dealt is + * above 0 4) The player is loaded into our mcMMO user profiles * * @param entityDamageEvent * @return */ - public static boolean isRealPlayerDamaged(@NotNull EntityDamageEvent entityDamageEvent) - { + public static boolean isRealPlayerDamaged(@NotNull EntityDamageEvent entityDamageEvent) { //Make sure the damage is above 0 double damage = entityDamageEvent.getFinalDamage(); @@ -122,8 +127,9 @@ public final class EventUtils { Entity entity = entityDamageEvent.getEntity(); //Check to make sure the entity is not an NPC - if(Misc.isNPCEntityExcludingVillagers(entity)) + if (Misc.isNPCEntityExcludingVillagers(entity)) { return false; + } if (!entity.isValid() || !(entity instanceof LivingEntity livingEntity)) { return false; @@ -134,21 +140,20 @@ public final class EventUtils { } if (livingEntity instanceof Player) { - Player player = (Player) entity; + final Player player = (Player) entity; if (!UserManager.hasPlayerDataKey(player)) { return true; } - McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player); + final McMMOPlayer mmoPlayer = UserManager.getPlayer(player); - if(mcMMOPlayer == null) - { + if (mmoPlayer == null) { return true; } /* Check for invincibility */ - if (mcMMOPlayer.getGodMode()) { + if (mmoPlayer.getGodMode()) { entityDamageEvent.setCancelled(true); return false; } @@ -163,14 +168,27 @@ public final class EventUtils { * Others */ - public static @NotNull McMMOPlayerAbilityActivateEvent callPlayerAbilityActivateEvent(@NotNull Player player, @NotNull PrimarySkillType skill) { - McMMOPlayerAbilityActivateEvent event = new McMMOPlayerAbilityActivateEvent(player, skill); + @Deprecated(forRemoval = true, since = "2.2.010") + public static @NotNull McMMOPlayerAbilityActivateEvent callPlayerAbilityActivateEvent( + @NotNull Player player, + @NotNull PrimarySkillType skill) { + return callPlayerAbilityActivateEvent(requireNonNull(UserManager.getPlayer(player)), skill); + } + + public static @NotNull McMMOPlayerAbilityActivateEvent callPlayerAbilityActivateEvent( + @NotNull McMMOPlayer mmoPlayer, + @NotNull PrimarySkillType skill) { + requireNonNull(mmoPlayer, "mmoPlayer cannot be null"); + requireNonNull(skill, "skill cannot be null"); + McMMOPlayerAbilityActivateEvent event = new McMMOPlayerAbilityActivateEvent(mmoPlayer, + skill); mcMMO.p.getServer().getPluginManager().callEvent(event); return event; } - public static @NotNull McMMOPlayerProfileLoadEvent callPlayerProfileLoadEvent(@NotNull Player player, @NotNull PlayerProfile profile){ + public static @NotNull McMMOPlayerProfileLoadEvent callPlayerProfileLoadEvent( + @NotNull Player player, @NotNull PlayerProfile profile) { McMMOPlayerProfileLoadEvent event = new McMMOPlayerProfileLoadEvent(player, profile); mcMMO.p.getServer().getPluginManager().callEvent(event); @@ -179,13 +197,29 @@ public final class EventUtils { /** * Calls a new SubSkillEvent for this SubSkill and then returns it + * * @param player target player * @param subSkillType target subskill * @return the event after it has been fired */ - @Deprecated - public static @NotNull SubSkillEvent callSubSkillEvent(Player player, SubSkillType subSkillType) { - SubSkillEvent event = new SubSkillEvent(player, subSkillType); + @Deprecated(forRemoval = true, since = "2.2.010") + public static @NotNull SubSkillEvent callSubSkillEvent(@NotNull Player player, + @NotNull SubSkillType subSkillType) { + return callSubSkillEvent(requireNonNull(UserManager.getPlayer(player)), subSkillType); + } + + /** + * Calls a new SubSkillEvent for this SubSkill and then returns it + * + * @param mmoPlayer target mmoPlayer + * @param subSkillType target subskill + * @return the event after it has been fired + */ + public static @NotNull SubSkillEvent callSubSkillEvent(@NotNull McMMOPlayer mmoPlayer, + @NotNull SubSkillType subSkillType) { + requireNonNull(mmoPlayer, "mmoPlayer cannot be null"); + requireNonNull(subSkillType, "subSkillType cannot be null"); + final SubSkillEvent event = new SubSkillEvent(mmoPlayer, subSkillType); mcMMO.p.getServer().getPluginManager().callEvent(event); return event; @@ -193,41 +227,25 @@ public final class EventUtils { /** * Calls a new SubSkillBlockEvent for this SubSkill and its related block and then returns it + * * @param player target player * @param subSkillType target subskill * @param block associated block * @return the event after it has been fired */ - @Deprecated - public static @NotNull SubSkillBlockEvent callSubSkillBlockEvent(@NotNull Player player, @NotNull SubSkillType subSkillType, @NotNull Block block) { + public static @NotNull SubSkillBlockEvent callSubSkillBlockEvent(@NotNull Player player, + @NotNull SubSkillType subSkillType, @NotNull Block block) { SubSkillBlockEvent event = new SubSkillBlockEvent(player, subSkillType, block); mcMMO.p.getServer().getPluginManager().callEvent(event); 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 Event callFakeArmSwingEvent(@NotNull Player player) { -// PlayerAnimationEvent event = new FakePlayerAnimationEvent(player, PlayerAnimationType.ARM_SWING); -// mcMMO.p.getServer().getPluginManager().callEvent(event); -// -// return event; -// } - - public static boolean tryLevelChangeEvent(Player player, PrimarySkillType skill, int levelsChanged, float xpRemoved, boolean isLevelUp, XPGainReason xpGainReason) { - McMMOPlayerLevelChangeEvent event = isLevelUp ? new McMMOPlayerLevelUpEvent(player, skill, levelsChanged, xpGainReason) : new McMMOPlayerLevelDownEvent(player, skill, levelsChanged, xpGainReason); + public static boolean tryLevelChangeEvent(Player player, PrimarySkillType skill, + int levelsChanged, float xpRemoved, boolean isLevelUp, XPGainReason xpGainReason) { + McMMOPlayerLevelChangeEvent event = + isLevelUp ? new McMMOPlayerLevelUpEvent(player, skill, levelsChanged, xpGainReason) + : new McMMOPlayerLevelDownEvent(player, skill, levelsChanged, xpGainReason); mcMMO.p.getServer().getPluginManager().callEvent(event); boolean isCancelled = event.isCancelled(); @@ -235,34 +253,49 @@ public final class EventUtils { if (isCancelled) { PlayerProfile profile = UserManager.getPlayer(player).getProfile(); - profile.modifySkill(skill, profile.getSkillLevel(skill) - (isLevelUp ? levelsChanged : -levelsChanged)); + profile.modifySkill(skill, + profile.getSkillLevel(skill) - (isLevelUp ? levelsChanged : -levelsChanged)); profile.addXp(skill, xpRemoved); } return isCancelled; } - public static boolean tryLevelChangeEvent(@NotNull McMMOPlayer mmoPlayer, PrimarySkillType skill, int levelsChanged, float xpRemoved, boolean isLevelUp, XPGainReason xpGainReason) { - McMMOPlayerLevelChangeEvent event = isLevelUp ? new McMMOPlayerLevelUpEvent(mmoPlayer.getPlayer(), skill, levelsChanged, xpGainReason) : new McMMOPlayerLevelDownEvent(mmoPlayer.getPlayer(), skill, levelsChanged, xpGainReason); + public static boolean tryLevelChangeEvent(@NotNull McMMOPlayer mmoPlayer, + PrimarySkillType skill, int levelsChanged, float xpRemoved, boolean isLevelUp, + XPGainReason xpGainReason) { + McMMOPlayerLevelChangeEvent event = + isLevelUp ? new McMMOPlayerLevelUpEvent(mmoPlayer.getPlayer(), skill, levelsChanged, + xpGainReason) + : new McMMOPlayerLevelDownEvent(mmoPlayer.getPlayer(), skill, levelsChanged, + xpGainReason); mcMMO.p.getServer().getPluginManager().callEvent(event); boolean isCancelled = event.isCancelled(); if (isCancelled) { - mmoPlayer.modifySkill(skill, mmoPlayer.getSkillLevel(skill) - (isLevelUp ? levelsChanged : -levelsChanged)); + mmoPlayer.modifySkill(skill, + mmoPlayer.getSkillLevel(skill) - (isLevelUp ? levelsChanged : -levelsChanged)); mmoPlayer.addXp(skill, xpRemoved); } else { if (isLevelUp) { - NotificationManager.processLevelUpBroadcasting(mmoPlayer, skill, mmoPlayer.getSkillLevel(skill)); - NotificationManager.processPowerLevelUpBroadcasting(mmoPlayer, mmoPlayer.getPowerLevel()); + NotificationManager.processLevelUpBroadcasting(mmoPlayer, skill, + mmoPlayer.getSkillLevel(skill)); + NotificationManager.processPowerLevelUpBroadcasting(mmoPlayer, + mmoPlayer.getPowerLevel()); } } return isCancelled; } - public static boolean tryLevelEditEvent(Player player, PrimarySkillType skill, int levelsChanged, float xpRemoved, boolean isLevelUp, XPGainReason xpGainReason, int oldLevel) { - McMMOPlayerLevelChangeEvent event = isLevelUp ? new McMMOPlayerLevelUpEvent(player, skill, levelsChanged - oldLevel, xpGainReason) : new McMMOPlayerLevelDownEvent(player, skill, levelsChanged, xpGainReason); + public static boolean tryLevelEditEvent(Player player, PrimarySkillType skill, + int levelsChanged, float xpRemoved, boolean isLevelUp, XPGainReason xpGainReason, + int oldLevel) { + McMMOPlayerLevelChangeEvent event = + isLevelUp ? new McMMOPlayerLevelUpEvent(player, skill, levelsChanged - oldLevel, + xpGainReason) + : new McMMOPlayerLevelDownEvent(player, skill, levelsChanged, xpGainReason); mcMMO.p.getServer().getPluginManager().callEvent(event); boolean isCancelled = event.isCancelled(); @@ -270,26 +303,36 @@ public final class EventUtils { if (isCancelled) { PlayerProfile profile = UserManager.getPlayer(player).getProfile(); - profile.modifySkill(skill, profile.getSkillLevel(skill) - (isLevelUp ? levelsChanged : -levelsChanged)); + profile.modifySkill(skill, + profile.getSkillLevel(skill) - (isLevelUp ? levelsChanged : -levelsChanged)); profile.addXp(skill, xpRemoved); } return isCancelled; } - public static boolean tryLevelEditEvent(@NotNull McMMOPlayer mmoPlayer, PrimarySkillType skill, int levelsChanged, float xpRemoved, boolean isLevelUp, XPGainReason xpGainReason, int oldLevel) { - McMMOPlayerLevelChangeEvent event = isLevelUp ? new McMMOPlayerLevelUpEvent(mmoPlayer.getPlayer(), skill, levelsChanged - oldLevel, xpGainReason) : new McMMOPlayerLevelDownEvent(mmoPlayer.getPlayer(), skill, levelsChanged, xpGainReason); + public static boolean tryLevelEditEvent(@NotNull McMMOPlayer mmoPlayer, PrimarySkillType skill, + int levelsChanged, float xpRemoved, boolean isLevelUp, XPGainReason xpGainReason, + int oldLevel) { + McMMOPlayerLevelChangeEvent event = + isLevelUp ? new McMMOPlayerLevelUpEvent(mmoPlayer.getPlayer(), skill, + levelsChanged - oldLevel, xpGainReason) + : new McMMOPlayerLevelDownEvent(mmoPlayer.getPlayer(), skill, levelsChanged, + xpGainReason); mcMMO.p.getServer().getPluginManager().callEvent(event); boolean isCancelled = event.isCancelled(); if (isCancelled) { - mmoPlayer.modifySkill(skill, mmoPlayer.getSkillLevel(skill) - (isLevelUp ? levelsChanged : -levelsChanged)); + mmoPlayer.modifySkill(skill, + mmoPlayer.getSkillLevel(skill) - (isLevelUp ? levelsChanged : -levelsChanged)); mmoPlayer.addXp(skill, xpRemoved); } else { if (isLevelUp) { - NotificationManager.processLevelUpBroadcasting(mmoPlayer, skill, mmoPlayer.getSkillLevel(skill)); - NotificationManager.processPowerLevelUpBroadcasting(mmoPlayer, mmoPlayer.getPowerLevel()); + NotificationManager.processLevelUpBroadcasting(mmoPlayer, skill, + mmoPlayer.getSkillLevel(skill)); + NotificationManager.processPowerLevelUpBroadcasting(mmoPlayer, + mmoPlayer.getPowerLevel()); } } @@ -299,11 +342,11 @@ public final class EventUtils { /** * Simulate a block break event. * - * @param block The block to break - * @param player The player breaking the block + * @param block The block to break + * @param player The player breaking the block * @param shouldArmSwing ignored (here for API compatibility) - * @return true if the event wasn't cancelled, false otherwise - * {@code @Deprecated} use {@link #simulateBlockBreak(Block, Player, FakeBlockBreakEventType)} instead + * @return true if the event wasn't cancelled, false otherwise {@code @Deprecated} use + * {@link #simulateBlockBreak(Block, Player, FakeBlockBreakEventType)} instead */ public static boolean simulateBlockBreak(Block block, Player player, boolean shouldArmSwing) { return simulateBlockBreak(block, player); @@ -314,8 +357,8 @@ public final class EventUtils { * * @param block The block to break * @param player The player breaking the block - * @return true if the event wasn't cancelled, false otherwise - * {@code @Deprecated} use {@link #simulateBlockBreak(Block, Player, FakeBlockBreakEventType)} instead + * @return true if the event wasn't cancelled, false otherwise {@code @Deprecated} use + * {@link #simulateBlockBreak(Block, Player, FakeBlockBreakEventType)} instead */ public static boolean simulateBlockBreak(Block block, Player player) { return simulateBlockBreak(block, player, FakeBlockBreakEventType.FAKE); @@ -324,34 +367,47 @@ public final class EventUtils { /** * Simulate a block break event. * - * @param block The block to break + * @param block The block to break * @param player The player breaking the block * @param eventType The type of event to signal to other plugins * @return true if the event wasn't cancelled, false otherwise */ - public static boolean simulateBlockBreak(Block block, Player player, FakeBlockBreakEventType eventType) { - PluginManager pluginManager = mcMMO.p.getServer().getPluginManager(); - - FakeBlockDamageEvent damageEvent = new FakeBlockDamageEvent(player, block, player.getInventory().getItemInMainHand(), true); - pluginManager.callEvent(damageEvent); - - BlockBreakEvent fakeBlockBreakEvent = null; - - switch (eventType) { - case FAKE -> fakeBlockBreakEvent = new FakeBlockBreakEvent(block, player); - case TREE_FELLER -> fakeBlockBreakEvent = new TreeFellerBlockBreakEvent(block, player); + public static boolean simulateBlockBreak(Block block, Player player, + FakeBlockBreakEventType eventType) { + if (IN_FAKE_BREAK.get()) { + return true; + } + IN_FAKE_BREAK.set(true); + + try { + final PluginManager pluginManager = mcMMO.p.getServer().getPluginManager(); + + final FakeBlockDamageEvent damageEvent = new FakeBlockDamageEvent(player, block, + player.getInventory().getItemInMainHand(), true); + pluginManager.callEvent(damageEvent); + + final BlockBreakEvent fakeBlockBreakEvent = switch (eventType) { + case FAKE -> new FakeBlockBreakEvent(block, player); + case TREE_FELLER -> new TreeFellerBlockBreakEvent(block, player); + }; + + pluginManager.callEvent(fakeBlockBreakEvent); + return !damageEvent.isCancelled() && !fakeBlockBreakEvent.isCancelled(); + } finally { + // always clear the flag + IN_FAKE_BREAK.set(false); } - pluginManager.callEvent(fakeBlockBreakEvent); - return !damageEvent.isCancelled() && !fakeBlockBreakEvent.isCancelled(); } public static void handlePartyTeleportEvent(Player teleportingPlayer, Player targetPlayer) { - McMMOPlayer mcMMOPlayer = UserManager.getPlayer(teleportingPlayer); + final McMMOPlayer mmoPlayer = UserManager.getPlayer(teleportingPlayer); - if(mcMMOPlayer == null) + if (mmoPlayer == null) { return; + } - McMMOPartyTeleportEvent event = new McMMOPartyTeleportEvent(teleportingPlayer, targetPlayer, mcMMOPlayer.getParty().getName()); + McMMOPartyTeleportEvent event = new McMMOPartyTeleportEvent(teleportingPlayer, targetPlayer, + mmoPlayer.getParty().getName()); mcMMO.p.getServer().getPluginManager().callEvent(event); if (event.isCancelled()) { @@ -359,12 +415,15 @@ public final class EventUtils { } // teleportingPlayer.teleport(targetPlayer); - mcMMO.p.getFoliaLib().getImpl().teleportAsync(teleportingPlayer, targetPlayer.getLocation()); + mcMMO.p.getFoliaLib().getScheduler() + .teleportAsync(teleportingPlayer, targetPlayer.getLocation()); - teleportingPlayer.sendMessage(LocaleLoader.getString("Party.Teleport.Player", targetPlayer.getName())); - targetPlayer.sendMessage(LocaleLoader.getString("Party.Teleport.Target", teleportingPlayer.getName())); + teleportingPlayer.sendMessage( + LocaleLoader.getString("Party.Teleport.Player", targetPlayer.getName())); + targetPlayer.sendMessage( + LocaleLoader.getString("Party.Teleport.Target", teleportingPlayer.getName())); - mcMMOPlayer.getPartyTeleportRecord().actualizeLastUse(); + mmoPlayer.getPartyTeleportRecord().actualizeLastUse(); } public static boolean handlePartyXpGainEvent(Party party, float xpGained) { @@ -380,7 +439,8 @@ public final class EventUtils { return !isCancelled; } - public static boolean handlePartyLevelChangeEvent(Party party, int levelsChanged, float xpRemoved) { + public static boolean handlePartyLevelChangeEvent(Party party, int levelsChanged, + float xpRemoved) { McMMOPartyLevelUpEvent event = new McMMOPartyLevelUpEvent(party, levelsChanged); mcMMO.p.getServer().getPluginManager().callEvent(event); @@ -394,12 +454,15 @@ public final class EventUtils { return !isCancelled; } - public static boolean handleXpGainEvent(Player player, PrimarySkillType skill, float xpGained, XPGainReason xpGainReason) { - McMMOPlayer mmoPlayer = UserManager.getPlayer(player); - if(mmoPlayer == null) + public static boolean handleXpGainEvent(Player player, PrimarySkillType skill, float xpGained, + XPGainReason xpGainReason) { + final McMMOPlayer mmoPlayer = UserManager.getPlayer(player); + if (mmoPlayer == null) { return true; - - McMMOPlayerXpGainEvent event = new McMMOPlayerXpGainEvent(player, skill, xpGained, xpGainReason); + } + + McMMOPlayerXpGainEvent event = new McMMOPlayerXpGainEvent(player, skill, xpGained, + xpGainReason); mcMMO.p.getServer().getPluginManager().callEvent(event); boolean isCancelled = event.isCancelled(); @@ -412,11 +475,14 @@ public final class EventUtils { return !isCancelled; } - public static boolean handleStatsLossEvent(Player player, HashMap levelChanged, HashMap experienceChanged) { - if(UserManager.getPlayer(player) == null) + public static boolean handleStatsLossEvent(Player player, HashMap levelChanged, + HashMap experienceChanged) { + if (UserManager.getPlayer(player) == null) { return true; + } - McMMOPlayerStatLossEvent event = new McMMOPlayerStatLossEvent(player, levelChanged, experienceChanged); + McMMOPlayerStatLossEvent event = new McMMOPlayerStatLossEvent(player, levelChanged, + experienceChanged); mcMMO.p.getServer().getPluginManager().callEvent(event); boolean isCancelled = event.isCancelled(); @@ -429,9 +495,11 @@ public final class EventUtils { for (PrimarySkillType primarySkillType : SkillTools.NON_CHILD_SKILLS) { String skillName = primarySkillType.toString(); int playerSkillLevel = playerProfile.getSkillLevel(primarySkillType); - int threshold = mcMMO.p.getGeneralConfig().getHardcoreDeathStatPenaltyLevelThreshold(); - if(playerSkillLevel > threshold) { - playerProfile.modifySkill(primarySkillType, Math.max(threshold, playerSkillLevel - levelChanged.get(skillName))); + int threshold = mcMMO.p.getGeneralConfig() + .getHardcoreDeathStatPenaltyLevelThreshold(); + if (playerSkillLevel > threshold) { + playerProfile.modifySkill(primarySkillType, + Math.max(threshold, playerSkillLevel - levelChanged.get(skillName))); playerProfile.removeXp(primarySkillType, experienceChanged.get(skillName)); if (playerProfile.getSkillXpLevel(primarySkillType) < 0) { @@ -448,9 +516,12 @@ public final class EventUtils { return !isCancelled; } - public static boolean handleVampirismEvent(Player killer, Player victim, HashMap levelChanged, HashMap experienceChanged) { - McMMOPlayerVampirismEvent eventKiller = new McMMOPlayerVampirismEvent(killer, false, levelChanged, experienceChanged); - McMMOPlayerVampirismEvent eventVictim = new McMMOPlayerVampirismEvent(victim, true, levelChanged, experienceChanged); + public static boolean handleVampirismEvent(Player killer, Player victim, + HashMap levelChanged, HashMap experienceChanged) { + McMMOPlayerVampirismEvent eventKiller = new McMMOPlayerVampirismEvent(killer, false, + levelChanged, experienceChanged); + McMMOPlayerVampirismEvent eventVictim = new McMMOPlayerVampirismEvent(victim, true, + levelChanged, experienceChanged); mcMMO.p.getServer().getPluginManager().callEvent(eventKiller); mcMMO.p.getServer().getPluginManager().callEvent(eventVictim); @@ -466,12 +537,14 @@ public final class EventUtils { McMMOPlayer killerPlayer = UserManager.getPlayer(killer); //Not loaded - if(killerPlayer == null) + if (killerPlayer == null) { return true; + } //Not loaded - if(UserManager.getPlayer(victim) == null) + if (UserManager.getPlayer(victim) == null) { return true; + } PlayerProfile victimProfile = UserManager.getPlayer(victim).getProfile(); @@ -480,9 +553,12 @@ public final class EventUtils { int victimSkillLevel = victimProfile.getSkillLevel(primarySkillType); killerPlayer.addLevels(primarySkillType, levelChangedKiller.get(skillName)); - killerPlayer.beginUnsharedXpGain(primarySkillType, experienceChangedKiller.get(skillName), XPGainReason.VAMPIRISM, XPGainSource.VAMPIRISM); + killerPlayer.beginUnsharedXpGain(primarySkillType, + experienceChangedKiller.get(skillName), XPGainReason.VAMPIRISM, + XPGainSource.VAMPIRISM); - victimProfile.modifySkill(primarySkillType, victimSkillLevel - levelChangedVictim.get(skillName)); + victimProfile.modifySkill(primarySkillType, + victimSkillLevel - levelChangedVictim.get(skillName)); victimProfile.removeXp(primarySkillType, experienceChangedVictim.get(skillName)); if (victimProfile.getSkillXpLevel(primarySkillType) < 0) { @@ -498,29 +574,52 @@ public final class EventUtils { return !isCancelled; } - public static McMMOPlayerAbilityDeactivateEvent callAbilityDeactivateEvent(Player player, SuperAbilityType ability) { - McMMOPlayerAbilityDeactivateEvent event = new McMMOPlayerAbilityDeactivateEvent(player, mcMMO.p.getSkillTools().getPrimarySkillBySuperAbility(ability)); + @Deprecated(forRemoval = true, since = "2.2.010") + public static McMMOPlayerAbilityDeactivateEvent callAbilityDeactivateEvent(Player player, + SuperAbilityType ability) { + return callAbilityDeactivateEvent(requireNonNull(UserManager.getPlayer(player)), ability); + } + + public static McMMOPlayerAbilityDeactivateEvent callAbilityDeactivateEvent( + @NotNull McMMOPlayer mmoPlayer, @NotNull SuperAbilityType ability) { + final McMMOPlayerAbilityDeactivateEvent event = new McMMOPlayerAbilityDeactivateEvent( + mmoPlayer, mcMMO.p.getSkillTools().getPrimarySkillBySuperAbility(ability)); mcMMO.p.getServer().getPluginManager().callEvent(event); return event; } - public static McMMOPlayerFishingTreasureEvent callFishingTreasureEvent(Player player, ItemStack treasureDrop, int treasureXp, Map enchants) { - McMMOPlayerFishingTreasureEvent event = enchants.isEmpty() ? new McMMOPlayerFishingTreasureEvent(player, treasureDrop, treasureXp) : new McMMOPlayerMagicHunterEvent(player, treasureDrop, treasureXp, enchants); + @Deprecated(forRemoval = true, since = "2.2.010") + public static McMMOPlayerFishingTreasureEvent callFishingTreasureEvent(Player player, + ItemStack treasureDrop, int treasureXp, Map enchants) { + return callFishingTreasureEvent(requireNonNull(UserManager.getPlayer(player)), treasureDrop, + treasureXp, enchants); + } + + public static McMMOPlayerFishingTreasureEvent callFishingTreasureEvent(McMMOPlayer mmoPlayer, + ItemStack treasureDrop, int treasureXp, Map enchants) { + final McMMOPlayerFishingTreasureEvent event = + enchants.isEmpty() ? new McMMOPlayerFishingTreasureEvent(mmoPlayer, treasureDrop, + treasureXp) + : new McMMOPlayerMagicHunterEvent(mmoPlayer, treasureDrop, treasureXp, + enchants); mcMMO.p.getServer().getPluginManager().callEvent(event); return event; } public static FakePlayerFishEvent callFakeFishEvent(Player player, FishHook hook) { - FakePlayerFishEvent event = new FakePlayerFishEvent(player, null, hook, PlayerFishEvent.State.FISHING); + FakePlayerFishEvent event = new FakePlayerFishEvent(player, null, hook, + PlayerFishEvent.State.FISHING); mcMMO.p.getServer().getPluginManager().callEvent(event); return event; } - public static McMMOPlayerRepairCheckEvent callRepairCheckEvent(Player player, short durability, ItemStack repairMaterial, ItemStack repairedObject) { - McMMOPlayerRepairCheckEvent event = new McMMOPlayerRepairCheckEvent(player, durability, repairMaterial, repairedObject); + public static McMMOPlayerRepairCheckEvent callRepairCheckEvent(Player player, short durability, + ItemStack repairMaterial, ItemStack repairedObject) { + McMMOPlayerRepairCheckEvent event = new McMMOPlayerRepairCheckEvent(player, durability, + repairMaterial, repairedObject); mcMMO.p.getServer().getPluginManager().callEvent(event); return event; @@ -540,8 +639,10 @@ public final class EventUtils { return event; } - public static McMMOPlayerSalvageCheckEvent callSalvageCheckEvent(Player player, ItemStack salvageMaterial, ItemStack salvageResults, ItemStack enchantedBook) { - McMMOPlayerSalvageCheckEvent event = new McMMOPlayerSalvageCheckEvent(player, salvageMaterial, salvageResults, enchantedBook); + public static McMMOPlayerSalvageCheckEvent callSalvageCheckEvent(Player player, + ItemStack salvageMaterial, ItemStack salvageResults, ItemStack enchantedBook) { + McMMOPlayerSalvageCheckEvent event = new McMMOPlayerSalvageCheckEvent(player, + salvageMaterial, salvageResults, enchantedBook); mcMMO.p.getServer().getPluginManager().callEvent(event); return event; diff --git a/src/main/java/com/gmail/nossr50/util/FixSpellingNetheriteUtil.java b/src/main/java/com/gmail/nossr50/util/FixSpellingNetheriteUtil.java index a9e6b4bea..e500d2853 100644 --- a/src/main/java/com/gmail/nossr50/util/FixSpellingNetheriteUtil.java +++ b/src/main/java/com/gmail/nossr50/util/FixSpellingNetheriteUtil.java @@ -2,8 +2,11 @@ package com.gmail.nossr50.util; import com.gmail.nossr50.datatypes.database.UpgradeType; import com.gmail.nossr50.mcMMO; - -import java.io.*; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; public class FixSpellingNetheriteUtil { @@ -11,7 +14,7 @@ public class FixSpellingNetheriteUtil { LogUtils.debug(mcMMO.p.getLogger(), "Checking " + fileName + " config material names..."); File configFile = new File(pluginRef.getDataFolder(), fileName); - if(configFile.exists()) { + if (configFile.exists()) { BufferedReader bufferedReader = null; FileWriter fileWriter = null; try { @@ -35,14 +38,14 @@ public class FixSpellingNetheriteUtil { } catch (IOException e) { e.printStackTrace(); } finally { - if(bufferedReader != null) { + if (bufferedReader != null) { try { bufferedReader.close(); } catch (IOException e) { e.printStackTrace(); } - if(fileWriter != null) { + if (fileWriter != null) { try { fileWriter.close(); } catch (IOException e) { @@ -53,7 +56,8 @@ public class FixSpellingNetheriteUtil { } } - pluginRef.getLogger().info("Finished checking "+fileName+" for certain misspelled material names."); + pluginRef.getLogger() + .info("Finished checking " + fileName + " for certain misspelled material names."); mcMMO.getUpgradeManager().setUpgradeCompleted(upgradeType); } diff --git a/src/main/java/com/gmail/nossr50/util/HardcoreManager.java b/src/main/java/com/gmail/nossr50/util/HardcoreManager.java index 491074a5e..dd50a6c67 100644 --- a/src/main/java/com/gmail/nossr50/util/HardcoreManager.java +++ b/src/main/java/com/gmail/nossr50/util/HardcoreManager.java @@ -9,25 +9,28 @@ import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.skills.SkillTools; import com.gmail.nossr50.worldguard.WorldGuardManager; import com.gmail.nossr50.worldguard.WorldGuardUtils; +import java.util.HashMap; import org.bukkit.entity.Player; -import java.util.HashMap; - public final class HardcoreManager { - private HardcoreManager() {} + private HardcoreManager() { + } public static void invokeStatPenalty(Player player) { - if(WorldGuardUtils.isWorldGuardLoaded()) { - if(!WorldGuardManager.getInstance().hasHardcoreFlag(player)) + if (WorldGuardUtils.isWorldGuardLoaded()) { + if (!WorldGuardManager.getInstance().hasHardcoreFlag(player)) { return; + } } - double statLossPercentage = mcMMO.p.getGeneralConfig().getHardcoreDeathStatPenaltyPercentage(); + double statLossPercentage = mcMMO.p.getGeneralConfig() + .getHardcoreDeathStatPenaltyPercentage(); int levelThreshold = mcMMO.p.getGeneralConfig().getHardcoreDeathStatPenaltyLevelThreshold(); - if(UserManager.getPlayer(player) == null) + if (UserManager.getPlayer(player) == null) { return; + } PlayerProfile playerProfile = UserManager.getPlayer(player).getProfile(); int totalLevelsLost = 0; @@ -51,7 +54,8 @@ public final class HardcoreManager { continue; } - double statsLost = Math.max(0, (playerSkillLevel - levelThreshold)) * (statLossPercentage * 0.01D); + double statsLost = + Math.max(0, (playerSkillLevel - levelThreshold)) * (statLossPercentage * 0.01D); int levelsLost = (int) statsLost; int xpLost = (int) Math.floor(playerSkillXpLevel * (statsLost - levelsLost)); levelChanged.put(primarySkillType.toString(), levelsLost); @@ -64,21 +68,26 @@ public final class HardcoreManager { return; } - NotificationManager.sendPlayerInformation(player, NotificationType.HARDCORE_MODE, "Hardcore.DeathStatLoss.PlayerDeath", String.valueOf(totalLevelsLost)); + NotificationManager.sendPlayerInformation(player, NotificationType.HARDCORE_MODE, + "Hardcore.DeathStatLoss.PlayerDeath", String.valueOf(totalLevelsLost)); } public static void invokeVampirism(Player killer, Player victim) { - if(WorldGuardUtils.isWorldGuardLoaded()) { - if(!WorldGuardManager.getInstance().hasHardcoreFlag(killer) || !WorldGuardManager.getInstance().hasHardcoreFlag(victim)) + if (WorldGuardUtils.isWorldGuardLoaded()) { + if (!WorldGuardManager.getInstance().hasHardcoreFlag(killer) + || !WorldGuardManager.getInstance().hasHardcoreFlag(victim)) { return; + } } - double vampirismStatLeechPercentage = mcMMO.p.getGeneralConfig().getHardcoreVampirismStatLeechPercentage(); + double vampirismStatLeechPercentage = mcMMO.p.getGeneralConfig() + .getHardcoreVampirismStatLeechPercentage(); int levelThreshold = mcMMO.p.getGeneralConfig().getHardcoreVampirismLevelThreshold(); - if(UserManager.getPlayer(killer) == null || UserManager.getPlayer(victim) == null) + if (UserManager.getPlayer(killer) == null || UserManager.getPlayer(victim) == null) { return; + } PlayerProfile killerProfile = UserManager.getPlayer(killer).getProfile(); PlayerProfile victimProfile = UserManager.getPlayer(victim).getProfile(); @@ -97,7 +106,8 @@ public final class HardcoreManager { int killerSkillLevel = killerProfile.getSkillLevel(primarySkillType); int victimSkillLevel = victimProfile.getSkillLevel(primarySkillType); - if (victimSkillLevel <= 0 || victimSkillLevel < killerSkillLevel / 2 || victimSkillLevel <= levelThreshold) { + if (victimSkillLevel <= 0 || victimSkillLevel < killerSkillLevel / 2 + || victimSkillLevel <= levelThreshold) { levelChanged.put(primarySkillType.toString(), 0); experienceChanged.put(primarySkillType.toString(), 0F); continue; @@ -119,12 +129,17 @@ public final class HardcoreManager { } if (totalLevelsStolen > 0) { - NotificationManager.sendPlayerInformation(killer, NotificationType.HARDCORE_MODE, "Hardcore.Vampirism.Killer.Success", String.valueOf(totalLevelsStolen), victim.getName()); - NotificationManager.sendPlayerInformation(victim, NotificationType.HARDCORE_MODE, "Hardcore.Vampirism.Victim.Success", killer.getName(), String.valueOf(totalLevelsStolen)); - } - else { - NotificationManager.sendPlayerInformation(killer, NotificationType.HARDCORE_MODE, "Hardcore.Vampirism.Killer.Failure", victim.getName()); - NotificationManager.sendPlayerInformation(victim, NotificationType.HARDCORE_MODE, "Hardcore.Vampirism.Victim.Failure", killer.getName()); + NotificationManager.sendPlayerInformation(killer, NotificationType.HARDCORE_MODE, + "Hardcore.Vampirism.Killer.Success", String.valueOf(totalLevelsStolen), + victim.getName()); + NotificationManager.sendPlayerInformation(victim, NotificationType.HARDCORE_MODE, + "Hardcore.Vampirism.Victim.Success", killer.getName(), + String.valueOf(totalLevelsStolen)); + } else { + NotificationManager.sendPlayerInformation(killer, NotificationType.HARDCORE_MODE, + "Hardcore.Vampirism.Killer.Failure", victim.getName()); + NotificationManager.sendPlayerInformation(victim, NotificationType.HARDCORE_MODE, + "Hardcore.Vampirism.Victim.Failure", killer.getName()); } } diff --git a/src/main/java/com/gmail/nossr50/util/HolidayManager.java b/src/main/java/com/gmail/nossr50/util/HolidayManager.java deleted file mode 100644 index 6ea18317b..000000000 --- a/src/main/java/com/gmail/nossr50/util/HolidayManager.java +++ /dev/null @@ -1,388 +0,0 @@ -//package com.gmail.nossr50.util; -// -//import com.gmail.nossr50.commands.skills.AprilCommand; -//import com.gmail.nossr50.config.Config; -//import com.gmail.nossr50.datatypes.interactions.NotificationType; -//import com.gmail.nossr50.datatypes.player.McMMOPlayer; -//import com.gmail.nossr50.datatypes.skills.PrimarySkillType; -//import com.gmail.nossr50.locale.LocaleLoader; -//import com.gmail.nossr50.mcMMO; -//import com.gmail.nossr50.util.player.NotificationManager; -//import com.gmail.nossr50.util.player.UserManager; -//import com.gmail.nossr50.util.sounds.SoundManager; -//import com.gmail.nossr50.util.sounds.SoundType; -//import com.gmail.nossr50.util.text.StringUtils; -//import com.google.common.collect.ImmutableList; -//import org.bukkit.ChatColor; -//import org.bukkit.Color; -//import org.bukkit.Statistic; -//import org.bukkit.command.CommandSender; -//import org.bukkit.command.PluginCommand; -//import org.bukkit.entity.Player; -//import org.bukkit.event.player.PlayerStatisticIncrementEvent; -// -//import java.io.*; -//import java.util.*; -//import java.util.regex.Pattern; -// -//public final class HolidayManager { -// private final ArrayList hasCelebrated; -// private final int currentYear; -// private static final int START_YEAR = 2011; -// -// private static final List ALL_COLORS; -// private static final List ALL_CHAT_COLORS; -// private static final List CHAT_FORMATS; -// -// public enum FakeSkillType { -// MACHO, -// JUMPING, -// THROWING, -// WRECKING, -// CRAFTING, -// WALKING, -// SWIMMING, -// FALLING, -// CLIMBING, -// FLYING, -// DIVING, -// PIGGY, -// UNKNOWN; -// -// public static FakeSkillType getByName(String skillName) { -// for (FakeSkillType type : values()) { -// if (type.name().equalsIgnoreCase(skillName)) { -// return type; -// } -// } -// return null; -// } -// -// public static FakeSkillType getByStatistic(Statistic statistic) { -// switch (statistic) { -// case DAMAGE_TAKEN: -// return FakeSkillType.MACHO; -// case JUMP: -// return FakeSkillType.JUMPING; -// case DROP: -// return FakeSkillType.THROWING; -// case MINE_BLOCK: -// case BREAK_ITEM: -// return FakeSkillType.WRECKING; -// case CRAFT_ITEM: -// return FakeSkillType.CRAFTING; -// case WALK_ONE_CM: -// return FakeSkillType.WALKING; -// case SWIM_ONE_CM: -// return FakeSkillType.SWIMMING; -// case FALL_ONE_CM: -// return FakeSkillType.FALLING; -// case CLIMB_ONE_CM: -// return FakeSkillType.CLIMBING; -// case FLY_ONE_CM: -// return FakeSkillType.FLYING; -// case WALK_UNDER_WATER_ONE_CM: -// return FakeSkillType.DIVING; -// case PIG_ONE_CM: -// return FakeSkillType.PIGGY; -// default: -// return FakeSkillType.UNKNOWN; -// } -// } -// } -// -// public final Set movementStatistics = EnumSet.of( -// Statistic.WALK_ONE_CM, Statistic.SWIM_ONE_CM, Statistic.FALL_ONE_CM, -// Statistic.CLIMB_ONE_CM, Statistic.FLY_ONE_CM, Statistic.WALK_UNDER_WATER_ONE_CM, -// Statistic.PIG_ONE_CM); -// -// static { -// List colors = new ArrayList<>(); -// List chatColors = new ArrayList<>(); -// List chatFormats = new ArrayList<>(); -// -// for (ChatColor color : ChatColor.values()) { -// if (color.isColor()) { -// chatColors.add(color); -// } -// else { -// chatFormats.add(color); -// } -// } -// -//// for (DyeColor color : DyeColor.values()) { -//// colors.add(color.getFireworkColor()); -//// } -// -// Collections.shuffle(chatColors, Misc.getRandom()); -// Collections.shuffle(colors, Misc.getRandom()); -// Collections.shuffle(chatFormats, Misc.getRandom()); -// -// ALL_CHAT_COLORS = ImmutableList.copyOf(chatColors); -// ALL_COLORS = ImmutableList.copyOf(colors); -// CHAT_FORMATS = ImmutableList.copyOf(chatFormats); -// } -// -// // This gets called onEnable -// public HolidayManager() { -// currentYear = Calendar.getInstance().get(Calendar.YEAR); -// -// File anniversaryFile = new File(mcMMO.getFlatFileDirectory(), "anniversary." + currentYear + ".yml"); -// -// if (!anniversaryFile.exists()) { -// try { -// anniversaryFile.createNewFile(); -// } -// catch (IOException ex) { -// mcMMO.p.getLogger().severe(ex.toString()); -// } -// } -// -// hasCelebrated = new ArrayList<>(); -// -// try { -// hasCelebrated.clear(); -// BufferedReader reader = new BufferedReader(new FileReader(anniversaryFile.getPath())); -// String line = reader.readLine(); -// -// while (line != null) { -// hasCelebrated.add(line); -// line = reader.readLine(); -// } -// -// reader.close(); -// } -// catch (Exception ex) { -// mcMMO.p.getLogger().severe(ex.toString()); -// } -// -// cleanupFiles(); -// } -// -// private void cleanupFiles() { -// File FlatFileDir = new File(mcMMO.getFlatFileDirectory()); -// File legacy = new File(FlatFileDir, "anniversary.yml"); -// List toDelete = new ArrayList<>(); -// -// if (legacy.exists()) { -// toDelete.add(legacy); -// } -// -// Pattern pattern = Pattern.compile("anniversary\\.(?:.+)\\.yml"); -// -// for (String fileName : FlatFileDir.list()) { -// if (!pattern.matcher(fileName).matches() || fileName.equals("anniversary." + currentYear + ".yml")) { -// continue; -// } -// -// File file = new File(FlatFileDir, fileName); -// -// if (file.isDirectory()) { -// continue; -// } -// -// toDelete.add(file); -// } -// -// for (File file : toDelete) { -// if (file.delete()) { -// LogUtils.debug(mcMMO.p.getLogger(), "Deleted: " + file.getName()); -// } -// } -// } -// -// // This gets called onDisable -// public void saveAnniversaryFiles() { -// LogUtils.debug(mcMMO.p.getLogger(), "Saving anniversary files..."); -// String anniversaryFilePath = mcMMO.getFlatFileDirectory() + "anniversary." + currentYear + ".yml"; -// -// try { -// BufferedWriter writer = new BufferedWriter(new FileWriter(anniversaryFilePath)); -// for (String player : hasCelebrated) { -// writer.write(player); -// writer.newLine(); -// } -// writer.close(); -// } -// catch (Exception ex) { -// mcMMO.p.getLogger().severe(ex.toString()); -// } -// } -// -// // This gets called from /mcmmo command -// public void anniversaryCheck(final CommandSender sender) { -// GregorianCalendar anniversaryStart = new GregorianCalendar(currentYear, Calendar.FEBRUARY, 3); -// GregorianCalendar anniversaryEnd = new GregorianCalendar(currentYear, Calendar.FEBRUARY, 6); -// GregorianCalendar day = new GregorianCalendar(); -// -// if (hasCelebrated.contains(sender.getName())) { -// return; -// } -// -// if (!getDateRange(day.getTime(), anniversaryStart.getTime(), anniversaryEnd.getTime())) { -// return; -// } -// -// sender.sendMessage(LocaleLoader.getString("Holiday.Anniversary", (currentYear - START_YEAR))); -// /*if (sender instanceof Player) { -// final int firework_amount = 10; -// for (int i = 0; i < firework_amount; i++) { -// int delay = (int) (Misc.getRandom().nextDouble() * 3 * Misc.TICK_CONVERSION_FACTOR) + 4; -// mcMMO.p.getServer().getScheduler().runTaskLater(mcMMO.p, new Runnable() { -// @Override -// public void run() { -// spawnFireworks((Player) sender); -// } -// }, delay); -// } -// }*/ -//// else { -// /* -// * Credit: http://www.geocities.com/spunk1111/ -// * (good luck finding that in 3 years heh) -// * .''. . *''* :_\/_: . -// * :_\/_: _\(/_ .:.*_\/_* : /\ : .'.:.'. -// * .''.: /\ : /)\ ':'* /\ * : '..'. -=:o:=- -// * :_\/_:'.:::. ' *''* * '.\'/.'_\(/_ '.':'.' -// * : /\ : ::::: *_\/_* -= o =- /)\ ' -// * '..' ':::' * /\ * .'/.\'. ' * -// * * *..* : * -// * * * * -// * * * * -// */ -// -// /* -// * Color map -// * AAAA D GGGG JJJJJJ K -// * AAAAAA DDDDD EEEGGGGGG JJJJJJ KKKKKKK -// * BBBBAAAAAA DDD EEEGGGGGG I JJJJJ KKKKKKK -// * BBBBBBACCCCC D FFFF G IIIIIIIHHHHH KKKKKKK -// * BBBBBB CCCCC FFFFFF IIIIIII HHH K -// * BBBB CCCCC FFFFFF IIIIIII H k -// * b FFFF I k -// * b i k -// * b i k -// */ -// Object[] colorParams = new Object[]{chatColorChoose(), chatColorChoose(), chatColorChoose(), chatColorChoose(), chatColorChoose(), chatColorChoose(), chatColorChoose(), chatColorChoose(), chatColorChoose(), chatColorChoose(), chatColorChoose()}; -// sender.sendMessage(String.format(" %1$s.''. %4$s. %7$s*''* %10$s:_\\/_: %11$s.", colorParams)); -// sender.sendMessage(String.format(" %1$s:_\\/_: %4$s_\\(/_ %5$s.:.%7$s*_\\/_* %10$s: /\\ : %11$s.'.:.'.", colorParams)); -// sender.sendMessage(String.format(" %2$s.''.%1$s: /\\ : %4$s/)\\ %5$s':'%7$s* /\\ * %9$s: %10$s'..'. %11$s-=:o:=-", colorParams)); -// sender.sendMessage(String.format("%2$s:_\\/_:%1$s'%3$s.:::. %4$s' %6$s*''* %7$s* %9$s'.\\'/.'%8$s_\\(/_ %11$s'.':'.'", colorParams)); -// sender.sendMessage(String.format("%2$s: /\\ : %3$s::::: %6$s*_\\/_* %9$s-= o =-%8$s /)\\ %11$s'", colorParams)); -// sender.sendMessage(String.format(" %2$s'..' %3$s':::' %6$s* /\\ * %9$s.'/.\\'. %8$s' %11$s*", colorParams)); -// sender.sendMessage(String.format(" %2$s* %6$s*..* %9$s: %11$s*", colorParams)); -// sender.sendMessage(String.format(" %2$s* %9$s* %11$s*", colorParams)); -// sender.sendMessage(String.format(" %2$s* %9$s* %11$s*", colorParams)); -//// } -// -// hasCelebrated.add(sender.getName()); -// } -// -// public boolean getDateRange(Date date, Date start, Date end) { -// return !(date.before(start) || date.after(end)); -// } -// -//// public void spawnFireworks(Player player) { -//// int power = Misc.getRandom().nextInt(3) + 1; -//// Type fireworkType = Type.values()[Misc.getRandom().nextInt(Type.values().length)]; -//// double varX = Misc.getRandom().nextGaussian() * 3; -//// double varZ = Misc.getRandom().nextGaussian() * 3; -//// -//// Firework fireworks = (Firework) player.getWorld().spawnEntity(player.getLocation().add(varX, 0, varZ), EntityType.FIREWORK); -//// FireworkMeta fireworkmeta = fireworks.getFireworkMeta(); -//// FireworkEffect effect = FireworkEffect.builder().flicker(Misc.getRandom().nextBoolean()).withColor(colorChoose()).withFade(colorChoose()).with(fireworkType).trail(Misc.getRandom().nextBoolean()).build(); -//// fireworkmeta.addEffect(effect); -//// fireworkmeta.setPower(power); -//// fireworks.setFireworkMeta(fireworkmeta); -//// } -// -// private static List colorChoose() { -// return ALL_COLORS.subList(0, Math.max(Misc.getRandom().nextInt(ALL_COLORS.size() + 1), 1)); -// } -// -// private static String chatColorChoose() { -// StringBuilder ret = new StringBuilder(ALL_CHAT_COLORS.get(Misc.getRandom().nextInt(ALL_CHAT_COLORS.size())).toString()); -// -// for (ChatColor chatFormat : CHAT_FORMATS) { -// if (Misc.getRandom().nextInt(CHAT_FORMATS.size()) == 0) { -// ret.append(chatFormat); -// } -// } -// -// return ret.toString(); -// } -// -// public boolean isAprilFirst() { -// if(!Config.getInstance().isAprilFoolsAllowed()) -// return false; -// -// GregorianCalendar aprilFirst = new GregorianCalendar(currentYear, Calendar.APRIL, 1); -// GregorianCalendar aprilSecond = new GregorianCalendar(currentYear, Calendar.APRIL, 2); -// GregorianCalendar day = new GregorianCalendar(); -// return getDateRange(day.getTime(), aprilFirst.getTime(), aprilSecond.getTime()); -// } -// -// public boolean nearingAprilFirst() { -// if(!Config.getInstance().isAprilFoolsAllowed()) -// return false; -// -// GregorianCalendar start = new GregorianCalendar(Calendar.getInstance().get(Calendar.YEAR), Calendar.MARCH, 28); -// GregorianCalendar end = new GregorianCalendar(Calendar.getInstance().get(Calendar.YEAR), Calendar.APRIL, 2); -// GregorianCalendar day = new GregorianCalendar(); -// -// return mcMMO.getHolidayManager().getDateRange(day.getTime(), start.getTime(), end.getTime()); -// } -// -// public void handleStatisticEvent(PlayerStatisticIncrementEvent event) { -// Player player = event.getPlayer(); -// Statistic statistic = event.getStatistic(); -// int newValue = event.getNewValue(); -// -// int modifier; -// switch (statistic) { -// case DAMAGE_TAKEN: -// modifier = 500; -// break; -// case JUMP: -// modifier = 500; -// break; -// case DROP: -// modifier = 200; -// break; -// case MINE_BLOCK: -// case BREAK_ITEM: -// modifier = 500; -// break; -// case CRAFT_ITEM: -// modifier = 100; -// break; -// default: -// return; -// } -// -// if (newValue % modifier == 0) { -// mcMMO.getHolidayManager().levelUpApril(player, FakeSkillType.getByStatistic(statistic)); -// } -// } -// -// public void levelUpApril(Player player, FakeSkillType fakeSkillType) { -// if(!Config.getInstance().isAprilFoolsAllowed()) -// return; -// -// final McMMOPlayer mmoPlayer = UserManager.getPlayer(player); -// if (mmoPlayer == null) return; -// -// int levelTotal = Misc.getRandom().nextInt(1 + mmoPlayer.getSkillLevel(PrimarySkillType.MINING)) + 1; -// SoundManager.sendSound(player, player.getLocation(), SoundType.LEVEL_UP); -// NotificationManager.sendPlayerInformation(player, NotificationType.HOLIDAY, "Holiday.AprilFools.Levelup", StringUtils.getCapitalized(fakeSkillType.toString()), String.valueOf(levelTotal)); -//// ParticleEffectUtils.fireworkParticleShower(player, ALL_COLORS.get(Misc.getRandom().nextInt(ALL_COLORS.size()))); -// } -// -// public void registerAprilCommand() { -// if(!Config.getInstance().isAprilFoolsAllowed()) -// return; -// -// PluginCommand command = mcMMO.p.getCommand("crafting"); -// command.setExecutor(new AprilCommand()); -// } -//} diff --git a/src/main/java/com/gmail/nossr50/metadata/ItemMetadataService.java b/src/main/java/com/gmail/nossr50/util/ItemMetadataUtils.java similarity index 59% rename from src/main/java/com/gmail/nossr50/metadata/ItemMetadataService.java rename to src/main/java/com/gmail/nossr50/util/ItemMetadataUtils.java index f1d1e9471..95d5c824f 100644 --- a/src/main/java/com/gmail/nossr50/metadata/ItemMetadataService.java +++ b/src/main/java/com/gmail/nossr50/util/ItemMetadataUtils.java @@ -1,60 +1,63 @@ -package com.gmail.nossr50.metadata; +package com.gmail.nossr50.util; + +import static com.gmail.nossr50.util.MetadataService.NSK_SUPER_ABILITY_BOOSTED_ITEM; import com.gmail.nossr50.mcMMO; -import org.bukkit.enchantments.Enchantment; +import java.util.List; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.persistence.PersistentDataContainer; import org.bukkit.persistence.PersistentDataType; import org.jetbrains.annotations.NotNull; -import java.util.List; +public final class ItemMetadataUtils { -import static com.gmail.nossr50.metadata.MetadataService.NSK_SUPER_ABILITY_BOOSTED_ITEM; + public static final @NotNull String LEGACY_ABILITY_TOOL_LORE = "mcMMO Ability Tool"; -public class ItemMetadataService { - - public final @NotNull String LEGACY_ABILITY_TOOL_LORE = "mcMMO Ability Tool"; - public final @NotNull mcMMO pluginRef; - - public ItemMetadataService(@NotNull mcMMO pluginRef) { - this.pluginRef = pluginRef; + private ItemMetadataUtils() { + // private ctor } - public void setSuperAbilityBoostedItem(@NotNull ItemStack itemStack, int originalDigSpeed) { + public static void setSuperAbilityBoostedItem(@NotNull ItemStack itemStack, + int originalDigSpeed) { if (itemStack.getItemMeta() == null) { - mcMMO.p.getLogger().severe("Can not assign persistent data to an item with null item metadata"); + mcMMO.p.getLogger() + .severe("Can not assign persistent data to an item with null item metadata"); return; } ItemMeta itemMeta = itemStack.getItemMeta(); PersistentDataContainer dataContainer = itemMeta.getPersistentDataContainer(); - dataContainer.set(NSK_SUPER_ABILITY_BOOSTED_ITEM, PersistentDataType.INTEGER, originalDigSpeed); + dataContainer.set(NSK_SUPER_ABILITY_BOOSTED_ITEM, PersistentDataType.INTEGER, + originalDigSpeed); itemStack.setItemMeta(itemMeta); } - public boolean isSuperAbilityBoosted(@NotNull ItemStack itemStack) { - if (itemStack.getItemMeta() == null) + public static boolean isSuperAbilityBoosted(@NotNull ItemStack itemStack) { + if (itemStack.getItemMeta() == null) { return false; + } ItemMeta itemMeta = itemStack.getItemMeta(); //Get container from entity PersistentDataContainer dataContainer = itemMeta.getPersistentDataContainer(); //If this value isn't null, then the tool can be considered dig speed boosted - Integer boostValue = dataContainer.get(NSK_SUPER_ABILITY_BOOSTED_ITEM, PersistentDataType.INTEGER); + Integer boostValue = dataContainer.get(NSK_SUPER_ABILITY_BOOSTED_ITEM, + PersistentDataType.INTEGER); return boostValue != null; } - public int getSuperAbilityToolOriginalDigSpeed(@NotNull ItemStack itemStack) { + public static int getSuperAbilityToolOriginalDigSpeed(@NotNull ItemStack itemStack) { //Get container from entity ItemMeta itemMeta = itemStack.getItemMeta(); - if (itemMeta == null) + if (itemMeta == null) { return 0; + } PersistentDataContainer dataContainer = itemMeta.getPersistentDataContainer(); @@ -63,23 +66,25 @@ public class ItemMetadataService { return 0; } else { //Too lazy to make a custom data type for this stuff - Integer boostValue = dataContainer.get(NSK_SUPER_ABILITY_BOOSTED_ITEM, PersistentDataType.INTEGER); + Integer boostValue = dataContainer.get(NSK_SUPER_ABILITY_BOOSTED_ITEM, + PersistentDataType.INTEGER); return Math.max(boostValue, 0); } } - public void removeBonusDigSpeedOnSuperAbilityTool(@NotNull ItemStack itemStack) { + public static void removeBonusDigSpeedOnSuperAbilityTool(@NotNull ItemStack itemStack) { int originalSpeed = getSuperAbilityToolOriginalDigSpeed(itemStack); ItemMeta itemMeta = itemStack.getItemMeta(); - if(itemMeta != null) { + if (itemMeta != null) { //TODO: can be optimized - if (itemMeta.hasEnchant(Enchantment.DIG_SPEED)) { - itemMeta.removeEnchant(Enchantment.DIG_SPEED); + if (itemMeta.hasEnchant(mcMMO.p.getEnchantmentMapper().getEfficiency())) { + itemMeta.removeEnchant(mcMMO.p.getEnchantmentMapper().getEfficiency()); } if (originalSpeed > 0) { - itemMeta.addEnchant(Enchantment.DIG_SPEED, originalSpeed, true); + itemMeta.addEnchant(mcMMO.p.getEnchantmentMapper().getEfficiency(), originalSpeed, + true); } PersistentDataContainer dataContainer = itemMeta.getPersistentDataContainer(); @@ -90,21 +95,19 @@ public class ItemMetadataService { } } - public boolean isLegacyAbilityTool(@NotNull ItemStack itemStack) { + public static boolean isLegacyAbilityTool(@NotNull ItemStack itemStack) { ItemMeta itemMeta = itemStack.getItemMeta(); - if (itemMeta == null) + if (itemMeta == null) { return false; + } List lore = itemMeta.getLore(); - if (lore == null || lore.isEmpty()) + if (lore == null || lore.isEmpty()) { return false; + } return lore.contains(LEGACY_ABILITY_TOOL_LORE); } - - public @NotNull String getLegacyAbilityToolLore() { - return LEGACY_ABILITY_TOOL_LORE; - } } diff --git a/src/main/java/com/gmail/nossr50/util/ItemUtils.java b/src/main/java/com/gmail/nossr50/util/ItemUtils.java index 4787e0159..16034f905 100644 --- a/src/main/java/com/gmail/nossr50/util/ItemUtils.java +++ b/src/main/java/com/gmail/nossr50/util/ItemUtils.java @@ -1,34 +1,81 @@ package com.gmail.nossr50.util; +import static java.util.Objects.requireNonNull; + +import com.gmail.nossr50.api.ItemSpawnReason; import com.gmail.nossr50.config.experience.ExperienceConfig; import com.gmail.nossr50.config.party.ItemWeightConfig; import com.gmail.nossr50.datatypes.treasure.EnchantmentWrapper; import com.gmail.nossr50.datatypes.treasure.FishingTreasureBook; +import com.gmail.nossr50.events.items.McMMOItemSpawnEvent; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.skills.smelting.Smelting; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Locale; +import java.util.function.Predicate; import org.bukkit.ChatColor; +import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.NamespacedKey; import org.bukkit.enchantments.Enchantment; +import org.bukkit.entity.Item; import org.bukkit.entity.Player; import org.bukkit.inventory.FurnaceRecipe; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.Recipe; import org.bukkit.inventory.meta.EnchantmentStorageMeta; import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.util.Vector; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.Collections; -import java.util.List; - public final class ItemUtils { + // Reflection for setItemName only available in newer APIs + private static final Method setItemName; + + static { + setItemName = getSetItemName(); + } + + private ItemUtils() { + // private constructor + } + + private static Method getSetItemName() { + try { + return ItemMeta.class.getMethod("setItemName", String.class); + } catch (NoSuchMethodException e) { + return null; + } + } + /** - * This is a static utility class, therefore we don't want any instances of - * this class. Making the constructor private prevents accidents like that. + * Sets the item name using the new API if available or falls back to the old API. + * + * @param itemMeta The item meta to set the name on + * @param name The name to set */ - private ItemUtils() {} + public static void setItemName(ItemMeta itemMeta, String name) { + if (setItemName != null) { + setItemNameModern(itemMeta, name); + } else { + itemMeta.setDisplayName(ChatColor.RESET + name); + } + } + + private static void setItemNameModern(ItemMeta itemMeta, String name) { + try { + setItemName.invoke(itemMeta, name); + } catch (IllegalAccessException | InvocationTargetException e) { + mcMMO.p.getLogger().severe("Failed to set item name: " + e.getMessage()); + throw new RuntimeException(e); + } + } /** * Checks if the item is a bow. @@ -36,82 +83,182 @@ public final class 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()); } + /** + * Exhaustive lookup for a Material by name. + *

+ * This method will first try a normal lookup, then a legacy lookup, then a lookup by ENUM name, + * and finally a lookup by ENUM name with legacy name. + * + * @param materialName The name of the material to lookup + * @return The Material if found, or null if not found + */ + public static @Nullable Material exhaustiveMaterialLookup(@NotNull String materialName) { + requireNonNull(materialName, "materialName cannot be null"); + + // First try a normal lookup + Material material = Material.matchMaterial(materialName); + + // If that fails, try a legacy lookup + if (material == null) { + material = Material.matchMaterial(materialName, true); + } + + // try to match to Material ENUM + if (material == null) { + material = Material.getMaterial(materialName.toUpperCase(Locale.ENGLISH)); + } + + // try to match to Material ENUM with legacy name + if (material == null) { + material = Material.getMaterial(materialName.toUpperCase(Locale.ENGLISH), true); + } + return material; + } + + /** + * Checks if a player has an item in their inventory or offhand. + * + * @param player Player to check + * @param material Material to check for + * @return true if the player has the item in their inventory or offhand, false otherwise + */ + public static boolean hasItemIncludingOffHand(Player player, Material material) { + // Checks main inventory / item bar + boolean containsInMain = player.getInventory().contains(material); + + if (containsInMain) { + return true; + } + + return player.getInventory().getItemInOffHand().getType() == material; + } + + /** + * Removes an item from a player's inventory, including their offhand. + * + * @param player Player to remove the item from + * @param material Material to remove + * @param amount Amount of the material to remove + */ + public static void removeItemIncludingOffHand(@NotNull Player player, + @NotNull Material material, int amount) { + // Checks main inventory / item bar + if (player.getInventory().contains(material)) { + player.getInventory().removeItem(new ItemStack(material, amount)); + return; + } + + // Check off-hand + final ItemStack offHandItem = player.getInventory().getItemInOffHand(); + if (offHandItem.getType() == material) { + int newAmount = offHandItem.getAmount() - amount; + if (newAmount > 0) { + offHandItem.setAmount(newAmount); + } else { + player.getInventory().setItemInOffHand(new ItemStack(Material.AIR)); + } + } + } + + // TODO: Unit tests public static boolean isCrossbow(@NotNull ItemStack item) { return mcMMO.getMaterialMapStore().isCrossbow(item.getType().getKey().getKey()); } - public static boolean hasItemInEitherHand(@NotNull Player player, Material material) { - return player.getInventory().getItemInMainHand().getType() == material || player.getInventory().getItemInOffHand().getType() == material; + // TODO: Unit tests + public static boolean isTrident(@NotNull ItemStack item) { + return mcMMO.getMaterialMapStore().isTrident(item.getType().getKey().getKey()); } - public static boolean doesPlayerHaveEnchantmentOnArmor(@NotNull Player player, @NotNull String enchantmentByName) { + public static boolean isMace(@NotNull ItemStack item) { + return mcMMO.getMaterialMapStore().isMace(item.getType().getKey().getKey()); + } + + public static boolean hasItemInEitherHand(@NotNull Player player, Material material) { + return player.getInventory().getItemInMainHand().getType() == material + || player.getInventory().getItemInOffHand().getType() == material; + } + + public static boolean doesPlayerHaveEnchantmentOnArmor(@NotNull Player player, + @NotNull String enchantmentByName) { Enchantment enchantment = getEnchantment(enchantmentByName); - if(enchantment == null) + if (enchantment == null) { return false; + } return doesPlayerHaveEnchantmentOnArmor(player, enchantment); } - public static boolean doesPlayerHaveEnchantmentOnArmor(@NotNull Player player, @NotNull Enchantment enchantment) { - for(ItemStack itemStack : player.getInventory().getArmorContents()) { - if(itemStack != null) { - if(hasEnchantment(itemStack, enchantment)) + public static boolean doesPlayerHaveEnchantmentOnArmor(@NotNull Player player, + @NotNull Enchantment enchantment) { + for (ItemStack itemStack : player.getInventory().getArmorContents()) { + if (itemStack != null) { + if (hasEnchantment(itemStack, enchantment)) { return true; + } } } return false; } - public static boolean doesPlayerHaveEnchantmentOnArmorOrHands(@NotNull Player player, @NotNull String enchantmentName) { + public static boolean doesPlayerHaveEnchantmentOnArmorOrHands(@NotNull Player player, + @NotNull String enchantmentName) { Enchantment enchantment = getEnchantment(enchantmentName); - if(enchantment == null) + if (enchantment == null) { return false; + } return doesPlayerHaveEnchantmentOnArmorOrHands(player, enchantment); } - public static boolean doesPlayerHaveEnchantmentOnArmorOrHands(@NotNull Player player, @NotNull Enchantment enchantment) { - if(doesPlayerHaveEnchantmentOnArmor(player, enchantment)) + public static boolean doesPlayerHaveEnchantmentOnArmorOrHands(@NotNull Player player, + @NotNull Enchantment enchantment) { + if (doesPlayerHaveEnchantmentOnArmor(player, enchantment)) { return true; + } - if(doesPlayerHaveEnchantmentInHands(player, enchantment)) - return true; - - return false; + return doesPlayerHaveEnchantmentInHands(player, enchantment); } - public static boolean doesPlayerHaveEnchantmentInHands(@NotNull Player player, @NotNull NamespacedKey enchantmentNameKey) { + public static boolean doesPlayerHaveEnchantmentInHands(@NotNull Player player, + @NotNull NamespacedKey enchantmentNameKey) { Enchantment enchantment = Enchantment.getByKey(enchantmentNameKey); - if(enchantment == null) + if (enchantment == null) { return false; + } return doesPlayerHaveEnchantmentInHands(player, enchantment); } - public static boolean doesPlayerHaveEnchantmentInHands(@NotNull Player player, @NotNull String enchantmentName) { + public static boolean doesPlayerHaveEnchantmentInHands(@NotNull Player player, + @NotNull String enchantmentName) { Enchantment enchantment = getEnchantment(enchantmentName); - if(enchantment == null) + if (enchantment == null) { return false; + } return doesPlayerHaveEnchantmentInHands(player, enchantment); } - public static boolean doesPlayerHaveEnchantmentInHands(@NotNull Player player, @NotNull Enchantment enchantment) { + public static boolean doesPlayerHaveEnchantmentInHands(@NotNull Player player, + @NotNull Enchantment enchantment) { return hasEnchantment(player.getInventory().getItemInMainHand(), enchantment) || - hasEnchantment(player.getInventory().getItemInOffHand(), enchantment); + hasEnchantment(player.getInventory().getItemInOffHand(), enchantment); } - public static boolean hasEnchantment(@NotNull ItemStack itemStack, @NotNull Enchantment enchantment) { - if(itemStack.getItemMeta() != null) { + public static boolean hasEnchantment(@NotNull ItemStack itemStack, + @NotNull Enchantment enchantment) { + if (itemStack.getItemMeta() != null) { return itemStack.getItemMeta().hasEnchant(enchantment); } @@ -119,8 +266,8 @@ public final class ItemUtils { } public static @Nullable Enchantment getEnchantment(@NotNull String enchantmentName) { - for(Enchantment enchantment : Enchantment.values()) { - if(enchantment.getKey().getKey().equalsIgnoreCase(enchantmentName)) { + for (Enchantment enchantment : Enchantment.values()) { + if (enchantment.getKey().getKey().equalsIgnoreCase(enchantmentName)) { return enchantment; } } @@ -300,6 +447,10 @@ public final class ItemUtils { return mcMMO.getMaterialMapStore().isStringTool(item.getType().getKey().getKey()); } + public static boolean isPrismarineTool(ItemStack item) { + return mcMMO.getMaterialMapStore().isPrismarineTool(item.getType().getKey().getKey()); + } + /** * Checks to see if an item is a gold tool. * @@ -371,7 +522,11 @@ public final class ItemUtils { return false; } - return isMiningDrop(item) || isWoodcuttingDrop(item) || isMobDrop(item) || isHerbalismDrop(item) || isMiscDrop(item); + return isMiningDrop(item) + || isWoodcuttingDrop(item) + || isMobDrop(item) + || isHerbalismDrop(item) + || isMiscDrop(item); } /** @@ -382,27 +537,14 @@ public final class ItemUtils { */ public static boolean isMiningDrop(ItemStack item) { //TODO: 1.14 This needs to be updated - switch (item.getType()) { - case COAL: - case COAL_ORE: - case DIAMOND: - case DIAMOND_ORE: - case EMERALD: - case EMERALD_ORE: - case GOLD_ORE: - case IRON_ORE: - case LAPIS_ORE: - case REDSTONE_ORE: // Should we also have Glowing Redstone Ore here? - case REDSTONE: - case GLOWSTONE_DUST: // Should we also have Glowstone here? - case QUARTZ: - case NETHER_QUARTZ_ORE: - case LAPIS_LAZULI: - return true; - - default: - return false; - } + return switch (item.getType()) { // Should we also have Glowing Redstone Ore here? + // Should we also have Glowstone here? + case COAL, COAL_ORE, DIAMOND, DIAMOND_ORE, EMERALD, EMERALD_ORE, GOLD_ORE, IRON_ORE, + LAPIS_ORE, + REDSTONE_ORE, REDSTONE, GLOWSTONE_DUST, QUARTZ, NETHER_QUARTZ_ORE, LAPIS_LAZULI -> + true; + default -> false; + }; } /** @@ -413,36 +555,16 @@ public final class ItemUtils { */ public static boolean isHerbalismDrop(ItemStack item) { //TODO: 1.14 This needs to be updated - switch (item.getType().getKey().getKey().toLowerCase()) { - case "wheat": - case "wheat_seeds": - case "carrot": - case "chorus_fruit": - case "chorus_flower": - case "potato": - case "beetroot": - case "beetroots": - case "beetroot_seeds": - case "nether_wart": - case "brown_mushroom": - case "red_mushroom": - case "rose_bush": - case "dandelion": - case "cactus": - case "sugar_cane": - case "melon": - case "melon_seeds": - case "pumpkin": - case "pumpkin_seeds": - case "lily_pad": - case "vine": - case "tall_grass": - case "cocoa_beans": - return true; - - default: - return false; - } + return switch (item.getType().getKey().getKey().toLowerCase()) { + case "wheat", "wheat_seeds", "carrot", "chorus_fruit", "chorus_flower", "potato", + "beetroot", "beetroots", + "beetroot_seeds", "nether_wart", "brown_mushroom", "red_mushroom", "rose_bush", + "dandelion", "cactus", + "sugar_cane", "melon", "melon_seeds", "pumpkin", "pumpkin_seeds", "lily_pad", + "vine", "tall_grass", + "cocoa_beans" -> true; + default -> false; + }; } @@ -454,54 +576,19 @@ public final class ItemUtils { */ public static boolean isMobDrop(ItemStack item) { //TODO: 1.14 This needs to be updated - switch (item.getType()) { - case STRING: - case FEATHER: - case CHICKEN: - case COOKED_CHICKEN: - case LEATHER: - case BEEF: - case COOKED_BEEF: - case PORKCHOP: - case COOKED_PORKCHOP: - case WHITE_WOOL: - case BLACK_WOOL: - case BLUE_WOOL: - case BROWN_WOOL: - case CYAN_WOOL: - case GRAY_WOOL: - case GREEN_WOOL: - case LIGHT_BLUE_WOOL: - case LIGHT_GRAY_WOOL: - case LIME_WOOL: - case MAGENTA_WOOL: - case ORANGE_WOOL: - case PINK_WOOL: - case PURPLE_WOOL: - case RED_WOOL: - case YELLOW_WOOL: - case IRON_INGOT: - case SNOWBALL: - case BLAZE_ROD: - case SPIDER_EYE: - case GUNPOWDER: - case ENDER_PEARL: - case GHAST_TEAR: - case MAGMA_CREAM: - case BONE: - case ARROW: - case SLIME_BALL: - case NETHER_STAR: - case ROTTEN_FLESH: - case GOLD_NUGGET: - case EGG: - case ROSE_BUSH: - case COAL: - return true; - - default: - return false; - } + return switch (item.getType()) { + case STRING, FEATHER, CHICKEN, COOKED_CHICKEN, LEATHER, BEEF, COOKED_BEEF, PORKCHOP, + COOKED_PORKCHOP, + WHITE_WOOL, BLACK_WOOL, BLUE_WOOL, BROWN_WOOL, CYAN_WOOL, GRAY_WOOL, GREEN_WOOL, + LIGHT_BLUE_WOOL, + LIGHT_GRAY_WOOL, LIME_WOOL, MAGENTA_WOOL, ORANGE_WOOL, PINK_WOOL, PURPLE_WOOL, + RED_WOOL, YELLOW_WOOL, + IRON_INGOT, SNOWBALL, BLAZE_ROD, SPIDER_EYE, GUNPOWDER, ENDER_PEARL, GHAST_TEAR, + MAGMA_CREAM, BONE, + ARROW, SLIME_BALL, NETHER_STAR, ROTTEN_FLESH, GOLD_NUGGET, EGG, ROSE_BUSH, COAL -> + true; + default -> false; + }; } /** @@ -511,39 +598,20 @@ public final class ItemUtils { * @return true if the item is a woodcutting drop, false otherwise */ public static boolean isWoodcuttingDrop(ItemStack item) { - switch (item.getType().toString()) { - case "ACACIA_LOG": - case "BIRCH_LOG": - case "DARK_OAK_LOG": - case "JUNGLE_LOG": - case "OAK_LOG": - case "SPRUCE_LOG": - case "STRIPPED_ACACIA_LOG": - case "STRIPPED_BIRCH_LOG": - case "STRIPPED_DARK_OAK_LOG": - case "STRIPPED_JUNGLE_LOG": - case "STRIPPED_OAK_LOG": - case "STRIPPED_SPRUCE_LOG": - case "STRIPPED_MANGROVE_LOG": - case "ACACIA_SAPLING": - case "SPRUCE_SAPLING": - case "BIRCH_SAPLING": - case "DARK_OAK_SAPLING": - case "JUNGLE_SAPLING": - case "OAK_SAPLING": - case "ACACIA_LEAVES": - case "BIRCH_LEAVES": - case "DARK_OAK_LEAVES": - case "JUNGLE_LEAVES": - case "OAK_LEAVES": - case "SPRUCE_LEAVES": - case "BEE_NEST": - case "APPLE": - return true; - - default: - return false; - } + return switch (item.getType().toString()) { + case "ACACIA_LOG", "BIRCH_LOG", "DARK_OAK_LOG", "PALE_OAK_LOG", "JUNGLE_LOG", "OAK_LOG", + "SPRUCE_LOG", + "STRIPPED_ACACIA_LOG", "STRIPPED_BIRCH_LOG", "STRIPPED_DARK_OAK_LOG", + "STRIPPED_PALE_OAK_LOG", + "STRIPPED_JUNGLE_LOG", "STRIPPED_OAK_LOG", "STRIPPED_SPRUCE_LOG", + "STRIPPED_MANGROVE_LOG", + "ACACIA_SAPLING", "SPRUCE_SAPLING", "BIRCH_SAPLING", "DARK_OAK_SAPLING", + "PALE_OAK_SAPLING", + "JUNGLE_SAPLING", "OAK_SAPLING", "ACACIA_LEAVES", "BIRCH_LEAVES", + "DARK_OAK_LEAVES", "PALE_OAK_LEAVES", + "JUNGLE_LEAVES", "OAK_LEAVES", "SPRUCE_LEAVES", "BEE_NEST", "APPLE" -> true; + default -> false; + }; } /** @@ -556,6 +624,7 @@ public final class ItemUtils { return ItemWeightConfig.getInstance().getMiscItems().contains(item.getType()); } + // TODO: This is used exclusively for Chimaera Wing... should revisit this sometime public static boolean isMcMMOItem(ItemStack item) { if (!item.hasItemMeta()) { return false; @@ -563,8 +632,9 @@ public final class ItemUtils { ItemMeta itemMeta = item.getItemMeta(); - if(itemMeta == null) + if (itemMeta == null) { return false; + } return itemMeta.getLore() != null && itemMeta.getLore().contains("mcMMO Item"); @@ -577,40 +647,27 @@ public final class ItemUtils { ItemMeta itemMeta = item.getItemMeta(); - if(itemMeta == null) + if (itemMeta == null) { return false; + } - return itemMeta.hasDisplayName() && itemMeta.getDisplayName().equals(ChatColor.GOLD + LocaleLoader.getString("Item.ChimaeraWing.Name")); + return itemMeta.hasDisplayName() && itemMeta.getDisplayName() + .equals(ChatColor.GOLD + LocaleLoader.getString("Item.ChimaeraWing.Name")); } -// public static void addAbilityLore(@NotNull ItemStack itemStack) { -// ItemMeta itemMeta = itemStack.getItemMeta(); -// List itemLore = new ArrayList<>(); -// -// if(itemMeta == null) -// return; -// -// if (itemMeta.hasLore()) { -// itemLore = itemMeta.getLore(); -// } -// -// itemLore.add("mcMMO Ability Tool"); -// -// itemMeta.setLore(itemLore); -// itemStack.setItemMeta(itemMeta); -// } - public static void removeAbilityLore(@NotNull ItemStack itemStack) { ItemMeta itemMeta = itemStack.getItemMeta(); - if(itemMeta == null) + if (itemMeta == null) { return; + } if (itemMeta.hasLore()) { List itemLore = itemMeta.getLore(); - if(itemLore == null) + if (itemLore == null) { return; + } if (itemLore.remove("mcMMO Ability Tool")) { itemMeta.setLore(itemLore); @@ -619,13 +676,16 @@ public final class ItemUtils { } } - public static void addDigSpeedToItem(@NotNull ItemStack itemStack, int existingEnchantLevel) { + public static void addDigSpeedToItem(@NotNull ItemStack itemStack, + int existingEnchantLevel) { ItemMeta itemMeta = itemStack.getItemMeta(); - if(itemMeta == null) + if (itemMeta == null) { return; + } - itemMeta.addEnchant(Enchantment.DIG_SPEED, existingEnchantLevel + mcMMO.p.getAdvancedConfig().getEnchantBuff(), true); + itemMeta.addEnchant(mcMMO.p.getEnchantmentMapper().getEfficiency(), + existingEnchantLevel + mcMMO.p.getAdvancedConfig().getEnchantBuff(), true); itemStack.setItemMeta(itemMeta); } @@ -633,25 +693,268 @@ public final class ItemUtils { return isShovel(itemStack) || isPickaxe(itemStack); } - public static @NotNull ItemStack createEnchantBook(@NotNull FishingTreasureBook fishingTreasureBook) { + public static @NotNull ItemStack createEnchantBook( + @NotNull FishingTreasureBook fishingTreasureBook) { ItemStack itemStack = fishingTreasureBook.getDrop().clone(); - EnchantmentWrapper enchantmentWrapper = getRandomEnchantment(fishingTreasureBook.getLegalEnchantments()); + EnchantmentWrapper enchantmentWrapper = getRandomEnchantment( + fishingTreasureBook.getLegalEnchantments()); ItemMeta itemMeta = itemStack.getItemMeta(); - if(itemMeta == null) { + if (itemMeta == null) { return itemStack; } EnchantmentStorageMeta enchantmentStorageMeta = (EnchantmentStorageMeta) itemMeta; - enchantmentStorageMeta.addStoredEnchant(enchantmentWrapper.getEnchantment(), enchantmentWrapper.getEnchantmentLevel(), ExperienceConfig.getInstance().allowUnsafeEnchantments()); + enchantmentStorageMeta.addStoredEnchant( + enchantmentWrapper.getEnchantment(), + enchantmentWrapper.getEnchantmentLevel(), + ExperienceConfig.getInstance().allowUnsafeEnchantments()); itemStack.setItemMeta(enchantmentStorageMeta); return itemStack; } - public static @NotNull EnchantmentWrapper getRandomEnchantment(@NotNull List enchantmentWrappers) { + public static @NotNull EnchantmentWrapper getRandomEnchantment( + @NotNull List enchantmentWrappers) { Collections.shuffle(enchantmentWrappers, Misc.getRandom()); int randomIndex = Misc.getRandom().nextInt(enchantmentWrappers.size()); return enchantmentWrappers.get(randomIndex); } + + /** + * Drop items at a given location. + * + * @param location The location to drop the items at + * @param itemStacks The items to drop + */ + public static void spawnItems(@Nullable Player player, + @NotNull Location location, + @NotNull Collection itemStacks, + @NotNull ItemSpawnReason itemSpawnReason) { + for (ItemStack is : itemStacks) { + spawnItem(player, location, is, itemSpawnReason); + } + } + + /** + * Drop items at a given location. + * + * @param player player to drop the items for + * @param location The location to drop the items at + * @param itemStacks The items to drop + * @param blackList The items to skip + * @param itemSpawnReason the reason for the item drop + */ + public static void spawnItems(@Nullable Player player, + @NotNull Location location, + @NotNull Collection itemStacks, + @NotNull Collection blackList, + @NotNull ItemSpawnReason itemSpawnReason) { + for (ItemStack is : itemStacks) { + // Skip blacklisted items + if (blackList.contains(is.getType())) { + continue; + } + spawnItem(player, location, is, itemSpawnReason); + } + } + + /** + * Drop items at a given location. + * + * @param location The location to drop the items at + * @param is The items to drop + * @param quantity The amount of items to drop + */ + public static void spawnItems(@Nullable Player player, + @NotNull Location location, + @NotNull ItemStack is, + int quantity, + @NotNull ItemSpawnReason itemSpawnReason) { + for (int i = 0; i < quantity; i++) { + spawnItem(player, location, is, itemSpawnReason); + } + } + + /** + * Drop an item at a given location. + * + * @param location The location to drop the item at + * @param itemStack The item to drop + * @param itemSpawnReason the reason for the item drop + * @return Dropped Item entity or null if invalid or cancelled + */ + public static @Nullable Item spawnItem(@Nullable Player player, + @NotNull Location location, + @NotNull ItemStack itemStack, + @NotNull ItemSpawnReason itemSpawnReason) { + if (itemStack.getType() == Material.AIR || location.getWorld() == null) { + return null; + } + + // We can't get the item until we spawn it and we want to make it cancellable, so we have a custom event. + final McMMOItemSpawnEvent event = new McMMOItemSpawnEvent(location, itemStack, + itemSpawnReason, player); + mcMMO.p.getServer().getPluginManager().callEvent(event); + + if (event.isCancelled()) { + return null; + } + + return location.getWorld().dropItem(location, event.getItemStack()); + } + + /** + * Drop an item at a given location. + * + * @param location The location to drop the item at + * @param itemStack The item to drop + * @param itemSpawnReason the reason for the item drop + * @return Dropped Item entity or null if invalid or cancelled + */ + public static @Nullable Item spawnItemNaturally(@Nullable Player player, + @NotNull Location location, + @NotNull ItemStack itemStack, + @NotNull ItemSpawnReason itemSpawnReason) { + if (itemStack.getType() == Material.AIR || location.getWorld() == null) { + return null; + } + + // We can't get the item until we spawn it and we want to make it cancellable, so we have a custom event. + final McMMOItemSpawnEvent event = new McMMOItemSpawnEvent(location, itemStack, + itemSpawnReason, player); + mcMMO.p.getServer().getPluginManager().callEvent(event); + + if (event.isCancelled()) { + return null; + } + + return location.getWorld().dropItemNaturally(location, event.getItemStack()); + } + + /** + * Drop items at a given location. + * + * @param fromLocation The location to drop the items at + * @param is The items to drop + * @param speed the speed that the item should travel + * @param quantity The amount of items to drop + */ + public static void spawnItemsTowardsLocation(@Nullable Player player, + @NotNull Location fromLocation, + @NotNull Location toLocation, + @NotNull ItemStack is, + int quantity, + double speed, + @NotNull ItemSpawnReason itemSpawnReason) { + for (int i = 0; i < quantity; i++) { + spawnItemTowardsLocation(player, fromLocation, toLocation, is, speed, itemSpawnReason); + } + } + + /** + * Drop an item at a given location. This method is fairly expensive as it creates clones of + * everything passed to itself since they are mutable objects + * + * @param fromLocation The location to drop the item at + * @param toLocation The location the item will travel towards + * @param itemToSpawn The item to spawn + * @param speed the speed that the item should travel + * @return Dropped Item entity or null if invalid or cancelled + */ + public static @Nullable Item spawnItemTowardsLocation(@Nullable Player player, + @NotNull Location fromLocation, + @NotNull Location toLocation, + @NotNull ItemStack itemToSpawn, + double speed, + @NotNull ItemSpawnReason itemSpawnReason) { + if (itemToSpawn.getType() == Material.AIR) { + return null; + } + + //Work with fresh copies of everything + ItemStack clonedItem = itemToSpawn.clone(); + Location spawnLocation = fromLocation.clone(); + Location targetLocation = toLocation.clone(); + + if (spawnLocation.getWorld() == null) { + return null; + } + + // We can't get the item until we spawn it and we want to make it cancellable, so we have a custom event. + McMMOItemSpawnEvent event = new McMMOItemSpawnEvent(spawnLocation, clonedItem, + itemSpawnReason, player); + mcMMO.p.getServer().getPluginManager().callEvent(event); + clonedItem = event.getItemStack(); + + //Something cancelled the event so back out + if (event.isCancelled()) { + return null; + } + + //Use the item from the event + Item spawnedItem = spawnLocation.getWorld().dropItem(spawnLocation, clonedItem); + Vector vecFrom = spawnLocation.clone().toVector().clone(); + Vector vecTo = targetLocation.clone().toVector().clone(); + + //Vector which is pointing towards out target location + Vector direction = vecTo.subtract(vecFrom).normalize(); + + //Modify the speed of the vector + direction = direction.multiply(speed); + spawnedItem.setVelocity(direction); + return spawnedItem; + } + + public static void spawnItemsFromCollection(@NotNull Player player, + @NotNull Location location, + @NotNull Collection drops, + @NotNull ItemSpawnReason itemSpawnReason) { + requireNonNull(drops, "drops cannot be null"); + for (ItemStack drop : drops) { + spawnItem(player, location, drop, itemSpawnReason); + } + } + + /** + * Drops only the first n items in a collection Size should always be a positive integer above + * 0 + * + * @param location target drop location + * @param drops collection to iterate over + * @param sizeLimit the number of drops to process + */ + public static void spawnItemsFromCollection(@Nullable Player player, + @NotNull Location location, + @NotNull Collection drops, + @NotNull ItemSpawnReason itemSpawnReason, + int sizeLimit) { + // TODO: This doesn't make much sense, unit test time? + final ItemStack[] arrayDrops = drops.toArray(new ItemStack[0]); + + for (int i = 0; i < sizeLimit - 1; i++) { + spawnItem(player, location, arrayDrops[i], itemSpawnReason); + } + } + + /** + * Spawn items form a collection if conditions are met. Each item is tested against the + * condition and spawned if it passes. + * + * @param potentialItemDrops The collection of items to iterate over, each one is tested and + * spawned if the predicate is true + * @param predicate The predicate to test the item against + * @param itemSpawnReason The reason for the item drop + * @param spawnLocation The location to spawn the item at + * @param player The player to spawn the item for + */ + public static void spawnItemsConditionally(@NotNull Collection potentialItemDrops, + @NotNull Predicate predicate, + @NotNull ItemSpawnReason itemSpawnReason, + @NotNull Location spawnLocation, + @NotNull Player player) { + potentialItemDrops.stream() + .filter(predicate) + .forEach(itemStack -> spawnItem(player, spawnLocation, itemStack, itemSpawnReason)); + } } diff --git a/src/main/java/com/gmail/nossr50/util/LogFilter.java b/src/main/java/com/gmail/nossr50/util/LogFilter.java index 4a1ee3898..25f9885e4 100644 --- a/src/main/java/com/gmail/nossr50/util/LogFilter.java +++ b/src/main/java/com/gmail/nossr50/util/LogFilter.java @@ -1,12 +1,11 @@ package com.gmail.nossr50.util; -import com.gmail.nossr50.mcMMO; +import static com.gmail.nossr50.util.LogUtils.DEBUG_STR; +import com.gmail.nossr50.mcMMO; import java.util.logging.Filter; import java.util.logging.LogRecord; -import static com.gmail.nossr50.util.LogUtils.DEBUG_STR; - public class LogFilter implements Filter { private final boolean debug; diff --git a/src/main/java/com/gmail/nossr50/util/LogUtils.java b/src/main/java/com/gmail/nossr50/util/LogUtils.java index b0c114d00..e9c970465 100644 --- a/src/main/java/com/gmail/nossr50/util/LogUtils.java +++ b/src/main/java/com/gmail/nossr50/util/LogUtils.java @@ -1,8 +1,7 @@ package com.gmail.nossr50.util; -import org.jetbrains.annotations.NotNull; - import java.util.logging.Logger; +import org.jetbrains.annotations.NotNull; public class LogUtils { diff --git a/src/main/java/com/gmail/nossr50/util/MaterialMapStore.java b/src/main/java/com/gmail/nossr50/util/MaterialMapStore.java index 6a54cd608..99ff99c70 100644 --- a/src/main/java/com/gmail/nossr50/util/MaterialMapStore.java +++ b/src/main/java/com/gmail/nossr50/util/MaterialMapStore.java @@ -1,18 +1,14 @@ package com.gmail.nossr50.util; -import org.bukkit.Material; -import org.jetbrains.annotations.NotNull; - import java.util.HashMap; import java.util.HashSet; import java.util.Locale; +import org.bukkit.Material; +import org.jetbrains.annotations.NotNull; /** - * Stores hash tables for item and block names - * This allows for better support across multiple versions of Minecraft - * - * This is a temporary class, mcMMO is spaghetti and I'l clean it up later - * + * Stores hash tables for item and block names This allows for better support across multiple + * versions of Minecraft */ public class MaterialMapStore { @@ -36,6 +32,7 @@ public class MaterialMapStore { private final @NotNull HashSet ironArmor; private final @NotNull HashSet ironTools; private final @NotNull HashSet stringTools; + private final @NotNull HashSet prismarineTools; private final @NotNull HashSet goldArmor; private final @NotNull HashSet goldTools; private final @NotNull HashSet chainmailArmor; @@ -52,8 +49,8 @@ public class MaterialMapStore { private final @NotNull HashSet bows; private final @NotNull HashSet crossbows; private final @NotNull HashSet tools; - private final @NotNull HashSet enchantables; + private final @NotNull HashSet maces; private final @NotNull HashSet ores; private final @NotNull HashSet intendedToolPickAxe; @@ -62,8 +59,7 @@ public class MaterialMapStore { private final @NotNull HashMap tierValue; - public MaterialMapStore() - { + public MaterialMapStore() { abilityBlackList = new HashSet<>(); toolBlackList = new HashSet<>(); mossyWhiteList = new HashSet<>(); @@ -93,6 +89,7 @@ public class MaterialMapStore { bows = new HashSet<>(); crossbows = new HashSet<>(); stringTools = new HashSet<>(); + prismarineTools = new HashSet<>(); tools = new HashSet<>(); swords = new HashSet<>(); @@ -101,6 +98,7 @@ public class MaterialMapStore { shovels = new HashSet<>(); hoes = new HashSet<>(); tridents = new HashSet<>(); + maces = new HashSet<>(); enchantables = new HashSet<>(); @@ -135,8 +133,7 @@ public class MaterialMapStore { fillTierMap(); } - public boolean isMultiBlockPlant(@NotNull Material material) - { + public boolean isMultiBlockPlant(@NotNull Material material) { return multiBlockPlant.contains(material.getKey().getKey()); } @@ -144,63 +141,56 @@ public class MaterialMapStore { return multiBlockHangingPlant.contains(material.getKey().getKey()); } - public boolean isAbilityActivationBlackListed(@NotNull Material material) - { + public boolean isAbilityActivationBlackListed(@NotNull Material material) { return abilityBlackList.contains(material.getKey().getKey()); } - public boolean isToolActivationBlackListed(@NotNull Material material) - { + public boolean isToolActivationBlackListed(@NotNull Material material) { return toolBlackList.contains(material.getKey().getKey()); } - public boolean isMossyWhiteListed(@NotNull Material material) - { + public boolean isMossyWhiteListed(@NotNull Material material) { return mossyWhiteList.contains(material.getKey().getKey()); } - public boolean isTreeFellerDestructible(@NotNull Material material) - { + public boolean isTreeFellerDestructible(@NotNull Material material) { return treeFellerDestructibleWhiteList.contains(material.getKey().getKey()); } - public boolean isHerbalismAbilityWhiteListed(@NotNull Material material) - { + public boolean isHerbalismAbilityWhiteListed(@NotNull Material material) { return herbalismAbilityBlackList.contains(material.getKey().getKey()); } - public boolean isBlockCrackerWhiteListed(@NotNull Material material) - { + public boolean isBlockCrackerWhiteListed(@NotNull Material material) { return blockCrackerWhiteList.contains(material.getKey().getKey()); } - public boolean isShroomyWhiteListed(@NotNull Material material) - { + public boolean isShroomyWhiteListed(@NotNull Material material) { return canMakeShroomyWhiteList.contains(material.getKey().getKey()); } private void fillTierMap() { - for(String id : leatherArmor) { + for (String id : leatherArmor) { tierValue.put(id, 1); } - for(String id : ironArmor) { + for (String id : ironArmor) { tierValue.put(id, 2); } - for(String id : goldArmor) { + for (String id : goldArmor) { tierValue.put(id, 3); } - for(String id : chainmailArmor) { + for (String id : chainmailArmor) { tierValue.put(id, 3); } - for(String id : diamondArmor) { + for (String id : diamondArmor) { tierValue.put(id, 6); } - for(String id : netheriteArmor) { + for (String id : netheriteArmor) { tierValue.put(id, 12); } } @@ -457,6 +447,7 @@ public class MaterialMapStore { enchantables.addAll(tridents); enchantables.addAll(bows); enchantables.addAll(crossbows); + enchantables.addAll(maces); enchantables.add("shears"); enchantables.add("fishing_rod"); @@ -472,7 +463,7 @@ public class MaterialMapStore { fillIronToolsWhiteList(); fillGoldToolsWhiteList(); fillDiamondToolsWhiteList(); - fillnetheriteToolsWhiteList(); + fillNetheriteToolsWhiteList(); fillSwords(); fillAxes(); @@ -480,7 +471,9 @@ public class MaterialMapStore { fillHoes(); fillShovels(); fillTridents(); + fillMaces(); fillStringTools(); + fillPrismarineTools(); fillBows(); fillCrossbows(); @@ -495,6 +488,7 @@ public class MaterialMapStore { tools.addAll(stringTools); tools.addAll(bows); tools.addAll(crossbows); + tools.addAll(maces); } private void fillBows() { @@ -509,6 +503,15 @@ public class MaterialMapStore { stringTools.add("bow"); stringTools.add("fishing_rod"); stringTools.add("carrot_on_a_stick"); + stringTools.add("crossbow"); + } + + private void fillPrismarineTools() { + prismarineTools.add("trident"); + } + + private void fillMaces() { + maces.add("mace"); } private void fillTridents() { @@ -678,7 +681,7 @@ public class MaterialMapStore { diamondTools.add("diamond_shovel"); } - private void fillnetheriteToolsWhiteList() { + private void fillNetheriteToolsWhiteList() { netheriteTools.add("netherite_sword"); netheriteTools.add("netherite_axe"); netheriteTools.add("netherite_hoe"); @@ -764,6 +767,7 @@ public class MaterialMapStore { /** * Checks if a Material is used for Armor + * * @param material target material * @return true if it is used for armor */ @@ -773,6 +777,7 @@ public class MaterialMapStore { /** * Checks if the id provided is used as armor + * * @param id target item id * @return true if the item id matches armor */ @@ -820,6 +825,22 @@ public class MaterialMapStore { 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 isMace(@NotNull Material material) { + return isMace(material.getKey().getKey()); + } + + public boolean isMace(@NotNull String id) { + return maces.contains(id); + } + public boolean isLeatherArmor(@NotNull Material material) { return isLeatherArmor(material.getKey().getKey()); } @@ -964,6 +985,14 @@ public class MaterialMapStore { return stringTools.contains(id); } + public boolean isPrismarineTool(@NotNull Material material) { + return isPrismarineTool(material.getKey().getKey()); + } + + public boolean isPrismarineTool(@NotNull String id) { + return prismarineTools.contains(id); + } + public boolean isGlass(@NotNull Material material) { return glassBlocks.contains(material.getKey().getKey()); } @@ -972,10 +1001,10 @@ public class MaterialMapStore { return foodItemWhiteList.contains(material.getKey().getKey()); } - private void fillMultiBlockPlantSet() - { + private void fillMultiBlockPlantSet() { //Multi-Block Plants multiBlockPlant.add("cactus"); + multiBlockPlant.add("cactus_flower"); multiBlockPlant.add("chorus_plant"); multiBlockPlant.add("chorus_flower"); multiBlockPlant.add("sugar_cane"); @@ -991,37 +1020,36 @@ public class MaterialMapStore { multiBlockHangingPlant.add("weeping_vines_plant"); multiBlockHangingPlant.add("twisted_vines_plant"); multiBlockHangingPlant.add("cave_vines_plant"); + multiBlockHangingPlant.add("pale_hanging_moss"); } - private void fillShroomyWhiteList() - { + private void fillShroomyWhiteList() { canMakeShroomyWhiteList.add("dirt"); canMakeShroomyWhiteList.add("grass_block"); canMakeShroomyWhiteList.add("dirt_path"); } - private void fillBlockCrackerWhiteList() - { + private void fillBlockCrackerWhiteList() { blockCrackerWhiteList.add("stone_bricks"); blockCrackerWhiteList.add("infested_stone_bricks"); } - private void fillHerbalismAbilityBlackList() - { + private void fillHerbalismAbilityBlackList() { herbalismAbilityBlackList.add("dirt"); herbalismAbilityBlackList.add("grass_block"); herbalismAbilityBlackList.add("dirt_path"); herbalismAbilityBlackList.add("farmland"); } - private void fillTreeFellerDestructibleWhiteList() - { + private void fillTreeFellerDestructibleWhiteList() { + treeFellerDestructibleWhiteList.add("pale_hanging_moss"); treeFellerDestructibleWhiteList.add("oak_leaves"); treeFellerDestructibleWhiteList.add("cherry_leaves"); treeFellerDestructibleWhiteList.add("acacia_leaves"); treeFellerDestructibleWhiteList.add("birch_leaves"); treeFellerDestructibleWhiteList.add("dark_oak_leaves"); + treeFellerDestructibleWhiteList.add("pale_oak_leaves"); treeFellerDestructibleWhiteList.add("jungle_leaves"); treeFellerDestructibleWhiteList.add("spruce_leaves"); treeFellerDestructibleWhiteList.add("azalea_leaves"); @@ -1034,8 +1062,7 @@ public class MaterialMapStore { treeFellerDestructibleWhiteList.add("red_mushroom_block"); } - private void fillMossyWhiteList() - { + private void fillMossyWhiteList() { mossyWhiteList.add("cobblestone"); mossyWhiteList.add("dirt"); mossyWhiteList.add("grass_path"); @@ -1043,8 +1070,7 @@ public class MaterialMapStore { mossyWhiteList.add("cobblestone_wall"); } - private void fillAbilityBlackList() - { + private void fillAbilityBlackList() { abilityBlackList.add("warped_fence_gate"); abilityBlackList.add("crimson_fence_gate"); abilityBlackList.add("warped_pressure_plate"); @@ -1081,6 +1107,7 @@ public class MaterialMapStore { abilityBlackList.add("oak_fence_gate"); abilityBlackList.add("acacia_fence_gate"); abilityBlackList.add("dark_oak_fence_gate"); + abilityBlackList.add("pale_oak_fence_gate"); abilityBlackList.add("spruce_fence_gate"); abilityBlackList.add("birch_fence_gate"); abilityBlackList.add("jungle_fence_gate"); @@ -1093,11 +1120,13 @@ public class MaterialMapStore { abilityBlackList.add("birch_button"); abilityBlackList.add("acacia_button"); abilityBlackList.add("dark_oak_button"); + abilityBlackList.add("pale_oak_button"); abilityBlackList.add("jungle_button"); abilityBlackList.add("spruce_button"); abilityBlackList.add("acacia_trapdoor"); abilityBlackList.add("birch_trapdoor"); abilityBlackList.add("dark_oak_trapdoor"); + abilityBlackList.add("pale_oak_trapdoor"); abilityBlackList.add("jungle_trapdoor"); abilityBlackList.add("oak_trapdoor"); abilityBlackList.add("spruce_trapdoor"); @@ -1106,7 +1135,9 @@ public class MaterialMapStore { abilityBlackList.add("birch_sign"); abilityBlackList.add("birch_wall_sign"); abilityBlackList.add("dark_oak_sign"); + abilityBlackList.add("pale_oak_sign"); abilityBlackList.add("dark_oak_wall_sign"); + abilityBlackList.add("pale_oak_wall_sign"); abilityBlackList.add("jungle_sign"); abilityBlackList.add("jungle_wall_sign"); abilityBlackList.add("spruce_sign"); @@ -1127,9 +1158,11 @@ public class MaterialMapStore { abilityBlackList.add("birch_door"); abilityBlackList.add("jungle_door"); abilityBlackList.add("dark_oak_door"); + abilityBlackList.add("pale_oak_door"); abilityBlackList.add("oak_fence"); abilityBlackList.add("acacia_fence"); abilityBlackList.add("dark_oak_fence"); + abilityBlackList.add("pale_oak_fence"); abilityBlackList.add("birch_fence"); abilityBlackList.add("jungle_fence"); abilityBlackList.add("spruce_fence"); @@ -1170,9 +1203,8 @@ public class MaterialMapStore { abilityBlackList.add("lodestone"); abilityBlackList.add("respawn_anchor"); } - - private void fillToolBlackList() - { + + private void fillToolBlackList() { toolBlackList.add("chiseled_bookshelf"); toolBlackList.add("black_bed"); toolBlackList.add("blue_bed"); @@ -1200,6 +1232,7 @@ public class MaterialMapStore { toolBlackList.add("oak_fence_gate"); toolBlackList.add("acacia_fence_gate"); toolBlackList.add("dark_oak_fence_gate"); + toolBlackList.add("pale_oak_fence_gate"); toolBlackList.add("spruce_fence_gate"); toolBlackList.add("birch_fence_gate"); toolBlackList.add("jungle_fence_gate"); @@ -1212,11 +1245,13 @@ public class MaterialMapStore { toolBlackList.add("birch_button"); toolBlackList.add("acacia_button"); toolBlackList.add("dark_oak_button"); + toolBlackList.add("pale_oak_button"); toolBlackList.add("jungle_button"); toolBlackList.add("spruce_button"); toolBlackList.add("acacia_trapdoor"); toolBlackList.add("birch_trapdoor"); toolBlackList.add("dark_oak_trapdoor"); + toolBlackList.add("pale_oak_trapdoor"); toolBlackList.add("jungle_trapdoor"); toolBlackList.add("oak_trapdoor"); toolBlackList.add("spruce_trapdoor"); @@ -1234,9 +1269,11 @@ public class MaterialMapStore { toolBlackList.add("birch_door"); toolBlackList.add("jungle_door"); toolBlackList.add("dark_oak_door"); + toolBlackList.add("pale_oak_door"); toolBlackList.add("oak_fence"); toolBlackList.add("acacia_fence"); toolBlackList.add("dark_oak_fence"); + toolBlackList.add("pale_oak_fence"); toolBlackList.add("birch_fence"); toolBlackList.add("jungle_fence"); toolBlackList.add("spruce_fence"); @@ -1265,8 +1302,11 @@ public class MaterialMapStore { toolBlackList.add("birch_hanging_sign"); toolBlackList.add("birch_wall_sign"); toolBlackList.add("dark_oak_sign"); + toolBlackList.add("pale_oak_sign"); toolBlackList.add("dark_oak_hanging_sign"); + toolBlackList.add("pale_oak_hanging_sign"); toolBlackList.add("dark_oak_wall_sign"); + toolBlackList.add("pale_oak_wall_sign"); toolBlackList.add("jungle_sign"); toolBlackList.add("jungle_hanging_sign"); toolBlackList.add("jungle_wall_sign"); @@ -1286,7 +1326,9 @@ public class MaterialMapStore { toolBlackList.add("stripped_birch_log"); toolBlackList.add("stripped_birch_wood"); toolBlackList.add("stripped_dark_oak_log"); + toolBlackList.add("stripped_pale_oak_log"); toolBlackList.add("stripped_dark_oak_wood"); + toolBlackList.add("stripped_pale_oak_wood"); toolBlackList.add("stripped_jungle_log"); toolBlackList.add("stripped_jungle_wood"); toolBlackList.add("stripped_oak_log"); @@ -1301,7 +1343,9 @@ public class MaterialMapStore { toolBlackList.add("birch_log"); toolBlackList.add("birch_wood"); toolBlackList.add("dark_oak_log"); + toolBlackList.add("pale_oak_log"); toolBlackList.add("dark_oak_wood"); + toolBlackList.add("pale_oak_wood"); toolBlackList.add("jungle_log"); toolBlackList.add("jungle_wood"); toolBlackList.add("oak_log"); @@ -1350,8 +1394,7 @@ public class MaterialMapStore { return tierValue.getOrDefault(id, 1); //1 for unknown items } - private void addToHashSet(@NotNull String string, @NotNull HashSet stringHashSet) - { + private void addToHashSet(@NotNull String string, @NotNull HashSet stringHashSet) { stringHashSet.add(string.toLowerCase(Locale.ENGLISH)); } } diff --git a/src/main/java/com/gmail/nossr50/util/MaterialUtils.java b/src/main/java/com/gmail/nossr50/util/MaterialUtils.java index 4a38eba2f..3715249e7 100644 --- a/src/main/java/com/gmail/nossr50/util/MaterialUtils.java +++ b/src/main/java/com/gmail/nossr50/util/MaterialUtils.java @@ -4,9 +4,10 @@ import com.gmail.nossr50.mcMMO; import org.bukkit.Material; public final class MaterialUtils { - private MaterialUtils() {} + private MaterialUtils() { + } - protected static boolean isOre(Material data) { + static boolean isOre(Material data) { return mcMMO.getMaterialMapStore().isOre(data.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 090e04d17..e0d4d54a4 100644 --- a/src/main/java/com/gmail/nossr50/util/MetadataConstants.java +++ b/src/main/java/com/gmail/nossr50/util/MetadataConstants.java @@ -1,28 +1,51 @@ package com.gmail.nossr50.util; -import com.google.common.collect.ImmutableSet; +import java.util.List; +import java.util.Set; import org.bukkit.metadata.FixedMetadataValue; import org.jetbrains.annotations.NotNull; -import java.util.HashSet; - /** * Stores our constants related to metadata */ public class MetadataConstants { - /* Metadata Values - * Take great care if you ever modify the value of these keys - */ + public static final @NotNull Set MOB_METADATA_KEYS = Set.of( + MetadataConstants.METADATA_KEY_MOB_SPAWNER_MOB, + MetadataConstants.METADATA_KEY_EGG_MOB, + MetadataConstants.METADATA_KEY_NETHER_PORTAL_MOB, + MetadataConstants.METADATA_KEY_COTW_SUMMONED_MOB, + MetadataConstants.METADATA_KEY_PLAYER_BRED_MOB, + MetadataConstants.METADATA_KEY_PLAYER_TAMED_MOB, + MetadataConstants.METADATA_KEY_EXPLOITED_ENDERMEN, + MetadataConstants.METADATA_KEY_CUSTOM_NAME, + MetadataConstants.METADATA_KEY_RUPTURE, + MetadataConstants.METADATA_KEY_EXPLOSION_FROM_RUPTURE, + MetadataConstants.METADATA_KEY_OLD_NAME_KEY, + MetadataConstants.METADATA_KEY_DODGE_TRACKER + ); + + public static final @NotNull List ARROW_METADATA_KEYS = List.of( + MetadataConstants.METADATA_KEY_INF_ARROW, + MetadataConstants.METADATA_KEY_BOW_FORCE, + MetadataConstants.METADATA_KEY_ARROW_DISTANCE, + MetadataConstants.METADATA_KEY_SPAWNED_ARROW, + MetadataConstants.METADATA_KEY_MULTI_SHOT_ARROW, + MetadataConstants.METADATA_KEY_BOUNCE_COUNT, + MetadataConstants.METADATA_KEY_CROSSBOW_PROJECTILE + ); + public static final @NotNull String METADATA_KEY_REPLANT = "mcMMO: Recently Replanted"; + public static final @NotNull String METADATA_KEY_CROSSBOW_PROJECTILE = "mcMMO: Crossbow Projectile"; + 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"; public static final @NotNull String METADATA_KEY_DODGE_TRACKER = "mcMMO: Dodge Tracker"; public static final @NotNull String METADATA_KEY_CUSTOM_DAMAGE = "mcMMO: Custom Damage"; public static final @NotNull String METADATA_KEY_TRAVELING_BLOCK = "mcMMO: Traveling Block"; - public static final @NotNull String METADATA_KEY_PISTON_TRACKING = "mcMMO: Piston Tracking"; public static final @NotNull String METADATA_KEY_TRACKED_TNT = "mcMMO: Tracked TNT"; public static final @NotNull String METADATA_KEY_NAME_VISIBILITY = "mcMMO: Name Visibility"; - public static final @NotNull String METADATA_KEY_TRACKED_ITEM = "mcMMO: Tracked Item"; public static final @NotNull String METADATA_KEY_INF_ARROW = "mcMMO: Infinite Arrow"; public static final @NotNull String METADATA_KEY_TRACKED_ARROW = "mcMMO: Tracked Arrow"; public static final @NotNull String METADATA_KEY_BOW_FORCE = "mcMMO: Bow Force"; @@ -31,8 +54,9 @@ public class MetadataConstants { public static final @NotNull String METADATA_KEY_DISARMED_ITEM = "mcMMO: Disarmed Item"; public static final @NotNull String METADATA_KEY_PLAYER_DATA = "mcMMO: Player Data"; public static final @NotNull String METADATA_KEY_DATABASE_COMMAND = "mcMMO: Processing Database Command"; - public static final @NotNull String METADATA_KEY_FURNACE_UUID_MOST_SIG = "furnace_uuid_most_sig"; - public static final @NotNull String METADATA_KEY_FURNACE_UUID_LEAST_SIG = "furnace_uuid_least_sig"; + // the value of these two keys have "furnace" to keep supporting legacy data + public static final @NotNull String METADATA_KEY_CONTAINER_UUID_MOST_SIG = "furnace_uuid_most_sig"; + public static final @NotNull String METADATA_KEY_CONTAINER_UUID_LEAST_SIG = "furnace_uuid_least_sig"; public static final @NotNull String METADATA_KEY_SUPER_ABILITY_BOOSTED_ITEM = "super_ability_boosted"; public static final @NotNull String METADATA_KEY_MOB_SPAWNER_MOB = "mcmmo_mob_spawner_mob"; public static final @NotNull String METADATA_KEY_EGG_MOB = "mcmmo_egg_mob"; @@ -45,28 +69,6 @@ public class MetadataConstants { public static final @NotNull String METADATA_KEY_CUSTOM_NAME = "mcmmo_custom_name"; public static final @NotNull String METADATA_KEY_OLD_NAME_KEY = "mcmmo_old_name"; public static final @NotNull String METADATA_KEY_RUPTURE = "mcmmo_rupture"; - public static final byte SIMPLE_FLAG_VALUE = (byte) 0x1; - - public static final @NotNull ImmutableSet MOB_METADATA_KEYS; - public static FixedMetadataValue MCMMO_METADATA_VALUE; - - static { - HashSet temp = new HashSet<>(); - temp.add(MetadataConstants.METADATA_KEY_MOB_SPAWNER_MOB); - temp.add(MetadataConstants.METADATA_KEY_EGG_MOB); - temp.add(MetadataConstants.METADATA_KEY_NETHER_PORTAL_MOB); - temp.add(MetadataConstants.METADATA_KEY_COTW_SUMMONED_MOB); - temp.add(MetadataConstants.METADATA_KEY_PLAYER_BRED_MOB); - temp.add(MetadataConstants.METADATA_KEY_PLAYER_TAMED_MOB); - temp.add(MetadataConstants.METADATA_KEY_EXPLOITED_ENDERMEN); - temp.add(MetadataConstants.METADATA_KEY_CUSTOM_NAME); - temp.add(MetadataConstants.METADATA_KEY_RUPTURE); - temp.add(MetadataConstants.METADATA_KEY_EXPLOSION_FROM_RUPTURE); - temp.add(MetadataConstants.METADATA_KEY_OLD_NAME_KEY); - temp.add(MetadataConstants.METADATA_KEY_DODGE_TRACKER); - - MOB_METADATA_KEYS = ImmutableSet.copyOf(temp); - } } diff --git a/src/main/java/com/gmail/nossr50/util/MetadataService.java b/src/main/java/com/gmail/nossr50/util/MetadataService.java new file mode 100644 index 000000000..f42b8ce85 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/util/MetadataService.java @@ -0,0 +1,52 @@ +package com.gmail.nossr50.util; + +import com.gmail.nossr50.mcMMO; +import org.bukkit.NamespacedKey; +import org.jetbrains.annotations.NotNull; + +public final class MetadataService { + static final @NotNull NamespacedKey NSK_SUPER_ABILITY_BOOSTED_ITEM; + static final @NotNull NamespacedKey NSK_MOB_SPAWNER_MOB; + static final @NotNull NamespacedKey NSK_EGG_MOB; + static final @NotNull NamespacedKey NSK_NETHER_GATE_MOB; + static final @NotNull NamespacedKey NSK_COTW_SUMMONED_MOB; + static final @NotNull NamespacedKey NSK_PLAYER_BRED_MOB; + static final @NotNull NamespacedKey NSK_PLAYER_TAMED_MOB; + static final @NotNull NamespacedKey NSK_VILLAGER_TRADE_ORIGIN_ITEM; + static final @NotNull NamespacedKey NSK_EXPLOITED_ENDERMEN; + static final @NotNull NamespacedKey NSK_CONTAINER_UUID_MOST_SIG; + static final @NotNull NamespacedKey NSK_CONTAINER_UUID_LEAST_SIG; + + private MetadataService() { + // private ctor + } + + static { + NSK_SUPER_ABILITY_BOOSTED_ITEM = getNamespacedKey( + MetadataConstants.METADATA_KEY_SUPER_ABILITY_BOOSTED_ITEM); + NSK_MOB_SPAWNER_MOB = getNamespacedKey(MetadataConstants.METADATA_KEY_MOB_SPAWNER_MOB); + NSK_EGG_MOB = getNamespacedKey(MetadataConstants.METADATA_KEY_EGG_MOB); + NSK_NETHER_GATE_MOB = getNamespacedKey(MetadataConstants.METADATA_KEY_NETHER_PORTAL_MOB); + NSK_COTW_SUMMONED_MOB = getNamespacedKey(MetadataConstants.METADATA_KEY_COTW_SUMMONED_MOB); + NSK_PLAYER_BRED_MOB = getNamespacedKey(MetadataConstants.METADATA_KEY_PLAYER_BRED_MOB); + NSK_PLAYER_TAMED_MOB = getNamespacedKey(MetadataConstants.METADATA_KEY_PLAYER_TAMED_MOB); + NSK_VILLAGER_TRADE_ORIGIN_ITEM = getNamespacedKey( + MetadataConstants.METADATA_KEY_VILLAGER_TRADE_ORIGIN_ITEM); + NSK_EXPLOITED_ENDERMEN = getNamespacedKey( + MetadataConstants.METADATA_KEY_EXPLOITED_ENDERMEN); + NSK_CONTAINER_UUID_MOST_SIG = getNamespacedKey( + MetadataConstants.METADATA_KEY_CONTAINER_UUID_MOST_SIG); + NSK_CONTAINER_UUID_LEAST_SIG = getNamespacedKey( + MetadataConstants.METADATA_KEY_CONTAINER_UUID_LEAST_SIG); + } + + /** + * Helper method to simplify generating namespaced keys + * + * @param key the {@link String} value of the key + * @return the generated {@link NamespacedKey} + */ + public static @NotNull NamespacedKey getNamespacedKey(@NotNull String key) { + return new NamespacedKey(mcMMO.p, key); + } +} diff --git a/src/main/java/com/gmail/nossr50/util/Misc.java b/src/main/java/com/gmail/nossr50/util/Misc.java index bbd9bb999..c3603f8f4 100644 --- a/src/main/java/com/gmail/nossr50/util/Misc.java +++ b/src/main/java/com/gmail/nossr50/util/Misc.java @@ -1,25 +1,24 @@ package com.gmail.nossr50.util; -import com.gmail.nossr50.api.ItemSpawnReason; import com.gmail.nossr50.datatypes.player.McMMOPlayer; -import com.gmail.nossr50.events.items.McMMOItemSpawnEvent; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.runnables.player.PlayerProfileLoadingTask; import com.gmail.nossr50.util.player.UserManager; import com.google.common.collect.ImmutableSet; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.block.BlockState; -import org.bukkit.entity.*; -import org.bukkit.inventory.ItemStack; -import org.bukkit.util.Vector; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.Collection; import java.util.Locale; import java.util.Random; import java.util.Set; +import org.bukkit.Location; +import org.bukkit.block.Block; +import org.bukkit.block.BlockState; +import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.ExperienceOrb; +import org.bukkit.entity.NPC; +import org.bukkit.entity.Player; +import org.bukkit.entity.Villager; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; public final class Misc { private static final @NotNull Random random = new Random(); @@ -41,22 +40,30 @@ public final class Misc { public static final float LEVELUP_PITCH = 0.5F; // Reduced to differentiate between vanilla level-up public static final float LEVELUP_VOLUME = 0.75F * Config.getInstance().getMasterVolume(); // Use max volume always*/ - public static final @NotNull Set modNames = ImmutableSet.of("LOTR", "BUILDCRAFT", "ENDERIO", "ENHANCEDBIOMES", "IC2", "METALLURGY", "FORESTRY", "GALACTICRAFT", "RAILCRAFT", "TWILIGHTFOREST", "THAUMCRAFT", "GRAVESTONEMOD", "GROWTHCRAFT", "ARCTICMOBS", "DEMONMOBS", "INFERNOMOBS", "SWAMPMOBS", "MARICULTURE", "MINESTRAPPOLATION"); + public static final @NotNull Set modNames = ImmutableSet.of("LOTR", "BUILDCRAFT", + "ENDERIO", + "ENHANCEDBIOMES", "IC2", "METALLURGY", "FORESTRY", "GALACTICRAFT", "RAILCRAFT", + "TWILIGHTFOREST", + "THAUMCRAFT", "GRAVESTONEMOD", "GROWTHCRAFT", "ARCTICMOBS", "DEMONMOBS", "INFERNOMOBS", + "SWAMPMOBS", + "MARICULTURE", "MINESTRAPPOLATION"); - private Misc() {} + private Misc() { + } /** - * Determines if an entity is an NPC but not a villager - * This method aims to establish compatibility between mcMMO and other plugins which create "NPCs" + * Determines if an entity is an NPC but not a villager This method aims to establish + * compatibility between mcMMO and other plugins which create "NPCs" + *

+ * It does this by checking the following 1) The entity is not a Villager 2) The entity can be + * considered an NPC + *

+ * In this context, an NPC is a bit hard to define. Various plugins determine what an NPC is in + * different ways. * - * It does this by checking the following - * 1) The entity is not a Villager - * 2) The entity can be considered an NPC - * - * In this context, an NPC is a bit hard to define. Various plugins determine what an NPC is in different ways. - * @see Misc::isNPCIncludingVillagers * @param entity target entity * @return true if the entity is not a Villager and is not a "NPC" + * @see Misc::isNPCIncludingVillagers */ public static boolean isNPCEntityExcludingVillagers(@NotNull Entity entity) { return (!isVillager(entity) @@ -90,163 +97,31 @@ public final class Misc { * @param first The first location * @param second The second location * @param maxDistance The max distance apart - * @return true if the distance between {@code first} and {@code second} is less than {@code maxDistance}, false otherwise + * @return true if the distance between {@code first} and {@code second} is less than + * {@code maxDistance}, false otherwise */ - public static boolean isNear(@NotNull Location first, @NotNull Location second, double maxDistance) { - return (first.getWorld() == second.getWorld()) && (first.distanceSquared(second) < (maxDistance * maxDistance) || maxDistance == 0); + public static boolean isNear(@NotNull Location first, @NotNull Location second, + double maxDistance) { + return (first.getWorld() == second.getWorld()) && ( + first.distanceSquared(second) < (maxDistance * maxDistance) || maxDistance == 0); } /** * Get the center of the given block. - * + * * @param blockState The {@link BlockState} of the block * @return A {@link Location} lying at the center of the block */ public static Location getBlockCenter(BlockState blockState) { - return blockState.getLocation().add(0.5, 0.5, 0.5); + return getBlockCenter(blockState.getLocation()); } - public static void spawnItemsFromCollection(@NotNull Player player, @NotNull Location location, @NotNull Collection drops, @NotNull ItemSpawnReason itemSpawnReason) { - for (ItemStack drop : drops) { - spawnItem(player, location, drop, itemSpawnReason); - } + public static Location getBlockCenter(Block block) { + return getBlockCenter(block.getLocation()); } - /** - * Drops only the first n items in a collection - * Size should always be a positive integer above 0 - * - * @param location target drop location - * @param drops collection to iterate over - * @param sizeLimit the number of drops to process - */ - public static void spawnItemsFromCollection(@Nullable Player player, @NotNull Location location, @NotNull Collection drops, @NotNull ItemSpawnReason itemSpawnReason, int sizeLimit) { - ItemStack[] arrayDrops = drops.toArray(new ItemStack[0]); - - for(int i = 0; i < sizeLimit-1; i++) { - spawnItem(player, location, arrayDrops[i], itemSpawnReason); - } - } - - /** - * Drop items at a given location. - * - * @param location The location to drop the items at - * @param is The items to drop - * @param quantity The amount of items to drop - */ - public static void spawnItems(@Nullable Player player, @NotNull Location location, @NotNull ItemStack is, int quantity, @NotNull ItemSpawnReason itemSpawnReason) { - for (int i = 0; i < quantity; i++) { - spawnItem(player, location, is, itemSpawnReason); - } - } - - /** - * Drop an item at a given location. - * - * @param location The location to drop the item at - * @param itemStack The item to drop - * @param itemSpawnReason the reason for the item drop - * @return Dropped Item entity or null if invalid or cancelled - */ - public static @Nullable Item spawnItem(@Nullable Player player, @NotNull Location location, @NotNull ItemStack itemStack, @NotNull ItemSpawnReason itemSpawnReason) { - if (itemStack.getType() == Material.AIR || location.getWorld() == null) { - return null; - } - - // We can't get the item until we spawn it and we want to make it cancellable, so we have a custom event. - McMMOItemSpawnEvent event = new McMMOItemSpawnEvent(location, itemStack, itemSpawnReason, player); - mcMMO.p.getServer().getPluginManager().callEvent(event); - - if (event.isCancelled()) { - return null; - } - - return location.getWorld().dropItem(location, itemStack); - } - - /** - * Drop an item at a given location. - * - * @param location The location to drop the item at - * @param itemStack The item to drop - * @param itemSpawnReason the reason for the item drop - * @return Dropped Item entity or null if invalid or cancelled - */ - public static @Nullable Item spawnItemNaturally(@Nullable Player player, @NotNull Location location, @NotNull ItemStack itemStack, @NotNull ItemSpawnReason itemSpawnReason) { - if (itemStack.getType() == Material.AIR || location.getWorld() == null) { - return null; - } - - // We can't get the item until we spawn it and we want to make it cancellable, so we have a custom event. - McMMOItemSpawnEvent event = new McMMOItemSpawnEvent(location, itemStack, itemSpawnReason, player); - mcMMO.p.getServer().getPluginManager().callEvent(event); - - if (event.isCancelled()) { - return null; - } - - return location.getWorld().dropItemNaturally(location, itemStack); - } - - /** - * Drop items at a given location. - * - * @param fromLocation The location to drop the items at - * @param is The items to drop - * @param speed the speed that the item should travel - * @param quantity The amount of items to drop - */ - public static void spawnItemsTowardsLocation(@Nullable Player player, @NotNull Location fromLocation, @NotNull Location toLocation, @NotNull ItemStack is, int quantity, double speed, @NotNull ItemSpawnReason itemSpawnReason) { - for (int i = 0; i < quantity; i++) { - spawnItemTowardsLocation(player, fromLocation, toLocation, is, speed, itemSpawnReason); - } - } - - /** - * Drop an item at a given location. - * This method is fairly expensive as it creates clones of everything passed to itself since they are mutable objects - * - * @param fromLocation The location to drop the item at - * @param toLocation The location the item will travel towards - * @param itemToSpawn The item to spawn - * @param speed the speed that the item should travel - * @return Dropped Item entity or null if invalid or cancelled - */ - public static @Nullable Item spawnItemTowardsLocation(@Nullable Player player, @NotNull Location fromLocation, @NotNull Location toLocation, @NotNull ItemStack itemToSpawn, double speed, @NotNull ItemSpawnReason itemSpawnReason) { - if (itemToSpawn.getType() == Material.AIR) { - return null; - } - - //Work with fresh copies of everything - ItemStack clonedItem = itemToSpawn.clone(); - Location spawnLocation = fromLocation.clone(); - Location targetLocation = toLocation.clone(); - - if(spawnLocation.getWorld() == null) - return null; - - // We can't get the item until we spawn it and we want to make it cancellable, so we have a custom event. - McMMOItemSpawnEvent event = new McMMOItemSpawnEvent(spawnLocation, clonedItem, itemSpawnReason, player); - mcMMO.p.getServer().getPluginManager().callEvent(event); - - //Something cancelled the event so back out - if (event.isCancelled()) { - return null; - } - - //Use the item from the event - Item spawnedItem = spawnLocation.getWorld().dropItem(spawnLocation, clonedItem); - Vector vecFrom = spawnLocation.clone().toVector().clone(); - Vector vecTo = targetLocation.clone().toVector().clone(); - - //Vector which is pointing towards out target location - Vector direction = vecTo.subtract(vecFrom).normalize(); - - //Modify the speed of the vector - direction = direction.multiply(speed); - spawnedItem.setVelocity(direction); - return spawnedItem; + public static Location getBlockCenter(Location location) { + return location.clone().add(0.5, 0.5, 0.5); } public static void profileCleanup(@NotNull String playerName) { @@ -254,13 +129,18 @@ public final class Misc { if (player != null) { UserManager.remove(player); - mcMMO.p.getFoliaLib().getImpl().runLaterAsync(new PlayerProfileLoadingTask(player), 1); // 1 Tick delay to ensure the player is marked as online before we begin loading + mcMMO.p.getFoliaLib().getScheduler().runLaterAsync(new PlayerProfileLoadingTask(player), + 1); // 1 Tick delay to ensure the player is marked as online before we begin loading } } public static void printProgress(int convertedUsers, int progressInterval, long startMillis) { if ((convertedUsers % progressInterval) == 0) { - mcMMO.p.getLogger().info(String.format("Conversion progress: %d users at %.2f users/second", convertedUsers, convertedUsers / (double) ((System.currentTimeMillis() - startMillis) / TIME_CONVERSION_FACTOR))); + mcMMO.p.getLogger() + .info(String.format("Conversion progress: %d users at %.2f users/second", + convertedUsers, + convertedUsers / (double) ((System.currentTimeMillis() - startMillis) + / TIME_CONVERSION_FACTOR))); } } @@ -308,7 +188,8 @@ public final class Misc { * @return true if the player is the party leader */ public static boolean isPartyLeader(@NotNull McMMOPlayer mmoPlayer) { - return mmoPlayer.getParty().getLeader().getUniqueId().equals(mmoPlayer.getPlayer().getUniqueId()); + return mmoPlayer.getParty().getLeader().getUniqueId() + .equals(mmoPlayer.getPlayer().getUniqueId()); } // public static void spawnExperienceOrb(@NotNull Location location, int orbAmount, int experienceValue) { @@ -318,16 +199,18 @@ public final class Misc { // } public static void spawnExperienceOrb(@NotNull Location location, int experienceValue) { - if(location.getWorld() == null) + if (location.getWorld() == null) { return; + } - ExperienceOrb experienceOrb = (ExperienceOrb) location.getWorld().spawnEntity(location, EntityType.EXPERIENCE_ORB); + ExperienceOrb experienceOrb = (ExperienceOrb) location.getWorld() + .spawnEntity(location, EntityType.EXPERIENCE_ORB); experienceOrb.setExperience(experienceValue); } private static class SpawnOrbTask implements Runnable { private final Location location; - private int orbExpValue; + private final int orbExpValue; private SpawnOrbTask(Location location, int orbExpValue) { this.location = location; @@ -336,11 +219,35 @@ public final class Misc { @Override public void run() { - if(location == null || location.getWorld() == null) + if (location == null || location.getWorld() == null) { return; + } - ExperienceOrb experienceOrb = (ExperienceOrb) location.getWorld().spawnEntity(location, EntityType.EXPERIENCE_ORB); + ExperienceOrb experienceOrb = (ExperienceOrb) location.getWorld() + .spawnEntity(location, EntityType.EXPERIENCE_ORB); 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/MobHealthbarUtils.java b/src/main/java/com/gmail/nossr50/util/MobHealthbarUtils.java index 3d956afe7..aa24e4ba3 100644 --- a/src/main/java/com/gmail/nossr50/util/MobHealthbarUtils.java +++ b/src/main/java/com/gmail/nossr50/util/MobHealthbarUtils.java @@ -13,7 +13,8 @@ import org.bukkit.event.entity.EntityDamageEvent; import org.bukkit.metadata.FixedMetadataValue; public final class MobHealthbarUtils { - private MobHealthbarUtils() {} + private MobHealthbarUtils() { + } /** * Fix issues with death messages caused by the mob healthbars. @@ -24,18 +25,23 @@ public final class MobHealthbarUtils { */ 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"; + 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); } /** * Handle the creation of mob healthbars. - * @param target the targetted entity + * + * @param target the targetted entity * @param damage damage done by the attack triggering this */ public static void handleMobHealthbars(LivingEntity target, double damage, mcMMO plugin) { - if (mcMMO.isHealthBarPluginEnabled() || !mcMMO.p.getGeneralConfig().getMobHealthbarEnabled()) { + if (mcMMO.isHealthBarPluginEnabled() || !mcMMO.p.getGeneralConfig() + .getMobHealthbarEnabled()) { return; } @@ -54,15 +60,18 @@ public final class MobHealthbarUtils { /* * Store the name in metadata */ - if(target.getMetadata(MetadataConstants.METADATA_KEY_OLD_NAME_KEY).size() <= 0) - target.setMetadata(MetadataConstants.METADATA_KEY_OLD_NAME_KEY, new OldName(originalName, plugin)); + if (target.getMetadata(MetadataConstants.METADATA_KEY_OLD_NAME_KEY).size() <= 0) { + target.setMetadata(MetadataConstants.METADATA_KEY_OLD_NAME_KEY, + new OldName(originalName, plugin)); + } if (oldName == null) { oldName = ""; } boolean oldNameVisible = target.isCustomNameVisible(); - String newName = createHealthDisplay(mcMMO.p.getGeneralConfig().getMobHealthbarDefault(), target, damage); + String newName = createHealthDisplay(mcMMO.p.getGeneralConfig().getMobHealthbarDefault(), + target, damage); target.setCustomName(newName); target.setCustomNameVisible(true); @@ -70,22 +79,30 @@ public final class MobHealthbarUtils { int displayTime = mcMMO.p.getGeneralConfig().getMobHealthbarTime(); if (displayTime != -1) { - boolean updateName = !ChatColor.stripColor(oldName).equalsIgnoreCase(ChatColor.stripColor(newName)); + boolean updateName = !ChatColor.stripColor(oldName) + .equalsIgnoreCase(ChatColor.stripColor(newName)); if (updateName) { - target.setMetadata(MetadataConstants.METADATA_KEY_CUSTOM_NAME, new FixedMetadataValue(mcMMO.p, oldName)); - target.setMetadata(MetadataConstants.METADATA_KEY_NAME_VISIBILITY, new FixedMetadataValue(mcMMO.p, oldNameVisible)); - } - else if (!target.hasMetadata(MetadataConstants.METADATA_KEY_CUSTOM_NAME)) { - target.setMetadata(MetadataConstants.METADATA_KEY_CUSTOM_NAME, new FixedMetadataValue(mcMMO.p, "")); - target.setMetadata(MetadataConstants.METADATA_KEY_NAME_VISIBILITY, new FixedMetadataValue(mcMMO.p, false)); + target.setMetadata(MetadataConstants.METADATA_KEY_CUSTOM_NAME, + new FixedMetadataValue(mcMMO.p, oldName)); + target.setMetadata(MetadataConstants.METADATA_KEY_NAME_VISIBILITY, + new FixedMetadataValue(mcMMO.p, oldNameVisible)); + } else if (!target.hasMetadata(MetadataConstants.METADATA_KEY_CUSTOM_NAME)) { + target.setMetadata(MetadataConstants.METADATA_KEY_CUSTOM_NAME, + new FixedMetadataValue(mcMMO.p, "")); + target.setMetadata(MetadataConstants.METADATA_KEY_NAME_VISIBILITY, + new FixedMetadataValue(mcMMO.p, false)); } - mcMMO.p.getFoliaLib().getImpl().runAtEntityLater(target, new MobHealthDisplayUpdaterTask(target), (long) displayTime * Misc.TICK_CONVERSION_FACTOR); // Clear health display after 3 seconds + mcMMO.p.getFoliaLib().getScheduler() + .runAtEntityLater(target, new MobHealthDisplayUpdaterTask(target), + (long) displayTime + * Misc.TICK_CONVERSION_FACTOR); // Clear health display after 3 seconds } } - private static String createHealthDisplay(MobHealthbarType mobHealthbarType, LivingEntity entity, double damage) { + private static String createHealthDisplay(MobHealthbarType mobHealthbarType, + LivingEntity entity, double damage) { double maxHealth = entity.getMaxHealth(); double currentHealth = Math.max(entity.getHealth() - damage, 0); double healthPercentage = (currentHealth / maxHealth) * 100.0D; @@ -106,20 +123,15 @@ public final class MobHealthbarUtils { if (healthPercentage >= 85) { color = ChatColor.DARK_GREEN; - } - else if (healthPercentage >= 70) { + } else if (healthPercentage >= 70) { color = ChatColor.GREEN; - } - else if (healthPercentage >= 55) { + } else if (healthPercentage >= 55) { color = ChatColor.GOLD; - } - else if (healthPercentage >= 40) { + } else if (healthPercentage >= 40) { color = ChatColor.YELLOW; - } - else if (healthPercentage >= 25) { + } else if (healthPercentage >= 25) { color = ChatColor.RED; - } - else if (healthPercentage >= 0) { + } else if (healthPercentage >= 0) { color = ChatColor.DARK_RED; } @@ -130,7 +142,8 @@ public final class MobHealthbarUtils { return null; } - int coloredDisplay = (int) Math.max(Math.ceil(fullDisplay * (healthPercentage / 100.0D)), 0.5); + int coloredDisplay = (int) Math.max(Math.ceil(fullDisplay * (healthPercentage / 100.0D)), + 0.5); int grayDisplay = fullDisplay - coloredDisplay; StringBuilder healthbar = new StringBuilder(color + ""); diff --git a/src/main/java/com/gmail/nossr50/util/MobMetadataUtils.java b/src/main/java/com/gmail/nossr50/util/MobMetadataUtils.java new file mode 100644 index 000000000..9e31ad01c --- /dev/null +++ b/src/main/java/com/gmail/nossr50/util/MobMetadataUtils.java @@ -0,0 +1,203 @@ +package com.gmail.nossr50.util; + +import static com.gmail.nossr50.util.MetadataService.NSK_COTW_SUMMONED_MOB; +import static com.gmail.nossr50.util.MetadataService.NSK_EGG_MOB; +import static com.gmail.nossr50.util.MetadataService.NSK_EXPLOITED_ENDERMEN; +import static com.gmail.nossr50.util.MetadataService.NSK_MOB_SPAWNER_MOB; +import static com.gmail.nossr50.util.MetadataService.NSK_NETHER_GATE_MOB; +import static com.gmail.nossr50.util.MetadataService.NSK_PLAYER_BRED_MOB; +import static com.gmail.nossr50.util.MetadataService.NSK_PLAYER_TAMED_MOB; + +import com.gmail.nossr50.api.exceptions.IncompleteNamespacedKeyRegister; +import com.gmail.nossr50.config.PersistentDataConfig; +import com.gmail.nossr50.metadata.MobMetaFlagType; +import com.google.common.collect.MapMaker; +import java.util.EnumMap; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import org.bukkit.NamespacedKey; +import org.bukkit.entity.Entity; +import org.bukkit.entity.LivingEntity; +import org.bukkit.persistence.PersistentDataContainer; +import org.bukkit.persistence.PersistentDataType; +import org.jetbrains.annotations.NotNull; + +public final class MobMetadataUtils { + private static final @NotNull ConcurrentMap> mobRegistry; // transient data + private static final @NotNull EnumMap mobFlagKeyMap; // used for persistent data + private static boolean isUsingPersistentData = false; + + private MobMetadataUtils() { + // private constructor to prevent instantiation + } + + static { + mobFlagKeyMap = new EnumMap<>(MobMetaFlagType.class); + // Using Guava for a concurrent weak hash map + // IMPORTANT: This type of map uses == for comparison over .equals(), + // which is a violation of map contract + mobRegistry = new MapMaker() + .weakKeys() + .concurrencyLevel(4) + .makeMap(); + + initMobFlagKeyMap(); + + for (MobMetaFlagType metaFlagType : MobMetaFlagType.values()) { + if (PersistentDataConfig.getInstance().isMobPersistent(metaFlagType)) { + isUsingPersistentData = true; + break; + } + } + } + + /** + * Registers the namespaced keys required by the API (CB/Spigot) Used primarily for persistent + * data + */ + private static void initMobFlagKeyMap() throws IncompleteNamespacedKeyRegister { + for (MobMetaFlagType mobMetaFlagType : MobMetaFlagType.values()) { + switch (mobMetaFlagType) { + case MOB_SPAWNER_MOB -> mobFlagKeyMap.put(mobMetaFlagType, NSK_MOB_SPAWNER_MOB); + case EGG_MOB -> mobFlagKeyMap.put(mobMetaFlagType, NSK_EGG_MOB); + case NETHER_PORTAL_MOB -> mobFlagKeyMap.put(mobMetaFlagType, NSK_NETHER_GATE_MOB); + case COTW_SUMMONED_MOB -> mobFlagKeyMap.put(mobMetaFlagType, NSK_COTW_SUMMONED_MOB); + case PLAYER_BRED_MOB -> mobFlagKeyMap.put(mobMetaFlagType, NSK_PLAYER_BRED_MOB); + case EXPLOITED_ENDERMEN -> + mobFlagKeyMap.put(mobMetaFlagType, NSK_EXPLOITED_ENDERMEN); + case PLAYER_TAMED_MOB -> mobFlagKeyMap.put(mobMetaFlagType, NSK_PLAYER_TAMED_MOB); + default -> throw new IncompleteNamespacedKeyRegister( + "Missing namespaced key register for type: " + mobMetaFlagType); + } + } + } + + /** + * Checks if a {@link LivingEntity} has a specific mcMMO mob flag. + * + * @param flag the type of mob flag to check for + * @param livingEntity the living entity to check + * @return true if the mob has the specified metadata flag + */ + public static boolean hasMobFlag(@NotNull MobMetaFlagType flag, + @NotNull LivingEntity livingEntity) { + if (PersistentDataConfig.getInstance().isMobPersistent(flag)) { + return livingEntity.getPersistentDataContainer() + .has(mobFlagKeyMap.get(flag), PersistentDataType.BYTE); + } else { + final Set flags = mobRegistry.get(livingEntity); + return flags != null && flags.contains(flag); + } + } + + /** + * Checks if a {@link LivingEntity} has any mcMMO mob flags. + * + * @param livingEntity the living entity to check + * @return true if the mob has any mcMMO mob-related metadata flags + */ + public static boolean hasMobFlags(@NotNull LivingEntity livingEntity) { + if (isUsingPersistentData) { + for (MobMetaFlagType metaFlagType : MobMetaFlagType.values()) { + if (hasMobFlag(metaFlagType, livingEntity)) { + return true; + } + } + return false; + } else { + final Set flags = mobRegistry.get(livingEntity); + return flags != null && !flags.isEmpty(); + } + } + + /** + * Copies all mcMMO mob flags from one {@link LivingEntity} to another. This does not clear + * existing mcMMO mob flags on the target. + * + * @param sourceEntity entity to copy from + * @param targetEntity entity to copy to + */ + public static void addMobFlags(@NotNull LivingEntity sourceEntity, + @NotNull LivingEntity targetEntity) { + if (!hasMobFlags(sourceEntity)) { + return; + } + + if (isUsingPersistentData) { + for (MobMetaFlagType flag : MobMetaFlagType.values()) { + if (hasMobFlag(flag, sourceEntity)) { + flagMetadata(flag, targetEntity); + } + } + } else { + Set sourceFlags = mobRegistry.get(sourceEntity); + if (sourceFlags != null) { + Set targetFlags = mobRegistry.computeIfAbsent(targetEntity, + k -> ConcurrentHashMap.newKeySet()); + targetFlags.addAll(sourceFlags); + } + } + } + + /** + * Adds a mob flag to a {@link LivingEntity}. The existence of the flag acts as a true value; + * non-existence is false. + * + * @param flag the desired flag to assign + * @param livingEntity the target living entity + */ + public static void flagMetadata(@NotNull MobMetaFlagType flag, + @NotNull LivingEntity livingEntity) { + if (PersistentDataConfig.getInstance().isMobPersistent(flag)) { + if (!hasMobFlag(flag, livingEntity)) { + PersistentDataContainer persistentDataContainer = livingEntity.getPersistentDataContainer(); + persistentDataContainer.set(mobFlagKeyMap.get(flag), PersistentDataType.BYTE, + MetadataConstants.SIMPLE_FLAG_VALUE); + } + } else { + final Set flags = mobRegistry.computeIfAbsent(livingEntity, + k -> ConcurrentHashMap.newKeySet()); + flags.add(flag); + } + } + + /** + * Removes a specific mob flag from a {@link LivingEntity}. + * + * @param flag the flag to remove + * @param livingEntity the target living entity + */ + public static void removeMobFlag(@NotNull MobMetaFlagType flag, + @NotNull LivingEntity livingEntity) { + if (PersistentDataConfig.getInstance().isMobPersistent(flag)) { + if (hasMobFlag(flag, livingEntity)) { + PersistentDataContainer persistentDataContainer = livingEntity.getPersistentDataContainer(); + persistentDataContainer.remove(mobFlagKeyMap.get(flag)); + } + } else { + final Set flags = mobRegistry.get(livingEntity); + if (flags != null) { + flags.remove(flag); + if (flags.isEmpty()) { + mobRegistry.remove(livingEntity, flags); + } + } + } + } + + /** + * Removes all mcMMO-related mob flags from a {@link LivingEntity}. + * + * @param livingEntity the target entity + */ + public static void removeMobFlags(@NotNull LivingEntity livingEntity) { + if (isUsingPersistentData) { + for (MobMetaFlagType flag : MobMetaFlagType.values()) { + removeMobFlag(flag, livingEntity); + } + } else { + mobRegistry.remove(livingEntity); + } + } +} diff --git a/src/main/java/com/gmail/nossr50/util/ModManager.java b/src/main/java/com/gmail/nossr50/util/ModManager.java index 19e1202ed..adbe20ae1 100644 --- a/src/main/java/com/gmail/nossr50/util/ModManager.java +++ b/src/main/java/com/gmail/nossr50/util/ModManager.java @@ -1,277 +1,275 @@ -package com.gmail.nossr50.util; - -import com.gmail.nossr50.config.mods.CustomArmorLegacyConfig; -import com.gmail.nossr50.config.mods.CustomBlockLegacyConfig; -import com.gmail.nossr50.config.mods.CustomEntityLegacyConfig; -import com.gmail.nossr50.config.mods.CustomToolLegacyConfig; -import com.gmail.nossr50.datatypes.mods.CustomBlock; -import com.gmail.nossr50.datatypes.mods.CustomEntity; -import com.gmail.nossr50.datatypes.mods.CustomTool; -import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.skills.repair.repairables.Repairable; -import org.bukkit.Material; -import org.bukkit.block.BlockState; -import org.bukkit.configuration.file.YamlConfiguration; -import org.bukkit.entity.Entity; -import org.bukkit.inventory.ItemStack; - -import java.io.File; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; - -public class ModManager { - private final List repairables = new ArrayList<>(); - - // Armor Mods - private final List customBoots = new ArrayList<>(); - private final List customChestplates = new ArrayList<>(); - private final List customHelmets = new ArrayList<>(); - private final List customLeggings = new ArrayList<>(); - - // Block Mods - private final List customExcavationBlocks = new ArrayList<>(); - private final List customHerbalismBlocks = new ArrayList<>(); - private final List customMiningBlocks = new ArrayList<>(); - private final List customOres = new ArrayList<>(); - private final List customLogs = new ArrayList<>(); - private final List customLeaves = new ArrayList<>(); - private final List customAbilityBlocks = new ArrayList<>(); - private final HashMap customBlockMap = new HashMap<>(); - - // Entity Mods - private final HashMap customEntityClassMap = new HashMap<>(); - private final HashMap customEntityTypeMap = new HashMap<>(); - - // Tool Mods - private final List customAxes = new ArrayList<>(); - private final List customBows = new ArrayList<>(); - private final List customHoes = new ArrayList<>(); - private final List customPickaxes = new ArrayList<>(); - private final List customShovels = new ArrayList<>(); - private final List customSwords = new ArrayList<>(); - private final HashMap customToolMap = new HashMap<>(); - - public void registerCustomArmor(CustomArmorLegacyConfig config) { - customBoots.addAll(config.customBoots); - customChestplates.addAll(config.customChestplates); - customHelmets.addAll(config.customHelmets); - customLeggings.addAll(config.customLeggings); - repairables.addAll(config.repairables); - } - - public void registerCustomBlocks(CustomBlockLegacyConfig config) { - customExcavationBlocks.addAll(config.customExcavationBlocks); - customHerbalismBlocks.addAll(config.customHerbalismBlocks); - customMiningBlocks.addAll(config.customMiningBlocks); - customOres.addAll(config.customOres); - customLogs.addAll(config.customLogs); - customLeaves.addAll(config.customLeaves); - customAbilityBlocks.addAll(config.customAbilityBlocks); - customBlockMap.putAll(config.customBlockMap); - } - - public void registerCustomEntities(CustomEntityLegacyConfig config) { - customEntityClassMap.putAll(config.customEntityClassMap); - customEntityTypeMap.putAll(config.customEntityTypeMap); - } - - public void registerCustomTools(CustomToolLegacyConfig config) { - customAxes.addAll(config.customAxes); - customBows.addAll(config.customBows); - customHoes.addAll(config.customHoes); - customPickaxes.addAll(config.customPickaxes); - customShovels.addAll(config.customShovels); - customSwords.addAll(config.customSwords); - customToolMap.putAll(config.customToolMap); - repairables.addAll(config.repairables); - } - - public boolean isCustomBoots(Material material) { - return mcMMO.p.getGeneralConfig().getArmorModsEnabled() && customBoots.contains(material); - } - - public boolean isCustomChestplate(Material material) { - return mcMMO.p.getGeneralConfig().getArmorModsEnabled() && customChestplates.contains(material); - } - - public boolean isCustomHelmet(Material material) { - return mcMMO.p.getGeneralConfig().getArmorModsEnabled() && customHelmets.contains(material); - } - - public boolean isCustomLeggings(Material material) { - return mcMMO.p.getGeneralConfig().getArmorModsEnabled() && customLeggings.contains(material); - } - - public boolean isCustomAxe(Material material) { - return mcMMO.p.getGeneralConfig().getToolModsEnabled() && customAxes.contains(material); - } - - public boolean isCustomBow(Material material) { - return mcMMO.p.getGeneralConfig().getToolModsEnabled() && customBows.contains(material); - } - - public boolean isCustomHoe(Material material) { - return mcMMO.p.getGeneralConfig().getToolModsEnabled() && customHoes.contains(material); - } - - public boolean isCustomPickaxe(Material material) { - return mcMMO.p.getGeneralConfig().getToolModsEnabled() && customPickaxes.contains(material); - } - - public boolean isCustomShovel(Material material) { - return mcMMO.p.getGeneralConfig().getToolModsEnabled() && customShovels.contains(material); - } - - public boolean isCustomSword(Material material) { - return mcMMO.p.getGeneralConfig().getToolModsEnabled() && customSwords.contains(material); - } - - public boolean isCustomOre(Material data) { - return mcMMO.p.getGeneralConfig().getBlockModsEnabled() && customOres.contains(data); - } - - public boolean isCustomLog(BlockState state) { - return mcMMO.p.getGeneralConfig().getBlockModsEnabled() && customLogs.contains(state.getType()); - } - - public boolean isCustomAbilityBlock(BlockState state) { - return mcMMO.p.getGeneralConfig().getBlockModsEnabled() && customAbilityBlocks.contains(state.getType()); - } - - public boolean isCustomExcavationBlock(BlockState state) { - return mcMMO.p.getGeneralConfig().getBlockModsEnabled() && customExcavationBlocks.contains(state.getType()); - } - - public boolean isCustomHerbalismBlock(BlockState state) { - return mcMMO.p.getGeneralConfig().getBlockModsEnabled() && customHerbalismBlocks.contains(state.getType()); - } - - public boolean isCustomMiningBlock(BlockState state) { - return mcMMO.p.getGeneralConfig().getBlockModsEnabled() && customMiningBlocks.contains(state.getType()); - } - - public CustomBlock getBlock(BlockState state) { - return customBlockMap.get(state.getType()); - } - - public CustomBlock getBlock(Material data) { - return customBlockMap.get(data); - } - - /** - * Checks to see if an item is a custom tool. - * - * @param item Item to check - * @return true if the item is a custom tool, false otherwise - */ - public boolean isCustomTool(ItemStack item) { - return mcMMO.p.getGeneralConfig().getToolModsEnabled() && item != null && customToolMap.containsKey(item.getType()); - } - - /** - * Get the custom tool associated with an item. - * - * @param item The item to check - * @return the tool if it exists, null otherwise - */ - public CustomTool getTool(ItemStack item) { - return item == null ? null : customToolMap.get(item.getType()); - } - - public List getLoadedRepairables() { - return repairables; - } - - public boolean isCustomEntity(Entity entity) { - if (!mcMMO.p.getGeneralConfig().getEntityModsEnabled()) { - return false; - } - - if (customEntityTypeMap.containsKey(entity.getType().toString())) { - return true; - } - - try { - return customEntityClassMap.containsKey(((Class) entity.getClass().getDeclaredField("entityClass").get(entity)).getName()); - } - catch (Exception e) { - if (e instanceof NoSuchFieldException || e instanceof IllegalArgumentException || e instanceof IllegalAccessException) { - return customEntityClassMap.containsKey(entity.getClass().getName()); - } - - e.printStackTrace(); - return false; - } - } - - public CustomEntity getEntity(Entity entity) { - CustomEntity customEntity = customEntityTypeMap.get(entity.getType().toString()); - - if (customEntity == null) { - try { - customEntity = customEntityClassMap.get(((Class) entity.getClass().getDeclaredField("entityClass").get(entity)).getName()); - } - catch (Exception e) { - if (e instanceof NoSuchFieldException || e instanceof IllegalArgumentException || e instanceof IllegalAccessException) { - customEntity = customEntityClassMap.get(entity.getClass().getName()); - } - else { - e.printStackTrace(); - } - } - } - - return customEntity; - } - - public void addCustomEntity(Entity entity) { - if (!mcMMO.p.getGeneralConfig().getEntityModsEnabled()) { - return; - } - - File entityFile = new File(mcMMO.p.getDataFolder(), "mods" + File.separator + "entities.default.yml"); - YamlConfiguration entitiesFile = YamlConfiguration.loadConfiguration(entityFile); - - String entityName = entity.getType().toString(); - String sanitizedEntityName = entityName.replace(".", "_"); - - if (entitiesFile.getKeys(false).contains(sanitizedEntityName)) { - return; - } - - entitiesFile.set(sanitizedEntityName + ".XP_Multiplier", 1.0D); - entitiesFile.set(sanitizedEntityName + ".Tameable", false); - entitiesFile.set(sanitizedEntityName + ".Taming_XP", 0); - entitiesFile.set(sanitizedEntityName + ".CanBeSummoned", false); - entitiesFile.set(sanitizedEntityName + ".COTW_Material", ""); - entitiesFile.set(sanitizedEntityName + ".COTW_Material_Data", 0); - entitiesFile.set(sanitizedEntityName + ".COTW_Material_Amount", 0); - - String className = ""; - - try { - className = ((Class) entity.getClass().getDeclaredField("entityClass").get(entity)).getName(); - } - catch (Exception e) { - if (e instanceof NoSuchFieldException || e instanceof IllegalArgumentException || e instanceof IllegalAccessException) { - className = entity.getClass().getName(); - } - else { - e.printStackTrace(); - } - } - - CustomEntity customEntity = new CustomEntity(1.0D, false, 0, false, null, 0); - customEntityTypeMap.put(entityName, customEntity); - customEntityClassMap.put(className, customEntity); - - try { - entitiesFile.save(entityFile); - LogUtils.debug(mcMMO.p.getLogger(), entity.getType().toString() + " was added to the custom entities file!"); - } - catch (Exception e) { - e.printStackTrace(); - } - } -} +//package com.gmail.nossr50.util; +// +//import com.gmail.nossr50.config.mods.CustomArmorLegacyConfig; +//import com.gmail.nossr50.config.mods.CustomBlockLegacyConfig; +//import com.gmail.nossr50.config.mods.CustomEntityLegacyConfig; +//import com.gmail.nossr50.config.mods.CustomToolLegacyConfig; +//import com.gmail.nossr50.datatypes.mods.CustomBlock; +//import com.gmail.nossr50.datatypes.mods.CustomEntity; +//import com.gmail.nossr50.datatypes.mods.CustomTool; +//import com.gmail.nossr50.mcMMO; +//import com.gmail.nossr50.skills.repair.repairables.Repairable; +//import org.bukkit.Material; +//import org.bukkit.block.BlockState; +//import org.bukkit.configuration.file.YamlConfiguration; +//import org.bukkit.entity.Entity; +//import org.bukkit.inventory.ItemStack; +// +//import java.io.File; +//import java.util.ArrayList; +//import java.util.HashMap; +//import java.util.List; +// +//public class ModManager { +// private final List repairables = new ArrayList<>(); +// +// // Armor Mods +// private final List customBoots = new ArrayList<>(); +// private final List customChestplates = new ArrayList<>(); +// private final List customHelmets = new ArrayList<>(); +// private final List customLeggings = new ArrayList<>(); +// +// // Block Mods +// private final List customExcavationBlocks = new ArrayList<>(); +// private final List customHerbalismBlocks = new ArrayList<>(); +// private final List customMiningBlocks = new ArrayList<>(); +// private final List customOres = new ArrayList<>(); +// private final List customLogs = new ArrayList<>(); +// private final List customLeaves = new ArrayList<>(); +// private final List customAbilityBlocks = new ArrayList<>(); +// private final HashMap customBlockMap = new HashMap<>(); +// +// // Entity Mods +// private final HashMap customEntityClassMap = new HashMap<>(); +// private final HashMap customEntityTypeMap = new HashMap<>(); +// +// // Tool Mods +// private final List customAxes = new ArrayList<>(); +// private final List customBows = new ArrayList<>(); +// private final List customHoes = new ArrayList<>(); +// private final List customPickaxes = new ArrayList<>(); +// private final List customShovels = new ArrayList<>(); +// private final List customSwords = new ArrayList<>(); +// private final HashMap customToolMap = new HashMap<>(); +// +// public void registerCustomArmor(CustomArmorLegacyConfig config) { +// customBoots.addAll(config.customBoots); +// customChestplates.addAll(config.customChestplates); +// customHelmets.addAll(config.customHelmets); +// customLeggings.addAll(config.customLeggings); +// repairables.addAll(config.repairables); +// } +// +// public void registerCustomBlocks(CustomBlockLegacyConfig config) { +// customExcavationBlocks.addAll(config.customExcavationBlocks); +// customHerbalismBlocks.addAll(config.customHerbalismBlocks); +// customMiningBlocks.addAll(config.customMiningBlocks); +// customOres.addAll(config.customOres); +// customLogs.addAll(config.customLogs); +// customLeaves.addAll(config.customLeaves); +// customAbilityBlocks.addAll(config.customAbilityBlocks); +// customBlockMap.putAll(config.customBlockMap); +// } +// +// public void registerCustomEntities(CustomEntityLegacyConfig config) { +// customEntityClassMap.putAll(config.customEntityClassMap); +// customEntityTypeMap.putAll(config.customEntityTypeMap); +// } +// +// public void registerCustomTools(CustomToolLegacyConfig config) { +// customAxes.addAll(config.customAxes); +// customBows.addAll(config.customBows); +// customHoes.addAll(config.customHoes); +// customPickaxes.addAll(config.customPickaxes); +// customShovels.addAll(config.customShovels); +// customSwords.addAll(config.customSwords); +// customToolMap.putAll(config.customToolMap); +// repairables.addAll(config.repairables); +// } +// +// public boolean isCustomBoots(Material material) { +// return mcMMO.p.getGeneralConfig().getArmorModsEnabled() && customBoots.contains(material); +// } +// +// public boolean isCustomChestplate(Material material) { +// return mcMMO.p.getGeneralConfig().getArmorModsEnabled() && customChestplates.contains(material); +// } +// +// public boolean isCustomHelmet(Material material) { +// return mcMMO.p.getGeneralConfig().getArmorModsEnabled() && customHelmets.contains(material); +// } +// +// public boolean isCustomLeggings(Material material) { +// return mcMMO.p.getGeneralConfig().getArmorModsEnabled() && customLeggings.contains(material); +// } +// +// public boolean isCustomAxe(Material material) { +// return mcMMO.p.getGeneralConfig().getToolModsEnabled() && customAxes.contains(material); +// } +// +// public boolean isCustomBow(Material material) { +// return mcMMO.p.getGeneralConfig().getToolModsEnabled() && customBows.contains(material); +// } +// +// public boolean isCustomHoe(Material material) { +// return mcMMO.p.getGeneralConfig().getToolModsEnabled() && customHoes.contains(material); +// } +// +// public boolean isCustomPickaxe(Material material) { +// return mcMMO.p.getGeneralConfig().getToolModsEnabled() && customPickaxes.contains(material); +// } +// +// public boolean isCustomShovel(Material material) { +// return mcMMO.p.getGeneralConfig().getToolModsEnabled() && customShovels.contains(material); +// } +// +// public boolean isCustomSword(Material material) { +// return mcMMO.p.getGeneralConfig().getToolModsEnabled() && customSwords.contains(material); +// } +// +// public boolean isCustomOre(Material data) { +// return mcMMO.p.getGeneralConfig().getBlockModsEnabled() && customOres.contains(data); +// } +// +// public boolean isCustomLog(BlockState state) { +// return mcMMO.p.getGeneralConfig().getBlockModsEnabled() && customLogs.contains(state.getType()); +// } +// +// public boolean isCustomAbilityBlock(BlockState state) { +// return mcMMO.p.getGeneralConfig().getBlockModsEnabled() && customAbilityBlocks.contains(state.getType()); +// } +// +// public boolean isCustomExcavationBlock(BlockState state) { +// return mcMMO.p.getGeneralConfig().getBlockModsEnabled() && customExcavationBlocks.contains(state.getType()); +// } +// +// public boolean isCustomHerbalismBlock(BlockState state) { +// return mcMMO.p.getGeneralConfig().getBlockModsEnabled() && customHerbalismBlocks.contains(state.getType()); +// } +// +// public boolean isCustomMiningBlock(BlockState state) { +// return mcMMO.p.getGeneralConfig().getBlockModsEnabled() && customMiningBlocks.contains(state.getType()); +// } +// +// public CustomBlock getBlock(BlockState state) { +// return customBlockMap.get(state.getType()); +// } +// +// public CustomBlock getBlock(Material data) { +// return customBlockMap.get(data); +// } +// +// /** +// * Checks to see if an item is a custom tool. +// * +// * @param item Item to check +// * @return true if the item is a custom tool, false otherwise +// */ +// public boolean isCustomTool(ItemStack item) { +// return mcMMO.p.getGeneralConfig().getToolModsEnabled() && item != null && customToolMap.containsKey(item.getType()); +// } +// +// /** +// * Get the custom tool associated with an item. +// * +// * @param item The item to check +// * @return the tool if it exists, null otherwise +// */ +// public CustomTool getTool(ItemStack item) { +// return item == null ? null : customToolMap.get(item.getType()); +// } +// +// public List getLoadedRepairables() { +// return repairables; +// } +// +// public boolean isCustomEntity(Entity entity) { +// if (!mcMMO.p.getGeneralConfig().getEntityModsEnabled()) { +// return false; +// } +// +// if (customEntityTypeMap.containsKey(entity.getType().toString())) { +// return true; +// } +// +// try { +// return customEntityClassMap.containsKey(((Class) entity.getClass().getDeclaredField("entityClass").get(entity)).getName()); +// } +// catch (Exception e) { +// if (e instanceof NoSuchFieldException || e instanceof IllegalArgumentException || e instanceof IllegalAccessException) { +// return customEntityClassMap.containsKey(entity.getClass().getName()); +// } +// +// e.printStackTrace(); +// return false; +// } +// } +// +// public CustomEntity getEntity(Entity entity) { +// CustomEntity customEntity = customEntityTypeMap.get(entity.getType().toString()); +// +// if (customEntity == null) { +// try { +// customEntity = customEntityClassMap.get(((Class) entity.getClass().getDeclaredField("entityClass").get(entity)).getName()); +// } +// catch (Exception e) { +// if (e instanceof NoSuchFieldException || e instanceof IllegalArgumentException || e instanceof IllegalAccessException) { +// customEntity = customEntityClassMap.get(entity.getClass().getName()); +// } else { +// e.printStackTrace(); +// } +// } +// } +// +// return customEntity; +// } +// +// public void addCustomEntity(Entity entity) { +// if (!mcMMO.p.getGeneralConfig().getEntityModsEnabled()) { +// return; +// } +// +// File entityFile = new File(mcMMO.p.getDataFolder(), "mods" + File.separator + "entities.default.yml"); +// YamlConfiguration entitiesFile = YamlConfiguration.loadConfiguration(entityFile); +// +// String entityName = entity.getType().toString(); +// String sanitizedEntityName = entityName.replace(".", "_"); +// +// if (entitiesFile.getKeys(false).contains(sanitizedEntityName)) { +// return; +// } +// +// entitiesFile.set(sanitizedEntityName + ".XP_Multiplier", 1.0D); +// entitiesFile.set(sanitizedEntityName + ".Tameable", false); +// entitiesFile.set(sanitizedEntityName + ".Taming_XP", 0); +// entitiesFile.set(sanitizedEntityName + ".CanBeSummoned", false); +// entitiesFile.set(sanitizedEntityName + ".COTW_Material", ""); +// entitiesFile.set(sanitizedEntityName + ".COTW_Material_Data", 0); +// entitiesFile.set(sanitizedEntityName + ".COTW_Material_Amount", 0); +// +// String className = ""; +// +// try { +// className = ((Class) entity.getClass().getDeclaredField("entityClass").get(entity)).getName(); +// } +// catch (Exception e) { +// if (e instanceof NoSuchFieldException || e instanceof IllegalArgumentException || e instanceof IllegalAccessException) { +// className = entity.getClass().getName(); +// } else { +// e.printStackTrace(); +// } +// } +// +// CustomEntity customEntity = new CustomEntity(1.0D, false, 0, false, null, 0); +// customEntityTypeMap.put(entityName, customEntity); +// customEntityClassMap.put(className, customEntity); +// +// try { +// entitiesFile.save(entityFile); +// LogUtils.debug(mcMMO.p.getLogger(), entity.getType().toString() + " was added to the custom entities file!"); +// } +// catch (Exception e) { +// e.printStackTrace(); +// } +// } +//} diff --git a/src/main/java/com/gmail/nossr50/util/Motd.java b/src/main/java/com/gmail/nossr50/util/Motd.java index ddad205c0..dec741b5c 100644 --- a/src/main/java/com/gmail/nossr50/util/Motd.java +++ b/src/main/java/com/gmail/nossr50/util/Motd.java @@ -4,16 +4,18 @@ import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.skills.PerksUtils; +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.util.Locale; import org.bukkit.entity.Player; import org.bukkit.plugin.PluginDescriptionFile; -import java.text.DecimalFormat; - public final class Motd { public static final String PERK_PREFIX = LocaleLoader.getString("MOTD.PerksPrefix") + " "; private static final PluginDescriptionFile pluginDescription = mcMMO.p.getDescription(); - private Motd() {} + private Motd() { + } public static void displayAll(Player player) { displayVersion(player, pluginDescription.getVersion()); @@ -28,7 +30,7 @@ public final class Motd { /** * Display version info. * - * @param player Target player + * @param player Target player * @param version Plugin version */ public static void displayVersion(Player player, String version) { @@ -66,14 +68,17 @@ public final class Motd { seperator = " & "; } - player.sendMessage(LocaleLoader.getString("MOTD.Hardcore.Enabled", statLossInfo + seperator + vampirismInfo)); + player.sendMessage(LocaleLoader.getString("MOTD.Hardcore.Enabled", + statLossInfo + seperator + vampirismInfo)); if (deathStatLossEnabled) { - player.sendMessage(LocaleLoader.getString("MOTD.Hardcore.DeathStatLoss.Stats", mcMMO.p.getGeneralConfig().getHardcoreDeathStatPenaltyPercentage())); + player.sendMessage(LocaleLoader.getString("MOTD.Hardcore.DeathStatLoss.Stats", + mcMMO.p.getGeneralConfig().getHardcoreDeathStatPenaltyPercentage())); } if (vampirismEnabled) { - player.sendMessage(LocaleLoader.getString("MOTD.Hardcore.Vampirism.Stats", mcMMO.p.getGeneralConfig().getHardcoreVampirismStatLeechPercentage())); + player.sendMessage(LocaleLoader.getString("MOTD.Hardcore.Vampirism.Stats", + mcMMO.p.getGeneralConfig().getHardcoreVampirismStatLeechPercentage())); } } @@ -86,7 +91,9 @@ public final class Motd { for (PrimarySkillType skill : PrimarySkillType.values()) { //TODO: Wow this is horrifying... if (PerksUtils.handleXpPerks(player, 1, skill) > 1) { - player.sendMessage(PERK_PREFIX + LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Perks.XP.Name"), LocaleLoader.getString("Perks.XP.Desc"))); + player.sendMessage(PERK_PREFIX + LocaleLoader.getString("Effects.Template", + LocaleLoader.getString("Perks.XP.Name"), + LocaleLoader.getString("Perks.XP.Desc"))); return; } } @@ -101,8 +108,12 @@ public final class Motd { double cooldownReduction = 1 - (PerksUtils.handleCooldownPerks(player, 12) / 12.0); if (cooldownReduction > 0.0) { - DecimalFormat percent = new DecimalFormat("##0.00%"); - player.sendMessage(PERK_PREFIX + LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Perks.Cooldowns.Name"), LocaleLoader.getString("Perks.Cooldowns.Desc", percent.format(cooldownReduction)))); + DecimalFormat percent = new DecimalFormat("##0.00%", + DecimalFormatSymbols.getInstance(Locale.US)); + player.sendMessage(PERK_PREFIX + LocaleLoader.getString("Effects.Template", + LocaleLoader.getString("Perks.Cooldowns.Name"), + LocaleLoader.getString("Perks.Cooldowns.Desc", + percent.format(cooldownReduction)))); } } @@ -115,7 +126,9 @@ public final class Motd { int perkAmount = PerksUtils.handleActivationPerks(player, 0, 0); if (perkAmount > 0) { - player.sendMessage(PERK_PREFIX + LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Perks.ActivationTime.Name"), LocaleLoader.getString("Perks.ActivationTime.Desc", perkAmount))); + player.sendMessage(PERK_PREFIX + LocaleLoader.getString("Effects.Template", + LocaleLoader.getString("Perks.ActivationTime.Name"), + LocaleLoader.getString("Perks.ActivationTime.Desc", perkAmount))); } } @@ -127,7 +140,9 @@ public final class Motd { public static void displayLuckyPerks(Player player) { for (PrimarySkillType skill : PrimarySkillType.values()) { if (Permissions.lucky(player, skill)) { - player.sendMessage(PERK_PREFIX + LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Perks.Lucky.Name"), LocaleLoader.getString("Perks.Lucky.Desc.Login"))); + player.sendMessage(PERK_PREFIX + LocaleLoader.getString("Effects.Template", + LocaleLoader.getString("Perks.Lucky.Name"), + LocaleLoader.getString("Perks.Lucky.Desc.Login"))); return; } } @@ -136,7 +151,7 @@ public final class Motd { /** * Display website info. * - * @param player Target player + * @param player Target player * @param website Plugin website */ public static void displayWebsite(Player player, String website) { diff --git a/src/main/java/com/gmail/nossr50/util/Permissions.java b/src/main/java/com/gmail/nossr50/util/Permissions.java index c405f84ab..60d905b4c 100644 --- a/src/main/java/com/gmail/nossr50/util/Permissions.java +++ b/src/main/java/com/gmail/nossr50/util/Permissions.java @@ -1,101 +1,234 @@ package com.gmail.nossr50.util; import com.gmail.nossr50.commands.party.PartySubcommandType; +import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.skills.ItemType; 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 java.util.Locale; 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 java.util.Locale; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; public final class Permissions { - private Permissions() {} + private Permissions() { + } /* * GENERAL */ - public static boolean motd(Permissible permissible) { return permissible.hasPermission("mcmmo.motd"); } - public static boolean levelUpBroadcast(Permissible permissible) { return permissible.hasPermission("mcmmo.broadcast.levelup"); } - public static boolean updateNotifications(Permissible permissible) {return permissible.hasPermission("mcmmo.tools.updatecheck"); } - public static boolean chimaeraWing(Permissible permissible) { return permissible.hasPermission("mcmmo.item.chimaerawing"); } - public static boolean showversion(Permissible permissible) { return permissible.hasPermission("mcmmo.showversion"); } + public static boolean motd(Permissible permissible) { + return permissible.hasPermission("mcmmo.motd"); + } + + public static boolean levelUpBroadcast(Permissible permissible) { + return permissible.hasPermission("mcmmo.broadcast.levelup"); + } + + public static boolean updateNotifications(Permissible permissible) { + return permissible.hasPermission("mcmmo.tools.updatecheck"); + } + + public static boolean chimaeraWing(Permissible permissible) { + return permissible.hasPermission("mcmmo.item.chimaerawing"); + } + + public static boolean showversion(Permissible permissible) { + return permissible.hasPermission("mcmmo.showversion"); + } /* BYPASS */ - public static boolean hardcoreBypass(Permissible permissible) { return permissible.hasPermission("mcmmo.bypass.hardcoremode"); } - public static boolean arcaneBypass(Permissible permissible) { return permissible.hasPermission("mcmmo.bypass.arcanebypass"); } + public static boolean hardcoreBypass(Permissible permissible) { + return permissible.hasPermission("mcmmo.bypass.hardcoremode"); + } + + public static boolean arcaneBypass(Permissible permissible) { + return permissible.hasPermission("mcmmo.bypass.arcanebypass"); + } /* CHAT */ - public static boolean partyChat(Permissible permissible) { return permissible.hasPermission("mcmmo.chat.partychat"); } - public static boolean adminChat(Permissible permissible) { return permissible.hasPermission("mcmmo.chat.adminchat"); } - public static boolean colorChat(Permissible permissible) { return permissible.hasPermission("mcmmo.chat.colors"); } + public static boolean partyChat(Permissible permissible) { + return permissible.hasPermission("mcmmo.chat.partychat"); + } + + public static boolean adminChat(Permissible permissible) { + return permissible.hasPermission("mcmmo.chat.adminchat"); + } + + public static boolean colorChat(Permissible permissible) { + return permissible.hasPermission("mcmmo.chat.colors"); + } /* * COMMANDS */ - public static boolean mmoinfo(Permissible permissible) { return permissible.hasPermission("mcmmo.commands.mmoinfo"); } - public static boolean addlevels(Permissible permissible) { return permissible.hasPermission("mcmmo.commands.addlevels"); } - public static boolean addlevelsOthers(Permissible permissible) { return permissible.hasPermission("mcmmo.commands.addlevels.others"); } + public static boolean mmoinfo(Permissible permissible) { + return permissible.hasPermission("mcmmo.commands.mmoinfo"); + } - public static boolean addxp(Permissible permissible) { return permissible.hasPermission("mcmmo.commands.addxp"); } - public static boolean addxpOthers(Permissible permissible) { return permissible.hasPermission("mcmmo.commands.addxp.others"); } + public static boolean addlevels(Permissible permissible) { + return permissible.hasPermission("mcmmo.commands.addlevels"); + } - public static boolean hardcoreModify(Permissible permissible) { return permissible.hasPermission("mcmmo.commands.hardcore.modify"); } - public static boolean hardcoreToggle(Permissible permissible) { return permissible.hasPermission("mcmmo.commands.hardcore.toggle"); } + public static boolean addlevelsOthers(Permissible permissible) { + return permissible.hasPermission("mcmmo.commands.addlevels.others"); + } - public static boolean inspect(Permissible permissible) { return (permissible.hasPermission("mcmmo.commands.inspect")); } - public static boolean inspectFar(Permissible permissible) { return (permissible.hasPermission("mcmmo.commands.inspect.far")); } - public static boolean inspectHidden(Permissible permissible) { return (permissible.hasPermission("mcmmo.commands.inspect.hidden")); } + public static boolean addxp(Permissible permissible) { + return permissible.hasPermission("mcmmo.commands.addxp"); + } - public static boolean mcability(Permissible permissible) { return (permissible.hasPermission("mcmmo.commands.mcability")); } - public static boolean mcabilityOthers(Permissible permissible) { return (permissible.hasPermission("mcmmo.commands.mcability.others")); } + public static boolean addxpOthers(Permissible permissible) { + return permissible.hasPermission("mcmmo.commands.addxp.others"); + } - public static boolean adminChatSpy(Permissible permissible) { return permissible.hasPermission("mcmmo.commands.mcchatspy");} - public static boolean adminChatSpyOthers(Permissible permissible) { return permissible.hasPermission("mcmmo.commands.mcchatspy.others");} + public static boolean hardcoreModify(Permissible permissible) { + return permissible.hasPermission("mcmmo.commands.hardcore.modify"); + } - public static boolean mcgod(Permissible permissible) { return permissible.hasPermission("mcmmo.commands.mcgod"); } - public static boolean mcgodOthers(Permissible permissible) { return permissible.hasPermission("mcmmo.commands.mcgod.others"); } + public static boolean hardcoreToggle(Permissible permissible) { + return permissible.hasPermission("mcmmo.commands.hardcore.toggle"); + } - public static boolean mcmmoDescription(Permissible permissible) { return permissible.hasPermission("mcmmo.commands.mcmmo.description"); } - public static boolean mcmmoHelp(Permissible permissible) { return permissible.hasPermission("mcmmo.commands.mcmmo.help"); } + public static boolean inspect(Permissible permissible) { + return (permissible.hasPermission("mcmmo.commands.inspect")); + } - public static boolean mcrank(Permissible permissible) { return (permissible.hasPermission("mcmmo.commands.mcrank")); } - public static boolean mcrankOthers(Permissible permissible) { return (permissible.hasPermission("mcmmo.commands.mcrank.others")); } - public static boolean mcrankFar(Permissible permissible) { return (permissible.hasPermission("mcmmo.commands.mcrank.others.far")); } - public static boolean mcrankOffline(Permissible permissible) { return (permissible.hasPermission("mcmmo.commands.mcrank.others.offline")); } + public static boolean inspectFar(Permissible permissible) { + return (permissible.hasPermission("mcmmo.commands.inspect.far")); + } - public static boolean mcrefresh(Permissible permissible) { return (permissible.hasPermission("mcmmo.commands.mcrefresh")); } - public static boolean mcrefreshOthers(Permissible permissible) { return (permissible.hasPermission("mcmmo.commands.mcrefresh.others")); } + public static boolean inspectHidden(Permissible permissible) { + return (permissible.hasPermission("mcmmo.commands.inspect.hidden")); + } - public static boolean mctop(Permissible permissible, PrimarySkillType skill) { return permissible.hasPermission("mcmmo.commands.mctop." + skill.toString().toLowerCase(Locale.ENGLISH)); } + public static boolean mcability(Permissible permissible) { + return (permissible.hasPermission("mcmmo.commands.mcability")); + } - public static boolean mmoedit(Permissible permissible) { return permissible.hasPermission("mcmmo.commands.mmoedit"); } - public static boolean mmoeditOthers(Permissible permissible) { return permissible.hasPermission("mcmmo.commands.mmoedit.others"); } + public static boolean mcabilityOthers(Permissible permissible) { + return (permissible.hasPermission("mcmmo.commands.mcability.others")); + } - public static boolean skillreset(Permissible permissible) { return permissible.hasPermission("mcmmo.commands.skillreset"); } - public static boolean skillreset(Permissible permissible, PrimarySkillType skill) { return permissible.hasPermission("mcmmo.commands.skillreset." + skill.toString().toLowerCase(Locale.ENGLISH)); } - public static boolean skillresetOthers(Permissible permissible) { return permissible.hasPermission("mcmmo.commands.skillreset.others"); } - public static boolean skillresetOthers(Permissible permissible, PrimarySkillType skill) { return permissible.hasPermission("mcmmo.commands.skillreset.others." + skill.toString().toLowerCase(Locale.ENGLISH)); } + public static boolean adminChatSpy(Permissible permissible) { + return permissible.hasPermission("mcmmo.commands.mcchatspy"); + } - public static boolean xplock(Permissible permissible, PrimarySkillType skill) { return permissible.hasPermission("mcmmo.commands.xplock." + skill.toString().toLowerCase(Locale.ENGLISH)); } + public static boolean adminChatSpyOthers(Permissible permissible) { + return permissible.hasPermission("mcmmo.commands.mcchatspy.others"); + } - public static boolean xprateSet(Permissible permissible) { return permissible.hasPermission("mcmmo.commands.xprate.set"); } - public static boolean xprateReset(Permissible permissible) { return permissible.hasPermission("mcmmo.commands.xprate.reset"); } + public static boolean mcgod(Permissible permissible) { + return permissible.hasPermission("mcmmo.commands.mcgod"); + } - public static boolean mcpurge(Permissible permissible) { return permissible.hasPermission("mcmmo.commands.mcpurge"); } - public static boolean mcremove(Permissible permissible) { return permissible.hasPermission("mcmmo.commands.mcremove"); } - public static boolean mmoupdate(Permissible permissible) { return permissible.hasPermission("mcmmo.commands.mmoupdate"); } - public static boolean reloadlocale(Permissible permissible) { return permissible.hasPermission("mcmmo.commands.reloadlocale"); } + public static boolean mcgodOthers(Permissible permissible) { + return permissible.hasPermission("mcmmo.commands.mcgod.others"); + } + + public static boolean mcmmoDescription(Permissible permissible) { + return permissible.hasPermission("mcmmo.commands.mcmmo.description"); + } + + public static boolean mcmmoHelp(Permissible permissible) { + return permissible.hasPermission("mcmmo.commands.mcmmo.help"); + } + + public static boolean mcrank(Permissible permissible) { + return (permissible.hasPermission("mcmmo.commands.mcrank")); + } + + public static boolean mcrankOthers(Permissible permissible) { + return (permissible.hasPermission("mcmmo.commands.mcrank.others")); + } + + public static boolean mcrankFar(Permissible permissible) { + return (permissible.hasPermission("mcmmo.commands.mcrank.others.far")); + } + + public static boolean mcrankOffline(Permissible permissible) { + return (permissible.hasPermission("mcmmo.commands.mcrank.others.offline")); + } + + public static boolean mcrefresh(Permissible permissible) { + return (permissible.hasPermission("mcmmo.commands.mcrefresh")); + } + + public static boolean mcrefreshOthers(Permissible permissible) { + return (permissible.hasPermission("mcmmo.commands.mcrefresh.others")); + } + + public static boolean mctop(Permissible permissible, PrimarySkillType skill) { + return permissible.hasPermission( + "mcmmo.commands.mctop." + skill.toString().toLowerCase(Locale.ENGLISH)); + } + + public static boolean mmoedit(Permissible permissible) { + return permissible.hasPermission("mcmmo.commands.mmoedit"); + } + + public static boolean mmoeditOthers(Permissible permissible) { + return permissible.hasPermission("mcmmo.commands.mmoedit.others"); + } + + public static boolean skillreset(Permissible permissible) { + return permissible.hasPermission("mcmmo.commands.skillreset"); + } + + public static boolean skillreset(Permissible permissible, PrimarySkillType skill) { + return permissible.hasPermission( + "mcmmo.commands.skillreset." + skill.toString().toLowerCase(Locale.ENGLISH)); + } + + public static boolean skillresetOthers(Permissible permissible) { + return permissible.hasPermission("mcmmo.commands.skillreset.others"); + } + + public static boolean skillresetOthers(Permissible permissible, PrimarySkillType skill) { + return permissible.hasPermission( + "mcmmo.commands.skillreset.others." + skill.toString().toLowerCase(Locale.ENGLISH)); + } + + public static boolean xplock(Permissible permissible, PrimarySkillType skill) { + return permissible.hasPermission( + "mcmmo.commands.xplock." + skill.toString().toLowerCase(Locale.ENGLISH)); + } + + public static boolean xprateSet(Permissible permissible) { + return permissible.hasPermission("mcmmo.commands.xprate.set"); + } + + public static boolean xprateReset(Permissible permissible) { + return permissible.hasPermission("mcmmo.commands.xprate.reset"); + } + + public static boolean mcpurge(Permissible permissible) { + return permissible.hasPermission("mcmmo.commands.mcpurge"); + } + + public static boolean mcremove(Permissible permissible) { + return permissible.hasPermission("mcmmo.commands.mcremove"); + } + + public static boolean mmoupdate(Permissible permissible) { + return permissible.hasPermission("mcmmo.commands.mmoupdate"); + } + + public static boolean reloadlocale(Permissible permissible) { + return permissible.hasPermission("mcmmo.commands.reloadlocale"); + } /* * PERKS @@ -103,157 +236,354 @@ public final class Permissions { /* BYPASS PERKS */ - public static boolean hasRepairEnchantBypassPerk(Permissible permissible) { return permissible.hasPermission("mcmmo.perks.bypass.repairenchant"); } - public static boolean hasSalvageEnchantBypassPerk(Permissible permissible) { return permissible.hasPermission("mcmmo.perks.bypass.salvageenchant"); } + public static boolean hasRepairEnchantBypassPerk(Permissible permissible) { + return permissible.hasPermission("mcmmo.perks.bypass.repairenchant"); + } - public static boolean lucky(Permissible permissible, PrimarySkillType skill) { return permissible.hasPermission("mcmmo.perks.lucky." + skill.toString().toLowerCase(Locale.ENGLISH)); } + public static boolean hasSalvageEnchantBypassPerk(Permissible permissible) { + return permissible.hasPermission("mcmmo.perks.bypass.salvageenchant"); + } + + public static boolean lucky(Permissible permissible, PrimarySkillType skill) { + return permissible.hasPermission( + "mcmmo.perks.lucky." + skill.toString().toLowerCase(Locale.ENGLISH)); + } /* XP PERKS */ - public static boolean quadrupleXp(Permissible permissible, PrimarySkillType skill) { + public static boolean quadrupleXp(Permissible permissible, PrimarySkillType skill) { return permissible.hasPermission("mcmmo.perks.xp.quadruple.all") - || permissible.hasPermission("mcmmo.perks.xp.quadruple." + skill.toString().toLowerCase(Locale.ENGLISH)); + || permissible.hasPermission( + "mcmmo.perks.xp.quadruple." + skill.toString().toLowerCase(Locale.ENGLISH)); } - - public static boolean tripleXp(Permissible permissible, PrimarySkillType skill) { + + public static boolean tripleXp(Permissible permissible, PrimarySkillType skill) { return permissible.hasPermission("mcmmo.perks.xp.triple.all") - || permissible.hasPermission("mcmmo.perks.xp.triple." + skill.toString().toLowerCase(Locale.ENGLISH)); + || permissible.hasPermission( + "mcmmo.perks.xp.triple." + skill.toString().toLowerCase(Locale.ENGLISH)); } - - public static boolean doubleAndOneHalfXp(Permissible permissible, PrimarySkillType skill) { + + public static boolean doubleAndOneHalfXp(Permissible permissible, PrimarySkillType skill) { return permissible.hasPermission("mcmmo.perks.xp.150percentboost.all") - || permissible.hasPermission("mcmmo.perks.xp.150percentboost." + skill.toString().toLowerCase(Locale.ENGLISH)); + || permissible.hasPermission( + "mcmmo.perks.xp.150percentboost." + skill.toString().toLowerCase(Locale.ENGLISH)); } - - public static boolean doubleXp(Permissible permissible, PrimarySkillType skill) { + + public static boolean doubleXp(Permissible permissible, PrimarySkillType skill) { return permissible.hasPermission("mcmmo.perks.xp.double.all") - || permissible.hasPermission("mcmmo.perks.xp.double." + skill.toString().toLowerCase(Locale.ENGLISH)); + || permissible.hasPermission( + "mcmmo.perks.xp.double." + skill.toString().toLowerCase(Locale.ENGLISH)); } - - public static boolean oneAndOneHalfXp(Permissible permissible, PrimarySkillType skill) { + + public static boolean oneAndOneHalfXp(Permissible permissible, PrimarySkillType skill) { return permissible.hasPermission("mcmmo.perks.xp.50percentboost.all") - || permissible.hasPermission("mcmmo.perks.xp.50percentboost." + skill.toString().toLowerCase(Locale.ENGLISH)); + || permissible.hasPermission( + "mcmmo.perks.xp.50percentboost." + skill.toString().toLowerCase(Locale.ENGLISH)); } public static boolean oneAndAQuarterXp(Permissible permissible, PrimarySkillType skill) { return permissible.hasPermission("mcmmo.perks.xp.25percentboost.all") - || permissible.hasPermission("mcmmo.perks.xp.25percentboost." + skill.toString().toLowerCase(Locale.ENGLISH)); + || permissible.hasPermission( + "mcmmo.perks.xp.25percentboost." + skill.toString().toLowerCase(Locale.ENGLISH)); } - public static boolean oneAndOneTenthXp(Permissible permissible, PrimarySkillType skill) { + public static boolean oneAndOneTenthXp(Permissible permissible, PrimarySkillType skill) { return permissible.hasPermission("mcmmo.perks.xp.10percentboost.all") - || permissible.hasPermission("mcmmo.perks.xp.10percentboost." + skill.toString().toLowerCase(Locale.ENGLISH)); + || permissible.hasPermission( + "mcmmo.perks.xp.10percentboost." + skill.toString().toLowerCase(Locale.ENGLISH)); } public static boolean customXpBoost(Permissible permissible, PrimarySkillType skill) { return permissible.hasPermission("mcmmo.perks.xp.customboost.all") - || permissible.hasPermission("mcmmo.perks.xp.customboost." + skill.toString().toLowerCase(Locale.ENGLISH)); + || permissible.hasPermission( + "mcmmo.perks.xp.customboost." + skill.toString().toLowerCase(Locale.ENGLISH)); } /* ACTIVATION PERKS */ - public static boolean twelveSecondActivationBoost(Permissible permissible) { return permissible.hasPermission("mcmmo.perks.activationtime.twelveseconds"); } - public static boolean eightSecondActivationBoost(Permissible permissible) { return permissible.hasPermission("mcmmo.perks.activationtime.eightseconds"); } - public static boolean fourSecondActivationBoost(Permissible permissible) { return permissible.hasPermission("mcmmo.perks.activationtime.fourseconds"); } + public static boolean twelveSecondActivationBoost(Permissible permissible) { + return permissible.hasPermission("mcmmo.perks.activationtime.twelveseconds"); + } + + public static boolean eightSecondActivationBoost(Permissible permissible) { + return permissible.hasPermission("mcmmo.perks.activationtime.eightseconds"); + } + + public static boolean fourSecondActivationBoost(Permissible permissible) { + return permissible.hasPermission("mcmmo.perks.activationtime.fourseconds"); + } /* COOLDOWN PERKS */ - public static boolean halvedCooldowns(Permissible permissible) { return permissible.hasPermission("mcmmo.perks.cooldowns.halved"); } - public static boolean thirdedCooldowns(Permissible permissible) { return permissible.hasPermission("mcmmo.perks.cooldowns.thirded"); } - public static boolean quarteredCooldowns(Permissible permissible) { return permissible.hasPermission("mcmmo.perks.cooldowns.quartered"); } + public static boolean halvedCooldowns(Permissible permissible) { + return permissible.hasPermission("mcmmo.perks.cooldowns.halved"); + } + + public static boolean thirdedCooldowns(Permissible permissible) { + return permissible.hasPermission("mcmmo.perks.cooldowns.thirded"); + } + + public static boolean quarteredCooldowns(Permissible permissible) { + return permissible.hasPermission("mcmmo.perks.cooldowns.quartered"); + } /* * SKILLS */ - 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()); } + 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(@Nullable Permissible permissible, + @NotNull SubSkillType subSkillType) { + if (permissible == null) { + return false; + } + return permissible.hasPermission(subSkillType.getPermissionNodeAddress()); + } + + public static boolean isSubSkillEnabled(@Nullable McMMOPlayer permissible, + @NotNull SubSkillType subSkillType) { + if (permissible == null) { + return false; + } + + return isSubSkillEnabled(permissible.getPlayer(), subSkillType); + } /* ACROBATICS */ - public static boolean dodge(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.acrobatics.dodge"); } - public static boolean gracefulRoll(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.acrobatics.gracefulroll"); } - public static boolean roll(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.acrobatics.roll"); } + public static boolean dodge(Permissible permissible) { + return permissible.hasPermission("mcmmo.ability.acrobatics.dodge"); + } + + public static boolean gracefulRoll(Permissible permissible) { + return permissible.hasPermission("mcmmo.ability.acrobatics.gracefulroll"); + } + + public static boolean roll(Permissible permissible) { + return permissible.hasPermission("mcmmo.ability.acrobatics.roll"); + } /* ALCHEMY */ - public static boolean catalysis(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.alchemy.catalysis"); } - public static boolean concoctions(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.alchemy.concoctions"); } + public static boolean catalysis(Permissible permissible) { + return permissible.hasPermission("mcmmo.ability.alchemy.catalysis"); + } + + public static boolean concoctions(Permissible permissible) { + return permissible.hasPermission("mcmmo.ability.alchemy.concoctions"); + } /* ARCHERY */ - 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"); } + 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"); + } /* AXES */ - public static boolean skullSplitter(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.axes.skullsplitter"); } + public static boolean skullSplitter(Permissible permissible) { + return permissible.hasPermission("mcmmo.ability.axes.skullsplitter"); + } /* EXCAVATION */ - public static boolean gigaDrillBreaker(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.excavation.gigadrillbreaker"); } + public static boolean gigaDrillBreaker(Permissible permissible) { + return permissible.hasPermission("mcmmo.ability.excavation.gigadrillbreaker"); + } /* HERBALISM */ - public static boolean greenTerra(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.herbalism.greenterra"); } - public static boolean greenThumbBlock(Permissible permissible, Material material) { return permissible.hasPermission("mcmmo.ability.herbalism.greenthumb.blocks." + material.toString().replace("_", "").toLowerCase(Locale.ENGLISH)); } - public static boolean greenThumbPlant(Permissible permissible, Material material) { return permissible.hasPermission("mcmmo.ability.herbalism.greenthumb.plants." + material.toString().replace("_", "").toLowerCase(Locale.ENGLISH)); } + public static boolean greenTerra(Permissible permissible) { + return permissible.hasPermission("mcmmo.ability.herbalism.greenterra"); + } + + public static boolean greenThumbBlock(Permissible permissible, Material material) { + return permissible.hasPermission( + "mcmmo.ability.herbalism.greenthumb.blocks." + material.toString().replace("_", "") + .toLowerCase(Locale.ENGLISH)); + } + + public static boolean greenThumbPlant(Permissible permissible, Material material) { + return permissible.hasPermission( + "mcmmo.ability.herbalism.greenthumb.plants." + material.toString().replace("_", "") + .toLowerCase(Locale.ENGLISH)); + } /* MINING */ - public static boolean biggerBombs(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.mining.blastmining.biggerbombs"); } - public static boolean demolitionsExpertise(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.mining.blastmining.demolitionsexpertise"); } - public static boolean remoteDetonation(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.mining.blastmining.detonate"); } - public static boolean superBreaker(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.mining.superbreaker"); } + public static boolean biggerBombs(Permissible permissible) { + return permissible.hasPermission("mcmmo.ability.mining.blastmining.biggerbombs"); + } + + public static boolean demolitionsExpertise(Permissible permissible) { + return permissible.hasPermission("mcmmo.ability.mining.blastmining.demolitionsexpertise"); + } + + public static boolean remoteDetonation(Permissible permissible) { + return permissible.hasPermission("mcmmo.ability.mining.blastmining.detonate"); + } + + public static boolean superBreaker(Permissible permissible) { + return permissible.hasPermission("mcmmo.ability.mining.superbreaker"); + } /* REPAIR */ - public static boolean repairItemType(Permissible permissible, ItemType repairItemType) { return permissible.hasPermission("mcmmo.ability.repair." + repairItemType.toString().toLowerCase(Locale.ENGLISH) + "repair"); } - public static boolean repairMaterialType(Permissible permissible, MaterialType repairMaterialType) { return permissible.hasPermission("mcmmo.ability.repair." + repairMaterialType.toString().toLowerCase(Locale.ENGLISH) + "repair"); } + public static boolean repairItemType(Permissible permissible, ItemType repairItemType) { + return permissible.hasPermission( + "mcmmo.ability.repair." + repairItemType.toString().toLowerCase(Locale.ENGLISH) + + "repair"); + } + + public static boolean repairMaterialType(Permissible permissible, + MaterialType repairMaterialType) { + return permissible.hasPermission( + "mcmmo.ability.repair." + repairMaterialType.toString().toLowerCase(Locale.ENGLISH) + + "repair"); + } /* SALVAGE */ - public static boolean arcaneSalvage(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.salvage.arcanesalvage"); } + public static boolean arcaneSalvage(Permissible permissible) { + return permissible.hasPermission("mcmmo.ability.salvage.arcanesalvage"); + } - public static boolean salvageItemType(Permissible permissible, ItemType salvageItemType) { return permissible.hasPermission("mcmmo.ability.salvage." + salvageItemType.toString().toLowerCase(Locale.ENGLISH) + "salvage"); } - public static boolean salvageMaterialType(Permissible permissible, MaterialType salvageMaterialType) { return permissible.hasPermission("mcmmo.ability.salvage." + salvageMaterialType.toString().toLowerCase(Locale.ENGLISH) + "salvage"); } + public static boolean salvageItemType(Permissible permissible, ItemType salvageItemType) { + return permissible.hasPermission( + "mcmmo.ability.salvage." + salvageItemType.toString().toLowerCase(Locale.ENGLISH) + + "salvage"); + } + + public static boolean salvageMaterialType(Permissible permissible, + MaterialType salvageMaterialType) { + return permissible.hasPermission("mcmmo.ability.salvage." + salvageMaterialType.toString() + .toLowerCase(Locale.ENGLISH) + "salvage"); + } /* SMELTING */ - public static boolean fluxMining(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.smelting.fluxmining"); } - public static boolean fuelEfficiency(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.smelting.fuelefficiency"); } + public static boolean fluxMining(Permissible permissible) { + return permissible.hasPermission("mcmmo.ability.smelting.fluxmining"); + } + + public static boolean fuelEfficiency(Permissible permissible) { + return permissible.hasPermission("mcmmo.ability.smelting.fuelefficiency"); + } /* SWORDS */ - public static boolean serratedStrikes(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.swords.serratedstrikes"); } + public static boolean serratedStrikes(Permissible permissible) { + return permissible.hasPermission("mcmmo.ability.swords.serratedstrikes"); + } /* TAMING */ - public static boolean callOfTheWild(Permissible permissible, EntityType type) { return permissible.hasPermission("mcmmo.ability.taming.callofthewild." + type.toString().toLowerCase(Locale.ENGLISH)); } + public static boolean callOfTheWild(Permissible permissible, EntityType type) { + return permissible.hasPermission("mcmmo.ability.taming.callofthewild." + type.toString() + .toLowerCase(Locale.ENGLISH)); + } /* UNARMED */ - public static boolean berserk(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.unarmed.berserk"); } + public static boolean berserk(Permissible permissible) { + return permissible.hasPermission("mcmmo.ability.unarmed.berserk"); + } /* WOODCUTTING */ - public static boolean treeFeller(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.woodcutting.treefeller"); } + public static boolean treeFeller(Permissible permissible) { + return permissible.hasPermission("mcmmo.ability.woodcutting.treefeller"); + } + + /* CROSSBOWS */ + 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 tridentsLimitBreak(Permissible permissible) { + return permissible.hasPermission("mcmmo.ability.tridents.superability"); + } + + /* MACES */ + public static boolean macesLimitBreak(Permissible permissible) { + return permissible.hasPermission("mcmmo.ability.maces.limitbreak"); + } /* * PARTY */ - public static boolean partySizeBypass(Permissible permissible) { return permissible.hasPermission("mcmmo.bypass.partylimit" ); } - public static boolean party(Permissible permissible) { return permissible.hasPermission("mcmmo.commands.party"); } - public static boolean partySubcommand(Permissible permissible, PartySubcommandType subcommand) { return permissible.hasPermission("mcmmo.commands.party." + subcommand.toString().toLowerCase(Locale.ENGLISH)); } - public static boolean friendlyFire(Permissible permissible) { return permissible.hasPermission("mcmmo.party.friendlyfire"); } + public static boolean partySizeBypass(Permissible permissible) { + return permissible.hasPermission("mcmmo.bypass.partylimit"); + } + + public static boolean party(Permissible permissible) { + return permissible.hasPermission("mcmmo.commands.party"); + } + + public static boolean partySubcommand(Permissible permissible, PartySubcommandType subcommand) { + return permissible.hasPermission( + "mcmmo.commands.party." + subcommand.toString().toLowerCase(Locale.ENGLISH)); + } + + public static boolean friendlyFire(Permissible permissible) { + return permissible.hasPermission("mcmmo.party.friendlyfire"); + } /* TELEPORT */ - public static boolean partyTeleportSend(Permissible permissible) { return permissible.hasPermission("mcmmo.commands.ptp.send"); } - public static boolean partyTeleportAccept(Permissible permissible) { return permissible.hasPermission("mcmmo.commands.ptp.accept"); } - public static boolean partyTeleportAcceptAll(Permissible permissible) { return permissible.hasPermission("mcmmo.commands.ptp.acceptall"); } - public static boolean partyTeleportToggle(Permissible permissible) { return permissible.hasPermission("mcmmo.commands.ptp.toggle"); } + public static boolean partyTeleportSend(Permissible permissible) { + return permissible.hasPermission("mcmmo.commands.ptp.send"); + } - public static boolean partyTeleportAllWorlds(Permissible permissible) { return permissible.hasPermission("mcmmo.commands.ptp.world.all"); } - public static boolean partyTeleportWorld(Permissible permissible, World world) { return permissible.hasPermission("mcmmo.commands.ptp.world." + world.getName()); } + public static boolean partyTeleportAccept(Permissible permissible) { + return permissible.hasPermission("mcmmo.commands.ptp.accept"); + } + + public static boolean partyTeleportAcceptAll(Permissible permissible) { + return permissible.hasPermission("mcmmo.commands.ptp.acceptall"); + } + + public static boolean partyTeleportToggle(Permissible permissible) { + return permissible.hasPermission("mcmmo.commands.ptp.toggle"); + } + + public static boolean partyTeleportAllWorlds(Permissible permissible) { + return permissible.hasPermission("mcmmo.commands.ptp.world.all"); + } + + public static boolean partyTeleportWorld(Permissible permissible, World world) { + return permissible.hasPermission("mcmmo.commands.ptp.world." + world.getName()); + } public static void generateWorldTeleportPermissions() { Server server = mcMMO.p.getServer(); PluginManager pluginManager = server.getPluginManager(); for (World world : server.getWorlds()) { - addDynamicPermission("mcmmo.commands.ptp.world." + world.getName(), PermissionDefault.OP, pluginManager); + addDynamicPermission("mcmmo.commands.ptp.world." + world.getName(), + PermissionDefault.OP, pluginManager); } } - private static void addDynamicPermission(String permissionName, PermissionDefault permissionDefault, PluginManager pluginManager) { + private static void addDynamicPermission(String permissionName, + PermissionDefault permissionDefault, PluginManager pluginManager) { Permission permission = new Permission(permissionName); 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/java/com/gmail/nossr50/util/PotionCompatibilityType.java b/src/main/java/com/gmail/nossr50/util/PotionCompatibilityType.java new file mode 100644 index 000000000..6981644b3 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/util/PotionCompatibilityType.java @@ -0,0 +1,6 @@ +package com.gmail.nossr50.util; + +public enum PotionCompatibilityType { + PRE_1_20_5, + MODERN +} diff --git a/src/main/java/com/gmail/nossr50/util/PotionEffectUtil.java b/src/main/java/com/gmail/nossr50/util/PotionEffectUtil.java new file mode 100644 index 000000000..d84a969d5 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/util/PotionEffectUtil.java @@ -0,0 +1,95 @@ +package com.gmail.nossr50.util; + +import org.bukkit.potion.PotionEffectType; + +/** + * This util class is responsible for mapping the correct potion effect types for the server + * version. This is necessary because the potion effect types have changed between versions. This + * util class will provide the correct potion effect types for the server version. + */ +final public class PotionEffectUtil { + private static final PotionEffectType haste; + private static final PotionEffectType nausea; + + static { + haste = findHastePotionEffectType(); + nausea = findNauseaPotionEffectType(); + } + + private PotionEffectUtil() { + // Utility class + } + + private static PotionEffectType findNauseaPotionEffectType() { + if (getNauseaLegacy() != null) { + return getNauseaLegacy(); + } else { + return getNauseaModern(); + } + } + + private static PotionEffectType getNauseaModern() { + try { + return (PotionEffectType) PotionEffectType.class.getField("NAUSEA").get(null); + } catch (NoSuchFieldException | IllegalAccessException e) { + return null; + } + } + + private static PotionEffectType getNauseaLegacy() { + try { + Object potionEffectTypeWrapper = PotionEffectType.class.getField("CONFUSION").get(null); + return (PotionEffectType) potionEffectTypeWrapper; + } catch (IllegalAccessException | NoSuchFieldException e) { + return null; + } + } + + private static PotionEffectType findHastePotionEffectType() { + if (getHasteLegacy() != null) { + return getHasteLegacy(); + } else if (getHasteModern() != null) { + return getHasteModern(); + } else { + throw new IllegalStateException("Unable to find the Haste PotionEffectType"); + } + } + + private static PotionEffectType getHasteLegacy() { + try { + Object potionEffectTypeWrapper = PotionEffectType.class.getField("FAST_DIGGING") + .get(null); + return (PotionEffectType) potionEffectTypeWrapper; + } catch (IllegalAccessException | NoSuchFieldException e) { + return null; + } + } + + private static PotionEffectType getHasteModern() { + try { + return (PotionEffectType) PotionEffectType.class.getField("HASTE").get(null); + } catch (NoSuchFieldException | IllegalAccessException e) { + return null; + } + } + + /** + * Get the Haste potion effect type. This will return the correct potion effect type for the + * server version. + * + * @return The Haste potion effect type. + */ + public static PotionEffectType getHastePotionEffectType() { + return haste; + } + + /** + * Get the Nausea potion effect type. This will return the correct potion effect type for the + * server version. + * + * @return The Nausea potion effect type. + */ + public static PotionEffectType getNauseaPotionEffectType() { + return nausea; + } +} diff --git a/src/main/java/com/gmail/nossr50/util/PotionUtil.java b/src/main/java/com/gmail/nossr50/util/PotionUtil.java new file mode 100644 index 000000000..9fee5840c --- /dev/null +++ b/src/main/java/com/gmail/nossr50/util/PotionUtil.java @@ -0,0 +1,569 @@ +package com.gmail.nossr50.util; + +import com.gmail.nossr50.mcMMO; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import org.bukkit.NamespacedKey; +import org.bukkit.inventory.meta.PotionMeta; +import org.bukkit.potion.PotionEffectType; +import org.bukkit.potion.PotionType; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class PotionUtil { + // Some of the old potion types got renamed, our configs can still contain these old names + private static final Map legacyPotionTypes = new HashMap<>(); + private static final Method methodPotionTypeGetKey; + private static final Method methodPotionTypeGetEffectType; + private static final Method methodPotionTypeGetPotionEffects; + private static final Method methodPotionDataIsUpgraded; + private static final Method methodPotionDataIsExtended; + private static final Method methodPotionDataGetType; + private static final Method methodPotionMetaGetBasePotionData; + private static final Method methodPotionMetaSetBasePotionData; + private static final Method methodPotionMetaGetBasePotionType; + private static final Method methodPotionMetaSetBasePotionType; + private static final Class potionDataClass; + + public static final String STRONG = "STRONG"; + public static final String LONG = "LONG"; + public static final String WATER_POTION_TYPE_STR = "WATER"; + + private static final PotionCompatibilityType COMPATIBILITY_MODE; + + static { + potionDataClass = getPotionDataClass(); + // Uncraftable doesn't exist in modern versions + // It served as a potion that didn't craft into anything else so it didn't conflict with vanilla systems + // Instead we will use Mundane, which doesn't make anything in vanilla systems + legacyPotionTypes.put("UNCRAFTABLE", "MUNDANE"); + legacyPotionTypes.put("JUMP", "LEAPING"); + legacyPotionTypes.put("SPEED", "SWIFTNESS"); + legacyPotionTypes.put("INSTANT_HEAL", "HEALING"); + legacyPotionTypes.put("INSTANT_DAMAGE", "HARMING"); + legacyPotionTypes.put("REGEN", "REGENERATION"); + methodPotionTypeGetKey = getKeyMethod(); + methodPotionDataIsUpgraded = getPotionDataIsUpgraded(); + methodPotionDataIsExtended = getPotionDataIsExtended(); + methodPotionMetaGetBasePotionData = getGetBasePotionDataMethod(); + methodPotionMetaGetBasePotionType = getGetBasePotionTypeMethod(); + methodPotionMetaSetBasePotionType = getMethodPotionMetaSetBasePotionType(); + methodPotionDataGetType = getPotionDataGetTypeMethod(); + methodPotionTypeGetEffectType = getPotionTypeEffectTypeMethod(); + methodPotionTypeGetPotionEffects = getPotionTypeGetPotionEffectsMethod(); + methodPotionMetaSetBasePotionData = setBasePotionData(); + + if (potionDataClass != null + && !mcMMO.getCompatibilityManager().getMinecraftGameVersion().isAtLeast(1, 20, 5)) { + COMPATIBILITY_MODE = PotionCompatibilityType.PRE_1_20_5; + } else { + COMPATIBILITY_MODE = PotionCompatibilityType.MODERN; + } + } + + /** + * Derive a potion from a partial name, and whether it should be upgraded or extended. + * + * @param partialName potion type as a string, can be a substring of the potion type but must + * match exactly + * @return The potion type + */ + public static PotionType matchPotionType(String partialName, boolean isUpgraded, + boolean isExtended) { + if (COMPATIBILITY_MODE == PotionCompatibilityType.PRE_1_20_5) { + return matchLegacyPotionType(partialName); + } else { + final String updatedName = convertLegacyNames(partialName).toUpperCase(Locale.ENGLISH); + return Arrays.stream(PotionType.values()) + .filter(potionType -> getKeyGetKey(potionType) + .toUpperCase(Locale.ENGLISH).contains(updatedName)) + .filter(potionType -> isUpgraded == potionType.name() + .toUpperCase(Locale.ENGLISH).startsWith(STRONG + "_")) + .filter(potionType -> isExtended == potionType.name() + .toUpperCase(Locale.ENGLISH).startsWith(LONG + "_")) + .findAny().orElse(null); + } + } + + /** + * Legacy matching for {@link PotionType} + * + * @param name The partial name of the potion + * @return The potion type + */ + private static PotionType matchLegacyPotionType(String name) { + return Arrays.stream(PotionType.values()) + .filter(potionType -> getKeyGetKey(potionType).equalsIgnoreCase(name) + || getKeyGetKey(potionType).equalsIgnoreCase(convertLegacyNames(name)) + || potionType.name().equalsIgnoreCase(name) + || potionType.name().equalsIgnoreCase(convertLegacyNames(name))) + .findAny().orElse(null); + } + + private static String convertUpgradedOrExtended(String potionType, boolean isUpgraded, + boolean isExtended) { + if (isUpgraded) { + potionType = STRONG + "_" + potionType; + } + if (isExtended) { + potionType = LONG + "_" + potionType; + } + return potionType; + } + + public static String getKeyGetKey(PotionType potionType) { + try { + if (getKeyMethod() != null) { + NamespacedKey key = (NamespacedKey) methodPotionTypeGetKey.invoke(potionType); + return key.getKey(); + } else { + return potionType.name(); + } + } catch (InvocationTargetException | IllegalAccessException e) { + mcMMO.p.getLogger().warning("Failed to get potion key for " + potionType.name()); + return potionType.name(); + } + } + + private static Class getPotionDataClass() { + try { + return Class.forName("org.bukkit.potion.PotionData"); + } catch (ClassNotFoundException e) { + return null; + } + } + + /** + * Older versions of Spigot do not have getKey() in PotionType We need to check for the + * existence of this method before calling it + * + * @return The getKey method + */ + private static @Nullable Method getKeyMethod() { + try { + return PotionType.class.getMethod("getKey"); + } catch (NoSuchMethodException e) { + return null; + } + } + + private static @Nullable Method setBasePotionData() { + try { + return PotionMeta.class.getMethod("setBasePotionData", potionDataClass); + } catch (NoSuchMethodException e) { + return null; + } + } + + private static Method getMethodPotionMetaSetBasePotionType() { + try { + return PotionMeta.class.getMethod("setBasePotionType", PotionType.class); + } catch (NoSuchMethodException e) { + return null; + } + } + + private static Method getSetBasePotionData() { + try { + return PotionMeta.class.getMethod("setBasePotionData", potionDataClass); + } catch (NoSuchMethodException e) { + return null; + } + } + + private static @Nullable Method getPotionDataIsUpgraded() { + try { + // TODO: Needed? + final Class clazz = Class.forName("org.bukkit.potion.PotionData"); + return clazz.getMethod("isUpgraded"); + } catch (NoSuchMethodException | ClassNotFoundException e) { + return null; + } + } + + private static @Nullable Method getPotionDataIsExtended() { + try { + // TODO: Needed? + final Class clazz = Class.forName("org.bukkit.potion.PotionData"); + return clazz.getMethod("isExtended"); + } catch (NoSuchMethodException | ClassNotFoundException e) { + return null; + } + } + + /** + * Newer versions of Spigot do not have getBasePotionData() in PotionMeta + * + * @return the getBasePotionData method, or null if it does not exist + */ + private static @Nullable Method getGetBasePotionDataMethod() { + try { + return PotionMeta.class.getMethod("getBasePotionData"); + } catch (NoSuchMethodException e) { + return null; + } + } + + private static Method getGetBasePotionTypeMethod() { + try { + return PotionMeta.class.getMethod("getBasePotionType"); + } catch (NoSuchMethodException e) { + return null; + } + } + + private static Method getPotionDataGetTypeMethod() { + try { + final Class clazz = Class.forName("org.bukkit.potion.PotionData"); + return clazz.getMethod("getType"); + } catch (NoSuchMethodException | ClassNotFoundException e) { + return null; + } + } + + private static Method getPotionTypeEffectTypeMethod() { + try { + return PotionType.class.getMethod("getEffectType"); + } catch (NoSuchMethodException e) { + return null; + } + } + + private static Method getPotionTypeGetPotionEffectsMethod() { + try { + return PotionType.class.getMethod("getPotionEffects"); + } catch (NoSuchMethodException e) { + return null; + } + } + + public static String convertPotionConfigName(String legacyName) { + String replacementName = legacyName; + + // Remove generated potions.yml config naming convention + if (replacementName.contains("POTION_OF_")) { + replacementName = replacementName.replace("POTION_OF_", ""); + } + + if (replacementName.contains("_II")) { + replacementName = replacementName.replace("_II", ""); + replacementName = "STRONG_" + replacementName; + } else if (replacementName.contains("_EXTENDED")) { + replacementName = replacementName.replace("_EXTENDED", ""); + replacementName = "LONG_" + replacementName; + } + return replacementName; + } + + public static String convertLegacyNames(String legacyPotionType) { + String modernized = legacyPotionType; + // check for legacy names + for (var key : legacyPotionTypes.keySet()) { + if (modernized.contains(key)) { + // Replace the legacy name with the new name + modernized = modernized.replace(key, legacyPotionTypes.get(key)); + break; + } + } + return modernized; + } + + public static boolean hasLegacyName(String potionType) { + for (var key : legacyPotionTypes.keySet()) { + if (potionType.contains(key)) { + return true; + } + } + return false; + } + + public static boolean isStrong(PotionMeta potionMeta) { + if (methodPotionMetaGetBasePotionData == null) { + return isStrongModern(potionMeta); + } else { + return isStrongLegacy(potionMeta); + } + + } + + public static boolean isLong(PotionMeta potionMeta) { + if (methodPotionMetaGetBasePotionData == null) { + return isLongModern(potionMeta); + } else { + return isLongLegacy(potionMeta); + } + } + + private static boolean isLongLegacy(PotionMeta potionMeta) { + try { + Object potionData = methodPotionMetaGetBasePotionData.invoke(potionMeta); + return (boolean) methodPotionDataIsExtended.invoke(potionData); + } catch (IllegalAccessException | InvocationTargetException e) { + throw new RuntimeException(e); + } + } + + private static boolean isLongModern(PotionMeta potionMeta) { + try { + return getModernPotionTypeKey(potionMeta).getKey().startsWith(LONG); + } catch (IllegalAccessException | InvocationTargetException e) { + throw new RuntimeException(e); + } + } + + private static boolean isStrongLegacy(PotionMeta potionMeta) { + try { + Object potionData = methodPotionMetaGetBasePotionData.invoke(potionMeta); + return (boolean) methodPotionDataIsUpgraded.invoke(potionData); + } catch (IllegalAccessException | InvocationTargetException e) { + throw new RuntimeException(e); + } + } + + private static boolean isStrongModern(PotionMeta potionMeta) { + try { + return getModernPotionTypeKey(potionMeta).getKey().startsWith(STRONG); + } catch (IllegalAccessException | InvocationTargetException e) { + throw new RuntimeException(e); + } + } + + private static NamespacedKey getModernPotionTypeKey(PotionMeta potionMeta) + throws IllegalAccessException, InvocationTargetException { + PotionType potionType = (PotionType) methodPotionMetaGetBasePotionType.invoke(potionMeta); + return (NamespacedKey) methodPotionTypeGetKey.invoke(potionType); + } + + public static boolean isPotionJustWater(PotionMeta potionMeta) { + return isPotionTypeWater(potionMeta) + && !hasBasePotionEffects(potionMeta) + && potionMeta.getCustomEffects().isEmpty(); + } + + public static boolean isPotionTypeWater(@NotNull PotionMeta potionMeta) { + if (COMPATIBILITY_MODE == PotionCompatibilityType.PRE_1_20_5) { + return isPotionTypeWaterLegacy(potionMeta); + } else { + return isPotionTypeWaterModern(potionMeta); + } + } + + public static boolean isPotionType(@NotNull PotionMeta potionMeta, String potionType) { + if (COMPATIBILITY_MODE == PotionCompatibilityType.PRE_1_20_5) { + return isPotionTypeLegacy(potionMeta, potionType); + } else { + return isPotionTypeModern(potionMeta, potionType); + } + } + + public static boolean isPotionTypeWithoutEffects(@NotNull PotionMeta potionMeta, + String potionType) { + return isPotionType(potionMeta, potionType) + && !hasBasePotionEffects(potionMeta) + && potionMeta.getCustomEffects().isEmpty(); + } + + private static boolean isPotionTypeModern(@NotNull PotionMeta potionMeta, String potionType) { + try { + return getModernPotionTypeKey(potionMeta).getKey().equalsIgnoreCase(potionType); + } catch (IllegalAccessException | InvocationTargetException ex) { + throw new RuntimeException(ex); + } + } + + private static boolean isPotionTypeLegacy(@NotNull PotionMeta potionMeta, String potionType) { + try { + Object potionData = methodPotionMetaGetBasePotionData.invoke(potionMeta); + PotionType potionTypeObj = (PotionType) methodPotionDataGetType.invoke(potionData); + return potionTypeObj.name().equalsIgnoreCase(potionType); + } catch (IllegalAccessException | InvocationTargetException ex) { + throw new RuntimeException(ex); + } + } + + private static boolean isPotionTypeWaterLegacy(@NotNull PotionMeta potionMeta) { + try { + Object potionData = methodPotionMetaGetBasePotionData.invoke(potionMeta); + PotionType potionType = (PotionType) methodPotionDataGetType.invoke(potionData); + return potionType.name().equalsIgnoreCase(WATER_POTION_TYPE_STR) + || PotionType.valueOf(WATER_POTION_TYPE_STR) == potionType; + } catch (InvocationTargetException | IllegalAccessException ex) { + throw new RuntimeException(ex); + } + } + + private static boolean isPotionTypeWaterModern(@NotNull PotionMeta potionMeta) { + try { + return getModernPotionTypeKey(potionMeta).getKey() + .equalsIgnoreCase(WATER_POTION_TYPE_STR); + } catch (IllegalAccessException | InvocationTargetException ex) { + throw new RuntimeException(ex); + } + } + + public static boolean samePotionType(PotionMeta potionMeta, PotionMeta otherPotionMeta) { + if (COMPATIBILITY_MODE == PotionCompatibilityType.PRE_1_20_5) { + return samePotionTypeLegacy(potionMeta, otherPotionMeta); + } else { + return samePotionTypeModern(potionMeta, otherPotionMeta); + } + } + + private static boolean samePotionTypeLegacy(PotionMeta potionMeta, PotionMeta otherPotionMeta) { + try { + Object potionData = methodPotionMetaGetBasePotionData.invoke(potionMeta); + Object otherPotionData = methodPotionMetaGetBasePotionData.invoke(otherPotionMeta); + PotionType potionType = (PotionType) methodPotionDataGetType.invoke(potionData); + PotionType otherPotionType = (PotionType) methodPotionDataGetType.invoke( + otherPotionData); + return potionType == otherPotionType; + } catch (IllegalAccessException | InvocationTargetException ex) { + throw new RuntimeException(ex); + } + } + + private static boolean samePotionTypeModern(PotionMeta potionMeta, PotionMeta otherPotionMeta) { + try { + PotionType potionType = (PotionType) methodPotionMetaGetBasePotionType.invoke( + potionMeta); + PotionType otherPotionType = (PotionType) methodPotionMetaGetBasePotionType.invoke( + otherPotionMeta); + return potionType == otherPotionType; + } catch (IllegalAccessException | InvocationTargetException e) { + throw new RuntimeException(e); + } + } + + public static boolean samePotionEffects(PotionMeta potionMeta, PotionMeta otherPotionMeta) { + if (COMPATIBILITY_MODE == PotionCompatibilityType.PRE_1_20_5) { + return true; + } else { + return samePotionEffectsModern(potionMeta, otherPotionMeta); + } + } + + private static boolean samePotionEffectsModern(PotionMeta potionMeta, + PotionMeta otherPotionMeta) { + return potionMeta.getCustomEffects().equals(otherPotionMeta.getCustomEffects()); + } + + public static boolean hasBasePotionEffects(PotionMeta potionMeta) { + if (COMPATIBILITY_MODE == PotionCompatibilityType.PRE_1_20_5) { + return hasBasePotionEffectsLegacy(potionMeta); + } else { + return hasBasePotionEffectsModern(potionMeta); + } + } + + private static boolean hasBasePotionEffectsLegacy(PotionMeta potionMeta) { + try { + Object potionData = methodPotionMetaGetBasePotionData.invoke(potionMeta); + PotionType potionType = (PotionType) methodPotionDataGetType.invoke(potionData); + return methodPotionTypeGetEffectType.invoke(potionType) != null; + } catch (IllegalAccessException | InvocationTargetException ex) { + throw new RuntimeException(ex); + } + } + + private static boolean hasBasePotionEffectsModern(PotionMeta potionMeta) { + try { + PotionType potionType = (PotionType) methodPotionMetaGetBasePotionType.invoke( + potionMeta); + List potionEffectTypeList = (List) methodPotionTypeGetPotionEffects.invoke( + potionType); + return potionEffectTypeList != null && !potionEffectTypeList.isEmpty(); + } catch (IllegalAccessException | InvocationTargetException ex) { + throw new RuntimeException(ex); + } + } + + /** + * Set the base potion type of a potion meta. Note that extended/upgraded are ignored in 1.20.5 + * and later. + * + * @param potionMeta the potion meta + * @param extended true if the potion is extended + * @param upgraded true if the potion is upgraded + */ + public static void setBasePotionType(PotionMeta potionMeta, PotionType potionType, + boolean extended, boolean upgraded) { + if (methodPotionMetaSetBasePotionType == null) { + setBasePotionTypeLegacy(potionMeta, potionType, extended, upgraded); + } else { + setBasePotionTypeModern(potionMeta, potionType); + } + } + + public static void setUpgradedAndExtendedProperties(PotionType potionType, + PotionMeta potionMeta, + boolean isUpgraded, boolean isExtended) { + if (potionDataClass == null || mcMMO.getCompatibilityManager().getMinecraftGameVersion() + .isAtLeast(1, 20, 5)) { + return; + } + + try { + final Object potionData = potionDataClass.getConstructor(PotionType.class, + boolean.class, boolean.class) + .newInstance(potionType, isExtended, isUpgraded); + methodPotionMetaSetBasePotionData.invoke(potionMeta, potionData); + } catch (IllegalAccessException | InvocationTargetException | InstantiationException + | NoSuchMethodException ex) { + throw new RuntimeException(ex); + } + } + + private static void setBasePotionTypeLegacy(PotionMeta potionMeta, PotionType potionType, + boolean extended, + boolean upgraded) { + try { + Object potionData = potionDataClass.getConstructor(PotionType.class, boolean.class, + boolean.class) + .newInstance(potionType, extended, upgraded); + methodPotionMetaSetBasePotionData.invoke(potionMeta, potionData); + } catch (IllegalAccessException | InvocationTargetException | InstantiationException | + NoSuchMethodException ex) { + throw new RuntimeException(ex); + } + } + + private static void setBasePotionTypeModern(PotionMeta potionMeta, PotionType potionType) { + try { + methodPotionMetaSetBasePotionType.invoke(potionMeta, potionType); + } catch (IllegalAccessException | InvocationTargetException ex) { + throw new RuntimeException(ex); + } + } + + public static boolean isPotionDataEqual(PotionMeta potionMeta, PotionMeta otherPotionMeta) { + if (COMPATIBILITY_MODE == PotionCompatibilityType.MODERN) { + return true; // we don't compare data on newer versions + } else { + try { + final Object potionData = methodPotionMetaGetBasePotionData.invoke(potionMeta); + final Object otherPotionData = methodPotionMetaGetBasePotionData.invoke( + otherPotionMeta); + final PotionType potionType = (PotionType) methodPotionDataGetType.invoke( + potionData); + final PotionType otherPotionType = (PotionType) methodPotionDataGetType.invoke( + otherPotionData); + if (potionType != otherPotionType) { + return false; + } + if (methodPotionDataIsExtended.invoke(potionData) + != methodPotionDataIsExtended.invoke(otherPotionData)) { + return false; + } + return methodPotionDataIsUpgraded.invoke(potionData) + == methodPotionDataIsUpgraded.invoke(otherPotionData); + } catch (IllegalAccessException | InvocationTargetException e) { + throw new RuntimeException(e); + } + } + } +} diff --git a/src/main/java/com/gmail/nossr50/util/TransientEntityTracker.java b/src/main/java/com/gmail/nossr50/util/TransientEntityTracker.java index 8b258d03a..08bbbe3a7 100644 --- a/src/main/java/com/gmail/nossr50/util/TransientEntityTracker.java +++ b/src/main/java/com/gmail/nossr50/util/TransientEntityTracker.java @@ -1,14 +1,19 @@ package com.gmail.nossr50.util; +import static java.util.stream.Collectors.toSet; + import com.gmail.nossr50.datatypes.skills.subskills.taming.CallOfTheWildType; -import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.skills.taming.TrackedTamingEntity; import com.gmail.nossr50.util.player.NotificationManager; import com.gmail.nossr50.util.skills.ParticleEffectUtils; import com.gmail.nossr50.util.text.StringUtils; -import com.google.common.collect.ImmutableSet; -import org.bukkit.Bukkit; -import org.bukkit.Chunk; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; import org.bukkit.Location; import org.bukkit.Sound; import org.bukkit.entity.LivingEntity; @@ -16,243 +21,45 @@ import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.*; - public class TransientEntityTracker { - //These two are updated in step with each other - private final @NotNull HashMap>> perPlayerTransientEntityMap; - private final @NotNull HashSet chunkLookupCache; + final @NotNull Map> playerSummonedEntityTracker; + // used for fast lookups during chunk unload events + final @NotNull Set entityLookupCache; public TransientEntityTracker() { - perPlayerTransientEntityMap = new HashMap<>(); - chunkLookupCache = new HashSet<>(); + this.playerSummonedEntityTracker = new ConcurrentHashMap<>(); + this.entityLookupCache = ConcurrentHashMap.newKeySet(); } - public synchronized @NotNull HashSet getChunkLookupCache() { - return chunkLookupCache; + public void initPlayer(@NotNull Player player) { + playerSummonedEntityTracker.computeIfAbsent(player.getUniqueId(), + __ -> ConcurrentHashMap.newKeySet()); } - public synchronized @NotNull HashMap>> getPerPlayerTransientEntityMap() { - return perPlayerTransientEntityMap; - } - - public synchronized void initPlayer(@NotNull Player player) { - if (!isPlayerRegistered(player.getUniqueId())) { - registerPlayer(player.getUniqueId()); - } - } - - /** - * Removes a player from the tracker - * - * @param playerUUID target player - */ - public synchronized void cleanupPlayer(@NotNull UUID playerUUID) { - cleanPlayer(null, playerUUID); - } - - /** - * Removes a player from the tracker - * - * @param player target player - */ - public synchronized void cleanupPlayer(@NotNull Player player) { + public void cleanupPlayer(@NotNull Player player) { cleanPlayer(player, player.getUniqueId()); } - /** - * Removes a player from the tracker - * - * @param player target player - * @param playerUUID target player UUID - */ - private void cleanPlayer(@Nullable Player player, @NotNull UUID playerUUID) { - cleanupAllSummons(player, player.getUniqueId()); - removePlayerFromMap(playerUUID); + public int getActiveSummonsForPlayerOfType(@NotNull UUID playerUUID, + @NotNull CallOfTheWildType callOfTheWildType) { + return getTrackedEntities(playerUUID, callOfTheWildType).stream() + .filter(tte -> tte.getLivingEntity().isValid()) + .mapToInt(tte -> 1) + .sum(); } - private void removePlayerFromMap(@NotNull UUID playerUUID) { - getPerPlayerTransientEntityMap().remove(playerUUID); + public void addSummon(@NotNull UUID playerUUID, + @NotNull TrackedTamingEntity trackedTamingEntity) { + playerSummonedEntityTracker.computeIfAbsent(playerUUID, __ -> ConcurrentHashMap.newKeySet()) + .add(trackedTamingEntity); + entityLookupCache.add(trackedTamingEntity.getLivingEntity()); } - /** - * Checks if a player has already been registered - * Being registered constitutes having necessary values initialized in our per-player map - * - * @param playerUUID target player - * @return true if the player is registered - */ - private synchronized boolean isPlayerRegistered(@NotNull UUID playerUUID) { - return getPerPlayerTransientEntityMap().get(playerUUID) != null; - } - - /** - * Register a player to our tracker, which initializes the necessary values in our per-player map - * - * @param playerUUID player to register - */ - private synchronized void registerPlayer(@NotNull UUID playerUUID) { - getPerPlayerTransientEntityMap().put(playerUUID, new HashMap<>()); - - for(CallOfTheWildType callOfTheWildType : CallOfTheWildType.values()) { - getPerPlayerTransientEntityMap().get(playerUUID).put(callOfTheWildType, new HashSet<>()); - } - } - - /** - * Get the tracked transient entities map for a specific player - * - * @param playerUUID the target uuid of the player - * @return the tracked entities map for the player, null if the player isn't registered - */ - public synchronized @Nullable HashMap> getPlayerTrackedEntityMap(@NotNull UUID playerUUID) { - return getPerPlayerTransientEntityMap().get(playerUUID); - } - - /** - * Registers an entity to a player - * This includes registration to our per-player map and our chunk lookup cache - * - * @param playerUUID target player's UUID - * @param trackedTamingEntity target entity - */ - public synchronized void registerEntity(@NotNull UUID playerUUID, @NotNull TrackedTamingEntity trackedTamingEntity) { - //Add to map entry - getTrackedEntities(playerUUID, trackedTamingEntity.getCallOfTheWildType()).add(trackedTamingEntity); - - //Add to cache for chunk lookups - addToChunkLookupCache(trackedTamingEntity); - } - - /** - * Checks if a living entity is a summon - * - * @param livingEntity target livinig entity - * @return true if target living entity is a summon - */ - public synchronized boolean isTransientSummon(@NotNull LivingEntity livingEntity) { - return getChunkLookupCache().contains(livingEntity); - } - - /** - * Get the tracked taming entities for a player - * If the player isn't registered this will return null - * - * @param playerUUID the target uuid of the player - * @param callOfTheWildType target type - * @return the set of tracked entities for the player, null if the player isn't registered, the set can be empty - */ - private synchronized @Nullable HashSet getTrackedEntities(@NotNull UUID playerUUID, @NotNull CallOfTheWildType callOfTheWildType) { - HashMap> playerEntityMap = getPlayerTrackedEntityMap(playerUUID); - - if(playerEntityMap == null) - return null; - - return playerEntityMap.get(callOfTheWildType); - } - - /** - * Adds an entity to our chunk lookup cache - * - * @param trackedTamingEntity target tracked taming entity - */ - private synchronized void addToChunkLookupCache(@NotNull TrackedTamingEntity trackedTamingEntity) { - getChunkLookupCache().add(trackedTamingEntity.getLivingEntity()); - } - - /** - * Removes an entity from our tracker - * This includes removal from our per-player map and our chunk lookup cache - * - * @param livingEntity target entity - */ - private void unregisterEntity(@NotNull LivingEntity livingEntity) { - chunkLookupCacheCleanup(livingEntity); - perPlayerTransientMapCleanup(livingEntity); - } - - /** - * Removes an entity from our chunk lookup cache - * - * @param livingEntity target entity - */ - private void chunkLookupCacheCleanup(@NotNull LivingEntity livingEntity) { - getChunkLookupCache().remove(livingEntity); - } - - /** - * Clean a living entity from our tracker - * Iterates over all players and their registered entities - * Doesn't do any kind of failure checking, if it doesn't find any player with a registered entity nothing bad happens or is reported - * However it should never happen like that, so maybe we could consider adding some failure to execute checking in the future - * - * @param livingEntity - */ - private void perPlayerTransientMapCleanup(@NotNull LivingEntity livingEntity) { - for(UUID uuid : getPerPlayerTransientEntityMap().keySet()) { - for(CallOfTheWildType callOfTheWildType : CallOfTheWildType.values()) { - - HashSet trackedEntities = getTrackedEntities(uuid, callOfTheWildType); - - if(trackedEntities == null) - continue; - - Iterator iterator = trackedEntities.iterator(); - while (iterator.hasNext()) { - if(iterator.next().getLivingEntity().equals(livingEntity)) { - iterator.remove(); - return; - } - } - } - } - } - - /** - * Get all transient entities that exist in a specific chunk - * - * @param chunk the chunk to match - * @return a list of transient entities that are located in the provided chunk - */ - public synchronized @NotNull List getAllTransientEntitiesInChunk(@NotNull Chunk chunk) { - ArrayList matchingEntities = new ArrayList<>(); - - for(LivingEntity livingEntity : getChunkLookupCache()) { - if(livingEntity.getLocation().getChunk().equals(chunk)) { - matchingEntities.add(livingEntity); - } - } - - return matchingEntities; - } - - /** - * Get the amount of a summon currently active for a player - * - * @param playerUUID target player - * @param callOfTheWildType summon type - * @return the amount of summons currently active for player of target type - */ - public synchronized int getAmountCurrentlySummoned(@NotNull UUID playerUUID, @NotNull CallOfTheWildType callOfTheWildType) { - HashSet trackedEntities = getTrackedEntities(playerUUID, callOfTheWildType); - - if(trackedEntities == null) - return 0; - - return trackedEntities.size(); - } - - /** - * Kills a summon and removes its metadata - * Then it removes it from the tracker / chunk lookup cache - * - * @param livingEntity entity to remove - * @param player associated player - */ - public synchronized void removeSummon(@NotNull LivingEntity livingEntity, @Nullable Player player, boolean timeExpired) { - //Kill the summon & remove it - if(livingEntity.isValid()) { - livingEntity.setHealth(0); //Should trigger entity death events + public void killSummonAndCleanMobFlags(@NotNull LivingEntity livingEntity, + @Nullable Player player, + boolean timeExpired) { + if (livingEntity.isValid()) { + livingEntity.setHealth(0); // Should trigger entity death events livingEntity.remove(); Location location = livingEntity.getLocation(); @@ -262,55 +69,88 @@ public class TransientEntityTracker { ParticleEffectUtils.playCallOfTheWildEffect(livingEntity); } - //Inform player of summon death - if(player != null && player.isOnline()) { - if(timeExpired) { - NotificationManager.sendPlayerInformationChatOnly(player, "Taming.Summon.COTW.TimeExpired", StringUtils.getPrettyEntityTypeString(livingEntity.getType())); + // Inform player of summon death + if (player != null && player.isOnline()) { + if (timeExpired) { + NotificationManager.sendPlayerInformationChatOnly(player, + "Taming.Summon.COTW.TimeExpired", + StringUtils.getPrettyEntityTypeString(livingEntity.getType())); } else { - NotificationManager.sendPlayerInformationChatOnly(player, "Taming.Summon.COTW.Removed", StringUtils.getPrettyEntityTypeString(livingEntity.getType())); + NotificationManager.sendPlayerInformationChatOnly(player, + "Taming.Summon.COTW.Removed", + StringUtils.getPrettyEntityTypeString(livingEntity.getType())); } } } - - //Remove our metadata - mcMMO.getMetadataService().getMobMetadataService().removeMobFlags(livingEntity); - - //Clean from trackers - unregisterEntity(livingEntity); } - /** - * Remove all tracked entities from existence if they currently exist - * Clear the tracked entity lists afterwards - * - * @deprecated use {@link #cleanupAllSummons(Player, UUID)} instead - */ - @Deprecated - private void cleanupAllSummons(@NotNull UUID playerUUID) { - cleanupAllSummons(Bukkit.getPlayer(playerUUID), playerUUID); + public boolean isTransient(@NotNull LivingEntity livingEntity) { + return entityLookupCache.contains(livingEntity); } - /** - * Kills and cleans up all data related to all summoned entities for a player - * - * @param player used to send messages, can be null - * @param playerUUID used to grab associated data, cannot be null - */ - private void cleanupAllSummons(@Nullable Player player, @NotNull UUID playerUUID) { - for(CallOfTheWildType callOfTheWildType : CallOfTheWildType.values()) { - HashSet trackedEntities = getTrackedEntities(playerUUID, callOfTheWildType); + private @NotNull Set getTrackedEntities(@NotNull UUID playerUUID, + @NotNull CallOfTheWildType callOfTheWildType) { + final Set entities = + playerSummonedEntityTracker.computeIfAbsent(playerUUID, + __ -> ConcurrentHashMap.newKeySet()); + return entities.stream() + .filter(trackedTamingEntity -> trackedTamingEntity.getCallOfTheWildType() + == callOfTheWildType) + .collect(toSet()); + } - if(trackedEntities == null) { - continue; - } + private void cleanPlayer(@Nullable Player player, @NotNull UUID playerUUID) { + killAndCleanAllSummons(playerUUID, player); + playerSummonedEntityTracker.remove(playerUUID); + } - ImmutableSet immutableSet = ImmutableSet.copyOf(trackedEntities); + private void killAndCleanAllSummons(@NotNull UUID playerUUID, @Nullable Player player) { + final Set entities = playerSummonedEntityTracker.get(playerUUID); + if (entities == null) { + return; + } - for(TrackedTamingEntity trackedTamingEntity : immutableSet) { - //Remove from existence - removeSummon(trackedTamingEntity.getLivingEntity(), player, false); - } + // Copy the set to avoid concurrent modification during iteration + final Set playerSummonsToRemove = new HashSet<>(entities); + // Kill and clean all summons + playerSummonsToRemove.forEach( + trackedTamingEntity -> killAndCleanSummon(playerUUID, player, trackedTamingEntity)); + } + + public void killAndCleanSummon(@NotNull UUID playerUUID, @Nullable Player player, + @NotNull TrackedTamingEntity trackedTamingEntity) { + killSummonAndCleanMobFlags(trackedTamingEntity.getLivingEntity(), player, false); + removeSummonFromTracker(playerUUID, trackedTamingEntity); + } + + public void removeSummonFromTracker(@NotNull UUID playerUUID, + @NotNull TrackedTamingEntity trackedTamingEntity) { + entityLookupCache.remove(trackedTamingEntity.getLivingEntity()); + + if (playerSummonedEntityTracker.containsKey(playerUUID)) { + playerSummonedEntityTracker.get(playerUUID).remove(trackedTamingEntity); } } + + public void removeTrackedEntity(@NotNull LivingEntity livingEntity) { + // Fail fast if the entity isn't being tracked + if (!entityLookupCache.contains(livingEntity)) { + return; + } + + final List matchingEntities = new ArrayList<>(); + + // Collect matching entities without copying each set + playerSummonedEntityTracker.values().forEach(trackedEntitiesPerPlayer -> + trackedEntitiesPerPlayer.stream() + .filter(trackedTamingEntity -> trackedTamingEntity.getLivingEntity() + == livingEntity) + .forEach(matchingEntities::add) + ); + + // Iterate over the collected list to handle removal and cleanup + matchingEntities.forEach(TrackedTamingEntity::run); + } + } diff --git a/src/main/java/com/gmail/nossr50/util/TransientMetadataTools.java b/src/main/java/com/gmail/nossr50/util/TransientMetadataTools.java index 8b21e9d1a..5e9ef8a9d 100644 --- a/src/main/java/com/gmail/nossr50/util/TransientMetadataTools.java +++ b/src/main/java/com/gmail/nossr50/util/TransientMetadataTools.java @@ -1,5 +1,7 @@ package com.gmail.nossr50.util; +import static com.gmail.nossr50.util.MobMetadataUtils.removeMobFlags; + import com.gmail.nossr50.mcMMO; import org.bukkit.entity.LivingEntity; import org.jetbrains.annotations.NotNull; @@ -14,27 +16,31 @@ public class TransientMetadataTools { public void cleanLivingEntityMetadata(@NotNull LivingEntity entity) { //Since it's not written anywhere, apparently the GC won't touch objects with metadata still present on them if (entity.hasMetadata(MetadataConstants.METADATA_KEY_CUSTOM_NAME)) { - entity.setCustomName(entity.getMetadata(MetadataConstants.METADATA_KEY_CUSTOM_NAME).get(0).asString()); + entity.setCustomName( + entity.getMetadata(MetadataConstants.METADATA_KEY_CUSTOM_NAME).get(0) + .asString()); entity.removeMetadata(MetadataConstants.METADATA_KEY_CUSTOM_NAME, pluginRef); } //Involved in changing mob names to hearts if (entity.hasMetadata(MetadataConstants.METADATA_KEY_NAME_VISIBILITY)) { - entity.setCustomNameVisible(entity.getMetadata(MetadataConstants.METADATA_KEY_NAME_VISIBILITY).get(0).asBoolean()); + entity.setCustomNameVisible( + entity.getMetadata(MetadataConstants.METADATA_KEY_NAME_VISIBILITY).get(0) + .asBoolean()); entity.removeMetadata(MetadataConstants.METADATA_KEY_NAME_VISIBILITY, pluginRef); } //Gets assigned to endermen, potentially doesn't get cleared before this point - if(entity.hasMetadata(MetadataConstants.METADATA_KEY_TRAVELING_BLOCK)) { + if (entity.hasMetadata(MetadataConstants.METADATA_KEY_TRAVELING_BLOCK)) { entity.removeMetadata(MetadataConstants.METADATA_KEY_TRAVELING_BLOCK, pluginRef); } //Cleanup mob metadata - mcMMO.getMetadataService().getMobMetadataService().removeMobFlags(entity); + removeMobFlags(entity); //TODO: This loop has some redundancy, this whole method needs to be rewritten - for(String key : MetadataConstants.MOB_METADATA_KEYS) { - if(entity.hasMetadata(key)) { + for (String key : MetadataConstants.MOB_METADATA_KEYS) { + if (entity.hasMetadata(key)) { entity.removeMetadata(key, pluginRef); } } diff --git a/src/main/java/com/gmail/nossr50/util/adapter/BiomeAdapter.java b/src/main/java/com/gmail/nossr50/util/adapter/BiomeAdapter.java index b9d19e6eb..57ab7f5ce 100644 --- a/src/main/java/com/gmail/nossr50/util/adapter/BiomeAdapter.java +++ b/src/main/java/com/gmail/nossr50/util/adapter/BiomeAdapter.java @@ -1,32 +1,50 @@ package com.gmail.nossr50.util.adapter; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.function.Function; import org.bukkit.block.Biome; - -import java.util.*; +import org.jetbrains.annotations.NotNull; public class BiomeAdapter { - public static final Set WATER_BIOMES; public static final Set ICE_BIOMES; - + + static final List knownColdBiomes = Arrays.asList("COLD_OCEAN", "DEEP_COLD_OCEAN", + "ICE_SPIKES", + "FROZEN_PEAKS", "FROZEN_OCEAN", "FROZEN_RIVER", "DEEP_FROZEN_OCEAN", "SNOWY_TAIGA", + "OLD_GROWTH_PINE_TAIGA", "OLD_GROWTH_SPRUCE_TAIGA", "TAIGA", "SNOWY_SLOPES", + "SNOWY_BEACH"); + static { - List allBiomes = Arrays.asList(Biome.values()); - List waterBiomes = new ArrayList<>(); - List iceBiomes = new ArrayList<>(); - for (Biome biome : allBiomes) { - if (isWater(biome.name()) && !isCold(biome.name())) { - waterBiomes.add(biome); - } else if (isCold(biome.name())) { - iceBiomes.add(biome); - } - } - WATER_BIOMES = EnumSet.copyOf(waterBiomes); - ICE_BIOMES = EnumSet.copyOf(iceBiomes); + final Set iceBiomes = new HashSet<>(); + knownColdBiomes.stream() + .map(biomeFromString()) + .filter(Objects::nonNull) + .forEach(iceBiomes::add); + ICE_BIOMES = Collections.unmodifiableSet(iceBiomes); } - private static boolean isWater(String name) { - return name.contains("RIVER") || name.contains("OCEAN"); - } - private static boolean isCold(String name) { - return (name.contains("COLD") || name.contains("ICE") || name.contains("FROZEN") || name.contains("TAIGA")) && !(name.contains("WARM")); + private static @NotNull Function biomeFromString() { + return potentialBiome -> { + try { + Class biomeClass = Class.forName("org.bukkit.block.Biome"); + Method methodValueOf = biomeClass.getMethod("valueOf", String.class); + return methodValueOf.invoke(null, potentialBiome) == null + ? null + : (Biome) methodValueOf.invoke(null, potentialBiome); + } catch (IllegalArgumentException | NullPointerException e) { + return null; + } catch (ClassNotFoundException | NoSuchMethodException | InvocationTargetException + | IllegalAccessException e) { + // Thrown when the method is not found or the class is not found + throw new RuntimeException(e); + } + }; } } diff --git a/src/main/java/com/gmail/nossr50/util/blockmeta/BitSetChunkStore.java b/src/main/java/com/gmail/nossr50/util/blockmeta/BitSetChunkStore.java index bdee4a3b9..17e8cb0c7 100644 --- a/src/main/java/com/gmail/nossr50/util/blockmeta/BitSetChunkStore.java +++ b/src/main/java/com/gmail/nossr50/util/blockmeta/BitSetChunkStore.java @@ -1,14 +1,23 @@ package com.gmail.nossr50.util.blockmeta; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InvalidClassException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.ObjectStreamClass; +import java.io.ObjectStreamConstants; +import java.io.PushbackInputStream; +import java.io.Serializable; +import java.util.BitSet; +import java.util.UUID; import org.bukkit.Bukkit; import org.bukkit.World; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.io.*; -import java.util.BitSet; -import java.util.UUID; - public class BitSetChunkStore implements ChunkStore { private static final int CURRENT_VERSION = 9; private static final int MAGIC_NUMBER = 0xEA5EDEBB; @@ -102,8 +111,11 @@ public class BitSetChunkStore implements ChunkStore { } private static int coordToIndex(int x, int y, int z, int worldMin, int worldMax) { - if (x < 0 || x >= 16 || y < worldMin || y >= worldMax || z < 0 || z >= 16) - throw new IndexOutOfBoundsException(String.format("x: %d y: %d z: %d World Min: %d World Max: %d", x, y, z, worldMin, worldMax)); + if (x < 0 || x >= 16 || y < worldMin || y > worldMax || z < 0 || z >= 16) { + throw new IndexOutOfBoundsException( + String.format("x: %d y: %d z: %d World Min: %d World Max: %d", x, y, z, + worldMin, worldMax)); + } int yOffset = -worldMin; // Ensures y multiplier remains positive return (z * 16 + x) + (256 * (y + yOffset)); } @@ -112,19 +124,20 @@ public class BitSetChunkStore implements ChunkStore { World world = Bukkit.getWorld(worldUid); // Not sure how this case could come up, but might as well handle it gracefully. Loading a chunkstore for an unloaded world? - if (world == null) + if (world == null) { throw new RuntimeException("Cannot grab a minimum world height for an unloaded world"); + } return world.getMinHeight(); } - private static int getWorldMax(@NotNull UUID worldUid) - { + private static int getWorldMax(@NotNull UUID worldUid) { World world = Bukkit.getWorld(worldUid); // Not sure how this case could come up, but might as well handle it gracefully. Loading a chunkstore for an unloaded world? - if (world == null) + if (world == null) { throw new RuntimeException("Cannot grab a maximum world height for an unloaded world"); + } return world.getMaxHeight(); } @@ -148,13 +161,15 @@ public class BitSetChunkStore implements ChunkStore { dirty = false; } - private static @NotNull BitSetChunkStore deserialize(@NotNull DataInputStream in) throws IOException { + private static @NotNull BitSetChunkStore deserialize(@NotNull DataInputStream in) + throws IOException { int magic = in.readInt(); // Can be used to determine the format of the file int fileVersionNumber = in.readInt(); - if (magic != MAGIC_NUMBER || fileVersionNumber < 8) + if (magic != MAGIC_NUMBER || fileVersionNumber < 8) { throw new IOException(); + } long lsb = in.readLong(); long msb = in.readLong(); @@ -163,8 +178,9 @@ public class BitSetChunkStore implements ChunkStore { int cz = in.readInt(); int worldMin = 0; - if (fileVersionNumber >= 9) + if (fileVersionNumber >= 9) { worldMin = in.readInt(); + } int worldMax = in.readInt(); byte[] temp = new byte[in.readInt()]; in.readFully(temp); @@ -175,23 +191,29 @@ public class BitSetChunkStore implements ChunkStore { // The order in which the world height update code occurs here is important, the world max truncate math only holds up if done before adjusting for min changes // Lop off extra data if world max has shrunk - if (currentWorldMax < worldMax) - stored.clear(coordToIndex(16, currentWorldMax, 16, worldMin, worldMax), stored.length()); + if (currentWorldMax < worldMax) { + stored.clear(coordToIndex(16, currentWorldMax, 16, worldMin, worldMax), + stored.length()); + } // Left shift store if world min has shrunk - if (currentWorldMin > worldMin) - stored = stored.get(currentWorldMin, stored.length()); // Because BitSet's aren't fixed size, a "substring" operation is equivalent to a left shift + if (currentWorldMin > worldMin) { + stored = stored.get(currentWorldMin, + stored.length()); // Because BitSet's aren't fixed size, a "substring" operation is equivalent to a left shift + } // Right shift store if world min has expanded - if (currentWorldMin < worldMin) - { - int offset = (worldMin - currentWorldMin) * 16 * 16; // We are adding this many bits to the front + if (currentWorldMin < worldMin) { + int offset = (worldMin - currentWorldMin) * 16 + * 16; // We are adding this many bits to the front // This isn't the most efficient way to do this, however, its a rare case to occur, and in the grand scheme of things, the small performance we could gain would cost us significant reduced readability of the code BitSet shifted = new BitSet(); - for (int i = 0; i < stored.length(); i++) + for (int i = 0; i < stored.length(); i++) { shifted.set(i + offset, stored.get(i)); + } stored = shifted; } - BitSetChunkStore chunkStore = new BitSetChunkStore(worldUid, currentWorldMin, currentWorldMax, cx, cz); + BitSetChunkStore chunkStore = new BitSetChunkStore(worldUid, currentWorldMin, + currentWorldMax, cx, cz); chunkStore.store.or(stored); chunkStore.dirty = currentWorldMin != worldMin || currentWorldMax != worldMax; @@ -200,46 +222,48 @@ public class BitSetChunkStore implements ChunkStore { public static class Serialization { - public static final short STREAM_MAGIC = (short)0xACDC; // Rock on + public static final short STREAM_MAGIC = (short) 0xACDC; // Rock on - public static @Nullable ChunkStore readChunkStore(@NotNull DataInputStream inputStream) throws IOException { - if (inputStream.markSupported()) + public static @Nullable ChunkStore readChunkStore(@NotNull DataInputStream inputStream) + throws IOException { + if (inputStream.markSupported()) { inputStream.mark(2); + } short magicNumber = inputStream.readShort(); - if (magicNumber == ObjectStreamConstants.STREAM_MAGIC) // Java serializable, use legacy serialization - { + // Java serializable, use legacy serialization + if (magicNumber == ObjectStreamConstants.STREAM_MAGIC) { // "Un-read" the magic number for Serializables, they need it to still be in the stream - if (inputStream.markSupported()) + if (inputStream.markSupported()) { inputStream.reset(); // Pretend we never read those bytes - else - { + } else { // Creates a new stream with the two magic number bytes and then the rest of the original stream... Java is so dumb. I just wanted to look at two bytes. - PushbackInputStream pushbackInputStream = new PushbackInputStream(inputStream, 2); + PushbackInputStream pushbackInputStream = new PushbackInputStream(inputStream, + 2); pushbackInputStream.unread((magicNumber) & 0xFF); pushbackInputStream.unread((magicNumber >>> 8) & 0xFF); inputStream = new DataInputStream(pushbackInputStream); } return new LegacyDeserializationInputStream(inputStream).readLegacyChunkStore(); - } - else if (magicNumber == STREAM_MAGIC) // Pure bytes format - { + } else if (magicNumber == STREAM_MAGIC) { + // Pure bytes format return BitSetChunkStore.deserialize(inputStream); } throw new IOException("Bad Data Format"); } - public static void writeChunkStore(@NotNull DataOutputStream outputStream, @NotNull ChunkStore chunkStore) throws IOException { - if (!(chunkStore instanceof BitSetChunkStore)) + public static void writeChunkStore(@NotNull DataOutputStream outputStream, + @NotNull ChunkStore chunkStore) throws IOException { + if (!(chunkStore instanceof BitSetChunkStore)) { throw new InvalidClassException("ChunkStore must be instance of BitSetChunkStore"); + } outputStream.writeShort(STREAM_MAGIC); - ((BitSetChunkStore)chunkStore).serialize(outputStream); + ((BitSetChunkStore) chunkStore).serialize(outputStream); } // Handles loading the old serialized class private static class LegacyDeserializationInputStream extends ObjectInputStream { - private static class LegacyChunkStoreDeserializer implements Serializable - { + private static class LegacyChunkStoreDeserializer implements Serializable { private static final long serialVersionUID = -1L; private int cx; @@ -248,7 +272,8 @@ public class BitSetChunkStore implements ChunkStore { private UUID worldUid; private boolean[][][] store; - private LegacyChunkStoreDeserializer() {} + private LegacyChunkStoreDeserializer() { + } @Deprecated private void writeObject(@NotNull ObjectOutputStream out) throws IOException { @@ -256,7 +281,8 @@ public class BitSetChunkStore implements ChunkStore { } @Deprecated - private void readObject(@NotNull ObjectInputStream in) throws IOException, ClassNotFoundException { + private void readObject(@NotNull ObjectInputStream in) + throws IOException, ClassNotFoundException { in.readInt(); // Magic number in.readInt(); // Format version long lsb = in.readLong(); @@ -270,18 +296,19 @@ public class BitSetChunkStore implements ChunkStore { worldMax = store[0][0].length; } - public @NotNull BitSetChunkStore convert() - { + public @NotNull BitSetChunkStore convert() { int currentWorldMin = getWorldMin(worldUid); int currentWorldMax = getWorldMax(worldUid); - BitSetChunkStore converted = new BitSetChunkStore(worldUid, currentWorldMin, currentWorldMax, cx, cz); + BitSetChunkStore converted = new BitSetChunkStore(worldUid, currentWorldMin, + currentWorldMax, cx, cz); // Read old data into new chunkstore for (int x = 0; x < 16; x++) { for (int z = 0; z < 16; z++) { for (int y = 0; y < worldMax && y < currentWorldMax; y++) { - converted.store.set(converted.coordToIndex(x, y, z), store[x][z][y]); + converted.store.set(converted.coordToIndex(x, y, z), + store[x][z][y]); } } } @@ -298,16 +325,19 @@ public class BitSetChunkStore implements ChunkStore { } @Override - protected @NotNull ObjectStreamClass readClassDescriptor() throws IOException, ClassNotFoundException { + protected @NotNull ObjectStreamClass readClassDescriptor() + throws IOException, ClassNotFoundException { ObjectStreamClass read = super.readClassDescriptor(); - if (read.getName().contentEquals("com.gmail.nossr50.util.blockmeta.chunkmeta.PrimitiveChunkStore")) + if (read.getName().contentEquals( + "com.gmail.nossr50.util.blockmeta.chunkmeta.PrimitiveChunkStore")) { return ObjectStreamClass.lookup(LegacyChunkStoreDeserializer.class); + } return read; } - public @Nullable ChunkStore readLegacyChunkStore(){ + public @Nullable ChunkStore readLegacyChunkStore() { try { - LegacyChunkStoreDeserializer deserializer = (LegacyChunkStoreDeserializer)readObject(); + LegacyChunkStoreDeserializer deserializer = (LegacyChunkStoreDeserializer) readObject(); return deserializer.convert(); } catch (IOException | ClassNotFoundException e) { return null; diff --git a/src/main/java/com/gmail/nossr50/util/blockmeta/ChunkManager.java b/src/main/java/com/gmail/nossr50/util/blockmeta/ChunkManager.java index a0b61ba6f..c695b5673 100644 --- a/src/main/java/com/gmail/nossr50/util/blockmeta/ChunkManager.java +++ b/src/main/java/com/gmail/nossr50/util/blockmeta/ChunkManager.java @@ -5,6 +5,8 @@ import org.jetbrains.annotations.NotNull; public interface ChunkManager extends UserBlockTracker { void closeAll(); + void chunkUnloaded(int cx, int cz, @NotNull World world); + void unloadWorld(@NotNull World world); } diff --git a/src/main/java/com/gmail/nossr50/util/blockmeta/ChunkStore.java b/src/main/java/com/gmail/nossr50/util/blockmeta/ChunkStore.java index 632cde2e2..f0d194d45 100644 --- a/src/main/java/com/gmail/nossr50/util/blockmeta/ChunkStore.java +++ b/src/main/java/com/gmail/nossr50/util/blockmeta/ChunkStore.java @@ -1,8 +1,7 @@ package com.gmail.nossr50.util.blockmeta; -import org.jetbrains.annotations.NotNull; - import java.util.UUID; +import org.jetbrains.annotations.NotNull; /** * A ChunkStore should be responsible for a 16x16xWorldHeight area of data @@ -37,6 +36,7 @@ public interface ChunkStore { int getChunkZ(); int getChunkMin(); + int getChunkMax(); @NotNull UUID getWorldId(); diff --git a/src/main/java/com/gmail/nossr50/util/blockmeta/HashChunkManager.java b/src/main/java/com/gmail/nossr50/util/blockmeta/HashChunkManager.java index 5f38022d5..d25beacc0 100644 --- a/src/main/java/com/gmail/nossr50/util/blockmeta/HashChunkManager.java +++ b/src/main/java/com/gmail/nossr50/util/blockmeta/HashChunkManager.java @@ -1,5 +1,15 @@ package com.gmail.nossr50.util.blockmeta; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.UUID; import org.bukkit.Bukkit; import org.bukkit.World; import org.bukkit.block.Block; @@ -7,12 +17,6 @@ import org.bukkit.block.BlockState; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.File; -import java.io.IOException; -import java.util.*; - public class HashChunkManager implements ChunkManager { private final HashMap regionMap = new HashMap<>(); // Tracks active regions private final HashMap> chunkUsageMap = new HashMap<>(); // Tracks active chunks by region @@ -21,51 +25,57 @@ public class HashChunkManager implements ChunkManager { @Override public synchronized void closeAll() { // Save all dirty chunkstores - for (ChunkStore chunkStore : chunkMap.values()) - { - if (!chunkStore.isDirty()) + for (ChunkStore chunkStore : chunkMap.values()) { + if (!chunkStore.isDirty()) { continue; + } World world = Bukkit.getWorld(chunkStore.getWorldId()); - if (world == null) + if (world == null) { continue; // Oh well + } writeChunkStore(world, chunkStore); } // Clear in memory chunks chunkMap.clear(); chunkUsageMap.clear(); // Close all region files - for (McMMOSimpleRegionFile rf : regionMap.values()) + for (McMMOSimpleRegionFile rf : regionMap.values()) { rf.close(); + } regionMap.clear(); } - private synchronized @Nullable ChunkStore readChunkStore(@NotNull World world, int cx, int cz) throws IOException { - McMMOSimpleRegionFile rf = getReadableSimpleRegionFile(world, cx, cz); - if (rf == null) - return null; // If there is no region file, there can't be a chunk + private synchronized @Nullable ChunkStore readChunkStore(@NotNull World world, int cx, int cz) + throws IOException { + final McMMOSimpleRegionFile rf = getWriteableSimpleRegionFile(world, cx, cz); try (DataInputStream in = rf.getInputStream(cx, cz)) { // Get input stream for chunk - if (in == null) + if (in == null) { return null; // No chunk + } return BitSetChunkStore.Serialization.readChunkStore(in); // Read in the chunkstore } } private synchronized void writeChunkStore(@NotNull World world, @NotNull ChunkStore data) { - if (!data.isDirty()) + if (!data.isDirty()) { return; // Don't save unchanged data + } try { - McMMOSimpleRegionFile rf = getWriteableSimpleRegionFile(world, data.getChunkX(), data.getChunkZ()); + McMMOSimpleRegionFile rf = getWriteableSimpleRegionFile(world, data.getChunkX(), + data.getChunkZ()); try (DataOutputStream out = rf.getOutputStream(data.getChunkX(), data.getChunkZ())) { BitSetChunkStore.Serialization.writeChunkStore(out, data); } data.setDirty(false); - } - catch (IOException e) { - throw new RuntimeException("Unable to write chunk meta data for " + data.getChunkX() + ", " + data.getChunkZ(), e); + } catch (IOException e) { + throw new RuntimeException( + "Unable to write chunk meta data for " + data.getChunkX() + ", " + + data.getChunkZ(), e); } } - private synchronized @NotNull McMMOSimpleRegionFile getWriteableSimpleRegionFile(@NotNull World world, int cx, int cz) { + private synchronized @NotNull McMMOSimpleRegionFile getWriteableSimpleRegionFile( + @NotNull World world, int cx, int cz) { CoordinateKey regionKey = toRegionKey(world.getUID(), cx, cz); return regionMap.computeIfAbsent(regionKey, k -> { @@ -75,28 +85,19 @@ public class HashChunkManager implements ChunkManager { }); } - private synchronized @Nullable McMMOSimpleRegionFile getReadableSimpleRegionFile(@NotNull World world, int cx, int cz) { - CoordinateKey regionKey = toRegionKey(world.getUID(), cx, cz); - - return regionMap.computeIfAbsent(regionKey, k -> { - File regionFile = getRegionFile(world, regionKey); - if (!regionFile.exists()) - return null; // Don't create the file on read-only operations - return new McMMOSimpleRegionFile(regionFile, regionKey.x, regionKey.z); - }); - } - private @NotNull File getRegionFile(@NotNull World world, @NotNull CoordinateKey regionKey) { - if (world.getUID() != regionKey.worldID) + if (world.getUID() != regionKey.worldID) { throw new IllegalArgumentException(); - return new File(new File(world.getWorldFolder(), "mcmmo_regions"), "mcmmo_" + regionKey.x + "_" + regionKey.z + "_.mcm"); + } + return new File(new File(world.getWorldFolder(), "mcmmo_regions"), + "mcmmo_" + regionKey.x + "_" + regionKey.z + "_.mcm"); } private @Nullable ChunkStore loadChunk(int cx, int cz, @NotNull World world) { try { return readChunkStore(world, cx, cz); + } catch (Exception ignored) { } - catch (Exception ignored) {} return null; } @@ -104,17 +105,19 @@ public class HashChunkManager implements ChunkManager { private void unloadChunk(int cx, int cz, @NotNull World world) { CoordinateKey chunkKey = toChunkKey(world.getUID(), cx, cz); ChunkStore chunkStore = chunkMap.remove(chunkKey); // Remove from chunk map - if (chunkStore == null) + if (chunkStore == null) { return; + } - if (chunkStore.isDirty()) + if (chunkStore.isDirty()) { writeChunkStore(world, chunkStore); + } CoordinateKey regionKey = toRegionKey(world.getUID(), cx, cz); HashSet chunkKeys = chunkUsageMap.get(regionKey); chunkKeys.remove(chunkKey); // remove from region file in-use set - if (chunkKeys.isEmpty()) // If it was last chunk in region, close the region file and remove it from memory - { + // If it was last chunk in the region, close the region file and remove it from memory + if (chunkKeys.isEmpty()) { chunkUsageMap.remove(regionKey); regionMap.remove(regionKey).close(); } @@ -132,27 +135,30 @@ public class HashChunkManager implements ChunkManager { // Save and remove all the chunks List chunkKeys = new ArrayList<>(chunkMap.keySet()); for (CoordinateKey chunkKey : chunkKeys) { - if (!wID.equals(chunkKey.worldID)) + if (!wID.equals(chunkKey.worldID)) { continue; + } ChunkStore chunkStore = chunkMap.remove(chunkKey); - if (!chunkStore.isDirty()) + if (!chunkStore.isDirty()) { continue; + } try { writeChunkStore(world, chunkStore); + } catch (Exception ignore) { } - catch (Exception ignore) { } } // Clear all the region files List regionKeys = new ArrayList<>(regionMap.keySet()); for (CoordinateKey regionKey : regionKeys) { - if (!wID.equals(regionKey.worldID)) + if (!wID.equals(regionKey.worldID)) { continue; + } regionMap.remove(regionKey).close(); chunkUsageMap.remove(regionKey); } } - private synchronized boolean isTrue(int x, int y, int z, @NotNull World world) { + private synchronized boolean isIneligible(int x, int y, int z, @NotNull World world) { CoordinateKey chunkKey = blockCoordinateToChunkKey(world.getUID(), x, y, z); // Get chunk, load from file if necessary @@ -160,17 +166,18 @@ public class HashChunkManager implements ChunkManager { ChunkStore check = chunkMap.computeIfAbsent(chunkKey, k -> { // Load from file ChunkStore loaded = loadChunk(chunkKey.x, chunkKey.z, world); - if (loaded == null) - return null; + if (loaded != null) { + chunkUsageMap.computeIfAbsent(toRegionKey(chunkKey.worldID, chunkKey.x, chunkKey.z), + j -> new HashSet<>()).add(chunkKey); + return loaded; + } // Mark chunk in-use for region tracking - chunkUsageMap.computeIfAbsent(toRegionKey(chunkKey.worldID, chunkKey.x, chunkKey.z), j -> new HashSet<>()).add(chunkKey); - return loaded; + chunkUsageMap.computeIfAbsent(toRegionKey(chunkKey.worldID, chunkKey.x, chunkKey.z), + j -> new HashSet<>()).add(chunkKey); + // Create a new chunkstore + return new BitSetChunkStore(world, chunkKey.x, chunkKey.z); }); - // No chunk, return false - if (check == null) - return false; - int ix = Math.abs(x) % 16; int iz = Math.abs(z) % 16; @@ -178,60 +185,65 @@ public class HashChunkManager implements ChunkManager { } @Override - public synchronized boolean isTrue(@NotNull Block block) { - return isTrue(block.getX(), block.getY(), block.getZ(), block.getWorld()); + public synchronized boolean isIneligible(@NotNull Block block) { + return isIneligible(block.getX(), block.getY(), block.getZ(), block.getWorld()); } @Override - public synchronized boolean isTrue(@NotNull BlockState blockState) { - return isTrue(blockState.getX(), blockState.getY(), blockState.getZ(), blockState.getWorld()); + public synchronized boolean isIneligible(@NotNull BlockState blockState) { + return isIneligible(blockState.getX(), blockState.getY(), blockState.getZ(), + blockState.getWorld()); } @Override - public synchronized void setTrue(@NotNull Block block) { + public synchronized boolean isEligible(@NotNull Block block) { + return !isIneligible(block); + } + + @Override + public synchronized boolean isEligible(@NotNull BlockState blockState) { + return !isIneligible(blockState); + } + + @Override + public synchronized void setIneligible(@NotNull Block block) { set(block.getX(), block.getY(), block.getZ(), block.getWorld(), true); } @Override - public synchronized void setTrue(@NotNull BlockState blockState) { + public synchronized void setIneligible(@NotNull BlockState blockState) { set(blockState.getX(), blockState.getY(), blockState.getZ(), blockState.getWorld(), true); } @Override - public synchronized void setFalse(@NotNull Block block) { + public synchronized void setEligible(@NotNull Block block) { set(block.getX(), block.getY(), block.getZ(), block.getWorld(), false); } @Override - public synchronized void setFalse(@NotNull BlockState blockState) { + public synchronized void setEligible(@NotNull BlockState blockState) { set(blockState.getX(), blockState.getY(), blockState.getZ(), blockState.getWorld(), false); } - private synchronized void set(int x, int y, int z, @NotNull World world, boolean value){ + private synchronized void set(int x, int y, int z, @NotNull World world, boolean value) { CoordinateKey chunkKey = blockCoordinateToChunkKey(world.getUID(), x, y, z); // Get/Load/Create chunkstore ChunkStore cStore = chunkMap.computeIfAbsent(chunkKey, k -> { // Load from file ChunkStore loaded = loadChunk(chunkKey.x, chunkKey.z, world); - if (loaded != null) - { - chunkUsageMap.computeIfAbsent(toRegionKey(chunkKey.worldID, chunkKey.x, chunkKey.z), j -> new HashSet<>()).add(chunkKey); + if (loaded != null) { + chunkUsageMap.computeIfAbsent(toRegionKey(chunkKey.worldID, chunkKey.x, chunkKey.z), + j -> new HashSet<>()).add(chunkKey); return loaded; } - // If setting to false, no need to create an empty chunkstore - if (!value) - return null; // Mark chunk in-use for region tracking - chunkUsageMap.computeIfAbsent(toRegionKey(chunkKey.worldID, chunkKey.x, chunkKey.z), j -> new HashSet<>()).add(chunkKey); + chunkUsageMap.computeIfAbsent(toRegionKey(chunkKey.worldID, chunkKey.x, chunkKey.z), + j -> new HashSet<>()).add(chunkKey); // Create a new chunkstore return new BitSetChunkStore(world, chunkKey.x, chunkKey.z); }); - // Indicates setting false on empty chunkstore - if (cStore == null) - return; - // Get block offset (offset from chunk corner) int ix = Math.abs(x) % 16; int iz = Math.abs(z) % 16; @@ -240,11 +252,12 @@ public class HashChunkManager implements ChunkManager { cStore.set(ix, y, iz, value); } - private @NotNull CoordinateKey blockCoordinateToChunkKey(@NotNull UUID worldUid, int x, int y, int z) { + private @NotNull CoordinateKey blockCoordinateToChunkKey(@NotNull UUID worldUid, int x, int y, + int z) { return toChunkKey(worldUid, x >> 4, z >> 4); } - private @NotNull CoordinateKey toChunkKey(@NotNull UUID worldUid, int cx, int cz){ + private @NotNull CoordinateKey toChunkKey(@NotNull UUID worldUid, int cx, int cz) { return new CoordinateKey(worldUid, cx, cz); } @@ -268,8 +281,12 @@ public class HashChunkManager implements ChunkManager { @Override public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } CoordinateKey coordinateKey = (CoordinateKey) o; return x == coordinateKey.x && z == coordinateKey.z && diff --git a/src/main/java/com/gmail/nossr50/util/blockmeta/McMMOSimpleRegionFile.java b/src/main/java/com/gmail/nossr50/util/blockmeta/McMMOSimpleRegionFile.java index 80f15699b..065ae70b4 100644 --- a/src/main/java/com/gmail/nossr50/util/blockmeta/McMMOSimpleRegionFile.java +++ b/src/main/java/com/gmail/nossr50/util/blockmeta/McMMOSimpleRegionFile.java @@ -19,26 +19,30 @@ */ package com.gmail.nossr50.util.blockmeta; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.io.*; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.RandomAccessFile; import java.util.BitSet; import java.util.zip.DeflaterOutputStream; import java.util.zip.InflaterInputStream; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; /** - * File format: - * bytes 0-4096 contain 1024 integer values representing the segment index of each chunk - * bytes 4096-8192 contain 1024 integer values representing the byte length of each chunk - * bytes 8192-8196 is the integer value of the segment exponent - * bytes 8196-12288 are reserved for future use - * bytes 12288+ contain the data segments, by default 1024 byte segments. - * Chunk data is compressed and stored in 1 or more segments as needed. + * File format: bytes 0-4096 contain 1024 integer values representing the segment index of each + * chunk bytes 4096-8192 contain 1024 integer values representing the byte length of each chunk + * bytes 8192-8196 is the integer value of the segment exponent bytes 8196-12288 are reserved for + * future use bytes 12288+ contain the data segments, by default 1024 byte segments. Chunk data is + * compressed and stored in 1 or more segments as needed. */ public class McMMOSimpleRegionFile { private static final int DEFAULT_SEGMENT_EXPONENT = 10; // TODO, analyze real world usage and determine if a smaller segment(512) is worth it or not. (need to know average chunkstore bytesize) - private static final int DEFAULT_SEGMENT_SIZE = (int)Math.pow(2, DEFAULT_SEGMENT_EXPONENT); // 1024 + private static final int DEFAULT_SEGMENT_SIZE = (int) Math.pow(2, + DEFAULT_SEGMENT_EXPONENT); // 1024 private static final int RESERVED_HEADER_BYTES = 12288; // This needs to be divisible by segment size private static final int NUM_CHUNKS = 1024; // 32x32 private static final int SEEK_CHUNK_SEGMENT_INDICES = 0; @@ -90,8 +94,9 @@ public class McMMOSimpleRegionFile { // Read chunk header data file.seek(SEEK_CHUNK_SEGMENT_INDICES); - for (int i = 0; i < NUM_CHUNKS; i++) + for (int i = 0; i < NUM_CHUNKS; i++) { chunkSegmentIndex[i] = file.readInt(); + } file.seek(SEEK_CHUNK_BYTE_LENGTHS); for (int i = 0; i < NUM_CHUNKS; i++) { @@ -101,15 +106,15 @@ public class McMMOSimpleRegionFile { } fixFileLength(); - } - catch (IOException fnfe) { + } catch (IOException fnfe) { throw new RuntimeException(fnfe); } } public synchronized @NotNull DataOutputStream getOutputStream(int x, int z) { int index = getChunkIndex(x, z); // Get chunk index - return new DataOutputStream(new DeflaterOutputStream(new McMMOSimpleChunkBuffer(this, index))); + return new DataOutputStream( + new DeflaterOutputStream(new McMMOSimpleChunkBuffer(this, index))); } private static class McMMOSimpleChunkBuffer extends ByteArrayOutputStream { @@ -131,7 +136,8 @@ public class McMMOSimpleRegionFile { private synchronized void write(int index, byte[] buffer, int size) throws IOException { int oldSegmentIndex = chunkSegmentIndex[index]; // Get current segment index markChunkSegments(index, false); // Clear our old segments - int newSegmentIndex = findContiguousSegments(oldSegmentIndex, size); // Find contiguous segments to save to + int newSegmentIndex = findContiguousSegments(oldSegmentIndex, + size); // Find contiguous segments to save to file.seek((long) newSegmentIndex << segmentExponent); // Seek to file location file.write(buffer, 0, size); // Write data // update in memory info @@ -152,8 +158,9 @@ public class McMMOSimpleRegionFile { int byteLength = chunkNumBytes[index]; // Get byte length of data // No bytes - if (byteLength == 0) + if (byteLength == 0) { return null; + } byte[] data = new byte[byteLength]; @@ -166,34 +173,35 @@ public class McMMOSimpleRegionFile { try { file.close(); segments.clear(); - } - catch (IOException ioe) { + } catch (IOException ioe) { throw new RuntimeException("Unable to close file", ioe); } } private synchronized void markChunkSegments(int index, boolean inUse) { // No bytes used - if (chunkNumBytes[index] == 0) + if (chunkNumBytes[index] == 0) { return; + } int start = chunkSegmentIndex[index]; int end = start + chunkNumSegments[index]; // If we are writing, assert we don't write over any in-use segments - if (inUse) - { + if (inUse) { int nextSetBit = segments.nextSetBit(start); - if (nextSetBit != -1 && nextSetBit < end) + if (nextSetBit != -1 && nextSetBit < end) { throw new IllegalStateException("Attempting to overwrite an in-use segment"); + } } segments.set(start, end, inUse); } private synchronized void fixFileLength() throws IOException { - int fileLength = (int)file.length(); - int extend = -fileLength & segmentMask; // how many bytes do we need to be divisible by segment size + int fileLength = (int) file.length(); + int extend = -fileLength + & segmentMask; // how many bytes do we need to be divisible by segment size // Go to end of file file.seek(fileLength); @@ -202,8 +210,9 @@ public class McMMOSimpleRegionFile { } private synchronized int findContiguousSegments(int hint, int size) { - if (size == 0) + if (size == 0) { return 0; // Zero byte data will not claim any chunks anyways + } int segments = bytesToSegments(size); // Number of segments we need @@ -217,8 +226,9 @@ public class McMMOSimpleRegionFile { } // We fit! - if (oldFree) + if (oldFree) { return hint; + } // Find somewhere to put us int start = 0; @@ -229,12 +239,14 @@ public class McMMOSimpleRegionFile { current++; // Move up a segment // Move up start if the segment was in use - if (segmentInUse) + if (segmentInUse) { start = current; + } // If we have enough segments now, return - if (current - start >= segments) + if (current - start >= segments) { return start; + } } // Return the end of the segments (will expand to fit them) @@ -242,15 +254,17 @@ public class McMMOSimpleRegionFile { } private synchronized int bytesToSegments(int bytes) { - if (bytes <= 0) + if (bytes <= 0) { return 1; + } return ((bytes - 1) >> segmentExponent) + 1; // ((bytes - 1) / segmentSize) + 1 } private synchronized int getChunkIndex(int x, int z) { - if (rx != (x >> 5) || rz != (z >> 5)) + if (rx != (x >> 5) || rz != (z >> 5)) { throw new IndexOutOfBoundsException(); + } x = x & 0x1F; // 5 bits (mod 32) z = z & 0x1F; // 5 bits (mod 32) diff --git a/src/main/java/com/gmail/nossr50/util/blockmeta/NullChunkManager.java b/src/main/java/com/gmail/nossr50/util/blockmeta/NullChunkManager.java index 203376780..e1d638ed9 100644 --- a/src/main/java/com/gmail/nossr50/util/blockmeta/NullChunkManager.java +++ b/src/main/java/com/gmail/nossr50/util/blockmeta/NullChunkManager.java @@ -8,33 +8,50 @@ import org.jetbrains.annotations.NotNull; public class NullChunkManager implements ChunkManager { @Override - public void closeAll() {} + public void closeAll() { + } @Override - public void chunkUnloaded(int cx, int cz, @NotNull World world) {} + public void chunkUnloaded(int cx, int cz, @NotNull World world) { + } @Override - public void unloadWorld(@NotNull World world) {} + public void unloadWorld(@NotNull World world) { + } @Override - public boolean isTrue(@NotNull Block block) { + public boolean isIneligible(@NotNull Block block) { return false; } @Override - public boolean isTrue(@NotNull BlockState blockState) { + public boolean isIneligible(@NotNull BlockState blockState) { return false; } @Override - public void setTrue(@NotNull Block block) {} + public boolean isEligible(@NotNull Block block) { + return true; + } @Override - public void setTrue(@NotNull BlockState blockState) {} + public boolean isEligible(@NotNull BlockState blockState) { + return true; + } @Override - public void setFalse(@NotNull Block block) {} + public void setIneligible(@NotNull Block block) { + } @Override - public void setFalse(@NotNull BlockState blockState) {} + public void setIneligible(@NotNull BlockState blockState) { + } + + @Override + public void setEligible(@NotNull Block block) { + } + + @Override + public void setEligible(@NotNull BlockState blockState) { + } } diff --git a/src/main/java/com/gmail/nossr50/util/blockmeta/UserBlockTracker.java b/src/main/java/com/gmail/nossr50/util/blockmeta/UserBlockTracker.java index e5428b0c1..01d9c8baa 100644 --- a/src/main/java/com/gmail/nossr50/util/blockmeta/UserBlockTracker.java +++ b/src/main/java/com/gmail/nossr50/util/blockmeta/UserBlockTracker.java @@ -6,51 +6,141 @@ import org.bukkit.block.BlockState; import org.jetbrains.annotations.NotNull; /** - * Contains blockstore methods that are safe for external plugins to access. - * An instance can be retrieved via {@link mcMMO#getPlaceStore() mcMMO.getPlaceStore()} + * Contains blockstore methods that are safe for external plugins to access. An instance can be + * retrieved via {@link mcMMO#getUserBlockTracker() mcMMO.getPlaceStore()} */ public interface UserBlockTracker { /** - * Check to see if a given block location is set to true + * Check to see if a given {@link Block} is ineligible for rewards. This is a location-based + * lookup, and the other properties of the {@link Block} do not matter. * - * @param block Block location to check - * @return true if the given block location is set to true, false if otherwise + * @param block Block to check + * @return true if the given block should not give rewards, false if otherwise */ - boolean isTrue(@NotNull Block block); + boolean isIneligible(@NotNull Block block); /** - * Check to see if a given BlockState location is set to true + * Check to see if a given {@link Block} is eligible for rewards. This is a location-based + * lookup, and the other properties of the {@link Block} do not matter. + * + * @param block Block to check + * @return true if the given block should give rewards, false if otherwise + */ + boolean isEligible(@NotNull Block block); + + /** + * Check to see if a given {@link BlockState} is eligible for rewards. This is a location-based + * lookup, and the other properties of the {@link BlockState} do not matter. * * @param blockState BlockState to check * @return true if the given BlockState location is set to true, false if otherwise */ - boolean isTrue(@NotNull BlockState blockState); + boolean isEligible(@NotNull BlockState blockState); /** - * Set a given block location to true + * Check to see if a given {@link BlockState} is ineligible for rewards. This is a + * location-based lookup, and the other properties of the {@link BlockState} do not matter. * - * @param block Block location to set + * @param blockState BlockState to check + * @return true if the given BlockState location is set to true, false if otherwise */ - void setTrue(@NotNull Block block); + boolean isIneligible(@NotNull BlockState blockState); + + /** + * Set a given {@link Block} as ineligible for rewards. This is a location-based lookup, and the + * other properties of the {@link Block} do not matter. + * + * @param block block whose location to set as ineligible + */ + void setIneligible(@NotNull Block block); /** * Set a given BlockState location to true * * @param blockState BlockState location to set */ - void setTrue(@NotNull BlockState blockState); + void setIneligible(@NotNull BlockState blockState); /** - * Set a given block location to false + * Set a given {@link Block} as eligible for rewards. This is a location-based lookup, and the + * other properties of the {@link Block} do not matter. * - * @param block Block location to set + * @param block block whose location to set as eligible */ - void setFalse(@NotNull Block block); + void setEligible(@NotNull Block block); /** * Set a given BlockState location to false * * @param blockState BlockState location to set */ - void setFalse(@NotNull BlockState blockState); + void setEligible(@NotNull BlockState blockState); + + /** + * Check to see if a given block location is set to true + * + * @param block Block location to check + * @return true if the given block location is set to true, false if otherwise + * @deprecated Use {@link #isIneligible(Block)} instead + */ + @Deprecated(since = "2.2.013") + default boolean isTrue(@NotNull Block block) { + return isIneligible(block); + } + + /** + * Check to see if a given BlockState location is set to true + * + * @param blockState BlockState to check + * @return true if the given BlockState location is set to true, false if otherwise + * @deprecated Use {@link #isIneligible(BlockState)} instead + */ + @Deprecated(since = "2.2.013") + default boolean isTrue(@NotNull BlockState blockState) { + return isIneligible(blockState); + } + + /** + * Set a given block location to true + * + * @param block Block location to set + * @deprecated Use {@link #setIneligible(Block)} instead + */ + @Deprecated(since = "2.2.013") + default void setTrue(@NotNull Block block) { + setIneligible(block); + } + + /** + * Set a given BlockState location to true + * + * @param blockState BlockState location to set + * @deprecated Use {@link #setIneligible(BlockState)} instead + */ + @Deprecated(since = "2.2.013") + default void setTrue(@NotNull BlockState blockState) { + setIneligible(blockState); + } + + /** + * Set a given block location to false + * + * @param block Block location to set + * @deprecated Use {@link #setEligible(Block)} instead + */ + @Deprecated(since = "2.2.013") + default void setFalse(@NotNull Block block) { + setEligible(block); + } + + /** + * Set a given BlockState location to false + * + * @param blockState BlockState location to set + * @deprecated Use {@link #setEligible(BlockState)} instead + */ + @Deprecated(since = "2.2.013") + default void setFalse(@NotNull BlockState blockState) { + setEligible(blockState); + } } 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 83d305486..224aed5ec 100644 --- a/src/main/java/com/gmail/nossr50/util/commands/CommandRegistrationManager.java +++ b/src/main/java/com/gmail/nossr50/util/commands/CommandRegistrationManager.java @@ -1,6 +1,13 @@ package com.gmail.nossr50.util.commands; -import com.gmail.nossr50.commands.*; +import com.gmail.nossr50.commands.McabilityCommand; +import com.gmail.nossr50.commands.McconvertCommand; +import com.gmail.nossr50.commands.McgodCommand; +import com.gmail.nossr50.commands.McmmoCommand; +import com.gmail.nossr50.commands.McnotifyCommand; +import com.gmail.nossr50.commands.McrefreshCommand; +import com.gmail.nossr50.commands.McscoreboardCommand; +import com.gmail.nossr50.commands.XprateCommand; import com.gmail.nossr50.commands.admin.CompatibilityCommand; import com.gmail.nossr50.commands.admin.McmmoReloadLocaleCommand; import com.gmail.nossr50.commands.admin.PlayerDebugCommand; @@ -14,100 +21,92 @@ import com.gmail.nossr50.commands.experience.MmoeditCommand; import com.gmail.nossr50.commands.experience.SkillresetCommand; import com.gmail.nossr50.commands.party.PartyCommand; import com.gmail.nossr50.commands.party.teleport.PtpCommand; -import com.gmail.nossr50.commands.player.*; -import com.gmail.nossr50.commands.skills.*; +import com.gmail.nossr50.commands.player.InspectCommand; +import com.gmail.nossr50.commands.player.McRankCommand; +import com.gmail.nossr50.commands.player.McTopCommand; +import com.gmail.nossr50.commands.player.MccooldownCommand; +import com.gmail.nossr50.commands.player.McstatsCommand; +import com.gmail.nossr50.commands.player.XPBarCommand; +import com.gmail.nossr50.commands.skills.AcrobaticsCommand; +import com.gmail.nossr50.commands.skills.AlchemyCommand; +import com.gmail.nossr50.commands.skills.ArcheryCommand; +import com.gmail.nossr50.commands.skills.AxesCommand; +import com.gmail.nossr50.commands.skills.CrossbowsCommand; +import com.gmail.nossr50.commands.skills.ExcavationCommand; +import com.gmail.nossr50.commands.skills.FishingCommand; +import com.gmail.nossr50.commands.skills.HerbalismCommand; +import com.gmail.nossr50.commands.skills.MacesCommand; +import com.gmail.nossr50.commands.skills.MiningCommand; +import com.gmail.nossr50.commands.skills.MmoInfoCommand; +import com.gmail.nossr50.commands.skills.RepairCommand; +import com.gmail.nossr50.commands.skills.SalvageCommand; +import com.gmail.nossr50.commands.skills.SmeltingCommand; +import com.gmail.nossr50.commands.skills.SwordsCommand; +import com.gmail.nossr50.commands.skills.TamingCommand; +import com.gmail.nossr50.commands.skills.TridentsCommand; +import com.gmail.nossr50.commands.skills.UnarmedCommand; +import com.gmail.nossr50.commands.skills.WoodcuttingCommand; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.text.StringUtils; -import org.bukkit.command.PluginCommand; - import java.util.ArrayList; import java.util.List; import java.util.Locale; +import org.bukkit.command.PluginCommand; public final class CommandRegistrationManager { - private CommandRegistrationManager() {} + private CommandRegistrationManager() { + } private static final String permissionsMessage = LocaleLoader.getString("mcMMO.NoPermission"); private static void registerSkillCommands() { - for (PrimarySkillType skill : PrimarySkillType.values()) { - String commandName = skill.toString().toLowerCase(Locale.ENGLISH); - String localizedName = mcMMO.p.getSkillTools().getLocalizedSkillName(skill).toLowerCase(Locale.ENGLISH); + for (PrimarySkillType primarySkillType : PrimarySkillType.values()) { + if (primarySkillType == PrimarySkillType.MACES + && !mcMMO.getCompatibilityManager().getMinecraftGameVersion() + .isAtLeast(1, 21, 0)) { + continue; + } - PluginCommand command; + final String commandName = primarySkillType.toString().toLowerCase(Locale.ENGLISH); + final String localizedName = mcMMO.p.getSkillTools() + .getLocalizedSkillName(primarySkillType).toLowerCase(Locale.ENGLISH); - command = mcMMO.p.getCommand(commandName); - command.setDescription(LocaleLoader.getString("Commands.Description.Skill", StringUtils.getCapitalized(localizedName))); + final PluginCommand command = mcMMO.p.getCommand(commandName); + if (command == null) { + mcMMO.p.getLogger().severe("Command not found: " + commandName); + continue; + } + + command.setDescription(LocaleLoader.getString("Commands.Description.Skill", + StringUtils.getCapitalized(localizedName))); command.setPermission("mcmmo.commands." + commandName); command.setPermissionMessage(permissionsMessage); - command.setUsage(LocaleLoader.getString("Commands.Usage.0", localizedName)); - command.setUsage(command.getUsage() + "\n" + LocaleLoader.getString("Commands.Usage.2", localizedName, "?", "[" + LocaleLoader.getString("Commands.Usage.Page") + "]")); + command.setUsage(LocaleLoader.getString("Commands.Usage.0", commandName)); + command.setUsage(command.getUsage() + "\n" + LocaleLoader.getString("Commands.Usage.2", + commandName, "?", "[" + LocaleLoader.getString("Commands.Usage.Page") + "]")); - switch (skill) { - case ACROBATICS: - command.setExecutor(new AcrobaticsCommand()); - break; - - case ALCHEMY: - command.setExecutor(new AlchemyCommand()); - break; - - case ARCHERY: - command.setExecutor(new ArcheryCommand()); - break; - - case AXES: - command.setExecutor(new AxesCommand()); - break; - - case EXCAVATION: - command.setExecutor(new ExcavationCommand()); - break; - - case FISHING: - command.setExecutor(new FishingCommand()); - break; - - case HERBALISM: - command.setExecutor(new HerbalismCommand()); - break; - - case MINING: - command.setExecutor(new MiningCommand()); - break; - - case REPAIR: - command.setExecutor(new RepairCommand()); - break; - - case SALVAGE: - command.setExecutor(new SalvageCommand()); - break; - - case SMELTING: - command.setExecutor(new SmeltingCommand()); - break; - - case SWORDS: - command.setExecutor(new SwordsCommand()); - break; - - case TAMING: - command.setExecutor(new TamingCommand()); - break; - - case UNARMED: - command.setExecutor(new UnarmedCommand()); - break; - - case WOODCUTTING: - command.setExecutor(new WoodcuttingCommand()); - break; - - default: - break; + switch (primarySkillType) { + case ACROBATICS -> command.setExecutor(new AcrobaticsCommand()); + case ALCHEMY -> command.setExecutor(new AlchemyCommand()); + case ARCHERY -> command.setExecutor(new ArcheryCommand()); + case AXES -> command.setExecutor(new AxesCommand()); + case CROSSBOWS -> command.setExecutor(new CrossbowsCommand()); + case EXCAVATION -> command.setExecutor(new ExcavationCommand()); + case FISHING -> command.setExecutor(new FishingCommand()); + case HERBALISM -> command.setExecutor(new HerbalismCommand()); + case MACES -> command.setExecutor(new MacesCommand()); + case MINING -> command.setExecutor(new MiningCommand()); + case REPAIR -> command.setExecutor(new RepairCommand()); + case SALVAGE -> command.setExecutor(new SalvageCommand()); + case SMELTING -> command.setExecutor(new SmeltingCommand()); + case SWORDS -> command.setExecutor(new SwordsCommand()); + case TAMING -> command.setExecutor(new TamingCommand()); + case TRIDENTS -> command.setExecutor(new TridentsCommand()); + case UNARMED -> command.setExecutor(new UnarmedCommand()); + case WOODCUTTING -> command.setExecutor(new WoodcuttingCommand()); + default -> throw new IllegalStateException("Unexpected value: " + primarySkillType); } } } @@ -117,7 +116,10 @@ public final class CommandRegistrationManager { command.setDescription(LocaleLoader.getString("Commands.Description.addlevels")); command.setPermission("mcmmo.commands.addlevels;mcmmo.commands.addlevels.others"); command.setPermissionMessage(permissionsMessage); - command.setUsage(LocaleLoader.getString("Commands.Usage.3.XP", "addlevels", "[" + LocaleLoader.getString("Commands.Usage.Player") + "]", "<" + LocaleLoader.getString("Commands.Usage.Skill") + ">", "<" + LocaleLoader.getString("Commands.Usage.Level") + ">")); + command.setUsage(LocaleLoader.getString("Commands.Usage.3.XP", "addlevels", + "[" + LocaleLoader.getString("Commands.Usage.Player") + "]", + "<" + LocaleLoader.getString("Commands.Usage.Skill") + ">", + "<" + LocaleLoader.getString("Commands.Usage.Level") + ">")); command.setExecutor(new AddlevelsCommand()); } @@ -126,7 +128,10 @@ public final class CommandRegistrationManager { command.setDescription(LocaleLoader.getString("Commands.Description.addxp")); command.setPermission("mcmmo.commands.addxp;mcmmo.commands.addxp.others"); command.setPermissionMessage(permissionsMessage); - command.setUsage(LocaleLoader.getString("Commands.Usage.3.XP", "addxp", "[" + LocaleLoader.getString("Commands.Usage.Player") + "]", "<" + LocaleLoader.getString("Commands.Usage.Skill") + ">", "<" + LocaleLoader.getString("Commands.Usage.XP") + ">")); + command.setUsage(LocaleLoader.getString("Commands.Usage.3.XP", "addxp", + "[" + LocaleLoader.getString("Commands.Usage.Player") + "]", + "<" + LocaleLoader.getString("Commands.Usage.Skill") + ">", + "<" + LocaleLoader.getString("Commands.Usage.XP") + ">")); command.setExecutor(new AddxpCommand()); } @@ -135,25 +140,18 @@ public final class CommandRegistrationManager { command.setDescription(LocaleLoader.getString("Commands.Description.mcgod")); command.setPermission("mcmmo.commands.mcgod;mcmmo.commands.mcgod.others"); command.setPermissionMessage(permissionsMessage); - command.setUsage(LocaleLoader.getString("Commands.Usage.1", "mcgod", "[" + LocaleLoader.getString("Commands.Usage.Player") + "]")); + command.setUsage(LocaleLoader.getString("Commands.Usage.1", "mcgod", + "[" + LocaleLoader.getString("Commands.Usage.Player") + "]")); command.setExecutor(new McgodCommand()); } -// private static void registerDropTreasureCommand() { -// PluginCommand command = mcMMO.p.getCommand("mmodroptreasures"); -// command.setDescription(LocaleLoader.getString("Commands.Description.droptreasures")); -// command.setPermission("mcmmo.commands.droptreasures"); -// command.setPermissionMessage(permissionsMessage); -// command.setUsage(LocaleLoader.getString("Commands.Usage.0", "mcgod")); -// command.setExecutor(new DropTreasureCommand()); -// } - private static void registerMmoInfoCommand() { PluginCommand command = mcMMO.p.getCommand("mmoinfo"); command.setDescription(LocaleLoader.getString("Commands.Description.mmoinfo")); command.setPermission("mcmmo.commands.mmoinfo"); command.setPermissionMessage(permissionsMessage); - command.setUsage(LocaleLoader.getString("Commands.Usage.1", "mmoinfo", "[" + LocaleLoader.getString("Commands.Usage.SubSkill") + "]")); + command.setUsage(LocaleLoader.getString("Commands.Usage.1", "mmoinfo", + "[" + LocaleLoader.getString("Commands.Usage.SubSkill") + "]")); command.setExecutor(new MmoInfoCommand()); } @@ -171,7 +169,8 @@ public final class CommandRegistrationManager { command.setDescription(LocaleLoader.getString("Commands.Description.mcchatspy")); command.setPermission("mcmmo.commands.mcchatspy;mcmmo.commands.mcchatspy.others"); command.setPermissionMessage(permissionsMessage); - command.setUsage(LocaleLoader.getString("Commands.Usage.1", "mcchatspy", "[" + LocaleLoader.getString("Commands.Usage.Player") + "]")); + command.setUsage(LocaleLoader.getString("Commands.Usage.1", "mcchatspy", + "[" + LocaleLoader.getString("Commands.Usage.Player") + "]")); command.setExecutor(new McChatSpy()); } @@ -180,7 +179,8 @@ public final class CommandRegistrationManager { command.setDescription(LocaleLoader.getString("Commands.Description.mcrefresh")); command.setPermission("mcmmo.commands.mcrefresh;mcmmo.commands.mcrefresh.others"); command.setPermissionMessage(permissionsMessage); - command.setUsage(LocaleLoader.getString("Commands.Usage.1", "mcrefresh", "[" + LocaleLoader.getString("Commands.Usage.Player") + "]")); + command.setUsage(LocaleLoader.getString("Commands.Usage.1", "mcrefresh", + "[" + LocaleLoader.getString("Commands.Usage.Player") + "]")); command.setExecutor(new McrefreshCommand()); } @@ -189,16 +189,22 @@ public final class CommandRegistrationManager { command.setDescription(LocaleLoader.getString("Commands.Description.mmoedit")); command.setPermission("mcmmo.commands.mmoedit;mcmmo.commands.mmoedit.others"); command.setPermissionMessage(permissionsMessage); - command.setUsage(LocaleLoader.getString("Commands.Usage.3.XP", "mmoedit", "[" + LocaleLoader.getString("Commands.Usage.Player") + "]", "<" + LocaleLoader.getString("Commands.Usage.Skill") + ">", "<" + LocaleLoader.getString("Commands.Usage.Level") + ">")); + command.setUsage(LocaleLoader.getString("Commands.Usage.3.XP", "mmoedit", + "[" + LocaleLoader.getString("Commands.Usage.Player") + "]", + "<" + LocaleLoader.getString("Commands.Usage.Skill") + ">", + "<" + LocaleLoader.getString("Commands.Usage.Level") + ">")); command.setExecutor(new MmoeditCommand()); } private static void registerSkillresetCommand() { PluginCommand command = mcMMO.p.getCommand("skillreset"); command.setDescription(LocaleLoader.getString("Commands.Description.skillreset")); - command.setPermission("mcmmo.commands.skillreset;mcmmo.commands.skillreset.others"); // Only need the main ones, not the individual skill ones + command.setPermission( + "mcmmo.commands.skillreset;mcmmo.commands.skillreset.others"); // Only need the main ones, not the individual skill ones command.setPermissionMessage(permissionsMessage); - command.setUsage(LocaleLoader.getString("Commands.Usage.2", "skillreset", "[" + LocaleLoader.getString("Commands.Usage.Player") + "]", "<" + LocaleLoader.getString("Commands.Usage.Skill") + ">")); + command.setUsage(LocaleLoader.getString("Commands.Usage.2", "skillreset", + "[" + LocaleLoader.getString("Commands.Usage.Player") + "]", + "<" + LocaleLoader.getString("Commands.Usage.Skill") + ">")); command.setExecutor(new SkillresetCommand()); } @@ -208,10 +214,14 @@ public final class CommandRegistrationManager { PluginCommand command = mcMMO.p.getCommand("xprate"); command.setDescription(LocaleLoader.getString("Commands.Description.xprate")); - command.setPermission("mcmmo.commands.xprate;mcmmo.commands.xprate.reset;mcmmo.commands.xprate.set"); + command.setPermission( + "mcmmo.commands.xprate;mcmmo.commands.xprate.reset;mcmmo.commands.xprate.set"); command.setPermissionMessage(permissionsMessage); - command.setUsage(LocaleLoader.getString("Commands.Usage.2", "xprate", "<" + LocaleLoader.getString("Commands.Usage.Rate") + ">", "")); - command.setUsage(command.getUsage() + "\n" + LocaleLoader.getString("Commands.Usage.1", "xprate", "reset")); + command.setUsage(LocaleLoader.getString("Commands.Usage.2", "xprate", + "<" + LocaleLoader.getString("Commands.Usage.Rate") + ">", "")); + command.setUsage( + command.getUsage() + "\n" + LocaleLoader.getString("Commands.Usage.1", "xprate", + "reset")); command.setAliases(aliasList); command.setExecutor(new XprateCommand()); } @@ -219,9 +229,11 @@ public final class CommandRegistrationManager { private static void registerInspectCommand() { PluginCommand command = mcMMO.p.getCommand("inspect"); command.setDescription(LocaleLoader.getString("Commands.Description.inspect")); - command.setPermission("mcmmo.commands.inspect;mcmmo.commands.inspect.far;mcmmo.commands.inspect.offline"); + command.setPermission( + "mcmmo.commands.inspect;mcmmo.commands.inspect.far;mcmmo.commands.inspect.offline"); command.setPermissionMessage(permissionsMessage); - command.setUsage(LocaleLoader.getString("Commands.Usage.1", "inspect", "<" + LocaleLoader.getString("Commands.Usage.Player") + ">")); + command.setUsage(LocaleLoader.getString("Commands.Usage.1", "inspect", + "<" + LocaleLoader.getString("Commands.Usage.Player") + ">")); command.setExecutor(new InspectCommand()); } @@ -239,7 +251,8 @@ public final class CommandRegistrationManager { command.setDescription(LocaleLoader.getString("Commands.Description.mcability")); command.setPermission("mcmmo.commands.mcability;mcmmo.commands.mcability.others"); command.setPermissionMessage(permissionsMessage); - command.setUsage(LocaleLoader.getString("Commands.Usage.1", "mcability", "[" + LocaleLoader.getString("Commands.Usage.Player") + "]")); + command.setUsage(LocaleLoader.getString("Commands.Usage.1", "mcability", + "[" + LocaleLoader.getString("Commands.Usage.Player") + "]")); command.setExecutor(new McabilityCommand()); } @@ -249,17 +262,21 @@ public final class CommandRegistrationManager { command.setPermission("mcmmo.commands.mcmmo.description;mcmmo.commands.mcmmo.help"); command.setPermissionMessage(permissionsMessage); command.setUsage(LocaleLoader.getString("Commands.Usage.0", "mcmmo")); - command.setUsage(command.getUsage() + "\n" + LocaleLoader.getString("Commands.Usage.1", "mcmmo", "help")); + command.setUsage( + command.getUsage() + "\n" + LocaleLoader.getString("Commands.Usage.1", "mcmmo", + "help")); command.setExecutor(new McmmoCommand()); } private static void registerMcrankCommand() { PluginCommand command = mcMMO.p.getCommand("mcrank"); command.setDescription(LocaleLoader.getString("Commands.Description.mcrank")); - command.setPermission("mcmmo.commands.mcrank;mcmmo.commands.mcrank.others;mcmmo.commands.mcrank.others.far;mcmmo.commands.mcrank.others.offline"); + command.setPermission( + "mcmmo.commands.mcrank;mcmmo.commands.mcrank.others;mcmmo.commands.mcrank.others.far;mcmmo.commands.mcrank.others.offline"); command.setPermissionMessage(permissionsMessage); - command.setUsage(LocaleLoader.getString("Commands.Usage.1", "mcrank", "[" + LocaleLoader.getString("Commands.Usage.Player") + "]")); - command.setExecutor(new McrankCommand()); + command.setUsage(LocaleLoader.getString("Commands.Usage.1", "mcrank", + "[" + LocaleLoader.getString("Commands.Usage.Player") + "]")); + command.setExecutor(new McRankCommand()); } private static void registerMcstatsCommand() { @@ -274,15 +291,19 @@ public final class CommandRegistrationManager { private static void registerMctopCommand() { PluginCommand command = mcMMO.p.getCommand("mctop"); command.setDescription(LocaleLoader.getString("Commands.Description.mctop")); - command.setPermission("mcmmo.commands.mctop"); // Only need the main one, not the individual skill ones + command.setPermission( + "mcmmo.commands.mctop"); // Only need the main one, not the individual skill ones command.setPermissionMessage(permissionsMessage); - command.setUsage(LocaleLoader.getString("Commands.Usage.2", "mctop", "[" + LocaleLoader.getString("Commands.Usage.Skill") + "]", "[" + LocaleLoader.getString("Commands.Usage.Page") + "]")); - command.setExecutor(new MctopCommand()); + command.setUsage(LocaleLoader.getString("Commands.Usage.2", "mctop", + "[" + LocaleLoader.getString("Commands.Usage.Skill") + "]", + "[" + LocaleLoader.getString("Commands.Usage.Page") + "]")); + command.setExecutor(new McTopCommand()); } private static void registerMcpurgeCommand() { PluginCommand command = mcMMO.p.getCommand("mcpurge"); - command.setDescription(LocaleLoader.getString("Commands.Description.mcpurge", mcMMO.p.getGeneralConfig().getOldUsersCutoff())); + command.setDescription(LocaleLoader.getString("Commands.Description.mcpurge", + mcMMO.p.getGeneralConfig().getOldUsersCutoff())); command.setPermission("mcmmo.commands.mcpurge"); command.setPermissionMessage(permissionsMessage); command.setUsage(LocaleLoader.getString("Commands.Usage.0", "mcpurge")); @@ -294,7 +315,8 @@ public final class CommandRegistrationManager { command.setDescription(LocaleLoader.getString("Commands.Description.mcremove")); command.setPermission("mcmmo.commands.mcremove"); command.setPermissionMessage(permissionsMessage); - command.setUsage(LocaleLoader.getString("Commands.Usage.1", "mcremove", "<" + LocaleLoader.getString("Commands.Usage.Player") + ">")); + command.setUsage(LocaleLoader.getString("Commands.Usage.1", "mcremove", + "<" + LocaleLoader.getString("Commands.Usage.Player") + ">")); command.setExecutor(new McremoveCommand()); } @@ -310,42 +332,28 @@ public final class CommandRegistrationManager { private static void registerMcconvertCommand() { PluginCommand command = mcMMO.p.getCommand("mcconvert"); command.setDescription(LocaleLoader.getString("Commands.Description.mcconvert")); - command.setPermission("mcmmo.commands.mcconvert;mcmmo.commands.mcconvert.experience;mcmmo.commands.mcconvert.database"); + command.setPermission( + "mcmmo.commands.mcconvert;mcmmo.commands.mcconvert.experience;mcmmo.commands.mcconvert.database"); command.setPermissionMessage(permissionsMessage); - command.setUsage(LocaleLoader.getString("Commands.Usage.2", "mcconvert", "database", "")); - command.setUsage(command.getUsage() + "\n" + LocaleLoader.getString("Commands.Usage.2", "mcconvert", "experience", "")); + command.setUsage(LocaleLoader.getString("Commands.Usage.2", "mcconvert", "database", + "")); + command.setUsage( + command.getUsage() + "\n" + LocaleLoader.getString("Commands.Usage.2", "mcconvert", + "experience", "")); command.setExecutor(new McconvertCommand()); } -// private static void registerAdminChatCommand() { -// PluginCommand command = mcMMO.p.getCommand("adminchat"); -// command.setDescription(LocaleLoader.getString("Commands.Description.adminchat")); -// command.setPermission("mcmmo.chat.adminchat"); -// command.setPermissionMessage(permissionsMessage); -// command.setUsage(LocaleLoader.getString("Commands.Usage.0", "adminchat")); -// command.setUsage(command.getUsage() + "\n" + LocaleLoader.getString("Commands.Usage.1", "adminchat", "")); -// command.setUsage(command.getUsage() + "\n" + LocaleLoader.getString("Commands.Usage.1", "adminchat", "<" + LocaleLoader.getString("Commands.Usage.Message") + ">")); -// command.setExecutor(new AdminChatCommand()); -// } - -// private static void registerPartyChatCommand() { -// PluginCommand command = mcMMO.p.getCommand("partychat"); -// command.setDescription(LocaleLoader.getString("Commands.Description.partychat")); -// command.setPermission("mcmmo.chat.partychat;mcmmo.commands.party"); -// command.setPermissionMessage(permissionsMessage); -// command.setUsage(LocaleLoader.getString("Commands.Usage.0", "partychat")); -// command.setUsage(command.getUsage() + "\n" + LocaleLoader.getString("Commands.Usage.1", "partychat", "")); -// command.setUsage(command.getUsage() + "\n" + LocaleLoader.getString("Commands.Usage.1", "partychat", "<" + LocaleLoader.getString("Commands.Usage.Message") + ">")); -// command.setExecutor(new PartyChatCommand()); -// } - private static void registerPartyCommand() { PluginCommand command = mcMMO.p.getCommand("party"); command.setDescription(LocaleLoader.getString("Commands.Description.party")); - command.setPermission("mcmmo.commands.party;mcmmo.commands.party.accept;mcmmo.commands.party.create;mcmmo.commands.party.disband;" + - "mcmmo.commands.party.xpshare;mcmmo.commands.party.invite;mcmmo.commands.party.itemshare;mcmmo.commands.party.join;" + - "mcmmo.commands.party.kick;mcmmo.commands.party.lock;mcmmo.commands.party.owner;mcmmo.commands.party.password;" + - "mcmmo.commands.party.quit;mcmmo.commands.party.rename;mcmmo.commands.party.unlock"); + command.setPermission( + "mcmmo.commands.party;mcmmo.commands.party.accept;mcmmo.commands.party.create;mcmmo.commands.party.disband;" + + + "mcmmo.commands.party.xpshare;mcmmo.commands.party.invite;mcmmo.commands.party.itemshare;mcmmo.commands.party.join;" + + + "mcmmo.commands.party.kick;mcmmo.commands.party.lock;mcmmo.commands.party.owner;mcmmo.commands.party.password;" + + + "mcmmo.commands.party.quit;mcmmo.commands.party.rename;mcmmo.commands.party.unlock"); command.setPermissionMessage(permissionsMessage); command.setExecutor(new PartyCommand()); } @@ -353,33 +361,17 @@ public final class CommandRegistrationManager { private static void registerPtpCommand() { PluginCommand command = mcMMO.p.getCommand("ptp"); command.setDescription(LocaleLoader.getString("Commands.Description.ptp")); - command.setPermission("mcmmo.commands.ptp"); // Only need the main one, not the individual ones for toggle/accept/acceptall + command.setPermission( + "mcmmo.commands.ptp"); // Only need the main one, not the individual ones for toggle/accept/acceptall command.setPermissionMessage(permissionsMessage); - command.setUsage(LocaleLoader.getString("Commands.Usage.1", "ptp", "<" + LocaleLoader.getString("Commands.Usage.Player") + ">")); - command.setUsage(command.getUsage() + "\n" + LocaleLoader.getString("Commands.Usage.1", "ptp", "")); + command.setUsage(LocaleLoader.getString("Commands.Usage.1", "ptp", + "<" + LocaleLoader.getString("Commands.Usage.Player") + ">")); + command.setUsage( + command.getUsage() + "\n" + LocaleLoader.getString("Commands.Usage.1", "ptp", + "")); command.setExecutor(new PtpCommand()); } -// private static void registerHardcoreCommand() { -// PluginCommand command = mcMMO.p.getCommand("hardcore"); -// command.setDescription(LocaleLoader.getString("Commands.Description.hardcore")); -// command.setPermission("mcmmo.commands.hardcore;mcmmo.commands.hardcore.toggle;mcmmo.commands.hardcore.modify"); -// command.setPermissionMessage(permissionsMessage); -// command.setUsage(LocaleLoader.getString("Commands.Usage.1", "hardcore", "[on|off]")); -// command.setUsage(command.getUsage() + "\n" + LocaleLoader.getString("Commands.Usage.1", "hardcore", "<" + LocaleLoader.getString("Commands.Usage.Rate") + ">")); -// command.setExecutor(new HardcoreCommand()); -// } -// -// private static void registerVampirismCommand() { -// PluginCommand command = mcMMO.p.getCommand("vampirism"); -// command.setDescription(LocaleLoader.getString("Commands.Description.vampirism")); -// command.setPermission("mcmmo.commands.vampirism;mcmmo.commands.vampirism.toggle;mcmmo.commands.vampirism.modify"); -// command.setPermissionMessage(permissionsMessage); -// command.setUsage(LocaleLoader.getString("Commands.Usage.1", "vampirism", "[on|off]")); -// command.setUsage(command.getUsage() + "\n" + LocaleLoader.getString("Commands.Usage.1", "vampirism", "<" + LocaleLoader.getString("Commands.Usage.Rate") + ">")); -// command.setExecutor(new VampirismCommand()); -// } - private static void registerMcnotifyCommand() { PluginCommand command = mcMMO.p.getCommand("mcnotify"); command.setDescription(LocaleLoader.getString("Commands.Description.mcnotify")); @@ -391,23 +383,17 @@ public final class CommandRegistrationManager { private static void registerMcscoreboardCommand() { PluginCommand command = mcMMO.p.getCommand("mcscoreboard"); - command.setDescription("Change the current mcMMO scoreboard being displayed"); //TODO: Localize + command.setDescription( + "Change the current mcMMO scoreboard being displayed"); //TODO: Localize command.setPermission("mcmmo.commands.mcscoreboard"); command.setPermissionMessage(permissionsMessage); - command.setUsage(LocaleLoader.getString("Commands.Usage.1", "mcscoreboard", "")); - command.setUsage(command.getUsage() + "\n" + LocaleLoader.getString("Commands.Usage.2", "mcscoreboard", "time", "")); + command.setUsage( + LocaleLoader.getString("Commands.Usage.1", "mcscoreboard", "")); + command.setUsage(command.getUsage() + "\n" + LocaleLoader.getString("Commands.Usage.2", + "mcscoreboard", "time", "")); command.setExecutor(new McscoreboardCommand()); } - private static void registerMcImportCommand() { - PluginCommand command = mcMMO.p.getCommand("mcimport"); - command.setDescription("Import mod config files"); //TODO: Localize - command.setPermission("mcmmo.commands.mcimport"); - command.setPermissionMessage(permissionsMessage); - command.setUsage(LocaleLoader.getString("Commands.Usage.0", "mcimport")); - command.setExecutor(new McImportCommand()); - } - private static void registerReloadLocaleCommand() { PluginCommand command = mcMMO.p.getCommand("mcmmoreloadlocale"); command.setDescription("Reloads locale"); // TODO: Localize @@ -427,8 +413,11 @@ public final class CommandRegistrationManager { private static void registerXPBarCommand() { PluginCommand command = mcMMO.p.getCommand("mmoxpbar"); //TODO: Localize command.setDescription(LocaleLoader.getString("Commands.Description.mmoxpbar")); - command.setUsage(LocaleLoader.getString("Commands.Usage.1", "mmoxpbar", "")); - command.setUsage(command.getUsage() +"\n" + LocaleLoader.getString("Commands.Usage.2", "mmoxpbar", "", "")); + command.setUsage( + LocaleLoader.getString("Commands.Usage.1", "mmoxpbar", "")); + command.setUsage( + command.getUsage() + "\n" + LocaleLoader.getString("Commands.Usage.2", "mmoxpbar", + "", "")); command.setExecutor(new XPBarCommand()); } @@ -437,7 +426,6 @@ public final class CommandRegistrationManager { registerXPBarCommand(); registerMmoInfoCommand(); registerMmoDebugCommand(); - registerMcImportCommand(); registerMcabilityCommand(); registerMcgodCommand(); registerMcChatSpyCommand(); @@ -459,13 +447,11 @@ public final class CommandRegistrationManager { registerMmoeditCommand(); registerSkillresetCommand(); - // Hardcore Commands -// registerHardcoreCommand(); -// registerVampirismCommand(); - // Party Commands - registerPartyCommand(); - registerPtpCommand(); + if (mcMMO.p.getPartyConfig().isPartyEnabled()) { + registerPartyCommand(); + registerPtpCommand(); + } // Player Commands registerInspectCommand(); diff --git a/src/main/java/com/gmail/nossr50/util/commands/CommandUtils.java b/src/main/java/com/gmail/nossr50/util/commands/CommandUtils.java index fcbd2fdbe..f08a5ab0c 100644 --- a/src/main/java/com/gmail/nossr50/util/commands/CommandUtils.java +++ b/src/main/java/com/gmail/nossr50/util/commands/CommandUtils.java @@ -12,34 +12,38 @@ import com.gmail.nossr50.util.skills.SkillTools; import com.gmail.nossr50.util.skills.SkillUtils; import com.gmail.nossr50.util.text.StringUtils; import com.google.common.collect.ImmutableList; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; import org.bukkit.OfflinePlayer; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; - public final class CommandUtils { - public static final List TRUE_FALSE_OPTIONS = ImmutableList.of("on", "off", "true", "false", "enabled", "disabled"); + public static final List TRUE_FALSE_OPTIONS = ImmutableList.of("on", "off", "true", + "false", "enabled", "disabled"); public static final List RESET_OPTIONS = ImmutableList.of("clear", "reset"); - private CommandUtils() {} + private CommandUtils() { + } public static boolean isChildSkill(CommandSender sender, PrimarySkillType skill) { if (skill == null || !SkillTools.isChildSkill(skill)) { return false; } - sender.sendMessage("Child skills are not supported by this command."); // TODO: Localize this + sender.sendMessage( + "Child skills are not supported by this command."); // TODO: Localize this return true; } public static boolean tooFar(CommandSender sender, Player target, boolean hasPermission) { - if(!target.isOnline() && !hasPermission) { + if (!target.isOnline() && !hasPermission) { sender.sendMessage(LocaleLoader.getString("Inspect.Offline")); return true; - } else if (sender instanceof Player && !Misc.isNear(((Player) sender).getLocation(), target.getLocation(), mcMMO.p.getGeneralConfig().getInspectDistance()) && !hasPermission) { + } else if (sender instanceof Player && !Misc.isNear(((Player) sender).getLocation(), + target.getLocation(), mcMMO.p.getGeneralConfig().getInspectDistance()) + && !hasPermission) { sender.sendMessage(LocaleLoader.getString("Inspect.TooFar")); return true; } @@ -70,17 +74,17 @@ public final class CommandUtils { } /** - * Checks if there is a valid mcMMOPlayer object. + * Checks if there is a valid mmoPlayer object. * * @param sender CommandSender who used the command * @param playerName name of the target player - * @param mcMMOPlayer mcMMOPlayer object of the target player - * - * @return true if the player is online and a valid mcMMOPlayer object was found + * @param mmoPlayer mmoPlayer object of the target player + * @return true if the player is online and a valid mmoPlayer object was found */ - public static boolean checkPlayerExistence(CommandSender sender, String playerName, McMMOPlayer mcMMOPlayer) { - if (mcMMOPlayer != null) { - if (CommandUtils.hidden(sender, mcMMOPlayer.getPlayer(), false)) { + public static boolean checkPlayerExistence(CommandSender sender, String playerName, + McMMOPlayer mmoPlayer) { + if (mmoPlayer != null) { + if (CommandUtils.hidden(sender, mmoPlayer.getPlayer(), false)) { sender.sendMessage(LocaleLoader.getString("Commands.Offline")); return false; } @@ -111,7 +115,8 @@ public final class CommandUtils { return false; } - boolean hasPlayerDataKey = ((Player) sender).hasMetadata(MetadataConstants.METADATA_KEY_PLAYER_DATA); + boolean hasPlayerDataKey = ((Player) sender).hasMetadata( + MetadataConstants.METADATA_KEY_PLAYER_DATA); if (!hasPlayerDataKey) { sender.sendMessage(LocaleLoader.getString("Commands.NotLoaded")); @@ -157,11 +162,13 @@ public final class CommandUtils { } public static boolean shouldEnableToggle(String arg) { - return arg.equalsIgnoreCase("on") || arg.equalsIgnoreCase("true") || arg.equalsIgnoreCase("enabled"); + return arg.equalsIgnoreCase("on") || arg.equalsIgnoreCase("true") || arg.equalsIgnoreCase( + "enabled"); } public static boolean shouldDisableToggle(String arg) { - return arg.equalsIgnoreCase("off") || arg.equalsIgnoreCase("false") || arg.equalsIgnoreCase("disabled"); + return arg.equalsIgnoreCase("off") || arg.equalsIgnoreCase("false") || arg.equalsIgnoreCase( + "disabled"); } /** @@ -171,7 +178,8 @@ public final class CommandUtils { * @param display The sender to display stats to */ public static void printGatheringSkills(Player inspect, CommandSender display) { - printGroupedSkillData(inspect, display, LocaleLoader.getString("Stats.Header.Gathering"), mcMMO.p.getSkillTools().GATHERING_SKILLS); + printGroupedSkillData(inspect, display, LocaleLoader.getString("Stats.Header.Gathering"), + mcMMO.p.getSkillTools().GATHERING_SKILLS); } public static void printGatheringSkills(Player player) { @@ -185,7 +193,8 @@ public final class CommandUtils { * @param display The sender to display stats to */ public static void printCombatSkills(Player inspect, CommandSender display) { - printGroupedSkillData(inspect, display, LocaleLoader.getString("Stats.Header.Combat"), mcMMO.p.getSkillTools().COMBAT_SKILLS); + printGroupedSkillData(inspect, display, LocaleLoader.getString("Stats.Header.Combat"), + mcMMO.p.getSkillTools().COMBAT_SKILLS); } public static void printCombatSkills(Player player) { @@ -199,7 +208,8 @@ public final class CommandUtils { * @param display The sender to display stats to */ public static void printMiscSkills(Player inspect, CommandSender display) { - printGroupedSkillData(inspect, display, LocaleLoader.getString("Stats.Header.Misc"), mcMMO.p.getSkillTools().getMiscSkills()); + printGroupedSkillData(inspect, display, LocaleLoader.getString("Stats.Header.Misc"), + mcMMO.p.getSkillTools().getMiscSkills()); } public static void printMiscSkills(Player player) { @@ -208,25 +218,36 @@ public final class CommandUtils { public static String displaySkill(PlayerProfile profile, PrimarySkillType skill) { if (SkillTools.isChildSkill(skill)) { - return LocaleLoader.getString("Skills.ChildStats", LocaleLoader.getString(StringUtils.getCapitalized(skill.toString()) + ".Listener") + " ", profile.getSkillLevel(skill)); + return LocaleLoader.getString("Skills.ChildStats", LocaleLoader.getString( + StringUtils.getCapitalized(skill.toString()) + ".Listener") + " ", + profile.getSkillLevel(skill)); } - if (profile.getSkillLevel(skill) == mcMMO.p.getSkillTools().getLevelCap(skill)){ - return LocaleLoader.getString("Skills.Stats", LocaleLoader.getString(StringUtils.getCapitalized(skill.toString()) + ".Listener") + " ", profile.getSkillLevel(skill), profile.getSkillXpLevel(skill), LocaleLoader.getString("Skills.MaxXP")); + if (profile.getSkillLevel(skill) == mcMMO.p.getSkillTools().getLevelCap(skill)) { + return LocaleLoader.getString("Skills.Stats", LocaleLoader.getString( + StringUtils.getCapitalized(skill.toString()) + ".Listener") + " ", + profile.getSkillLevel(skill), profile.getSkillXpLevel(skill), + LocaleLoader.getString("Skills.MaxXP")); } - return LocaleLoader.getString("Skills.Stats", LocaleLoader.getString(StringUtils.getCapitalized(skill.toString()) + ".Listener") + " ", profile.getSkillLevel(skill), profile.getSkillXpLevel(skill), profile.getXpToLevel(skill)); + return LocaleLoader.getString("Skills.Stats", + LocaleLoader.getString(StringUtils.getCapitalized(skill.toString()) + ".Listener") + + " ", profile.getSkillLevel(skill), profile.getSkillXpLevel(skill), + profile.getXpToLevel(skill)); } - private static void printGroupedSkillData(Player inspectTarget, CommandSender display, String header, List skillGroup) { - if(UserManager.getPlayer(inspectTarget) == null) + private static void printGroupedSkillData(Player inspectTarget, CommandSender display, + String header, List skillGroup) { + if (UserManager.getPlayer(inspectTarget) == null) { return; + } - PlayerProfile profile = UserManager.getPlayer(inspectTarget).getProfile(); + final PlayerProfile profile = UserManager.getPlayer(inspectTarget).getProfile(); - List displayData = new ArrayList<>(); + final List displayData = new ArrayList<>(); displayData.add(header); for (PrimarySkillType primarySkillType : skillGroup) { - if (mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(inspectTarget, primarySkillType)) { + if (mcMMO.p.getSkillTools() + .doesPlayerHaveSkillPermission(inspectTarget, primarySkillType)) { displayData.add(displaySkill(profile, primarySkillType)); } } @@ -255,7 +276,6 @@ public final class CommandUtils { * Get a matched player name if one was found in the database. * * @param partialName Name to match - * * @return Matched name or {@code partialName} if no match was found */ public static String getMatchedPlayerName(String partialName) { @@ -265,8 +285,7 @@ public final class CommandUtils { if (matches.size() == 1) { partialName = matches.get(0); } - } - else { + } else { Player player = mcMMO.p.getServer().getPlayer(partialName); if (player != null) { @@ -278,10 +297,11 @@ public final class CommandUtils { } /** - * Attempts to match any player names with the given name, and returns a list of all possibly matches. - * - * This list is not sorted in any particular order. - * If an exact match is found, the returned list will only contain a single result. + * Attempts to match any player names with the given name, and returns a list of all possibly + * matches. + *

+ * This list is not sorted in any particular order. If an exact match is found, the returned + * list will only contain a single result. * * @param partialName Name to match * @return List of all possible names @@ -291,10 +311,13 @@ public final class CommandUtils { for (OfflinePlayer offlinePlayer : mcMMO.p.getServer().getOfflinePlayers()) { String playerName = offlinePlayer.getName(); - - if (playerName == null) { //Do null checking here to detect corrupted data before sending it throuogh .equals - System.err.println("[McMMO] Player data file with UIID " + offlinePlayer.getUniqueId() + " is missing a player name. This may be a legacy file from before bukkit.lastKnownName. This should be okay to ignore."); - continue; //Don't let an error here interrupt the loop + + if (playerName + == null) { //Do null checking here to detect corrupted data before sending it throuogh .equals + System.err.println( + "[McMMO] Player data file with UIID " + offlinePlayer.getUniqueId() + + " is missing a player name. This may be a legacy file from before bukkit.lastKnownName. This should be okay to ignore."); + continue; //Don't let an error here interrupt the loop } if (partialName.equalsIgnoreCase(playerName)) { @@ -304,7 +327,8 @@ public final class CommandUtils { break; } - if (playerName.toLowerCase(Locale.ENGLISH).contains(partialName.toLowerCase(Locale.ENGLISH))) { + if (playerName.toLowerCase(Locale.ENGLISH) + .contains(partialName.toLowerCase(Locale.ENGLISH))) { // Partial match matchedPlayers.add(playerName); } 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 5abbaa818..7dbd576bf 100644 --- a/src/main/java/com/gmail/nossr50/util/compat/CompatibilityLayer.java +++ b/src/main/java/com/gmail/nossr50/util/compat/CompatibilityLayer.java @@ -6,7 +6,11 @@ package com.gmail.nossr50.util.compat; public interface CompatibilityLayer { /** * Whether this CompatibilityLayer successfully initialized and in theory should be functional + * * @return true if this CompatibilityLayer is functional */ - default boolean noErrorsOnInitialize() { return true; }; + default boolean noErrorsOnInitialize() { + return true; + } + } diff --git a/src/main/java/com/gmail/nossr50/util/compat/CompatibilityManager.java b/src/main/java/com/gmail/nossr50/util/compat/CompatibilityManager.java index 11d4a6d68..e7a9237ad 100644 --- a/src/main/java/com/gmail/nossr50/util/compat/CompatibilityManager.java +++ b/src/main/java/com/gmail/nossr50/util/compat/CompatibilityManager.java @@ -11,19 +11,15 @@ import com.gmail.nossr50.util.compat.layers.skills.MasterAnglerCompatibilityLaye import com.gmail.nossr50.util.nms.NMSVersion; import com.gmail.nossr50.util.platform.MinecraftGameVersion; import com.gmail.nossr50.util.text.StringUtils; +import java.util.HashMap; import org.bukkit.command.CommandSender; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.HashMap; - /** - * - * These classes are a band-aid solution for adding NMS support into 2.1.XXX - * In 2.2 we are switching to modules and that will clean things up significantly - * + * These classes are a band-aid solution for adding NMS support into 2.1.XXX In 2.2 we are switching + * to modules and that will clean things up significantly */ -//TODO: I need to delete this crap public class CompatibilityManager { private @NotNull HashMap supportedLayers; private boolean isFullyCompatibleServerSoftware = true; //true if all compatibility layers load successfully @@ -50,14 +46,14 @@ public class CompatibilityManager { private void initSupportedLayersMap() { supportedLayers = new HashMap<>(); //Init map - for(CompatibilityType compatibilityType : CompatibilityType.values()) { - supportedLayers.put(compatibilityType, false); //All layers are set to false when initialized + for (CompatibilityType compatibilityType : CompatibilityType.values()) { + supportedLayers.put(compatibilityType, + false); //All layers are set to false when initialized } } /** - * Initialize all necessary compatibility layers - * For any unsupported layers, load a dummy layer + * Initialize all necessary compatibility layers For any unsupported layers, load a dummy layer */ private void initCompatibilityLayers() { initBungeeSerializerLayer(); @@ -67,7 +63,7 @@ public class CompatibilityManager { } private void initMasterAnglerLayer() { - if(minecraftGameVersion.isAtLeast(1, 16, 3)) { + if (minecraftGameVersion.isAtLeast(1, 16, 3)) { masterAnglerCompatibility = new MasterAnglerCompatibilityLayer(); } else { masterAnglerCompatibility = null; @@ -75,7 +71,7 @@ public class CompatibilityManager { } private void initBungeeSerializerLayer() { - if(minecraftGameVersion.isAtLeast(1, 16, 0)) { + if (minecraftGameVersion.isAtLeast(1, 16, 0)) { bungeeSerializerCompatibilityLayer = new BungeeModernSerializerCompatibilityLayer(); } else { bungeeSerializerCompatibilityLayer = new BungeeLegacySerializerCompatibilityLayer(); @@ -86,20 +82,22 @@ public class CompatibilityManager { //TODO: move to text manager public void reportCompatibilityStatus(@NotNull CommandSender commandSender) { - if(isFullyCompatibleServerSoftware) { + if (isFullyCompatibleServerSoftware) { commandSender.sendMessage(LocaleLoader.getString("mcMMO.Template.Prefix", "mcMMO is fully compatible with the currently running server software.")); } else { //TODO: Better messages for each incompatible layer - for(CompatibilityType compatibilityType : CompatibilityType.values()) { - if(!supportedLayers.get(compatibilityType)) { + for (CompatibilityType compatibilityType : CompatibilityType.values()) { + if (!supportedLayers.get(compatibilityType)) { commandSender.sendMessage(LocaleLoader.getString("mcMMO.Template.Prefix", - LocaleLoader.getString("Compatibility.Layer.Unsupported", StringUtils.getCapitalized(compatibilityType.toString())))); + LocaleLoader.getString("Compatibility.Layer.Unsupported", + StringUtils.getCapitalized(compatibilityType.toString())))); } } } - commandSender.sendMessage(LocaleLoader.getString("mcMMO.Template.Prefix", "NMS Status - " + nmsVersion.toString())); + commandSender.sendMessage(LocaleLoader.getString("mcMMO.Template.Prefix", + "NMS Status - " + nmsVersion)); } public boolean isCompatibilityLayerOperational(@NotNull CompatibilityType compatibilityType) { @@ -116,7 +114,7 @@ public class CompatibilityManager { private @NotNull NMSVersion determineNMSVersion() { //This bit here helps prevent mcMMO breaking if it isn't updated but the game continues to update - if(minecraftGameVersion.isAtLeast(1, 17, 0)) { + if (minecraftGameVersion.isAtLeast(1, 17, 0)) { return NMSVersion.NMS_1_17; } @@ -134,13 +132,13 @@ public class CompatibilityManager { case 16: if (minecraftGameVersion.getPatchVersion().asInt() == 1) { return NMSVersion.NMS_1_16_1; - } else if(minecraftGameVersion.getPatchVersion().asInt() == 2) { + } else if (minecraftGameVersion.getPatchVersion().asInt() == 2) { return NMSVersion.NMS_1_16_2; - } else if(minecraftGameVersion.getPatchVersion().asInt() == 3) { + } else if (minecraftGameVersion.getPatchVersion().asInt() == 3) { return NMSVersion.NMS_1_16_3; - } else if(minecraftGameVersion.getPatchVersion().asInt() == 4) { + } else if (minecraftGameVersion.getPatchVersion().asInt() == 4) { return NMSVersion.NMS_1_16_4; - } else if(minecraftGameVersion.getPatchVersion().asInt() >= 5) { + } else if (minecraftGameVersion.getPatchVersion().asInt() >= 5) { return NMSVersion.NMS_1_16_5; } case 17: @@ -159,7 +157,7 @@ public class CompatibilityManager { return masterAnglerCompatibility; } - public @Nullable MinecraftGameVersion getMinecraftGameVersion() { + public @NotNull MinecraftGameVersion getMinecraftGameVersion() { return minecraftGameVersion; } } diff --git a/src/main/java/com/gmail/nossr50/util/compat/layers/AbstractCompatibilityLayer.java b/src/main/java/com/gmail/nossr50/util/compat/layers/AbstractCompatibilityLayer.java index 2ae4a61e1..ab32dc2b4 100644 --- a/src/main/java/com/gmail/nossr50/util/compat/layers/AbstractCompatibilityLayer.java +++ b/src/main/java/com/gmail/nossr50/util/compat/layers/AbstractCompatibilityLayer.java @@ -3,10 +3,8 @@ package com.gmail.nossr50.util.compat.layers; import com.gmail.nossr50.util.compat.CompatibilityLayer; /** - * - * These classes are a band-aid solution for adding NMS support into 2.1.XXX - * In 2.2 we are switching to modules and that will clean things up significantly - * + * These classes are a band-aid solution for adding NMS support into 2.1.XXX In 2.2 we are switching + * to modules and that will clean things up significantly */ public abstract class AbstractCompatibilityLayer implements CompatibilityLayer { @@ -14,6 +12,7 @@ public abstract class AbstractCompatibilityLayer implements CompatibilityLayer { /** * Initialize the CompatibilityLayer + * * @return true if the CompatibilityLayer initialized and should be functional */ public abstract boolean initializeLayer(); diff --git a/src/main/java/com/gmail/nossr50/util/compat/layers/AbstractNMSCompatibilityLayer.java b/src/main/java/com/gmail/nossr50/util/compat/layers/AbstractNMSCompatibilityLayer.java index 05136c189..f337f61fd 100644 --- a/src/main/java/com/gmail/nossr50/util/compat/layers/AbstractNMSCompatibilityLayer.java +++ b/src/main/java/com/gmail/nossr50/util/compat/layers/AbstractNMSCompatibilityLayer.java @@ -4,10 +4,8 @@ import com.gmail.nossr50.util.nms.NMSVersion; import org.jetbrains.annotations.NotNull; /** - * - * These classes are a band-aid solution for adding NMS support into 2.1.XXX - * In 2.2 we are switching to modules and that will clean things up significantly - * + * These classes are a band-aid solution for adding NMS support into 2.1.XXX In 2.2 we are switching + * to modules and that will clean things up significantly */ public abstract class AbstractNMSCompatibilityLayer extends AbstractCompatibilityLayer { @@ -19,6 +17,7 @@ public abstract class AbstractNMSCompatibilityLayer extends AbstractCompatibilit /** * Initialize the CompatibilityLayer + * * @return true if the CompatibilityLayer initialized and should be functional */ public abstract boolean initializeLayer(); diff --git a/src/main/java/com/gmail/nossr50/util/compat/layers/attackcooldown/PlayerAttackCooldownMethods.java b/src/main/java/com/gmail/nossr50/util/compat/layers/attackcooldown/PlayerAttackCooldownMethods.java index 510577a68..c7ae24085 100644 --- a/src/main/java/com/gmail/nossr50/util/compat/layers/attackcooldown/PlayerAttackCooldownMethods.java +++ b/src/main/java/com/gmail/nossr50/util/compat/layers/attackcooldown/PlayerAttackCooldownMethods.java @@ -1,24 +1,30 @@ package com.gmail.nossr50.util.compat.layers.attackcooldown; +import java.lang.reflect.InvocationTargetException; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; -import java.lang.reflect.InvocationTargetException; - public interface PlayerAttackCooldownMethods { /** - * Grabs the attack strength for a player - * Should be noted that as of today there is no way to capture a players current attack strength in spigot when they attack an entity outside of network packet listening + * Grabs the attack strength for a player Should be noted that as of today there is no way to + * capture a players current attack strength in spigot when they attack an entity outside of + * network packet listening + * * @param player target player * @return the float value of the player's attack strength */ - float getAttackStrength(@NotNull Player player) throws InvocationTargetException, IllegalAccessException; + float getAttackStrength(@NotNull Player player) + throws InvocationTargetException, IllegalAccessException; - float getCooldownValue(@NotNull Player player) throws InvocationTargetException, IllegalAccessException; + float getCooldownValue(@NotNull Player player) + throws InvocationTargetException, IllegalAccessException; - void resetAttackStrength(@NotNull Player player) throws InvocationTargetException, IllegalAccessException; + void resetAttackStrength(@NotNull Player player) + throws InvocationTargetException, IllegalAccessException; - int getCooldownFieldValue(@NotNull Player player) throws InvocationTargetException, IllegalAccessException; + int getCooldownFieldValue(@NotNull Player player) + throws InvocationTargetException, IllegalAccessException; - void setCooldownFieldValue(@NotNull Player player, int fieldValue) throws InvocationTargetException, IllegalAccessException; + void setCooldownFieldValue(@NotNull Player player, int fieldValue) + throws InvocationTargetException, IllegalAccessException; } diff --git a/src/main/java/com/gmail/nossr50/util/compat/layers/attackcooldown/PlayerAttackCooldownToolLayer.java b/src/main/java/com/gmail/nossr50/util/compat/layers/attackcooldown/PlayerAttackCooldownToolLayer.java index 5b0026198..c35d7f6ad 100644 --- a/src/main/java/com/gmail/nossr50/util/compat/layers/attackcooldown/PlayerAttackCooldownToolLayer.java +++ b/src/main/java/com/gmail/nossr50/util/compat/layers/attackcooldown/PlayerAttackCooldownToolLayer.java @@ -12,7 +12,7 @@ //import java.lang.reflect.InvocationTargetException; //import java.lang.reflect.Method; // -///** +/// ** // * // * These classes are a band-aid solution for adding NMS support into 2.1.XXX // * In 2.2 we are switching to modules and that will clean things up significantly @@ -37,15 +37,15 @@ // public PlayerAttackCooldownToolLayer(@NotNull NMSVersion nmsVersion) { // super(nmsVersion); // mcMMO.p.getLogger().info("Loading Compatibility Layer... (Player Attack Cooldown Exploit Prevention)"); -// if(!isCompatibleWithMinecraftVersion(nmsVersion)) { +// if (!isCompatibleWithMinecraftVersion(nmsVersion)) { // mcMMO.p.getLogger().severe("this version of mcMMO does not support NMS for this version of Minecraft, try updating mcMMO or updating Minecraft. Not all versions of Minecraft will have NMS support built into mcMMO."); // cbNMSVersionPath = ""; // } else { -// if(NMSConstants.getCraftBukkitVersionPath(nmsVersion) != null) { +// if (NMSConstants.getCraftBukkitVersionPath(nmsVersion) != null) { // cbNMSVersionPath = NMSConstants.getCraftBukkitVersionPath(nmsVersion); // noErrorsOnInitialize = initializeLayer(); // -// if(noErrorsOnInitialize) { +// if (noErrorsOnInitialize) { // mcMMO.p.getLogger().info("Successfully Loaded Compatibility Layer! (Player Attack Cooldown Exploit Prevention)"); // } // } else { diff --git a/src/main/java/com/gmail/nossr50/util/compat/layers/bungee/AbstractBungeeSerializerCompatibilityLayer.java b/src/main/java/com/gmail/nossr50/util/compat/layers/bungee/AbstractBungeeSerializerCompatibilityLayer.java index 590a65381..683f0efee 100644 --- a/src/main/java/com/gmail/nossr50/util/compat/layers/bungee/AbstractBungeeSerializerCompatibilityLayer.java +++ b/src/main/java/com/gmail/nossr50/util/compat/layers/bungee/AbstractBungeeSerializerCompatibilityLayer.java @@ -6,6 +6,6 @@ import org.checkerframework.checker.nullness.qual.NonNull; public abstract class AbstractBungeeSerializerCompatibilityLayer { - public abstract @NonNull Component deserialize(final @NonNull BaseComponent @NonNull[] input); + public abstract @NonNull Component deserialize(final @NonNull BaseComponent @NonNull [] input); } diff --git a/src/main/java/com/gmail/nossr50/util/compat/layers/bungee/BungeeLegacySerializerCompatibilityLayer.java b/src/main/java/com/gmail/nossr50/util/compat/layers/bungee/BungeeLegacySerializerCompatibilityLayer.java index 09c44faaa..24f614157 100644 --- a/src/main/java/com/gmail/nossr50/util/compat/layers/bungee/BungeeLegacySerializerCompatibilityLayer.java +++ b/src/main/java/com/gmail/nossr50/util/compat/layers/bungee/BungeeLegacySerializerCompatibilityLayer.java @@ -5,7 +5,8 @@ import net.kyori.adventure.text.serializer.bungeecord.BungeeComponentSerializer; import net.md_5.bungee.api.chat.BaseComponent; import org.checkerframework.checker.nullness.qual.NonNull; -public class BungeeLegacySerializerCompatibilityLayer extends AbstractBungeeSerializerCompatibilityLayer { +public class BungeeLegacySerializerCompatibilityLayer extends + AbstractBungeeSerializerCompatibilityLayer { @Override public @NonNull Component deserialize(@NonNull BaseComponent @NonNull [] input) { return BungeeComponentSerializer.legacy().deserialize(input); diff --git a/src/main/java/com/gmail/nossr50/util/compat/layers/bungee/BungeeModernSerializerCompatibilityLayer.java b/src/main/java/com/gmail/nossr50/util/compat/layers/bungee/BungeeModernSerializerCompatibilityLayer.java index 0fc93a702..41d27030c 100644 --- a/src/main/java/com/gmail/nossr50/util/compat/layers/bungee/BungeeModernSerializerCompatibilityLayer.java +++ b/src/main/java/com/gmail/nossr50/util/compat/layers/bungee/BungeeModernSerializerCompatibilityLayer.java @@ -5,7 +5,8 @@ import net.kyori.adventure.text.serializer.bungeecord.BungeeComponentSerializer; import net.md_5.bungee.api.chat.BaseComponent; import org.checkerframework.checker.nullness.qual.NonNull; -public class BungeeModernSerializerCompatibilityLayer extends AbstractBungeeSerializerCompatibilityLayer { +public class BungeeModernSerializerCompatibilityLayer extends + AbstractBungeeSerializerCompatibilityLayer { @Override public @NonNull Component deserialize(@NonNull BaseComponent @NonNull [] input) { return BungeeComponentSerializer.get().deserialize(input); diff --git a/src/main/java/com/gmail/nossr50/util/compat/layers/skills/MasterAnglerCompatibilityLayer.java b/src/main/java/com/gmail/nossr50/util/compat/layers/skills/MasterAnglerCompatibilityLayer.java index 665bd1aec..e0b5a4d5f 100644 --- a/src/main/java/com/gmail/nossr50/util/compat/layers/skills/MasterAnglerCompatibilityLayer.java +++ b/src/main/java/com/gmail/nossr50/util/compat/layers/skills/MasterAnglerCompatibilityLayer.java @@ -12,8 +12,7 @@ public class MasterAnglerCompatibilityLayer extends AbstractMasterAnglerCompatib /** * Get the minimum number of ticks one has to wait for a fish biting. *

- * The default is 100 ticks (5 seconds).
- * Note that this is before applying lure. + * The default is 100 ticks (5 seconds).
Note that this is before applying lure. * * @return Minimum number of ticks one has to wait for a fish biting */ @@ -24,11 +23,9 @@ public class MasterAnglerCompatibilityLayer extends AbstractMasterAnglerCompatib /** * Set the minimum number of ticks one has to wait for a fish biting. *

- * The default is 100 ticks (5 seconds).
- * Note that this is before applying lure. + * The default is 100 ticks (5 seconds).
Note that this is before applying lure. * - * @param minWaitTime Minimum number of ticks one has to wait for a fish - * biting + * @param minWaitTime Minimum number of ticks one has to wait for a fish biting */ public void setMinWaitTime(@NotNull FishHook fishHook, int minWaitTime) { fishHook.setMinWaitTime(minWaitTime); @@ -37,8 +34,7 @@ public class MasterAnglerCompatibilityLayer extends AbstractMasterAnglerCompatib /** * Get the maximum number of ticks one has to wait for a fish biting. *

- * The default is 600 ticks (30 seconds).
- * Note that this is before applying lure. + * The default is 600 ticks (30 seconds).
Note that this is before applying lure. * * @return Maximum number of ticks one has to wait for a fish biting */ @@ -49,41 +45,33 @@ public class MasterAnglerCompatibilityLayer extends AbstractMasterAnglerCompatib /** * Set the maximum number of ticks one has to wait for a fish biting. *

- * The default is 600 ticks (30 seconds).
- * Note that this is before applying lure. + * The default is 600 ticks (30 seconds).
Note that this is before applying lure. * - * @param maxWaitTime Maximum number of ticks one has to wait for a fish - * biting + * @param maxWaitTime Maximum number of ticks one has to wait for a fish biting */ public void setMaxWaitTime(@NotNull FishHook fishHook, int maxWaitTime) { fishHook.setMaxWaitTime(maxWaitTime); } /** - * Get whether the lure enchantment should be applied to reduce the wait - * time. + * Get whether the lure enchantment should be applied to reduce the wait time. *

- * The default is true.
- * Lure reduces the wait time by 100 ticks (5 seconds) for each level of the - * enchantment. + * The default is true.
Lure reduces the wait time by 100 ticks (5 seconds) for each level + * of the enchantment. * - * @return Whether the lure enchantment should be applied to reduce the wait - * time + * @return Whether the lure enchantment should be applied to reduce the wait time */ public boolean getApplyLure(@NotNull FishHook fishHook) { return fishHook.getApplyLure(); } /** - * Set whether the lure enchantment should be applied to reduce the wait - * time. + * Set whether the lure enchantment should be applied to reduce the wait time. *

- * The default is true.
- * Lure reduces the wait time by 100 ticks (5 seconds) for each level of the - * enchantment. + * The default is true.
Lure reduces the wait time by 100 ticks (5 seconds) for each level + * of the enchantment. * - * @param applyLure Whether the lure enchantment should be applied to reduce - * the wait time + * @param applyLure Whether the lure enchantment should be applied to reduce the wait time */ public void setApplyLure(@NotNull FishHook fishHook, boolean applyLure) { fishHook.setApplyLure(applyLure); diff --git a/src/main/java/com/gmail/nossr50/util/experience/ExperienceBarManager.java b/src/main/java/com/gmail/nossr50/util/experience/ExperienceBarManager.java index c4617bd69..dc155fcdc 100644 --- a/src/main/java/com/gmail/nossr50/util/experience/ExperienceBarManager.java +++ b/src/main/java/com/gmail/nossr50/util/experience/ExperienceBarManager.java @@ -7,19 +7,18 @@ import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.runnables.skills.ExperienceBarHideTask; import com.gmail.nossr50.util.Misc; import com.gmail.nossr50.util.player.NotificationManager; +import java.util.HashMap; +import java.util.HashSet; import org.bukkit.plugin.Plugin; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.HashMap; -import java.util.HashSet; - /** - * ExperienceBarManager handles displaying and updating mcMMO experience bars for players - * Each ExperienceBarManager only manages a single player + * ExperienceBarManager handles displaying and updating mcMMO experience bars for players Each + * ExperienceBarManager only manages a single player */ public class ExperienceBarManager { - private final McMMOPlayer mcMMOPlayer; + private final McMMOPlayer mmoPlayer; int delaySeconds = 3; private HashMap experienceBars; @@ -28,9 +27,8 @@ public class ExperienceBarManager { private HashSet alwaysVisible; private HashSet disabledBars; - public ExperienceBarManager(McMMOPlayer mcMMOPlayer) - { - this.mcMMOPlayer = mcMMOPlayer; + public ExperienceBarManager(McMMOPlayer mmoPlayer) { + this.mmoPlayer = mmoPlayer; init(); } @@ -44,29 +42,31 @@ public class ExperienceBarManager { disabledBars = new HashSet<>(); } - public void updateExperienceBar(PrimarySkillType primarySkillType, Plugin plugin) - { - if(disabledBars.contains(primarySkillType) + public void updateExperienceBar(PrimarySkillType primarySkillType, Plugin plugin) { + if (disabledBars.contains(primarySkillType) || !ExperienceConfig.getInstance().isExperienceBarsEnabled() - || !ExperienceConfig.getInstance().isExperienceBarEnabled(primarySkillType)) + || !ExperienceConfig.getInstance().isExperienceBarEnabled(primarySkillType)) { return; + } //Init Bar - if(experienceBars.get(primarySkillType) == null) - experienceBars.put(primarySkillType, new ExperienceBarWrapper(primarySkillType, mcMMOPlayer)); + if (experienceBars.get(primarySkillType) == null) { + experienceBars.put(primarySkillType, + new ExperienceBarWrapper(primarySkillType, mmoPlayer)); + } //Get Bar ExperienceBarWrapper experienceBarWrapper = experienceBars.get(primarySkillType); //Update Progress - experienceBarWrapper.setProgress(mcMMOPlayer.getProgressInCurrentSkillLevel(primarySkillType)); + experienceBarWrapper.setProgress( + mmoPlayer.getProgressInCurrentSkillLevel(primarySkillType)); //Show Bar experienceBarWrapper.showExperienceBar(); //Setup Hide Bar Task - if(experienceBarHideTaskHashMap.get(primarySkillType) != null) - { + if (experienceBarHideTaskHashMap.get(primarySkillType) != null) { experienceBarHideTaskHashMap.get(primarySkillType).cancel(); } @@ -74,41 +74,46 @@ public class ExperienceBarManager { } private void scheduleHideTask(PrimarySkillType primarySkillType, Plugin plugin) { - if(alwaysVisible.contains(primarySkillType)) + if (alwaysVisible.contains(primarySkillType)) { return; + } - ExperienceBarHideTask experienceBarHideTask = new ExperienceBarHideTask(this, mcMMOPlayer, primarySkillType); - mcMMO.p.getFoliaLib().getImpl().runAtEntityLater(mcMMOPlayer.getPlayer(), experienceBarHideTask, (long) delaySeconds * Misc.TICK_CONVERSION_FACTOR); + ExperienceBarHideTask experienceBarHideTask = new ExperienceBarHideTask(this, mmoPlayer, + primarySkillType); + mcMMO.p.getFoliaLib().getScheduler() + .runAtEntityLater(mmoPlayer.getPlayer(), experienceBarHideTask, + (long) delaySeconds * Misc.TICK_CONVERSION_FACTOR); experienceBarHideTaskHashMap.put(primarySkillType, experienceBarHideTask); } - public void hideExperienceBar(PrimarySkillType primarySkillType) - { - if(experienceBars.containsKey(primarySkillType)) + public void hideExperienceBar(PrimarySkillType primarySkillType) { + if (experienceBars.containsKey(primarySkillType)) { experienceBars.get(primarySkillType).hideExperienceBar(); + } } - public void clearTask(PrimarySkillType primarySkillType) - { + public void clearTask(PrimarySkillType primarySkillType) { experienceBarHideTaskHashMap.remove(primarySkillType); } public void disableAllBars() { - for(PrimarySkillType primarySkillType : PrimarySkillType.values()) { + for (PrimarySkillType primarySkillType : PrimarySkillType.values()) { xpBarSettingToggle(XPBarSettingTarget.HIDE, primarySkillType); } - NotificationManager.sendPlayerInformationChatOnlyPrefixed(mcMMOPlayer.getPlayer(), "Commands.XPBar.DisableAll"); + NotificationManager.sendPlayerInformationChatOnlyPrefixed(mmoPlayer.getPlayer(), + "Commands.XPBar.DisableAll"); } - public void xpBarSettingToggle(@NotNull XPBarSettingTarget settingTarget, @Nullable PrimarySkillType skillType) { - switch(settingTarget) { + public void xpBarSettingToggle(@NotNull XPBarSettingTarget settingTarget, + @Nullable PrimarySkillType skillType) { + switch (settingTarget) { case SHOW: disabledBars.remove(skillType); alwaysVisible.add(skillType); //Remove lingering tasks - if(experienceBarHideTaskHashMap.containsKey(skillType)) { + if (experienceBarHideTaskHashMap.containsKey(skillType)) { experienceBarHideTaskHashMap.get(skillType).cancel(); } @@ -119,7 +124,7 @@ public class ExperienceBarManager { disabledBars.add(skillType); //Remove lingering tasks - if(experienceBarHideTaskHashMap.containsKey(skillType)) { + if (experienceBarHideTaskHashMap.containsKey(skillType)) { experienceBarHideTaskHashMap.get(skillType).cancel(); } @@ -135,7 +140,7 @@ public class ExperienceBarManager { private void resetBarSettings() { //Hide all currently permanent bars - for(PrimarySkillType permanent : alwaysVisible) { + for (PrimarySkillType permanent : alwaysVisible) { hideExperienceBar(permanent); } @@ -147,14 +152,25 @@ public class ExperienceBarManager { disabledBars.add(PrimarySkillType.SMELTING); } - private void informPlayer(@NotNull ExperienceBarManager.@NotNull XPBarSettingTarget settingTarget, @Nullable PrimarySkillType primarySkillType) { + private void informPlayer( + @NotNull ExperienceBarManager.@NotNull XPBarSettingTarget settingTarget, + @Nullable PrimarySkillType primarySkillType) { //Inform player of setting change - if(settingTarget != XPBarSettingTarget.RESET) { - NotificationManager.sendPlayerInformationChatOnlyPrefixed(mcMMOPlayer.getPlayer(), "Commands.XPBar.SettingChanged", mcMMO.p.getSkillTools().getLocalizedSkillName(primarySkillType), settingTarget.toString()); + if (settingTarget != XPBarSettingTarget.RESET) { + NotificationManager.sendPlayerInformationChatOnlyPrefixed(mmoPlayer.getPlayer(), + "Commands.XPBar.SettingChanged", + mcMMO.p.getSkillTools().getLocalizedSkillName(primarySkillType), + settingTarget.toString()); } else { - NotificationManager.sendPlayerInformationChatOnlyPrefixed(mcMMOPlayer.getPlayer(), "Commands.XPBar.Reset"); + NotificationManager.sendPlayerInformationChatOnlyPrefixed(mmoPlayer.getPlayer(), + "Commands.XPBar.Reset"); } } - public enum XPBarSettingTarget { SHOW, HIDE, RESET, DISABLE } + public enum XPBarSettingTarget { + SHOW, + HIDE, + RESET, + DISABLE + } } 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 185026ed9..4da3da66f 100644 --- a/src/main/java/com/gmail/nossr50/util/experience/ExperienceBarWrapper.java +++ b/src/main/java/com/gmail/nossr50/util/experience/ExperienceBarWrapper.java @@ -6,13 +6,12 @@ import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.util.player.PlayerLevelUtils; import com.gmail.nossr50.util.text.StringUtils; +import java.util.List; import org.bukkit.boss.BarColor; import org.bukkit.boss.BarStyle; import org.bukkit.boss.BossBar; import org.bukkit.entity.Player; -import java.util.List; - /** * A visual representation of a player's skill level progress for a PrimarySkillType */ @@ -20,7 +19,7 @@ public class ExperienceBarWrapper { private final PrimarySkillType primarySkillType; //Primary Skill private BossBar bossBar; - protected final McMMOPlayer mcMMOPlayer; + protected final McMMOPlayer mmoPlayer; private int lastLevelUpdated; /* @@ -29,9 +28,8 @@ public class ExperienceBarWrapper { protected String niceSkillName; protected String title; - public ExperienceBarWrapper(PrimarySkillType primarySkillType, McMMOPlayer mcMMOPlayer) - { - this.mcMMOPlayer = mcMMOPlayer; + public ExperienceBarWrapper(PrimarySkillType primarySkillType, McMMOPlayer mmoPlayer) { + this.mmoPlayer = mmoPlayer; this.primarySkillType = primarySkillType; title = ""; lastLevelUpdated = 0; @@ -43,8 +41,7 @@ public class ExperienceBarWrapper { initBar(); } - private void initBar() - { + private void initBar() { title = getTitleTemplate(); createBossBar(); } @@ -57,21 +54,38 @@ public class ExperienceBarWrapper { private String getTitleTemplate() { //If they are using extra details - if(ExperienceConfig.getInstance().isEarlyGameBoostEnabled() && PlayerLevelUtils.qualifiesForEarlyGameBoost(mcMMOPlayer, primarySkillType)) { - return LocaleLoader.getString("XPBar.Template.EarlyGameBoost"); - } else if(ExperienceConfig.getInstance().getAddExtraDetails()) - return LocaleLoader.getString("XPBar.Complex.Template", LocaleLoader.getString("XPBar."+niceSkillName, getLevel()), getCurrentXP(), getMaxXP(), getPowerLevel(), getPercentageOfLevel()); + if (ExperienceConfig.getInstance().isEarlyGameBoostEnabled() + && PlayerLevelUtils.qualifiesForEarlyGameBoost(mmoPlayer, primarySkillType)) { + return LocaleLoader.getString("XPBar.Template.EarlyGameBoost"); + } else if (ExperienceConfig.getInstance().getAddExtraDetails()) { + return LocaleLoader.getString("XPBar.Complex.Template", + LocaleLoader.getString("XPBar." + niceSkillName, getLevel()), getCurrentXP(), + getMaxXP(), getPowerLevel(), getPercentageOfLevel()); + } - return LocaleLoader.getString("XPBar."+niceSkillName, getLevel(), getCurrentXP(), getMaxXP(), getPowerLevel(), getPercentageOfLevel()); + return LocaleLoader.getString("XPBar." + niceSkillName, getLevel(), getCurrentXP(), + getMaxXP(), getPowerLevel(), getPercentageOfLevel()); } private int getLevel() { - return mcMMOPlayer.getSkillLevel(primarySkillType); + return mmoPlayer.getSkillLevel(primarySkillType); + } + + private int getCurrentXP() { + return mmoPlayer.getSkillXpLevel(primarySkillType); + } + + private int getMaxXP() { + return mmoPlayer.getXpToLevel(primarySkillType); + } + + private int getPowerLevel() { + return mmoPlayer.getPowerLevel(); + } + + private int getPercentageOfLevel() { + return (int) (mmoPlayer.getProgressInCurrentSkillLevel(primarySkillType) * 100); } - private int getCurrentXP() { return mcMMOPlayer.getSkillXpLevel(primarySkillType); } - private int getMaxXP() { return mcMMOPlayer.getXpToLevel(primarySkillType); } - private int getPowerLevel() { return mcMMOPlayer.getPowerLevel(); } - private int getPercentageOfLevel() { return (int) (mcMMOPlayer.getProgressInCurrentSkillLevel(primarySkillType) * 100); } public String getTitle() { return bossBar.getTitle(); @@ -99,24 +113,25 @@ public class ExperienceBarWrapper { public void setProgress(double v) { //Clamp Values - if(v < 0) + if (v < 0) { bossBar.setProgress(0.0D); - - else if(v > 1) + } else if (v > 1) { bossBar.setProgress(1.0D); - else + } else { bossBar.setProgress(v); + } //Check player level - if(ExperienceConfig.getInstance().isEarlyGameBoostEnabled() && PlayerLevelUtils.qualifiesForEarlyGameBoost(mcMMOPlayer, primarySkillType)) { - setColor(BarColor.YELLOW); + if (ExperienceConfig.getInstance().isEarlyGameBoostEnabled() + && PlayerLevelUtils.qualifiesForEarlyGameBoost(mmoPlayer, primarySkillType)) { + setColor(BarColor.YELLOW); } else { setColor(ExperienceConfig.getInstance().getExperienceBarColor(primarySkillType)); } //Every time progress updates we need to check for a title update - if(getLevel() != lastLevelUpdated || ExperienceConfig.getInstance().getDoExperienceBarsAlwaysUpdateTitle()) - { + if (getLevel() != lastLevelUpdated || ExperienceConfig.getInstance() + .getDoExperienceBarsAlwaysUpdateTitle()) { updateTitle(); lastLevelUpdated = getLevel(); } @@ -134,27 +149,23 @@ public class ExperienceBarWrapper { return bossBar.isVisible(); } - public void hideExperienceBar() - { + public void hideExperienceBar() { bossBar.setVisible(false); } - public void showExperienceBar() - { + public void showExperienceBar() { bossBar.setVisible(true); } - /*public NamespacedKey getKey() - { + /*public NamespacedKey getKey() { return bossBar }*/ - private void createBossBar() - { - bossBar = mcMMOPlayer.getPlayer().getServer().createBossBar( + private void createBossBar() { + bossBar = mmoPlayer.getPlayer().getServer().createBossBar( title, ExperienceConfig.getInstance().getExperienceBarColor(primarySkillType), ExperienceConfig.getInstance().getExperienceBarStyle(primarySkillType)); - bossBar.addPlayer(mcMMOPlayer.getPlayer()); + bossBar.addPlayer(mmoPlayer.getPlayer()); } } diff --git a/src/main/java/com/gmail/nossr50/util/experience/FormulaManager.java b/src/main/java/com/gmail/nossr50/util/experience/FormulaManager.java index a120f4b9b..eab3810fa 100644 --- a/src/main/java/com/gmail/nossr50/util/experience/FormulaManager.java +++ b/src/main/java/com/gmail/nossr50/util/experience/FormulaManager.java @@ -11,6 +11,7 @@ import org.jetbrains.annotations.VisibleForTesting; import java.io.File; import java.util.HashMap; import java.util.Map; +import org.bukkit.configuration.file.YamlConfiguration; public class FormulaManager { private static final File formulaFile = new File(mcMMO.getFlatFileDirectory() + "formula.yml"); @@ -70,9 +71,8 @@ public class FormulaManager { } /** - * Calculate the total amount of experience earned based on - * the amount of levels and experience, using the previously - * used formula type. + * Calculate the total amount of experience earned based on the amount of levels and experience, + * using the previously used formula type. * * @param skillLevel Amount of levels * @param skillXPLevel Amount of experience @@ -91,15 +91,15 @@ public class FormulaManager { } /** - * Calculate how many levels a player should have using - * the new formula type. + * Calculate how many levels a player should have using the new formula type. * * @param primarySkillType skill where new levels and experience are calculated for * @param experience total amount of experience * @param formulaType The new {@link FormulaType} * @return the amount of levels and experience */ - public int[] calculateNewLevel(PrimarySkillType primarySkillType, int experience, FormulaType formulaType) { + public int[] calculateNewLevel(PrimarySkillType primarySkillType, int experience, + FormulaType formulaType) { int newLevel = 0; int remainder = 0; int maxLevel = mcMMO.p.getSkillTools().getLevelCap(primarySkillType); @@ -116,13 +116,12 @@ public class FormulaManager { experience -= experienceToNextLevel; } - return new int[]{ newLevel, remainder }; + return new int[]{newLevel, remainder}; } /** - * Get the cached amount of experience needed to reach the next level, - * if cache doesn't contain the given value it is calculated and added - * to the cached data. + * Get the cached amount of experience needed to reach the next level, if cache doesn't contain + * the given value it is calculated and added to the cached data. * * @param level level to check * @param formulaType The {@link FormulaType} used @@ -143,13 +142,14 @@ public class FormulaManager { } /** - * Gets the value of XP needed for the next level based on the level Scaling, the level, and the formula type + * Gets the value of XP needed for the next level based on the level Scaling, the level, and the + * formula type + * * @param level target level * @param formulaType target formulaType */ private int processXPToNextLevel(int level, FormulaType formulaType) { - if(mcMMO.isRetroModeEnabled()) - { + if (mcMMO.isRetroModeEnabled()) { return processXPRetroToNextLevel(level, formulaType); } else { return processStandardXPToNextLevel(level, formulaType); @@ -157,19 +157,23 @@ public class FormulaManager { } /** - * Calculate the XP needed for the next level for the linear formula for Standard scaling (1-100) + * Calculate the XP needed for the next level for the linear formula for Standard scaling + * (1-100) + * * @param level target level * @return raw xp needed to reach the next level */ private int processStandardXPToNextLevel(int level, FormulaType formulaType) { - Map experienceMapRef = formulaType == FormulaType.LINEAR ? experienceNeededStandardLinear : experienceNeededStandardExponential; + Map experienceMapRef = + formulaType == FormulaType.LINEAR ? experienceNeededStandardLinear + : experienceNeededStandardExponential; - if(!experienceMapRef.containsKey(level)) { + if (!experienceMapRef.containsKey(level)) { int experienceSum = 0; int retroIndex = (level * 10) + 1; //Sum the range of levels in Retro that this Standard level would represent - for(int x = retroIndex; x < (retroIndex + 10); x++) { + for (int x = retroIndex; x < (retroIndex + 10); x++) { //calculateXPNeeded doesn't cache results so we use that instead of invoking the Retro XP methods to avoid memory bloat experienceSum += calculateXPNeeded(x, formulaType); } @@ -181,14 +185,17 @@ public class FormulaManager { } /** - * Calculates the XP to next level for Retro Mode scaling - * Results are cached to reduce needless operations + * Calculates the XP to next level for Retro Mode scaling Results are cached to reduce needless + * operations + * * @param level target level * @param formulaType target formula type * @return raw xp needed to reach the next level based on formula type */ private int processXPRetroToNextLevel(int level, FormulaType formulaType) { - Map experienceMapRef = formulaType == FormulaType.LINEAR ? experienceNeededRetroLinear : experienceNeededRetroExponential; + Map experienceMapRef = + formulaType == FormulaType.LINEAR ? experienceNeededRetroLinear + : experienceNeededRetroExponential; if (!experienceMapRef.containsKey(level)) { int experience = calculateXPNeeded(level, formulaType); @@ -199,8 +206,9 @@ public class FormulaManager { } /** - * Does the actual math to get the XP needed for a level in RetroMode scaling - * Standard uses a sum of RetroMode XP needed levels for its own thing, so it uses this too + * Does the actual math to get the XP needed for a level in RetroMode scaling Standard uses a + * sum of RetroMode XP needed levels for its own thing, so it uses this too + * * @param level target level * @param formulaType target formulatype * @return the raw XP needed for the next level based on formula type @@ -209,7 +217,7 @@ public class FormulaManager { int base = ExperienceConfig.getInstance().getBase(formulaType); double multiplier = ExperienceConfig.getInstance().getMultiplier(formulaType); - switch(formulaType) { + switch (formulaType) { case LINEAR: return (int) Math.floor(base + level * multiplier); case EXPONENTIAL: @@ -217,7 +225,8 @@ public class FormulaManager { return (int) Math.floor(multiplier * Math.pow(level, exponent) + base); default: //TODO: Should never be called - mcMMO.p.getLogger().severe("Invalid formula specified for calculation, defaulting to Linear"); + mcMMO.p.getLogger() + .severe("Invalid formula specified for calculation, defaulting to Linear"); return calculateXPNeeded(level, FormulaType.LINEAR); } } @@ -232,8 +241,7 @@ public class FormulaManager { try { formulasFile.save(formulaFile); - } - catch (Exception e) { + } catch (Exception e) { e.printStackTrace(); } } diff --git a/src/main/java/com/gmail/nossr50/util/nms/NMSConstants.java b/src/main/java/com/gmail/nossr50/util/nms/NMSConstants.java index 38d65eb4b..dd931b859 100644 --- a/src/main/java/com/gmail/nossr50/util/nms/NMSConstants.java +++ b/src/main/java/com/gmail/nossr50/util/nms/NMSConstants.java @@ -12,10 +12,12 @@ public class NMSConstants { /** * Grabs the fully qualified path of a class from CB + * * @param targetClass source root path * @return the fully qualified path of a CB class */ - protected static String getFullyQualifiedCraftBukkitPath(String cbVersionPackage, String targetClass) { + protected static String getFullyQualifiedCraftBukkitPath(String cbVersionPackage, + String targetClass) { return CRAFT_BUKKIT_PACKAGE_PATH + "." + cbVersionPackage + "." + targetClass; } @@ -23,8 +25,9 @@ public class NMSConstants { return BUKKIT_PACKAGE_PATH + "." + fromSourceRoot; } - protected static String getFullyQualifiedNMSPath(String cbVersionPackage, String fromSourceRoot) { - return NET_MINECRAFT_SERVER + "." +cbVersionPackage + "." + fromSourceRoot; + protected static String getFullyQualifiedNMSPath(String cbVersionPackage, + String fromSourceRoot) { + return NET_MINECRAFT_SERVER + "." + cbVersionPackage + "." + fromSourceRoot; } public static String getCraftPlayerClassPath(String cbVersionPackage) { diff --git a/src/main/java/com/gmail/nossr50/util/nms/NMSVersion.java b/src/main/java/com/gmail/nossr50/util/nms/NMSVersion.java index 8c1e3c8b4..4df964049 100644 --- a/src/main/java/com/gmail/nossr50/util/nms/NMSVersion.java +++ b/src/main/java/com/gmail/nossr50/util/nms/NMSVersion.java @@ -36,7 +36,8 @@ public enum NMSVersion { /** * The standardized major.minor.patch {@link String} for the current NMS mappings * - * @return the standardized major.minor.patch version string, patch is omitted if it is not a patch version + * @return the standardized major.minor.patch version string, patch is omitted if it is not a + * patch version */ public String getSanitizedVersionNumber() { return sanitizedVersionNumber; diff --git a/src/main/java/com/gmail/nossr50/util/platform/AbstractPlatform.java b/src/main/java/com/gmail/nossr50/util/platform/AbstractPlatform.java index 3a6e11ed5..e8f891215 100644 --- a/src/main/java/com/gmail/nossr50/util/platform/AbstractPlatform.java +++ b/src/main/java/com/gmail/nossr50/util/platform/AbstractPlatform.java @@ -3,18 +3,17 @@ package com.gmail.nossr50.util.platform; import com.gmail.nossr50.util.compat.CompatibilityManager; /** - * - * These classes are a band-aid solution for adding NMS support into 2.1.XXX - * In 2.2 we are switching to modules and that will clean things up significantly - * + * These classes are a band-aid solution for adding NMS support into 2.1.XXX In 2.2 we are switching + * to modules and that will clean things up significantly */ -public abstract class AbstractPlatform implements Platform{ +public abstract class AbstractPlatform implements Platform { protected final CompatibilityManager compatibilityManager; protected final MinecraftGameVersion minecraftGameVersion; protected final ServerSoftwareType serverSoftwareType; - public AbstractPlatform(MinecraftGameVersion minecraftGameVersion, ServerSoftwareType serverSoftwareType, CompatibilityManager compatibilityManager) { + public AbstractPlatform(MinecraftGameVersion minecraftGameVersion, + ServerSoftwareType serverSoftwareType, CompatibilityManager compatibilityManager) { this.minecraftGameVersion = minecraftGameVersion; this.serverSoftwareType = serverSoftwareType; this.compatibilityManager = compatibilityManager; diff --git a/src/main/java/com/gmail/nossr50/util/platform/BukkitPlatform.java b/src/main/java/com/gmail/nossr50/util/platform/BukkitPlatform.java index 7183665a4..0f6ca778e 100644 --- a/src/main/java/com/gmail/nossr50/util/platform/BukkitPlatform.java +++ b/src/main/java/com/gmail/nossr50/util/platform/BukkitPlatform.java @@ -4,14 +4,13 @@ import com.gmail.nossr50.util.compat.CompatibilityManager; import org.jetbrains.annotations.NotNull; /** - * - * These classes are a band-aid solution for adding NMS support into 2.1.XXX - * In 2.2 we are switching to modules and that will clean things up significantly - * + * These classes are a band-aid solution for adding NMS support into 2.1.XXX In 2.2 we are switching + * to modules and that will clean things up significantly */ public class BukkitPlatform extends AbstractPlatform { public BukkitPlatform(MinecraftGameVersion minecraftGameVersion) { - super(minecraftGameVersion, ServerSoftwareType.CRAFT_BUKKIT, new CompatibilityManager(minecraftGameVersion)); + super(minecraftGameVersion, ServerSoftwareType.CRAFT_BUKKIT, + new CompatibilityManager(minecraftGameVersion)); } @Override 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 47f41a82e..c944cf858 100644 --- a/src/main/java/com/gmail/nossr50/util/platform/MajorMinorPatchVersion.java +++ b/src/main/java/com/gmail/nossr50/util/platform/MajorMinorPatchVersion.java @@ -2,16 +2,13 @@ package com.gmail.nossr50.util.platform; import com.gmail.nossr50.util.platform.version.SimpleNumericVersion; import com.gmail.nossr50.util.platform.version.Versioned; +import java.util.Objects; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.Objects; - /** - * - * These classes are a band-aid solution for adding NMS support into 2.1.XXX - * In 2.2 we are switching to modules and that will clean things up significantly - * + * These classes are a band-aid solution for adding NMS support into 2.1.XXX In 2.2 we are switching + * to modules and that will clean things up significantly */ public abstract class MajorMinorPatchVersion implements Versioned { @@ -22,17 +19,21 @@ public abstract class MajorMinorPatchVersion implements Versioned { @NotNull private final SimpleNumericVersion patchVersion; - public MajorMinorPatchVersion(@NotNull SimpleNumericVersion majorVersion, @NotNull SimpleNumericVersion minorVersion) { + public MajorMinorPatchVersion(@NotNull SimpleNumericVersion majorVersion, + @NotNull SimpleNumericVersion minorVersion) { this.majorVersion = majorVersion; this.minorVersion = minorVersion; this.patchVersion = new SimpleNumericVersion(0); } - public MajorMinorPatchVersion(@NotNull SimpleNumericVersion majorVersion, @NotNull SimpleNumericVersion minorVersion, @Nullable SimpleNumericVersion patchVersion) { + public MajorMinorPatchVersion(@NotNull SimpleNumericVersion majorVersion, + @NotNull SimpleNumericVersion minorVersion, + @Nullable SimpleNumericVersion patchVersion) { this.majorVersion = majorVersion; this.minorVersion = minorVersion; - this.patchVersion = Objects.requireNonNullElseGet(patchVersion, () -> new SimpleNumericVersion(0)); + this.patchVersion = Objects.requireNonNullElseGet(patchVersion, + () -> new SimpleNumericVersion(0)); } public MajorMinorPatchVersion(int majorVerNumber, int minorVerNumber, int patchVerNumber) { @@ -49,6 +50,7 @@ public abstract class MajorMinorPatchVersion implements Versioned { /** * Get the major version string + * * @return the major version string */ public @NotNull SimpleNumericVersion getMajorVersion() { @@ -57,6 +59,7 @@ public abstract class MajorMinorPatchVersion implements Versioned { /** * Get the minor version string + * * @return the minor version string */ public @NotNull SimpleNumericVersion getMinorVersion() { @@ -65,6 +68,7 @@ public abstract class MajorMinorPatchVersion implements Versioned { /** * Get the patch version string + * * @return patch version string or null if patch numeric value is less than or equal to 0 */ public @NotNull SimpleNumericVersion getPatchVersion() { @@ -73,7 +77,7 @@ public abstract class MajorMinorPatchVersion implements Versioned { @Override public String getVersionStr() { - if(isPatch()) { + if (isPatch()) { return majorVersion.getVersionString() + "." + minorVersion + "." + patchVersion; @@ -84,8 +88,9 @@ public abstract class MajorMinorPatchVersion implements Versioned { } /** - * Whether this version of Minecraft is a patch - * a patch version value above 0 will indicate that this 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 */ public boolean isPatch() { @@ -94,8 +99,12 @@ public abstract class MajorMinorPatchVersion implements Versioned { @Override public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } MajorMinorPatchVersion that = (MajorMinorPatchVersion) o; return majorVersion.equals(that.majorVersion) && minorVersion.equals(that.minorVersion) && 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 387d831d1..73b12ae63 100644 --- a/src/main/java/com/gmail/nossr50/util/platform/MinecraftGameVersion.java +++ b/src/main/java/com/gmail/nossr50/util/platform/MinecraftGameVersion.java @@ -5,17 +5,18 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; /** - * - * These classes are a band-aid solution for adding NMS support into 2.1.XXX - * In 2.2 we are switching to modules and that will clean things up significantly - * + * These classes are a band-aid solution for adding NMS support into 2.1.XXX In 2.2 we are switching + * to modules and that will clean things up significantly */ public class MinecraftGameVersion extends MajorMinorPatchVersion { - public MinecraftGameVersion(@NotNull SimpleNumericVersion majorVersion, @NotNull SimpleNumericVersion minorVersion) { + public MinecraftGameVersion(@NotNull SimpleNumericVersion majorVersion, + @NotNull SimpleNumericVersion minorVersion) { super(majorVersion, minorVersion); } - public MinecraftGameVersion(@NotNull SimpleNumericVersion majorVersion, @NotNull SimpleNumericVersion minorVersion, @Nullable SimpleNumericVersion patchVersion) { + public MinecraftGameVersion(@NotNull SimpleNumericVersion majorVersion, + @NotNull SimpleNumericVersion minorVersion, + @Nullable SimpleNumericVersion patchVersion) { super(majorVersion, minorVersion, patchVersion); } @@ -29,30 +30,33 @@ public class MinecraftGameVersion extends MajorMinorPatchVersion { /** * 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 * + * @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 * @return returns true if Minecraft is at least a certain version */ public boolean isAtLeast(int majorVerNumber, int minorVerNumber, int patchVerNumber) { //First check if the major version is higher, if it is we have no need to check minor version or patch version - if(getMajorVersion().asInt() > majorVerNumber) { + if (getMajorVersion().asInt() > majorVerNumber) { return true; //Major version is one higher and hierarchically more important than the other versions } - if(getMajorVersion().asInt() < majorVerNumber) { + if (getMajorVersion().asInt() < majorVerNumber) { return false; //Major version is below, so return false } //Major version meets the requirement, check minor version - if(getMinorVersion().asInt() > minorVerNumber) { + if (getMinorVersion().asInt() > minorVerNumber) { return true; //Minor version is one higher and hierarchically more important than patch version, so exit here } - if(getMinorVersion().asInt() < minorVerNumber) { + if (getMinorVersion().asInt() < minorVerNumber) { return false; //Minor version is at least one version behind, return false } diff --git a/src/main/java/com/gmail/nossr50/util/platform/Platform.java b/src/main/java/com/gmail/nossr50/util/platform/Platform.java index 7a6c81395..b9c5cda7e 100644 --- a/src/main/java/com/gmail/nossr50/util/platform/Platform.java +++ b/src/main/java/com/gmail/nossr50/util/platform/Platform.java @@ -4,27 +4,28 @@ import com.gmail.nossr50.util.compat.CompatibilityManager; import org.jetbrains.annotations.NotNull; /** - * - * These classes are a band-aid solution for adding NMS support into 2.1.XXX - * In 2.2 we are switching to modules and that will clean things up significantly - * + * These classes are a band-aid solution for adding NMS support into 2.1.XXX In 2.2 we are switching + * to modules and that will clean things up significantly */ public interface Platform { /** * Target {@link ServerSoftwareType} for this {@link Platform} + * * @return the {@link ServerSoftwareType} for this {@link Platform} */ @NotNull ServerSoftwareType getServerSoftwareType(); /** * Get the {@link CompatibilityManager} for this {@link Platform} + * * @return the {@link CompatibilityManager} for this platform */ @NotNull CompatibilityManager getCompatibilityManager(); /** * The target game version of this {@link Platform} + * * @return the target {@link MinecraftGameVersion} of this {@link Platform} */ @NotNull MinecraftGameVersion getGameVersion(); diff --git a/src/main/java/com/gmail/nossr50/util/platform/PlatformBuilder.java b/src/main/java/com/gmail/nossr50/util/platform/PlatformBuilder.java index a2930137e..7cafd8a2f 100644 --- a/src/main/java/com/gmail/nossr50/util/platform/PlatformBuilder.java +++ b/src/main/java/com/gmail/nossr50/util/platform/PlatformBuilder.java @@ -4,10 +4,8 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; /** - * - * These classes are a band-aid solution for adding NMS support into 2.1.XXX - * In 2.2 we are switching to modules and that will clean things up significantly - * + * These classes are a band-aid solution for adding NMS support into 2.1.XXX In 2.2 we are switching + * to modules and that will clean things up significantly */ public class PlatformBuilder { private MinecraftGameVersion minecraftGameVersion; @@ -17,7 +15,8 @@ public class PlatformBuilder { } - public PlatformBuilder setMinecraftGameVersion(@NotNull MinecraftGameVersion minecraftGameVersion) { + public PlatformBuilder setMinecraftGameVersion( + @NotNull MinecraftGameVersion minecraftGameVersion) { this.minecraftGameVersion = minecraftGameVersion; return this; } @@ -28,15 +27,10 @@ public class PlatformBuilder { } public @Nullable Platform build() { - switch(serverSoftwareType) { - - case PAPER: - case SPIGOT: - case CRAFT_BUKKIT: - return createBukkitPlatform(); - default: - return null; - } + return switch (serverSoftwareType) { + case PAPER, SPIGOT, CRAFT_BUKKIT -> createBukkitPlatform(); + default -> null; + }; } private BukkitPlatform createBukkitPlatform() { diff --git a/src/main/java/com/gmail/nossr50/util/platform/PlatformManager.java b/src/main/java/com/gmail/nossr50/util/platform/PlatformManager.java index e68ff1912..f14e95f78 100644 --- a/src/main/java/com/gmail/nossr50/util/platform/PlatformManager.java +++ b/src/main/java/com/gmail/nossr50/util/platform/PlatformManager.java @@ -3,19 +3,16 @@ package com.gmail.nossr50.util.platform; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.LogUtils; import com.gmail.nossr50.util.compat.CompatibilityManager; +import java.util.Locale; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import org.bukkit.Bukkit; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.Locale; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - /** - * - * These classes are a band-aid solution for adding NMS support into 2.1.XXX - * In 2.2 we are switching to modules and that will clean things up significantly - * + * These classes are a band-aid solution for adding NMS support into 2.1.XXX In 2.2 we are switching + * to modules and that will clean things up significantly */ public class PlatformManager { protected Platform platform; //current platform @@ -51,7 +48,8 @@ public class PlatformManager { LogUtils.debug(mcMMO.p.getLogger(), "Platform String: " + platformVersionString); // Gets two numbers separated by . and optional third number after next dot. Must end with - or _ - Matcher versionMatch = Pattern.compile("(\\d+)\\.(\\d+)(?:\\.(\\d+))?[-_].*").matcher(platformVersionString); + Matcher versionMatch = Pattern.compile("(\\d+)\\.(\\d+)(?:\\.(\\d+))?[-_].*") + .matcher(platformVersionString); if (versionMatch.find()) { major = Integer.parseInt(versionMatch.group(1)); @@ -72,30 +70,25 @@ public class PlatformManager { //TODO: Rewrite this properly once we actually support a not-bukkit platform private @NotNull ServerSoftwareType determinePlatformType() { - if(Bukkit.getVersion().toLowerCase(Locale.ENGLISH).contains("paper")) + if (Bukkit.getVersion().toLowerCase(Locale.ENGLISH).contains("paper")) { return ServerSoftwareType.PAPER; - else if(Bukkit.getVersion().toLowerCase(Locale.ENGLISH).contains("spigot")) + } else if (Bukkit.getVersion().toLowerCase(Locale.ENGLISH).contains("spigot")) { return ServerSoftwareType.SPIGOT; - else + } else { return ServerSoftwareType.CRAFT_BUKKIT; + } } - public ServerSoftwareType getServerSoftware() - { + public ServerSoftwareType getServerSoftware() { return platform.getServerSoftwareType(); } - public String getServerSoftwareStr() - { - switch(getServerSoftware()) - { - case PAPER: - return "Paper"; - case SPIGOT: - return "Spigot"; - default: - return "CraftBukkit"; - } + public String getServerSoftwareStr() { + return switch (getServerSoftware()) { + case PAPER -> "Paper"; + case SPIGOT -> "Spigot"; + default -> "CraftBukkit"; + }; } public @Nullable CompatibilityManager getCompatibilityManager() { diff --git a/src/main/java/com/gmail/nossr50/util/player/NotificationManager.java b/src/main/java/com/gmail/nossr50/util/player/NotificationManager.java index aede17cf0..0c4e4fd31 100644 --- a/src/main/java/com/gmail/nossr50/util/player/NotificationManager.java +++ b/src/main/java/com/gmail/nossr50/util/player/NotificationManager.java @@ -15,6 +15,7 @@ import com.gmail.nossr50.util.sounds.SoundManager; import com.gmail.nossr50.util.sounds.SoundType; import com.gmail.nossr50.util.text.McMMOMessageType; import com.gmail.nossr50.util.text.TextComponentFactory; +import java.time.LocalDate; import net.kyori.adventure.audience.Audience; import net.kyori.adventure.identity.Identity; import net.kyori.adventure.text.Component; @@ -29,106 +30,117 @@ import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; -import java.time.LocalDate; - public class NotificationManager { public static final String HEX_BEIGE_COLOR = "#c2a66e"; public static final String HEX_LIME_GREEN_COLOR = "#8ec26e"; /** - * Sends players notifications from mcMMO - * Does so by sending out an event so other plugins can cancel it + * Sends players notifications from mcMMO Does so by sending out an event so other plugins can + * cancel it + * * @param player target player * @param notificationType notifications defined type * @param key the locale key for the notifications defined message */ - public static void sendPlayerInformation(Player player, NotificationType notificationType, String key) - { - if(UserManager.getPlayer(player) == null || !UserManager.getPlayer(player).useChatNotifications()) + public static void sendPlayerInformation(Player player, NotificationType notificationType, + String key) { + if (UserManager.getPlayer(player) == null || !UserManager.getPlayer(player) + .useChatNotifications()) { return; + } McMMOMessageType destination = mcMMO.p.getAdvancedConfig().doesNotificationUseActionBar(notificationType) ? McMMOMessageType.ACTION_BAR : McMMOMessageType.SYSTEM; Component message = TextComponentFactory.getNotificationTextComponentFromLocale(key); - McMMOPlayerNotificationEvent customEvent = checkNotificationEvent(player, notificationType, destination, message); + McMMOPlayerNotificationEvent customEvent = checkNotificationEvent(player, notificationType, + destination, message); sendNotification(player, customEvent); } - public static boolean doesPlayerUseNotifications(Player player) - { - if(UserManager.getPlayer(player) == null) + public static boolean doesPlayerUseNotifications(Player player) { + if (UserManager.getPlayer(player) == null) { return false; - else + } else { return UserManager.getPlayer(player).useChatNotifications(); + } } /** - * Sends players notifications from mcMMO - * This does this by sending out an event so other plugins can cancel it - * This event in particular is provided with a source player, and players near the source player are sent the information + * Sends players notifications from mcMMO This does this by sending out an event so other + * plugins can cancel it This event in particular is provided with a source player, and players + * near the source player are sent the information + * * @param targetPlayer the recipient player for this message * @param notificationType type of notification * @param key Locale Key for the string to use with this event * @param values values to be injected into the locale string */ - public static void sendNearbyPlayersInformation(Player targetPlayer, NotificationType notificationType, String key, - String... values) - { + public static void sendNearbyPlayersInformation(Player targetPlayer, + NotificationType notificationType, String key, + String... values) { sendPlayerInformation(targetPlayer, notificationType, key, values); } - public static void sendPlayerInformationChatOnly(Player player, String key, String... values) - { - if(UserManager.getPlayer(player) == null || !UserManager.getPlayer(player).useChatNotifications()) + public static void sendPlayerInformationChatOnly(Player player, String key, String... values) { + if (UserManager.getPlayer(player) == null || !UserManager.getPlayer(player) + .useChatNotifications()) { return; + } String preColoredString = LocaleLoader.getString(key, (Object[]) values); player.sendMessage(preColoredString); } - public static void sendPlayerInformationChatOnlyPrefixed(Player player, String key, String... values) - { - if(UserManager.getPlayer(player) == null || !UserManager.getPlayer(player).useChatNotifications()) + public static void sendPlayerInformationChatOnlyPrefixed(Player player, String key, + String... values) { + if (UserManager.getPlayer(player) == null || !UserManager.getPlayer(player) + .useChatNotifications()) { return; + } String preColoredString = LocaleLoader.getString(key, (Object[]) values); - String prefixFormattedMessage = LocaleLoader.getString("mcMMO.Template.Prefix", preColoredString); + String prefixFormattedMessage = LocaleLoader.getString("mcMMO.Template.Prefix", + preColoredString); player.sendMessage(prefixFormattedMessage); } - public static void sendPlayerInformation(Player player, NotificationType notificationType, String key, - String... values) - { - if(UserManager.getPlayer(player) == null || !UserManager.getPlayer(player).useChatNotifications()) + public static void sendPlayerInformation(Player player, NotificationType notificationType, + String key, + String... values) { + if (UserManager.getPlayer(player) == null || !UserManager.getPlayer(player) + .useChatNotifications()) { return; + } - McMMOMessageType destination = mcMMO.p.getAdvancedConfig().doesNotificationUseActionBar(notificationType) ? McMMOMessageType.ACTION_BAR : McMMOMessageType.SYSTEM; + McMMOMessageType destination = + mcMMO.p.getAdvancedConfig().doesNotificationUseActionBar(notificationType) + ? McMMOMessageType.ACTION_BAR : McMMOMessageType.SYSTEM; Component message = TextComponentFactory.getNotificationMultipleValues(key, values); - McMMOPlayerNotificationEvent customEvent = checkNotificationEvent(player, notificationType, destination, message); + McMMOPlayerNotificationEvent customEvent = checkNotificationEvent(player, notificationType, + destination, message); sendNotification(player, customEvent); } private static void sendNotification(Player player, McMMOPlayerNotificationEvent customEvent) { - if (customEvent.isCancelled()) + if (customEvent.isCancelled()) { return; + } final Audience audience = mcMMO.getAudiences().player(player); - //If the message is being sent to the action bar we need to check if the copy if a copy is sent to the chat system Component notificationTextComponent = customEvent.getNotificationTextComponent(); - if(customEvent.getChatMessageType() == McMMOMessageType.ACTION_BAR) - { + if (customEvent.getChatMessageType() == McMMOMessageType.ACTION_BAR) { audience.sendActionBar(notificationTextComponent); - if(customEvent.isMessageAlsoBeingSentToChat()) - { + // If the message is being sent to the action bar we need to check if a copy is also sent to the chat system + if (customEvent.isMessageAlsoBeingSentToChat()) { //Send copy to chat system audience.sendMessage(notificationTextComponent); } @@ -137,9 +149,10 @@ public class NotificationManager { } } - private static McMMOPlayerNotificationEvent checkNotificationEvent(Player player, NotificationType notificationType, - McMMOMessageType destination, - Component message) { + private static McMMOPlayerNotificationEvent checkNotificationEvent(Player player, + NotificationType notificationType, + McMMOMessageType destination, + Component message) { //Init event McMMOPlayerNotificationEvent customEvent = new McMMOPlayerNotificationEvent(player, notificationType, message, destination, @@ -151,69 +164,75 @@ public class NotificationManager { } /** - * Handles sending level up notifications to a mcMMOPlayer - * @param mcMMOPlayer target mcMMOPlayer + * Handles sending level up notifications to a mmoPlayer + * + * @param mmoPlayer target mmoPlayer * @param skillName skill that leveled up * @param newLevel new level of that skill */ - public static void sendPlayerLevelUpNotification(McMMOPlayer mcMMOPlayer, PrimarySkillType skillName, - int levelsGained, int newLevel) - { - if(!mcMMOPlayer.useChatNotifications()) + public static void sendPlayerLevelUpNotification(McMMOPlayer mmoPlayer, + PrimarySkillType skillName, + int levelsGained, int newLevel) { + if (!mmoPlayer.useChatNotifications()) { return; + } McMMOMessageType destination - = mcMMO.p.getAdvancedConfig().doesNotificationUseActionBar(NotificationType.LEVEL_UP_MESSAGE) + = mcMMO.p.getAdvancedConfig() + .doesNotificationUseActionBar(NotificationType.LEVEL_UP_MESSAGE) ? McMMOMessageType.ACTION_BAR : McMMOMessageType.SYSTEM; Component levelUpTextComponent = TextComponentFactory.getNotificationLevelUpTextComponent( skillName, levelsGained, newLevel); McMMOPlayerNotificationEvent customEvent = checkNotificationEvent( - mcMMOPlayer.getPlayer(), + mmoPlayer.getPlayer(), NotificationType.LEVEL_UP_MESSAGE, destination, levelUpTextComponent); - sendNotification(mcMMOPlayer.getPlayer(), customEvent); + sendNotification(mmoPlayer.getPlayer(), customEvent); } - public static void broadcastTitle(Server server, String title, String subtitle, int i1, int i2, int i3) - { - for(Player player : server.getOnlinePlayers()) - { + public static void broadcastTitle(Server server, String title, String subtitle, int i1, int i2, + int i3) { + for (Player player : server.getOnlinePlayers()) { player.sendTitle(title, subtitle, i1, i2, i3); } } - public static void sendPlayerUnlockNotification(McMMOPlayer mcMMOPlayer, SubSkillType subSkillType) - { - if(!mcMMOPlayer.useChatNotifications()) + public static void sendPlayerUnlockNotification(McMMOPlayer mmoPlayer, + SubSkillType subSkillType) { + if (!mmoPlayer.useChatNotifications()) { return; + } //CHAT MESSAGE - mcMMO.getAudiences().player(mcMMOPlayer.getPlayer()).sendMessage(Identity.nil(), - TextComponentFactory.getSubSkillUnlockedNotificationComponents(mcMMOPlayer.getPlayer(), subSkillType)); + mcMMO.getAudiences().player(mmoPlayer.getPlayer()).sendMessage(Identity.nil(), + TextComponentFactory.getSubSkillUnlockedNotificationComponents( + mmoPlayer.getPlayer(), subSkillType)); //Unlock Sound Effect - SoundManager.sendCategorizedSound(mcMMOPlayer.getPlayer(), mcMMOPlayer.getPlayer().getLocation(), + SoundManager.sendCategorizedSound(mmoPlayer.getPlayer(), + mmoPlayer.getPlayer().getLocation(), SoundType.SKILL_UNLOCKED, SoundCategory.MASTER); } /** - * Sends a message to all admins with the admin notification formatting from the locale - * Admins are currently players with either Operator status or Admin Chat permission + * Sends a message to all admins with the admin notification formatting from the locale Admins + * are currently players with either Operator status or Admin Chat permission + * * @param msg message fetched from locale */ private static void sendAdminNotification(String msg) { //If its not enabled exit - if(!mcMMO.p.getGeneralConfig().adminNotifications()) + if (!mcMMO.p.getGeneralConfig().adminNotifications()) { return; + } - for(Player player : Bukkit.getServer().getOnlinePlayers()) - { - if(player.isOp() || Permissions.adminChat(player)) - { - player.sendMessage(LocaleLoader.getString("Notifications.Admin.Format.Others", msg)); + for (Player player : Bukkit.getServer().getOnlinePlayers()) { + if (player.isOp() || Permissions.adminChat(player)) { + player.sendMessage( + LocaleLoader.getString("Notifications.Admin.Format.Others", msg)); } } @@ -223,6 +242,7 @@ public class NotificationManager { /** * Sends a confirmation message to the CommandSender who just executed an admin command + * * @param commandSender target command sender * @param msg message fetched from locale */ @@ -232,30 +252,31 @@ public class NotificationManager { /** * Convenience method to report info about a command sender using a sensitive command + * * @param commandSender the command user * @param sensitiveCommandType type of command issued */ public static void processSensitiveCommandNotification(CommandSender commandSender, - SensitiveCommandType sensitiveCommandType, String... args) { + SensitiveCommandType sensitiveCommandType, String... args) { /* * Determine the 'identity' of the one who executed the command to pass as a parameters */ String senderName = LocaleLoader.getString("Server.ConsoleName"); - if(commandSender instanceof Player) - { + if (commandSender instanceof Player) { senderName = ((Player) commandSender).getDisplayName() + ChatColor.RESET + "-" + ((Player) commandSender).getUniqueId(); } //Send the notification - switch(sensitiveCommandType) - { + switch (sensitiveCommandType) { case XPRATE_MODIFY: - sendAdminNotification(LocaleLoader.getString("Notifications.Admin.XPRate.Start.Others", - addItemToFirstPositionOfArray(senderName, args))); + sendAdminNotification( + LocaleLoader.getString("Notifications.Admin.XPRate.Start.Others", + addItemToFirstPositionOfArray(senderName, args))); sendAdminCommandConfirmation( - commandSender, LocaleLoader.getString("Notifications.Admin.XPRate.Start.Self", args)); + commandSender, + LocaleLoader.getString("Notifications.Admin.XPRate.Start.Self", args)); break; case XPRATE_END: sendAdminNotification( @@ -269,13 +290,18 @@ public class NotificationManager { } /** - * Takes an array and an object, makes a new array with object in the first position of the new array, - * and the following elements in this new array being a copy of the existing array retaining their order + * Takes an array and an object, makes a new array with object in the first position of the new + * array, and the following elements in this new array being a copy of the existing array + * retaining their order + * * @param itemToAdd the string to put at the beginning of the new array - * @param existingArray the existing array to be copied to the new array at position [0]+1 relative to their original index - * @return the new array combining itemToAdd at the start and existing array elements following while retaining their order + * @param existingArray the existing array to be copied to the new array at position [0]+1 + * relative to their original index + * @return the new array combining itemToAdd at the start and existing array elements following + * while retaining their order */ - public static String[] addItemToFirstPositionOfArray(String itemToAdd, String... existingArray) { + public static String[] addItemToFirstPositionOfArray(String itemToAdd, + String... existingArray) { String[] newArray = new String[existingArray.length + 1]; newArray[0] = itemToAdd; @@ -284,35 +310,41 @@ public class NotificationManager { return newArray; } - public static void processLevelUpBroadcasting(@NotNull McMMOPlayer mmoPlayer, @NotNull PrimarySkillType primarySkillType, int level) { - if(level <= 0) + public static void processLevelUpBroadcasting(@NotNull McMMOPlayer mmoPlayer, + @NotNull PrimarySkillType primarySkillType, int level) { + if (level <= 0) { return; + } //Check if broadcasting is enabled - if(mcMMO.p.getGeneralConfig().shouldLevelUpBroadcasts()) { + if (mcMMO.p.getGeneralConfig().shouldLevelUpBroadcasts()) { //Permission check - if(!Permissions.levelUpBroadcast(mmoPlayer.getPlayer())) { + if (!Permissions.levelUpBroadcast(mmoPlayer.getPlayer())) { return; } int levelInterval = mcMMO.p.getGeneralConfig().getLevelUpBroadcastInterval(); int remainder = level % levelInterval; - if(remainder == 0) { + if (remainder == 0) { //Grab appropriate audience - Audience audience = mcMMO.getAudiences().filter(getLevelUpBroadcastPredicate(mmoPlayer.getPlayer())); + Audience audience = mcMMO.getAudiences() + .filter(getLevelUpBroadcastPredicate(mmoPlayer.getPlayer())); //TODO: Make prettier - HoverEvent levelMilestoneHover = Component.text(mmoPlayer.getPlayer().getName()) + HoverEvent levelMilestoneHover = Component.text( + mmoPlayer.getPlayer().getName()) .append(Component.newline()) .append(Component.text(LocalDate.now().toString())) .append(Component.newline()) .append(Component.text( mcMMO.p.getSkillTools().getLocalizedSkillName(primarySkillType) - + " reached level "+level)).color(TextColor.fromHexString(HEX_BEIGE_COLOR)) + + " reached level " + level)) + .color(TextColor.fromHexString(HEX_BEIGE_COLOR)) .asHoverEvent(); String localeMessage = LocaleLoader.getString( - "Broadcasts.LevelUpMilestone", mmoPlayer.getPlayer().getDisplayName(), level, + "Broadcasts.LevelUpMilestone", mmoPlayer.getPlayer().getDisplayName(), + level, mcMMO.p.getSkillTools().getLocalizedSkillName(primarySkillType)); Component component = LegacyComponentSerializer .legacySection() @@ -320,7 +352,7 @@ public class NotificationManager { .hoverEvent(levelMilestoneHover); // TODO: Update system msg API - mcMMO.p.getFoliaLib().getImpl().runNextTick( + mcMMO.p.getFoliaLib().getScheduler().runNextTick( t -> audience.sendMessage(component)); } } @@ -328,45 +360,55 @@ public class NotificationManager { //TODO: Remove the code duplication, am lazy atm //TODO: Fix broadcasts being skipped for situations where a player skips over the milestone like with the addlevels command - public static void processPowerLevelUpBroadcasting(@NotNull McMMOPlayer mmoPlayer, int powerLevel) { - if(powerLevel <= 0) + public static void processPowerLevelUpBroadcasting(@NotNull McMMOPlayer mmoPlayer, + int powerLevel) { + if (powerLevel <= 0) { return; + } //Check if broadcasting is enabled - if(mcMMO.p.getGeneralConfig().shouldPowerLevelUpBroadcasts()) { + if (mcMMO.p.getGeneralConfig().shouldPowerLevelUpBroadcasts()) { //Permission check - if(!Permissions.levelUpBroadcast(mmoPlayer.getPlayer())) { + if (!Permissions.levelUpBroadcast(mmoPlayer.getPlayer())) { return; } int levelInterval = mcMMO.p.getGeneralConfig().getPowerLevelUpBroadcastInterval(); int remainder = powerLevel % levelInterval; - if(remainder == 0) { + if (remainder == 0) { //Grab appropriate audience - Audience audience = mcMMO.getAudiences().filter(getPowerLevelUpBroadcastPredicate(mmoPlayer.getPlayer())); + Audience audience = mcMMO.getAudiences() + .filter(getPowerLevelUpBroadcastPredicate(mmoPlayer.getPlayer())); //TODO: Make prettier - HoverEvent levelMilestoneHover = Component.text(mmoPlayer.getPlayer().getName()) + HoverEvent levelMilestoneHover = Component.text( + mmoPlayer.getPlayer().getName()) .append(Component.newline()) .append(Component.text(LocalDate.now().toString())) .append(Component.newline()) - .append(Component.text("Power level has reached "+powerLevel)).color(TextColor.fromHexString(HEX_BEIGE_COLOR)) + .append(Component.text("Power level has reached " + powerLevel)) + .color(TextColor.fromHexString(HEX_BEIGE_COLOR)) .asHoverEvent(); - String localeMessage = LocaleLoader.getString("Broadcasts.PowerLevelUpMilestone", mmoPlayer.getPlayer().getDisplayName(), powerLevel); - Component message = LegacyComponentSerializer.legacySection().deserialize(localeMessage).hoverEvent(levelMilestoneHover); + String localeMessage = LocaleLoader.getString("Broadcasts.PowerLevelUpMilestone", + mmoPlayer.getPlayer().getDisplayName(), powerLevel); + Component message = LegacyComponentSerializer.legacySection() + .deserialize(localeMessage).hoverEvent(levelMilestoneHover); - mcMMO.p.getFoliaLib().getImpl().runNextTick(t -> audience.sendMessage(message)); + mcMMO.p.getFoliaLib().getScheduler() + .runNextTick(t -> audience.sendMessage(message)); } } } //TODO: Could cache - public static @NotNull LevelUpBroadcastPredicate getLevelUpBroadcastPredicate(@NotNull CommandSender levelUpPlayer) { + public static @NotNull LevelUpBroadcastPredicate getLevelUpBroadcastPredicate( + @NotNull CommandSender levelUpPlayer) { return new LevelUpBroadcastPredicate<>(levelUpPlayer); } - public static @NotNull PowerLevelUpBroadcastPredicate getPowerLevelUpBroadcastPredicate(@NotNull CommandSender levelUpPlayer) { + public static @NotNull PowerLevelUpBroadcastPredicate getPowerLevelUpBroadcastPredicate( + @NotNull CommandSender levelUpPlayer) { return new PowerLevelUpBroadcastPredicate<>(levelUpPlayer); } diff --git a/src/main/java/com/gmail/nossr50/util/player/PlayerLevelUtils.java b/src/main/java/com/gmail/nossr50/util/player/PlayerLevelUtils.java index 1f0cba2f1..d1ec0ea6c 100644 --- a/src/main/java/com/gmail/nossr50/util/player/PlayerLevelUtils.java +++ b/src/main/java/com/gmail/nossr50/util/player/PlayerLevelUtils.java @@ -19,7 +19,7 @@ public class PlayerLevelUtils { // int levelCap = Config.getInstance().getLevelCap(primarySkillType); // int cap; // -// if(levelCap == Integer.MAX_VALUE || levelCap <= 0) +// if (levelCap == Integer.MAX_VALUE || levelCap <= 0) // { // cap = Config.getInstance().getIsRetroMode() ? 50 : 5; // } else { @@ -30,19 +30,22 @@ public class PlayerLevelUtils { // } // } - public int getEarlyGameCutoff(PrimarySkillType primarySkillType) - { + public int getEarlyGameCutoff(PrimarySkillType primarySkillType) { return 1; } /** - * Check if a player is currently qualifying for the early game boosted XP - * Will return false only if a player is above the boost level cutoff, it does not check config settings to see if the early game boost is on - * @param mcMMOPlayer target player + * Check if a player is currently qualifying for the early game boosted XP Will return false + * only if a player is above the boost level cutoff, it does not check config settings to see if + * the early game boost is on + * + * @param mmoPlayer target player * @param primarySkillType target skill * @return if the player would qualify for the XP boost if its enabled */ - public static boolean qualifiesForEarlyGameBoost(McMMOPlayer mcMMOPlayer, PrimarySkillType primarySkillType) { - return mcMMOPlayer.getSkillLevel(primarySkillType) < mcMMO.getPlayerLevelUtils().getEarlyGameCutoff(primarySkillType); + public static boolean qualifiesForEarlyGameBoost(McMMOPlayer mmoPlayer, + PrimarySkillType primarySkillType) { + return mmoPlayer.getSkillLevel(primarySkillType) < mcMMO.getPlayerLevelUtils() + .getEarlyGameCutoff(primarySkillType); } } diff --git a/src/main/java/com/gmail/nossr50/util/player/UserManager.java b/src/main/java/com/gmail/nossr50/util/player/UserManager.java index a7f4a840b..5d8a64408 100644 --- a/src/main/java/com/gmail/nossr50/util/player/UserManager.java +++ b/src/main/java/com/gmail/nossr50/util/player/UserManager.java @@ -5,6 +5,9 @@ import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.LogUtils; import com.gmail.nossr50.util.MetadataConstants; import com.google.common.collect.ImmutableList; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; import org.bukkit.OfflinePlayer; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; @@ -12,33 +15,33 @@ import org.bukkit.metadata.FixedMetadataValue; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; - public final class UserManager { private static HashSet playerDataSet; //Used to track players for sync saves on shutdown - private UserManager() {} + private UserManager() { + } /** * Track a new user. * - * @param mcMMOPlayer the player profile to start tracking + * @param mmoPlayer the player profile to start tracking */ - public static void track(@NotNull McMMOPlayer mcMMOPlayer) { - mcMMOPlayer.getPlayer().setMetadata(MetadataConstants.METADATA_KEY_PLAYER_DATA, new FixedMetadataValue(mcMMO.p, mcMMOPlayer)); + public static void track(@NotNull McMMOPlayer mmoPlayer) { + mmoPlayer.getPlayer().setMetadata(MetadataConstants.METADATA_KEY_PLAYER_DATA, + new FixedMetadataValue(mcMMO.p, mmoPlayer)); - if(playerDataSet == null) + if (playerDataSet == null) { playerDataSet = new HashSet<>(); + } - playerDataSet.add(mcMMOPlayer); //for sync saves on shutdown + playerDataSet.add(mmoPlayer); //for sync saves on shutdown } - public static void cleanupPlayer(McMMOPlayer mcMMOPlayer) { - if(playerDataSet != null) - playerDataSet.remove(mcMMOPlayer); + public static void cleanupPlayer(McMMOPlayer mmoPlayer) { + if (playerDataSet != null) { + playerDataSet.remove(mmoPlayer); + } } /** @@ -47,16 +50,17 @@ public final class UserManager { * @param player The Player object */ public static void remove(@NotNull Player player) { - McMMOPlayer mcMMOPlayer = getPlayer(player); + final McMMOPlayer mmoPlayer = getPlayer(player); - if(mcMMOPlayer == null) + if (mmoPlayer == null) { return; + } - mcMMOPlayer.cleanup(); + mmoPlayer.cleanup(); player.removeMetadata(MetadataConstants.METADATA_KEY_PLAYER_DATA, mcMMO.p); - if(playerDataSet != null) { - playerDataSet.remove(mcMMOPlayer); //Clear sync save tracking + if (playerDataSet != null) { + playerDataSet.remove(mmoPlayer); //Clear sync save tracking } } @@ -68,34 +72,36 @@ public final class UserManager { remove(player); } - if(playerDataSet != null) + if (playerDataSet != null) { playerDataSet.clear(); //Clear sync save tracking + } } /** * Save all users ON THIS THREAD. */ public static void saveAll() { - if(playerDataSet == null) + if (playerDataSet == null) { return; + } ImmutableList trackedSyncData = ImmutableList.copyOf(playerDataSet); - mcMMO.p.getLogger().info("Saving mcMMOPlayers... (" + trackedSyncData.size() + ")"); + mcMMO.p.getLogger().info("Saving mmoPlayers... (" + trackedSyncData.size() + ")"); for (McMMOPlayer playerData : trackedSyncData) { - try - { - LogUtils.debug(mcMMO.p.getLogger(), "Saving data for player: "+playerData.getPlayerName()); + try { + LogUtils.debug(mcMMO.p.getLogger(), + "Saving data for player: " + playerData.getPlayerName()); playerData.getProfile().save(true); - } - catch (Exception e) - { - mcMMO.p.getLogger().warning("Could not save mcMMO player data for player: " + playerData.getPlayerName()); + } catch (Exception e) { + mcMMO.p.getLogger().warning("Could not save mcMMO player data for player: " + + playerData.getPlayerName()); } } - mcMMO.p.getLogger().info("Finished save operation for "+trackedSyncData.size()+" players!"); + mcMMO.p.getLogger() + .info("Finished save operation for " + trackedSyncData.size() + " players!"); } public static @NotNull Collection getPlayers() { @@ -133,27 +139,34 @@ public final class UserManager { } /** - * Gets the McMMOPlayer object for a player, this can be null if the player has not yet been loaded. + * Gets the McMMOPlayer object for a player, this can be null if the player has not yet been + * loaded. + * * @param player target player * @return McMMOPlayer object for this player, null if Player has not been loaded */ public static @Nullable McMMOPlayer getPlayer(@Nullable Player player) { //Avoid Array Index out of bounds - if(player != null && player.hasMetadata(MetadataConstants.METADATA_KEY_PLAYER_DATA)) - return (McMMOPlayer) player.getMetadata(MetadataConstants.METADATA_KEY_PLAYER_DATA).get(0).value(); - else + if (player != null && player.hasMetadata(MetadataConstants.METADATA_KEY_PLAYER_DATA)) { + return (McMMOPlayer) player.getMetadata(MetadataConstants.METADATA_KEY_PLAYER_DATA) + .get(0).value(); + } else { return null; + } } - private static @Nullable McMMOPlayer retrieveMcMMOPlayer(@Nullable String playerName, boolean offlineValid) { - if(playerName == null) + private static @Nullable McMMOPlayer retrieveMcMMOPlayer(@Nullable String playerName, + boolean offlineValid) { + if (playerName == null) { return null; + } Player player = mcMMO.p.getServer().getPlayerExact(playerName); if (player == null) { if (!offlineValid) { - mcMMO.p.getLogger().warning("A valid mcMMOPlayer object could not be found for " + playerName + "."); + mcMMO.p.getLogger().warning( + "A valid mmoPlayer object could not be found for " + playerName + "."); } return null; 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 677d3e63e..000000000 --- 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/Probability.java b/src/main/java/com/gmail/nossr50/util/random/Probability.java new file mode 100644 index 000000000..ca63ced3f --- /dev/null +++ b/src/main/java/com/gmail/nossr50/util/random/Probability.java @@ -0,0 +1,110 @@ +package com.gmail.nossr50.util.random; + +import java.util.concurrent.ThreadLocalRandom; +import org.jetbrains.annotations.NotNull; + +public interface Probability { + /** + * A Probability that always fails. + */ + Probability ALWAYS_FAILS = () -> 0; + + /** + * A Probability that always succeeds. + */ + Probability ALWAYS_SUCCEEDS = () -> 1; + + /** + * Create a new Probability of a percentage. This method takes a percentage and creates a + * Probability of equivalent odds. + *

+ * 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) { + if (percentage < 0) { + throw new IllegalArgumentException( + "Value should never be negative for Probability! This suggests a coding mistake, contact the devs!"); + } + + // Convert to a 0-1 floating point representation + double probabilityValue = percentage / 100.0D; + return new ProbabilityImpl(probabilityValue); + } + + /** + * Create a new Probability of a value. This method takes a value between 0 and 1 and creates a + * Probability of equivalent odds. 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. + * + * @param value the value of the probability + * @return a new Probability with the given value + */ + static @NotNull Probability ofValue(double value) { + return new ProbabilityImpl(value); + } + + /** + * 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(1D); + } + + /** + * The value of this Probability Should return a result between 0 and 1 (inclusive) 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(); + + /** + * 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()); + } + + /** + * 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); + } + + /** + * 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 + * @param finalProbabilityMultiplier probability will be multiplied by this after the first + * multiplier, should be between 0 and 1 + * @return true if the probability succeeded, false if it failed + */ + default boolean evaluate(double probabilityMultiplier, double finalProbabilityMultiplier) { + double probabilityValue = getValue() * probabilityMultiplier; + return isSuccessfulRoll(probabilityValue * finalProbabilityMultiplier); + } +} 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 000000000..2ada7236b --- /dev/null +++ b/src/main/java/com/gmail/nossr50/util/random/ProbabilityImpl.java @@ -0,0 +1,51 @@ +package com.gmail.nossr50.util.random; + +import com.google.common.base.Objects; + +public class ProbabilityImpl implements Probability { + + private final double probabilityValue; + + /** + * Create a probability from a static value. A value of 0 represents a 0% chance of success, A + * value of 1 represents a 100% chance of success. A value of 0.5 represents a 50% chance of + * success. A value of 0.01 represents a 1% chance of success. And so on. + * + * @param value the value of the probability between 0 and 100 + */ + public ProbabilityImpl(double value) throws IllegalArgumentException { + if (value < 0) { + throw new IndexOutOfBoundsException("Value should never be negative for Probability!" + + " This suggests a coding mistake, contact the devs!"); + } + + probabilityValue = value; + } + + @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/ProbabilityUtil.java b/src/main/java/com/gmail/nossr50/util/random/ProbabilityUtil.java new file mode 100644 index 000000000..5bc7b7b96 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/util/random/ProbabilityUtil.java @@ -0,0 +1,483 @@ +package com.gmail.nossr50.util.random; + +import static java.util.Objects.requireNonNull; + +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 java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.util.Locale; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.VisibleForTesting; + +public class ProbabilityUtil { + public static final @NotNull DecimalFormat percent = new DecimalFormat("##0.00%", + DecimalFormatSymbols.getInstance(Locale.US)); + public static final double LUCKY_MODIFIER = 1.333D; + + /** + * Return a chance of success in "percentage" format, shown 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 + * @deprecated use {@link #chanceOfSuccessPercentage(McMMOPlayer, SubSkillType, boolean)} + * instead + */ + @Deprecated(forRemoval = true, since = "2.2.010") + public static double chanceOfSuccessPercentage(@Nullable Player player, + @NotNull SubSkillType subSkillType, + boolean isLucky) { + return chanceOfSuccessPercentage(requireNonNull(UserManager.getPlayer(player)), + subSkillType, isLucky); + } + + public static double chanceOfSuccessPercentage(@Nullable McMMOPlayer mmoPlayer, + @NotNull SubSkillType subSkillType, + boolean isLucky) { + final Probability probability = getSubSkillProbability(subSkillType, mmoPlayer); + //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; + } + + /** + * Return a chance of success as a double representing a "percentage". + * + * @param probability the probability of success + * @param isLucky whether to apply luck modifiers + * @return a double as a "percentage" representation of success + */ + 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; + } + + @VisibleForTesting + static Probability getStaticRandomChance(@NotNull SubSkillType subSkillType) + throws InvalidStaticChance { + return switch (subSkillType) { + 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(); + }; + } + + 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; + } + + @Deprecated(forRemoval = true, since = "2.2.010") + private static @NotNull Probability ofSubSkill(@Nullable Player player, + @NotNull SubSkillType subSkillType) { + // no null check needed here + return ofSubSkill(UserManager.getPlayer(player), subSkillType); + } + + private static @NotNull Probability ofSubSkill(@Nullable McMMOPlayer mmoPlayer, + @NotNull SubSkillType subSkillType) { + switch (getProbabilityType(subSkillType)) { + case DYNAMIC_CONFIGURABLE: + double probabilityCeiling; + double skillLevel; + double maxBonusLevel; // If a skill level is equal to the cap, it has the full probability + + if (mmoPlayer != null) { + skillLevel = mmoPlayer.getSkillLevel(subSkillType.getParentSkill()); + } else { + skillLevel = 0; + } + + //Probability ceiling is configurable in this type + probabilityCeiling = mcMMO.p.getAdvancedConfig() + .getMaximumProbability(subSkillType); + //The xCeiling is configurable in this type + maxBonusLevel = mcMMO.p.getAdvancedConfig().getMaxBonusLevel(subSkillType); + return calculateCurrentSkillProbability(skillLevel, 0, probabilityCeiling, + maxBonusLevel); + case STATIC_CONFIGURABLE: + try { + return getStaticRandomChance(subSkillType); + } catch (InvalidStaticChance invalidStaticChance) { + throw new RuntimeException(invalidStaticChance); + } + default: + throw new IllegalStateException( + "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 + * @deprecated use {@link #isSkillRNGSuccessful(SubSkillType, McMMOPlayer)} instead + */ + @Deprecated(forRemoval = true, since = "2.2.010") + public static boolean isSkillRNGSuccessful(@NotNull SubSkillType subSkillType, + @Nullable Player player) { + return isSkillRNGSuccessful(subSkillType, UserManager.getPlayer(player)); + } + + /** + * 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 mmoPlayer 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 McMMOPlayer mmoPlayer) { + final Probability probability = getSkillProbability(subSkillType, mmoPlayer); + + //Luck + boolean isLucky = mmoPlayer != null && Permissions.lucky(mmoPlayer.getPlayer(), + subSkillType.getParentSkill()); + + if (isLucky) { + return probability.evaluate(LUCKY_MODIFIER); + } else { + return probability.evaluate(); + } + } + + /** + * This is one of several Skill RNG evaluation methods. This one specifically allows for a + * probability multiplier to be passed in. This probability multiplier is applied after any + * lucky modifiers, affecting the final result. + *

+ * 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 mmoPlayer 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 McMMOPlayer mmoPlayer, + double probabilityMultiplier) { + final Probability probability = getSkillProbability(subSkillType, mmoPlayer); + + //Luck + boolean isLucky = mmoPlayer != null && Permissions.lucky(mmoPlayer.getPlayer(), + subSkillType.getParentSkill()); + + if (isLucky) { + return probability.evaluate(LUCKY_MODIFIER, probabilityMultiplier); + } else { + return probability.evaluate(); + } + } + + /** + * Returns the {@link Probability} for a specific {@link SubSkillType} for a specific + * {@link Player}. This does not take into account perks such as lucky for the player. This is + * affected by other plugins who can listen to the {@link SubSkillEvent} and cancel it or mutate + * it. Null players will be treated as zero skill players. + * + * @param subSkillType the target subskill + * @param player the target player can be null (null players have the worst odds) + * @return the probability for this skill + * @deprecated use {@link #getSkillProbability(SubSkillType, McMMOPlayer)} instead + */ + @Deprecated(forRemoval = true) + public static Probability getSkillProbability(@NotNull SubSkillType subSkillType, + @Nullable Player player) { + return getSkillProbability(subSkillType, UserManager.getPlayer(player)); + } + + /** + * Returns the {@link Probability} for a specific {@link SubSkillType} for a specific + * {@link Player}. This does not take into account perks such as lucky for the player. This is + * affected by other plugins who can listen to the {@link SubSkillEvent} and cancel it or mutate + * it. Null players will be treated as zero skill players. + * + * @param subSkillType the target subskill + * @param mmoPlayer the target player can be null (null players have the worst odds) + * @return the probability for this skill + */ + public static Probability getSkillProbability(@NotNull SubSkillType subSkillType, + @Nullable McMMOPlayer mmoPlayer) { + // Process probability + Probability probability = getSubSkillProbability(subSkillType, mmoPlayer); + + // Send out event + if (mmoPlayer != null) { + SubSkillEvent subSkillEvent = EventUtils.callSubSkillEvent(mmoPlayer, subSkillType); + + if (subSkillEvent.isCancelled()) { + return Probability.ALWAYS_FAILS; + } + + // Result modifier + double resultModifier = subSkillEvent.getResultModifier(); + + // Mutate probability + if (resultModifier != 1.0D) { + probability = Probability.ofPercent(probability.getValue() * resultModifier); + } + } + + return 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 + * @deprecated use {@link #isStaticSkillRNGSuccessful(PrimarySkillType, McMMOPlayer, double)} + * instead + */ + @Deprecated(forRemoval = true, since = "2.2.010") + public static boolean isStaticSkillRNGSuccessful(@NotNull PrimarySkillType primarySkillType, + @Nullable Player player, double probabilityPercentage) { + return isStaticSkillRNGSuccessful(primarySkillType, player, + Probability.ofPercent(probabilityPercentage)); + } + + /** + * 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 mmoPlayer 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 McMMOPlayer mmoPlayer, double probabilityPercentage) { + //Grab a probability converted from a "percentage" value + final Probability probability = Probability.ofPercent(probabilityPercentage); + + return isStaticSkillRNGSuccessful(primarySkillType, mmoPlayer, 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 + * @deprecated use + * {@link #isStaticSkillRNGSuccessful(PrimarySkillType, McMMOPlayer, Probability)} instead, this + * method is redundant and will be removed. + */ + @Deprecated(forRemoval = true, since = "2.2.010") + public static boolean isStaticSkillRNGSuccessful(@NotNull PrimarySkillType primarySkillType, + @Nullable Player player, @NotNull Probability probability) { + return isStaticSkillRNGSuccessful(primarySkillType, UserManager.getPlayer(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 mmoPlayer's Luck + * + * @param primarySkillType the related primary skill + * @param mmoPlayer the target mmoPlayer can be null (null players have the worst odds) + * @param probability the probability of this mmoPlayer succeeding + * @return true if the RNG succeeds, false if it fails + */ + public static boolean isStaticSkillRNGSuccessful(@NotNull PrimarySkillType primarySkillType, + @Nullable McMMOPlayer mmoPlayer, @NotNull Probability probability) { + boolean isLucky = + mmoPlayer != null && Permissions.lucky(mmoPlayer.getPlayer(), 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) + * @deprecated use {@link #isNonRNGSkillActivationSuccessful(SubSkillType, McMMOPlayer)} instead + */ + @Deprecated(forRemoval = true, since = "2.2.010") + public static boolean isNonRNGSkillActivationSuccessful(@NotNull SubSkillType subSkillType, + @NotNull Player player) { + return isNonRNGSkillActivationSuccessful(subSkillType, + requireNonNull(UserManager.getPlayer(player))); + } + + /** + * Skills activate without RNG, this allows other plugins to prevent that activation + * + * @param subSkillType target subskill + * @param mmoPlayer target player + * @return true if the skill succeeds (wasn't cancelled by any other plugin) + */ + public static boolean isNonRNGSkillActivationSuccessful(@NotNull SubSkillType subSkillType, + @NotNull McMMOPlayer mmoPlayer) { + return !EventUtils.callSubSkillEvent(mmoPlayer, subSkillType).isCancelled(); + } + + /** + * Retrieves the {@link Probability} of success for a specified {@link SubSkillType} for a given + * {@link Player}. + * + * @param subSkillType The targeted subskill. + * @param player The player in question. If null, the method treats it as a player with no + * levels or luck and calculates the probability accordingly. + * @return The probability that the specified skill will succeed. + * @deprecated use {@link #getSubSkillProbability(SubSkillType, McMMOPlayer)} instead + */ + @Deprecated(forRemoval = true, since = "2.2.010") + public static @NotNull Probability getSubSkillProbability(@NotNull SubSkillType subSkillType, + @Nullable Player player) { + return ProbabilityUtil.ofSubSkill(player, subSkillType); + } + + /** + * Retrieves the {@link Probability} of success for a specified {@link SubSkillType} for a given + * {@link Player}. + * + * @param subSkillType The targeted subskill. + * @param mmoPlayer The player in question. If null, the method treats it as a player with no + * levels or luck and calculates the probability accordingly. + * @return The probability that the specified skill will succeed. + */ + public static @NotNull Probability getSubSkillProbability(@NotNull SubSkillType subSkillType, + @Nullable McMMOPlayer mmoPlayer) { + return ProbabilityUtil.ofSubSkill(mmoPlayer, subSkillType); + } + + public static @NotNull String[] getRNGDisplayValues(@Nullable McMMOPlayer mmoPlayer, + @NotNull SubSkillType subSkill) { + double firstValue = chanceOfSuccessPercentage(mmoPlayer, subSkill, false); + double secondValue = chanceOfSuccessPercentage(mmoPlayer, 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)}; + } + + /** + * Helper function to calculate what probability a given skill has at a certain level + * + * @param skillLevel the skill level currently between the floor and the ceiling + * @param floor the minimum odds this skill can have + * @param ceiling the maximum odds this skill can have + * @param maxBonusLevel the maximum level this skill can have to reach the ceiling + * @return the probability of success for this skill at this level + */ + public static Probability calculateCurrentSkillProbability(double skillLevel, double floor, + double ceiling, + double maxBonusLevel) { + // The odds of success are between the value of the floor and the value of the ceiling. + // If the skill has a maxBonusLevel of 500 on this skill, then at skill level 500 you would have the full odds, + // at skill level 250 it would be half odds. + + if (skillLevel >= maxBonusLevel || maxBonusLevel <= 0) { + // Avoid divide by zero bugs + // Max benefit has been reached, should always succeed + return Probability.ofPercent(ceiling); + } + + double odds = ((skillLevel / maxBonusLevel) * ceiling); + + // make sure the odds aren't lower or higher than the floor or ceiling + return Probability.ofPercent(Math.min(Math.max(floor, odds), ceiling)); + } +} 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 e5d51d740..000000000 --- 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 92d91ec83..000000000 --- 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 c96b71d6b..000000000 --- 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 0b09a4a3c..000000000 --- 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, double probabilityCap, boolean isLucky) { - this.xPos = xPos; - this.probabilityCap = probabilityCap; - 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 deleted file mode 100644 index 0191172c1..000000000 --- a/src/main/java/com/gmail/nossr50/util/random/RandomChanceUtil.java +++ /dev/null @@ -1,337 +0,0 @@ -package com.gmail.nossr50.util.random; - -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.mcMMO; -import com.gmail.nossr50.util.EventUtils; -import com.gmail.nossr50.util.Permissions; -import com.gmail.nossr50.util.skills.SkillActivationType; -import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -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 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 - * - * @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 - */ - 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); - } - - /** - * Used for stuff like Excavation, Fishing, etc... - * - * @param randomChance - * @return - */ - public static boolean checkRandomChanceExecutionSuccess(@NotNull RandomChanceSkillStatic randomChance, double resultModifier) { - double chanceOfSuccess = calculateChanceOfSuccess(randomChance); - - //Check the odds - return rollDice(chanceOfSuccess, 100, resultModifier); - } - - /** - * Used for stuff like Excavation, Fishing, etc... - * - * @param randomChance - * @return - */ - 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); - } - - - /*public static double getRandomChanceExecutionChance(RandomChanceSkill randomChance) - { - double chanceOfSuccess = calculateChanceOfSuccess(randomChance); - return chanceOfSuccess; - }*/ - - /** - * Gets the Static Chance for something to activate - * - * @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; - } - - /*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(); - 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 ) - * - * @return the chance of success from 0-100 (100 = guaranteed) - */ - 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) { - 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)); - } - - - public static boolean checkRandomStaticChanceExecutionSuccess(@Nullable Player player, @NotNull SubSkillType subSkillType) { - try { - return checkRandomChanceExecutionSuccess(new RandomChanceSkillStatic(getStaticRandomChance(subSkillType), player, subSkillType)); - } catch (InvalidStaticChance invalidStaticChance) { - //Catch invalid static skills - invalidStaticChance.printStackTrace(); - } - - 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 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(); - } - } - - 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, LINEAR_CURVE_VAR, false); - double successChance = getRandomChanceExecutionChance(rcs); - - RandomChanceStatic rcs_lucky = new RandomChanceStatic(chance, LINEAR_CURVE_VAR, 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 mcMMO.p.getAdvancedConfig().getMaximumProbability(subSkillType); - } - - public static double getMaxBonusLevelCap(@NotNull SubSkillType subSkillType) { - return mcMMO.p.getAdvancedConfig().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 000000000..95814f6a1 --- /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/scoreboards/ScoreboardManager.java b/src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardManager.java index 331d3f5b3..8531edab6 100644 --- a/src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardManager.java +++ b/src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardManager.java @@ -15,6 +15,11 @@ import com.gmail.nossr50.util.player.UserManager; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Lists; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.entity.Player; @@ -24,8 +29,6 @@ import org.bukkit.scoreboard.Scoreboard; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.*; - /** * Manages the Scoreboards used to display a variety of mcMMO related information to the player */ @@ -37,7 +40,8 @@ public class ScoreboardManager { static final String POWER_OBJECTIVE = "mcmmo_pwrlvl"; static final String HEADER_STATS = LocaleLoader.getString("Scoreboard.Header.PlayerStats"); - static final String HEADER_COOLDOWNS = LocaleLoader.getString("Scoreboard.Header.PlayerCooldowns"); + static final String HEADER_COOLDOWNS = LocaleLoader.getString( + "Scoreboard.Header.PlayerCooldowns"); static final String HEADER_RANK = LocaleLoader.getString("Scoreboard.Header.PlayerRank"); static final String TAG_POWER_LEVEL = LocaleLoader.getString("Scoreboard.Header.PowerLevel"); @@ -50,7 +54,7 @@ public class ScoreboardManager { // static final String LABEL_ABILITY_COOLDOWN = LocaleLoader.getString("Scoreboard.Misc.Cooldown"); // static final String LABEL_OVERALL = LocaleLoader.getString("Scoreboard.Misc.Overall"); - static final Map skillLabels; + static final Map skillLabels; static final Map abilityLabelsColored; static final Map abilityLabelsSkill; @@ -94,13 +98,19 @@ public class ScoreboardManager { int i = 0; for (PrimarySkillType primarySkillType : PrimarySkillType.values()) { // Include child skills - skillLabelBuilder.put(primarySkillType, getShortenedName(colors.get(i) + mcMMO.p.getSkillTools().getLocalizedSkillName(primarySkillType), false)); + skillLabelBuilder.put(primarySkillType, getShortenedName( + colors.get(i) + mcMMO.p.getSkillTools() + .getLocalizedSkillName(primarySkillType), false)); if (mcMMO.p.getSkillTools().getSuperAbility(primarySkillType) != null) { - abilityLabelBuilder.put(mcMMO.p.getSkillTools().getSuperAbility(primarySkillType), getShortenedName(colors.get(i) + mcMMO.p.getSkillTools().getSuperAbility(primarySkillType).getLocalizedName())); + abilityLabelBuilder.put( + mcMMO.p.getSkillTools().getSuperAbility(primarySkillType), + getShortenedName(colors.get(i) + mcMMO.p.getSkillTools() + .getSuperAbility(primarySkillType).getLocalizedName())); if (primarySkillType == PrimarySkillType.MINING) { - abilityLabelBuilder.put(SuperAbilityType.BLAST_MINING, getShortenedName(colors.get(i) + SuperAbilityType.BLAST_MINING.getLocalizedName())); + abilityLabelBuilder.put(SuperAbilityType.BLAST_MINING, getShortenedName( + colors.get(i) + SuperAbilityType.BLAST_MINING.getLocalizedName())); } } @@ -116,20 +126,28 @@ public class ScoreboardManager { else { for (PrimarySkillType primarySkillType : PrimarySkillType.values()) { // Include child skills - skillLabelBuilder.put(primarySkillType, getShortenedName(ChatColor.GREEN + mcMMO.p.getSkillTools().getLocalizedSkillName(primarySkillType))); + skillLabelBuilder.put(primarySkillType, getShortenedName( + ChatColor.GREEN + mcMMO.p.getSkillTools() + .getLocalizedSkillName(primarySkillType))); if (mcMMO.p.getSkillTools().getSuperAbility(primarySkillType) != null) { - abilityLabelBuilder.put(mcMMO.p.getSkillTools().getSuperAbility(primarySkillType), formatAbility(mcMMO.p.getSkillTools().getSuperAbility(primarySkillType).getLocalizedName())); + abilityLabelBuilder.put( + mcMMO.p.getSkillTools().getSuperAbility(primarySkillType), + formatAbility(mcMMO.p.getSkillTools().getSuperAbility(primarySkillType) + .getLocalizedName())); if (primarySkillType == PrimarySkillType.MINING) { - abilityLabelBuilder.put(SuperAbilityType.BLAST_MINING, formatAbility(SuperAbilityType.BLAST_MINING.getLocalizedName())); + abilityLabelBuilder.put(SuperAbilityType.BLAST_MINING, + formatAbility(SuperAbilityType.BLAST_MINING.getLocalizedName())); } } } } for (SuperAbilityType type : SuperAbilityType.values()) { - abilityLabelSkillBuilder.put(type, formatAbility((type == SuperAbilityType.BLAST_MINING ? ChatColor.BLUE : ChatColor.AQUA), type.getLocalizedName())); + abilityLabelSkillBuilder.put(type, formatAbility( + (type == SuperAbilityType.BLAST_MINING ? ChatColor.BLUE : ChatColor.AQUA), + type.getLocalizedName())); } skillLabels = skillLabelBuilder.build(); @@ -155,8 +173,7 @@ public class ScoreboardManager { private static String formatAbility(ChatColor color, String abilityName) { if (mcMMO.p.getGeneralConfig().getShowAbilityNames()) { return getShortenedName(color + abilityName); - } - else { + } else { return color + LocaleLoader.getString("Scoreboard.Misc.Ability"); } } @@ -185,18 +202,20 @@ public class ScoreboardManager { // Called by PlayerQuitEvent listener and OnPlayerTeleport under certain circumstances public static void teardownPlayer(Player player) { - if(player == null) + if (player == null) { return; - - //Hacky world blacklist fix - if(player.isOnline() && player.isValid()) { - if(Bukkit.getServer().getScoreboardManager() != null) - player.setScoreboard(Bukkit.getServer().getScoreboardManager().getMainScoreboard()); } - if(getWrapper(player) != null) { + //Hacky world blacklist fix + if (player.isOnline() && player.isValid()) { + if (Bukkit.getServer().getScoreboardManager() != null) { + player.setScoreboard(Bukkit.getServer().getScoreboardManager().getMainScoreboard()); + } + } + + if (getWrapper(player) != null) { ScoreboardWrapper wrapper = PLAYER_SCOREBOARDS.remove(player.getName()); - if(wrapper.revertTask != null) { + if (wrapper.revertTask != null) { wrapper.revertTask.cancel(); } } @@ -204,8 +223,10 @@ public class ScoreboardManager { // Called in onDisable() public static void teardownAll() { - ImmutableList onlinePlayers = ImmutableList.copyOf(mcMMO.p.getServer().getOnlinePlayers()); - LogUtils.debug(mcMMO.p.getLogger(), "Tearing down scoreboards... (" + onlinePlayers.size() + ")"); + ImmutableList onlinePlayers = ImmutableList.copyOf( + mcMMO.p.getServer().getOnlinePlayers()); + LogUtils.debug(mcMMO.p.getLogger(), + "Tearing down scoreboards... (" + onlinePlayers.size() + ")"); for (Player player : onlinePlayers) { teardownPlayer(player); } @@ -225,13 +246,14 @@ public class ScoreboardManager { // Selfboards ScoreboardWrapper wrapper = getWrapper(player); - if(wrapper == null) { + if (wrapper == null) { setupPlayer(player); wrapper = getWrapper(player); } - if(wrapper != null) { - if ((wrapper.isSkillScoreboard() && wrapper.targetSkill == skill) || (wrapper.isStatsScoreboard()) && wrapper.isBoardShown()) { + if (wrapper != null) { + if ((wrapper.isSkillScoreboard() && wrapper.targetSkill == skill) + || (wrapper.isStatsScoreboard()) && wrapper.isBoardShown()) { wrapper.doSidebarUpdateSoon(); } @@ -239,12 +261,14 @@ public class ScoreboardManager { String playerName = player.getName(); for (ScoreboardWrapper iWrapper : PLAYER_SCOREBOARDS.values()) { - if (iWrapper.isStatsScoreboard() && playerName.equals(iWrapper.targetPlayer) && wrapper.isBoardShown()) { + if (iWrapper.isStatsScoreboard() && playerName.equals(iWrapper.targetPlayer) + && wrapper.isBoardShown()) { wrapper.doSidebarUpdateSoon(); } } - if (mcMMO.p.getGeneralConfig().getPowerLevelTagsEnabled() && !dirtyPowerLevels.contains(playerName)) { + if (mcMMO.p.getGeneralConfig().getPowerLevelTagsEnabled() && !dirtyPowerLevels.contains( + playerName)) { dirtyPowerLevels.add(playerName); } @@ -260,7 +284,8 @@ public class ScoreboardManager { // Selfboards ScoreboardWrapper wrapper = getWrapper(player); - if (wrapper != null && wrapper.isSkillScoreboard() && wrapper.targetSkill == skill && wrapper.isBoardShown()) { + if (wrapper != null && wrapper.isSkillScoreboard() && wrapper.targetSkill == skill + && wrapper.isBoardShown()) { wrapper.doSidebarUpdateSoon(); } } @@ -270,13 +295,15 @@ public class ScoreboardManager { // Selfboards ScoreboardWrapper wrapper = getWrapper(player); - if(wrapper == null) { + if (wrapper == null) { setupPlayer(player); wrapper = getWrapper(player); } - if(wrapper != null) { - if ((wrapper.isCooldownScoreboard() || wrapper.isSkillScoreboard() && wrapper.targetSkill == skill) && wrapper.isBoardShown()) { + if (wrapper != null) { + if ((wrapper.isCooldownScoreboard() + || wrapper.isSkillScoreboard() && wrapper.targetSkill == skill) + && wrapper.isBoardShown()) { wrapper.doSidebarUpdateSoon(); } } @@ -285,17 +312,17 @@ public class ScoreboardManager { // **** Setup methods **** // public static void enablePlayerSkillScoreboard(Player player, PrimarySkillType skill) { - McMMOPlayer mmoPlayer = UserManager.getPlayer(player); + final McMMOPlayer mmoPlayer = UserManager.getPlayer(player); mmoPlayer.setLastSkillShownScoreboard(skill); ScoreboardWrapper wrapper = getWrapper(player); - if(wrapper == null) { + if (wrapper == null) { setupPlayer(player); wrapper = getWrapper(player); } - if(wrapper != null) { + if (wrapper != null) { wrapper.setOldScoreboard(); wrapper.setTypeSkill(skill); @@ -304,17 +331,17 @@ public class ScoreboardManager { } public static void retryLastSkillBoard(Player player) { - McMMOPlayer mmoPlayer = UserManager.getPlayer(player); + final McMMOPlayer mmoPlayer = UserManager.getPlayer(player); PrimarySkillType primarySkillType = mmoPlayer.getLastSkillShownScoreboard(); ScoreboardWrapper wrapper = getWrapper(player); - if(wrapper == null) { + if (wrapper == null) { setupPlayer(player); wrapper = getWrapper(player); } - if(wrapper != null) { + if (wrapper != null) { wrapper.setOldScoreboard(); wrapper.setTypeSkill(primarySkillType); @@ -328,8 +355,9 @@ public class ScoreboardManager { // Do NOT run if already shown if (wrapper != null && wrapper.isBoardShown()) { - if(wrapper.isBoardShown()) + if (wrapper.isBoardShown()) { return; + } wrapper.setOldScoreboard(); wrapper.setTypeSkill(skill); @@ -340,9 +368,9 @@ public class ScoreboardManager { public static void enablePlayerStatsScoreboard(Player player) { ScoreboardWrapper wrapper = getWrapper(player); - if(wrapper == null) + if (wrapper == null) { return; - + } wrapper.setOldScoreboard(); wrapper.setTypeSelfStats(); @@ -350,15 +378,16 @@ public class ScoreboardManager { changeScoreboard(wrapper, mcMMO.p.getGeneralConfig().getStatsScoreboardTime()); } - public static void enablePlayerInspectScoreboard(@NotNull Player player, @NotNull PlayerProfile targetProfile) { + public static void enablePlayerInspectScoreboard(@NotNull Player player, + @NotNull PlayerProfile targetProfile) { ScoreboardWrapper wrapper = getWrapper(player); - if(wrapper == null) { + if (wrapper == null) { setupPlayer(player); wrapper = getWrapper(player); } - if(wrapper != null) { + if (wrapper != null) { wrapper.setOldScoreboard(); wrapper.setTypeInspectStats(targetProfile); @@ -366,15 +395,16 @@ public class ScoreboardManager { } } - public static void enablePlayerInspectScoreboard(@NotNull Player player, @NotNull McMMOPlayer targetMcMMOPlayer) { + public static void enablePlayerInspectScoreboard(@NotNull Player player, + @NotNull McMMOPlayer targetMcMMOPlayer) { ScoreboardWrapper wrapper = getWrapper(player); - if(wrapper == null) { + if (wrapper == null) { setupPlayer(player); wrapper = getWrapper(player); } - if(wrapper != null) { + if (wrapper != null) { wrapper.setOldScoreboard(); wrapper.setTypeInspectStats(targetMcMMOPlayer); @@ -385,12 +415,12 @@ public class ScoreboardManager { public static void enablePlayerCooldownScoreboard(Player player) { ScoreboardWrapper wrapper = getWrapper(player); - if(wrapper == null) { + if (wrapper == null) { setupPlayer(player); wrapper = getWrapper(player); } - if(wrapper != null) { + if (wrapper != null) { wrapper.setOldScoreboard(); wrapper.setTypeCooldowns(); @@ -398,15 +428,16 @@ public class ScoreboardManager { } } - public static void showPlayerRankScoreboard(Player player, Map rank) { + public static void showPlayerRankScoreboard(Player player, + Map rank) { ScoreboardWrapper wrapper = getWrapper(player); - if(wrapper == null) { + if (wrapper == null) { setupPlayer(player); wrapper = getWrapper(player); } - if(wrapper != null) { + if (wrapper != null) { wrapper.setOldScoreboard(); wrapper.setTypeSelfRank(); wrapper.acceptRankData(rank); @@ -415,15 +446,16 @@ public class ScoreboardManager { } } - public static void showPlayerRankScoreboardOthers(Player player, String targetName, Map rank) { + public static void showPlayerRankScoreboardOthers(Player player, String targetName, + Map rank) { ScoreboardWrapper wrapper = getWrapper(player); - if(wrapper == null) { + if (wrapper == null) { setupPlayer(player); wrapper = getWrapper(player); } - if(wrapper != null) { + if (wrapper != null) { wrapper.setOldScoreboard(); wrapper.setTypeInspectRank(targetName); wrapper.acceptRankData(rank); @@ -432,16 +464,17 @@ public class ScoreboardManager { } } - public static void showTopScoreboard(Player player, PrimarySkillType skill, int pageNumber, List stats) { + public static void showTopScoreboard(Player player, PrimarySkillType skill, int pageNumber, + List stats) { ScoreboardWrapper wrapper = getWrapper(player); - if(wrapper == null) { + if (wrapper == null) { setupPlayer(player); wrapper = getWrapper(player); } - if(wrapper != null) { + if (wrapper != null) { wrapper.setOldScoreboard(); wrapper.setTypeTop(skill, pageNumber); wrapper.acceptLeaderboardData(stats); @@ -450,15 +483,16 @@ public class ScoreboardManager { } } - public static void showTopPowerScoreboard(Player player, int pageNumber, List stats) { + public static void showTopPowerScoreboard(Player player, int pageNumber, + List stats) { ScoreboardWrapper wrapper = getWrapper(player); - if(wrapper == null) { + if (wrapper == null) { setupPlayer(player); wrapper = getWrapper(player); } - if(wrapper != null) { + if (wrapper != null) { wrapper.setOldScoreboard(); wrapper.setTypeTopPower(pageNumber); wrapper.acceptLeaderboardData(stats); @@ -468,7 +502,7 @@ public class ScoreboardManager { } public static @Nullable ScoreboardWrapper getWrapper(Player player) { - if(PLAYER_SCOREBOARDS.get(player.getName()) == null) { + if (PLAYER_SCOREBOARDS.get(player.getName()) == null) { makeNewScoreboard(player); } @@ -488,14 +522,14 @@ public class ScoreboardManager { } for (String playerName : dirtyPowerLevels) { - McMMOPlayer mcMMOPlayer = UserManager.getPlayer(playerName); + final McMMOPlayer mmoPlayer = UserManager.getPlayer(playerName); - if (mcMMOPlayer == null) { + if (mmoPlayer == null) { continue; } - Player player = mcMMOPlayer.getPlayer(); - int power = mcMMOPlayer.getPowerLevel(); + Player player = mmoPlayer.getPlayer(); + int power = mmoPlayer.getPowerLevel(); mainObjective.getScore(playerName).setScore(power); @@ -511,34 +545,38 @@ public class ScoreboardManager { /** * Gets or creates the power level objective on the main targetBoard. *

- * If power levels are disabled, the objective is deleted and null is - * returned. + * If power levels are disabled, the objective is deleted and null is returned. * * @return the main targetBoard objective, or null if disabled */ public static @Nullable Objective getPowerLevelObjective() { if (!mcMMO.p.getGeneralConfig().getPowerLevelTagsEnabled()) { - if(getScoreboardManager() == null) + if (getScoreboardManager() == null) { return null; + } - Objective objective = getScoreboardManager().getMainScoreboard().getObjective(POWER_OBJECTIVE); + Objective objective = getScoreboardManager().getMainScoreboard() + .getObjective(POWER_OBJECTIVE); if (objective != null) { objective.unregister(); - LogUtils.debug(mcMMO.p.getLogger(), "Removed leftover targetBoard objects from Power Level Tags."); + LogUtils.debug(mcMMO.p.getLogger(), + "Removed leftover targetBoard objects from Power Level Tags."); } return null; } - - if(getScoreboardManager() == null) + if (getScoreboardManager() == null) { return null; + } - Objective powerObjective = getScoreboardManager().getMainScoreboard().getObjective(POWER_OBJECTIVE); + Objective powerObjective = getScoreboardManager().getMainScoreboard() + .getObjective(POWER_OBJECTIVE); if (powerObjective == null) { - powerObjective = getScoreboardManager().getMainScoreboard().registerNewObjective(POWER_OBJECTIVE, "dummy", DISPLAY_NAME); + powerObjective = getScoreboardManager().getMainScoreboard() + .registerNewObjective(POWER_OBJECTIVE, "dummy", DISPLAY_NAME); powerObjective.setDisplayName(TAG_POWER_LEVEL); powerObjective.setDisplaySlot(DisplaySlot.BELOW_NAME); } @@ -546,15 +584,15 @@ public class ScoreboardManager { return powerObjective; } - public @Nullable static org.bukkit.scoreboard.ScoreboardManager getScoreboardManager() { + public @Nullable + static org.bukkit.scoreboard.ScoreboardManager getScoreboardManager() { return mcMMO.p.getServer().getScoreboardManager(); } public static void changeScoreboard(ScoreboardWrapper wrapper, int displayTime) { if (displayTime == -1) { wrapper.showBoardWithNoRevert(); - } - else { + } else { wrapper.showBoardAndScheduleRevert(displayTime * Misc.TICK_CONVERSION_FACTOR); } } @@ -572,7 +610,8 @@ public class ScoreboardManager { } public static void setRevertTimer(String playerName, int seconds) { - PLAYER_SCOREBOARDS.get(playerName).showBoardAndScheduleRevert(seconds * Misc.TICK_CONVERSION_FACTOR); + PLAYER_SCOREBOARDS.get(playerName) + .showBoardAndScheduleRevert(seconds * Misc.TICK_CONVERSION_FACTOR); } public static boolean isPlayerBoardSetup(@NotNull String playerName) { @@ -580,12 +619,14 @@ public class ScoreboardManager { } public static @Nullable ScoreboardWrapper makeNewScoreboard(Player player) { - if(getScoreboardManager() == null) + if (getScoreboardManager() == null) { return null; + } //Call our custom event Scoreboard scoreboard = getScoreboardManager().getNewScoreboard(); - McMMOScoreboardMakeboardEvent event = new McMMOScoreboardMakeboardEvent(scoreboard, player.getScoreboard(), player, ScoreboardEventReason.CREATING_NEW_SCOREBOARD); + McMMOScoreboardMakeboardEvent event = new McMMOScoreboardMakeboardEvent(scoreboard, + player.getScoreboard(), player, ScoreboardEventReason.CREATING_NEW_SCOREBOARD); player.getServer().getPluginManager().callEvent(event); //Use the values from the event return new ScoreboardWrapper(event.getTargetPlayer(), event.getTargetBoard()); 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 1237ce086..7be68d8f3 100644 --- a/src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardWrapper.java +++ b/src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardWrapper.java @@ -1,5 +1,7 @@ package com.gmail.nossr50.util.scoreboards; +import static java.util.Objects.requireNonNull; + import com.gmail.nossr50.datatypes.database.PlayerStat; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.player.PlayerProfile; @@ -11,7 +13,6 @@ import com.gmail.nossr50.events.scoreboard.ScoreboardEventReason; 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; @@ -19,7 +20,8 @@ import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.scoreboards.ScoreboardManager.SidebarType; import com.gmail.nossr50.util.skills.SkillTools; import com.tcoded.folialib.wrapper.task.WrappedTask; -import org.apache.commons.lang.Validate; +import java.util.List; +import java.util.Map; import org.bukkit.ChatColor; import org.bukkit.entity.Player; import org.bukkit.scoreboard.DisplaySlot; @@ -28,9 +30,6 @@ import org.bukkit.scoreboard.Score; import org.bukkit.scoreboard.Scoreboard; import org.jetbrains.annotations.NotNull; -import java.util.List; -import java.util.Map; - public class ScoreboardWrapper { public static final String SIDE_OBJECTIVE = "mcMMO_sideObjective"; public static final String POWER_OBJECTIVE = "mcMMO_powerObjective"; @@ -63,14 +62,16 @@ public class ScoreboardWrapper { private void initBoard() { sidebarType = SidebarType.NONE; - if(registered) { + if (registered) { //Make sure our references are pointed at the right things sidebarObjective = scoreboard.getObjective(ScoreboardManager.SIDEBAR_OBJECTIVE); powerObjective = scoreboard.getObjective(ScoreboardManager.POWER_OBJECTIVE); } else { //Register Objectives - sidebarObjective = this.scoreboard.registerNewObjective(ScoreboardManager.SIDEBAR_OBJECTIVE, "dummy", SIDE_OBJECTIVE); - powerObjective = this.scoreboard.registerNewObjective(ScoreboardManager.POWER_OBJECTIVE, "dummy", POWER_OBJECTIVE); + sidebarObjective = this.scoreboard.registerNewObjective( + ScoreboardManager.SIDEBAR_OBJECTIVE, "dummy", SIDE_OBJECTIVE); + powerObjective = this.scoreboard.registerNewObjective(ScoreboardManager.POWER_OBJECTIVE, + "dummy", POWER_OBJECTIVE); registered = true; } @@ -78,8 +79,9 @@ public class ScoreboardWrapper { powerObjective.setDisplayName(ScoreboardManager.TAG_POWER_LEVEL); powerObjective.setDisplaySlot(DisplaySlot.BELOW_NAME); - for (McMMOPlayer mcMMOPlayer : UserManager.getPlayers()) { - powerObjective.getScore(mcMMOPlayer.getProfile().getPlayerName()).setScore(mcMMOPlayer.getPowerLevel()); + for (McMMOPlayer mmoPlayer : UserManager.getPlayers()) { + powerObjective.getScore(mmoPlayer.getProfile().getPlayerName()) + .setScore(mmoPlayer.getPowerLevel()); } } } @@ -112,8 +114,7 @@ public class ScoreboardWrapper { // Stop updating if it's no longer something displaying cooldowns if (isBoardShown() && (isSkillScoreboard() || isCooldownScoreboard())) { doSidebarUpdateSoon(); - } - else { + } else { stopCooldownUpdating(); } } @@ -123,7 +124,8 @@ public class ScoreboardWrapper { public void doSidebarUpdateSoon() { if (updateTask == null) { // To avoid spamming the scheduler, store the instance and run 2 ticks later - updateTask = mcMMO.p.getFoliaLib().getImpl().runAtEntityLater(player, new ScoreboardQuickUpdate(), 2L); + updateTask = mcMMO.p.getFoliaLib().getScheduler() + .runAtEntityLater(player, new ScoreboardQuickUpdate(), 2L); } } @@ -131,7 +133,9 @@ public class ScoreboardWrapper { if (cooldownTask == null) { // Repeat every 5 seconds. // Cancels once all cooldowns are done, using stopCooldownUpdating(). - cooldownTask = mcMMO.p.getFoliaLib().getImpl().runAtEntityTimer(player, new ScoreboardCooldownTask(), 5 * Misc.TICK_CONVERSION_FACTOR, 5 * Misc.TICK_CONVERSION_FACTOR); + cooldownTask = mcMMO.p.getFoliaLib().getScheduler() + .runAtEntityTimer(player, new ScoreboardCooldownTask(), + 5 * Misc.TICK_CONVERSION_FACTOR, 5 * Misc.TICK_CONVERSION_FACTOR); } } @@ -139,8 +143,7 @@ public class ScoreboardWrapper { if (cooldownTask != null) { try { cooldownTask.cancel(); - } - catch (Exception e) { + } catch (Exception e) { e.printStackTrace(); } @@ -176,11 +179,11 @@ public class ScoreboardWrapper { if (previousBoard == scoreboard) { // Already displaying it if (this.oldBoard == null) { // (Shouldn't happen) Use failsafe value - we're already displaying our board, but we don't have the one we should revert to - if(mcMMO.p.getServer().getScoreboardManager() != null) + if (mcMMO.p.getServer().getScoreboardManager() != null) { this.oldBoard = mcMMO.p.getServer().getScoreboardManager().getMainScoreboard(); + } } - } - else { + } else { this.oldBoard = previousBoard; } } @@ -214,13 +217,15 @@ public class ScoreboardWrapper { } player.setScoreboard(scoreboard); - revertTask = mcMMO.p.getFoliaLib().getImpl().runAtEntityLater(player, new ScoreboardChangeTask(), ticks); + revertTask = mcMMO.p.getFoliaLib().getScheduler() + .runAtEntityLater(player, new ScoreboardChangeTask(), ticks); // TODO is there any way to do the time that looks acceptable? // player.sendMessage(LocaleLoader.getString("Commands.Scoreboard.Timer", StringUtils.capitalize(sidebarType.toString().toLowerCase(Locale.ENGLISH)), ticks / 20F)); - if(UserManager.getPlayer(playerName) == null) + if (UserManager.getPlayer(playerName) == null) { return; + } PlayerProfile profile = UserManager.getPlayer(player).getProfile(); @@ -231,8 +236,7 @@ public class ScoreboardWrapper { if (!tippedKeep) { tippedKeep = true; player.sendMessage(LocaleLoader.getString("Commands.Scoreboard.Tip.Keep")); - } - else if (!tippedClear) { + } else if (!tippedClear) { tippedClear = true; player.sendMessage(LocaleLoader.getString("Commands.Scoreboard.Tip.Clear")); profile.increaseTipsShown(); @@ -252,14 +256,15 @@ public class ScoreboardWrapper { /* Call the revert scoreboard custom event */ - McMMOScoreboardRevertEvent event = new McMMOScoreboardRevertEvent(oldBoard, player.getScoreboard(), player, ScoreboardEventReason.REVERTING_BOARD); + McMMOScoreboardRevertEvent event = new McMMOScoreboardRevertEvent(oldBoard, + player.getScoreboard(), player, ScoreboardEventReason.REVERTING_BOARD); player.getServer().getPluginManager().callEvent(event); //Modify the player based on the event event.getTargetPlayer().setScoreboard(event.getTargetBoard()); oldBoard = null; - } - else { - LogUtils.debug(mcMMO.p.getLogger(), "Not reverting targetBoard for " + playerName + " - targetBoard was changed by another plugin (Consider disabling the mcMMO scoreboards if you don't want them!)"); + } else { + LogUtils.debug(mcMMO.p.getLogger(), "Not reverting targetBoard for " + playerName + + " - targetBoard was changed by another plugin (Consider disabling the mcMMO scoreboards if you don't want them!)"); } } @@ -338,10 +343,10 @@ public class ScoreboardWrapper { loadObjective(LocaleLoader.getString("Scoreboard.Header.PlayerInspect", targetPlayer)); } - public void setTypeInspectStats(@NotNull McMMOPlayer mcMMOPlayer) { + public void setTypeInspectStats(@NotNull McMMOPlayer mmoPlayer) { this.sidebarType = SidebarType.STATS_BOARD; - targetPlayer = mcMMOPlayer.getPlayer().getName(); - targetProfile = mcMMOPlayer.getProfile(); + targetPlayer = mmoPlayer.getPlayer().getName(); + targetProfile = mmoPlayer.getProfile(); targetSkill = null; leaderboardPage = -1; @@ -392,7 +397,8 @@ public class ScoreboardWrapper { int endPosition = page * 10; int startPosition = endPosition - 9; - loadObjective(String.format("%s (%2d - %2d)", ScoreboardManager.POWER_LEVEL, startPosition, endPosition)); + loadObjective(String.format("%s (%2d - %2d)", ScoreboardManager.POWER_LEVEL, startPosition, + endPosition)); } public void setTypeTop(PrimarySkillType skill, int page) { @@ -405,33 +411,43 @@ public class ScoreboardWrapper { int endPosition = page * 10; int startPosition = endPosition - 9; - loadObjective(String.format("%s (%2d - %2d)", ScoreboardManager.skillLabels.get(skill), startPosition, endPosition)); + loadObjective(String.format("%s (%2d - %2d)", ScoreboardManager.skillLabels.get(skill), + startPosition, endPosition)); } // Setup for after a board type change protected void loadObjective(String displayName) { //Unregister objective - McMMOScoreboardObjectiveEvent unregisterEvent = callObjectiveEvent(ScoreboardObjectiveEventReason.UNREGISTER_THIS_OBJECTIVE); - if(!unregisterEvent.isCancelled()) { + McMMOScoreboardObjectiveEvent unregisterEvent = callObjectiveEvent( + ScoreboardObjectiveEventReason.UNREGISTER_THIS_OBJECTIVE); + if (!unregisterEvent.isCancelled()) { try { sidebarObjective.unregister(); } catch (IllegalStateException e) { - McMMOPlayer mmoPlayer = UserManager.getPlayer(player); + final McMMOPlayer mmoPlayer = UserManager.getPlayer(player); - LogUtils.debug(mcMMO.p.getLogger(), "Recovering scoreboard for player: " + player.getName()); + LogUtils.debug(mcMMO.p.getLogger(), + "Recovering scoreboard for player: " + player.getName()); - if(mmoPlayer.isDebugMode()) - NotificationManager.sendPlayerInformationChatOnlyPrefixed(player, "Scoreboard.Recovery"); + if (mmoPlayer.isDebugMode()) { + NotificationManager.sendPlayerInformationChatOnlyPrefixed(player, + "Scoreboard.Recovery"); + } initBoard(); //Start over - mcMMO.p.getFoliaLib().getImpl().runAtEntity(player, t -> ScoreboardManager.retryLastSkillBoard(player)); + mcMMO.p.getFoliaLib().getScheduler() + .runAtEntity(player, t -> ScoreboardManager.retryLastSkillBoard(player)); } } //Register objective - McMMOScoreboardObjectiveEvent registerEvent = callObjectiveEvent(ScoreboardObjectiveEventReason.REGISTER_NEW_OBJECTIVE); - if(!registerEvent.isCancelled()) - sidebarObjective = registerEvent.getTargetBoard().registerNewObjective(ScoreboardManager.SIDEBAR_OBJECTIVE, "dummy", SIDE_OBJECTIVE); + McMMOScoreboardObjectiveEvent registerEvent = callObjectiveEvent( + ScoreboardObjectiveEventReason.REGISTER_NEW_OBJECTIVE); + if (!registerEvent.isCancelled()) { + sidebarObjective = registerEvent.getTargetBoard() + .registerNewObjective(ScoreboardManager.SIDEBAR_OBJECTIVE, "dummy", + SIDE_OBJECTIVE); + } if (displayName.length() > 32) { displayName = displayName.substring(0, 32); @@ -444,8 +460,10 @@ public class ScoreboardWrapper { sidebarObjective.setDisplaySlot(DisplaySlot.SIDEBAR); } - private McMMOScoreboardObjectiveEvent callObjectiveEvent(ScoreboardObjectiveEventReason reason) { - McMMOScoreboardObjectiveEvent event = new McMMOScoreboardObjectiveEvent(sidebarObjective, reason, scoreboard, scoreboard, player, ScoreboardEventReason.OBJECTIVE); + private McMMOScoreboardObjectiveEvent callObjectiveEvent( + ScoreboardObjectiveEventReason reason) { + McMMOScoreboardObjectiveEvent event = new McMMOScoreboardObjectiveEvent(sidebarObjective, + reason, scoreboard, scoreboard, player, ScoreboardEventReason.OBJECTIVE); player.getServer().getPluginManager().callEvent(event); return event; } @@ -454,7 +472,7 @@ public class ScoreboardWrapper { * Load new values into the sidebar. */ private void updateSidebar() { - if(updateTask != null) { + if (updateTask != null) { try { updateTask.cancel(); } catch (Exception e) { @@ -464,7 +482,6 @@ public class ScoreboardWrapper { updateTask = null; } - if (sidebarType == SidebarType.NONE) { return; } @@ -476,51 +493,64 @@ public class ScoreboardWrapper { return; } - McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player); + final McMMOPlayer mmoPlayer = UserManager.getPlayer(player); - if(mcMMOPlayer == null) + if (mmoPlayer == null) { return; + } switch (sidebarType) { case NONE: break; case SKILL_BOARD: - Validate.notNull(targetSkill); + requireNonNull(targetSkill); if (!SkillTools.isChildSkill(targetSkill)) { - int currentXP = mcMMOPlayer.getSkillXpLevel(targetSkill); + int currentXP = mmoPlayer.getSkillXpLevel(targetSkill); - sidebarObjective.getScore(ScoreboardManager.LABEL_CURRENT_XP).setScore(currentXP); - sidebarObjective.getScore(ScoreboardManager.LABEL_REMAINING_XP).setScore(mcMMOPlayer.getXpToLevel(targetSkill) - currentXP); - } - else { - for (PrimarySkillType parentSkill : FamilyTree.getParents(targetSkill)) { - sidebarObjective.getScore(ScoreboardManager.skillLabels.get(parentSkill)).setScore(mcMMOPlayer.getSkillLevel(parentSkill)); + sidebarObjective.getScore(ScoreboardManager.LABEL_CURRENT_XP) + .setScore(currentXP); + sidebarObjective.getScore(ScoreboardManager.LABEL_REMAINING_XP) + .setScore(mmoPlayer.getXpToLevel(targetSkill) - currentXP); + } else { + for (PrimarySkillType parentSkill : mcMMO.p.getSkillTools() + .getChildSkillParents(targetSkill)) { + sidebarObjective.getScore(ScoreboardManager.skillLabels.get(parentSkill)) + .setScore(mmoPlayer.getSkillLevel(parentSkill)); } } - sidebarObjective.getScore(ScoreboardManager.LABEL_LEVEL).setScore(mcMMOPlayer.getSkillLevel(targetSkill)); + sidebarObjective.getScore(ScoreboardManager.LABEL_LEVEL) + .setScore(mmoPlayer.getSkillLevel(targetSkill)); if (mcMMO.p.getSkillTools().getSuperAbility(targetSkill) != null) { boolean stopUpdating; if (targetSkill == PrimarySkillType.MINING) { // Special-Case: Mining has two abilities, both with cooldowns - Score cooldownSB = sidebarObjective.getScore(ScoreboardManager.abilityLabelsSkill.get(SuperAbilityType.SUPER_BREAKER)); - Score cooldownBM = sidebarObjective.getScore(ScoreboardManager.abilityLabelsSkill.get(SuperAbilityType.BLAST_MINING)); - int secondsSB = Math.max(mcMMOPlayer.calculateTimeRemaining(SuperAbilityType.SUPER_BREAKER), 0); - int secondsBM = Math.max(mcMMOPlayer.calculateTimeRemaining(SuperAbilityType.BLAST_MINING), 0); + Score cooldownSB = sidebarObjective.getScore( + ScoreboardManager.abilityLabelsSkill.get( + SuperAbilityType.SUPER_BREAKER)); + Score cooldownBM = sidebarObjective.getScore( + ScoreboardManager.abilityLabelsSkill.get( + SuperAbilityType.BLAST_MINING)); + int secondsSB = Math.max( + mmoPlayer.calculateTimeRemaining(SuperAbilityType.SUPER_BREAKER), + 0); + int secondsBM = Math.max( + mmoPlayer.calculateTimeRemaining(SuperAbilityType.BLAST_MINING), 0); cooldownSB.setScore(secondsSB); cooldownBM.setScore(secondsBM); stopUpdating = (secondsSB == 0 && secondsBM == 0); - } - else { - SuperAbilityType ability = mcMMO.p.getSkillTools().getSuperAbility(targetSkill); - Score cooldown = sidebarObjective.getScore(ScoreboardManager.abilityLabelsSkill.get(ability)); - int seconds = Math.max(mcMMOPlayer.calculateTimeRemaining(ability), 0); + } else { + SuperAbilityType ability = mcMMO.p.getSkillTools() + .getSuperAbility(targetSkill); + Score cooldown = sidebarObjective.getScore( + ScoreboardManager.abilityLabelsSkill.get(ability)); + int seconds = Math.max(mmoPlayer.calculateTimeRemaining(ability), 0); cooldown.setScore(seconds); @@ -529,8 +559,7 @@ public class ScoreboardWrapper { if (stopUpdating) { stopCooldownUpdating(); - } - else { + } else { startCooldownUpdating(); } } @@ -540,19 +569,19 @@ public class ScoreboardWrapper { boolean anyCooldownsActive = false; for (SuperAbilityType ability : SuperAbilityType.values()) { - int seconds = Math.max(mcMMOPlayer.calculateTimeRemaining(ability), 0); + int seconds = Math.max(mmoPlayer.calculateTimeRemaining(ability), 0); if (seconds != 0) { anyCooldownsActive = true; } - sidebarObjective.getScore(ScoreboardManager.abilityLabelsColored.get(ability)).setScore(seconds); + sidebarObjective.getScore(ScoreboardManager.abilityLabelsColored.get(ability)) + .setScore(seconds); } if (anyCooldownsActive) { startCooldownUpdating(); - } - else { + } else { stopCooldownUpdating(); } break; @@ -563,11 +592,9 @@ public class ScoreboardWrapper { if (targetProfile != null) { newProfile = targetProfile; // offline - } - else if (targetPlayer == null) { - newProfile = mcMMOPlayer.getProfile(); // self - } - else { + } else if (targetPlayer == null) { + newProfile = mmoPlayer.getProfile(); // self + } else { newProfile = UserManager.getPlayer(targetPlayer).getProfile(); // online } @@ -583,7 +610,8 @@ public class ScoreboardWrapper { continue; } - sidebarObjective.getScore(ScoreboardManager.skillLabels.get(skill)).setScore(level); + sidebarObjective.getScore(ScoreboardManager.skillLabels.get(skill)) + .setScore(level); } sidebarObjective.getScore(ScoreboardManager.LABEL_POWER_LEVEL).setScore(powerLevel); @@ -591,10 +619,10 @@ public class ScoreboardWrapper { case RANK_BOARD: case TOP_BOARD: - /* - * @see #acceptRankData(Map rank) - * @see #acceptLeaderboardData(List stats) - */ + /* + * @see #acceptRankData(Map rank) + * @see #acceptLeaderboardData(List stats) + */ break; default: @@ -627,13 +655,13 @@ public class ScoreboardWrapper { public void acceptLeaderboardData(@NotNull List leaderboardData) { for (PlayerStat stat : leaderboardData) { - String name = stat.name; + String name = stat.playerName(); if (name.equals(playerName)) { name = ChatColor.GOLD + "--You--"; } - sidebarObjective.getScore(name).setScore(stat.statVal); + sidebarObjective.getScore(name).setScore(stat.value()); } } 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 5f060f582..fc308689c 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java +++ b/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java @@ -1,5 +1,10 @@ package com.gmail.nossr50.util.skills; +import static com.gmail.nossr50.datatypes.experience.XPGainReason.PVP; +import static com.gmail.nossr50.util.AttributeMapper.MAPPED_MOVEMENT_SPEED; +import static com.gmail.nossr50.util.MobMetadataUtils.hasMobFlag; +import static com.gmail.nossr50.util.skills.ProjectileUtils.isCrossbowProjectile; + import com.gmail.nossr50.config.experience.ExperienceConfig; import com.gmail.nossr50.datatypes.experience.XPGainReason; import com.gmail.nossr50.datatypes.interactions.NotificationType; @@ -9,23 +14,39 @@ import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SubSkillType; 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; import com.gmail.nossr50.skills.axes.AxesManager; +import com.gmail.nossr50.skills.maces.MacesManager; 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.ItemUtils; +import com.gmail.nossr50.util.MetadataConstants; +import com.gmail.nossr50.util.Misc; +import com.gmail.nossr50.util.MobHealthbarUtils; +import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.player.NotificationManager; import com.gmail.nossr50.util.player.UserManager; +import java.util.List; import org.bukkit.GameMode; import org.bukkit.Material; -import org.bukkit.attribute.Attribute; import org.bukkit.attribute.AttributeInstance; -import org.bukkit.entity.*; +import org.bukkit.entity.AbstractArrow; +import org.bukkit.entity.AnimalTamer; +import org.bukkit.entity.Animals; +import org.bukkit.entity.ArmorStand; +import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.IronGolem; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Monster; +import org.bukkit.entity.Player; +import org.bukkit.entity.Tameable; +import org.bukkit.entity.Trident; +import org.bukkit.entity.Wolf; import org.bukkit.event.entity.EntityDamageByEntityEvent; import org.bukkit.event.entity.EntityDamageEvent.DamageCause; import org.bukkit.inventory.ItemStack; @@ -35,17 +56,54 @@ import org.bukkit.projectiles.ProjectileSource; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.List; - public final class CombatUtils { - private CombatUtils() {} + private static final ThreadLocal IN_MCMO_DAMAGE + = ThreadLocal.withInitial(() -> false); - private static @NotNull MobMetadataService getMobMetadataService() { - return mcMMO.getMetadataService().getMobMetadataService(); + + public static void safeDealDamage(@NotNull LivingEntity target, double amount) { + safeDealDamage(target, amount, null); } - //Likely.. because who knows what plugins are throwing around + /** + * Safely deals damage to a target entity, preventing recursive mcMMO damage calls. + * + * @param target The {@link LivingEntity} to damage. + * @param amount The amount of damage to deal. + * @param attacker The {@link Entity} responsible for the damage, or null if none. + */ + public static void safeDealDamage(@NotNull LivingEntity target, double amount, + @Nullable Entity attacker) { + boolean prev = IN_MCMO_DAMAGE.get(); + + if (prev || target.isDead()) { + return; + } + + try { + IN_MCMO_DAMAGE.set(true); + if (!hasIgnoreDamageMetadata(target)) { + applyIgnoreDamageMetadata(target); + } + + if (attacker != null) { + target.damage(amount, attacker); + } else { + target.damage(amount); + } + } finally { + IN_MCMO_DAMAGE.set(false); + if (hasIgnoreDamageMetadata(target)) { + removeIgnoreDamageMetadata(target); + } + } + } + + private CombatUtils() { + } + + @Deprecated(forRemoval = true, since = "2.2.039") public static boolean isDamageLikelyFromNormalCombat(@NotNull DamageCause damageCause) { return switch (damageCause) { case ENTITY_ATTACK, ENTITY_SWEEP_ATTACK, PROJECTILE -> true; @@ -53,95 +111,255 @@ public final class CombatUtils { }; } + @Deprecated(forRemoval = true, since = "2.2.039") public static boolean hasWeakenedDamage(@NotNull LivingEntity livingEntity) { return livingEntity.hasPotionEffect(PotionEffectType.WEAKNESS); } - private static void processSwordCombat(@NotNull LivingEntity target, @NotNull Player player, @NotNull EntityDamageByEntityEvent event) { + private static void processSwordCombat(@NotNull LivingEntity target, @NotNull Player player, + @NotNull EntityDamageByEntityEvent event) { if (event.getCause() == DamageCause.THORNS) { return; } - McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player); + final McMMOPlayer mmoPlayer = UserManager.getPlayer(player); //Make sure the profiles been loaded - if(mcMMOPlayer == null) { + if (mmoPlayer == null) { return; } - SwordsManager swordsManager = mcMMOPlayer.getSwordsManager(); + SwordsManager swordsManager = mmoPlayer.getSwordsManager(); double boostedDamage = event.getDamage(); if (swordsManager.canActivateAbility()) { - mcMMOPlayer.checkAbilityActivation(PrimarySkillType.SWORDS); - } - - if(target.getHealth() - event.getFinalDamage() > 0) { - swordsManager.processRupture(target); + mmoPlayer.checkAbilityActivation(PrimarySkillType.SWORDS); } //Add Stab Damage - if(swordsManager.canUseStab()) - { - boostedDamage += (swordsManager.getStabDamage() * mcMMOPlayer.getAttackStrength()); + if (swordsManager.canUseStab()) { + boostedDamage += (swordsManager.getStabDamage() * mmoPlayer.getAttackStrength()); } if (swordsManager.canUseSerratedStrike()) { swordsManager.serratedStrikes(target, event.getDamage()); } - if(canUseLimitBreak(player, target, SubSkillType.SWORDS_SWORDS_LIMIT_BREAK)) - { - boostedDamage += (getLimitBreakDamage(player, target, SubSkillType.SWORDS_SWORDS_LIMIT_BREAK) * mcMMOPlayer.getAttackStrength()); + if (canUseLimitBreak(player, target, SubSkillType.SWORDS_SWORDS_LIMIT_BREAK)) { + boostedDamage += (getLimitBreakDamage + (player, target, SubSkillType.SWORDS_SWORDS_LIMIT_BREAK) + * mmoPlayer.getAttackStrength()); } event.setDamage(boostedDamage); - processCombatXP(mcMMOPlayer, target, PrimarySkillType.SWORDS); - printFinalDamageDebug(player, event, mcMMOPlayer); + if (target.getHealth() - event.getFinalDamage() > 0) { + swordsManager.processRupture(target); + } + + processCombatXP(mmoPlayer, target, PrimarySkillType.SWORDS); + + printFinalDamageDebug(player, event, mmoPlayer); } - private static void printFinalDamageDebug(@NotNull Player player, @NotNull EntityDamageByEntityEvent event, @NotNull McMMOPlayer mcMMOPlayer, @Nullable String @Nullable ... extraInfoLines) { - if(mcMMOPlayer.isDebugMode()) { - player.sendMessage("Final Damage value after mcMMO modifiers: "+ event.getFinalDamage()); - if(extraInfoLines != null) { - for(String str : extraInfoLines) { - if(str != null) + private static void printFinalDamageDebug(@NotNull Player player, + @NotNull EntityDamageByEntityEvent event, + @NotNull McMMOPlayer mmoPlayer, + @Nullable String @Nullable ... extraInfoLines) { + if (mmoPlayer.isDebugMode()) { + player.sendMessage( + "Final Damage value after mcMMO modifiers: " + event.getFinalDamage()); + player.sendMessage("Your current attack strength: " + player.getAttackCooldown()); + if (extraInfoLines != null) { + for (String str : extraInfoLines) { + if (str != null) { player.sendMessage(str); + } } } } } - private static void processAxeCombat(@NotNull LivingEntity target, @NotNull Player player, @NotNull EntityDamageByEntityEvent event) { + private static void processTridentCombatMelee(@NotNull LivingEntity target, + @NotNull Player player, @NotNull EntityDamageByEntityEvent event) { if (event.getCause() == DamageCause.THORNS) { return; } double boostedDamage = event.getDamage(); - McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player); + final McMMOPlayer mmoPlayer = UserManager.getPlayer(player); //Make sure the profiles been loaded - if(mcMMOPlayer == null) { + if (mmoPlayer == null) { return; } - AxesManager axesManager = mcMMOPlayer.getAxesManager(); + final TridentsManager tridentsManager = mmoPlayer.getTridentsManager(); + +// if (tridentsManager.canActivateAbility()) { +// mmoPlayer.checkAbilityActivation(PrimarySkillType.TRIDENTS); +// } + + if (SkillUtils.canUseSubskill(player, SubSkillType.TRIDENTS_IMPALE)) { + boostedDamage += (tridentsManager.impaleDamageBonus() * mmoPlayer.getAttackStrength()); + } + + if (canUseLimitBreak(player, target, SubSkillType.TRIDENTS_TRIDENTS_LIMIT_BREAK)) { + boostedDamage += (getLimitBreakDamage( + player, target, SubSkillType.TRIDENTS_TRIDENTS_LIMIT_BREAK) + * mmoPlayer.getAttackStrength()); + } + + event.setDamage(boostedDamage); + processCombatXP(mmoPlayer, target, PrimarySkillType.TRIDENTS); + + printFinalDamageDebug(player, event, mmoPlayer); + } + + private static void processTridentCombatRanged(@NotNull Trident trident, + @NotNull LivingEntity target, + @NotNull Player player, + @NotNull EntityDamageByEntityEvent event) { + if (event.getCause() == DamageCause.THORNS) { + return; + } + + double boostedDamage = event.getDamage(); + + final McMMOPlayer mmoPlayer = UserManager.getPlayer(player); + + //Make sure the profiles been loaded + if (mmoPlayer == null) { + return; + } + + final TridentsManager tridentsManager = mmoPlayer.getTridentsManager(); + + if (SkillUtils.canUseSubskill(player, SubSkillType.TRIDENTS_IMPALE)) { + boostedDamage += (tridentsManager.impaleDamageBonus()); + } + + if (canUseLimitBreak(player, target, SubSkillType.TRIDENTS_TRIDENTS_LIMIT_BREAK)) { + boostedDamage += (getLimitBreakDamage(player, target, + SubSkillType.TRIDENTS_TRIDENTS_LIMIT_BREAK)); + } + + event.setDamage(boostedDamage); + processCombatXP(mmoPlayer, target, PrimarySkillType.TRIDENTS); + + printFinalDamageDebug(player, event, mmoPlayer); + } + + private static void processCrossbowsCombat(@NotNull LivingEntity target, @NotNull Player player, + @NotNull EntityDamageByEntityEvent event, @NotNull AbstractArrow arrow) { + double initialDamage = event.getDamage(); + + final McMMOPlayer mmoPlayer = UserManager.getPlayer(player); + + //Make sure the profiles been loaded + if (mmoPlayer == null) { + delayArrowMetaCleanup(arrow); + return; + } + + double boostedDamage = event.getDamage(); + + if (SkillUtils.canUseSubskill(player, SubSkillType.CROSSBOWS_POWERED_SHOT)) { + //Not Additive + boostedDamage = mmoPlayer.getCrossbowsManager().poweredShot(initialDamage); + } + + 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(mmoPlayer, target, PrimarySkillType.CROSSBOWS, + forceMultiplier * distanceMultiplier); + + printFinalDamageDebug(player, event, mmoPlayer, + "Distance Multiplier: " + distanceMultiplier, + "Force Multiplier: " + forceMultiplier, + "Initial Damage: " + initialDamage, + "Final Damage: " + boostedDamage); + + //Clean data + delayArrowMetaCleanup(arrow); + } + + private static void processMacesCombat(@NotNull LivingEntity target, + @NotNull Player player, + @NotNull EntityDamageByEntityEvent event) { + if (event.getCause() == DamageCause.THORNS) { + return; + } + + double boostedDamage = event.getDamage(); + + final McMMOPlayer mmoPlayer = UserManager.getPlayer(player); + + //Make sure the profiles been loaded + if (mmoPlayer == null) { + return; + } + + final MacesManager macesManager = mmoPlayer.getMacesManager(); + + // Apply Limit Break DMG + if (canUseLimitBreak(player, target, SubSkillType.MACES_MACES_LIMIT_BREAK)) { + boostedDamage += (getLimitBreakDamage( + player, target, SubSkillType.MACES_MACES_LIMIT_BREAK) + * mmoPlayer.getAttackStrength()); + } + + // Apply Crush DMG + boostedDamage += (macesManager.getCrushDamage() * mmoPlayer.getAttackStrength()); + + event.setDamage(boostedDamage); + + // Apply Cripple + if (target.getHealth() - event.getFinalDamage() > 0) { + macesManager.processCripple(target); + } + + processCombatXP(mmoPlayer, target, PrimarySkillType.MACES); + printFinalDamageDebug(player, event, mmoPlayer); + } + + private static void processAxeCombat(@NotNull LivingEntity target, @NotNull Player player, + @NotNull EntityDamageByEntityEvent event) { + if (event.getCause() == DamageCause.THORNS) { + return; + } + + double boostedDamage = event.getDamage(); + + final McMMOPlayer mmoPlayer = UserManager.getPlayer(player); + + //Make sure the profiles been loaded + if (mmoPlayer == null) { + return; + } + + final AxesManager axesManager = mmoPlayer.getAxesManager(); if (axesManager.canActivateAbility()) { - mcMMOPlayer.checkAbilityActivation(PrimarySkillType.AXES); + mmoPlayer.checkAbilityActivation(PrimarySkillType.AXES); } if (axesManager.canUseAxeMastery()) { - boostedDamage+=axesManager.axeMastery(); + boostedDamage += axesManager.axeMastery() * mmoPlayer.getAttackStrength(); } if (axesManager.canImpact(target)) { axesManager.impactCheck(target); - } - else if (axesManager.canGreaterImpact(target)) { - boostedDamage+=axesManager.greaterImpact(target); + } else if (axesManager.canGreaterImpact(target)) { + boostedDamage += axesManager.greaterImpact(target) * mmoPlayer.getAttackStrength(); } if (axesManager.canUseSkullSplitter(target)) { @@ -149,76 +367,83 @@ public final class CombatUtils { } if (axesManager.canCriticalHit(target)) { - boostedDamage+=(axesManager.criticalHit(target, boostedDamage) * mcMMOPlayer.getAttackStrength()); + boostedDamage += (axesManager.criticalHit(target, boostedDamage) + * mmoPlayer.getAttackStrength()); } - if(canUseLimitBreak(player, target, SubSkillType.AXES_AXES_LIMIT_BREAK)) - { - boostedDamage+=(getLimitBreakDamage(player, target, SubSkillType.AXES_AXES_LIMIT_BREAK) * mcMMOPlayer.getAttackStrength()); + if (canUseLimitBreak(player, target, SubSkillType.AXES_AXES_LIMIT_BREAK)) { + boostedDamage += ( + getLimitBreakDamage(player, target, SubSkillType.AXES_AXES_LIMIT_BREAK) + * mmoPlayer.getAttackStrength()); } event.setDamage(boostedDamage); - processCombatXP(mcMMOPlayer, target, PrimarySkillType.AXES); + processCombatXP(mmoPlayer, target, PrimarySkillType.AXES); - printFinalDamageDebug(player, event, mcMMOPlayer); + printFinalDamageDebug(player, event, mmoPlayer); } - private static void processUnarmedCombat(@NotNull LivingEntity target, @NotNull Player player, @NotNull EntityDamageByEntityEvent event) { + private static void processUnarmedCombat(@NotNull LivingEntity target, @NotNull Player player, + @NotNull EntityDamageByEntityEvent event) { if (event.getCause() == DamageCause.THORNS) { return; } double boostedDamage = event.getDamage(); - McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player); + final McMMOPlayer mmoPlayer = UserManager.getPlayer(player); //Make sure the profiles been loaded - if(mcMMOPlayer == null) { + if (mmoPlayer == null) { return; } - UnarmedManager unarmedManager = mcMMOPlayer.getUnarmedManager(); + final UnarmedManager unarmedManager = mmoPlayer.getUnarmedManager(); if (unarmedManager.canActivateAbility()) { - mcMMOPlayer.checkAbilityActivation(PrimarySkillType.UNARMED); + mmoPlayer.checkAbilityActivation(PrimarySkillType.UNARMED); } if (unarmedManager.canUseSteelArm()) { - boostedDamage+=(unarmedManager.calculateSteelArmStyleDamage() * mcMMOPlayer.getAttackStrength()); + boostedDamage += (unarmedManager.calculateSteelArmStyleDamage() + * mmoPlayer.getAttackStrength()); } if (unarmedManager.canUseBerserk()) { - boostedDamage+=(unarmedManager.berserkDamage(boostedDamage) * mcMMOPlayer.getAttackStrength()); + boostedDamage += (unarmedManager.berserkDamage(boostedDamage) + * mmoPlayer.getAttackStrength()); } if (unarmedManager.canDisarm(target)) { unarmedManager.disarmCheck((Player) target); } - if(canUseLimitBreak(player, target, SubSkillType.UNARMED_UNARMED_LIMIT_BREAK)) - { - boostedDamage+=(getLimitBreakDamage(player, target, SubSkillType.UNARMED_UNARMED_LIMIT_BREAK) * mcMMOPlayer.getAttackStrength()); + if (canUseLimitBreak(player, target, SubSkillType.UNARMED_UNARMED_LIMIT_BREAK)) { + boostedDamage += (getLimitBreakDamage( + player, target, SubSkillType.UNARMED_UNARMED_LIMIT_BREAK) + * mmoPlayer.getAttackStrength()); } event.setDamage(boostedDamage); - processCombatXP(mcMMOPlayer, target, PrimarySkillType.UNARMED); + processCombatXP(mmoPlayer, target, PrimarySkillType.UNARMED); - printFinalDamageDebug(player, event, mcMMOPlayer); + printFinalDamageDebug(player, event, mmoPlayer); } - private static void processTamingCombat(@NotNull LivingEntity target, @Nullable Player master, @NotNull Wolf wolf, @NotNull EntityDamageByEntityEvent event) { + private static void processTamingCombat(@NotNull LivingEntity target, @Nullable Player master, + @NotNull Wolf wolf, @NotNull EntityDamageByEntityEvent event) { double initialDamage = event.getDamage(); double boostedDamage = initialDamage; - if(master != null && master.isOnline() && master.isValid()) { - McMMOPlayer mcMMOPlayer = UserManager.getPlayer(master); + if (master != null && master.isOnline() && master.isValid()) { + final McMMOPlayer mmoPlayer = UserManager.getPlayer(master); //Make sure the profiles been loaded - if(mcMMOPlayer == null) { + if (mmoPlayer == null) { return; } - TamingManager tamingManager = mcMMOPlayer.getTamingManager(); + final TamingManager tamingManager = mmoPlayer.getTamingManager(); if (tamingManager.canUseFastFoodService()) { tamingManager.fastFoodService(wolf, event.getDamage()); @@ -227,32 +452,33 @@ public final class CombatUtils { tamingManager.pummel(target, wolf); if (tamingManager.canUseSharpenedClaws()) { - boostedDamage+=tamingManager.sharpenedClaws(); + boostedDamage += tamingManager.sharpenedClaws(); } if (tamingManager.canUseGore()) { - boostedDamage+=tamingManager.gore(target, initialDamage); + boostedDamage += tamingManager.gore(target, initialDamage); } event.setDamage(boostedDamage); - processCombatXP(mcMMOPlayer, target, PrimarySkillType.TAMING, 3); + processCombatXP(mmoPlayer, target, PrimarySkillType.TAMING, 3); } } - 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 AbstractArrow arrow) { double initialDamage = event.getDamage(); - McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player); + final McMMOPlayer mmoPlayer = UserManager.getPlayer(player); //Make sure the profiles been loaded - if(mcMMOPlayer == null) { - cleanupArrowMetadata(arrow); + if (mmoPlayer == null) { + delayArrowMetaCleanup(arrow); return; } - ArcheryManager archeryManager = mcMMOPlayer.getArcheryManager(); - + final ArcheryManager archeryManager = mmoPlayer.getArcheryManager(); + double boostedDamage = event.getDamage(); if (archeryManager.canSkillShot()) { @@ -261,34 +487,39 @@ public final class CombatUtils { } if (archeryManager.canDaze(target)) { - boostedDamage+=archeryManager.daze((Player) target); //the cast is checked by the if condition + boostedDamage += archeryManager.daze( + (Player) target); //the cast is checked by the if condition } - if (!arrow.hasMetadata(MetadataConstants.METADATA_KEY_INF_ARROW) && archeryManager.canRetrieveArrows()) { + if (!arrow.hasMetadata(MetadataConstants.METADATA_KEY_INF_ARROW) + && archeryManager.canRetrieveArrows()) { archeryManager.retrieveArrows(target, arrow); } - if(canUseLimitBreak(player, target, SubSkillType.ARCHERY_ARCHERY_LIMIT_BREAK)) - { - boostedDamage+=getLimitBreakDamage(player, target, SubSkillType.ARCHERY_ARCHERY_LIMIT_BREAK); + if (canUseLimitBreak(player, target, SubSkillType.ARCHERY_ARCHERY_LIMIT_BREAK)) { + 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)) - forceMultiplier = arrow.getMetadata(MetadataConstants.METADATA_KEY_BOW_FORCE).get(0).asDouble(); + if (arrow.hasMetadata(MetadataConstants.METADATA_KEY_BOW_FORCE)) { + forceMultiplier = arrow.getMetadata(MetadataConstants.METADATA_KEY_BOW_FORCE).get(0) + .asDouble(); + } event.setDamage(boostedDamage); - processCombatXP(mcMMOPlayer, target, PrimarySkillType.ARCHERY, forceMultiplier * distanceMultiplier); + processCombatXP(mmoPlayer, target, PrimarySkillType.ARCHERY, + forceMultiplier * distanceMultiplier); - printFinalDamageDebug(player, event, mcMMOPlayer, - "Distance Multiplier: "+distanceMultiplier, - "Force Multiplier: "+forceMultiplier, - "Initial Damage: "+initialDamage, - "Final Damage: "+boostedDamage); + printFinalDamageDebug(player, event, mmoPlayer, + "Distance Multiplier: " + distanceMultiplier, + "Force Multiplier: " + forceMultiplier, + "Initial Damage: " + initialDamage, + "Final Damage: " + boostedDamage); //Clean data - cleanupArrowMetadata(arrow); + delayArrowMetaCleanup(arrow); } /** @@ -296,12 +527,18 @@ public final class CombatUtils { * * @param event The event to run the combat checks on. */ - public static void processCombatAttack(@NotNull EntityDamageByEntityEvent event, @NotNull Entity painSourceRoot, @NotNull LivingEntity target) { + public static void processCombatAttack(@NotNull EntityDamageByEntityEvent event, + @NotNull Entity painSourceRoot, + @NotNull LivingEntity target) { Entity painSource = event.getDamager(); EntityType entityType = painSource.getType(); + if (target instanceof ArmorStand) { + return; + } + if (target instanceof Player player) { - if(ExperienceConfig.getInstance().isNPCInteractionPrevented()) { + if (ExperienceConfig.getInstance().isNPCInteractionPrevented()) { if (Misc.isNPCEntityExcludingVillagers(target)) { return; } @@ -311,19 +548,20 @@ public final class CombatUtils { return; } - McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player); - AcrobaticsManager acrobaticsManager = mcMMOPlayer.getAcrobaticsManager(); + final McMMOPlayer mmoPlayer = UserManager.getPlayer(player); + final AcrobaticsManager acrobaticsManager = mmoPlayer.getAcrobaticsManager(); if (acrobaticsManager.canDodge(target)) { event.setDamage(acrobaticsManager.dodgeCheck(painSourceRoot, event.getDamage())); } if (ItemUtils.isSword(player.getInventory().getItemInMainHand())) { - if (!mcMMO.p.getSkillTools().canCombatSkillsTrigger(PrimarySkillType.SWORDS, target)) { + if (!mcMMO.p.getSkillTools() + .canCombatSkillsTrigger(PrimarySkillType.SWORDS, target)) { return; } - SwordsManager swordsManager = mcMMOPlayer.getSwordsManager(); + final SwordsManager swordsManager = mmoPlayer.getSwordsManager(); if (swordsManager.canUseCounterAttack(painSource)) { swordsManager.counterAttackChecks((LivingEntity) painSource, event.getDamage()); @@ -332,7 +570,6 @@ public final class CombatUtils { } if (painSourceRoot instanceof Player player && entityType == EntityType.PLAYER) { - if (!UserManager.hasPlayerDataKey(player)) { return; } @@ -356,83 +593,125 @@ public final class CombatUtils { } if (ItemUtils.isSword(heldItem)) { - if (!mcMMO.p.getSkillTools().canCombatSkillsTrigger(PrimarySkillType.SWORDS, target)) { + if (!mcMMO.p.getSkillTools() + .canCombatSkillsTrigger(PrimarySkillType.SWORDS, target)) { return; } - if (mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, PrimarySkillType.SWORDS)) { + if (mcMMO.p.getSkillTools() + .doesPlayerHaveSkillPermission(player, PrimarySkillType.SWORDS)) { processSwordCombat(target, player, event); - } - } - else if (ItemUtils.isAxe(heldItem)) { - if (!mcMMO.p.getSkillTools().canCombatSkillsTrigger(PrimarySkillType.AXES, target)) { + } else if (ItemUtils.isAxe(heldItem)) { + if (!mcMMO.p.getSkillTools() + .canCombatSkillsTrigger(PrimarySkillType.AXES, target)) { return; } - if (mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, PrimarySkillType.AXES)) { + if (mcMMO.p.getSkillTools() + .doesPlayerHaveSkillPermission(player, PrimarySkillType.AXES)) { processAxeCombat(target, player, event); } - } - else if (ItemUtils.isUnarmed(heldItem)) { - if (!mcMMO.p.getSkillTools().canCombatSkillsTrigger(PrimarySkillType.UNARMED, target)) { + } else if (ItemUtils.isUnarmed(heldItem)) { + if (!mcMMO.p.getSkillTools() + .canCombatSkillsTrigger(PrimarySkillType.UNARMED, target)) { return; } - if (mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, PrimarySkillType.UNARMED)) { + if (mcMMO.p.getSkillTools() + .doesPlayerHaveSkillPermission(player, PrimarySkillType.UNARMED)) { processUnarmedCombat(target, player, event); } - } - } + } else if (ItemUtils.isTrident(heldItem)) { + if (!mcMMO.p.getSkillTools() + .canCombatSkillsTrigger(PrimarySkillType.TRIDENTS, target)) { + return; + } - else if (entityType == EntityType.WOLF) { + if (mcMMO.p.getSkillTools() + .doesPlayerHaveSkillPermission(player, PrimarySkillType.TRIDENTS)) { + processTridentCombatMelee(target, player, event); + } + } else if (ItemUtils.isMace(heldItem)) { + if (!mcMMO.p.getSkillTools() + .canCombatSkillsTrigger(PrimarySkillType.MACES, target)) { + return; + } + + if (mcMMO.p.getSkillTools() + .doesPlayerHaveSkillPermission(player, PrimarySkillType.MACES)) { + processMacesCombat(target, player, event); + } + } + } else if (entityType == EntityType.WOLF) { Wolf wolf = (Wolf) painSource; AnimalTamer tamer = wolf.getOwner(); - if (tamer instanceof Player master && mcMMO.p.getSkillTools().canCombatSkillsTrigger(PrimarySkillType.TAMING, target)) { + if (tamer instanceof Player master && mcMMO.p.getSkillTools() + .canCombatSkillsTrigger(PrimarySkillType.TAMING, target)) { - if (!Misc.isNPCEntityExcludingVillagers(master) && mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(master, PrimarySkillType.TAMING)) { + if (!Misc.isNPCEntityExcludingVillagers(master) && mcMMO.p.getSkillTools() + .doesPlayerHaveSkillPermission(master, PrimarySkillType.TAMING)) { processTamingCombat(target, master, wolf, event); } } - } - else if (entityType == EntityType.ARROW || entityType == EntityType.SPECTRAL_ARROW) { - Projectile arrow = (Projectile) painSource; + } else if (painSource instanceof Trident trident) { + ProjectileSource projectileSource = trident.getShooter(); + + if (projectileSource instanceof Player player) { + if (!Misc.isNPCEntityExcludingVillagers(player)) { + if (mcMMO.p.getSkillTools() + .canCombatSkillsTrigger(PrimarySkillType.TRIDENTS, target)) { + processTridentCombatRanged(trident, target, player, event); + } + } + } + } else if (painSource instanceof AbstractArrow arrow) { ProjectileSource projectileSource = arrow.getShooter(); - - if (projectileSource instanceof Player player && mcMMO.p.getSkillTools().canCombatSkillsTrigger(PrimarySkillType.ARCHERY, target)) { - - if (!Misc.isNPCEntityExcludingVillagers(player) && mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, PrimarySkillType.ARCHERY)) { - processArcheryCombat(target, player, event, arrow); + boolean isCrossbow = isCrossbowProjectile(arrow); + if (projectileSource instanceof Player player) { + if (!Misc.isNPCEntityExcludingVillagers(player)) { + if (!isCrossbow && mcMMO.p.getSkillTools() + .canCombatSkillsTrigger(PrimarySkillType.ARCHERY, target)) { + processArcheryCombat(target, player, event, arrow); + } else if (isCrossbow && mcMMO.p.getSkillTools() + .canCombatSkillsTrigger(PrimarySkillType.CROSSBOWS, target)) { + processCrossbowsCombat(target, player, event, arrow); + } } else { //Cleanup Arrow - cleanupArrowMetadata(arrow); + delayArrowMetaCleanup(arrow); } - if (target.getType() != EntityType.CREEPER && !Misc.isNPCEntityExcludingVillagers(player) && mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, PrimarySkillType.TAMING)) { - McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player); + if (target.getType() != EntityType.CREEPER + && !Misc.isNPCEntityExcludingVillagers(player) + && mcMMO.p.getSkillTools() + .doesPlayerHaveSkillPermission(player, PrimarySkillType.TAMING)) { + final McMMOPlayer mmoPlayer = UserManager.getPlayer(player); - if(mcMMOPlayer == null) + if (mmoPlayer == null) { return; + } - TamingManager tamingManager = mcMMOPlayer.getTamingManager(); + TamingManager tamingManager = mmoPlayer.getTamingManager(); tamingManager.attackTarget(target); } } } - } /** * This cleans up names from displaying in chat as hearts + * * @param entity target entity */ - public static void fixNames(@NotNull LivingEntity entity) - { - List metadataValue = entity.getMetadata(MetadataConstants.METADATA_KEY_OLD_NAME_KEY); + public static void fixNames(@NotNull LivingEntity entity) { + List metadataValue = entity.getMetadata( + MetadataConstants.METADATA_KEY_OLD_NAME_KEY); - if(metadataValue.size() <= 0) + if (metadataValue.size() <= 0) { return; + } OldName oldName = (OldName) metadataValue.get(0); entity.setCustomName(oldName.asString()); @@ -443,51 +722,58 @@ public final class CombatUtils { /** * Calculate and return the RAW damage bonus from Limit Break before reductions + * * @param attacker attacking player * @param defender defending living entity * @param subSkillType the specific limit break skill for calculations * @return the RAW damage bonus from Limit Break which is applied before reductions */ - public static int getLimitBreakDamage(@NotNull Player attacker, @NotNull LivingEntity defender, @NotNull SubSkillType subSkillType) { - if(defender instanceof Player playerDefender) { - return getLimitBreakDamageAgainstQuality(attacker, subSkillType, getArmorQualityLevel(playerDefender)); + public static int getLimitBreakDamage(@NotNull Player attacker, @NotNull LivingEntity defender, + @NotNull SubSkillType subSkillType) { + if (defender instanceof Player playerDefender) { + return getLimitBreakDamageAgainstQuality(attacker, subSkillType, + getArmorQualityLevel(playerDefender)); } else { return getLimitBreakDamageAgainstQuality(attacker, subSkillType, 1000); } } /** - * Calculate the RAW daamge value of limit break based on the armor quality of the target - * PVE mobs are passed in with a value of 1000 for armor quality, hacky... I'll change it later + * Calculate the RAW daamge value of limit break based on the armor quality of the target PVE + * mobs are passed in with a value of 1000 for armor quality, hacky... I'll change it later + * * @param attacker Living entity attacker * @param subSkillType Target limit break * @param armorQualityLevel Armor quality level * @return the RAW damage boost after its been mutated by armor quality */ - public static int getLimitBreakDamageAgainstQuality(@NotNull Player attacker, @NotNull SubSkillType subSkillType, int armorQualityLevel) { - int rawDamageBoost = RankUtils.getRank(attacker, subSkillType); + public static int getLimitBreakDamageAgainstQuality(@NotNull Player attacker, + @NotNull SubSkillType subSkillType, + int armorQualityLevel) { + float rawDamageBoost = RankUtils.getRank(attacker, subSkillType); - if(armorQualityLevel <= 4) { - rawDamageBoost *= .25; //75% Nerf - } else if(armorQualityLevel <= 8) { - rawDamageBoost *= .50; //50% Nerf - } else if(armorQualityLevel <= 12) { - rawDamageBoost *= .75; //25% Nerf + if (armorQualityLevel <= 4) { + rawDamageBoost *= .25F; //75% Nerf + } else if (armorQualityLevel <= 8) { + rawDamageBoost *= .50F; //50% Nerf + } else if (armorQualityLevel <= 12) { + rawDamageBoost *= .75F; //25% Nerf } - return rawDamageBoost; + return (int) rawDamageBoost; } /** * Get the quality level of the armor of a player used for Limit Break calculations + * * @param defender target defending player * @return the armor quality of the defending player */ public static int getArmorQualityLevel(@NotNull Player defender) { int armorQualityLevel = 0; - for(ItemStack itemStack : defender.getInventory().getArmorContents()) { - if(itemStack != null) { + for (ItemStack itemStack : defender.getInventory().getArmorContents()) { + if (itemStack != null) { armorQualityLevel += getArmorQuality(itemStack); } } @@ -497,6 +783,7 @@ public final class CombatUtils { /** * Get the armor quality for a specific item used for Limit Break calculations + * * @param itemStack target item stack * @return the armor quality of a specific Item Stack */ @@ -506,11 +793,13 @@ public final class CombatUtils { /** * Checks if player has access to their weapons limit break + * * @param player target entity * @return true if the player has access to the limit break */ - public static boolean canUseLimitBreak(@NotNull Player player, LivingEntity target, @NotNull SubSkillType subSkillType) { - if(target instanceof Player || mcMMO.p.getAdvancedConfig().canApplyLimitBreakPVE()) { + public static boolean canUseLimitBreak(@NotNull Player player, LivingEntity target, + @NotNull SubSkillType subSkillType) { + if (target instanceof Player || mcMMO.p.getAdvancedConfig().canApplyLimitBreakPVE()) { return RankUtils.hasUnlockedSubskill(player, subSkillType) && Permissions.isSubSkillEnabled(player, subSkillType); } else { @@ -523,93 +812,25 @@ public final class CombatUtils { * * @param target LivingEntity which to attempt to damage * @param damage Amount of damage to attempt to do + * @deprecated use {@link #safeDealDamage(LivingEntity, double, Entity)} instead */ + @Deprecated(since = "2.2.039") public static void dealDamage(@NotNull LivingEntity target, double damage) { - dealDamage(target, damage, DamageCause.CUSTOM, null); + safeDealDamage(target, damage, null); } /** * Attempt to damage target for value dmg with reason ENTITY_ATTACK with damager attacker * - * @param target LivingEntity which to attempt to damage + * @param target the entity to attempt to damage * @param damage Amount of damage to attempt to do - * @param attacker Player to pass to event as damager + * @param attacker the responsible entity (nullable) + * @deprecated use {@link #safeDealDamage(LivingEntity, double, Entity)} instead */ - @Deprecated - public static void dealDamage(@NotNull LivingEntity target, double damage, @NotNull LivingEntity attacker) { - dealDamage(target, damage, DamageCause.CUSTOM, attacker); - } - -// /** -// * Attempt to damage target for value dmg with reason ENTITY_ATTACK with damager attacker -// * -// * @param target LivingEntity which to attempt to damage -// * @param damage Amount of damage to attempt to do -// * @param attacker Player to pass to event as damager -// */ -// public static void dealDamage(LivingEntity target, double damage, Map modifiers, LivingEntity attacker) { -// if (target.isDead()) { -// return; -// } -// -// // Aren't we applying the damage twice???? -// target.damage(getFakeDamageFinalResult(attacker, target, damage, modifiers)); -// } - - /** - * Attempt to damage target for value dmg with reason ENTITY_ATTACK with damager attacker - * - * @param target LivingEntity which to attempt to damage - * @param damage Amount of damage to attempt to do - * @param attacker Player to pass to event as damager - */ - @Deprecated - public static void dealDamage(@NotNull LivingEntity target, double damage, @NotNull DamageCause cause, @Nullable Entity attacker) { - if (target.isDead()) { - return; - } - try { - // TODO: Check for Spigot API for DamageSource, if DamageSource is found then send out a damage() with a custom damage source - applyIgnoreDamageMetadata(target); - if (attacker != null) { - target.damage(damage, attacker); - } else { - target.damage(damage); - } - } finally { - removeIgnoreDamageMetadata(target); - } - } - - private static boolean processingNoInvulnDamage; - public static boolean isProcessingNoInvulnDamage() { - return processingNoInvulnDamage; - } - - public static void dealNoInvulnerabilityTickDamage(@NotNull LivingEntity target, double damage, @Nullable Entity attacker) { - if (target.isDead()) { - return; - } - - // TODO: This is horrible, but there is no cleaner way to do this without potentially breaking existing code right now - // calling damage here is a double edged sword: On one hand, without a call, plugins won't see this properly when the entity dies, - // potentially mis-attributing the death cause; calling a fake event would partially fix this, but this and setting the last damage - // cause do have issues around plugin observability. This is not a perfect solution, but it appears to be the best one here - // We also set no damage ticks to 0, to ensure that damage is applied for this case, and reset it back to the original value - // Snapshot current state so we can pop up properly - boolean wasMetaSet = hasIgnoreDamageMetadata(target); - boolean wasProcessing = processingNoInvulnDamage; - // set markers - processingNoInvulnDamage = true; - applyIgnoreDamageMetadata(target); - int noDamageTicks = target.getNoDamageTicks(); - target.setNoDamageTicks(0); - target.damage(damage, attacker); - target.setNoDamageTicks(noDamageTicks); - if (!wasMetaSet) - removeIgnoreDamageMetadata(target); - if (!wasProcessing) - processingNoInvulnDamage = false; + @Deprecated(since = "2.2.039") + public static void dealDamage(@NotNull LivingEntity target, double damage, + @Nullable Entity attacker) { + safeDealDamage(target, damage, attacker); } public static void removeIgnoreDamageMetadata(@NotNull LivingEntity target) { @@ -617,59 +838,26 @@ public final class CombatUtils { } public static void applyIgnoreDamageMetadata(@NotNull LivingEntity target) { - target.setMetadata(MetadataConstants.METADATA_KEY_CUSTOM_DAMAGE, MetadataConstants.MCMMO_METADATA_VALUE); + target.setMetadata(MetadataConstants.METADATA_KEY_CUSTOM_DAMAGE, + MetadataConstants.MCMMO_METADATA_VALUE); } public static boolean hasIgnoreDamageMetadata(@NotNull LivingEntity target) { - return target.getMetadata(MetadataConstants.METADATA_KEY_CUSTOM_DAMAGE).size() != 0; - } - - public static void dealNoInvulnerabilityTickDamageRupture(@NotNull LivingEntity target, double damage, Entity attacker, int toolTier) { - if (target.isDead()) { - return; - } - - 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); -// } + return target.hasMetadata(MetadataConstants.METADATA_KEY_CUSTOM_DAMAGE); } /** * Apply Area-of-Effect ability actions. - * @param attacker The attacking player + * + * @param attacker The attacking player * @param target The defending entity * @param damage The initial damage amount * @param type The type of skill being used */ - public static void applyAbilityAoE(@NotNull Player attacker, @NotNull LivingEntity target, double damage, @NotNull PrimarySkillType type) { - int numberOfTargets = getTier(attacker.getInventory().getItemInMainHand()); // The higher the weapon tier, the more targets you hit + public static void applyAbilityAoE(@NotNull Player attacker, @NotNull LivingEntity target, + double damage, @NotNull PrimarySkillType type) { + int numberOfTargets = getTier(attacker.getInventory() + .getItemInMainHand()); // The higher the weapon tier, the more targets you hit double damageAmount = Math.max(damage, 1); for (Entity entity : target.getNearbyEntities(2.5, 2.5, 2.5)) { @@ -677,8 +865,10 @@ public final class CombatUtils { break; } - if ((ExperienceConfig.getInstance().isNPCInteractionPrevented() && Misc.isNPCEntityExcludingVillagers(entity)) - || !(entity instanceof LivingEntity livingEntity) || !shouldBeAffected(attacker, entity)) { + if ((ExperienceConfig.getInstance().isNPCInteractionPrevented() + && Misc.isNPCEntityExcludingVillagers(entity)) + || !(entity instanceof LivingEntity livingEntity) || !shouldBeAffected(attacker, + entity)) { continue; } @@ -687,12 +877,14 @@ public final class CombatUtils { switch (type) { case SWORDS: if (entity instanceof Player) { - NotificationManager.sendPlayerInformation((Player)entity, NotificationType.SUBSKILL_MESSAGE, "Swords.Combat.SS.Struck"); + NotificationManager.sendPlayerInformation((Player) entity, + NotificationType.SUBSKILL_MESSAGE, + "Swords.Combat.SS.Struck"); } - McMMOPlayer mmoAttacker = UserManager.getPlayer(attacker); + final McMMOPlayer mmoAttacker = UserManager.getPlayer(attacker); - if(mmoAttacker != null) { + if (mmoAttacker != null) { mmoAttacker.getSwordsManager().processRupture(livingEntity); } @@ -700,16 +892,17 @@ public final class CombatUtils { case AXES: if (entity instanceof Player) { - NotificationManager.sendPlayerInformation((Player)entity, NotificationType.SUBSKILL_MESSAGE, "Axes.Combat.SS.Struck"); + NotificationManager.sendPlayerInformation((Player) entity, + NotificationType.SUBSKILL_MESSAGE, + "Axes.Combat.SS.Struck"); } - break; default: break; } - dealDamage(livingEntity, damageAmount, attacker); + safeDealDamage(livingEntity, damageAmount, attacker); numberOfTargets--; } } @@ -717,86 +910,81 @@ public final class CombatUtils { /** * Start the task that gives combat XP. * - * @param mcMMOPlayer The attacking player + * @param mmoPlayer The attacking player * @param target The defending entity * @param primarySkillType The skill being used */ - public static void processCombatXP(@NotNull McMMOPlayer mcMMOPlayer, @NotNull LivingEntity target, @NotNull PrimarySkillType primarySkillType) { - processCombatXP(mcMMOPlayer, target, primarySkillType, 1.0); + public static void processCombatXP(@NotNull McMMOPlayer mmoPlayer, @NotNull LivingEntity target, + @NotNull PrimarySkillType primarySkillType) { + processCombatXP(mmoPlayer, target, primarySkillType, 1.0); } /** * Start the task that gives combat XP. * - * @param mcMMOPlayer The attacking player + * @param mmoPlayer The attacking player * @param target The defending entity * @param primarySkillType The skill being used * @param multiplier final XP result will be multiplied by this */ - public static void processCombatXP(@NotNull McMMOPlayer mcMMOPlayer, - @NotNull LivingEntity target, - @NotNull PrimarySkillType primarySkillType, - double multiplier) { + public static void processCombatXP(@NotNull McMMOPlayer mmoPlayer, + @NotNull LivingEntity target, + @NotNull PrimarySkillType primarySkillType, + double multiplier) { double baseXP = 0; XPGainReason xpGainReason; if (target instanceof Player defender) { - if (!ExperienceConfig.getInstance().getExperienceGainsPlayerVersusPlayerEnabled() || PartyManager.inSameParty(mcMMOPlayer.getPlayer(), (Player) target)) { + if (!ExperienceConfig.getInstance().getExperienceGainsPlayerVersusPlayerEnabled() + || + (mcMMO.p.getPartyConfig().isPartyEnabled() + && mcMMO.p.getPartyManager() + .inSameParty(mmoPlayer.getPlayer(), defender))) { return; } - xpGainReason = XPGainReason.PVP; + xpGainReason = PVP; - if (defender.isOnline() && SkillUtils.cooldownExpired(mcMMOPlayer.getRespawnATS(), Misc.PLAYER_RESPAWN_COOLDOWN_SECONDS)) { + if (defender.isOnline() + && SkillUtils.cooldownExpired(mmoPlayer.getRespawnATS(), + Misc.PLAYER_RESPAWN_COOLDOWN_SECONDS)) { baseXP = 20 * ExperienceConfig.getInstance().getPlayerVersusPlayerXP(); } - } - else { - if (mcMMO.getModManager().isCustomEntity(target)) { - baseXP = mcMMO.getModManager().getEntity(target).getXpMultiplier(); - } - else if (target instanceof Animals) { + } 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); - } - else { + } else { EntityType type = target.getType(); if (ExperienceConfig.getInstance().hasCombatXP(type)) { - if (type == EntityType.IRON_GOLEM) - { - if (!((IronGolem) target).isPlayerCreated()) { + if (type == EntityType.IRON_GOLEM && target instanceof IronGolem ironGolem) { + if (!ironGolem.isPlayerCreated()) { baseXP = ExperienceConfig.getInstance().getCombatXP(type); } - } - else - { + } else { baseXP = ExperienceConfig.getInstance().getCombatXP(type); } - } - else - { + } else { baseXP = 1.0; - mcMMO.getModManager().addCustomEntity(target); } } - if(getMobMetadataService().hasMobFlag(MobMetaFlagType.COTW_SUMMONED_MOB, target)) { + if (hasMobFlag(MobMetaFlagType.COTW_SUMMONED_MOB, target)) { baseXP = 0; - } else if(getMobMetadataService().hasMobFlag(MobMetaFlagType.MOB_SPAWNER_MOB, target) || target.hasMetadata("ES")) { + } else if (hasMobFlag(MobMetaFlagType.MOB_SPAWNER_MOB, target) || target.hasMetadata( + "ES")) { baseXP *= ExperienceConfig.getInstance().getSpawnedMobXpMultiplier(); - } else if(getMobMetadataService().hasMobFlag(MobMetaFlagType.NETHER_PORTAL_MOB, target)) { + } else if (hasMobFlag(MobMetaFlagType.NETHER_PORTAL_MOB, target)) { baseXP *= ExperienceConfig.getInstance().getNetherPortalXpMultiplier(); - } else if(getMobMetadataService().hasMobFlag(MobMetaFlagType.EGG_MOB, target)) { + } else if (hasMobFlag(MobMetaFlagType.EGG_MOB, target)) { baseXP *= ExperienceConfig.getInstance().getEggXpMultiplier(); - } else if (getMobMetadataService().hasMobFlag(MobMetaFlagType.PLAYER_BRED_MOB, target)) { + } else if (hasMobFlag(MobMetaFlagType.PLAYER_BRED_MOB, target)) { baseXP *= ExperienceConfig.getInstance().getBredMobXpMultiplier(); - } else if(getMobMetadataService().hasMobFlag(MobMetaFlagType.PLAYER_TAMED_MOB, target)) { + } else if (hasMobFlag(MobMetaFlagType.PLAYER_TAMED_MOB, target)) { baseXP *= ExperienceConfig.getInstance().getTamedMobXpMultiplier(); } @@ -806,8 +994,10 @@ public final class CombatUtils { baseXP *= multiplier; - if (baseXP != 0) { - mcMMO.p.getFoliaLib().getImpl().runAtEntity(mcMMOPlayer.getPlayer(), new AwardCombatXpTask(mcMMOPlayer, primarySkillType, baseXP, target, xpGainReason)); + if (baseXP > 0) { + mcMMO.p.getFoliaLib().getScheduler().runAtEntity(target, + new AwardCombatXpTask(mmoPlayer, primarySkillType, baseXP, target, + xpGainReason)); } } @@ -821,22 +1011,29 @@ public final class CombatUtils { private static boolean shouldBeAffected(@NotNull Player player, @NotNull Entity entity) { if (entity instanceof Player defender) { //TODO: NPC Interaction? - if(UserManager.getPlayer(defender) == null) + if (UserManager.getPlayer(defender) == null) { return true; + } - if (!defender.getWorld().getPVP() || defender == player || UserManager.getPlayer(defender).getGodMode()) { + if (!defender.getWorld().getPVP() || defender == player || UserManager.getPlayer( + defender).getGodMode()) { return false; } - if ((PartyManager.inSameParty(player, defender) || PartyManager.areAllies(player, defender)) && !(Permissions.friendlyFire(player) && Permissions.friendlyFire(defender))) { - return false; + if (mcMMO.p.getPartyConfig().isPartyEnabled()) { + if ((mcMMO.p.getPartyManager().inSameParty(player, defender) + || mcMMO.p.getPartyManager().areAllies(player, defender)) + && !(Permissions.friendlyFire(player) && Permissions.friendlyFire( + defender))) { + return false; + } } // Vanished players should not be able to get hit by AoE effects if (!player.canSee(defender)) { return false; } - + // Spectators should not be affected return defender.getGameMode() != GameMode.SPECTATOR; } else if (entity instanceof Tameable tameableEntity) { @@ -863,7 +1060,8 @@ public final class CombatUtils { * So apparently if you do more damage to a LivingEntity than its last damage int you bypass the invincibility. * So yeah, this is for that. */ - return (entity.getNoDamageTicks() > entity.getMaximumNoDamageTicks() / 2.0F) && (eventDamage <= entity.getLastDamage()); + return (entity.getNoDamageTicks() > entity.getMaximumNoDamageTicks() / 2.0F) && (eventDamage + <= entity.getLastDamage()); } /** @@ -879,7 +1077,9 @@ public final class CombatUtils { if (tamer instanceof Player owner) { - return (owner == attacker || PartyManager.inSameParty(attacker, owner) || PartyManager.areAllies(attacker, owner)); + return (owner == attacker || (mcMMO.p.getPartyConfig().isPartyEnabled() + && (mcMMO.p.getPartyManager().inSameParty(attacker, owner) + || mcMMO.p.getPartyManager().areAllies(attacker, owner)))); } } @@ -897,34 +1097,29 @@ public final class CombatUtils { if (ItemUtils.isWoodTool(inHand)) { tier = 1; - } - else if (ItemUtils.isStoneTool(inHand)) { + } else if (ItemUtils.isStoneTool(inHand)) { tier = 2; - } - else if (ItemUtils.isIronTool(inHand)) { + } else if (ItemUtils.isIronTool(inHand)) { tier = 3; - } - else if (ItemUtils.isGoldTool(inHand)) { + } else if (ItemUtils.isGoldTool(inHand)) { tier = 1; - } - else if (ItemUtils.isDiamondTool(inHand)) { + } else if (ItemUtils.isDiamondTool(inHand)) { tier = 4; } else if (ItemUtils.isNetheriteTool(inHand)) { tier = 5; } - else if (mcMMO.getModManager().isCustomTool(inHand)) { - tier = mcMMO.getModManager().getTool(inHand).getTier(); - } return tier; } - public static void handleHealthbars(@NotNull Entity attacker, @NotNull LivingEntity target, double damage, @NotNull mcMMO plugin) { + public static void handleHealthbars(@NotNull Entity attacker, @NotNull LivingEntity target, + double damage, @NotNull mcMMO plugin) { if (!(attacker instanceof Player player)) { return; } - if (Misc.isNPCEntityExcludingVillagers(player) || Misc.isNPCEntityExcludingVillagers(target)) { + if (Misc.isNPCEntityExcludingVillagers(player) || Misc.isNPCEntityExcludingVillagers( + target)) { return; } @@ -935,40 +1130,23 @@ public final class CombatUtils { MobHealthbarUtils.handleMobHealthbars(target, damage, plugin); } + @Deprecated(forRemoval = true, since = "2.2.039") public static void modifyMoveSpeed(@NotNull LivingEntity livingEntity, double multiplier) { - AttributeInstance attributeInstance = livingEntity.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED); + AttributeInstance attributeInstance = livingEntity.getAttribute(MAPPED_MOVEMENT_SPEED); - if(attributeInstance != null) { + if (attributeInstance != null) { double normalSpeed = attributeInstance.getBaseValue(); attributeInstance.setBaseValue(normalSpeed * multiplier); } } - /** - * 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 + * @param arrow the projectile */ - public static void delayArrowMetaCleanup(@NotNull Projectile entity) { - mcMMO.p.getFoliaLib().getImpl().runLater(() -> cleanupArrowMetadata(entity), 20*60); + public static void delayArrowMetaCleanup(@NotNull AbstractArrow arrow) { + mcMMO.p.getFoliaLib().getScheduler() + .runLater(() -> ProjectileUtils.cleanupProjectileMetadata(arrow), 20 * 120); } } diff --git a/src/main/java/com/gmail/nossr50/util/skills/ParticleEffectUtils.java b/src/main/java/com/gmail/nossr50/util/skills/ParticleEffectUtils.java index 48265d03f..18791d4f2 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/ParticleEffectUtils.java +++ b/src/main/java/com/gmail/nossr50/util/skills/ParticleEffectUtils.java @@ -1,12 +1,17 @@ package com.gmail.nossr50.util.skills; +import com.gmail.nossr50.datatypes.interactions.NotificationType; +import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.mcMMO; +import com.gmail.nossr50.util.player.NotificationManager; +import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.sounds.SoundManager; import com.gmail.nossr50.util.sounds.SoundType; -import org.apache.commons.lang.math.RandomUtils; +import org.apache.commons.lang3.RandomUtils; import org.bukkit.Effect; import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.SoundCategory; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; @@ -16,7 +21,8 @@ import org.jetbrains.annotations.NotNull; public final class ParticleEffectUtils { - private ParticleEffectUtils() {} + private ParticleEffectUtils() { + } public static void playGreenThumbEffect(Location location) { World world = location.getWorld(); @@ -29,7 +35,28 @@ public final class ParticleEffectUtils { return; } - livingEntity.getWorld().playEffect(getParticleLocation(livingEntity), Effect.STEP_SOUND, Material.REDSTONE_WIRE); + livingEntity.getWorld().playEffect(getParticleLocation(livingEntity), + Effect.STEP_SOUND, Material.REDSTONE_WIRE); + } + + public static void playCrippleEffect(@NotNull LivingEntity livingEntity) { + if (!mcMMO.p.getGeneralConfig().getCrippleEffectEnabled()) { + return; + } + + SoundManager.sendCategorizedSound(livingEntity.getLocation(), SoundType.CRIPPLE, + SoundCategory.PLAYERS, 0.2F); + livingEntity.getWorld() + .playEffect(getParticleLocation(livingEntity), Effect.ANVIL_BREAK, null, 20); + + if (livingEntity instanceof Player player) { + final McMMOPlayer mmoPlayer = UserManager.getPlayer(player); + boolean useChatNotification = mmoPlayer == null || mmoPlayer.useChatNotifications(); + if (useChatNotification) { + NotificationManager.sendPlayerInformation( + player, NotificationType.SUBSKILL_MESSAGE, "Maces.SubSkill.Cripple.Proc"); + } + } } private static @NotNull Location getParticleLocation(@NotNull LivingEntity livingEntity) { @@ -42,31 +69,22 @@ public final class ParticleEffectUtils { double offSetVal = 0.3D; - switch(RandomUtils.nextInt(10)) { - - case 0: - return new Location(world, x - offSetVal, y, z); - case 1: - return new Location(world, x + offSetVal, y, z); - case 2: - return new Location(world, x, y + offSetVal, z); - case 3: - return new Location(world, x, y - offSetVal, z); - case 4: Location locE = new Location(world, x, y, z + offSetVal); - return new Location(world, x, y, z - offSetVal); - case 5: - return new Location(world, x + offSetVal, y, z + offSetVal); - case 6: - return new Location(world, x - offSetVal, y, z - offSetVal); - case 7: - return new Location(world, x - offSetVal, y - offSetVal, z - offSetVal); - case 8: - return new Location(world, x + offSetVal, y - offSetVal, z + offSetVal); - case 9: - return new Location(world, x - offSetVal, y + offSetVal, z - offSetVal); - default: - return new Location(world, x + offSetVal, y + offSetVal, z - offSetVal); - } + return switch (RandomUtils.nextInt(0, 10)) { + case 0 -> new Location(world, x - offSetVal, y, z); + case 1 -> new Location(world, x + offSetVal, y, z); + case 2 -> new Location(world, x, y + offSetVal, z); + case 3 -> new Location(world, x, y - offSetVal, z); + case 4 -> { + Location locE = new Location(world, x, y, z + offSetVal); + yield new Location(world, x, y, z - offSetVal); + } + case 5 -> new Location(world, x + offSetVal, y, z + offSetVal); + case 6 -> new Location(world, x - offSetVal, y, z - offSetVal); + case 7 -> new Location(world, x - offSetVal, y - offSetVal, z - offSetVal); + case 8 -> new Location(world, x + offSetVal, y - offSetVal, z + offSetVal); + case 9 -> new Location(world, x - offSetVal, y + offSetVal, z - offSetVal); + default -> new Location(world, x + offSetVal, y + offSetVal, z - offSetVal); + }; } public static void playDodgeEffect(Player player) { @@ -82,8 +100,9 @@ public final class ParticleEffectUtils { return; } - if(location.getWorld() == null) + if (location.getWorld() == null) { return; + } location.getWorld().playEffect(location, Effect.MOBSPAWNER_FLAMES, 1); } @@ -91,8 +110,9 @@ public final class ParticleEffectUtils { public static void playSmokeEffect(Location location) { World world = location.getWorld(); - if(world == null) + if (world == null) { return; + } // Have to do it this way, because not all block directions are valid for smoke world.playEffect(location, Effect.SMOKE, BlockFace.SOUTH_EAST); @@ -113,7 +133,9 @@ public final class ParticleEffectUtils { Location location = livingEntity.getEyeLocation(); - livingEntity.getWorld().createExplosion(location.getX(), location.getY(), location.getZ(), 0F, false, false); + livingEntity.getWorld() + .createExplosion(location.getX(), location.getY(), location.getZ(), 0F, false, + false); } public static void playCallOfTheWildEffect(LivingEntity livingEntity) { @@ -121,7 +143,8 @@ public final class ParticleEffectUtils { return; } - livingEntity.getWorld().playEffect(livingEntity.getEyeLocation(), Effect.MOBSPAWNER_FLAMES, 1); + livingEntity.getWorld() + .playEffect(livingEntity.getEyeLocation(), Effect.MOBSPAWNER_FLAMES, 1); } public static void playAbilityDisabledEffect(Player player) { diff --git a/src/main/java/com/gmail/nossr50/util/skills/PerksUtils.java b/src/main/java/com/gmail/nossr50/util/skills/PerksUtils.java index 2d83cb063..176592999 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/PerksUtils.java +++ b/src/main/java/com/gmail/nossr50/util/skills/PerksUtils.java @@ -1,6 +1,7 @@ package com.gmail.nossr50.util.skills; import com.gmail.nossr50.config.experience.ExperienceConfig; +import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.events.skills.SkillActivationPerkEvent; import com.gmail.nossr50.util.Permissions; @@ -13,16 +14,15 @@ public final class PerksUtils { private static final int LUCKY_SKILL_ACTIVATION_CHANCE = 75; private static final int NORMAL_SKILL_ACTIVATION_CHANCE = 100; - private PerksUtils() {} + private PerksUtils() { + } public static int handleCooldownPerks(Player player, int cooldown) { if (Permissions.halvedCooldowns(player)) { cooldown *= 0.5; - } - else if (Permissions.thirdedCooldowns(player)) { + } else if (Permissions.thirdedCooldowns(player)) { cooldown *= (2.0 / 3.0); - } - else if (Permissions.quarteredCooldowns(player)) { + } else if (Permissions.quarteredCooldowns(player)) { cooldown *= 0.75; } @@ -36,15 +36,14 @@ public final class PerksUtils { if (Permissions.twelveSecondActivationBoost(player)) { ticks += 12; - } - else if (Permissions.eightSecondActivationBoost(player)) { + } else if (Permissions.eightSecondActivationBoost(player)) { ticks += 8; - } - else if (Permissions.fourSecondActivationBoost(player)) { + } else if (Permissions.fourSecondActivationBoost(player)) { ticks += 4; } - final SkillActivationPerkEvent skillActivationPerkEvent = new SkillActivationPerkEvent(player, ticks, maxTicks); + final SkillActivationPerkEvent skillActivationPerkEvent = new SkillActivationPerkEvent( + player, ticks, maxTicks); Bukkit.getPluginManager().callEvent(skillActivationPerkEvent); return skillActivationPerkEvent.getTicks(); } @@ -53,40 +52,39 @@ public final class PerksUtils { double modifier = 1.0F; if (Permissions.customXpBoost(player, skill)) { - if(UserManager.getPlayer(player) != null && UserManager.getPlayer(player).isDebugMode()) { - player.sendMessage(ChatColor.GOLD + "[DEBUG] " + ChatColor.DARK_GRAY + "XP Perk Multiplier IS CUSTOM! "); + if (UserManager.getPlayer(player) != null && UserManager.getPlayer(player) + .isDebugMode()) { + player.sendMessage(ChatColor.GOLD + "[DEBUG] " + ChatColor.DARK_GRAY + + "XP Perk Multiplier IS CUSTOM! "); } - modifier = ExperienceConfig.getInstance().getCustomXpPerkBoost(); - } - else if (Permissions.quadrupleXp(player, skill)) { + modifier = ExperienceConfig.getInstance().getCustomXpPerkBoost(); + } else if (Permissions.quadrupleXp(player, skill)) { modifier = 4; - } - else if (Permissions.tripleXp(player, skill)) { + } else if (Permissions.tripleXp(player, skill)) { modifier = 3; - } - else if (Permissions.doubleAndOneHalfXp(player, skill)) { + } else if (Permissions.doubleAndOneHalfXp(player, skill)) { modifier = 2.5; - } - else if (Permissions.doubleXp(player, skill)) { + } else if (Permissions.doubleXp(player, skill)) { modifier = 2; - } - else if (Permissions.oneAndOneHalfXp(player, skill)) { + } else if (Permissions.oneAndOneHalfXp(player, skill)) { modifier = 1.5; - } - else if (Permissions.oneAndAQuarterXp(player, skill)) { + } else if (Permissions.oneAndAQuarterXp(player, skill)) { modifier = 1.25; - } - else if (Permissions.oneAndOneTenthXp(player, skill)) { + } else if (Permissions.oneAndOneTenthXp(player, skill)) { modifier = 1.1; } float modifiedXP = (float) (xp * modifier); - if(UserManager.getPlayer(player) != null && UserManager.getPlayer(player).isDebugMode()) { - player.sendMessage(ChatColor.GOLD + "[DEBUG] " + ChatColor.RESET + "XP Perk Multiplier - " + ChatColor.GOLD + modifier); - player.sendMessage(ChatColor.GOLD + "[DEBUG] " + ChatColor.RESET + "Original XP before perk boosts " + ChatColor.RED + (double) xp); - player.sendMessage(ChatColor.GOLD + "[DEBUG] " + ChatColor.RESET + "XP AFTER PERKS " + ChatColor.DARK_RED + modifiedXP); + if (UserManager.getPlayer(player) != null && UserManager.getPlayer(player).isDebugMode()) { + player.sendMessage( + ChatColor.GOLD + "[DEBUG] " + ChatColor.RESET + "XP Perk Multiplier - " + + ChatColor.GOLD + modifier); + player.sendMessage(ChatColor.GOLD + "[DEBUG] " + ChatColor.RESET + + "Original XP before perk boosts " + ChatColor.RED + (double) xp); + player.sendMessage(ChatColor.GOLD + "[DEBUG] " + ChatColor.RESET + "XP AFTER PERKS " + + ChatColor.DARK_RED + modifiedXP); } return modifiedXP; @@ -106,4 +104,19 @@ public final class PerksUtils { return NORMAL_SKILL_ACTIVATION_CHANCE; } + + /** + * Calculate activation chance for a skill. + * + * @param mmoPlayer Player to check the activation chance for + * @param skill PrimarySkillType to check the activation chance of + * @return the activation chance with "lucky perk" accounted for + */ + public static int handleLuckyPerks(McMMOPlayer mmoPlayer, PrimarySkillType skill) { + if (Permissions.lucky(mmoPlayer.getPlayer(), skill)) { + return LUCKY_SKILL_ACTIVATION_CHANCE; + } + + return NORMAL_SKILL_ACTIVATION_CHANCE; + } } 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 000000000..d4e138096 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/util/skills/ProjectileUtils.java @@ -0,0 +1,70 @@ +package com.gmail.nossr50.util.skills; + +import static com.gmail.nossr50.util.MetadataConstants.ARROW_METADATA_KEYS; +import static com.gmail.nossr50.util.MetadataConstants.MCMMO_METADATA_VALUE; + +import com.gmail.nossr50.mcMMO; +import com.gmail.nossr50.util.MetadataConstants; +import org.bukkit.block.BlockFace; +import org.bukkit.entity.AbstractArrow; +import org.bukkit.entity.Arrow; +import org.bukkit.metadata.FixedMetadataValue; +import org.bukkit.metadata.MetadataValue; +import org.bukkit.plugin.Plugin; +import org.bukkit.util.Vector; +import org.jetbrains.annotations.NotNull; + +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); + }; + } + + /** + * Clean up all possible mcMMO related metadata for a projectile + * + * @param arrow projectile + */ + public static void cleanupProjectileMetadata(@NotNull AbstractArrow arrow) { + ARROW_METADATA_KEYS.stream() + .filter(arrow::hasMetadata) + .forEach(key -> arrow.removeMetadata(key, mcMMO.p)); + } + + /** + * Copies metadata from one arrow to another. + * + * @param pluginRef mcMMO plugin reference. + * @param sourceArrow The arrow from which metadata is copied. + * @param targetArrow The arrow to which metadata is copied. + */ + public static void copyArrowMetadata(@NotNull Plugin pluginRef, @NotNull Arrow sourceArrow, + @NotNull Arrow targetArrow) { + ARROW_METADATA_KEYS.stream() + .filter(sourceArrow::hasMetadata) + .forEach(key -> { + final MetadataValue metadataValue = sourceArrow.getMetadata(key).get(0); + if (key.equals(MetadataConstants.METADATA_KEY_BOW_FORCE)) { + targetArrow.setMetadata(key, + new FixedMetadataValue(pluginRef, metadataValue.asDouble())); + } else if (key.equals(MetadataConstants.METADATA_KEY_CROSSBOW_PROJECTILE)) { + targetArrow.setMetadata(key, MCMMO_METADATA_VALUE); + } else { + targetArrow.setMetadata(key, metadataValue); + } + }); + } + + public static boolean isCrossbowProjectile(@NotNull AbstractArrow arrow) { + return arrow.isShotFromCrossbow() + || arrow.hasMetadata(MetadataConstants.METADATA_KEY_CROSSBOW_PROJECTILE); + } +} 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 ec4d56481..c2d258dce 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/RankUtils.java +++ b/src/main/java/com/gmail/nossr50/util/skills/RankUtils.java @@ -11,76 +11,75 @@ import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.runnables.skills.SkillUnlockNotificationTask; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.player.UserManager; +import java.util.HashMap; import org.bukkit.entity.Player; import org.bukkit.plugin.Plugin; -import java.util.HashMap; - public class RankUtils { private static HashMap> subSkillRanks; private static int count = 0; /** - * * @param plugin plugin instance ref - * @param mcMMOPlayer target player - * @param primarySkillType + * @param mmoPlayer target player + * @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) - { - for(SubSkillType subSkillType : mcMMO.p.getSkillTools().getSubSkills(primarySkillType)) - { - int playerRankInSkill = getRank(mcMMOPlayer.getPlayer(), subSkillType); + public static void executeSkillUnlockNotifications(Plugin plugin, McMMOPlayer mmoPlayer, + PrimarySkillType primarySkillType, int newLevel) { + for (SubSkillType subSkillType : mcMMO.p.getSkillTools().getSubSkills(primarySkillType)) { + int playerRankInSkill = getRank(mmoPlayer.getPlayer(), subSkillType); HashMap innerMap = subSkillRanks.get(subSkillType.toString()); //If the skill doesn't have registered ranks gtfo - if(innerMap == null || innerMap.get(playerRankInSkill) == null) + if (innerMap == null || innerMap.get(playerRankInSkill) == null) { continue; + } //Don't send notifications if the player lacks the permission node - if(!Permissions.isSubSkillEnabled(mcMMOPlayer.getPlayer(), subSkillType)) + if (!Permissions.isSubSkillEnabled(mmoPlayer.getPlayer(), subSkillType)) { continue; + } //The players level is the exact level requirement for this skill - if(newLevel == innerMap.get(playerRankInSkill)) - { - SkillUnlockNotificationTask skillUnlockNotificationTask = new SkillUnlockNotificationTask(mcMMOPlayer, subSkillType, newLevel); + if (newLevel == innerMap.get(playerRankInSkill)) { + SkillUnlockNotificationTask skillUnlockNotificationTask = new SkillUnlockNotificationTask( + mmoPlayer, subSkillType, newLevel); - mcMMO.p.getFoliaLib().getImpl().runAtEntityLater(mcMMOPlayer.getPlayer(), skillUnlockNotificationTask, (count * 100L)); + mcMMO.p.getFoliaLib().getScheduler() + .runAtEntityLater(mmoPlayer.getPlayer(), skillUnlockNotificationTask, + (count * 100L)); count++; } } } - public static void resetUnlockDelayTimer() - { + /** + * Reset the interval between skill unlock notifications + */ + public static void resetUnlockDelayTimer() { count = 0; } /* NEW SYSTEM */ - private static void addRanks(AbstractSubSkill abstractSubSkill) - { + private static void addRanks(AbstractSubSkill abstractSubSkill) { //Fill out the rank array - for(int i = 0; i < abstractSubSkill.getNumRanks(); i++) - { + for (int i = 0; i < abstractSubSkill.getNumRanks(); i++) { //This adds the highest ranks first - addRank(abstractSubSkill, abstractSubSkill.getNumRanks()-i); + addRank(abstractSubSkill, abstractSubSkill.getNumRanks() - i); //TODO: Remove debug code /*System.out.println("DEBUG: Adding rank "+(numRanks-i)+" to "+subSkillType.toString());*/ } } - private static void addRanks(SubSkillType subSkillType) - { + private static void addRanks(SubSkillType subSkillType) { //Fill out the rank array - for(int i = 0; i < subSkillType.getNumRanks(); i++) - { + for (int i = 0; i < subSkillType.getNumRanks(); i++) { //This adds the highest ranks first - addRank(subSkillType, subSkillType.getNumRanks()-i); + addRank(subSkillType, subSkillType.getNumRanks() - i); //TODO: Remove debug code /*System.out.println("DEBUG: Adding rank "+(numRanks-i)+" to "+subSkillType.toString());*/ @@ -90,27 +89,24 @@ public class RankUtils { /** * Populates the ranks for every skill we know about */ - public static void populateRanks() - { - for(SubSkillType subSkillType : SubSkillType.values()) - { + public static void populateRanks() { + for (SubSkillType subSkillType : SubSkillType.values()) { addRanks(subSkillType); } - for(AbstractSubSkill abstractSubSkill : InteractionManager.getSubSkillList()) - { + for (AbstractSubSkill abstractSubSkill : InteractionManager.getSubSkillList()) { addRanks(abstractSubSkill); } } /** * 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 */ - public static boolean hasUnlockedSubskill(Player player, SubSkillType subSkillType) - { + public static boolean hasUnlockedSubskill(Player player, SubSkillType subSkillType) { int curRank = getRank(player, subSkillType); //-1 means the skill has no unlockable levels and is therefor unlocked @@ -119,12 +115,12 @@ public class RankUtils { /** * 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 */ - public static boolean hasUnlockedSubskill(Player player, AbstractSubSkill abstractSubSkill) - { + public static boolean hasUnlockedSubskill(Player player, AbstractSubSkill abstractSubSkill) { int curRank = getRank(player, abstractSubSkill); //-1 means the skill has no unlockable levels and is therefor unlocked @@ -133,81 +129,90 @@ public class RankUtils { /** * 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 * @return true if the player is at least that rank in this subskill */ - public static boolean hasReachedRank(int rank, Player player, SubSkillType subSkillType) - { + public static boolean hasReachedRank(int rank, Player player, SubSkillType subSkillType) { return getRank(player, subSkillType) >= rank; } /** * 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 * @return true if the player is at least that rank in this subskill */ - public static boolean hasReachedRank(int rank, Player player, AbstractSubSkill abstractSubSkill) - { + public static boolean hasReachedRank(int rank, Player player, + AbstractSubSkill abstractSubSkill) { return getRank(player, abstractSubSkill) >= rank; } /** * Gets the current rank of the subskill for the player + * * @param mmoPlayer The player in question * @param subSkillType Target subskill - * @return The rank the player currently has achieved in this skill. -1 for skills without ranks. + * @return The rank the player currently has achieved in this skill. -1 for skills without + * ranks. */ - public static int getRank(McMMOPlayer mmoPlayer, SubSkillType subSkillType) - { + public static int getRank(McMMOPlayer mmoPlayer, SubSkillType subSkillType) { return getRank(mmoPlayer.getPlayer(), subSkillType); } /** * Gets the current rank of the subskill for the player + * * @param player The player in question * @param subSkillType Target subskill - * @return The rank the player currently has achieved in this skill. -1 for skills without ranks. + * @return The rank the player currently has achieved in this skill. -1 for skills without + * ranks. */ - public static int getRank(Player player, SubSkillType subSkillType) - { + public static int getRank(Player player, SubSkillType subSkillType) { String skillName = subSkillType.toString(); int numRanks = subSkillType.getNumRanks(); - if(subSkillRanks == null) + if (subSkillRanks == null) { subSkillRanks = new HashMap<>(); + } - if(numRanks == 0) + if (numRanks == 0) { return -1; //-1 Means the skill doesn't have ranks + } - if(subSkillRanks.get(skillName) == null && numRanks > 0) + if (subSkillRanks.get(skillName) == null && numRanks > 0) { addRanks(subSkillType); + } //Get our rank map HashMap rankMap = subSkillRanks.get(skillName); - if(UserManager.getPlayer(player) == null) + if (UserManager.getPlayer(player) == null) { return 0; + } //Skill level of parent skill - int currentSkillLevel = UserManager.getPlayer(player).getSkillLevel(subSkillType.getParentSkill()); + int currentSkillLevel = UserManager.getPlayer(player) + .getSkillLevel(subSkillType.getParentSkill()); - for(int i = 0; i < numRanks; i++) - { + for (int i = 0; i < numRanks; i++) { //Compare against the highest to lowest rank in that order - int rank = numRanks-i; + int rank = numRanks - i; int unlockLevel = getRankUnlockLevel(subSkillType, rank); //If we check all ranks and still cannot unlock the skill, we return rank 0 - if(rank == 0) + if (rank == 0) { return 0; + } //True if our skill level can unlock the current rank - if(currentSkillLevel >= unlockLevel) + if (currentSkillLevel >= unlockLevel) { return rank; + } } return 0; //We should never reach this @@ -215,46 +220,53 @@ public class RankUtils { /** * Gets the current rank of the subskill for the player + * * @param player The player in question * @param abstractSubSkill Target subskill - * @return The rank the player currently has achieved in this skill. -1 for skills without ranks. + * @return The rank the player currently has achieved in this skill. -1 for skills without + * ranks. */ - public static int getRank(Player player, AbstractSubSkill abstractSubSkill) - { + public static int getRank(Player player, AbstractSubSkill abstractSubSkill) { String skillName = abstractSubSkill.getConfigKeyName(); int numRanks = abstractSubSkill.getNumRanks(); - if(subSkillRanks == null) + if (subSkillRanks == null) { subSkillRanks = new HashMap<>(); + } - if(numRanks == 0) + if (numRanks == 0) { return -1; //-1 Means the skill doesn't have ranks + } - if(subSkillRanks.get(skillName) == null && numRanks > 0) + if (subSkillRanks.get(skillName) == null && numRanks > 0) { addRanks(abstractSubSkill); + } //Get our rank map HashMap rankMap = subSkillRanks.get(skillName); - if(UserManager.getPlayer(player) == null) + if (UserManager.getPlayer(player) == null) { return 0; + } //Skill level of parent skill - int currentSkillLevel = UserManager.getPlayer(player).getSkillLevel(abstractSubSkill.getPrimarySkill()); + int currentSkillLevel = UserManager.getPlayer(player) + .getSkillLevel(abstractSubSkill.getPrimarySkill()); - for(int i = 0; i < numRanks; i++) - { + for (int i = 0; i < numRanks; i++) { //Compare against the highest to lowest rank in that order - int rank = numRanks-i; + int rank = numRanks - i; int unlockLevel = getRankUnlockLevel(abstractSubSkill, rank); //If we check all ranks and still cannot unlock the skill, we return rank 0 - if(rank == 0) + if (rank == 0) { return 0; + } //True if our skill level can unlock the current rank - if(currentSkillLevel >= unlockLevel) + if (currentSkillLevel >= unlockLevel) { return rank; + } } return 0; //We should never reach this @@ -262,11 +274,11 @@ public class RankUtils { /** * Adds ranks to our map + * * @param abstractSubSkill The subskill to add ranks for * @param rank The rank to add */ - private static void addRank(AbstractSubSkill abstractSubSkill, int rank) - { + private static void addRank(AbstractSubSkill abstractSubSkill, int rank) { initMaps(abstractSubSkill.getConfigKeyName()); HashMap rankMap = subSkillRanks.get(abstractSubSkill.getConfigKeyName()); @@ -275,8 +287,7 @@ public class RankUtils { } @Deprecated - private static void addRank(SubSkillType subSkillType, int rank) - { + private static void addRank(SubSkillType subSkillType, int rank) { initMaps(subSkillType.toString()); HashMap rankMap = subSkillRanks.get(subSkillType.toString()); @@ -285,75 +296,73 @@ public class RankUtils { } private static void initMaps(String s) { - if (subSkillRanks == null) + if (subSkillRanks == null) { subSkillRanks = new HashMap<>(); + } subSkillRanks.computeIfAbsent(s, k -> new HashMap<>()); } /** * Gets the unlock level for a specific rank in a subskill + * * @param subSkillType The target subskill * @param rank The target rank * @return The level at which this rank unlocks */ - public static int getRankUnlockLevel(SubSkillType subSkillType, int rank) - { + public static int getRankUnlockLevel(SubSkillType subSkillType, int rank) { return RankConfig.getInstance().getSubSkillUnlockLevel(subSkillType, rank); } - public static int getRankUnlockLevel(AbstractSubSkill abstractSubSkill, int rank) - { + public static int getRankUnlockLevel(AbstractSubSkill abstractSubSkill, int rank) { return RankConfig.getInstance().getSubSkillUnlockLevel(abstractSubSkill, rank); } /** * Get the level at which a skill is unlocked for a player (this is the first rank of a skill) + * * @param subSkillType target subskill * @return The unlock requirements for rank 1 in this skill */ - public static int getUnlockLevel(SubSkillType subSkillType) - { + public static int getUnlockLevel(SubSkillType subSkillType) { return RankConfig.getInstance().getSubSkillUnlockLevel(subSkillType, 1); } /** * Get the level at which a skill is unlocked for a player (this is the first rank of a skill) + * * @param abstractSubSkill target subskill * @return The unlock requirements for rank 1 in this skill */ - public static int getUnlockLevel(AbstractSubSkill abstractSubSkill) - { + public static int getUnlockLevel(AbstractSubSkill abstractSubSkill) { return RankConfig.getInstance().getSubSkillUnlockLevel(abstractSubSkill, 1); } /** * Get the highest rank of a subskill + * * @param subSkillType target subskill * @return the last rank of a subskill */ - public static int getHighestRank(SubSkillType subSkillType) - { + public static int getHighestRank(SubSkillType subSkillType) { return subSkillType.getNumRanks(); } - public static String getHighestRankStr(SubSkillType subSkillType) - { + public static String getHighestRankStr(SubSkillType subSkillType) { return String.valueOf(subSkillType.getNumRanks()); } /** * Get the highest rank of a subskill + * * @param abstractSubSkill target subskill * @return the last rank of a subskill */ - public static int getHighestRank(AbstractSubSkill abstractSubSkill) - { + public static int getHighestRank(AbstractSubSkill abstractSubSkill) { return abstractSubSkill.getNumRanks(); } - public static int getSuperAbilityUnlockRequirement(SuperAbilityType superAbilityType) - { + public static int getSuperAbilityUnlockRequirement(SuperAbilityType superAbilityType) { return getRankUnlockLevel(superAbilityType.getSubSkillTypeDefinition(), 1); } 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 240bd6861..a9bae0238 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/SkillTools.java +++ b/src/main/java/com/gmail/nossr50/util/skills/SkillTools.java @@ -13,6 +13,12 @@ import com.gmail.nossr50.util.text.StringUtils; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; +import java.util.ArrayList; +import java.util.Collections; +import java.util.EnumMap; +import java.util.HashSet; +import java.util.List; +import java.util.Set; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.entity.Tameable; @@ -20,17 +26,17 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.VisibleForTesting; -import java.util.*; - public class SkillTools { private final mcMMO pluginRef; - - //TODO: Figure out which ones we don't need, this was copy pasted from a diff branch + // TODO: Java has immutable types now, switch to those + // TODO: Figure out which ones we don't need, this was copy pasted from a diff branch public final @NotNull ImmutableList LOCALIZED_SKILL_NAMES; public final @NotNull ImmutableList FORMATTED_SUBSKILL_NAMES; 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; @@ -45,28 +51,33 @@ public class SkillTools { static { ArrayList tempNonChildSkills = new ArrayList<>(); - for(PrimarySkillType primarySkillType : PrimarySkillType.values()) { - if (primarySkillType != PrimarySkillType.SALVAGE && primarySkillType != PrimarySkillType.SMELTING) + for (PrimarySkillType primarySkillType : PrimarySkillType.values()) { + if (primarySkillType != PrimarySkillType.SALVAGE + && primarySkillType != PrimarySkillType.SMELTING) { tempNonChildSkills.add(primarySkillType); + } } 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) { + public SkillTools(@NotNull mcMMO pluginRef) throws InvalidSkillException { this.pluginRef = pluginRef; /* * Setup subskill -> parent relationship map */ - EnumMap tempSubParentMap = new EnumMap<>(SubSkillType.class); + EnumMap tempSubParentMap = new EnumMap<>( + SubSkillType.class); //Super hacky and disgusting - for(PrimarySkillType primarySkillType1 : PrimarySkillType.values()) { - for(SubSkillType subSkillType : SubSkillType.values()) { + for (PrimarySkillType primarySkillType1 : PrimarySkillType.values()) { + for (SubSkillType subSkillType : SubSkillType.values()) { String[] splitSubSkillName = subSkillType.toString().split("_"); - if(primarySkillType1.toString().equalsIgnoreCase(splitSubSkillName[0])) { + if (primarySkillType1.toString().equalsIgnoreCase(splitSubSkillName[0])) { //Parent Skill Found tempSubParentMap.put(subSkillType, primarySkillType1); } @@ -79,15 +90,16 @@ public class SkillTools { * Setup primary -> (collection) subskill map */ - EnumMap> tempPrimaryChildMap = new EnumMap<>(PrimarySkillType.class); + EnumMap> tempPrimaryChildMap = new EnumMap<>( + PrimarySkillType.class); //Init the empty Hash Sets - for(PrimarySkillType primarySkillType1 : PrimarySkillType.values()) { + for (PrimarySkillType primarySkillType1 : PrimarySkillType.values()) { tempPrimaryChildMap.put(primarySkillType1, new HashSet<>()); } //Fill in the hash sets - for(SubSkillType subSkillType : SubSkillType.values()) { + for (SubSkillType subSkillType : SubSkillType.values()) { PrimarySkillType parentSkill = subSkillParentRelationshipMap.get(subSkillType); //Add this subskill as a child @@ -116,15 +128,17 @@ public class SkillTools { * Setup primary -> ability map */ - EnumMap tempAbilityParentRelationshipMap = new EnumMap<>(SuperAbilityType.class); - EnumMap tempMainActivatedAbilityChildMap = new EnumMap<>(PrimarySkillType.class); + EnumMap tempAbilityParentRelationshipMap = new EnumMap<>( + SuperAbilityType.class); + EnumMap tempMainActivatedAbilityChildMap = new EnumMap<>( + PrimarySkillType.class); - for(SuperAbilityType superAbilityType : SuperAbilityType.values()) { + for (SuperAbilityType superAbilityType : SuperAbilityType.values()) { try { PrimarySkillType parent = getSuperAbilityParent(superAbilityType); tempAbilityParentRelationshipMap.put(superAbilityType, parent); - if(superAbilityType != SuperAbilityType.BLAST_MINING) { + if (superAbilityType != SuperAbilityType.BLAST_MINING) { //This map is used only for abilities that have a tool readying phase, so blast mining is ignored tempMainActivatedAbilityChildMap.put(parent, superAbilityType); } @@ -141,26 +155,53 @@ public class SkillTools { */ List childSkills = new ArrayList<>(); -// List nonChildSkills = new ArrayList<>(); for (PrimarySkillType primarySkillType : PrimarySkillType.values()) { - if (isChildSkill(primarySkillType)) + if (isChildSkill(primarySkillType)) { childSkills.add(primarySkillType); -// } { -// nonChildSkills.add(primarySkillType); -// } + } } CHILD_SKILLS = ImmutableList.copyOf(childSkills); -// NON_CHILD_SKILLS = ImmutableList.copyOf(nonChildSkills); /* * 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); + // We are in a game version with Maces + if (mcMMO.getCompatibilityManager().getMinecraftGameVersion().isAtLeast(1, 21, 0)) { + COMBAT_SKILLS = ImmutableList.of( + PrimarySkillType.ARCHERY, + PrimarySkillType.AXES, + PrimarySkillType.CROSSBOWS, + PrimarySkillType.MACES, + PrimarySkillType.SWORDS, + PrimarySkillType.TAMING, + PrimarySkillType.TRIDENTS, + PrimarySkillType.UNARMED); + } else { + // No Maces in this version + 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 @@ -171,37 +212,32 @@ public class SkillTools { EXACT_SUBSKILL_NAMES = ImmutableSet.copyOf(buildExactSubSkillNameList()); } - 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()); - } + private @NotNull PrimarySkillType getSuperAbilityParent(SuperAbilityType superAbilityType) + throws InvalidSkillException { + 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 TRIDENTS_SUPER_ABILITY -> PrimarySkillType.TRIDENTS; + case EXPLOSIVE_SHOT -> PrimarySkillType.ARCHERY; + case MACES_SUPER_ABILITY -> PrimarySkillType.MACES; + }; } /** - * Makes a list of the "nice" version of sub skill names - * Used in tab completion mostly + * Makes a list of the "nice" version of sub skill names Used in tab completion mostly + * * @return a list of formatted sub skill names */ private @NotNull ArrayList buildFormattedSubSkillNameList() { ArrayList subSkillNameList = new ArrayList<>(); - for(SubSkillType subSkillType : SubSkillType.values()) { + for (SubSkillType subSkillType : SubSkillType.values()) { subSkillNameList.add(subSkillType.getNiceNameNoSpaces(subSkillType)); } @@ -211,7 +247,7 @@ public class SkillTools { private @NotNull HashSet buildExactSubSkillNameList() { HashSet subSkillNameExactSet = new HashSet<>(); - for(SubSkillType subSkillType : SubSkillType.values()) { + for (SubSkillType subSkillType : SubSkillType.values()) { subSkillNameExactSet.add(subSkillType.toString()); } @@ -220,13 +256,14 @@ public class SkillTools { /** * Builds a list of localized {@link PrimarySkillType} names + * * @return list of localized {@link PrimarySkillType} names */ @VisibleForTesting private @NotNull ArrayList buildLocalizedPrimarySkillNames() { ArrayList localizedSkillNameList = new ArrayList<>(); - for(PrimarySkillType primarySkillType : PrimarySkillType.values()) { + for (PrimarySkillType primarySkillType : PrimarySkillType.values()) { localizedSkillNameList.add(getLocalizedSkillName(primarySkillType)); } @@ -236,10 +273,9 @@ public class SkillTools { } /** - * Matches a string of a skill to a skill - * This is NOT case-sensitive - * First it checks the locale file and tries to match by the localized name of the skill - * Then if nothing is found it checks against the hard coded "name" of the skill, which is just its name in English + * Matches a string of a skill to a skill This is NOT case-sensitive First it checks the locale + * file and tries to match by the localized name of the skill Then if nothing is found it checks + * against the hard coded "name" of the skill, which is just its name in English * * @param skillName target skill name * @return the matching PrimarySkillType if one is found, otherwise null @@ -248,7 +284,8 @@ public class SkillTools { public PrimarySkillType matchSkill(@NotNull String skillName) { if (!pluginRef.getGeneralConfig().getLocale().equalsIgnoreCase("en_US")) { for (PrimarySkillType type : PrimarySkillType.values()) { - if (skillName.equalsIgnoreCase(LocaleLoader.getString(StringUtils.getCapitalized(type.name()) + ".SkillName"))) { + if (skillName.equalsIgnoreCase(LocaleLoader.getString( + StringUtils.getCapitalized(type.name()) + ".SkillName"))) { return type; } } @@ -260,6 +297,11 @@ public class SkillTools { } } + if (!skillName.equalsIgnoreCase("all")) { + pluginRef.getLogger() + .warning("Invalid mcMMO skill (" + skillName + ")"); //TODO: Localize + } + return null; } @@ -286,8 +328,9 @@ public class SkillTools { } /** - * Gets the PrimarySkillStype to which a SubSkillType belongs - * Return null if it does not belong to one.. which should be impossible in most circumstances + * Gets the PrimarySkillStype to which a SubSkillType belongs Return null if it does not belong + * to one.. which should be impossible in most circumstances + * * @param subSkillType target subskill * @return the PrimarySkillType of this SubSkill, null if it doesn't exist */ @@ -296,8 +339,9 @@ public class SkillTools { } /** - * Gets the PrimarySkillStype to which a SuperAbilityType belongs - * Return null if it does not belong to one.. which should be impossible in most circumstances + * Gets the PrimarySkillStype to which a SuperAbilityType belongs Return null if it does not + * belong to one.. which should be impossible in most circumstances + * * @param superAbilityType target super ability * @return the PrimarySkillType of this SuperAbilityType, null if it doesn't exist */ @@ -306,14 +350,16 @@ public class SkillTools { } public SuperAbilityType getSuperAbility(PrimarySkillType primarySkillType) { - if(mainActivatedAbilityChildMap.get(primarySkillType) == null) + if (mainActivatedAbilityChildMap.get(primarySkillType) == null) { return null; + } return mainActivatedAbilityChildMap.get(primarySkillType); } public boolean isSuperAbilityUnlocked(PrimarySkillType primarySkillType, Player player) { - SuperAbilityType superAbilityType = mcMMO.p.getSkillTools().getSuperAbility(primarySkillType); + SuperAbilityType superAbilityType = mcMMO.p.getSkillTools() + .getSuperAbility(primarySkillType); SubSkillType subSkillType = superAbilityType.getSubSkillTypeDefinition(); return RankUtils.hasUnlockedSubskill(player, subSkillType); } @@ -339,34 +385,30 @@ public class SkillTools { } public Set getSubSkills(PrimarySkillType primarySkillType) { - //TODO: Cache this! return primarySkillChildrenMap.get(primarySkillType); } - public double getXpModifier(PrimarySkillType primarySkillType) { + public double getXpMultiplier(PrimarySkillType primarySkillType) { return ExperienceConfig.getInstance().getFormulaSkillModifier(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; + }; } /** * Get the localized name for a {@link PrimarySkillType} + * * @param primarySkillType target {@link PrimarySkillType} * @return the localized name for a {@link PrimarySkillType} */ public String getLocalizedSkillName(PrimarySkillType primarySkillType) { - //TODO: Replace with current impl - return StringUtils.getCapitalized(LocaleLoader.getString(StringUtils.getCapitalized(primarySkillType.toString()) + ".SkillName")); + return LocaleLoader.getString( + StringUtils.getCapitalized(primarySkillType.toString()) + ".SkillName"); } public boolean doesPlayerHaveSkillPermission(Player player, PrimarySkillType primarySkillType) { @@ -374,7 +416,9 @@ public class SkillTools { } public boolean canCombatSkillsTrigger(PrimarySkillType primarySkillType, Entity target) { - return (target instanceof Player || (target instanceof Tameable && ((Tameable) target).isTamed())) ? getPVPEnabled(primarySkillType) : getPVEEnabled(primarySkillType); + return (target instanceof Player || (target instanceof Tameable + && ((Tameable) target).isTamed())) ? getPVPEnabled(primarySkillType) + : getPVEEnabled(primarySkillType); } public String getCapitalizedPrimarySkillName(PrimarySkillType primarySkillType) { @@ -389,26 +433,6 @@ public class SkillTools { return pluginRef.getGeneralConfig().getMaxLength(superAbilityType); } - public String getSuperAbilityOnLocaleKey(SuperAbilityType superAbilityType) { - return "SuperAbility." + StringUtils.getPrettyCamelCaseName(superAbilityType) + ".On"; - } - - public String getSuperAbilityOffLocaleKey(SuperAbilityType superAbilityType) { - return "SuperAbility." + StringUtils.getPrettyCamelCaseName(superAbilityType) + ".Off"; - } - - public String getSuperAbilityOtherPlayerActivationLocaleKey(SuperAbilityType superAbilityType) { - return "SuperAbility." + StringUtils.getPrettyCamelCaseName(superAbilityType) + ".Other.On"; - } - - public String getSuperAbilityOtherPlayerDeactivationLocaleKey(SuperAbilityType superAbilityType) { - return "SuperAbility." + StringUtils.getPrettyCamelCaseName(superAbilityType) + "Other.Off"; - } - - public String getSuperAbilityRefreshedLocaleKey(SuperAbilityType superAbilityType) { - return "SuperAbility." + StringUtils.getPrettyCamelCaseName(superAbilityType) + ".Refresh"; - } - public int getLevelCap(@NotNull PrimarySkillType primarySkillType) { return mcMMO.p.getGeneralConfig().getLevelCap(primarySkillType); } @@ -421,34 +445,7 @@ public class SkillTools { * @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() { @@ -470,4 +467,19 @@ public class SkillTools { 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/java/com/gmail/nossr50/util/skills/SkillUtils.java b/src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java index 6a15963ef..eb0307e17 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java +++ b/src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java @@ -1,5 +1,10 @@ package com.gmail.nossr50.util.skills; +import static com.gmail.nossr50.util.ItemMetadataUtils.isLegacyAbilityTool; +import static com.gmail.nossr50.util.ItemMetadataUtils.isSuperAbilityBoosted; +import static com.gmail.nossr50.util.ItemMetadataUtils.removeBonusDigSpeedOnSuperAbilityTool; +import static com.gmail.nossr50.util.PotionEffectUtil.getHastePotionEffectType; + import com.gmail.nossr50.config.HiddenConfig; import com.gmail.nossr50.datatypes.experience.XPGainReason; import com.gmail.nossr50.datatypes.experience.XPGainSource; @@ -10,16 +15,17 @@ import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.datatypes.skills.SuperAbilityType; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.metadata.ItemMetadataService; +import com.gmail.nossr50.util.ItemMetadataUtils; 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; +import java.util.Iterator; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; -import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.Recipe; @@ -27,41 +33,42 @@ import org.bukkit.inventory.ShapedRecipe; import org.bukkit.inventory.ShapelessRecipe; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.potion.PotionEffect; -import org.bukkit.potion.PotionEffectType; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.Iterator; - public final class SkillUtils { /** - * This is a static utility class, therefore we don't want any instances of - * this class. Making the constructor private prevents accidents like that. + * This is a static utility class, therefore we don't want any instances of this class. Making + * the constructor private prevents accidents like that. */ - private SkillUtils() {} - - public static void applyXpGain(McMMOPlayer mcMMOPlayer, PrimarySkillType skill, float xp, XPGainReason xpGainReason) { - mcMMOPlayer.beginXpGain(skill, xp, xpGainReason, XPGainSource.SELF); + private SkillUtils() { } - public static void applyXpGain(McMMOPlayer mcMMOPlayer, PrimarySkillType skill, float xp, XPGainReason xpGainReason, XPGainSource xpGainSource) { - mcMMOPlayer.beginXpGain(skill, xp, xpGainReason, xpGainSource); + public static void applyXpGain(McMMOPlayer mmoPlayer, PrimarySkillType skill, float xp, + XPGainReason xpGainReason) { + mmoPlayer.beginXpGain(skill, xp, xpGainReason, XPGainSource.SELF); + } + + public static void applyXpGain(McMMOPlayer mmoPlayer, PrimarySkillType skill, float xp, + XPGainReason xpGainReason, XPGainSource xpGainSource) { + mmoPlayer.beginXpGain(skill, xp, xpGainReason, xpGainSource); } /* * Skill Stat Calculations */ - public static String[] calculateLengthDisplayValues(Player player, float skillValue, PrimarySkillType skill) { - int maxLength = mcMMO.p.getSkillTools().getSuperAbilityMaxLength(mcMMO.p.getSkillTools().getSuperAbility(skill)); + public static String[] calculateLengthDisplayValues(Player player, float skillValue, + PrimarySkillType skill) { + int maxLength = mcMMO.p.getSkillTools() + .getSuperAbilityMaxLength(mcMMO.p.getSkillTools().getSuperAbility(skill)); int abilityLengthVar = mcMMO.p.getAdvancedConfig().getAbilityLength(); int abilityLengthCap = mcMMO.p.getAdvancedConfig().getAbilityLengthCap(); int length; - if(abilityLengthCap > 0) - { - length = (int) Math.min(abilityLengthCap, 2 + (skillValue / abilityLengthVar)); + if (abilityLengthCap > 0) { + length = (int) Math.min(abilityLengthCap, 2 + (skillValue / abilityLengthVar)); } else { length = 2 + (int) (skillValue / abilityLengthVar); } @@ -72,20 +79,21 @@ public final class SkillUtils { length = Math.min(length, maxLength); } - return new String[] { String.valueOf(length), String.valueOf(enduranceLength) }; + return new String[]{String.valueOf(length), String.valueOf(enduranceLength)}; } /* * Others */ - public static int handleFoodSkills(Player player, int eventFoodLevel, SubSkillType subSkillType) { + public static int handleFoodSkills(Player player, int eventFoodLevel, + SubSkillType subSkillType) { int curRank = RankUtils.getRank(player, subSkillType); int currentFoodLevel = player.getFoodLevel(); int foodChange = eventFoodLevel - currentFoodLevel; - foodChange+=curRank; + foodChange += curRank; return currentFoodLevel + foodChange; } @@ -96,24 +104,24 @@ public final class SkillUtils { * @param deactivatedTimeStamp Time of deactivation * @param cooldown The length of the cooldown * @param player The Player to check for cooldown perks - * * @return the number of seconds remaining before the cooldown expires */ public static int calculateTimeLeft(long deactivatedTimeStamp, int cooldown, Player player) { - return (int) (((deactivatedTimeStamp + (PerksUtils.handleCooldownPerks(player, cooldown) * Misc.TIME_CONVERSION_FACTOR)) - System.currentTimeMillis()) / Misc.TIME_CONVERSION_FACTOR); + return (int) (((deactivatedTimeStamp + (PerksUtils.handleCooldownPerks(player, cooldown) + * Misc.TIME_CONVERSION_FACTOR)) - System.currentTimeMillis()) + / Misc.TIME_CONVERSION_FACTOR); } /** - * Check if the cooldown has expired. - * This does NOT account for cooldown perks! + * Check if the cooldown has expired. This does NOT account for cooldown perks! * * @param deactivatedTimeStamp Time of deactivation in seconds * @param cooldown The length of the cooldown in seconds - * * @return true if the cooldown is expired */ public static boolean cooldownExpired(long deactivatedTimeStamp, int cooldown) { - return System.currentTimeMillis() >= (deactivatedTimeStamp + cooldown) * Misc.TIME_CONVERSION_FACTOR; + return System.currentTimeMillis() + >= (deactivatedTimeStamp + cooldown) * Misc.TIME_CONVERSION_FACTOR; } /** @@ -123,15 +131,19 @@ public final class SkillUtils { * @return true if this is a valid skill, false otherwise */ public static boolean isSkill(String skillName) { - return mcMMO.p.getGeneralConfig().getLocale().equalsIgnoreCase("en_US") ? mcMMO.p.getSkillTools().matchSkill(skillName) != null : isLocalizedSkill(skillName); + return mcMMO.p.getGeneralConfig().getLocale().equalsIgnoreCase("en_US") ? + mcMMO.p.getSkillTools().matchSkill(skillName) != null : isLocalizedSkill(skillName); } - public static void sendSkillMessage(Player player, NotificationType notificationType, String key) { + public static void sendSkillMessage(Player player, NotificationType notificationType, + String key) { Location location = player.getLocation(); for (Player otherPlayer : player.getWorld().getPlayers()) { - if (otherPlayer != player && Misc.isNear(location, otherPlayer.getLocation(), Misc.SKILL_MESSAGE_MAX_SENDING_DISTANCE)) { - NotificationManager.sendNearbyPlayersInformation(otherPlayer, notificationType, key, player.getName()); + if (otherPlayer != player && Misc.isNear(location, otherPlayer.getLocation(), + Misc.SKILL_MESSAGE_MAX_SENDING_DISTANCE)) { + NotificationManager.sendNearbyPlayersInformation(otherPlayer, notificationType, key, + player.getName()); } } } @@ -140,30 +152,28 @@ public final class SkillUtils { if (HiddenConfig.getInstance().useEnchantmentBuffs()) { ItemStack heldItem = player.getInventory().getItemInMainHand(); - if(heldItem == null) + if (heldItem == null) { return; + } if (!ItemUtils.canBeSuperAbilityDigBoosted(heldItem)) { return; } - int originalDigSpeed = heldItem.getEnchantmentLevel(Enchantment.DIG_SPEED); - - //Add dig speed - - //Lore no longer gets added, no point to it afaik - //ItemUtils.addAbilityLore(heldItem); //lore can be a secondary failsafe for 1.13 and below - ItemUtils.addDigSpeedToItem(heldItem, heldItem.getEnchantmentLevel(Enchantment.DIG_SPEED)); + int originalDigSpeed = heldItem.getEnchantmentLevel( + mcMMO.p.getEnchantmentMapper().getEfficiency()); + ItemUtils.addDigSpeedToItem(heldItem, + heldItem.getEnchantmentLevel(mcMMO.p.getEnchantmentMapper().getEfficiency())); //1.13.2+ will have persistent metadata for this item - mcMMO.getMetadataService().getItemMetadataService().setSuperAbilityBoostedItem(heldItem, originalDigSpeed); + ItemMetadataUtils.setSuperAbilityBoostedItem(heldItem, originalDigSpeed); } else { int duration = 0; int amplifier = 0; - if (player.hasPotionEffect(PotionEffectType.FAST_DIGGING)) { + if (player.hasPotionEffect(getHastePotionEffectType())) { for (PotionEffect effect : player.getActivePotionEffects()) { - if (effect.getType() == PotionEffectType.FAST_DIGGING) { + if (effect.getType() == getHastePotionEffectType()) { duration = effect.getDuration(); amplifier = effect.getAmplifier(); break; @@ -171,29 +181,37 @@ public final class SkillUtils { } } - McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player); + final McMMOPlayer mmoPlayer = UserManager.getPlayer(player); //Not Loaded - if(mcMMOPlayer == null) + if (mmoPlayer == null) { return; + } - PrimarySkillType skill = mcMMOPlayer.getAbilityMode(SuperAbilityType.SUPER_BREAKER) ? PrimarySkillType.MINING : PrimarySkillType.EXCAVATION; + PrimarySkillType skill = mmoPlayer.getAbilityMode(SuperAbilityType.SUPER_BREAKER) + ? PrimarySkillType.MINING : PrimarySkillType.EXCAVATION; int abilityLengthVar = mcMMO.p.getAdvancedConfig().getAbilityLength(); int abilityLengthCap = mcMMO.p.getAdvancedConfig().getAbilityLengthCap(); int ticks; - if(abilityLengthCap > 0) - { - ticks = PerksUtils.handleActivationPerks(player, Math.min(abilityLengthCap, 2 + (mcMMOPlayer.getSkillLevel(skill) / abilityLengthVar)), - mcMMO.p.getSkillTools().getSuperAbilityMaxLength(mcMMO.p.getSkillTools().getSuperAbility(skill))) * Misc.TICK_CONVERSION_FACTOR; + if (abilityLengthCap > 0) { + ticks = PerksUtils.handleActivationPerks(player, Math.min(abilityLengthCap, + 2 + (mmoPlayer.getSkillLevel(skill) / abilityLengthVar)), + mcMMO.p.getSkillTools().getSuperAbilityMaxLength( + mcMMO.p.getSkillTools().getSuperAbility(skill))) + * Misc.TICK_CONVERSION_FACTOR; } else { - ticks = PerksUtils.handleActivationPerks(player, 2 + ((mcMMOPlayer.getSkillLevel(skill)) / abilityLengthVar), - mcMMO.p.getSkillTools().getSuperAbilityMaxLength(mcMMO.p.getSkillTools().getSuperAbility(skill))) * Misc.TICK_CONVERSION_FACTOR; + ticks = PerksUtils.handleActivationPerks(player, + 2 + ((mmoPlayer.getSkillLevel(skill)) / abilityLengthVar), + mcMMO.p.getSkillTools().getSuperAbilityMaxLength( + mcMMO.p.getSkillTools().getSuperAbility(skill))) + * Misc.TICK_CONVERSION_FACTOR; } - PotionEffect abilityBuff = new PotionEffect(PotionEffectType.FAST_DIGGING, duration + ticks, amplifier + 10); + PotionEffect abilityBuff = new PotionEffect(getHastePotionEffectType(), + duration + ticks, amplifier + 10); player.addPotionEffect(abilityBuff, true); } } @@ -205,30 +223,29 @@ public final class SkillUtils { } public static void removeAbilityBuff(@Nullable ItemStack itemStack) { - if(itemStack == null) + if (itemStack == null) { return; + } - if(!ItemUtils.canBeSuperAbilityDigBoosted(itemStack)) + if (!ItemUtils.canBeSuperAbilityDigBoosted(itemStack)) { return; - + } //1.13.2+ will have persistent metadata for this itemStack - ItemMetadataService itemMetadataService = mcMMO.getMetadataService().getItemMetadataService(); - - if(itemMetadataService.isLegacyAbilityTool(itemStack)) { + if (isLegacyAbilityTool(itemStack)) { ItemMeta itemMeta = itemStack.getItemMeta(); - if(itemMeta != null) { + if (itemMeta != null) { // This is safe to call without prior checks. - itemMeta.removeEnchant(Enchantment.DIG_SPEED); + itemMeta.removeEnchant(mcMMO.p.getEnchantmentMapper().getEfficiency()); itemStack.setItemMeta(itemMeta); ItemUtils.removeAbilityLore(itemStack); } } - if(itemMetadataService.isSuperAbilityBoosted(itemStack)) { - itemMetadataService.removeBonusDigSpeedOnSuperAbilityTool(itemStack); + if (isSuperAbilityBoosted(itemStack)) { + removeBonusDigSpeedOnSuperAbilityTool(itemStack); } } @@ -237,78 +254,90 @@ public final class SkillUtils { } /** - * Modify the durability of an ItemStack, using Tools specific formula for unbreaking enchant damage reduction + * Modify the durability of an ItemStack, using Tools specific formula for unbreaking enchant + * damage reduction * * @param itemStack The ItemStack which durability should be modified * @param durabilityModifier the amount to modify the durability by * @param maxDamageModifier the amount to adjust the max damage by */ - public static void handleDurabilityChange(ItemStack itemStack, double durabilityModifier, double maxDamageModifier) { - if(itemStack.hasItemMeta() && itemStack.getItemMeta().isUnbreakable()) { + public static void handleDurabilityChange(ItemStack itemStack, double durabilityModifier, + double maxDamageModifier) { + if (itemStack.hasItemMeta() && itemStack.getItemMeta().isUnbreakable()) { return; } Material type = itemStack.getType(); - short maxDurability = mcMMO.getRepairableManager().isRepairable(type) ? mcMMO.getRepairableManager().getRepairable(type).getMaximumDurability() : type.getMaxDurability(); - durabilityModifier = (int) Math.min(durabilityModifier / (itemStack.getEnchantmentLevel(Enchantment.DURABILITY) + 1), maxDurability * maxDamageModifier); + short maxDurability = + mcMMO.getRepairableManager().isRepairable(type) ? mcMMO.getRepairableManager() + .getRepairable(type).getMaximumDurability() : type.getMaxDurability(); + durabilityModifier = (int) Math.min(durabilityModifier / ( + itemStack.getEnchantmentLevel(mcMMO.p.getEnchantmentMapper().getUnbreaking()) + 1), + maxDurability * maxDamageModifier); - itemStack.setDurability((short) Math.min(itemStack.getDurability() + durabilityModifier, maxDurability)); + itemStack.setDurability( + (short) Math.min(itemStack.getDurability() + durabilityModifier, maxDurability)); } private static boolean isLocalizedSkill(String skillName) { for (PrimarySkillType skill : PrimarySkillType.values()) { - if (skillName.equalsIgnoreCase(LocaleLoader.getString(StringUtils.getCapitalized(skill.toString()) + ".SkillName"))) { + if (skillName.equalsIgnoreCase(LocaleLoader.getString( + StringUtils.getCapitalized(skill.toString()) + ".SkillName"))) { return true; } } return false; } - - + + /** - * Modify the durability of an ItemStack, using Armor specific formula for unbreaking enchant damage reduction + * Modify the durability of an ItemStack, using Armor specific formula for unbreaking enchant + * damage reduction * * @param itemStack The ItemStack which durability should be modified * @param durabilityModifier the amount to modify the durability by * @param maxDamageModifier the amount to adjust the max damage by */ - public static void handleArmorDurabilityChange(ItemStack itemStack, double durabilityModifier, double maxDamageModifier) { - if(itemStack.hasItemMeta() && itemStack.getItemMeta().isUnbreakable()) { + public static void handleArmorDurabilityChange(ItemStack itemStack, double durabilityModifier, + double maxDamageModifier) { + if (itemStack.hasItemMeta() && itemStack.getItemMeta().isUnbreakable()) { return; } Material type = itemStack.getType(); - short maxDurability = mcMMO.getRepairableManager().isRepairable(type) ? mcMMO.getRepairableManager().getRepairable(type).getMaximumDurability() : type.getMaxDurability(); - durabilityModifier = (int) Math.min(durabilityModifier * (0.6 + 0.4/ (itemStack.getEnchantmentLevel(Enchantment.DURABILITY) + 1)), maxDurability * maxDamageModifier); + short maxDurability = + mcMMO.getRepairableManager().isRepairable(type) ? mcMMO.getRepairableManager() + .getRepairable(type).getMaximumDurability() : type.getMaxDurability(); + durabilityModifier = (int) Math.min(durabilityModifier * (0.6 + 0.4 / ( + itemStack.getEnchantmentLevel(mcMMO.p.getEnchantmentMapper().getUnbreaking()) + 1)), + maxDurability * maxDamageModifier); - itemStack.setDurability((short) Math.min(itemStack.getDurability() + durabilityModifier, maxDurability)); + itemStack.setDurability( + (short) Math.min(itemStack.getDurability() + durabilityModifier, maxDurability)); } @Nullable public static Material getRepairAndSalvageItem(@NotNull ItemStack inHand) { - if (ItemUtils.isDiamondTool(inHand) || ItemUtils.isDiamondArmor(inHand)) { + if (ItemUtils.isPrismarineTool(inHand)) { + return Material.PRISMARINE_CRYSTALS; + } else if (ItemUtils.isNetheriteTool(inHand) || ItemUtils.isNetheriteArmor(inHand)) { + return Material.NETHERITE_SCRAP; + } else if (ItemUtils.isDiamondTool(inHand) || ItemUtils.isDiamondArmor(inHand)) { return Material.DIAMOND; - } - else if (ItemUtils.isGoldTool(inHand) || ItemUtils.isGoldArmor(inHand)) { + } else if (ItemUtils.isGoldTool(inHand) || ItemUtils.isGoldArmor(inHand)) { return Material.GOLD_INGOT; - } - else if (ItemUtils.isIronTool(inHand) || ItemUtils.isIronArmor(inHand)) { + } else if (ItemUtils.isIronTool(inHand) || ItemUtils.isIronArmor(inHand)) { return Material.IRON_INGOT; - } - else if (ItemUtils.isStoneTool(inHand)) { + } else if (ItemUtils.isStoneTool(inHand)) { return Material.COBBLESTONE; - } - else if (ItemUtils.isWoodTool(inHand)) { + } else if (ItemUtils.isWoodTool(inHand)) { return Material.OAK_WOOD; - } - else if (ItemUtils.isLeatherArmor(inHand)) { + } else if (ItemUtils.isLeatherArmor(inHand)) { return Material.LEATHER; - } - else if (ItemUtils.isStringTool(inHand)) { + } else if (ItemUtils.isStringTool(inHand)) { return Material.STRING; - } - else { + } else { return null; } } @@ -317,21 +346,29 @@ public final class SkillUtils { return getRepairAndSalvageQuantities(item.getType(), getRepairAndSalvageItem(item)); } - public static int getRepairAndSalvageQuantities(Material itemMaterial, Material recipeMaterial) { + public static int getRepairAndSalvageQuantities(Material itemMaterial, + Material recipeMaterial) { int quantity = 0; - if(mcMMO.getMaterialMapStore().isNetheriteTool(itemMaterial) || mcMMO.getMaterialMapStore().isNetheriteArmor(itemMaterial)) { + if (mcMMO.getMaterialMapStore().isPrismarineTool(itemMaterial)) { + return 16; + } + + if (mcMMO.getMaterialMapStore().isNetheriteTool(itemMaterial) + || mcMMO.getMaterialMapStore().isNetheriteArmor(itemMaterial)) { //One netherite bar requires 4 netherite scraps return 4; } - for(Iterator recipeIterator = Bukkit.getServer().recipeIterator(); recipeIterator.hasNext();) { + for (Iterator recipeIterator = Bukkit.getServer().recipeIterator(); + recipeIterator.hasNext(); ) { Recipe bukkitRecipe = recipeIterator.next(); - if(bukkitRecipe.getResult().getType() != itemMaterial) + if (bukkitRecipe.getResult().getType() != itemMaterial) { continue; + } - if(bukkitRecipe instanceof ShapelessRecipe) { + if (bukkitRecipe instanceof ShapelessRecipe) { for (ItemStack ingredient : ((ShapelessRecipe) bukkitRecipe).getIngredientList()) { if (ingredient != null && (recipeMaterial == null || ingredient.getType() == recipeMaterial) @@ -339,8 +376,9 @@ public final class SkillUtils { quantity += ingredient.getAmount(); } } - } else if(bukkitRecipe instanceof ShapedRecipe) { - for (ItemStack ingredient : ((ShapedRecipe) bukkitRecipe).getIngredientMap().values()) { + } else if (bukkitRecipe instanceof ShapedRecipe) { + for (ItemStack ingredient : ((ShapedRecipe) bukkitRecipe).getIngredientMap() + .values()) { if (ingredient != null && (recipeMaterial == null || ingredient.getType() == recipeMaterial) && (ingredient.getType() == recipeMaterial)) { @@ -352,4 +390,16 @@ public final class SkillUtils { 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, @NotNull SubSkillType subSkillType) { + return Permissions.isSubSkillEnabled(player, subSkillType) && RankUtils.hasUnlockedSubskill( + player, subSkillType); + } } diff --git a/src/main/java/com/gmail/nossr50/util/skills/SmeltingTracker.java b/src/main/java/com/gmail/nossr50/util/skills/SmeltingTracker.java deleted file mode 100644 index 83e993a10..000000000 --- a/src/main/java/com/gmail/nossr50/util/skills/SmeltingTracker.java +++ /dev/null @@ -1,102 +0,0 @@ -package com.gmail.nossr50.util.skills; - -import com.gmail.nossr50.datatypes.player.McMMOPlayer; -import com.gmail.nossr50.datatypes.skills.PrimarySkillType; -import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.util.player.UserManager; -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.OfflinePlayer; -import org.bukkit.block.Furnace; -import org.bukkit.entity.Player; -import org.bukkit.inventory.FurnaceInventory; -import org.bukkit.inventory.Inventory; -import org.jetbrains.annotations.Nullable; - -import java.util.UUID; - -public class SmeltingTracker { - -// private final HashMap furnaceOwners; - - private void changeFurnaceOwnership(Furnace furnace, Player player) { - - McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player); - - /* - Debug output - */ - printOwnershipGainDebug(furnace, mcMMOPlayer); - - printOwnershipLossDebug(furnace); - - setFurnaceOwner(furnace, player); - } - - private void setFurnaceOwner(Furnace furnace, Player player) { - mcMMO.getMetadataService().getBlockMetadataService().setFurnaceOwner(furnace, player.getUniqueId()); - } - - private void printOwnershipGainDebug(Furnace furnace, McMMOPlayer mcMMOPlayer) { - if(mcMMOPlayer != null) { - if(mcMMOPlayer.isDebugMode()) { - mcMMOPlayer.getPlayer().sendMessage("Furnace ownership " + - ChatColor.GREEN +"gained " + ChatColor.RESET + - "at location: " + furnace.getLocation().toString()); - } - - } - } - - private void printOwnershipLossDebug(Furnace furnace) { - OfflinePlayer furnaceOwner = getFurnaceOwner(furnace); - - if(furnaceOwner != null && furnaceOwner.isOnline()) { - McMMOPlayer furnaceOwnerProfile = UserManager.getPlayer(furnaceOwner.getPlayer()); - - if(furnaceOwnerProfile != null) { - if(furnaceOwnerProfile.isDebugMode()) { - furnaceOwnerProfile.getPlayer().sendMessage("Furnace ownership " + - ChatColor.RED + "lost " + ChatColor.RESET + - "at location: " + furnace.getLocation().toString()); - } - } - } - } - - public @Nullable OfflinePlayer getFurnaceOwner(Furnace furnace) { - UUID uuid = mcMMO.getMetadataService().getBlockMetadataService().getFurnaceOwner(furnace); - - if(uuid != null) { - return Bukkit.getOfflinePlayer(uuid); - } else { - return null; - } - } - - @Nullable - public Furnace getFurnaceFromInventory(Inventory inventory) { - if (!(inventory instanceof FurnaceInventory)) { - return null; - } - - return (Furnace) inventory.getHolder(); - } - - public boolean isFurnaceOwned(Furnace furnace) { - return getFurnaceOwner(furnace) != null; - } - - public void processFurnaceOwnership(Furnace furnace, Player player) { - if(!mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, PrimarySkillType.SMELTING)) - return; - - //Don't swap ownership if its the same player - if(getFurnaceOwner(furnace) != null) { - if(getFurnaceOwner(furnace).getUniqueId().equals(player.getUniqueId())) - return; - } - - changeFurnaceOwnership(furnace, player); - } -} diff --git a/src/main/java/com/gmail/nossr50/util/sounds/SoundManager.java b/src/main/java/com/gmail/nossr50/util/sounds/SoundManager.java index e3b21da03..a345f1bc7 100644 --- a/src/main/java/com/gmail/nossr50/util/sounds/SoundManager.java +++ b/src/main/java/com/gmail/nossr50/util/sounds/SoundManager.java @@ -2,6 +2,8 @@ package com.gmail.nossr50.util.sounds; import com.gmail.nossr50.config.SoundConfig; import com.gmail.nossr50.util.Misc; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import org.bukkit.Location; import org.bukkit.Sound; import org.bukkit.SoundCategory; @@ -9,63 +11,103 @@ import org.bukkit.World; import org.bukkit.entity.Player; public class SoundManager { + private static Sound CRIPPLE_SOUND; + + private static final String ITEM_MACE_SMASH_GROUND = "ITEM_MACE_SMASH_GROUND"; + + private static final String VALUE_OF = "valueOf"; + + private static final String ORG_BUKKIT_SOUND = "org.bukkit.Sound"; + /** * Sends a sound to the player + * * @param soundType the type of sound */ - public static void sendSound(Player player, Location location, SoundType soundType) - { - if(SoundConfig.getInstance().getIsEnabled(soundType)) - player.playSound(location, getSound(soundType), SoundCategory.MASTER, getVolume(soundType), getPitch(soundType)); + public static void sendSound(Player player, Location location, SoundType soundType) { + if (SoundConfig.getInstance().getIsEnabled(soundType)) { + player.playSound(location, getSound(soundType), + SoundCategory.MASTER, getVolume(soundType), getPitch(soundType)); + } } - public static void sendCategorizedSound(Player player, Location location, SoundType soundType, SoundCategory soundCategory) - { - if(SoundConfig.getInstance().getIsEnabled(soundType)) - player.playSound(location, getSound(soundType), soundCategory, getVolume(soundType), getPitch(soundType)); + public static void sendCategorizedSound(Location location, SoundType soundType, + SoundCategory soundCategory) { + if (SoundConfig.getInstance().getIsEnabled(soundType)) { + final World world = location.getWorld(); + if (world != null) { + world.playSound(location, getSound(soundType), soundCategory, + getVolume(soundType), getPitch(soundType)); + } + } } - public static void sendCategorizedSound(Player player, Location location, SoundType soundType, SoundCategory soundCategory, float pitchModifier) - { + public static void sendCategorizedSound(Location location, SoundType soundType, + SoundCategory soundCategory, + float pitchModifier) { + if (SoundConfig.getInstance().getIsEnabled(soundType)) { + final World world = location.getWorld(); + if (world != null) { + float totalPitch = Math.min(2.0F, (getPitch(soundType) + pitchModifier)); + world.playSound(location, getSound(soundType), soundCategory, getVolume(soundType), + totalPitch); + } + } + } + + public static void sendCategorizedSound(Player player, Location location, + SoundType soundType, SoundCategory soundCategory) { + if (SoundConfig.getInstance().getIsEnabled(soundType)) { + player.playSound(location, getSound(soundType), soundCategory, getVolume(soundType), + getPitch(soundType)); + } + } + + public static void sendCategorizedSound(Player player, Location location, + SoundType soundType, SoundCategory soundCategory, float pitchModifier) { float totalPitch = Math.min(2.0F, (getPitch(soundType) + pitchModifier)); - if(SoundConfig.getInstance().getIsEnabled(soundType)) - player.playSound(location, getSound(soundType), soundCategory, getVolume(soundType), totalPitch); + if (SoundConfig.getInstance().getIsEnabled(soundType)) { + player.playSound(location, getSound(soundType), soundCategory, getVolume(soundType), + totalPitch); + } } - public static void worldSendSound(World world, Location location, SoundType soundType) - { - if(SoundConfig.getInstance().getIsEnabled(soundType)) - world.playSound(location, getSound(soundType), getVolume(soundType), getPitch(soundType)); + public static void worldSendSound(World world, Location location, SoundType soundType) { + if (SoundConfig.getInstance().getIsEnabled(soundType)) { + world.playSound(location, getSound(soundType), getVolume(soundType), + getPitch(soundType)); + } } public static void worldSendSoundMaxPitch(World world, Location location, SoundType soundType) { - if(SoundConfig.getInstance().getIsEnabled(soundType)) + if (SoundConfig.getInstance().getIsEnabled(soundType)) { world.playSound(location, getSound(soundType), getVolume(soundType), 2.0F); + } } /** * All volume is multiplied by the master volume to get its final value + * * @param soundType target soundtype * @return the volume for this soundtype */ - private static float getVolume(SoundType soundType) - { - return SoundConfig.getInstance().getVolume(soundType) * SoundConfig.getInstance().getMasterVolume(); + private static float getVolume(SoundType soundType) { + return SoundConfig.getInstance().getVolume(soundType) * SoundConfig.getInstance() + .getMasterVolume(); } - private static float getPitch(SoundType soundType) - { - if(soundType == SoundType.FIZZ) + private static float getPitch(SoundType soundType) { + if (soundType == SoundType.FIZZ) { return getFizzPitch(); - else if (soundType == SoundType.POP) + } else if (soundType == SoundType.POP) { return getPopPitch(); - else + } else { return SoundConfig.getInstance().getPitch(soundType); + } } - private static Sound getSound(SoundType soundType) - { + private static Sound getSound(SoundType soundType) { return switch (soundType) { case ANVIL -> Sound.BLOCK_ANVIL_PLACE; case ITEM_BREAK -> Sound.ENTITY_ITEM_BREAK; @@ -81,9 +123,29 @@ public class SoundManager { case DEFLECT_ARROWS, BLEED -> Sound.ENTITY_ENDER_EYE_DEATH; case GLASS -> Sound.BLOCK_GLASS_BREAK; case ITEM_CONSUMED -> Sound.ITEM_BOTTLE_EMPTY; + case CRIPPLE -> getCrippleSound(); }; } + private static Sound getCrippleSound() { + if (CRIPPLE_SOUND != null) { + return CRIPPLE_SOUND; + } + + try { + // Spigot changed the class from enum to interface around 1.21.3 + final Class clazz = Class.forName(ORG_BUKKIT_SOUND); + final Method valueOf = clazz.getMethod(VALUE_OF); + CRIPPLE_SOUND = (Sound) valueOf.invoke(null, ITEM_MACE_SMASH_GROUND); + } catch (IllegalArgumentException | ClassNotFoundException | NoSuchMethodException | + InvocationTargetException + | IllegalAccessException e) { + CRIPPLE_SOUND = Sound.BLOCK_ANVIL_PLACE; + } + + return CRIPPLE_SOUND; + } + public static float getFizzPitch() { return 2.6F + (Misc.getRandom().nextFloat() - Misc.getRandom().nextFloat()) * 0.8F; } diff --git a/src/main/java/com/gmail/nossr50/util/sounds/SoundType.java b/src/main/java/com/gmail/nossr50/util/sounds/SoundType.java index 67e9b0e0b..7a0056537 100644 --- a/src/main/java/com/gmail/nossr50/util/sounds/SoundType.java +++ b/src/main/java/com/gmail/nossr50/util/sounds/SoundType.java @@ -16,11 +16,11 @@ public enum SoundType { BLEED, GLASS, ITEM_CONSUMED, + CRIPPLE, TIRED; - public boolean usesCustomPitch() - { - switch(this){ + public boolean usesCustomPitch() { + switch (this) { case POP: case FIZZ: return true; diff --git a/src/main/java/com/gmail/nossr50/util/text/ConfigStringUtils.java b/src/main/java/com/gmail/nossr50/util/text/ConfigStringUtils.java new file mode 100644 index 000000000..32ec8f33e --- /dev/null +++ b/src/main/java/com/gmail/nossr50/util/text/ConfigStringUtils.java @@ -0,0 +1,74 @@ +package com.gmail.nossr50.util.text; + +import static com.gmail.nossr50.util.text.StringUtils.getCapitalized; + +import com.gmail.nossr50.datatypes.party.PartyFeature; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Function; +import org.bukkit.Material; +import org.bukkit.entity.EntityType; +import org.jetbrains.annotations.NotNull; + +/** + * Utility class for String operations, including formatting and caching deterministic results to + * improve performance. + */ +public class ConfigStringUtils { + public static final String UNDERSCORE = "_"; + public static final String SPACE = " "; + + // Using concurrent hash maps to avoid concurrency issues (Folia) + private static final Map configEntityStrings = new ConcurrentHashMap<>(); + private static final Map configMaterialStrings = new ConcurrentHashMap<>(); + private static final Map configPartyFeatureStrings = new ConcurrentHashMap<>(); + + public static String getMaterialConfigString(Material material) { + return configMaterialStrings.computeIfAbsent(material, + ConfigStringUtils::createConfigFriendlyString); + } + + public static String getConfigEntityTypeString(EntityType entityType) { + return configEntityStrings.computeIfAbsent(entityType, + ConfigStringUtils::createConfigFriendlyString); + } + + public static String getConfigPartyFeatureString(PartyFeature partyFeature) { + return configPartyFeatureStrings.computeIfAbsent(partyFeature, + // For whatever dumb reason, party feature enums got formatted like this... + pf -> createConfigFriendlyString(pf.name()).replace(UNDERSCORE, "")); + } + + private static String createConfigFriendlyString(String baseString) { + return CONFIG_FRIENDLY_STRING_FORMATTER.apply(baseString); + } + + private static final Function CONFIG_FRIENDLY_STRING_FORMATTER = baseString -> { + if (baseString.contains(UNDERSCORE) && !baseString.contains(SPACE)) { + return asConfigFormat(baseString.split(UNDERSCORE)); + } else { + if (baseString.contains(SPACE)) { + return asConfigFormat(baseString.split(SPACE)); + } else { + return getCapitalized(baseString); + } + } + }; + + private static @NotNull String asConfigFormat(String[] substrings) { + final StringBuilder configString = new StringBuilder(); + + for (int i = 0; i < substrings.length; i++) { + configString.append(getCapitalized(substrings[i])); + if (i < substrings.length - 1) { + configString.append(UNDERSCORE); + } + } + + return configString.toString(); + } + + private static String createConfigFriendlyString(Object object) { + return createConfigFriendlyString(object.toString()); + } +} diff --git a/src/main/java/com/gmail/nossr50/util/text/McMMOMessageType.java b/src/main/java/com/gmail/nossr50/util/text/McMMOMessageType.java index f4fb0d7bb..8ac40fd80 100644 --- a/src/main/java/com/gmail/nossr50/util/text/McMMOMessageType.java +++ b/src/main/java/com/gmail/nossr50/util/text/McMMOMessageType.java @@ -1,15 +1,15 @@ package com.gmail.nossr50.util.text; +import java.util.function.BiConsumer; import net.kyori.adventure.audience.Audience; import net.kyori.adventure.audience.MessageType; import net.kyori.adventure.identity.Identity; import net.kyori.adventure.text.Component; -import java.util.function.BiConsumer; - public enum McMMOMessageType { ACTION_BAR(Audience::sendActionBar), - SYSTEM((audience, message) -> audience.sendMessage(Identity.nil(), message, MessageType.SYSTEM)); + SYSTEM((audience, message) -> audience.sendMessage(Identity.nil(), message, + MessageType.SYSTEM)); private final BiConsumer sender; @@ -18,6 +18,6 @@ public enum McMMOMessageType { } public void send(final Audience audience, final Component message) { - this.sender.accept(audience, message); + this.sender.accept(audience, message); } } diff --git a/src/main/java/com/gmail/nossr50/util/text/StringUtils.java b/src/main/java/com/gmail/nossr50/util/text/StringUtils.java index d0252a846..73ca90919 100644 --- a/src/main/java/com/gmail/nossr50/util/text/StringUtils.java +++ b/src/main/java/com/gmail/nossr50/util/text/StringUtils.java @@ -1,189 +1,192 @@ package com.gmail.nossr50.util.text; -import com.gmail.nossr50.datatypes.party.PartyFeature; +import static java.util.Objects.requireNonNull; + import com.gmail.nossr50.datatypes.skills.SuperAbilityType; +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.util.Locale; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Function; import org.bukkit.Material; -import org.bukkit.block.data.Ageable; -import org.bukkit.block.data.BlockData; import org.bukkit.entity.EntityType; import org.jetbrains.annotations.NotNull; -import java.text.DecimalFormat; -import java.util.Locale; - +/** + * Utility class for String operations, including formatting and caching deterministic results to + * improve performance. + */ public class StringUtils { - protected static DecimalFormat percent = new DecimalFormat("##0.00%"); - protected static DecimalFormat shortDecimal = new DecimalFormat("##0.0"); + protected static final DecimalFormat percent = new DecimalFormat("##0.00%", + DecimalFormatSymbols.getInstance(Locale.US)); + protected static final DecimalFormat shortDecimal = new DecimalFormat("##0.0", + DecimalFormatSymbols.getInstance(Locale.US)); + + // Using concurrent hash maps to avoid concurrency issues (Folia) + private static final Map formattedEntityStrings = new ConcurrentHashMap<>(); + private static final Map formattedSuperAbilityStrings = new ConcurrentHashMap<>(); + private static final Map formattedMaterialStrings = new ConcurrentHashMap<>(); /** - * Gets a capitalized version of the target string. + * Gets a capitalized version of the target string. Results are cached to improve performance. * - * @param target - * String to capitalize + * @param target String to capitalize * @return the capitalized string */ public static String getCapitalized(String target) { - return target.substring(0, 1).toUpperCase() + target.substring(1).toLowerCase(Locale.ENGLISH); + if (target == null || target.isEmpty()) { + return target; + } + return target.substring(0, 1).toUpperCase(Locale.ENGLISH) + target.substring(1) + .toLowerCase(Locale.ENGLISH); } + /** + * Converts ticks to seconds, formatted to one decimal place. + * + * @param ticks Number of ticks + * @return String representation of seconds + */ public static String ticksToSeconds(double ticks) { return shortDecimal.format(ticks / 20); } - public static String convertToCamelCaseString(String baseString, String splitBy) { - String[] substrings = baseString.split(splitBy); - String prettyString = ""; - int size = 1; - - for (String string : substrings) { - prettyString = prettyString.concat(getCapitalized(string)); - - if (size < substrings.length) { - prettyString = prettyString.concat(""); - } - - size++; - } - - return prettyString; - } - - public static String getPrettyCamelCaseName(Object o) { - return StringUtils.convertToCamelCaseString(o.toString(), "_"); - } - - public static String getPrettySuperAbilityName(SuperAbilityType superAbilityType) { - return StringUtils.getPrettySuperAbilityString(superAbilityType); - } - - public static String getPrettySuperAbilityString(SuperAbilityType ability) { - return createPrettyString(ability.toString()); + /** + * Gets a pretty string representation of a SuperAbilityType. Results are cached to improve + * performance. + * + * @param superAbilityType SuperAbilityType to convert + * @return Pretty string representation of the SuperAbilityType + */ + public static String getPrettySuperAbilityString(SuperAbilityType superAbilityType) { + requireNonNull(superAbilityType, "superAbilityType cannot be null"); + return formattedSuperAbilityStrings.computeIfAbsent(superAbilityType, + StringUtils::createPrettyString); } /** - * Creates a string from an array skipping the first n elements - * @param args the array to iterate over when forming the string - * @param index the amount of elements to skip over - * @return the "trimmed" string + * Creates a string from an array skipping the first n elements. + * + * @param args The array to iterate over when forming the string + * @param index The number of elements to skip over + * @return The "trimmed" string */ - public static String buildStringAfterNthElement(@NotNull String @NotNull []args, int index) { - StringBuilder trimMessage = new StringBuilder(); + public static String buildStringAfterNthElement(@NotNull String @NotNull [] args, int index) { + if (index < 0) { + throw new IllegalArgumentException("Index must be greater than or equal to 0"); + } + + final StringBuilder trimMessage = new StringBuilder(); for (int i = index; i < args.length; i++) { - if(i + 1 >= args.length) - trimMessage.append(args[i]); - else - trimMessage.append(args[i]).append(" "); + if (i > index) { + trimMessage.append(' '); + } + trimMessage.append(args[i]); } return trimMessage.toString(); } - public static String getPrettyItemString(Material material) { - return createPrettyString(material.toString()); - } - - public static String getPrettyEntityTypeString(EntityType entity) { - return createPrettyString(entity.toString()); - } - - public static String getPrettyAbilityString(SuperAbilityType ability) { - return createPrettyString(ability.toString()); - } - - public static String getWildcardConfigBlockDataString(BlockData data) { - return getWildcardConfigMaterialString(data.getMaterial()); - } - - public static String getWildcardConfigMaterialString(Material data) { - return StringUtils.getPrettyItemString(data).replace(" ", "_") + "|*"; - } - - public static String getFriendlyConfigBlockDataString(BlockData data) { - switch(data.getMaterial()){ - case CHORUS_FLOWER: - case COCOA: - case WHEAT: - case BEETROOTS: - case CARROTS: - case POTATOES: - case NETHER_WART: { - if (data instanceof Ageable ageData) { - if (ageData.getAge() == ageData.getMaximumAge()) { - return getPrettyItemString(data.getMaterial()).replace(" ", "_") + "_Ripe"; - } - } - return getPrettyItemString(data.getMaterial()).replace(" ", "_") + "_Ungrown"; - } - } - return getPrettyItemString(data.getMaterial()).replace(" ", "_"); - } - - public static String getFriendlyConfigMaterialString(Material data) { - return getPrettyItemString(data).replace(" ", "_"); - } - - public static String getExplicitConfigBlockDataString(BlockData data) { - return getExplicitConfigMaterialString(data.getMaterial()); - } - - public static String getExplicitConfigMaterialString(Material data) { - return StringUtils.getPrettyItemString(data).replace(" ", "_"); - } - - public static String getPrettyPartyFeatureString(PartyFeature partyFeature) { - return createPrettyString(partyFeature.toString()); - } - - private static String createPrettyString(String baseString) { - String[] substrings = baseString.split("_"); - String prettyString = ""; - int size = 1; - - for (String string : substrings) { - prettyString = prettyString.concat(getCapitalized(string)); - - if (size < substrings.length) { - prettyString = prettyString.concat(" "); - } - - size++; - } - - return prettyString; + /** + * Gets a pretty string representation of a Material. Results are cached to improve + * performance. + * + * @param material Material to convert + * @return Pretty string representation of the Material + */ + public static String getPrettyMaterialString(Material material) { + return formattedMaterialStrings.computeIfAbsent(material, StringUtils::createPrettyString); } /** - * Determine if a string represents an Integer + * Gets a pretty string representation of an EntityType. Results are cached to improve + * performance. * - * @param string - * String to check + * @param entityType EntityType to convert + * @return Pretty string representation of the EntityType + */ + public static String getPrettyEntityTypeString(EntityType entityType) { + return formattedEntityStrings.computeIfAbsent(entityType, StringUtils::createPrettyString); + } + + /** + * Creates a pretty string from a base string by splitting underscores and capitalizing words. + * + * @param baseString String to convert + * @return Pretty string + */ + private static String createPrettyString(String baseString) { + return PRETTY_STRING_FUNC.apply(baseString); + } + + /** + * Function to create a pretty string from a base string. + */ + private static final Function PRETTY_STRING_FUNC = baseString -> { + if (baseString.contains("_") && !baseString.contains(" ")) { + return prettify(baseString.split("_")); + } else { + if (baseString.contains(" ")) { + return prettify(baseString.split(" ")); + } else { + return getCapitalized(baseString); + } + } + }; + + private static @NotNull String prettify(String[] substrings) { + final StringBuilder prettyString = new StringBuilder(); + + for (int i = 0; i < substrings.length; i++) { + prettyString.append(getCapitalized(substrings[i])); + if (i < substrings.length - 1) { + prettyString.append(' '); + } + } + + return prettyString.toString(); + } + + /** + * Creates a pretty string from an object. + * + * @param object Object to convert + * @return Pretty string representation of the object + */ + private static String createPrettyString(Object object) { + return createPrettyString(object.toString()); + } + + /** + * Determine if a string represents an Integer. + * + * @param string String to check * @return true if the string is an Integer, false otherwise */ public static boolean isInt(String string) { try { Integer.parseInt(string); return true; - } catch (NumberFormatException nFE) { + } catch (NumberFormatException ignored) { return false; } } /** - * Determine if a string represents a Double + * Determine if a string represents a Double. * - * @param string - * String to check + * @param string String to check * @return true if the string is a Double, false otherwise */ public static boolean isDouble(String string) { try { Double.parseDouble(string); return true; - } catch (NumberFormatException nFE) { + } catch (NumberFormatException ignored) { return false; } } - } 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 81ac8da28..16d10ed09 100644 --- a/src/main/java/com/gmail/nossr50/util/text/TextComponentFactory.java +++ b/src/main/java/com/gmail/nossr50/util/text/TextComponentFactory.java @@ -10,7 +10,11 @@ import com.gmail.nossr50.listeners.InteractionManager; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.Permissions; +import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.skills.RankUtils; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; import net.kyori.adventure.audience.Audience; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.TextComponent; @@ -19,23 +23,21 @@ import net.kyori.adventure.text.event.HoverEvent; import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.TextColor; import net.kyori.adventure.text.format.TextDecoration; +import org.bukkit.ChatColor; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; - /** * This class handles many of the JSON components that mcMMO makes and uses */ public class TextComponentFactory { /** - * Makes a text component using strings from a locale and supports passing an undefined number of variables to the LocaleLoader + * Makes a text component using strings from a locale and supports passing an undefined number + * of variables to the LocaleLoader * * @param localeKey target locale string address - * @param values vars to be passed to the locale loader + * @param values vars to be passed to the locale loader * @return */ public static TextComponent getNotificationMultipleValues(String localeKey, String... values) { @@ -47,8 +49,11 @@ public class TextComponentFactory { return getNotificationTextComponent(LocaleLoader.getString(localeKey)); } - public static Component getNotificationLevelUpTextComponent(PrimarySkillType skill, int levelsGained, int currentLevel) { - return Component.text(LocaleLoader.getString("Overhaul.Levelup", LocaleLoader.getString("Overhaul.Name." + StringUtils.getCapitalized(skill.toString())), levelsGained, currentLevel)); + public static Component getNotificationLevelUpTextComponent(PrimarySkillType skill, + int levelsGained, int currentLevel) { + return Component.text(LocaleLoader.getString("Overhaul.Levelup", LocaleLoader.getString( + "Overhaul.Name." + StringUtils.getCapitalized(skill.toString())), levelsGained, + currentLevel)); } private static TextComponent getNotificationTextComponent(String text) { @@ -56,18 +61,28 @@ public class TextComponentFactory { return Component.text(text); } - public static void sendPlayerSubSkillWikiLink(Player player, String subskillformatted) { - if (!mcMMO.p.getGeneralConfig().getUrlLinksEnabled()) - return; + public static String getSubSkillWikiLink(SubSkillType subSkillType) { + return "https://wiki.mcmmo.org/en/skills/" + + subSkillType.getParentSkill().toString().toLowerCase(Locale.ENGLISH) + "#" + + subSkillType.getWikiUrl().toLowerCase(Locale.ENGLISH); + } - TextComponent.Builder wikiLinkComponent = Component.text().content(LocaleLoader.getString("Overhaul.mcMMO.MmoInfo.Wiki")); + public static void sendPlayerSubSkillWikiLink(Player player, String subskillformatted, + SubSkillType subSkillType) { + if (!mcMMO.p.getGeneralConfig().getUrlLinksEnabled()) { + return; + } + + TextComponent.Builder wikiLinkComponent = Component.text() + .content(LocaleLoader.getString("Overhaul.mcMMO.MmoInfo.Wiki")); wikiLinkComponent.decoration(TextDecoration.UNDERLINED, true); - String wikiUrl = "https://wiki.mcmmo.org/" + subskillformatted; + final String subSkillWikiLink = getSubSkillWikiLink(subSkillType); + wikiLinkComponent.clickEvent(ClickEvent.openUrl(subSkillWikiLink)); - wikiLinkComponent.clickEvent(ClickEvent.openUrl(wikiUrl)); - - TextComponent.Builder componentBuilder = Component.text().content(subskillformatted).append(Component.newline()).append(Component.text(wikiUrl)).color(NamedTextColor.GRAY).decoration(TextDecoration.ITALIC, true); + TextComponent.Builder componentBuilder = Component.text().content(subskillformatted) + .append(Component.newline()).append(Component.text(subSkillWikiLink)) + .color(NamedTextColor.GRAY).decoration(TextDecoration.ITALIC, true); wikiLinkComponent.hoverEvent(HoverEvent.showText(componentBuilder.build())); @@ -75,9 +90,11 @@ public class TextComponentFactory { } public static void sendPlayerUrlHeader(Player player) { - TextComponent prefix = Component.text(LocaleLoader.getString("Overhaul.mcMMO.Url.Wrap.Prefix") + " "); + TextComponent prefix = Component.text( + LocaleLoader.getString("Overhaul.mcMMO.Url.Wrap.Prefix") + " "); /*prefix.setColor(ChatColor.DARK_AQUA);*/ - TextComponent suffix = Component.text(" " + LocaleLoader.getString("Overhaul.mcMMO.Url.Wrap.Suffix")); + TextComponent suffix = Component.text( + " " + LocaleLoader.getString("Overhaul.mcMMO.Url.Wrap.Suffix")); /*suffix.setColor(ChatColor.DARK_AQUA);*/ TextComponent emptySpace = Component.space(); @@ -101,18 +118,20 @@ public class TextComponentFactory { } /** - * Sends a player a bunch of text components that represent a list of sub-skills - * Styling and formatting is applied before sending the messages + * Sends a player a bunch of text components that represent a list of sub-skills Styling and + * formatting is applied before sending the messages * - * @param player target player + * @param player target player * @param subSkillComponents the text components representing the sub-skills by name */ - public static void sendPlayerSubSkillList(@NotNull Player player, @NotNull List subSkillComponents) { + public static void sendPlayerSubSkillList(@NotNull Player player, + @NotNull List subSkillComponents) { final Audience audience = mcMMO.getAudiences().player(player); //@ Signs, done for style Component space = Component.space(); - TextComponent atSignComponent = Component.text(LocaleLoader.getString("JSON.Hover.AtSymbolSkills")); + TextComponent atSignComponent = Component.text( + LocaleLoader.getString("JSON.Hover.AtSymbolSkills")); //Only send 3 sub-skills per line Component[][] splitSubSkills = TextUtils.splitComponentsIntoGroups(subSkillComponents, 3); @@ -133,38 +152,43 @@ public class TextComponentFactory { TextComponent.Builder webTextComponent; switch (webLinks) { - case WEBSITE: - webTextComponent = Component.text().content(LocaleLoader.getString("JSON.Hover.AtSymbolURL")); + case WEBSITE -> { + webTextComponent = Component.text() + .content(LocaleLoader.getString("JSON.Hover.AtSymbolURL")); TextUtils.addChildWebComponent(webTextComponent, "Web"); webTextComponent.clickEvent(getUrlClickEvent(McMMOUrl.urlWebsite)); - break; - case SPIGOT: - webTextComponent = Component.text().content(LocaleLoader.getString("JSON.Hover.AtSymbolURL")); + } + case SPIGOT -> { + webTextComponent = Component.text() + .content(LocaleLoader.getString("JSON.Hover.AtSymbolURL")); TextUtils.addChildWebComponent(webTextComponent, "Spigot"); webTextComponent.clickEvent(getUrlClickEvent(McMMOUrl.urlSpigot)); - break; - case DISCORD: - webTextComponent = Component.text().content(LocaleLoader.getString("JSON.Hover.AtSymbolURL")); + } + case DISCORD -> { + webTextComponent = Component.text() + .content(LocaleLoader.getString("JSON.Hover.AtSymbolURL")); TextUtils.addChildWebComponent(webTextComponent, "Discord"); webTextComponent.clickEvent(getUrlClickEvent(McMMOUrl.urlDiscord)); - break; - case PATREON: - webTextComponent = Component.text().content(LocaleLoader.getString("JSON.Hover.AtSymbolURL")); + } + case PATREON -> { + webTextComponent = Component.text() + .content(LocaleLoader.getString("JSON.Hover.AtSymbolURL")); TextUtils.addChildWebComponent(webTextComponent, "Patreon"); webTextComponent.clickEvent(getUrlClickEvent(McMMOUrl.urlPatreon)); - break; - case WIKI: - webTextComponent = Component.text().content(LocaleLoader.getString("JSON.Hover.AtSymbolURL")); + } + case WIKI -> { + webTextComponent = Component.text() + .content(LocaleLoader.getString("JSON.Hover.AtSymbolURL")); TextUtils.addChildWebComponent(webTextComponent, "Wiki"); webTextComponent.clickEvent(getUrlClickEvent(McMMOUrl.urlWiki)); - break; - case HELP_TRANSLATE: - webTextComponent = Component.text().content(LocaleLoader.getString("JSON.Hover.AtSymbolURL")); + } + 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)); @@ -177,52 +201,70 @@ public class TextComponentFactory { TextComponent.Builder componentBuilder = Component.text().content(webLinks.getNiceTitle()); switch (webLinks) { - case WEBSITE: + 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: + 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)); + } + 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: + componentBuilder.append( + Component.text(webLinks.getLocaleDescription(), NamedTextColor.GREEN)); + componentBuilder.append( + Component.text("\nI post regularly in the discussion thread here!", + NamedTextColor.GRAY)); + } + case PATREON -> { addUrlHeaderHover(webLinks, componentBuilder); componentBuilder.append(Component.newline()).append(Component.newline()); - componentBuilder.append(Component.text(webLinks.getLocaleDescription(), NamedTextColor.GREEN)); + 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: + componentBuilder.append(Component.text("Show support by buying me a coffee :)", + NamedTextColor.GRAY)); + } + case WIKI -> { addUrlHeaderHover(webLinks, componentBuilder); componentBuilder.append(Component.newline()).append(Component.newline()); - componentBuilder.append(Component.text(webLinks.getLocaleDescription(), NamedTextColor.GREEN)); + 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: + componentBuilder.append(Component.text( + "I'm looking for more wiki staff, contact me on our discord!", + NamedTextColor.DARK_GRAY)); + } + case DISCORD -> { addUrlHeaderHover(webLinks, componentBuilder); componentBuilder.append(Component.newline()).append(Component.newline()); - componentBuilder.append(Component.text(webLinks.getLocaleDescription(), NamedTextColor.GREEN)); - break; - case HELP_TRANSLATE: + componentBuilder.append( + Component.text(webLinks.getLocaleDescription(), NamedTextColor.GREEN)); + } + case HELP_TRANSLATE -> { addUrlHeaderHover(webLinks, componentBuilder); componentBuilder.append(Component.newline()).append(Component.newline()); - componentBuilder.append(Component.text(webLinks.getLocaleDescription(), NamedTextColor.GREEN)); + 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)); + 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)); + } } return componentBuilder.build(); } - private static void addUrlHeaderHover(McMMOWebLinks webLinks, TextComponent.Builder componentBuilder) { + private static void addUrlHeaderHover(McMMOWebLinks webLinks, + TextComponent.Builder componentBuilder) { componentBuilder.append(Component.newline()); - componentBuilder.append(Component.text(webLinks.getUrl(), NamedTextColor.GRAY, TextDecoration.ITALIC)); + componentBuilder.append( + Component.text(webLinks.getUrl(), NamedTextColor.GRAY, TextDecoration.ITALIC)); } private static ClickEvent getUrlClickEvent(String url) { @@ -230,15 +272,17 @@ public class TextComponentFactory { } private static Component getSubSkillTextComponent(Player player, SubSkillType subSkillType) { - //Get skill name - String skillName = subSkillType.getLocaleName(); + //Get skill name and strip it of color + final String skillName = ChatColor.stripColor(subSkillType.getLocaleName()); boolean skillUnlocked = RankUtils.hasUnlockedSubskill(player, subSkillType); - TextComponent.Builder textComponent = initNewSkillTextComponent(player, skillName, subSkillType, skillUnlocked); + TextComponent.Builder textComponent = initNewSkillTextComponent(player, skillName, + subSkillType, skillUnlocked); //Hover Event - TextUtils.addNewHoverComponentToTextComponent(textComponent, getSubSkillHoverComponent(player, subSkillType)); + TextUtils.addNewHoverComponentToTextComponent(textComponent, + getSubSkillHoverComponent(player, subSkillType)); //Insertion textComponent.insertion(skillName); @@ -246,7 +290,8 @@ public class TextComponentFactory { return textComponent.build(); } - private static TextComponent getSubSkillTextComponent(Player player, AbstractSubSkill abstractSubSkill) { + private static TextComponent getSubSkillTextComponent(Player player, + AbstractSubSkill abstractSubSkill) { //String key = abstractSubSkill.getConfigKeyName(); String skillName = abstractSubSkill.getNiceName(); @@ -255,10 +300,12 @@ public class TextComponentFactory { boolean skillUnlocked = RankUtils.hasUnlockedSubskill(player, subSkillType); - TextComponent.Builder textComponent = initNewSkillTextComponent(player, skillName, subSkillType, skillUnlocked); + TextComponent.Builder textComponent = initNewSkillTextComponent(player, skillName, + subSkillType, skillUnlocked); //Hover Event - TextUtils.addNewHoverComponentToTextComponent(textComponent, getSubSkillHoverComponent(player, abstractSubSkill)); + TextUtils.addNewHoverComponentToTextComponent(textComponent, + getSubSkillHoverComponent(player, abstractSubSkill)); //Insertion textComponent.insertion(skillName); @@ -266,15 +313,21 @@ public class TextComponentFactory { return textComponent.build(); } - private static TextComponent.Builder initNewSkillTextComponent(Player player, String skillName, SubSkillType subSkillType, boolean skillUnlocked) { + private static TextComponent.Builder initNewSkillTextComponent(Player player, String skillName, + SubSkillType subSkillType, boolean skillUnlocked) { TextComponent.Builder textComponent; if (skillUnlocked) { - if (RankUtils.getHighestRank(subSkillType) == RankUtils.getRank(player, subSkillType) && subSkillType.getNumRanks() > 1) - textComponent = Component.text().content(LocaleLoader.getString("JSON.Hover.MaxRankSkillName", skillName)); - else - textComponent = Component.text().content(LocaleLoader.getString("JSON.Hover.SkillName", skillName)); + if (RankUtils.getHighestRank(subSkillType) == RankUtils.getRank(player, subSkillType) + && subSkillType.getNumRanks() > 1) { + textComponent = Component.text() + .content(LocaleLoader.getString("JSON.Hover.MaxRankSkillName", skillName)); + } else { + textComponent = Component.text() + .content(LocaleLoader.getString("JSON.Hover.SkillName", skillName)); + } - textComponent.clickEvent(ClickEvent.runCommand("/mmoinfo " + subSkillType.getNiceNameNoSpaces(subSkillType))); + textComponent.clickEvent(ClickEvent.runCommand( + "/mmoinfo " + subSkillType.getNiceNameNoSpaces(subSkillType))); } else { textComponent = Component.text().content(LocaleLoader.getString("JSON.Hover.Mystery", @@ -285,7 +338,8 @@ public class TextComponentFactory { return textComponent; } - private static Component getSubSkillHoverComponent(Player player, AbstractSubSkill abstractSubSkill) { + private static Component getSubSkillHoverComponent(Player player, + AbstractSubSkill abstractSubSkill) { return getSubSkillHoverEventJSON(abstractSubSkill, player); } @@ -297,11 +351,12 @@ public class TextComponentFactory { * Used for the skill in the new skill system (Deriving from AbstractSubSkill) * * @param abstractSubSkill this subskill - * @param player the player who owns this subskill + * @param player the player who owns this subskill * @return the hover basecomponent object for this subskill */ - private static Component getSubSkillHoverEventJSON(AbstractSubSkill abstractSubSkill, Player player) { - String skillName = abstractSubSkill.getNiceName(); + private static Component getSubSkillHoverEventJSON(AbstractSubSkill abstractSubSkill, + Player player) { + String skillName = ChatColor.stripColor(abstractSubSkill.getNiceName()); /* * Hover Event BaseComponent color table @@ -313,11 +368,13 @@ public class TextComponentFactory { SubSkillType subSkillType = abstractSubSkill.getSubSkillType(); //SubSkillType Name - TextComponent.Builder componentBuilder = setupSkillComponentNameStyle(player, skillName, subSkillType, RankUtils.hasUnlockedSubskill(player, abstractSubSkill)); + TextComponent.Builder componentBuilder = setupSkillComponentNameStyle(player, skillName, + subSkillType, RankUtils.hasUnlockedSubskill(player, abstractSubSkill)); if (!RankUtils.hasUnlockedSubskill(player, abstractSubSkill)) { //Skill is not unlocked yet - addLocked(abstractSubSkill, ccLocked, ccLevelRequirement, ccLevelRequired, componentBuilder); + addLocked(abstractSubSkill, ccLocked, ccLevelRequirement, ccLevelRequired, + componentBuilder); } else { addSubSkillTypeToHoverEventJSON(abstractSubSkill, componentBuilder); @@ -329,32 +386,43 @@ public class TextComponentFactory { nextRank = RankUtils.getRankUnlockLevel(abstractSubSkill, curRank + 1); } - addRanked(componentBuilder, abstractSubSkill.getNumRanks(), RankUtils.getRank(player, abstractSubSkill), nextRank); + addRanked(componentBuilder, abstractSubSkill.getNumRanks(), + RankUtils.getRank(player, abstractSubSkill), nextRank); - componentBuilder.append(Component.text(LocaleLoader.getString("JSON.DescriptionHeader"))); - componentBuilder.append(Component.newline()).append(Component.text(abstractSubSkill.getDescription())).append(Component.newline()); + componentBuilder.append( + Component.text(LocaleLoader.getString("JSON.DescriptionHeader"))); + componentBuilder.append(Component.newline()) + .append(Component.text(abstractSubSkill.getDescription())) + .append(Component.newline()); //Empty line componentBuilder.append(Component.newline()).decoration(TextDecoration.BOLD, false); componentBuilder.append(Component.newline()); //Finally, add details to the tooltip - abstractSubSkill.addStats(componentBuilder, player); + // TODO: pass in McMMOPlayer instead + abstractSubSkill.addStats(componentBuilder, UserManager.getPlayer(player)); } return componentBuilder.build(); } - private static TextComponent.Builder setupSkillComponentNameStyle(Player player, String skillName, SubSkillType subSkillType, boolean skillUnlocked) { + private static TextComponent.Builder setupSkillComponentNameStyle(Player player, + String skillName, SubSkillType subSkillType, boolean skillUnlocked) { TextComponent.Builder componentBuilder; if (skillUnlocked) { - if (RankUtils.getHighestRank(subSkillType) == RankUtils.getRank(player, subSkillType) && subSkillType.getNumRanks() > 1) - componentBuilder = getNewComponentBuilder(LocaleLoader.getString("JSON.Hover.MaxRankSkillName", skillName)); - else - componentBuilder = getNewComponentBuilder(LocaleLoader.getString("JSON.Hover.SkillName", skillName)); - } else + if (RankUtils.getHighestRank(subSkillType) == RankUtils.getRank(player, subSkillType) + && subSkillType.getNumRanks() > 1) { + componentBuilder = getNewComponentBuilder( + LocaleLoader.getString("JSON.Hover.MaxRankSkillName", skillName)); + } else { + componentBuilder = getNewComponentBuilder( + LocaleLoader.getString("JSON.Hover.SkillName", skillName)); + } + } else { componentBuilder = getNewComponentBuilder(LocaleLoader.getString("JSON.Hover.Mystery", String.valueOf(RankUtils.getUnlockLevel(subSkillType)))); + } return componentBuilder; } @@ -364,37 +432,56 @@ public class TextComponentFactory { return componentBuilder; } - private static void addRanked(TextComponent.Builder componentBuilder, int numRanks, int rank, int nextRank) { + private static void addRanked(TextComponent.Builder componentBuilder, int numRanks, int rank, + int nextRank) { if (numRanks > 0) { //Rank: x - componentBuilder.append(Component.text(LocaleLoader.getString("JSON.Hover.Rank", String.valueOf(rank)))).append(Component.newline()); + componentBuilder.append( + Component.text(LocaleLoader.getString("JSON.Hover.Rank", String.valueOf(rank)))) + .append(Component.newline()); //Next Rank: x - if (nextRank > rank) - componentBuilder.append(Component.text(LocaleLoader.getString("JSON.Hover.NextRank", String.valueOf(nextRank)))).append(Component.newline()); + if (nextRank > rank) { + componentBuilder.append(Component.text( + LocaleLoader.getString("JSON.Hover.NextRank", String.valueOf(nextRank)))) + .append(Component.newline()); + } } } - private static void addLocked(SubSkillType subSkillType, TextColor ccLocked, TextColor ccLevelRequirement, TextColor ccLevelRequired, TextComponent.Builder componentBuilder) { + private static void addLocked(SubSkillType subSkillType, TextColor ccLocked, + TextColor ccLevelRequirement, TextColor ccLevelRequired, + TextComponent.Builder componentBuilder) { addLocked(ccLocked, ccLevelRequirement, componentBuilder); - componentBuilder.append(Component.text(String.valueOf(RankConfig.getInstance().getSubSkillUnlockLevel(subSkillType, 1)), ccLevelRequired)); + componentBuilder.append(Component.text( + String.valueOf(RankConfig.getInstance().getSubSkillUnlockLevel(subSkillType, 1)), + ccLevelRequired)); //componentBuilder.append(Component.newline()); } - private static void addLocked(AbstractSubSkill abstractSubSkill, TextColor ccLocked, TextColor ccLevelRequirement, TextColor ccLevelRequired, TextComponent.Builder componentBuilder) { + private static void addLocked(AbstractSubSkill abstractSubSkill, TextColor ccLocked, + TextColor ccLevelRequirement, TextColor ccLevelRequired, + TextComponent.Builder componentBuilder) { addLocked(ccLocked, ccLevelRequirement, componentBuilder); - componentBuilder.append(Component.text(String.valueOf(RankConfig.getInstance().getSubSkillUnlockLevel(abstractSubSkill, 1)), ccLevelRequired)); + componentBuilder.append(Component.text(String.valueOf( + RankConfig.getInstance().getSubSkillUnlockLevel(abstractSubSkill, 1)), + ccLevelRequired)); //componentBuilder.append(Component.newline()); } - private static void addLocked(TextColor ccLocked, TextColor ccLevelRequirement, TextComponent.Builder componentBuilder) { - componentBuilder.append(Component.text(LocaleLoader.getString("JSON.Locked"), ccLocked, TextDecoration.BOLD)); + private static void addLocked(TextColor ccLocked, TextColor ccLevelRequirement, + TextComponent.Builder componentBuilder) { + componentBuilder.append(Component.text(LocaleLoader.getString("JSON.Locked"), ccLocked, + TextDecoration.BOLD)); componentBuilder.append(Component.newline()).append(Component.newline()); - componentBuilder.append(Component.text(LocaleLoader.getString("JSON.LevelRequirement") + ": ", ccLevelRequirement)); + componentBuilder.append( + Component.text(LocaleLoader.getString("JSON.LevelRequirement") + ": ", + ccLevelRequirement)); } private static Component getSubSkillHoverEventJSON(SubSkillType subSkillType, Player player) { - String skillName = subSkillType.getLocaleName(); + // Get skill name and strip it of color + String skillName = ChatColor.stripColor(subSkillType.getLocaleName()); /* * Hover Event BaseComponent color table @@ -406,11 +493,13 @@ public class TextComponentFactory { TextColor ccLevelRequired = NamedTextColor.RED; //SubSkillType Name - TextComponent.Builder componentBuilder = setupSkillComponentNameStyle(player, skillName, subSkillType, RankUtils.hasUnlockedSubskill(player, subSkillType)); + TextComponent.Builder componentBuilder = setupSkillComponentNameStyle(player, skillName, + subSkillType, RankUtils.hasUnlockedSubskill(player, subSkillType)); if (!RankUtils.hasUnlockedSubskill(player, subSkillType)) { //Skill is not unlocked yet - addLocked(subSkillType, ccLocked, ccLevelRequirement, ccLevelRequired, componentBuilder); + addLocked(subSkillType, ccLocked, ccLevelRequirement, ccLevelRequired, + componentBuilder); } else { //addSubSkillTypeToHoverEventJSON(subSkillType, componentBuilder); @@ -428,18 +517,19 @@ public class TextComponentFactory { } componentBuilder.append(Component.newline()); - componentBuilder.append(Component.text(LocaleLoader.getString("JSON.DescriptionHeader"))); - componentBuilder.color(ccDescriptionHeader); + componentBuilder.append(Component.text(LocaleLoader.getString("JSON.DescriptionHeader")) + .color(ccDescriptionHeader)); componentBuilder.append(Component.newline()); - componentBuilder.append(Component.text(subSkillType.getLocaleDescription())); - componentBuilder.color(ccDescription); + componentBuilder.append( + Component.text(ChatColor.stripColor(subSkillType.getLocaleDescription())) + .color(ccDescription)); } return componentBuilder.build(); } private static void addSubSkillTypeToHoverEventJSON(AbstractSubSkill abstractSubSkill, - TextComponent.Builder componentBuilder) { + TextComponent.Builder componentBuilder) { if (abstractSubSkill.isSuperAbility()) { componentBuilder.append(Component.text(LocaleLoader.getString("JSON.Type.SuperAbility"), NamedTextColor.LIGHT_PURPLE, TextDecoration.BOLD)); @@ -455,18 +545,22 @@ public class TextComponentFactory { } public static void getSubSkillTextComponents(Player player, List textComponents, - PrimarySkillType parentSkill) { + PrimarySkillType parentSkill) { for (SubSkillType subSkillType : SubSkillType.values()) { if (subSkillType.getParentSkill() == parentSkill) { //TODO: Hacky rewrite later //Only some versions of MC have this skill if (subSkillType == SubSkillType.FISHING_MASTER_ANGLER - && mcMMO.getCompatibilityManager().getMasterAnglerCompatibilityLayer() == null) + && mcMMO.getCompatibilityManager().getMasterAnglerCompatibilityLayer() + == null) { continue; + } if (Permissions.isSubSkillEnabled(player, subSkillType)) { - if (!InteractionManager.hasSubSkill(subSkillType)) - textComponents.add(TextComponentFactory.getSubSkillTextComponent(player, subSkillType)); + if (!InteractionManager.hasSubSkill(subSkillType)) { + textComponents.add(TextComponentFactory.getSubSkillTextComponent(player, + subSkillType)); + } } } } @@ -474,16 +568,23 @@ public class TextComponentFactory { /* NEW SKILL SYSTEM */ for (AbstractSubSkill abstractSubSkill : InteractionManager.getSubSkillList()) { if (abstractSubSkill.getPrimarySkill() == parentSkill) { - if (Permissions.isSubSkillEnabled(player, abstractSubSkill)) - textComponents.add(TextComponentFactory.getSubSkillTextComponent(player, abstractSubSkill)); + if (Permissions.isSubSkillEnabled(player, abstractSubSkill.getSubSkillType())) { + textComponents.add(TextComponentFactory.getSubSkillTextComponent(player, + abstractSubSkill)); + } } } } - public static TextComponent getSubSkillUnlockedNotificationComponents(Player player, SubSkillType subSkillType) { - TextComponent.Builder unlockMessage = Component.text().content(LocaleLoader.getString("JSON.SkillUnlockMessage", subSkillType.getLocaleName(), RankUtils.getRank(player, subSkillType))); - unlockMessage.hoverEvent(HoverEvent.showText(getSubSkillHoverComponent(player, subSkillType))); - unlockMessage.clickEvent(ClickEvent.runCommand("/" + subSkillType.getParentSkill().toString().toLowerCase(Locale.ENGLISH))); + public static TextComponent getSubSkillUnlockedNotificationComponents(Player player, + SubSkillType subSkillType) { + TextComponent.Builder unlockMessage = Component.text().content( + LocaleLoader.getString("JSON.SkillUnlockMessage", subSkillType.getLocaleName(), + RankUtils.getRank(player, subSkillType))); + unlockMessage.hoverEvent( + HoverEvent.showText(getSubSkillHoverComponent(player, subSkillType))); + unlockMessage.clickEvent(ClickEvent.runCommand( + "/" + subSkillType.getParentSkill().toString().toLowerCase(Locale.ENGLISH))); return unlockMessage.build(); } } diff --git a/src/main/java/com/gmail/nossr50/util/text/TextUtils.java b/src/main/java/com/gmail/nossr50/util/text/TextUtils.java index 1d3c001d5..aea2a243f 100644 --- a/src/main/java/com/gmail/nossr50/util/text/TextUtils.java +++ b/src/main/java/com/gmail/nossr50/util/text/TextUtils.java @@ -1,6 +1,7 @@ package com.gmail.nossr50.util.text; import com.gmail.nossr50.mcMMO; +import java.util.List; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.ComponentBuilder; import net.kyori.adventure.text.TextComponent; @@ -13,8 +14,6 @@ import net.md_5.bungee.api.chat.BaseComponent; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.List; - public class TextUtils { private static @Nullable LegacyComponentSerializer customLegacySerializer; @@ -23,24 +22,31 @@ public class TextUtils { } /** - * Makes a single component from an array of components, can optionally add prefixes and suffixes to come before and after each component + * Makes a single component from an array of components, can optionally add prefixes and + * suffixes to come before and after each component + * * @param componentsArray target array * @return a component with optional styling built from an array */ - static @NotNull Component fromArray(@NotNull Component[] componentsArray, @Nullable Component prefixComponent, @Nullable Component suffixComponent) { + static @NotNull Component fromArray(@NotNull Component[] componentsArray, + @Nullable Component prefixComponent, @Nullable Component suffixComponent) { TextComponent.Builder componentBuilder = Component.text(); - for(Component component : componentsArray) { - if(component == null) //Individual elements can be null + for (Component component : componentsArray) { + if (component == null) //Individual elements can be null + { continue; + } - if(prefixComponent != null) + if (prefixComponent != null) { componentBuilder.append(prefixComponent); + } componentBuilder.append(component); - if(suffixComponent != null) + if (suffixComponent != null) { componentBuilder.append(suffixComponent); + } } @@ -55,7 +61,8 @@ public class TextUtils { * @param groupsSize maximum size per array * @return a 2D array with components split into groups */ - static @NotNull Component[][] splitComponentsIntoGroups(@NotNull List components, int groupsSize) { + static @NotNull Component[][] splitComponentsIntoGroups(@NotNull List components, + int groupsSize) { int groupCount = (int) Math.ceil((double) components.size() / (double) groupsSize); Component[][] splitGroups = new Component[groupCount][groupsSize]; @@ -64,18 +71,19 @@ public class TextUtils { while (groupsFinished < groupCount) { //Fill group with members - for(int i = 0; i < groupsSize; i++) { - int indexOfPotentialMember = i + (groupsFinished * 3); //Groups don't always fill all members neatly + for (int i = 0; i < groupsSize; i++) { + int indexOfPotentialMember = + i + (groupsFinished * 3); //Groups don't always fill all members neatly //Some groups won't have entirely non-null elements - if(indexOfPotentialMember > components.size()-1) { + if (indexOfPotentialMember > components.size() - 1) { break; } Component potentialMember = components.get(indexOfPotentialMember); //Make sure the potential member exists because of rounding - if(potentialMember != null) { + if (potentialMember != null) { splitGroups[groupsFinished][i] = potentialMember; } } @@ -87,12 +95,14 @@ public class TextUtils { return splitGroups; } - static void addChildWebComponent(@NotNull ComponentBuilder webTextComponent, @NotNull String childName) { + static void addChildWebComponent(@NotNull ComponentBuilder webTextComponent, + @NotNull String childName) { TextComponent childComponent = Component.text(childName).color(NamedTextColor.BLUE); webTextComponent.append(childComponent); } - static void addNewHoverComponentToTextComponent(@NotNull TextComponent.Builder textComponent, @NotNull Component baseComponent) { + static void addNewHoverComponentToTextComponent(@NotNull TextComponent.Builder textComponent, + @NotNull Component baseComponent) { textComponent.hoverEvent(HoverEvent.showText(baseComponent)); } @@ -101,7 +111,9 @@ public class TextUtils { } public static @NotNull TextComponent ofBungeeComponents(@NotNull BaseComponent[] bungeeName) { - return TextComponent.ofChildren(mcMMO.getCompatibilityManager().getBungeeSerializerCompatibilityLayer().deserialize(bungeeName)); + return TextComponent.ofChildren( + mcMMO.getCompatibilityManager().getBungeeSerializerCompatibilityLayer() + .deserialize(bungeeName)); } public static @NotNull TextComponent ofBungeeRawStrings(@NotNull String bungeeRawString) { @@ -113,7 +125,7 @@ public class TextUtils { } public static @NotNull TextComponent colorizeText(@NotNull String rawtext) { - if(customLegacySerializer == null) { + if (customLegacySerializer == null) { customLegacySerializer = getSerializer(); } @@ -139,7 +151,7 @@ public class TextUtils { } public static @NotNull String sanitizeForSerializer(@NotNull String string) { - if(customLegacySerializer == null) { + if (customLegacySerializer == null) { customLegacySerializer = getSerializer(); } diff --git a/src/main/java/com/gmail/nossr50/util/upgrade/UpgradeManager.java b/src/main/java/com/gmail/nossr50/util/upgrade/UpgradeManager.java index 4bb13f6eb..9855d2479 100644 --- a/src/main/java/com/gmail/nossr50/util/upgrade/UpgradeManager.java +++ b/src/main/java/com/gmail/nossr50/util/upgrade/UpgradeManager.java @@ -4,7 +4,6 @@ import com.gmail.nossr50.config.BukkitConfig; import com.gmail.nossr50.datatypes.database.UpgradeType; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.LogUtils; - import java.util.Arrays; import java.util.EnumSet; import java.util.Set; @@ -24,7 +23,6 @@ public class UpgradeManager extends BukkitConfig { * Check if the given {@link UpgradeType} is necessary. * * @param type Upgrade type to check - * * @return true if plugin data needs to have the given upgrade */ public boolean shouldUpgrade(final UpgradeType type) { @@ -32,8 +30,8 @@ public class UpgradeManager extends BukkitConfig { } /** - * Set the given {@link UpgradeType} as completed. Does nothing if - * the upgrade was applied previously. + * Set the given {@link UpgradeType} as completed. Does nothing if the upgrade was applied + * previously. * * @param type Upgrade type to set as complete */ @@ -42,14 +40,14 @@ public class UpgradeManager extends BukkitConfig { return; } - LogUtils.debug(mcMMO.p.getLogger(), "Saving upgrade status for type " + type.toString() + "..."); + LogUtils.debug(mcMMO.p.getLogger(), + "Saving upgrade status for type " + type.toString() + "..."); - config.set("Upgrades_Finished." + type.toString(), true); + config.set("Upgrades_Finished." + type, true); try { config.save(getFile()); - } - catch (Exception e) { + } catch (Exception e) { e.printStackTrace(); } } @@ -62,6 +60,7 @@ public class UpgradeManager extends BukkitConfig { } } - LogUtils.debug(mcMMO.p.getLogger(), "Needed upgrades: " + Arrays.toString(setNeededUpgrades.toArray(new UpgradeType[setNeededUpgrades.size()]))); + LogUtils.debug(mcMMO.p.getLogger(), "Needed upgrades: " + Arrays.toString( + setNeededUpgrades.toArray(new UpgradeType[setNeededUpgrades.size()]))); } } diff --git a/src/main/java/com/gmail/nossr50/worldguard/WorldGuardManager.java b/src/main/java/com/gmail/nossr50/worldguard/WorldGuardManager.java index 29b4e89c2..0aa7afbe7 100644 --- a/src/main/java/com/gmail/nossr50/worldguard/WorldGuardManager.java +++ b/src/main/java/com/gmail/nossr50/worldguard/WorldGuardManager.java @@ -1,5 +1,7 @@ package com.gmail.nossr50.worldguard; +import static org.bukkit.Bukkit.getServer; + import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.LogUtils; import com.sk89q.worldedit.bukkit.BukkitAdapter; @@ -12,65 +14,70 @@ import com.sk89q.worldguard.protection.regions.RegionQuery; import org.bukkit.entity.Player; import org.bukkit.plugin.Plugin; -import static org.bukkit.Bukkit.getServer; - public class WorldGuardManager { private static WorldGuardManager instance; private WorldGuardPlugin worldGuardPluginRef; public static WorldGuardManager getInstance() { - if(instance == null) + if (instance == null) { instance = new WorldGuardManager(); + } return instance; } - public boolean hasMainFlag(Player player) - { - if(player == null) + public boolean hasMainFlag(Player player) { + if (player == null) { return false; + } BukkitPlayer localPlayer = BukkitAdapter.adapt(player); com.sk89q.worldedit.util.Location loc = localPlayer.getLocation(); //WorldGuardPlugin worldGuard = getWorldGuard(); - RegionQuery query = WorldGuard.getInstance().getPlatform().getRegionContainer().createQuery(); + RegionQuery query = WorldGuard.getInstance().getPlatform().getRegionContainer() + .createQuery(); //ApplicableRegionSet set = query.getApplicableRegions(loc); - return query.testState(loc, WorldGuardPlugin.inst().wrapPlayer(player), WorldGuardFlags.MCMMO_ENABLE_WG_FLAG); + return query.testState(loc, WorldGuardPlugin.inst().wrapPlayer(player), + WorldGuardFlags.MCMMO_ENABLE_WG_FLAG); } - public boolean hasXPFlag(Player player) - { - if(player == null) + public boolean hasXPFlag(Player player) { + if (player == null) { return false; + } BukkitPlayer localPlayer = BukkitAdapter.adapt(player); com.sk89q.worldedit.util.Location loc = localPlayer.getLocation(); //WorldGuardPlugin worldGuard = getWorldGuard(); - RegionQuery query = WorldGuard.getInstance().getPlatform().getRegionContainer().createQuery(); + RegionQuery query = WorldGuard.getInstance().getPlatform().getRegionContainer() + .createQuery(); //ApplicableRegionSet set = query.getApplicableRegions(loc); - return query.testState(loc, WorldGuardPlugin.inst().wrapPlayer(player), WorldGuardFlags.MCMMO_XP_WG_FLAG); + return query.testState(loc, WorldGuardPlugin.inst().wrapPlayer(player), + WorldGuardFlags.MCMMO_XP_WG_FLAG); } - public boolean hasHardcoreFlag(Player player) - { - if(player == null) + public boolean hasHardcoreFlag(Player player) { + if (player == null) { return false; + } BukkitPlayer localPlayer = BukkitAdapter.adapt(player); com.sk89q.worldedit.util.Location loc = localPlayer.getLocation(); //WorldGuardPlugin worldGuard = getWorldGuard(); - RegionQuery query = WorldGuard.getInstance().getPlatform().getRegionContainer().createQuery(); + RegionQuery query = WorldGuard.getInstance().getPlatform().getRegionContainer() + .createQuery(); //ApplicableRegionSet set = query.getApplicableRegions(loc); - return query.testState(loc, WorldGuardPlugin.inst().wrapPlayer(player), WorldGuardFlags.MCMMO_HARDCORE_WG_FLAG); + return query.testState(loc, WorldGuardPlugin.inst().wrapPlayer(player), + WorldGuardFlags.MCMMO_HARDCORE_WG_FLAG); } private WorldGuardPlugin getWorldGuard() { @@ -85,8 +92,7 @@ public class WorldGuardManager { return worldGuardPluginRef; } - public void registerFlags() - { + public void registerFlags() { try { FlagRegistry registry = WorldGuard.getInstance().getFlagRegistry(); diff --git a/src/main/java/com/gmail/nossr50/worldguard/WorldGuardUtils.java b/src/main/java/com/gmail/nossr50/worldguard/WorldGuardUtils.java index d37f0a50c..9ba52ad45 100644 --- a/src/main/java/com/gmail/nossr50/worldguard/WorldGuardUtils.java +++ b/src/main/java/com/gmail/nossr50/worldguard/WorldGuardUtils.java @@ -1,15 +1,14 @@ package com.gmail.nossr50.worldguard; +import static org.bukkit.Bukkit.getServer; + import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.LogUtils; import com.sk89q.worldguard.WorldGuard; import com.sk89q.worldguard.bukkit.WorldGuardPlugin; import com.sk89q.worldguard.protection.flags.registry.SimpleFlagRegistry; -import org.bukkit.plugin.Plugin; - import java.util.ArrayList; - -import static org.bukkit.Bukkit.getServer; +import org.bukkit.plugin.Plugin; public class WorldGuardUtils { private static WorldGuardPlugin worldGuardPluginRef; @@ -41,10 +40,10 @@ public class WorldGuardUtils { WGClassList.add("com.sk89q.worldguard.protection.regions.RegionQuery"); } - public static boolean isWorldGuardLoaded() - { - if(detectedIncompatibleWG) + public static boolean isWorldGuardLoaded() { + if (detectedIncompatibleWG) { return false; + } worldGuardPluginRef = getWorldGuard(); @@ -52,29 +51,27 @@ public class WorldGuardUtils { } /** - * Gets the instance of the WG plugin if its compatible - * Results are cached + * Gets the instance of the WG plugin if its compatible Results are cached + * * @return the instance of WG plugin, null if its not compatible or isn't present */ - private static WorldGuardPlugin getWorldGuard() - { + private static WorldGuardPlugin getWorldGuard() { //WG plugin reference is already cached so just return it - if(isLoaded) + if (isLoaded) { return worldGuardPluginRef; + } //Grab WG if it exists Plugin plugin = getServer().getPluginManager().getPlugin("WorldGuard"); - if(plugin == null) { + if (plugin == null) { //WG is not present detectedIncompatibleWG = true; LogUtils.debug(mcMMO.p.getLogger(), "WorldGuard was not detected."); } else { //Check that its actually of class WorldGuardPlugin - if(plugin instanceof WorldGuardPlugin) - { - if(isCompatibleVersion(plugin)) - { + if (plugin instanceof WorldGuardPlugin) { + if (isCompatibleVersion(plugin)) { worldGuardPluginRef = (WorldGuardPlugin) plugin; isLoaded = true; } @@ -84,14 +81,14 @@ public class WorldGuardUtils { } } - return worldGuardPluginRef; } /** - * Checks to make sure the version of WG installed is compatible - * Does this by checking for necessary WG classes via Reflection - * This does not guarantee compatibility, but it should help reduce the chance that mcMMO tries to hook into WG and its not compatible + * Checks to make sure the version of WG installed is compatible Does this by checking for + * necessary WG classes via Reflection This does not guarantee compatibility, but it should help + * reduce the chance that mcMMO tries to hook into WG and its not compatible + * * @return true if the version of WG appears to be compatible */ private static boolean isCompatibleVersion(Plugin plugin) { @@ -105,12 +102,12 @@ public class WorldGuardUtils { markWGIncompatible(); } else { //Use Reflection to check for a class not present in all versions of WG7 - for(String classString : WGClassList) { + for (String classString : WGClassList) { try { Class checkForClass = Class.forName(classString); } catch (ClassNotFoundException | NoClassDefFoundError e) { allClassesFound = false; - mcMMO.p.getLogger().severe("Missing WorldGuard class - "+classString); + mcMMO.p.getLogger().severe("Missing WorldGuard class - " + classString); markWGIncompatible(); } } @@ -119,10 +116,12 @@ public class WorldGuardUtils { * If WG appears to have all of its classes we can then check to see if its been initialized properly */ try { - if(allClassesFound) { - if(!((SimpleFlagRegistry) WorldGuard.getInstance().getFlagRegistry()).isInitialized()) { + if (allClassesFound) { + if (!((SimpleFlagRegistry) WorldGuard.getInstance() + .getFlagRegistry()).isInitialized()) { markWGIncompatible(); - mcMMO.p.getLogger().severe("WG did not initialize properly, this can cause errors with mcMMO so mcMMO is disabling certain features."); + mcMMO.p.getLogger() + .severe("WG did not initialize properly, this can cause errors with mcMMO so mcMMO is disabling certain features."); } } } catch (Exception e) { @@ -138,10 +137,13 @@ public class WorldGuardUtils { * Mark WG as being incompatible to avoid unnecessary operations */ private static void markWGIncompatible() { - mcMMO.p.getLogger().severe("You are using a version of WG that is not compatible with mcMMO, " + - "WG features for mcMMO will be disabled. mcMMO requires you to be using a new version of WG7 " + - "in order for it to use WG features. Not all versions of WG7 are compatible."); - mcMMO.p.getLogger().severe("mcMMO will continue to function normally, but if you wish to use WG support you must use a compatible version."); + mcMMO.p.getLogger() + .severe("You are using a version of WG that is not compatible with mcMMO, " + + "WG features for mcMMO will be disabled. mcMMO requires you to be using a new version of WG7 " + + + "in order for it to use WG features. Not all versions of WG7 are compatible."); + mcMMO.p.getLogger() + .severe("mcMMO will continue to function normally, but if you wish to use WG support you must use a compatible version."); detectedIncompatibleWG = true; } } diff --git a/src/main/java/net/shatteredlands/shatt/backup/ZipLibrary.java b/src/main/java/net/shatteredlands/shatt/backup/ZipLibrary.java index 4ce8fee08..0d2ec917b 100644 --- a/src/main/java/net/shatteredlands/shatt/backup/ZipLibrary.java +++ b/src/main/java/net/shatteredlands/shatt/backup/ZipLibrary.java @@ -2,7 +2,6 @@ package net.shatteredlands.shatt.backup; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.LogUtils; - import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; @@ -11,20 +10,24 @@ import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; +import java.util.Locale; import java.util.zip.Deflater; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; public class ZipLibrary { - private static final String BACKUP_DIRECTORY = mcMMO.getMainDirectory() + "backup" + File.separator; + private static final String BACKUP_DIRECTORY = + mcMMO.getMainDirectory() + "backup" + File.separator; private static final File BACKUP_DIR = new File(BACKUP_DIRECTORY); private static final File FLAT_FILE_DIRECTORY = new File(mcMMO.getFlatFileDirectory()); private static final File MOD_FILE_DIRECTORY = new File(mcMMO.getModDirectory()); private static final File CONFIG_FILE = new File(mcMMO.getMainDirectory() + "config.yml"); - private static final File EXPERIENCE_FILE = new File(mcMMO.getMainDirectory() + "experience.yml"); + private static final File EXPERIENCE_FILE = new File( + mcMMO.getMainDirectory() + "experience.yml"); private static final File TREASURE_FILE = new File(mcMMO.getMainDirectory() + "treasures.yml"); private static final File ADVANCED_FILE = new File(mcMMO.getMainDirectory() + "advanced.yml"); - private static final File REPAIR_FILE = new File(mcMMO.getMainDirectory() + "repair.vanilla.yml"); + private static final File REPAIR_FILE = new File( + mcMMO.getMainDirectory() + "repair.vanilla.yml"); public static void mcMMOBackup() throws IOException { if (mcMMO.p.getGeneralConfig().getUseMySQL()) { @@ -36,15 +39,15 @@ public class ZipLibrary { if (BACKUP_DIR.mkdir()) { LogUtils.debug(mcMMO.p.getLogger(), "Created Backup Directory."); } - } - catch (Exception e) { + } catch (Exception e) { mcMMO.p.getLogger().severe(e.toString()); } // Generate the proper date for the backup filename Date date = new Date(); - SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss"); - File fileZip = new File(BACKUP_DIRECTORY + File.separator + dateFormat.format(date) + ".zip"); + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss", Locale.US); + File fileZip = new File( + BACKUP_DIRECTORY + File.separator + dateFormat.format(date) + ".zip"); // Create the Source List, and add directories/etc to the file. List sources = new ArrayList<>(); @@ -73,8 +76,7 @@ public class ZipLibrary { for (File source : sources) { if (source.isDirectory()) { zipDir(zipOut, "", source); - } - else { + } else { zipFile(zipOut, "", source); } } @@ -94,7 +96,8 @@ public class ZipLibrary { private static void zipDir(ZipOutputStream zos, String path, File dir) throws IOException { if (!dir.canRead()) { - mcMMO.p.getLogger().severe("Cannot read " + dir.getCanonicalPath() + " (Maybe because of permissions?)"); + mcMMO.p.getLogger().severe("Cannot read " + dir.getCanonicalPath() + + " (Maybe because of permissions?)"); return; } @@ -104,8 +107,7 @@ public class ZipLibrary { for (File source : files) { if (source.isDirectory()) { zipDir(zos, path, source); - } - else { + } else { zipFile(zos, path, source); } } @@ -113,7 +115,8 @@ public class ZipLibrary { private static void zipFile(ZipOutputStream zos, String path, File file) throws IOException { if (!file.canRead()) { - mcMMO.p.getLogger().severe("Cannot read " + file.getCanonicalPath() + "(File Permissions?)"); + mcMMO.p.getLogger() + .severe("Cannot read " + file.getCanonicalPath() + "(File Permissions?)"); return; } diff --git a/src/main/resources/advanced.yml b/src/main/resources/advanced.yml index 4e37db678..4e876fa76 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 @@ -83,6 +83,11 @@ Feedback: SendCopyOfMessageToChat: false Skills: General: + # Attack Cooldown refers to the strength of attacks in Minecraft. + # If an attack is spammed, it will have less bonus damage and RNG for skills to activate from mcMMO. + # If you want, you can turn this behavior off by setting it to false. + Attack_Cooldown: + Adjust_Skills_For_Attack_Cooldown: true LimitBreak: AllowPVE: false StartingLevel: 0 @@ -264,6 +269,11 @@ Skills: MaxBonusLevel: Standard: 100 RetroMode: 1000 + VerdantBounty: + ChanceMax: 50.0 + MaxBonusLevel: + Standard: 1000 + RetroMode: 10000 HylianLuck: # ChanceMax: Maximum chance of Hylian Luck when on or higher @@ -284,6 +294,11 @@ Skills: # Settings for Mining ### Mining: + MotherLode: + MaxBonusLevel: + Standard: 1000 + RetroMode: 10000 + ChanceMax: 50.0 SuperBreaker: AllowTripleDrops: true DoubleDrops: @@ -458,6 +473,9 @@ Skills: # Settings for Swords ### Swords: + Stab: + Base_Damage: 1.0 + Per_Rank_Multiplier: 1.5 Rupture: Rupture_Mechanics: # This is % chance, 15 would mean 15% percent of the time @@ -526,7 +544,6 @@ Skills: FastFoodService: # Chance: The chance for wolves to heal hp when inflicting damage Chance: 50.0 - EnvironmentallyAware: ThickFur: # Modifier: Damage will get divided by this modifier Modifier: 2.0 @@ -608,12 +625,26 @@ Skills: Knock_On_Wood: Add_XP_Orbs_To_Drops: true + # Triple Drops + CleanCuts: + # ChanceMax: Maximum chance of receiving triple drops (100 = 100%) + # MaxBonusLevel: Level when the maximum chance of receiving triple drops is reached + ChanceMax: 50.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 MaxBonusLevel: Standard: 100 - RetroMode: 1000 \ No newline at end of file + RetroMode: 1000 + Maces: + Cripple: + Chance_To_Apply_On_Hit: + Rank_1: 10 + Rank_2: 15 + Rank_3: 20 + Rank_4: 33 \ No newline at end of file diff --git a/src/main/resources/chat.yml b/src/main/resources/chat.yml index 34f812a07..febf9c9f6 100644 --- a/src/main/resources/chat.yml +++ b/src/main/resources/chat.yml @@ -8,10 +8,12 @@ Chat: Enable: true # Whether to use the current display name of a player Use_Display_Names: true + Send_To_Console: true Spies: # 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 to use the current display name of a player diff --git a/src/main/resources/child.yml b/src/main/resources/child.yml deleted file mode 100644 index 685a6ce71..000000000 --- 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/main/resources/config.yml b/src/main/resources/config.yml index 789729cc6..936ea67b7 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -49,6 +49,10 @@ General: RetroMode: Enabled: true Locale: en_US + PowerLevel: + Skill_Mastery: + Enabled: true + AprilFoolsEvent: true MOTD_Enabled: true EventBroadcasts: true EventInfoOnPlayerJoin: true @@ -222,6 +226,9 @@ Hardcore: Taming: false Unarmed: false Woodcutting: false + Tridents: false + Crossbows: false + Maces: false Vampirism: Leech_Percentage: 5.0 Level_Threshold: 0 @@ -239,6 +246,9 @@ Hardcore: Taming: false Unarmed: false Woodcutting: false + Tridents: false + Crossbows: false + Maces: false # # Settings for SMP Mods @@ -405,6 +415,18 @@ Skills: Enabled_For_PVP: true Enabled_For_PVE: true Level_Cap: 0 + Tridents: + Enabled_For_PVP: true + Enabled_For_PVE: true + Level_Cap: 0 + Crossbows: + Enabled_For_PVP: true + Enabled_For_PVE: true + Level_Cap: 0 + Maces: + Enabled_For_PVP: true + Enabled_For_PVE: true + Level_Cap: 0 Taming: Enabled_For_PVP: true Enabled_For_PVE: true @@ -461,6 +483,16 @@ Green_Thumb_Replanting_Crops: ### Bonus_Drops: Herbalism: + Bush: true + Cactus_Flower: true + Firefly_Bush: true + Leaf_Litter: true + Short_Dry_Grass: true + Tall_Dry_Grass: true + Wildflowers: true + Eyeblossom: true + Open_Eyeblossom: true + Closed_Eyeblossom: true Pitcher_Plant: true Torchflower: true Pink_Petals: true @@ -604,7 +636,9 @@ Bonus_Drops: Cherry_Wood: true Cherry_Log: true Dark_Oak_Wood: true + Pale_Oak_Wood: true Dark_Oak_Log: true + Pale_Oak_Log: true Oak_Wood: true Oak_Log: true Jungle_Wood: true @@ -672,6 +706,7 @@ Particles: Flux: true Greater_Impact: true Call_of_the_Wild: true + Cripple: true # These settings determine if fireworks should get launched when a player levels-up, # this will happen by default for every 100 levels. diff --git a/src/main/resources/custom_item_support.yml b/src/main/resources/custom_item_support.yml new file mode 100644 index 000000000..76285867e --- /dev/null +++ b/src/main/resources/custom_item_support.yml @@ -0,0 +1,11 @@ +# This is meant to be a general config for allowing mcMMO to allow interaction with custom items. +# In the future, I would like to add configs to be specific about certain custom items. +# For now, support is generalized to whether the custom item has a custom model. +# This is an easy solution to implement for now, but not the most ideal. +Custom_Item_Support: + Repair: + # Turn this off to disable repair on any items with custom model data + Allow_Repair_On_Items_With_Custom_Model_Data: true + Salvage: + # Turn this off to disable salvage on any items with custom model data + Allow_Salvage_On_Items_With_Custom_Model_Data: true diff --git a/src/main/resources/experience.yml b/src/main/resources/experience.yml index 00e72f01d..7e7c18725 100644 --- a/src/main/resources/experience.yml +++ b/src/main/resources/experience.yml @@ -1,13 +1,3 @@ -# -# Experience configuration -# Last updated on ${project.version}-b${BUILD_NUMBER} -# -# Configure the experience formula and experience settings here. -# -##### - - - # https://hub.spigotmc.org/javadocs/spigot/org/bukkit/boss/BarColor.html # These are the only valid colors for Experience Bars, use the exact name found here # BLUE, GREEN, PINK, PURPLE, RED, WHITE, YELLOW (As of the time of this update these are the only Bar colors available, this could change in the future so check the BarColor enum to see if it has) @@ -39,15 +29,18 @@ ExploitFix: TreeFellerReducedXP: true PistonCheating: true SnowGolemExcavation: true + PreventArmorStandInteraction: 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 something is an NPC, it checks a few known things, see our source code to see how PreventPluginNPCInteraction: true + # This will limit XP gained from unnaturally tall plants, like those created by Bone Meal + LimitTallPlantFarming: true Fishing_ExploitFix_Options: MoveRange: 3 OverFishLimit: 10 Experience_Bars: - # Turn this to false if you wanna disable XP bars + # Turn this to false if you want to disable XP bars Enable: true Update: # XP that you gained from your party but not yourself @@ -77,6 +70,10 @@ Experience_Bars: Enable: true Color: BLUE BarStyle: SEGMENTED_6 + Crossbows: + Enable: true + Color: BLUE + BarStyle: SEGMENTED_6 Excavation: Enable: true Color: YELLOW @@ -93,6 +90,10 @@ Experience_Bars: Enable: true Color: YELLOW BarStyle: SEGMENTED_6 + Maces: + Enable: true + Color: BLUE + BarStyle: SEGMENTED_6 Repair: Enable: true Color: PURPLE @@ -113,6 +114,10 @@ Experience_Bars: Enable: true Color: RED BarStyle: SEGMENTED_6 + Tridents: + Enable: true + Color: BLUE + BarStyle: SEGMENTED_6 Unarmed: Enable: true Color: BLUE @@ -159,8 +164,11 @@ 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: + Maces: 1.0 + Crossbows: 1.0 + Tridents: 1.0 Swords: 1.0 Taming: 1.0 Acrobatics: 1.0 @@ -206,6 +214,9 @@ Diminished_Returns: Repair: 20000 Fishing: 20000 Alchemy: 20000 + Crossbows: 20000 + Tridents: 20000 + Maces: 20000 Time_Interval: 10 @@ -230,17 +241,18 @@ Experience_Values: # FeatherFall_Multiplier: Multiply Acrobatics XP by this value when wearing boots with the Feather Fall enchant FeatherFall_Multiplier: 2.0 Alchemy: - # Alchemy potion stages are based on the number of ingredients added - # Potion_Stage_1 represents a base potion - # Potion_Stage_2 represents a base potion with one ingredient - # Potion_Stage_3 represents a base potion with one ingredient and one amplifier - # Potion_Stage_4 represents a base potion with one ingredient and two amplifiers - # Potion_Stage_5 represents a base potion with one ingredient where the amplifiers are swapped - Potion_Stage_1: 15 - Potion_Stage_2: 30 - Potion_Stage_3: 60 - Potion_Stage_4: 120 - Potion_Stage_5: 0 + Potion_Brewing: + # Alchemy potion stages are based on the number of ingredients added + # Stage_1 represents a base potion + # Stage_2 represents a base potion with one ingredient + # Stage_3 represents a base potion with one ingredient and one amplifier + # Stage_4 represents a base potion with one ingredient and two amplifiers + # Stage_5 represents a base potion with one ingredient where the amplifiers are swapped + Stage_1: 666 + Stage_2: 1111 + Stage_3: 1750 + Stage_4: 2250 + Stage_5: 0 Archery: Distance_Multiplier: 0.025 Fishing: @@ -283,6 +295,7 @@ Experience_Values: Jungle_Log: 100 Acacia_Log: 90 Dark_Oak_Log: 90 + Pale_Oak_Log: 130 Stripped_Oak_Log: 70 Stripped_Cherry_Log: 105 Stripped_Spruce_Log: 80 @@ -290,6 +303,7 @@ Experience_Values: Stripped_Jungle_Log: 100 Stripped_Acacia_Log: 90 Stripped_Dark_Oak_Log: 90 + Stripped_Pale_Oak_Log: 130 Stripped_Oak_Wood: 70 Stripped_Cherry_Wood: 70 Stripped_Spruce_Wood: 80 @@ -297,6 +311,7 @@ Experience_Values: Stripped_Jungle_Wood: 100 Stripped_Acacia_Wood: 90 Stripped_Dark_Oak_Wood: 90 + Stripped_Pale_Oak_Wood: 90 Stripped_Mangrove_Log: 110 Stripped_Crimson_Stem: 50 Stripped_Warped_Stem: 50 @@ -307,6 +322,7 @@ Experience_Values: Jungle_Wood: 70 Acacia_Wood: 70 Dark_Oak_Wood: 70 + Pale_Oak_Wood: 110 Mangrove_Wood: 80 Mangrove_Log: 95 Mangrove_Roots: 10 @@ -314,12 +330,25 @@ Experience_Values: Brown_Mushroom_Block: 70 Mushroom_Stem: 80 Herbalism: + Bush: 11 + Cactus_Flower: 60 + Firefly_Bush: 15 + Leaf_Litter: 2 + Short_Dry_Grass: 6 + Tall_Dry_Grass: 12 + Wildflowers: 15 + Eyeblossom: 66 + Open_Eyeblossom: 66 + Closed_Eyeblossom: 66 Pitcher_Plant: 160 Pink_Petals: 10 Small_Dripleaf: 140 Big_Dripleaf: 140 Cave_Vines: 90 Cave_Vines_Plant: 90 + Pale_Hanging_Moss: 150 + Pale_Moss_Block: 10 + Pale_Moss_Carpet: 10 Glow_Lichen: 5 Moss_Block: 150 Crimson_Roots: 6 @@ -377,6 +406,7 @@ Experience_Values: Cocoa: 30 Potatoes: 50 Wheat: 50 + Beetroot: 50 Beetroots: 50 Nether_Wart: 50 Dead_Bush: 30 @@ -571,6 +601,7 @@ Experience_Values: Combat: Multiplier: Animals: 1.0 + Armadillo: 1.1 Creeper: 4.0 Skeleton: 3.0 Spider: 2.0 @@ -578,6 +609,8 @@ Experience_Values: Zombie: 2.0 Slime: 2.0 Ghast: 3.0 + Happy_Ghast: 1.0 + Ghastling: 0.5 Pig_Zombie: 3.0 Enderman: 1.0 Cave_Spider: 3.0 @@ -647,3 +680,5 @@ Experience_Values: Sniffer: 1.1 Snifflet: 1.1 Camel: 1.2 + Bogged: 2.0 + Breeze: 4.0 diff --git a/src/main/resources/locale/locale_cs_CZ.properties b/src/main/resources/locale/locale_cs_CZ.properties index c74ce2d7e..e4abdeb09 100644 --- a/src/main/resources/locale/locale_cs_CZ.properties +++ b/src/main/resources/locale/locale_cs_CZ.properties @@ -182,7 +182,7 @@ Repair.SubSkill.ArcaneForging.Description=Oprava enchantovanych predmetu Repair.SubSkill.Salvage.Name=Sbírat({0}+ Dovednost) Repair.SubSkill.Salvage.Description=Sbírat Nástroje a Zbroj Repair.Error=&4V mcMMO došlo k chybě při opravě tohoto itemu! -Repair.Listener.Anvil=&4Položil si kovadlinu, na kovadlině můžeš opravovat nástroje a zbroj. +Repair.Listener.Anvil=&aPoložil si kovadlinu, na kovadlině můžeš opravovat nástroje a zbroj. Repair.Listener.Anvil2=&4Polozil jsi Salvage kovadlinu, pouzij ji na zachranu armoru. Repair.Listener=Opravovani: Repair.SkillName=OPRAVOVANI diff --git a/src/main/resources/locale/locale_cy.properties b/src/main/resources/locale/locale_cy.properties index 4689705a9..efadbcdcf 100644 --- a/src/main/resources/locale/locale_cy.properties +++ b/src/main/resources/locale/locale_cy.properties @@ -165,7 +165,7 @@ Repair.SubSkill.ArcaneForging.Description=Atgyweiriwch eitemau sydd hud Repair.SubSkill.Salvage.Name=Salvage ({0}+ SKILL) Repair.SubSkill.Salvage.Description=Salvage Tools & Armor Repair.Error=&4mcMMO encountered an error attempting to repair this item! -Repair.Listener.Anvil=&4You have placed an anvil, anvils can repair tools and armor. +Repair.Listener.Anvil=&aYou have placed an anvil, anvils can repair tools and armor. Repair.Listener.Anvil2=&4You have placed a Salvage anvil, use this to Salvage tools and armor. Repair.Listener=Atgyweirio: Repair.SkillName=ATGYWEIRIO: diff --git a/src/main/resources/locale/locale_da.properties b/src/main/resources/locale/locale_da.properties index d14a1cf0c..33e57ef19 100644 --- a/src/main/resources/locale/locale_da.properties +++ b/src/main/resources/locale/locale_da.properties @@ -165,7 +165,7 @@ Repair.SubSkill.ArcaneForging.Description=Reparer magiske genstande Repair.SubSkill.Salvage.Name=Genbrug ({0}+ EVNE) Repair.SubSkill.Salvage.Description=Genbrugelige Værktøjer og Rustninger Repair.Error=&4mcMMO mødte en fejl mens den forsøgte at reparere dette objekt! -Repair.Listener.Anvil=&4Du har placeret en armbolt, armbolte kan reparere værktøj og rustning. +Repair.Listener.Anvil=&aDu har placeret en armbolt, armbolte kan reparere værktøj og rustning. Repair.Listener.Anvil2=&4Du har placeret en Genbrugs Ambolt, Brug den til at Genbruge Værktøjer og Rustning (Få materialer tilbage) Repair.Listener=Reparer: Repair.SkillName=REPARER diff --git a/src/main/resources/locale/locale_en_US.properties b/src/main/resources/locale/locale_en_US.properties index 27c45d0d9..ed051f5ad 100644 --- a/src/main/resources/locale/locale_en_US.properties +++ b/src/main/resources/locale/locale_en_US.properties @@ -1,10 +1,6 @@ -#I'm going to try to normalize our locale file, forgive the mess for now. -# TODO: Update JSON to support hex - -#DO NOT USE COLOR CODES IN THE JSON KEYS -#COLORS ARE DEFINED IN advanced.yml IF YOU WISH TO CHANGE THEM +Placeholder= This value is for any WIP locale entries that will not be displayed to users JSON.Rank=Rank -JSON.DescriptionHeader=Description +JSON.DescriptionHeader=Description: JSON.JWrapper.Header=Details JSON.Type.Passive=Passive JSON.Type.Active=Active @@ -21,6 +17,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 +26,8 @@ JSON.Repair=Repair JSON.Salvage=Salvage JSON.Swords=Swords JSON.Taming=Taming +JSON.Tridents=Tridents +JSON.Maces=Maces JSON.Unarmed=Unarmed JSON.Woodcutting=Woodcutting JSON.URL.Website=The official mcMMO Website! @@ -88,6 +87,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,13 +97,15 @@ Overhaul.Name.Salvage=Salvage Overhaul.Name.Smelting=Smelting Overhaul.Name.Swords=Swords Overhaul.Name.Taming=Taming +Overhaul.Name.Tridents=Tridents +Overhaul.Name.Maces=Maces Overhaul.Name.Unarmed=Unarmed Overhaul.Name.Woodcutting=Woodcutting # /mcMMO Command Style Stuff -Commands.mcc.Header=&c---[]&amcMMO Commands&c[]--- -Commands.Other=&c---[]&aSPECIAL COMMANDS&c[]--- -Commands.Party.Header=&c-----[]&aPARTY&c[]----- -Commands.Party.Features.Header=&c-----[]&aFEATURES&c[]----- +Commands.mcc.Header=&c[]=====[] &amcMMO Commands &c[]=====[] +Commands.Other=&c[]=====[] &aSPECIAL COMMANDS &c[]=====[] +Commands.Party.Header=&c[]=====[] &aPARTY &c[]=====[] +Commands.Party.Features.Header=&c[]=====[] &aFEATURES &c[]=====[] # XP BAR Allows for the following variables -- {0} = Skill Level, {1} Current XP, {2} XP Needed for next level, {3} Power Level, {4} Percentage of Level # Make sure you turn on Experience_Bars.ThisMayCauseLag.AlwaysUpdateTitlesWhenXPIsGained if you want the XP bar title to update every time a player gains XP! XPBar.Template={0} @@ -112,6 +114,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 +124,8 @@ 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.Maces=Maces 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 @@ -160,8 +165,6 @@ Alchemy.Listener=Alchemy: Alchemy.Ability.Locked.0=LOCKED UNTIL {0}+ SKILL (CATALYSIS) Alchemy.SkillName=ALCHEMY #ARCHERY - - Archery.SubSkill.SkillShot.Name=Skill Shot Archery.SubSkill.SkillShot.Description=Increases damage done with bows Archery.SubSkill.SkillShot.Stat=Skill Shot Bonus Damage @@ -176,6 +179,13 @@ 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.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} +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 @@ -285,8 +295,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,8 +324,11 @@ 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=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 Mining.SubSkill.BlastMining.Stat=Blast Mining:&a Rank {0}/{1} &7({2}) @@ -358,7 +374,7 @@ Repair.SubSkill.ArcaneForging.Description=Repair magic items Repair.SubSkill.ArcaneForging.Stat=Arcane Forging: &eRank {0}/{1} Repair.SubSkill.ArcaneForging.Stat.Extra=&3Arcane Forging Odds:&7 Success &a{0}&7%, Failure &c{1}&7% Repair.Error=&4mcMMO encountered an error attempting to repair this item! -Repair.Listener.Anvil=&4You have placed an anvil, anvils can repair tools and armor. +Repair.Listener.Anvil=&aYou have placed an anvil, anvils can repair tools and armor. Repair.Listener=Repair: Repair.SkillName=REPAIR Repair.Skills.AdeptDiamond=&4You're not skilled enough to repair Diamond. @@ -381,7 +397,7 @@ Salvage.SubSkill.UnderstandingTheArt.Name=Understanding The Art Salvage.SubSkill.UnderstandingTheArt.Description=You're not just digging through your neighbors trash, you're taking care of the environment.\nPowers up various properties of Salvaging. Salvage.SubSkill.ScrapCollector.Name=Scrap Collector Salvage.SubSkill.ScrapCollector.Description=Salvage materials from an item, a perfect salvage depends on skill and luck. -Salvage.SubSkill.ScrapCollector.Stat=Scrap Collector: &aSalvage up to &e{0}&a items. Some luck is involved. +Salvage.SubSkill.ScrapCollector.Stat=Scrap Collector: &aSalvage up to &e{0}&a items. Salvage.SubSkill.ArcaneSalvage.Name=Arcane Salvaging Salvage.SubSkill.ArcaneSalvage.Description=Extract enchantments from items Salvage.SubSkill.ArcaneSalvage.Stat=Arcane Salvaging: &eRank {0}/{1} @@ -395,8 +411,8 @@ 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.Listener.Anvil=&4You have placed a Salvage anvil, use this to Salvage tools and armor. +Salvage.Skills.ArcaneSuccess=&aYou were able to extract all the knowledge contained within this item! +Salvage.Listener.Anvil=&aYou have placed a Salvage anvil, use this to Salvage tools and armor. Salvage.Listener=Salvage: Salvage.SkillName=SALVAGE Salvage.Skills.Lottery.Normal=&6You were able to salvage &3{0}&6 materials from &e{1}&6. @@ -404,6 +420,60 @@ 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! +Anvil.Repair.Reject.CustomModelData=A mysterious force prevents you from repairing this item... +Anvil.Salvage.Reject.CustomModelData=A mysterious force prevents you from salvaging this item... +#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.PoweredShot.Name=Powered Shot +Crossbows.SubSkill.PoweredShot.Description=Increases damage done with crossbows +Crossbows.SubSkill.PoweredShot.Stat=Powered Shot Bonus Damage +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 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 +Tridents.SkillName=TRIDENTS +Tridents.Ability.Lower=&7You lower your trident. +Tridents.Ability.Ready=&3You &6ready&3 your Trident. +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 +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 +Commands.McTop.MacesNotSupported=[[GREEN]]Maces are not supported in this version of Minecraft. +Maces.SkillName=MACES +Maces.Ability.Lower=&7You lower your mace. +Maces.Ability.Ready=&3You &6ready&3 your Mace. +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.SubSkill.Crush.Name=Crush +Maces.SubSkill.Crush.Description=Adds bonus damage to your attacks. +Maces.SubSkill.Crush.Stat=Crush Damage +Maces.SubSkill.Cripple.Proc=**CRIPPLED** +Maces.SubSkill.Cripple.Activated=CRIPPLED TARGET! +Maces.SubSkill.Cripple.Name=Cripple +Maces.SubSkill.Cripple.Description=Adds a chance to cripple your target. +Maces.SubSkill.Cripple.Stat=Cripple Chance +Maces.SubSkill.Cripple.Stat.Extra=[[DARK_AQUA]]Cripple Duration: &e{0}s&a vs Players, &e{1}s&a vs Mobs. +Maces.Listener=Maces: + #SWORDS Swords.Ability.Lower=&7You lower your sword. Swords.Ability.Ready=&3You &6ready&3 your Sword. @@ -542,8 +612,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.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 @@ -587,7 +660,7 @@ Commands.Ability.On=Ability use toggled &aon Commands.Ability.Toggle=Ability use has been toggled for &e{0} Commands.AdminChat.Off=Admin Chat only &cOff Commands.AdminChat.On=Admin Chat only &aOn -Commands.AdminToggle=&a- Toggle admin chat +Commands.AdminToggle=&3 /adminchat &a- Toggle admin chat Commands.Chat.Console=*Console* Commands.Cooldowns.Header=&6--= &amcMMO Ability Cooldowns&6 =-- Commands.Cooldowns.Row.N=\ &c{0}&f - &6{1} seconds left @@ -609,10 +682,10 @@ Commands.Healthbars.Changed.HEARTS=[mcMMO] Your healthbar display type was chang Commands.Healthbars.Changed.BAR=[mcMMO] Your healthbar display type was changed to &eBoxes&f. Commands.Healthbars.Changed.DISABLED=[mcMMO] Your mob healthbars have been &7disabled&f. Commands.Healthbars.Invalid=Invalid healthbar type! -Commands.Inspect= &a- View detailed player info +Commands.Inspect=&3 /inspect &a- View detailed player info Commands.Invite.Success=&aInvite sent successfully. -Commands.Leaderboards= &a- Leaderboards -Commands.mcgod=&a- Toggle GodMode +Commands.Leaderboards=&3 /mctop &a- Leaderboards +Commands.mcgod=&3 /mcgod &a- Toggle GodMode Commands.mchud.Invalid=That is not a valid HUD type. Commands.mcpurge.Success=&aThe database was successfully purged! Commands.mcrank.Heading=&6-=PERSONAL RANKINGS=- @@ -623,7 +696,7 @@ Commands.mcrank.Unranked=&fUnranked Commands.mcrefresh.Success={0}''s cooldowns have been refreshed. Commands.mcremove.Success=&a{0} was successfully removed from the database! Commands.mctop.Tip=&6Tip: Use &c/mcrank&6 to view all of your personal rankings! -Commands.mmoedit=[player] &a - Modify target +Commands.mmoedit=&3 /mmoedit [player] &a - Modify target Commands.mmoedit.AllSkills.1=&aYour level in all skills was set to {0}! Commands.mmoedit.Modified.1=&aYour level in {0} was set to {1}! Commands.mmoedit.Modified.2={0} has been modified for {1}. @@ -650,13 +723,13 @@ Commands.Party.ItemShare=&7ITEM &3({0}) Commands.Party.ExpShare=&7EXP &3({0}) Commands.Party.ItemShareCategories=&8Sharing Items: &7&o{0} Commands.Party.MembersNear=&8NEAR YOU &3{0}&8/&3{1} -Commands.Party.Accept=&a- Accept party invite +Commands.Party.Accept=&3 /party accept &a- Accept party invite Commands.Party.Chat.Off=Party Chat only &cOff Commands.Party.Chat.On=Party Chat only &aOn Commands.Party.Commands=&c---[]&aPARTY COMMANDS&c[]--- Commands.Party.Invite.0=&cALERT: &aYou have received a party invite for {0} from {1} Commands.Party.Invite.1=&eType &a/party accept&e to accept the invite -Commands.Party.Invite=&a- Send party invite +Commands.Party.Invite=&3 /party invite &a- Send party invite Commands.Party.Invite.Accepted=&aInvite Accepted. You have joined party {0} Commands.Party.Join=&7Joined Party: {0} Commands.Party.PartyFull=&6{0}&c is full! @@ -671,11 +744,11 @@ Commands.Party.Kick=&cYou were kicked from party &a{0}&c! Commands.Party.Leave=&eYou have left that party Commands.Party.Members.Header=&c-----[]&aMEMBERS&c[]----- Commands.Party.None=&cYou are not in a party. -Commands.Party.Quit=&a- Leave your current party -Commands.Party.Teleport=&a- Teleport to party member -Commands.Party.Toggle=&a- Toggle Party Chat -Commands.Party1=&a- Create a new party -Commands.Party2=&a- Join a players party +Commands.Party.Quit=&3 /party quit &a- Leave your current party +Commands.Party.Teleport=&3 /party teleport &a- Teleport to party member +Commands.Party.Toggle=&3 /party chat &a- Toggle Party Chat +Commands.Party1=&3 /party create &a- Create a new party +Commands.Party2=&3 /party join &a- Join a players party Commands.Party.Alliance.Header=&c-----[]&aPARTY ALLIANCE&c[]----- Commands.Party.Alliance.Ally=&f{0} &8IS ALLIED WITH: &f{1} Commands.Party.Alliance.Members.Header=&c-----[]&aALLIANCE MEMBERS&c[]----- @@ -700,7 +773,7 @@ Commands.PowerLevel.Capped=&4POWER LEVEL: &a{0} &4MAX LEVEL: &e{1} Commands.PowerLevel=&4POWER LEVEL: &a{0} Commands.Reset.All=&aAll of your skill levels have been reset successfully. Commands.Reset.Single=&aYour {0} skill level has been reset successfully. -Commands.Reset=&a- Reset a skill's level to 0 +Commands.Reset=&3 /skillreset &a- Reset a skill's level to 0 Commands.Scoreboard.Clear=&3mcMMO scoreboard cleared. Commands.Scoreboard.NoBoard=&cThe mcMMO scoreboard is not active. Commands.Scoreboard.Keep=&3The mcMMO scoreboard will stay up until you use &a/mcscoreboard clear&3. @@ -715,10 +788,10 @@ Commands.XPBar.Reset=&6XP Bar settings for mcMMO have been reset. Commands.XPBar.SettingChanged=&6XP Bar setting for &a{0}&6 is now set to &a{1} Commands.Skill.Invalid=That is not a valid skillname! Commands.Skill.ChildSkill=Child skills are not valid for this command! -Commands.Skill.Leaderboard=--mcMMO &9{0}&e Leaderboard-- -Commands.SkillInfo=&a- View detailed information about a skill -Commands.Stats=&a- View your mcMMO stats -Commands.ToggleAbility=&a- Toggle ability activation with right click +Commands.Skill.Leaderboard=-&e-mcMMO &9{0}&e Leaderboard-- +Commands.SkillInfo=&3 / &a- View detailed information about a skill +Commands.Stats=&3 /mcstats &a- View your mcMMO stats +Commands.ToggleAbility=&3 /mcability &a- Toggle ability activation with right click Commands.Usage.0=&cProper usage is /{0} Commands.Usage.1=&cProper usage is /{0} {1} Commands.Usage.2=&cProper usage is /{0} {1} {2} @@ -830,20 +903,23 @@ 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 +Commands.XPGain.Maces=Attacking Monsters 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} Commands.xplock.locked=&6Your XP BAR is now locked to {0}! Commands.xplock.unlocked=&6Your XP BAR is now &aUNLOCKED&6! Commands.xprate.modified=&cThe XP RATE was modified to {0} -Commands.xprate.over=&cmcMMO XP Rate Event is OVER!! +Commands.xprate.over=&cmcMMO XP Rate Event is OVER!! Commands.xprate.proper.0=&cProper usage to change the XP rate is /xprate Commands.xprate.proper.1=&cProper usage to restore the XP rate to default is /xprate reset Commands.xprate.proper.2=&cPlease specify true or false to indicate if this is an xp event or not @@ -881,8 +957,8 @@ Guides.Acrobatics.Section.2=&3How does Dodge work?\n&eDodge is a passive chance Guides.Alchemy.Section.0=[[DARK_AQUA]]About Alchemy:\n[[YELLOW]]Alchemy is about brewing potions.\n[[YELLOW]]It provides a speed increase in the potion brew time, as well\n[[YELLOW]]as the addition of new (previously) unobtainable potions.\n\n\n[[DARK_AQUA]]XP GAIN:\n[[YELLOW]]To gain XP in this skill you need to brew potions. Guides.Alchemy.Section.1=[[DARK_AQUA]]How does Catalysis work?\n[[YELLOW]]Catalysis speeds of the brewing process, with a\n[[YELLOW]]max speed of 4x at level 1000.\n[[YELLOW]]This ability is unlocked at level 100 by default. Guides.Alchemy.Section.2=[[DARK_AQUA]]How does Concoctions work?\n[[YELLOW]]Concoctions allows brewing of more potions with custom ingredients.\n[[YELLOW]]Which special ingredients are unlocked is determined\n[[YELLOW]]by your Rank. There are 8 ranks to unlock. -Guides.Alchemy.Section.3=[[DARK_AQUA]]Concoctions tier 1 ingredients:\n[[YELLOW]]Blaze Powder, Fermented Spider Eye, Ghast Tear, Redstone,\n[[YELLOW]]Glowstone Dust, Sugar, Glistering Melon, Golden Carrot,\n[[YELLOW]]Magma Cream, Nether Wart, Spider Eye, Suplhur, Water Lily,\n[[YELLOW]]Pufferfish\n[[YELLOW]](Vanilla Potions) -Guides.Alchemy.Section.4=[[DARK_AQUA]]Concoctions tier 2 ingredients:\n[[YELLOW]]Carrot (Potion of Haste)\n[[YELLOW]]Slimeball (Potion of Dullness)\n\n[[DARK_AQUA]]Concoctions tier 3 ingredients:\n[[YELLOW]]Quartz (Potion of Absorption)\n[[YELLOW]]Rabbit's Foot (Potion of Leaping) +Guides.Alchemy.Section.3=[[DARK_AQUA]]Concoctions tier 1 ingredients:\n[[YELLOW]]Blaze Powder, Fermented Spider Eye, Ghast Tear, Redstone,\n[[YELLOW]]Glowstone Dust, Sugar, Glistering Melon, Golden Carrot,\n[[YELLOW]]Magma Cream, Nether Wart, Spider Eye, Gunpowder, Rabbit's Foot,\n[[YELLOW]]Pufferfish\n[[YELLOW]](Vanilla Potions) +Guides.Alchemy.Section.4=[[DARK_AQUA]]Concoctions tier 2 ingredients:\n[[YELLOW]]Carrot (Potion of Haste)\n[[YELLOW]]Slimeball (Potion of Dullness)\n\n[[DARK_AQUA]]Concoctions tier 3 ingredients:\n[[YELLOW]]Quartz (Potion of Absorption)\n[[YELLOW]] Guides.Alchemy.Section.5=[[DARK_AQUA]]Concoctions tier 4 ingredients:\n[[YELLOW]]Apple (Potion of Health Boost)\n[[YELLOW]]Rotten Flesh (Potion of Hunger)\n\n[[DARK_AQUA]]Concoctions tier 5 ingredients:\n[[YELLOW]]Brown Mushroom (Potion of Nausea)\n[[YELLOW]]Ink Sack (Potion of Blindness) Guides.Alchemy.Section.6=[[DARK_AQUA]]Concoctions tier 6 ingredients:\n[[YELLOW]]Fern (Potion of Saturation)\n\n[[DARK_AQUA]]Concoctions tier 7 ingredients:\n[[YELLOW]]Poisonous Potato (Potion of Decay)\n\n[[DARK_AQUA]]Concoctions tier 8 ingredients:\n[[YELLOW]]Regular Golden Apple (Potion of Resistance) @@ -970,6 +1046,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.\nThis is a WIP skill and more information will be added soon. +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.\nThis is a WIP skill and more information will be added soon. +Guides.Maces.Section.0=&3About Maces:\n&eMaces is all about smashing your foes with a mace.\n\n&3XP GAIN:\n&eXP is gained whenever you hit mobs with a mace.\nThis is a WIP skill and more information will be added soon. + #INSPECT Inspect.Offline= &cYou do not have permission to inspect offline players! Inspect.OfflineStats=mcMMO Stats for Offline Player &e{0} @@ -1144,4 +1227,4 @@ Broadcasts.LevelUpMilestone=&6(&amcMMO&6) {0}&7 has reached level &a{1}&7 in &3{ Broadcasts.PowerLevelUpMilestone=&6(&amcMMO&6) {0}&7 has reached a Power level of &a{1}&7! Scoreboard.Recovery=Attempting to recover mcMMO scoreboard... Scoreboard.Disabled=The mcMMO scoreboards for this server are disabled, this setting is found in mcMMO/config.yml -Scoreboard.NotSetupYet=Your mcMMO scoreboard has not been setup yet, try again later. \ No newline at end of file +Scoreboard.NotSetupYet=Your mcMMO scoreboard has not been setup yet, try again later. diff --git a/src/main/resources/locale/locale_es.properties b/src/main/resources/locale/locale_es.properties index 1a97cd0fa..a4aa338ee 100644 --- a/src/main/resources/locale/locale_es.properties +++ b/src/main/resources/locale/locale_es.properties @@ -1,677 +1,1230 @@ -Acrobatics.Ability.Proc=&a**Aterrizaje Agraciado** +Placeholder= Este valor es para cualquier entrada de idioma en progreso que no se mostrará a los usuarios +JSON.Rank=Rango +JSON.DescriptionHeader=Descripción: +JSON.JWrapper.Header=Detalles +JSON.Type.Passive=Pasivo +JSON.Type.Active=Activo +JSON.Type.SuperAbility=Súper Habilidad +JSON.Locked=-=[BLOQUEADO]=- +JSON.LevelRequirement=Requisito de Nivel +JSON.JWrapper.Target.Type=Tipo de Objetivo: +JSON.JWrapper.Target.Block=Bloque +JSON.JWrapper.Target.Player=Jugador +JSON.JWrapper.Perks.Header=&6Beneficios de Suerte +JSON.JWrapper.Perks.Lucky={0}% Mejores Probabilidades +JSON.Hover.Tips=Consejos +JSON.Acrobatics=Acróbatas +JSON.Alchemy=Alquimia +JSON.Archery=Arquería +JSON.Axes=Hachas +JSON.Crossbows=Ballestas +JSON.Excavation=Excavación +JSON.Fishing=Pesca +JSON.Herbalism=Herboristería +JSON.Mining=Minería +JSON.Repair=Reparación +JSON.Salvage=Recuperación +JSON.Swords=Espadas +JSON.Taming=Domesticación +JSON.Tridents=Tridentes +JSON.Maces=Mazas +JSON.Unarmed=Desarmado +JSON.Woodcutting=Tala +JSON.URL.Website=¡El sitio web oficial de mcMMO! +JSON.URL.Discord=¡El servidor oficial de Discord de mcMMO! +JSON.URL.Patreon=¡Apoya a nossr50 y su trabajo en mcMMO en Patreon! +JSON.URL.Spigot=¡La página de recursos oficial de mcMMO en Spigot! +JSON.URL.Translation=¡Traduce mcMMO a otros idiomas! +JSON.URL.Wiki=¡La wiki oficial de mcMMO! +JSON.SkillUnlockMessage=&6[ mcMMO&e @&3{0} &6Rango &3{1}&6 Desbloqueado! ] +JSON.Hover.Rank=&e&lRango:&r &f{0} +JSON.Hover.NextRank=&7&oPróxima mejora en el nivel {0} +# for JSON.Hover.Mystery you can add {0} to insert the level required into the name, I don't like how that looks so I'm not doing that atm +JSON.Hover.Mystery=&7??? +JSON.Hover.Mystery2=&e[&8{0}&e]&8???&r +JSON.Hover.SkillName=&3{0}&r +JSON.Hover.SuperAbility=&5{0}&r +JSON.Hover.MaxRankSkillName=&6{0}&r +JSON.Hover.AtSymbolSkills=&e@ +JSON.Hover.AtSymbolURL=&e@ + +#This is the message sent to players when an ability is activated +JSON.Notification.SuperAbility={0} + +#These are the JSON Strings used for SubSkills +JSON.Acrobatics.Roll.Interaction.Activated=Prueba &cRodado Prueba +JSON.Acrobatics.SubSkill.Roll.Details.Tips=Si mantienes presionado el botón de agacharse mientras caes, puedes prevenir hasta el doble del daño que normalmente recibirías. +Anvil.SingleItemStack=&cNo puedes desmantelar o reparar pilas de objetos que tengan más de un objeto, separa la pila primero. + +#DO NOT USE COLOR CODES IN THE JSON KEYS +#COLORS ARE DEFINED IN advanced.yml IF YOU WISH TO CHANGE THEM + +mcMMO.Template.Prefix=&6(&amcMMO&6) &7{0} +# BEGIN STYLING +Ability.Generic.Refresh=&a**HABILIDADES REFRESCADAS!** +Ability.Generic.Template.Lock=&7{0} +# Skill Command Styling +Ability.Generic.Template=&3{0}: &a{1} +Ability.Generic.Template.Custom=&3{0} +Skills.Overhaul.Header=&c[]=====[]&a {0} &c[]=====[] +Effects.Effects=EFECTOS +Effects.SubSkills.Overhaul=Sub-Habilidades +Effects.Child.Overhaul=&3Nivel de Hijo.&e {0}&3: {1} +Effects.Child.ParentList=&a{0}&6(&3Nivel.&e{1}&6) +Effects.Level.Overhaul=&6NIV: &e{0} &3XP&e(&6{1}&e/&6{2}&e) +Effects.Parent=&6{0} - +Effects.Template=&3{0}: &a{1} +Commands.Stats.Self.Overhaul=Estadísticas +Commands.XPGain.Overhaul=&6GANANCIA DE XP: &3{0} +MOTD.Version.Overhaul=&6[mcMMO] &3Era de Overhaul&6 - &3{0} +Overhaul.mcMMO.Header=&c[]=====[]&a mcMMO - Era de Overhaul &c[]=====[] +Overhaul.mcMMO.Url.Wrap.Prefix=&c[| +Overhaul.mcMMO.Url.Wrap.Suffix=&c|] +Overhaul.mcMMO.MmoInfo.Wiki=&e[&f¡Ver esta habilidad en la wiki!&e] +# Overhaul.Levelup can take {0} - Skill Name defined in Overhaul.Name {1} - Amount of levels gained {2} - Level in skill +Overhaul.Levelup=&l{0} aumentó a &r&a&l{2}&r&f. +Overhaul.Name.Acrobatics=Acróbatas +Overhaul.Name.Alchemy=Alquimia +Overhaul.Name.Archery=Arquería +Overhaul.Name.Axes=Hachas +Overhaul.Name.Crossbows=Ballestas +Overhaul.Name.Excavation=Excavación +Overhaul.Name.Fishing=Pesca +Overhaul.Name.Herbalism=Herboristería +Overhaul.Name.Mining=Minería +Overhaul.Name.Repair=Reparación +Overhaul.Name.Salvage=Recuperación +Overhaul.Name.Smelting=Fundición +Overhaul.Name.Swords=Espadas +Overhaul.Name.Taming=Domesticación +Overhaul.Name.Tridents=Tridentes +Overhaul.Name.Maces=Mazas +Overhaul.Name.Unarmed=Desarmado +Overhaul.Name.Woodcutting=Leñador +# /mcMMO Command Style Stuff +Commands.mcc.Header=&c---[]&amcMMO Comandos&c[]--- +Commands.Other=&c---[]&aCOMANDOS ESPECIALES&c[]--- +Commands.Party.Header=&c-----[]&aPARTIDO&c[]----- +Commands.Party.Features.Header=&c-----[]&aCARACTERÍSTICAS&c[]----- +# XP BAR Allows for the following variables -- {0} = Skill Level, {1} Current XP, {2} XP Needed for next level, {3} Power Level, {4} Percentage of Level +# Make sure you turn on Experience_Bars.ThisMayCauseLag.AlwaysUpdateTitlesWhenXPIsGained if you want the XP bar title to update every time a player gains XP! +XPBar.Template={0} +XPBar.Template.EarlyGameBoost=&6Aprendiendo una nueva habilidad... +XPBar.Acrobatics=Acróbatas Nv.&6{0} +XPBar.Alchemy=Alquimia Nv.&6{0} +XPBar.Archery=Arquería Nv.&6{0} +XPBar.Axes=Hachas Nv.&6{0} +XPBar.Crossbows=Ballestas Nv.&6{0} +XPBar.Excavation=Excavación Nv.&6{0} +XPBar.Fishing=Pesca Nv.&6{0} +XPBar.Herbalism=Herboristería Nv.&6{0} +XPBar.Mining=Minería Nv.&6{0} +XPBar.Repair=Reparación Nv.&6{0} +XPBar.Salvage=Recuperación Nv.&6{0} +XPBar.Smelting=Fundición Nv.&6{0} +XPBar.Swords=Espadas Nv.&6{0} +XPBar.Taming=Domar Nv.&6{0} +XPBar.Tridents=Tridentes Nv.&6{0} +XPBar.Maces=Mazas Nv.&6{0} +XPBar.Unarmed=Desarmado Nv.&6{0} +XPBar.Woodcutting=Leñador Nv.&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 +XPBar.Complex.Template={0} &3 {4}&f% &3(&f{1}&3/&f{2}&3) +# XP BAR Allows for the following variables -- {0} = Skill Level, {1} Current XP, {2} XP Needed for next level, {3} Power Level, {4} Percentage of Level +# Make sure you turn on Experience_Bars.ThisMayCauseLag.AlwaysUpdateTitlesWhenXPIsGained if you want the XP bar title to update every time a player gains XP! +# END STYLING + +#ACROBATICS +Acrobatics.Ability.Proc=&a**Aterrizaje Gracioso** Acrobatics.Combat.Proc=&a**Esquivado** -Acrobatics.DodgeChance=Probabilidad de Esquivar: &e{0}% -Acrobatics.SubSkill.Roll.Name=Rodada -Acrobatics.SubSkill.Roll.Description=Reduce o Elimina el daño de caida -Acrobatics.SubSkill.GracefulRoll.Name=Rodada Majestuosa -Acrobatics.SubSkill.GracefulRoll.Description=El doble de efectivo que una rodada normal +Acrobatics.SubSkill.Roll.Stats=&6Probabilidad de Rodar &e{0}%&6 Probabilidad de Rodar Gracioso&e {1}% +Acrobatics.SubSkill.Roll.Stat=Probabilidad de Rodar +Acrobatics.SubSkill.Roll.Stat.Extra=Probabilidad de Rodar Gracioso +Acrobatics.SubSkill.Roll.Name=Rodar +Acrobatics.SubSkill.Roll.Description=Aterriza estratégicamente para evitar daños. +Acrobatics.SubSkill.Roll.Chance=Probabilidad de Rodar: &e{0} +Acrobatics.SubSkill.Roll.GraceChance=Probabilidad de Rodar Gracioso: &e{0} +Acrobatics.SubSkill.Roll.Mechanics=&7Rodar es una Sub-Habilidad activa con un componente pasivo.\nCada vez que recibes daño por caída, tienes una probabilidad de anular completamente el daño en función de tu nivel de habilidad, en el nivel &e{6}%&7 tienes un &e{0}%&7 de probabilidad de evitar daño, y un &e{1}%&7 si activas Rodar Gracioso.\nLa probabilidad de éxito se escala con tu nivel de habilidad en una curva lineal hasta el nivel &e{2}&7 donde se maximiza, cada nivel en Acróbatas te da un &e{3}%&7 de probabilidad de éxito.\nManteniendo presionado el botón de agacharse, puedes duplicar tus probabilidades de evitar daño por caída y evitar hasta el doble de daño por caída! Mantener presionado el botón de agacharse transformará un rodar normal en un Rodar Gracioso.\nRodar solo evitará hasta &c{4}&7 de daño. Los Rodar Graciosos evitarán hasta &a{5}&7 de daño. +Acrobatics.SubSkill.GracefulRoll.Name=Rodar Gracioso +Acrobatics.SubSkill.GracefulRoll.Description=Doble de efectivo que un rodar normal Acrobatics.SubSkill.Dodge.Name=Esquivar -Acrobatics.SubSkill.Dodge.Description=Reduce el daño de ataque a la mitad -Acrobatics.Listener=Acrobacias: -Acrobatics.SubSkill.Roll.Chance=Probabilidad de Rodar: &e{0}% -Acrobatics.SubSkill.Roll.GraceChance=Probabilidad de Rodada Majestuosa: &e{0}% -Acrobatics.Roll.Text=**Rodado** -Acrobatics.SkillName=ACROBACIAS -Acrobatics.Skillup=Habilidad de Acrobacias incrementada en {0}. Total ({1}) -Archery.Combat.DazeChance=Probabilidad de Aturdimiento: &e{0}% -Archery.Combat.RetrieveChance=Probabilidad de Recuperar Flechas: &e{0} -Archery.Combat.SkillshotBonus=Daño bonus por Habilidad de Tiro: &e{0} -Archery.SubSkill.SkillShot.Name=Habilidad de Tiro -Archery.SubSkill.SkillShot.Description=Incrementar daño hecho con arcos -Archery.SubSkill.Daze.Name=Aturdir (Jugadores) -Archery.SubSkill.Daze.Description=Desorienta a los enemigos y inflige {0} DMG -Archery.SubSkill.ArrowRetrieval.Name=Recuperación de Flecha -Archery.SubSkill.ArrowRetrieval.Description=Probabilidad de recuperar flechas de los cadaveres +Acrobatics.SubSkill.Dodge.Description=Reduce el daño de los ataques a la mitad +Acrobatics.SubSkill.Dodge.Stat=Probabilidad de Esquivar +Acrobatics.Listener=Acróbatas: +Acrobatics.Roll.Text=&o**Rodado** +Acrobatics.SkillName=ACRÓBATAS +#ALCHEMY +Alchemy.SubSkill.Catalysis.Name=Catalización +Alchemy.SubSkill.Catalysis.Description=Aumenta la velocidad de elaboración de pociones +Alchemy.SubSkill.Catalysis.Stat=Velocidad de Elaboración +Alchemy.SubSkill.Concoctions.Name=Concocciones +Alchemy.SubSkill.Concoctions.Description=Elaborar pociones con más ingredientes +Alchemy.SubSkill.Concoctions.Stat=Rango de Concocciones: &a{0}&3/&a{1} +Alchemy.SubSkill.Concoctions.Stat.Extra=Ingredientes [&a{0}&3]: &a{1} +Alchemy.Listener=Alquimia: +Alchemy.Ability.Locked.0=BLOQUEADO HASTA NIVEL {0}+ DE HABILIDAD (CATALIZACIÓN) +Alchemy.SkillName=ALQUIMIA +#ARCHERY +Archery.SubSkill.SkillShot.Name=Tiro de Habilidad +Archery.SubSkill.SkillShot.Description=Aumenta el daño hecho con arcos +Archery.SubSkill.SkillShot.Stat=Bonificación de Daño por Tiro de Habilidad +Archery.SubSkill.Daze.Name=Aturdir +Archery.SubSkill.Daze.Description=Desorienta a los enemigos y hace daño adicional +Archery.SubSkill.Daze.Stat=Probabilidad de Aturdir +Archery.SubSkill.ArrowRetrieval.Name=Recuperación de Flechas +Archery.SubSkill.ArrowRetrieval.Description=Probabilidad de recuperar flechas de cadáveres +Archery.SubSkill.ArrowRetrieval.Stat=Probabilidad de Recuperación de Flechas +Archery.SubSkill.ArcheryLimitBreak.Name=Ruptura de Límite de Arquería +Archery.SubSkill.ArcheryLimitBreak.Description=Superando tus límites. Aumento de daño contra oponentes fuertes. Destinado al PVP, según la configuración del servidor para determinar si aumentará el daño en PVE. +Archery.SubSkill.ArcheryLimitBreak.Stat=Daño Máximo de Ruptura de Límite Archery.Listener=Arquería: Archery.SkillName=ARQUERÍA -Archery.Skillup=Habilidad de Arquería incrementada en {0}. Total ({1}) -Axes.Ability.Bonus.0=Dominio del Hacha -Axes.Ability.Bonus.1={0} de Daño Bonus -Axes.Ability.Bonus.2=Impacto -Axes.Ability.Bonus.3=Aplicar un bonus de {0} de daño a la armadura -Axes.Ability.Bonus.4=Gran Impacto -Axes.Ability.Bonus.5=Hacer {0} de daño bonus a los enemigos sin armadura -Axes.Ability.Lower=&7**BAJAS TU HACHA** -Axes.Ability.Ready=&a**PREPARAS TU HACHA** -Axes.Combat.CritStruck=&4¡Fuiste golpeado CRÍTICAMENTE! -Axes.Combat.CritChance=Probabilidad de golpe crítico: &e{0}% +Archery.SubSkill.ExplosiveShot.Name=Tiro Explosivo +Archery.SubSkill.ExplosiveShot.Description=Dispara una flecha explosiva +Archery.Skills.ExplosiveShot.Off= +Archery.Skills.ExplosiveShot.On=&a**TIRO EXPLOSIVO ACTIVADO** +Archery.Skills.ExplosiveShot.Other.Off=Tiro Explosivo&a se ha desactivado para &e{0} +Archery.Skills.ExplosiveShot.Other.On=&a{0}&2 ha usado &cTiro Explosivo! +Archery.Skills.ExplosiveShot.Refresh=&aTu habilidad &Tiro Explosivo &ha sido refrescada! +#AXES +Axes.Ability.Bonus.0=Maestría con Hachas +Axes.Ability.Bonus.1=Bonificación de {0} daño +Axes.Ability.Bonus.2=Impacto en la Armadura +Axes.Ability.Bonus.3=Inflige {0} daño adicional a la armadura +Axes.Ability.Bonus.4=Impacto Mayor +Axes.Ability.Bonus.5=Inflige {0} daño adicional a enemigos sin armadura +Axes.Ability.Lower=&7Bajas tu Hacha. +Axes.Ability.Ready=&3Preparas &6tu Hacha&3. +Axes.Ability.Ready.Extra=&3Preparas &6tu Hacha&3. &7({0} está en enfriamiento por {1}s) +Axes.Combat.CritStruck=&4¡Has recibido un GOLPE CRÍTICO! Axes.Combat.CriticalHit=¡GOLPE CRÍTICO! Axes.Combat.GI.Proc=&a**GOLPEADO CON GRAN FUERZA** Axes.Combat.GI.Struck=**GOLPEADO POR IMPACTO MAYOR** -Axes.Combat.SS.Struck=&4Golpeado mediante DIVISOR DE CRANEOS! -Axes.Combat.SS.Length=Duración de Parte Cráneos: &e{0}seg -Axes.SubSkill.SkullSplitter.Name=Parte Cráneos (HABILIDAD) -Axes.SubSkill.SkullSplitter.Description=Distribuir Daño en el Área de Cobertura +Axes.Combat.SS.Struck=&4¡Golpeado por ROMPECRÁNEOS! +Axes.SubSkill.SkullSplitter.Name=Rompecráneos +Axes.SubSkill.SkullSplitter.Description=Causa Daño en Área (AoE) +Axes.SubSkill.SkullSplitter.Stat=Duración de Rompecráneos Axes.SubSkill.CriticalStrikes.Name=Golpes Críticos Axes.SubSkill.CriticalStrikes.Description=Daño Doble -Axes.SubSkill.AxeMastery.Name=Dominio del Hacha -Axes.SubSkill.AxeMastery.Description=Agrega daño bonus -Axes.SubSkill.ArmorImpact.Name=Impacto -Axes.SubSkill.ArmorImpact.Description=Golpear con fuerza como para destruir armaduras -Axes.SubSkill.GreaterImpact.Name=Gran Impacto -Axes.SubSkill.GreaterImpact.Description=Hacer daño bonus a los enemigos sin armadura +Axes.SubSkill.CriticalStrikes.Stat=Probabilidad de Golpe Crítico +Axes.SubSkill.AxeMastery.Name=Maestría en Hachas +Axes.SubSkill.AxeMastery.Description=Añade bonificación de DAÑO +Axes.SubSkill.AxesLimitBreak.Name=Límite de Rotura de Hachas +Axes.SubSkill.AxesLimitBreak.Description=Rompe tus límites. Aumenta el daño contra oponentes difíciles. Intencionado para PvP, depende de la configuración del servidor si incrementará el daño en PvE. +Axes.SubSkill.AxesLimitBreak.Stat=Daño Máximo del Límite de Rotura +Axes.SubSkill.ArmorImpact.Name=Impacto en Armadura +Axes.SubSkill.ArmorImpact.Description=Golpea con suficiente fuerza para romper la armadura +Axes.SubSkill.GreaterImpact.Name=Impacto Mayor +Axes.SubSkill.GreaterImpact.Description=Causa daño adicional a enemigos sin armadura Axes.Listener=Hachas: Axes.SkillName=HACHAS -Axes.Skills.SS.Off=**Parte Cráneos ha expirado** -Axes.Skills.SS.On=&a**PARTE CRÁNEOS ACTIVADO** -Axes.Skills.SS.Refresh=&a¡Tu habilidad &eParte Cráneos &aestá refrescada! -Axes.Skills.SS.Other.Off=Parte Cráneos&a le ha expirado a &e{0} -Axes.Skills.SS.Other.On=&a¡{0}&2 usó &cParte Cráneos! -Axes.Skillup=Habilidad de Hacha incrementada en {0}. Total ({1}) -Excavation.Ability.Lower=&7**BAJAS TU PALA** -Excavation.Ability.Ready=&a**PREPARAS TU PALA** -Excavation.SubSkill.GigaDrillBreaker.Name=Ultra Taladro Destructor (HABILIDAD) -Excavation.SubSkill.GigaDrillBreaker.Description=Triple Drop, Tripe EXP, Más Velocidad -Excavation.SubSkill.TreasureHunter.Name=Cazador de Tesoros -Excavation.SubSkill.TreasureHunter.Description=Habilidad para cavar por tesoros -Excavation.Effect.Length=Duración de Ultra Taladro Destructor: &e{0}seg +Axes.Skills.SS.Off=**Rompecráneos ha terminado** +Axes.Skills.SS.On=&a**Rompecráneos ACTIVADO** +Axes.Skills.SS.Refresh=&aTu &eRompecráneos &a habilidad ha sido refrescada! +Axes.Skills.SS.Other.Off=Rompecráneos&a ha terminado para &e{0} +Axes.Skills.SS.Other.On=&a{0}&2 ha usado &cRompecráneos! +#EXCAVATION +Excavation.Ability.Lower=&7Bajas tu pala. +Excavation.Ability.Ready=&3Tú &6preparas&3 tu Pala. +Excavation.SubSkill.GigaDrillBreaker.Name=Giga Taladro Destructor +Excavation.SubSkill.GigaDrillBreaker.Description=3x Tasa de Caída, 3x EXP, +Velocidad +Excavation.SubSkill.GigaDrillBreaker.Stat=Duración de Giga Taladro Destructor +Excavation.SubSkill.Archaeology.Name=Arqueología +Excavation.SubSkill.Archaeology.Description=¡Desentierra los secretos de la tierra! Los niveles altos de habilidad aumentan tus probabilidades de encontrar orbes de experiencia al encontrar tesoros. +Excavation.SubSkill.Archaeology.Stat=Probabilidad de Orbe de Experiencia de Arqueología +Excavation.SubSkill.Archaeology.Stat.Extra=Cantidad de Orbes de Experiencia de Arqueología Excavation.Listener=Excavación: Excavation.SkillName=EXCAVACIÓN -Excavation.Skills.GigaDrillBreaker.Off=**Ultra Taladro Destructor ha expirado** -Excavation.Skills.GigaDrillBreaker.On=&a**GIGA DRILL BREAKER ACTIVADO** -Excavation.Skills.GigaDrillBreaker.Refresh=&a¡Tu habilidad de &eUltra Taladro Destructor &afue refrescada! -Excavation.Skills.GigaDrillBreaker.Other.Off=Ultra Taladro Destructor&a le ha expirado a &e{0} -Excavation.Skills.GigaDrillBreaker.Other.On=&a¡{0}&2 usó &cUltra Taladro Destructor! -Excavation.Skillup=Habilidad de Excavación incrementada en {0}. Total ({1}) -Fishing.Ability.Chance=Probabilidad de mordisco: &e{0} -Fishing.Ability.Info=Cazador Mágico: &7 **Mejora con Rango de Buscador de Tesoros** -Fishing.Ability.Locked.0=Bloqueado hasta {0}+ habilidad (sacudir) -Fishing.Ability.Locked.1=Bloqueado hasta {0}+ HABILIDAD (PESCA DE HIELO) -Fishing.Ability.Rank=Cazador de Tesoros: &eRango {0}/5 -Fishing.Ability.TH.MagicRate=Probabilidad de Cazador Mágico: &e{0} -Fishing.Ability.Shake=Probabilidad de esquivar: &e{0} -Fishing.Ability.IceFishing=Pesca de hielo: ve a pescar en el hielo -Fishing.Ability.FD=Dieta del pescador: &eRank {0} -Fishing.SubSkill.TreasureHunter.Name=Cazador de Tesoros (Pasivo) -Fishing.SubSkill.TreasureHunter.Description=Pescar objetos misceláneos +Excavation.Skills.GigaDrillBreaker.Off=**Giga Taladro Destructor ha terminado** +Excavation.Skills.GigaDrillBreaker.On=&a**GIGA TALADRO DESTRUCTOR ACTIVADO** +Excavation.Skills.GigaDrillBreaker.Refresh=&aLa habilidad de tu &eGiga Taladro Destructor &a ha sido refrescada! +Excavation.Skills.GigaDrillBreaker.Other.Off=Giga Taladro Destructor&a ha terminado para &e{0} +Excavation.Skills.GigaDrillBreaker.Other.On=&a{0}&2 ha usado &cGiga Taladro Destructor! +#FISHING +Fishing.ScarcityTip=&e&oEsta área está sufriendo de sobrepesca, lanza tu caña en un lugar diferente para obtener más peces. Al menos a {0} bloques de distancia. +Fishing.Scared=&7&o¡Movimientos caóticos espantarán a los peces! +Fishing.Exhausting=&c&oEl uso inadecuado de la caña de pescar causará fatiga y desgastará la caña. +Fishing.LowResourcesTip=&7Sientes que podría no haber muchos peces en esta área. Intenta pescar al menos a {0} bloques de distancia. +Fishing.Ability.Info=Cazador Mágico: &7 **Mejora con el rango de Cazador de Tesoros** +Fishing.Ability.Locked.0=BLOQUEADO HASTA NIVEL {0}+ HABILIDAD (SACUDIR) +Fishing.Ability.Locked.1=BLOQUEADO HASTA NIVEL {0}+ HABILIDAD (PESCA EN HIELO) +Fishing.Ability.Locked.2=BLOQUEADO HASTA NIVEL {0}+ HABILIDAD (MAESTRO PESCADOR) +Fishing.SubSkill.TreasureHunter.Name=Cazador de Tesoros +Fishing.SubSkill.TreasureHunter.Description=Pesca objetos diversos +Fishing.SubSkill.TreasureHunter.Stat=Rango de Cazador de Tesoros: &a{0}&3/&a{1} +Fishing.SubSkill.TreasureHunter.Stat.Extra=Tasa de Caída: &7Común: &e{0} &aNo común: &e{1}\n&9Raro: &e{2} &dÉpico: &e{3} &6Legendario: &e{4} &bMítico: &e{5} Fishing.SubSkill.MagicHunter.Name=Cazador Mágico -Fishing.SubSkill.MagicHunter.Description=Encuentra Objetos Encantados -Fishing.SubSkill.Shake.Name=Sacudir (contra Entidades) -Fishing.SubSkill.Shake.Description=Sacudir los items fuera de los monstruos con la caña de pescar -Fishing.SubSkill.FishermansDiet.Name=Dieta del pescador -Fishing.SubSkill.FishermansDiet.Description=Mejora el hambre restaurada a partir de alimentos pescados -Fishing.SubSkill.MasterAngler.Name=Maestro pescador -Fishing.SubSkill.IceFishing.Name=Pesca de hielo -Fishing.SubSkill.IceFishing.Description=Te permite pescar en biomas de hielo -Fishing.Chance.Raining=&9 Lluvia de Bonus -Fishing.Listener=Pescador: -Fishing.Ability.TH.MagicFound=&7Sientes un toque de magia con esta pesca... -Fishing.SkillName=PESCADOR -Fishing.Skillup=Habilidad de Pescador incrementada en {0}. Total ({1}) -Herbalism.Ability.DoubleDropChance=Probabilidad de Doble Drop: &e{0} -Herbalism.Ability.FD=Dieta del granjero: &eRank {0} -Herbalism.Ability.GTe.Length=Duración de Tierra Verde: &e{0}seg -Herbalism.Ability.GTe.NeedMore=Necesitas mas semillas para esparcir tierra verde -Herbalism.Ability.GTh.Chance=Probabilidad de Pulgar Verde: &e{0} -Herbalism.Ability.GTh.Fail=**PULGAR VERDE FALLÓ** -Herbalism.Ability.GTh.Stage=Etapa de pulgar verde: &e Los cultivos crecen en la etapa {0} +Fishing.SubSkill.MagicHunter.Description=Encuentra objetos encantados +Fishing.SubSkill.MagicHunter.Stat=Probabilidad de Cazador Mágico +Fishing.SubSkill.Shake.Name=Sacudir +Fishing.SubSkill.Shake.Description=Sacude objetos de mobs o jugadores con una caña de pescar +Fishing.SubSkill.Shake.Stat=Probabilidad de Sacudir +Fishing.SubSkill.FishermansDiet.Name=Dieta del Pescador +Fishing.SubSkill.FishermansDiet.Description=Mejora la restauración de hambre con alimentos pescados +Fishing.SubSkill.FishermansDiet.Stat=Dieta del Pescador:&a Rango {0} +Fishing.SubSkill.MasterAngler.Name=Maestro Pescador +Fishing.SubSkill.MasterAngler.Description=Los peces se capturan con más frecuencia, funciona mejor cuando se pesca desde un bote. +Fishing.SubSkill.MasterAngler.Stat=Reducción de tiempo mínimo de espera para pescar: &a-{0} segundos +Fishing.SubSkill.MasterAngler.Stat.Extra=Reducción de tiempo máximo de espera para pescar: &a-{0} segundos +Fishing.SubSkill.IceFishing.Name=Pesca en Hielo +Fishing.SubSkill.IceFishing.Description=Te permite pescar en biomas helados +Fishing.SubSkill.IceFishing.Stat=Pesca en Hielo +Fishing.Chance.Raining=&9 Bonificación por Lluvia +Fishing.Listener=Pesca: +Fishing.Ability.TH.MagicFound=&7Sientes un toque de magia con esta captura... +Fishing.Ability.TH.Boom=&7¡TIEMPO DE EXPLOSIÓN! +Fishing.Ability.TH.Poison=&7Algo no huele bien... +Fishing.SkillName=PESCA +#HERBALISM +Herbalism.Ability.GTe.NeedMore=Necesitas más semillas para esparcir Terra Verde. +Herbalism.Ability.GTh.Fail=**FALLO EN PULGAR VERDE** Herbalism.Ability.GTh=&a**PULGAR VERDE** -Herbalism.Ability.HylianLuck=Probabilidad de Suerte de Hylian: &e{0} -Herbalism.Ability.Lower=&7**BAJAS TU AZADA** -Herbalism.Ability.Ready=&a**PREPARASTE TU AZADA** -Herbalism.Ability.ShroomThumb.Chance=Probabilidad de Pulgar Hongo: &e{0} -Herbalism.Ability.ShroomThumb.Fail=**PULGAR HONGO FALLIDO** -Herbalism.SubSkill.GreenTerra.Name=Tierra Verde (HABILIDAD) -Herbalism.SubSkill.GreenTerra.Description=Arar la Tierra, Triple Drops -Herbalism.SubSkill.GreenThumb.Name=Pulgar Verde (Trigo) -Herbalism.SubSkill.GreenThumb.Description=Autoplantar semillas cuando estas cosechando -Herbalism.Effect.4=Pulgar verde (Bloques) -Herbalism.SubSkill.GreenThumb.Description.2=Haces ladrillos mohosos o hacer crecer el pasto +Herbalism.Ability.Lower=&7Bajas tu Azada. +Herbalism.Ability.Ready=&3Tú &6preparas&3 tu Azada. +Herbalism.Ability.ShroomThumb.Fail=**FALLO EN PULGAR DE HONGO** +Herbalism.SubSkill.GreenTerra.Name=Terra Verde +Herbalism.SubSkill.GreenTerra.Description=Esparce la Terra, 3x Caídas, Aumenta Pulgar Verde +Herbalism.SubSkill.GreenTerra.Stat=Duración de Terra Verde +Herbalism.SubSkill.GreenThumb.Name=Pulgar Verde +Herbalism.SubSkill.GreenThumb.Description=Auto-Planta cultivos al cosechar con la azada +Herbalism.SubSkill.GreenThumb.Stat=Probabilidad de Pulgar Verde +Herbalism.SubSkill.GreenThumb.Stat.Extra=Etapa de Pulgar Verde: &a Los cultivos crecen en la etapa {0} +Herbalism.Effect.4=Pulgar Verde (Bloques) +Herbalism.SubSkill.GreenThumb.Description.2=Haz que los ladrillos se cubran de musgo o que crezca la hierba Herbalism.SubSkill.FarmersDiet.Name=Dieta del Granjero -Herbalism.SubSkill.FarmersDiet.Description=Aumenta el hambre restaurada por la comida cultivada -Herbalism.SubSkill.DoubleDrops.Name=Doble Drops (Todas las Hierbas) -Herbalism.SubSkill.DoubleDrops.Description=El doble del botín normal -Herbalism.SubSkill.HylianLuck.Name=Suerte de Hylian -Herbalism.SubSkill.HylianLuck.Description=Da una pequeña posibilidad de encontrar objetos raros -Herbalism.SubSkill.ShroomThumb.Name=Pulgar Hongo -Herbalism.SubSkill.ShroomThumb.Description=Esparcir micelio a tierra e hierva. -Herbalism.HylianLuck=&aLa suerte de Hyrule esta contigo hoy! -Herbalism.Listener=Herbalismo: -Herbalism.SkillName=HERBALISMO -Herbalism.Skills.GTe.On=&a**TIERRA VERDE ACTIVADO** -Herbalism.Skills.GTe.Refresh=&a¡Tu habilidad &eTierra Verde &aestá refrescada! -Herbalism.Skills.GTe.Other.Off=Tierra Verde&a le ha expirado a &e{0} -Herbalism.Skills.GTe.Other.On=&a¡{0}&2 usó &cTierra Verde! -Herbalism.Skillup=Habilidad de Herbalismo incrementada en {0}. Total ({1}) -Mining.Ability.Length=Duración de Super Destructor: &e{0}seg -Mining.Ability.Locked.0=Bloqueado hasta {0} + HABILIDAD (MINERIA EXPLOSIVA) -Mining.Ability.Locked.1=Bloqueado hasta {0} + HABILIDAD (MAYORES BOMBAS) -Mining.Ability.Locked.2=Bloqueado hasta {0} + HABILIDAD (EXPERTO EN DEMOLICIONES) -Mining.Ability.Lower=&7**BAJASTE TU PICO** -Mining.Ability.Ready=&a**PREPARAS TU PICO** -Mining.SubSkill.SuperBreaker.Name=Súper Destructor (HABILIDAD) -Mining.SubSkill.SuperBreaker.Description=Aumento de Velocidad, Probabilidad de Triple Drop -Mining.SubSkill.DoubleDrops.Name=Doble Drops -Mining.SubSkill.DoubleDrops.Description=El doble del botín normal -Mining.SubSkill.BlastMining.Name=Minería Explosiva -Mining.SubSkill.BlastMining.Description=Bonuses a la minería con TNT -Mining.SubSkill.BiggerBombs.Name=Mayores Bombas -Mining.SubSkill.BiggerBombs.Description=Incrementa el radio de la explosión de TNT -Mining.SubSkill.DemolitionsExpertise.Name=Experto en Demoliciones -Mining.SubSkill.DemolitionsExpertise.Description=Reduce el daño de las explosiones de TNT -Mining.Effect.Decrease=Daño de Experto en Demolición Decrementado: &e{0} -Mining.Effect.DropChance=Probabilidad de Doble Drop: &e{0} +Herbalism.SubSkill.FarmersDiet.Description=Mejora la restauración de hambre con alimentos cultivados +Herbalism.SubSkill.FarmersDiet.Stat=Dieta del Granjero: &aRango {0} +Herbalism.SubSkill.DoubleDrops.Name=Doble Recompensa +Herbalism.SubSkill.DoubleDrops.Description=Cosecha hábilmente el doble de botín +Herbalism.SubSkill.DoubleDrops.Stat=Probabilidad de Doble Recompensa +Herbalism.SubSkill.VerdantBounty.Name=Abundancia Verde +Herbalism.SubSkill.VerdantBounty.Description=Cosecha con maestría el triple de botín +Herbalism.SubSkill.VerdantBounty.Stat=Probabilidad de Triple Botín +Herbalism.SubSkill.HylianLuck.Name=Suerte Hyliana +Herbalism.SubSkill.HylianLuck.Description=Otorga una pequeña probabilidad de encontrar objetos raros +Herbalism.SubSkill.HylianLuck.Stat=Probabilidad de Suerte Hyliana +Herbalism.SubSkill.ShroomThumb.Name=Dedo de Hongo +Herbalism.SubSkill.ShroomThumb.Description=Extiende micelio sobre tierra y césped +Herbalism.SubSkill.ShroomThumb.Stat=Probabilidad de Dedo de Hongo +Herbalism.HylianLuck=&a¡La suerte de Hyrule está contigo hoy! +Herbalism.Listener=Herboristería: +Herbalism.SkillName=HERBORISTERÍA +Herbalism.Skills.GTe.Off=**Green Terra se ha desvanecido** +Herbalism.Skills.GTe.On=&a**GREEN TERRA ACTIVADO** +Herbalism.Skills.GTe.Refresh=&aTu habilidad &eGreen Terra &a ha sido refrescada! +Herbalism.Skills.GTe.Other.Off=Green Terra&a se ha desvanecido para &e{0} +Herbalism.Skills.GTe.Other.On=&a{0}&2 ha usado &cGreen Terra! +#MINING +Mining.Ability.Locked.0=BLOQUEADO HASTA {0}+ SKILL (BLAST MINING) +Mining.Ability.Locked.1=BLOQUEADO HASTA {0}+ SKILL (BIGGER BOMBS) +Mining.Ability.Locked.2=BLOQUEADO HASTA {0}+ SKILL (DEMOLITIONS EXPERTISE) +Mining.Ability.Lower=&7Bajas tu pico. +Mining.Ability.Ready=&3Preparas&3 tu pico. +Mining.SubSkill.SuperBreaker.Name=Super Rompedor +Mining.SubSkill.SuperBreaker.Description=Velocidad+, Probabilidad de Triple Botín +Mining.SubSkill.SuperBreaker.Stat=Duración de Super Rompedor +Mining.SubSkill.DoubleDrops.Name=Botín Doble +Mining.SubSkill.DoubleDrops.Description=Extrae el doble de botín con habilidad +Mining.SubSkill.DoubleDrops.Stat=Probabilidad de Botín Doble +Mining.SubSkill.MotherLode.Name=Veta Madre +Mining.SubSkill.MotherLode.Description=Extrae con maestría el triple de botín +Mining.SubSkill.MotherLode.Stat=Probabilidad de Triple Botín +Mining.SubSkill.BlastMining.Name=Minería con Explosivos +Mining.SubSkill.BlastMining.Description=Bonificaciones al minar con TNT +Mining.SubSkill.BlastMining.Stat=Minería con Explosivos:&a Rango {0}/{1} &7({2}) +Mining.SubSkill.BlastMining.Stat.Extra=Incremento de Radio de Explosión: &a+{0} +Mining.SubSkill.BiggerBombs.Name=Bombas Más Grandes +Mining.SubSkill.BiggerBombs.Description=Aumenta el radio de explosión del TNT +Mining.SubSkill.DemolitionsExpertise.Name=Experiencia en Demoliciones +Mining.SubSkill.DemolitionsExpertise.Description=Disminuye el daño de las explosiones de TNT +Mining.SubSkill.DemolitionsExpertise.Stat=Reducción de Daño por Experiencia en Demoliciones + Mining.Listener=Minería: Mining.SkillName=MINERÍA -Mining.Skills.SuperBreaker.Off=**Súper Destructor ha expirado** -Mining.Skills.SuperBreaker.On=&a**SÚPER DESTRUCTOR ACTIVADO** -Mining.Skills.SuperBreaker.Other.Off=Súper Destructor&a le ha expirado a &e{0} -Mining.Skills.SuperBreaker.Other.On=&a¡{0}&2 usó &cSuper Destructor! -Mining.Skills.SuperBreaker.Refresh=&a¡Tu habilidad de &eSúper Destructor &aestá refrescada! -Mining.Skillup=Habilidad de Minería incrementada en {0}. Total ({1}) +Mining.Skills.SuperBreaker.Off=**Super Rompedor se ha desvanecido** +Mining.Skills.SuperBreaker.On=&a**SUPER ROMPEDOR ACTIVADO** +Mining.Skills.SuperBreaker.Other.Off=Super Rompedor&a se ha desvanecido para &e{0} +Mining.Skills.SuperBreaker.Other.On=&a{0}&2 ha usado &cSuper Rompedor! +Mining.Skills.SuperBreaker.Refresh=&aTu habilidad &eSuper Rompedor &a ha sido refrescada! +#Blast Mining Mining.Blast.Boom=&7**BOOM** -Mining.Blast.Effect=+ {0} mineral de rendimiento, {1} x drops -Mining.Blast.Radius.Increase=Incrementado Radio de Explosión: &e+{0} -Mining.Blast.Rank=Minería Explosiva: &e Rango {0}/8 &7({1}) -Mining.Blast.Other.On=&a¡{0}&2 usó &cMinería Explosiva! -Mining.Blast.Refresh=&a¡Tu habilidad de &eMinería Explosiva &aestá refrescada! -Repair.SubSkill.Repair.Name=Reparación +Mining.Blast.Cooldown= +Mining.Blast.Effect=+{0} rendimiento de mineral, {1}x botín +Mining.Blast.Other.On=&a{0}&2 ha usado &cMinería con Explosivos! +Mining.Blast.Refresh=&aTu habilidad &eMinería con Explosivos &a ha sido refrescada! +#REPAIR +Repair.SubSkill.Repair.Name=Reparar Repair.SubSkill.Repair.Description=Reparar Herramientas y Armaduras -Repair.SubSkill.GoldRepair.Name=Reparar Oro (HABILIDAD {0}+) +Repair.SubSkill.GoldRepair.Name=Reparación de Oro ({0}+ HABILIDAD) Repair.SubSkill.GoldRepair.Description=Reparar Herramientas y Armaduras de Oro -Repair.SubSkill.IronRepair.Name=Reparar Metal (HABILIDAD {0}+) -Repair.SubSkill.IronRepair.Description=Reparar Herramientas y Armaduras de Metal -Repair.SubSkill.StoneRepair.Name=Reparar Piedra (HABILIDAD {0}+) +Repair.SubSkill.IronRepair.Name=Reparación de Hierro ({0}+ HABILIDAD) +Repair.SubSkill.IronRepair.Description=Reparar Herramientas y Armaduras de Hierro +Repair.SubSkill.StoneRepair.Name=Reparación de Piedra ({0}+ HABILIDAD) Repair.SubSkill.StoneRepair.Description=Reparar Herramientas de Piedra -Repair.SubSkill.RepairMastery.Name=Maestría de la Reparación -Repair.SubSkill.RepairMastery.Description=Cantidad de reparación Incrementada +Repair.SubSkill.RepairMastery.Name=Maestría en Reparación +Repair.SubSkill.RepairMastery.Description=Incrementa la cantidad de reparación +Repair.SubSkill.RepairMastery.Stat=Maestría en Reparación: &aExtra {0} durabilidad restaurada Repair.SubSkill.SuperRepair.Name=Súper Reparación -Repair.SubSkill.SuperRepair.Description=Doble Efectividad -Repair.SubSkill.DiamondRepair.Name=Reparación de Diamante ({0}+ SKILL) +Repair.SubSkill.SuperRepair.Description=Efectividad Doble +Repair.SubSkill.SuperRepair.Stat=Probabilidad de Súper Reparación +Repair.SubSkill.DiamondRepair.Name=Reparación de Diamante ({0}+ HABILIDAD) Repair.SubSkill.DiamondRepair.Description=Reparar Herramientas y Armaduras de Diamante -Repair.SubSkill.ArcaneForging.Name=Forjado Arcano +Repair.SubSkill.ArcaneForging.Name=Forja Arcana Repair.SubSkill.ArcaneForging.Description=Reparar objetos mágicos -Repair.SubSkill.Salvage.Name=Rescatado ({0}+ HABILIDAD) -Repair.SubSkill.Salvage.Description=&4Haz colocado un yunque, utiliza esto para reparar herramientas y armaduras. -Repair.Error=&4mcMMO encontro un error al intentar reparar este objeto! -Repair.Listener.Anvil=&4Has colocado un yunque y estos pueden usarse para reparar herramientas y armaduras. -Repair.Listener.Anvil2=&4Tu colocaste un yunque de reparación, utiliza esto para arreglar herramientas y armaduras. +Repair.SubSkill.ArcaneForging.Stat=Forja Arcana: &eRango {0}/{1} +Repair.SubSkill.ArcaneForging.Stat.Extra=&3Probabilidad de Forja Arcana:&7 Éxito &a{0}&7%, Fallo &c{1}&7% +Repair.Error=&4mcMMO encontró un error al intentar reparar este objeto. +Repair.Listener.Anvil=&aHas colocado un yunque, los yunques pueden reparar herramientas y armaduras. Repair.Listener=Reparación: Repair.SkillName=REPARACIÓN -Repair.Skills.AdeptSalvage=&4No tienes la habilidad suficiente para salvar objetos. -Repair.Skills.AdeptDiamond=&4No tienes la suficiente habilidad para reparar Diamante. -Repair.Skills.AdeptGold=&4No tienes la suficiente habilidad para reparar Oro. -Repair.Skills.AdeptIron=&4No tienes la suficiente habilidad para reparar Hierro. -Repair.Skills.AdeptStone=&4No tienes la suficiente habilidad para reparar Piedra. -Repair.Skills.Adept=Debes ser nivel &e{0}&c para reparar &e{1} -Repair.Skills.FeltEasy=&7Eso ha sido fácil. -Repair.Skills.FullDurability=&7Esto está nuevo. -Repair.Skills.SalvageSuccess=&7Objeto recuperado! -Repair.Skills.NotFullDurability=&4 No se puede rescatar los elementos dañados. -Repair.Skills.Mastery=Maestría de la Reparación: &e{0} de durabilidad adicional restaurada -Repair.Skills.StackedItems=&4No puedes reparar items apilados. -Repair.Skills.Super.Chance=Probabilidad de Super Reparación: &e{0} -Repair.Skillup=Habilidad de Reparación incrementada en {0}. Total ({1}) +Repair.Skills.AdeptDiamond=&4No tienes la habilidad suficiente para reparar Diamante. +Repair.Skills.AdeptGold=&4No tienes la habilidad suficiente para reparar Oro. +Repair.Skills.AdeptIron=&4No tienes la habilidad suficiente para reparar Hierro. +Repair.Skills.AdeptStone=&4No tienes la habilidad suficiente para reparar Piedra. +Repair.Skills.Adept=&cDebes ser nivel &e{0}&c para reparar &e{1} +Repair.Skills.FeltEasy=&7Eso se sintió fácil. +Repair.Skills.FullDurability=&7Eso está en plena durabilidad. +Repair.Skills.StackedItems=&4No puedes reparar objetos apilados. Repair.Pretty.Name=Reparar -Salvage.Pretty.Name=Objetos salvados -Repair.Arcane.Chance.Downgrade=&7Probabilidad de Degradación en FA: &e{0}% -Repair.Arcane.Chance.Success=&7Tasa de Éxito de FA: &e{0}% -Repair.Arcane.Downgrade=El poder Arcano de este objeto ha disminuído. -Repair.Arcane.Fail=El objeto ha perdido permanentemente sus poderes Arcanos -Repair.Arcane.Lost=No tienes habilidad suficiente para mantener ningún tipo de encantamientos. -Repair.Arcane.Perfect=&aHas logrado mantener las energías Arcanas de este objeto. -Repair.Arcane.Rank=Forja Arcana: &eRango {0}/4 -Swords.Ability.Lower=&7**BAJAS TU ESPADA** -Swords.Ability.Ready=&a**PREPARASTE TU ESPADA** -Swords.Combat.Bleed.Chance=Probabilidad de Sangramiento: &e{0} -Swords.Combat.Bleed.Length=Duración del Sangrado: &e{0} ticks -Swords.Combat.Bleed.Note=&7NOTA: &e1 Tick sucede cada 2 segundos -Swords.Combat.Bleeding.Started=&a**ENEMIGO SANGRANDO** -Swords.Combat.Bleeding.Stopped=&7¡El sangrado ha &aparado&7! +#Arcane Forging +Repair.Arcane.Downgrade=El poder arcano ha disminuido para este objeto. +Repair.Arcane.Fail=El poder arcano ha dejado permanentemente el objeto. +Repair.Arcane.Lost=No fuiste lo suficientemente hábil para mantener ningún encantamiento. +Repair.Arcane.Perfect=&aHas mantenido las energías arcanas en este objeto. +#SALVAGE +Salvage.Pretty.Name=Recuperar +Salvage.SubSkill.UnderstandingTheArt.Name=Comprender El Arte +Salvage.SubSkill.UnderstandingTheArt.Description=No solo estás hurgando en la basura de tu vecino, estás cuidando el medio ambiente.\nPotencia varias propiedades de la Recuperación. +Salvage.SubSkill.ScrapCollector.Name=Recolector de Chatarra +Salvage.SubSkill.ScrapCollector.Description=Recupera materiales de un objeto, una recuperación perfecta depende de la habilidad y la suerte. +Salvage.SubSkill.ScrapCollector.Stat=Recolector de Chatarra: &aRecupera hasta &e{0}&a objetos. +Salvage.SubSkill.ArcaneSalvage.Name=Desguace Arcano +Salvage.SubSkill.ArcaneSalvage.Description=Extrae encantamientos de los objetos +Salvage.SubSkill.ArcaneSalvage.Stat=Desguace Arcano: &eRango {0}/{1} +Salvage.Ability.Bonus.0=Recolector de Chatarra +Salvage.Ability.Bonus.1=Desguaza hasta &e{0}&a objetos. Se necesita algo de suerte. +Salvage.Arcane.ExtractFull=&7Probabilidad de Desguace Arcano para Encantamientos Completos +Salvage.Arcane.ExtractPartial=&7Probabilidad de Desguace Arcano para Encantamientos Parciales +Salvage.Skills.Success=&a¡Objeto desguazado! +Salvage.Skills.Adept.Damaged=&4No tienes la habilidad suficiente para desguazar objetos dañados. +Salvage.Skills.Adept.Level=Debes ser nivel &e{0}&c para desguazar &e{1} +Salvage.Skills.TooDamaged=&4Este objeto está demasiado dañado para ser desguazado. +Salvage.Skills.ArcaneFailed=&cNo pudiste extraer el conocimiento contenido en este objeto. +Salvage.Skills.ArcanePartial=&cSolo pudiste extraer parte del conocimiento contenido en este objeto. +Salvage.Skills.ArcaneSuccess=&a¡Pudiste extraer todo el conocimiento contenido en este objeto! +Salvage.Listener.Anvil=&aHas colocado un yunque de desguace, úsalo para desguazar herramientas y armaduras. +Salvage.Listener=Desguace: +Salvage.SkillName=DESGUACE +Salvage.Skills.Lottery.Normal=&6Pudiste desguazar &3{0}&6 materiales de &e{1}&6. +Salvage.Skills.Lottery.Perfect=&a&l¡Perfecto!&r&6 Desguazaste &3{1}&6 sin esfuerzo, recuperando &3{0}&6 materiales. +Salvage.Skills.Lottery.Untrained=&7No estás debidamente entrenado en desguace. Solo pudiste recuperar &c{0}&7 materiales de &a{1}&7. +#Anvil (Shared between SALVAGE and REPAIR) +Anvil.Unbreakable=¡Este objeto es irrompible! +Anvil.Repair.Reject.CustomModelData=Una fuerza misteriosa te impide reparar este objeto... +Anvil.Salvage.Reject.CustomModelData=Una fuerza misteriosa te impide desguazar este objeto... +#CROSSBOWS +Crossbows.SkillName=BALLESTAS +Crossbows.Ability.Lower=&7Bajas tu ballesta. +Crossbows.Ability.Ready=&3Preparas tu &6ballesta&3. +Crossbows.Skills.SSG.Refresh=&a¡Tu habilidad &eSuper Escopeta &ase ha recargado! +Crossbows.Skills.SSG.Other.On=&a{0}&2 usó &Super Escopeta! +Crossbows.SubSkill.PoweredShot.Name=Disparo Potenciado +Crossbows.SubSkill.PoweredShot.Description=Aumenta el daño causado con ballestas +Crossbows.SubSkill.PoweredShot.Stat=Bonificación de Daño por Disparo Potenciado +Crossbows.SubSkill.CrossbowsLimitBreak.Name=Límite de Ballestas +Crossbows.SubSkill.CrossbowsLimitBreak.Description=Superando tus límites. Aumenta el daño contra oponentes difíciles. Diseñado para PVP, según la configuración del servidor si aumentará el daño en PVE. +Crossbows.SubSkill.CrossbowsLimitBreak.Stat=Daño Máximo por Límite +Crossbows.SubSkill.TrickShot.Name=Disparo Truco +Crossbows.SubSkill.TrickShot.Description=Rebota flechas con ángulos pronunciados +Crossbows.SubSkill.TrickShot.Stat=Máximo de Rebotes por Disparo Truco +Crossbows.SubSkill.TrickShot.Stat.Extra=Máximo de Rebotes por Disparo Truco: &a{0} +Crossbows.SubSkill.TrickShot.Stat.Extra2=Daño Reducido por Rebote en Disparo Truco: &a{0} +Crossbows.SubSkill.SuperShotgun.Name=Super Escopeta +Crossbows.Listener=Ballestas: + +#TRIDENTS +Tridents.SkillName=TRIDENTES +Tridents.Ability.Lower=&7Bajas tu tridente. +Tridents.Ability.Ready=&3Preparas tu &6tridente&3. +Tridents.SubSkill.Impale.Name=Empalar +Tridents.SubSkill.Impale.Description=Aumenta el daño causado con tridentes +Tridents.SubSkill.Impale.Stat=Bonificación de Daño por Empalar +Tridents.SubSkill.TridentsLimitBreak.Name=Límite de Tridentes +Tridents.SubSkill.TridentsLimitBreak.Description=Superando tus límites. Aumenta el daño contra oponentes difíciles. Diseñado para PVP, según la configuración del servidor si aumentará el daño en PVE. +Tridents.SubSkill.TridentsLimitBreak.Stat=Daño Máximo por Límite +Tridents.SubSkill.TridentAbility.Name=En Proceso +Tridents.Listener=Tridentes: + +#MACES +Commands.McTop.MacesNotSupported=[[VERDE]]Las mazas no son compatibles con esta versión de Minecraft. +Maces.SkillName=MACES +Maces.Ability.Lower=&7Bajas tu maza. +Maces.Ability.Ready=&3Preparas tu &6maza&3. +Maces.SubSkill.MacesLimitBreak.Name=Límite de Mazas +Maces.SubSkill.MacesLimitBreak.Description=Superando tus límites. Aumenta el daño contra oponentes difíciles. Diseñado para PVP, según la configuración del servidor si aumentará el daño en PVE. +Maces.SubSkill.MacesLimitBreak.Stat=Daño Máximo por Límite +Maces.SubSkill.Crush.Name=Destruir +Maces.SubSkill.Crush.Description=Añade daño adicional a tus ataques. +Maces.SubSkill.Crush.Stat=Daño por Destrucción +Maces.SubSkill.Cripple.Proc=**LISIADO** +Maces.SubSkill.Cripple.Activated=¡OBJETIVO LISIADO! +Maces.SubSkill.Cripple.Name=Lisiar +Maces.SubSkill.Cripple.Description=Añade una posibilidad de lisiar a tu objetivo. +Maces.SubSkill.Cripple.Stat=Probabilidad de Lisiar +Maces.SubSkill.Cripple.Stat.Extra=[[AQUA_OSCURO]]Duración del Lisiado: &e{0}s&a contra Jugadores, &e{1}s&a contra Mobs. +Maces.Listener=Mazas: + +#SWORDS +Swords.Ability.Lower=&7Bajas tu espada. +Swords.Ability.Ready=&3Preparas tu &6espada&3. +Swords.Combat.Rupture.Note.Update.One=&7(Nota de Ruptura): El daño periódico no es letal, ocurre dos veces por segundo y atraviesa la armadura +Swords.Combat.Bleeding.Started=&4 ¡Estás sangrando! +Swords.Combat.Bleeding.Stopped=&7¡La hemorragia ha &asedetendido&7! Swords.Combat.Bleeding=&a**ENEMIGO SANGRANDO** -Swords.Combat.Counter.Chance=Probabilidad de Contra Ataque: &e{0} -Swords.Combat.Counter.Hit=&4¡Alcanzado por un contra ataque! -Swords.Combat.Countered=&a**CONTRA-ATACADO** -Swords.Combat.SS.Struck=&4¡Golpeado por ATAQUE DENTADO! -Swords.SubSkill.CounterAttack.Name=Contra Ataque -Swords.SubSkill.CounterAttack.Description=Refleja {0} del daño tomando mientras se bloquea -Swords.SubSkill.SerratedStrikes.Name=Ataque Dentado (HABILIDAD) -Swords.SubSkill.SerratedStrikes.Description={0} DMG AoE, Sangrado + AoE -Swords.Effect.4=Ataque Dentado Sangriento+ -Swords.Effect.5={0} marca de sangrado -Swords.SubSkill.Bleed.Name=Sangrado -Swords.SubSkill.Bleed.Description=Aplicar sangrado que daña con el tiempo +Swords.Combat.Counter.Hit=&4¡Golpeado con un contraataque! +Swords.Combat.Countered=&a**CONTRAATACADO** +Swords.Combat.SS.Struck=&4¡Golpeado por GOLPES SERRADOS! +Swords.SubSkill.CounterAttack.Name=Contraataque +Swords.SubSkill.CounterAttack.Description=¡Refleja una parte del daño cuando te atacan! +Swords.SubSkill.CounterAttack.Stat=Probabilidad de Contraataque +Swords.SubSkill.SerratedStrikes.Name=Golpes Serrados +Swords.SubSkill.SerratedStrikes.Description=Inflige daño parcial en un AOE con posibilidad de aplicar Ruptura +Swords.SubSkill.SerratedStrikes.Stat=Duración de Golpes Serrados +Swords.SubSkill.Rupture.Name=Ruptura +Swords.SubSkill.Rupture.Description=Un efecto de daño con el tiempo que termina explosivamente +Swords.SubSkill.Stab.Name=Apuñalar +Swords.SubSkill.Stab.Description=Añade daño adicional a tus ataques. +Swords.SubSkill.Stab.Stat=Daño por Apuñalamiento +Swords.SubSkill.SwordsLimitBreak.Name=Límite de Espadas +Swords.SubSkill.SwordsLimitBreak.Description=Superando tus límites. Aumenta el daño contra oponentes difíciles. Diseñado para PVP, según la configuración del servidor si aumentará el daño en PVE. +Swords.SubSkill.SwordsLimitBreak.Stat=Daño Máximo por Límite +Swords.SubSkill.Rupture.Stat=Probabilidad de Ruptura +Swords.SubSkill.Rupture.Stat.Extra=[[DARK_AQUA]]Duración de Ruptura: &e{0}s&a contra Jugadores, &e{1}s&a contra Mobs. +Swords.SubSkill.Rupture.Stat.TickDamage=[[DARK_AQUA]]Daño Puro por Tics de Ruptura: &e{0}&a contra Jugadores, &e{1}&a contra Mobs. +Swords.SubSkill.Rupture.Stat.ExplosionDamage=[[DARK_AQUA]]Daño por Explosión de Ruptura: &e{0}&a contra Jugadores, &e{1}&a contra Mobs. +Swords.Effect.4=Serrated Strikes Ruptura+ +Swords.Effect.5={0} Tic de Ruptura Swords.Listener=Espadas: Swords.SkillName=ESPADAS -Swords.Skills.SS.Off=**Ataque Dentado ha expirado** -Swords.Skills.SS.On=&a**ATAQUE DENTADO ACTIVADO** -Swords.Skills.SS.Refresh=&a¡Tu habilidad de &eGolpe Dentado &afue refrescada! -Swords.Skills.SS.Other.Off=Ataque Dentado&a le ha expirado a &e{0} -Swords.Skills.SS.Other.On=&a¡{0}&2 usó &cAtaque Dentado! -Swords.Skillup=Skill de espada se incremento en {0}. Total ({1}) -Swords.SS.Length=Duración del Ataque Dentado: &e{0}s -Taming.Ability.Bonus.0=Consciente del Entorno -Taming.Ability.Bonus.1=Lobos evitan peligros -Taming.Ability.Bonus.2=Piel Gruesa -Taming.Ability.Bonus.3=1/{0}Daño, Resistencia al fuego -Taming.Ability.Bonus.4=A Prueba de Golpes -Taming.Ability.Bonus.5=Los explosivos hacen un 1/{0} de daño normal. +Swords.Skills.SS.Off=**Serrated Strikes se ha desactivado** +Swords.Skills.SS.On=&a**SERRATED STRIKES ACTIVADO** +Swords.Skills.SS.Refresh=&aTu habilidad &eSerrated Strikes &ase ha refrescado! +Swords.Skills.SS.Other.Off=Serrated Strikes&a se ha desactivado para &e{0} +Swords.Skills.SS.Other.On=&a{0}&2 ha usado &cSerrated Strikes! +#TAMING +Taming.Ability.Bonus.0=Consciencia Ambiental +Taming.Ability.Bonus.1=Los lobos evitan el peligro +Taming.Ability.Bonus.2=Pelo Grueso +Taming.Ability.Bonus.3=1/{0} Daño, Resistencia al Fuego +Taming.Ability.Bonus.4=A prueba de choques +Taming.Ability.Bonus.5=Los explosivos hacen 1/{0} del daño normal Taming.Ability.Bonus.6=Garras Afiladas Taming.Ability.Bonus.7=+{0} Daño Taming.Ability.Bonus.8=Servicio de Comida Rápida -Taming.Ability.Bonus.9={0} Posibilidad de curarse durante el ataque -Taming.Ability.Bonus.10=Sabueso divino -Taming.Ability.Bonus.11=Recuperar vida cuando eres dañado por magia o veneno -Taming.Ability.Locked.0=Bloqueado hasta {0} + HABILIDAD (CONCIENCIADO CON EL MEDIOAMBIENTE) -Taming.Ability.Locked.1=Bloqueado hasta {0} + HABILIDAD (PIEL GRUESA) -Taming.Ability.Locked.2=Bloqueado hasta {0} + HABILIDAD (A PRUEBA DE GOLPES) -Taming.Ability.Locked.3=Bloqueado hasta {0} + HABILIDAD (GARRAS AFILADAS) -Taming.Ability.Locked.4=Bloqueado hasta {0} + HABILIDAD (SERVICIO DE COMIDA RAPIDA) -Taming.Ability.Locked.5=Bloqueado hasta {0}+ HABILIDAD (SABUESO DIVINO) -Taming.Combat.Chance.Gore=Probabilidad de Gore: &e{0} -Taming.SubSkill.BeastLore.Name=Conocimiento de la Bestia -Taming.SubSkill.BeastLore.Description=Golpear con un hueso para inspeccionar los lobos y ocelotes -Taming.SubSkill.ShockProof.Name=A Prueba de Golpes -Taming.SubSkill.ShockProof.Description=Reducción de Daño por Explosiones -Taming.SubSkill.CallOfTheWild.Name=Llamado a la Naturaleza -Taming.SubSkill.CallOfTheWild.Description=Convocar a un animal a tu lado -Taming.SubSkill.CallOfTheWild.Description.2=&7TIP (Ocelote): Agacharse y hacer click izquierdo con {0} pescados en la mano -Taming.Effect.15=&7TIP (Lobo): Agacharse y hacer click izquierdo con {0} huesos en la mano -Taming.SubSkill.Gore.Name0=&7 COTW (caballo): Agachate y haz clic con {0} manzanas en la mano +Taming.Ability.Bonus.9=Probabilidad de curarse al atacar del {0} +Taming.Ability.Bonus.10=Sabueso Sagrado +Taming.Ability.Bonus.11=Recupera salud cuando es dañado por magia o veneno +Taming.Ability.Locked.0=BLOQUEADO HASTA NIVEL {0}+ (CONSCIENCIA AMBIENTAL) +Taming.Ability.Locked.1=BLOQUEADO HASTA NIVEL {0}+ (PELO GRUESO) +Taming.Ability.Locked.2=BLOQUEADO HASTA NIVEL {0}+ (A PRUEBA DE CHOQUES) +Taming.Ability.Locked.3=BLOQUEADO HASTA NIVEL {0}+ (GARRAS AFILADAS) +Taming.Ability.Locked.4=BLOQUEADO HASTA NIVEL {0}+ (SERVICIO DE COMIDA RÁPIDA) +Taming.Ability.Locked.5=BLOQUEADO HASTA NIVEL {0}+ (SABUESO SAGRADO) +Taming.Combat.Chance.Gore=Probabilidad de Desgarro +Taming.SubSkill.BeastLore.Name=Conocimiento de Bestias +Taming.SubSkill.BeastLore.Description=Inspecciona lobos y ocelotes golpeándolos con un hueso +Taming.SubSkill.ShockProof.Name=A prueba de choques +Taming.SubSkill.ShockProof.Description=Reducción de Daño Explosivo +Taming.SubSkill.CallOfTheWild.Name=Llamado de la Naturaleza +Taming.SubSkill.CallOfTheWild.Description=Invoca un animal a tu lado +Taming.SubSkill.CallOfTheWild.Description.2=&7COTW: Agáchate y haz clic izquierdo con\n {0} {1} (Ocelote), {2} {3} (Lobo), {4} {5} (Caballo) Taming.SubSkill.FastFoodService.Name=Servicio de Comida Rápida -Taming.SubSkill.FastFoodService.Description=Probabilidad de que los lobos se curen en ataque -Taming.SubSkill.HolyHound.Name=Sabueso divino -Taming.SubSkill.HolyHound.Description=Curado por magia y veneno -Taming.SubSkill.Gore.Name=Mordisco -Taming.SubSkill.Gore.Description=Golpe Crítico que aplica Sangrado +Taming.SubSkill.FastFoodService.Description=Probabilidad de que los lobos se curen al atacar +Taming.SubSkill.HolyHound.Name=Sabueso Sagrado +Taming.SubSkill.HolyHound.Description=Curado por Magia y Veneno +Taming.SubSkill.Gore.Name=Desgarro +Taming.SubSkill.Gore.Description=Golpe Crítico que aplica Ruptura Taming.SubSkill.SharpenedClaws.Name=Garras Afiladas -Taming.SubSkill.SharpenedClaws.Description=Daño Bonus -Taming.SubSkill.EnvironmentallyAware.Name=Consciente del Entorno -Taming.SubSkill.EnvironmentallyAware.Description=Fobia al Cactus y a la Lava, Inmune al Daño por Caídas -Taming.SubSkill.ThickFur.Name=Piel Gruesa -Taming.SubSkill.ThickFur.Description=Daño Reducido, Resistencia al Fuego -Taming.Listener.Wolf=&8Tú lobo se escabulle hacia tí... -Taming.Listener=Domador: -Taming.SkillName=DOMADOR -Taming.Skillup=Habilidad de Domador incrementada en {0}. Total ({1}) -Taming.Summon.Complete=&aInvocación completada -Taming.Summon.Fail.Ocelot=Tienes demasiados ocelotes cerca como para convocar más. -Taming.Summon.Fail.Wolf=Tienes demasiados lobos cerca como para convocar más. -Taming.Summon.Fail.Horse=Tienes cerca demasiados caballos para poder invocar a uno. -Taming.Summon.Name.Format={0}s {1} -Unarmed.Ability.Berserk.Length=Duración de Enloquecido: &e{0}seg -Unarmed.Ability.Bonus.0=Estilo del Puño de Hierro -Unarmed.Ability.Bonus.1=+{0} Mejora de DAÑO -Unarmed.Ability.Chance.ArrowDeflect=Probabilidad de Desviar Flechas: &e{0}% -Unarmed.Ability.Chance.Disarm=Probabilidad de Desarmar: &e{0} -Unarmed.Ability.Chance.IronGrip=Probabilidad de agarre de hierro: &e{0} -Unarmed.Ability.IronGrip.Attacker= Tu oponente tiene agarre de hierro! -Unarmed.Ability.IronGrip.Defender=&aTu agarre de hierro te salvo de ser desarmado! -Unarmed.Ability.Lower=&7**BAJAS TUS PUÑOS** -Unarmed.Ability.Ready=&a**LEVANTASTE LA GUARDIA** -Unarmed.SubSkill.Berserk.Name=Enloquecido (HABILIDAD) -Unarmed.SubSkill.Berserk.Description=+50% de Daño, Rompe materiales débiles -Unarmed.SubSkill.Disarm.Name=Desarmar (Jugadores) -Unarmed.SubSkill.Disarm.Description=Hace soltar el item que un enemigo lleva en la mano -Unarmed.SubSkill.IronArmStyle.Name=Estilo del Puño de Hierro -Unarmed.SubSkill.IronArmStyle.Description=Endurece su brazo con el tiempo -Unarmed.SubSkill.ArrowDeflect.Name=Flecha Desviada -Unarmed.SubSkill.ArrowDeflect.Description=Desviar flechas -Unarmed.SubSkill.IronGrip.Name=Agarre de hierro -Unarmed.SubSkill.IronGrip.Description=Te previene de ser desarmado +Taming.SubSkill.SharpenedClaws.Description=Bonificación de Daño +Taming.SubSkill.EnvironmentallyAware.Name=Consciencia Ambiental +Taming.SubSkill.EnvironmentallyAware.Description=Fobia a Cactus/Lava, Inmunidad a Daño por Caída +Taming.SubSkill.ThickFur.Name=Pelo Grueso +Taming.SubSkill.ThickFur.Description=Reducción de Daño, Resistencia al Fuego +Taming.SubSkill.Pummel.Name=Apalear +Taming.SubSkill.Pummel.Description=Tus lobos tienen la posibilidad de derribar a los enemigos +Taming.SubSkill.Pummel.TargetMessage=¡Un lobo te ha derribado! +Taming.Listener.Wolf=&8Tu lobo corre hacia ti... +Taming.Listener=Domesticación: +Taming.SkillName=DOMESTICACIÓN +Taming.Summon.COTW.Success.WithoutLifespan=&a(Llamado de la Naturaleza) &7Has invocado a un &6{0}&7 +Taming.Summon.COTW.Success.WithLifespan=&a(Llamado de la Naturaleza) &7Has invocado a un &6{0}&7 que tiene una duración de &6{1}&7 segundos. +Taming.Summon.COTW.Limit=&a(Llamado de la Naturaleza) &7Solo puedes tener &c{0} &7mascotas invocadas &7{1} al mismo tiempo. +Taming.Summon.COTW.TimeExpired=&a(Llamado de la Naturaleza) &7El tiempo ha terminado, tu &6{0}&7 se va. +Taming.Summon.COTW.Removed=&a(Llamado de la Naturaleza) &7Tu invocado &6{0}&7 ha desaparecido de este mundo. +Taming.Summon.COTW.BreedingDisallowed=&a(Llamado de la Naturaleza) &cNo puedes criar a un animal invocado. +Taming.Summon.COTW.NeedMoreItems=&a(Llamado de la Naturaleza) &7Necesitas &e{0}&7 más &3{1}&7(s) +Taming.Summon.Name.Format=&6(COTW) &f{0}''s {1} +#UNARMED +Unarmed.Ability.Bonus.0=Estilo Brazo de Acero +Unarmed.Ability.Bonus.1=+{0} Mejora de Daño +Unarmed.Ability.IronGrip.Attacker=¡Tu oponente tiene un agarre de hierro! +Unarmed.Ability.IronGrip.Defender=&a¡Tu agarre de hierro te impidió ser desarmado! +Unarmed.Ability.Lower=&7Bajas los puños. +Unarmed.Ability.Ready=&3Preparas tus puños. +Unarmed.SubSkill.Berserk.Name=Furia +Unarmed.SubSkill.Berserk.Description=+50% Daño, Rompe materiales débiles +Unarmed.SubSkill.Berserk.Stat=Duración de la Furia +Unarmed.SubSkill.Disarm.Name=Desarmar +Unarmed.SubSkill.Disarm.Description=Hace que el enemigo suelte el objeto que sostiene en la mano +Unarmed.SubSkill.Disarm.Stat=Probabilidad de Desarmar +Unarmed.SubSkill.UnarmedLimitBreak.Name=Límite Desarmado +Unarmed.SubSkill.UnarmedLimitBreak.Description=Rompe tus límites. Mayor daño contra oponentes duros. Previsto para PVP, queda a criterio del servidor si aumentará el daño en PVE. +Unarmed.SubSkill.UnarmedLimitBreak.Stat=Daño Máximo de Límite +Unarmed.SubSkill.SteelArmStyle.Name=Estilo Brazo de Acero +Unarmed.SubSkill.SteelArmStyle.Description=Endurece tu brazo con el tiempo +Unarmed.SubSkill.ArrowDeflect.Name=Desvío de Flechas +Unarmed.SubSkill.ArrowDeflect.Description=Desvía flechas +Unarmed.SubSkill.ArrowDeflect.Stat=Probabilidad de Desvío de Flechas +Unarmed.SubSkill.IronGrip.Name=Agarre de Hierro +Unarmed.SubSkill.IronGrip.Description=Evita que seas desarmado +Unarmed.SubSkill.IronGrip.Stat=Probabilidad de Agarre de Hierro +Unarmed.SubSkill.BlockCracker.Name=Rompedor de Bloques +Unarmed.SubSkill.BlockCracker.Description=Rompe roca con los puños Unarmed.Listener=Desarmado: Unarmed.SkillName=DESARMADO -Unarmed.Skills.Berserk.Off=**Enloquecido ha expirado** -Unarmed.Skills.Berserk.On=&a**ENLOQUECIDO ACTIVADO** -Unarmed.Skills.Berserk.Other.Off=Enloquecido&a le ha expirado a &e{0} -Unarmed.Skills.Berserk.Other.On=&a¡{0}&2 usó &cEnloquecido! -Unarmed.Skills.Berserk.Refresh=&a¡Tú habilidad &eEnloquecido &aestá refrescada! -Unarmed.Skillup=Habilidad de Desarmado incrementada en {0}. Total ({1}) -Woodcutting.Ability.0=Soplador de Hojas -Woodcutting.Ability.1=Remover hojas -Woodcutting.Ability.Chance.DDrop=Probabilidad de Doble Drop: &e{0} -Woodcutting.Ability.Length=Duración de Caída de Árbol: &e{0}seg -Woodcutting.Ability.Locked.0=Bloqueado hasta {0} + HABILIDAD (soplador de hojas) -Woodcutting.SubSkill.TreeFeller.Name=Caída de Árbol (HABILIDAD) -Woodcutting.SubSkill.TreeFeller.Description=Hace que el árbol explote -Woodcutting.SubSkill.LeafBlower.Name=Soplador de Hojas -Woodcutting.SubSkill.LeafBlower.Description=Remover Hojas -Woodcutting.SubSkill.HarvestLumber.Name=Doble Drops -Woodcutting.SubSkill.HarvestLumber.Description=El doble del botín normal +Unarmed.Skills.Berserk.Off=**La Furia se ha desactivado** +Unarmed.Skills.Berserk.On=&a**FURIA ACTIVADA** +Unarmed.Skills.Berserk.Other.Off=La Furia&a se ha desactivado para &e{0} +Unarmed.Skills.Berserk.Other.On=&a{0}&2 ha usado &cFuria +Unarmed.Skills.Berserk.Refresh=&aTu habilidad &eBerserk &ase ha refrescado! +#WOODCUTTING +Woodcutting.Ability.0=Explosión de hojas +Woodcutting.Ability.1=Soplar hojas +Woodcutting.Ability.Locked.0=BLOQUEADO HASTA {0}+ HABILIDAD (EXPLOSIÓN DE HOJAS) +Woodcutting.SubSkill.TreeFeller.Name=Talador de árboles +Woodcutting.SubSkill.TreeFeller.Description=Haz explotar los árboles +Woodcutting.SubSkill.TreeFeller.Stat=Duración del talador de árboles +Woodcutting.SubSkill.LeafBlower.Name=Soplador de hojas +Woodcutting.SubSkill.LeafBlower.Description=Soplar hojas +Woodcutting.SubSkill.KnockOnWood.Name=Toca madera +Woodcutting.SubSkill.KnockOnWood.Description=Encuentra cosas adicionales al usar Talador de árboles +Woodcutting.SubSkill.KnockOnWood.Stat=Toca madera +Woodcutting.SubSkill.KnockOnWood.Loot.Normal=Botín estándar de los árboles +Woodcutting.SubSkill.KnockOnWood.Loot.Rank2=Botín estándar de los árboles y orbes de experiencia +Woodcutting.SubSkill.HarvestLumber.Name=Cosecha de madera +Woodcutting.SubSkill.HarvestLumber.Description=Extrae hábilmente hasta el doble de madera +Woodcutting.SubSkill.HarvestLumber.Stat=Probabilidad de doble gota +Woodcutting.SubSkill.CleanCuts.Name=Cortes limpios +Woodcutting.SubSkill.CleanCuts.Description=Extrae con maestría hasta el triple de madera +Woodcutting.SubSkill.CleanCuts.Stat=Probabilidad de triple gota +Woodcutting.SubSkill.Splinter.Name=Aserrín +Woodcutting.SubSkill.Splinter.Description=Tala árboles con mayor eficiencia +Woodcutting.SubSkill.BarkSurgeon.Name=Cirujano de corteza +Woodcutting.SubSkill.BarkSurgeon.Description=Extrae materiales útiles al quitar la corteza de los árboles +Woodcutting.SubSkill.NaturesBounty.Name=Recompensa de la naturaleza +Woodcutting.SubSkill.NaturesBounty.Description=Recoge experiencia de la naturaleza Woodcutting.Listener=Leñador: -Woodcutting.SkillName=LEÑADOR -Woodcutting.Skills.TreeFeller.Off=**Caida de Árbol ha expirado** -Woodcutting.Skills.TreeFeller.On=&a**CAÍDA DE ÁRBOL ACTIVADA** -Woodcutting.Skills.TreeFeller.Refresh=&a¡Tu habilidad &eCaída de Árbol &aestá refrescada! -Woodcutting.Skills.TreeFeller.Other.Off=Caída de Árbol&a le ha expirado a &e{0} -Woodcutting.Skills.TreeFeller.Other.On=&a¡{0}&2 usó &cCaída de Árbol! -Woodcutting.Skills.TreeFeller.Splinter=¡TU HACHA EXPLOTÓ EN MILES DE PEDAZOS! +Woodcutting.SkillName=TALA DE ÁRBOLES +Woodcutting.Skills.TreeFeller.Off=**El talador de árboles se ha desactivado** +Woodcutting.Skills.TreeFeller.On=&a**TALADOR DE ÁRBOLES ACTIVADO** +Woodcutting.Skills.TreeFeller.Refresh=&aTu habilidad &eTalador de árboles &aestá renovada +Woodcutting.Skills.TreeFeller.Other.Off=El talador de árboles de &a se ha desactivado para &e{0} +Woodcutting.Skills.TreeFeller.Other.On=&a{0}&2 ha usado &cTalador de árboles +Woodcutting.Skills.TreeFeller.Splinter=¡TU HACHA SE HACE AÑICOS EN DECENAS DE PIEZAS! Woodcutting.Skills.TreeFeller.Threshold=¡Ese árbol es demasiado grande! -Woodcutting.Skillup=Habilidad de Leñador incrementada en {0}. Total ({1}) -Ability.Generic.Refresh=&a**¡HABILIDADES REFRESCADAS!** -Ability.Generic.Template.Lock=&7{0} -Ability.Generic.Template=&6{0}: &3{1} -Combat.ArrowDeflect=&f**FLECHA DESVIADA** -Combat.BeastLore=&a**CONOCIMIENTO DE LA BESTIA** +#ABILITY + +#COMBAT +Combat.ArrowDeflect=&f**DESVÍO DE FLECHA** +Combat.BeastLore=&a**SABIDURÍA DE LA BESTIA** Combat.BeastLoreHealth=&3Salud (&a{0}&3/{1}) -Combat.BeastLoreOwner=&3Dueño (&c{0}&3) -Combat.Gore=&a**MORDISCO** -Combat.StruckByGore=**FUISTE MORDISQUEADO** -Combat.TargetDazed=El objetivo fue &4aturdido -Combat.TouchedFuzzy=&4Estás confuso. Te sientes mareado. -mcMMO.Description=&3Sobre el proyecto&emcMMO&3:,&6mcMMO es un mod RPG de&ccodigo abierto&6 creado en Febrero de 2011, &6por &9nossr50&6. La meta es proveer una experiencia igual a la de los RPG.,&3Consejos:,&6 - &aUsa &c/mcmmo help&a para ver los comandos,&6 - &aTeclea &c/SKILLNAME&apara ver informacion detalada de las habilidades,&3Desarrolladores:,&6 - &anossr50 &9(Founder & Project Lead),&6 - &aGJ &9(Former Project Lead),&6 - &aNuclearW &9(Developer),&6 - &abm01 &9(Developer),&6 - &aTfT_02 &9(Developer),&6 - &aGlitchfinder &9(Developer),&6 - &at00thpick1 &9(Developer),&3Useful Links:,&6 - &ahttps://github.com/mcMMO-Dev/mcMMO/issues&6 Reporte de fallos,&6 - &a#mcmmo @ irc.esper.net&6 IRC Chat, -Commands.addlevels.AwardAll.1=&aFuistes recompensado con {0} niveles en todas las habilidades! -Commands.addlevels.AwardAll.2=Todas las Skins han sido mofificadas por {0}. -Commands.addlevels.AwardSkill.1=&aFuistes recompensado con {0} niveles en {1}! -Commands.addlevels.AwardSkill.2={0} ha sido modificado por {1}. -Commands.addxp.AwardAll=&aFuistes recompensado con {0} experiencia en todas las habilidades! -Commands.addxp.AwardSkill=&aFuistes recompensado con {0} experiencia en {1}! -Commands.Ability.Off=Habilidades &cdesactivadas -Commands.Ability.On=Habilidades &aactivadas -Commands.AdminChat.Off=Chat sólo para Admins &cdesactivado -Commands.AdminChat.On=Chat sólo para Admins &aactivado -Commands.AdminToggle=- Alternar chat de admin +Combat.BeastLoreOwner=&3Propietario (&c{0}&3) +Combat.BeastLoreHorseSpeed=&3Velocidad de movimiento del caballo (&a{0} bloques/s&3) +Combat.BeastLoreHorseJumpStrength=&3Fuerza de salto del caballo (&aMáximo {0} bloques&3) +Combat.Gore=&a**EMPALADO** +Combat.StruckByGore=**HAS SIDO EMPALADO** +Combat.TargetDazed=El objetivo estaba &4Aturdido +Combat.TouchedFuzzy=&4Tocaste algo difuso. Te sentiste mareado. +#COMMANDS +##generic +mcMMO.Description=&3Sobre el Proyecto &emcMMO&3:, &6mcMMO es un mod de rol de &ccódigo abierto&6 creado en febrero de 2011,&6por &9nossr50&6. El objetivo es proporcionar una experiencia de rol de calidad.,&3Consejos:,&6 - &aUsa &c/mcmmo help&a para ver los comandos,&6 - &aEscribe &c/SKILLNAME&a para ver información detallada sobre la habilidad,&3Desarrolladores:,&6 - &anossr50 &9(Creador y Líder del Proyecto),&6 - &aelectronicboy &9(Desarrollador),&6 - &akashike &9(Desarrollador),&6 - &at00thpick1 &9(Mantenedor Clásico) +mcMMO.Description.FormerDevs=&3Antiguos desarrolladores: &aGJ, NuclearW, bm01, TfT_02, Glitchfinder +Commands.addlevels.AwardAll.1=&aHas recibido {0} niveles en todas las habilidades +Commands.addlevels.AwardAll.2=Todas las habilidades han sido modificadas para {0}. +Commands.addlevels.AwardSkill.1=&aHas recibido {0} niveles en {1} +Commands.addlevels.AwardSkill.2={0} ha sido modificado para {1}. +Commands.addxp.AwardAll=&aHas recibido {0} experiencia en todas las habilidades +Commands.addxp.AwardSkill=&aHas recibido {0} experiencia en {1} +Commands.Ability.Off=Uso de habilidades desactivado &c +Commands.Ability.On=Uso de habilidades activado &a +Commands.Ability.Toggle=El uso de habilidades se ha cambiado para &e{0} +Commands.AdminChat.Off=Chat de administración solo &cDesactivado +Commands.AdminChat.On=Chat de administración solo &aActivado +Commands.AdminToggle=&a- Alternar chat de administración Commands.Chat.Console=*Consola* -Commands.Disabled=Este comando está deshabilitado. -Commands.DoesNotExist=¡El jugador no existe en la base de datos! -Commands.GodMode.Disabled=mcMMO Modo Dios Desactivado -Commands.GodMode.Enabled=mcMMO Modo Dios Activado -Commands.GodMode.Forbidden=[mcMMO] No se permite Modo Dios en este mundo (Ver permisos) -Commands.Inspect= &c-Ver información detallada del jugador -Commands.Party.Invite.Accepted=&aInvitación Aceptada. Te uniste al grupo {0} -Commands.Invite.Success=&aInvitación enviada satisfactoriamente -Commands.Leaderboards= &c- Tabla de posiciones -Commands.mcc.Header=---[]&eComandos mcMMO&c[]--- -Commands.mcgod=- Alternar Modo Dios -Commands.mchud.Invalid=Ese no es un tipo valido de HUD. -Commands.mcpurge.Success=&aLa base de datos fue purgada exitosamente! -Commands.mcrank.Heading=&6-=CLASIFICACION PERSONAL=- -Commands.mcrank.Overall=Conjunto&a - &6Clasificacion &f#&a{0} -Commands.mcrank.Player=OBJETIVO: &f{0} -Commands.mcrank.Skill={0}&a - &6Clasificacion &f#&a{1} +Commands.Cooldowns.Header=&6--= &aEnfriamientos de habilidades de mcMMO&6 =-- +Commands.Cooldowns.Row.N=\ &c{0}&f - &6{1} segundos restantes +Commands.Cooldowns.Row.Y=\ &b{0}&f - &2¡Listo! +Commands.Database.CooldownMS=Debes esperar {0} milisegundos antes de usar este comando de nuevo. +Commands.Database.Cooldown=Debes esperar {0} segundos antes de usar este comando de nuevo. +Commands.Database.Processing=Tu comando anterior sigue procesándose. Por favor, espera. +Commands.Disabled=Este comando está desactivado. +Commands.DoesNotExist= &c¡El jugador no existe en la base de datos! +Commands.GodMode.Disabled=Modo Dios de mcMMO desactivado +Commands.GodMode.Enabled=Modo Dios de mcMMO activado +Commands.AdminChatSpy.Enabled=Espionaje de chat de grupo de mcMMO activado +Commands.AdminChatSpy.Disabled=Espionaje de chat de grupo de mcMMO desactivado +Commands.AdminChatSpy.Toggle=El espionaje de chat de grupo de mcMMO se ha cambiado para &e{0} +Commands.AdminChatSpy.Chat=&6[ESPIA: &a{0}&6] &f{1} +Commands.GodMode.Forbidden=[mcMMO] Modo Dios no permitido en este mundo (Consulta los permisos) +Commands.GodMode.Toggle=El modo Dios se ha cambiado para &e{0} +Commands.Healthbars.Changed.HEARTS=[mcMMO] El tipo de visualización de la barra de salud se cambió a &cCorazones&f. +Commands.Healthbars.Changed.BAR=[mcMMO] El tipo de visualización de la barra de salud se cambió a &eCajas&f. +Commands.Healthbars.Changed.DISABLED=[mcMMO] Las barras de salud de tus mobs se han &7desactivado&f. +Commands.Healthbars.Invalid=¡Tipo de barra de salud inválido! +Commands.Inspect= &a- Ver información detallada del jugador +Commands.Invite.Success=&aInvitación enviada con éxito. +Commands.Leaderboards= &a- Tablas de clasificación +Commands.mcgod=&a- Alternar modo Dios +Commands.mchud.Invalid=Ese no es un tipo de HUD válido. +Commands.mcpurge.Success=&a¡La base de datos se purgó con éxito! +Commands.mcrank.Heading=&6-=CLASIFICACIONES PERSONALES=- +Commands.mcrank.Overall=General&a - &6Rango &f#&a{0} +Commands.mcrank.Player=&eClasificaciones de &f{0} +Commands.mcrank.Skill=&e{0}&a - &6Rango &f#&a{1} Commands.mcrank.Unranked=&fSin clasificar -Commands.mcrefresh.Success={0}\'\'s del tiempo de reutilizacion ha sido renovado. -Commands.mcremove.Success=&a{0} fue eliminado de la base de datos exitosamente!! -Commands.mctop.Tip=&6Tip: Usa &c/mcrank&6 para ver todas tus estadisticas! -Commands.mmoedit=[jugador] &c - Modificar habilidad -Commands.mmoedit.AllSkills.1=&atu nivel en todas las habilidades fue cambiado a {0}! -Commands.mmoedit.Modified.1=&aTu nivel en {0} fue modificado a {1}! +Commands.mcrefresh.Success=Los enfriamientos de {0} se han renovado. +Commands.mcremove.Success=&a{0} se eliminó correctamente de la base de datos +Commands.mctop.Tip=&6Consejo: Usa &c/mcrank&6 para ver todas tus clasificaciones personales. +Commands.mmoedit=[jugador] &a - Modificar objetivo +Commands.mmoedit.AllSkills.1=&a¡Tu nivel en todas las habilidades se estableció en {0}! +Commands.mmoedit.Modified.1=&aTu nivel en {0} se estableció en {1}! Commands.mmoedit.Modified.2={0} ha sido modificado por {1}. -Commands.mcconvert.Database.Same=Ya estas usando la base de datos {0} -Commands.mcconvert.Database.InvalidType={0} no en un tipo de base de datos valido. -Commands.mcconvert.Database.Start=&7Comenzando conversion de {0} a {1}... -Commands.mcconvert.Database.Finish=&7Migracion de la base de datos completada; La base datos {1} ahora tiene todos los datos de la base de datos {0}. -Commands.mmoshowdb=La base de datos usada actualmente es &a{0} -Commands.mcconvert.Experience.Invalid=Tipo de formula desconocidaa Los tipos validos son: &aLINEAR &cy &aEXPONENTIAL. -Commands.mcconvert.Experience.Same=Ya esta usando el tipo de formula {0} -Commands.mcconvert.Experience.Start=&7Comenznado converso de la curva {0} a {1} -Commands.mcconvert.Experience.Finish=&7Formula de conversion completa; ahora usando la curva XP {0}. -Commands.ModDescription=- Lea la descripción breve del mod -Commands.NoConsole=Este comando no es soportado desde la consola. -Commands.Notifications.Off=Notificaciones de habilidad &cdesactivadas -Commands.Notifications.On=Notificaciones de habilidad &aactivadas -Commands.Offline=Este comando no sirve para jugadores desconectados -Commands.Other=&a--OTROS COMANDOS-- -Commands.Party.Header=-----[]&aGRUPO&c[]----- -Commands.Party.Status=&8NOMBRE: &f{0} {1} -Commands.Party.ShareMode=&8MODO COMPARTIR: -Commands.Party.ItemShare=&7OBJETO &3({0}) +Commands.mcconvert.Database.Same=¡Ya estás utilizando la base de datos {0}! +Commands.mcconvert.Database.InvalidType={0} no es un tipo de base de datos válido. +Commands.mcconvert.Database.Start=&7Iniciando la conversión de {0} a {1}... +Commands.mcconvert.Database.Finish=&7Migración de base de datos completada; la base de datos {1} ahora contiene todos los datos de la base de datos {0}. +Commands.mmoshowdb=La base de datos en uso actualmente es &a{0} +Commands.mcconvert.Experience.Invalid=¡Tipo de fórmula desconocido! Los tipos válidos son: &aLINEAL &cy &aEXPONENCIAL. +Commands.mcconvert.Experience.Same=Ya estás utilizando el tipo de fórmula {0} +Commands.mcconvert.Experience.Start=&7Iniciando la conversión de {0} a la curva {1} +Commands.mcconvert.Experience.Finish=&7Conversión de fórmula completada; ahora se está utilizando la curva de XP {0}. +Commands.ModDescription=&a- Leer una breve descripción del mod +Commands.NoConsole=Este comando no es compatible con el uso en la consola. +Commands.Notifications.Off=Notificaciones de habilidades &ctoggleadas off +Commands.Notifications.On=Notificaciones de habilidades &ctoggleadas on +Commands.Offline=Este comando no funciona para jugadores fuera de línea. +Commands.NotLoaded=El perfil del jugador aún no se ha cargado. +Commands.Party.Status=&8NOMBRE: &f{0} {1} &8NIVEL: &3{2} +Commands.Party.Status.Alliance=&8ALIADO: &f{0} +Commands.Party.UnlockedFeatures=&8Características desbloqueadas: &7&o{0} +Commands.Party.ShareMode=&8MODO DE COMPARTIR: +Commands.Party.ItemShare=&7ITEM &3({0}) Commands.Party.ExpShare=&7EXP &3({0}) -Commands.Party.ItemShareCategories=&8Compartiendo objetos: &7&o{0} +Commands.Party.ItemShareCategories=&8Compartiendo artículos: &7&o{0} Commands.Party.MembersNear=&8CERCA DE TI &3{0}&8/&3{1} -Commands.Party.Accept=- Aceptar invitación al grupo -Commands.Party.Chat.Off=Sólo chat de grupo &cdesactivado -Commands.Party.Chat.On=Sólo chat de grupo &cactivado -Commands.Party.Commands=&a--COMANDOS DEL GRUPO-- -Commands.Party.Invite.0=ATENCIÓN: &aFuiste invitado al grupo {0} por {1} -Commands.Party.Invite.1=Teclea &a/party accept&e para aceptar la invitacion al grupo -Commands.Party.Invite=&c- Invitacion de grupo enviada -Commands.Party.Join=&7Unido al grupo: {0} -Commands.Party.Create=&7Grupo creado: {0} -Commands.Party.Rename=&7el nombre del grupo ha cambiado a: &f{0} -Commands.Party.SetSharing=&7Grupo {0} compartir establecido a: &3{1} -Commands.Party.ToggleShareCategory=&7Objetos de grupo compartiendo por&6{0} &7ha sido &3{1} -Commands.Party.AlreadyExists=&4El grupo {0} ya existe! -Commands.Party.Kick=¡Fuiste expulsado del grupo {0}! -Commands.Party.Leave=Abandonaste el grupo -Commands.Party.Members.Header=-----[]&aMIEMBROS&c[]----- -Commands.Party.None=No estás en un grupo. -Commands.Party.Quit=- Abandona tu grupo actual -Commands.Party.Teleport= &c- Teletransportarse al miembro del grupo -Commands.Party.Toggle=- Alternar chat de grupo -Commands.Party.1=- Nuevo grupo creado -Commands.Party.2=&c- Unete a un grupo de jugadores -Commands.ptp.Enabled=Teletransportacion de grupo &aactivada -Commands.ptp.Disabled=Teletransportacion de grupo &cdesactivada -Commands.ptp.NoRequests=No tienes ninguna peticion de teletransporte ahora mismo -Commands.ptp.NoWorldPermissions=[mcMMO] No tienes permiso para teletransportarte al mundo {0}. -Commands.ptp.Request1={0} &aha pedido teletransportarse a tu posicion. -Commands.ptp.Request2=&aPara teletransportarse, teclea &e/ptp accept. &aLa peticion expira en &c{0} &asegundos. -Commands.ptp.AcceptAny.Enabled=Confirmacion de la peticion de teletransportacion del grupo &ahabilitada -Commands.ptp.AcceptAny.Disabled=Confirmacion de la peticion de teletransportacion del grupo &adeshabilitada -Commands.ptp.RequestExpired=La peticion de teletransporte del grupo ha expirado! -Commands.PowerLevel.Leaderboard=--mcMMO-- Tabla de Líderes: &9Nivel de Poder -Commands.PowerLevel.Capped=&4NIVEL DE PODER: &a{0} &4MAXIMO PODER: &e{1} -Commands.PowerLevel=&4NIVEL DE PODER: &a{0} -Commands.Reset.All=&aTodos los niveles de tus habilidades se resetearon correctamente -Commands.Reset.Single=&aTu {0} nivel de skill se reseteo correctamente. -Commands.Reset=Resetea el nivel de una habilidad a 0 -Commands.Skill.Invalid=¡Esa no es una habilidad válida! -Commands.Skill.Leaderboard=--mcMMO-- Tabla de Líderes: &9{0} -Commands.SkillInfo=- Ver informacion detallada sobre habilidades -Commands.Stats.Self=TUS ESTADÍSTICAS -Commands.Stats=- Ver tus estadísticas de mcMMO -Commands.ToggleAbility=- Alternar activación de habilidades con click derecho -Commands.Usage.0=El uso correcto es /{0} -Commands.Usage.1=El uso adecuado es /{0} {1} -Commands.Usage.2=El uso correcto es /{0} {1} {2} -Commands.Usage.3=El uso correcto es /{0} {1} {2} {3} -Commands.Usage.FullClassName=Clase -Commands.Usage.Level=Nivel +Commands.Party.Accept=&a- Aceptar invitación a la party +Commands.Party.Chat.Off=Chat de party solo &cOff +Commands.Party.Chat.On=Chat de party solo &aOn +Commands.Party.Commands=&c---[]&aCOMANDOS DE PARTY&c[]--- +Commands.Party.Invite.0=&cALERTA: &aHas recibido una invitación a la party {0} de {1} +Commands.Party.Invite.1=&eEscribe &a/party accept&e para aceptar la invitación +Commands.Party.Invite=&a- Enviar invitación a la party +Commands.Party.Invite.Accepted=&aInvitación aceptada. Te has unido a la party {0} +Commands.Party.Join=&7Te has unido a la party: {0} +Commands.Party.PartyFull=&6{0}&c está lleno/a! +Commands.Party.PartyFull.Invite=No puedes invitar a &e{0}&c a &a{1}&c porque ya tiene &3{2}&c jugadores en ella! +Commands.Party.PartyFull.InviteAccept=No puedes unirte a &a{0}&c porque ya tiene &3{1}&c jugadores en ella! +Commands.Party.Create=&7Se ha creado la party: {0} +Commands.Party.Rename=&7El nombre de la party se ha cambiado a: &f{0} +Commands.Party.SetSharing=&7El compartir de la party {0} se ha configurado en: &3{1} +Commands.Party.ToggleShareCategory=&7El compartir artículos de la party para &6{0} &7se ha &3{1} +Commands.Party.AlreadyExists=&4La party {0} ya existe! +Commands.Party.Kick=&c¡Has sido expulsado/a de la party &a{0}&c! +Commands.Party.Leave=&eHas dejado esa party +Commands.Party.Members.Header=&c-----[]&aMIEMBROS&c[]----- +Commands.Party.None=&cNo estás en una party. +Commands.Party.Quit=&a- Dejar tu party actual +Commands.Party.Teleport=&a- Teleportarse a un miembro de la party +Commands.Party.Toggle=&a- Alternar el Chat de Party +Commands.Party1=&a- Crear una nueva party +Commands.Party2=&a- Unirse a la party de un jugador +Commands.Party.Alliance.Header=&c-----[]&aALIANZA DE PARTY&c[]----- +Commands.Party.Alliance.Ally=&f{0} &8ESTÁ ALIADO CON: &f{1} +Commands.Party.Alliance.Members.Header=&c-----[]&aMIEMBROS DE LA ALIANZA&c[]----- +Commands.Party.Alliance.Invite.0=ALERTA: &aHas recibido una invitación a una alianza de party para {0} de {1} +Commands.Party.Alliance.Invite.1=Escribe &a/party alliance accept&e para aceptar la invitación +Commands.Party.Alliance.Invite.Accepted=&aInvitación de alianza aceptada. +Commands.Party.Alliance.None=&cTu party no tiene aliado. +Commands.Party.Alliance.AlreadyAllies=&cTu party ya tiene un aliado. Disuelve con &3/party alliance disband +Commands.Party.Alliance.Help.0=&cEsta party no ha formado una alianza. Invita a un líder de party +Commands.Party.Alliance.Help.1=&c a una alianza con &3/party alliance invite &c. +Commands.ptp.Enabled=Teletransporte de party &ahabilitado +Commands.ptp.Disabled=Teletransporte de party &cdeshabilitado +Commands.ptp.NoRequests=&cNo tienes solicitudes de teletransporte en este momento +Commands.ptp.NoWorldPermissions=&c[mcMMO] No tienes permiso para teletransportarte al mundo {0}. +Commands.ptp.Request1=&e{0} &aha solicitado teletransportarse a ti. +Commands.ptp.Request2=&aPara teletransportarte, escribe &e/ptp accept&a. La solicitud expira en &c{0} &asegundos. +Commands.ptp.AcceptAny.Enabled=Confirmación de solicitud de teletransporte de party &ahabilitada +Commands.ptp.AcceptAny.Disabled=Confirmación de solicitud de teletransporte de party &cdeshabilitada +Commands.ptp.RequestExpired=&c¡La solicitud de teletransporte de party ha expirado! +Commands.PowerLevel.Leaderboard=&e--mcMMO&9 Tabla de clasificación de Power Level &e-- +Commands.PowerLevel.Capped=&4POWER LEVEL: &a{0} &4NIVEL MÁXIMO: &e{1} +Commands.PowerLevel=&4POWER LEVEL: &a{0} +Commands.Reset.All=&aTodos tus niveles de habilidad se han restablecido correctamente. +Commands.Reset.Single=&aTu nivel de habilidad {0} se ha restablecido correctamente. +Commands.Reset=&a- Restablecer el nivel de una habilidad a 0 +Commands.Scoreboard.Clear=&3Tabla de puntuación de mcMMO borrada. +Commands.Scoreboard.NoBoard=&cLa tabla de puntuación de mcMMO no está activa. +Commands.Scoreboard.Keep=&3La tabla de puntuación de mcMMO permanecerá visible hasta que uses &a/mcscoreboard clear&3. +Commands.Scoreboard.Timer=&3La tabla de puntuación de mcMMO se borrará en &6{0}&3 segundos. +Commands.Scoreboard.Help.0=&6 == &aAyuda para &c/mcscoreboard&6 == +Commands.Scoreboard.Help.1=&3/mcscoreboard&b clear &f - borrar la tabla de puntuación de McMMO +Commands.Scoreboard.Help.2=&3/mcscoreboard&b keep &f - mantener visible la tabla de puntuación de mcMMO +Commands.Scoreboard.Help.3=&3/mcscoreboard&b time [n] &f - borrar la tabla de puntuación de McMMO después de &dn&f segundos +Commands.Scoreboard.Tip.Keep=&6Consejo: Usa &c/mcscoreboard keep&6 mientras la tabla de puntuación esté visible para mantenerla sin que desaparezca. +Commands.Scoreboard.Tip.Clear=&6Consejo: Usa &c/mcscoreboard clear&6 para quitar la tabla de puntuación. +Commands.XPBar.Reset=&6Los ajustes de la barra de XP para mcMMO han sido restablecidos. +Commands.XPBar.SettingChanged=&6El ajuste de la barra de XP para &a{0}&6 ahora está configurado en &a{1} +Commands.Skill.Invalid=¡Ese no es un nombre de habilidad válido! +Commands.Skill.ChildSkill=¡Las habilidades secundarias no son válidas para este comando! +Commands.Skill.Leaderboard=-&e-mcMMO &9Tabla de clasificación de {0}&e -- +Commands.SkillInfo=&a- Ver información detallada sobre una habilidad +Commands.Stats=&a- Ver tus estadísticas de mcMMO +Commands.ToggleAbility=&a- Alternar la activación de habilidades con clic derecho +Commands.Usage.0=&cEl uso adecuado es /{0} +Commands.Usage.1=&cEl uso adecuado es /{0} {1} +Commands.Usage.2=&cEl uso adecuado es /{0} {1} {2} +Commands.Usage.3=&cEl uso adecuado es /{0} {1} {2} {3} +Commands.Usage.3.XP=&cUso correcto es /{0} {1} {2} {3}&7 (Puedes incluir -s al final para ejecutar el comando sin informar al jugador, silenciándolo efectivamente) +Commands.Usage.FullClassName=nombredeclase +Commands.Usage.Level=nivel Commands.Usage.Message=mensaje -Commands.Usage.Page=pagina +Commands.Usage.Page=página Commands.Usage.PartyName=nombre -Commands.Usage.Password=Contraseña -Commands.Usage.Player=Jugador -Commands.Usage.Rate=Velocidad -Commands.Usage.Skill=Habilidad -Commands.Usage.XP=XP -mcMMO.NoInvites=No tienes invitaciones en este momento +Commands.Usage.Password=contraseña +Commands.Usage.Player=jugador +Commands.Usage.Rate=valoración +Commands.Usage.Skill=habilidad +Commands.Usage.SubSkill=subhabilidad +Commands.Usage.XP=experiencia +Commands.Description.mmoinfo=Leer detalles sobre una habilidad o mecánica. +Commands.MmoInfo.Mystery=&7¡No has desbloqueado esta habilidad todavía, pero cuando lo hagas podrás leer detalles sobre ella aquí! +Commands.MmoInfo.NoMatch=¡Esa subhabilidad no existe! +Commands.MmoInfo.Header=&3-=[]=====[]&6 Información MMO &3[]=====[]=- +Commands.MmoInfo.SubSkillHeader=&6Nombre:&e {0} +Commands.MmoInfo.DetailsHeader=&3-=[]=====[]&a Detalles &3[]=====[]=- +Commands.MmoInfo.OldSkill=&7Las habilidades de mcMMO están siendo convertidas en un sistema de habilidades modulares mejorado, lamentablemente esta habilidad aún no ha sido convertida y carece de estadísticas detalladas. El nuevo sistema permitirá tiempos de lanzamiento más rápidos para nuevas habilidades de mcMMO y mayor flexibilidad con las habilidades existentes. +Commands.MmoInfo.Mechanics=&3-=[]=====[]&6 Mecánicas &3[]=====[]=- +Commands.MmoInfo.Stats=ESTADÍSTICAS: {0} +Commands.Mmodebug.Toggle=El modo de depuración de mcMMO ahora está &6{0}&7, usa este comando nuevamente para alternar. Con el modo de depuración activado, puedes golpear bloques para imprimir información útil utilizada para soporte. +mcMMO.NoInvites=&cNo tienes invitaciones en este momento. mcMMO.NoPermission=&4Permisos insuficientes. -mcMMO.NoSkillNote=&8Si no tienes acceso a una habilidad no será mostrada aquí. -Party.Forbidden=[mcMMO] No se permiten grupos en este mundo (Ver permisos) -Party.Help.0=El uso adecuado es&3{0} [password]. -Party.Help.1=Para crear un grupo, usa &3{0} [password]. -Party.Help.2=Consulta &3{0} &cpara mas informacion -Party.Help.3=Usa &3{0} [password] &cpara entrar o &3{1} &csalir -Party.Help.4=Para bloquear o desbloquear tu grupo, usa &3{0} -Party.Help.5=Para proteger el grupo con contraseña, usa &3{0} -Party.Help.6=Para echar a un jugador del grupo usa, use &3{0} -Party.Help.7=Para pasar el lider a otro, usa &3{0} -Party.Help.8=Para eliminar tu grupo, usa &3{0} -Party.Help.9=Usa &3{0} &cpara compartir objetos con los miembros del grupo -Party.Help.10=Usa &3{0} &cpara activar la XP compartida con los miembros del grupo. -Party.InformedOnJoin={0} &aha entrado en tu grupo -Party.InformedOnQuit={0} &aha salido de tu grupo -Party.InformedOnNameChange=&6{0} &aha cambiado el nombre del grupo a &f{1} -Party.InvalidName=&4Ese no es un nombre de grupo válido. -Party.Invite.Self=No puedes invitarte a ti mismo! -Party.IsLocked=¡Este grupo ya está bloqueado! -Party.IsntLocked=¡Este grupo no está bloqueado! -Party.Locked=El grupo está bloqueado, solo el líder puede invitarte -Party.NotInYourParty=&4{0} no esta en tu fiesta -Party.NotOwner=&4No eres el lider del grupo -Party.Owner.New=&a{0} es el nuevo lider del grupo. -Party.Owner.NotLeader=&4Ya no eres el lider del grupo. -Party.Owner.Player=&aAhora eres el lider del grupo -Party.Password.None=Este grupo esta protegido por contraseña. Escribala para poder entrar. -Party.Password.Incorrect=La contraseña del grupo es incorrecta -Party.Password.Set=&aContraseña del grupo establecida: &c{0} -Party.Password.Removed=&aLa contraseña del grupo ha sido eliminada. -Party.Player.Invalid=Ese no es un jugador válido. -Party.NotOnline=&4{0} no esta conectado! -Party.Player.InSameParty={0} ya esta en tu grupo! -Party.PlayerNotInParty=&4{0} no esta en un grupo -Party.Specify=Debes especificar un grupo -Party.Teleport.Dead=No te puedes teletransportar a un jugador muerto. -Party.Teleport.Hurt=Has sido herido en los ultimos {0} segundos y no te puedes teletransportar. -Party.Teleport.Player=&aTe teletransportaste a {0}. -Party.Teleport.Self=No puedes teletransportarte a ti mismo! -Party.Teleport.Target=&a{0} se teletransportó a ti. -Party.Teleport.Disabled={0} no permite teletransportacion de grupo. -Party.Rename.Same=Ese es ya el nombre de tu grupo! -Party.Join.Self=No puedes te puedes unir a ti mismo! -Party.Unlocked=&7El grupo está desbloqueado -Party.Disband=&7El grupo ha sido eliminado -Party.Status.Locked=&4(Solo para invitados) -Party.Status.Unlocked=&2(Abierto) -Party.ShareType.Xp=EXP -Party.ShareType.Item=OBJETO -Party.ShareMode.None=NINGUNO -Party.ShareMode.Equal=IGUAL -Party.ShareMode.Random=ALEATORIO -Party.XpShare.Disabled=El grupo no comparte la experiencia. -Party.ItemShare.Disabled=El grupo no comparte los objetos. -Party.ItemShare.Category.Loot=Saquear -Party.ItemShare.Category.Mining=Mineria -Party.ItemShare.Category.Herbalism=Herbolaria -Party.ItemShare.Category.Woodcutting=Tala de arboles -Party.ItemShare.Category.Misc=Misc -Commands.XPGain.Acrobatics=Cayendo -Commands.XPGain.Archery=Atacando a Monstruos -Commands.XPGain.Axes=Atacando a Monstruos -Commands.XPGain.Child=Niveles obtenidos de las habilidades padre -Commands.XPGain.Excavation=Excavar y encontrar tesoros -Commands.XPGain.Fishing=Pesca (¡Imagínate!) -Commands.XPGain.Herbalism=Recolectando hierbas -Commands.XPGain.Mining=Minando Piedra y Minerales +mcMMO.NoSkillNote=&8Si no tienes acceso a una habilidad, no se mostrará aquí. +##party +Party.Forbidden=[mcMMO] Las fiestas no están permitidas en este mundo (Consulta permisos). +Party.Help.0=&cUso correcto es &3{0} [contraseña]. +Party.Help.1=&cPara crear una fiesta, usa &3{0} [contraseña]. +Party.Help.2=&cConsulta &3{0} &cpara más información. +Party.Help.3=&cUsa &3{0} [contraseña] &cpara unirte o &3{1} &cpara salir. +Party.Help.4=&cPara bloquear o desbloquear tu fiesta, usa &3{0}. +Party.Help.5=&cPara proteger tu fiesta con una contraseña, usa &3{0} . +Party.Help.6=&cPara expulsar a un jugador de tu fiesta, usa &3{0} . +Party.Help.7=&cPara transferir la propiedad de tu fiesta, usa &3{0} . +Party.Help.8=&cPara disolver tu fiesta, usa &3{0}. +Party.Help.9=&cUsa &3{0} &cpara compartir artículos con miembros de la fiesta. +Party.Help.10=&cUsa &3{0} &cpara habilitar el compartir de XP con miembros de la fiesta. +Party.InformedOnJoin={0} &ase ha unido a tu fiesta. +Party.InformedOnQuit={0} &aha dejado tu fiesta. +Party.InformedOnNameChange=&6{0} &aha cambiado el nombre de la fiesta a &f{1}. +Party.InvalidName=&4Ese no es un nombre válido para una fiesta. +Party.Invite.Self=&c¡No puedes invitarte a ti mismo! +Party.IsLocked=&c¡Esta fiesta ya está bloqueada! +Party.IsntLocked=&c¡Esta fiesta no está bloqueada! +Party.Locked=&cFiesta bloqueada, solo el líder de la fiesta puede invitar. +Party.NotInYourParty=&4{0} no está en tu fiesta. +Party.NotOwner=&4No eres el líder de la fiesta. +Party.Target.NotOwner=&4{0} no es el líder de la fiesta. +Party.Owner.New=&a{0} es el nuevo líder de la fiesta. +Party.Owner.NotLeader=&4Ya no eres el líder de la fiesta. +Party.Owner.Player=&aAhora eres el líder de la fiesta. +Party.Password.None=&cEsta fiesta está protegida por una contraseña. Por favor, proporciona una contraseña para unirte. +Party.Password.Incorrect=&cLa contraseña de la fiesta es incorrecta. +Party.Password.Set=&aContraseña de la fiesta establecida en {0}. +Party.Password.Removed=&aLa contraseña de la fiesta ha sido eliminada. +Party.Player.Invalid=&cEse no es un jugador válido. +Party.NotOnline=&4¡{0} no está en línea! +Party.Player.InSameParty=&c{0} ya está en tu fiesta. +Party.PlayerNotInParty=&4{0} no está en una fiesta. +Party.Specify=&cDebes especificar una fiesta. +Party.Teleport.Dead=&cNo puedes teletransportarte a un jugador muerto. +Party.Teleport.Hurt=&cHas sido herido en los últimos {0} segundos y no puedes teletransportarte. +Party.Teleport.Player=&aTe has teletransportado a {0}. +Party.Teleport.Self=&c¡No puedes teletransportarte a ti mismo! +Party.Teleport.Target=&a{0} se ha teletransportado a ti. +Party.Teleport.Disabled=&c{0} no permite la teletransportación en fiestas. +Party.Rename.Same=&c¡Ese ya es el nombre de tu fiesta! +Party.Join.Self=&c¡No puedes unirte a ti mismo! +Party.Unlocked=&7Fiesta desbloqueada. +Party.Disband=&7La fiesta ha sido disuelta. +Party.Alliance.Formed=&7Tu fiesta ahora está aliada con &a{0}. +Party.Alliance.Disband=&7Tu fiesta ya no está aliada con &c{0}. +Party.Status.Locked=&4(SOLO INVITACIÓN). +Party.Status.Unlocked=&2(ABIERTA). +Party.LevelUp=&eEl nivel de la fiesta ha aumentado en {0}. Total ({1}). +Party.Feature.Chat=Chat de fiesta. +Party.Feature.Teleport=Teletransporte de fiesta. +Party.Feature.Alliance=Alianzas. +Party.Feature.ItemShare=Compartir objetos. +Party.Feature.XpShare=Compartir XP. +Party.Feature.Locked.Chat=BLOQUEADO HASTA {0}+ (CHAT DE FIESTA). +Party.Feature.Locked.Teleport=BLOQUEADO HASTA {0}+ (TELETRANSPORTE DE FIESTA). +Party.Feature.Locked.Alliance=BLOQUEADO HASTA {0}+ (ALIANZAS). +Party.Feature.Locked.ItemShare=BLOQUEADO HASTA {0}+ (COMPARTIR OBJETOS). +Party.Feature.Locked.XpShare=BLOQUEADO HASTA {0}+ (COMPARTIR XP). +Party.Feature.Disabled.1=&cEl chat de fiesta no está desbloqueado todavía. +Party.Feature.Disabled.2=&cEl teletransporte de fiesta no está desbloqueado todavía. +Party.Feature.Disabled.3=&cLas alianzas de fiesta no están desbloqueadas todavía. +Party.Feature.Disabled.4=&cEl compartir objetos de fiesta no está desbloqueado todavía. +Party.Feature.Disabled.5=&cEl compartir XP de fiesta no está desbloqueado todavía. +Party.ShareType.Xp=XP. +Party.ShareType.Item=OBJETO. +Party.ShareMode.None=NADA. +Party.ShareMode.Equal=IGUAL. +Party.ShareMode.Random=ALEATORIO. +Party.ItemShare.Category.Loot=Botín. +Party.ItemShare.Category.Mining=Minería. +Party.ItemShare.Category.Herbalism=Herboristería. +Party.ItemShare.Category.Woodcutting=Tala. +Party.ItemShare.Category.Misc=Varios. +##xp +Commands.XPGain.Acrobatics=Caída +Commands.XPGain.Alchemy=Preparando pociones +Commands.XPGain.Archery=Atacando monstruos +Commands.XPGain.Axes=Atacando monstruos +Commands.XPGain.Child=Gana niveles de las habilidades principales +Commands.XPGain.Crossbows=Atacando monstruos +Commands.XPGain.Excavation=Excavando y encontrando tesoros +Commands.XPGain.Fishing=Pescando (¡Qué sorpresa!) +Commands.XPGain.Herbalism=Cosechando hierbas +Commands.XPGain.Maces=Atacando monstruos +Commands.XPGain.Mining=Minería de piedra y mineral Commands.XPGain.Repair=Reparando -Commands.XPGain.Swords=Atacando a Monstruos -Commands.XPGain.Taming=Domando animales, o combatiendo con tus lobos -Commands.XPGain.Unarmed=Atacando a Monstruos -Commands.XPGain.Woodcutting=Tala de arboles -Commands.XPGain=&8OBTENCIÓN DE EXPERIENCIA: &f{0} -Commands.xplock.locked=&6Tu BARRA DE EXP esta bloqueada a {0}! -Commands.xplock.unlocked=&6Tu BARRA DE EXP esta ahora &aDESBLOQUEADA&6! -Commands.xprate.modified=La probabilidad de XP fue modificada a {0} -Commands.xprate.over=mcMMO EXP Rate Event TERMINO!! -Commands.xprate.proper.0=&3El uso correcto es /xprate -Commands.xprate.proper.1=Uso correcto para restaurar el ratio de EXP por defecto es /xprate reset -Commands.xprate.proper.2=Por favor especifique true o false para indicar si este es un evento de experiencia o no -Commands.xprate.started.0=&6¡EL EVENTO DE EXP DE mcMMO HA COMENZADO! -Commands.xprate.started.1=&6¡mcMMO está ahora en un evento de EXP! ¡El ratio de EXP es x{0}! -XPRate.Event=&6¡mcMMO está ahora en un evento de rate de EXP! ¡El rate de EXP es {0}x! -Effects.Effects=EFECTOS -Effects.Child=&8NIVEL: &a{0} -Effects.Level=&8Nivel: &a{0} &3EXP&e(&6{1}&e/&6{2}&e) -Effects.Parent=&6{0} - -Effects.Template=&3{0}: &a{1} -Guides.Available=&7Guia para {0} disponible - tipo /{1} ? [page] -Guides.Header=&6-=&a{0} Guia&6=- -Guides.Page.Invalid=Numero de pagina no disponible -Guides.Page.OutOfRange=La pagina no existe, solo hay {0} paginas en total +Commands.XPGain.Swords=Atacando monstruos +Commands.XPGain.Taming=Domesticando animales o combatiendo con tus lobos +Commands.XPGain.Tridents=Atacando monstruos +Commands.XPGain.Unarmed=Atacando monstruos +Commands.XPGain.Woodcutting=Talar árboles +Commands.XPGain=&8GANANCIA DE XP: &f{0} +Commands.xplock.locked=&6¡Tu BARRA DE XP ahora está bloqueada en {0}! +Commands.xplock.unlocked=&6¡Tu BARRA DE XP ahora está &aDESBLOQUEADA&6! +Commands.xprate.modified=&cLa TASA DE XP fue modificada a {0} +Commands.xprate.over=&c¡El Evento de Tasa de XP de mcMMO ha TERMINADO! +Commands.xprate.proper.0=&cEl uso correcto para cambiar la tasa de XP es /xprate +Commands.xprate.proper.1=&cEl uso correcto para restaurar la tasa de XP al valor predeterminado es /xprate reset +Commands.xprate.proper.2=&cPor favor, especifica verdadero o falso para indicar si es un evento de XP o no +Commands.NegativeNumberWarn=¡No uses números negativos! +Commands.Event.Start=&amcMMO&6 ¡Evento! +Commands.Event.Stop=&amcMMO&3 ¡Evento terminado! +Commands.Event.Stop.Subtitle=&a¡Espero que te hayas divertido! +Commands.Event.XP=&3La tasa de XP ahora es &6{0}&3x +Commands.xprate.started.0=&6¡EL EVENTO DE XP PARA mcMMO HA COMENZADO! +Commands.xprate.started.1=&6¡LA TASA DE XP DE mcMMO AHORA ES {0}x! + +# Admin Notifications +Server.ConsoleName=&e[Servidor] +Notifications.Admin.XPRate.Start.Self=&7Has establecido el multiplicador global de tasa de XP a &6{0}x +Notifications.Admin.XPRate.End.Self=&7Has terminado el evento de tasa de XP. +Notifications.Admin.XPRate.End.Others={0} &7ha terminado el evento de tasa de XP +Notifications.Admin.XPRate.Start.Others={0} &7ha comenzado o modificado un evento de tasa de XP con un multiplicador global de {1}x +Notifications.Admin.Format.Others=&6(&amcMMO &3Admin&6) &7{0} +Notifications.Admin.Format.Self=&6(&amcMMO&6) &7{0} + +# Event +XPRate.Event=&6¡mcMMO está actualmente en un evento de tasa de XP! La tasa de XP es {0}x! + +#GUIDES +Guides.Available=&7Guía para {0} disponible - escribe /{1} ? [page] +Guides.Header=&6-=&aGuía de {0}&6=- +Guides.Page.Invalid=¡Número de página no válido! +Guides.Page.OutOfRange=Esa página no existe, solo hay {0} páginas en total. Guides.Usage= El uso es /{0} ? [page] -Guides.Smelting.Section.0=Muy pronto... -Inspect.Offline=¡No tienen permiso para inspeccionar jugadores fuera de linea! +##Acrobatics +Guides.Acrobatics.Section.0=&3Acerca de Acrobacias:\n&eLas Acrobacias son el arte de moverse con gracia en mcMMO.\n&eProporciona bonificaciones de combate y reducción de daño ambiental.\n\n&3GANANCIA DE XP:\n&ePara ganar XP en esta habilidad, debes realizar una esquiva\n&een combate o sobrevivir caídas de alturas que te causen daño. +Guides.Acrobatics.Section.1=&3¿Cómo funciona Rodar?\n&eTienes una probabilidad pasiva de anular el daño por caída\n&ecuando recibes daño por caída. Puedes mantener presionado el botón de agacharte para\n&eduplicar tus posibilidades durante la caída.\n&eEsto activa un Rodar Grácil en lugar de uno estándar.\n&eLos Rodar Grácil son como los rodar normales, pero tienen el doble de probabilidad de ocurrir\n&ey brindan más seguridad contra el daño que los rodar normales.\n&ela probabilidad de rodar está ligada a tu nivel de habilidad. +Guides.Acrobatics.Section.2=&3¿Cómo funciona Esquivar?\n&eEsquivar es una probabilidad pasiva de reducir a la mitad el daño recibido\n&ecuando eres herido en combate.\n&eEstá ligada a tu nivel de habilidad. +##Alchemy +Guides.Alchemy.Section.0=[[DARK_AQUA]]Acerca de la Alquimia:\n[[YELLOW]]La Alquimia se trata de preparar pociones.\n[[YELLOW]]Proporciona un aumento en la velocidad de preparación de pociones,\n[[YELLOW]]además de la adición de nuevas pociones (anteriormente) inalcanzables.\n\n\n[[DARK_AQUA]]GANANCIA DE XP:\n[[YELLOW]]Para ganar XP en esta habilidad, necesitas preparar pociones. +Guides.Alchemy.Section.1=[[DARK_AQUA]]¿Cómo funciona la Catálisis?\n[[YELLOW]]La Catálisis acelera el proceso de preparación, con una\n[[YELLOW]]velocidad máxima de 4x a nivel 1000.\n[[YELLOW]]Esta habilidad se desbloquea por defecto en el nivel 100. +Guides.Alchemy.Section.2=[[DARK_AQUA]]¿Cómo funciona Concoctions?\n[[YELLOW]]Concoctions permite la preparación de más pociones con ingredientes personalizados.\n[[YELLOW]]Los ingredientes especiales que se desbloquean están determinados por tu Rango.\n[[YELLOW]]Hay 8 rangos para desbloquear. +Guides.Alchemy.Section.3=[[DARK_AQUA]]Ingredientes de Concoctions de nivel 1:\n[[YELLOW]]Polvo de Blaze, Ojo de Araña Fermentado, Lágrima de Ghast, Piedra Roja,\n[[YELLOW]]Polvo de Piedra Luminosa, Azúcar, Melón Reluciente, Zanahoria Dorada,\n[[YELLOW]]Crema de Magma, Verruga del Nether, Ojo de Araña, Pólvora, Pata de Conejo,\n[[YELLOW]]Pez Globo\n[[YELLOW]](Pociones de Vainilla) +Guides.Alchemy.Section.4=[[DARK_AQUA]]Ingredientes de Concoctions de nivel 2:\n[[YELLOW]]Zanahoria (Poción de Prisa)\n[[YELLOW]]Bola de Slime (Poción de Lentitud)\n\n[[DARK_AQUA]]Ingredientes de Concoctions de nivel 3:\n[[YELLOW]]Cuarzo (Poción de Absorción)\n[[YELLOW]] +Guides.Alchemy.Section.5=[[DARK_AQUA]]Ingredientes de Concoctions de nivel 4:\n[[YELLOW]]Manzana (Poción de Aumento de Salud)\n[[YELLOW]]Carne Podrida (Poción de Hambre)\n\n[[DARK_AQUA]]Ingredientes de Concoctions de nivel 5:\n[[YELLOW]]Champiñón Marrón (Poción de Náusea)\n[[YELLOW]]Saco de Tinta (Poción de Ceguera) +Guides.Alchemy.Section.6=[[DARK_AQUA]]Ingredientes de Concoctions de nivel 6:\n[[YELLOW]]Helecho (Poción de Saturación)\n\n[[DARK_AQUA]]Ingredientes de Concoctions de nivel 7:\n[[YELLOW]]Patata Venenosa (Poción de Decaimiento)\n\n[[DARK_AQUA]]Ingredientes de Concoctions de nivel 8:\n[[YELLOW]]Manzana Dorada Regular (Poción de Resistencia) + +##Archery +Guides.Archery.Section.0=&3Acerca de Tiro con Arco:\n&eEl Tiro con Arco trata de disparar con tu arco y flecha.\n&eProporciona varias bonificaciones de combate, como un aumento de daño\n&equese escala con tu nivel y la habilidad de aturdir a tus\n&eoponentes en PvP. Además, puedes recuperar\n&ealgunas de tus flechas gastadas de los cadáveres de tus enemigos.\n\n\n&3GANANCIA DE XP:\n&ePara ganar XP en esta habilidad, necesitas disparar a mobs o\n&eotros jugadores. +Guides.Archery.Section.1=&3¿Cómo funciona el Disparo Hábil?\n&eEl Disparo Hábil proporciona daño adicional a tus disparos.\n&eEl daño adicional del Disparo Hábil aumenta a medida que\n&esubes de nivel en Tiro con Arco.\n&eCon la configuración predeterminada, el daño de tu tiro con arco aumenta un 10%\n&ecada 50 niveles, hasta un máximo de 200% de daño adicional. +Guides.Archery.Section.2=&3¿Cómo funciona Aturdir?\n&eTienes una probabilidad pasiva de aturdir a otros jugadores\n&ecuando les disparas. Cuando Aturdir se activa, obliga a tus oponentes\n&ea mirar directamente hacia arriba durante un breve período.\n&eUn disparo Aturdidor también inflige 4 puntos de daño adicionales (2 corazones). +Guides.Archery.Section.3=&3¿Cómo funciona la Recuperación de Flechas?\n&eTienes una probabilidad pasiva de recuperar algunas de tus flechas\n&ecuando matas a un mob con tu arco.\n&eEsta probabilidad aumenta a medida que subes de nivel en Tiro con Arco.\n&ePor defecto, esta habilidad aumenta un 0.1% por nivel, hasta un 100%\n&eal nivel 1000. +##Axes +Guides.Axes.Section.0=&3Acerca de Hachas:\n&eCon la habilidad de Hachas puedes usar tu hacha para mucho más que\n&esolo talar árboles. Puedes golpear y cortar a mobs y\n&ejugadores para ganar XP, causando efecto de retroceso a los mobs\n&ey aplicando críticos MORTALES a mobs y jugadores.\n&eTu hacha también se convierte en una trituradora de mano,\n&erompiendo la armadura del enemigo con facilidad a medida que subes\n&ede nivel.\n&3GANANCIA DE XP:\n&ePara ganar XP en esta habilidad necesitas golpear a otros mobs o jugadores\n&econ un hacha. +Guides.Axes.Section.1=&3¿Cómo funciona Partir Cráneos?\n&eEsta habilidad te permite realizar un golpe en área (AoE, por sus siglas en inglés).\n&eEste golpe en área infligirá la mitad del daño que hiciste al\n&eobjetivo principal, por lo que es excelente para eliminar grandes grupos de mobs. +Guides.Axes.Section.2=&3¿Cómo funcionan los Golpes Críticos?\n&eLos Golpes Críticos son una habilidad pasiva que da a los jugadores una\n&eprobabilidad de infligir daño adicional.\n&eCon la configuración predeterminada, cada 2 niveles de habilidad en Hachas otorgan un\n&e0.1% de probabilidad de realizar un Golpe Crítico, causando 2.0 veces el daño\n&econtra mobs o 1.5 veces el daño contra otros jugadores. +Guides.Axes.Section.3=&3¿Cómo funciona la Maestría en Hachas?\n&eLa Maestría en Hachas es una habilidad pasiva que agrega daño adicional\n&a tus golpes cuando usas hachas.\n&ePor defecto, el daño adicional aumenta en 1 cada 50 niveles,\n&ehasta un límite de 4 puntos de daño extra al nivel 200. +Guides.Axes.Section.4=&3¿Cómo funciona el Impacto en la Armadura?\n&e¡Golpea con suficiente fuerza para destrozar la armadura!\n&eEl Impacto en la Armadura tiene una probabilidad pasiva de dañar la\n&earmadura de tu oponente. Este daño aumenta a medida que subes de nivel en Hachas. +Guides.Axes.Section.5=&3¿Cómo funciona el Impacto Mayor?\n&eTienes una probabilidad pasiva de lograr un impacto mayor cuando\n&egolpeas a mobs o jugadores con tu hacha.\n&ePor defecto, esta probabilidad es del 25%. Esta habilidad pasiva tiene un\n&efuerte efecto de retroceso, similar al encantamiento Retroceso II.\n&eAdemás, inflige daño adicional al objetivo. +##Excavation +Guides.Excavation.Section.0=&3Acerca de Excavación:\n&eLa Excavación es el acto de cavar la tierra para encontrar tesoros.\n&eAl excavar la tierra, encontrarás tesoros.\n&eCuanto más lo hagas, más tesoros podrás encontrar.\n\n&3GANANCIA DE XP:\n&ePara ganar XP en esta habilidad, debes cavar con una pala en mano.\n&eSolo ciertos materiales pueden ser excavados para obtener tesoros y XP. +Guides.Excavation.Section.1=&3Materiales Compatibles:\n&eHierba, Tierra, Arena, Arcilla, Grava, Micelio, Arena de Alma, Nieve +Guides.Excavation.Section.2=&3¿Cómo usar Rompeperforadoras Giga?:\n&eCon una pala en mano, haz clic derecho para preparar tu herramienta.\n&eUna vez en este estado, tienes unos 4 segundos para hacer\n&econtacto con materiales compatibles con Excavación, lo que activará\n&eRompeperforadoras Giga. +Guides.Excavation.Section.3=&3¿Qué es Rompeperforadoras Giga?:\n&eRompeperforadoras Giga es una habilidad con un tiempo de enfriamiento\n&eligada a la habilidad de Excavación. Triplica tu posibilidad\n&ede encontrar tesoros y permite romper instantáneamente\n&emateriales de Excavación. +Guides.Excavation.Section.4=&3¿Cómo funciona la Arqueología?:\n&eCada posible tesoro de Excavación tiene su propio\n&erequisito de nivel de habilidad para poder caer, como resultado,\n&ees difícil decir cuánto te está ayudando.\n&eSolo ten en cuenta que cuanto mayor sea tu habilidad de Excavación,\n&e más tesoros podrás encontrar.\n&eY también ten en cuenta que cada tipo de material\n&ecompatible con Excavación tiene su propia lista única de tesoros.\n&eEn otras palabras, encontrarás diferentes tesoros en la Tierra\n&eque los que encontrarías en la Grava. +Guides.Excavation.Section.5=&3Notas sobre Excavación:\n&eLos objetos obtenidos por Excavación son completamente personalizables,\n&epor lo tanto, los resultados varían de un servidor a otro. +##Fishing +Guides.Fishing.Section.0=&3Acerca de la Pesca:\n&eCon la habilidad de Pesca, ¡la Pesca es emocionante de nuevo!\n&eEncuentra tesoros escondidos y sacude objetos de los mobs.\n\n&3GANANCIA DE XP:\n&eAtrapa peces. +Guides.Fishing.Section.1=&3¿Cómo funciona el Cazador de Tesoros?:\n&eEsta habilidad te permite encontrar tesoros al pescar\n&econ una pequeña posibilidad de que los objetos estén encantados.\n&eCada posible tesoro para Pesca tiene una posibilidad\n&ede caer en cualquier nivel. Sin embargo, depende\n&ede la rareza del objeto con qué frecuencia caerá.\n&eCuanto mayor sea tu habilidad de Pesca, mejores\n&eseran tus posibilidades de encontrar mejores tesoros. +Guides.Fishing.Section.2=&3¿Cómo funciona la Pesca en Hielo?:\n&eEsta habilidad pasiva te permite pescar en lagos de hielo.\n&eLanza tu caña de pescar en un lago de hielo y la habilidad\n&ecreará un pequeño agujero en el hielo para pescar. +Guides.Fishing.Section.3=&3¿Cómo funciona el Maestro Pescador?:\n&eEsta habilidad pasiva aumenta la probabilidad de mordida mientras pescas.\n&eCuando desbloqueas esta habilidad, pescar mientras estás en\n&eun bote mejora las probabilidades de atrapar un pez. +Guides.Fishing.Section.4=&3¿Cómo funciona Sacudir?:\n&eEsta habilidad activa te permite sacudir objetos de los mobs\n&eal engancharlos con la caña de pescar.\n&eLos mobs soltarán los objetos que normalmente dejarían caer al morir.\n&eTambién es posible adquirir cráneos de mobs, que normalmente\n&eson inalcanzables en modo supervivencia. +Guides.Fishing.Section.5=&3¿Cómo funciona la Dieta del Pescador?:\n&eEsta habilidad pasiva aumenta la cantidad de hambre restaurada\n&eal comer pescado. +Guides.Fishing.Section.6=&3Notas sobre la Pesca:\n&eLos objetos obtenidos por Pesca son completamente personalizables,\n&epor lo tanto, los resultados varían de un servidor a otro. +##Herbalism +Guides.Herbalism.Section.0=&3Acerca de la Herboristería:\n&eLa Herboristería trata de recolectar hierbas y plantas.\n\n\n&3GANANCIA DE XP:\n&eRecolecta plantas y hierbas. +Guides.Herbalism.Section.1=&3Bloques Compatibles\n&eTrigo, Patatas, Zanahorias, Melones,\n&eCalabazas, Cañas de Azúcar, Frijoles de Cacao, Flores, Cactus, Hongos,\n&eVerruga del Nether, Nenúfares y Enredaderas. +Guides.Herbalism.Section.2=&3¿Cómo funciona la Tierra Verde?:\n&eTierra Verde es una habilidad activa, puedes hacer clic derecho\n&emientras sostienes una azada para activar Tierra Verde.\n&eTierra Verde otorga a los jugadores una oportunidad de obtener 3x de botín\n&eal cosechar plantas. También le da a los jugadores la habilidad de\n&eextender la vida en bloques y transformarlos usando semillas\n&ede tu inventario. +Guides.Herbalism.Section.3=&3¿Cómo funciona el Pulgar Verde (Cultivos)?:\n&eEsta habilidad pasiva replantará automáticamente los cultivos cuando\n&eestés cosechando.\n&eTu posibilidad de éxito depende de tu habilidad en Herboristería. +Guides.Herbalism.Section.4=&3¿Cómo funciona el Pulgar Verde (Piedra/Cobblestone/Tierra)?:\n&eEsta habilidad activa te permite convertir bloques en sus\n&econtrapartes "relacionadas con plantas". Puedes hacerlo haciendo clic derecho\n&een un bloque mientras sostienes semillas. Esto consumirá 1 semilla. +Guides.Herbalism.Section.5=&3¿Cómo funciona la Dieta del Granjero?:\n&eEsta habilidad pasiva aumenta la cantidad de hambre restaurada\n&eal comer Pan, Galletas, Melones, Sopa de Hongos, Zanahorias,\n&ey Patatas. +Guides.Herbalism.Section.6=&3¿Cómo funciona la Suerte Hyliana?:\n&eEsta habilidad pasiva te da una oportunidad de encontrar objetos raros\n&eal romper ciertos bloques con una espada. +Guides.Herbalism.Section.7=&3¿Cómo funcionan las Doble Recolectas?:\n&eEsta habilidad pasiva le da a los jugadores un mayor rendimiento\n&ede sus cosechas. +##Mining +Guides.Mining.Section.0=&3Acerca de Minería:\n&eLa minería consiste en minar piedra y minerales. Proporciona bonificaciones\n&ea la cantidad de materiales que caen al minar.\n\n&3GANANCIA DE XP:\n&ePara ganar XP en esta habilidad, debes minar con un pico en la mano.\n&eSolo ciertos bloques otorgan XP. +Guides.Mining.Section.1=&3Materiales Compatibles:\n&ePiedra, Carbón, Hierro, Oro, Diamante, Redstone,\n&eLapislázuli, Obsidiana, Piedra Musgosa, Piedra del End,\n&ePiedra Luminosa, y Netherrack. +Guides.Mining.Section.2=&3Cómo usar Super Breaker:\n&eCon un pico en la mano, haz clic derecho para preparar tu herramienta.\n&eUna vez en este estado, tienes unos 4 segundos para hacer contacto\n&econ los materiales compatibles con Minería, lo que activará Super\n&eBreaker. +Guides.Mining.Section.3=&3¿Qué es Super Breaker?\n&eSuper Breaker es una habilidad con un tiempo de reutilización ligado a la\n&ehabilidad de Minería. Triplica tu posibilidad de obtener objetos extra\n&ey permite romper materiales de Minería al instante. +Guides.Mining.Section.4=&3Cómo usar Blast Mining:\n&eCon un pico en la mano,\n&eagáchate y haz clic derecho sobre la TNT desde una distancia. Esto hará que la TNT\n&eexplote al instante. +Guides.Mining.Section.5=&3¿Cómo funciona Blast Mining?\n&eBlast Mining es una habilidad con un tiempo de reutilización ligado a la\n&ehabilidad de Minería. Proporciona bonificaciones al minar con TNT y te\n&epermite detonar TNT a distancia. Hay tres partes en Blast Mining.\n&eLa primera parte es Bombas Más Grandes, que incrementa el radio de explosión.\n&eLa segunda es Experto en Demoliciones, que disminuye el daño\n&ede las explosiones de TNT. La tercera parte simplemente incrementa la\n&ecantidad de minerales que caen de la TNT y reduce los\n&edesechos que caen. +##Repair +Guides.Repair.Section.0=&3Acerca de Reparar:\n&eReparar te permite usar un bloque de hierro para reparar armaduras y\n&eherramientas.\n\n&3GANANCIA DE XP:\n&eRepara herramientas o armaduras usando el Yunque de mcMMO. Este es un\n&ebloque de hierro por defecto y no debe confundirse con el\n&eYunque de Minecraft Vanilla. +Guides.Repair.Section.1=&3¿Cómo puedo usar Reparar?\n&eColoca un Yunque de mcMMO y haz clic derecho para reparar el objeto\n&eque estés sosteniendo. Esto consume 1 objeto por cada uso. +Guides.Repair.Section.2=&3¿Cómo funciona la Maestría en Reparar?\n&eLa Maestría en Reparar aumenta la cantidad reparada. La cantidad extra\n&ereparada está influenciada por tu nivel de habilidad en Reparar. +Guides.Repair.Section.3=&3¿Cómo funciona Súper Reparar?\n&eSúper Reparar es una habilidad pasiva. Al reparar un objeto,\n&eotorga a los jugadores la posibilidad de repararlo con\n&eedoble efectividad. +Guides.Repair.Section.4=&3¿Cómo funciona la Forja Arcana?\n&eEsta habilidad pasiva te permite reparar objetos con una cierta\n&eprobabilidad de mantener sus encantamientos. Los encantamientos pueden\n&econservarse en sus niveles actuales, reducirse a un nivel inferior,\n&eo perderse por completo. +##Salvage +Guides.Salvage.Section.0=&3Acerca de Desmantelar:\n&eDesmantelar te permite usar un bloque de oro para desmantelar armaduras y\n&eherramientas.\n\n&3GANANCIA DE XP:\n&eDesmantelar es una habilidad secundaria de Reparar y Pescar, tu nivel\n&ede habilidad en Desmantelar se basa en tus niveles de habilidad en Pescar y Reparar. +Guides.Salvage.Section.1=&3¿Cómo puedo usar Desmantelar?\n&eColoca un Yunque de Desmantelar de mcMMO y haz clic derecho para\n&edesmantelar el objeto que estés sosteniendo. Esto descompondrá el objeto,\n&ey te devolverá los materiales usados para fabricarlo.\n\n&ePor ejemplo, desmantelar un pico de hierro te devolverá lingotes de hierro. +Guides.Salvage.Section.2=&3¿Cómo funciona el Desmantelado Avanzado?\n&eCuando se desbloquea, esta habilidad te permite desmantelar objetos dañados.\n&eporcentaje de rendimiento aumenta a medida que subes de nivel. Un mayor\n&erendimiento significa que puedes recuperar más materiales.\n&eCon el desmantelado avanzado, siempre recuperarás al menos 1 material,\n&eexcepto si el objeto está demasiado dañado. No tendrás que preocuparte\n&ede destruir objetos sin obtener nada a cambio. +Guides.Salvage.Section.3=&3Para ilustrar cómo funciona, aquí tienes un ejemplo:\n&eSupongamos que desmantelamos un pico de oro que está dañado en un 20%,\n&eesto significa que la cantidad máxima que podrías obtener es solo 2\n&elingotes (porque el pico se fabrica con 3 lingotes - cada uno vale\n&e33,33% de durabilidad), lo que equivale al 66%. Si tu porcentaje de\n&erendimiento está por debajo del 66%, no podrás obtener 2 lingotes.\n&eSi está por encima de este valor, podrás obtener la "cantidad completa",\n&eque significa que recibirás 2 lingotes. +Guides.Salvage.Section.4=&3¿Cómo funciona el Desmantelado Arcano?\n&eEsta habilidad te permite obtener libros encantados al desmantelar\n&eobjetos encantados. Dependiendo de tu nivel, la posibilidad de\n&eextraer con éxito un encantamiento completo o parcial varía.\n\n&eCuando un encantamiento se extrae parcialmente, el libro\n&eencantado tendrá un encantamiento de nivel inferior al que\n&eestaba en el objeto. +##Smelting +Guides.Smelting.Section.0=Próximamente... +##Swords +Guides.Swords.Section.0=&3Sobre Espadas:\n&eEsta habilidad otorga bonificaciones de combate a cualquiera que\n&eluche con una espada.\n\n&3GANANCIA DE XP:\n&eLa XP se gana en función de la cantidad de daño infligido a\n&emobs u otros jugadores cuando se empuña una espada. +Guides.Swords.Section.1=&3¿Cómo funciona Golpes Serrados?\n&eGolpes Serrados es una habilidad activa, se puede activar\n&ehaciendo clic derecho con una espada. Esta habilidad permite\n&erealizar un golpe de área de efecto (AoE). Este AoE hará un\n&edaño adicional del 25% y puede aplicar Ruptura. +Guides.Swords.Section.2=&3¿Cómo funciona Contraataque?\n&eContraataque es una habilidad activa. Al bloquear y recibir\n&egolpes de mobs, tendrás la oportunidad de reflejar el 50%\n&edel daño recibido. +Guides.Swords.Section.3=&3¿Cómo funciona Ruptura?\n&eRuptura hace que los enemigos reciban daño cada dos segundos.\n&eel objetivo sangrará hasta que el efecto se disipe o muera,\n&elo que ocurra primero.\n&eLa duración del sangrado aumenta según tu nivel de habilidad con la espada. +##Taming +Guides.Taming.Section.0=&3Sobre la Domesticación:\n&eLa domesticación otorgará varios beneficios de combate a los\n&ejugadores que utilicen lobos domesticados.\n\n&3GANANCIA DE XP:\n&ePara ganar XP en esta habilidad, necesitas domesticar lobos/ocelotes o\n&eluchar con tus lobos. +Guides.Taming.Section.1=&3¿Cómo funciona Llamada de la Naturaleza?\n&eLlamada de la Naturaleza es una habilidad activa que te permitirá\n&einvocar un lobo o un ocelote a tu lado. Puedes hacerlo\n&eagachándote + clic izquierdo mientras sostienes huesos o peces. +Guides.Taming.Section.2=&3¿Cómo funciona Conocimiento de Bestias?\n&eConocimiento de Bestias permite a los jugadores inspeccionar mascotas y\n&ecomprobar las estadísticas de los lobos y ocelotes. Haz clic izquierdo en\n&eun lobo u ocelote para usar Conocimiento de Bestias. +Guides.Taming.Section.3=&3¿Cómo funciona Desgarrar?\n&eDesgarrar es una habilidad pasiva que tiene la posibilidad de\n&einfligir un efecto de sangrado en los objetivos de tus lobos. +Guides.Taming.Section.4=&3¿Cómo funciona Garras Afiladas?\n&eGarras Afiladas proporciona un bono de daño al daño infligido\n&epor los lobos. El bono de daño depende de tu nivel de Domesticación. +Guides.Taming.Section.5=&3¿Cómo funciona Consciencia Ambiental?\n&eEsta habilidad pasiva permitirá a los lobos teletransportarse hacia ti cuando\n&eestén cerca de peligros, como cactus/lava. También otorgará inmunidad\n&eal daño por caída a los lobos. +Guides.Taming.Section.6=&3¿Cómo funciona Pelo Grueso?\n&eEsta habilidad pasiva reducirá el daño y hará a los lobos\n&eresistentes al fuego. +Guides.Taming.Section.7=&3¿Cómo funciona A Prueba de Explosiones?\n&eEsta habilidad pasiva reduce el daño que reciben los lobos\n&ede las explosiones. +Guides.Taming.Section.8=&3¿Cómo funciona Servicio de Comida Rápida?\n&eEsta habilidad pasiva da a los lobos la oportunidad de curarse cuando\n&eataquen. +##Unarmed +Guides.Unarmed.Section.0=&3Sobre Desarmado:\n&eDesarmado otorgará varios beneficios de combate a los\n&ejugadores cuando usen sus puños como arma.\n\n&3GANANCIA DE XP:\n&eLa XP se gana en función de la cantidad de daño infligido a\n&emobs u otros jugadores cuando estás desarmado. +Guides.Unarmed.Section.1=&3¿Cómo funciona Berserk?\n&eBerserk es una habilidad activa que se activa\n&ehaciendo clic derecho. Mientras estés en modo Berserk, infliges un\n&e50% más de daño y puedes romper materiales débiles al instante, como\n&eTierra y Hierba. +Guides.Unarmed.Section.2=&3¿Cómo funciona Estilo Brazo de Acero?\n&eEstilo Brazo de Acero aumenta el daño infligido al golpear mobs o\n&eotros jugadores con tus puños. +Guides.Unarmed.Section.3=&3¿Cómo funciona Desviar Flechas?\n&eDesviar Flechas es una habilidad pasiva que te da la oportunidad\n&ede desviar flechas disparadas por Esqueletos u otros jugadores.\n&ela flecha caerá inofensivamente al suelo. +Guides.Unarmed.Section.4=&3¿Cómo funciona Agarre de Hierro?\n&eAgarre de Hierro es una habilidad pasiva que contrarresta el desarme. A medida\n&eaumenta tu nivel de desarmado, aumenta la probabilidad de prevenir un desarme. +Guides.Unarmed.Section.5=&3¿Cómo funciona Desarmar?\n&eEsta habilidad pasiva permite a los jugadores desarmar a otros jugadores,\n&ehaciendo que el objeto equipado del objetivo caiga al suelo. +##Woodcutting +Guides.Woodcutting.Section.0=&3Acerca de la Tala de Árboles:\n&eLa tala de árboles consiste en talar árboles.\n\n&3GANANCIA DE XP:\n&eSe obtiene XP cada vez que rompes bloques de troncos. +Guides.Woodcutting.Section.1=&3¿Cómo funciona Cortaárboles?\n&eCortaárboles es una habilidad activa, puedes hacer clic\n&ederecho mientras sostienes un hacha para activar Cortaárboles. Esto hará\n&equitar todo el árbol al instante, dejando caer todos\n&elos troncos de una vez. +Guides.Woodcutting.Section.2=&3¿Cómo funciona Rompehojas?\n&eRompehojas es una habilidad pasiva que hará que los bloques de hojas\n&e se rompan al instante cuando se golpean con un hacha. Por defecto,\n&eesta habilidad se desbloquea en el nivel 100. +Guides.Woodcutting.Section.3=&3¿Cómo funcionan las Doble Recompensas?\n&eEsta habilidad pasiva te da la oportunidad de obtener un bloque adicional\n&epor cada tronco que cortes. +# Crossbows +Guides.Crossbows.Section.0=&3Acerca de las Ballestas:\n&eLas ballestas se tratan de disparar con tu ballesta.\n\n&3GANANCIA DE XP:\n&eSe obtiene XP cada vez que disparas a mobs con una ballesta.\nEsta es una habilidad en progreso y se agregarán más detalles pronto. +Guides.Crossbows.Section.1=&3¿Cómo funciona Tiro al Blanco?\n&eTiro al Blanco es una habilidad pasiva, disparas tus flechas en un ángulo bajo con una ballesta para intentar un Tiro al Blanco. Esto hará que la flecha rebote en los bloques y potencialmente golpee un objetivo. La cantidad de rebotes potenciales de un ricochet depende del nivel de Tiro al Blanco. +# Tridents +Guides.Tridents.Section.0=&3Acerca de los Tridentes:\n&eLa habilidad con tridentes implica empalar a los enemigos con tu tridente.\n\n&3GANANCIA DE XP:\n&eSe obtiene XP cada vez que golpeas a mobs con un tridente.\nEsta es una habilidad en progreso y se agregarán más detalles pronto. +Guides.Maces.Section.0=&3Acerca de las Mazas:\n&eLas mazas se tratan de aplastar a tus enemigos con una maza.\n\n&3GANANCIA DE XP:\n&eSe obtiene XP cada vez que golpeas a mobs con una maza.\nEsta es una habilidad en progreso y se agregarán más detalles pronto. + +#INSPECT +Inspect.Offline=&c¡No tienes permiso para inspeccionar jugadores desconectados! Inspect.OfflineStats=Estadísticas de mcMMO para el Jugador Desconectado &e{0} -Inspect.Stats=&aEstadísticas de mcMMO para &e{0} -Inspect.TooFar=¡Estás demasiado lejos como para inspeccionar a ese jugador! -Item.ChimaeraWing.Fail=**¡LAS ALAS DE QUIMERA FALLARON!** -Item.ChimaeraWing.Pass=**¡ALAS DE QUIMERA!** -Item.ChimaeraWing.Name=Ala de quimera -Item.ChimaeraWing.Lore=&7Teletransportate a tu cama. -Item.Generic.Wait=Tienes que esperar hasta que puedas usar esto de nuevo! &e({0}s) -Item.Injured.Wait=Te lesionaste recientemente y tenés que esperar para usar esto. &e({0}seg) -Teleport.Commencing=&7Comenzando el teletransporte en &6({0}) &7segundos, por favor mantente hasta... -Teleport.Cancelled=&4Teletransportacion cancelada! -Skills.Child=&6(HABILIDAD HIJA) +Inspect.Stats=&amcMMO Estadísticas para &e{0} +Inspect.TooFar=¡Estás demasiado lejos para inspeccionar a ese jugador! +#ITEMS +Item.ChimaeraWing.Fail=&c**¡ALA DE QUIMERA FALLIDA!** +Item.ChimaeraWing.Pass=**ALA DE QUIMERA** +Item.ChimaeraWing.Name=Ala de Quimera +Item.ChimaeraWing.Lore=&7Te teletransporta a tu cama. +Item.ChimaeraWing.NotEnough=¡Necesitas &e{0}&c más &6{1}&c! +Item.NotEnough=¡Necesitas &e{0}&c más &6{1}&c! +Item.Generic.Wait=¡Debes esperar antes de usar esto de nuevo! &e({0}s) +Item.Injured.Wait=Fuiste herido recientemente y debes esperar para usar esto. &e({0}s) +Item.FluxPickaxe.Name=Pico de Flux +Item.FluxPickaxe.Lore.1=&7Tiene la posibilidad de fundir instantáneamente minerales. +Item.FluxPickaxe.Lore.2=&7Requiere nivel de Fundición {0}+ +#TELEPORTATION +Teleport.Commencing=&7Iniciando teletransportación en &6({0}) &7segundos, por favor mantente quieto... +Teleport.Cancelled=&4¡Teletransportación cancelada! +#SKILLS +Skills.Child=&6(HABILIDAD INFANTIL) Skills.Disarmed=&4¡Has sido desarmado! -Skills.Header=-----[]&a{0}&c[]----- -Skills.NeedMore=&4Necesitas más +Skills.Header=-----[] &a{0}&c []----- +Skills.NeedMore=&4Necesitas más &7{0} +Skills.NeedMore.Extra=&4Necesitas más &7{0}{1} Skills.Parents=PADRES -Skills.Stats={0}&a{1}&3 EXP(&7{2}&3/&7{3}&3) -Skills.TooTired=Estás demasiado cansado como para utilizar esa habilidad de nuevo. -Skills.Cancelled={0} cancelado! -Skills.ConfirmOrCancel=&aClick derecho otra vez para confirmar &6{0}&a. Click izquierdo para cancelar. +Skills.Stats={0}&a{1}&3 XP(&7{2}&3/&7{3}&3) +Skills.ChildStats={0}&a{1} +Skills.MaxXP=Máximo +Skills.TooTired=Estás demasiado cansado para usar esa habilidad de nuevo. &e({0}s) +Skills.TooTired.Named=&7(&6{0}&e {1}s&7) +Skills.TooTired.Extra=&6{0} &eSuper Habilidad CDs - {1} +Skills.Cancelled=&6{0} &ccancelado! +Skills.ConfirmOrCancel=&aHaz clic derecho de nuevo para confirmar &6{0}&a. Haz clic izquierdo para cancelar. +Skills.AbilityGateRequirementFail=&7Necesitas &e{0}&7 niveles más de &3{1}&7 para usar esta super habilidad. +#STATISTICS Stats.Header.Combat=&6-=HABILIDADES DE COMBATE=- Stats.Header.Gathering=&6-=HABILIDADES DE RECOLECCIÓN=- -Stats.Header.Misc=&6-=HABILIDADES VARIAS=- +Stats.Header.Misc=&6-=HABILIDADES MISCELÁNEAS=- Stats.Own.Stats=&a[mcMMO] Estadísticas +#PERKS Perks.XP.Name=Experiencia -Perks.XP.Desc=Recibes un impulso de XP en ciertas habilidades. +Perks.XP.Desc=Recibe XP adicional en ciertas habilidades. Perks.Lucky.Name=Suerte -Perks.Lucky.Desc=Da {0} destrezas y habilidades de un 33,3% más posibilidades de activar. -Perks.Lucky.Desc.Login=Da ciertas destrezas y habilidades de un 33,3% más posibilidades de activar. -Perks.Lucky.Bonus=&6 ({0} con suerte de beneficios adicionales) -Perks.Cooldowns.Name=Recuperación rapida -Perks.Cooldowns.Desc=Acorta la duración de tiempo de reutilización {0} +Perks.Lucky.Desc=Otorga a {0} habilidades y habilidades un 33.3% más de probabilidad de activarse. +Perks.Lucky.Desc.Login=Otorga a ciertas habilidades y habilidades un 33.3% más de probabilidad de activarse. +Perks.Lucky.Bonus=&6 ({0} con la Ventaja de Suerte) +Perks.Cooldowns.Name=Recuperación Rápida +Perks.Cooldowns.Desc=Reduce la duración del tiempo de espera en {0}. Perks.ActivationTime.Name=Resistencia -Perks.ActivationTime.Desc=Aumenta el tiempo de activación de la capacidad por {0} segundos. -Perks.ActivationTime.Bonus=&6 ({0}s con beneficio de resistencia) -Hardcore.Mode.Disabled=&6[mcMMO] Modo hardcore {0} desactivado. {1} -Hardcore.Mode.Enabled=&6[mcMMO] Modo dhrdcore {0} activado. {1} -Hardcore.DeathStatLoss.Name=Bonus de pena de muerte. -Hardcore.DeathStatLoss.PlayerDeath=&6[mcMMO] &4Has perdido &9{0}&4 de la muerte. -Hardcore.DeathStatLoss.PercentageChanged=&6[mcMMO] El porcentaje de perdida de stats fue cambiado a {0}. +Perks.ActivationTime.Desc=Aumenta el tiempo de activación de la habilidad en {0} segundos. +Perks.ActivationTime.Bonus=&6 ({0}s con la Ventaja de Resistencia) +#HARDCORE +Hardcore.Mode.Disabled=&6[mcMMO] Modo Hardcore {0} desactivado para {1}. +Hardcore.Mode.Enabled=&6[mcMMO] Modo Hardcore {0} activado para {1}. +Hardcore.DeathStatLoss.Name=Penalización por Muerte en Habilidad +Hardcore.DeathStatLoss.PlayerDeath=&6[mcMMO] &4Has perdido &9{0}&4 niveles por muerte. +Hardcore.DeathStatLoss.PercentageChanged=&6[mcMMO] El porcentaje de pérdida de estadísticas se cambió a {0}. Hardcore.Vampirism.Name=Vampirismo -Hardcore.Vampirism.Killer.Failure=&6[mcMMO] &e{0}&7 era demasiado inexperto para concederte algo de sabiduria. +Hardcore.Vampirism.Killer.Failure=&6[mcMMO] &e{0}&7 era demasiado inexperto para otorgarte algún conocimiento. Hardcore.Vampirism.Killer.Success=&6[mcMMO] &3Has robado &9{0}&3 niveles de &e{1}. -Hardcore.Vampirism.Victim.Failure=&6[mcMMO] &e{0}&7 fue incapaz de robarte sabiduria! -Hardcore.Vampirism.Victim.Success=&6[mcMMO] &e{0}&4 te ha robado &9{1}&4 niveles! -Hardcore.Vampirism.PercentageChanged=&6[mcMMO] El porcentaje de sanguijuela fue cambiado a {0}. -MOTD.Donate=&3Informacion de la donacion: -MOTD.Hardcore.Enabled=&6[mcMMO] &3Modo hardcore activado: &4{0} -MOTD.Hardcore.DeathStatLoss.Stats=&6[mcMMO] &3Penalizacion de habilidad por muerte: &4{0}% -MOTD.Hardcore.Vampirism.Stats=&6[mcMMO] &3Estadisticas de sanguijuela vampirica: &4{0}% -MOTD.PerksPrefix=[mcMMO Beneficios] -MOTD.Version=&6[mcMMO] Utilizando la version &3{0} -MOTD.Website=&6[mcMMO] &a{0}&e - Pagina web de mcMMO -Smelting.Ability.FluxMining=Probabilidad de mineria fluida: &e{0} -Smelting.Ability.FuelEfficiency=Multiplicador de eficiencia del combustible: &e{0}x -Smelting.Ability.Locked.0=Bloqueado hasta {0}+ HABILIDAD (IMPULSO DE XP VANILLA) -Smelting.Ability.Locked.1=Bloqueado hasta {0}+ HABILIDAD (MINERIA FLUIDA) -Smelting.Ability.SecondSmelt=Probabilidad de segundo fundido: &e{0} -Smelting.Ability.VanillaXPBoost=Multiplicador de XP Vanilla: &e{0}x -Smelting.SubSkill.FuelEfficiency.Name=Eficiencia del combustible -Smelting.SubSkill.FuelEfficiency.Description=Aumente el tiempo de quemado de combustible utilizado en los hornos mientras se funde. -Smelting.SubSkill.SecondSmelt.Name=Seunda fusion -Smelting.SubSkill.SecondSmelt.Description=Recursos dobles obtenidos por fusion -Smelting.Effect.4=Impulso de XP Vamilla -Smelting.Effect.5=Aumento de la XP VANILLA obtenida mientras de funde -Smelting.SubSkill.FluxMining.Name=Mineria fluida -Smelting.SubSkill.FluxMining.Description=Probabilidad de que los minerales sean automaticamente fundidos mientras se mina (toque de seda) -Smelting.FluxMining.Success=&aEse mineral se fundio por si solo! -Smelting.Listener=Fusion -Smelting.SkillName=FUNDIENDO -Commands.Description.addlevels=Añadir niveles mcMMO a un usuario -Commands.Description.adminchat=Activa/Desactiva el chat de administarcion mcMMO o envia mensajes de chat de administración -Commands.Description.addxp=Añadir XP mcMMO a un usuario -Commands.Description.hardcore=Modifica el porcentaje de mcMMO Hardcore o Activa/Desactiva el modo hardcore -Commands.Description.inspect=Ver informacion mcMMO detallada de un jugador -Commands.Description.mcability=Activar/Desactivar habilidades mcMMO en boton derecho del raton -Commands.Description.mcgod=Activa/Desactiva modo dios mcMMO -Commands.Description.mchud=Cambiar el estilo de mcMMO HUD +Hardcore.Vampirism.Victim.Failure=&6[mcMMO] &e{0}&7 no pudo robarte conocimiento! +Hardcore.Vampirism.Victim.Success=&6[mcMMO] &e{0}&4 ha robado &9{1}&4 niveles de ti. +Hardcore.Vampirism.PercentageChanged=&6[mcMMO] El porcentaje de absorción de estadísticas se cambió a {0}. +#MOTD +MOTD.Donate=&3Información sobre donaciones: +MOTD.Hardcore.Enabled=&6[mcMMO] &3Modo Hardcore activado: &4{0} +MOTD.Hardcore.DeathStatLoss.Stats=&6[mcMMO] &3Penalización por muerte en habilidad: &4{0}% +MOTD.Hardcore.Vampirism.Stats=&6[mcMMO] &3Absorción de estadísticas por vampirismo: &4{0}% +MOTD.PerksPrefix=&6[mcMMO Ventajas] +MOTD.Version=&6[mcMMO] Ejecutando la versión &3{0} +MOTD.Website=&6[mcMMO] &a{0}&e - Sitio web de mcMMO +#SMELTING +Smelting.SubSkill.UnderstandingTheArt.Name=Entendiendo el Arte +Smelting.SubSkill.UnderstandingTheArt.Description=Tal vez estás pasando demasiado tiempo fundiendo en las cuevas.\nPotencia varias propiedades de la Fundición. +Smelting.SubSkill.UnderstandingTheArt.Stat=Multiplicador de XP de Vanilla: &e{0}x +Smelting.Ability.Locked.0=BLOQUEADO HASTA {0}+ HABILIDAD (AUMENTO DE XP DE VANILLA) +Smelting.Ability.Locked.1=BLOQUEADO HASTA {0}+ HABILIDAD (MINERÍA FLUX) +Smelting.SubSkill.FuelEfficiency.Name=Eficiencia del Combustible +Smelting.SubSkill.FuelEfficiency.Description=Aumenta el tiempo de combustión del combustible utilizado en los hornos al fundir +Smelting.SubSkill.FuelEfficiency.Stat=Multiplicador de Eficiencia del Combustible: &e{0}x +Smelting.SubSkill.SecondSmelt.Name=Segunda Fundición +Smelting.SubSkill.SecondSmelt.Description=Duplica los recursos obtenidos al fundir +Smelting.SubSkill.SecondSmelt.Stat=Probabilidad de Segunda Fundición +Smelting.Effect.4=Aumento de XP de Vanilla +Smelting.Effect.5=Aumenta el XP de Vanilla obtenido al fundir +Smelting.SubSkill.FluxMining.Name=Minería Flux +Smelting.SubSkill.FluxMining.Description=Probabilidad de que los minerales se fundan instantáneamente al minar +Smelting.SubSkill.FluxMining.Stat=Probabilidad de Minería Flux +Smelting.Listener=Fundición: +Smelting.SkillName=FUNDICIÓN +#COMMAND DESCRIPTIONS +Commands.Description.addlevels=Añadir niveles de mcMMO a un usuario +Commands.Description.adminchat=Activar/desactivar el chat de administración de mcMMO o enviar mensajes de chat de administración +Commands.Description.addxp=Añadir XP de mcMMO a un usuario +Commands.Description.hardcore=Modificar el porcentaje de hardcore de mcMMO o activar/desactivar el modo hardcore +Commands.Description.inspect=Ver información detallada de mcMMO sobre otro jugador +Commands.Description.mcability=Activar/desactivar las habilidades de mcMMO al hacer clic derecho +Commands.Description.mccooldown=Ver todos los tiempos de espera de habilidades de mcMMO +Commands.Description.mcchatspy=Activar/desactivar el espionaje de chat de grupo de mcMMO +Commands.Description.mcgod=Activar/desactivar el modo dios de mcMMO +Commands.Description.mchud=Cambiar el estilo de tu HUD de mcMMO Commands.Description.mcmmo=Mostrar una breve descripción de mcMMO -Commands.Description.mcnotify=Activa/Desactiva las notificaciones de habilidad -Commands.Description.mcpurge=Purgar usuarios con ningun nivel mcMMO y usuarios que no se han conectado en {0} meses de la base de datos -Commands.Description.mcrank=Mostrar las estadisticas mcMMO de un jugador -Commands.Description.mcrefresh=Actualizar todos los tiempos de reutilización para mcMMO -Commands.Description.mcremove=Elimina a un usuario de la base de datos de mcMMO -Commands.Description.mcstats=Muestra tu nivel y XP mcMMO -Commands.Description.mctop=Mostrar tablas de clasificación mcMMO -Commands.Description.mmoedit=Editar niveles mcMMO de un usuario -Commands.Description.mmoupdate=Migrar la base de datos mcMMO de una base de datos antigua a una nueva actual -Commands.Description.mcconvert=Convierte tipos de basa de datos o tipos de formulas de experiencia. -Commands.Description.mmoshowdb=Muestra el nombre del tipo de base de datos actual(para mas tarde usarla con /mmoupdate) -Commands.Description.party=Controlar varias configuraciones de los grupos mcMMO -Commands.Description.partychat=Activar/Desactivar el chat de grupo o enviar mensajes por el chat de grupo -Commands.Description.ptp=Teletransportate a un mienbro de tu grupo mcMMO -Commands.Description.Skill=Ver informacion detallada de la habilidades {0} -Commands.Description.skillreset=Resetear el nivel mcMMO de un usuario -Commands.Description.vampirism=Modifica el porcentaje de vampirismo mcMMO o Activa/Desactiva el modo vampiro -Commands.Description.xplock=Bloquear la barra de experiencia mcMMO de una habilidad especifica -Commands.Description.xprate=Modifica la velocidad del mcMMO XP o comieza un evento de mcMMO XP -UpdateChecker.Outdated=Estas usando una version de mcMMO antigua! -UpdateChecker.NewAvailable=Hay una nueva version disponible en BukkitDev -Scoreboard.Header.PlayerStats=Estadisticas de mcMMO -Scoreboard.Header.PlayerRank=Rankings de mcMMO -Scoreboard.Header.PlayerInspect=Estadisticas mcMMO: -Scoreboard.Header.PowerLevel=Nivel de poder -Scoreboard.Misc.PowerLevel=Nivel de poder -Scoreboard.Misc.Level=Nivel -Scoreboard.Misc.CurrentXP=XP actual -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 its in compatibility mode or fully functional. +Commands.Description.mcnotify=Activar/desactivar las notificaciones de chat de habilidades de mcMMO +Commands.Description.mcpurge=Depurar usuarios sin niveles de mcMMO y usuarios que no se han conectado en más de {0} meses de la base de datos de mcMMO. +Commands.Description.mcrank=Mostrar la clasificación de mcMMO de un jugador +Commands.Description.mcrefresh=Actualizar todos los tiempos de espera de mcMMO +Commands.Description.mcremove=Eliminar un usuario de la base de datos de mcMMO +Commands.Description.mcscoreboard=Gestionar tu marcador de mcMMO +Commands.Description.mcstats=Mostrar tus niveles y XP de mcMMO +Commands.Description.mctop=Mostrar tablas de clasificación de mcMMO +Commands.Description.mmoedit=Editar niveles de mcMMO para un usuario +Commands.Description.mmodebug=Activar/desactivar un modo de depuración que imprime información útil cuando golpeas bloques +Commands.Description.mmoupdate=Migrar la base de datos de mcMMO de una base de datos antigua a la actual +Commands.Description.mcconvert=Convertir tipos de base de datos o tipos de fórmulas de experiencia +Commands.Description.mmoshowdb=Mostrar el nombre del tipo de base de datos actual (para uso posterior con /mmoupdate) +Commands.Description.party=Controlar varias configuraciones de grupos de mcMMO +Commands.Description.partychat=Activar/desactivar el chat de grupo de mcMMO o enviar mensajes de chat de grupo +Commands.Description.ptp=Teletransportarse a un miembro de grupo de mcMMO +Commands.Description.Skill=Mostrar información detallada de habilidad de mcMMO para {0} +Commands.Description.skillreset=Restablecer niveles de mcMMO para un usuario +Commands.Description.vampirism=Modificar el porcentaje de vampirismo de mcMMO o activar/desactivar el modo vampirismo +Commands.Description.xplock=Bloquear tu barra de XP de mcMMO en una habilidad específica de mcMMO +Commands.Description.xprate=Modificar la tasa de XP de mcMMO o iniciar un evento de XP de mcMMO +#UPDATE CHECKER +UpdateChecker.Outdated=¡Estás usando una versión desactualizada de mcMMO! +UpdateChecker.NewAvailable=Hay una nueva versión disponible en Spigot. +#SCOREBOARD HEADERS +Scoreboard.Header.PlayerStats=&eEstadísticas mcMMO +Scoreboard.Header.PlayerCooldowns=&eTiempos de Espera mcMMO +Scoreboard.Header.PlayerRank=&eClasificaciones mcMMO +Scoreboard.Header.PlayerInspect=&eEstadísticas mcMMO: {0} +Scoreboard.Header.PowerLevel=&cNivel de Poder +Scoreboard.Misc.PowerLevel=&6Nivel de Poder +Scoreboard.Misc.Level=&3Nivel +Scoreboard.Misc.CurrentXP=&aXP Actual +Scoreboard.Misc.RemainingXP=&eXP Restante +Scoreboard.Misc.Cooldown=&dTiempo de Espera +Scoreboard.Misc.Overall=&6General +Scoreboard.Misc.Ability=Habilidad +#DATABASE RECOVERY +Profile.PendingLoad=&cTus datos de jugador de mcMMO aún no se han cargado. +Profile.Loading.Success=&aTu perfil de mcMMO se ha cargado. +Profile.Loading.FailurePlayer=&cmcMMO está teniendo problemas para cargar tus datos, hemos intentado cargarlo &a{0}&c veces.&c Podrías querer contactar a los administradores del servidor sobre este problema. mcMMO intentará cargar tus datos hasta que te desconectes, no ganarás XP ni podrás usar habilidades mientras los datos no estén cargados. +Profile.Loading.FailureNotice=&4[A]&c mcMMO no pudo cargar los datos del jugador para &e{0}&c. &dPor favor, revisa la configuración de tu base de datos. Intentos realizados hasta ahora {1}. +#Holiday +Holiday.AprilFools.Levelup=&6{0} ahora es nivel &a{1}&6! +Holiday.Anniversary=&9¡Feliz {0} Aniversario!\n&9En honor a todo el trabajo de nossr50 y todos los desarrolladores, ¡aquí tienes un espectáculo de fuegos artificiales! +#Reminder Messages +Reminder.Squelched=&7Recordatorio: Actualmente no estás recibiendo notificaciones de mcMMO, para habilitar las notificaciones, ejecuta el comando /mcnotify nuevamente. Este es un recordatorio automático cada hora. +#Locale +Locale.Reloaded=&a¡Configuración regional recargada! +#Player Leveling Stuff +LevelCap.PowerLevel=&6(&amcMMO&6) &eHas alcanzado el límite de nivel de poder de &c{0}&e. Dejarás de subir de nivel en habilidades a partir de este punto. +LevelCap.Skill=&6(&amcMMO&6) &eHas alcanzado el límite de nivel de &c{0}&e para &6{1}&e. Dejarás de subir de nivel en esta habilidad a partir de este punto. +Commands.XPBar.Usage=El uso correcto es /mmoxpbar +Commands.Description.mmoxpbar=Configuraciones de jugador para las barras de XP de mcMMO +Commands.Description.mmocompat=Información sobre mcMMO y si está en modo de compatibilidad o completamente funcional. +Compatibility.Layer.Unsupported=&6La compatibilidad para &a{0}&6 no es compatible con esta versión de Minecraft. +Compatibility.Layer.PartialSupport=&6La compatibilidad para &a{0}&6 no está completamente soportada por esta versión de Minecraft, pero mcMMO está ejecutando un sistema secundario para emular algunas de las características faltantes. +Commands.XPBar.DisableAll=&6 Todas las barras de XP de mcMMO están ahora desactivadas, usa /mmoxpbar reset para restaurar las configuraciones por defecto. +#Modern Chat Settings +Chat.Style.Admin=&b(A) &r{0} &b\u2192 &r{1} +Chat.Style.Party=&a(P) &r{0} &a\u2192 &r{1} +Chat.Style.Party.Leader=&a(P) &r{0} &6\u2192 &r{1} +Chat.Identity.Console=&6* Consola * +Chat.Channel.On=&6(&amcMMO-Chat&6) &eTus mensajes de chat ahora se enviarán automáticamente al canal de chat &a{0}&e. +Chat.Channel.Off=&6(&amcMMO-Chat&6) &7Tus mensajes de chat ya no se enviarán automáticamente a canales de chat específicos. +Chat.Spy.Party=&6[&eESPÍA&6-&a{2}&6] &r{0} &b\u2192 &r{1} +Broadcasts.LevelUpMilestone=&6(&amcMMO&6) {0}&7 ha alcanzado el nivel &a{1}&7 en &3{2}&7! +Broadcasts.PowerLevelUpMilestone=&6(&amcMMO&6) {0}&7 ha alcanzado un Nivel de Poder de &a{1}&7! +Scoreboard.Recovery=Intentando recuperar el marcador de mcMMO... +Scoreboard.Disabled=Los marcadores de mcMMO para este servidor están desactivados, esta configuración se encuentra en mcMMO/config.yml +Scoreboard.NotSetupYet=Tu marcador de mcMMO aún no se ha configurado, inténtalo de nuevo más tarde. diff --git a/src/main/resources/locale/locale_fi.properties b/src/main/resources/locale/locale_fi.properties index 75570f4aa..03f88a9c5 100644 --- a/src/main/resources/locale/locale_fi.properties +++ b/src/main/resources/locale/locale_fi.properties @@ -66,7 +66,7 @@ Repair.SubSkill.DiamondRepair.Name=Timantti Korjaus ({0}+ TAITO) Repair.SubSkill.DiamondRepair.Description=Korjaa Timantti työkaluja & haarniskoita Repair.SubSkill.ArcaneForging.Name=Mystinen Korjaus Repair.SubSkill.ArcaneForging.Description=Korjaa lumottuja esineitä -Repair.Listener.Anvil=&4Olet asettanut alasimen paikalleen, voit korjata työkalusi ja haarniskasi sillä. +Repair.Listener.Anvil=&aOlet asettanut alasimen paikalleen, voit korjata työkalusi ja haarniskasi sillä. Repair.Listener=Korjaus: Repair.SkillName=KORJAA Repair.Skills.AdeptDiamond=&4Et ole tarpeeksi taitava korjataksesi timanttia. diff --git a/src/main/resources/locale/locale_fr.properties b/src/main/resources/locale/locale_fr.properties index c7df2078c..6beecc569 100644 --- a/src/main/resources/locale/locale_fr.properties +++ b/src/main/resources/locale/locale_fr.properties @@ -357,7 +357,7 @@ Repair.SubSkill.ArcaneForging.Description=Répare les objets magiques Repair.SubSkill.ArcaneForging.Stat=Arcane Forging: &eRank {0}/{1} Repair.SubSkill.ArcaneForging.Stat.Extra=&3Arcane Forging Odds:&7 Success &a{0}&7%, Failure &c{1}&7% Repair.Error=&4McMMO a rencontré une erreur en essayant de réparer cet objet ! -Repair.Listener.Anvil=&4Vous venez de poser une enclume, elle peut être utilisée pour réparer votre équipement. +Repair.Listener.Anvil=&aVous venez de poser une enclume, elle peut être utilisée pour réparer votre équipement. Repair.Listener=Réparation : Repair.SkillName=RÉPARATION Repair.Skills.AdeptDiamond=&4Vous n\'êtes pas suffisamment compétent pour réparer le diamant. @@ -380,7 +380,7 @@ Salvage.SubSkill.UnderstandingTheArt.Name=Compréhension de l\'art Salvage.SubSkill.UnderstandingTheArt.Description=Vous n\'êtes pas juste en train de miner à travers la poubelle de votre voisin, vous prenez soin de l\'environment.\nRenforce la récupération. Salvage.SubSkill.ScrapCollector.Name=Collection de fragment Salvage.SubSkill.ScrapCollector.Description=Récupération de materiel depuis un item, une récupération parfaite en accord avec vos compétences et votre chance. -Salvage.SubSkill.ScrapCollector.Stat=Collection de fragment: &aRécupération de &e{0}&a items. Un peu de chance y est impliqué. +Salvage.SubSkill.ScrapCollector.Stat=Collection de fragment: &aRécupération de &e{0}&a items. Salvage.SubSkill.ArcaneSalvage.Name=Recyclage Arcanique Salvage.SubSkill.ArcaneSalvage.Description=Extrait les enchantements des objets Salvage.SubSkill.ArcaneSalvage.Stat=Recyclage Arcanique: &eGrade {0}/{1} @@ -395,7 +395,7 @@ Salvage.Skills.TooDamaged=&4C\'est objet est trop endommagé pour être recyclé Salvage.Skills.ArcaneFailed=Vous avez été incapable d\'extraire la connaissance contenue dans cet objet. Salvage.Skills.ArcanePartial=Vous avez été capable d\'extraire toute la connaissance contenue dans cet objet. Salvage.Skills.ArcaneSuccess=&aVous avez été capable d\'extraire toute la connaissance contenue dans cet objet. -Salvage.Listener.Anvil=&4Vous avez placé une enclume de réparation, utilisez-la pour recycler vos outils et vos armures. +Salvage.Listener.Anvil=&aVous avez placé une enclume de réparation, utilisez-la pour recycler vos outils et vos armures. Salvage.Listener=Recyclage: Salvage.SkillName=RECYCLAGE Salvage.Skills.Lottery.Normal=&6Vous êtes capable de récupérer &3{0}&6 matériel de &e{1}&6. @@ -847,7 +847,7 @@ Commands.xprate.proper.2=Veuillez spécifier true ou false pour indiquer si il s Commands.NegativeNumberWarn=N'utilisez pas des nombres négatifs ! Commands.Event.Start=&amcMMO&6 évènement ! Commands.Event.Stop=&amcMMO&3 évènement terminé ! -Commands.Event.Stop.Subtitle=&aJ'espère que vous vous amesurez ! +Commands.Event.Stop.Subtitle=&aJ'espère que tu t'es bien amusé ! Commands.Event.XP=&3Ratio d\'XP est désormais &6{0}&3x Commands.xprate.started.0=&6L’ÉVÉNEMENT BONUS D\'XP mcMMO VIENT DE COMMENCER ! Commands.xprate.started.1=&6Le bonus d\'XP mcMMO est maintenant de {0}x ! diff --git a/src/main/resources/locale/locale_hu_HU.properties b/src/main/resources/locale/locale_hu_HU.properties index c0d286a7f..54b09d0ba 100644 --- a/src/main/resources/locale/locale_hu_HU.properties +++ b/src/main/resources/locale/locale_hu_HU.properties @@ -357,7 +357,7 @@ Repair.SubSkill.ArcaneForging.Description=Mágikus eszközök javítása Repair.SubSkill.ArcaneForging.Stat=Mágikus Kovácsolás: &eSzint {0}/{1} Repair.SubSkill.ArcaneForging.Stat.Extra=&3Mágikus Kovácsolás Esély:&7 Siker &a{0}&7%, Sikertelen &c{1}&7% Repair.Error=&4Az mcMMO hibát észlelt a tárgy megjavítása közben! -Repair.Listener.Anvil=&4Lehelyeztél egy üllőt. Az üllőkkel eszközöket és páncélzatot lehet javítani +Repair.Listener.Anvil=&aLehelyeztél egy üllőt. Az üllőkkel eszközöket és páncélzatot lehet javítani Repair.Listener=Javítás: Repair.SkillName=JAVÍTÁS Repair.Skills.AdeptDiamond=&4Nem vagy elég tapasztalt ahhoz, hogy Gyémánttal javíts. @@ -380,7 +380,7 @@ Salvage.SubSkill.UnderstandingTheArt.Name=A Művészet Megértése Salvage.SubSkill.UnderstandingTheArt.Description=Nem csak a szomszédok szemétében kutatsz, hanem gondoskodsz a környezetről is.\nAz Értékmentés különböző tulajdonságait növeli. Salvage.SubSkill.ScrapCollector.Name=Hulladékgyűjtő Salvage.SubSkill.ScrapCollector.Description=Hasznosítsd újra az anyagokat egy tárgyból, egy sikeres újrahasznosítás a képességen és a szerencsén múlik. -Salvage.SubSkill.ScrapCollector.Stat=Hulladékgyűjtő: &aHulladékgyűjtő: &aHasznosíts újra akár &e{0}&a tárgyat. Egy kis szerencsével. +Salvage.SubSkill.ScrapCollector.Stat=Hulladékgyűjtő: &aHulladékgyűjtő: &aHasznosíts újra akár &e{0}&a tárgyat. Salvage.SubSkill.ArcaneSalvage.Name=Mágikus Újrahasznosítás Salvage.SubSkill.ArcaneSalvage.Description=Varázslatok kinyerése tárgyakból Salvage.SubSkill.ArcaneSalvage.Stat=Mágikus Újrahasznosítás Szint: &e {0}/{1} @@ -395,7 +395,7 @@ Salvage.Skills.TooDamaged=&4Ez a tárgy túlságosan sérült az újrahasznosít Salvage.Skills.ArcaneFailed=&cNem tudtad kinyerni a tudást, ami ebben a tárgyban lakozik. Salvage.Skills.ArcanePartial=&cCsak részleges tudást tudtál kinyerni ebből a tárgyból. Salvage.Skills.ArcaneSuccess=&aSikeresen kinyertél minden tudást ebből a tárgyból! -Salvage.Listener.Anvil=&4Lehelyeztél egy Értékmentő Üllőt. Használd ezt eszközök, és páncélzatok újrahasznosításhoz. +Salvage.Listener.Anvil=&aLehelyeztél egy Értékmentő Üllőt. Használd ezt eszközök, és páncélzatok újrahasznosításhoz. Salvage.Listener=Újrahasznosítás: Salvage.SkillName=ÚJRAHASZNOSÍTÁS Salvage.Skills.Lottery.Normal=&6Újrahasznosíthatsz &3{0}&6 anyagot ebből &e{1}&6. diff --git a/src/main/resources/locale/locale_it.properties b/src/main/resources/locale/locale_it.properties index 250245ed3..84a858a56 100644 --- a/src/main/resources/locale/locale_it.properties +++ b/src/main/resources/locale/locale_it.properties @@ -362,7 +362,7 @@ Repair.SubSkill.ArcaneForging.Description=Ripara oggetti magici Repair.SubSkill.ArcaneForging.Stat=Forgiatura Arcana: &eGrado {0}/{1} Repair.SubSkill.ArcaneForging.Stat.Extra=&3Probabilità Forgiatura Arcana:&7 Successo &a{0}&7%, Fallimento &c{1}&7% Repair.Error=&4mcMMO ha riscontrato un errore nel tentativo di riparare questo oggetto! -Repair.Listener.Anvil=&4Hai posizionato un'incudine, le incudini possono riparare attrezzi e armature. +Repair.Listener.Anvil=&aHai posizionato un'incudine, le incudini possono riparare attrezzi e armature. Repair.Listener=Riparazione: Repair.SkillName=RIPARAZIONE Repair.Skills.AdeptDiamond=&4Non sei abbastanza abile da riparare il Diamante. @@ -385,7 +385,7 @@ Salvage.SubSkill.UnderstandingTheArt.Name=Capire l'Arte Salvage.SubSkill.UnderstandingTheArt.Description=Non stai semplicemente scavando nella spazzatura dei tuoi vicini, ti stai prendendo cura dell'ambiente.\nPotenzia varie proprietà della Rottamazione. Salvage.SubSkill.ScrapCollector.Name=Collezionista di Rottami Salvage.SubSkill.ScrapCollector.Description=Recupera materiali da un oggetto, un perfetto recupero dipende da abilità e fortuna. -Salvage.SubSkill.ScrapCollector.Stat=Collezionista di Rottami: &aRecupera fino a &e{0}&a oggetti. è coinvolta un po' di fortuna. +Salvage.SubSkill.ScrapCollector.Stat=Collezionista di Rottami: &aRecupera fino a &e{0}&a oggetti. Salvage.SubSkill.ArcaneSalvage.Name=Rottamazione Arcana Salvage.SubSkill.ArcaneSalvage.Description=Estrae incantesimi dagli oggetti Salvage.SubSkill.ArcaneSalvage.Stat=Rottamazione Arcana: &eGrado {0}/{1} @@ -400,7 +400,7 @@ Salvage.Skills.TooDamaged=&4Questo oggetto è troppo danneggiato per essere rott Salvage.Skills.ArcaneFailed=&cNon sei riuscito a estrarre le conoscenze contenute in questo oggetto. Salvage.Skills.ArcanePartial=&cSei riuscito a estrarre solo alcune delle conoscenze contenute all'interno di questo oggetto. Salvage.Skills.ArcaneSuccess=&aSei riuscito a estrarre tutte le conoscenze contenute in questo oggetto! -Salvage.Listener.Anvil=&4Hai posizionato un'incudine da Rottamazione, usala per Rottamare attrezzi e armature. +Salvage.Listener.Anvil=&aHai posizionato un'incudine da Rottamazione, usala per Rottamare attrezzi e armature. Salvage.Listener=Rottamazione: Salvage.SkillName=ROTTAMAZIONE Salvage.Skills.Lottery.Normal=&6Sei riuscito a rottamare &3{0}&6 materiali da &e{1}&6. diff --git a/src/main/resources/locale/locale_ja_JP.properties b/src/main/resources/locale/locale_ja_JP.properties index 9f123a5a1..62ee8f9e9 100644 --- a/src/main/resources/locale/locale_ja_JP.properties +++ b/src/main/resources/locale/locale_ja_JP.properties @@ -20,6 +20,7 @@ JSON.Acrobatics=アクロバティック JSON.Alchemy=錬金術 JSON.Archery=弓 JSON.Axes=斧 +JSON.Crossbows=クロスボウ JSON.Excavation=掘削 JSON.Fishing=釣り JSON.Herbalism=農業 @@ -28,6 +29,8 @@ JSON.Repair=修理 JSON.Salvage=サルベージ JSON.Swords=剣 JSON.Taming=調教 +JSON.Tridents=トライデント +JSON.Maces=メイス JSON.Unarmed=素手 JSON.Woodcutting=木こり JSON.URL.Website=mcMMO公式ウェブサイト @@ -89,6 +92,7 @@ Overhaul.Name.Acrobatics=アクロバティック Overhaul.Name.Alchemy=錬金術 Overhaul.Name.Archery=弓 Overhaul.Name.Axes=斧 +Overhaul.Name.Crossbows=クロスボウ Overhaul.Name.Excavation=掘削 Overhaul.Name.Fishing=釣り Overhaul.Name.Herbalism=農業 @@ -98,14 +102,16 @@ Overhaul.Name.Salvage=サルベージ Overhaul.Name.Smelting=精錬 Overhaul.Name.Swords=剣 Overhaul.Name.Taming=調教 +Overhaul.Name.Tridents=トライデント +Overhaul.Name.Maces=メイス Overhaul.Name.Unarmed=素手 Overhaul.Name.Woodcutting=木こり # /mcMMO Command Style Stuff -Commands.mcc.Header=&c---[]&amcMMO コマンド&c[]--- -Commands.Other=&c---[]&aスペシャルコマンド&c[]--- -Commands.Party.Header=&c-----[]&aパーティー&c[]----- -Commands.Party.Features.Header=&c-----[]&a特徴&c[]----- +Commands.mcc.Header=&c[]=====[] &amcMMO コマンド &c[]=====[] +Commands.Other=&c[]=====[] &aスペシャルコマンド &c[]=====[] +Commands.Party.Header=&c[]=====[] &aパーティー &c[]=====[] +Commands.Party.Features.Header=&c[]=====[] &a機能 &c[]=====[] # XP BAR Allows for the following variables -- {0} = Skill Level, {1} Current XP, {2} XP Needed for next level, {3} Power Level, {4} Percentage of Level # Make sure you turn on Experience_Bars.ThisMayCauseLag.AlwaysUpdateTitlesWhenXPIsGained if you want the XP bar title to update every time a player gains XP! XPBar.Template={0} @@ -114,6 +120,7 @@ XPBar.Acrobatics=アクロバティック Lv.&6{0} XPBar.Alchemy=錬金術 Lv.&6{0} XPBar.Archery=弓 Lv.&6{0} XPBar.Axes=斧 Lv.&6{0} +XPBar.Crossbows=クロスボウ Lv.&6{0} XPBar.Excavation=掘削 Lv.&6{0} XPBar.Fishing=釣り Lv.&6{0} XPBar.Herbalism=農業 Lv.&6{0} @@ -123,6 +130,8 @@ XPBar.Salvage=サルベージ Lv.&6{0} XPBar.Smelting=精錬 Lv.&6{0} XPBar.Swords=剣 Lv.&6{0} XPBar.Taming=調教 Lv.&6{0} +XPBar.Tridents=トライデント Lv.&6{0} +XPBar.Maces=メイス Lv.&6{0} XPBar.Unarmed=素手 Lv.&6{0} XPBar.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 @@ -144,7 +153,7 @@ Acrobatics.SubSkill.Roll.Chance=受け身の確率: &e{0} Acrobatics.SubSkill.Roll.GraceChance=優雅な受け身の確率: &e{0} Acrobatics.SubSkill.Roll.Mechanics=&7落下ダメージを受けるたびに、スキルレベルに応じてダメージを完全に防ぐ可能性があり、レベル&e{6}%&7ではダメージを防ぐ確率が&e{0}%&7です。\nスニークボタンを押すことで、落下ダメージを回避する確率が2倍になり、最大2倍の落下ダメージを回避することができます。スニークボタンを押すと、通常の受け身が「優雅な受け身」に変化します。優雅な受け身は最大で&a{5}&7ダメージを防ぐことができます。 Acrobatics.SubSkill.GracefulRoll.Name=優雅な受け身 -Acrobatics.SubSkill.GracefulRoll.Description=受け身の二倍の効果を発揮する。 +Acrobatics.SubSkill.GracefulRoll.Description=通常の受け身の2倍の効果を発揮する。 Acrobatics.SubSkill.Dodge.Name=躱す Acrobatics.SubSkill.Dodge.Description=攻撃で受けるダメージを半減する。 Acrobatics.SubSkill.Dodge.Stat=躱す確率 @@ -157,11 +166,11 @@ Alchemy.SubSkill.Catalysis.Name=触媒作用 Alchemy.SubSkill.Catalysis.Description=ポーションの醸造速度を向上する。 Alchemy.SubSkill.Catalysis.Stat=醸造速度 Alchemy.SubSkill.Concoctions.Name=調合 -Alchemy.SubSkill.Concoctions.Description=もっと材料を入れたポーションを作成する。 +Alchemy.SubSkill.Concoctions.Description=さらなる材料を使ったポーションを作成する。 Alchemy.SubSkill.Concoctions.Stat=調合 ランク: &a{0}&3/&a{1} Alchemy.SubSkill.Concoctions.Stat.Extra=材料 [&a{0}&3]: &a{1} Alchemy.Listener=錬金術: -Alchemy.Ability.Locked.0=ロックされるまで {0}+ スキル (触媒作用) +Alchemy.Ability.Locked.0=スキルレベル {0}+ でロック解除 (触媒作用) Alchemy.SkillName=錬金術 # ARCHERY @@ -174,25 +183,32 @@ Archery.SubSkill.Daze.Stat=幻惑の確率 Archery.SubSkill.ArrowRetrieval.Name=矢回収 Archery.SubSkill.ArrowRetrieval.Description=死体から矢を確率で回収する。 Archery.SubSkill.ArrowRetrieval.Stat=矢回収の確率 -Archery.SubSkill.ArcheryLimitBreak.Name=限界突破 +Archery.SubSkill.ArcheryLimitBreak.Name=弓 限界突破 Archery.SubSkill.ArcheryLimitBreak.Description=限界を破る。タフな敵に対するダメージが増加します。PvPを対象とし、PvEへの適応はサーバーの設定次第です。 Archery.SubSkill.ArcheryLimitBreak.Stat=限界突破 最大ダメージ Archery.Listener=弓: Archery.SkillName=弓 +Archery.SubSkill.ExplosiveShot.Name=爆発ショット +Archery.SubSkill.ExplosiveShot.Description=爆発する矢を発射する。 +Archery.Skills.ExplosiveShot.Off= +Archery.Skills.ExplosiveShot.On=&a**爆発ショット アクティベート** +Archery.Skills.ExplosiveShot.Other.Off=&e{0}が &f爆発ショット &aを消耗した +Archery.Skills.ExplosiveShot.Other.On=&a{0}&2が &c爆発ショット &2を使った! +Archery.Skills.ExplosiveShot.Refresh=&e爆発ショット &aアビリティが回復しました! # AXES Axes.Ability.Bonus.0=アックスマスタリー Axes.Ability.Bonus.1=ボーナス {0} ダメージ Axes.Ability.Bonus.2=アーマーインパクト Axes.Ability.Bonus.3=防具に{0}のボーナスダメージを与える -Axes.Ability.Bonus.4=グリーターインパクト +Axes.Ability.Bonus.4=グレーターインパクト Axes.Ability.Bonus.5=防具のない敵に{0}のボーナスダメージを与える Axes.Ability.Lower=&7斧を下げた。 Axes.Ability.Ready=&3斧を&6準備&3した。 Axes.Ability.Ready.Extra=&3斧を&6準備&3した。 &7({0} が {1} 秒のクールダウン中) Axes.Combat.CritStruck=&4あなたは重大なダメージを受けました! Axes.Combat.CriticalHit=クリティカルヒット! -Axes.Combat.GI.Proc=&a**大きな力が襲ってきた** +Axes.Combat.GI.Proc=&a**グレーターインパクト発動** Axes.Combat.GI.Struck=**グレーターインパクトに襲われた!** Axes.Combat.SS.Struck=&4スカルスプリッターに襲われた! Axes.SubSkill.SkullSplitter.Name=スカルスプリッター @@ -205,7 +221,7 @@ Axes.SubSkill.AxeMastery.Name=アックスマスタリー Axes.SubSkill.AxeMastery.Description=追加ダメージを与える。 Axes.SubSkill.AxesLimitBreak.Name=斧 限界突破 Axes.SubSkill.AxesLimitBreak.Description=限界を破る。タフな敵に対するダメージが増加します。PvPを対象とし、PvEへの適応はサーバーの設定次第です。 -Axes.SubSkill.AxesLimitBreak.Stat=限界突破 追加ダメージ +Axes.SubSkill.AxesLimitBreak.Stat=限界突破 最大ダメージ Axes.SubSkill.ArmorImpact.Name=アーマーインパクト Axes.SubSkill.ArmorImpact.Description=防具を粉砕する威力で攻撃する。 Axes.SubSkill.GreaterImpact.Name=グレーターインパクト @@ -243,9 +259,9 @@ Fishing.Scared=&7&o混沌とした動きは魚を怖がらせます! Fishing.Exhausting=&c&o釣り竿を不適切に使用すると、疲労を引き起こしたり、耐久値を消費したりします。 Fishing.LowResourcesTip=&7この地域にいる魚がそれほど多くないことを感じました。少なくとも{0}ブロック離れたところで釣りをしてみて下さい。 Fishing.Ability.Info=マジックハンター: &7 **トレジャーハンター ランクで改善する** -Fishing.Ability.Locked.0=ロックされるまで {0}+ スキル (シェイク) -Fishing.Ability.Locked.1=ロックされるまで {0}+ スキル (アイスフィッシング) -Fishing.Ability.Locked.2=ロックされるまで {0}+ スキル (マスターアングラー) +Fishing.Ability.Locked.0=スキルレベル {0}+ でロック解除 (シェイク) +Fishing.Ability.Locked.1=スキルレベル {0}+ でロック解除 (アイスフィッシング) +Fishing.Ability.Locked.2=スキルレベル {0}+ でロック解除 (マスターアングラー) Fishing.SubSkill.TreasureHunter.Name=トレジャーハンター Fishing.SubSkill.TreasureHunter.Description=魚や物を釣り上げる。 Fishing.SubSkill.TreasureHunter.Stat=トレジャーハンター ランク: &a{0}&3/&a{1} @@ -292,9 +308,12 @@ Herbalism.SubSkill.GreenThumb.Description.2=石レンガを苔むした状態に Herbalism.SubSkill.FarmersDiet.Name=農家の食事 Herbalism.SubSkill.FarmersDiet.Description=農作物から回復する満腹度を改善する。 Herbalism.SubSkill.FarmersDiet.Stat=農家の食事: &aランク {0} -Herbalism.SubSkill.DoubleDrops.Name=ドロップ二倍 -Herbalism.SubSkill.DoubleDrops.Description=ドロップが二倍になる。 -Herbalism.SubSkill.DoubleDrops.Stat=ドロップ二倍の確率 +Herbalism.SubSkill.DoubleDrops.Name=ドロップ2倍 +Herbalism.SubSkill.DoubleDrops.Description=ドロップが2倍になる。 +Herbalism.SubSkill.DoubleDrops.Stat=ドロップ2倍の確率 +Herbalism.SubSkill.VerdantBounty.Name=豊かな実り +Herbalism.SubSkill.VerdantBounty.Description=ドロップが3倍になる。 +Herbalism.SubSkill.VerdantBounty.Stat=ドロップ3倍の確率 Herbalism.SubSkill.HylianLuck.Name=ハイリアンラック Herbalism.SubSkill.HylianLuck.Description=希少品を見つける確率が上がる。 Herbalism.SubSkill.HylianLuck.Stat=ハイリアンラックの確率 @@ -311,17 +330,20 @@ Herbalism.Skills.GTe.Other.Off=&e{0}が &fグリーンテラ &aを消耗した Herbalism.Skills.GTe.Other.On=&a{0}&2が &cグリーンテラ &2を使った! # MINING -Mining.Ability.Locked.0=ロックされるまで {0}+ スキル (ブラストマイニング) -Mining.Ability.Locked.1=ロックされるまで {0}+ スキル (大きな爆弾) -Mining.Ability.Locked.2=ロックされるまで {0}+ スキル (解体専門知識) +Mining.Ability.Locked.0=スキルレベル {0}+ でロック解除 (ブラストマイニング) +Mining.Ability.Locked.1=スキルレベル {0}+ でロック解除 (大きな爆弾) +Mining.Ability.Locked.2=スキルレベル {0}+ でロック解除 (解体専門知識) Mining.Ability.Lower=&7ピッケルを下げた。 Mining.Ability.Ready=&3ピッケルを&6準備&3した。 Mining.SubSkill.SuperBreaker.Name=スーパーブレイカー -Mining.SubSkill.SuperBreaker.Description=スピード+, ドロップ率三倍 +Mining.SubSkill.SuperBreaker.Description=スピード+, ドロップ率3倍 Mining.SubSkill.SuperBreaker.Stat=スーパーブレイカーの長さ -Mining.SubSkill.DoubleDrops.Name=ドロップ二倍 -Mining.SubSkill.DoubleDrops.Description=ドロップが二倍になる。 -Mining.SubSkill.DoubleDrops.Stat=ドロップ二倍の確率: &e{0} +Mining.SubSkill.DoubleDrops.Name=ドロップ2倍 +Mining.SubSkill.DoubleDrops.Description=ドロップが2倍になる。 +Mining.SubSkill.DoubleDrops.Stat=ドロップ2倍の確率 +Mining.SubSkill.MotherLode.Name=大鉱脈 +Mining.SubSkill.MotherLode.Description=ドロップが3倍になる。 +Mining.SubSkill.MotherLode.Stat=ドロップ3倍の確率 Mining.SubSkill.BlastMining.Name=ブラストマイニング Mining.SubSkill.BlastMining.Description=TNTによる採掘のボーナス Mining.SubSkill.BlastMining.Stat=ブラストマイニング:&a ランク {0}/{1} &7({2}) @@ -359,16 +381,16 @@ Repair.SubSkill.RepairMastery.Name=リペアマスタリー Repair.SubSkill.RepairMastery.Description=修理量の増加 Repair.SubSkill.RepairMastery.Stat=リペアマスタリー: &a追加 {0} 耐久力回復 Repair.SubSkill.SuperRepair.Name=スーパーリペア -Repair.SubSkill.SuperRepair.Description=二重の効果 +Repair.SubSkill.SuperRepair.Description=2倍の効果 Repair.SubSkill.SuperRepair.Stat=スーパーリペアの確率 -Repair.SubSkill.DiamondRepair.Name=ダイアモンド 修理 ({0}+ SKILL) -Repair.SubSkill.DiamondRepair.Description=ダイアモンドのツールと防具を修理する。 +Repair.SubSkill.DiamondRepair.Name=ダイヤモンド 修理 ({0}+ SKILL) +Repair.SubSkill.DiamondRepair.Description=ダイヤモンドのツールと防具を修理する。 Repair.SubSkill.ArcaneForging.Name=アルカンフォージング Repair.SubSkill.ArcaneForging.Description=魔法のアイテムを修理する。 Repair.SubSkill.ArcaneForging.Stat=アルカンフォージング: &eランク {0}/{1} Repair.SubSkill.ArcaneForging.Stat.Extra=&3アルカンフォージング オッズ:&7 成功 &a{0}&7%, 失敗 &c{1}&7% Repair.Error=&4このアイテムを修理しようとしているときにmcMMOでエラーが発生しました。 -Repair.Listener.Anvil=&4鉄床を設置しました、鉄床はツールと防具を修理できます。 +Repair.Listener.Anvil=&a鉄床を設置しました、鉄床はツールと防具を修理できます。 Repair.Listener=修理: Repair.SkillName=修理 Repair.Skills.AdeptDiamond=&4あなたはダイヤモンドを修理するのに十分な練度を得ていません。 @@ -377,23 +399,23 @@ Repair.Skills.AdeptIron=&4あなたは鉄を修理するのに十分な練度を Repair.Skills.AdeptStone=&4あなたは石を修理するのに十分な練度を得ていません。 Repair.Skills.Adept=&e{1} &cを修理するためには &e{0} &cレベルが必要です。 Repair.Skills.FeltEasy=&7それは簡単に感じた。 -Repair.Skills.FullDurability=&7それは完全な耐久性です。 +Repair.Skills.FullDurability=&7耐久値が減っていません。 Repair.Skills.StackedItems=&4スタックされたアイテムは修理できません。 Repair.Pretty.Name=修理 # Arcane Forging -Repair.Arcane.Downgrade=このアイテムの難解な力は減少しました。 -Repair.Arcane.Fail=難解な力はこのアイテムから消えました。 -Repair.Arcane.Lost=あなたはエンチャントする程十分な練度を獲得していませんでした。 -Repair.Arcane.Perfect=&aあなたはこのアイテムの難解なエネルギーを持続してきました。 +Repair.Arcane.Downgrade=このアイテムに秘められた力は弱まりました。 +Repair.Arcane.Fail=このアイテムに秘められた力は消えました。 +Repair.Arcane.Lost=あなたはエンチャントを維持する程十分な練度を獲得していませんでした。 +Repair.Arcane.Perfect=&aこのアイテムに秘められた力を維持することができました! # SALVAGE Salvage.Pretty.Name=サルベージ Salvage.SubSkill.UnderstandingTheArt.Name=芸術を理解する。 -Salvage.SubSkill.UnderstandingTheArt.Description=あなたはただあなたの隣人のゴミを掘り下げるのではなく、あなたは環境の世話をしています。\nサルベージの様々な特性を引き出す。 +Salvage.SubSkill.UnderstandingTheArt.Description=あなたはただ近所のゴミを掘り漁っているのではなく、環境改善に貢献しているのだ。\nサルベージの様々な特性を引き出そう。 Salvage.SubSkill.ScrapCollector.Name=スクラップコレクター -Salvage.SubSkill.ScrapCollector.Description=サルベージによるアイテムからの素材回収、完璧なサルベージはスキルと運に依存します。 -Salvage.SubSkill.ScrapCollector.Stat=スクラップコレクター: &a最大&e{0}個&aのアイテムをサルベージ。運が関係しています。 +Salvage.SubSkill.ScrapCollector.Description=サルベージによりアイテムから素材を取り出す。完璧なサルベージはスキルと運に依存します。 +Salvage.SubSkill.ScrapCollector.Stat=スクラップコレクター: &a最大&e{0}個&aのアイテムをサルベージ。 Salvage.SubSkill.ArcaneSalvage.Name=アルカンサルベージ Salvage.SubSkill.ArcaneSalvage.Description=アイテムからエンチャントを抽出する。 Salvage.SubSkill.ArcaneSalvage.Stat=アルカンサルベージ: &eランク {0}/{1} @@ -408,7 +430,7 @@ Salvage.Skills.TooDamaged=&4このアイテムはダメージを受けている Salvage.Skills.ArcaneFailed=&cこのアイテムに含まれている知識を抽出できませんでした。 Salvage.Skills.ArcanePartial=&cこのアイテムに含まれている知識を一部しか抽出できませんでした。 Salvage.Skills.ArcaneSuccess=&aこのアイテムに含まれている知識を抽出できました! -Salvage.Listener.Anvil=&4あなたはサルベージアンビルを設置しました。これをツールと防具のサルベージに使ってください。 +Salvage.Listener.Anvil=&aあなたはサルベージアンビルを設置しました。これをツールと防具のサルベージに使ってください。 Salvage.Listener=サルベージ: Salvage.SkillName=サルベージ Salvage.Skills.Lottery.Normal=&e{1}&6から&3{0}&6の素材を回収することができました。 @@ -417,17 +439,70 @@ Salvage.Skills.Lottery.Untrained=&7あなたはサルベージを正しく訓練 # Anvil (Shared between SALVAGE and REPAIR) Anvil.Unbreakable=このアイテムは壊れません! +Anvil.Repair.Reject.CustomModelData=このアイテムの修理は不思議な力によって妨害された... +Anvil.Salvage.Reject.CustomModelData=このアイテムのサルベージは不思議な力によって妨害された... +#CROSSBOWS +Crossbows.SkillName=クロスボウ +Crossbows.Ability.Lower=&7クロスボウを下げた。 +Crossbows.Ability.Ready=&3クロスボウを&6準備&3した。 +Crossbows.Skills.SSG.Refresh=&eスーパーショットガン &aアビリティが回復しました! +Crossbows.Skills.SSG.Other.On=&a{0}&2 が &cスーパーショットガン &2を使った! +Crossbows.SubSkill.PoweredShot.Name=パワーショット +Crossbows.SubSkill.PoweredShot.Description=クロスボウによるダメージを増加する。 +Crossbows.SubSkill.PoweredShot.Stat=パワーショット 追加ダメージ +Crossbows.SubSkill.CrossbowsLimitBreak.Name=クロスボウ 限界突破 +Crossbows.SubSkill.CrossbowsLimitBreak.Description=限界を破る。タフな敵に対するダメージが増加します。PvPを対象とし、PvEへの適応はサーバーの設定次第です。 +Crossbows.SubSkill.CrossbowsLimitBreak.Stat=限界突破 最大ダメージ +Crossbows.SubSkill.TrickShot.Name=トリックショット +Crossbows.SubSkill.TrickShot.Description=浅い角度で放ったクロスボウの矢が地面で跳ね返る。 +Crossbows.SubSkill.TrickShot.Stat=トリックショット 最大跳弾回数 +Crossbows.SubSkill.TrickShot.Stat.Extra=トリックショット 最大跳弾回数: &a{0} +Crossbows.SubSkill.TrickShot.Stat.Extra2=トリックショット 跳弾ごとに減少するダメージ: &a{0} +Crossbows.SubSkill.SuperShotgun.Name=スーパーショットガン +Crossbows.Listener=クロスボウ: + +#TRIDENTS +Tridents.SkillName=トライデント +Tridents.Ability.Lower=&7トライデントを下げた。 +Tridents.Ability.Ready=&3トライデントを&6準備&3した。 +Tridents.SubSkill.Impale.Name=刺突 +Tridents.SubSkill.Impale.Description=トライデントによるダメージを増加する。 +Tridents.SubSkill.Impale.Stat=刺突 追加ダメージ +Tridents.SubSkill.TridentsLimitBreak.Name=トライデント 限界突破 +Tridents.SubSkill.TridentsLimitBreak.Description=限界を破る。タフな敵に対するダメージが増加します。PvPを対象とし、PvEへの適応はサーバーの設定次第です。 +Tridents.SubSkill.TridentsLimitBreak.Stat=限界突破 最大ダメージ +Tridents.SubSkill.TridentAbility.Name=WIP +Tridents.Listener=トライデント: + +#MACES +Commands.McTop.MacesNotSupported=[[GREEN]]メイスはこのバージョンのMinecraftではサポートされていません。 +Maces.SkillName=メイス +Maces.Ability.Lower=&7メイスを下げた。 +Maces.Ability.Ready=&3メイスを&6準備&3した。 +Maces.SubSkill.MacesLimitBreak.Name=メイス 限界突破 +Maces.SubSkill.MacesLimitBreak.Description=限界を破る。タフな敵に対するダメージが増加します。PvPを対象とし、PvEへの適応はサーバーの設定次第です。 +Maces.SubSkill.MacesLimitBreak.Stat=限界突破 最大ダメージ +Maces.SubSkill.Crush.Name=クラッシュ +Maces.SubSkill.Crush.Description=攻撃にボーナスダメージを与える。 +Maces.SubSkill.Crush.Stat=クラッシュ ダメージ +Maces.SubSkill.Cripple.Proc=**移動阻害を受けた** +Maces.SubSkill.Cripple.Activated=ターゲットの移動を阻害した +Maces.SubSkill.Cripple.Name=移動阻害 +Maces.SubSkill.Cripple.Description=確率で相手の移動を阻害します。 +Maces.SubSkill.Cripple.Stat=移動阻害の確率 +Maces.SubSkill.Cripple.Stat.Extra=[[DARK_AQUA]]移動阻害の持続時間: &e{0}s&a vs Players, &e{1}s&a vs Mobs. +Maces.Listener=メイス: # SWORDS Swords.Ability.Lower=&7剣を下げた。 Swords.Ability.Ready=&3剣を&6準備&3した。 -Swords.Combat.Rupture.Note=&7注意:&e 0.5秒ごとに1tickが発生します。 +Swords.Combat.Rupture.Note.Update.One=&7注意:&e 出血により非致死性のダメージを毎秒2回受けます。防具では軽減されません。 Swords.Combat.Bleeding.Started=&4 あなたは出血しています! Swords.Combat.Bleeding.Stopped=&7出血が &a止まりました&7! Swords.Combat.Bleeding=&a**エネミー 出血** Swords.Combat.Counter.Hit=&4カウンター攻撃がヒット! Swords.Combat.Countered=&a**カウンター攻撃** -Swords.Combat.SS.Struck=&4Struck by SERRATED STRIKES! +Swords.Combat.SS.Struck=&4セレーションストライクに襲われた! Swords.SubSkill.CounterAttack.Name=カウンター攻撃 Swords.SubSkill.CounterAttack.Description=攻撃されたときにダメージの一部を反射する! Swords.SubSkill.CounterAttack.Stat=カウンター攻撃の確率 @@ -441,7 +516,7 @@ Swords.SubSkill.Stab.Description=攻撃にボーナスダメージを与える Swords.SubSkill.Stab.Stat=スタブ ダメージ Swords.SubSkill.SwordsLimitBreak.Name=剣 限界突破 Swords.SubSkill.SwordsLimitBreak.Description=限界を破る。タフな敵に対するダメージが増加します。PvPを対象とし、PvEへの適応はサーバーの設定次第です。 -Swords.SubSkill.SwordsLimitBreak.Stat=限界突破 追加ダメージ +Swords.SubSkill.SwordsLimitBreak.Stat=限界突破 最大ダメージ Swords.SubSkill.Rupture.Stat=破裂の確率 Swords.SubSkill.Rupture.Stat.Extra=&3破裂: &e{0}s&a vs プレイヤー, &e{1}s&a vs Mobs. Swords.SubSkill.Rupture.Stat.TickDamage=&3破裂のティックあたりのダメージ: &e{0}&a vs プレイヤー, &e{1}&a vs Mobs. @@ -468,13 +543,13 @@ Taming.Ability.Bonus.7=+{0} ダメージ Taming.Ability.Bonus.8=ファーストフードサービス Taming.Ability.Bonus.9={0} の確率で攻撃時回復 Taming.Ability.Bonus.10=ホーリーハウンド -Taming.Ability.Bonus.11=魔法や毒でダメージを受けた時状態異常を取り消す。 -Taming.Ability.Locked.0=ロックされるまで {0}+ スキル (環境配慮) -Taming.Ability.Locked.1=ロックされるまで {0}+ スキル (厚い毛皮) -Taming.Ability.Locked.2=ロックされるまで {0}+ スキル (衝撃耐性) -Taming.Ability.Locked.3=ロックされるまで {0}+ スキル (鋭い爪) -Taming.Ability.Locked.4=ロックされるまで {0}+ スキル (ファーストフードサービス) -Taming.Ability.Locked.5=ロックされるまで {0}+ スキル (ホーリーハウンド) +Taming.Ability.Bonus.11=魔法や毒でダメージを受けた時に体力を回復する。 +Taming.Ability.Locked.0=スキルレベル {0}+ でロック解除 (環境配慮) +Taming.Ability.Locked.1=スキルレベル {0}+ でロック解除 (厚い毛皮) +Taming.Ability.Locked.2=スキルレベル {0}+ でロック解除 (衝撃耐性) +Taming.Ability.Locked.3=スキルレベル {0}+ でロック解除 (鋭い爪) +Taming.Ability.Locked.4=スキルレベル {0}+ でロック解除 (ファーストフードサービス) +Taming.Ability.Locked.5=スキルレベル {0}+ でロック解除 (ホーリーハウンド) Taming.Combat.Chance.Gore=流血の確率 Taming.SubSkill.BeastLore.Name=ビーストロア Taming.SubSkill.BeastLore.Description=狼と猫を骨で検査する。 @@ -482,13 +557,13 @@ Taming.SubSkill.ShockProof.Name=衝撃耐性 Taming.SubSkill.ShockProof.Description=爆発ダメージの軽減 Taming.SubSkill.CallOfTheWild.Name=コールオブザワイルド Taming.SubSkill.CallOfTheWild.Description=動物を召喚する。 -Taming.SubSkill.CallOfTheWild.Description.2=&7COTW: しゃがんで左クリック\n {0} {1} (猫), {2} {3} (Wolf), {4} {5} (馬) +Taming.SubSkill.CallOfTheWild.Description.2=&7COTW: しゃがんで左クリック\n {0} {1} (ヤマネコ), {2} {3} (オオカミ), {4} {5} (馬) Taming.SubSkill.FastFoodService.Name=ファーストフードサービス Taming.SubSkill.FastFoodService.Description=確率で狼が攻撃時回復する。 Taming.SubSkill.HolyHound.Name=ホーリーハウンド Taming.SubSkill.HolyHound.Description=魔法と毒で狼を回復する。 Taming.SubSkill.Gore.Name=流血 -Taming.SubSkill.Gore.Description=クリティかつ攻撃で破裂効果を与える。 +Taming.SubSkill.Gore.Description=クリティカル攻撃で破裂効果を与える。 Taming.SubSkill.SharpenedClaws.Name=鋭い爪 Taming.SubSkill.SharpenedClaws.Description=ダメージボーナス Taming.SubSkill.EnvironmentallyAware.Name=環境配慮 @@ -520,16 +595,16 @@ Unarmed.SubSkill.Berserk.Name=バーサーカー Unarmed.SubSkill.Berserk.Description=+50% ダメージ, 弱いマテリアルを壊す Unarmed.SubSkill.Berserk.Stat=バーサーカー 長さ Unarmed.SubSkill.Disarm.Name=武装解除 -Unarmed.SubSkill.Disarm.Description=敵のアイテムをドロップさせる。 +Unarmed.SubSkill.Disarm.Description=相手が手に持っているアイテムをドロップさせる。 Unarmed.SubSkill.Disarm.Stat=武装解除の確率 Unarmed.SubSkill.UnarmedLimitBreak.Name=素手 限界突破 Unarmed.SubSkill.UnarmedLimitBreak.Description=限界を破る。タフな敵に対するダメージが増加します。PvPを対象とし、PvEへの適応はサーバーの設定次第です。 -Unarmed.SubSkill.UnarmedLimitBreak.Stat=限界突破 追加ダメージ +Unarmed.SubSkill.UnarmedLimitBreak.Stat=限界突破 最大ダメージ Unarmed.SubSkill.SteelArmStyle.Name=スチールアームスタイル -Unarmed.SubSkill.SteelArmStyle.Description=時間が経つと腕が硬くなる +Unarmed.SubSkill.SteelArmStyle.Description=時が経つにつれて腕が硬くなる Unarmed.SubSkill.ArrowDeflect.Name=アローディフレクション Unarmed.SubSkill.ArrowDeflect.Description=矢をそらす。 -Unarmed.SubSkill.ArrowDeflect.Stat=矢をそらすの確率 +Unarmed.SubSkill.ArrowDeflect.Stat=矢をそらす確率 Unarmed.SubSkill.IronGrip.Name=アイアングリップ Unarmed.SubSkill.IronGrip.Description=武装解除されるのを防ぎます。 Unarmed.SubSkill.IronGrip.Stat=アイアングリップの確率 @@ -546,7 +621,7 @@ Unarmed.Skills.Berserk.Refresh=&eバーサーカー &aアビリティが回復 # WOODCUTTING Woodcutting.Ability.0=リーフブロワー Woodcutting.Ability.1=葉を吹き飛ばす -Woodcutting.Ability.Locked.0=ロックされるまで {0}+ スキル (リーフブロワー) +Woodcutting.Ability.Locked.0=スキルレベル {0}+ でロック解除 (リーフブロワー) Woodcutting.SubSkill.TreeFeller.Name=ツリーフェラー Woodcutting.SubSkill.TreeFeller.Description=木を爆発させる。 Woodcutting.SubSkill.TreeFeller.Stat=ツリーフェラー 長さ @@ -558,12 +633,15 @@ Woodcutting.SubSkill.KnockOnWood.Stat=ノックオンウッド Woodcutting.SubSkill.KnockOnWood.Loot.Normal=木からの標準的なアイテム Woodcutting.SubSkill.KnockOnWood.Loot.Rank2=木からの標準的なアイテムと経験値オーブ Woodcutting.SubSkill.HarvestLumber.Name=収穫材 -Woodcutting.SubSkill.HarvestLumber.Description=より多くの木材を巧みに抽出する。 -Woodcutting.SubSkill.HarvestLumber.Stat=ドロップ二倍の確率 -Woodcutting.SubSkill.Splinter.Name=破片 +Woodcutting.SubSkill.HarvestLumber.Description=木を伐採するときにドロップが2倍になる。 +Woodcutting.SubSkill.HarvestLumber.Stat=ドロップ2倍の確率 +Woodcutting.SubSkill.CleanCuts.Name=クリーンカット +Woodcutting.SubSkill.CleanCuts.Description=木を伐採するときにドロップが3倍になる。 +Woodcutting.SubSkill.CleanCuts.Stat=ドロップ3倍の確率 +Woodcutting.SubSkill.Splinter.Name=破砕 Woodcutting.SubSkill.Splinter.Description=より効率よく木を伐採する。 Woodcutting.SubSkill.BarkSurgeon.Name=樹皮外科医 -Woodcutting.SubSkill.BarkSurgeon.Description=木を剥ぎ取るときに有用な材料を抽出する。 +Woodcutting.SubSkill.BarkSurgeon.Description=樹皮を剥ぐときに有用な材料を抽出する。 Woodcutting.SubSkill.NaturesBounty.Name=自然の恵み Woodcutting.SubSkill.NaturesBounty.Description=自然から経験値を集める。 Woodcutting.Listener=木こり: @@ -581,12 +659,12 @@ Combat.ArrowDeflect=&f**矢をそらした** Combat.BeastLore=&a**ビーストロア** Combat.BeastLoreHealth=&3体力 (&a{0}&3/{1}) Combat.BeastLoreOwner=&3所有者 (&c{0}&3) -Combat.BeastLoreHorseSpeed=&3馬の移動速 (&a{0} ブロック/秒&3) +Combat.BeastLoreHorseSpeed=&3馬の移動速度 (&a{0} ブロック/秒&3) Combat.BeastLoreHorseJumpStrength=&3馬のジャンプ力 (&a最大 {0} ブロック&3) Combat.Gore=&a**流血** Combat.StruckByGore=**流血しています** -Combat.TargetDazed=ターゲットは&4幻惑[&rだった -Combat.TouchedFuzzy=&4Touched Fuzzy. Felt Dizzy. +Combat.TargetDazed=ターゲットは&4幻惑&rした +Combat.TouchedFuzzy=&4めまいがした # COMMANDS ## generic @@ -732,9 +810,9 @@ Commands.XPBar.SettingChanged=&6a{0} &6のXPバー設定を &a{1} に変更し Commands.Skill.Invalid=有効なスキル名ではありません! Commands.Skill.ChildSkill=このコマンドでは子スキルは無効です! Commands.Skill.Leaderboard=--mcMMO &9{0}&e リーダーボード-- -Commands.SkillInfo=&a- スキルに関する詳細情報を表示する -Commands.Stats=&a- mcMMOの統計を表示する -Commands.ToggleAbility=&a- 右クリックでアビリティを切り替える +Commands.SkillInfo=&3 / &a- スキルに関する詳細情報を表示する +Commands.Stats=&3 /mcstats &a- mcMMOの統計を表示する +Commands.ToggleAbility=&3 /mcability &a- 右クリックで有効化するアビリティのオン/オフを切り替える Commands.Usage.0=&c適切な使用法は /{0} Commands.Usage.1=&c適切な使用法は /{0} {1} Commands.Usage.2=&c適切な使用法は /{0} {1} {2} @@ -751,14 +829,14 @@ Commands.Usage.Rate=レート Commands.Usage.Skill=スキル Commands.Usage.SubSkill=サブスキル Commands.Usage.XP=xp -Commands.Description.mmoinfo=スキルまたはメカニックに関する詳細を読む +Commands.Description.mmoinfo=スキルまたはその仕組みに関する詳細を読む Commands.MmoInfo.Mystery=&7このスキルのロックはまだ解除されていませんが、解除するとここで詳細を読むことができます! Commands.MmoInfo.NoMatch=そのサブスキルは存在しません! Commands.MmoInfo.Header=&3-=[]=====[]&6 MMO 情報 &3[]=====[]=- Commands.MmoInfo.SubSkillHeader=&6名前:&e {0} Commands.MmoInfo.DetailsHeader=&3-=[]=====[]&a 詳細 &3[]=====[]=- -Commands.MmoInfo.OldSkill=&7mcMMOスキルは改善されたもジューラースキルシステムに変換されていますが、残念ながらこのスキルはまだ変換されていないため詳細な統計情報がありません。新しいシステムにより、新しいmcMMOスキルのリリース時間が短縮され、木依存のスキルとの柔軟性が向上します。 -Commands.MmoInfo.Mechanics=&3-=[]=====[]&6 力学 &3[]=====[]=- +Commands.MmoInfo.OldSkill=&7mcMMOスキルは改善されたもジューラースキルシステムに変換されていますが、残念ながらこのスキルはまだ変換されていないため詳細な統計情報がありません。新しいシステムにより、新しいmcMMOスキルのリリース時間が短縮され、既存のスキルとの柔軟性が向上します。 +Commands.MmoInfo.Mechanics=&3-=[]=====[]&6 仕組み &3[]=====[]=- Commands.MmoInfo.Stats=統計: {0} Commands.Mmodebug.Toggle=mcMMOデバッグモードは[0]になりました。このコマンドは再び使用することで切り替えられます。デバッグモードがtrueの場合、ブロックの叩いてサポートに使用される情報を出力できます。 mcMMO.NoInvites=&c現在、招待はありません。 @@ -768,7 +846,7 @@ mcMMO.NoSkillNote=&8スキルにアクセスできない場合は、ここには Party.Forbidden=[mcMMO] このワールドではパーティーが許可されていません(権限を参照) Party.Help.0=&c適切な使用法は &3{0} <プレイヤー> [パスワード] です。 Party.Help.1=&cパーティーを作成するには &3{0} <名称> [パスワード] を使用します。 -Party.Help.2=&c詳細は &3{0} &c に相談してください。 +Party.Help.2=&c詳細は &3{0} &c を参照してください。 Party.Help.3=&3{0} <プレイヤー> [パスワード] &cを使用して参加するか、&3{1} &cを使用して抜けます。 Party.Help.4=&cパーティーのロックまたはロック解除には、&3{0} &cを使用します。 Party.Help.5=&cパーティーをパスワードで保護するには、&3{0} <パスワード> &cを使用します。 @@ -820,11 +898,11 @@ Party.Feature.Teleport=パーティーテレポート Party.Feature.Alliance=同盟 Party.Feature.ItemShare=アイテム共有 Party.Feature.XpShare=XP共有 -Party.Feature.Locked.Chat=ロックされるまで {0}+ (パーティーチャット) -Party.Feature.Locked.Teleport=ロックされるまで {0}+ (パーティーテレポート) -Party.Feature.Locked.Alliance=ロックされるまで {0}+ (同盟) -Party.Feature.Locked.ItemShare=ロックされるまで {0}+ (アイテム共有) -Party.Feature.Locked.XpShare=ロックされるまで {0}+ (XP共有) +Party.Feature.Locked.Chat=スキルレベル {0}+ でロック解除 (パーティーチャット) +Party.Feature.Locked.Teleport=スキルレベル {0}+ でロック解除 (パーティーテレポート) +Party.Feature.Locked.Alliance=スキルレベル {0}+ でロック解除 (同盟) +Party.Feature.Locked.ItemShare=スキルレベル {0}+ でロック解除 (アイテム共有) +Party.Feature.Locked.XpShare=スキルレベル {0}+ でロック解除 (XP共有) Party.Feature.Disabled.1=&cパーティーチャットはまだ開放されていません。 Party.Feature.Disabled.2=&cパーティーテレポートはまだ開放されていません。 Party.Feature.Disabled.3=&c同盟はまだ開放されていません。 @@ -846,13 +924,16 @@ Commands.XPGain.Alchemy=ポーション醸造 Commands.XPGain.Archery=モンスターへの攻撃 Commands.XPGain.Axes=モンスターへの攻撃 Commands.XPGain.Child=親スキルからレベル獲得 +Commands.XPGain.Crossbows=モンスターへの攻撃 Commands.XPGain.Excavation=宝物を堀り、探す Commands.XPGain.Fishing=釣り -Commands.XPGain.Herbalism=ハーブの収穫 +Commands.XPGain.Herbalism=植物の収穫 +Commands.XPGain.Maces=モンスターへの攻撃 Commands.XPGain.Mining=鉱石と石の採掘 Commands.XPGain.Repair=修理 Commands.XPGain.Swords=モンスターへの攻撃 Commands.XPGain.Taming=動物を飼いならす、または狼と共に戦う +Commands.XPGain.Tridents=モンスターへの攻撃 Commands.XPGain.Unarmed=モンスターへの攻撃 Commands.XPGain.Woodcutting=木を切り倒す Commands.XPGain=&8XP獲得: &f{0} @@ -866,7 +947,7 @@ Commands.xprate.proper.2=&cxpイベントかを示すためにtrueまたはfalse Commands.NegativeNumberWarn=負の値を使わないでください。 Commands.Event.Start=&amcMMO&6 イベント! Commands.Event.Stop=&amcMMO&3 イベント終了! -Commands.Event.Stop.Subtitle=&a楽しんでくれたことを願ってます! +Commands.Event.Stop.Subtitle=&aお楽しみいただけたなら幸いです! Commands.Event.XP=&3XPレートは現在&6{0}&3x Commands.xprate.started.0=&6mcMMOのXPイベントが開始されました! Commands.xprate.started.1=&6mcMMOのXPレートは3倍になりました! @@ -916,8 +997,8 @@ Guides.Axes.Section.5=&3グレーターインパクトの効果は?\n&eYou hav ## Excavation Guides.Excavation.Section.0=&3掘削について:\n&eExcavation is the act of digging up dirt to find treasures.\n&eBy excavating the land you will find treasures.\n&eThe more you do this the more treasures you can find.\n\n&3XP GAIN:\n&eTo gain XP in this skill you must dig with a shovel in hand.\n&eOnly certain materials can be dug up for treasures and XP. Guides.Excavation.Section.1=&3互換性のあるブロック:\n&eGrass, Dirt, Sand, Clay, Gravel, Mycelium, Soul Sand, Snow -Guides.Excavation.Section.2=&3ギガドリルブレーカーを使うにはどうすればいいですか?:\n&eWith a shovel in hand right click to ready your tool.\n&eOnce in this state you have about 4 seconds to make\n&econtact with Excavation compatible materials this will\n&eactivate Giga Drill Breaker. -Guides.Excavation.Section.3=&3ギガドリルブレーカーとは?\n&eGiga Drill Breaker is an ability with a cooldown\n&etied to Excavation skill. It triples your chance\n&eof finding treasures and enables instant break\n&eon Excavation materials. +Guides.Excavation.Section.2=&3ギガドリルブレイカーを使うにはどうすればいいですか?:\n&eWith a shovel in hand right click to ready your tool.\n&eOnce in this state you have about 4 seconds to make\n&econtact with Excavation compatible materials this will\n&eactivate Giga Drill Breaker. +Guides.Excavation.Section.3=&3ギガドリルブレイカーとは?\n&eGiga Drill Breaker is an ability with a cooldown\n&etied to Excavation skill. It triples your chance\n&eof finding treasures and enables instant break\n&eon Excavation materials. Guides.Excavation.Section.4=&3考古学の効果は?\n&eEvery possible treasure for Excavation has its own\n&eskill level requirement for it to drop, as a result it's\n&edifficult to say how much it is helping you.\n&eJust keep in mind that the higher your Excavation skill\n&eis, the more treasures that can be found.\n&eAnd also keep in mind that each type of Excavation\n&ecompatible material has its own unique list of treasures.\n&eIn other words you will find different treasures in Dirt\nðan you would in Gravel. Guides.Excavation.Section.5=&3掘削についての注意事項:\n&eExcavation drops are completely customizeable\n&eSo results vary server to server. ## Fishing @@ -985,6 +1066,13 @@ Guides.Woodcutting.Section.0=&3木こりについて:\n&eWoodcutting is all ab Guides.Woodcutting.Section.1=&3ツリーフェラーの効果は?\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=&3リーフブロワーの効果は?\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=&3ドロップ二倍の効果は?\n&eThis passive ability gives you a chance to obtain an extra\n&eblock for every log you chop. +# Crossbows +Guides.Crossbows.Section.0=&3クロスボウについて:\n&eCrossbows is all about shooting with your crossbow.\n\n&3XP GAIN:\n&eXP is gained whenever you shoot mobs with a crossbow.\nThis is a WIP skill and more information will be added soon. +Guides.Crossbows.Section.1=&3トリックショットの効果は?\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=&3トライデントについて:\n&eTridents skill involves impaling foes with your trident.\n\n&3XP GAIN:\n&eXP is gained whenever you hit mobs with a trident.\nThis is a WIP skill and more information will be added soon. +# Maces +Guides.Maces.Section.0=&3メイスについて:\n&eMaces is all about smashing your foes with a mace.\n\n&3XP GAIN:\n&eXP is gained whenever you hit mobs with a mace.\nThis is a WIP skill and more information will be added soon. # INSPECT Inspect.Offline= &cあなたはオフラインプレイヤーを調べる権限を持っていません! @@ -1071,10 +1159,10 @@ MOTD.Website=&6[mcMMO] &a{0}&e - mcMMO ウェブサイト Smelting.SubSkill.UnderstandingTheArt.Name=芸術を理解する Smelting.SubSkill.UnderstandingTheArt.Description=洞窟の中で製錬に時間をかけ過ぎているかもしれません。\n製錬のさまざまな特性を強化します。 Smelting.SubSkill.UnderstandingTheArt.Stat=バニラXP Multiplier: &e{0}x -Smelting.Ability.Locked.0=ロックされるまで {0}+ スキル (バニラXPブースト) -Smelting.Ability.Locked.1=ロックされるまで {0}+ スキル (フラックスマイニング) +Smelting.Ability.Locked.0=スキルレベル {0}+ でロック解除 (バニラXPブースト) +Smelting.Ability.Locked.1=スキルレベル {0}+ でロック解除 (フラックスマイニング) Smelting.SubSkill.FuelEfficiency.Name=燃料効率 -Smelting.SubSkill.FuelEfficiency.Description=製錬時に竈で使用する燃料の燃焼時間を長くする。 +Smelting.SubSkill.FuelEfficiency.Description=製錬時にかまどで使用する燃料の燃焼時間を長くする。 Smelting.SubSkill.FuelEfficiency.Stat=燃料効率 乗数: &e{0}x Smelting.SubSkill.SecondSmelt.Name=第二精錬 Smelting.SubSkill.SecondSmelt.Description=製錬から得たアイテムを2倍にする。 @@ -1082,7 +1170,7 @@ Smelting.SubSkill.SecondSmelt.Stat=第二精錬の確率 Smelting.Effect.4=バニラXPブースト Smelting.Effect.5=製錬中に得られるバニラXPを増やす。 Smelting.SubSkill.FluxMining.Name=フラックスマイニング -Smelting.SubSkill.FluxMining.Description=確率で採掘した鉱物が生産されます。 +Smelting.SubSkill.FluxMining.Description=確率で採掘した鉱物が即座に製錬されます。 Smelting.SubSkill.FluxMining.Stat=フラックスマイニングの確率 Smelting.Listener=精錬: Smelting.SkillName=精錬 @@ -1174,4 +1262,6 @@ Chat.Channel.Off=&6(&amcMMO-チャット&6) &7あなたのチャットメッセ Chat.Spy.Party=&6[&eSPY&6-&a{2}&6] &r{0} &b→ &r{1} Broadcasts.LevelUpMilestone=&6(&amcMMO&6) {0} &7が &3{2} でレベル &a{1} &7に到達しました! Broadcasts.PowerLevelUpMilestone=&6(&amcMMO&6) {0}&7 のパワーレベルが &a{1} &7に到達しました! -Scoreboard.Recovery=mcMMOのスコアボードを復元しようとしています... \ No newline at end of file +Scoreboard.Recovery=mcMMOのスコアボードを復元しようとしています... +Scoreboard.Disabled=このサーバーではmcMMOのスコアボードが無効化されています。設定はmcMMO/config.ymlにあります。 +Scoreboard.NotSetupYet=mcMMOスコアボードはまだセットアップされていません。しばらくお待ちください。 diff --git a/src/main/resources/locale/locale_ko.properties b/src/main/resources/locale/locale_ko.properties index 5eabe51e2..555313433 100644 --- a/src/main/resources/locale/locale_ko.properties +++ b/src/main/resources/locale/locale_ko.properties @@ -1,60 +1,49 @@ # korean locale file v2.0 # ----------------- -# Setting up a new standard for string names, for easier localization. -# SkillName.SubType.LocalEffect.Increment -# Skill name, such as ACROBATICS, MINING. -# Sub-type, such as EFFECT, ABILITY, COMBAT. -# Local Effect, local text for Skill Name; ACROBATICS_ROLL, IGNITIONTIME,GRACECHANCE. -# Increment, for multi-line or array-like lists. -# ###### -# -# EXAMPLES: -# -# Acrobatics.Ability.Proc -# Axes.Ability.Refresh.1 -# -# --wolfwork +# Work : MangChi__ / JJangGu +#로케일 파일을 정규화하려고 합니다. 지금은 혼란스러운 점을 용서해 주세요. +# TODO: 16진수를 지원하도록 JSON을 업데이트합니다. -#DO NOT USE COLOR CODES IN THE JSON KEYS -#COLORS ARE DEFINED IN advanced.yml IF YOU WISH TO CHANGE THEM -JSON.Rank=랭크 +#JSON 키에 색상 코드를 사용하지 마세요. +#색상을 변경하려는 경우에는 Advanced.yml에 정의되어 있습니다. +JSON.Rank=등급 JSON.DescriptionHeader=설명 JSON.JWrapper.Header=세부 정보 -JSON.Type.Passive=패시브 -JSON.Type.Active=액티브 +JSON.Type.Passive=수동적 +JSON.Type.Active=능동적 JSON.Type.SuperAbility=슈퍼 능력 -JSON.Locked=-=[해금되지 않음]=- +JSON.Locked=-=[잠김]=- JSON.LevelRequirement=레벨 요구 사항 JSON.JWrapper.Target.Type=대상 유형: JSON.JWrapper.Target.Block=블록 JSON.JWrapper.Target.Player=플레이어 -JSON.JWrapper.Perks.Header=&6행운 퍽 +JSON.JWrapper.Perks.Header=&6운이 좋은 특성 JSON.JWrapper.Perks.Lucky={0}% 더 좋은 확률 JSON.Hover.Tips=팁 JSON.Acrobatics=곡예 JSON.Alchemy=연금술 -JSON.Archery=궁술 -JSON.Axes=부술 -JSON.Excavation=발굴 +JSON.Archery=활쏘기 +JSON.Axes=참수 +JSON.Excavation=파괴 JSON.Fishing=낚시 -JSON.Herbalism=약초학 +JSON.Herbalism=약초 채집 JSON.Mining=채광 JSON.Repair=수리 -JSON.Salvage=회수 +JSON.Salvage=분해 JSON.Swords=검술 -JSON.Taming=조련 -JSON.Unarmed=비무장 -JSON.Woodcutting=벌목 -JSON.URL.Website=mcMMO 공식 웹사이트! -JSON.URL.Discord=mcMMO 공식 디스코드 서버! -JSON.URL.Patreon=nossr50와 mcMMO를 위한 Patreon에서 지원하세요! -JSON.URL.Spigot=mcMMO 공식 Spigot 리소스 페이지! +JSON.Taming=길들이기 +JSON.Unarmed=맨손전투 +JSON.Woodcutting=나무 베기 +JSON.URL.Website=공식 mcMMO 웹사이트! +JSON.URL.Discord=공식 mcMMO 디스코드 서버! +JSON.URL.Patreon=nossr50과 mcMMO에 대한 작업을 Patreon에서 지원하세요! +JSON.URL.Spigot=공식 mcMMO Spigot 리소스 페이지! JSON.URL.Translation=mcMMO를 다른 언어로 번역하세요! -JSON.URL.Wiki=mcMMO 공식 위키! -JSON.SkillUnlockMessage=&6[ mcMMO&e @&3{0} &6랭크 &3{1}&6이(가) 해제되었습니다! ] -JSON.Hover.Rank=&e&l랭크:&r &f{0} +JSON.URL.Wiki=공식 mcMMO 위키! +JSON.SkillUnlockMessage=&6[ mcMMO&e @&3{0} &6등급 &3{1}&6 해제되었습니다! ] +JSON.Hover.Rank=&e&l등급:&r &f{0} JSON.Hover.NextRank=&7&o다음 업그레이드: 레벨 {0} -# for JSON.Hover.Mystery you can add {0} to insert the level required into the name, I don't like how that looks so I'm not doing that atm +# JSON.Hover.Mystery에 {0}을 추가하여 필요한 레벨을 이름에 삽입할 수 있지만, 현재는 사용하지 않습니다. JSON.Hover.Mystery=&7??? JSON.Hover.Mystery2=&e[&8{0}&e]&8???&r JSON.Hover.SkillName=&3{0}&r @@ -63,29 +52,27 @@ JSON.Hover.MaxRankSkillName=&6{0}&r JSON.Hover.AtSymbolSkills=&e@ JSON.Hover.AtSymbolURL=&e@ -#This is the message sent to players when an ability is activated +# 능력이 활성화될 때 플레이어에게 전송되는 메시지입니다. JSON.Notification.SuperAbility={0} -#These are the JSON Strings used for SubSkills -JSON.Acrobatics.Roll.Interaction.Activated=테스트 &c구른 테스트 -JSON.Acrobatics.SubSkill.Roll.Details.Tips=낙하 중 웅크리기 키를 누르면 일반적으로 받을 데미지의 2배까지 방지할 수 있습니다! -Anvil.SingleItemStack=&c하나 이상의 아이템을 가진 아이템 스택은 회수하거나 수리할 수 없습니다. 먼저 스택을 분할하세요. +# 하위 스킬에 사용되는 JSON 문자열입니다. +JSON.Acrobatics.Roll.Interaction.Activated=테스트 &c굴러가기 테스트 +JSON.Acrobatics.SubSkill.Roll.Details.Tips=낙하 중에 스프린트 키를 누르면 일반적으로 받을 데미지의 최대 2배까지 예방할 수 있습니다! +Anvil.SingleItemStack=&c한 개 이상의 아이템이 있는 아이템 스택은 분해하거나 수리할 수 없습니다. 먼저 스택을 나누세요. -#DO NOT USE COLOR CODES IN THE JSON KEYS -#COLORS ARE DEFINED IN advanced.yml IF YOU WISH TO CHANGE THEM +#JSON 키에 색상 코드를 사용하지 마세요. +#색상을 변경하려는 경우에는 Advanced.yml에 정의되어 있습니다. mcMMO.Template.Prefix=&6(&amcMMO&6) &7{0} - -# BEGIN STYLING -Ability.Generic.Refresh=&a**능력이 갱신되었습니다!** +# 스타일링 시작 +Ability.Generic.Refresh=&a**능력 갱신됨!** Ability.Generic.Template.Lock=&7{0} - -# Skill Command Styling +# 스킬 명령어 스타일링 Ability.Generic.Template=&3{0}: &a{1} Ability.Generic.Template.Custom=&3{0} Skills.Overhaul.Header=&c[]=====[]&a {0} &c[]=====[] Effects.Effects=효과 -Effects.SubSkills.Overhaul=부가 스킬 +Effects.SubSkills.Overhaul=하위 스킬 Effects.Child.Overhaul=&3하위 레벨.&e {0}&3: {1} Effects.Child.ParentList=&a{0}&6(&3레벨.&e{1}&6) Effects.Level.Overhaul=&6레벨: &e{0} &3경험치&e(&6{1}&e/&6{2}&e) @@ -93,1197 +80,1077 @@ Effects.Parent=&6{0} - Effects.Template=&3{0}: &a{1} Commands.Stats.Self.Overhaul=스탯 Commands.XPGain.Overhaul=&6경험치 획득: &3{0} -MOTD.Version.Overhaul=&6[mcMMO] &3Overhaul 시대&6 - &3{0} -Overhaul.mcMMO.Header=&c[]=====[]&a mcMMO - Overhaul 시대 &c[]=====[] +MOTD.Version.Overhaul=&6[mcMMO] &3오버홀 시대&6 - &3{0} +Overhaul.mcMMO.Header=&c[]=====[]&a mcMMO - 오버홀 시대 &c[]=====[] Overhaul.mcMMO.Url.Wrap.Prefix=&c[| Overhaul.mcMMO.Url.Wrap.Suffix=&c|] -Overhaul.mcMMO.MmoInfo.Wiki=&e[&f이 스킬을 위키에서 보기!&e] - +Overhaul.mcMMO.MmoInfo.Wiki=&e[&f이 스킬을 위키에서 확인하세요!&e] +# Overhaul.Levelup can take {0} - Skill Name defined in Overhaul.Name {1} - Amount of levels gained {2} - Level in skill +Overhaul.Levelup=&l{0} 능력이 증가하여 &r&a&l{2}&r&f이 되었습니다. +Overhaul.Name.Acrobatics=곡예 +Overhaul.Name.Alchemy=연금술 +Overhaul.Name.Archery=활쏘기 +Overhaul.Name.Axes=참수 +Overhaul.Name.Excavation=파괴 +Overhaul.Name.Fishing=낚시 +Overhaul.Name.Herbalism=약초 채집 +Overhaul.Name.Mining=채광 +Overhaul.Name.Repair=수리 +Overhaul.Name.Salvage=분해 +Overhaul.Name.Smelting=제련 +Overhaul.Name.Swords=검술 +Overhaul.Name.Taming=길들이기 +Overhaul.Name.Unarmed=맨손 전투 +Overhaul.Name.Woodcutting=벌목 # /mcMMO Command Style Stuff Commands.mcc.Header=&c---[]&amcMMO 명령어&c[]--- Commands.Other=&c---[]&a특수 명령어&c[]--- Commands.Party.Header=&c-----[]&a파티&c[]----- Commands.Party.Features.Header=&c-----[]&a기능&c[]----- -# XP BAR Allows for the following variables -- {0} = Skill Level, {1} Current XP, {2} XP Needed for next level, {3} Power Level, {4} Percentage of Level -# Make sure you turn on Experience_Bars.ThisMayCauseLag.AlwaysUpdateTitlesWhenXPIsGained if you want the XP bar title to update every time a player gains XP! +# XP 바는 다음 변수를 사용할 수 있습니다. -- {0} = 스킬 레벨, {1} 현재 경험치, {2} 다음 레벨까지 필요한 경험치, {3} 파워 레벨, {4} 레벨의 백분율 +# XP 바 제목이 플레이어가 경험치를 획득할 때마다 업데이트되기를 원한다면 Experience_Bars.ThisMayCauseLag.AlwaysUpdateTitlesWhenXPIsGained를 켜주세요! XPBar.Template={0} -XPBar.Template.EarlyGameBoost=&6새로운 스킬을 습득하는 중... -XPBar.Acrobatics=곡예 Lv.&6{0} -XPBar.Alchemy=연금술 Lv.&6{0} -XPBar.Archery=궁술 Lv.&6{0} -XPBar.Axes=부술 Lv.&6{0} -XPBar.Excavation=발굴 Lv.&6{0} -XPBar.Fishing=낚시 Lv.&6{0} -XPBar.Herbalism=약초학 Lv.&6{0} -XPBar.Mining=채광 Lv.&6{0} -XPBar.Repair=수리 Lv.&6{0} -XPBar.Salvage=회수 Lv.&6{0} -XPBar.Smelting=제련 Lv.&6{0} -XPBar.Swords=검술 Lv.&6{0} -XPBar.Taming=조련 Lv.&6{0} -XPBar.Unarmed=비무장 Lv.&6{0} -XPBar.Woodcutting=벌목 Lv.&6{0} +XPBar.Template.EarlyGameBoost=&6새로운 스킬 배움 중... +XPBar.Acrobatics=곡예 레벨 &6{0} +XPBar.Alchemy=연금술 레벨 &6{0} +XPBar.Archery=활쏘기 레벨 &6{0} +XPBar.Axes=참수 레벨 &6{0} +XPBar.Excavation=파괴 레벨 &6{0} +XPBar.Fishing=낚시 레벨 &6{0} +XPBar.Herbalism=약초 채집 레벨 &6{0} +XPBar.Mining=채광 레벨 &6{0} +XPBar.Repair=수리 레벨 &6{0} +XPBar.Salvage=분해 레벨 &6{0} +XPBar.Smelting=제련 레벨 &6{0} +XPBar.Swords=검술 레벨 &6{0} +XPBar.Taming=길들이기 레벨 &6{0} +XPBar.Unarmed=맨손 전투 레벨 &6{0} +XPBar.Woodcutting=벌목 레벨 &6{0} +#이것은 experience.yml에서 'ExtraDetails' 설정이 켜져 있는 경우(기본적으로 꺼져 있음) 사용되는 미리 설정된 템플릿일 뿐입니다. 이 템플릿을 무시하고 위의 문자열만 편집하면 됩니다. XPBar.Complex.Template={0} &3 {4}&f% &3(&f{1}&3/&f{2}&3) -#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 -XPBar.Complex.Template={0} &3 {4}&f% &3(&f{1}&3/&f{2}&3) -# XP BAR Allows for the following variables -- {0} = Skill Level, {1} Current XP, {2} XP Needed for next level, {3} Power Level, {4} Percentage of Level -# Make sure you turn on Experience_Bars.ThisMayCauseLag.AlwaysUpdateTitlesWhenXPIsGained if you want the XP bar title to update every time a player gains XP! -# END STYLING +# XP 바는 다음 변수를 사용할 수 있습니다. -- {0} = 스킬 레벨, {1} 현재 경험치, {2} 다음 레벨까지 필요한 경험치, {3} 파워 레벨, {4} 레벨의 백분율 +# XP 바 제목이 플레이어가 경험치를 획득할 때마다 업데이트되기를 원한다면 Experience_Bars.ThisMayCauseLag.AlwaysUpdateTitlesWhenXPIsGained를 켜주세요! +# 스타일링 끝 - -#ACROBATICS -Acrobatics.SubSkill.Roll.Stats=&6구르기 확률 &e{0}%&6 우아한 구르기 확률&e {1}% -Acrobatics.SubSkill.Roll.Stat=구르기 확률 -Acrobatics.SubSkill.Roll.Stat.Extra=우아한 구르기 확률 -Acrobatics.SubSkill.Roll.Chance=구르기 확률: &e{0} -Acrobatics.SubSkill.Roll.Mechanics=&7구르기는 수동적인 부분이 있는 능력입니다.\n낙하 데미지를 입을 때마다, 당신은 당신의 능력 레벨에 따라 데미지를 완전히 무효화할 수 있습니다. 능력 레벨이 &e{6}%&7일 때, 당신은 &e{0}%&7의 확률로 데미지를 무효화할 수 있으며, 우아한 구르기를 활성화하면 &e{1}%&7의 확률로 데미지를 무효화할 수 있습니다.\n성공 확률은 능력 레벨에 따라 선형적으로 조정되며, 능력 레벨 &e{2}&7에서 최대치에 도달합니다. 곡예 능력을 1 레벨 올릴 때마다 &e{3}%&7의 확률이 증가합니다.\n웅크리기 버튼을 누르면 구르기 확률이 2배가 되며, 데미지를 2배로 감소시킬 수 있습니다. 웅크리기를 누르면 일반적인 구르기가 우아한 구르기로 변합니다.\n구르기는 최대 &c{4}&7의 데미지를 무효화합니다. 우아한 구르기는 최대 &a{5}&7의 데미지를 무효화합니다. -Acrobatics.SubSkill.GracefulRoll.Name=우아한 구르기 -Acrobatics.SubSkill.Dodge.Stat=구르기 확률 -Acrobatics.Ability.Proc=&a**우아한 구르기** -Acrobatics.Combat.Proc=&a**회피** -Acrobatics.DodgeChance=회피 확률: &e{0} -Acrobatics.SubSkill.Roll.Name=구르기 -Acrobatics.SubSkill.Roll.Description=추락 데미지 감소 또는 무효 -Acrobatics.SubSkill.GracefulRoll.Name=우아한 구르기 -Acrobatics.SubSkill.GracefulRoll.Description=구르기 2배 효과 +#재주 넘기 +Acrobatics.Ability.Proc=&a**용아치** (Graceful Landing) +Acrobatics.Combat.Proc=&a**회피** (Dodged) +Acrobatics.SubSkill.Roll.Stats=&6Roll 확률 &e{0}%&6 우아한 Roll 확률 &e{1}% +Acrobatics.SubSkill.Roll.Stat=Roll 확률 +Acrobatics.SubSkill.Roll.Stat.Extra=우아한 Roll 확률 +Acrobatics.SubSkill.Roll.Name=Roll +Acrobatics.SubSkill.Roll.Description=전략적으로 착지하여 피해를 피합니다. +Acrobatics.SubSkill.Roll.Chance=Roll 확률: &e{0} +Acrobatics.SubSkill.Roll.GraceChance=우아한 Roll 확률: &e{0} +Acrobatics.SubSkill.Roll.Mechanics=&7Roll은 수동 구성 요소가 있는 능동적인 하위 기술입니다.\n낙하 피해를 입을 때마다 기술 레벨에 따라 피해를 완전히 무효화할 기회가 있습니다. 레벨 &e{6}%&7에서 피해를 방지할 확률은 &e{0}%&7이며, 우아한 Roll을 활성화하면 &e{1}%&7입니다.\n성공 확률은 능력 레벨에 따라 선형 곡선으로 조정되며, 능력이 있는 Acrobatics 레벨마다 &e{3}%&7의 성공 확률이 주어집니다.\n스니크 버튼을 누르면 낙하 피해를 피하는 기회가 두 배로 늘어나며, 최대 2배의 낙하 피해를 피할 수 있습니다! 스니크를 누르면 일반적인 Roll이 우아한 Roll로 변합니다.\nRoll은 최대 &c{4}&7의 피해를 방지할 수 있으며, 우아한 Roll은 최대 &a{5}&7의 피해를 방지할 수 있습니다. +Acrobatics.SubSkill.GracefulRoll.Name=우아한 Roll +Acrobatics.SubSkill.GracefulRoll.Description=일반 Roll의 2배 효과적인 기술 Acrobatics.SubSkill.Dodge.Name=회피 -Acrobatics.SubSkill.Dodge.Description=낙하 데미지 절반 감소 -Acrobatics.Listener=곡예(ACROBATICS): -Acrobatics.SubSkill.Roll.Chance=구르기 확률: &e{0} -Acrobatics.SubSkill.Roll.GraceChance=우아한 구르기 확률: &e{0} -Acrobatics.Roll.Text=**구르기** +Acrobatics.SubSkill.Dodge.Description=공격 피해를 절반으로 줄입니다. +Acrobatics.SubSkill.Dodge.Stat=회피 확률 +Acrobatics.Listener=곡예: +Acrobatics.Roll.Text=&o**Roll 사용** Acrobatics.SkillName=곡예 -Acrobatics.Skillup=낙법 기술이 {0} 올라 총 {1} 레벨이 되었습니다 -#ALCHEMY -Alchemy.SubSkill.Catalysis.Name=촉매 -Alchemy.SubSkill.Catalysis.Description=포션 양조 속도 증가 -Alchemy.SubSkill.Concoctions.Name=혼합 -Alchemy.SubSkill.Concoctions.Description=더 많은 성분의 포션 양조 -Alchemy.Listener=연금술(ALCHEMY): -Alchemy.Ability.Locked.0={0}레벨 때 기술해제 (촉매) -Alchemy.Catalysis.Speed=양조 속도: &e{0} -Alchemy.Concoctions.Rank=혼합 랭크: &e{0}/{1} -Alchemy.Concoctions.Ingredients=성분 [&e{0}&c]: &e{1} -Alchemy.SkillName=연금술 -Alchemy.Skillup=연금술 기술이 {0} 올라 총 {1} 레벨이 되었습니다 -Alchemy.SubSkill.Catalysis.Stat=양조 속도 -Alchemy.SubSkill.Concoctions.Stat=혼합 랭크: &a{0}&3/&a{1} -Alchemy.SubSkill.Concoctions.Stat.Extra=성분 [&a{0}&3]: &a{1} -Alchemy.Ability.Locked.0={0}+ 레벨에서 해금됩니다 (촉매) +#연금술 +Alchemy.SubSkill.Catalysis.Name=촉매작용 +Alchemy.SubSkill.Catalysis.Description=포션 제조 속도를 증가시킵니다. +Alchemy.SubSkill.Catalysis.Stat=포션 제조 속도 +Alchemy.SubSkill.Concoctions.Name=조합 +Alchemy.SubSkill.Concoctions.Description=더 많은 재료로 포션을 제조합니다. +Alchemy.SubSkill.Concoctions.Stat=조합 순위: &a{0}&3/&a{1} +Alchemy.SubSkill.Concoctions.Stat.Extra=재료 [&a{0}&3]: &a{1} +Alchemy.Listener=연금술: +Alchemy.Ability.Locked.0={0}+ SKILL (CATALYSIS)까지 잠금 Alchemy.SkillName=연금술 -#ARCHERY -Archery.Combat.DazeChance=현혹 확률: &e{0} -Archery.Combat.RetrieveChance=화살 회수 확률: &e{0} -Archery.Combat.SkillshotBonus=쏘기 솜씨 추가 피해 확률: &e{0} -Archery.SubSkill.SkillShot.Name=쏘기 솜씨 -Archery.SubSkill.SkillShot.Description=활 피해 영구 증가 -Archery.SubSkill.Daze.Name=현혹 (플레이어) -Archery.SubSkill.Daze.Description=적에게 혼란, {0} 피해 추가 +#양궁 +Archery.SubSkill.SkillShot.Name=스킬 사격 +Archery.SubSkill.SkillShot.Description=활로 입히는 피해량을 증가시킵니다. +Archery.SubSkill.SkillShot.Stat=스킬 사격 추가 피해 +Archery.SubSkill.Daze.Name=혼란시키기 +Archery.SubSkill.Daze.Description=상대를 혼란시키고 추가 피해를 입힙니다. +Archery.SubSkill.Daze.Stat=혼란 확률 Archery.SubSkill.ArrowRetrieval.Name=화살 회수 -Archery.SubSkill.ArrowRetrieval.Description=시체에서 화살 회수 확률 증가 -Archery.Listener=궁술(ARCHERY): -Archery.SkillName=궁술 -Archery.Skillup=궁술 기술이 {0} 올라 총 {1} 레벨이 되었습니다 -Archery.SubSkill.SkillShot.Stat=스킬샷 추가 피해 -Archery.SubSkill.Daze.Stat=현혹 확률 +Archery.SubSkill.ArrowRetrieval.Description=시체에서 화살을 회수할 확률이 있습니다. Archery.SubSkill.ArrowRetrieval.Stat=화살 회수 확률 -Archery.SubSkill.ArcheryLimitBreak.Name=궁술 한계 돌파 -Archery.SubSkill.ArcheryLimitBreak.Description=한계 돌파. 강한 적에게 추가 피해를 줍니다. PVP를 위해 만들어졌으며, PVE에서 추가 피해를 줄지는 서버 설정에 따라 다릅니다. -Archery.SubSkill.ArcheryLimitBreak.Stat=한계 돌파 최대 피해 +Archery.SubSkill.ArcheryLimitBreak.Name=양궁 한계 극복 +Archery.SubSkill.ArcheryLimitBreak.Description=한계를 극복합니다. 강력한 상대에 대한 피해량이 증가합니다. PVP용으로 적용되며, PVE에서 피해량을 증가시킬지는 서버 설정에 따릅니다. +Archery.SubSkill.ArcheryLimitBreak.Stat=한계 극복 최대 피해량 +Archery.Listener=양궁: +Archery.SkillName=양궁 - -#AXES -Axes.Ability.Bonus.0=도끼 마스터리 -Axes.Ability.Bonus.1={0} 추가 피해 -Axes.Ability.Bonus.2=갑옷 충격 -Axes.Ability.Bonus.3=방어구 추가 피해: {0} -Axes.Ability.Bonus.4=엄청난 충격 -Axes.Ability.Bonus.5=비무장 추가 피해: {0} -Axes.Ability.Lower=&7**도끼 준비 해제** -Axes.Ability.Ready=&a**도끼 준비 완료** -Axes.Combat.CritStruck=&4크리티컬 히트에 맞았습니다! -Axes.Combat.CritChance=크리티컬 히트 확률: &e{0} -Axes.Combat.CriticalHit=크리티컬 히트! -Axes.Combat.GI.Proc=&a**최고의 강타를 때렸습니다** -Axes.Combat.GI.Struck=**엄청난 충격을 받았습니다** -Axes.Combat.SS.Struck=&4뼈 쪼개기에 맞았습니다! -Axes.Combat.SS.Length=뼈 쪼개기 지속시간: &e{0}초 -Axes.SubSkill.SkullSplitter.Name=뼈 쪼개기 (능력) -Axes.SubSkill.SkullSplitter.Description=광역 추가 피해 -Axes.SubSkill.CriticalStrikes.Name=크리티컬 스트라이크 -Axes.SubSkill.CriticalStrikes.Description=피해 2배 -Axes.SubSkill.AxeMastery.Name=도끼 마스터리 -Axes.SubSkill.AxeMastery.Description=추가 특혜 피해 -Axes.SubSkill.ArmorImpact.Name=갑옷 충격 -Axes.SubSkill.ArmorImpact.Description=갑옷 파괴 공격 -Axes.SubSkill.GreaterImpact.Name=엄청난 충격 -Axes.SubSkill.GreaterImpact.Description=비무장 추가 피해 -Axes.Listener=부술(AXES): -Axes.SkillName=부술 -Axes.Skills.SS.Off=**뼈 쪼개기 발동 해제** -Axes.Skills.SS.On=&a**뼈 쪼개기 발동** -Axes.Skills.SS.Refresh=&a당신의 &e뼈 쪼개기 &a기술은 이제 사용 가능합니다! -Axes.Skills.SS.Other.Off={0}님이 &c뼈 쪼개기를&a 준비 해제했습니다 -Axes.Skills.SS.Other.On=&a{0}&2님이 &c뼈 쪼개기를 사용했습니다! -Axes.Skillup=부술 기술이 {0} 올라 총 ({1}) 레벨이 되었습니다 -Axes.Ability.Ready.Extra=도끼 준비 완료. &7({0}은 {1}초 동안 쿨타임 중입니다) -Axes.SubSkill.SkullSplitter.Stat=뼈 쪼개기 지속시간 -Axes.SubSkill.CriticalStrikes.Stat=크리티컬 스트라이크 확률 -Axes.SubSkill.AxesLimitBreak.Name=도끼 한계 돌파 -Axes.SubSkill.AxesLimitBreak.Description=한계를 돌파합니다. 강한 상대에 대한 추가 피해가 증가합니다. PVP를 위해 만들어졌으며, PVE에서 추가 피해를 줄지는 서버 설정에 따라 다릅니다. +#참수 +Axes.Ability.Bonus.0=도끼 숙련 +Axes.Ability.Bonus.1=추가 {0} 피해 +Axes.Ability.Bonus.2=방어구 타격 +Axes.Ability.Bonus.3={0} 추가 피해를 방어구에 입힙니다. +Axes.Ability.Bonus.4=강력한 타격 +Axes.Ability.Bonus.5={0} 추가 피해를 방어구가 없는 적에게 입힙니다. +Axes.Ability.Lower=&7도끼를 내려놓습니다. +Axes.Ability.Ready=&3도끼를 &6준비&3합니다. +Axes.Ability.Ready.Extra=&3참수를 &6준비&3합니다. &7({0}이(가) {1}초 동안 재사용 대기 중입니다) +Axes.Combat.CritStruck=&4치명적으로 맞았습니다! +Axes.Combat.CriticalHit=치명타! +Axes.Combat.GI.Proc=&a**강력한 힘으로 타격받았습니다** +Axes.Combat.GI.Struck=**강력한 타격으로 맞았습니다** +Axes.Combat.SS.Struck=&4해골 분쇄로 맞았습니다! +Axes.SubSkill.SkullSplitter.Name=해골 분쇄 +Axes.SubSkill.SkullSplitter.Description=광역 피해를 입힙니다. +Axes.SubSkill.SkullSplitter.Stat=해골 분쇄 지속 시간 +Axes.SubSkill.CriticalStrikes.Name=치명타 +Axes.SubSkill.CriticalStrikes.Description=두 배의 피해를 입힙니다. +Axes.SubSkill.CriticalStrikes.Stat=치명타 확률 +Axes.SubSkill.AxeMastery.Name=참수 숙련 +Axes.SubSkill.AxeMastery.Description=추가 피해를 입힙니다. +Axes.SubSkill.AxesLimitBreak.Name=참수 한계 돌파 +Axes.SubSkill.AxesLimitBreak.Description=한계를 돌파합니다. 강력한 적에 대한 추가 피해가 증가합니다. PVP를 위해 설계되었으며, PVE에서의 추가 피해 증가 여부는 서버 설정에 따릅니다. Axes.SubSkill.AxesLimitBreak.Stat=한계 돌파 최대 피해 - -#EXCAVATION -Excavation.Ability.Lower=&7**삽 준비 해제** -Excavation.Ability.Ready=&a**삽 준비 완료** -Excavation.SubSkill.GigaDrillBreaker.Name=기가 드릴 버서커 (능력) -Excavation.SubSkill.GigaDrillBreaker.Description=드롭 속도 3배, 경험치 3배, 속도 증가 -Excavation.SubSkill.TreasureHunter.Name=보물 사냥꾼 -Excavation.SubSkill.TreasureHunter.Description=보물 발굴 능력 -Excavation.Effect.Length=기가 드릴 버서커 지속시간: &e{0}초 -Excavation.Listener=발굴(EXCAVATION): -Excavation.SkillName=발굴 -Excavation.Skills.GigaDrillBreaker.Off=**기가 드릴 버서커 발동 해제** -Excavation.Skills.GigaDrillBreaker.On=&a**기가 드릴 버서커 발동** -Excavation.Skills.GigaDrillBreaker.Refresh=&a당신의 &e기가 드릴 버서커 &a기술은 이제 사용 가능합니다! -Excavation.Skills.GigaDrillBreaker.Other.Off={0}&2님은 &c기가 드릴 버서커를 사용했습니다! -Excavation.Skills.GigaDrillBreaker.Other.On=&a{0}&2님은 &c기가 드릴 버서커를 사용 했습니다! -Excavation.Skillup=발굴 기술이 {0} 올라 총 {1} 레벨이 되었습니다 -Excavation.SubSkill.GigaDrillBreaker.Stat=기가 드릴 버서커 지속시간 +Axes.SubSkill.ArmorImpact.Name=방어구 타격 +Axes.SubSkill.ArmorImpact.Description=충분한 힘으로 방어구를 깨뜨립니다. +Axes.SubSkill.GreaterImpact.Name=강력한 타격 +Axes.SubSkill.GreaterImpact.Description=방어구가 없는 적에게 추가 피해를 입힙니다. +Axes.Listener=참수: +Axes.SkillName=참수 +Axes.Skills.SS.Off=**해골 분쇄 효과가 사라졌습니다** +Axes.Skills.SS.On=&a**해골 분쇄 활성화됨** +Axes.Skills.SS.Refresh=&a해당 &e해골 분쇄 &a기술이 회복되었습니다! +Axes.Skills.SS.Other.Off=해골 분쇄&a 효과가 &e{0}에게서 사라졌습니다 +Axes.Skills.SS.Other.On=&a{0}&2이(가) &c해골 분쇄를 사용했습니다! +#발굴 +Excavation.Ability.Lower=&7삽을 내려놓습니다. +Excavation.Ability.Ready=&3삽을 &6준비&3합니다. +Excavation.SubSkill.GigaDrillBreaker.Name=기가 드릴 브레이커 +Excavation.SubSkill.GigaDrillBreaker.Description=드롭 확률 3배, 경험치 3배, 속도 증가 +Excavation.SubSkill.GigaDrillBreaker.Stat=기가 드릴 브레이커 지속 시간 Excavation.SubSkill.Archaeology.Name=고고학 -Excavation.SubSkill.Archaeology.Description=땅의 비밀을 발굴하세요! 높은 기술 레벨은 보물을 찾을 때 경험치 구슬을 찾을 확률을 높입니다! -Excavation.SubSkill.Archaeology.Stat=고고학 경험치 구슬 확률 -Excavation.SubSkill.Archaeology.Stat.Extra=고고학 경험치 구슬량 - -#FISHING -Fishing.Ability.Chance=입질 확률: &e{0} -Fishing.Ability.Info=매직 헌터: &7 **트레져 헌터 랭크 향상** -Fishing.Ability.Locked.0={0}레벨 때 기술 해제 (흔들기) -Fishing.Ability.Locked.1={0}레벨 때 기술 해제 (얼음 낚시) -Fishing.Ability.Locked.2={0}레벨 때 기술 해제 (낚시꾼 장인) -Fishing.Ability.Rank=트레져 헌터 랭크: &e{0}/5랭크 -Fishing.Ability.TH.DropRate= 드롭 비율: &4함정: &e{0} &7공통: &e{1} &a비공통: &e{2}\n&9레어: &e{3} &d에픽: &e{4} &6레전드리: &e{5} &b레코드: &e{6} -Fishing.Ability.TH.MagicRate=매직 헌터 확률: &e{0} -Fishing.Ability.Shake=흔들기 확률: &e{0} -Fishing.Ability.IceFishing=얼음 낚시: 얼음에서 낚시 -Fishing.Ability.FD=어부의 다이어트 랭크: &e{0}랭크 -Fishing.SubSkill.TreasureHunter.Name=트레져 헌터 (패시브) -Fishing.SubSkill.TreasureHunter.Description=물건(그외) 낚시 -Fishing.SubSkill.MagicHunter.Name=매직 헌터 -Fishing.SubSkill.MagicHunter.Description=인챈트된 아이템 발견 -Fishing.SubSkill.Shake.Name=흔들기 (vs. 독립체) -Fishing.SubSkill.Shake.Description=아이템을 몹이나 낚시에서 얻음 -Fishing.SubSkill.FishermansDiet.Name=어부의 다이어트 -Fishing.SubSkill.FishermansDiet.Description=어류 음식 허기 회복 증가 -Fishing.SubSkill.MasterAngler.Name=낚시꾼 장인 -Fishing.SubSkill.IceFishing.Name=얼음 낚시 -Fishing.SubSkill.IceFishing.Description=얼음이 덮혀있는 환경에서 낚시 가능 -Fishing.Chance.Raining=&9 비 특혜 -Fishing.Listener=낚시(FISHING): -Fishing.Ability.TH.MagicFound=&7이 입질에서 마법이 느껴집니다... -Fishing.Ability.TH.Boom=&7폭발 시간!!! -Fishing.Ability.TH.Poison=&7낌새가 좋지 않습니다... -Fishing.SkillName=낚시 -Fishing.Skillup=낚시 기술이 {0} 올라 총 {1} 레벨이 되었습니다 -Fishing.ScarcityTip=&e&o이 지역은 과잉 낚시로 인해 어필이 부족합니다. 더 많은 물고기를 잡으려면 다른 곳에 낚싯대를 던져보세요. 적어도 {0} 블록 이상 떨어진 곳에서 낚시하세요. -Fishing.Scared=&7&o물고기를 놀라게 하는 불규칙한 움직임입니다! -Fishing.Exhausting=&c&o낚싯대를 부적절하게 사용하면 피로가 쌓이고 낚싯대가 닳아버립니다! -Fishing.LowResourcesTip=&7이 지역에는 물고기가 많이 남아있지 않을 것 같습니다. 적어도 {0} 블록 이상 떨어진 곳에서 낚시해보세요. -Fishing.SubSkill.TreasureHunter.Stat=보물 사냥꾼 랭크: &a{0}&3/&a{1} -Fishing.SubSkill.TreasureHunter.Stat.Extra=드롭 비율: &7일반: &e{0} &a희귀: &e{1}\n&9레어: &e{2} &d에픽: &e{3} &6레전드리: &e{4} &b신화: &e{5} -Fishing.SubSkill.MagicHunter.Stat=매직 헌터 확률 +Excavation.SubSkill.Archaeology.Description=땅의 비밀을 밝혀냅니다! 높은 스킬 레벨은 보물을 찾을 때 경험치 오브를 발견할 확률을 높입니다! +Excavation.SubSkill.Archaeology.Stat=고고학 경험치 오브 확률 +Excavation.SubSkill.Archaeology.Stat.Extra=고고학 경험치 오브 양 +Excavation.Listener=발굴: +Excavation.SkillName=발굴 +Excavation.Skills.GigaDrillBreaker.Off=**기가 드릴 브레이커 효과가 사라졌습니다** +Excavation.Skills.GigaDrillBreaker.On=&a**기가 드릴 브레이커 활성화됨** +Excavation.Skills.GigaDrillBreaker.Refresh=&a해당 &e기가 드릴 브레이커 &a기술이 회복되었습니다! +Excavation.Skills.GigaDrillBreaker.Other.Off=기가 드릴 브레이커&a 효과가 &e{0}에게서 사라졌습니다 +Excavation.Skills.GigaDrillBreaker.Other.On=&a{0}&2이(가) &c기가 드릴 브레이커를 사용했습니다! +#낚시 +Fishing.ScarcityTip=&e&o이 지역은 낚시가 과잉되어 있습니다. 더 많은 물고기를 잡으려면 다른 곳에 낚싯대를 던지세요. 적어도 {0} 블록 떨어진 곳에서 낚시하세요. +Fishing.Scared=&7&o난잡한 움직임은 물고기를 놀라게 합니다! +Fishing.Exhausting=&c&o낚시대를 부적절하게 사용하면 피로가 쌓이고 낚시대가 닳습니다! +Fishing.LowResourcesTip=&7이 지역에는 물고기가 많지 않을 것 같습니다. 적어도 {0} 블록 떨어진 곳에서 낚시하세요. +Fishing.Ability.Info=마법사 사냥꾼: &7 **보물사냥꾼 랭크에 따라 향상됩니다** +Fishing.Ability.Locked.0={0}+ 스킬까지 잠금 (흔들기) +Fishing.Ability.Locked.1={0}+ 스킬까지 잠금 (얼음 낚시) +Fishing.Ability.Locked.2={0}+ 스킬까지 잠금 (마스터 낚시꾼) +Fishing.SubSkill.TreasureHunter.Name=보물사냥꾼 +Fishing.SubSkill.TreasureHunter.Description=다양한 물건을 낚아올립니다 +Fishing.SubSkill.TreasureHunter.Stat=보물사냥꾼 랭크: &a{0}&3/&a{1} +Fishing.SubSkill.TreasureHunter.Stat.Extra=드롭 확률: &7흔함: &e{0} &a보통: &e{1}\n&9희귀: &e{2} &d에픽: &e{3} &6전설: &e{4} &b신화: &e{5} +Fishing.SubSkill.MagicHunter.Name=마법사 사냥꾼 +Fishing.SubSkill.MagicHunter.Description=마법 부여된 아이템을 찾습니다 +Fishing.SubSkill.MagicHunter.Stat=마법사 사냥꾼 확률 +Fishing.SubSkill.Shake.Name=흔들기 +Fishing.SubSkill.Shake.Description=낚싯대로 몹이나 플레이어에서 아이템을 흔들어 떨구세요 Fishing.SubSkill.Shake.Stat=흔들기 확률 -Fishing.SubSkill.FishermansDiet.Stat=어부의 다이어트: &a랭크 {0} -Fishing.SubSkill.MasterAngler.Description=어부가 더 자주 물고기를 잡습니다. 보트에서 낚시할 때 더 잘 작동합니다. +Fishing.SubSkill.FishermansDiet.Name=어부의 식단 +Fishing.SubSkill.FishermansDiet.Description=낚은 음식의 포만감을 개선합니다 +Fishing.SubSkill.FishermansDiet.Stat=어부의 식단: &a랭크 {0} +Fishing.SubSkill.MasterAngler.Name=마스터 낚시꾼 +Fishing.SubSkill.MasterAngler.Description=물고기를 더 자주 잡을 수 있으며, 배에서 낚시할 때 더 잘 작동합니다. Fishing.SubSkill.MasterAngler.Stat=낚시 최소 대기 시간 감소: &a-{0} 초 Fishing.SubSkill.MasterAngler.Stat.Extra=낚시 최대 대기 시간 감소: &a-{0} 초 +Fishing.SubSkill.IceFishing.Name=얼음 낚시 +Fishing.SubSkill.IceFishing.Description=얼음 생물이 서식하는 생물꾼입니다 Fishing.SubSkill.IceFishing.Stat=얼음 낚시 - -#HERBALISM -Herbalism.Ability.DoubleDropChance=2배 드롭 확률: &e{0} -Herbalism.Ability.FD=농부의 다이어트: &e{0}랭크 -Herbalism.Ability.GTe.Length=재배의 대지 지속시간: &e{0}초 -Herbalism.Ability.GTe.NeedMore=재배의 대지에 뿌릴 씨가 좀더 필요합니다. -Herbalism.Ability.GTh.Chance=재배의 재능 확률: &e{0} -Herbalism.Ability.GTh.Fail=**재배의 재능 실패** -Herbalism.Ability.GTh.Stage=재배의 재능 단계: &e 작물 재배 {0}단계 -Herbalism.Ability.GTh=&a**재배의 재능** -Herbalism.Ability.HylianLuck=하이랄인의 행운 확률: &e{0} -Herbalism.Ability.Lower=&7**호미 준비 해제** -Herbalism.Ability.Ready=&a**호미 준비 완료** -Herbalism.Ability.ShroomThumb.Chance=버섯재배자의 숨결 확률: &e{0} -Herbalism.Ability.ShroomThumb.Fail=**버섯재배자의 숨결 실패** -Herbalism.SubSkill.GreenTerra.Name=재배의 대지 (능력) -Herbalism.SubSkill.GreenTerra.Description=대지 뿌리기, 드롭 3배, 재배의 재능 부스트 -Herbalism.SubSkill.GreenThumb.Name=재배의 재능 (밀) -Herbalism.SubSkill.GreenThumb.Description=수확시 자동 씨 심기 -Herbalism.Effect.4=재배의 재능 (블록들) -Herbalism.SubSkill.GreenThumb.Description.2=이끼 낀 블록 만들기, 잔디 자라게 하기 -Herbalism.SubSkill.FarmersDiet.Name=농부의 다이어트 -Herbalism.SubSkill.FarmersDiet.Description=농작물 배고품 회복 향상 -Herbalism.SubSkill.DoubleDrops.Name=2배 드롭 (모든 작물) -Herbalism.SubSkill.DoubleDrops.Description=항상 드롭 2배 -Herbalism.SubSkill.HylianLuck.Name=하이랄인의 행운 -Herbalism.SubSkill.HylianLuck.Description=적은 확률로 레어 아이템 얻음 -Herbalism.SubSkill.ShroomThumb.Name=버섯재배자의 숨결 -Herbalism.SubSkill.ShroomThumb.Description=흙 & 잔디에 균사체 살포 -Herbalism.HylianLuck=&a하이랄의 행운이 오늘 너에게 따르는구나! -Herbalism.Listener=약초학(HERBALISM): +Fishing.Chance.Raining=&9 비 보너스 +Fishing.Listener=낚시: +Fishing.Ability.TH.MagicFound=&7이 잡은 물고기에는 마법의 손길을 느낍니다... +Fishing.Ability.TH.Boom=&7폭발 시간!!! +Fishing.Ability.TH.Poison=&7뭔가 이상한 냄새가 납니다... +Fishing.SkillName=낚시 +#약초학 +Herbalism.Ability.GTe.NeedMore=더 많은 씨앗이 필요합니다. 녹색 에너지를 전파하기 위해서입니다. +Herbalism.Ability.GTh.Fail=**식물재배 실패** +Herbalism.Ability.GTh=&a**식물재배** +Herbalism.Ability.Lower=&7국지를 낮춥니다. +Herbalism.Ability.Ready=&3국지를 &6준비&3합니다. +Herbalism.Ability.ShroomThumb.Fail=**버섯썸 실패** +Herbalism.SubSkill.GreenTerra.Name=그린 테라 +Herbalism.SubSkill.GreenTerra.Description=테라를 전파하며, 드롭 3배 증가, 식물재배 강화 +Herbalism.SubSkill.GreenTerra.Stat=그린 테라 지속시간 +Herbalism.SubSkill.GreenThumb.Name=식물재배 +Herbalism.SubSkill.GreenThumb.Description=국지로 작물 수확 시 자동으로 심기 +Herbalism.SubSkill.GreenThumb.Stat=식물재배 확률 +Herbalism.SubSkill.GreenThumb.Stat.Extra=식물재배 단계: &a작물 단계 {0}에서 자랍니다 +Herbalism.Effect.4=식물재배 (블록) +Herbalism.SubSkill.GreenThumb.Description.2=벽돌에 이끼를 더하거나 풀을 자라게 합니다 +Herbalism.SubSkill.FarmersDiet.Name=농부의 식단 +Herbalism.SubSkill.FarmersDiet.Description=농산물로부터 회복되는 허기가 향상됩니다 +Herbalism.SubSkill.FarmersDiet.Stat=농부의 식단: &a등급 {0} +Herbalism.SubSkill.DoubleDrops.Name=더블 드롭 +Herbalism.SubSkill.DoubleDrops.Description=보통 드롭의 2배 획득 +Herbalism.SubSkill.DoubleDrops.Stat=더블 드롭 확률 +Herbalism.SubSkill.HylianLuck.Name=하이랄의 행운 +Herbalism.SubSkill.HylianLuck.Description=희귀 아이템을 찾을 작은 확률 제공 +Herbalism.SubSkill.HylianLuck.Stat=하이랄의 행운 확률 +Herbalism.SubSkill.ShroomThumb.Name=버섯썸 +Herbalism.SubSkill.ShroomThumb.Description=흙과 풀에 균사체를 전파합니다 +Herbalism.SubSkill.ShroomThumb.Stat=버섯썸 확률 +Herbalism.HylianLuck=&a하이라루의 행운이 오늘은 함께 합니다! +Herbalism.Listener=약초학: Herbalism.SkillName=약초학 -Herbalism.Skills.GTe.Off=**재배의 대지 비활성화됨** -Herbalism.Skills.GTe.On=&a**재배의 대지 활성화됨** -Herbalism.Skills.GTe.Refresh=&a당신의 &e재배의 대지 &a기술은 이제 사용 가능합니다! -Herbalism.Skills.GTe.Other.Off={0}&2님은 &c재배의 대지를 사용했습니다! -Herbalism.Skills.GTe.Other.On=&a{0}&2님은 &c재배의 대지를 사용했습니다! -Herbalism.Skillup=약초학 기술이 {0} 올라 총 {1} 레벨이 되었습니다 -Herbalism.SubSkill.GreenTerra.Stat=재배의 대지 지속 시간 -Herbalism.SubSkill.GreenThumb.Stat=재배의 재능 확률 -Herbalism.SubSkill.GreenThumb.Stat.Extra=재배의 재능 단계: &a작물이 {0} 단계로 자라납니다 -Herbalism.SubSkill.FarmersDiet.Stat=농부의 다이어트: &a랭크 {0} -Herbalism.SubSkill.DoubleDrops.Stat=2배 드롭 확률 -Herbalism.SubSkill.HylianLuck.Stat=하이랄인의 행운 확률 -Herbalism.SubSkill.ShroomThumb.Stat=버섯재배자의 숨결 확률 +Herbalism.Skills.GTe.Off=**그린 테라가 종료되었습니다** +Herbalism.Skills.GTe.On=&a**그린 테라 활성화됨** +Herbalism.Skills.GTe.Refresh=&a그린 테라 능력이 갱신되었습니다! +Herbalism.Skills.GTe.Other.Off=&e{0}&a님의 그린 테라가 종료되었습니다 +Herbalism.Skills.GTe.Other.On=&a{0}&2님이 &c그린 테라를 사용했습니다! +#채광 +Mining.Ability.Locked.0={0}+ 스킬이 필요합니다 (폭탄 채굴) +Mining.Ability.Locked.1={0}+ 스킬이 필요합니다 (더 큰 폭탄) +Mining.Ability.Locked.2={0}+ 스킬이 필요합니다 (폭파 전문가) +Mining.Ability.Lower=&7곡괭이를 낮춥니다. +Mining.Ability.Ready=&3곡괭이를 &6준비&3합니다. +Mining.SubSkill.SuperBreaker.Name=슈퍼 브레이커 +Mining.SubSkill.SuperBreaker.Description=속도+, 드롭 3배 확률 +Mining.SubSkill.SuperBreaker.Stat=슈퍼 브레이커 지속시간 +Mining.SubSkill.DoubleDrops.Name=더블 드롭 +Mining.SubSkill.DoubleDrops.Description=보통 드롭의 2배 획득 +Mining.SubSkill.DoubleDrops.Stat=더블 드롭 확률 +Mining.SubSkill.BlastMining.Name=폭탄 채굴 +Mining.SubSkill.BlastMining.Description=TNT로 채굴 시 보너스 효과 +Mining.SubSkill.BlastMining.Stat=폭탄 채굴: &a등급 {0}/{1} &7({2}) +Mining.SubSkill.BlastMining.Stat.Extra=폭발 반경 증가: &a+{0} +Mining.SubSkill.BiggerBombs.Name=더 큰 폭탄 +Mining.SubSkill.BiggerBombs.Description=TNT 폭발 반경 증가 +Mining.SubSkill.DemolitionsExpertise.Name=폭파 전문가 +Mining.SubSkill.DemolitionsExpertise.Description=TNT 폭발로 인한 피해 감소 +Mining.SubSkill.DemolitionsExpertise.Stat=폭파 전문가 피해 감소 -#MINING -Mining.Ability.Length=파괴자 지속시간: &e{0}s -Mining.Ability.Locked.0={0}레벨 때 기술 해제 (폭발 채굴) -Mining.Ability.Locked.1={0}레벨 때 기술 해제 (거대 폭발) -Mining.Ability.Locked.2={0}레벨 때 기술 해제 (전문 폭파) -Mining.Ability.Lower=&7**곡괭이 준비 해제** -Mining.Ability.Ready=&a**곡괭이 준비 완료** -Mining.SubSkill.SuperBreaker.Name=파괴자 (능력) -Mining.SubSkill.SuperBreaker.Description=속도 향상, 드롭 확률 3배 -Mining.SubSkill.DoubleDrops.Name=드롭 2배 -Mining.SubSkill.DoubleDrops.Description=항상 드롭 2배 -Mining.SubSkill.BlastMining.Name=폭발 채굴 -Mining.SubSkill.BlastMining.Description=TNT로 채굴시 추가 광물 -Mining.SubSkill.BiggerBombs.Name=거대 폭발 -Mining.SubSkill.BiggerBombs.Description=TNT 폭발거리 증가 -Mining.SubSkill.DemolitionsExpertise.Name=전문 폭파 -Mining.SubSkill.DemolitionsExpertise.Description=TNT 폭발 피해 감소 -Mining.Effect.Decrease=전문 폭파 피해 감소: &e{0} -Mining.Effect.DropChance=드롭 2배 확률: &e{0} -Mining.Listener=채광(MINING): +Mining.Listener=Mining: Mining.SkillName=채광 -Mining.Skills.SuperBreaker.Off=**파괴자 발동 해제** -Mining.Skills.SuperBreaker.On=&a**파괴자 발동** -Mining.Skills.SuperBreaker.Other.Off={0}&2님은 &c파괴자를 사용했습니다! -Mining.Skills.SuperBreaker.Other.On=&a{0}&2님은 &c파괴자를 사용했습니다! -Mining.Skills.SuperBreaker.Refresh=&a당신의 &e파괴자는 &a이제 사용 가능합니다! -Mining.Skillup=채광 기술이 {0} 올라 총 {1} 레벨이 되었습니다 -Mining.SubSkill.SuperBreaker.Stat=파괴자 지속 시간 -Mining.SubSkill.DoubleDrops.Stat=드롭 2배 확률 -Mining.SubSkill.BlastMining.Stat=폭발 채광: &a랭크 {0}/{1} &7({2}) -Mining.SubSkill.BlastMining.Stat.Extra=폭발 범위 증가: &a+{0} -Mining.SubSkill.DemolitionsExpertise.Stat=전문 폭파 피해 감소 - -#폭발 채굴 -Mining.Blast.Boom=&7**폭발** -Mining.Blast.Effect=+{0} 광물 이익, {1}x 드롭 -Mining.Blast.Radius.Increase=폭발 반경 증가: &e+{0} -Mining.Blast.Rank=폭발 채굴: &e{0}/8랭크 &7({1}) -Mining.Blast.Other.On=&a{0}&2님은 &c폭발 채굴을 사용하셨습니다! -Mining.Blast.Refresh=&a당신의 &e폭발 채굴 &a기술은 이제 사용 가능합니다! - +Mining.Skills.SuperBreaker.Off=**슈퍼 브레이커가 사라졌습니다** +Mining.Skills.SuperBreaker.On=&a**슈퍼 브레이커가 활성화되었습니다** +Mining.Skills.SuperBreaker.Other.Off=슈퍼 브레이커가 &e{0}님에게서 사라졌습니다 +Mining.Skills.SuperBreaker.Other.On=&a{0}&2님이 &c슈퍼 브레이커를 사용하였습니다! +Mining.Skills.SuperBreaker.Refresh=&a당신의 &e슈퍼 브레이커&a 능력이 갱신되었습니다! +Mining.Listener=Mining: +Mining.SkillName=채광 +Mining.Skills.SuperBreaker.Off=슈퍼 브레이커가 사라졌습니다 +Mining.Skills.SuperBreaker.On=&a슈퍼 브레이커가 활성화되었습니다 +Mining.Skills.SuperBreaker.Other.Off=슈퍼 브레이커가 &e{0}님에게서 사라졌습니다 +Mining.Skills.SuperBreaker.Other.On=&a{0}&2님이 &c슈퍼 브레이커를 사용하였습니다! +Mining.Skills.SuperBreaker.Refresh=&a당신의 &e슈퍼 브레이커&a 능력이 갱신되었습니다! +#Blast Mining +Mining.Blast.Boom=&7펑 +Mining.Blast.Cooldown= +Mining.Blast.Effect=채굴량 +{0}, 드롭 횟수 {1}배 증가 +Mining.Blast.Other.On=&a{0}&2님이 &c폭발 채굴을 사용하였습니다! +Mining.Blast.Refresh=&a폭발 채굴 능력이 갱신되었습니다! #REPAIR Repair.SubSkill.Repair.Name=수리 -Repair.SubSkill.Repair.Description=도구 & 방어구 수리 -Repair.SubSkill.GoldRepair.Name=금 수리 ({0}레벨 이상) -Repair.SubSkill.GoldRepair.Description=금 도구 & 방어구 수리 -Repair.SubSkill.IronRepair.Name=철 수리 ({0}레벨 이상) -Repair.SubSkill.IronRepair.Description=철 도구 & 방어구 수리 -Repair.SubSkill.StoneRepair.Name=돌 수리 ({0}레벨 이상) +Repair.SubSkill.Repair.Description=도구 및 갑옷 수리 +Repair.SubSkill.GoldRepair.Name=금 수리 ({0}+ 레벨) +Repair.SubSkill.GoldRepair.Description=금 도구 및 갑옷 수리 +Repair.SubSkill.IronRepair.Name=철 수리 ({0}+ 레벨) +Repair.SubSkill.IronRepair.Description=철 도구 및 갑옷 수리 +Repair.SubSkill.StoneRepair.Name=돌 수리 ({0}+ 레벨) Repair.SubSkill.StoneRepair.Description=돌 도구 수리 -Repair.SubSkill.RepairMastery.Name=수리 마스터리 -Repair.SubSkill.RepairMastery.Description=수리 양 증가 +Repair.SubSkill.RepairMastery.Name=수리 숙련 +Repair.SubSkill.RepairMastery.Description=수리량 증가 +Repair.SubSkill.RepairMastery.Stat=수리 숙련도: &a추가로 {0} 내구도 복구 Repair.SubSkill.SuperRepair.Name=슈퍼 수리 -Repair.SubSkill.SuperRepair.Description=효율 2배 -Repair.SubSkill.DiamondRepair.Name=다이아몬드 수리 ({0} 레벨) -Repair.SubSkill.DiamondRepair.Description=다이아몬드 도구 & 방어구 수리 -Repair.SubSkill.ArcaneForging.Name=인챈트 아이템 수리 -Repair.SubSkill.ArcaneForging.Description=마법 아이템 수리 -Repair.Error=&4mcMMO이 아이템을 수리하려고 시도하는 동안 오류가 발생했습니다! -Repair.Listener.Anvil=&4당신은 모루를 놓았습니다, 모루는 도구들과 방어구를 수리할 수 있습니다. -Repair.Listener=수리(REPAIR): -Repair.SkillName=수리 -Repair.Skills.AdeptDiamond=&4당신은 아직 다이아몬드를 수리할 수 있는 기술을 배우지 않았습니다. -Repair.Skills.AdeptGold=&4당신은 아직 금을 수리할 수 있는 기술을 배우지 않았습니다. -Repair.Skills.AdeptIron=&4당신은 아직 철을 수리할 수 있는 기술을 배우지 않았습니다. -Repair.Skills.AdeptStone=&4당신은 아직 돌을 수리할 수 있는 기술을 배우지 않았습니다. -Repair.Skills.Adept=당신은 &e{1}을/를 수리할려면 &e{0}&c레벨이 필요합니다 -Repair.Skills.FeltEasy=&7쉬운 느낌~ -Repair.Skills.FullDurability=&7내구도가 꽉 찼습니다. -Repair.Skills.Mastery=수리 마스터리: &e추가 내구성 복구: {0} -Repair.Skills.StackedItems=&4한번에 많은 아이템을 수리할 수 없습니다. -Repair.Skills.Super.Chance=슈퍼 수리 확률: &e{0} -Repair.Skillup=수리 기술이 {0} 올라 총 {1} 레벨이 되었습니다 -Repair.Pretty.Name=수리 -Repair.SubSkill.RepairMastery.Stat=수리 마스터리: &a추가 {0} 내구성 복구 +Repair.SubSkill.SuperRepair.Description=두 배로 효과 증가 Repair.SubSkill.SuperRepair.Stat=슈퍼 수리 확률 -Repair.SubSkill.ArcaneForging.Stat=인챈트 아이템 수리: &e랭크 {0}/{1} -Repair.SubSkill.ArcaneForging.Stat.Extra=&3인챈트 아이템 수리 확률:&7 성공 &a{0}&7%, 실패 &c{1}&7% - +Repair.SubSkill.DiamondRepair.Name=다이아몬드 수리 ({0}+ 레벨) +Repair.SubSkill.DiamondRepair.Description=다이아몬드 도구 및 갑옷 수리 +Repair.SubSkill.ArcaneForging.Name=신비한 대장간 +Repair.SubSkill.ArcaneForging.Description=마법 아이템 수리 +Repair.SubSkill.ArcaneForging.Stat=신비한 대장간: &e등급 {0}/{1} +Repair.SubSkill.ArcaneForging.Stat.Extra=&3신비한 대장간 확률:&7 성공 &a{0}&7%, 실패 &c{1}&7% +Repair.Error=&4mcMMO가 이 아이템을 수리하는 동안 오류가 발생했습니다! +Repair.Listener.Anvil=&a당신은 모루를 배치했습니다. 모루는 도구와 갑옷을 수리할 수 있습니다. +Repair.Listener=수리: +Repair.SkillName=수리 +Repair.Skills.AdeptDiamond=&4다이아몬드 수리에 능숙하지 않습니다. +Repair.Skills.AdeptGold=&4금 수리에 능숙하지 않습니다. +Repair.Skills.AdeptIron=&4철 수리에 능숙하지 않습니다. +Repair.Skills.AdeptStone=&4돌 수리에 능숙하지 않습니다. +Repair.Skills.Adept=&c레벨 &e{0}&c 이상이어야 &e{1}&c을(를) 수리할 수 있습니다. +Repair.Skills.FeltEasy=&7쉽게 느껴졌습니다. +Repair.Skills.FullDurability=&7이 아이템은 완전한 내구도입니다. +Repair.Skills.StackedItems=&4중첩된 아이템은 수리할 수 없습니다. +Repair.Pretty.Name=수리 #Arcane Forging -Repair.Arcane.Chance.Downgrade=&7인챈트 수리 격하 확률: &e{0}% -Repair.Arcane.Chance.Success=&7인챈트 수리 성공 확률: &e{0}% -Repair.Arcane.Downgrade=이 아이템의 인챈트는 감소했습니다. -Repair.Arcane.Fail=이 아이템의 인챈트는 영구적으로 소멸되었습니다. -Repair.Arcane.Lost=당신은 모든 인챈트를 유지할 기술이 충분치 않습니다. -Repair.Arcane.Perfect=&a이 아이템의 인챈트를 지속시켰습니다. -Repair.Arcane.Rank=인챈트 수리: &e{0}/{1}랭크 - +Repair.Arcane.Downgrade=이 아이템의 신비한 힘이 감소되었습니다. +Repair.Arcane.Fail=이 아이템의 신비한 힘이 영구히 사라졌습니다. +Repair.Arcane.Lost=너무 능력이 부족하여 마법을 추출할 수 없었습니다. +Repair.Arcane.Perfect=&a이 아이템의 신비한 힘을 유지하였습니다. #SALVAGE -Salvage.Pretty.Name=회수 -Salvage.SubSkill.AdvancedSalvage.Name=전문적인 회수 -Salvage.SubSkill.AdvancedSalvage.Description=손상된 아이템 회수 -Salvage.Ability.Locked.0={0} 레벨 때 기술해제 (전문적인 회수) -Salvage.Ability.Bonus.0=전문적인 회수 -Salvage.Ability.Bonus.1=부셔진 아이템의 최대 추출량 {0} -Salvage.Arcane.Rank=신비로운 회수: &eRank {0}/{1} -Salvage.Arcane.ExtractFull=&7최대-인챈트 기회 부과 -Salvage.Arcane.ExtractPartial=&7일부-인챈트 기회 부과 -Salvage.Skills.Success=&a아이템 회수됨! -Salvage.Skills.Adept.Damaged=&4손상된 아이템을 회수할 능력이 없습니다. -Salvage.Skills.Adept.Level={1}를 &c회수하려면 &e{0}&c 레벨이 되야합니다 -Salvage.Skills.TooDamaged=&4이 아이템은 심하게 손상되어 회수할 수 없습니다. -Salvage.Skills.ArcaneFailed=당신은 이 아이템 속의 지식을 추출할 수 없습니다. -Salvage.Skills.ArcanePartial=당신은 이 아이템 속의 지식의 일부만 추출할 수 있었습니다. -Salvage.Skills.ArcaneSuccess=&a당신은 이 아이템의 모든 지식을 추출할 수 있습니다! -Salvage.Listener.Anvil=&4당신은 회수 모루를 놓았습니다, 도구나 방어구 회수에 쓰입니다. -Salvage.Listener=회수(SALVAGE): -Salvage.SkillName=회수 -Salvage.Pretty.Name=Salvage +Salvage.Pretty.Name=분해 Salvage.SubSkill.UnderstandingTheArt.Name=예술의 이해 -Salvage.SubSkill.UnderstandingTheArt.Description=이웃의 쓰레기를 뒤지는 것뿐만 아니라 환경을 보호하는 것입니다.\n회수의 다양한 속성을 강화합니다. +Salvage.SubSkill.UnderstandingTheArt.Description=이웃의 쓰레기를 털기 위한 것이 아니라 환경을 보호하기 위한 것입니다.\n분해의 다양한 속성을 강화합니다. Salvage.SubSkill.ScrapCollector.Name=폐기물 수집가 -Salvage.SubSkill.ScrapCollector.Description=아이템에서 재료를 회수하며, 완벽한 회수는 기술과 운에 달려 있습니다. -Salvage.SubSkill.ScrapCollector.Stat=폐기물 수집가: &a최대 &e{0}&a개의 아이템을 회수합니다. 운이 조금 관여됩니다. -Salvage.SubSkill.ArcaneSalvage.Name=신비로운 회수 -Salvage.SubSkill.ArcaneSalvage.Description=아이템에서 인챈트 추출 -Salvage.SubSkill.ArcaneSalvage.Stat=신비로운 회수: &e랭크 {0}/{1} -Salvage.Skills.Lottery.Normal=&6{1}&6에서 &3{0}&6개의 재료를 회수했습니다. -Salvage.Skills.Lottery.Perfect=&a&l완벽합니다!&r&6{1}&6에서 수고 없이 &3{0}&6개의 재료를 회수했습니다. -Salvage.Skills.Lottery.Untrained=&7회수에 적절하게 훈련되지 않았습니다. {1}&7에서는 &c{0}&7개의 재료만 회수할 수 있었습니다. - -#Anvil (Shared between SALVAGE and REPAIR) -Anvil.Unbreakable=이 아이템은 Unbreakable입니다! - -#SWORDS -Swords.Ability.Lower=&7**검 준비 해제** -Swords.Ability.Ready=&a**검 준비 완료** -Swords.Combat.Bleed.Chance=출혈 확률: &e{0} -Swords.Combat.Bleed.Length=출혈 지속시간: &e{0} 틱 -Swords.Combat.Bleed.Note=&7알림: &e1 틱은 2초입니다 -Swords.Combat.Bleeding.Started=&4 당신은 피를 흘리고 있습니다! -Swords.Combat.Bleeding.Stopped=&7출혈이 &a멈췄습니다&7! -Swords.Combat.Bleeding=&a**출혈** -Swords.Combat.Counter.Chance=카운터 어택 확률: &e{0} -Swords.Combat.Counter.Hit=&4카운터 어택에 맞았습니다! -Swords.Combat.Countered=&a**카운터-어택** -Swords.Combat.SS.Struck=&4톱날 공격에 맞았습니다! -Swords.SubSkill.CounterAttack.Name=카운터 어택 -Swords.SubSkill.CounterAttack.Description={0} 피해 반사 -Swords.SubSkill.SerratedStrikes.Name=톱날 공격 (능력) -Swords.SubSkill.SerratedStrikes.Description=피해 {0} 증가, 출혈 증가 -Swords.Effect.4=톱날 공격 출혈 증가 -Swords.Effect.5={0} 틱 출혈 -Swords.SubSkill.Bleed.Name=출혈 -Swords.SubSkill.Bleed.Description=과다 출혈 -Swords.Listener=검술(SWORDS): -Swords.SkillName=검술 -Swords.Skills.SS.Off=**톱날 공격 발동 해제** -Swords.Skills.SS.On=&a**톱날 공격 발동** -Swords.Skills.SS.Refresh=&a당신의 &e톱날 공격 &a스킬은 이제 사용 가능합니다! -Swords.Skills.SS.Other.Off={0}&2님은 &c톱날 공격 스킬을 사용 해제했습니다! -Swords.Skills.SS.Other.On=&a{0}&2님은 &c톱날 공격 스킬을 사용했습니다! -Swords.Skillup=검술 스킬이 {0} 올라 총 {1} 레벨이 되었습니다 -Swords.SS.Length=톱날 공격 지속시간: &e{0}초 -Swords.Combat.Rupture.Note.Update.One=&7(파열 노트): 주기적인 피해는 치명적이지 않으며 초당 두 번 발생하며 방어구를 무시합니다. +Salvage.SubSkill.ScrapCollector.Description=아이템에서 재료를 분해합니다. 완벽한 분해는 기술과 운에 달려있습니다. +Salvage.SubSkill.ScrapCollector.Stat=폐기물 수집가: &a최대 &e{0}&a개의 아이템 분해. +Salvage.SubSkill.ArcaneSalvage.Name=신비한 분해 +Salvage.SubSkill.ArcaneSalvage.Description=아이템에서 마법을 추출합니다. +Salvage.SubSkill.ArcaneSalvage.Stat=신비한 분해: &e등급 {0}/{1} +Salvage.Ability.Bonus.0=폐기물 수집가 +Salvage.Ability.Bonus.1=최대 &e{0}&a개의 아이템 분해. 일부 운이 필요합니다. +Salvage.Arcane.ExtractFull=&7신비한 분해 전체 마법 추출 확률 +Salvage.Arcane.ExtractPartial=&7신비한 분해 부분적 마법 추출 확률 +Salvage.Skills.Success=&a아이템을 분해하였습니다! +Salvage.Skills.Adept.Damaged=&4손상된 아이템은 분해할 수 없습니다. +Salvage.Skills.Adept.Level=레벨 &e{0}&c 이상이어야 &e{1}&c을(를) 분해할 수 있습니다. +Salvage.Skills.TooDamaged=&4이 아이템은 너무 손상되었어 분해할 수 없습니다. +Salvage.Skills.ArcaneFailed=&c이 아이템에 담긴 지식을 추출하지 못했습니다. +Salvage.Skills.ArcanePartial=&c이 아이템에 담긴 일부 지식만 추출할 수 있었습니다. +Salvage.Skills.ArcaneSuccess=&a이 아이템에 담긴 모든 지식을 추출할 수 있었습니다! +Salvage.Listener.Anvil=&a당신은 분해 모루를 배치했습니다. 도구와 갑옷을 분해하려면 이를 사용하세요. +Salvage.Listener=분해: +Salvage.SkillName=분해 +Salvage.Skills.Lottery.Normal=&6{1}&6에서 &3{0}&6개의 재료를 분해하였습니다. +Salvage.Skills.Lottery.Perfect=&a&l완벽해요!&r&6 &3{1}&6을 쉽게 회수하여 &3{0}&6 자료를 검색했습니다. +Salvage.Skills.Lottery.Untrained=&7인양에 대한 교육을 제대로 받지 못했습니다. &a{1}&7에서 &c{0}&7 자료만 복구할 수 있었습니다. +#모루(SALVAGE와 REPAIR 간에 공유) +Anvil.Unbreakable=이 아이템은 깨지지 않습니다! +#검 +Swords.Ability.Lower=&7검을 내려놓습니다. +Swords.Ability.Ready=&3당신은 &6검을 준비합니다&3. +Swords.Combat.Rupture.Note.Update.One=&7(파열 노트): 주기적인 피해는 매초 두 번 발생하며 방어구를 뚫고 발생합니다. +Swords.Combat.Bleeding.Started=&4출혈 중입니다! +Swords.Combat.Bleeding.Stopped=&7출혈이 &a중단&7되었습니다! +Swords.Combat.Bleeding=&a**적이 출혈 중** +Swords.Combat.Counter.Hit=&4반격으로 공격당했습니다! +Swords.Combat.Countered=&a**반격당함** +Swords.Combat.SS.Struck=&4톱니 모양의 타격을 받았습니다! +Swords.SubSkill.CounterAttack.Name=반격 +Swords.SubSkill.CounterAttack.Description=공격당했을 때 일부 피해를 반사합니다! Swords.SubSkill.CounterAttack.Stat=반격 확률 -Swords.SubSkill.SerratedStrikes.Stat=톱날 공격 지속시간 +Swords.SubSkill.SerratedStrikes.Name=톱니 모양 타격 +Swords.SubSkill.SerratedStrikes.Description=일정 범위 내에서 부분적인 피해를 입히며 파열을 적용할 확률이 있습니다! +Swords.SubSkill.SerratedStrikes.Stat=톱니 모양 타격 길이 Swords.SubSkill.Rupture.Name=파열 Swords.SubSkill.Rupture.Description=폭발적으로 끝나는 지속 피해 효과 Swords.SubSkill.Stab.Name=찌르기 Swords.SubSkill.Stab.Description=공격에 추가 피해를 줍니다. Swords.SubSkill.Stab.Stat=찌르기 피해 Swords.SubSkill.SwordsLimitBreak.Name=검 한계 돌파 -Swords.SubSkill.SwordsLimitBreak.Description=한계를 깨는 것. 강력한 상대에 대한 추가 피해. PVP를 위해 설계되었으며, PVE에서 피해 증가 여부는 서버 설정에 따릅니다. +Swords.SubSkill.SwordsLimitBreak.Description=한계 돌파. 강한 상대에 대한 피해 증가. PVP용으로 의도되었으며 PVE에서 피해를 증가시킬 것인지는 서버 설정에 따라 다릅니다. Swords.SubSkill.SwordsLimitBreak.Stat=한계 돌파 최대 피해 Swords.SubSkill.Rupture.Stat=파열 확률 -Swords.SubSkill.Rupture.Stat.Extra=[[DARK_AQUA]]파열 지속 시간: &e{0}초&a (플레이어), &e{1}초&a (몹). -Swords.SubSkill.Rupture.Stat.TickDamage=[[DARK_AQUA]]파열 순수 틱 피해: &e{0}&a (플레이어), &e{1}&a (몹). -Swords.SubSkill.Rupture.Stat.ExplosionDamage=[[DARK_AQUA]]파열 폭발 피해: &e{0}&a (플레이어), &e{1}&a (몹). - -#TAMING +Swords.SubSkill.Rupture.Stat.Extra=[[DARK_AQUA]]파열 지속 시간: &e{0}초&a 플레이어 대상, &e{1}초&a 몹 대상. +Swords.SubSkill.Rupture.Stat.TickDamage=[[DARK_AQUA]]파열 순수 틱 피해: &e{0}&a 플레이어 대상, &e{1}&a 몹 대상. +Swords.SubSkill.Rupture.Stat.ExplosionDamage=[[DARK_AQUA]]파열 폭발 피해: &e{0}&a 플레이어 대상, &e{1}&a 몹 대상 +Swords.Effect.4=톱니 모양 타격 파열+ +Swords.Effect.5={0} 틱 파열 +Swords.Listener=검: +Swords.SkillName=검술 +Swords.Skills.SS.Off=**톱니 모양 타격 효과가 사라졌습니다** +Swords.Skills.SS.On=&a**톱니 모양 타격 활성화됨** +Swords.Skills.SS.Refresh=&a당신의 &e톱니 모양 타격 &a능력이 갱신되었습니다! +Swords.Skills.SS.Other.Off=톱니 모양 타격&a가 &e{0}에게 종료되었습니다 +Swords.Skills.SS.Other.On=&a{0}&2님이 &c톱니 모양 타격을 사용했습니다! +#길들이기 Taming.Ability.Bonus.0=환경 인식 -Taming.Ability.Bonus.1=늑대 위험 회피 +Taming.Ability.Bonus.1=늑대가 위험을 피합니다 Taming.Ability.Bonus.2=두꺼운 털 -Taming.Ability.Bonus.3=1/{0} 피해, 내화성(불저항력) -Taming.Ability.Bonus.4=충격 증명 -Taming.Ability.Bonus.5=항상 1/{0} 폭발 피해 -Taming.Ability.Bonus.6=날카로운 발톱 +Taming.Ability.Bonus.3=1/{0} 피해, 화염 저항 +Taming.Ability.Bonus.4=내구성이 좋음 +Taming.Ability.Bonus.5=폭발물의 일반 피해를 1/{0} 받습니다 +Taming.Ability.Bonus.6=올바르게 갈겨진 발톱 Taming.Ability.Bonus.7=+{0} 피해 -Taming.Ability.Bonus.8=빠른 음식 제공 -Taming.Ability.Bonus.9={0} 확률로 공격시 회복 -Taming.Ability.Bonus.10=신성한 사냥개 -Taming.Ability.Bonus.11=마법이나 독으로 인한 손상 회복 -Taming.Ability.Locked.0={0}레벨 때 스킬해제 (환경 인식) -Taming.Ability.Locked.1={0}레벨 때 스킬해제 (두꺼운 털) -Taming.Ability.Locked.2={0}레벨 때 스킬해제 (충격 증명) -Taming.Ability.Locked.3={0}레벨 때 스킬해제 (날카로운 발톱) -Taming.Ability.Locked.4={0}레벨 때 스킬해제 (빠른 음식 제공) -Taming.Ability.Locked.5={0}레벨 때 스킬해제 (신성한 사냥개) -Taming.Combat.Chance.Gore=돌진 확률: &e{0} -Taming.SubSkill.BeastLore.Name=짐승의 포효 -Taming.SubSkill.BeastLore.Description=뼈로 늑대/오셀롯 검사 -Taming.SubSkill.ShockProof.Name=충격 방지 -Taming.SubSkill.ShockProof.Description=폭발 피해 절감 -Taming.SubSkill.CallOfTheWild.Name=야생의 포효 -Taming.SubSkill.CallOfTheWild.Description=옆에 동물 소환 -Taming.SubSkill.CallOfTheWild.Description.2=&7COTW (오셀롯): 쭈그리면서 물고기를 들고 {0}번 좌 클릭 -Taming.Effect.15=&7COTW (늑대): 쭈그리면서 뼈를 들고 {0}번 좌 클릭 -Taming.SubSkill.Gore.Name0=&7COTW (말): 쭈그리면서 사과를 들고 {0}번 좌 클릭 -Taming.SubSkill.FastFoodService.Name=빠른 음식 제공 -Taming.SubSkill.FastFoodService.Description=공격시 치료 기회 -Taming.SubSkill.HolyHound.Name=신성한 사냥개 -Taming.SubSkill.HolyHound.Description=마법 & 독 피해 치료 -Taming.SubSkill.Gore.Name=돌진 -Taming.SubSkill.Gore.Description=크리티컬 스크라이크 출혈 적용 -Taming.SubSkill.SharpenedClaws.Name=날카로운 발톱 -Taming.SubSkill.SharpenedClaws.Description=추가 피해 +Taming.Ability.Bonus.8=패스트 푸드 서비스 +Taming.Ability.Bonus.9=공격 시 회복 확률 {0} +Taming.Ability.Bonus.10=성스러운 사냥개 +Taming.Ability.Bonus.11=마법 또는 독 피해를 받을 때 체력 회복 +Taming.Ability.Locked.0={0}+ 능력(환경 인식)까지 잠금 해제됨 +Taming.Ability.Locked.1={0}+ 능력(두꺼운 털)까지 잠금 해제됨 +Taming.Ability.Locked.2={0}+ 능력(내구성이 좋음)까지 잠금 해제됨 +Taming.Ability.Locked.3={0}+ 능력(올바르게 갈겨진 발톱)까지 잠금 해제됨 +Taming.Ability.Locked.4={0}+ 능력(패스트 푸드 서비스)까지 잠금 해제됨 +Taming.Ability.Locked.5={0}+ 능력(성스러운 사냥개)까지 잠금 해제됨 +Taming.Combat.Chance.Gore=피 피하기 확률 +Taming.SubSkill.BeastLore.Name=야수 지식 +Taming.SubSkill.BeastLore.Description=늑대와 오셀롯을 검토하면서 골격을 칩니다 +Taming.SubSkill.ShockProof.Name=내구성이 좋음 +Taming.SubSkill.ShockProof.Description=폭발 데미지 감소 +Taming.SubSkill.CallOfTheWild.Name=야생의 부름 +Taming.SubSkill.CallOfTheWild.Description=동물을 당신 곁으로 소환합니다 +Taming.SubSkill.CallOfTheWild.Description.2=&7COTW: 앉아서 왼쪽 버튼을 클릭하면\n {0} {1} (오셀롯), {2} {3} (늑대), {4} {5} (말)이 소환됩니다 +Taming.SubSkill.FastFoodService.Name=패스트 푸드 서비스 +Taming.SubSkill.FastFoodService.Description=늑대가 공격할 때 회복할 확률 +Taming.SubSkill.HolyHound.Name=성스러운 사냥개 +Taming.SubSkill.HolyHound.Description=마법 및 독으로 회복됩니다 +Taming.SubSkill.Gore.Name=피 피하기 +Taming.SubSkill.Gore.Description=파열을 적용하는 크리티컬 스트라이크 +Taming.SubSkill.SharpenedClaws.Name=올바르게 갈겨진 발톱 +Taming.SubSkill.SharpenedClaws.Description=피해 보너스 Taming.SubSkill.EnvironmentallyAware.Name=환경 인식 -Taming.SubSkill.EnvironmentallyAware.Description=선인장/용암 공포증, 낙사 피해 감소 +Taming.SubSkill.EnvironmentallyAware.Description=선인장/용암 공포증, 낙하 피해 면역 Taming.SubSkill.ThickFur.Name=두꺼운 털 -Taming.SubSkill.ThickFur.Description=피해 감소, 내화성(불저항력) -Taming.Listener.Wolf=&8늑대가 당신에게 되돌아감... -Taming.Listener=조련(TAMING): -Taming.SkillName=조련 -Taming.Skillup=조련 스킬이 {0} 올라 총 {1} 레벨이 되었습니다 -Taming.Summon.Complete=&a소환 완료 -Taming.Summon.Fail.Ocelot=당신 근처에 이미 많은 오셀롯이 있어 더는 소환시킬 수 없습니다. -Taming.Summon.Fail.Wolf=당신 근처에 이미 많은 늑대가 있어 더는 소환시킬 수 없습니다. -Taming.Summon.Fail.Horse=당신 근처에 이미 많은 말이 있어 더는 소환시킬 수 없습니다. -Taming.SubSkill.Pummel.Name=퍼멜 -Taming.SubSkill.Pummel.Description=당신의 늑대는 상대방을 넉백시킬 확률이 있습니다. -Taming.SubSkill.Pummel.TargetMessage=늑대에 의해 넉백당했습니다! -Taming.Summon.COTW.Success.WithoutLifespan=&a(Call Of The Wild) &7당신은 &6{0}&7을 소환했습니다. -Taming.Summon.COTW.Success.WithLifespan=&a(Call Of The Wild) &7당신은 &6{0}&7을 소환했으며, 지속 시간은 &6{1}&7초입니다. -Taming.Summon.COTW.Limit=&a(Call Of The Wild) &7동시에 소환할 수 있는 애완동물은 최대 &c{0}마리&7입니다. -Taming.Summon.COTW.TimeExpired=&a(Call Of The Wild) &7시간이 지났습니다. 당신의 &6{0}&7이(가) 떠납니다. -Taming.Summon.COTW.Removed=&a(Call Of The Wild) &7소환된 &6{0}&7이(가) 이 세상에서 사라졌습니다. -Taming.Summon.COTW.BreedingDisallowed=&a(Call Of The Wild) &c소환된 동물은 번식할 수 없습니다. -Taming.Summon.COTW.NeedMoreItems=&a(Call Of The Wild) &7더 필요한 아이템은 &e{0}&7개의 &3{1}&7입니다. -Taming.Summon.Name.Format=&6(COTW) &f{0}의 {1} - -#UNARMED -Unarmed.Ability.Berserk.Length=버서커 지속시간: &e{0}초 -Unarmed.Ability.Bonus.0=아이언 암 스타일 +Taming.SubSkill.ThickFur.Description=피해 감소, 화염 저항 +Taming.SubSkill.Pummel.Name=때리기 +Taming.SubSkill.Pummel.Description=늑대가 적을 밀치는 확률이 있습니다 +Taming.SubSkill.Pummel.TargetMessage=늑대에 의해 밀렸습니다! +Taming.Listener.Wolf=&8당신의 늑대가 당신에게로 달려옵니다... +Taming.Listener=길들이기: +Taming.SkillName=길들이기 +Taming.Summon.COTW.Success.WithoutLifespan=&a(야생의 부름) &7당신은 &6{0}&7을(를) 소환했습니다 +Taming.Summon.COTW.Success.WithLifespan=&a(야생의 부름) &7당신은 &6{0}&7을(를) 소환했고 지속 시간은 &6{1}&7초입니다. +Taming.Summon.COTW.Limit=&a(야생의 부름) &7동시에 &c{0} &7마리의 &7{1}을(를) 소환할 수 있습니다. +Taming.Summon.COTW.TimeExpired=&a(야생의 부름) &7시간이 지나갔습니다, 당신의 &6{0}&7이(가) 떠납니다. +Taming.Summon.COTW.Removed=&a(야생의 부름) &7당신이 소환한 &6{0}&7이(가) 이 세계에서 사라졌습니다. +Taming.Summon.COTW.BreedingDisallowed=&a(야생의 부름) &c소환된 동물을 번식할 수 없습니다. +Taming.Summon.COTW.NeedMoreItems=&a(야생의 부름) &7더 많은 &e{0}&7개의 &3{1}&7이(가) 필요합니다 +Taming.Summon.Name.Format=&6(야생의 부름) &f{0}의 {1} +#비무장 +Unarmed.Ability.Bonus.0=강철 팔 스타일 Unarmed.Ability.Bonus.1=+{0} 피해 업그레이드 -Unarmed.Ability.Chance.ArrowDeflect=화살 회피 확률: &e{0} -Unarmed.Ability.Chance.Disarm=비무장 확률: &e{0} -Unarmed.Ability.Chance.IronGrip=강철 주먹 확률: &e{0} -Unarmed.Ability.IronGrip.Attacker=상대는 강철 주먹을 가지고 있습니다! -Unarmed.Ability.IronGrip.Defender=&a강철 주먹의 비무장을 일시적으로 방어했습니다! -Unarmed.Ability.Lower=&7**손 준비 해제** -Unarmed.Ability.Ready=&a**손 준비 완료** -Unarmed.SubSkill.Berserk.Name=버서커 (능력) -Unarmed.SubSkill.Berserk.Description=+50% 피해, 약한 광물들을 부숨 -Unarmed.SubSkill.Disarm.Name=비무장 (플레이어) -Unarmed.SubSkill.Disarm.Description=적이 들고있는 아이템 드롭 -Unarmed.SubSkill.IronArmStyle.Name=강철 팔 형태 -Unarmed.SubSkill.IronArmStyle.Description=견고해지는 팔 -Unarmed.SubSkill.ArrowDeflect.Name=화살 회피 -Unarmed.SubSkill.ArrowDeflect.Description=회피 화살 -Unarmed.SubSkill.IronGrip.Name=아이언 그립 -Unarmed.SubSkill.IronGrip.Description=비무장 상태 방지 -Unarmed.Listener=비무장(UNARMED): -Unarmed.SkillName=비무장 -Unarmed.Skills.Berserk.Off=**버서커 발동 해제** -Unarmed.Skills.Berserk.On=&a**버서커 발동** -Unarmed.Skills.Berserk.Other.Off={0}&2님은 &c버서커를 사용했습니다! -Unarmed.Skills.Berserk.Other.On=&a{0}&2님은 &c버서커를 사용합니다! -Unarmed.Skills.Berserk.Refresh=&a당신의 &e버서커 &a스킬은 이제 사용 가능합니다! -Unarmed.Skillup=비무장 스킬이 {0} 올라 총 {1} 레벨이 되었습니다 -Unarmed.SubSkill.Berserk.Stat=버서커 지속시간 -Unarmed.SubSkill.Disarm.Stat=비무장 확률 +Unarmed.Ability.IronGrip.Attacker=상대방이 철제 손잡이를 가지고 있습니다! +Unarmed.Ability.IronGrip.Defender=&a철제 손잡이 덕분에 무장 해제를 막았습니다! +Unarmed.Ability.Lower=&7주먹을 내립니다. +Unarmed.Ability.Ready=&3주먹을 &6준비합니다&3. +Unarmed.SubSkill.Berserk.Name=광폭화 +Unarmed.SubSkill.Berserk.Description=+50% 피해, 약한 물체를 파괴합니다 +Unarmed.SubSkill.Berserk.Stat=광폭화 지속 시간 +Unarmed.SubSkill.Disarm.Name=무장 해제 +Unarmed.SubSkill.Disarm.Description=상대방이 손에 든 아이템을 떨어뜨립니다 +Unarmed.SubSkill.Disarm.Stat=무장 해제 확률 Unarmed.SubSkill.UnarmedLimitBreak.Name=비무장 한계 돌파 -Unarmed.SubSkill.UnarmedLimitBreak.Description=한계를 깨는 것. 강한 상대에 대한 향상된 피해. PVP를 위해 고안되었으며, PVE에서 피해 증가 여부는 서버 설정에 따라 다릅니다. +Unarmed.SubSkill.UnarmedLimitBreak.Description=한계를 돌파합니다. 강력한 상대에 대한 피해가 증가합니다. PVP를 위해 의도되었으며 PVE에서 피해를 증가시킬 것인지는 서버 설정에 따릅니다. Unarmed.SubSkill.UnarmedLimitBreak.Stat=한계 돌파 최대 피해 -Unarmed.SubSkill.SteelArmStyle.Name=강철 팔 형태 -Unarmed.SubSkill.SteelArmStyle.Description=견고해지는 팔 -Unarmed.SubSkill.ArrowDeflect.Stat=화살 회피 확률 -Unarmed.SubSkill.IronGrip.Stat=강철 주먹 확률 +Unarmed.SubSkill.SteelArmStyle.Name=강철 팔 스타일 +Unarmed.SubSkill.SteelArmStyle.Description=시간이 지남에 따라 팔을 강화합니다 +Unarmed.SubSkill.ArrowDeflect.Name=화살 방어 +Unarmed.SubSkill.ArrowDeflect.Description=화살을 튕깁니다 +Unarmed.SubSkill.ArrowDeflect.Stat=화살 방어 확률 +Unarmed.SubSkill.IronGrip.Name=철제 손잡이 +Unarmed.SubSkill.IronGrip.Description=무장 해제되지 않도록 합니다 +Unarmed.SubSkill.IronGrip.Stat=철제 손잡이 확률 Unarmed.SubSkill.BlockCracker.Name=블록 크래커 -Unarmed.SubSkill.BlockCracker.Description=주먹으로 바위 부수기 - -#WOODCUTTING -Woodcutting.Ability.0=나뭇잎 떨어트리기 -Woodcutting.Ability.1=나뭇잎 청소 -Woodcutting.Ability.Chance.DDrop=드롭 2배 확률: &e{0} -Woodcutting.Ability.Length=나무꾼 지속시간: &e{0}초 -Woodcutting.Ability.Locked.0={0}레벨 때 스킬이 해제됩니다 (나뭇잎 떨어트리기) -Woodcutting.SubSkill.TreeFeller.Name=나무꾼 (능력) -Woodcutting.SubSkill.TreeFeller.Description=나무 폭발시키기 -Woodcutting.SubSkill.LeafBlower.Name=나뭇잎 떨어트리기 -Woodcutting.SubSkill.LeafBlower.Description=나뭇잎 청소 -Woodcutting.SubSkill.HarvestLumber.Name=드롭 2배 -Woodcutting.SubSkill.HarvestLumber.Description=항상 드롭 2배 -Woodcutting.Listener=벌목(WOODCUTTING): -Woodcutting.SkillName=벌목 -Woodcutting.Skills.TreeFeller.Off=**나무꾼 발동 해제** -Woodcutting.Skills.TreeFeller.On=&a**나무꾼 발동** -Woodcutting.Skills.TreeFeller.Refresh=&a당신의 &e나무꾼 &a스킬은 이제 사용 가능합니다! -Woodcutting.Skills.TreeFeller.Other.Off={0}&2님은 &c나무꾼 스킬을 사용 해제했습니다! -Woodcutting.Skills.TreeFeller.Other.On=&a{0}&2님은 &c나무꾼 스킬을 사용했습니다! -Woodcutting.Skills.TreeFeller.Splinter=도끼 파편 조각 수집! -Woodcutting.Skills.TreeFeller.Threshold=그 나무는 너무 큽니다! -Woodcutting.Skillup=벌목 스킬이 {0} 올라 총 {1} 레벨이 되었습니다 -Woodcutting.SubSkill.TreeFeller.Stat=나무꾼 지속시간 -Woodcutting.SubSkill.KnockOnWood.Name=나무 두드리기 -Woodcutting.SubSkill.KnockOnWood.Description=나무꾼을 사용할 때 추가 아이템을 찾을 수 있습니다. -Woodcutting.SubSkill.KnockOnWood.Stat=나무 두드리기 -Woodcutting.SubSkill.KnockOnWood.Loot.Normal=나무에서 일반적인 아이템 획득 -Woodcutting.SubSkill.KnockOnWood.Loot.Rank2=나무에서 일반적인 아이템과 경험치 오브 획득 -Woodcutting.SubSkill.HarvestLumber.Stat=드롭 2배 확률 +Unarmed.SubSkill.BlockCracker.Description=주먹으로 바위를 부수세요 +Unarmed.Listener=비무장 전투: +Unarmed.SkillName=비무장 전투 +Unarmed.Skills.Berserk.Off=**광폭화가 사라졌습니다** +Unarmed.Skills.Berserk.On=&a**광폭화가 활성화되었습니다** +Unarmed.Skills.Berserk.Other.Off=광폭화&a가 &e{0}에게 종료되었습니다 +Unarmed.Skills.Berserk.Other.On=&a{0}&2님이 &c광폭화를 사용했습니다! +Unarmed.Skills.Berserk.Refresh=&a당신의 &e광폭화 &a능력이 갱신되었습니다! +#나무꾼 +Woodcutting.Ability.0=잎 블로워 +Woodcutting.Ability.1=잎을 날려 버립니다 +Woodcutting.Ability.Locked.0={0}+ 기술(잎 블로워)까지 잠금 해제됨 +Woodcutting.SubSkill.TreeFeller.Name=나무 패러 +Woodcutting.SubSkill.TreeFeller.Description=나무를 폭발시킵니다 +Woodcutting.SubSkill.TreeFeller.Stat=나무 패러 지속 시간 +Woodcutting.SubSkill.LeafBlower.Name=잎 블로워 +Woodcutting.SubSkill.LeafBlower.Description=잎을 날려 버립니다 +Woodcutting.SubSkill.KnockOnWood.Name=나무를 두드립니다 +Woodcutting.SubSkill.KnockOnWood.Description=나무 패러를 사용할 때 추가 아이템을 찾을 수 있습니다 +Woodcutting.SubSkill.KnockOnWood.Stat=나무를 두드림 +Woodcutting.SubSkill.KnockOnWood.Loot.Normal=나무에서 표준 전리품 +Woodcutting.SubSkill.KnockOnWood.Loot.Rank2=나무에서 표준 전리품과 경험의 오브 +Woodcutting.SubSkill.HarvestLumber.Name=목재 수확 +Woodcutting.SubSkill.HarvestLumber.Description=숙련된 기술로 더 많은 목재를 추출합니다 +Woodcutting.SubSkill.HarvestLumber.Stat=더블 드롭 확률 Woodcutting.SubSkill.Splinter.Name=파편 -Woodcutting.SubSkill.Splinter.Description=나무를 더 효율적으로 베어내세요. +Woodcutting.SubSkill.Splinter.Description=나무를 효율적으로 베어 내세요. Woodcutting.SubSkill.BarkSurgeon.Name=나무 껍질 수술 Woodcutting.SubSkill.BarkSurgeon.Description=나무 껍질을 벗길 때 유용한 재료를 추출하세요. -Woodcutting.SubSkill.NaturesBounty.Name=자연의 풍요 -Woodcutting.SubSkill.NaturesBounty.Description=자연에서 경험치를 모으세요. - -#ABILITIY - -#COMBAT -Combat.ArrowDeflect=&f**화살 회피** -Combat.BeastLore=&a**짐승의 포효** -Combat.BeastLoreHealth=&3체력: (&a{0}&3/{1}) -Combat.BeastLoreOwner=&3주인: (&c{0}&3) -Combat.Gore=&a**돌진** -Combat.StruckByGore=**돌진에 맞았습니다** -Combat.TargetDazed=목표가 &4혼란스러워합니다 -Combat.TouchedFuzzy=&4혼란이 일어났습니다. 아~ 어지러워. +Woodcutting.SubSkill.NaturesBounty.Name=자연의 축복 +Woodcutting.SubSkill.NaturesBounty.Description=자연으로부터 경험치를 얻으세요. +Woodcutting.Listener=나무꾼: +Woodcutting.SkillName=나무꾼 +Woodcutting.Skills.TreeFeller.Off=**나무 패러가 사라졌습니다** +Woodcutting.Skills.TreeFeller.On=&a**나무 패러가 활성화되었습니다** +Woodcutting.Skills.TreeFeller.Refresh=&a당신의 &e나무 패러 &a능력이 갱신되었습니다! +Woodcutting.Skills.TreeFeller.Other.Off=나무 패러&a가 &e{0}에게 종료되었습니다 +Woodcutting.Skills.TreeFeller.Other.On=&a{0}&2님이 &c나무 패러를 사용했습니다! +Woodcutting.Skills.TreeFeller.Splinter=당신의 도끼가 수십 개의 조각으로 깨졌습니다! +Woodcutting.Skills.TreeFeller.Threshold=그 나무는 너무 큽니다! +#전투 +Combat.ArrowDeflect=&f**화살 방어** +Combat.BeastLore=&a**야수 지식** +Combat.BeastLoreHealth=&3체력 (&a{0}&3/{1}) +Combat.BeastLoreOwner=&3주인 (&c{0}&3) Combat.BeastLoreHorseSpeed=&3말 이동 속도 (&a{0} 블록/초&3) Combat.BeastLoreHorseJumpStrength=&3말 점프 강도 (&a최대 {0} 블록&3) +Combat.Gore=&a**찔림** +Combat.StruckByGore=**당신은 찔렸습니다** +Combat.TargetDazed=대상이 &4현기를 잃었습니다 +Combat.TouchedFuzzy=&4털에 닿았습니다. 어지러웠습니다. -#COMMANDS -##generic -mcMMO.Description=mcMMO&3 프로젝트에 대해서:,&6mcMMO는 한 &c오픈 소스&6 RPG 모드로 2011년 2월에 &9nossr50&6님이 만들었습니다. 목표는 질좋은 RPG 경험을 제공하는 것 입니다.,&3팁:,&6 - &c/mcmmo help&a 명령어들을 봅니다,&6 - &a타입 &c/스킬이름&a 자세한 스킬 정보를 봅니다,&3개발자들:,&6 - &anossr50 &9(제작자),&6 - &aGJ &9(프로젝트 주장),&6 - &aNuclearW &9(개발자),&6 - &abm01 &9(개발자),&6 - &aTfT_02 &9(개발자),&6 - &aGlitchfinder &9(개발자),&6 - &at00thpick1 &9(개발자),&3유용한 링크:,&6 - &ahttps://github.com/mcMMO-Dev/mcMMO/issues&6 버그 보고,&6 - &a#mcmmo @ irc.esper.net&6 IRC 채팅, +#커멘드 +##일반적인 +mcMMO.Description=&3&emcMMO&3 프로젝트에 대해:,&6mcMMO는 2011년 2월에 &c오픈 소스&6 RPG 모드로 생성되었습니다,&6nossr50&6에 의해. 목표는 품질 높은 RPG 경험을 제공하는 것입니다.,&3팁:,&6 - &a/mcmmo help&a 명령어를 사용하여 명령어를 확인하세요,&6 - &a/SKILLNAME&a 을(를) 입력하여 자세한 스킬 정보를 확인하세요,&3개발자:,&6 - &anossr50 &9(창조자 및 프로젝트 리드),&6 - &aelectronicboy &9(개발자),&6 - &akashike &9(개발자),&6 - &at00thpick1 &9(클래식 관리자) mcMMO.Description.FormerDevs=&3이전 개발자: &aGJ, NuclearW, bm01, TfT_02, Glitchfinder -Commands.addlevels.AwardAll.1=&a당신은 모든 스킬에 {0} 레벨을 지급했습니다! -Commands.addlevels.AwardAll.2=모든 스킬이 {0}로 변경되었습니다 -Commands.addlevels.AwardSkill.1=&a당신은 {0} 레벨을 {1}에 지급하였습니다! -Commands.addlevels.AwardSkill.2={1} 님은 {0}을/를 수정하였습니다 -Commands.addxp.AwardAll=&a당신은 모든 스킬에 {0} 경험치를 지급했습니다! -Commands.addxp.AwardSkill=&a당신은 {0} 경험치를 {1}에 지급하였습니다! -Commands.Ability.Off=능력 사용이 &c꺼졌습니다 -Commands.Ability.On=능력 사용이 &a켜졌습니다 -Commands.Ability.Toggle=능력 사용은 &e{0}(으)로 전환되었습니다 -Commands.AdminChat.Off=관리자 채팅이 &c꺼졌습니다 -Commands.AdminChat.On=관리자 채팅이 &a켜졌습니다 -Commands.AdminToggle=&a- 관리자 채팅을 켜기/끄기합니다 -Commands.Chat.Console=*시스템* -Commands.Cooldowns.Header=&6--= &amcMMO 능력 재 사용 대기시간&6 =-- -Commands.Cooldowns.Row.N=\ &c{0}&f - &6{1}초 남음 -Commands.Cooldowns.Row.Y=\ &b{0}&f - &2준비! -Commands.Database.Cooldown=이 명령어를 다시 치기전에 1초를 기달려야만 합니다. -Commands.Database.Processing=당신의 이전 명령어가 여전히 실행 중입니다. 기다려주세요. -Commands.Database.CooldownMS=이 명령어를 다시 사용하기 전에 {0} 밀리초를 기다려야 합니다. -Commands.Disabled=이 명령어는 비활성화 되있습니다. -Commands.DoesNotExist= &c플레이어가 데이터베이스에 존재하지 않습니다! -Commands.AdminChatSpy.Enabled=mcMMO 파티 채팅 감시가 활성화되었습니다. -Commands.AdminChatSpy.Disabled=mcMMO 파티 채팅 감시가 비활성화되었습니다. -Commands.AdminChatSpy.Toggle=mcMMO 파티 채팅 감시가 &e{0}&6님에 의해 토글되었습니다. -Commands.AdminChatSpy.Chat=&6[감시: &a{0}&6] &f{1} -Commands.GodMode.Disabled=mcMMO 불사신 모드 비활성화 -Commands.GodMode.Enabled=mcMMO 불사신 모드 활성화 -Commands.GodMode.Forbidden=[mcMMO] 이 월드에서 불사신 모드는 허용 금지입니다 (펄미션을 확인하세요) -Commands.GodMode.Toggle=불사신 모드는 &e{0}&f(으)로 전환되었습니다 -Commands.Healthbars.Changed.HEARTS=[mcMMO] 당신의 체력바 보기 방식은 &c하트&f로 변경되었습니다. -Commands.Healthbars.Changed.BAR=[mcMMO] 당신의 체력바 보기 방식은 &e박스&f로 변경되었습니다. -Commands.Healthbars.Changed.DISABLED=[mcMMO] 당신의 몹 체력바는 &7비활성화&f 되었습니다. -Commands.Healthbars.Invalid=잘못된 체력바 타입! -Commands.Inspect=<플레이어> &a- 상세한 플레이어 정보를 봅니다 -Commands.Invite.Success=&a초대를 성공적으로 보냈습니다. -Commands.Leaderboards=<스킬> <페이지> &a- mcMMO 스킬 정보 -Commands.mcc.Header=---[]&amcMMO 명령어&c[]--- -Commands.mcgod=&a- 불사신 모드 켜기/끄기 -Commands.mchud.Invalid=HUD 타입이 올바르지 않습니다. -Commands.mcpurge.Success=&a데이터베이스가 성공적으로 초기화됬습니다! +Commands.addlevels.AwardAll.1=&a모든 스킬에 {0} 레벨이 수여되었습니다! +Commands.addlevels.AwardAll.2=모든 스킬에 {0}이(가) 수정되었습니다. +Commands.addlevels.AwardSkill.1=&a{1} 스킬에서 {0} 레벨이 수여되었습니다! +Commands.addlevels.AwardSkill.2={1}에서 {0}이(가) 수정되었습니다. +Commands.addxp.AwardAll=&a모든 스킬에 {0} 경험이 주어졌습니다! +Commands.addxp.AwardSkill=&a{1} 스킬에 {0} 경험이 주어졌습니다! +Commands.Ability.Off=능력 사용이 &c비활성화&f되었습니다 +Commands.Ability.On=능력 사용이 &a활성화&f되었습니다 +Commands.Ability.Toggle=능력 사용이 &e{0}&f에 대해 전환되었습니다 +Commands.AdminChat.Off=어드민 채팅 전용 &c비활성화&f됨 +Commands.AdminChat.On=어드민 채팅 전용 &a활성화&f됨 +Commands.AdminToggle=&a- 어드민 채팅 전환 +Commands.Chat.Console=*콘솔* +Commands.Cooldowns.Header=&6--= &amcMMO 능력 쿨다운&6 =-- +Commands.Cooldowns.Row.N=\ &c{0}&f - &6남은 시간: {1} 초 +Commands.Cooldowns.Row.Y=\ &b{0}&f - &2준비 완료! +Commands.Database.CooldownMS=이 명령을 다시 사용하기 전에 {0} 밀리초를 기다려야 합니다. +Commands.Database.Cooldown=이 명령을 다시 사용하기 전에 {0} 초를 기다려야 합니다. +Commands.Database.Processing=이전 명령이 아직 처리 중입니다. 기다려 주십시오. +Commands.Disabled=이 명령은 비활성화되었습니다. +Commands.DoesNotExist= &c플레이어가 데이터베이스에 없습니다! +Commands.GodMode.Disabled=mcMMO 갓 모드 비활성화됨 +Commands.GodMode.Enabled=mcMMO 갓 모드 활성화됨 +Commands.AdminChatSpy.Enabled=mcMMO 파티 채팅 감시 활성화됨 +Commands.AdminChatSpy.Disabled=mcMMO 파티 채팅 감시 비활성화됨 +Commands.AdminChatSpy.Toggle=mcMMO 파티 채팅이 &e{0}&f에 대해 전환되었습니다 +Commands.AdminChatSpy.Chat=&6[SPY: &a{0}&6] &f{1} +Commands.GodMode.Forbidden=[mcMMO] 이 월드에서 갓 모드가 허용되지 않습니다 (권한 참조) +Commands.GodMode.Toggle=갓 모드가 &e{0}&f에 대해 전환되었습니다 +Commands.Healthbars.Changed.HEARTS=[mcMMO] 건강 막대 표시 유형이 &c하트&f로 변경되었습니다. +Commands.Healthbars.Changed.BAR=[mcMMO] 건강 막대 표시 유형이 &e상자&f로 변경되었습니다. +Commands.Healthbars.Changed.DISABLED=[mcMMO] 몹의 건강 막대가 &7비활성화&f되었습니다. +Commands.Healthbars.Invalid=유효하지 않은 건강 막대 유형입니다! +Commands.Inspect=<플레이어> &a- 자세한 플레이어 정보 보기 +Commands.Invite.Success=&a초대가 성공적으로 전송되었습니다. +Commands.Leaderboards=<스킬> <페이지> &a- 리더보드 +Commands.mcgod=&a- 갓 모드 전환 +Commands.mchud.Invalid=유효하지 않은 HUD 유형입니다. +Commands.mcpurge.Success=&a데이터베이스가 성공적으로 정리되었습니다! Commands.mcrank.Heading=&6-=개인 순위=- -Commands.mcrank.Overall=종합&a - &6랭크 &f#&a{0} -Commands.mcrank.Player=타겟: &f{0} -Commands.mcrank.Skill={0}&a - &6랭크 &f#&a{1} -Commands.mcrank.Unranked=&f랭크없음 -Commands.mcrefresh.Success={0}의 쿨다운이 초기화되었습니다. -Commands.mcremove.Success=&a{0}님의 데이터베이스가 성공적으로 삭제되었습니다! -Commands.mctop.Tip=&6팁: &c/mcrank&6 명령어를 사용하면 모든 개인 순위를 볼수 있습니다! -Commands.mmoedit=[플레이어] <스킬> <새값> &a - 대상을 수정합니다 -Commands.mmoedit.AllSkills.1=&a당신의 모든 스킬 레벨이 {0}로 설정되었습니다! -Commands.mmoedit.Modified.1=&a당신의 {0} 레벨이 {1}로 설정되었습니다! -Commands.mmoedit.Modified.2={0}님은 {1}를 수정했습니다. -Commands.mcconvert.Database.Same=당신은 이미 {0} 데이터베이스를 사용중입니다! -Commands.mcconvert.Database.InvalidType={0} 은/는 잘못된 데이터베이스 타입입니다. -Commands.mcconvert.Database.Start=&7{0}에서 {1}(으)로 전환 시작중... -Commands.mcconvert.Database.Finish=&7데이터베이스 이동 완료; {1} 데이터베이스는 이제 {0} 데이터베이스로부터 모든 자료를 가집니다. -Commands.mmoshowdb=현재 사용하는 데이터베이스: &a{0} -Commands.mcconvert.Experience.Invalid=잘못된 공식 타입! 올바른 타입: &aLINEAR &c그리고 &aEXPONENTIAL. -Commands.mcconvert.Experience.Same=이미 {0} 공식을 사용중입니다 -Commands.mcconvert.Experience.Start=&7{0} 에서 {1} 곡선으로 변환 시작 -Commands.mcconvert.Experience.Finish=&7공식 변환 완료; 이제 {0} XP 곡선입니다. -Commands.ModDescription=&a- 플러그인에 대한 정보를 봅니다 -Commands.NoConsole=이 명령어는 콘솔에서의 사용을 지원하지 않습니다. -Commands.Notifications.Off=능력 알림이 &c켜졌습니다 -Commands.Notifications.On=능력 알림이 &a꺼졌습니다 -Commands.Offline=이 명령어는 오프라인 플레이어에게 동작하지 않습니다. -Commands.NotLoaded=플레이어 프로파일을 아직 불러오지 못했습니다. -Commands.Other=---[]&a기타 명령어&c[]--- -Commands.Party.Header=-----[]&a파티&c[]----- -Commands.Party.Features.Header=-----[]&a특징&c[]----- +Commands.mcrank.Overall=종합&a - &6순위 &f#&a{0} +Commands.mcrank.Player=&e{0}에 대한 순위 +Commands.mcrank.Skill=&e{0}&a - &6순위 &f#&a{1} +Commands.mcrank.Unranked=&f순위 없음 +Commands.mcrefresh.Success={0}의 쿨다운이 새로 고쳐졌습니다. +Commands.mcremove.Success=&a{0}가 데이터베이스에서 성공적으로 제거되었습니다! +Commands.mctop.Tip=&6팁: 모든 개인 순위를 보려면 &c/mcrank&6을(를) 사용하세요! +Commands.mmoedit=[플레이어] <스킬> <새값> &a - 대상 수정 +Commands.mmoedit.AllSkills.1=모든 스킬의 레벨이 {0}(으)로 설정되었습니다! +Commands.mmoedit.Modified.1={0}의 레벨이 {1}(으)로 설정되었습니다! +Commands.mmoedit.Modified.2={0}이(가) {1}로 수정되었습니다. +Commands.mcconvert.Database.Same=이미 {0} 데이터베이스를 사용 중입니다! +Commands.mcconvert.Database.InvalidType={0}은(는) 유효하지 않은 데이터베이스 유형입니다. +Commands.mcconvert.Database.Start=&7{0}에서 {1}(으)로 변환 시작 중... +Commands.mcconvert.Database.Finish=&7데이터베이스 마이그레이션이 완료되었습니다; {1} 데이터베이스에는 이제 {0} 데이터베이스의 모든 데이터가 포함되어 있습니다. +Commands.mmoshowdb=현재 사용 중인 데이터베이스는 &a{0}&f입니다 +Commands.mcconvert.Experience.Invalid=알 수 없는 공식 유형! 유효한 유형은 다음과 같습니다: &aLINEAR 및 &aEXPONENTIAL. +Commands.mcconvert.Experience.Same=이미 {0} 공식 유형을 사용 중입니다 +Commands.mcconvert.Experience.Start=&7{0}에서 {1} 곡선으로 변환 시작 중 +Commands.mcconvert.Experience.Finish=&7공식 변환 완료; 이제 {0} 경험 곡선을 사용합니다. +Commands.ModDescription=&a- 간단한 모드 설명 읽기 +Commands.NoConsole=이 명령은 콘솔 사용을 지원하지 않습니다. +Commands.Notifications.Off=능력 알림이 &c비활성화&f되었습니다 +Commands.Notifications.On=능력 알림이 &a활성화&f되었습니다 +Commands.Offline=이 명령은 오프라인 플레이어에게 작동하지 않습니다. +Commands.NotLoaded=플레이어 프로필이 아직 로드되지 않았습니다. Commands.Party.Status=&8이름: &f{0} {1} &8레벨: &3{2} Commands.Party.Status.Alliance=&8동맹: &f{0} -Commands.Party.UnlockedFeatures=&8해제된 특징: &7&o{0} +Commands.Party.UnlockedFeatures=&8잠금 해제된 기능: &7&o{0} Commands.Party.ShareMode=&8공유 모드: Commands.Party.ItemShare=&7아이템 &3({0}) -Commands.Party.ExpShare=&7EXP &3({0}) -Commands.Party.ItemShareCategories=&8공유중인 아이템: &7&o{0} -Commands.Party.MembersNear=&8당신의 근처 &3{0}&8/&3{1} -Commands.Party.Accept=&a- 파티 초대 허용 -Commands.Party.Chat.Off=파티 채팅을 &c끕니다 -Commands.Party.Chat.On=파티 채팅을 &a켭니다 -Commands.Party.Commands=---[]&a파티 명령어&c[]--- -Commands.Party.Invite.0=알림: &a당신은 {1} 님으로부터 {0} 파티 초대에 권유받았습니다 -Commands.Party.Invite.1=타입 &a/party accept&e 명령어를 치면 파티 초대에 승낙됩니다 -Commands.Party.Invite=<플레이어> &a- 파티 초대를 보냅니다 -Commands.Party.Invite.Accepted=&a초대 수락됨. 당신은 {0} 파티에 가입되었습니다 -Commands.Party.Join=참여된 파티: {0} -Commands.Party.Create=&7만들어진 파티: {0} -Commands.Party.Rename=&7변경된 파티 이름: &f{0} +Commands.Party.ExpShare=&7경험치 &3({0}) +Commands.Party.ItemShareCategories=&8아이템 공유: &7&o{0} +Commands.Party.MembersNear=&8근처 플레이어 &3{0}&8/&3{1} +Commands.Party.Accept=&a- 파티 초대 수락 +Commands.Party.Chat.Off=파티 채팅 전용 &c비활성화 +Commands.Party.Chat.On=파티 채팅 전용 &a활성화 +Commands.Party.Commands=&c---[]&a파티 명령어&c[]--- +Commands.Party.Invite.0=&c알림: &a{1}님이 {0}으로부터 파티 초대를 받았습니다. +Commands.Party.Invite.1=&e파티 초대를 수락하려면 &a/party accept&e를 입력하세요. +Commands.Party.Invite=&a- 파티 초대 전송 +Commands.Party.Invite.Accepted=&a초대가 수락되었습니다. {0} 파티에 가입했습니다. +Commands.Party.Join=&7파티에 가입: {0} +Commands.Party.PartyFull=&6{0}&c 파티가 가득 찼습니다! +Commands.Party.PartyFull.Invite=이미 &a{1}&c에 &e{0}&c을(를) 초대했습니다. 이미 &3{2}&c명이 이 파티에 있습니다! +Commands.Party.PartyFull.InviteAccept=&a{0}&c 파티에 가입할 수 없습니다. 이미 &3{1}&c명이 이 파티에 있습니다! +Commands.Party.Create=&7파티 생성: {0} +Commands.Party.Rename=&7파티 이름이 다음으로 변경되었습니다: &f{0} Commands.Party.SetSharing=&7파티 {0} 공유 설정: &3{1} -Commands.Party.ToggleShareCategory=&7파티 아이템 공유 &6{0} &7가 &3{1}되었습니다 -Commands.Party.AlreadyExists=&4{0} 파티은/는 이미 존재합니다! -Commands.Party.Kick=당신은 {0} 파티에서 추방 당하였습니다. -Commands.Party.Leave=파티를 떠났습니다 -Commands.Party.Members.Header=-----[]&a맴버들&c[]----- -Commands.Party.None=당신은 파티에 참여되어 있지 않습니다. -Commands.Party.Quit=&a- 현재 참여 되어있는 파티를 나갑니다 -Commands.Party.Teleport=&a- 파티 맴버한테 텔레포트합니다 -Commands.Party.Toggle=&a- 파티 채팅을 켜기/끄기 합니다 -Commands.Party1=&a- 새 파티를 만듭니다 -Commands.Party2=&a- 플레이어가 파티에 가입합니다 -Commands.Party.Alliance.Header=-----[]&a파티 동맹&c[]----- -Commands.Party.Alliance.Ally=&f{0} &8파티의 동맹: &f{1} -Commands.Party.Alliance.Members.Header=-----[]&a동맹 구성원&c[]----- -Commands.Party.Alliance.Invite.0=알림: &a{1} 파티로부터 {0} 파티와의 동맹 초대를 받았습니다 -Commands.Party.Alliance.Invite.1=타입 &a/party alliance accept&e 초대에 수락합니다 -Commands.Party.Alliance.Invite.Accepted=&a동맹 초대 수락됨. -Commands.Party.Alliance.None=당신은 동맹을 가지고 있지 않습니다. -Commands.Party.Alliance.AlreadyAllies=당신의 파티는 이미 동맹을 가지고 있습니다. 관계를 해지하려면 &3/party alliance disband -Commands.Party.Alliance.Help.0=이 파티는 동맹 형태를 가지고 있지 않습니다. 파티장을 초대하세요 -Commands.Party.Alliance.Help.1= 동맹을 하려면 &3/party alliance invite &c. -Commands.ptp.Enabled=파티 텔레포트 &a활성화됨 -Commands.ptp.Disabled=파티 텔레포트 &c비활성화됨 -Commands.ptp.NoRequests=당신은 이 시간에 텔레포트 요청을 하실 수 없습니다 -Commands.ptp.NoWorldPermissions=[mcMMO] 당신은 월드 {0}(으)로 텔레포트할 권한이 없습니다. -Commands.ptp.Request1={0} &a님이 당신에게 텔레포트를 신청했습니다. -Commands.ptp.Request2=&a텔레포트하려면, 타입 &e/ptp accept&a. &c{0}&a초에 요청이 만기됩니다. +Commands.Party.ToggleShareCategory=&7파티 &6{0} &7의 아이템 공유가 &3{1}&7로 변경되었습니다. +Commands.Party.AlreadyExists=&4파티 {0}이(가) 이미 존재합니다! +Commands.Party.Kick=&c{0}&c님이 파티에서 추방되었습니다: &a{1}&c! +Commands.Party.Leave=&e현재 파티를 나갔습니다 +Commands.Party.Members.Header=&c-----[]&a파티 멤버&c[]----- +Commands.Party.None=&c파티에 속해 있지 않습니다. +Commands.Party.Quit=&a- 현재 파티 나가기 +Commands.Party.Teleport=&a- 파티 멤버로 이동 +Commands.Party.Toggle=&a- 파티 채팅 전환 +Commands.Party1=&a- 새로운 파티 생성 +Commands.Party2=&a- 플레이어의 파티 가입 +Commands.Party.Alliance.Header=&c-----[]&a파티 동맹&c[]----- +Commands.Party.Alliance.Ally=&f{0} &8동맹: &f{1} +Commands.Party.Alliance.Members.Header=&c-----[]&a동맹 멤버&c[]----- +Commands.Party.Alliance.Invite.0=알림: &a{1}님이 {0}으로부터 파티 동맹 초대를 받았습니다. +Commands.Party.Alliance.Invite.1=파티 동맹 초대를 수락하려면 &a/party alliance accept&e를 입력하세요. +Commands.Party.Alliance.Invite.Accepted=&a파티 동맹 초대가 수락되었습니다. +Commands.Party.Alliance.None=&c파티에 동맹이 없습니다. +Commands.Party.Alliance.AlreadyAllies=&c파티에 이미 동맹이 있습니다. &3/party alliance disband&c로 해체하세요. +Commands.Party.Alliance.Help.0=&c이 파티는 아직 동맹을 맺지 않았습니다. 파티 리더를 초대하여 +Commands.Party.Alliance.Help.1=&c 동맹을 맺으세요. &3/party alliance invite <플레이어>&c. +Commands.ptp.Enabled=파티 텔레포팅 &a활성화됨 +Commands.ptp.Disabled=파티 텔레포팅 &c비활성화됨 +Commands.ptp.NoRequests=&c현재 텔레포트 요청이 없습니다. +Commands.ptp.NoWorldPermissions=&c[mcMMO] 월드 {0}로 텔레포트할 권한이 없습니다. +Commands.ptp.Request1=&e{0} &a님이 당신에게 텔레포트를 요청했습니다. +Commands.ptp.Request2=&a텔레포트하려면 &e/ptp accept&a를 입력하세요. 요청은 &c{0} &a초 후 만료됩니다. Commands.ptp.AcceptAny.Enabled=파티 텔레포트 요청 확인 &a활성화됨 Commands.ptp.AcceptAny.Disabled=파티 텔레포트 요청 확인 &c비활성화됨 -Commands.ptp.RequestExpired=파티 텔레포트 요청이 만기됨! -Commands.PowerLevel.Leaderboard=--mcMMO&9 총 레벨 &e점수표-- -Commands.PowerLevel.Capped=&4총 레벨: &a{0} &4최대 레벨: &e{1} -Commands.PowerLevel=&4총 레벨: &a{0} -Commands.Reset.All=&a당신의 모든 스킬이 성공적으로 초기화되었습니다. -Commands.Reset.Single=&a당신의 {0} 스킬이 성공적으로 초기화되었습니다. -Commands.Reset=&a스킬 레벨을 0으로 초기화 시킵니다 -Commands.Scoreboard.Clear=&3mcMMO 점수판 청소됨. -Commands.Scoreboard.NoBoard=mcMMO 점수판이 활성화 되어있지 않음. -Commands.Scoreboard.Keep=&3mcMMO 점수판은 당신이 &a/mcscoreboard clear&3를 사용할 때까지 유지될 것임. -Commands.Scoreboard.Timer=&3mcMMO 점수판은 지금으로부터 &6{0}&3초 내에 청소될 예정임. -Commands.Scoreboard.Help.0=&6 == &c/mcscoreboard &a도움말&6 == -Commands.Scoreboard.Help.1=&3/mcscoreboard&b clear &f - McMMO 점수판을 청소함 -Commands.Scoreboard.Help.2=&3/mcscoreboard&b keep &f - McMMO 점수판을 유지함 -Commands.Scoreboard.Help.3=&3/mcscoreboard&b time [n] &f - McMMO 점수판을 &dn&f초 후에 청소함 -Commands.Scoreboard.Tip.Keep=&6팁: &c/mcscoreboard keep&6 점수판을 보이게 항상 유지. -Commands.Scoreboard.Tip.Clear=&6팁: &c/mcscoreboard clear&6 점수판 감춤. -Commands.Skill.Invalid=잘못된 스킬 이름 입니다! -Commands.Skill.ChildSkill=이 명령어에는 부가 스킬을 사용할 수 없습니다! -Commands.Skill.Leaderboard=--mcMMO &9{0}&e 점수표-- -Commands.SkillInfo=&a- 스킬에 대한 자세한 정보를 봅니다 -Commands.Stats.Self=당신의 통계 -Commands.Stats=&a- 당신의 mcMMO 통계 보기 -Commands.ToggleAbility=&a- 우클릭시 사용되는 스킬들을 켜기/끄기 합니다 -Commands.Usage.0=올바른 사용법 /{0} -Commands.Usage.1=올바른 사용법 /{0} {1} -Commands.Usage.2=올바른 사용법 /{0} {1} {2} -Commands.Usage.3=올바른 사용법 /{0} {1} {2} {3} -Commands.Usage.3.XP=&c올바른 사용법은 /{0} {1} {2} {3}&7입니다 (명령어를 실행한 플레이어에게 알리지 않고 실행하려면 끝에 -s를 포함시킬 수 있습니다) -Commands.Usage.FullClassName=클레스이름 +Commands.ptp.RequestExpired=&c파티 텔레포트 요청이 만료되었습니다! +Commands.PowerLevel.Leaderboard=&e--mcMMO&9 파워 레벨 &e리더보드-- +Commands.PowerLevel.Capped=&4파워 레벨: &a{0} &4최대 레벨: &e{1} +Commands.PowerLevel=&4파워 레벨: &a{0} +Commands.Reset.All=&a모든 스킬 레벨이 성공적으로 재설정되었습니다. +Commands.Reset.Single=&a{0} 스킬 레벨이 성공적으로 재설정되었습니다. +Commands.Reset=&a- 스킬 레벨을 0으로 재설정 +Commands.Scoreboard.Clear=&3mcMMO 스코어보드가 지워졌습니다. +Commands.Scoreboard.NoBoard=&cmcMMO 스코어보드가 활성화되지 않았습니다. +Commands.Scoreboard.Keep=&3mcMMO 스코어보드가 사용 중입니다. &a/mcscoreboard clear&3를 사용하여 제거하세요. +Commands.Scoreboard.Timer=&3mcMMO 스코어보드가 &6{0}&3초 후에 사라집니다. +Commands.Scoreboard.Help.0=&6 == &a/mcscoreboard&6 도움말 == +Commands.Scoreboard.Help.1=&3/mcscoreboard&b clear &f - mcMMO 스코어보드를 지웁니다. +Commands.Scoreboard.Help.2=&3/mcscoreboard&b keep &f - mcMMO 스코어보드를 유지합니다. +Commands.Scoreboard.Help.3=&3/mcscoreboard&b time [n] &f - mcMMO 스코어보드를 &d[n]&f초 후에 지웁니다. +Commands.Scoreboard.Tip.Keep=&6팁: 스코어보드가 표시된 상태에서 &c/mcscoreboard keep&6을 사용하여 보여지도록 유지하세요. +Commands.Scoreboard.Tip.Clear=&6팁: 스코어보드를 제거하려면 &c/mcscoreboard clear&6를 사용하세요. +Commands.XPBar.Reset=&6mcMMO의 XP 바 설정이 재설정되었습니다. +Commands.XPBar.SettingChanged=&6{0}&a의 XP 바 설정이 &a{1}&a(으)로 변경되었습니다. +Commands.Skill.Invalid=유효하지 않은 스킬명입니다! +Commands.Skill.ChildSkill=이 명령어에 대한 하위 스킬은 유효하지 않습니다! +Commands.Skill.Leaderboard=--mcMMO &9{0}&e 리더보드-- +Commands.SkillInfo=&a- 스킬 또는 기능에 대한 자세한 정보 보기 +Commands.Stats=&a- 당신의 mcMMO 스탯 보기 +Commands.ToggleAbility=&a- 우클릭으로 능력 활성화/비활성화 토글 +Commands.Usage.0=&c올바른 사용법은 /{0}입니다. +Commands.Usage.1=&c올바른 사용법은 /{0} {1}입니다. +Commands.Usage.2=&c올바른 사용법은 /{0} {1} {2}입니다. +Commands.Usage.3=&c올바른 사용법은 /{0} {1} {2} {3}입니다. +Commands.Usage.3.XP=&c올바른 사용법은 /{0} {1} {2} {3}&7입니다 (플레이어에게 알리지 않고 명령어를 실행하려면 마지막에 -s를 포함시킵니다). +Commands.Usage.FullClassName=클래스명 Commands.Usage.Level=레벨 -Commands.Usage.Message=메세지 +Commands.Usage.Message=메시지 Commands.Usage.Page=페이지 Commands.Usage.PartyName=이름 Commands.Usage.Password=비밀번호 Commands.Usage.Player=플레이어 -Commands.Usage.Rate=배율 +Commands.Usage.Rate=비율 Commands.Usage.Skill=스킬 -Commands.Usage.SubSkill=부가 스킬 -Commands.Usage.XP=xp -Commands.XPBar.Reset=&6mcMMO의 XP 바 설정이 초기화되었습니다. -Commands.XPBar.SettingChanged=&6{0}&6의 XP 바 설정이 &a{1}&6로 변경되었습니다. -Commands.Description.mmoinfo=스킬 또는 메커니즘에 대한 자세한 정보를 읽습니다. -Commands.MmoInfo.Mystery=&7아직 이 스킬을 해금하지 않았지만, 해금하면 여기에서 자세한 정보를 읽을 수 있습니다! -Commands.MmoInfo.NoMatch=해당 부가 스킬이 존재하지 않습니다! +Commands.Usage.SubSkill=하위 스킬 +Commands.Usage.XP=경험치 +Commands.Description.mmoinfo=스킬 또는 기능에 대한 자세한 정보를 읽으세요. +Commands.MmoInfo.Mystery=&7아직이 스킬을 잠금 해제하지 않았지만, 잠금 해제하면 여기에서 자세한 정보를 읽을 수 있습니다! +Commands.MmoInfo.NoMatch=그런 하위 스킬은 존재하지 않습니다! Commands.MmoInfo.Header=&3-=[]=====[]&6 MMO 정보 &3[]=====[]=- Commands.MmoInfo.SubSkillHeader=&6이름:&e {0} -Commands.MmoInfo.DetailsHeader=&3-=[]=====[]&a 자세한 내용 &3[]=====[]=- -Commands.MmoInfo.OldSkill=&7mcMMO 스킬은 개선된 모듈식 스킬 시스템으로 변환되고 있습니다. 불행히도 이 스킬은 아직 변환되지 않았으며 자세한 통계가 없습니다. 새로운 시스템은 새로운 mcMMO 스킬을 더 빠르게 출시하고 기존 스킬에 대한 유연성을 높일 수 있게 해줍니다. -Commands.MmoInfo.Mechanics=&3-=[]=====[]&6 메커니즘 &3[]=====[]=- +Commands.MmoInfo.DetailsHeader=&3-=[]=====[]&a 상세 정보 &3[]=====[]=- +Commands.MmoInfo.OldSkill=&7mcMMO 스킬은 개선된 모듈식 스킬 시스템으로 변환되고 있으며, 이 스킬은 아직 변환되지 않아 상세한 통계가 없습니다. 새로운 시스템에서는 새로운 mcMMO 스킬의 빠른 출시와 기존 스킬의 유연성이 향상될 것입니다. +Commands.MmoInfo.Mechanics=&3-=[]=====[]&6 기계 &3[]=====[]=- Commands.MmoInfo.Stats=통계: {0} -Commands.Mmodebug.Toggle=mcMMO 디버그 모드가 &6{0}&7되었습니다. 디버그 모드를 활성화하면 지원을 위해 유용한 정보를 얻기 위해 블록을 클릭할 수 있습니다. -mcMMO.NoInvites=이 시간에 당신은 초대하지 못합니다 -mcMMO.NoPermission=&4권한이 부족합니다. -mcMMO.NoSkillNote=&8만약 당신이 스킬을 사용할 수 없다면 여기에 표시되지 않습니다. - - - -##party -Party.Forbidden=[mcMMO] 이 월드에서 파티를 하실 수 없습니다 (펄미션을 확인하세요) -Party.Help.0=올바른 사용법 &3{0} <플레이어> [비밀번호]. -Party.Help.1=파티를 만들려면, &3{0} <이름> [비밀번호]. -Party.Help.2=파티 정보를 볼려면 &3{0} -Party.Help.3=파티에 가입할려면 &3{0} <플레이어> [비밀번호] &c나갈려면 &3{1} -Party.Help.4=파티를 잠금/잠금해제 할려면, &3{0} -Party.Help.5=비밀번호로 파티를 보호할려면, &3{0} <비밀번호> -Party.Help.6=파티에서 플레이어를 추방시킬려면, &3{0} <플레이어> -Party.Help.7=파티장을 교체할려면, &3{0} <플레이어> -Party.Help.8=파티를 해체할려면, &3{0} -Party.Help.9=파티 맴버들과 아이템을 공유하려면 &3{0} -Party.Help.10=파티 맴버들과 경험치 공유를 활성화화려면 &3{0} -Party.InformedOnJoin={0} &a님이 당신의 파티에 참여했습니다 -Party.InformedOnQuit={0} &a님이 당신의 파티에서 떠났습니다 -Party.InformedOnNameChange=&6{0} &a님이 파티 이름을 &f{1}로 설정했습니다 -Party.InvalidName=&4잘못된 파티 이름입니다. -Party.Invite.Self=자기자신을 초대할 수는 없습니다! -Party.IsLocked=이 파티는 이미 잠겨져 있습니다! -Party.IsntLocked=이 파티는 잠겨져 있지 않습니다! -Party.Locked=파티가 잠겼습니다, 오직 파티장만이 초대를 할 수 있습니다. -Party.NotInYourParty=&4{0}님은 당신의 파티에 없습니다 -Party.NotOwner=&4당신은 파티장이 아닙니다. -Party.Target.NotOwner=&4{0}님은 파티장이 아닙니다. -Party.Owner.New=&a{0}님이 새 파티장이 되었습니다. -Party.Owner.NotLeader=&4당신은 이제 파티장이 아닙니다. -Party.Owner.Player =&a당신은 이제 파티장입니다. -Party.Password.None=이 파티는 비밀번호로 보호되고 있습니다. 가입할때 비밀번호를 제공해주세요. -Party.Password.Incorrect=파티 비밀번호가 올바르지 않습니다. -Party.Password.Set=&a설정한 파티 비밀번호는 {0} 입니다 -Party.Password.Removed=&a파티 비밀번호가 청소되었습니다. -Party.Player.Invalid=그 플레이어는 올바르지 않습니다. -Party.NotOnline=&4{0}님은 접속중이 아닙니다! -Party.Player.InSameParty={0}님은 이미 당신의 파티에 있습니다! -Party.PlayerNotInParty=&4{0}님은 파티에 없습니다 -Party.Specify=당신은 파티를 명기해야합니다. -Party.Teleport.Dead=당신은 죽은 플레이어에게로 텔레포트 할 수 없습니다. -Party.Teleport.Hurt=당신은 마지막으로 {0}초에 다쳐 텔레포트 할 수 없습니다. -Party.Teleport.Player=&a당신은 {0}로 텔레포트했습니다. -Party.Teleport.Self=자기자신한테 텔레포트 할 수 없습니다! -Party.Teleport.Target=&a{0}님이 당신에게로 텔레포트했습니다. -Party.Teleport.Disabled={0}님은 파티 텔레포트를 허용하고 있지 않습니다. -Party.Rename.Same=이미 당신의 파티 이름입니다! -Party.Join.Self=자기자신을 가입시킬수 없습니다! -Party.Unlocked=&7파티가 잠금해제 되었습니다 -Party.Disband=&7그 파티가 해체되었습니다 -Party.Alliance.Formed=&7당신의 파티는 이제 &a{0} 파티와 동맹입니다 -Party.Alliance.Disband=&7당신의 파티는 더 이상 &c{0} 파티와 동맹이 아닙니다 -Party.Status.Locked=&4(초대만-허용) -Party.Status.Unlocked=&2(개방) -Party.LevelUp=파티 레벨이 {0} 올라 총 {1} 레벨이 되었습니다 +Commands.Mmodebug.Toggle=mcMMO 디버그 모드가 이제 &6{0}&7입니다. 디버그 모드가 true이면 지원에 사용되는 유용한 정보를 얻기 위해 블록을 두드릴 수 있습니다. +mcMMO.NoInvites=&c현재 초대가 없습니다. +mcMMO.NoPermission=&4권한이 충분하지 않습니다. +mcMMO.NoSkillNote=&8해당 스킬에 액세스 권한이 없으면 여기에 표시되지 않습니다. +##파티 +Party.Forbidden=[mcMMO] 이 월드에서는 파티가 허용되지 않습니다 (권한 확인). +Party.Help.0=&c올바른 사용법은 &3{0} <플레이어> [비밀번호]입니다. +Party.Help.1=&c파티를 생성하려면 &3{0} <이름> [비밀번호]를 사용하세요. +Party.Help.2=&c자세한 정보는 &3{0} &c를 참조하세요. +Party.Help.3=&c가입하려면 &3{0} <플레이어> [비밀번호]&c를 사용하고 나가려면 &3{1} &c를 사용하세요. +Party.Help.4=&c파티를 잠그거나 잠금 해제하려면 &3{0} &c를 사용하세요. +Party.Help.5=&c파티에 비밀번호를 설정하려면 &3{0} <비밀번호>&c를 사용하세요. +Party.Help.6=&c플레이어를 파티에서 추방하려면 &3{0} <플레이어>&c를 사용하세요. +Party.Help.7=&c파티 소유권을 이전하려면 &3{0} <플레이어>&c를 사용하세요. +Party.Help.8=&c파티를 해체하려면 &3{0} &c를 사용하세요. +Party.Help.9=&c파티 멤버와 아이템을 공유하려면 &3{0} &c를 사용하세요. +Party.Help.10=&c파티 멤버와 경험치를 공유하려면 &3{0} &c를 사용하세요. +Party.InformedOnJoin={0} &a님이 당신의 파티에 가입했습니다 +Party.InformedOnQuit={0} &a님이 당신의 파티를 나갔습니다 +Party.InformedOnNameChange=&6{0} &a님이 파티 이름을 &f{1}&a(으)로 설정했습니다 +Party.InvalidName=&4유효하지 않은 파티 이름입니다. +Party.Invite.Self=&c자신을 초대할 수 없습니다! +Party.IsLocked=&c이 파티는 이미 잠겨 있습니다! +Party.IsntLocked=&c이 파티는 잠겨 있지 않습니다! +Party.Locked=&c파티가 잠겨 있어서, 파티 리더만 초대할 수 있습니다. +Party.NotInYourParty=&4{0}님이 당신의 파티에 속해 있지 않습니다. +Party.NotOwner=&4파티 리더가 아닙니다. +Party.Target.NotOwner=&4{0}님이 파티 리더가 아닙니다. +Party.Owner.New=&a{0}님이 새로운 파티 리더가 되었습니다. +Party.Owner.NotLeader=&4더 이상 파티 리더가 아닙니다. +Party.Owner.Player =&a파티 리더가 되었습니다. +Party.Password.None=&c파티에 비밀번호가 설정되어 있습니다. 가입하려면 비밀번호를 제공하세요. +Party.Password.Incorrect=&c파티 비밀번호가 잘못되었습니다. +Party.Password.Set=&a파티 비밀번호가 &a{0}&a(으)로 설정되었습니다. +Party.Password.Removed=&a파티 비밀번호가 지워졌습니다. +Party.Player.Invalid=&c유효하지 않은 플레이어입니다. +Party.NotOnline=&4{0}님이 오프라인입니다! +Party.Player.InSameParty=&c{0}님은 이미 당신의 파티에 속해 있습니다! +Party.PlayerNotInParty=&4{0}님이 파티에 속해 있지 않습니다. +Party.Specify=&c파티를 지정해야 합니다. +Party.Teleport.Dead=&c죽은 플레이어에게 텔레포트할 수 없습니다. +Party.Teleport.Hurt=&c최근 {0}초 동안 다치셨기 때문에 텔레포트할 수 없습니다. +Party.Teleport.Player=&a당신이 {0}님에게 텔레포트하였습니다. +Party.Teleport.Self=&c자신에게 텔레포트할 수 없습니다! +Party.Teleport.Target=&a{0}님이 당신에게 텔레포트하였습니다. +Party.Teleport.Disabled=&c{0}님이 파티 텔레포트를 허용하지 않습니다. +Party.Rename.Same=&c이미 해당 파티의 이름입니다! +Party.Join.Self=&c자신에게 가입할 수 없습니다! +Party.Unlocked=&7파티가 잠금 해제되었습니다 +Party.Disband=&7파티가 해체되었습니다 +Party.Alliance.Formed=&7당신의 파티가 이제 &a{0}&7님과 동맹 관계입니다 +Party.Alliance.Disband=&7당신의 파티는 더 이상 &c{0}&7님과 동맹 관계가 아닙니다 +Party.Status.Locked=&4(초대 전용) +Party.Status.Unlocked=&2(공개) +Party.LevelUp=&e파티 레벨이 {0}만큼 증가하였습니다. 전체 ({1}) Party.Feature.Chat=파티 채팅 Party.Feature.Teleport=파티 텔레포트 Party.Feature.Alliance=동맹 Party.Feature.ItemShare=아이템 공유 -Party.Feature.XpShare=경험치 공유 -Party.Feature.Locked.Chat={0}레벨 때 스킬해제 (파티 채팅) -Party.Feature.Locked.Teleport={0}레벨 때 스킬해제 (파티 텔레포트) -Party.Feature.Locked.Alliance={0}레벨 때 스킬해제 (동맹) -Party.Feature.Locked.ItemShare={0}레벨 때 스킬해제 (아이템 공유) -Party.Feature.Locked.XpShare={0}레벨 때 스킬해제 (경험치 공유) -Party.Feature.Disabled.1=파티 채팅은 아직 해제되지 않았습니다. -Party.Feature.Disabled.2=파티 텔레포트는 아직 해제되지 않았습니다. -Party.Feature.Disabled.3=파티 동맹은 아직 해제되지 않았습니다. -Party.Feature.Disabled.4=아이템 공유는 아직 해제되지 않았습니다. -Party.Feature.Disabled.5=경험치 공유는 아직 해제되지 않았습니다. -Party.ShareType.Xp=경험치 +Party.Feature.XpShare=XP 공유 +Party.Feature.Locked.Chat=잠금 해제까지 {0}+ (파티 채팅) +Party.Feature.Locked.Teleport=잠금 해제까지 {0}+ (파티 텔레포트) +Party.Feature.Locked.Alliance=잠금 해제까지 {0}+ (동맹) +Party.Feature.Locked.ItemShare=잠금 해제까지 {0}+ (아이템 공유) +Party.Feature.Locked.XpShare=잠금 해제까지 {0}+ (XP 공유) +Party.Feature.Disabled.1=&c파티 채팅이 아직 잠금 해제되지 않았습니다. +Party.Feature.Disabled.2=&c파티 텔레포트가 아직 잠금 해제되지 않았습니다. +Party.Feature.Disabled.3=&c파티 동맹이 아직 잠금 해제되지 않았습니다. +Party.Feature.Disabled.4=&c파티 아이템 공유가 아직 잠금 해제되지 않았습니다. +Party.Feature.Disabled.5=&c파티 XP 공유가 아직 잠금 해제되지 않았습니다. +Party.ShareType.Xp=XP Party.ShareType.Item=아이템 Party.ShareMode.None=없음 -Party.ShareMode.Equal=균등 -Party.ShareMode.Random=무작위 -Party.ItemShare.Category.Loot=강탈 -Party.ItemShare.Category.Mining=채광 -Party.ItemShare.Category.Herbalism=약초학 -Party.ItemShare.Category.Woodcutting=벌목 +Party.ShareMode.Equal=동등 +Party.ShareMode.Random=랜덤 +Party.ItemShare.Category.Loot=전리품 +Party.ItemShare.Category.Mining=채굴 +Party.ItemShare.Category.Herbalism=허브 수확 +Party.ItemShare.Category.Woodcutting=나무 벌채 Party.ItemShare.Category.Misc=기타 - ##xp -Commands.XPGain.Acrobatics=떨어지기 -Commands.XPGain.Alchemy=포션 양조하기 -Commands.XPGain.Archery=몬스터 공격하기 -Commands.XPGain.Axes=몬스터 공격하기 -Commands.XPGain.Child=상위 스킬들로 부터 레벨들을 얻습니다 -Commands.XPGain.Excavation=땅 파거나 보물 발견하기 -Commands.XPGain.Fishing=낚시하기 -Commands.XPGain.Herbalism=식물 수집하기 -Commands.XPGain.Mining=돌이나 광석 캐기 -Commands.XPGain.Repair=수리하기 -Commands.XPGain.Swords=몬스터 공격하기 -Commands.XPGain.Taming=동물을 조련하거나, 조련된 동물로 사냥하기 -Commands.XPGain.Unarmed=몬스터 공격하기 -Commands.XPGain.Woodcutting=나무 자르기 -Commands.XPGain=&8경험치 얻는 방법: &f{0} -Commands.xplock.locked=&6당신의 경험치 바는 {0}로 잠겼습니다! -Commands.xplock.unlocked=&6당신의 경험치 바는 &a잠금 해제되었습니다&6! -Commands.xprate.modified=경험치 배율이 {0}배로 수정되었습니다 -Commands.xprate.over=mcMMO 경험치 이벤트가 종료되었습니다!! -Commands.xprate.proper.0=경험치 배율 이벤트를 사용법: &f/xprate <배율> -Commands.xprate.proper.1=경험치 배율을 초기화 방법: &f/xprate reset -Commands.xprate.proper.2=이것은 XP 이벤트인지 아닌지 true 또는 false로 나타내기 위해 지정하십시오 -Commands.xprate.started.0=&6mcMMO 경험치 이벤트가 시작되었습니다! -Commands.xprate.started.1=&6mcMMO 경험치 배율은 {0}배 입니다! -XPRate.Event= &6mcMMO 는 현재 경험치 이벤트 중입니다! 경험치는 {0}배 입니다! -Commands.NegativeNumberWarn=마이너스 숫자는 허용되지 않습니다! -Commands.Event.Start=&amcMMO&6 이벤트 시작! +Commands.XPGain.Acrobatics=낙하 +Commands.XPGain.Alchemy=포션 제조 +Commands.XPGain.Archery=몬스터 공격 +Commands.XPGain.Axes=몬스터 공격 +Commands.XPGain.Child=상위 스킬로부터 레벨을 얻음 +Commands.XPGain.Excavation=파헤치기 및 보물 찾기 +Commands.XPGain.Fishing=낚시 (당연한 얘기지요!) +Commands.XPGain.Herbalism=약초 수확 +Commands.XPGain.Mining=돌 및 광석 채굴 +Commands.XPGain.Repair=수리 +Commands.XPGain.Swords=몬스터 공격 +Commands.XPGain.Taming=동물 조련 또는 늑대와의 전투 +Commands.XPGain.Unarmed=몬스터 공격 +Commands.XPGain.Woodcutting=나무 베기 +Commands.XPGain=&8XP 획득: &f{0} +Commands.xplock.locked=&6XP 바가 이제 {0}으로 잠겨 있습니다! +Commands.xplock.unlocked=&6XP 바가 이제 &a잠금 해제&6되었습니다! +Commands.xprate.modified=&cXP 비율이 {0}(으)로 변경되었습니다 +Commands.xprate.over=&cmcMMO XP 비율 이벤트가 종료되었습니다!! +Commands.xprate.proper.0=&cXP 비율을 변경하려면 올바른 사용법은 /xprate <정수> 입니다 +Commands.xprate.proper.1=&cXP 비율을 기본값으로 복원하려면 올바른 사용법은 /xprate reset입니다 +Commands.xprate.proper.2=&cXP 이벤트 여부를 지정하려면 true 또는 false를 명시하십시오 +Commands.NegativeNumberWarn=음수를 사용하지 마세요! +Commands.Event.Start=&amcMMO&6 이벤트! Commands.Event.Stop=&amcMMO&3 이벤트 종료! -Commands.Event.Stop.Subtitle=&a즐거운 시간이었기를 바랍니다! -Commands.Event.XP=&3XP 배율이 이제 &6{0}&3배입니다 +Commands.Event.Stop.Subtitle=&a즐거웠길 바랍니다! +Commands.Event.XP=&3XP 비율은 이제 &6{0}&3배입니다 Commands.xprate.started.0=&6mcMMO XP 이벤트가 시작되었습니다! -Commands.xprate.started.1=&6mcMMO XP 배율은 이제 {0}배입니다! +Commands.xprate.started.1=&6mcMMO XP 비율이 {0}배로 설정되었습니다! -# Admin Notifications +# 관리자 알림 Server.ConsoleName=&e[서버] -Notifications.Admin.XPRate.Start.Self=&7전체 XP 배율을 &6{0}배로 설정했습니다. -Notifications.Admin.XPRate.End.Self=&7XP 배율 이벤트를 종료했습니다. -Notifications.Admin.XPRate.End.Others={0} &7님이 XP 배율 이벤트를 종료했습니다. -Notifications.Admin.XPRate.Start.Others={0} &7님이 전체 XP 배율 {1}배로 이벤트를 시작 또는 수정했습니다. +Notifications.Admin.XPRate.Start.Self=&7전역 XP 비율 배수를 &6{0}배&7로 설정했습니다 +Notifications.Admin.XPRate.End.Self=&7XP 비율 이벤트를 종료했습니다. +Notifications.Admin.XPRate.End.Others={0}&7님이 XP 비율 이벤트를 종료했습니다 +Notifications.Admin.XPRate.Start.Others={0}&7님이 전역 배수가 {1}배인 XP 비율 이벤트를 시작하거나 수정했습니다 Notifications.Admin.Format.Others=&6(&amcMMO &3관리자&6) &7{0} Notifications.Admin.Format.Self=&6(&amcMMO&6) &7{0} -#GUIDES -Guides.Available=&7{0} 가이드가 있습니다 - 타입 /{1} ? [페이지] +# 이벤트 +XPRate.Event=&6mcMMO가 현재 XP 비율 이벤트 중입니다! XP 비율은 {0}배입니다! + +#가이드 +Guides.Available=&7{0}에 대한 가이드 사용 가능 - /{1} ? [페이지] Guides.Header=&6-=&a{0} 가이드&6=- -Guides.Page.Invalid=올바른 페이지 번호가 아닙니다! -Guides.Page.OutOfRange=그 페이지는 존재하지 않습니다, 오직 총 {0} 페이지가 있습니다. -Guides.Usage= 사용법 /{0} ? [페이지] - -##Acrobatics -Guides.Acrobatics.Section.0=&3곡예에 대하여:\n&e곡예는 mcMMO의 우아하게 움직이는 예술입니다.\n&e전투 특혜와 환경 손상 특혜를 증가시킵니다.\n\n&3XP 얻기:\n&e이 스킬의 XP를 얻을려면 전투나 생존에서 피해를 \n&e입는 낙하에서 착지 행동이 요구됩니다. -Guides.Acrobatics.Section.1=&3어떻게 구르기를 하나요?\n&e당신이 낙하 피해를 받을 때 피해를 무효화할\n&e지속적인 기회를 가지게 됩니다. 웅크리기 키를 누르고 있으면\n&e떨어지는 동안 두 배의 기회를 가지게 됩니다.\n&e이는 일반 구르기 대신 우아한 구르기를 발동시킵니다.\n&e우아한 구르기는 일반 구르기보다 두 배 더 자주 발동되며\n&e일반 구르기보다 더 많은 피해 방어를 제공합니다.\n&e구르기 확률은 스킬 레벨에 연결됩니다. -Guides.Acrobatics.Section.2=&3어떻게 회피를 하나요?\n&e회피는 당신이 전투에서 상처를 입을 때 입는\n&e피해를 반감시키는 지속적인 기회입니다.\n&e이것은 당신의 스킬 레벨과 연결됩니다. - -##Alchemy -Guides.Alchemy.Section.0=[[DARK_AQUA]]연금술에 대하여:\n[[YELLOW]]연금술은 물약을 양조하는 것입니다.\n[[YELLOW]]물약 양조 시간을 빠르게 하고, 이전에 얻을 수 없었던\n[[YELLOW]]새로운 물약을 추가합니다.\n\n\n[[DARK_AQUA]]XP 획득:\n[[YELLOW]]이 스킬에서 XP를 얻으려면 물약을 양조해야 합니다. -Guides.Alchemy.Section.1=[[DARK_AQUA]]Catalysis는 어떻게 작동하나요?\n[[YELLOW]]Catalysis는 양조 과정을 가속화시키며, 최대\n[[YELLOW]]속도는 기본 설정에서 레벨 1000에서 4배입니다.\n[[YELLOW]]이 능력은 기본 설정에서 레벨 100에서 잠금 해제됩니다. -Guides.Alchemy.Section.2=[[DARK_AQUA]]Concoctions는 어떻게 작동하나요?\n[[YELLOW]]Concoctions는 사용자 정의 재료로 더 많은 물약을 양조할 수 있게 합니다.\n[[YELLOW]]잠금 해제되는 특별한 재료는 등급에 따라 결정됩니다.\n[[YELLOW]]잠금 해제할 수 있는 등급은 총 8개입니다. -Guides.Alchemy.Section.3=[[DARK_AQUA]]Concoctions 1단계 재료:\n[[YELLOW]]블레이즈 가루, 발효된 거미 눈, 가스트 눈물, 레드스톤,\n[[YELLOW]]발광석 가루, 설탕, 반짝이는 수박 조각, 황금 당근,\n[[YELLOW]]마그마 크림, 네더 사마귀, 거미 눈, 수플후르, 워터 릴리,\n[[YELLOW]]복어\n[[YELLOW]](바닐라 물약) -Guides.Alchemy.Section.4=[[DARK_AQUA]]Concoctions 2단계 재료:\n[[YELLOW]]당근 (신속의 물약)\n[[YELLOW]]슬라임볼 (채굴 피로의 물약)\n\n[[DARK_AQUA]]Concoctions 3단계 재료:\n[[YELLOW]]석영 (흡수의 물약)\n[[YELLOW]]토끼 발 (도약의 물약) -Guides.Alchemy.Section.5=[[DARK_AQUA]]Concoctions 4단계 재료:\n[[YELLOW]]사과 (생명력 강화의 물약)\n[[YELLOW]]썩은 고기 (허기의 물약)\n\n[[DARK_AQUA]]Concoctions 5단계 재료:\n[[YELLOW]]갈색 버섯 (멀미의 물약)\n[[YELLOW]]잉크 주머니 (실명의 물약) -Guides.Alchemy.Section.6=[[DARK_AQUA]]Concoctions 6단계 재료:\n[[YELLOW]]고사리 (포화의 물약)\n\n[[DARK_AQUA]]Concoctions 7단계 재료:\n[[YELLOW]]독이 있는 감자 (부패의 물약)\n\n[[DARK_AQUA]]Concoctions 8단계 재료:\n[[YELLOW]]일반 황금 사과 (저항의 물약) - -##Archery -Guides.Archery.Section.0=&3궁술에 대하여:\n&e궁술은 활과 화살로 사격하는 것입니다.\n&e레벨에 따라 증가하는 데미지 보너스와 PvP에서 상대를\n&e혼란시키는 능력과 같은 다양한 전투 보너스를 제공합니다.\n&e또한, 상대의 시체에서 사용한 화살을 일부 회수할 수 있습니다.\n\n\n&3XP 획득:\n&e이 스킬에서 XP를 얻으려면 몹이나 다른 플레이어를\n&e쏴서 맞춰야 합니다. -Guides.Archery.Section.1=&3Skill Shot은 어떻게 작동하나요?\n&eSkill Shot은 사격에 추가 데미지를 제공합니다.\n&eSkill Shot의 보너스 데미지는 궁술 레벨에 따라\n&e증가합니다.\n&e기본 설정에서 Archery 레벨당 활 데미지가 50 레벨마다\n&e10% 증가하여 최대 200%의 보너스 데미지를 얻을 수 있습니다. -Guides.Archery.Section.2=&3Daze는 어떻게 작동하나요?\n&e상대를 사격할 때 상대를 혼란시키는 확률이 있습니다.\n&eDaze가 발동되면 상대는 잠시 동안 위를 바라보게 됩니다.\n&eDaze 사격은 추가로 4의 데미지(2 하트)를 입힙니다. -Guides.Archery.Section.3=&3Arrow Retrieval은 어떻게 작동하나요?\n&e활로 몹을 처치할 때 일부 화살을 회수할 수 있는\n&e확률이 있습니다.\n&e이 확률은 궁술 레벨에 따라 증가합니다.\n&e기본 설정에서 이 능력은 레벨당 0.1%씩 증가하여\n&e레벨 1000에서 100%까지 증가합니다. - -##Axes -Guides.Axes.Section.0=&3부술에 대하여:\n&e부술 스킬을 사용하여 도끼로 나무를 베는 것 이상의 다양한 기능을 사용할 수 있습니다.\n&e부술 스킬을 사용하여 몹과 플레이어를 공격하고 경험치를 얻을 수 있으며,\n&e넉백 효과로 몹에게 치명적인 일격을 가할 수 있습니다.\n&e또한, 레벨이 올라감에 따라 적의 갑옷을 쉽게 파괴할 수 있는\n&e손에 들고 사용하는 나무 굴삭기가 됩니다.\n&3XP 획득:\n&e이 스킬에서 XP를 얻으려면 도끼로 다른 몹이나 플레이어를 공격해야 합니다. -Guides.Axes.Section.1=&3뼈 쪼개기는 어떻게 작동하나요?\n&e이 능력을 사용하면 AoE(영역 효과) 공격을 할 수 있습니다.\n&e이 AoE 공격은 주요 대상에 가한 데미지의 절반만큼의 데미지를 입힙니다.\n&e따라서 대량의 몹을 제거하는 데에 효과적입니다. -Guides.Axes.Section.2=&3크리티컬 히트는 어떻게 작동하나요?\n&e크리티컬 히트는 플레이어가 추가 데미지를 입힐 수 있는\n&e확률적인 능력입니다.\n&e기본 설정에서, 부술 스킬 레벨 2마다 0.1%의 확률로\n&e크리티컬 히트를 가할 수 있으며, 이로 인해 몹에게는\n&e2배의 데미지를, 다른 플레이어에게는 1.5배의 데미지를 입힙니다. -Guides.Axes.Section.3=&3도끼 마스터리는 어떻게 작동하나요?\n&e도끼 마스터리는 액스를 사용할 때 공격에 추가 데미지를\n&e줍니다.\n&e기본 설정에서, 보너스 데미지는 레벨당 50마다 1씩 증가하며,\n&e레벨 200에서 최대 4의 추가 데미지를 얻을 수 있습니다. -Guides.Axes.Section.4=&3갑옷 충격는 어떻게 작동하나요?\n&e강력한 힘으로 갑옷을 파괴하세요!\n&e갑옷 충격는 상대의 갑옷을 손상시킬 확률이 있습니다.\n&e이 확률은 부술 스킬 레벨이 올라감에 따라 증가합니다. -Guides.Axes.Section.5=&3엄청난 충격는 어떻게 작동하나요?\n&e부술 스킬로 몹이나 플레이어를 공격할 때\n&e더 큰 영향을 줄 확률이 있습니다.\n&e기본 설정에서 이 확률은 25%입니다.\n&e이 패시브 능력은 넉백 II 마법과 유사한\n&e인챈트 효과를 가지며, 대상에게 추가 데미지를 입힙니다. - -##Excavation -Guides.Excavation.Section.0=&3발굴에 대하여:\n&e발굴은 보물을 찾기 위해 흙을 파내는 행위입니다.\n&e땅을 파내면 보물을 찾을 수 있습니다.\n&e이를 계속하면 더 많은 보물을 찾을 수 있습니다.\n\n&3XP 획득:\n&e이 스킬에서 XP를 얻으려면 삽을 들고 파야 합니다.\n&e일부 재료만 보물과 XP를 얻을 수 있습니다. -Guides.Excavation.Section.1=&3호환 가능한 재료:\n&e풀, 흙, 모래, 점토, 자갈, 버섯, 영혼 모래, 눈 -Guides.Excavation.Section.2=&3기가 드릴 버서커 사용 방법:\n&e삽을 들고 우클릭하여 도구를 준비합니다.\n&e이 상태에서 약 4초 안에 발굴 호환 가능한 재료에\n&e접촉하면 기가 드릴 버서커가 활성화됩니다. -Guides.Excavation.Section.3=&3기가 드릴 버서커란 무엇인가요?\n&e기가 드릴 버서커는 발굴 스킬과 연결된 재사용 대기시간이 있는\n&e능력입니다. 이는 보물을 찾을 확률을 세 배로 늘리고\n&e발굴 재료를 즉시 부술 수 있게 합니다. -Guides.Excavation.Section.4=&3고고학은 어떻게 작동하나요?\n&e발굴을 위한 가능한 모든 보물은 떨어지기 위한\n&e스킬 레벨 요구 사항이 있으므로, 얼마나 도움이 되는지\n&정확히 말하기는 어렵습니다.\n&e단지 기억해 두세요. 발굴 스킬이 높을수록\n&더 많은 보물을 찾을 수 있습니다.\n&또한, 각각의 발굴 호환 가능한 재료에는 고유한 보물 목록이 있습니다.\n&다시 말해, 흙에서 찾는 보물과 자갈에서 찾는 보물은 다릅니다. -Guides.Excavation.Section.5=&3발굴에 대한 참고 사항:\n&e발굴 보상은 완전히 사용자 정의할 수 있으므로\n&결과는 서버마다 다릅니다. - -##Fishing -Guides.Fishing.Section.0=&3낚시에 대하여:\n&e낚시 스킬이 있다면 낚시가 다시 즐거워집니다!\n&e숨겨진 보물을 찾고 몹에서 아이템을 떨어뜨립니다.\n\n&3XP 획득:\n&e물고기를 낚아서 경험치를 얻습니다. -Guides.Fishing.Section.1=&3보물 사냥꾼은 어떻게 작동하나요?\n&e이 능력을 사용하면 낚시로 보물을 찾을 수 있습니다.\n&e아이템이 인챈트된 상태로 드롭될 수 있는 작은 확률이 있습니다.\n&e낚시로 얻을 수 있는 모든 보물은 어떤 레벨에서든 드롭될 수 있습니다.\n&e그러나 아이템의 희귀도에 따라 얼마나 자주 드롭되는지가 달라집니다.\n&e낚시 스킬이 높을수록 더 좋은 보물을 찾을 확률이 높아집니다. -Guides.Fishing.Section.2=&3얼음 낚시는 어떻게 작동하나요?\n&e이 패시브 스킬을 사용하면 얼음 호수에서 낚시를 할 수 있습니다!\n&e낚싯대를 얼음 호수에 던지면 물고기를 낚을 수 있는 작은 구멍이 생성됩니다. -Guides.Fishing.Section.3=&3낚시꾼 장인은 어떻게 작동하나요?\n&e이 패시브 스킬은 낚시할 때 물고기가 물에 물릴 확률을 증가시킵니다.\n&e이 능력을 잠금 해제하면 보트에서 낚시할 때\n&e물고기를 잡을 확률이 높아집니다. -Guides.Fishing.Section.4=&3흔들기는 어떻게 작동하나요?\n&e이 액티브 능력을 사용하면 낚싯대로 몹에게서 아이템을 흔들어 떨어뜨릴 수 있습니다.\n&e몹은 일반적으로 죽을 때 떨어뜨리는 아이템을 드롭합니다.\n&e또한, 서바이벌 모드에서는 얻을 수 없는 몹 머리를 획득할 수도 있습니다. -Guides.Fishing.Section.5=&3어부의 다이어트는 어떻게 작동하나요?\n&e이 패시브 스킬은 물고기를 먹을 때 회복되는 포만감을 증가시킵니다. -Guides.Fishing.Section.6=&3낚시에 대한 참고 사항:\n&e낚시 아이템은 완전히 사용자 정의할 수 있으므로\n&결과는 서버마다 다릅니다. - -##Herbalism -Guides.Herbalism.Section.0=&3약초학에 대하여:\n&e약초학은 허브와 식물을 수집하는 것에 관한 스킬입니다.\n\n\n&3XP 획득:\n&e식물과 허브를 수집하세요. -Guides.Herbalism.Section.1=&3호환 가능한 블록:\n&e밀, 감자, 당근, 수박, \n&e호박, 사탕수수, 코코아 콩, 꽃, 선인장, 버섯,\n&e네더 사마귀, 원반, 덩굴. -Guides.Herbalism.Section.2=&3재배의 대지는 어떻게 작동하나요?\n&e재배의 대지는 액티브 능력으로, 괭이를 들고 우클릭하여\n&e재배의 대지를 활성화할 수 있습니다.\n&e재배의 대지는 식물을 수확할 때 3배의 드롭을 얻을 확률을\n&제공합니다. 또한 인벤토리의 씨앗을 사용하여 블록에\n&생명을 불어넣고 변형시킬 수 있는 능력을 제공합니다. -Guides.Herbalism.Section.3=&3재배의 재능 (작물)은 어떻게 작동하나요?\n&e이 패시브 능력은 작물을 수확할 때 자동으로 재심을\n&합니다. 성공 확률은 약초학 스킬 레벨에 따라 달라집니다. -Guides.Herbalism.Section.4=&3재배의 재능 (석재/돌/흙)은 어떻게 작동하나요?\n&e이 액티브 능력은 블록을 해당하는 "식물 관련" 블록으로\n&변환할 수 있게 합니다. 씨앗을 들고 블록을 우클릭하여\n&사용할 수 있습니다. 이 과정에서 1개의 씨앗이 소모됩니다. -Guides.Herbalism.Section.5=&3농부의 다이어트는 어떻게 작동하나요?\n&e이 패시브 스킬은 빵, 쿠키, 수박, 버섯 스튜, 당근,\n&감자를 섭취할 때 회복되는 포만감을 증가시킵니다. -Guides.Herbalism.Section.6=&3하이랄인의 행운은 어떻게 작동하나요?\n&e이 패시브 능력은 검으로 특정 블록을 부술 때\n&희귀 아이템을 얻을 확률을 제공합니다. -Guides.Herbalism.Section.7=&32배 드롭은 어떻게 작동하나요?\n&e이 패시브 능력은 수확 시 더 많은 수확량을 제공합니다. - -##Mining -Guides.Mining.Section.0=&3채광에 대하여:\n&e채광은 돌과 광석을 캐는 것으로, 채굴 시 드롭되는 자원의 양에 보너스를 제공합니다.\n\n&3XP 획득:\n&e이 스킬에서 XP를 얻으려면 손에 곡괭이를 들고 채굴해야 합니다.\n&e일부 블록만 XP를 제공합니다. -Guides.Mining.Section.1=&3호환 가능한 자료:\n&e돌, 석탄 광석, 철 광석, 금 광석, 다이아몬드 광석, 레드스톤 광석,\n&e청금석 광석, 흑요석, 이끼 낀 석재, 엔더 돌,\n&e발광석, 네더랙입니다. -Guides.Mining.Section.2=&3파괴자는 어떻게 작동하나요?\n&e곡괭이를 손에 들고, 우클릭을 하면 도구가 준비 상태가 됩니다.\n&e이 상태에서, 4초 안에 채광 가능 블록을 좌클릭하면, 이것은 파괴자를 발동할 것입니다. -Guides.Mining.Section.3=&3파괴자가 무엇인가요?\n&e파괴자는 채광 스킬과 연결된 재사용 대기시간이 있는 능력입니다. 이는 추가 아이템이 떨어질 확률을 세 배로 늘리고 채광 재료를 즉시 부술 수 있게 합니다. -Guides.Mining.Section.4=&3폭발 채굴은 어떻게 작동하나요?\n&e곡괭이를 손에 들고 웅크리기를 한 후 TNT를 멀리서 우클릭하세요. 이것은 TNT를 즉시 폭발시킬 것입니다. -Guides.Mining.Section.5=&3폭발 채굴은 어떻게 작동합니까?\n&e 폭발 채굴은 채광 스킬과 연결된 쿨타임이 있는 기능입니다. TNT로 채굴할 때 보너스를 제공하고 TNT를 원격으로 폭발시킬 수 있습니다. 폭발 채굴에는 세 가지 부분이 있습니다.\n&e 첫 번째 부분은 폭발 반경을 증가시키는 더 큰 폭탄입니다.\n&e 두 번째 부분은 TNT 폭발로 인한 피해를 감소시키는 해체 전문가입니다. 세 번째 부분은 단순히 TNT에서 떨어지는 광석의 양을 증가시키고 떨어지는 파편을 감소시킵니다. - -##Repair -Guides.Repair.Section.0=&3수리에 대하여:\n&e수리는 철 블록을 사용하여 갑옷과 도구를 수리할 수 있게 합니다.\n\n&3XP 획득:\n&emcMMO 모루를 사용하여 도구나 갑옷을 수리하세요. 이는\n&e기본적으로 철 블록이며, Minecraft의 일반 모루와 혼동되지 않아야 합니다. -Guides.Repair.Section.1=&3어떻게 수리를 사용할 수 있나요?\n&emcMMO 모루를 설치하고 현재 들고 있는 아이템을 우클릭하여 수리하세요. 이는 사용할 때마다 1개의 아이템을 소모합니다. -Guides.Repair.Section.2=&3수리 마스터리은 어떻게 작동하나요?\n&e수리 마스터리은 수리량을 증가시킵니다. 추가로 수리되는 양은 수리 스킬 레벨에 영향을 받습니다. -Guides.Repair.Section.3=&3슈퍼 수리는 어떻게 작동하나요?\n&e슈퍼 수리는 패시브 능력입니다. 아이템을 수리할 때\n&e더욱 효과적으로 아이템을 수리할 수 있는 기회를 제공합니다. -Guides.Repair.Section.4=&3인챈트 아이템 수리는 어떻게 작동하나요?\n&e이 패시브 능력은 일정 확률로 아이템을 수리할 때\n&e인챈트를 유지할 수 있게 합니다. 인챈트는\n&e기존 레벨로 유지되거나 낮은 레벨로 강등되거나\n&완전히 사라질 수 있습니다. - -##Salvage -Guides.Salvage.Section.0=&3회수에 대하여:\n&e회수는 금 블록을 사용하여 갑옷과 도구를 회수할 수 있게 합니다.\n\n&3XP 획득:\n&e회수는 수리 및 낚시의 부가 스킬로, 회수 스킬 레벨은 낚시 및 수리 스킬 레벨에 기반합니다. -Guides.Salvage.Section.1=&3회수를 어떻게 사용할 수 있나요?\n&emcMMO 회수 모루를 설치하고 현재 들고 있는 아이템을 우클릭하여 회수하세요. 이렇게 하면 아이템이 분해되고 아이템을 제작하는 데 사용된 재료가 반환됩니다.\n\n&e예를 들어, 철 곡괭이를 회수하면 철 주괴를 얻을 수 있습니다. -Guides.Salvage.Section.2=&3전문적인 회수는 어떻게 작동하나요?\n&e전문적인 회수를 잠금 해제하면 손상된 아이템을 회수할 수 있습니다. 레벨이 올라감에 따라 수확률이 증가합니다. 높은 수확률은 더 많은 재료를 얻을 수 있음을 의미합니다.\n&e전문적인 회수를 사용하면 항상 1개의 재료를 얻게 되며, 아이템이 너무 손상된 경우를 제외하고는 아이템을 파괴하고 아무것도 얻지 못하는 일은 없습니다. -Guides.Salvage.Section.3=&3작동 방식을 설명하기 위해 예를 들어보겠습니다:\n&e손상된 금 곡괭이를 회수한다고 가정해 봅시다. 이 경우 최대로 얻을 수 있는 양은 2개입니다(곡괭이는 3개의 주괴로 제작되며 각각의 주괴는 33.33%의 내구성을 가지므로 66%에 해당하는 2개입니다). 수확률이 66%보다 낮으면 2개의 주괴를 얻을 수 없습니다. 수확률이 이 값보다 높으면 "전체 양"을 얻을 수 있으며, 즉 2개의 주괴를 얻게 됩니다. -Guides.Salvage.Section.4=&3신비로운 회수는 어떻게 작동하나요?\n&e이 능력을 사용하면 마법이 부여된 아이템을 회수할 때 마법이 부여된 책을 얻을 수 있습니다. 레벨에 따라 완전한 부분 또는 부분적인 부여를 성공적으로 추출할 확률이 다릅니다.\n\n&e부분적으로 추출된 경우, 부여된 책은 아이템에 있던 부여보다 낮은 레벨의 부여를 가지게 됩니다. - -##Smelting -Guides.Smelting.Section.0=준비 중... - -##Swords -Guides.Swords.Section.0=&3검술에 대해:\n&e이 스킬은 검을 사용하는 사람에게 전투 보너스를 제공합니다.\n\n&3XP 획득:\n&e검을 사용하여 몹이나 다른 플레이어에게 입힌 데미지에 따라 경험치를 획득합니다. -Guides.Swords.Section.1=&3톱날 공격은 어떻게 작동하나요?\n&e톱날 공격은 액티브 능력으로, 검으로 우클릭하여 활성화할 수 있습니다. 이 능력을 사용하면 AoE(영역 효과) 공격을 할 수 있습니다. 이 AoE는 추가 25%의 데미지를 입히며, Rupture를 적용할 수도 있습니다. -Guides.Swords.Section.2=&3카운터 어택은 활성 능력입니다. 몹으로부터 공격을 막으면서 피해를 입을 때, 받은 피해의 50%를 반사할 확률이 있습니다. -Guides.Swords.Section.3=&3파열은 적에게 2초마다 피해를 입힙니다. 이 효과는 피해를 입은 대상이 죽거나 효과가 사라질 때까지 계속됩니다. 검 기술이 높을수록 피 효과의 지속 시간이 증가합니다. - -##Taming -Guides.Taming.Section.0=&3조련에 대하여:\n&e조련은 길들인 늑대를 사용할 때 다양한 전투 보너스를 제공합니다.\n\n&3XP 획득:\n&e이 스킬에서 경험치를 얻으려면 늑대/오셀롯을 길들이거나\n&e늑대와 전투해야 합니다. -Guides.Taming.Section.1=&3야생의 포효는 어떻게 작동하나요?\n&e야생의 포효는 액티브 능력으로, 뼈다귀나 생선을 들고\n&e웅크리고 좌클릭하여 늑대나 오셀롯을 소환할 수 있습니다. -Guides.Taming.Section.2=&3짐승의 포효는 어떻게 작동하나요?\n&e짐승의 포효는 펫을 검사하고 늑대와 오셀롯의\n&estats를 확인할 수 있게 합니다. 늑대나 오셀롯을 좌클릭하여\n&e짐승의 포효를 사용하세요. -Guides.Taming.Section.3=&3돌진은 어떻게 작동하나요?\n&e돌진은 패시브 능력으로, 늑대의 대상에게 출혈 효과를\n&적용할 수 있는 확률이 있습니다. -Guides.Taming.Section.4=&3날카로운 발톱은 어떻게 작동하나요?\n&e날카로운 발톱은 늑대가 입히는 피해에 추가적인 데미지 보너스를\n&제공합니다. 이 데미지 보너스는 테이밍 레벨에 따라 달라집니다. -Guides.Taming.Section.5=&3환경 인식은 어떻게 작동하나요?\n&e이 패시브 능력은 늑대가 선인장/용암과 같은 위험 요소에\n&가까이 다가갈 때 당신에게 순간이동할 수 있게 합니다.\n&또한, 늑대에게 낙하 피해 면역성을 제공합니다. -Guides.Taming.Section.6=&3두꺼운 털은 어떻게 작동하나요?\n&e이 패시브 능력은 늑대의 피해를 감소시키고\n&불에 대한 내성을 제공합니다. -Guides.Taming.Section.7=&3충격 방지는 어떻게 작동하나요?\n&e이 패시브 능력은 늑대가 폭발로 인한 피해를\n&감소시킵니다. -Guides.Taming.Section.8=&3빠른 음식 제공은 어떻게 작동하나요?\n&e이 패시브 능력은 늑대가 공격할 때마다 회복할\n&수 있는 기회를 제공합니다. - -##Unarmed -Guides.Unarmed.Section.0=&3비무장에 대해:\n&e비무장은 주먹을 무기로 사용할 때 플레이어에게 다양한 전투 보너스를 제공합니다. \n\n&3XP 획득:\n&e맨손으로 몹이나 다른 플레이어에게 입힌 피해량에 따라 경험치를 획득합니다. -Guides.Unarmed.Section.1=&3버서커는 어떻게 작동하나요?\n&e버서커는 우클릭으로 활성화되는 액티브 능력입니다. 버서커 모드에서는 추가로 50%의 피해를 입히며, 흙과 풀과 같은 약한 재료를 즉시 부술 수 있습니다. -Guides.Unarmed.Section.2=&3강철 팔 형태는 어떻게 작동하나요?\n&e강철 팔 형태는 주먹으로 몹이나 플레이어를 때릴 때 입히는 피해량을 증가시킵니다. -Guides.Unarmed.Section.3=&3화살 회피는 어떻게 작동하나요?\n&e화살 튕김은 스켈레톤이나 다른 플레이어가 발사한 화살을 튕길 확률을 제공하는 패시브 능력입니다. 화살은 피해를 입히지 않고 땅에 떨어집니다. -Guides.Unarmed.Section.4=&3강철 주먹은 어떻게 작동하나요?\n&e강철 주먹은 다른 스킬의 강제 무장 해제 효과를 방지하는 패시브 능력입니다. 비무장 레벨이 올라갈수록 강제 무장 해제를 방지하는 확률이 증가합니다. -Guides.Unarmed.Section.5=&3비무장은 어떻게 작동하나요?\n&e이 패시브 능력은 플레이어가 다른 플레이어의 무기를 해제할 수 있게 해줍니다. 대상의 장착된 아이템은 땅에 떨어집니다. - -##Woodcutting -Guides.Woodcutting.Section.0=&3벌목에 대하여:\n&e벌목은 나무를 베는 것에 관한 스킬입니다.\n\n&3XP 획득:\n&e나무 블록을 부술 때마다 경험치를 얻습니다. -Guides.Woodcutting.Section.1=&3나무꾼은 어떻게 작동하나요?\n&e나무꾼은 액티브 능력으로, 도끼를 들고 우클릭하여\n&e나무 베기를 활성화할 수 있습니다. 이렇게 하면\n&e전체 나무가 즉시 부서지고 한 번에 모든\n&나무 블록이 떨어집니다. -Guides.Woodcutting.Section.2=&3나뭇잎 청소는 어떻게 작동하나요?\n&e나뭇잎 청소는 패시브 능력으로, 도끼로\n&맞힌 잎사귀 블록이 즉시 부서지게 합니다.\n&기본적으로 이 능력은 레벨 100에서 해금됩니다. -Guides.Woodcutting.Section.3=&3드롭 2배는 어떻게 작동하나요?\n&e이 패시브 능력은 베는 나무마다 추가로\n&한 개의 블록을 얻을 수 있는 기회를 제공합니다. - -#INSPECT -Inspect.Offline= &c그 플레이어는 오프라인 상태이므로 검사할 수 없습니다. 오프라인 플레이어를 검사하려면 권한이 필요합니다. -Inspect.OfflineStats=mcMMO 오프라인 유저 스텟은 &e{0} 입니다 -Inspect.Stats=&amcMMO 스텟은 &e{0} 입니다 -Inspect.TooFar=당신은 그 플레이어와 너무 멀리 떨어져 있어 검사할 수 없습니다! - -#ITEMS -Item.ChimaeraWing.Fail=**키메라의 날개 실패!** -Item.ChimaeraWing.Pass=**키메라의 날개** -Item.ChimaeraWing.Name=키메라의 날개 -Item.ChimaeraWing.Lore=&7당신의 침대로 텔레포트합니다. -Item.Generic.Wait=키메라의 날개를 다시 사용하려면 &e({0}초) &c기다려야 합니다! -Item.Injured.Wait=당신은 최근에 부상을 당했으며 이것을 사용하려면 &e({0}초) &f기다려야 합니다 -Item.FluxPickaxe.Name=용해 곡괭이 -Item.FluxPickaxe.Lore.1=&7광물을 즉시 제련할 기회를 가집니다. -Item.FluxPickaxe.Lore.2=&7제련 요구 레벨 {0} 이상 - -#TELEPORTATION -Teleport.Commencing=&7텔레포트가 &6({0}) &7초안에 시작됩니다, 가만히 기다려주세요... +Guides.Page.Invalid=유효한 페이지 번호가 아닙니다! +Guides.Page.OutOfRange=해당 페이지가 존재하지 않습니다. 전체 페이지 수는 {0}입니다. +Guides.Usage= 사용법: /{0} ? [페이지] +##곡예 +Guides.Acrobatics.Section.0=&3곡예에 대해:\n&e곡예는 mcMMO에서 우아하게 움직이는 예술입니다.\n&e전투 보너스 및 환경 피해 보너스를 제공합니다.\n\n&3XP 획득:\n&e이 스킬에서 XP를 획득하려면 전투에서 피격을 회피하거나\n&e높은 곳에서 떨어져서 피해를 입어야 합니다. +Guides.Acrobatics.Section.1=&3롤링이 작동하는 방법은?\n&e낙하 피해를 입을 때 자동으로 피해를 무효화할\n&epassive한 확률이 있습니다.\n&eeSneak 버튼을 누르고 낙하 중에 확률을 두배로 늘릴 수 있습니다.\n&e이로 인해 표준 롤이 아닌 우아한 롤이 발생합니다.\n&e우아한 롤은 일반 롤과 유사하지만 두 배의 확률로\n&e발생하며 표준 롤보다 더 많은 피해 안전을 제공합니다.\n&e롤링 확률은 스킬 레벨에 결합됩니다. +Guides.Acrobatics.Section.2=&3회피가 작동하는 방법은?\n&e회피는 전투 중에\n&e입은 피해를 절반으로 줄이는 자동 확률입니다.\n&e스킬 레벨에 결합됩니다. +##연금술 +Guides.Alchemy.Section.0=[[DARK_AQUA]]연금술에 대해:\n[[YELLOW]]연금술는 포션 제조와 관련이 있습니다.\n[[YELLOW]]포션 제조 시간을 빠르게 할 뿐만 아니라\n[[YELLOW]]이전에 얻을 수 없던 새로운 포션도 추가합니다.\n\n\n[[DARK_AQUA]]XP 획득:\n[[YELLOW]]이 스킬에서 XP를 획득하려면 포션을 제조해야 합니다. +Guides.Alchemy.Section.1=[[DARK_AQUA]]카탈리시스가 작동하는 방법은?\n[[YELLOW]]카탈리시스는 제조 과정을 가속화합니다.\n[[YELLOW]]레벨 100에서 최대 속도가 4배까지 증가합니다.\n[[YELLOW]]이 능력은 기본적으로 레벨 100에서 잠금 해제됩니다. +Guides.Alchemy.Section.2=[[DARK_AQUA]]조제가 작동하는 방법은?\n[[YELLOW]]조제는 사용자 정의 재료로 더 많은 포션을 제조할 수 있습니다.\n[[YELLOW]]잠금 해제된 특별한 재료는 사용자의 등급에 따라 결정됩니다.\n[[YELLOW]]잠금 해제된 특별한 재료는 사용자의 등급에 따라 결정됩니다. 8개의 등급이 있습니다. +Guides.Alchemy.Section.3=[[DARK_AQUA]]조제 1단계 재료:\n[[YELLOW]]Blaze Powder, Fermented Spider Eye, Ghast Tear, Redstone,\n[[YELLOW]]Glowstone Dust, Sugar, Glistering Melon, Golden Carrot,\n[[YELLOW]]Magma Cream, Nether Wart, Spider Eye, Suplhur, Water Lily,\n[[YELLOW]]Pufferfish\n[[YELLOW]](기본 포션) +Guides.Alchemy.Section.4=[[DARK_AQUA]]조제 2단계 재료:\n[[YELLOW]]Carrot (Potion of Haste)\n[[YELLOW]]Slimeball (Potion of Dullness)\n\n[[DARK_AQUA]]조제 3단계 재료:\n[[YELLOW]]Quartz (Potion of Absorption)\n[[YELLOW]]Rabbit's Foot (Potion of Leaping) +Guides.Alchemy.Section.5=[[DARK_AQUA]]조제 4단계 재료:\n[[YELLOW]]Apple (Potion of Health Boost)\n[[YELLOW]]Rotten Flesh (Potion of Hunger)\n\n[[DARK_AQUA]]조제 5단계 재료:\n[[YELLOW]]Brown Mushroom (Potion of Nausea)\n[[YELLOW]]Ink Sack (Potion of Blindness) +Guides.Alchemy.Section.6=[[DARK_AQUA]]조제 6단계 재료:\n[[YELLOW]]Fern (Potion of Saturation)\n\n[[DARK_AQUA]]조제 7단계 재료:\n[[YELLOW]]Poisonous Potato (Potion of Decay)\n\n[[DARK_AQUA]]조제 8단계 재료:\n[[YELLOW]]Regular Golden Apple (Potion of Resistance) +#양궁 +Guides.Archery.Section.0=&3양궁에 대해:\n&e양궁는 활과 화살로 사격하는 것에 관한 것입니다.\n&e전투 보너스로는 레벨에 따라 증가하는 추가 데미지\n&ee와 PvP에서 상대를 헷갈리게 하는 능력 등이 있습니다.\n&ee이외에도 적들의 시체에서 사용한 화살 중 일부를\n&ee회수할 수 있습니다.\n\n\n&3XP 획득:\n&e이 스킬에서 XP를 획득하려면 몹이나 다른 플레이어를\n&ee사격해야 합니다. +Guides.Archery.Section.1=&3스킬샷이 작동하는 방법은?\n&e스킬샷은 사격에 추가 데미지를 제공합니다.\n&e스킬샷의 보너스 데미지는 양궁 레벨이\n&ee증가함에 따라 증가합니다.\n&e기본 설정에서 양궁 데미지는 매 50 레벨마다\n&ee 10%씩 증가하여 최대 200%의 보너스 데미지를 얻습니다. +Guides.Archery.Section.2=&3현혹이 작동하는 방법은?\n&e상대를 사격할 때 다른 플레이어를 헷갈리게 할\n&e자동 확률이 있습니다. 현혹이 발생하면 상대방을\n&ekort 올려 상당한 시간 동안 움직일 수 없게 합니다.\n&e현훅 사격은 추가적으로 4 데미지(2 하트)를 줍니다. +Guides.Archery.Section.3=&3화살 회수가 작동하는 방법은?\n&e활로 몹을 죽일 때 사용한 화살 중 일부를\n&e회수할 수 있는 자동 확률이 있습니다.\n&e양궁 레벨이 증가함에 따라 이 확률이\n&ee증가합니다.\n&e기본적으로 레벨마다 0.1%씩 증가하여 레벨 1000에서\n&ee 100%까지 증가합니다. +##참수 +Guides.Axes.Section.0=&3참수에 대해:\n&eAxe 스킬을 사용하면 나무를 베는 것 이상의 일에\n&e도끼를 사용할 수 있습니다! 몹과 플레이어를 찍고\n&e베어 경험치를 얻을 수 있습니다. 다른 몹에게\n&e넉백 효과를 적용하고 몹과 플레이어에게 치명적인\n&e크리티컬을 입힐 수도 있습니다. 레벨이 오르면\n&ee아처의 갑옷을 쉽게 깨는 수동 핸드 헬드 우드칩퍼가 됩니다.\n&3XP 획득:\n&e이 스킬에서 XP를 획득하려면 도끼로 다른 몹이나 플레이어를\n&eb 치면 됩니다. +Guides.Axes.Section.1=&3스컬 스플리터가 작동하는 방법은?\n&e이 능력은 범위 피해를 입히도록 허용합니다.\n&ee이 범위 피해는 주요 대상에 가한 피해의 절반이 됩니다.\n&e그래서 많은 몹을 쉽게 제거할 수 있습니다. +Guides.Axes.Section.2=&3치명타가 작동하는 방법은?\n&e치명타는 추가 데미지를 줄 수 있는\n&e확률을 제공하는 수동 능력입니다.\n&e기본 설정에서 Axes 2 레벨마다 0.1%의 기회를\n&e얻으며, 이로 인해 몹에게는 2배의 데미지,\n&e플레이어에게는 1.5배의 데미지를 입힐 수 있습니다. +Guides.Axes.Section.3=&3도끼 마스터리가 작동하는 방법은?\n&e도끼 마스터리는 도끼를 사용할 때 피해를 추가합니다.\n&e기본적으로 50 레벨마다 보너스 데미지가 1씩\n&e증가하여 레벨 200에서 최대 4의 추가 피해를\n&ee받습니다. +Guides.Axes.Section.4=&3갑옷 충격이 작동하는 방법은?\n&e갑옷을 파괴할만큼 충격적으로 공격하세요!\n&e갑옷 충격에는 상대의 갑옷을 손상시킬 수 있는\n&ee자동 확률이 있습니다. Axes 레벨이 오르면\n&ee이 데미지가 증가합니다. +Guides.Axes.Section.5=&3더 큰 영향이 작동하는 방법은?\n&e도끼로 몹이나 플레이어를 공격할 때 더 큰\n&e영향을 줄 수 있는 자동 확률이 있습니다.\n&e기본적으로 이 확률은 25%입니다. 이 자동 능력은\n&e넉백 II 인첸트와 유사한 극단적인 넉백 효과를\n&ee가지며 대상에게 추가 데미지를 줍니다. +##발굴 +Guides.Excavation.Section.0=&3발굴에 대해:\n&e발굴은 보물을 찾기 위해 흙을 파는 작업입니다.\n&e땅을 파면 보물을 찾을 수 있습니다.\n&e이를 통해 더 많은 보물을 찾을 수 있습니다.\n\n&3XP 획득:\n&e이 스킬에서 XP를 획득하려면 손에 삽을 들고 파야 합니다.\n&e특정한 재료만이 보물과 XP를 얻을 수 있습니다. +Guides.Excavation.Section.1=&3호환되는 재료:\n&e풀, 흙, 모래, 점토, 자갈, 버섯, 영혼 모래, 눈 +Guides.Excavation.Section.2=&3기가 드릴 브레이커 사용 방법:\n&e삽을 손에 든 상태에서 우클릭하여 도구를 준비합니다.\n&e이 상태에서 약 4초 동안 발굴 호환 재료에\n&e접촉하면 기가 드릴 브레이커를 활성화합니다. +Guides.Excavation.Section.3=&3기가 드릴 브레이커가 무엇인가요?\n&e기가 드릴 브레이커는 발굴 스킬에 링크된\n&e재사용 대기시간이 있는 능력입니다. 보물을 찾을 기회를\n&e3배로 늘리고 발굴 재료에 대한 즉시 부서를\n&ee능력화합니다. +Guides.Excavation.Section.4=&3고고학이 작동하는 방법은?\n&e발굴을 위한 모든 가능한 보물은 획득을 위한\n&e스킬 레벨 요구 사항이 있기 때문에\n&e어느 정도 도움이 되는지 어렵습니다.\n&e단지 발굴 스킬이 높을수록 찾을 수 있는\n&ee보물이 많아집니다.\n&e또한 각 발굴 호환 재료 유형마다 고유한\n&e보물 목록이 있습니다.\n&e다시 말해 Dirt에서는 다른 보물을 발견합니다.\n&ee Gravel. +Guides.Excavation.Section.5=&3발굴에 대한 참고 사항:\n&e발굴 드롭은 완전히 사용자 정의할 수 있습니다.\n&e결과는 서버마다 다릅니다. +##낚시 +Guides.Fishing.Section.0=&3낚시에 관하여:\n&e낚시 스킬을 사용하면 낚시가 다시 흥미로워집니다!\n&e숨겨진 보물을 발견하고 몹에서 아이템을 떨어뜨릴 수 있습니다.\n\n&3XP 획득:\n&e물고기를 낚아라. +Guides.Fishing.Section.1=&3보물 사냥꾼가 작동하는 방법은?\n&e이 능력을 통해 낚시로부터 보물을 발견할 수 있으며\n&e아이템의 일부가 마법부여되어 있는 작은 확률이 있습니다.\n&e낚시의 모든 가능한 보물은 어느 레벨에서나 떨어질 수 있는\n&e확률이 있습니다. 그러나 아이템의 희귀도에 따라\n&ee얼마나 자주 떨어지는지가 달라집니다.\n&e낚시 스킬이 높을수록 더 좋은 보물을 발견할 확률이\n&ee더 좋아집니다. +Guides.Fishing.Section.2=&3얼음 낚시이 작동하는 방법은?\n&e이 수동 능력을 통해 얼음 호수에서 낚시할 수 있습니다!\n&e얼음 호수에 낚싯대를 던지면 능력이 활성화되어\n&e작은 구멍을 만들어 낚시를 할 수 있습니다. +Guides.Fishing.Section.3=&3낚시꾼의 대가가 작동하는 방법은?\n&e이 수동 능력은 낚시할 때 물고기가 낚일 확률을\n&e증가시킵니다. 이 능력을 해제하면 보트에 탑승한\n&ee상태에서 낚시할 때 물고기를 잡을 확률이 높아집니다. +Guides.Fishing.Section.4=&3떨림이 작동하는 방법은?\n&e이 수동 능력을 사용하면 낚싯대로 몹에게서 아이템을\n&e떨어뜨릴 수 있습니다. \n&e몹은 일반적으로 죽을 때 떨어뜨릴 아이템을 떨어뜨립니다.\n&e생존 모드에서 획득할 수 없는 몹 해골도 획득할 수 있습니다. +Guides.Fishing.Section.5=&3어부의 다이어트가 작동하는 방법은?\n&e이 수동 능력은 물고기를 먹을 때 회복되는\n&e배고픔의 양을 증가시킵니다. +Guides.Fishing.Section.6=&3낚시에 관한 참고 사항:\n&e낚시 드롭은 완전히 사용자 정의할 수 있으므로,\n&ee결과는 서버마다 다릅니다. +##약초학 +Guides.Herbalism.Section.0=&3허브 수집에 관하여:\n&eHerbalism은 허브와 식물을 수집하는 것입니다.\n\n\n&3XP 획득:\n&e식물과 허브를 수집하십시오. +Guides.Herbalism.Section.1=&3호환되는 블록\n&e밀, 감자, 당근, 수박,\n&e호박, 사탕수수, 코코아, 꽃, 선인장, 버섯,\n&e네더 와트, 연꽃잎, 덩굴. +Guides.Herbalism.Section.2=&3녹색 에너지가 작동하는 방법은?\n&e녹색 에너지는 활성 능력으로, 괭이를 들고 있는\n&ee상태에서 마우스 오른쪽 버튼을 클릭하여 녹색 에너지를\n&e활성화할 수 있습니다.\n&e녹색 에너지는 플레이어에게 작물을 수확할 때 3배의 드롭을\n&ee얻을 기회를 부여합니다. 또한 인벤토리에서 씨앗을 사용하여\n&e블록에 생명을 주고 변형시킬 수 있는 능력을 제공합니다. +Guides.Herbalism.Section.3=&3식물 재배 (Crops)가 작동하는 방법은?\n&e이 수동 능력은 수확할 때 자동으로 작물을 재배합니다.\n&ee성공 확률은 허브 스킬에 따라 다릅니다. +Guides.Herbalism.Section.4=&3식물 재배 (Cobble/Stone Brick/Dirt)가 작동하는 방법은?\n&e이 수동 능력을 사용하면 블록을 "식물 관련" 동료로 변환할 수 있습니다.\n&e씨앗을 들고 블록을 마우스 오른쪽 버튼으로 클릭하면 됩니다. 이렇게 하면 1개의 씨앗이 소비됩니다. +Guides.Herbalism.Section.5=&3Farmer's Diet가 작동하는 방법은?\n&e이 수동 능력은 빵, 쿠키, 수박, 버섯 수프, 당근,\n&ee감자를 먹을 때 회복되는 배고픔의 양을 증가시킵니다. +Guides.Herbalism.Section.6=&3약초학의 행운이 작동하는 방법은?\n&e이 수동 능력은 일부 블록이 검술로 파괴될 때 희귀 아이템을 찾을 기회를 부여합니다. +Guides.Herbalism.Section.7=&3더블 드롭이 작동하는 방법은?\n&e이 수동 능력은 수확할 때 플레이어에게 더 많은 수확량을 제공합니다. +##채광 +Guides.Mining.Section.0=&3광업에 관하여:\n&e광업은 돌과 광물을 캐는 것으로, 채굴할 때 드롭되는 자원의 양을\n&e증가시켜줍니다.\n\n&3XP 획득:\n&e이 스킬에서 XP를 얻으려면 손에 곡괭이를 들고 채굴해야 합니다.\n&e일부 블록들만이 XP를 부여합니다. +Guides.Mining.Section.1=&3호환되는 블록:\n&e돌, 석탄 광석, 철 광석, 금 광석, 다이아몬드 광석, 레드스톤 광석,\n&e청금석 광석, 옵시디언, 이끼 난간돌, 엔더 돌,\n&e발광석, 네더랙. +Guides.Mining.Section.2=&3슈퍼 브레이커를 사용하는 방법은?\n&e손에 곡괭이를 들고 마우스 오른쪽 버튼을 클릭하여 도구를\n&e준비합니다. 이 상태에서 광업 호환되는 블록에 접촉하여\n&e슈퍼 브레이커를 활성화합니다. +Guides.Mining.Section.3=&3슈퍼 브레이커란 무엇인가요?\n&e슈퍼 브레이커는 광업 스킬에 결합된 쿨다운이 있는 능력입니다.\n&e추가 아이템이 드롭되는 확률을 세 배로 증가시키고,\n&e광업 블록에 대해 즉시 파괴할 수 있습니다. +Guides.Mining.Section.4=&3폭파 광업을 사용하는 방법은?\n&e손에 곡괭이를 들고,\n&e웅크리고 TNT를 거리에서 마우스 오른쪽 버튼으로 클릭합니다.\n&e그러면 TNT가 즉시 폭발합니다. +Guides.Mining.Section.5=&3폭파 광업이 작동하는 방법은?\n&e폭파 광업은 광업 스킬에 결합된 쿨다운이 있는 능력입니다.\n&eTNT와 함께 채굴할 때 보너스를 제공하고,\n&eTNT를 원격으로 폭파할 수 있습니다. 폭파 광업에는 세 가지 부분이 있습니다.\n&e첫 번째는 Bigger Bombs로, 폭발 반경을 증가시킵니다.\n&e두 번째는 철거 전문가로, TNT 폭발로부터의\n&e피해를 감소시킵니다. 세 번째 부분은 단순히\n&eTNT로부터 드롭되는 광석의 양을 증가시키고\n&e파편을 감소시킵니다. +##수리하다 +Guides.Repair.Section.0=&3수리에 관하여:\n&e수리를 사용하면 철 블록을 사용하여 갑옷과\n&e도구를 수리할 수 있습니다.\n\n&3XP 획득:\n&emcMMO 모루를 사용하여 도구나 갑옷을 수리하세요.\n&edefault로 철 블록이며, Vanilla Minecraft 모루와\n&e혼동해서는 안 됩니다. +Guides.Repair.Section.1=&3어떻게 수리를 사용할 수 있나요?\n&emcMMO 모루를 설치하고 현재 들고 있는 아이템을 수리하려면\n&emcMMO 모루를 클릭합니다. 이렇게 하면 사용할 때마다 1개의 아이템이 소모됩니다. +Guides.Repair.Section.2=&3수리 마스터리가 작동하는 방법은?\n&e수리 마스터리는 수리 양을 증가시킵니다. 추가로 수리된\n&e양은 수리 스킬 레벨에 영향을 받습니다. +Guides.Repair.Section.3=&3슈퍼 수리가 작동하는 방법은?\n&e슈퍼 수리는 수동 능력입니다. 아이템을 수리할 때\n&ee더 효과적으로 아이템을 수리할 기회를 부여합니다. +Guides.Repair.Section.4=&3비밀의 단조가 작동하는 방법은?\n&e이 수동 능력을 사용하면 특정 확률로 인챈트된 아이템을 수리하고\n&ee던지지 않을 수 있습니다. 인챈트는 현재 레벨에 따라\n&ee그대로 유지되거나 낮은 수준으로 강등되거나\n&ee완전히 손실될 수 있습니다. +##산출기능술 +Guides.Salvage.Section.0=&3산출에 관하여:\n&e산출을 사용하면 금 블록을 사용하여 갑옷과\n&e도구를 분해할 수 있습니다.\n\n&3XP 획득:\n&e산출은 수리 및 어업의 하위 스킬이며, 여러분의 산출\n&eskil 레벨은 여러분의 낚시 및 수리 스킬 레벨에 기반합니다. +Guides.Salvage.Section.1=&3어떻게 산출을 사용할 수 있나요?\n&emcMMO 산출 모루를 설치하고 현재 들고 있는 아이템을\n&emcMMO 산출 모루를 클릭합니다. 이렇게 하면 아이템이 분해되고,\n&e아이템을 제작하는 데 사용된 자원을 돌려받습니다.\n\n&예를 들어, 철 곡괭이를 산출하면 철 막대를 얻게 됩니다. +Guides.Salvage.Section.2=&3고급 산출이 작동하는 방법은?\n&e이 능력을 잠금 해제하면 손상된 아이템을 분해할 수 있습니다.\n&e생산 비율은 레벨이 올라감에 따라 증가합니다. 높은 생산률은\n&ee더 많은 자원을 얻을 수 있다는 의미입니다.\n&e고급 산출로 인해 항상 1개의 자원을 얻게 되며,\n&e아이템이 너무 손상되어 있는 경우에는 아무것도 얻지 못합니다.\n&e부스러기를 드롭하지 않고. +Guides.Salvage.Section.3=&3이를 설명하기 위해 예를 들어보겠습니다.\n&ee.g. 우리가 20% 손상된 금 곡괭이를 산출한다면,\n&ee최대 얻을 수 있는 양은 2개입니다.\n&e(곡괭이는 각각 33.33% 내구도로 제작되었으므로 각각 66%를 나타냅니다.)\n&ee당신의 수익률이 66% 미만인 경우 2개의 막대를 얻을 수 없습니다.\n&ee그 이상인 경우 "전체 양"을 얻을 수 있습니다.\n&ee이는 2개의 막대를 얻게됩니다. +Guides.Salvage.Section.4=&3비밀의 산출이 작동하는 방법은?\n&e이 능력을 사용하면 인챈트된 아이템을 산출하여 인챈트된 책을\n&ee얻을 수 있습니다. 성공적으로 전체 또는 부분적인 인챈트를\n&ee추출할 확률은 여러분의 레벨에 따라 다릅니다.\n\n&ee인챈트가 부분적으로 추출되는 경우 인챈트된\n&ee책은 아이템에 있던 것보다 낮은 레벨의 인챈트를 가지게 됩니다. +##제련 +Guides.Smelting.Section.0=곧 출시됩니다... +##검 +Guides.Swords.Section.0=&3검에 관하여:\n&e이 스킬은 검을 사용하는 모든 사람에게 전투 보너스를 부여합니다.\n\n&3XP 획득:\n&e검을 사용하여 몹이나 다른 플레이어에게 입힌 데미지 양에 따라 XP를 획득합니다. +Guides.Swords.Section.1=&3톱날 타격이 작동하는 방법은?\n&e톱날 타격은 액티브 능력으로, 검을 들고 우클릭하여 활성화할 수 있습니다.\n&ee오브리오트 (효과 범위) 타격을 할 수 있습니다. 이 AO는\n&e보너스 25% 데미지를 가하고 럽처를 적용할 수 있습니다. +Guides.Swords.Section.2=&3반격이 작동하는 방법은?\n&e반격은 액티브 능력입니다. 몹으로부터 공격을 받을 때 블록하면\n&ee받은 데미지의 50%를 반사할 기회가 생깁니다. +Guides.Swords.Section.3=&3파열이 작동하는 방법은?\n&e파열은 적이 매 두 초마다 피해를 입게 만듭니다. 효과가 사라지거나\n&ee적이 죽을 때까지 타겟은 출혈합니다.\n&e출혈 지속 시간은 검 스킬에 따라 증가합니다. +##길들이기 +Guides.Taming.Section.0=&3테이밍에 관하여:\n&e테이밍은 길들인 늑대를 사용할 때 플레이어에게 다양한 전투 보너스를 부여합니다.\n\n&3XP 획득:\n&e이 스킬에서 XP를 얻으려면 늑대/오셀롯을 길들이거나\n&e자신의 늑대와 전투에 들어가야 합니다. +Guides.Taming.Section.1=&3야생의 부름이 작동하는 방법은?\n&e야생의 부름은 능동적인 능력으로, 뼈나 생선을 들고 있을 때 웅크리고 왼쪽 클릭하여\n&e웅크리기 + 왼쪽 클릭를 하면 늑대나 오셀롯을 소환할 수 있습니다. +Guides.Taming.Section.2=&3야수 상식이 작동하는 방법은?\n&e야수 상식을 사용하면 애완동물을 조사하고 늑대와 오셀롯의 통계를 확인할 수 있습니다.\n&ee야수 지식를 사용하려면 늑대나 오셀롯을 왼쪽 클릭합니다. +Guides.Taming.Section.3=&3천식이 작동하는 방법은?\n&e천식은 늑대의 대상에게 출혈 효과를 발생시키는 기회가 있는 패시브 능력입니다. +Guides.Taming.Section.4=&3연마된 발톱이 작동하는 방법은?\n&e연마된 발톱은 늑대가 가하는 피해에 추가 피해 보너스를 제공합니다.\n&e데미지 보너스는 길들이기 레벨에 따라 다릅니다. +Guides.Taming.Section.5=&3환경 인식이 작동하는 방법은?\n&e이 패시브 능력은 늑대가 가시나 용암과 같은 위험에 가까이 갈 때\n&e당신에게 텔레포트할 수 있도록 합니다. 그리고 늑대에게 추락\n&e피해 면역를 부여합니다. +Guides.Taming.Section.6=&3두꺼운 모피가 작동하는 방법은?\n&e이 패시브 능력은 데미지를 줄이고 늑대를 화염 내성으로 만듭니다. +Guides.Taming.Section.7=&3충격 방지가 작동하는 방법은?\n&e이 패시브 능력은 폭발로 인한 늑대에게 가해지는 피해를 줄입니다. +Guides.Taming.Section.8=&3패스트 푸드 서비스가 작동하는 방법은?\n&e이 패시브 능력은 늑대가 공격할 때마다 회복할 기회를 제공합니다. +##비무장 +Guides.Unarmed.Section.0=&3무장에 관하여:\n&e무장은 주먹으로 무기를 사용할 때 플레이어에게 다양한 전투 보너스를 부여합니다.\n\n&3XP 획득:\n&e주먹으로 몹이나 다른 플레이어에게 가한 데미지 양에 따라 XP를 획득합니다. +Guides.Unarmed.Section.1=&3광분이 작동하는 방법은?\n&e광분은 우클릭으로 활성화되는 액티브 능력입니다. 광분 모드에서는 50% 더 많은\n&e피해 를 가하고, 흙과 풀과 같은 약한 재료를 즉시 부술 수 있습니다. +Guides.Unarmed.Section.2=&3철 팔 스타일이 작동하는 방법은?\n&e철 팔 스타일은 주먹으로 몹이나 플레이어를 때릴 때 가하는 피해를 증가시킵니다. +Guides.Unarmed.Section.3=&3화살 반사가 작동하는 방법은?\n&e화살 반사는 스켈레톤이나 다른 플레이어가 발사한 화살을 반사할 기회를 주는 패시브 능력입니다.\n&e화살은 위험하게 땅에 떨어집니다. +Guides.Unarmed.Section.4=&3철제 그립이 작동하는 방법은?\n&e철제 그립은 무장해제을 카운터하는 패시브 능력입니다. 무장 레벨이 올라갈수록 무장해제을\n&e방지하는 기회가 늘어납니다. +Guides.Unarmed.Section.5=&3무장 해제가 작동하는 방법은?\n&e이 패시브 능력은 다른 플레이어를 무장해제하여 대상의 장비가 땅에 떨어지게 만듭니다. +##벌목 +Guides.Woodcutting.Section.0=&3나무꾼에 관하여:\n&e나무꾼은 나무를 베는 데에 관한 것입니다.\n\n&3XP 획득:\n&e네모난 블록을 부술 때마다 XP가 획득됩니다. +Guides.Woodcutting.Section.1=&3트리 펠러가 작동하는 방법은?\n&e트리 펠러는 액티브 능력으로, 도끼를 들고 우클릭하여 트리 펠러를 활성화할 수 있습니다.\n&ee전체 트리를 즉시 부수고 모든 나무를 한 번에 드랍합니다. +Guides.Woodcutting.Section.2=&3잎 블로어가 작동하는 방법은?\n&e잎 블로어는 도끼로 맞을 때 잎 블록이 즉시 부서지도록 하는 패시브 능력입니다.\n&e기본으로 이 능력은 레벨 100에서 잠금 해제됩니다. +Guides.Woodcutting.Section.3=&3더블 드롭이 작동하는 방법은?\n&e이 패시브 능력은 베어 나무마다 추가 블록을 얻을 기회를 제공합니다. +#검사 +Inspect.Offline= &c오프라인 플레이어를 확인할 권한이 없습니다! +Inspect.OfflineStats=오프라인 플레이어 &e{0}의 mcMMO 통계 +Inspect.Stats=&a{0}의 mcMMO 통계 +Inspect.TooFar=해당 플레이어를 확인하기에 너무 멀리 있습니다! +#아이템 +Item.ChimaeraWing.Fail=&c**카이메라 날개 실패!** +Item.ChimaeraWing.Pass=**카이메라 날개** +Item.ChimaeraWing.Name=카이메라 날개 +Item.ChimaeraWing.Lore=&7침대로 이동합니다. +Item.ChimaeraWing.NotEnough= &e{1}&c이(가) 더 필요합니다! {0}개 +Item.NotEnough= &e{1}&c이(가) 더 필요합니다! {0}개 +Item.Generic.Wait=다시 사용하기 전에 기다려야 합니다! &e({0}초) +Item.Injured.Wait=최근에 부상당했으므로 사용을 기다려야 합니다. &e({0}초) +Item.FluxPickaxe.Name=플럭스 곡괭이 +Item.FluxPickaxe.Lore.1=&7광물을 즉시 제련하는 기회가 있습니다. +Item.FluxPickaxe.Lore.2=&7제련 레벨 {0} 이상 필요 +#텔레포트 +Teleport.Commencing=&7텔레포트 시작 &6({0}초), &7제자리에 서십시오... Teleport.Cancelled=&4텔레포트 취소됨! - -#SKILLS -Skills.Child=&6(부가 스킬) -Skills.Disarmed=&4당신은 무장 해제되었습니다! -Skills.Header=-----[]&a{0}&c[]----- -Skills.NeedMore=&4당신은 &7{0}&4가 더 필요합니다 -Skills.NeedMore.Extra=&4당신은 &7{0}{1}가 더 필요합니다 -Skills.Parents = 상위 속성들 -Skills.MaxXP=최대 XP +#스킬 +Skills.Child=&6(하위 스킬) +Skills.Disarmed=&4무장이 해제되었습니다! +Skills.Header=-----[] &a{0}&c []----- +Skills.NeedMore=&4{0}를 더 필요합니다 +Skills.NeedMore.Extra=&4{0}{1}를 더 필요합니다 +Skills.Parents= 상위 스킬 Skills.Stats={0}&a{1}&3 XP(&7{2}&3/&7{3}&3) Skills.ChildStats={0}&a{1} -Skills.TooTired=스킬 재 사용 대기시간: ({0}초) -Skills.TooTired.Named=&7(&6{0}&e {1}s&7) -Skills.TooTired.Extra=&6{0}&e의 쿨타임: {1} -Skills.Cancelled={0} 취소됨! -Skills.ConfirmOrCancel=&a다시 우-클릭을 하면 확인 &6{0}&a. 좌-클릭을 하면 취소가 됩니다. -Skills.AbilityGateRequirementFail=&7이 슈퍼 능력을 사용하려면 &e{0}&7만큼의 &3{1}&7 스킬 레벨이 필요합니다. - -#STATISTICS +Skills.MaxXP=최대 +Skills.TooTired=다시 사용하려면 너무 피곤합니다. &e({0}초) +Skills.TooTired.Named=&7(&6{0}&e 초&7) +Skills.TooTired.Extra=&6{0} &e슈퍼 능력 대기시간 - {1} +Skills.Cancelled=&6{0} &c취소되었습니다! +Skills.ConfirmOrCancel=&a다시 오른쪽 클릭하여 &6{0}&a 확인하십시오. 왼쪽 클릭하여 취소하십시오. +Skills.AbilityGateRequirementFail=&7이 슈퍼 능력을 사용하려면 &3{1}&7 레벨이 더 필요합니다. +#통계 Stats.Header.Combat=&6-=전투 스킬=- -Stats.Header.Gathering=&6-=수집 스킬=- +Stats.Header.Gathering=&6-=채집 스킬=- Stats.Header.Misc=&6-=기타 스킬=- -Stats.Own.Stats=&a[mcMMO] 스텟 - -#PERKS +Stats.Own.Stats=&a[mcMMO] 통계 +#특전 Perks.XP.Name=경험치 -Perks.XP.Desc=특정 스킬에 경험치 부스트를 받음. +Perks.XP.Desc=특정 스킬에서 부스트된 XP를 받습니다. Perks.Lucky.Name=행운 -Perks.Lucky.Desc={0} 스킬과 능력에 33.3%의 더 많은 활성화 확률을 부여합니다. -Perks.Lucky.Desc.Login=특정 스킬과 능력에 33.3%의 더 많은 활성화 확률을 부여합니다. -Perks.Lucky.Bonus=&6 ({0} 운좋은 특전과 함께) +Perks.Lucky.Desc={0} 스킬과 능력이 33.3% 더 활성화됩니다. +Perks.Lucky.Desc.Login=특정 스킬과 능력이 33.3% 더 활성화됩니다. +Perks.Lucky.Bonus=&6 (행운 특전으로 {0}) Perks.Cooldowns.Name=빠른 회복 -Perks.Cooldowns.Desc=재사용대기시간을 {0}만큼 줄입니다 -Perks.ActivationTime.Name=인내력 -Perks.ActivationTime.Desc=능력 활성 시간이 {0}초로 증가합니다. -Perks.ActivationTime.Bonus=&6 ({0}초의 인내력 특전) - -#HARDCORE -Hardcore.Mode.Disabled=&6[mcMMO] 하드코어 모드 {0}가 {1}에 비활성화됨. -Hardcore.Mode.Enabled=&6[mcMMO] 하드코어 모드 {0}가 {1}에 활성화됨. -Hardcore.DeathStatLoss.Name=스킬 데스 패널티 -Hardcore.DeathStatLoss.PlayerDeath=&6[mcMMO] &4당신은 죽어서 &9{0}&4 레벨을 잃었습니다. -Hardcore.DeathStatLoss.PercentageChanged=&6[mcMMO] 스텟 감소 비율이 {0}로 변경되었습니다.. -Hardcore.Vampirism.Name=뱀파이어리즘 -Hardcore.Vampirism.Killer.Failure=&6[mcMMO] &e{0}&7님은 특별한 기술을 가지고 있지 않아 당신이 가져갈 지식이 없습니다. -Hardcore.Vampirism.Killer.Success=&6[mcMMO] &3당신은 &e{1}&3님으로부터 &9{0}&3 레벨을 훔쳤습니다. -Hardcore.Vampirism.Victim.Failure=&6[mcMMO] &e{0}&7님은 당신의 지식을 가져갈 수 없었습니다! -Hardcore.Vampirism.Victim.Success=&6[mcMMO] &e{0}&4님은 당신에게서 &9{1}&4 레벨을 훔쳐갔습니다! - +Perks.Cooldowns.Desc=쿨다운 기간을 {0} 만큼 줄입니다. +Perks.ActivationTime.Name=지속력 +Perks.ActivationTime.Desc=능력 활성화 시간을 {0}초로 증가시킵니다. +Perks.ActivationTime.Bonus=&6 ({0}초의 지속력 특전) +#하드코어 +Hardcore.Mode.Disabled=&6[mcMMO] 하드코어 모드 {0}이(가) {1}에 대해 비활성화되었습니다. +Hardcore.Mode.Enabled=&6[mcMMO] 하드코어 모드 {0}이(가) {1}에 대해 활성화되었습니다. +Hardcore.DeathStatLoss.Name=스킬 사망 페널티 +Hardcore.DeathStatLoss.PlayerDeath=&6[mcMMO] &4죽음으로 인해 &9{0} 레벨이 손실되었습니다. +Hardcore.DeathStatLoss.PercentageChanged=&6[mcMMO] 페널티 손실 비율이 {0}로 변경되었습니다. +Hardcore.Vampirism.Name=흡혈 +Hardcore.Vampirism.Killer.Failure=&6[mcMMO] &e{0}&7님은 지식을 훔치기에는 너무 미숙합니다. +Hardcore.Vampirism.Killer.Success=&6[mcMMO] &3당신은 &e{1} &9{0} 레벨을 훔쳤습니다. +Hardcore.Vampirism.Victim.Failure=&6[mcMMO] &e{0}&7님이 당신으로부터 지식을 훔치는 데 실패했습니다! +Hardcore.Vampirism.Victim.Success=&6[mcMMO] &e{0}&4님이 당신으로부터 &9{1} 레벨을 훔쳤습니다! +Hardcore.Vampirism.PercentageChanged=&6[mcMMO] 플레이어로부터 지식을 흡수하는 비율이 {0}로 변경되었습니다. #MOTD MOTD.Donate=&3기부 정보: MOTD.Hardcore.Enabled=&6[mcMMO] &3하드코어 모드 활성화됨: &4{0} -MOTD.Hardcore.DeathStatLoss.Stats=&6[mcMMO] &3데스 패널티 능력: &4{0}% -MOTD.Hardcore.Vampirism.Stats=&6[mcMMO] &3뱀파이어리즘 스텟 흡수: &4{0}% -MOTD.PerksPrefix=[mcMMO 특전] -MOTD.Version=&6[mcMMO] 구동중인 버전 &3{0} +MOTD.Hardcore.DeathStatLoss.Stats=&6[mcMMO] &3스킬 사망 페널티: &4{0}% +MOTD.Hardcore.Vampirism.Stats=&6[mcMMO] &3흡혈 스탯 흡수: &4{0}% +MOTD.PerksPrefix=&6[mcMMO 특전] +MOTD.Version=&6[mcMMO] 버전 &3{0} 실행 중 MOTD.Website=&6[mcMMO] &a{0}&e - mcMMO 웹사이트 - -#SMELTING -Smelting.Ability.FluxMining=유동 채굴 확률: &e{0} -Smelting.Ability.FuelEfficiency=연료 효율성 배율: &e{0}x -Smelting.Ability.Locked.0={0}레벨 때 기술이 해제됩니다 (바닐라 XP 부스트) -Smelting.Ability.Locked.1={0}레벨 때 기술이 해제됩니다 (유동 채굴) -Smelting.Ability.SecondSmelt=두번째 재련 확률: &e{0} -Smelting.Ability.VanillaXPBoost=바닐라 XP 배율: &e{0}x -Smelting.SubSkill.UnderstandingTheArt.Name=예술의 이해 -Smelting.SubSkill.UnderstandingTheArt.Description=아마도 동굴에서 너무 많은 시간을 보내고 있을지도 모릅니다.\n제련의 다양한 속성을 강화합니다. -Smelting.SubSkill.UnderstandingTheArt.Stat=바닐라 XP 배율: &e{0}배 +#제련 +Smelting.SubSkill.UnderstandingTheArt.Name=Understanding The Art +Smelting.SubSkill.UnderstandingTheArt.Description=아마도 동굴에서 제련하는 데 너무 많은 시간을 소비하고 있습니다.\n제련의 다양한 속성을 강화합니다. +Smelting.SubSkill.UnderstandingTheArt.Stat=바닐라 경험치 배율: &e{0}배 +Smelting.Ability.Locked.0={0}+ 스킬까지 잠김 (바닐라 XP 부스트) +Smelting.Ability.Locked.1={0}+ 스킬까지 잠김 (플럭스 광산) Smelting.SubSkill.FuelEfficiency.Name=연료 효율성 +Smelting.SubSkill.FuelEfficiency.Description=제련할 때 사용되는 화로 연료의 연소 시간을 증가시킵니다. Smelting.SubSkill.FuelEfficiency.Stat=연료 효율성 배율: &e{0}배 -Smelting.SubSkill.FuelEfficiency.Description=화로에서 재련시 연료 연소 시간 증가 -Smelting.SubSkill.SecondSmelt.Name=두 번째 제련 -Smelting.SubSkill.SecondSmelt.Description=제련시 얻는 자원 2배 -Smelting.SubSkill.SecondSmelt.Stat=두 번째 재련 확률 +Smelting.SubSkill.SecondSmelt.Name=이중 제련 +Smelting.SubSkill.SecondSmelt.Description=제련으로 얻은 자원을 두 배로 늘립니다. +Smelting.SubSkill.SecondSmelt.Stat=이중 제련 확률 Smelting.Effect.4=바닐라 XP 부스트 -Smelting.Effect.5=제련중 바닐라 XP 얻기 증가 -Smelting.SubSkill.FluxMining.Name=유동 채굴 -Smelting.SubSkill.FluxMining.Description=채굴중 광물 즉시 재련 확률 -Smelting.SubSkill.FluxMining.Stat=유동 채굴 확률 -Smelting.FluxMining.Success=&a광물이 재련되었습니다! -Smelting.Listener=제련(Smelting): +Smelting.Effect.5=제련 시 얻는 바닐라 XP를 증가시킵니다. +Smelting.SubSkill.FluxMining.Name=플럭스 광산 +Smelting.SubSkill.FluxMining.Description=광물이 채굴되는 동안 즉시 제련되는 확률이 있습니다. +Smelting.SubSkill.FluxMining.Stat=플럭스 광산 확률 +Smelting.Listener=제련: Smelting.SkillName=제련 - - -#COMMAND DESCRIPTIONS -Commands.Description.addlevels=mcMMO 레벨을 유저에게 추가 -Commands.Description.adminchat=mcMMO 관리자 채팅 켜기/끄기나 관리자 채팅 메세지 보내기 -Commands.Description.addxp=mcMMO 경험치를 유저에게 추가 -Commands.Description.hardcore=mcMMO 하드코어 확률 수정이나 하드코어 모드 켜기/끄기 -Commands.Description.inspect=다른 플레이어의 mcMMO 자세한 정보 보기 -Commands.Description.mcability=mcMMO 우-클릭 능력 켜기/끄기 -Commands.Description.mccooldown=모든 mcMMO 능력 재 사용 대기시간 보기 -Commands.Description.mcchatspy=mcMMO 파티 채팅 감시 켜기/끄기 -Commands.Description.mcgod=mcMMO 불사신-모드 켜기/끄기 -Commands.Description.mchud=mcMMO HUD 방식 변경 -Commands.Description.mcmmo=mcMMO 제작자 설명 보기 -Commands.Description.mcnotify=mcMMO 능력 채팅 알림 보기 켜기/끄기 -Commands.Description.mcpurge={0} 달 이상 접속안한 유저의 mcMMO 레벨과 유저를 mcMMO 데이터베이스에서 초기화시킴 -Commands.Description.mcrank=플레이어 mcMMO 순위 보기 -Commands.Description.mcrefresh=모든 mcMMO 쿨다운 초기화 -Commands.Description.mcremove=유저 mcMMO 데이터베이스 삭제 -Commands.Description.mcscoreboard=당신의 mcMMO 점수판 관리 -Commands.Description.mcstats=자신의 mcMMO 레벨과 XP 보기 -Commands.Description.mctop=mcMMO 점수표 보기 -Commands.Description.mmoedit=유저의 mcMMO 레벨 수정 -Commands.Description.mmodebug=블록을 때릴 때 유용한 정보를 출력하는 디버그 모드를 켜기/끄기. -Commands.Description.mmoupdate=mcMMO 데이터베이스를 flatfile에서 MySQL로 전환 -Commands.Description.mcconvert=데이터베이스 타입 또는 경험 공식 타입 전환 -Commands.Description.mmoshowdb=현재 데이터베이스 타입 이름 보기(나중에 /mmoupdate와 함께 쓰입니다) -Commands.Description.party=다양한 mcMMO 파티 설정 관리 -Commands.Description.partychat=mcMMO 파티 채팅 켜기/끄기나 파티 채팅 메세지 보내기 -Commands.Description.ptp=mcMMO 파티 맴버 텔레포트 -Commands.Description.Skill=mcMMO 기술 {0}의 자세한 정보 보기 -Commands.Description.skillreset=유저의 mcMMO 레벨 재설정 -Commands.Description.vampirism=mcMMO 뱀파이어리즘 비율이나 뱀파이어리즘 모드 켜기/끄기 -Commands.Description.xplock=명확한 mcMMO 기술의 mcMMO xp 바를 잠금 -Commands.Description.xprate=mcMMO XP 배율 수정이나 mcMMO XP 이벤트 시작 - -#UPDATE CHECKER -UpdateChecker.outdated=당신은 mcMMO 구버전을 사용중입니다! -UpdateChecker.newavailable=신 버전이 Spigot에 업로드되어 있습니다. - -#SCOREBOARD HEADERS -Scoreboard.Header.PlayerStats=mcMMO 스텟 -Scoreboard.Header.PlayerCooldowns=mcMMO 재 사용 대기시간 -Scoreboard.Header.PlayerRank=mcMMO 순위 -Scoreboard.Header.PlayerInspect=mcMMO 스텟: -Scoreboard.Header.PowerLevel=총 레벨 -Scoreboard.Misc.PowerLevel=&6총 레벨 +#명령어 설명 +Commands.Description.addlevels=사용자에게 mcMMO 레벨을 추가합니다. +Commands.Description.adminchat=mcMMO 관리자 채팅을 켜거나 끕니다. 또는 관리자 채팅 메시지를 보냅니다. +Commands.Description.addxp=사용자에게 mcMMO XP를 추가합니다. +Commands.Description.hardcore=mcMMO 하드코어 백분율을 수정하거나 하드코어 모드를 켜거나 끕니다. +Commands.Description.inspect=다른 플레이어에 대한 자세한 mcMMO 정보를 확인합니다. +Commands.Description.mcability=오른쪽 클릭으로 mcMMO 능력 사용을 준비하거나 해제합니다. +Commands.Description.mccooldown=모든 mcMMO 능력 쿨다운을 보여줍니다. +Commands.Description.mcchatspy=mcMMO 파티 채팅 감시를 켜거나 끕니다. +Commands.Description.mcgod=mcMMO 갓 모드를 켜거나 끕니다. +Commands.Description.mchud=mcMMO HUD 스타일을 변경합니다. +Commands.Description.mcmmo=mcMMO에 대한 간략한 설명을 표시합니다. +Commands.Description.mcnotify=mcMMO 능력 채팅 표시 알림을 켜거나 끕니다. +Commands.Description.mcpurge=mcMMO 데이터베이스에서 mcMMO 레벨이 없거나 지정된 개월 동안 접속하지 않은 사용자를 제거합니다. +Commands.Description.mcrank=플레이어의 mcMMO 순위를 표시합니다. +Commands.Description.mcrefresh=mcMMO의 모든 쿨다운을 새로 고칩니다. +Commands.Description.mcremove=사용자를 mcMMO 데이터베이스에서 제거합니다. +Commands.Description.mcscoreboard=mcMMO 스코어보드를 관리합니다. +Commands.Description.mcstats=사용자의 mcMMO 레벨과 XP를 표시합니다. +Commands.Description.mctop=mcMMO 리더보드를 표시합니다. +Commands.Description.mmoedit=사용자의 mcMMO 레벨을 편집합니다. +Commands.Description.mmodebug=디버그 모드를 토글하여 블록을 탭할 때 유용한 정보를 출력합니다. +Commands.Description.mmoupdate=이전 데이터베이스에서 현재 데이터베이스로 mcMMO 데이터베이스를 마이그레이션합니다. +Commands.Description.mcconvert=데이터베이스 유형이나 경험치 공식 유형을 변환합니다. +Commands.Description.mmoshowdb=현재 데이터베이스 유형의 이름을 표시합니다 (/mmoupdate에서 사용됨). +Commands.Description.party=다양한 mcMMO 파티 설정을 제어합니다. +Commands.Description.partychat=mcMMO 파티 채팅을 켜거나 끕니다. 또는 파티 채팅 메시지를 보냅니다. +Commands.Description.ptp=mcMMO 파티 멤버로 텔레포트합니다. +Commands.Description.Skill={0}에 대한 자세한 mcMMO 스킬 정보를 표시합니다. +Commands.Description.skillreset=사용자의 mcMMO 레벨을 재설정합니다. +Commands.Description.vampirism=mcMMO 흡혈 백분율을 수정하거나 흡혈 모드를 켜거나 끕니다. +Commands.Description.xplock=mcMMO XP 바를 특정 mcMMO 스킬에 잠급니다. +Commands.Description.xprate=mcMMO XP 비율을 수정하거나 mcMMO XP 이벤트를 시작합니다. +#업데이트 체크 +UpdateChecker.Outdated=사용 중인 mcMMO 버전이 오래되었습니다! +UpdateChecker.NewAvailable=Spigot에서 새 버전을 사용할 수 있습니다. +#스코어보드 헤더 +Scoreboard.Header.PlayerStats=&emcMMO 통계 +Scoreboard.Header.PlayerCooldowns=&emcMMO 쿨다운 +Scoreboard.Header.PlayerRank=&emcMMO 순위 +Scoreboard.Header.PlayerInspect=&emcMMO 통계: {0} +Scoreboard.Header.PowerLevel=&c파워 레벨 +Scoreboard.Misc.PowerLevel=&6파워 레벨 Scoreboard.Misc.Level=&3레벨 Scoreboard.Misc.CurrentXP=&a현재 XP -Scoreboard.Misc.RemainingXP=남은 XP -Scoreboard.Misc.Cooldown=&d재 사용 대기시간 -Scoreboard.Misc.Overall=&6종합 +Scoreboard.Misc.RemainingXP=&e남은 XP +Scoreboard.Misc.Cooldown=&d쿨다운 +Scoreboard.Misc.Overall=&6전체 Scoreboard.Misc.Ability=능력 - -#DATABASE RECOVERY -Profile.PendingLoad=&c당신의 mcMMO 프로파일을 아직 불러오지 못했습니다. -Profile.Loading.Success=&a당신의 mcMMO 프로파일을 불러왔습니다. -Profile.Loading.Failure=mcMMO는 여전히 당신의 데이터를 읽을 수 없습니다. 당신은 아마도 &b서버관리자와 연락&c하기를 원할 것입니다.\n&e당신은 여전히 서버에서 게임중이지만, 당신은 &lmcMMO 레벨이 없고&e 당신이 얻은 어느 XP도 &l저장되지 않을 겁니다&e. -Profile.Loading.AdminFailureNotice=&4[A]&c mcMMO는 &e{0}&c 플레이어 데이터 읽기가 불가능합니다. &d당신의 데이터베이스 설치를 검사해주세요. -Profile.Loading.FailurePlayer=mcMMO가 데이터를 로드하는 데 문제가 발생했습니다. 로드 시도 횟수: {0}회. 이 문제에 대해 서버 관리자에게 문의하십시오. 데이터가 로드되지 않은 동안 XP를 획득하거나 기술을 사용할 수 없습니다. -Profile.Loading.FailureNotice=&4[A]&c mcMMO는 &e{0}&c 플레이어 데이터를 로드하지 못했습니다. &d데이터베이스 설정을 확인하십시오. 현재까지 시도한 횟수: {1}. -Commands.XPBar.Usage=올바른 사용법: /mmoxpbar <스킬명 | reset> -Commands.Description.mmoxpbar=mcMMO XP 바에 대한 플레이어 설정 -Commands.Description.mmocompat=mcMMO의 호환 모드 또는 완전한 기능 여부에 대한 정보 - +#데이터베이스 복구 +Profile.PendingLoad=&c당신의 mcMMO 플레이어 데이터가 아직로드되지 않았습니다. +Profile.Loading.Success=&a당신의 mcMMO 프로필이 로드되었습니다. +Profile.Loading.FailurePlayer=&cmcMMO는 데이터로드에 문제가 있습니다. 우리는 &a{0}번&c 시도했습니다. &c이 문제에 대해 서버 관리자에게 문의하십시오. mcMMO는 데이터가로드되지 않은 동안 XP를 획득하거나 기술을 사용할 수 없습니다. +Profile.Loading.FailureNotice=&4[A]&c mcMMO가 &e{0}&c의 플레이어 데이터를로드하지 못했습니다. &d데이터베이스 설정을 확인하십시오. 지금까지 시도한 시도 {1}. #Holiday -Holiday.AprilFools.Levelup=&6{0}은(는) 이제 &a{1}&6레벨입니다! -Holiday.Anniversary=&9{0}주년을 축하합니다!\n&9nossr50의 모든 작업과 개발자들을 기리기 위해 불꽃쇼를 선물합니다! - +Holiday.AprilFools.Levelup=&6{0}님이 이제 레벨 &a{1}&6입니다! +Holiday.Anniversary=&9{0}주년을 축하합니다!\n&9모든 nossr50의 작업과 개발자들을 기념하여 불꽃놀이를 여기에 선사합니다! #Reminder Messages -Reminder.Squelched=&7알림: 현재 mcMMO로부터 알림을 받지 않고 있습니다. 알림을 활성화하려면 다시 /mcnotify 명령을 실행하십시오. 이것은 자동으로 매 시간마다 알림이 전송되는 것입니다. - +Reminder.Squelched=&7리마인더: 당신은 현재 mcMMO로부터 알림을받지 않습니다. 알림을 받으려면 다시 /mcnotify 명령을 실행하십시오. 이것은 자동으로 시간당 알림입니다. #Locale -Locale.Reloaded=&a번역을 리로드했습니다! - +Locale.Reloaded=&a로케일이 다시로드되었습니다! #Player Leveling Stuff -LevelCap.PowerLevel=&6(&amcMMO&6) &e파워 레벨 &c{0}&e에 도달했습니다. 이제부터 스킬 레벨이 상승하지 않습니다. -LevelCap.Skill=&6(&amcMMO&6) &e&6{1}&e 스킬의 레벨 캡 &c{0}&e에 도달했습니다. 이제부터 이 스킬의 레벨이 상승하지 않습니다. -Commands.XPBar.Usage=올바른 사용법: /mmoxpbar <스킬명 | reset> +LevelCap.PowerLevel=&6(&amcMMO&6) &e파워 레벨 상한에 도달했습니다: &c{0}&e. 여기서부터는 더 이상 기술을 레벨링하지 않습니다. +LevelCap.Skill=&6(&amcMMO&6) &e&6{1}&e의 레벨 상한에 도달했습니다: &c{0}&e. 여기서부터는 이 기술의 레벨이 증가하지 않습니다. +Commands.XPBar.Usage=올바른 사용법은 /mmoxpbar <기술명 | 재설정> <표시 | 숨기기> 입니다. Commands.Description.mmoxpbar=mcMMO XP 바에 대한 플레이어 설정 -Commands.Description.mmocompat=mcMMO의 호환 모드 또는 완전한 기능 여부에 대한 정보 -Compatibility.Layer.Unsupported=&6{0}&6의 호환성은 이 버전의 Minecraft에서 지원되지 않습니다. -Compatibility.Layer.PartialSupport=&6{0}&6의 호환성은 이 버전의 Minecraft에서 완전히 지원되지 않지만, mcMMO는 일부 기능을 에뮬레이션하기 위해 보조 시스템을 실행 중입니다. -Commands.XPBar.DisableAll=&6모든 mcMMO XP 바가 비활성화되었습니다. 기본 설정으로 복원하려면 /mmoxpbar reset을 사용하세요. - +Commands.Description.mmocompat=mcMMO에 대한 정보 및 호환 모드 또는 완전 기능적 모드 여부. +Compatibility.Layer.Unsupported=&6{0}&6의 호환성은 이 Minecraft 버전에서 지원되지 않습니다. +Compatibility.Layer.PartialSupport=&6{0}&6의 호환성은 이 Minecraft 버전에서 완전히 지원되지 않지만, mcMMO는 일부 부족한 기능을 모방하기위한 보조 시스템을 실행 중입니다. +Commands.XPBar.DisableAll=&6모든 mcMMO XP 바가 비활성화되었습니다. 기본 설정으로 복원하려면 /mmoxpbar 재설정을 사용하세요. #Modern Chat Settings Chat.Style.Admin=&b(A) &r{0} &b\u2192 &r{1} Chat.Style.Party=&a(P) &r{0} &a\u2192 &r{1} Chat.Style.Party.Leader=&a(P) &r{0} &6\u2192 &r{1} Chat.Identity.Console=&6* 콘솔 * -Chat.Channel.On=&6(&amcMMO-Chat&6) &e당신의 채팅 메시지는 이제 &a{0}&e 채팅 채널로 자동 전달됩니다. -Chat.Channel.Off=&6(&amcMMO-Chat&6) &7당신의 채팅 메시지는 더 이상 특정 채팅 채널로 자동 전달되지 않습니다. +Chat.Channel.On=&6(&amcMMO-채팅&6) &e당신의 채팅 메시지는 이제 &a{0}&e 채널로 자동 전달됩니다. +Chat.Channel.Off=&6(&amcMMO-채팅&6) &7당신의 채팅 메시지는 더 이상 특정 채팅 채널로 자동 전달되지 않습니다. Chat.Spy.Party=&6[&eSPY&6-&a{2}&6] &r{0} &b\u2192 &r{1} -Broadcasts.LevelUpMilestone=&6(&amcMMO&6) {0}&7님이 &3{2}&7에서 레벨 &a{1}&7에 도달했습니다! -Broadcasts.PowerLevelUpMilestone=&6(&amcMMO&6) {0}&7님이 파워 레벨 &a{1}&7에 도달했습니다! -Scoreboard.Recovery=mcMMO 점수판을 복구하는 중입니다... -Scoreboard.Disabled=이 서버의 mcMMO 점수판이 비활성화되었습니다. 이 설정은 mcMMO/config.yml에서 찾을 수 있습니다. -Scoreboard.NotSetupYet=당신의 mcMMO 점수판이 아직 설정되지 않았습니다. 나중에 다시 시도해보세요. +Broadcasts.LevelUpMilestone=&6(&amcMMO&6) {0}&7님이 &3{2}&7에서 레벨 &a{1}&7달렸습니다! +Broadcasts.PowerLevelUpMilestone=&6(&amcMMO&6) {0}&7님이 &a{1}&7단계의 파워 레벨에 도달했습니다! +Scoreboard.Recovery=mcMMO 스코어보드를 복구하는 중입니다... +Scoreboard.Disabled=이 서버의 mcMMO 스코어보드가 비활성화되었습니다. 이 설정은 mcMMO/config.yml에서 찾을 수 있습니다. +Scoreboard.NotSetupYet=당신의 mcMMO 스코어보드가 아직 설정되지 않았습니다. 나중에 다시 시도하십시오. diff --git a/src/main/resources/locale/locale_lt_LT.properties b/src/main/resources/locale/locale_lt_LT.properties index 040aecec0..59e37442c 100644 --- a/src/main/resources/locale/locale_lt_LT.properties +++ b/src/main/resources/locale/locale_lt_LT.properties @@ -353,7 +353,7 @@ Repair.SubSkill.ArcaneForging.Description=Sutaisyti magiškus daiktus Repair.SubSkill.ArcaneForging.Stat=Arkaniška Kalvystė: &eRankas {0}/{1} Repair.SubSkill.ArcaneForging.Stat.Extra=&3Arkaniškos Kalvystės Šansas:&7 Sėkmė &a{0}&7%, Nesekmė &c{1}&7% Repair.Error=&4mcMMO susidūrė su problema bandant taisyti šį daiktą! -Repair.Listener.Anvil=&4Pastatei Kaltą, kaltai gali taisyti įrankius ir šarvus. +Repair.Listener.Anvil=&aPastatei Kaltą, kaltai gali taisyti įrankius ir šarvus. Repair.Listener=Taisymas: Repair.SkillName=REPAIR Repair.Skills.AdeptDiamond=&4Jūs neesate pakankamai įgudę, jog sutaisytumete deimantą. @@ -391,7 +391,7 @@ Salvage.Skills.TooDamaged=&4Šis daiktas per daug sulaužytas kad būtų galima Salvage.Skills.ArcaneFailed=&cJūs negalėjote ištraukti žinių esančių šiame daikte. Salvage.Skills.ArcanePartial=&cJūs galėjote ištraukti tik dalį žinių esančių šiame daikte. Salvage.Skills.ArcaneSuccess=&aJūs galėjote ištraukti visas žinias iš šio daikto! -Salvage.Listener.Anvil=&4Jūs pastatėte išgelbėjimo priekalą, naudokite jį išgelbėti medžiagas iš daiktų. +Salvage.Listener.Anvil=&aJūs pastatėte išgelbėjimo priekalą, naudokite jį išgelbėti medžiagas iš daiktų. Salvage.Listener=Išgelbėjimas: Salvage.SkillName=SALVAGE Salvage.Skills.Lottery.Normal=&6Jūs išgelbėjote &3{0}&6 medžiagų iš &e{1}&6. @@ -399,6 +399,20 @@ Salvage.Skills.Lottery.Perfect=&a&lTobula!&r&6 Jūs išgelbėjote &3{1}&6 be pas Salvage.Skills.Lottery.Untrained=&7Jūs neesate tinkamai išmokyti rinkimo. Jūs tik galėjote surinkti &c{0}&7 daiktų iš &a{1}&7. #Anvil (Shared between SALVAGE and REPAIR) Anvil.Unbreakable=Šis daiktas yra nesunaikinamas! + +#TRIDENTS +Tridents.SkillName=TRIŠAKIAI +Tridents.Ability.Lower=&7Jūs nuleidote savo trišakį. +Tridents.Ability.Ready=&3Jūs &6paruošėte&3 savo trišakį. +Tridents.SubSkill.Impale.Name=Perdurimas +Tridents.SubSkill.Impale.Description=Padidina žalą, padarytą trišakiais +Tridents.SubSkill.Impale.Stat=Papildoma perdurimo žala +Tridents.SubSkill.TridentsLimitBreak.Name=Trišakių ribos peržengimas +Tridents.SubSkill.TridentsLimitBreak.Description=Peržengti savo ribas. Padidinta žala prieš stiprius priešininkus. Skirta PVP, tačiau ar tai padidins žalą PVE režimu, priklauso nuo serverio nustatymų. +Tridents.SubSkill.TridentsLimitBreak.Stat=Maksimali žala peržengus ribą +Tridents.SubSkill.TridentAbility.Name=Vis dar kuriama +Tridents.Listener=Trišakiai: + #SWORDS Swords.Ability.Lower=&7Jūs nuleidote savo kardą. Swords.Ability.Ready=&3Tu &6paruošei&3 savo kardą. diff --git a/src/main/resources/locale/locale_nl.properties b/src/main/resources/locale/locale_nl.properties index 5fbae168e..fe648b719 100644 --- a/src/main/resources/locale/locale_nl.properties +++ b/src/main/resources/locale/locale_nl.properties @@ -132,7 +132,7 @@ Repair.SubSkill.DiamondRepair.Name=Diamanten Reparatie ({0}+ SKILL) Repair.SubSkill.DiamondRepair.Description=Repareer Diamanten Gereedschap & Wapenuitrusting Repair.SubSkill.ArcaneForging.Name=Arcane Smeden Repair.SubSkill.ArcaneForging.Description=Magische voorwerpen repareren -Repair.Listener.Anvil=&4Je hebt een aambeeld geplaatst. Met een aambeeld kun je je gereedschappen en pantser repareren +Repair.Listener.Anvil=&aJe hebt een aambeeld geplaatst. Met een aambeeld kun je je gereedschappen en pantser repareren Repair.Listener=Repareer: Repair.SkillName=REPAREER Repair.Skills.AdeptDiamond=&4Je bent nog niet sterk genoeg om diamant te repareren. diff --git a/src/main/resources/locale/locale_pl.properties b/src/main/resources/locale/locale_pl.properties index d62facf80..a85eb9a2e 100644 --- a/src/main/resources/locale/locale_pl.properties +++ b/src/main/resources/locale/locale_pl.properties @@ -355,7 +355,7 @@ Repair.SubSkill.ArcaneForging.Description=Naprawa magicznych przedmiotów Repair.SubSkill.ArcaneForging.Stat=Ranga Tajemnego Fałszowania: &e {0}/{1} Repair.SubSkill.ArcaneForging.Stat.Extra=&3Szansa na Tajemne Fałszowanie:&7 Powodzenie: &a{0}&7%, Niepowodzenie: &c{1}&7% Repair.Error=&4mcMMO napotkał błąd podczas próby naprawy tego przedmiotu! -Repair.Listener.Anvil=&4r Umieściłeś kowadło, kowadła mogą naprawiać narzędzia i zbroję. +Repair.Listener.Anvil=&ar Umieściłeś kowadło, kowadła mogą naprawiać narzędzia i zbroję. Repair.Listener=Naprawianie: Repair.SkillName=NAPRAWIANIE Repair.Skills.AdeptDiamond=&4Nie masz wystarczających umiejętności, aby naprawić Diament. @@ -379,7 +379,7 @@ Salvage.SubSkill.UnderstandingTheArt.Description=Nie tylko przekopujesz śmieci \nWzmacnia różne właściwości Odzyskiwacza. Salvage.SubSkill.ScrapCollector.Name=Zbieracz złomu Salvage.SubSkill.ScrapCollector.Description=Odzyskaj materiały z przedmiotu, idealne odzyskanie zależy od umiejętności i szczęścia. -Salvage.SubSkill.ScrapCollector.Stat=Zbieracz złomu: &aOdzyskaj do & e {0} & jednej rzeczy. W grę wchodzi trochę szczęścia. +Salvage.SubSkill.ScrapCollector.Stat=Zbieracz złomu: &aOdzyskaj do &e{0}&a rzeczy. Salvage.SubSkill.ArcaneSalvage.Name=Tajemne odzyskiwanie Salvage.SubSkill.ArcaneSalvage.Description=Wydobywaj zaklęcia z przedmiotów Salvage.SubSkill.ArcaneSalvage.Stat=Ranga Tajemnego odzyskiwania: &e {0}/{1} @@ -394,7 +394,7 @@ Salvage.Skills.TooDamaged=&4Ten przedmiot jest zbyt uszkodzony, aby go uratować Salvage.Skills.ArcaneFailed=&cNie udało Ci się wydobyć wiedzy zawartej w tym elemencie. Salvage.Skills.ArcanePartial=&cUdało Ci się tylko wydobyć część wiedzy zawartej w tym elemencie. Salvage.Skills.ArcaneSuccess=&aJesteś w stanie wydobyć całą wiedzę zawartą w tym elemencie! -Salvage.Listener.Anvil=&4Umieściłeś/aś kowadło, użyj go do zbroi i narzędzi. +Salvage.Listener.Anvil=&aUmieściłeś/aś kowadło, użyj go do zbroi i narzędzi. Salvage.Listener=Odzyskiwanie: Salvage.SkillName=ODZYSKIWANIE Salvage.Skills.Lottery.Normal=&6Udało Ci się odzyskać & 3 {0} & 6 materiałów z & e {1} & 6. diff --git a/src/main/resources/locale/locale_pt_BR.properties b/src/main/resources/locale/locale_pt_BR.properties index 308cc0518..c53dc2fb4 100644 --- a/src/main/resources/locale/locale_pt_BR.properties +++ b/src/main/resources/locale/locale_pt_BR.properties @@ -1,5 +1,6 @@ #Não use códigos de cores nas KEYS do Json #Caso queira mudar as cores, elas são definidas em advanced.yml +Placeholder=Esse valor é para quaisquer entradas de localidade WIP que não serão exibidas aos usuários JSON.Rank=Rank JSON.DescriptionHeader=Descrição JSON.JWrapper.Header=Detalhes @@ -28,6 +29,9 @@ JSON.Swords=Espadas JSON.Taming=Adestramento JSON.Unarmed=Desarmado JSON.Woodcutting=Lenhador +JSON.Crossbows=Besta +JSON.Tridents=Tridente +JSON.Maces=Mangual JSON.URL.Website=O site oficial do McMMO! JSON.URL.Discord=O servidor de discord oficial do McMMO! JSON.URL.Patreon=Ajude nossr50 e seu trabalho no mcMMO pelo Patreon! @@ -96,6 +100,9 @@ Overhaul.Name.Swords=Espadas Overhaul.Name.Taming=Adestramento Overhaul.Name.Unarmed=Desarmado Overhaul.Name.Woodcutting=Lenhador +Overhaul.Name.Crossbows=Besta +Overhaul.Name.Tridents=Tridente +Overhaul.Name.Maces=Mangual # /mcMMO Command Style Stuff Commands.mcc.Header=&c---[]&aComandos do McMMO&c[]--- Commands.Other=&c---[]&aCOMANDOS ESPECIAIS&c[]--- @@ -120,6 +127,9 @@ XPBar.Swords=Espadas Nv.&6{0} XPBar.Taming=Adestramento Nv.&6{0} XPBar.Unarmed=Desarmado Nv.&6{0} XPBar.Woodcutting=Lenhador Nv.&6{0} +XPBar.Crossbows=Bestas Nv.&6{0} +XPBar.Tridents=Tridentes Nv.&6{0} +XPBar.Maces=Mangual Nv.&6{0} #Este é apenas um modelo predefinido que é usado se a configuração 'ExtraDetails' estiver ativada em experience.yml (desativada por padrão), você pode ignorar este modelo e apenas editar as strings acima XPBar.Complex.Template={0} &3 {4}&f% &3(&f{1}&3/&f{2}&3) # Pode ser usado as seguintes variáveis em XP BAR -- {0} = Nível da Habilidade, {1} XP atual, {2} XP necessária para o próximo nível, {3} Power Level, {4} Porcentagem do nível @@ -172,6 +182,13 @@ Archery.SubSkill.ArcheryLimitBreak.Description=Quebre seus limites. Aumento de d Archery.SubSkill.ArcheryLimitBreak.Stat=DANO máximo com a quebra de limite Archery.Listener=Arquearia: Archery.SkillName=ARQUEARIA +Archery.SubSkill.ExplosiveShot.Name=Tiro Explosivo +Archery.SubSkill.ExplosiveShot.Description=Dispare uma flecha explosiva +Archery.Skills.ExplosiveShot.Off= +Archery.Skills.ExplosiveShot.On=&a**TIRO EXPLOSIVO ATIVADO** +Archery.Skills.ExplosiveShot.Other.Off=Tiro Explosivo&a acabou para &e{0} +Archery.Skills.ExplosiveShot.Other.On=&a{0}&2 usou &cTiro Explosivo! +Archery.Skills.ExplosiveShot.Refresh=&aSeu &Tiro Explosivo &habilidade foi recarregada! #MACHADOS Axes.Ability.Bonus.0=Maestria com Machado @@ -211,6 +228,7 @@ Axes.Skills.SS.Refresh=&aSua habilidade &eRacha Crânio &afoi recarregada! Axes.Skills.SS.Other.Off=Racha Crânio&a foi desativada por &e{0} Axes.Skills.SS.Other.On=&a{0}&2 usou &cRacha Crânio! + #ESCAVAÇÃO Excavation.Ability.Lower=&7Você abaixou sua pá. Excavation.Ability.Ready=Você está com a sua pá &6pronta.&3 @@ -301,6 +319,9 @@ Herbalism.Skills.GTe.On=&a**Terra verde ATIVADA** Herbalism.Skills.GTe.Refresh=&aSua habilidade &eTerra Verde &afoi recarregada! Herbalism.Skills.GTe.Other.Off=Terra Verde&a foi desativada por &e{0} Herbalism.Skills.GTe.Other.On=&a{0}&2 usou &cTerra Verde! +Herbalism.SubSkill.VerdantBounty.Name=Colheita Verdejante +Herbalism.SubSkill.VerdantBounty.Description=Colha habilmente o triplo de loot +Herbalism.SubSkill.VerdantBounty.Stat=Chance Triplicada de Drop #MINERAÇÃO Mining.Ability.Locked.0=BLOQUEADO ATÉ CHEGAR NO NÍVEL {0}+ HABILIDADE (MINERAÇÃO EXPLOSIVA) @@ -323,6 +344,9 @@ Mining.SubSkill.BiggerBombs.Description=Aumenta o raio das explosões de TNT Mining.SubSkill.DemolitionsExpertise.Name=Especialista em Demolição Mining.SubSkill.DemolitionsExpertise.Description=Diminui o dano recebido por explosões de TNT Mining.SubSkill.DemolitionsExpertise.Stat=Diminuição de dano do Especialista em Demolição +Mining.SubSkill.MotherLode.Name=Filão +Mining.SubSkill.MotherLode.Description=Minere habilmente o triplo de loot +Mining.SubSkill.MotherLode.Stat=Chance Triplicada de Drop Mining.Listener=Mineração: Mining.SkillName=MINERAÇÃO @@ -361,7 +385,7 @@ Repair.SubSkill.ArcaneForging.Description=Repara itens mágicos Repair.SubSkill.ArcaneForging.Stat=Forja Arcana: &eRank {0}/{1} Repair.SubSkill.ArcaneForging.Stat.Extra=&3Chance de Forja Arcana:&7 Sucesso &a{0}&7%, Falha &c{1}&7% Repair.Error=&4mcMMO encontrou um erro ao tentar reparar esse item! -Repair.Listener.Anvil=&4Você colocou uma bigorna, bigorna pode reparar ferramentas e armaduras. +Repair.Listener.Anvil=&aVocê colocou uma bigorna, bigorna pode reparar ferramentas e armaduras. Repair.Listener=Reparação: Repair.SkillName=REPARAÇÃO Repair.Skills.AdeptDiamond=&4Você não tem habilidade o suficiente para reparar Diamante. @@ -386,7 +410,7 @@ Salvage.SubSkill.UnderstandingTheArt.Name=Entendendo a Arte Salvage.SubSkill.UnderstandingTheArt.Description=Você não está só vasculhando o lixo de seus vizinhos, mas também está cuidando do meio ambiente.\nAumenta várias propriedades de Recuperação. Salvage.SubSkill.ScrapCollector.Name=Coletor de Sucata Salvage.SubSkill.ScrapCollector.Description=Recupera materiais de um item, uma recuperação perfeita depende de habilidade e sorte. -Salvage.SubSkill.ScrapCollector.Stat=Scrap Collector: &aRecuperou &e{0}&a itens. Teve um pouco de sorte envolvida. +Salvage.SubSkill.ScrapCollector.Stat=Scrap Collector: &aRecuperou &e{0}&a itens. Salvage.SubSkill.ArcaneSalvage.Name=Recuperação Arcana Salvage.SubSkill.ArcaneSalvage.Description=Extrai encantamentos de um item Salvage.SubSkill.ArcaneSalvage.Stat=Recuperação Arcana: &eRank {0}/{1} @@ -401,7 +425,7 @@ Salvage.Skills.TooDamaged=&4Esse item está muito danificado para ser recuperado Salvage.Skills.ArcaneFailed=&cVocê não conseguiu extrair o conhecimento contido dentro deste item. Salvage.Skills.ArcanePartial=&cVocê só conseguiu extrair um pouco do conhecimento contido dentro deste item. Salvage.Skills.ArcaneSuccess=&aVocê conseguiu extrair todo o conhecimento contido dentro deste item! -Salvage.Listener.Anvil=&4Você colocou uma birgona de recuperação, use ela para recuperar ferramentas e armaduras. +Salvage.Listener.Anvil=&aVocê colocou uma birgona de recuperação, use ela para recuperar ferramentas e armaduras. Salvage.Listener=Recuperação: Salvage.SkillName=RECUPERAÇÃO Salvage.Skills.Lottery.Normal=&6Você conseguiu recuperar &3{0}&6 materiais de &e{1}&6. @@ -409,7 +433,9 @@ Salvage.Skills.Lottery.Perfect=&a&lPerfeito!&r&6 Você recuperou &3{1}&6 sem esf Salvage.Skills.Lottery.Untrained=&7Você não está bem treinado em recuperação. Só conseguiu recuperar &c{0}&7 materiais de &a{1}&7. #Bigorna (Compartilhado entre RECUPERAÇÃO E REPARAÇÃO) -Anvil.Unbreakable=Este item é inquebravél! +Anvil.Unbreakable=Este item é inquebrável! +Anvil.Repair.Reject.CustomModelData=Uma força misteriosa impede você de reparar este item... +Anvil.Salvage.Reject.CustomModelData=Uma força misteriosa impede você de salvar este item... #ESPADAS Swords.Ability.Lower=&7Você abaixou sua espada. @@ -560,6 +586,10 @@ Woodcutting.SubSkill.BarkSurgeon.Name=Cirurgião de Tronco Woodcutting.SubSkill.BarkSurgeon.Description=Extrai materiais úteis ao remover Árvores. Woodcutting.SubSkill.NaturesBounty.Name=Generosidade da Natureza Woodcutting.SubSkill.NaturesBounty.Description=Ganhe experiência da natureza. +Woodcutting.SubSkill.CleanCuts.Name=Cortes Limpos +Woodcutting.SubSkill.CleanCuts.Description=Extraia habilmente até três vezes mais madeira +Woodcutting.SubSkill.CleanCuts.Stat=Chance Triplicada de Drop + Woodcutting.Listener=Lenhador: Woodcutting.SkillName=Lenhador Woodcutting.Skills.TreeFeller.Off=**Lenhador foi desligado** @@ -570,6 +600,58 @@ Woodcutting.Skills.TreeFeller.Other.On=&a{0}&2 usou &cLenhador! Woodcutting.Skills.TreeFeller.Splinter=SEU MACHADO SE ESTILHAÇOU EM VÁRIOS PEDAÇOS! Woodcutting.Skills.TreeFeller.Threshold=Essa Árvore é muito grande! +# BESTAS +Crossbows.SkillName=BESTA +Crossbows.Ability.Lower=&7Você abaixou sua besta. +Crossbows.Ability.Ready=&3Você &6preparou&3 sua Besta. +Crossbows.Skills.SSG.Refresh=&aSua habilidade &eSuper Shotgun&a foi recarregada! +Crossbows.Skills.SSG.Other.On=&a{0}&2 usou &eSuper Shotgun! +Crossbows.SubSkill.PoweredShot.Name=Tiro Potencializado +Crossbows.SubSkill.PoweredShot.Description=Aumenta o dano feito com bestas +Crossbows.SubSkill.PoweredShot.Stat=Dano Bônus de Tiro Potencializado +Crossbows.SubSkill.CrossbowsLimitBreak.Name=Quebra de Limite das Bestas +Crossbows.SubSkill.CrossbowsLimitBreak.Description=Quebrando seus limites. Dano aumentado contra oponentes difíceis. Destinado ao PVP, dependendo das configurações do servidor, pode aumentar o dano no PVE. +Crossbows.SubSkill.CrossbowsLimitBreak.Stat=Dano Máximo de Quebra de Limite +Crossbows.SubSkill.TrickShot.Name=Tiro Mirabolante +Crossbows.SubSkill.TrickShot.Description=Ricocheteia flechas em ângulos íngremes +Crossbows.SubSkill.TrickShot.Stat=Número Máximo de Rebotes de Tiro Mirabolante +Crossbows.SubSkill.TrickShot.Stat.Extra=Número Máximo de Rebotes de Tiro Mirabolante: &a{0} +Crossbows.SubSkill.TrickShot.Stat.Extra2=Redução de Dano por Rebote de Tiro Mirabolante: &a{0} +Crossbows.SubSkill.SuperShotgun.Name=Super Shotgun +Crossbows.Listener=BESTAS: + +# TRIDENTES +Tridents.SkillName=TRIDENTES +Tridents.Ability.Lower=&7Você abaixou seu tridente. +Tridents.Ability.Ready=&3Você &6preparou&3 seu Tridente. +Tridents.SubSkill.Impale.Name=Empalar +Tridents.SubSkill.Impale.Description=Aumenta o dano feito com tridentes +Tridents.SubSkill.Impale.Stat=Dano Bônus de Empalar +Tridents.SubSkill.TridentsLimitBreak.Name=Quebra de Limite dos Tridentes +Tridents.SubSkill.TridentsLimitBreak.Description=Quebrando seus limites. Dano aumentado contra oponentes difíceis. Destinado ao PVP, dependendo das configurações do servidor, pode aumentar o dano no PVE. +Tridents.SubSkill.TridentsLimitBreak.Stat=Dano Máximo de Quebra de Limite +Tridents.SubSkill.TridentAbility.Name=WIP +Tridents.Listener=TRIDENTES: + +# MANGUAL +Commands.McTop.MacesNotSupported=[[VERDE]]Mangual não é suportado nesta versão do Minecraft. +Maces.SkillName=MANGUAL +Maces.Ability.Lower=&7Você abaixou seu mangual. +Maces.Ability.Ready=&3Você &6preparou&3 seu Mangual. +Maces.SubSkill.MacesLimitBreak.Name=Quebra de Limite do Mangual +Maces.SubSkill.MacesLimitBreak.Description=Quebrando seus limites. Dano aumentado contra oponentes difíceis. Destinado ao PVP, dependendo das configurações do servidor, pode aumentar o dano no PVE. +Maces.SubSkill.MacesLimitBreak.Stat=Dano Máximo de Quebra de Limite +Maces.SubSkill.Crush.Name=Esmagar +Maces.SubSkill.Crush.Description=Adiciona dano bônus aos seus ataques. +Maces.SubSkill.Crush.Stat=Dano de Esmagar +Maces.SubSkill.Cripple.Proc=**ALEIJADO** +Maces.SubSkill.Cripple.Activated=ALVO ALEIJADO! +Maces.SubSkill.Cripple.Name=Aleijado +Maces.SubSkill.Cripple.Description=Adiciona uma chance de deixar seu alvo cripple. +Maces.SubSkill.Cripple.Stat=Chance de Aleijamento +Maces.SubSkill.Cripple.Stat.Extra=[[AZUL_ESCURO]]Duração de Aleijamento: &e{0}s&a vs Jogadores, &e{1}s&a vs Mobs. +Maces.Listener=MANGUAL: + #HABILIDADE #COMBATE @@ -599,6 +681,11 @@ Commands.Ability.On=Uso de habilidade &cAtivado Commands.Ability.Toggle=Uso de habilidade for alterado por &e{0} Commands.AdminChat.Off=Chat só para Admins &cDesativado Commands.AdminChat.On=Chat só para Admins &aAtivado +Commands.AdminChatSpy.Enabled=Espionagem de Chat de Grupo do mcMMO Habilitada +Commands.AdminChatSpy.Disabled=Espionagem de Chat de Grupo do mcMMO Desabilitada +Commands.AdminChatSpy.Toggle=Espionagem de Chat de Grupo do mcMMO foi alternada para &e{0} +Commands.AdminChatSpy.Chat=&6[ESPIÃO: &a{0}&6] &f{1} + Commands.AdminToggle=&a- Alterou chat para Admin Commands.Chat.Console=*Console* Commands.Cooldowns.Header=&6--= &aCooldowns de Habilidades do mcMMO&6 =-- @@ -853,6 +940,9 @@ Commands.XPGain.Swords=Atacando Monstros Commands.XPGain.Taming=Adestrando animais, ou lutando junto com os seus lobos Commands.XPGain.Unarmed=Atacando Monstros Commands.XPGain.Woodcutting=Cortando árvores +Commands.XPGain.Crossbows=Atacando Monstros +Commands.XPGain.Maces=Atacando Monstros +Commands.XPGain.Tridents=Atacando Monstros Commands.XPGain=&8XP GANHO: &f{0} Commands.xplock.locked=&6Sua BARRA DE XP agora está em {0}! Commands.xplock.unlocked=&6Sua BARRA DE XP agora está &aDESBLOQUEADA&6! @@ -984,6 +1074,15 @@ Guides.Woodcutting.Section.1=&3Como Lenhador funciona?\n&eLenhador é uma habili Guides.Woodcutting.Section.2=&3Como Soprador de Folhas funciona?\n&eSoprador de Folhas é uma habilidade passiva que fará com que os blocos de\n&efolha se quebrem instantaneamente uando atingido por um machado. Por padrão\n&eessa habilidade é desbloqueada no nível 100. Guides.Woodcutting.Section.3=&3Como Drops duplos funcionam?\n&eEsta habilidade passiva te dá a chance de obter um bloco\n&eextra para cada bloco de madeira que você corta. +# Bestas +Guides.Crossbows.Section.0=&3Sobre Bestas:\n&eBestas trata de disparar com sua besta.\n\n&3GANHO DE XP:\n&eXP é ganha sempre que você atira em mobs com uma besta.\nEsta é uma habilidade em progresso e mais informações serão adicionadas em breve. +Guides.Crossbows.Section.1=&3Como funciona o Tiro Mirabolante?\n&eO Tiro Mirabolante é uma habilidade passiva, você atira suas flechas em um ângulo raso com a besta para tentar um Tiro Mirabolante. Isso fará com que a flecha ricocheteie em blocos e potencialmente atinja um alvo. O número de rebotes potenciais de um ricochete depende do rank do Tiro Mirabolante. + +# Tridentes +Guides.Tridents.Section.0=&3Sobre Tridentes:\n&eA habilidade de Tridentes envolve empalar inimigos com seu tridente.\n\n&3GANHO DE XP:\n&eXP é ganha sempre que você acerta mobs com um tridente.\nEsta é uma habilidade em progresso e mais informações serão adicionadas em breve. +# Mangual +Guides.Maces.Section.0=&3Sobre Mangual:\n&eMangual trata de esmagar seus inimigos com um mangual.\n\n&3GANHO DE XP:\n&eXP é ganha sempre que você atinge mobs com um mangual.\nEsta é uma habilidade em progresso e mais informações serão adicionadas em breve. + #INSPECIONAR Inspect.Offline= &cVocê não tem permissão para inspecionar jogadores offline! Inspect.OfflineStats=Estatísticas do mcMMO do jogador offline &e{0} @@ -1169,3 +1268,5 @@ Chat.Spy.Party=&6[&eESPIÃO&6-&a{2}&6] &r{0} &b→ &r{1} Broadcasts.LevelUpMilestone=&6(&amcMMO&6) {0}&7 chegou no nível &a{1}&7 em &3{2}&7! Broadcasts.PowerLevelUpMilestone=&6(&amcMMO&6) {0}&7 chegou no Nível de Poder &a{1}&7! Scoreboard.Recovery=Tentando recuperar o scoreboard do mcMMO... +Scoreboard.Disabled=Os placares do mcMMO para este servidor estão desativados, essa configuração é encontrada em mcMMO/config.yml +Scoreboard.NotSetupYet=Seu placar do mcMMO ainda não foi configurado, tente novamente mais tarde. diff --git a/src/main/resources/locale/locale_ru.properties b/src/main/resources/locale/locale_ru.properties index 1698a5b04..abbc24488 100644 --- a/src/main/resources/locale/locale_ru.properties +++ b/src/main/resources/locale/locale_ru.properties @@ -358,7 +358,7 @@ Repair.SubSkill.ArcaneForging.Description=Ремонт волшебных пре Repair.SubSkill.ArcaneForging.Stat=Волшебная ковка: &eРанг {0}/{1} Repair.SubSkill.ArcaneForging.Stat.Extra=&3Шансы Волшебной ковки:&7 успех &a{0}&7%, провал &c{1}&7% Repair.Error=&4В mcMMO произошла ошибка при попытке починить этот предмет! -Repair.Listener.Anvil=&4Вы разместили наковальню, на которой можете чинить инструменты и броню. +Repair.Listener.Anvil=&aВы разместили наковальню, на которой можете чинить инструменты и броню. Repair.Listener=Ремонт: Repair.SkillName=РЕМОНТ Repair.Skills.AdeptDiamond=&4Вы недостаточно умелы, чтобы чинить алмазные вещи. @@ -381,7 +381,7 @@ Salvage.SubSkill.UnderstandingTheArt.Name=Понимание искусства Salvage.SubSkill.UnderstandingTheArt.Description=Вы не просто копаетесь в соседском мусоре - вы заботитесь об окружающей среде.\nУлучшает различные параметры Переработки. Salvage.SubSkill.ScrapCollector.Name=Коллекционер хлама Salvage.SubSkill.ScrapCollector.Description=Разбирайте предметы на материалы, качество разборки зависит от навыка и удачи. -Salvage.SubSkill.ScrapCollector.Stat=Коллекционер хлама: &aРазбирайте до &e{0}&a предметов. Удача пригодится. +Salvage.SubSkill.ScrapCollector.Stat=Коллекционер хлама: &aРазбирайте до &e{0}&a предметов. Salvage.SubSkill.ArcaneSalvage.Name=Магическая переработка Salvage.SubSkill.ArcaneSalvage.Description=Извлечение зачарований из предметов Salvage.SubSkill.ArcaneSalvage.Stat=Магическая переработка: &eРанг {0}/{1} @@ -396,7 +396,7 @@ Salvage.Skills.TooDamaged=&4Этот предмет слишком повреж Salvage.Skills.ArcaneFailed=&cУ вас не вышло извлечь знания, содержащиеся в данном предмете. Salvage.Skills.ArcanePartial=&cУ вас вышло только частично извлечь знания, содержащиеся в данном предмете. Salvage.Skills.ArcaneSuccess=&aУ вас вышло извлечь все знания, содержащиеся в данном предмете! -Salvage.Listener.Anvil=&4Вы установили Разборочную наковальню - используйте её для разборки инструментов и брони. +Salvage.Listener.Anvil=&aВы установили Разборочную наковальню - используйте её для разборки инструментов и брони. Salvage.Listener=Разборка: Salvage.SkillName=РАЗБОРКА Salvage.Skills.Lottery.Normal=&6У вас вышло извлечь &3{0}&6 материалов из &e{1}&6. diff --git a/src/main/resources/locale/locale_th_TH.properties b/src/main/resources/locale/locale_th_TH.properties index 74debe67d..db264dded 100644 --- a/src/main/resources/locale/locale_th_TH.properties +++ b/src/main/resources/locale/locale_th_TH.properties @@ -182,7 +182,7 @@ Repair.SubSkill.ArcaneForging.Description=ซ่อมสิ่งของไ Repair.SubSkill.Salvage.Name=ทักษะ Salvage (ต้องการทักษะ {0}+) Repair.SubSkill.Salvage.Description=กูอุปกรณ์และเกราะ Repair.Error=&4mcMMO พบข้อผิดพลาดพยายามที่จะซ่อมแซมสินค้ารายการนี้! -Repair.Listener.Anvil=&4คุณได้วาง Anvil สามารถซ่อมแซมเครื่องมือและเกราะ. +Repair.Listener.Anvil=&aคุณได้วาง Anvil สามารถซ่อมแซมเครื่องมือและเกราะ. Repair.Listener.Anvil2=&4คุณได้วางทั่งสามารถกู้เครื่องมือและเกราะ. Repair.Listener=ทักษะ Repair: Repair.SkillName=REPAIR diff --git a/src/main/resources/locale/locale_zh_CN.properties b/src/main/resources/locale/locale_zh_CN.properties index d7c53438e..8585846be 100644 --- a/src/main/resources/locale/locale_zh_CN.properties +++ b/src/main/resources/locale/locale_zh_CN.properties @@ -1,7 +1,4 @@ -#作者:我正计划统一mcMMO的本地化文件,请暂时原谅本地文件现在如此混乱 - -#不要在JSON关键字中使用颜色代码 -#如果你想修改颜色请在advanced.yml中修改 +Placeholder= 该值为占位符不会展示给玩家 JSON.Rank=等级 JSON.DescriptionHeader=描述 JSON.JWrapper.Header=细节 @@ -13,13 +10,14 @@ JSON.LevelRequirement=等级需求 JSON.JWrapper.Target.Type=目标类型: JSON.JWrapper.Target.Block=方块 JSON.JWrapper.Target.Player=玩家 -JSON.JWrapper.Perks.Header=&6幸运津贴 -JSON.JWrapper.Perks.Lucky={0}% 更好的赔率 +JSON.JWrapper.Perks.Header=&6幸运加成 +JSON.JWrapper.Perks.Lucky={0}% 更高的概率 JSON.Hover.Tips=提示 JSON.Acrobatics=杂技 JSON.Alchemy=炼金 JSON.Archery=箭术 JSON.Axes=斧技 +JSON.Crossbows=弩术 JSON.Excavation=挖掘 JSON.Fishing=钓鱼 JSON.Herbalism=草药学 @@ -28,6 +26,8 @@ JSON.Repair=修理 JSON.Salvage=分解 JSON.Swords=剑术 JSON.Taming=驯兽 +JSON.Tridents=三叉戟术 +JSON.Maces=重锤术 JSON.Unarmed=格斗 JSON.Woodcutting=伐木 JSON.URL.Website=mcMMO官方网站! @@ -40,7 +40,7 @@ JSON.SkillUnlockMessage=&6[ mcMMO&e @&3{0} &6等级 &3{1}&6 解锁! ] JSON.Hover.Rank=&e&l等级:&r &f{0} JSON.Hover.NextRank=&7&o下次升级等级 {0} #对于 JSON.Hover.Mystery 你可以添加 {0} 以在名称中插入所需要的级别,我不喜欢他的外观所以现在不想搞它 -JSON.Hover.Mystery=&7未知能力 +JSON.Hover.Mystery=&7??? JSON.Hover.Mystery2=&e[&8{0}&e]&8???&r JSON.Hover.SkillName=&3{0}&r JSON.Hover.SuperAbility=&5{0}&r @@ -54,7 +54,7 @@ JSON.Notification.SuperAbility={0} #这里是子技能使用的JSON字符串 JSON.Acrobatics.Roll.Interaction.Activated=测试 &c翻滚测试 JSON.Acrobatics.SubSkill.Roll.Details.Tips=如果你在摔落时按下潜行键,你将触发两倍翻滚效果 -Anvil.SingleItemStack=&c你不能分解货修复有多个物品的物品堆, 请拆分后再使用. +Anvil.SingleItemStack=&c你不能分解或修复有多个物品的物品堆, 请拆分后再使用. #不要在JSON关键字中使用颜色代码 #如果你想修改颜色请在advanced.yml中修改 @@ -87,6 +87,7 @@ Overhaul.Name.Acrobatics=杂技 Overhaul.Name.Alchemy=炼金 Overhaul.Name.Archery=箭术 Overhaul.Name.Axes=斧技 +Overhaul.Name.Crossbows=弩术 Overhaul.Name.Excavation=挖掘 Overhaul.Name.Fishing=钓鱼 Overhaul.Name.Herbalism=草药学 @@ -96,13 +97,15 @@ Overhaul.Name.Salvage=分解 Overhaul.Name.Smelting=冶炼 Overhaul.Name.Swords=剑术 Overhaul.Name.Taming=驯兽 +Overhaul.Name.Tridents=三叉戟术 +Overhaul.Name.Maces=重锤术 Overhaul.Name.Unarmed=格斗 Overhaul.Name.Woodcutting=伐木 # /mcMMO 命令风格 -Commands.mcc.Header=&c---[]&amcMMO 命令&c[]--- -Commands.Other=&c---[]&a其他命令&c[]--- -Commands.Party.Header=&c-----[]&a队伍&c[]----- -Commands.Party.Features.Header=&c-----[]&a特性&c[]----- +Commands.mcc.Header=&c[][]=====&amcMMO 命令&c[]=====[] +Commands.Other=&c[]=====[] &a其他命令&c[]=====[] +Commands.Party.Header=&c[]=====[]&a队伍&c[]=====[] +Commands.Party.Features.Header=&c[]=====[] &a特性&c[]=====[] # 经验条可以使用下面的变量 -- {0} = 技能等级, {1} 当前经验, {2} 到下一等级所需的经验, {3} 技能等级, {4} 当前等级的百分比 # 如果你想让玩家每次获得经验的时候显示经验条则确保选项 Experience_Bars.ThisMayCauseLag.AlwaysUpdateTitlesWhenXPIsGained 处于打开状态 XPBar.Template={0} @@ -111,6 +114,7 @@ XPBar.Acrobatics=杂技 Lv.&6{0} XPBar.Alchemy=炼金 Lv.&6{0} XPBar.Archery=箭术 Lv.&6{0} XPBar.Axes=斧技 Lv.&6{0} +XPBar.Crossbows=弩术 Lv.&6{0} XPBar.Excavation=挖掘 Lv.&6{0} XPBar.Fishing=钓鱼 Lv.&6{0} XPBar.Herbalism=草药学 Lv.&6{0} @@ -120,6 +124,8 @@ XPBar.Salvage=分解 Lv.&6{0} XPBar.Smelting=冶炼 Lv.&6{0} XPBar.Swords=剑术 Lv.&6{0} XPBar.Taming=驯兽 Lv.&6{0} +XPBar.Tridents=三叉戟术 Lv.&6{0} +XPBar.Maces=重锤术 Lv.&6{0} XPBar.Unarmed=格斗 Lv.&6{0} XPBar.Woodcutting=伐木 Lv.&6{0} #这只是一个预设模板,如果在 Experience.yml 中打开了“ExtraDetails”设置(默认情况下关闭),则可以使用该模板,您可以忽略此模板,只需编辑上面的字符串 @@ -138,7 +144,7 @@ Acrobatics.SubSkill.Roll.Name=翻滚 Acrobatics.SubSkill.Roll.Description=减少或者取消掉落伤害. Acrobatics.SubSkill.Roll.Chance=翻滚几率: &e{0} Acrobatics.SubSkill.Roll.GraceChance=优雅的翻滚几率: &e{0} -Acrobatics.SubSkill.Roll.Mechanics=&7翻滚是杂技的被动子技能.\n当你受到摔落伤害时,会根据你的杂技技能等级获得一定几率的减伤或免伤, 在你50级时你有 &e{0}%&7 的几率获得减伤或免伤, 如果你激活优雅的翻滚则有 &e{1}%&7 的几率触发双倍翻滚效果,.\n触发的几率会按照你技能等级线性增长,直到 &e{2}&7 级, 每一级的杂技等级提供 &e{3}%&7 的触发几率.\n通过按住潜行键(shift)可以翻倍翻滚几率以及两倍减伤效果! 翻滚最多减少 &c{4}&7 伤害. 优雅翻滚最多减少 &a{5}&7 伤害. +Acrobatics.SubSkill.Roll.Mechanics=&7翻滚是杂技的主动子技能(包含被动效果).\n当你受到摔落伤害时,会根据你的杂技技能等级获得一定几率的减伤或免伤(被动), 在你50级时你有 &e{0}%&7 的几率获得减伤或免伤, 如果你激活优雅的翻滚则有 &e{1}%&7 的几率触发双倍翻滚效果,.\n触发的几率会按照你技能等级线性增长,直到 &e{2}&7 级, 每一级的杂技等级提供 &e{3}%&7 的触发几率.\n通过按住潜行键(shift)可以翻倍翻滚几率以及两倍减伤效果! 翻滚最多减少 &c{4}&7 伤害. 优雅翻滚最多减少 &a{5}&7 伤害. Acrobatics.SubSkill.GracefulRoll.Name=优雅翻滚 Acrobatics.SubSkill.GracefulRoll.Description=普通翻滚的两倍效果 Acrobatics.SubSkill.Dodge.Name=闪避 @@ -159,8 +165,6 @@ Alchemy.Listener=炼金(Alchemy): Alchemy.Ability.Locked.0=锁定状态,直到 {0}+ 技能(催化) Alchemy.SkillName=炼金 #箭术 - - Archery.SubSkill.SkillShot.Name=技巧射击 Archery.SubSkill.SkillShot.Description=增加弓箭造成的伤害 Archery.SubSkill.SkillShot.Stat=增加射击造成的伤害 @@ -171,10 +175,17 @@ Archery.SubSkill.ArrowRetrieval.Name=箭矢回收 Archery.SubSkill.ArrowRetrieval.Description=有几率从尸体上回收箭矢 Archery.SubSkill.ArrowRetrieval.Stat=箭矢回收几率 Archery.SubSkill.ArcheryLimitBreak.Name=箭术极限突破 -Archery.SubSkill.ArcheryLimitBreak.Description=突破你的极限. +Archery.SubSkill.ArcheryLimitBreak.Description=突破你的极限。提高对敌人的伤害。适用于PVP,在PVE中是否能提高伤害取决于服务器设置。 Archery.SubSkill.ArcheryLimitBreak.Stat=突破极限的伤害加成 Archery.Listener=箭术(Archery): Archery.SkillName=箭术 +Archery.SubSkill.ExplosiveShot.Name=高爆射击 +Archery.SubSkill.ExplosiveShot.Description=射出一支爆炸箭 +Archery.Skills.ExplosiveShot.Off= +Archery.Skills.ExplosiveShot.On=&a**高爆射击已激活** +Archery.Skills.ExplosiveShot.Other.Off=高爆射击&a 结束了,进入冷却 &e{0} +Archery.Skills.ExplosiveShot.Other.On=&a{0}&2 使用了 &c高爆射击! +Archery.Skills.ExplosiveShot.Refresh=&a你的 &高爆射击 &a技能可以使用了! #斧技 Axes.Ability.Bonus.0=斧头精通 Axes.Ability.Bonus.1=附加 {0} 伤害 @@ -199,7 +210,7 @@ Axes.SubSkill.CriticalStrikes.Stat=暴击几率 Axes.SubSkill.AxeMastery.Name=斧头精通 Axes.SubSkill.AxeMastery.Description=增加额外伤害 Axes.SubSkill.AxesLimitBreak.Name=斧技极限突破 -Axes.SubSkill.AxesLimitBreak.Description=突破你的极限. +Axes.SubSkill.AxesLimitBreak.Description=突破你的极限。适用于PVP,在PVE中是否能提高伤害取决于服务器设置。 Axes.SubSkill.AxesLimitBreak.Stat=突破极限的伤害加成 Axes.SubSkill.ArmorImpact.Name=破甲 Axes.SubSkill.ArmorImpact.Description=用足够的力量击碎护甲 @@ -233,7 +244,7 @@ Excavation.Skills.GigaDrillBreaker.Other.On=&a{0}&2 使用了 &c暴走钻头! Fishing.ScarcityTip=&e&o该区域已经过度捕捞, 请换一个新区域再尝试,请到至少 {0} 的方块以外. Fishing.Scared=&7&o乱动会吓跑鱼! Fishing.Exhausting=&c&o不正当使用鱼竿会加剧耐久的损耗! -Fishing.LowResources=&7你觉得这块区域似乎没有多少鱼了. +Fishing.LowResourcesTip=&7你觉得这块区域似乎没有多少鱼了,试着在至少 {0} 个方块外钓鱼。 Fishing.Ability.Info=魔法猎人: &7 **随着淘金者等级提高** Fishing.Ability.Locked.0=锁定状态,直到 {0}+ 技能(抖动) Fishing.Ability.Locked.1={0}+ 级后解锁 (冰钓) @@ -254,12 +265,12 @@ Fishing.SubSkill.FishermansDiet.Stat=渔夫的食谱:&a 等级 {0} Fishing.SubSkill.MasterAngler.Name=钓鱼大师 Fishing.SubSkill.MasterAngler.Description=钓鱼的效率提升,如果在船上钓鱼效果会更好 Fishing.SubSkill.MasterAngler.Stat=钓鱼的最短等待时间减少: &a{0} 秒 -Fishing.SubSkill.MasterAngler.Stat.Extra=钓鱼最长等待时间减少: &a{0} 秒 +Fishing.SubSkill.MasterAngler.Stat.Extra=钓鱼最长等待时间缩短: &a{0} 秒 Fishing.SubSkill.IceFishing.Name=冰钓 Fishing.SubSkill.IceFishing.Description=允许你在冰冷的环境下钓鱼 Fishing.SubSkill.IceFishing.Stat=冰钓 Fishing.Chance.Raining=&9 大量奖励 -Fishing.Listener=钓鱼: +Fishing.Listener=钓鱼(Fishing): Fishing.Ability.TH.MagicFound=&7你感到一股魔力的波动... Fishing.Ability.TH.Boom=&7繁荣时期!!! Fishing.Ability.TH.Poison=&7有什么东西闻着不太对劲... @@ -286,6 +297,9 @@ Herbalism.SubSkill.FarmersDiet.Stat=农夫食谱: &a等级 {0} Herbalism.SubSkill.DoubleDrops.Name=双倍掉落 Herbalism.SubSkill.DoubleDrops.Description=双倍物品 Herbalism.SubSkill.DoubleDrops.Stat=双倍掉落几率 +Herbalism.SubSkill.VerdantBounty.Name=繁茂恩赐 +Herbalism.SubSkill.VerdantBounty.Description=娴熟地收获了三倍物品 +Herbalism.SubSkill.VerdantBounty.Stat=三倍掉落几率 Herbalism.SubSkill.HylianLuck.Name=海拉尔的祝福 Herbalism.SubSkill.HylianLuck.Description=给予小概率找到稀有物品的能力 Herbalism.SubSkill.HylianLuck.Stat=海拉尔的祝福的几率 @@ -312,6 +326,9 @@ Mining.SubSkill.SuperBreaker.Stat=超级碎石机持续时间 Mining.SubSkill.DoubleDrops.Name=双倍掉落 Mining.SubSkill.DoubleDrops.Description=双倍普通物品 Mining.SubSkill.DoubleDrops.Stat=双倍掉落概率: &e{0} +Mining.SubSkill.MotherLode.Name=母矿 +Mining.SubSkill.MotherLode.Description=娴熟地挖矿三倍掉落 +Mining.SubSkill.MotherLode.Stat=三倍掉落几率 Mining.SubSkill.BlastMining.Name=爆破开采 Mining.SubSkill.BlastMining.Description=使用 TNT 炸矿物时会获得额外物品 Mining.SubSkill.BlastMining.Stat=爆破开采:&a 等级 {0}/{1} &7({2}) @@ -357,7 +374,7 @@ Repair.SubSkill.ArcaneForging.Description=修理附魔物品 Repair.SubSkill.ArcaneForging.Stat=秘法锻造: &e等级 {0}/{1} Repair.SubSkill.ArcaneForging.Stat.Extra=&3秘法锻造赔率:&7 成功 &a{0}&7%, 失败 &c{1}&7% Repair.Error=&4mcMMO 在尝试修理此物品时发生了错误! -Repair.Listener.Anvil=&4你放置的铁方块可以用来修理工具和防具. +Repair.Listener.Anvil=&a你放置的铁方块可以用来修理工具和防具. Repair.Listener=修理(Repair): Repair.SkillName=修理 Repair.Skills.AdeptDiamond=&4你的技能等级不足以修理钻石装备. @@ -369,7 +386,7 @@ Repair.Skills.FeltEasy=&7那看起来很简单. Repair.Skills.FullDurability=&7你的装备已经满耐久度了 Repair.Skills.StackedItems=&4你无法修理已叠加的物品. Repair.Pretty.Name=修理 -#奥数锻造 +#奥术锻造 Repair.Arcane.Downgrade=这件物品的附魔等级已下降. Repair.Arcane.Fail=这件物品的附魔已消失. Repair.Arcane.Lost=你的技能等级不足以保留附魔属性. @@ -380,15 +397,12 @@ Salvage.SubSkill.UnderstandingTheArt.Name=分解精通 Salvage.SubSkill.UnderstandingTheArt.Description=你不仅仅是在翻邻居的垃圾, 你是在保护环境.\n增强分解的各种属性. Salvage.SubSkill.ScrapCollector.Name=废料回收 Salvage.SubSkill.ScrapCollector.Description=从物品中分解出材料, 能否完美分解取决于技能等级和运气. -Salvage.SubSkill.ScrapCollector.Stat=废料回收: &a最多分解出 &e{0}&a 个物品. 占一些运气成分. -Salvage.SubSkill.AdvancedSalvage.Name=进阶分解 -Salvage.SubSkill.AdvancedSalvage.Description=分解损坏的物品 -Salvage.SubSkill.ArcaneSalvage.Name=奥数分解 +Salvage.SubSkill.ScrapCollector.Stat=废料回收: &a最多分解出 &e{0}&a 个物品. +Salvage.SubSkill.ArcaneSalvage.Name=奥术分解 Salvage.SubSkill.ArcaneSalvage.Description=从物品中拆解附魔 -Salvage.SubSkill.ArcaneSalvage.Stat=奥数分解: &e等级 {0}/{1} -Salvage.Ability.Locked.0=锁定直至 {0}+ 技能等级 (进阶分解) -Salvage.Ability.Bonus.0=进阶分解 -Salvage.Ability.Bonus.1=最大限度回收 {0} 损坏的物品 +Salvage.SubSkill.ArcaneSalvage.Stat=奥术分解: &e等级 {0}/{1} +Salvage.Ability.Bonus.0=废料回收 +Salvage.Ability.Bonus.1=废料回收: &a最多分解出 &e{0}&a 个物品取决于运气. Salvage.Arcane.ExtractFull=&7完全拆解出附魔几率 Salvage.Arcane.ExtractPartial=&7部分拆解出附魔几率 Salvage.Skills.Success=&a物品已分解! @@ -398,16 +412,73 @@ Salvage.Skills.TooDamaged=&4该物品损坏过于严重,无法分解. Salvage.Skills.ArcaneFailed=&c您无法拆解出本物品所蕴含的知识. Salvage.Skills.ArcanePartial=&c您只能拆解出本物品所蕴含的部分知识. Salvage.Skills.ArcaneSuccess=&a您能够完全拆解出本物品所含的知识! -Salvage.Listener.Anvil=&4您已经放置了一个分解砧,使用它来分解工具和护甲. +Salvage.Listener.Anvil=&a您已经放置了一个分解砧,使用它来分解工具和护甲. Salvage.Listener=分解(Salvage): Salvage.SkillName=分解 +Salvage.Skills.Lottery.Normal=&6你可以从 &e{1}&6 分解出 &3{0}&6 材料。 +Salvage.Skills.Lottery.Perfect=&a&l完美!&r&6 你轻松分解出了 &3{1}&6 ,获得了 &3{0}&6 材料。 +Salvage.Skills.Lottery.Untrained=&7你没有接受足够的分解训练。你只能从 &a{1}&7 获得 &c{0}&7 材料。 # 铁砧 (分解和修理公用) Anvil.Unbreakable=这个物品不会损坏! +Anvil.Repair.Reject.CustomModelData=一种神秘的力量阻止您修理这件物品…… +Anvil.Salvage.Reject.CustomModelData=一种神秘的力量阻止您分解这件物品…… +#弩术 +Crossbows.SkillName=弩术 +Crossbows.Ability.Lower=&7你放下你的弩。 +Crossbows.Ability.Ready=&3你 &6端起了&3 你的弩。 +Crossbows.Skills.SSG.Refresh=&a你的 &e超级霰弹枪 &a技能可以使用了! +Crossbows.Skills.SSG.Other.On=&a{0}&2 使用了 &超级霰弹枪! +Crossbows.SubSkill.PoweredShot.Name=强力射击 +Crossbows.SubSkill.PoweredShot.Description=增加弩造成的伤害 +Crossbows.SubSkill.PoweredShot.Stat=强力射击额外伤害 +Crossbows.SubSkill.CrossbowsLimitBreak.Name=弩术极限突破 +Crossbows.SubSkill.CrossbowsLimitBreak.Description=突破你的极限。提高对敌人的伤害。适用于PVP,在PVE中是否会提高伤害取决于服务器设置。 +Crossbows.SubSkill.CrossbowsLimitBreak.Stat=极限突破最大伤害 +Crossbows.SubSkill.TrickShot.Name=巧射 +Crossbows.SubSkill.TrickShot.Description=大角度射击来反弹箭矢 +Crossbows.SubSkill.TrickShot.Stat=巧射最大反弹次数 +Crossbows.SubSkill.TrickShot.Stat.Extra=巧射最大反弹次数: &a{0} +Crossbows.SubSkill.TrickShot.Stat.Extra2=巧射每次反弹伤害衰减: &a{0} +Crossbows.SubSkill.SuperShotgun.Name=超级霰弹枪 +Crossbows.Listener=弩术(Crossbows): + +#三叉戟术 +Tridents.SkillName=三叉戟术 +Tridents.Ability.Lower=&7你放下了三叉戟。 +Tridents.Ability.Ready=&3你 &6举起了&3 你的三叉戟。 +Tridents.SubSkill.Impale.Name=贯穿 +Tridents.SubSkill.Impale.Description=提升三叉戟造成的伤害 +Tridents.SubSkill.Impale.Stat=贯穿提升的伤害 +Tridents.SubSkill.TridentsLimitBreak.Name=三叉戟术极限突破 +Tridents.SubSkill.TridentsLimitBreak.Description=突破你的极限。提高对敌人的伤害。适用于PVP,在PVE中是否会提高伤害取决于服务器设置。 +Tridents.SubSkill.TridentsLimitBreak.Stat=极限突破最大伤害 +Tridents.SubSkill.TridentAbility.Name=未完工 +Tridents.Listener=三叉戟术(Tridents): + +#重锤术 +Commands.McTop.MacesNotSupported=[[GREEN]]当前游戏版本不支持重锤术。 +Maces.SkillName=重锤术 +Maces.Ability.Lower=&7你放下了你的重锤。 +Maces.Ability.Ready=&3你 &6举起了&3 你的重锤。 +Maces.SubSkill.MacesLimitBreak.Name=重锤术极限突破 +Maces.SubSkill.MacesLimitBreak.Description=突破你的极限。提高对敌人的伤害。适用于PVP,在PVE中是否会提高伤害取决于服务器设置。 +Maces.SubSkill.MacesLimitBreak.Stat=极限突破最大伤害 +Maces.SubSkill.Crush.Name=碾碎 +Maces.SubSkill.Crush.Description=为你的攻击增加额外伤害。 +Maces.SubSkill.Crush.Stat=碾碎伤害 +Maces.SubSkill.Cripple.Proc=**致残** +Maces.SubSkill.Cripple.Activated=目标被致残! +Maces.SubSkill.Cripple.Name=致残 +Maces.SubSkill.Cripple.Description=增加目标的致残几率。 +Maces.SubSkill.Cripple.Stat=致残几率 +Maces.SubSkill.Cripple.Stat.Extra=[[DARK_AQUA]]致残时间: &e{0}s&a (玩家), &e{1}s&a (怪物). +Maces.Listener=重锤术(Maces): + # 剑术 Swords.Ability.Lower=&7你放下了你的剑. Swords.Ability.Ready=&3你 &6握紧&3 了你的剑. -Swords.Combat.Rupture.Note=&7注释: &e1 Tick 等价于 0.5 秒! -Swords.Combat.Bleeding.Started=&4 你在流血! +Swords.Combat.Rupture.Note.Update.One=&7(撕裂说明): 周期性伤害为非致命伤害,每秒发生两次,可忽略护甲保护。 +Swords.Combat.Bleeding.Started=&4 你正在流血! Swords.Combat.Bleeding.Stopped=&7流血 &a已停止&7! Swords.Combat.Bleeding=&a**敌人正在不断流血** Swords.Combat.Counter.Hit=&4你反击了对手! @@ -425,12 +496,12 @@ Swords.SubSkill.Stab.Name=穿刺 Swords.SubSkill.Stab.Description=为你的攻击增加额外伤害. Swords.SubSkill.Stab.Stat=穿刺伤害 Swords.SubSkill.SwordsLimitBreak.Name=剑术极限突破 -Swords.SubSkill.SwordsLimitBreak.Description=突破你的极限. +Swords.SubSkill.SwordsLimitBreak.Description=突破你的极限.提高对强大敌人的伤害.主要用于PVP,在PVE中是否提升伤害取决于服务器设置. Swords.SubSkill.SwordsLimitBreak.Stat=突破极限的伤害加成 Swords.SubSkill.Rupture.Stat=撕裂概率 -Swords.SubSkill.Rupture.Stat.Extra=[[DARK_AQUA]]撕裂: &a{0} tick 时间 [对玩家造成 {1} 伤害] [对怪物造成 {2} 伤害] -Swords.SubSkill.Rupture.Stat.TickDamage=[[DARK_AQUA]]撕裂每造成的纯伤害: &e{0}&a 对玩家, &e{1}&a 对怪物. -Swords.SubSkill.Rupture.Stat.ExplosionDamage=[[DARK_AQUA]]爆炸伤害: &e{0}&a 对玩家, &e{1}&a 对怪物. +Swords.SubSkill.Rupture.Stat.Extra=[[DARK_AQUA]]撕裂持续时间: &e{0}s&a (玩家),&e{1}s&a(怪物). +Swords.SubSkill.Rupture.Stat.TickDamage=[[DARK_AQUA]]撕裂: 每tick造成的纯伤害: &e{0}&a (玩家), &e{1}&a (怪物). +Swords.SubSkill.Rupture.Stat.ExplosionDamage=[[DARK_AQUA]]爆炸伤害: &e{0}&a (玩家), &e{1}&a (怪物). Swords.Effect.4=利刃突刺 撕裂+ Swords.Effect.5={0} Tick 撕裂 Swords.Listener=剑术(Swords): @@ -509,8 +580,8 @@ Unarmed.SubSkill.Disarm.Stat=缴械概率 Unarmed.SubSkill.UnarmedLimitBreak.Name=格斗极限突破 Unarmed.SubSkill.UnarmedLimitBreak.Description=突破你的极限. Unarmed.SubSkill.UnarmedLimitBreak.Stat=突破极限的伤害加成 -Unarmed.SubSkill.IronArmStyle.Name=铁臂式 -Unarmed.SubSkill.IronArmStyle.Description=伤害加成 +Unarmed.SubSkill.SteelArmStyle.Name=铁臂式 +Unarmed.SubSkill.SteelArmStyle.Description=伤害加成 Unarmed.SubSkill.ArrowDeflect.Name=箭矢偏向 Unarmed.SubSkill.ArrowDeflect.Description=让箭矢偏向 Unarmed.SubSkill.ArrowDeflect.Stat=箭矢偏向几率 @@ -543,6 +614,9 @@ Woodcutting.SubSkill.KnockOnWood.Loot.Rank2=从树上获取了正常的物品和 Woodcutting.SubSkill.HarvestLumber.Name=树木丰收 Woodcutting.SubSkill.HarvestLumber.Description=巧妙地获取更多木头\n有几率双倍掉落 Woodcutting.SubSkill.HarvestLumber.Stat=树木丰收双倍几率 +Woodcutting.SubSkill.CleanCuts.Name=充分砍伐 +Woodcutting.SubSkill.CleanCuts.Description=娴熟地伐取三倍木材。 +Woodcutting.SubSkill.CleanCuts.Stat=三倍掉落几率 Woodcutting.SubSkill.Splinter.Name=粉碎 Woodcutting.SubSkill.Splinter.Description=更有效的砍树. Woodcutting.SubSkill.BarkSurgeon.Name=树木外科医生 @@ -580,7 +654,7 @@ Commands.addlevels.AwardAll.2=你所有的技能等级已被 {0} 修改. Commands.addlevels.AwardSkill.1=&a你的 {0} 技能等级被提升了 {1} 级! Commands.addlevels.AwardSkill.2={0} 技能等级已被 {1} 修改. Commands.addxp.AwardAll=&a你所有的技能获得 {0} 经验! -Commands.addxp.AwardSkill=&a你的 {0} 技能获得了 {1} 经验! +Commands.addxp.AwardSkill=&a你的 {1} 技能获得了 {0} 经验! Commands.Ability.Off=能力使用切换 &c关闭 Commands.Ability.On=能力使用切换 &a开启 Commands.Ability.Toggle=能力使用已切换为 &e{0} @@ -773,7 +847,7 @@ Party.NotOwner=&4你不是队长 Party.Target.NotOwner=&4{0} 不是队长。 Party.Owner.New=&a{0} 现在是新的派系领队. Party.Owner.NotLeader=&4你已经不再是派系内的领队. -Party.Owner.Player=&a你现在不是队长了 +Party.Owner.Player =&a你现在不是队长了 Party.Password.None=&c加入这个队伍需要密码. 请提供密码再加入 Party.Password.Incorrect=&c队伍密码错误 Party.Password.Set=&a队伍密码设置为 {0} @@ -826,16 +900,19 @@ Party.ItemShare.Category.Misc=杂项 ##经验 Commands.XPGain.Acrobatics=掉落 Commands.XPGain.Alchemy=酿造药水 -Commands.XPGain.Archery=空手攻击怪物 +Commands.XPGain.Archery=攻击怪物 Commands.XPGain.Axes=攻击怪物 Commands.XPGain.Child=从主技能获取等级 +Commands.XPGain.Crossbows=攻击怪物 Commands.XPGain.Excavation=挖到宝物 -Commands.XPGain.Fishing=钓鱼 (去研究吧!) +Commands.XPGain.Fishing=钓鱼(去研究吧!) Commands.XPGain.Herbalism=收获作物 +Commands.XPGain.Maces=攻击怪物 Commands.XPGain.Mining=挖掘石头和矿物 Commands.XPGain.Repair=修理 Commands.XPGain.Swords=攻击怪物 -Commands.XPGain.Taming=驯兽, 和你的狼一起战斗 +Commands.XPGain.Taming=驯兽,和你的狼一起战斗 +Commands.XPGain.Tridents=攻击怪物 Commands.XPGain.Unarmed=攻击怪物 Commands.XPGain.Woodcutting=砍伐树木 Commands.XPGain=&8经验来源: &f{0} @@ -846,13 +923,13 @@ Commands.xprate.over=&cmcMMO 高倍经验事件结束!! Commands.xprate.proper.0=&c想修改经验获取率请输入 /xprate Commands.xprate.proper.1=&c想把经验获取率调整为默认请输入 /xprate reset Commands.xprate.proper.2=&c请指定 true 或 false 来表明这是否是一个经验活动 -Commands.xprate.started.0=&6mcMMO 高倍经验活动已开始! -Commands.xprate.started.1=&6mcMMO 经验获取率现在为 {0} 倍! Commands.NegativeNumberWarn=不要使用负数! Commands.Event.Start=&amcMMO&6 活动! Commands.Event.Stop=&amcMMO&3 活动结束! Commands.Event.Stop.Subtitle=&a我希望你玩的开心! Commands.Event.XP=&3多倍经验倍率为 &6{0}&3 倍 +Commands.xprate.started.0=&6mcMMO 高倍经验活动已开始! +Commands.xprate.started.1=&6mcMMO 经验获取率现在为 {0} 倍! # 管理员提醒 Server.ConsoleName=&e[Server] @@ -871,7 +948,7 @@ Guides.Available=&7{0} 的向导 - 输入 /{1} ? [页数] Guides.Header=&6-=&a{0} 向导&6=- Guides.Page.Invalid=不是一个有效的页数! Guides.Page.OutOfRange=那页不存在, 总共只有 {0} 页 -Guides.Usage= 用法 /{0} ? [页数] +Guides.Usage= 用法: /{0} ? [页数] ##杂技 Guides.Acrobatics.Section.0=&3关于杂技:\n&e杂技是 mcMMO 中优雅移动的艺术。\n&e它提供了战斗加成和环境伤害加成。\n\n&3经验获取:\n&e通过在战斗中闪避或者从高处\n&e跌落时受伤并幸存来获得经验。 Guides.Acrobatics.Section.1=&3翻滚是如何工作的?\n&e当您受到跌落伤害时您有被动机会来免受伤害。\n&e您可以在跌落中按住潜行键来提升触发几率。\n&e这将触发一个优雅地翻滚而不是普通的翻滚。\n&e优雅地翻滚类似普通的翻滚但是它有双倍几率\n&e发生,并且能够提供比普通地翻滚更高的伤害减免。\n&e翻滚几率取决于您的技能等级 @@ -949,7 +1026,7 @@ Guides.Swords.Section.2=&3反击如何工作?\n&e反击是一个主动技能, Guides.Swords.Section.3=&3撕裂如何工作?\n&e撕裂是一个被动技能,攻击时有几率出发撕裂. \n&e撕裂会对对少造成持续的流血伤害,直到持续时间结束或对手死亡, \n&e持续时间取决于你的剑术等级. ##驯兽 Guides.Taming.Section.0=&3驯兽\n&e驯兽技能让玩家能在用狼战斗时\n&e时有加成效果.\n\n&3经验来源:\n&e要获取经验,须训服狼或豹猫,\n&e或与你的狼一同战斗. -Guides.Taming.Section.1=&3什么是野性的召唤?\n&e野性的召唤是一个主动技能让你\n&e可以召唤一只狼或豹猫,\n&e只要手持骨头或生鱼,点左键. +Guides.Taming.Section.1=&3什么是野性的召唤?\n&e野性的召唤是一个主动技能让你\n&e可以召唤一只狼或豹猫,\n&e只要手持骨头或生鱼潜行并点击鼠标左键. Guides.Taming.Section.2=&3什么是野兽信息?\n&e野兽信息能让你查看宠物的状态,\n&e对宠物点击左键就能使用这项能力. Guides.Taming.Section.3=&3什么是嗜血?\n&e血腥攻击是一个主动技能,能造成\n&e狼的攻击目标有机率陷入流血状态. Guides.Taming.Section.4=&3什么是利爪?\n&e利爪使狼的攻击力随着驯兽等级\n&e增加而增加. @@ -969,6 +1046,13 @@ Guides.Woodcutting.Section.0=&3关于伐木:\n&e伐木是关于砍树的.\n\n&3 Guides.Woodcutting.Section.1=&3伐木工如何工作?\n&e伐木工是一个主动技能\n&e在手持斧头的同时右键并破坏木头以激活伐木工\n&e这将瞬间破坏整棵树. Guides.Woodcutting.Section.2=&3秋风扫落叶如何工作?\n&e秋风扫落叶是一个被动技能\n&e当斧头击中树叶方块时会导致瞬间消失\n&e默认情况下,100级解锁. Guides.Woodcutting.Section.3=&3树木丰收如何工作?\n&e这个被动技能使你在砍树时\n&e有几率掉落双倍木头. +# 弩术 +Guides.Crossbows.Section.0=&3关于弩术:\n&e弩术就是使用你的弩射击的技术。\n\n&3经验来源:\n&e在用弩攻击怪物或玩家时可以获取经验. +Guides.Crossbows.Section.1=&3巧射是如何工作的?\n&e巧射是一种被动技能,使用弩以浅角度射出箭,尝试进行巧射。这将使箭从障碍物上弹射出去,并有可能击中目标。反弹的潜在次数取决于巧射技能的等级。 +# 三叉戟术 +Guides.Tridents.Section.0=&3关于三叉戟术:\n&e三叉戟术是用三叉戟刺穿敌人。\n\n&3经验来源:\n&e在用三叉戟攻击怪物或玩家时可以获取经验. + + #检查 Inspect.Offline= &c你没有查询不在线玩家信息的权限! Inspect.OfflineStats=不在线玩家的mcMMO统计信息 &e{0} @@ -1059,7 +1143,7 @@ Smelting.Effect.5=提高冶炼获取的经验球 Smelting.SubSkill.FluxMining.Name=祝融之镐 Smelting.SubSkill.FluxMining.Description=挖矿时一定几率使矿石立即被熔炼 Smelting.SubSkill.FluxMining.Stat=祝融之镐发动几率 -Smelting.Listener=冶炼: +Smelting.Listener=冶炼(Smelting): Smelting.SkillName=冶炼 #指令简介 Commands.Description.addlevels=给玩家增加 mcMMO 等级 @@ -1113,8 +1197,8 @@ Scoreboard.Misc.Ability=能力 #数据库恢复 Profile.PendingLoad=&c你的mcMMO玩家数据未正常加载. Profile.Loading.Success=&a你的mcMMO数据已加载 -Profile.Loading.Failure=&cmcMMO 无法加载你的数据. 请联系 &b服务器管理员反馈你的问题.\n&e你可以继续在服务器游玩, 但是你 &l没有mcMMO等级&e 并且你获得的任何经验都 &l不会被保存&e. -Profile.Loading.AdminFailureNotice=&4[A]&c mcMMO 无法加载玩家 &e{0}&c 的数据. &d请检查你的数据库. +Profile.Loading.FailurePlayer=&cmcMMO在加载你的数据的时候遇到了问题,我们试图加载了 &a{0}&c 次。&c 你可能需要联系服务器管理员来解决。 mcMMO会在你离线前试图加载你的数据,在数据没有加载的情况下你将无法获得经验或使用技能。 +Profile.Loading.FailureNotice=&4[A]&c mcMMO无法加载 &e{0}&c 的数据。 &d请检查你的数据库设置。已经尝试了 {1} 次。 #节日 Holiday.AprilFools.Levelup=&6{0} 现在 &a{1}&6 级! Holiday.Anniversary=&9mcMMO {0} 周年快乐!\n&9为了纪念 nossr50 和所有开发者的工作, 这里有一场烟火表演! @@ -1142,3 +1226,5 @@ Chat.Spy.Party=&6[&eSPY&6-&a{2}&6] &r{0} &b→ &r{1} Broadcasts.LevelUpMilestone=&6(&amcMMO&6) {0}&7 的 &3{2}&7 技能等级提升到了 &a{1}&7! Broadcasts.PowerLevelUpMilestone=&6(&amcMMO&6) {0}&7 总等级已达到 &a{1}&7! Scoreboard.Recovery=正在尝试恢复 mcMMO 记分牌... +Scoreboard.Disabled=该服务器的 mcMMO 计分板已禁用,此设置可在 mcMMO/config.yml 中找到。 +Scoreboard.NotSetupYet=您的 mcMMO 记分板尚未设置,请稍后再试。 diff --git a/src/main/resources/locale/locale_zh_TW.properties b/src/main/resources/locale/locale_zh_TW.properties index 8bfb2a458..6b5e71f63 100644 --- a/src/main/resources/locale/locale_zh_TW.properties +++ b/src/main/resources/locale/locale_zh_TW.properties @@ -20,6 +20,7 @@ JSON.Acrobatics=雜技 JSON.Alchemy=煉金術 JSON.Archery=箭術 JSON.Axes=斧技 +JSON.Crossbows=弩 JSON.Excavation=挖掘 JSON.Fishing=釣魚 JSON.Herbalism=草藥學 @@ -28,6 +29,8 @@ JSON.Repair=修理 JSON.Salvage=分解 JSON.Swords=劍術 JSON.Taming=馴獸 +JSON.Tridents=三叉戟 +JSON.Maces=重錘 JSON.Unarmed=格鬥 JSON.Woodcutting=伐木 JSON.URL.Website=mcMMO 官方網站 ! @@ -87,6 +90,7 @@ Overhaul.Name.Acrobatics=雜技 Overhaul.Name.Alchemy=煉金術 Overhaul.Name.Archery=箭術 Overhaul.Name.Axes=斧技 +Overhaul.Name.Crossbows=弩技 Overhaul.Name.Excavation=挖掘 Overhaul.Name.Fishing=釣魚 Overhaul.Name.Herbalism=草藥學 @@ -96,6 +100,8 @@ Overhaul.Name.Salvage=分解 Overhaul.Name.Smelting=冶煉 Overhaul.Name.Swords=劍術 Overhaul.Name.Taming=馴獸 +Overhaul.Name.Tridents=三叉戟技 +Overhaul.Name.Maces=重錘 Overhaul.Name.Unarmed=格鬥 Overhaul.Name.Woodcutting=伐木 # /mcMMO Command Style Stuff @@ -111,6 +117,7 @@ XPBar.Acrobatics=雜技 Lv.&6{0} XPBar.Alchemy=煉金術 Lv.&6{0} XPBar.Archery=箭術 Lv.&6{0} XPBar.Axes=斧技 Lv.&6{0} +XPBar.Crossbows=弩技 Lv.&6{0} XPBar.Excavation=挖掘 Lv.&6{0} XPBar.Fishing=釣魚 Lv.&6{0} XPBar.Herbalism=草藥學 Lv.&6{0} @@ -120,6 +127,8 @@ XPBar.Salvage=分解 Lv.&6{0} XPBar.Smelting=冶煉 Lv.&6{0} XPBar.Swords=劍術 Lv.&6{0} XPBar.Taming=馴獸 Lv.&6{0} +XPBar.Tridents=三叉戟技 Lv.&6{0} +XPBar.Maces=重錘 Lv.&6{0} XPBar.Unarmed=格鬥 Lv.&6{0} XPBar.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 @@ -175,6 +184,13 @@ Archery.SubSkill.ArcheryLimitBreak.Description=突破你的極限。 Archery.SubSkill.ArcheryLimitBreak.Stat=突破極限的傷害加成 Archery.Listener=箭術 (Archery) : Archery.SkillName=箭術 +Archery.SubSkill.ExplosiveShot.Name=爆炸箭 +Archery.SubSkill.ExplosiveShot.Description=射出一支爆炸箭 +Archery.Skills.ExplosiveShot.Off=爆炸箭關閉 +Archery.Skills.ExplosiveShot.On=&a**爆炸箭啟動** +Archery.Skills.ExplosiveShot.Other.Off=爆炸箭&a 已經為 &e{0} 失效 +Archery.Skills.ExplosiveShot.Other.On=&a{0}&2 已經使用了 &c爆炸箭! +Archery.Skills.ExplosiveShot.Refresh=&a你的 &爆炸箭 &技能已經刷新! #AXES Axes.Ability.Bonus.0=斧頭精通 Axes.Ability.Bonus.1=附加 {0} 傷害 @@ -357,7 +373,7 @@ Repair.SubSkill.ArcaneForging.Description=修理附魔物品 Repair.SubSkill.ArcaneForging.Stat=秘法鍛造 : &e等級 {0}/{1} Repair.SubSkill.ArcaneForging.Stat.Extra=&3秘法鍛造賠率 : &7成功 &a{0}&7%,失敗 &c{1}&7% Repair.Error=&4mcMMO 在嘗試修理此物品時發生了錯誤 ! -Repair.Listener.Anvil=&4你放置的鐵方塊可以用來修理工具和裝備。 +Repair.Listener.Anvil=&a你放置的鐵方塊可以用來修理工具和裝備。 Repair.Listener=修理 (Repair) : Repair.SkillName=修理 Repair.Skills.AdeptDiamond=&4你的技能等級不足以修理鑽石裝備。 @@ -380,7 +396,7 @@ Salvage.SubSkill.UnderstandingTheArt.Name=分解精通 Salvage.SubSkill.UnderstandingTheArt.Description=你不只是再翻鄰居的垃圾,你是在保護環境。\n增強分解的各種屬性。 Salvage.SubSkill.ScrapCollector.Name=廢物利用 Salvage.SubSkill.ScrapCollector.Description=從物品中分解出材料,完美分解取決於技能和運氣。 -Salvage.SubSkill.ScrapCollector.Stat=廢物利用 : &a最多分解出 &e{0}&a 個物品。佔一些運氣成分。 +Salvage.SubSkill.ScrapCollector.Stat=廢物利用 : &a最多分解出 &e{0}&a 個物品。 Salvage.SubSkill.ArcaneSalvage.Name=奧數分解 Salvage.SubSkill.ArcaneSalvage.Description=從物品中拆解附魔 Salvage.SubSkill.ArcaneSalvage.Stat=奧數分解 : &e等級 {0}/{1} @@ -395,7 +411,7 @@ Salvage.Skills.TooDamaged=&4該物品損壞過於嚴重,無法分解。 Salvage.Skills.ArcaneFailed=&c你無法拆解出本物品所蘊含的知識。 Salvage.Skills.ArcanePartial=&c你只能拆解出本物品所蘊含的部分知識。 Salvage.Skills.ArcaneSuccess=&a你能夠完全拆解出本物品所含的知識 ! -Salvage.Listener.Anvil=&4你已經放置了分解鐵砧,使用它來分解工具和盔甲。 +Salvage.Listener.Anvil=&a你已經放置了分解鐵砧,使用它來分解工具和盔甲。 Salvage.Listener=分解 (Salvage) : Salvage.SkillName=分解 Salvage.Skills.Lottery.Normal=&6你能夠從 &e{1}&6 中回收 &3{0}&6 材料。 @@ -403,6 +419,50 @@ Salvage.Skills.Lottery.Perfect=&a&l完美 !&r&6 你毫不費力地搶救了 &3 Salvage.Skills.Lottery.Untrained=&7你在回收方面沒有得到適當的訓練,你只能從 &a{1}&7 中回復 &c{0}&7 材料。 #Anvil (Shared between SALVAGE and REPAIR) Anvil.Unbreakable=這個物品不會損壞 ! +Anvil.Repair.Reject.CustomModelData=一股神秘的力量阻止你修理這個物品… +Anvil.Salvage.Reject.CustomModelData=一股神秘的力量阻止你拆解這個物品… +#CROSSBOWS +Crossbows.SkillName=弩技 +Crossbows.Ability.Lower=&7你放下你的弩。 +Crossbows.Ability.Ready=&3你 &6準備好&3 你的弩。 +Crossbows.Skills.SSG.Refresh=&a你的 &e超級霰彈槍 &a技能已刷新! +Crossbows.Skills.SSG.Other.On=&a{0}&2 使用了 &超級霰彈槍! +Crossbows.SubSkill.PoweredShot.Name=強力射擊 +Crossbows.SubSkill.PoweredShot.Description=增加弩的傷害 +Crossbows.SubSkill.PoweredShot.Stat=強力射擊加成傷害 +Crossbows.SubSkill.CrossbowsLimitBreak.Name=弩的極限突破 +Crossbows.SubSkill.CrossbowsLimitBreak.Description=突破你的極限。對強大的對手增加傷害。主要用於PVP,是否在PVE中增加傷害取決於伺服器設置。 +Crossbows.SubSkill.CrossbowsLimitBreak.Stat=極限突破最大傷害 +Crossbows.SubSkill.TrickShot.Name=花式射擊 +Crossbows.SubSkill.TrickShot.Description=以陡角度反彈箭矢 +Crossbows.SubSkill.TrickShot.Stat=花式射擊最大反彈次數 +Crossbows.SubSkill.TrickShot.Stat.Extra=花式射擊最大反彈次數: &a{0} +Crossbows.SubSkill.TrickShot.Stat.Extra2=花式射擊每次反彈減少傷害: &a{0} +Crossbows.SubSkill.SuperShotgun.Name=超級霰彈槍 +Crossbows.Listener=弩技: + +#TRIDENTS +Tridents.SkillName=三叉戟技 +Tridents.Ability.Lower=&7你放下你的三叉戟。 +Tridents.Ability.Ready=&3你 &6準備好&3 你的三叉戟。 +Tridents.SubSkill.Impale.Name=刺穿 +Tridents.SubSkill.Impale.Description=增加三叉戟的傷害 +Tridents.SubSkill.Impale.Stat=刺穿加成傷害 +Tridents.SubSkill.TridentsLimitBreak.Name=三叉戟的極限突破 +Tridents.SubSkill.TridentsLimitBreak.Description=突破你的極限。對強大的對手增加傷害。主要用於PVP,是否在PVE中增加傷害取決於伺服器設置。 +Tridents.SubSkill.TridentsLimitBreak.Stat=極限突破最大傷害 +Tridents.SubSkill.TridentAbility.Name=WIP +Tridents.Listener=三叉戟技: + +#MACES +Maces.SkillName=重錘 +Maces.Ability.Lower=&7你放下你的重錘。 +Maces.Ability.Ready=&3你 &6準備好&3 你的重錘。 +Maces.SubSkill.MacesLimitBreak.Name=重錘的極限突破 +Maces.SubSkill.MacesLimitBreak.Description=突破你的極限。對強大的對手增加傷害。主要用於PVP,是否在PVE中增加傷害取決於伺服器設置。 +Maces.SubSkill.MacesLimitBreak.Stat=極限突破最大傷害 +Maces.Listener=重錘: + #SWORDS Swords.Ability.Lower=&7你放下了你的劍。 Swords.Ability.Ready=&3你 &6握緊&3 了你的劍。 @@ -573,7 +633,7 @@ Combat.TargetDazed=目標被 &4被擊暈 Combat.TouchedFuzzy=&4頭暈目眩。 #COMMANDS ##generic -mcMMO.Description=&3關於&e mcMMO &3: &6mcMMO 是&c開源&6 RPG 模組,&6由 &9nossr50&6 主導建立於 2011 年 2 月。主旨為玩家提供高品質的 RPG 體驗。&3小提醒 : &6- &a使用&c/mcMMO help&a 查看指令,&6 - &a輸入 &c/mcmmo help&a 查看詳細的技能資訊,&3開發者 : &6- &anossr50 &9(創始人& 項目負責人)&6 - &aGJ &9(項目組長)&6 - &aNuclearW &9(開發者)&6 - &abm01 &9(開發者)&6 - &aTfT_02 &9(開發者)&6 - &aGlitchfinder &9(開發者)&6 - &at00thpick1 &9(開發者)&6 - &aFlandre_tw &3翻譯員。&3實用連結 :&6 - &ahttps://github.com/mcMMO-Dev/mcMMO/issues&6 漏洞報告&6 - &ahttps://discord.gg/EJGVanb &6官方 Discord 伺服器 +mcMMO.Description=&3關於&e mcMMO &3: &6mcMMO 是&c開源&6 RPG 模組,&6由 &9nossr50&6 主導建立於 2011 年 2 月。主旨為玩家提供高品質的 RPG 體驗。&3小提醒 : &6- &a使用&c/mcMMO help&a 查看指令,&6 - &a輸入 &c/mcmmo help&a 查看詳細的技能資訊,&3開發者 : &6- &anossr50 &9(創始人& 項目負責人)&6 - &aGJ &9(項目組長)&6 - &aNuclearW &9(開發者)&6 - &abm01 &9(開發者)&6 - &aTfT_02 &9(開發者)&6 - &aGlitchfinder &9(開發者)&6 - &at00thpick1 &9(開發者)&6 - &aFlandre_tw &3(翻譯員)&6 - &aItzTheBear &3(翻譯員)。&3實用連結 :&6 - &ahttps://github.com/mcMMO-Dev/mcMMO/issues&6 漏洞報告&6 - &ahttps://discord.gg/EJGVanb &6官方 Discord 伺服器 mcMMO.Description.FormerDevs=&3前開發者 : &aGJ、NuclearW、bm01、TfT_02、Glitchfinder Commands.addlevels.AwardAll.1=你所有的技能等級被提升了 {0} 級 ! Commands.addlevels.AwardAll.2=你所有的技能等級已被 {0} 修改。 @@ -969,6 +1029,13 @@ Guides.Woodcutting.Section.0=&3關於伐木 : \n&e伐木是關於砍樹的。\ Guides.Woodcutting.Section.1=&3伐木工如何運作 ? \n&e伐木工是主動技能\n&e在手持斧頭的同時右鍵並破壞木頭以開啟伐木工\n&e這將瞬間破壞整棵樹。 Guides.Woodcutting.Section.2=&3秋風掃落葉如何運作 ? \n&e秋風掃落葉是被動技能\n&e當斧頭擊中樹葉方塊時會導致瞬間消失\n&e預設情況下,100 級解鎖。 Guides.Woodcutting.Section.3=&3樹木豐收如何運作 ? \n&e這個被動技能使你在砍樹時\n&e有機率掉落雙倍木頭。 +# Crossbows +Guides.Crossbows.Section.0=&3關於弩:\n&e弩技能主要是使用你的弩射擊。\n\n&3經驗值獲取:\n&e每當你用弩射擊怪物時,會獲得經驗值。 +Guides.Crossbows.Section.1=&3花式射擊是如何運作的?\n&e花式射擊是一個被動技能,你用弩以淺角度射擊箭矢來嘗試花式射擊。這會導致箭矢從方塊上反彈並有可能擊中目標。反彈的次數取決於花式射擊的等級。 +# Tridents +Guides.Tridents.Section.0=&3關於三叉戟:\n&e三叉戟技能涉及用三叉戟刺穿敵人。\n\n&3經驗值獲取:\n&e每當你用三叉戟擊中怪物時,會獲得經驗值。 + + #INSPECT Inspect.Offline= &c你沒有查詢離線玩家資訊的權限 ! Inspect.OfflineStats=離線玩家的 mcMMO 統計資訊 &e{0} @@ -999,12 +1066,12 @@ Skills.Parents=主技能 Skills.Stats={0}&a{1}&3 點經驗值 (&7{2}&3/&7{3}&3) Skills.ChildStats={0}&a{1} Skills.MaxXP=最大 -Skills.TooTired=你太累了暫時無法使用該技能。&({0}s) +Skills.TooTired=你太累了暫時無法使用該技能。&e({0}s) Skills.TooTired.Named=&7(&6{0}&e {1}s&7) Skills.TooTired.Extra=&6{0} &e超能力冷卻 - {1} Skills.Cancelled=&6{0} &c已取消 ! Skills.ConfirmOrCancel=&a再次點擊右鍵以確定 &6{0}&a,點擊左鍵取消。 -Skills.AbilityGateRequirementFail=&7你需要 &e{0}&7 級以上的 &3{1}&7 來使用這個能力。 +Skills.AbilityGateRequirementFail=&7你還需要 &e{0}&7 級以上的 &3{1}&7 來使用這個能力。 #STATISTICS Stats.Header.Combat=&6-=格鬥技能=- Stats.Header.Gathering=&6-=採集技能=- @@ -1121,7 +1188,7 @@ Holiday.Anniversary=&9mcMMO {0} 週年快樂 ! \n&9為了紀念 nossr50 和所 #Reminder Messages Reminder.Squelched=&7提醒 : 你現在不再接收來自 mcMMO 的通知訊息,如想開啟請再次使用 /mcnotify 指令,每小時提醒一次。 #Locale -Locale.Reloaded=&a語言配置已經重新載入,中文化重編 : Flandre_tw,原作為簡體中文 (有問題請聯絡 Discord 蘭蘭露#4885) +Locale.Reloaded=&a語言配置已經重新載入,中文化重編 : Flandre_tw 和 ItzTheBear (有問題請聯絡 Discord: chunkiu),原作為簡體中文 (有問題請聯絡 Discord: 蘭蘭露#4885) #Player Leveling Stuff LevelCap.PowerLevel=&6(&amcMMO&6) &e你已經到達了戰鬥力的等級封頂 &c{0}&e 級,你的該技能將無法再升級。 LevelCap.Skill=&6(&amcMMO&6) &e你已經到達了&6{1}&e技能的等級封頂 &c{0}&e 級,你的該技能將無法再升級。 @@ -1142,3 +1209,5 @@ Chat.Spy.Party=&6[&eSPY&6-&a{2}&6] &r{0} &b→ &r{1} Broadcasts.LevelUpMilestone=&6(&amcMMO&6) {0}&7 在&3{2}&7 已經達到了 &a{1}&7 級 ! Broadcasts.PowerLevelUpMilestone=&6(&amcMMO&6) {0}&7 已經達到 &a{1}&7 的最高等級 ! Scoreboard.Recovery=正在嘗試回復 mcMMO 計分板…… +Scoreboard.Disabled=這個伺服器的 mcMMO 記分板已被禁用,這個設定在 mcMMO/config.yml 中可以找到。 +Scoreboard.NotSetupYet=你的 mcMMO 記分板尚未設置,請稍後再試。 diff --git a/src/main/resources/party.yml b/src/main/resources/party.yml new file mode 100644 index 000000000..16eebf6cb --- /dev/null +++ b/src/main/resources/party.yml @@ -0,0 +1,4 @@ +# Settings for mcMMO Party System +Party: + # Enable or disable the mcMMO party system + Enabled: true \ No newline at end of file diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index a8b56712c..700e0c5cd 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -14,15 +14,12 @@ author: nossr50 authors: [GJ, NuclearW, bm01, Glitchfinder, TfT_02, t00thpick1, Riking, electronicboy, kashike] website: https://www.mcmmo.org main: com.gmail.nossr50.mcMMO -softdepend: [WorldGuard, CombatTag, HealthBar, PlaceholderAPI] +softdepend: [WorldGuard, CombatTag, HealthBar, PlaceholderAPI, ProtocolLib] load: POSTWORLD folia-supported: true 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 @@ -70,9 +67,6 @@ commands: mcgod: description: Toggle mcMMO god-mode on/off permission: mcmmo.commands.mcgod - mcimport: - description: Import mod config files - permission: mcmmo.commands.mcimport mcstats: aliases: [stats] description: Shows your mcMMO stats and xp @@ -124,12 +118,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 @@ -151,6 +151,13 @@ commands: salvage: description: Detailed mcMMO skill info permission: mcmmo.commands.salvage + maces: + description: Detailed mcMMO skill info + permission: mcmmo.commands.maces + 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 @@ -158,14 +165,6 @@ commands: mcpurge: description: Purge users with 0 powerlevel and/or who haven't connected in several months from the server DB. permission: mcmmo.commands.mcpurge -# hardcore: -# aliases: [mchardcore] -# description: Modify the mcMMO hardcore percentage or toggle hardcore mode on/off -# permission: mcmmo.commands.hardcore -# vampirism: -# aliases: [mcvampirism] -# description: Modify the mcMMO vampirism percentage or toggle vampirism mode on/off -# permission: mcmmo.commands.vampirism mcnotify: aliases: [notify] description: Toggle mcMMO abilities chat display notifications on/off @@ -174,11 +173,6 @@ commands: aliases: [mcsb] description: Manage your mcMMO Scoreboard permission: mcmmo.commands.mcscoreboard - #mcfools: - crafting: - aliases: [macho, jumping, throwing, wrecking, walking, swimming, falling, climbing, flying, diving, piggy] - description: Deploy jokes - permission: mcmmo.commands.mcfools mcmmoreloadlocale: aliases: [mcreloadlocale] description: Reloads locale @@ -234,15 +228,18 @@ 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 + mcmmo.ability.maces.all: true mcmmo.ability.mining.all: true mcmmo.ability.repair.all: true mcmmo.ability.salvage.all: true 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.*: @@ -281,12 +278,15 @@ 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 and crossbows + description: Adds damage to bows mcmmo.ability.archery.skillshot: description: Allows bonus damage from the Archery SkillShot ability mcmmo.ability.archery.daze: @@ -319,6 +319,22 @@ 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.trickshot: true + mcmmo.ability.crossbows.poweredshot: true + mcmmo.ability.crossbows.crossbowslimitbreak: true + mcmmo.ability.crossbows.crossbowslimitbreak: + 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 @@ -376,6 +392,9 @@ permissions: mcmmo.ability.herbalism.greenthumb.all: true mcmmo.ability.herbalism.hylianluck: true mcmmo.ability.herbalism.shroomthumb: true + 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 mcmmo.ability.herbalism.farmersdiet: @@ -445,6 +464,23 @@ permissions: description: Allows access to the Hylian Luck ability mcmmo.ability.herbalism.shroomthumb: description: Allows access to the Shroom Thumb ability + mcmmo.ability.maces.*: + default: false + description: Allows access to all Maces abilities + children: + mcmmo.ability.mining.all: true + mcmmo.ability.maces.all: + description: Allows access to all Maces abilities + children: + mcmmo.ability.maces.crush: true + mcmmo.ability.maces.cripple: true + mcmmo.ability.maces.maceslimitbreak: true + mcmmo.ability.maces.maceslimitbreak: + description: Allows access to Maces Limit Break subskill + mcmmo.ability.maces.crush: + description: Allows access to the Crush ability + mcmmo.ability.maces.cripple: + description: Allows access to the Cripple ability mcmmo.ability.mining.*: default: false description: Allows access to all Mining abilities @@ -456,6 +492,7 @@ permissions: mcmmo.ability.mining.blastmining.all: true mcmmo.ability.mining.doubledrops: true mcmmo.ability.mining.superbreaker: true + mcmmo.ability.mining.motherlode: true mcmmo.ability.mining.blastmining.*: default: false description: Allows access to all Blast Mining abilities @@ -473,6 +510,8 @@ permissions: description: Allows access to the Demolitions Expertise ability mcmmo.ability.mining.blastmining.detonate: description: Allows for remote TNT detonation + 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: @@ -677,6 +716,20 @@ 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.impale: true + mcmmo.ability.tridents.tridentslimitbreak: true + mcmmo.ability.tridents.impale: + description: Allows access to tridents Impale ability + mcmmo.ability.tridents.tridentslimitbreak: + description: Adds damage to tridents mcmmo.ability.unarmed.*: default: false description: Allows access to all Unarmed abilities @@ -721,6 +774,9 @@ permissions: mcmmo.ability.woodcutting.knockonwood: true mcmmo.ability.woodcutting.leafblower: true mcmmo.ability.woodcutting.treefeller: true + 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 mcmmo.ability.woodcutting.splinter: @@ -802,6 +858,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 @@ -814,6 +872,7 @@ permissions: mcmmo.commands.mcscoreboard: true mcmmo.commands.mcstats: true mcmmo.commands.mctop.all: true + mcmmo.commands.maces: true mcmmo.commands.mining: true mcmmo.commands.party.all: true mcmmo.commands.ptp.all: true @@ -824,6 +883,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: @@ -841,7 +901,6 @@ permissions: mcmmo.commands.mcchatspy.others: true mcmmo.commands.mcgod: true mcmmo.commands.mcgod.others: true - mcmmo.commands.mcimport: true mcmmo.commands.mcpurge: true mcmmo.commands.mcrank.others.all: true mcmmo.commands.mcrefresh: true @@ -871,29 +930,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 @@ -958,8 +1004,6 @@ permissions: description: Allows access to the mcnotify command mcmmo.commands.mcpurge: description: Allows access to the mcpurge command - mcmmo.commands.mcimport: - description: Allows access to the mcimport command mcmmo.commands.mcrank: description: Allows access to the mcrank command mcmmo.commands.mcrank.others.*: @@ -999,15 +1043,18 @@ 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 + mcmmo.commands.mctop.maces: true mcmmo.commands.mctop.mining: true mcmmo.commands.mctop.repair: true mcmmo.commands.mctop.salvage: true 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: @@ -1020,12 +1067,16 @@ 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: description: Allows access to the mctop command for fishing mcmmo.commands.mctop.herbalism: description: Allows access to the mctop command for herbalism + mcmmo.commands.mctop.maces: + description: Allows access to the mctop command for maces mcmmo.commands.mctop.mining: description: Allows access to the mctop command for mining mcmmo.commands.mctop.repair: @@ -1038,6 +1089,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: @@ -1184,6 +1237,9 @@ permissions: mcmmo.commands.skillreset.taming: true mcmmo.commands.skillreset.unarmed: true mcmmo.commands.skillreset.woodcutting: true + mcmmo.commands.skillreset.crossbows: true + mcmmo.commands.skillreset.tridents: true + mcmmo.commands.skillreset.maces: true mcmmo.commands.skillreset: description: Allows access to the skillreset command mcmmo.commands.skillreset.acrobatics: @@ -1202,6 +1258,12 @@ permissions: description: Allows access to the skillreset command for herbalism mcmmo.commands.skillreset.mining: description: Allows access to the skillreset command for mining + mcmmo.commands.skillreset.crossbows: + description: Allows access to the skillreset command for crossbows + mcmmo.commands.skillreset.tridents: + description: Allows access to the skillreset command for tridents + mcmmo.commands.skillreset.maces: + description: Allows access to the skillreset command for maces mcmmo.commands.skillreset.others.*: default: false description: Implies access to all mcmmo.commands.skillreset.others permissions @@ -1226,6 +1288,9 @@ permissions: mcmmo.commands.skillreset.others.taming: true mcmmo.commands.skillreset.others.unarmed: true mcmmo.commands.skillreset.others.woodcutting: true + mcmmo.commands.skillreset.others.crossbows: true + mcmmo.commands.skillreset.others.tridents: true + mcmmo.commands.skillreset.others.maces: true mcmmo.commands.skillreset.others: description: Allows access to the skillreset command for other players mcmmo.commands.skillreset.others.acrobatics: @@ -1258,6 +1323,12 @@ permissions: description: Allows access to the skillreset command for unarmed for other players mcmmo.commands.skillreset.others.woodcutting: description: Allows access to the skillreset command for woodcutting for other players + mcmmo.commands.skillreset.others.crossbows: + description: Allows access to the skillreset command for crossbows for other players + mcmmo.commands.skillreset.others.tridents: + description: Allows access to the skillreset command for tridents for other players + mcmmo.commands.skillreset.others.maces: + description: Allows access to the skillreset command for maces for other players mcmmo.commands.skillreset.repair: description: Allows access to the skillreset command for repair mcmmo.commands.skillreset.salvage: @@ -1282,23 +1353,6 @@ permissions: description: Allows access to the taming command mcmmo.commands.unarmed: description: Allows access to the unarmed command -# mcmmo.commands.vampirism.*: -# default: false -# description: Implies access to all mcmmo.commands.vampirism permissions -# children: -# mcmmo.commands.vampirism.all: true -# mcmmo.commands.vampirism.all: -# description: Implies access to all mcmmo.commands.vampirism permissions -# children: -# mcmmo.commands.vampirism: true -# mcmmo.commands.vampirism.modify: true -# mcmmo.commands.vampirism.toggle: true -# mcmmo.commands.vampirism: -# description: Allows access to the vampirism command -# mcmmo.commands.vampirism.modify: -# description: Allows access to the vampirism command to modify the vampirism rate -# mcmmo.commands.vampirism.toggle: -# description: Allows access to the vampirism command to toggle vampirism on/off mcmmo.commands.woodcutting: description: Allows access to the woodcutting command mcmmo.commands.xprate.*: @@ -1432,6 +1486,7 @@ permissions: mcmmo.perks.lucky.excavation: true mcmmo.perks.lucky.fishing: true mcmmo.perks.lucky.herbalism: true + mcmmo.perks.lucky.maces: true mcmmo.perks.lucky.mining: true mcmmo.perks.lucky.repair: true mcmmo.perks.lucky.salvage: true @@ -1440,6 +1495,8 @@ permissions: mcmmo.perks.lucky.taming: true mcmmo.perks.lucky.unarmed: true mcmmo.perks.lucky.woodcutting: true + mcmmo.perks.lucky.crossbows: true + mcmmo.perks.lucky.tridents: true mcmmo.perks.lucky.acrobatics: default: false description: Gives Acrobatics abilities & skills a 33.3% better chance to activate. @@ -1452,6 +1509,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. @@ -1461,6 +1521,9 @@ permissions: mcmmo.perks.lucky.herbalism: default: false description: Gives Herbalism abilities & skills a 33.3% better chance to activate. + mcmmo.perks.lucky.maces: + default: false + description: Gives Mining abilities & skills a 33.3% better chance to activate. mcmmo.perks.lucky.mining: default: false description: Gives Mining abilities & skills a 33.3% better chance to activate. @@ -1479,6 +1542,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. @@ -1520,14 +1586,17 @@ 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 + mcmmo.perks.xp.150percentboost.maces: true mcmmo.perks.xp.150percentboost.mining: true mcmmo.perks.xp.150percentboost.repair: true 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: @@ -1542,6 +1611,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 @@ -1551,6 +1623,9 @@ permissions: mcmmo.perks.xp.150percentboost.herbalism: default: false description: Multiplies incoming Herbalism XP by 2.5 + mcmmo.perks.xp.150percentboost.maces: + default: false + description: Multiplies incoming Maces XP by 2.5 mcmmo.perks.xp.150percentboost.mining: default: false description: Multiplies incoming Mining XP by 2.5 @@ -1566,6 +1641,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 @@ -1590,14 +1668,17 @@ 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 + mcmmo.perks.xp.50percentboost.maces: true mcmmo.perks.xp.50percentboost.mining: true mcmmo.perks.xp.50percentboost.repair: true 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: @@ -1612,6 +1693,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 @@ -1621,6 +1705,9 @@ permissions: mcmmo.perks.xp.50percentboost.herbalism: default: false description: Multiplies incoming Herbalism XP by 1.5 + mcmmo.perks.xp.50percentboost.maces: + default: false + description: Multiplies incoming Maces XP by 1.5 mcmmo.perks.xp.50percentboost.mining: default: false description: Multiplies incoming Mining XP by 1.5 @@ -1636,6 +1723,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 @@ -1656,20 +1746,23 @@ 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.maces: 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 @@ -1682,6 +1775,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 @@ -1691,6 +1787,9 @@ permissions: mcmmo.perks.xp.25percentboost.herbalism: default: false description: Multiplies incoming Herbalism XP by 1.25 + mcmmo.perks.xp.25percentboost.maces: + default: false + description: Multiplies incoming Maces XP by 1.25 mcmmo.perks.xp.25percentboost.mining: default: false description: Multiplies incoming Mining XP by 1.25 @@ -1706,6 +1805,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 @@ -1730,14 +1832,17 @@ 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 + mcmmo.perks.xp.10percentboost.maces: true mcmmo.perks.xp.10percentboost.mining: true mcmmo.perks.xp.10percentboost.repair: true 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: @@ -1752,6 +1857,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 @@ -1761,6 +1869,9 @@ permissions: mcmmo.perks.xp.10percentboost.herbalism: default: false description: Multiplies incoming Herbalism XP by 1.1 + mcmmo.perks.xp.10percentboost.maces: + default: false + description: Multiplies incoming Maces XP by 1.1 mcmmo.perks.xp.10percentboost.mining: default: false description: Multiplies incoming Mining XP by 1.1 @@ -1776,6 +1887,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 @@ -1800,14 +1914,17 @@ 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 + mcmmo.perks.xp.customboost.maces: true mcmmo.perks.xp.customboost.mining: true mcmmo.perks.xp.customboost.repair: true 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: @@ -1822,6 +1939,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 @@ -1831,6 +1951,9 @@ permissions: mcmmo.perks.xp.customboost.herbalism: default: false description: Multiplies incoming Herbalism XP by the boost amount defined in the experience config + mcmmo.perks.xp.customboost.maces: + default: false + description: Multiplies incoming Maces XP by the boost amount defined in the experience config mcmmo.perks.xp.customboost.mining: default: false description: Multiplies incoming Mining XP by the boost amount defined in the experience config @@ -1846,6 +1969,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 @@ -1870,14 +1996,17 @@ 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 + mcmmo.perks.xp.double.maces: true mcmmo.perks.xp.double.mining: true mcmmo.perks.xp.double.repair: true 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: @@ -1892,6 +2021,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 @@ -1901,6 +2033,9 @@ permissions: mcmmo.perks.xp.double.herbalism: default: false description: Doubles incoming Herbalism XP + mcmmo.perks.xp.double.maces: + default: false + description: Doubles incoming Maces XP mcmmo.perks.xp.double.mining: default: false description: Doubles incoming Mining XP @@ -1916,6 +2051,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 @@ -1940,14 +2078,17 @@ 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 + mcmmo.perks.xp.quadruple.maces: true mcmmo.perks.xp.quadruple.mining: true mcmmo.perks.xp.quadruple.repair: true 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: @@ -1962,6 +2103,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 @@ -1971,6 +2115,9 @@ permissions: mcmmo.perks.xp.quadruple.herbalism: default: false description: Quadruples incoming Herbalism XP + mcmmo.perks.xp.quadruple.maces: + default: false + description: Quadruples incoming Maces XP mcmmo.perks.xp.quadruple.mining: default: false description: Quadruples incoming Mining XP @@ -1986,6 +2133,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 @@ -2010,14 +2160,17 @@ 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 mcmmo.perks.xp.triple.mining: true + mcmmo.perks.xp.triple.maces: true mcmmo.perks.xp.triple.repair: true 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: @@ -2032,6 +2185,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 @@ -2041,6 +2197,9 @@ permissions: mcmmo.perks.xp.triple.herbalism: default: false description: Triples incoming Herbalism XP + mcmmo.perks.xp.triple.maces: + default: false + description: Triples incoming Maces XP mcmmo.perks.xp.triple.mining: default: false description: Triples incoming Mining XP @@ -2056,6 +2215,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 @@ -2083,6 +2245,7 @@ permissions: mcmmo.skills.excavation: true mcmmo.skills.fishing: true mcmmo.skills.herbalism: true + mcmmo.skills.maces: true mcmmo.skills.mining: true mcmmo.skills.repair: true mcmmo.skills.salvage: true @@ -2091,6 +2254,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: @@ -2111,6 +2276,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: @@ -2156,6 +2326,16 @@ permissions: children: mcmmo.ability.taming.all: true mcmmo.commands.taming: true + mcmmo.skills.maces: + description: Allows access to the Maces skill + children: + mcmmo.ability.maces.all: true + mcmmo.commands.maces: 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: @@ -2169,16 +2349,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/potions.yml b/src/main/resources/potions.yml index 4e14491b7..de54bea52 100644 --- a/src/main/resources/potions.yml +++ b/src/main/resources/potions.yml @@ -4,6 +4,7 @@ ### Concoctions: Tier_One_Ingredients: + - BREEZE_ROD - BLAZE_POWDER - FERMENTED_SPIDER_EYE - GHAST_TEAR @@ -19,6 +20,10 @@ Concoctions: - WATER_LILY - PUFFERFISH - DRAGON_BREATH + - STONE + - SLIME_BLOCK + - COBWEB + - TURTLE_HELMET Tier_Two_Ingredients: - CARROT - SLIME_BALL @@ -67,6 +72,7 @@ Potions: PotionData: PotionType: WATER Children: + BREEZE_ROD: POTION_OF_MUNDANE SPIDER_EYE: POTION_OF_MUNDANE FERMENTED_SPIDER_EYE: POTION_OF_WEAKNESS GLOWSTONE_DUST: POTION_OF_THICK @@ -84,6 +90,7 @@ Potions: PotionData: PotionType: UNCRAFTABLE Children: + BREEZE_ROD: POTION_OF_MUNDANE SPIDER_EYE: POTION_OF_MUNDANE FERMENTED_SPIDER_EYE: POTION_OF_WEAKNESS GLOWSTONE_DUST: POTION_OF_THICK @@ -113,6 +120,7 @@ Potions: PotionData: PotionType: AWKWARD Children: + BREEZE_ROD: POTION_OF_WIND_CHARGING QUARTZ: POTION_OF_ABSORPTION GUNPOWDER: SPLASH_POTION_OF_AWKWARD BROWN_MUSHROOM: POTION_OF_NAUSEA @@ -135,6 +143,9 @@ Potions: GHAST_TEAR: POTION_OF_REGENERATION TURTLE_HELMET: POTION_OF_TURTLE_MASTER RABBIT_FOOT: POTION_OF_LEAPING + STONE: POTION_OF_INFESTATION + SLIME_BLOCK: POTION_OF_OOZING + COBWEB: POTION_OF_WEAVING POTION_OF_NIGHT_VISION: Material: POTION PotionData: @@ -692,6 +703,7 @@ Potions: PotionData: PotionType: WATER Children: + BREEZE_ROD: SPLASH_POTION_OF_MUNDANE SUGAR: SPLASH_POTION_OF_MUNDANE BLAZE_POWDER: SPLASH_POTION_OF_MUNDANE GHAST_TEAR: SPLASH_POTION_OF_MUNDANE @@ -1298,6 +1310,7 @@ Potions: PotionData: PotionType: WATER Children: + BREEZE_ROD: LINGERING_POTION_OF_MUNDANE REDSTONE: LINGERING_POTION_OF_MUNDANE GLISTERING_MELON_SLICE: LINGERING_POTION_OF_MUNDANE GHAST_TEAR: LINGERING_POTION_OF_MUNDANE @@ -1786,4 +1799,104 @@ Potions: PotionData: PotionType: UNCRAFTABLE Effects: ["SATURATION 1 1"] - + POTION_OF_INFESTATION: + Name: Potion of Infestation + Material: POTION + Color: 0x878787 + PotionData: + PotionType: UNCRAFTABLE + Effects: ["INFESTED 0 3600"] + Children: + GUNPOWDER: SPLASH_POTION_OF_INFESTATION + DRAGON_BREATH: SPLASH_POTION_OF_INFESTATION + SPLASH_POTION_OF_INFESTATION: + Name: Splash Potion of Infestation + Material: SPLASH_POTION + Color: 0x878787 + PotionData: + PotionType: UNCRAFTABLE + Effects: ["INFESTED 0 2500"] + Children: + DRAGON_BREATH: LINGERING_POTION_OF_INFESTATION + LINGERING_POTION_OF_INFESTATION: + Name: Lingering Potion of Infestation + Material: LINGERING_POTION + Color: 0x878787 + PotionData: + PotionType: UNCRAFTABLE + Effects: ["INFESTED 0 3000"] + POTION_OF_WEAVING: + Name: Potion of Weaving + Material: POTION + Color: 0xC7C7C7 + PotionData: + PotionType: UNCRAFTABLE + Effects: ["WEAVING 0 3600"] + Children: + GUNPOWDER: SPLASH_POTION_OF_WEAVING + SPLASH_POTION_OF_WEAVING: + Name: Splash Potion of Weaving + Material: SPLASH_POTION + Color: 0xC7C7C7 + PotionData: + PotionType: UNCRAFTABLE + Effects: ["WEAVING 0 2500"] + Children: + DRAGON_BREATH: LINGERING_POTION_OF_WEAVING + LINGERING_POTION_OF_WEAVING: + Name: Lingering Potion of Weaving + Material: LINGERING_POTION + Color: 0xC7C7C7 + PotionData: + PotionType: UNCRAFTABLE + Effects: ["WEAVING 0 3000"] + POTION_OF_WIND_CHARGING: + Name: Potion of Wind Charging + Material: POTION + Color: 0xBDC9FF + PotionData: + PotionType: UNCRAFTABLE + Effects: [ "WIND_CHARGED 0 3600" ] + Children: + GUNPOWDER: SPLASH_POTION_OF_WIND_CHARGING + SPLASH_POTION_OF_WIND_CHARGING: + Name: Splash Potion of Wind Charging + Material: SPLASH_POTION + Color: 0xBDC9FF + PotionData: + PotionType: UNCRAFTABLE + Effects: [ "WIND_CHARGED 0 2500" ] + Children: + DRAGON_BREATH: LINGERING_POTION_OF_WIND_CHARGING + LINGERING_POTION_WIND_CHARGING: + Name: Lingering Potion of Wind Charging + Material: LINGERING_POTION + Color: 0xBDC9FF + PotionData: + PotionType: UNCRAFTABLE + Effects: [ "WIND_CHARGED 0 3000" ] + POTION_OF_OOZING: + Name: Potion of Oozing + Material: POTION + Color: 0x03FF00 + PotionData: + PotionType: UNCRAFTABLE + Effects: ["OOZING 0 3600"] + Children: + GUNPOWDER: SPLASH_POTION_OF_OOZING + SPLASH_POTION_OF_OOZING: + Name: Splash Potion of Oozing + Material: SPLASH_POTION + Color: 0x03FF00 + PotionData: + PotionType: UNCRAFTABLE + Effects: ["OOZING 0 2500"] + Children: + DRAGON_BREATH: LINGERING_POTION_OF_OOZING + LINGERING_POTION_OF_OOZING: + Name: Lingering Potion of Oozing + Material: LINGERING_POTION + Color: 0x03FF00 + PotionData: + PotionType: UNCRAFTABLE + Effects: ["OOZING 0 3000"] diff --git a/src/main/resources/repair.vanilla.yml b/src/main/resources/repair.vanilla.yml index 72ba687bd..52165805f 100644 --- a/src/main/resources/repair.vanilla.yml +++ b/src/main/resources/repair.vanilla.yml @@ -284,4 +284,12 @@ Repairables: ItemMaterialCategory: OTHER RepairMaterial: PRISMARINE_CRYSTALS MinimumQuantity: 16 + MaximumDurability: 250 + MACE: + MinimumLevel: 0 + XpMultiplier: 3 + ItemType: TOOL + ItemMaterialCategory: OTHER + RepairMaterial: BREEZE_ROD + MinimumQuantity: 4 MaximumDurability: 250 \ No newline at end of file diff --git a/src/main/resources/salvage.vanilla.yml b/src/main/resources/salvage.vanilla.yml index 4977c492b..dbcd66a5e 100644 --- a/src/main/resources/salvage.vanilla.yml +++ b/src/main/resources/salvage.vanilla.yml @@ -290,3 +290,10 @@ Salvageables: CARROT_ON_A_STICK: MinimumLevel: 0 XpMultiplier: .5 + CROSSBOW: + MinimumLevel: 0 + XpMultiplier: 1 + # Other + TRIDENT: + MinimumLevel: 0 + XpMultiplier: 1 diff --git a/src/main/resources/skillranks.yml b/src/main/resources/skillranks.yml index 1a305921b..66e2cb06e 100644 --- a/src/main/resources/skillranks.yml +++ b/src/main/resources/skillranks.yml @@ -201,6 +201,129 @@ Axes: Rank_2: 100 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 + 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 + 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 +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 + 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: @@ -320,7 +443,58 @@ Salvage: Rank_6: 750 Rank_7: 850 Rank_8: 1000 +Maces: + MacesLimitBreak: + 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 + Cripple: + Standard: + Rank_1: 5 + Rank_2: 20 + Rank_3: 40 + Rank_4: 80 + RetroMode: + Rank_1: 50 + Rank_2: 200 + Rank_3: 400 + Rank_4: 800 + Crush: + Standard: + Rank_1: 10 + Rank_2: 25 + Rank_3: 75 + Rank_4: 90 + RetroMode: + Rank_1: 100 + Rank_2: 250 + Rank_3: 750 + Rank_4: 900 Mining: + MotherLode: + Standard: + Rank_1: 100 + RetroMode: + Rank_1: 1000 DoubleDrops: Standard: Rank_1: 1 @@ -368,6 +542,11 @@ Herbalism: Rank_1: 1 RetroMode: Rank_1: 1 + VerdantBounty: + Standard: + Rank_1: 100 + RetroMode: + Rank_1: 1000 GreenTerra: Standard: Rank_1: 5 @@ -398,6 +577,11 @@ Herbalism: Rank_4: 800 Rank_5: 1000 Fishing: + Mastery: + Standard: + Rank_1: 100 + RetroMode: + Rank_1: 1000 MagicHunter: Standard: Rank_1: 20 @@ -637,6 +821,11 @@ Woodcutting: Rank_1: 1 RetroMode: Rank_1: 1 + CleanCuts: + Standard: + Rank_1: 100 + RetroMode: + Rank_1: 1000 KnockOnWood: Standard: Rank_1: 30 diff --git a/src/main/resources/sounds.yml b/src/main/resources/sounds.yml index 8f88c574f..b6d4fcba4 100644 --- a/src/main/resources/sounds.yml +++ b/src/main/resources/sounds.yml @@ -67,4 +67,8 @@ Sounds: BLEED: Enable: true Volume: 2.0 - Pitch: 2.0 \ No newline at end of file + Pitch: 2.0 + CRIPPLE: + Enable: true + Volume: 1.0 + Pitch: 0.5 \ No newline at end of file diff --git a/src/test/java/com/gmail/nossr50/MMOTestEnvironment.java b/src/test/java/com/gmail/nossr50/MMOTestEnvironment.java new file mode 100644 index 000000000..f80636585 --- /dev/null +++ b/src/test/java/com/gmail/nossr50/MMOTestEnvironment.java @@ -0,0 +1,285 @@ +package com.gmail.nossr50; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.when; + +import com.gmail.nossr50.api.exceptions.InvalidSkillException; +import com.gmail.nossr50.config.AdvancedConfig; +import com.gmail.nossr50.config.ChatConfig; +import com.gmail.nossr50.config.GeneralConfig; +import com.gmail.nossr50.config.RankConfig; +import com.gmail.nossr50.config.experience.ExperienceConfig; +import com.gmail.nossr50.config.party.PartyConfig; +import com.gmail.nossr50.datatypes.player.McMMOPlayer; +import com.gmail.nossr50.datatypes.player.PlayerProfile; +import com.gmail.nossr50.datatypes.skills.PrimarySkillType; +import com.gmail.nossr50.datatypes.skills.SubSkillType; +import com.gmail.nossr50.util.EventUtils; +import com.gmail.nossr50.util.MaterialMapStore; +import com.gmail.nossr50.util.Misc; +import com.gmail.nossr50.util.Permissions; +import com.gmail.nossr50.util.TransientEntityTracker; +import com.gmail.nossr50.util.blockmeta.ChunkManager; +import com.gmail.nossr50.util.compat.CompatibilityManager; +import com.gmail.nossr50.util.platform.MinecraftGameVersion; +import com.gmail.nossr50.util.player.NotificationManager; +import com.gmail.nossr50.util.player.UserManager; +import com.gmail.nossr50.util.skills.RankUtils; +import com.gmail.nossr50.util.skills.SkillTools; +import com.gmail.nossr50.util.sounds.SoundManager; +import java.util.UUID; +import java.util.logging.Logger; +import org.bukkit.Bukkit; +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.entity.Player; +import org.bukkit.event.Event; +import org.bukkit.inventory.ItemFactory; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.PlayerInventory; +import org.bukkit.plugin.PluginManager; +import org.mockito.MockedStatic; +import org.mockito.Mockito; + +public abstract class MMOTestEnvironment { + protected MockedStatic mockedBukkit; + 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 MockedStatic notificationManager; + protected MockedStatic mockedSoundManager; + protected TransientEntityTracker transientEntityTracker; + protected AdvancedConfig advancedConfig; + protected PartyConfig partyConfig; + protected GeneralConfig generalConfig; + protected RankConfig rankConfig; + protected SkillTools skillTools; + protected Server server; + protected PluginManager pluginManager; + protected World world; + + /* Mocks */ + protected Player player; + + protected UUID playerUUID = UUID.randomUUID(); + protected ItemStack itemInMainHand; + + protected PlayerInventory playerInventory; + protected PlayerProfile playerProfile; + protected McMMOPlayer mmoPlayer; + protected ItemFactory itemFactory; + + protected ChunkManager chunkManager; + protected MaterialMapStore materialMapStore; + + protected CompatibilityManager compatibilityManager; + + protected void mockBaseEnvironment(Logger logger) throws InvalidSkillException { + compatibilityManager = mock(CompatibilityManager.class); + final MinecraftGameVersion minecraftGameVersion = mock(MinecraftGameVersion.class); + when(compatibilityManager.getMinecraftGameVersion()).thenReturn(minecraftGameVersion); + // TODO: We should change minecraftGameVersion to be a passed in parameter instead of always returning true + when(minecraftGameVersion.isAtLeast(anyInt(), anyInt(), anyInt())).thenReturn(true); + mockedMcMMO = mockStatic(mcMMO.class); + when(mcMMO.getCompatibilityManager()).thenReturn(compatibilityManager); + mcMMO.p = mock(mcMMO.class); + when(mcMMO.p.getLogger()).thenReturn(logger); + + // place store + chunkManager = mock(ChunkManager.class); + when(mcMMO.getUserBlockTracker()).thenReturn(chunkManager); + + // chat config + mockedChatConfig = mockStatic(ChatConfig.class); + when(ChatConfig.getInstance()).thenReturn(mock(ChatConfig.class)); + + // general config + mockGeneralConfig(); + + // party config + mockPartyConfig(); + + // rank config + mockRankConfig(); + + // wire advanced config + mockAdvancedConfig(); + + // wire experience config + mockExperienceConfig(); + + // wire skill tools + this.skillTools = new SkillTools(mcMMO.p); + when(mcMMO.p.getSkillTools()).thenReturn(skillTools); + + this.transientEntityTracker = new TransientEntityTracker(); + when(mcMMO.getTransientEntityTracker()).thenReturn(transientEntityTracker); + + mockPermissions(); + + mockedRankUtils = mockStatic(RankUtils.class); + + // wire server + this.server = mock(Server.class); + when(mcMMO.p.getServer()).thenReturn(server); + + // wire Bukkit + mockedBukkit = mockStatic(Bukkit.class); + when(Bukkit.getItemFactory()).thenReturn(itemFactory); + itemFactory = mock(ItemFactory.class); + + // wire Bukkit call to get server + when(Bukkit.getServer()).thenReturn(server); + + // wire plugin manager + this.pluginManager = mock(PluginManager.class); + // wire server -> plugin manager + when(server.getPluginManager()).thenReturn(pluginManager); + // wire Bukkit -> plugin manager + when(Bukkit.getPluginManager()).thenReturn(pluginManager); + // return the argument provided when call event is invoked on plugin manager mock + doAnswer(invocation -> { + Object[] args = invocation.getArguments(); + return args[0]; + }).when(pluginManager).callEvent(any(Event.class)); + + // wire world + this.world = mock(World.class); + + // wire Misc + this.mockedMisc = mockStatic(Misc.class); + when(Misc.getBlockCenter(any(Block.class))).thenReturn(new Location(world, 0, 0, 0)); + when(Misc.getBlockCenter(any(BlockState.class))).thenReturn(new Location(world, 0, 0, 0)); + + // setup player and player related mocks after everything else + this.player = mock(Player.class); + when(player.getUniqueId()).thenReturn(playerUUID); + when(player.isValid()).thenReturn(true); + when(player.isOnline()).thenReturn(true); + // health + when(player.getHealth()).thenReturn(20D); + // wire inventory + this.playerInventory = mock(PlayerInventory.class); + when(player.getInventory()).thenReturn(playerInventory); + // player location + Location playerLocation = mock(Location.class); + Block playerLocationBlock = mock(Block.class); + when(player.getLocation()).thenReturn(playerLocation); + when(playerLocation.getBlock()).thenReturn(playerLocationBlock); + // when(playerLocationBlock.getType()).thenReturn(Material.AIR); + + // 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 = mockStatic(UserManager.class); + when(UserManager.getPlayer(player)).thenReturn(mmoPlayer); + + this.materialMapStore = new MaterialMapStore(); + when(mcMMO.getMaterialMapStore()).thenReturn(materialMapStore); + + // wire notification manager + notificationManager = mockStatic(NotificationManager.class); + + // wire sound manager + mockedSoundManager = mockStatic(SoundManager.class); + } + + private void mockPermissions() { + mockedPermissions = mockStatic(Permissions.class); + when(Permissions.isSubSkillEnabled(any(Player.class), any(SubSkillType.class))).thenReturn( + true); + when(Permissions.canUseSubSkill(any(Player.class), any(SubSkillType.class))).thenReturn( + true); + when(Permissions.isSubSkillEnabled(any(Player.class), any(SubSkillType.class))).thenReturn( + true); + when(Permissions.canUseSubSkill(any(Player.class), any(SubSkillType.class))).thenReturn( + true); + when(Permissions.lucky(player, PrimarySkillType.WOODCUTTING)).thenReturn( + false); // player is not lucky + } + + private void mockRankConfig() { + rankConfig = mock(RankConfig.class); + } + + private void mockAdvancedConfig() { + this.advancedConfig = mock(AdvancedConfig.class); + when(mcMMO.p.getAdvancedConfig()).thenReturn(advancedConfig); + } + + private void mockGeneralConfig() { + generalConfig = mock(GeneralConfig.class); + when(generalConfig.getTreeFellerThreshold()).thenReturn(100); + when(generalConfig.getDoubleDropsEnabled(PrimarySkillType.WOODCUTTING, + Material.OAK_LOG)).thenReturn(true); + when(generalConfig.getLocale()).thenReturn("en_US"); + when(mcMMO.p.getGeneralConfig()).thenReturn(generalConfig); + } + + private void mockPartyConfig() { + partyConfig = mock(PartyConfig.class); + when(partyConfig.isPartyEnabled()).thenReturn(false); + when(mcMMO.p.getPartyConfig()).thenReturn(partyConfig); + } + + private void mockExperienceConfig() { + experienceConfig = mockStatic(ExperienceConfig.class); + + when(ExperienceConfig.getInstance()).thenReturn(mock(ExperienceConfig.class)); + + // Combat + when(ExperienceConfig.getInstance().getCombatXP("Cow")).thenReturn(1D); + } + + protected void cleanUpStaticMocks() { + // 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(); + } + if (mockedBukkit != null) { + mockedBukkit.close(); + } + if (notificationManager != null) { + notificationManager.close(); + } + if (mockedSoundManager != null) { + mockedSoundManager.close(); + } + } +} diff --git a/src/test/java/com/gmail/nossr50/MMOTestEnvironmentBasic.java b/src/test/java/com/gmail/nossr50/MMOTestEnvironmentBasic.java index 106648c97..2814c270b 100644 --- a/src/test/java/com/gmail/nossr50/MMOTestEnvironmentBasic.java +++ b/src/test/java/com/gmail/nossr50/MMOTestEnvironmentBasic.java @@ -1,7 +1,15 @@ package com.gmail.nossr50; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + import com.gmail.nossr50.commands.levelup.LevelUpCommandManager; -import com.gmail.nossr50.config.*; +import com.gmail.nossr50.config.AdvancedConfig; +import com.gmail.nossr50.config.ChatConfig; +import com.gmail.nossr50.config.CommandOnLevelUpConfig; +import com.gmail.nossr50.config.GeneralConfig; +import com.gmail.nossr50.config.RankConfig; import com.gmail.nossr50.config.experience.ExperienceConfig; import com.gmail.nossr50.datatypes.experience.FormulaType; import com.gmail.nossr50.datatypes.player.McMMOPlayer; @@ -11,13 +19,17 @@ import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.events.experience.McMMOPlayerLevelUpEvent; import com.gmail.nossr50.events.experience.McMMOPlayerPreXpGainEvent; import com.gmail.nossr50.listeners.SelfListener; -import com.gmail.nossr50.util.*; +import com.gmail.nossr50.util.EventUtils; +import com.gmail.nossr50.util.Misc; +import com.gmail.nossr50.util.Permissions; +import com.gmail.nossr50.util.TransientEntityTracker; import com.gmail.nossr50.util.blockmeta.ChunkManager; import com.gmail.nossr50.util.experience.FormulaManager; import com.gmail.nossr50.util.player.NotificationManager; import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.skills.RankUtils; import com.gmail.nossr50.util.skills.SkillTools; +import java.util.UUID; import org.bukkit.Bukkit; import org.bukkit.Server; import org.bukkit.World; @@ -31,14 +43,9 @@ import org.junit.jupiter.api.BeforeEach; import org.mockito.MockedStatic; import org.mockito.Mockito; -import java.util.UUID; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - public abstract class MMOTestEnvironmentBasic { - private final java.util.logging.Logger logger = java.util.logging.Logger.getLogger(MMOTestEnvironmentBasic.class.getName()); + private final java.util.logging.Logger logger = java.util.logging.Logger.getLogger( + MMOTestEnvironmentBasic.class.getName()); protected MockedStatic mockedMcMMO; protected MockedStatic mockedBukkit; protected MockedStatic mockedChatConfig; @@ -143,7 +150,8 @@ public abstract class MMOTestEnvironmentBasic { }).when(pluginManager).callEvent(any(McMMOPlayerLevelUpEvent.class)); // Don't process pre-gain events - Mockito.doAnswer((ignored) -> null).when(pluginManager).callEvent(any(McMMOPlayerPreXpGainEvent.class)); + Mockito.doAnswer((ignored) -> null).when(pluginManager) + .callEvent(any(McMMOPlayerPreXpGainEvent.class)); // wire world this.world = mock(World.class); @@ -167,9 +175,12 @@ public abstract class MMOTestEnvironmentBasic { private void mockPermissions() { mockedPermissions = Mockito.mockStatic(Permissions.class); - when(Permissions.isSubSkillEnabled(any(Player.class), any(SubSkillType.class))).thenReturn(true); - when(Permissions.isSubSkillEnabled(any(Player.class), any(SubSkillType.class))).thenReturn(true); - when(Permissions.skillEnabled(any(Player.class), any(PrimarySkillType.class))).thenReturn(true); + when(Permissions.isSubSkillEnabled(any(Player.class), any(SubSkillType.class))).thenReturn( + true); + when(Permissions.isSubSkillEnabled(any(Player.class), any(SubSkillType.class))).thenReturn( + true); + when(Permissions.skillEnabled(any(Player.class), any(PrimarySkillType.class))).thenReturn( + true); } private void mockNotifications() { @@ -213,7 +224,8 @@ public abstract class MMOTestEnvironmentBasic { when(ExperienceConfig.getInstance().getFormulaType()).thenReturn(FormulaType.LINEAR); when(ExperienceConfig.getInstance().getBase(FormulaType.LINEAR)).thenReturn(1020); when(ExperienceConfig.getInstance().getMultiplier(FormulaType.LINEAR)).thenReturn(20D); - when(ExperienceConfig.getInstance().getFormulaSkillModifier(any(PrimarySkillType.class))).thenReturn(1D); + when(ExperienceConfig.getInstance() + .getFormulaSkillModifier(any(PrimarySkillType.class))).thenReturn(1D); when(ExperienceConfig.getInstance().getExperienceGainsGlobalMultiplier()).thenReturn(1D); when(ExperienceConfig.getInstance().getExpModifier()).thenReturn(1D); } @@ -264,7 +276,8 @@ public abstract class MMOTestEnvironmentBasic { when(player.getInventory()).thenReturn(playerInventory); // Player Profile - PlayerProfile playerProfile = Mockito.spy(new PlayerProfile(playerName, player.getUniqueId(), startingLevel)); + PlayerProfile playerProfile = Mockito.spy( + new PlayerProfile(playerName, player.getUniqueId(), startingLevel)); when(playerProfile.isLoaded()).thenReturn(true); // McMMOPlayer McMMOPlayer mmoPlayer = Mockito.spy(new McMMOPlayer(player, playerProfile)); diff --git a/src/test/java/com/gmail/nossr50/commands/levelup/LevelUpCommandTest.java b/src/test/java/com/gmail/nossr50/commands/levelup/LevelUpCommandTest.java index 6499a80ca..cebf3eee2 100644 --- a/src/test/java/com/gmail/nossr50/commands/levelup/LevelUpCommandTest.java +++ b/src/test/java/com/gmail/nossr50/commands/levelup/LevelUpCommandTest.java @@ -1,5 +1,17 @@ package com.gmail.nossr50.commands.levelup; +import static com.gmail.nossr50.datatypes.skills.PrimarySkillType.MINING; +import static com.gmail.nossr50.datatypes.skills.PrimarySkillType.WOODCUTTING; +import static java.util.Objects.requireNonNull; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.atLeast; +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + import com.gmail.nossr50.MMOTestEnvironmentBasic; import com.gmail.nossr50.datatypes.experience.XPGainReason; import com.gmail.nossr50.datatypes.experience.XPGainSource; @@ -8,6 +20,10 @@ import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.events.experience.McMMOPlayerLevelUpEvent; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.EventUtils; +import java.util.List; +import java.util.UUID; +import java.util.function.BiPredicate; +import java.util.function.Predicate; import org.bukkit.Bukkit; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -15,18 +31,6 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.Mockito; -import java.util.List; -import java.util.UUID; -import java.util.function.BiPredicate; -import java.util.function.Predicate; - -import static com.gmail.nossr50.datatypes.skills.PrimarySkillType.MINING; -import static com.gmail.nossr50.datatypes.skills.PrimarySkillType.WOODCUTTING; -import static java.util.Objects.requireNonNull; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.*; - class LevelUpCommandTest extends MMOTestEnvironmentBasic { private static final BiPredicate ALWAYS_TRUE = (skill, level) -> true; private McMMOPlayer mmoPlayer; @@ -66,9 +70,12 @@ class LevelUpCommandTest extends MMOTestEnvironmentBasic { // GIVEN assert mcMMO.p.getLevelUpCommandManager().getLevelUpCommands().isEmpty(); final String commandStr = "say hello"; - BiPredicate predicate = (skill, skillLevel) -> skill == MINING && skillLevel == 3; - BiPredicate predicate2 = (skill, skillLevel) -> skill == WOODCUTTING && skillLevel == 3; - final LevelUpCommand levelUpCommand = buildLevelUpCommand(commandStr, List.of(predicate, predicate2)); + BiPredicate predicate = (skill, skillLevel) -> skill == MINING + && skillLevel == 3; + BiPredicate predicate2 = (skill, skillLevel) -> + skill == WOODCUTTING && skillLevel == 3; + final LevelUpCommand levelUpCommand = buildLevelUpCommand(commandStr, + List.of(predicate, predicate2)); mcMMO.p.getLevelUpCommandManager().registerCommand(levelUpCommand); @@ -127,7 +134,8 @@ class LevelUpCommandTest extends MMOTestEnvironmentBasic { levelPlayerViaXP(mmoPlayer, MINING, levelsGained); // THEN the command should be checked for execution - verify(levelUpCommandManager, times(levelsGained)).applySkillLevelUp(any(), any(), any(), any()); + verify(levelUpCommandManager, times(levelsGained)).applySkillLevelUp(any(), any(), any(), + any()); verify(levelUpCommand, times(levelsGained)).process(any(), any(), any(), any()); // THEN the command should have executed @@ -155,11 +163,14 @@ class LevelUpCommandTest extends MMOTestEnvironmentBasic { final String commandStr = "say hello {@player}"; final String expectedStr = "say hello " + playerName; - final LevelUpCommand levelUpCommandOne = buildLevelUpCommand(commandStr, (skill, level) -> skill == MINING && level == 1); + final LevelUpCommand levelUpCommandOne = buildLevelUpCommand(commandStr, + (skill, level) -> skill == MINING && level == 1); mcMMO.p.getLevelUpCommandManager().registerCommand(levelUpCommandOne); - final LevelUpCommand levelUpCommandTwo = buildLevelUpCommand(commandStr, (skill, level) -> skill == MINING && level == 2); + final LevelUpCommand levelUpCommandTwo = buildLevelUpCommand(commandStr, + (skill, level) -> skill == MINING && level == 2); mcMMO.p.getLevelUpCommandManager().registerCommand(levelUpCommandTwo); - final LevelUpCommand levelUpCommandThree = buildLevelUpCommand(commandStr, (skill, level) -> skill == MINING && level == 3); + final LevelUpCommand levelUpCommandThree = buildLevelUpCommand(commandStr, + (skill, level) -> skill == MINING && level == 3); mcMMO.p.getLevelUpCommandManager().registerCommand(levelUpCommandThree); int levelsGained = 5; @@ -167,7 +178,8 @@ class LevelUpCommandTest extends MMOTestEnvironmentBasic { levelPlayerViaXP(mmoPlayer, MINING, levelsGained); // THEN the command should be checked for execution - verify(levelUpCommandManager, times(levelsGained)).applySkillLevelUp(any(), any(), any(), any()); + verify(levelUpCommandManager, times(levelsGained)).applySkillLevelUp(any(), any(), any(), + any()); verify(levelUpCommandOne, times(levelsGained)).process(any(), any(), any(), any()); verify(levelUpCommandTwo, times(levelsGained)).process(any(), any(), any(), any()); verify(levelUpCommandThree, times(levelsGained)).process(any(), any(), any(), any()); @@ -192,11 +204,14 @@ class LevelUpCommandTest extends MMOTestEnvironmentBasic { final String commandStr = "say hello {@player}"; final String expectedStr = "say hello " + playerName; - final LevelUpCommand levelUpCommandOne = buildLevelUpCommand(commandStr, (skill, level) -> skill == MINING && (level == 1 || level == 4)); + final LevelUpCommand levelUpCommandOne = buildLevelUpCommand(commandStr, + (skill, level) -> skill == MINING && (level == 1 || level == 4)); mcMMO.p.getLevelUpCommandManager().registerCommand(levelUpCommandOne); - final LevelUpCommand levelUpCommandTwo = buildLevelUpCommand(commandStr, (skill, level) -> skill == MINING && level == 2); + final LevelUpCommand levelUpCommandTwo = buildLevelUpCommand(commandStr, + (skill, level) -> skill == MINING && level == 2); mcMMO.p.getLevelUpCommandManager().registerCommand(levelUpCommandTwo); - final LevelUpCommand levelUpCommandThree = buildLevelUpCommand(commandStr, (skill, level) -> skill == MINING && level == 3); + final LevelUpCommand levelUpCommandThree = buildLevelUpCommand(commandStr, + (skill, level) -> skill == MINING && level == 3); mcMMO.p.getLevelUpCommandManager().registerCommand(levelUpCommandThree); int levelsGained = 5; @@ -204,7 +219,8 @@ class LevelUpCommandTest extends MMOTestEnvironmentBasic { levelPlayerViaXP(mmoPlayer, MINING, levelsGained); // THEN the command should be checked for execution - verify(levelUpCommandManager, times(levelsGained)).applySkillLevelUp(any(), any(), any(), any()); + verify(levelUpCommandManager, times(levelsGained)).applySkillLevelUp(any(), any(), any(), + any()); verify(levelUpCommandOne, times(levelsGained)).process(any(), any(), any(), any()); verify(levelUpCommandTwo, times(levelsGained)).process(any(), any(), any(), any()); verify(levelUpCommandThree, times(levelsGained)).process(any(), any(), any(), any()); @@ -229,7 +245,9 @@ class LevelUpCommandTest extends MMOTestEnvironmentBasic { final String expectedStr4 = "say hello " + playerName + ", you have reached level 4"; final String expectedStr5 = "say hello " + playerName + ", you have reached level 5"; - final LevelUpCommand levelUpCommand = buildLevelUpCommand(commandStr, (skill, ignored) -> skill == MINING); mcMMO.p.getLevelUpCommandManager().registerCommand(levelUpCommand); + final LevelUpCommand levelUpCommand = buildLevelUpCommand(commandStr, + (skill, ignored) -> skill == MINING); + mcMMO.p.getLevelUpCommandManager().registerCommand(levelUpCommand); // WHEN player gains 5 levels in mining int levelsGained = 5; @@ -260,12 +278,14 @@ class LevelUpCommandTest extends MMOTestEnvironmentBasic { // GIVEN level up command for Mining should always execute for Mining level up assert mcMMO.p.getLevelUpCommandManager().getLevelUpCommands().isEmpty(); final String commandStr = "say hello"; - final LevelUpCommand levelUpCommand = buildLevelUpCommand(commandStr, (skill, ignored) -> skill == MINING); + final LevelUpCommand levelUpCommand = buildLevelUpCommand(commandStr, + (skill, ignored) -> skill == MINING); mcMMO.p.getLevelUpCommandManager().registerCommand(levelUpCommand); int levelsGained = 1; // WHEN player gains 5 levels in mining - McMMOPlayerLevelUpEvent event = new McMMOPlayerLevelUpEvent(mmoPlayer.getPlayer(), MINING, levelsGained, XPGainReason.PVE); + McMMOPlayerLevelUpEvent event = new McMMOPlayerLevelUpEvent(mmoPlayer.getPlayer(), MINING, + levelsGained, XPGainReason.PVE); selfListener.onPlayerLevelUp(event); // THEN the command should be checked for execution @@ -280,13 +300,14 @@ class LevelUpCommandTest extends MMOTestEnvironmentBasic { // GIVEN level up command for Woodcutting should not execute for Mining level up assert mcMMO.p.getLevelUpCommandManager().getLevelUpCommands().isEmpty(); final String commandStr = "say hello"; - final LevelUpCommand levelUpCommand = buildLevelUpCommand(commandStr, (skill, ignored) -> skill == WOODCUTTING); + final LevelUpCommand levelUpCommand = buildLevelUpCommand(commandStr, + (skill, ignored) -> skill == WOODCUTTING); mcMMO.p.getLevelUpCommandManager().registerCommand(levelUpCommand); - int levelsGained = 5; // WHEN player gains 5 levels in mining - McMMOPlayerLevelUpEvent event = new McMMOPlayerLevelUpEvent(mmoPlayer.getPlayer(), MINING, levelsGained, XPGainReason.PVE); + McMMOPlayerLevelUpEvent event = new McMMOPlayerLevelUpEvent(mmoPlayer.getPlayer(), MINING, + levelsGained, XPGainReason.PVE); selfListener.onPlayerLevelUp(event); // THEN the command should be checked for execution @@ -308,7 +329,8 @@ class LevelUpCommandTest extends MMOTestEnvironmentBasic { levelPlayerViaXP(mmoPlayer, MINING, 10); // THEN the command should be checked for execution - verify(levelUpCommandManager, atLeastOnce()).applySkillLevelUp(any(), eq(MINING), any(), any()); + verify(levelUpCommandManager, atLeastOnce()).applySkillLevelUp(any(), eq(MINING), any(), + any()); verify(levelUpCommand, atLeastOnce()).process(any(), any(), any(), any()); // THEN the command should have executed verify(levelUpCommand, times(10)).executeCommand(any(McMMOPlayer.class)); @@ -335,8 +357,8 @@ class LevelUpCommandTest extends MMOTestEnvironmentBasic { } private LevelUpCommand buildLevelUpCommand(@NotNull String commandStr, - @NotNull List> conditions, - @Nullable Predicate powerLevelCondition) { + @NotNull List> conditions, + @Nullable Predicate powerLevelCondition) { requireNonNull(commandStr, "commandStr cannot be null"); requireNonNull(conditions, "conditions cannot be null"); final var builder = new LevelUpCommandBuilder(); @@ -350,13 +372,13 @@ class LevelUpCommandTest extends MMOTestEnvironmentBasic { } private LevelUpCommand buildLevelUpCommand(@NotNull String commandStr, - @NotNull List> conditions) { + @NotNull List> conditions) { return buildLevelUpCommand(commandStr, conditions, null); } private LevelUpCommand buildLevelUpCommand(@NotNull String commandStr, - @NotNull BiPredicate predicate, - @Nullable Predicate powerLevelCondition) { + @NotNull BiPredicate predicate, + @Nullable Predicate powerLevelCondition) { requireNonNull(commandStr, "commandStr cannot be null"); requireNonNull(predicate, "predicate cannot be null"); final var builder = new LevelUpCommandBuilder(); @@ -370,15 +392,18 @@ class LevelUpCommandTest extends MMOTestEnvironmentBasic { } private LevelUpCommand buildLevelUpCommand(@NotNull String commandStr, - @NotNull BiPredicate predicate) { + @NotNull BiPredicate predicate) { return buildLevelUpCommand(commandStr, predicate, null); } - private void levelPlayerViaXP(@NotNull McMMOPlayer mmoPlayer, @NotNull PrimarySkillType skill, int levelsGained) { - System.out.println("Leveling " + mmoPlayer.getPlayer().getName() + " up " + levelsGained + " levels in " + skill.getName()); + private void levelPlayerViaXP(@NotNull McMMOPlayer mmoPlayer, @NotNull PrimarySkillType skill, + int levelsGained) { + System.out.println("Leveling " + mmoPlayer.getPlayer().getName() + " up " + levelsGained + + " levels in " + skill.getName()); assertEquals(0, mmoPlayer.getSkillLevel(skill)); for (int i = 0; i < levelsGained; i++) { - mmoPlayer.applyXpGain(skill, mmoPlayer.getProfile().getXpToLevel(skill), XPGainReason.COMMAND, XPGainSource.COMMAND); + mmoPlayer.applyXpGain(skill, mmoPlayer.getProfile().getXpToLevel(skill), + XPGainReason.COMMAND, XPGainSource.COMMAND); } assertEquals(levelsGained, mmoPlayer.getSkillLevel(skill)); } diff --git a/src/test/java/com/gmail/nossr50/config/skills/alchemy/PotionConfigTest.java b/src/test/java/com/gmail/nossr50/config/skills/alchemy/PotionConfigTest.java new file mode 100644 index 000000000..b9b648046 --- /dev/null +++ b/src/test/java/com/gmail/nossr50/config/skills/alchemy/PotionConfigTest.java @@ -0,0 +1,69 @@ +//package com.gmail.nossr50.config.skills.alchemy; +// +//import com.gmail.nossr50.MMOTestEnvironment; +//import org.bukkit.inventory.meta.ItemMeta; +//import org.bukkit.inventory.meta.PotionMeta; +//import org.junit.jupiter.api.AfterEach; +//import org.junit.jupiter.api.BeforeEach; +//import org.junit.jupiter.api.Test; +// +//import java.io.File; +//import java.net.URL; +//import java.util.logging.Logger; +// +//import static org.junit.jupiter.api.Assertions.assertNotNull; +//import static org.mockito.ArgumentMatchers.any; +//import static org.mockito.Mockito.mock; +//import static org.mockito.Mockito.when; +// +//class PotionConfigTest extends MMOTestEnvironment { +// +// public static final String POTION_LEGACY_POTION_YML = "potion/legacy_potion.yml"; +// public static final String POTION_MODERN_YML = "potion/modern_potion.yml"; +// public static final Logger logger = Logger.getLogger(PotionConfigTest.class.getName()); +// +// @BeforeEach +// void setUp() { +// mockBaseEnvironment(logger); +// final PotionMeta potionMeta = mock(PotionMeta.class); +// when(itemFactory.getItemMeta(any())).thenReturn(potionMeta); +// } +// +// @AfterEach +// void tearDown() { +// cleanupBaseEnvironment(); +// } +// +// @Test +// void testLoadLegacyConfig() { +// final PotionConfig potionConfig = getPotionConfig(POTION_LEGACY_POTION_YML); +// assertNotNull(potionConfig); +// +// potionConfig.loadConcoctions(); +// int loaded = potionConfig.loadPotionMap(); +// System.out.println("Loaded " + loaded + " potions"); +// } +// +// @Test +// void testModernConfig() { +// final PotionConfig potionConfig = getPotionConfig(POTION_MODERN_YML); +// assertNotNull(potionConfig); +// +// potionConfig.loadConcoctions(); +// int loaded = potionConfig.loadPotionMap(); +// System.out.println("Loaded " + loaded + " potions"); +// } +// +// private PotionConfig getPotionConfig(String path) { +// // Get the file URL using the class loader +// final URL resource = getClass().getClassLoader().getResource(path); +// if (resource == null) { +// throw new IllegalArgumentException("file not found!"); +// } else { +// // Convert URL to a File object +// final File potionFile = new File(resource.getFile()); +// System.out.println("File path: " + potionFile.getAbsolutePath()); +// return new PotionConfig(potionFile); +// } +// } +//} \ No newline at end of file diff --git a/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java b/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java index f626002c1..6b8d79099 100644 --- a/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java +++ b/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java @@ -1,5 +1,14 @@ package com.gmail.nossr50.database; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.mock; + import com.gmail.nossr50.database.flatfile.LeaderboardStatus; import com.gmail.nossr50.datatypes.database.DatabaseType; import com.gmail.nossr50.datatypes.player.PlayerProfile; @@ -8,16 +17,12 @@ import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SuperAbilityType; import com.gmail.nossr50.util.skills.SkillTools; import com.google.common.io.Files; -import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -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.Mockito; - -import java.io.*; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; @@ -27,11 +32,14 @@ import java.util.UUID; import java.util.logging.Filter; import java.util.logging.LogRecord; import java.util.logging.Logger; +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.Mockito; -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,29 +47,30 @@ class FlatFileDatabaseManagerTest { public static final @NotNull String BAD_DATA_FILE_LINE_TWENTY_THREE = "nossr51:baddata:::baddata:baddata:640:baddata:1000:1000:1000:baddata:baddata:baddata:baddata:16:0:500:20273:0:0:0:0::1000:0:0:baddata:1593543012:0:0:0:0::1000:0:0:baddata:IGNORED:1000:0:588fe472-1c82-4c4e-9aa1-7eefccb277e3:1:0:"; public static final @NotNull String DB_BADDATA = "baddatadb.users"; public static final @NotNull String DB_HEALTHY = "healthydb.users"; - public static final @NotNull String HEALTHY_DB_LINE_1 = "nossr50:1:IGNORED:IGNORED:10:2:20:3:4:5:6:7:8:9:10:30:40:50:60:70:80:90:100:IGNORED:11:110:111:222:333:444:555:666:777:IGNORED:12:120:888:IGNORED:HEARTS:13:130:588fe472-1c82-4c4e-9aa1-7eefccb277e3:1111:999:2020:"; public static final @NotNull String HEALTHY_DB_LINE_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:"; private static File tempDir; private final static @NotNull Logger logger = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME); private final long PURGE_TIME = 2630000000L; - private static @Nullable FlatFileDatabaseManager db; //Making them all unique makes it easier on us to edit this stuff later 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, expectedLvlMaces = 16; 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, expectedExpMaces = 160; long expectedBerserkCd = 111, expectedGigaDrillBreakerCd = 222, expectedTreeFellerCd = 333, expectedGreenTerraCd = 444, expectedSerratedStrikesCd = 555, expectedSkullSplitterCd = 666, - expectedSuperBreakerCd = 777, expectedBlastMiningCd = 888, expectedChimaeraWingCd = 999; + expectedSuperBreakerCd = 777, expectedBlastMiningCd = 888, expectedChimaeraWingCd = 999, + expectedSuperShotgunCd = 1111, expectedTridentSuperCd = 2222, expectedExplosiveShotCd = 3333, + expectedMacesSuperCd = 4444; int expectedScoreboardTips = 1111; Long expectedLastLogin = 2020L; @@ -73,10 +82,8 @@ class FlatFileDatabaseManagerTest { @BeforeEach void init() { - assertNull(db); //noinspection UnstableApiUsage tempDir = Files.createTempDir(); - db = new FlatFileDatabaseManager(new File(getTemporaryUserFilePath()), logger, PURGE_TIME, 0, true); } private @NotNull String getTemporaryUserFilePath() { @@ -86,7 +93,6 @@ class FlatFileDatabaseManagerTest { @AfterEach void tearDown() { recursiveDelete(tempDir); - db = null; } //Nothing wrong with this database @@ -98,14 +104,16 @@ class FlatFileDatabaseManagerTest { private static final String[] badUUIDDatabaseData = { "nossr50:1000:::0:1000:640:1000:1000:1000:1000:1000:1000:1000:1000:16:0:500:0:0:0:0:0::1000:0:0:0:1593543012:0:0:0:0::1000:0:0:1593806053:HEARTS:1000:0:588fe472-1c82-4c4e-9aa1-7eefccb277e3:0:0:", - "z750: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:3:5:1600906906:", //This one has an incorrect UUID representation + "z750: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:3:5:1600906906:", + //This one has an incorrect UUID representation "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:0:HEARTS:0:0:e0d07db8-f7e8-43c7-9ded-864dfc6f3b7c:5:1600906906:" }; private static final String[] outdatedDatabaseData = { "nossr50:1000:::0:1000:640:1000:1000:1000:1000:1000:1000:1000:1000:16:0:500:0:0:0:0:0::1000:0:0:0:1593543012:0:0:0:0::1000:0:0:1593806053:HEARTS:1000:0:588fe472-1c82-4c4e-9aa1-7eefccb277e3:0:0:", "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:", - "electronicboy: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:0:HEARTS:0:0:e0d07db8-f7e8-43c7-9ded-864dfc6f3b7c:" //This user is missing data added after UUID index + "electronicboy: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:0:HEARTS:0:0:e0d07db8-f7e8-43c7-9ded-864dfc6f3b7c:" + //This user is missing data added after UUID index }; private static final String[] emptyLineDatabaseData = { @@ -148,17 +156,21 @@ class FlatFileDatabaseManagerTest { @Test void testDefaultInit() { - db = new FlatFileDatabaseManager(getTemporaryUserFilePath(), logger, PURGE_TIME, 0); + new FlatFileDatabaseManager(getTemporaryUserFilePath(), logger, PURGE_TIME, 0); } @Test void testUpdateLeaderboards() { - assertNotNull(db); - assertEquals(LeaderboardStatus.UPDATED, db.updateLeaderboards()); + FlatFileDatabaseManager flatFileDatabaseManager = new FlatFileDatabaseManager( + new File(getTemporaryUserFilePath()), logger, PURGE_TIME, 0, true); + assertNotNull(flatFileDatabaseManager); + assertEquals(LeaderboardStatus.UPDATED, flatFileDatabaseManager.updateLeaderboards()); } @Test void testSaveUser() { + FlatFileDatabaseManager flatFileDatabaseManager = new FlatFileDatabaseManager( + new File(getTemporaryUserFilePath()), logger, PURGE_TIME, 0, true); //Make a Profile to save and check to see if it worked UUID uuid = UUID.fromString("588fe472-1c82-4c4e-9aa1-7eefccb277e3"); String playerName = "nossr50"; @@ -166,16 +178,18 @@ class FlatFileDatabaseManagerTest { //The above profile should be "zero" initialized //Save the zero version and see if it looks correct - assertNotNull(db); - assertTrue(db.getUsersFile().exists()); //Users file should have been created from the above com.gmail.nossr50.database.FlatFileDatabaseManager.checkFileHealthAndStructure - assertNotNull(db.getUsersFile()); + assertNotNull(flatFileDatabaseManager); + assertTrue(flatFileDatabaseManager.getUsersFile() + .exists()); //Users file should have been created from the above com.gmail.nossr50.database.FlatFileDatabaseManager.checkFileHealthAndStructure + assertNotNull(flatFileDatabaseManager.getUsersFile()); - //The DB is empty at this point, add our user - assertTrue(db.saveUser(testProfile)); //True means we saved the user + //The flatFileDatabaseManager is empty at this point, add our user + assertTrue(flatFileDatabaseManager.saveUser(testProfile)); //True means we saved the user //Check for the empty profile - PlayerProfile retrievedFromData = db.loadPlayerProfile(uuid); - assertTrue(retrievedFromData.isLoaded()); //PlayerProfile::isLoaded returns true if the data was created from the file, false if it wasn't found and a dummy profile was returned + PlayerProfile retrievedFromData = flatFileDatabaseManager.loadPlayerProfile(uuid); + assertTrue( + retrievedFromData.isLoaded()); //PlayerProfile::isLoaded returns true if the data was created from the file, false if it wasn't found and a dummy profile was returned assertEquals(uuid, retrievedFromData.getUniqueId()); assertEquals(playerName, retrievedFromData.getPlayerName()); @@ -185,10 +199,12 @@ class FlatFileDatabaseManagerTest { String alteredName = "changedmyname"; PlayerProfile changedNameProfile = new PlayerProfile(alteredName, uuid, 0); - assertTrue(db.saveUser(changedNameProfile)); //True means we saved the user + assertTrue(flatFileDatabaseManager.saveUser( + changedNameProfile)); //True means we saved the user - retrievedFromData = db.loadPlayerProfile(uuid); - assertTrue(retrievedFromData.isLoaded()); //PlayerProfile::isLoaded returns true if the data was created from the file, false if it wasn't found and a dummy profile was returned + retrievedFromData = flatFileDatabaseManager.loadPlayerProfile(uuid); + assertTrue( + retrievedFromData.isLoaded()); //PlayerProfile::isLoaded returns true if the data was created from the file, false if it wasn't found and a dummy profile was returned assertEquals(uuid, retrievedFromData.getUniqueId()); assertEquals(alteredName, retrievedFromData.getPlayerName()); } @@ -196,50 +212,29 @@ class FlatFileDatabaseManagerTest { @Test void testAddedMissingLastLoginValues() { File dbFile = prepareDatabaseTestResource(DB_MISSING_LAST_LOGIN); - - //This makes sure our private method is working before the tests run afterwards - ArrayList dataFromFile = getSplitDataFromFile(dbFile); - logger.info("File Path: "+ dbFile.getAbsolutePath()); - assertArrayEquals(LINE_TWO_FROM_MISSING_DB.split(":"), dataFromFile.get(1)); - assertEquals(dataFromFile.get(1)[FlatFileDatabaseManager.UUID_INDEX], HEALTHY_DB_LINE_ONE_UUID_STR); - - db = new FlatFileDatabaseManager(dbFile, logger, PURGE_TIME, 0, true); - List flagsFound = db.checkFileHealthAndStructure(); + FlatFileDatabaseManager flatFileDatabaseManager = new FlatFileDatabaseManager(dbFile, + logger, PURGE_TIME, 0, true); + List flagsFound = flatFileDatabaseManager.checkFileHealthAndStructure(); assertNotNull(flagsFound); assertTrue(flagsFound.contains(FlatFileDataFlag.LAST_LOGIN_SCHEMA_UPGRADE)); //Check for the fixed value - PlayerProfile profile = db.loadPlayerProfile("nossr50"); + PlayerProfile profile = flatFileDatabaseManager.loadPlayerProfile("nossr50"); assertEquals(-1, (long) profile.getLastLogin()); } @Test void testLoadByName() { File healthyDB = prepareDatabaseTestResource(DB_HEALTHY); - - /* - * We have established the files are in good order, so now for the actual testing - */ - - //This makes sure our private method is working before the tests run afterwards - ArrayList dataFromFile = getSplitDataFromFile(healthyDB); - logger.info("File Path: "+healthyDB.getAbsolutePath()); - assertArrayEquals(HEALTHY_DB_LINE_1.split(":"), dataFromFile.get(0)); - assertEquals(dataFromFile.get(0)[FlatFileDatabaseManager.UUID_INDEX], HEALTHY_DB_LINE_ONE_UUID_STR); - UUID healthDBEntryOneUUID = UUID.fromString(HEALTHY_DB_LINE_ONE_UUID_STR); - - db = new FlatFileDatabaseManager(healthyDB, logger, PURGE_TIME, 0, true); - List flagsFound = db.checkFileHealthAndStructure(); + FlatFileDatabaseManager flatFileDatabaseManager = new FlatFileDatabaseManager(healthyDB, + logger, PURGE_TIME, 0, true); + List flagsFound = flatFileDatabaseManager.checkFileHealthAndStructure(); assertNull(flagsFound); //No flags should be found - /* - * Once the DB looks fine load the profile - */ - String playerName = "nossr50"; UUID uuid = UUID.fromString("588fe472-1c82-4c4e-9aa1-7eefccb277e3"); - PlayerProfile profile = db.loadPlayerProfile(playerName); + PlayerProfile profile = flatFileDatabaseManager.loadPlayerProfile(playerName); testHealthyDataProfileValues(playerName, uuid, profile); } @@ -250,16 +245,18 @@ class FlatFileDatabaseManagerTest { String playerName = "nossr50"; int newUserTestStartingLvl = 1337; - db = new FlatFileDatabaseManager(new File(tempDir.getPath() + File.separator + TEST_FILE_NAME), logger, PURGE_TIME, newUserTestStartingLvl, true); - db.checkFileHealthAndStructure(); + var flatFileDatabaseManager = new FlatFileDatabaseManager( + new File(tempDir.getPath() + File.separator + TEST_FILE_NAME), logger, PURGE_TIME, + newUserTestStartingLvl, true); + flatFileDatabaseManager.checkFileHealthAndStructure(); - PlayerProfile playerProfile = db.newUser(playerName, uuid); + PlayerProfile playerProfile = flatFileDatabaseManager.newUser(playerName, uuid); assertTrue(playerProfile.isLoaded()); assertEquals(playerName, playerProfile.getPlayerName()); assertEquals(uuid, playerProfile.getUniqueId()); - PlayerProfile retrievedFromDisk = db.loadPlayerProfile(uuid); + PlayerProfile retrievedFromDisk = flatFileDatabaseManager.loadPlayerProfile(uuid); assertTrue(retrievedFromDisk.isLoaded()); assertEquals(playerName, retrievedFromDisk.getPlayerName()); assertEquals(uuid, retrievedFromDisk.getUniqueId()); @@ -269,11 +266,11 @@ class FlatFileDatabaseManagerTest { checkNewUserValues(retrievedFromDisk, newUserTestStartingLvl); //TODO: Should we do any dupe checking? Probably not needed as it would be caught on the next load - db.newUser("disco", new UUID(3, 3)); - db.newUser("dingus", new UUID(3, 4)); - db.newUser("duped_dingus", new UUID(3, 4)); + flatFileDatabaseManager.newUser("disco", new UUID(3, 3)); + flatFileDatabaseManager.newUser("dingus", new UUID(3, 4)); + flatFileDatabaseManager.newUser("duped_dingus", new UUID(3, 4)); - assertEquals(5, getSplitDataFromFile(db.getUsersFile()).size()); + assertEquals(5, getSplitDataFromFile(flatFileDatabaseManager.getUsersFile()).size()); } @Test @@ -285,16 +282,17 @@ class FlatFileDatabaseManagerTest { File file = prepareDatabaseTestResource(DB_HEALTHY); //Existing DB int newUserTestStartingLvl = 1337; - db = new FlatFileDatabaseManager(file, logger, PURGE_TIME, newUserTestStartingLvl, true); - db.checkFileHealthAndStructure(); + var flatFileDatabaseManager = new FlatFileDatabaseManager(file, logger, PURGE_TIME, + newUserTestStartingLvl, true); + flatFileDatabaseManager.checkFileHealthAndStructure(); - PlayerProfile playerProfile = db.newUser(playerName, uuid); + PlayerProfile playerProfile = flatFileDatabaseManager.newUser(playerName, uuid); assertTrue(playerProfile.isLoaded()); assertEquals(playerName, playerProfile.getPlayerName()); assertEquals(uuid, playerProfile.getUniqueId()); - PlayerProfile retrievedFromDisk = db.loadPlayerProfile(uuid); + PlayerProfile retrievedFromDisk = flatFileDatabaseManager.loadPlayerProfile(uuid); assertTrue(retrievedFromDisk.isLoaded()); assertEquals(playerName, retrievedFromDisk.getPlayerName()); assertEquals(uuid, retrievedFromDisk.getUniqueId()); @@ -304,28 +302,29 @@ class FlatFileDatabaseManagerTest { checkNewUserValues(retrievedFromDisk, newUserTestStartingLvl); //TODO: Should we do any dupe checking? Probably not needed as it would be caught on the next load - db.newUser("bidoof", new UUID(3, 3)); - db.newUser("derp", new UUID(3, 4)); - db.newUser("pizza", new UUID(3, 4)); + flatFileDatabaseManager.newUser("bidoof", new UUID(3, 3)); + flatFileDatabaseManager.newUser("derp", new UUID(3, 4)); + flatFileDatabaseManager.newUser("pizza", new UUID(3, 4)); - assertEquals(7, getSplitDataFromFile(db.getUsersFile()).size()); + assertEquals(7, getSplitDataFromFile(flatFileDatabaseManager.getUsersFile()).size()); - //Now we *fix* the DB and there should be one less - db.checkFileHealthAndStructure(); - assertEquals(6, getSplitDataFromFile(db.getUsersFile()).size()); + //Now we *fix* the flatFileDatabaseManager and there should be one less + flatFileDatabaseManager.checkFileHealthAndStructure(); + assertEquals(6, getSplitDataFromFile(flatFileDatabaseManager.getUsersFile()).size()); } private void checkNewUserValues(@NotNull PlayerProfile playerProfile, int startingLevel) { //Checking a new user for being zero initialized - for(PrimarySkillType primarySkillType : PrimarySkillType.values()) { - if(SkillTools.isChildSkill(primarySkillType)) + for (PrimarySkillType primarySkillType : PrimarySkillType.values()) { + if (SkillTools.isChildSkill(primarySkillType)) { continue; + } assertEquals(startingLevel, playerProfile.getSkillLevel(primarySkillType)); assertEquals(0, playerProfile.getSkillXpLevelRaw(primarySkillType), 0); } - for(SuperAbilityType superAbilityType : SuperAbilityType.values()) { + for (SuperAbilityType superAbilityType : SuperAbilityType.values()) { assertEquals(0, playerProfile.getAbilityDATS(superAbilityType)); } @@ -337,71 +336,48 @@ class FlatFileDatabaseManagerTest { @Test void testLoadByUUID() { File dbFile = prepareDatabaseTestResource(DB_HEALTHY); - - /* - * We have established the files are in good order, so now for the actual testing - */ - - //This makes sure our private method is working before the tests run afterwards - ArrayList dataFromFile = getSplitDataFromFile(dbFile); - logger.info("File Path: " + dbFile.getAbsolutePath()); - assertArrayEquals(HEALTHY_DB_LINE_1.split(":"), dataFromFile.get(0)); - assertEquals(dataFromFile.get(0)[FlatFileDatabaseManager.UUID_INDEX], HEALTHY_DB_LINE_ONE_UUID_STR); - - db = new FlatFileDatabaseManager(dbFile, logger, PURGE_TIME, 0, true); - List flagsFound = db.checkFileHealthAndStructure(); + var flatFileDatabaseManager = new FlatFileDatabaseManager(dbFile, logger, PURGE_TIME, 0, + true); + List flagsFound = flatFileDatabaseManager.checkFileHealthAndStructure(); assertNull(flagsFound); //No flags should be found /* - * Once the DB looks fine load the profile + * Once the flatFileDatabaseManager looks fine load the profile */ String playerName = "nossr50"; UUID uuid = UUID.fromString("588fe472-1c82-4c4e-9aa1-7eefccb277e3"); - PlayerProfile profile1 = db.loadPlayerProfile(uuid); + PlayerProfile profile1 = flatFileDatabaseManager.loadPlayerProfile(uuid); testHealthyDataProfileValues(playerName, uuid, profile1); - - assertFalse(db.loadPlayerProfile(new UUID(0, 1)).isLoaded()); //This profile should not exist and therefor will return unloaded + assertFalse(flatFileDatabaseManager.loadPlayerProfile(new UUID(0, 1)) + .isLoaded()); //This profile should not exist and therefor will return unloaded } @Test void testLoadByUUIDAndName() { File dbFile = prepareDatabaseTestResource(DB_HEALTHY); - - /* - * We have established the files are in good order, so now for the actual testing - */ - - //This makes sure our private method is working before the tests run afterwards - ArrayList dataFromFile = getSplitDataFromFile(dbFile); - logger.info("File Path: " + dbFile.getAbsolutePath()); - assertArrayEquals(HEALTHY_DB_LINE_1.split(":"), dataFromFile.get(0)); - assertEquals(dataFromFile.get(0)[FlatFileDatabaseManager.UUID_INDEX], HEALTHY_DB_LINE_ONE_UUID_STR); - - db = new FlatFileDatabaseManager(dbFile, logger, PURGE_TIME, 0, true); - List flagsFound = db.checkFileHealthAndStructure(); + var flatFileDatabaseManager = new FlatFileDatabaseManager(dbFile, logger, PURGE_TIME, 0, + true); + List flagsFound = flatFileDatabaseManager.checkFileHealthAndStructure(); assertNull(flagsFound); //No flags should be found - /* - * Once the DB looks fine load the profile - */ - String playerName = "nossr50"; UUID uuid = UUID.fromString("588fe472-1c82-4c4e-9aa1-7eefccb277e3"); Player player = initMockPlayer(playerName, uuid); - PlayerProfile profile1 = db.loadPlayerProfile(player); + PlayerProfile profile1 = flatFileDatabaseManager.loadPlayerProfile(player); testHealthyDataProfileValues(playerName, uuid, profile1); String updatedName = "updatedName"; Player updatedNamePlayer = initMockPlayer(updatedName, uuid); - PlayerProfile updatedNameProfile = db.loadPlayerProfile(updatedNamePlayer); + PlayerProfile updatedNameProfile = flatFileDatabaseManager.loadPlayerProfile( + updatedNamePlayer); testHealthyDataProfileValues(updatedName, uuid, updatedNameProfile); Player shouldNotExist = initMockPlayer("doesntexist", new UUID(0, 1)); - PlayerProfile profile3 = db.loadPlayerProfile(shouldNotExist); + PlayerProfile profile3 = flatFileDatabaseManager.loadPlayerProfile(shouldNotExist); assertFalse(profile3.isLoaded()); } @@ -420,7 +396,7 @@ class FlatFileDatabaseManagerTest { assertNotNull(resourceFileURI); File copyOfFile = new File(tempDir.getPath() + File.separator + dbFileName); - if(copyOfFile.exists()) { + if (copyOfFile.exists()) { //noinspection ResultOfMethodCallIgnored copyOfFile.delete(); } @@ -438,8 +414,10 @@ class FlatFileDatabaseManagerTest { return copyOfFile; } - private void testHealthyDataProfileValues(@NotNull String playerName, @NotNull UUID uuid, @NotNull PlayerProfile profile) { - assertTrue(profile.isLoaded()); //PlayerProfile::isLoaded returns true if the data was created from the file, false if it wasn't found and a dummy profile was returned + private void testHealthyDataProfileValues(@NotNull String playerName, @NotNull UUID uuid, + @NotNull PlayerProfile profile) { + assertTrue( + profile.isLoaded()); //PlayerProfile::isLoaded returns true if the data was created from the file, false if it wasn't found and a dummy profile was returned assertEquals(uuid, profile.getUniqueId()); assertEquals(playerName, profile.getPlayerName()); @@ -447,220 +425,241 @@ class FlatFileDatabaseManagerTest { * Player is a match and data is loaded, check values */ - for(PrimarySkillType primarySkillType : PrimarySkillType.values()) { - if(SkillTools.isChildSkill(primarySkillType)) + for (PrimarySkillType primarySkillType : PrimarySkillType.values()) { + 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 - for(SuperAbilityType superAbilityType : SuperAbilityType.values()) { - assertEquals(getExpectedSuperAbilityDATS(superAbilityType), profile.getAbilityDATS(superAbilityType)); + for (SuperAbilityType superAbilityType : SuperAbilityType.values()) { + assertEquals(getExpectedSuperAbilityDATS(superAbilityType), + profile.getAbilityDATS(superAbilityType)); } - assertEquals(expectedChimaeraWingCd, profile.getUniqueData(UniqueDataType.CHIMAERA_WING_DATS)); + assertEquals(expectedChimaeraWingCd, + profile.getUniqueData(UniqueDataType.CHIMAERA_WING_DATS)); assertEquals(expectedScoreboardTips, profile.getScoreboardTipsShown()); assertEquals(expectedLastLogin, profile.getLastLogin()); } private long getExpectedSuperAbilityDATS(@NotNull SuperAbilityType superAbilityType) { - switch(superAbilityType) { - case BERSERK: - return expectedBerserkCd; - case SUPER_BREAKER: - return expectedSuperBreakerCd; - case GIGA_DRILL_BREAKER: - return expectedGigaDrillBreakerCd; - case GREEN_TERRA: - return expectedGreenTerraCd; - case SKULL_SPLITTER: - return expectedSkullSplitterCd; - case TREE_FELLER: - return expectedTreeFellerCd; - case SERRATED_STRIKES: - return expectedSerratedStrikesCd; - case BLAST_MINING: - return expectedBlastMiningCd; - } + return switch (superAbilityType) { + case BERSERK -> expectedBerserkCd; + case SUPER_BREAKER -> expectedSuperBreakerCd; + case GIGA_DRILL_BREAKER -> expectedGigaDrillBreakerCd; + case GREEN_TERRA -> expectedGreenTerraCd; + case SKULL_SPLITTER -> expectedSkullSplitterCd; + case SUPER_SHOTGUN -> expectedSuperShotgunCd; + case TREE_FELLER -> expectedTreeFellerCd; + case SERRATED_STRIKES -> expectedSerratedStrikesCd; + case BLAST_MINING -> expectedBlastMiningCd; + case TRIDENTS_SUPER_ABILITY -> expectedTridentSuperCd; + case EXPLOSIVE_SHOT -> expectedExplosiveShotCd; + case MACES_SUPER_ABILITY -> expectedMacesSuperCd; + default -> + throw new RuntimeException("Values not defined for super ability please add " + + "values for " + superAbilityType + " to the test"); + }; - return -1; } - //TODO: Why is this stuff a float? - private float getExpectedExperienceHealthyDBEntryOne(@NotNull PrimarySkillType primarySkillType) { - switch(primarySkillType) { - case ACROBATICS: - return expectedExpAcrobatics; - case ALCHEMY: - return expectedExpAlchemy; - case ARCHERY: - return expectedExpArchery; - case AXES: - return expectedExpAxes; - case EXCAVATION: - return expectedExpExcavation; - case FISHING: - return expectedExpFishing; - case HERBALISM: - return expectedExpHerbalism; - case MINING: - return expectedExpMining; - case REPAIR: - return expectedExpRepair; - case SALVAGE: - case SMELTING: - return 0; - case SWORDS: - return expectedExpSwords; - case TAMING: - return expectedExpTaming; - case UNARMED: - return expectedExpUnarmed; - case WOODCUTTING: - return expectedExpWoodcutting; - } + private float getExpectedExperienceHealthyDBEntryOne( + @NotNull PrimarySkillType primarySkillType) { + return switch (primarySkillType) { + case ACROBATICS -> expectedExpAcrobatics; + case ALCHEMY -> expectedExpAlchemy; + case ARCHERY -> expectedExpArchery; + case AXES -> expectedExpAxes; + case CROSSBOWS -> expectedExpCrossbows; + case EXCAVATION -> expectedExpExcavation; + case FISHING -> expectedExpFishing; + case HERBALISM -> expectedExpHerbalism; + case MINING -> expectedExpMining; + case REPAIR -> expectedExpRepair; + case SALVAGE, SMELTING -> 0; + case SWORDS -> expectedExpSwords; + case TAMING -> expectedExpTaming; + case TRIDENTS -> expectedExpTridents; + case UNARMED -> expectedExpUnarmed; + case WOODCUTTING -> expectedExpWoodcutting; + case MACES -> expectedExpMaces; + default -> throw new RuntimeException( + "Values for skill not defined, please add values for " + + primarySkillType + " to the test"); + }; - return -1; } private int getExpectedLevelHealthyDBEntryOne(@NotNull PrimarySkillType primarySkillType) { - switch(primarySkillType) { - case ACROBATICS: - return expectedLvlAcrobatics; - case ALCHEMY: - return expectedLvlAlchemy; - case ARCHERY: - return expectedLvlArchery; - case AXES: - return expectedLvlAxes; - case EXCAVATION: - return expectedLvlExcavation; - case FISHING: - return expectedLvlFishing; - case HERBALISM: - return expectedLvlHerbalism; - case MINING: - return expectedLvlMining; - case REPAIR: - return expectedLvlRepair; - case SALVAGE: - case SMELTING: - return 0; - case SWORDS: - return expectedLvlSwords; - case TAMING: - return expectedLvlTaming; - case UNARMED: - return expectedLvlUnarmed; - case WOODCUTTING: - return expectedLvlWoodcutting; - } + return switch (primarySkillType) { + case ACROBATICS -> expectedLvlAcrobatics; + case ALCHEMY -> expectedLvlAlchemy; + case ARCHERY -> expectedLvlArchery; + case AXES -> expectedLvlAxes; + case CROSSBOWS -> expectedLvlCrossbows; + case EXCAVATION -> expectedLvlExcavation; + case FISHING -> expectedLvlFishing; + case HERBALISM -> expectedLvlHerbalism; + case MINING -> expectedLvlMining; + case REPAIR -> expectedLvlRepair; + case SALVAGE, SMELTING -> 0; + case SWORDS -> expectedLvlSwords; + case TAMING -> expectedLvlTaming; + case TRIDENTS -> expectedLvlTridents; + case UNARMED -> expectedLvlUnarmed; + case WOODCUTTING -> expectedLvlWoodcutting; + case MACES -> expectedLvlMaces; + default -> throw new RuntimeException( + "Values for skill not defined, please add values for " + + primarySkillType + " to the test"); + }; - return -1; } @Test void testOverwriteName() { - overwriteDataAndCheckForFlag(db, duplicateNameDatabaseData, FlatFileDataFlag.DUPLICATE_NAME); - ArrayList splitDataLines = getSplitDataFromFile(db.getUsersFile()); + FlatFileDatabaseManager flatFileDatabaseManager = new FlatFileDatabaseManager( + new File(getTemporaryUserFilePath()), logger, PURGE_TIME, 0, true); + overwriteDataAndCheckForFlag(flatFileDatabaseManager, duplicateNameDatabaseData, + FlatFileDataFlag.DUPLICATE_NAME); + ArrayList splitDataLines = getSplitDataFromFile( + flatFileDatabaseManager.getUsersFile()); assertNotEquals(splitDataLines.get(1)[0], splitDataLines.get(0)[0]); //Name comparison } @Test void testDataNotFound() { + FlatFileDatabaseManager flatFileDatabaseManager = new FlatFileDatabaseManager( + new File(getTemporaryUserFilePath()), logger, PURGE_TIME, 0, true); //Save the zero version and see if it looks correct - assertNotNull(db); - assertTrue(db.getUsersFile().exists()); - assertNotNull(db.getUsersFile()); + assertNotNull(flatFileDatabaseManager); + assertTrue(flatFileDatabaseManager.getUsersFile().exists()); + assertNotNull(flatFileDatabaseManager.getUsersFile()); //Check for the "unloaded" profile - PlayerProfile retrievedFromData = db.loadPlayerProfile("nossr50"); - assertFalse(retrievedFromData.isLoaded()); //PlayerProfile::isLoaded returns false if data doesn't exist for the user + PlayerProfile retrievedFromData = flatFileDatabaseManager.loadPlayerProfile("nossr50"); + assertFalse( + retrievedFromData.isLoaded()); //PlayerProfile::isLoaded returns false if data doesn't exist for the user } @Test void testPurgePowerlessUsers() { - replaceDataInFile(db, normalDatabaseData); - int purgeCount = db.purgePowerlessUsers(); + FlatFileDatabaseManager flatFileDatabaseManager = new FlatFileDatabaseManager( + new File(getTemporaryUserFilePath()), logger, PURGE_TIME, 0, true); + replaceDataInFile(flatFileDatabaseManager, normalDatabaseData); + int purgeCount = flatFileDatabaseManager.purgePowerlessUsers(); assertEquals(purgeCount, 1); //1 User should have been purged } @Test void testCheckFileHealthAndStructure() { - replaceDataInFile(db, badDatabaseData); + FlatFileDatabaseManager flatFileDatabaseManager = new FlatFileDatabaseManager( + new File(getTemporaryUserFilePath()), logger, PURGE_TIME, 0, true); + replaceDataInFile(flatFileDatabaseManager, badDatabaseData); - List dataFlags = db.checkFileHealthAndStructure(); + List dataFlags = flatFileDatabaseManager.checkFileHealthAndStructure(); assertNotNull(dataFlags); assertNotEquals(dataFlags.size(), 0); } @Test void testFindFixableDuplicateNames() { - overwriteDataAndCheckForFlag(db, duplicateNameDatabaseData, FlatFileDataFlag.DUPLICATE_NAME); + FlatFileDatabaseManager flatFileDatabaseManager = new FlatFileDatabaseManager( + new File(getTemporaryUserFilePath()), logger, PURGE_TIME, 0, true); + overwriteDataAndCheckForFlag(flatFileDatabaseManager, duplicateNameDatabaseData, + FlatFileDataFlag.DUPLICATE_NAME); } @Test void testFindDuplicateUUIDs() { - overwriteDataAndCheckForFlag(db, duplicateUUIDDatabaseData, FlatFileDataFlag.DUPLICATE_UUID); + FlatFileDatabaseManager flatFileDatabaseManager = new FlatFileDatabaseManager( + new File(getTemporaryUserFilePath()), logger, PURGE_TIME, 0, true); + overwriteDataAndCheckForFlag(flatFileDatabaseManager, duplicateUUIDDatabaseData, + FlatFileDataFlag.DUPLICATE_UUID); } @Test() void findBadUUIDData() { - overwriteDataAndCheckForFlag(db, badUUIDDatabaseData, FlatFileDataFlag.BAD_UUID_DATA); + FlatFileDatabaseManager flatFileDatabaseManager = new FlatFileDatabaseManager( + new File(getTemporaryUserFilePath()), logger, PURGE_TIME, 0, true); + overwriteDataAndCheckForFlag(flatFileDatabaseManager, badUUIDDatabaseData, + FlatFileDataFlag.BAD_UUID_DATA); } @Test void testFindCorruptData() { - overwriteDataAndCheckForFlag(db, corruptDatabaseData, FlatFileDataFlag.CORRUPTED_OR_UNRECOGNIZABLE); + FlatFileDatabaseManager flatFileDatabaseManager = new FlatFileDatabaseManager( + new File(getTemporaryUserFilePath()), logger, PURGE_TIME, 0, true); + overwriteDataAndCheckForFlag(flatFileDatabaseManager, corruptDatabaseData, + FlatFileDataFlag.CORRUPTED_OR_UNRECOGNIZABLE); } @Test void testFindEmptyNames() { - overwriteDataAndCheckForFlag(db, emptyNameDatabaseData, FlatFileDataFlag.MISSING_NAME); + FlatFileDatabaseManager flatFileDatabaseManager = new FlatFileDatabaseManager( + new File(getTemporaryUserFilePath()), logger, PURGE_TIME, 0, true); + overwriteDataAndCheckForFlag(flatFileDatabaseManager, emptyNameDatabaseData, + FlatFileDataFlag.MISSING_NAME); } @Test void testFindBadValues() { - overwriteDataAndCheckForFlag(db, badDatabaseData, FlatFileDataFlag.BAD_VALUES); + FlatFileDatabaseManager flatFileDatabaseManager = new FlatFileDatabaseManager( + new File(getTemporaryUserFilePath()), logger, PURGE_TIME, 0, true); + overwriteDataAndCheckForFlag(flatFileDatabaseManager, badDatabaseData, + FlatFileDataFlag.BAD_VALUES); } @Test void testFindOutdatedData() { - overwriteDataAndCheckForFlag(db, outdatedDatabaseData, FlatFileDataFlag.INCOMPLETE); + FlatFileDatabaseManager flatFileDatabaseManager = new FlatFileDatabaseManager( + new File(getTemporaryUserFilePath()), logger, PURGE_TIME, 0, true); + overwriteDataAndCheckForFlag(flatFileDatabaseManager, outdatedDatabaseData, + FlatFileDataFlag.INCOMPLETE); } @Test void testGetDatabaseType() { - assertNotNull(db); - assertEquals(db.getDatabaseType(), DatabaseType.FLATFILE); + FlatFileDatabaseManager flatFileDatabaseManager = new FlatFileDatabaseManager( + new File(getTemporaryUserFilePath()), logger, PURGE_TIME, 0, true); + assertNotNull(flatFileDatabaseManager); + assertEquals(flatFileDatabaseManager.getDatabaseType(), DatabaseType.FLATFILE); } @Test void testReadRank() { //This is an empty DB - assertNotNull(db); + FlatFileDatabaseManager flatFileDatabaseManager = new FlatFileDatabaseManager( + new File(getTemporaryUserFilePath()), logger, PURGE_TIME, 0, true); String rankBoyName = "rankBoy"; UUID rankBoyUUID = new UUID(1337, 1337); String rankGirlName = "rankGirl"; UUID rankGirlUUID = new UUID(7331, 7331); - PlayerProfile rankGirlProfile = addPlayerProfileWithLevelsAndSave(rankGirlName, rankGirlUUID, 100); //Rank 1 - PlayerProfile rankBoyProfile = addPlayerProfileWithLevelsAndSave(rankBoyName, rankBoyUUID, 10); //Rank 2 + PlayerProfile rankGirlProfile = addPlayerProfileWithLevelsAndSave(rankGirlName, + rankGirlUUID, 100); //Rank 1 + PlayerProfile rankBoyProfile = addPlayerProfileWithLevelsAndSave(rankBoyName, rankBoyUUID, + 10); //Rank 2 - assertEquals(LeaderboardStatus.UPDATED, db.updateLeaderboards()); - Map rankGirlPositions = db.readRank(rankGirlName); - Map rankBoyPositions = db.readRank(rankBoyName); + assertEquals(LeaderboardStatus.UPDATED, flatFileDatabaseManager.updateLeaderboards()); + Map rankGirlPositions = flatFileDatabaseManager.readRank( + rankGirlName); + Map rankBoyPositions = flatFileDatabaseManager.readRank( + rankBoyName); - for(PrimarySkillType primarySkillType : PrimarySkillType.values()) { - if(primarySkillType.isChildSkill()) { + for (PrimarySkillType primarySkillType : PrimarySkillType.values()) { + if (primarySkillType.isChildSkill()) { assertNull(rankBoyPositions.get(primarySkillType)); assertNull(rankGirlPositions.get(primarySkillType)); } else { @@ -669,8 +668,10 @@ class FlatFileDatabaseManagerTest { } } - assertEquals(1, db.readRank(rankGirlName).get(null)); //Girl should be position 1 - assertEquals(2, db.readRank(rankBoyName).get(null)); //Boy should be position 2 + assertEquals(1, flatFileDatabaseManager.readRank(rankGirlName) + .get(null)); //Girl should be position 1 + assertEquals(2, + flatFileDatabaseManager.readRank(rankBoyName).get(null)); //Boy should be position 2 } @Test @@ -689,7 +690,7 @@ class FlatFileDatabaseManagerTest { assertNotNull(resourceFileURI); File copyOfFile = new File(tempDir.getPath() + File.separator + DB_BADDATA); - if(copyOfFile.exists()) { + if (copyOfFile.exists()) { copyOfFile.delete(); } @@ -705,12 +706,13 @@ class FlatFileDatabaseManagerTest { //This makes sure our private method is working before the tests run afterwards ArrayList dataFromFile = getSplitDataFromFile(copyOfFile); - logger.info("File Path: "+copyOfFile.getAbsolutePath()); + logger.info("File Path: " + copyOfFile.getAbsolutePath()); assertArrayEquals(BAD_FILE_LINE_ONE.split(":"), dataFromFile.get(0)); assertEquals(dataFromFile.get(22)[0], "nossr51"); assertArrayEquals(BAD_DATA_FILE_LINE_TWENTY_THREE.split(":"), dataFromFile.get(22)); - FlatFileDatabaseManager db_a = new FlatFileDatabaseManager(copyOfFile, logger, PURGE_TIME, 0, true); + FlatFileDatabaseManager db_a = new FlatFileDatabaseManager(copyOfFile, logger, PURGE_TIME, + 0, true); List flagsFound = db_a.checkFileHealthAndStructure(); assertNotNull(flagsFound); assertTrue(flagsFound.contains(FlatFileDataFlag.BAD_VALUES)); @@ -723,8 +725,9 @@ class FlatFileDatabaseManagerTest { String line; while ((line = bufferedReader.readLine()) != null) { - if (line.isEmpty()) + if (line.isEmpty()) { continue; + } String[] splitData = line.split(":"); splitDataList.add(splitData); @@ -737,29 +740,33 @@ class FlatFileDatabaseManagerTest { return splitDataList; } - private @NotNull PlayerProfile addPlayerProfileWithLevelsAndSave(String playerName, UUID uuid, int levels) { - assertNotNull(db); - assertFalse(db.loadPlayerProfile(uuid).isLoaded()); + private @NotNull PlayerProfile addPlayerProfileWithLevelsAndSave(String playerName, UUID uuid, + int levels) { + FlatFileDatabaseManager flatFileDatabaseManager = new FlatFileDatabaseManager( + new File(getTemporaryUserFilePath()), logger, PURGE_TIME, 0, true); + assertFalse(flatFileDatabaseManager.loadPlayerProfile(uuid).isLoaded()); - db.newUser(playerName, uuid); - PlayerProfile leveledProfile = db.loadPlayerProfile(uuid); + flatFileDatabaseManager.newUser(playerName, uuid); + PlayerProfile leveledProfile = flatFileDatabaseManager.loadPlayerProfile(uuid); assertTrue(leveledProfile.isLoaded()); assertEquals(playerName, leveledProfile.getPlayerName()); assertEquals(uuid, leveledProfile.getUniqueId()); - for(PrimarySkillType primarySkillType : PrimarySkillType.values()) { - if(SkillTools.isChildSkill(primarySkillType)) + for (PrimarySkillType primarySkillType : PrimarySkillType.values()) { + if (SkillTools.isChildSkill(primarySkillType)) { continue; + } - leveledProfile.modifySkill(primarySkillType, levels); //TODO: This method also resets XP, not cool + leveledProfile.modifySkill(primarySkillType, + levels); //TODO: This method also resets XP, not cool } - db.saveUser(leveledProfile); - leveledProfile = db.loadPlayerProfile(uuid); + flatFileDatabaseManager.saveUser(leveledProfile); + leveledProfile = flatFileDatabaseManager.loadPlayerProfile(uuid); - for(PrimarySkillType primarySkillType : PrimarySkillType.values()) { - if(SkillTools.isChildSkill(primarySkillType)) { + for (PrimarySkillType primarySkillType : PrimarySkillType.values()) { + if (SkillTools.isChildSkill(primarySkillType)) { continue; } @@ -769,7 +776,8 @@ class FlatFileDatabaseManagerTest { return leveledProfile; } - private void replaceDataInFile(@NotNull FlatFileDatabaseManager flatFileDatabaseManager, @NotNull String[] dataEntries) { + private void replaceDataInFile(@NotNull FlatFileDatabaseManager flatFileDatabaseManager, + @NotNull String[] dataEntries) { String filePath = flatFileDatabaseManager.getUsersFile().getAbsolutePath(); BufferedReader in = null; FileWriter out = null; @@ -777,7 +785,7 @@ class FlatFileDatabaseManagerTest { try { StringBuilder writer = new StringBuilder(); - for(String data : dataEntries) { + for (String data : dataEntries) { writer.append(data).append("\r\n"); } @@ -792,15 +800,15 @@ class FlatFileDatabaseManagerTest { if (out != null) { try { out.close(); - } - catch (IOException e) { + } catch (IOException e) { // Ignore } } } try { - logger.info("Added the following lines to the FlatFileDatabase for the purposes of the test..."); + logger.info( + "Added the following lines to the FlatFileDatabase for the purposes of the test..."); // Open the file in = new BufferedReader(new FileReader(filePath)); String line; @@ -813,15 +821,15 @@ class FlatFileDatabaseManagerTest { if (in != null) { try { in.close(); - } - catch (IOException e) { + } catch (IOException e) { // Ignore } } } } - private void overwriteDataAndCheckForFlag(@NotNull FlatFileDatabaseManager targetDatabase, @NotNull String[] data, @NotNull FlatFileDataFlag flag) { + private void overwriteDataAndCheckForFlag(@NotNull FlatFileDatabaseManager targetDatabase, + @NotNull String[] data, @NotNull FlatFileDataFlag flag) { replaceDataInFile(targetDatabase, data); List dataFlags = targetDatabase.checkFileHealthAndStructure(); 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 000000000..959777ab9 --- /dev/null +++ b/src/test/java/com/gmail/nossr50/database/SQLDatabaseManagerTest.java @@ -0,0 +1,245 @@ +//package com.gmail.nossr50.database; +// +//import com.gmail.nossr50.config.AdvancedConfig; +//import com.gmail.nossr50.config.GeneralConfig; +//import com.gmail.nossr50.datatypes.MobHealthbarType; +//import com.gmail.nossr50.datatypes.player.PlayerProfile; +//import com.gmail.nossr50.datatypes.skills.PrimarySkillType; +//import com.gmail.nossr50.mcMMO; +//import com.gmail.nossr50.util.compat.CompatibilityManager; +//import com.gmail.nossr50.util.platform.MinecraftGameVersion; +//import com.gmail.nossr50.util.skills.SkillTools; +//import com.gmail.nossr50.util.upgrade.UpgradeManager; +//import org.bukkit.entity.Player; +//import org.jetbrains.annotations.NotNull; +//import org.junit.jupiter.api.*; +//import org.mockito.MockedStatic; +//import org.mockito.Mockito; +// +//import java.util.logging.Logger; +// +//import static org.junit.jupiter.api.Assertions.*; +//import static org.mockito.ArgumentMatchers.any; +//import static org.mockito.Mockito.when; +// +//class SQLDatabaseManagerTest { +// private final static @NotNull Logger logger = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME); +// static MockedStatic mockedMcMMO; +// SQLDatabaseManager sqlDatabaseManager; +// static GeneralConfig generalConfig; +// static AdvancedConfig advancedConfig; +// static UpgradeManager upgradeManager; +// static CompatibilityManager compatibilityManager; +// static SkillTools skillTools; +// +// @BeforeAll +// static void setUpAll() { +// // stub mcMMO.p +// mockedMcMMO = Mockito.mockStatic(mcMMO.class); +// mcMMO.p = Mockito.mock(mcMMO.class); +// when(mcMMO.p.getLogger()).thenReturn(logger); +// +// // general config mock +// mockGeneralConfig(); +// +// // advanced config mock +// advancedConfig = Mockito.mock(AdvancedConfig.class); +// when(mcMMO.p.getAdvancedConfig()).thenReturn(advancedConfig); +// +// // starting level +// when(mcMMO.p.getAdvancedConfig().getStartingLevel()).thenReturn(0); +// +// // wire skill tools +// skillTools = new SkillTools(mcMMO.p); +// when(mcMMO.p.getSkillTools()).thenReturn(skillTools); +// +// // compatibility manager mock +// compatibilityManager = Mockito.mock(CompatibilityManager.class); +// when(mcMMO.getCompatibilityManager()).thenReturn(compatibilityManager); +// when(compatibilityManager.getMinecraftGameVersion()).thenReturn(new MinecraftGameVersion(1, 20, 4)); +// +// // upgrade manager mock +// upgradeManager = Mockito.mock(UpgradeManager.class); +// when(mcMMO.getUpgradeManager()).thenReturn(upgradeManager); +// +// // don't trigger upgrades +// when(mcMMO.getUpgradeManager().shouldUpgrade(any())).thenReturn(false); +// } +// +// private static void mockGeneralConfig() { +// generalConfig = Mockito.mock(GeneralConfig.class); +// when(generalConfig.getLocale()).thenReturn("en_US"); +// when(mcMMO.p.getGeneralConfig()).thenReturn(generalConfig); +// +// // max pool size +// when(mcMMO.p.getGeneralConfig().getMySQLMaxPoolSize(SQLDatabaseManager.PoolIdentifier.MISC)) +// .thenReturn(10); +// when(mcMMO.p.getGeneralConfig().getMySQLMaxPoolSize(SQLDatabaseManager.PoolIdentifier.LOAD)) +// .thenReturn(20); +// when(mcMMO.p.getGeneralConfig().getMySQLMaxPoolSize(SQLDatabaseManager.PoolIdentifier.SAVE)) +// .thenReturn(20); +// +// // max connections +// when(mcMMO.p.getGeneralConfig().getMySQLMaxConnections(SQLDatabaseManager.PoolIdentifier.MISC)) +// .thenReturn(30); +// when(mcMMO.p.getGeneralConfig().getMySQLMaxConnections(SQLDatabaseManager.PoolIdentifier.LOAD)) +// .thenReturn(30); +// when(mcMMO.p.getGeneralConfig().getMySQLMaxConnections(SQLDatabaseManager.PoolIdentifier.SAVE)) +// .thenReturn(30); +// +// // table prefix +// when(mcMMO.p.getGeneralConfig().getMySQLTablePrefix()).thenReturn("mcmmo_"); +// +// // public key retrieval +// when(mcMMO.p.getGeneralConfig().getMySQLPublicKeyRetrieval()).thenReturn(true); +// +// // debug +// when(mcMMO.p.getGeneralConfig().getMySQLDebug()).thenReturn(true); +// +// // use mysql +// when(mcMMO.p.getGeneralConfig().getUseMySQL()).thenReturn(true); +// +// // use ssl +// when(mcMMO.p.getGeneralConfig().getMySQLSSL()).thenReturn(true); +// +// // username +// when(mcMMO.p.getGeneralConfig().getMySQLUserName()).thenReturn("sa"); +// +// // password +// when(mcMMO.p.getGeneralConfig().getMySQLUserPassword()).thenReturn(""); +// +// // host +// when(mcMMO.p.getGeneralConfig().getMySQLServerName()).thenReturn("localhost"); +// +// // unused mob health bar thingy +// when(mcMMO.p.getGeneralConfig().getMobHealthbarDefault()).thenReturn(MobHealthbarType.HEARTS); +// } +// +// @BeforeEach +// void setUp() { +// assertNull(sqlDatabaseManager); +// sqlDatabaseManager = new SQLDatabaseManager(logger, "org.h2.Driver", true); +// } +// +// @AfterEach +// void tearDown() { +// sqlDatabaseManager = null; +// } +// +// @AfterAll +// static void tearDownAll() { +// mockedMcMMO.close(); +// } +// +// @Test +// void testGetConnectionMisc() throws Exception { +// assertNotNull(sqlDatabaseManager.getConnection(SQLDatabaseManager.PoolIdentifier.MISC)); +// } +// +// @Test +// void testGetConnectionLoad() throws Exception { +// assertNotNull(sqlDatabaseManager.getConnection(SQLDatabaseManager.PoolIdentifier.LOAD)); +// } +// +// @Test +// void testGetConnectionSave() throws Exception { +// assertNotNull(sqlDatabaseManager.getConnection(SQLDatabaseManager.PoolIdentifier.SAVE)); +// } +// +// @Test +// void testNewUser() { +// Player player = Mockito.mock(Player.class); +// when(player.getUniqueId()).thenReturn(java.util.UUID.randomUUID()); +// when(player.getName()).thenReturn("nossr50"); +// sqlDatabaseManager.newUser(player); +// } +// +// @Test +// void testNewUserGetSkillLevel() { +// Player player = Mockito.mock(Player.class); +// when(player.getUniqueId()).thenReturn(java.util.UUID.randomUUID()); +// when(player.getName()).thenReturn("nossr50"); +// PlayerProfile playerProfile = sqlDatabaseManager.newUser(player); +// +// for (PrimarySkillType primarySkillType : PrimarySkillType.values()) { +// assertEquals(0, playerProfile.getSkillLevel(primarySkillType)); +// } +// } +// +// @Test +// void testNewUserGetSkillXpLevel() { +// Player player = Mockito.mock(Player.class); +// when(player.getUniqueId()).thenReturn(java.util.UUID.randomUUID()); +// when(player.getName()).thenReturn("nossr50"); +// PlayerProfile playerProfile = sqlDatabaseManager.newUser(player); +// +// for (PrimarySkillType primarySkillType : PrimarySkillType.values()) { +// assertEquals(0, playerProfile.getSkillXpLevel(primarySkillType)); +// } +// } +// +// @Test +// void testSaveSkillLevelValues() { +// Player player = Mockito.mock(Player.class); +// when(player.getUniqueId()).thenReturn(java.util.UUID.randomUUID()); +// when(player.getName()).thenReturn("nossr50"); +// PlayerProfile playerProfile = sqlDatabaseManager.newUser(player); +// +// // Validate values are starting from zero +// for (PrimarySkillType primarySkillType : PrimarySkillType.values()) { +// assertEquals(0, playerProfile.getSkillXpLevel(primarySkillType)); +// } +// +// // Change values +// for (PrimarySkillType primarySkillType : PrimarySkillType.values()) { +// playerProfile.modifySkill(primarySkillType, 1 + primarySkillType.ordinal()); +// } +// +// boolean saveSuccess = sqlDatabaseManager.saveUser(playerProfile); +// assertTrue(saveSuccess); +// +// PlayerProfile retrievedUser = sqlDatabaseManager.loadPlayerProfile(player.getName()); +// +// // Check that values got saved +// for (PrimarySkillType primarySkillType : PrimarySkillType.values()) { +// if (primarySkillType == PrimarySkillType.SALVAGE || primarySkillType == PrimarySkillType.SMELTING) { +// // Child skills are not saved, but calculated +// continue; +// } +// +// assertEquals(1 + primarySkillType.ordinal(), retrievedUser.getSkillLevel(primarySkillType)); +// } +// } +// +// @Test +// void testSaveSkillXpValues() { +// Player player = Mockito.mock(Player.class); +// when(player.getUniqueId()).thenReturn(java.util.UUID.randomUUID()); +// when(player.getName()).thenReturn("nossr50"); +// PlayerProfile playerProfile = sqlDatabaseManager.newUser(player); +// +// // Validate values are starting from zero +// for (PrimarySkillType primarySkillType : PrimarySkillType.values()) { +// assertEquals(0, playerProfile.getSkillXpLevel(primarySkillType)); +// } +// +// // Change values +// for (PrimarySkillType primarySkillType : PrimarySkillType.values()) { +// playerProfile.setSkillXpLevel(primarySkillType, 1 + primarySkillType.ordinal()); +// } +// +// sqlDatabaseManager.saveUser(playerProfile); +// +// PlayerProfile retrievedUser = sqlDatabaseManager.loadPlayerProfile(player.getName()); +// +// // Check that values got saved +// for (PrimarySkillType primarySkillType : PrimarySkillType.values()) { +// if (primarySkillType == PrimarySkillType.SALVAGE || primarySkillType == PrimarySkillType.SMELTING) { +// // Child skills are not saved, but calculated +// continue; +// } +// +// assertEquals(1 + primarySkillType.ordinal(), retrievedUser.getSkillXpLevel(primarySkillType)); +// } +// } +//} diff --git a/src/test/java/com/gmail/nossr50/database/flatfile/FlatFileDataUtilTest.java b/src/test/java/com/gmail/nossr50/database/flatfile/FlatFileDataUtilTest.java index db7fad9f5..399709a1c 100644 --- a/src/test/java/com/gmail/nossr50/database/flatfile/FlatFileDataUtilTest.java +++ b/src/test/java/com/gmail/nossr50/database/flatfile/FlatFileDataUtilTest.java @@ -1,11 +1,10 @@ package com.gmail.nossr50.database.flatfile; import com.gmail.nossr50.database.FlatFileDatabaseManager; +import java.util.HashSet; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import java.util.HashSet; - class FlatFileDataUtilTest { @Test @@ -26,7 +25,8 @@ class FlatFileDataUtilTest { @Test void testTooManyDataEntriesSplitString() { Assertions.assertThrows(AssertionError.class, () -> { - FlatFileDataContainer dataContainer = new CategorizedFlatFileData(0, new HashSet<>(), new String[FlatFileDatabaseManager.DATA_ENTRY_COUNT + 1]); + FlatFileDataContainer dataContainer = new CategorizedFlatFileData(0, new HashSet<>(), + new String[FlatFileDatabaseManager.DATA_ENTRY_COUNT + 1]); FlatFileDataUtil.getPreparedSaveDataLine(dataContainer); }); } diff --git a/src/test/java/com/gmail/nossr50/locale/LocaleLoaderTest.java b/src/test/java/com/gmail/nossr50/locale/LocaleLoaderTest.java new file mode 100644 index 000000000..d1e149f4e --- /dev/null +++ b/src/test/java/com/gmail/nossr50/locale/LocaleLoaderTest.java @@ -0,0 +1,76 @@ +package com.gmail.nossr50.locale; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.List; +import org.bukkit.ChatColor; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class LocaleLoaderTest { + + @BeforeEach + void setUp() { + } + + @AfterEach + void tearDown() { + } + + @ParameterizedTest + @ValueSource(strings = {"§cTest", "[[RED]]Test"}) + void addColorsShouldAddColorRed(String testString) { + // When + final String result = LocaleLoader.addColors(testString); + + // Then + assertThat(result).isEqualTo(ChatColor.RED + "Test"); + } + + // hex colors test + @Test + void translateHexColorCodesShouldAddRed() { + // Given + final String testString = "&#FF0000Test"; + + // When + final String result = LocaleLoader.translateHexColorCodes(testString); + + // Then + final String expectedResult = "§x§F§F§0§0§0§0Test"; + assertThat(result).isEqualTo(expectedResult); + } + + @Test + void reverseTranslateHexColorCodesShouldRemoveRed() { + // Given + final String testString = "§x§F§F§0§0§0§0Test"; + + // When + final String result = LocaleLoader.reverseTranslateHexColorCodes(testString); + + // Then + final String expectedResult = "&#FF0000Test"; + assertThat(result).isEqualTo(expectedResult); + } + + @ParameterizedTest + @ValueSource(strings = {"&#FF0000Te�FFst", "&#FF0000Te[[RED]]st", "[[BLUE]]Te[[RED]]st", + "§9Te§cst"}) + void addColorsShouldAddRedAndBlue(String testString) { + // When + final String result = LocaleLoader.addColors(testString); + + // TODO: Hacky, clean this up sometime in the future + // Then + // All legal representations of the same string + final List expectedResults = List.of("§x§F§F§0§0§0§0Te§x§0§0§0§0§F§Fst", + "§x§F§F§0§0§0§0Te§x§0§0§0§0§F§Fst", + "§x§F§F§0§0§0§0Te§cst", + "§9Te§cst"); + assertThat(expectedResults).contains(result); + } +} \ No newline at end of file diff --git a/src/test/java/com/gmail/nossr50/party/PartyManagerTest.java b/src/test/java/com/gmail/nossr50/party/PartyManagerTest.java new file mode 100644 index 000000000..2cb0e426b --- /dev/null +++ b/src/test/java/com/gmail/nossr50/party/PartyManagerTest.java @@ -0,0 +1,315 @@ +package com.gmail.nossr50.party; + +import static java.util.logging.Logger.getLogger; +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.contains; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import com.gmail.nossr50.MMOTestEnvironment; +import com.gmail.nossr50.datatypes.interactions.NotificationType; +import com.gmail.nossr50.datatypes.party.Party; +import com.gmail.nossr50.datatypes.party.PartyLeader; +import com.gmail.nossr50.datatypes.player.McMMOPlayer; +import com.gmail.nossr50.mcMMO; +import com.gmail.nossr50.util.player.NotificationManager; +import com.gmail.nossr50.util.player.UserManager; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.logging.Logger; +import org.bukkit.OfflinePlayer; +import org.bukkit.entity.Player; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +class PartyManagerTest extends MMOTestEnvironment { + private static final Logger logger = getLogger(PartyManagerTest.class.getName()); + + @BeforeEach + public void setUp() { + mockBaseEnvironment(logger); + + // currently unnecessary, but may be needed for future tests + when(partyConfig.isPartyEnabled()).thenReturn(true); + } + + @AfterEach + public void tearDown() { + cleanUpStaticMocks(); + + // disable parties in config for other tests + when(partyConfig.isPartyEnabled()).thenReturn(false); + } + + @Test + public void createPartyWithoutPasswordShouldSucceed() { + // Given + PartyManager partyManager = new PartyManager(mcMMO.p); + String partyName = "TestParty"; + + Player player = mock(Player.class); + final McMMOPlayer mmoPlayer = mock(McMMOPlayer.class); + when(mmoPlayer.getPlayer()).thenReturn(player); + when(player.getUniqueId()).thenReturn(new UUID(0, 0)); + + // When & Then + partyManager.createParty(mmoPlayer, partyName, null); + } + + @Test + public void createPartyWithPasswordShouldSucceed() { + // Given + PartyManager partyManager = new PartyManager(mcMMO.p); + String partyName = "TestParty"; + String partyPassword = "somePassword"; + + Player player = mock(Player.class); + final McMMOPlayer mmoPlayer = mock(McMMOPlayer.class); + when(mmoPlayer.getPlayer()).thenReturn(player); + when(player.getUniqueId()).thenReturn(new UUID(0, 0)); + + // When & Then + partyManager.createParty(mmoPlayer, partyName, partyPassword); + } + + @Test + public void createPartyWithoutNameShouldFail() { + // Given + PartyManager partyManager = new PartyManager(mcMMO.p); + String partyPassword = "somePassword"; + + Player player = mock(Player.class); + final McMMOPlayer mmoPlayer = mock(McMMOPlayer.class); + when(mmoPlayer.getPlayer()).thenReturn(player); + when(player.getUniqueId()).thenReturn(new UUID(0, 0)); + + // When & Then + assertThrows(NullPointerException.class, + () -> partyManager.createParty(mmoPlayer, null, partyPassword)); + } + + @Test + public void createPartyWithoutPlayerShouldFail() { + // Given + PartyManager partyManager = new PartyManager(mcMMO.p); + String partyName = "TestParty"; + String partyPassword = "somePassword"; + + // When & Then + assertThrows(NullPointerException.class, + () -> partyManager.createParty(null, partyName, partyPassword)); + } + + @Test + public void checkPartyPasswordFailsWithIncorrectPassword() { + PartyManager partyManager = new PartyManager(mcMMO.p); + + Party party = Mockito.mock(Party.class); + Player player = Mockito.mock(Player.class); + + when(party.isLocked()).thenReturn(true); + when(party.getPassword()).thenReturn("correctPassword"); + + boolean result = partyManager.checkPartyPassword(player, party, "wrongPassword"); + + assertThat(result).isFalse(); + verify(player).sendMessage(contains("Party password is incorrect")); + } + + @Test + public void checkPartyPasswordFailsWithNullInput() { + PartyManager partyManager = new PartyManager(mcMMO.p); + + Party party = Mockito.mock(Party.class); + Player player = Mockito.mock(Player.class); + + when(party.isLocked()).thenReturn(true); + when(party.getPassword()).thenReturn("secure"); + + boolean result = partyManager.checkPartyPassword(player, party, null); + + assertThat(result).isFalse(); + verify(player).sendMessage( + contains("This party is password protected. Please provide a password to join.")); + } + + @Test + public void checkPartyExistenceReturnsTrueIfExists() { + PartyManager partyManager = new PartyManager(mcMMO.p); + + Party party = Mockito.mock(Party.class); + Mockito.when(party.getName()).thenReturn("ExistingParty"); + + partyManager.getParties().add(party); + + boolean result = partyManager.checkPartyExistence(player, "ExistingParty"); + + assertThat(result).isTrue(); + Mockito.verify(player).sendMessage(Mockito.contains("Party ExistingParty already exists!")); + } + + @Test + public void inSamePartyShouldReturnTrueIfSameParty() { + PartyManager partyManager = new PartyManager(mcMMO.p); + + Party party = Mockito.mock(Party.class); + Player playerA = mock(Player.class); + Player playerB = mock(Player.class); + + McMMOPlayer mmoA = mock(McMMOPlayer.class); + McMMOPlayer mmoB = mock(McMMOPlayer.class); + + mockedUserManager.when(() -> UserManager.getPlayer(playerA)).thenReturn(mmoA); + mockedUserManager.when(() -> UserManager.getPlayer(playerB)).thenReturn(mmoB); + + when(mmoA.getParty()).thenReturn(party); + when(mmoB.getParty()).thenReturn(party); + + assertThat(partyManager.inSameParty(playerA, playerB)).isTrue(); + } + + @Test + public void areAlliesShouldReturnTrueIfMutuallyAllied() { + PartyManager partyManager = new PartyManager(mcMMO.p); + + Player p1 = mock(Player.class); + Player p2 = mock(Player.class); + + McMMOPlayer mmo1 = mock(McMMOPlayer.class); + McMMOPlayer mmo2 = mock(McMMOPlayer.class); + + Party party1 = mock(Party.class); + Party party2 = mock(Party.class); + + mockedUserManager.when(() -> UserManager.getPlayer(p1)).thenReturn(mmo1); + mockedUserManager.when(() -> UserManager.getPlayer(p2)).thenReturn(mmo2); + + when(mmo1.getParty()).thenReturn(party1); + when(mmo2.getParty()).thenReturn(party2); + when(party1.getAlly()).thenReturn(party2); + when(party2.getAlly()).thenReturn(party1); + + assertTrue(partyManager.areAllies(p1, p2)); + } + + @Test + public void removeFromPartyDoesNothing() { + PartyManager partyManager = new PartyManager(mcMMO.p); + + McMMOPlayer mmoPlayer = mock(McMMOPlayer.class); + when(mmoPlayer.getParty()).thenReturn(null); + + partyManager.removeFromParty(mmoPlayer); + } + + @Test + public void removeFromPartyWithPartyRemovesCorrectly() { + PartyManager partyManager = new PartyManager(mcMMO.p); + + McMMOPlayer mmoPlayer = mock(McMMOPlayer.class); + Player player = mock(Player.class); + Party party = mock(Party.class); + UUID uuid = UUID.randomUUID(); + + when(player.getUniqueId()).thenReturn(uuid); + when(player.getName()).thenReturn("PlayerName"); + when(player.isOnline()).thenReturn(true); + when(player.getPlayer()).thenReturn(player); + + when(mmoPlayer.getPlayer()).thenReturn(player); + when(mmoPlayer.getParty()).thenReturn(party); + + when(party.getMembers()).thenReturn(new LinkedHashMap<>(Map.of(uuid, "PlayerName"))); + when(party.getOnlineMembers()).thenReturn(new ArrayList<>(List.of(player))); + when(party.getLeader()).thenReturn(new PartyLeader(uuid, "PlayerName")); + + partyManager.getParties().add(party); + partyManager.removeFromParty(mmoPlayer); + + // Party should be removed since it had only one member + assertFalse(partyManager.getParties().contains(party)); + } + + @Test + public void changeOrJoinPartyNotInPartyTriggersEventAndReturnsTrue() { + PartyManager partyManager = new PartyManager(mcMMO.p); + + McMMOPlayer mmoPlayer = mock(McMMOPlayer.class); + Player player = mock(Player.class); + + when(mmoPlayer.getPlayer()).thenReturn(player); + when(mmoPlayer.inParty()).thenReturn(false); + + assertTrue(partyManager.changeOrJoinParty(mmoPlayer, "NewParty")); + } + + @Test + public void removeFromPartyLeaderLeavesNewLeaderIsAssigned() { + PartyManager partyManager = new PartyManager(mcMMO.p); + + UUID oldLeaderUUID = UUID.randomUUID(); + UUID newLeaderUUID = UUID.randomUUID(); + + // Setup players + OfflinePlayer oldLeader = mock(OfflinePlayer.class); + when(oldLeader.getUniqueId()).thenReturn(oldLeaderUUID); + when(oldLeader.getName()).thenReturn("OldLeader"); + when(oldLeader.isOnline()).thenReturn(true); + when(oldLeader.getPlayer()).thenReturn( + mock(Player.class)); // required for party.getOnlineMembers() + + OfflinePlayer newLeader = mock(OfflinePlayer.class); + when(newLeader.getUniqueId()).thenReturn(newLeaderUUID); + when(newLeader.getName()).thenReturn("NewLeader"); + + // Setup party and members + Party party = new Party(new PartyLeader(oldLeaderUUID, "OldLeader"), "SomeParty", null); + party.getMembers().put(oldLeaderUUID, "OldLeader"); + party.getMembers().put(newLeaderUUID, "NewLeader"); + + Player newLeaderOnline = mock(Player.class); + when(newLeaderOnline.getUniqueId()).thenReturn(newLeaderUUID); + party.getOnlineMembers().add(newLeaderOnline); // simulate second member online + + partyManager.getParties().add(party); + + // Act + partyManager.removeFromParty(oldLeader, party); + + // Assert + PartyLeader newLeaderObj = party.getLeader(); + assertThat(newLeaderUUID).isEqualTo(newLeaderObj.getUniqueId()); + assertThat("NewLeader").isEqualTo(newLeaderObj.getPlayerName()); + } + + @Test + public void joinInvitedPartyPartyDoesNotExistDoesNotJoin() { + PartyManager partyManager = new PartyManager(mcMMO.p); + + McMMOPlayer mmoPlayer = mock(McMMOPlayer.class); + Player player = mock(Player.class); + Party partyWhichNoLongerExists = mock(Party.class); + + when(mmoPlayer.getPartyInvite()).thenReturn(partyWhichNoLongerExists); + when(mmoPlayer.getPlayer()).thenReturn(player); + + assertFalse(partyManager.getParties().contains(partyWhichNoLongerExists)); + + partyManager.joinInvitedParty(mmoPlayer); + + // Should have sent disband message + notificationManager.verify(() -> + NotificationManager.sendPlayerInformation(player, NotificationType.PARTY_MESSAGE, + "Party.Disband")); + } + +} \ No newline at end of file diff --git a/src/test/java/com/gmail/nossr50/skills/acrobatics/AcrobaticsTest.java b/src/test/java/com/gmail/nossr50/skills/acrobatics/AcrobaticsTest.java new file mode 100644 index 000000000..862e6a902 --- /dev/null +++ b/src/test/java/com/gmail/nossr50/skills/acrobatics/AcrobaticsTest.java @@ -0,0 +1,109 @@ +package com.gmail.nossr50.skills.acrobatics; + +import static java.util.logging.Logger.getLogger; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +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.skills.subskills.AbstractSubSkill; +import com.gmail.nossr50.datatypes.skills.subskills.acrobatics.Roll; +import com.gmail.nossr50.mcMMO; +import com.gmail.nossr50.util.skills.RankUtils; +import java.util.logging.Logger; +import org.bukkit.entity.Player; +import org.bukkit.event.entity.EntityDamageEvent; +import org.jetbrains.annotations.NotNull; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +class AcrobaticsTest extends MMOTestEnvironment { + private static final Logger logger = getLogger(AcrobaticsTest.class.getName()); + + @BeforeEach + void setUp() throws InvalidSkillException { + mockBaseEnvironment(logger); + when(rankConfig.getSubSkillUnlockLevel(SubSkillType.ACROBATICS_ROLL, 1)).thenReturn(1); + when(rankConfig.getSubSkillUnlockLevel(SubSkillType.ACROBATICS_DODGE, 1)).thenReturn(1); + + // wire advanced config + when(advancedConfig.getMaximumProbability(SubSkillType.ACROBATICS_ROLL)).thenReturn(100D); + when(advancedConfig.getMaxBonusLevel(SubSkillType.ACROBATICS_ROLL)).thenReturn(1000); + when(advancedConfig.getRollDamageThreshold()).thenReturn(7D); + + Mockito.when(RankUtils.getRankUnlockLevel(SubSkillType.ACROBATICS_ROLL, 1)) + .thenReturn(1); // needed? + Mockito.when(RankUtils.getRankUnlockLevel(SubSkillType.ACROBATICS_DODGE, 1)) + .thenReturn(1000); // needed? + + when(RankUtils.getRankUnlockLevel(SubSkillType.ACROBATICS_ROLL, 1)).thenReturn( + 1); // needed? + when(RankUtils.hasReachedRank(eq(1), any(Player.class), + eq(SubSkillType.ACROBATICS_ROLL))).thenReturn(true); + when(RankUtils.hasReachedRank(eq(1), any(Player.class), + any(AbstractSubSkill.class))).thenReturn(true); + } + + @AfterEach + void tearDown() { + cleanUpStaticMocks(); + } + + @SuppressWarnings("deprecation") + @Test + public void rollShouldLowerDamage() { + // Given + final Roll roll = new Roll(); + final double damage = 2D; + final EntityDamageEvent mockEvent = mockEntityDamageEvent(damage); + mmoPlayer.modifySkill(PrimarySkillType.ACROBATICS, 1000); + when(roll.canRoll(mmoPlayer)).thenReturn(true); + assertThat(roll.canRoll(mmoPlayer)).isTrue(); + + // When + roll.doInteraction(mockEvent, mcMMO.p); + + // Then + verify(mockEvent, atLeastOnce()).setDamage(0); + } + + @SuppressWarnings("deprecation") + @Test + public void rollShouldNotLowerDamage() { + // Given + final Roll roll = new Roll(); + final double damage = 100D; + final EntityDamageEvent mockEvent = mockEntityDamageEvent(damage); + mmoPlayer.modifySkill(PrimarySkillType.ACROBATICS, 0); + when(roll.canRoll(mmoPlayer)).thenReturn(true); + assertThat(roll.canRoll(mmoPlayer)).isTrue(); + + // When + roll.doInteraction(mockEvent, mcMMO.p); + + // Then + assertThat(roll.canRoll(mmoPlayer)).isTrue(); + verify(mockEvent, Mockito.never()).setDamage(any(Double.class)); + } + + private @NotNull EntityDamageEvent mockEntityDamageEvent(double damage) { + final EntityDamageEvent mockEvent = mock(EntityDamageEvent.class); + when(mockEvent.isApplicable(any(EntityDamageEvent.DamageModifier.class))).thenReturn(true); + when(mockEvent.getCause()).thenReturn(EntityDamageEvent.DamageCause.FALL); + when(mockEvent.getFinalDamage()).thenReturn(damage); + when(mockEvent.getDamage(any(EntityDamageEvent.DamageModifier.class))).thenReturn(damage); + when(mockEvent.getDamage()).thenReturn(damage); + when(mockEvent.isCancelled()).thenReturn(false); + when(mockEvent.getEntity()).thenReturn(player); + return mockEvent; + } +} \ No newline at end of file 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 000000000..ac4a73bc1 --- /dev/null +++ b/src/test/java/com/gmail/nossr50/skills/excavation/ExcavationTest.java @@ -0,0 +1,114 @@ +package com.gmail.nossr50.skills.excavation; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +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 java.util.ArrayList; +import java.util.List; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import 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.itemInMainHand = new ItemStack(Material.DIAMOND_SHOVEL); + when(playerInventory.getItemInMainHand()).thenReturn(itemInMainHand); + } + + @AfterEach + void tearDown() { + cleanUpStaticMocks(); + } + + @Test + void excavationShouldHaveTreasureDrops() { + mmoPlayer.modifySkill(PrimarySkillType.EXCAVATION, 1000); + + // Wire block + Block block = Mockito.mock(Block.class); + when(block.getType()).thenReturn(Material.SAND); + when(block.getDrops(any())).thenReturn(null); + + ExcavationManager excavationManager = Mockito.spy(new ExcavationManager(mmoPlayer)); + doReturn(getGuaranteedTreasureDrops()).when(excavationManager).getTreasures(block); + excavationManager.excavationBlockCheck(block); + + // verify ExcavationManager.processExcavationBonusesOnBlock was called + verify(excavationManager, atLeastOnce()).processExcavationBonusesOnBlock( + any(ExcavationTreasure.class), any(Location.class)); + } + + @Test + void excavationShouldNotDropTreasure() { + mmoPlayer.modifySkill(PrimarySkillType.EXCAVATION, 1000); + + // Wire block + Block block = Mockito.mock(Block.class); + when(block.getType()).thenReturn(Material.SAND); + when(block.getDrops(any())).thenReturn(null); + + ExcavationManager excavationManager = Mockito.spy(new ExcavationManager(mmoPlayer)); + doReturn(getImpossibleTreasureDrops()).when(excavationManager).getTreasures(block); + excavationManager.excavationBlockCheck(block); + + // verify ExcavationManager.processExcavationBonusesOnBlock was called + verify(excavationManager, never()).processExcavationBonusesOnBlock( + 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; + } +} 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 000000000..13c6031ae --- /dev/null +++ b/src/test/java/com/gmail/nossr50/skills/tridents/TridentsTest.java @@ -0,0 +1,43 @@ +package com.gmail.nossr50.skills.tridents; + +import static java.util.logging.Logger.getLogger; + +import com.gmail.nossr50.MMOTestEnvironment; +import com.gmail.nossr50.api.exceptions.InvalidSkillException; +import java.util.logging.Logger; +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 Logger logger = getLogger(TridentsTest.class.getName()); + + TridentsManager tridentsManager; + ItemStack trident; + + @BeforeEach + void setUp() throws InvalidSkillException { + mockBaseEnvironment(logger); + + // setup player and player related mocks after everything else + this.player = Mockito.mock(Player.class); + Mockito.when(player.getUniqueId()).thenReturn(playerUUID); + + // wire inventory + this.playerInventory = Mockito.mock(PlayerInventory.class); + this.trident = new ItemStack(Material.TRIDENT); + Mockito.when(playerInventory.getItemInMainHand()).thenReturn(trident); + + // Set up spy for manager + tridentsManager = Mockito.spy(new TridentsManager(mmoPlayer)); + } + + @AfterEach + void tearDown() { + cleanUpStaticMocks(); + } +} 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 000000000..720d450aa --- /dev/null +++ b/src/test/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingTest.java @@ -0,0 +1,234 @@ +package com.gmail.nossr50.skills.woodcutting; + +import static java.util.logging.Logger.getLogger; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockStatic; + +import com.gmail.nossr50.MMOTestEnvironment; +import com.gmail.nossr50.api.exceptions.InvalidSkillException; +import com.gmail.nossr50.config.experience.ExperienceConfig; +import com.gmail.nossr50.datatypes.skills.PrimarySkillType; +import com.gmail.nossr50.datatypes.skills.SubSkillType; +import com.gmail.nossr50.mcMMO; +import com.gmail.nossr50.util.BlockUtils; +import com.gmail.nossr50.util.skills.RankUtils; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.ThreadLocalRandom; +import java.util.logging.Logger; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +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; + +class WoodcuttingTest extends MMOTestEnvironment { + private static final Logger logger = getLogger(WoodcuttingTest.class.getName()); + + private WoodcuttingManager woodcuttingManager; + + @BeforeEach + void setUp() throws InvalidSkillException { + mockBaseEnvironment(logger); + Mockito.when(rankConfig.getSubSkillUnlockLevel(SubSkillType.WOODCUTTING_HARVEST_LUMBER, 1)) + .thenReturn(1); + + // wire advanced config + Mockito.when(advancedConfig.getMaximumProbability(SubSkillType.WOODCUTTING_HARVEST_LUMBER)) + .thenReturn(100D); + Mockito.when(advancedConfig.getMaximumProbability(SubSkillType.WOODCUTTING_CLEAN_CUTS)) + .thenReturn(10D); + Mockito.when(advancedConfig.getMaxBonusLevel(SubSkillType.WOODCUTTING_HARVEST_LUMBER)) + .thenReturn(1000); + Mockito.when(advancedConfig.getMaxBonusLevel(SubSkillType.WOODCUTTING_CLEAN_CUTS)) + .thenReturn(10000); + + Mockito.when(RankUtils.getRankUnlockLevel(SubSkillType.WOODCUTTING_HARVEST_LUMBER, 1)) + .thenReturn(1); // needed? + Mockito.when(RankUtils.getRankUnlockLevel(SubSkillType.WOODCUTTING_CLEAN_CUTS, 1)) + .thenReturn(1000); // needed? + Mockito.when(RankUtils.hasReachedRank(eq(1), any(Player.class), + eq(SubSkillType.WOODCUTTING_HARVEST_LUMBER))).thenReturn(true); + Mockito.when(RankUtils.hasReachedRank(eq(1), any(Player.class), + eq(SubSkillType.WOODCUTTING_CLEAN_CUTS))).thenReturn(true); + + // wire inventory + 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() { + cleanUpStaticMocks(); + } + + @Test + void harvestLumberShouldDoubleDrop() { + mmoPlayer.modifySkill(PrimarySkillType.WOODCUTTING, 1000); + + Block block = mock(Block.class); + // return empty collection if ItemStack + Mockito.when(block.getDrops(any())).thenReturn(Collections.emptyList()); + Mockito.when(block.getType()).thenReturn(Material.OAK_LOG); + woodcuttingManager.processBonusDropCheck(block); + + // verify bonus drops were spawned + // TODO: using at least once since triple drops can also happen + // TODO: Change the test env to disallow triple drop in the future + Mockito.verify(woodcuttingManager, Mockito.atLeastOnce()) + .spawnHarvestLumberBonusDrops(block); + } + + @Test + void harvestLumberShouldNotDoubleDrop() { + mmoPlayer.modifySkill(PrimarySkillType.WOODCUTTING, 0); + + Block block = mock(Block.class); + // wire block + + Mockito.when(block.getDrops(any())).thenReturn(null); + Mockito.when(block.getType()).thenReturn(Material.OAK_LOG); + woodcuttingManager.processBonusDropCheck(block); + + // verify bonus drops were not spawned + Mockito.verify(woodcuttingManager, Mockito.times(0)).spawnHarvestLumberBonusDrops(block); + } + + @Test + void testProcessWoodcuttingBlockXP() { + Block targetBlock = mock(Block.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()); + } + + @Test + void treeFellerShouldStopAtThreshold() { + // Set threshold artificially low + int fakeThreshold = 3; + Mockito.when(generalConfig.getTreeFellerThreshold()).thenReturn(fakeThreshold); + + WoodcuttingManager manager = Mockito.spy(new WoodcuttingManager(mmoPlayer)); + + // Simulate all blocks are logs with XP + MockedStatic mockedBlockUtils = mockStatic(BlockUtils.class); + mockedBlockUtils.when(() -> BlockUtils.hasWoodcuttingXP(any(Block.class))).thenReturn(true); + mockedBlockUtils.when(() -> BlockUtils.isNonWoodPartOfTree(any(Block.class))) + .thenReturn(false); + + // Simulate that block tracker always allows processing + Mockito.when(mcMMO.getUserBlockTracker().isIneligible(any(Block.class))).thenReturn(false); + + // Create distinct mocked blocks to simulate recursion + Block centerBlock = mock(Block.class); + List relatives = new ArrayList<>(); + + for (int i = 0; i < 10; i++) { + Block relative = mock(Block.class, "block_" + i); + Mockito.when(relative.getRelative(any(BlockFace.class))).thenReturn(relative); + Mockito.when(relative.getRelative(anyInt(), anyInt(), anyInt())).thenReturn(relative); + relatives.add(relative); + } + + // Wire center block to return a different relative each time + Mockito.when(centerBlock.getRelative(any(BlockFace.class))) + .thenAnswer(inv -> relatives.get(0)); + Mockito.when(centerBlock.getRelative(anyInt(), anyInt(), anyInt())) + .thenAnswer(inv -> relatives.get( + ThreadLocalRandom.current().nextInt(relatives.size()))); + + Set treeFellerBlocks = new HashSet<>(); + manager.processTree(centerBlock, treeFellerBlocks); + + // --- Assertions --- + + // It processed *at least one* block + assertFalse(treeFellerBlocks.isEmpty(), "Tree Feller should process at least one block"); + + // It reached or slightly exceeded the threshold + assertTrue(treeFellerBlocks.size() >= fakeThreshold, + "Tree Feller should process up to the threshold limit"); + + // Confirm it stopped due to the threshold + assertTrue(getPrivateTreeFellerReachedThreshold(manager), + "Tree Feller should set treeFellerReachedThreshold to true"); + + mockedBlockUtils.close(); + } + + private boolean getPrivateTreeFellerReachedThreshold(WoodcuttingManager manager) { + try { + Field field = WoodcuttingManager.class.getDeclaredField("treeFellerReachedThreshold"); + field.setAccessible(true); + return (boolean) field.get(manager); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Test + void treeFellerShouldNotReachThreshold() throws NoSuchFieldException, IllegalAccessException { + int threshold = 10; + Mockito.when(generalConfig.getTreeFellerThreshold()).thenReturn(threshold); + + WoodcuttingManager manager = Mockito.spy(new WoodcuttingManager(mmoPlayer)); + + MockedStatic mockedBlockUtils = mockStatic(BlockUtils.class); + mockedBlockUtils.when(() -> BlockUtils.hasWoodcuttingXP(any(Block.class))).thenReturn(true); + mockedBlockUtils.when(() -> BlockUtils.isNonWoodPartOfTree(any(Block.class))) + .thenReturn(false); + Mockito.when(mcMMO.getUserBlockTracker().isIneligible(any(Block.class))).thenReturn(false); + + // Create 4 blocks (well below threshold) + Block b0 = mock(Block.class, "b0"); + Block b1 = mock(Block.class, "b1"); + Block b2 = mock(Block.class, "b2"); + Block b3 = mock(Block.class, "b3"); + + // Deterministically chain recursion: b0 → b1 → b2 → b3 → null + Mockito.when(b0.getRelative(anyInt(), anyInt(), anyInt())).thenReturn(b1); + Mockito.when(b1.getRelative(anyInt(), anyInt(), anyInt())).thenReturn(b2); + Mockito.when(b2.getRelative(anyInt(), anyInt(), anyInt())).thenReturn(b3); + Mockito.when(b3.getRelative(anyInt(), anyInt(), anyInt())).thenReturn(null); + + Mockito.when(b0.getRelative(any(BlockFace.class))).thenReturn(b1); + Mockito.when(b1.getRelative(any(BlockFace.class))).thenReturn(b2); + Mockito.when(b2.getRelative(any(BlockFace.class))).thenReturn(b3); + Mockito.when(b3.getRelative(any(BlockFace.class))).thenReturn(null); + + Set processed = new HashSet<>(); + manager.processTree(b0, processed); + + assertEquals(3, processed.size(), "Should process exactly 4 blocks"); + assertFalse(getPrivateTreeFellerReachedThreshold(manager), + "treeFellerReachedThreshold should remain false"); + + mockedBlockUtils.close(); + } + +} diff --git a/src/test/java/com/gmail/nossr50/util/PotionEffectUtilTest.java b/src/test/java/com/gmail/nossr50/util/PotionEffectUtilTest.java new file mode 100644 index 000000000..6e3b6ce88 --- /dev/null +++ b/src/test/java/com/gmail/nossr50/util/PotionEffectUtilTest.java @@ -0,0 +1,60 @@ +package com.gmail.nossr50.util; + +import static com.gmail.nossr50.util.PotionEffectUtil.getNauseaPotionEffectType; +import static java.util.logging.Logger.getLogger; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.when; + +import com.gmail.nossr50.mcMMO; +import com.gmail.nossr50.util.compat.CompatibilityManager; +import com.gmail.nossr50.util.platform.MinecraftGameVersion; +import org.bukkit.potion.PotionEffectType; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; + +class PotionEffectUtilTest { + private MockedStatic mockedStaticMcMMO; + private static final java.util.logging.Logger logger = getLogger( + PotionEffectUtilTest.class.getName()); + + @BeforeEach + void setUp() { + mockedStaticMcMMO = mockStatic(mcMMO.class); + mcMMO.p = mock(mcMMO.class); + when(mcMMO.p.getLogger()).thenReturn(logger); + CompatibilityManager compatibilityManager = mock(CompatibilityManager.class); + MinecraftGameVersion minecraftGameVersion = mock(MinecraftGameVersion.class); + when(compatibilityManager.getMinecraftGameVersion()).thenReturn(minecraftGameVersion); + when(minecraftGameVersion.isAtLeast(1, 20, 5)).thenReturn(false); + when(mcMMO.getCompatibilityManager()).thenReturn(compatibilityManager); + } + + @AfterEach + void tearDown() { + mockedStaticMcMMO.close(); + } + + @Test + @Tag("skip") + void testGetNauseaPotionEffectType() { + // TODO: Test only works on older versions since we aren't properly mocking the spigot registry + final PotionEffectType nausea = getNauseaPotionEffectType(); + assertNotNull(nausea); + assertThat(nausea).isEqualTo(PotionEffectType.NAUSEA); + } + + @Test + @Tag("skip") + void testGetHastePotionEffectType() { + // TODO: Test only works on older versions since we aren't properly mocking the spigot registry + final PotionEffectType haste = PotionEffectUtil.getHastePotionEffectType(); + assertNotNull(haste); + assertThat(haste).isEqualTo(PotionEffectType.HASTE); + } +} \ No newline at end of file diff --git a/src/test/java/com/gmail/nossr50/util/PotionUtilTest.java b/src/test/java/com/gmail/nossr50/util/PotionUtilTest.java new file mode 100644 index 000000000..cbcf4cfc7 --- /dev/null +++ b/src/test/java/com/gmail/nossr50/util/PotionUtilTest.java @@ -0,0 +1,72 @@ +package com.gmail.nossr50.util; + +import static com.gmail.nossr50.util.PotionUtil.convertLegacyNames; +import static com.gmail.nossr50.util.PotionUtil.matchPotionType; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.when; + +import com.gmail.nossr50.mcMMO; +import com.gmail.nossr50.util.compat.CompatibilityManager; +import com.gmail.nossr50.util.platform.MinecraftGameVersion; +import org.bukkit.potion.PotionType; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; + +class PotionUtilTest { + + MockedStatic mockedStaticMcMMO; + + @BeforeEach + void setUp() { + mockedStaticMcMMO = mockStatic(mcMMO.class); + CompatibilityManager compatibilityManager = mock(CompatibilityManager.class); + MinecraftGameVersion minecraftGameVersion = mock(MinecraftGameVersion.class); + when(compatibilityManager.getMinecraftGameVersion()).thenReturn(minecraftGameVersion); + when(minecraftGameVersion.isAtLeast(1, 20, 5)).thenReturn(true); + when(mcMMO.getCompatibilityManager()).thenReturn(compatibilityManager); + } + + @AfterEach + void tearDown() { + mockedStaticMcMMO.close(); + } + + @Test + void testMatchPotionTypeStrengthII() { + final String potionTypeStr = "STRENGTH"; + final PotionType potionType = matchPotionType(potionTypeStr, true, false); + assertEquals(PotionType.STRONG_STRENGTH, potionType); + } + + @Test + void testMatchPotionTypeRegen() { + final String potionTypeStr = "REGEN"; + final PotionType potionType = matchPotionType(potionTypeStr, false, false); + assertEquals(PotionType.REGENERATION, potionType); + } + + @Test + void testMatchPotionTypeUncraftable() { + final String potionTypeStr = "UNCRAFTABLE"; + final PotionType potionType = matchPotionType(potionTypeStr, false, false); + assertEquals(PotionType.MUNDANE, potionType); + } + + @Test + void testConvertLegacyNamesUncraftable() { + final String potionTypeStr = "UNCRAFTABLE"; + final String converted = convertLegacyNames(potionTypeStr); + assertEquals("MUNDANE", converted); + } + + @Test + void testConvertLegacyNamesRegen() { + final String potionTypeStr = "REGEN"; + final String converted = convertLegacyNames(potionTypeStr); + assertEquals("REGENERATION", converted); + } +} \ No newline at end of file diff --git a/src/test/java/com/gmail/nossr50/util/blockmeta/BitSetChunkStoreTest.java b/src/test/java/com/gmail/nossr50/util/blockmeta/BitSetChunkStoreTest.java new file mode 100644 index 000000000..81993e614 --- /dev/null +++ b/src/test/java/com/gmail/nossr50/util/blockmeta/BitSetChunkStoreTest.java @@ -0,0 +1,131 @@ +package com.gmail.nossr50.util.blockmeta; + +import static com.gmail.nossr50.util.blockmeta.BlockStoreTestUtils.LEGACY_WORLD_HEIGHT_MAX; +import static com.gmail.nossr50.util.blockmeta.BlockStoreTestUtils.LEGACY_WORLD_HEIGHT_MIN; +import static com.gmail.nossr50.util.blockmeta.BlockStoreTestUtils.assertChunkStoreEquals; +import static com.gmail.nossr50.util.blockmeta.BlockStoreTestUtils.assertEqualIgnoreMinMax; +import static com.gmail.nossr50.util.blockmeta.BlockStoreTestUtils.serializeChunkStore; +import static com.gmail.nossr50.util.blockmeta.UserBlockTrackerTest.recursiveDelete; +import static org.bukkit.Bukkit.getWorld; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.when; + +import com.gmail.nossr50.mcMMO; +import com.google.common.io.Files; +import java.io.ByteArrayInputStream; +import java.io.DataInputStream; +import java.io.File; +import java.io.IOException; +import java.util.UUID; +import org.bukkit.Bukkit; +import org.bukkit.World; +import org.junit.jupiter.api.AfterAll; +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; + +class BitSetChunkStoreTest { + private static File tempDir; + + @BeforeAll + public static void setUpClass() { + tempDir = Files.createTempDir(); + } + + @AfterAll + public static void tearDownClass() { + recursiveDelete(tempDir); + } + + private World mockWorld; + + private MockedStatic bukkitMock; + private MockedStatic mcMMOMock; + + @BeforeEach + void setUpMock() { + UUID worldUUID = UUID.randomUUID(); + mockWorld = Mockito.mock(World.class); + when(mockWorld.getUID()).thenReturn(worldUUID); + when(mockWorld.getMaxHeight()).thenReturn(256); + when(mockWorld.getWorldFolder()).thenReturn(tempDir); + + bukkitMock = mockStatic(Bukkit.class); + bukkitMock.when(() -> getWorld(worldUUID)).thenReturn(mockWorld); + + mcMMOMock = mockStatic(mcMMO.class); + + when(mockWorld.getMinHeight()).thenReturn(LEGACY_WORLD_HEIGHT_MIN); + when(mockWorld.getMaxHeight()).thenReturn(LEGACY_WORLD_HEIGHT_MAX); + } + + @AfterEach + void teardownMock() { + bukkitMock.close(); + mcMMOMock.close(); + } + + @Test + void testSetValue() { + final BitSetChunkStore original = new BitSetChunkStore(mockWorld, 0, 0); + original.setTrue(0, 0, 0); + assertTrue(original.isTrue(0, 0, 0)); + original.setFalse(0, 0, 0); + assertFalse(original.isTrue(0, 0, 0)); + } + + @Test + void testIsEmpty() { + final BitSetChunkStore original = new BitSetChunkStore(mockWorld, 0, 0); + assertTrue(original.isEmpty()); + original.setTrue(0, 0, 0); + original.setFalse(0, 0, 0); + assertTrue(original.isEmpty()); + } + + @Test + void testRoundTrip() throws IOException { + final BitSetChunkStore original = new BitSetChunkStore(mockWorld, 1, 2); + original.setTrue(14, 89, 12); + original.setTrue(14, 90, 12); + original.setTrue(13, 89, 12); + byte[] serializedBytes = serializeChunkStore(original); + final ChunkStore deserialized = BitSetChunkStore.Serialization.readChunkStore( + new DataInputStream(new ByteArrayInputStream(serializedBytes))); + assertChunkStoreEquals(original, deserialized); + } + + @Test + void testNegativeWorldMin() throws IOException { + when(mockWorld.getMinHeight()).thenReturn(-64); + + final BitSetChunkStore original = new BitSetChunkStore(mockWorld, 1, 2); + original.setTrue(14, -32, 12); + original.setTrue(14, -64, 12); + original.setTrue(13, -63, 12); + byte[] serializedBytes = serializeChunkStore(original); + final ChunkStore deserialized = BitSetChunkStore.Serialization.readChunkStore( + new DataInputStream(new ByteArrayInputStream(serializedBytes))); + assertChunkStoreEquals(original, deserialized); + } + + @Test + void testNegativeWorldMinUpgrade() throws IOException { + final BitSetChunkStore original = new BitSetChunkStore(mockWorld, 1, 2); + original.setTrue(14, 1, 12); + original.setTrue(14, 2, 12); + original.setTrue(13, 3, 12); + byte[] serializedBytes = serializeChunkStore(original); + + when(mockWorld.getMinHeight()).thenReturn(-64); + final ChunkStore deserialized = BitSetChunkStore.Serialization.readChunkStore( + new DataInputStream(new ByteArrayInputStream(serializedBytes))); + assert deserialized != null; + assertEqualIgnoreMinMax(original, deserialized); + } +} \ No newline at end of file diff --git a/src/test/java/com/gmail/nossr50/util/blockmeta/BlockStoreTestUtils.java b/src/test/java/com/gmail/nossr50/util/blockmeta/BlockStoreTestUtils.java new file mode 100644 index 000000000..883f6c745 --- /dev/null +++ b/src/test/java/com/gmail/nossr50/util/blockmeta/BlockStoreTestUtils.java @@ -0,0 +1,57 @@ +package com.gmail.nossr50.util.blockmeta; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import org.jetbrains.annotations.NotNull; + +public class BlockStoreTestUtils { + public static final int LEGACY_WORLD_HEIGHT_MAX = 256; + public static final int LEGACY_WORLD_HEIGHT_MIN = 0; + + /** + * Asserts that the two ChunkStores are equal. + * + * @param expected The expected ChunkStore + * @param actual The actual ChunkStore + */ + static void assertChunkStoreEquals(ChunkStore expected, ChunkStore actual) { + assertEquals(expected.getChunkMin(), actual.getChunkMin()); + assertEquals(expected.getChunkMax(), actual.getChunkMax()); + assertEqualIgnoreMinMax(expected, actual); + } + + static byte[] serializeChunkStore(@NotNull ChunkStore chunkStore) throws IOException { + final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + if (chunkStore instanceof BitSetChunkStore) { + BitSetChunkStore.Serialization.writeChunkStore( + new DataOutputStream(byteArrayOutputStream), chunkStore); + } else { + new UnitTestObjectOutputStream(byteArrayOutputStream).writeObject( + chunkStore); // Serializes the class as if + } + // it were the old + // PrimitiveChunkStore + return byteArrayOutputStream.toByteArray(); + } + + static void assertEqualIgnoreMinMax(ChunkStore expected, ChunkStore actual) { + assertEquals(expected.getChunkX(), actual.getChunkX()); + assertEquals(expected.getChunkZ(), actual.getChunkZ()); + assertEquals(expected.getWorldId(), actual.getWorldId()); + for (int y = Math.min(actual.getChunkMin(), expected.getChunkMin()); + y < Math.max(actual.getChunkMax(), expected.getChunkMax()); y++) { + if (expected.getChunkMin() > y || actual.getChunkMin() > y + || expected.getChunkMax() <= y || actual.getChunkMax() <= y) { + continue; // Ignore + } + for (int x = 0; x < 16; x++) { + for (int z = 0; z < 16; z++) { + assertEquals(expected.isTrue(x, y, z), actual.isTrue(x, y, z)); + } + } + } + } +} diff --git a/src/test/java/com/gmail/nossr50/util/blockmeta/ChunkStoreTest.java b/src/test/java/com/gmail/nossr50/util/blockmeta/ChunkStoreTest.java index 969de6ec4..797897f78 100644 --- a/src/test/java/com/gmail/nossr50/util/blockmeta/ChunkStoreTest.java +++ b/src/test/java/com/gmail/nossr50/util/blockmeta/ChunkStoreTest.java @@ -1,28 +1,34 @@ package com.gmail.nossr50.util.blockmeta; +import static com.gmail.nossr50.util.blockmeta.BlockStoreTestUtils.LEGACY_WORLD_HEIGHT_MAX; +import static com.gmail.nossr50.util.blockmeta.BlockStoreTestUtils.LEGACY_WORLD_HEIGHT_MIN; +import static com.gmail.nossr50.util.blockmeta.BlockStoreTestUtils.assertChunkStoreEquals; +import static com.gmail.nossr50.util.blockmeta.BlockStoreTestUtils.serializeChunkStore; +import static com.gmail.nossr50.util.blockmeta.UserBlockTrackerTest.recursiveDelete; +import static org.bukkit.Bukkit.getWorld; +import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.when; import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.util.BlockUtils; import com.google.common.io.Files; +import java.io.ByteArrayInputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.File; +import java.io.IOException; +import java.util.UUID; import org.bukkit.Bukkit; import org.bukkit.World; -import org.bukkit.block.Block; -import org.jetbrains.annotations.NotNull; -import org.junit.jupiter.api.*; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +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.io.*; -import java.util.UUID; - -/** - * Could be a lot better. But some tests are better than none! Tests the major things, still kinda unit-testy. Verifies - * that the serialization isn't completely broken. - */ class ChunkStoreTest { - - public static final int LEGACY_WORLD_HEIGHT_MAX = 256; - public static final int LEGACY_WORLD_HEIGHT_MIN = 0; private static File tempDir; @BeforeAll @@ -44,151 +50,40 @@ class ChunkStoreTest { void setUpMock() { UUID worldUUID = UUID.randomUUID(); mockWorld = Mockito.mock(World.class); - Mockito.when(mockWorld.getUID()).thenReturn(worldUUID); - Mockito.when(mockWorld.getMaxHeight()).thenReturn(256); - Mockito.when(mockWorld.getWorldFolder()).thenReturn(tempDir); + when(mockWorld.getUID()).thenReturn(worldUUID); + when(mockWorld.getMaxHeight()).thenReturn(256); + when(mockWorld.getWorldFolder()).thenReturn(tempDir); - bukkitMock = Mockito.mockStatic(Bukkit.class); - bukkitMock.when(() -> Bukkit.getWorld(worldUUID)).thenReturn(mockWorld); + bukkitMock = mockStatic(Bukkit.class); + bukkitMock.when(() -> getWorld(worldUUID)).thenReturn(mockWorld); - mcMMOMock = Mockito.mockStatic(mcMMO.class); + mcMMOMock = mockStatic(mcMMO.class); - Mockito.when(mockWorld.getMinHeight()).thenReturn(LEGACY_WORLD_HEIGHT_MIN); - Mockito.when(mockWorld.getMaxHeight()).thenReturn(LEGACY_WORLD_HEIGHT_MAX); + when(mockWorld.getMinHeight()).thenReturn(LEGACY_WORLD_HEIGHT_MIN); + when(mockWorld.getMaxHeight()).thenReturn(LEGACY_WORLD_HEIGHT_MAX); } - + @AfterEach void teardownMock() { bukkitMock.close(); mcMMOMock.close(); } - @Test - void testIndexOutOfBounds() { - Mockito.when(mockWorld.getMinHeight()).thenReturn(-64); - HashChunkManager hashChunkManager = new HashChunkManager(); - - // Top Block - Block illegalHeightBlock = initMockBlock(1337, 256, -1337); - Assertions.assertFalse(hashChunkManager.isTrue(illegalHeightBlock)); - Assertions.assertThrows(IndexOutOfBoundsException.class, () -> hashChunkManager.setTrue(illegalHeightBlock)); - } - - @Test - void testSetTrue() { - Mockito.when(mockWorld.getMinHeight()).thenReturn(-64); - HashChunkManager hashChunkManager = new HashChunkManager(); - int radius = 2; // Could be anything but drastically changes test time - - for (int x = -radius; x <= radius; x++) { - for (int y = mockWorld.getMinHeight(); y < mockWorld.getMaxHeight(); y++) { - for (int z = -radius; z <= radius; z++) { - Block testBlock = initMockBlock(x, y, z); - - hashChunkManager.setTrue(testBlock); - Assertions.assertTrue(hashChunkManager.isTrue(testBlock)); - hashChunkManager.setFalse(testBlock); - Assertions.assertFalse(hashChunkManager.isTrue(testBlock)); - } - } - } - - // Bot Block - Block bottomBlock = initMockBlock(1337, 0, -1337); - Assertions.assertFalse(hashChunkManager.isTrue(bottomBlock)); - - Assertions.assertTrue(BlockUtils.isWithinWorldBounds(bottomBlock)); - hashChunkManager.setTrue(bottomBlock); - Assertions.assertTrue(hashChunkManager.isTrue(bottomBlock)); - - // Top Block - Block topBlock = initMockBlock(1337, 255, -1337); - Assertions.assertFalse(hashChunkManager.isTrue(topBlock)); - - Assertions.assertTrue(BlockUtils.isWithinWorldBounds(topBlock)); - hashChunkManager.setTrue(topBlock); - Assertions.assertTrue(hashChunkManager.isTrue(topBlock)); - } - - @Test - void testSetValue() { - BitSetChunkStore original = new BitSetChunkStore(mockWorld, 0, 0); - original.setTrue(0, 0, 0); - Assertions.assertTrue(original.isTrue(0, 0, 0)); - original.setFalse(0, 0, 0); - Assertions.assertFalse(original.isTrue(0, 0, 0)); - } - - @Test - void testIsEmpty() { - BitSetChunkStore original = new BitSetChunkStore(mockWorld, 0, 0); - Assertions.assertTrue(original.isEmpty()); - original.setTrue(0, 0, 0); - original.setFalse(0, 0, 0); - Assertions.assertTrue(original.isEmpty()); - } - - @Test - void testRoundTrip() throws IOException { - BitSetChunkStore original = new BitSetChunkStore(mockWorld, 1, 2); - original.setTrue(14, 89, 12); - original.setTrue(14, 90, 12); - original.setTrue(13, 89, 12); - byte[] serializedBytes = serializeChunkstore(original); - ChunkStore deserialized = BitSetChunkStore.Serialization.readChunkStore(new DataInputStream(new ByteArrayInputStream(serializedBytes))); - assertEqual(original, deserialized); - } - - @Test - void testNegativeWorldMin() throws IOException { - Mockito.when(mockWorld.getMinHeight()).thenReturn(-64); - - BitSetChunkStore original = new BitSetChunkStore(mockWorld, 1, 2); - original.setTrue(14, -32, 12); - original.setTrue(14, -64, 12); - original.setTrue(13, -63, 12); - byte[] serializedBytes = serializeChunkstore(original); - ChunkStore deserialized = BitSetChunkStore.Serialization.readChunkStore(new DataInputStream(new ByteArrayInputStream(serializedBytes))); - assertEqual(original, deserialized); - } - - @Test - void testNegativeWorldMinUpgrade() throws IOException { - BitSetChunkStore original = new BitSetChunkStore(mockWorld, 1, 2); - original.setTrue(14, 1, 12); - original.setTrue(14, 2, 12); - original.setTrue(13, 3, 12); - byte[] serializedBytes = serializeChunkstore(original); - - Mockito.when(mockWorld.getMinHeight()).thenReturn(-64); - ChunkStore deserialized = BitSetChunkStore.Serialization.readChunkStore(new DataInputStream(new ByteArrayInputStream(serializedBytes))); - assert deserialized != null; - assertEqualIgnoreMinMax(original, deserialized); - } - - @Test - void testChunkCoords() throws IOException { - for (int x = -96; x < 0; x++) { - int cx = x >> 4; - int ix = Math.abs(x) % 16; - //System.out.print(cx + ":" + ix + " "); - } - } - @Test void testUpgrade() throws IOException { LegacyChunkStore original = new LegacyChunkStore(mockWorld, 12, 32); original.setTrue(14, 89, 12); original.setTrue(14, 90, 12); original.setTrue(13, 89, 12); - byte[] serializedBytes = serializeChunkstore(original); - ChunkStore deserialized = BitSetChunkStore.Serialization.readChunkStore(new DataInputStream(new ByteArrayInputStream(serializedBytes))); + byte[] serializedBytes = serializeChunkStore(original); + ChunkStore deserialized = BitSetChunkStore.Serialization.readChunkStore( + new DataInputStream(new ByteArrayInputStream(serializedBytes))); assert deserialized != null; - assertEqual(original, deserialized); + assertChunkStoreEquals(original, deserialized); } @Test - void testSimpleRegionRoundtrip() throws IOException { + void testSimpleRegionRoundTrip() throws IOException { LegacyChunkStore original = new LegacyChunkStore(mockWorld, 12, 12); original.setTrue(14, 89, 12); original.setTrue(14, 90, 12); @@ -196,237 +91,19 @@ class ChunkStoreTest { File file = new File(tempDir, "SimpleRegionRoundTrip.region"); McMMOSimpleRegionFile region = new McMMOSimpleRegionFile(file, 0, 0); try (DataOutputStream outputStream = region.getOutputStream(12, 12)) { - outputStream.write(serializeChunkstore(original)); + outputStream.write(serializeChunkStore(original)); } region.close(); region = new McMMOSimpleRegionFile(file, 0, 0); - try (DataInputStream is = region.getInputStream(original.getChunkX(), original.getChunkZ())) { + try (DataInputStream is = region.getInputStream(original.getChunkX(), + original.getChunkZ())) { Assertions.assertNotNull(is); ChunkStore deserialized = BitSetChunkStore.Serialization.readChunkStore(is); assert deserialized != null; - assertEqual(original, deserialized); + assertChunkStoreEquals(original, deserialized); } region.close(); file.delete(); } - @Test - void testSimpleRegionRejectsOutOfBounds() { - File file = new File(tempDir, "SimpleRegionRoundTrip.region"); - McMMOSimpleRegionFile region = new McMMOSimpleRegionFile(file, 0, 0); - Assertions.assertThrows(IndexOutOfBoundsException.class, () -> region.getOutputStream(-1, 0)); - Assertions.assertThrows(IndexOutOfBoundsException.class, () -> region.getOutputStream(0, -1)); - Assertions.assertThrows(IndexOutOfBoundsException.class, () -> region.getOutputStream(32, 0)); - Assertions.assertThrows(IndexOutOfBoundsException.class, () -> region.getOutputStream(0, 32)); - region.close(); - } - - @Test - void testChunkStoreRejectsOutOfBounds() { - ChunkStore chunkStore = new BitSetChunkStore(mockWorld, 0, 0); - Assertions.assertThrows(IndexOutOfBoundsException.class, () -> chunkStore.setTrue(-1, 0, 0)); - Assertions.assertThrows(IndexOutOfBoundsException.class, () -> chunkStore.setTrue(0, -1, 0)); - Assertions.assertThrows(IndexOutOfBoundsException.class, () -> chunkStore.setTrue(0, 0, -1)); - Assertions.assertThrows(IndexOutOfBoundsException.class, () -> chunkStore.setTrue(16, 0, 0)); - Assertions.assertThrows(IndexOutOfBoundsException.class, () -> chunkStore.setTrue(0, mockWorld.getMaxHeight(), 0)); - Assertions.assertThrows(IndexOutOfBoundsException.class, () -> chunkStore.setTrue(0, 0, 16)); - } - - @Test - void testRegressionChunkMirrorBug() { - ChunkManager chunkManager = new HashChunkManager(); - Block mockBlockA = Mockito.mock(Block.class); - Mockito.when(mockBlockA.getX()).thenReturn(15); - Mockito.when(mockBlockA.getZ()).thenReturn(15); - Mockito.when(mockBlockA.getY()).thenReturn(0); - Mockito.when(mockBlockA.getWorld()).thenReturn(mockWorld); - Block mockBlockB = Mockito.mock(Block.class); - Mockito.when(mockBlockB.getX()).thenReturn(-15); - Mockito.when(mockBlockB.getZ()).thenReturn(-15); - Mockito.when(mockBlockB.getY()).thenReturn(0); - Mockito.when(mockBlockB.getWorld()).thenReturn(mockWorld); - - chunkManager.setTrue(mockBlockA); - chunkManager.setFalse(mockBlockB); - Assertions.assertTrue(chunkManager.isTrue(mockBlockA)); - } - - private void assertEqual(ChunkStore expected, ChunkStore actual) { - Assertions.assertEquals(expected.getChunkMin(), actual.getChunkMin()); - Assertions.assertEquals(expected.getChunkMax(), actual.getChunkMax()); - assertEqualIgnoreMinMax(expected, actual); - } - - private void assertEqualIgnoreMinMax(ChunkStore expected, ChunkStore actual) { - Assertions.assertEquals(expected.getChunkX(), actual.getChunkX()); - Assertions.assertEquals(expected.getChunkZ(), actual.getChunkZ()); - Assertions.assertEquals(expected.getWorldId(), actual.getWorldId()); - for (int y = Math.min(actual.getChunkMin(), expected.getChunkMin()); y < Math.max(actual.getChunkMax(), expected.getChunkMax()); y++) { - if (expected.getChunkMin() > y || actual.getChunkMin() > y || expected.getChunkMax() <= y || actual.getChunkMax() <= y) - continue; // Ignore - for (int x = 0; x < 16; x++) - for (int z = 0; z < 16; z++) - Assertions.assertEquals(expected.isTrue(x, y, z), actual.isTrue(x, y, z)); - } - } - - private static byte[] serializeChunkstore(@NotNull ChunkStore chunkStore) throws IOException { - ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); - if (chunkStore instanceof BitSetChunkStore) - BitSetChunkStore.Serialization.writeChunkStore(new DataOutputStream(byteArrayOutputStream), chunkStore); - else - new UnitTestObjectOutputStream(byteArrayOutputStream).writeObject(chunkStore); // Serializes the class as if - // it were the old - // PrimitiveChunkStore - return byteArrayOutputStream.toByteArray(); - } - - public static class LegacyChunkStore implements ChunkStore, Serializable { - private static final long serialVersionUID = -1L; - transient private boolean dirty = false; - public boolean[][][] store; - private static final int CURRENT_VERSION = 7; - private static final int MAGIC_NUMBER = 0xEA5EDEBB; - private final int cx; - private final int cz; - private final @NotNull UUID worldUid; - - public LegacyChunkStore(@NotNull World world, int cx, int cz) { - this.cx = cx; - this.cz = cz; - this.worldUid = world.getUID(); - this.store = new boolean[16][16][world.getMaxHeight()]; - } - - @Override - public boolean isDirty() { - return dirty; - } - - @Override - public void setDirty(boolean dirty) { - this.dirty = dirty; - } - - @Override - public int getChunkX() { - return cx; - } - - @Override - public int getChunkZ() { - return cz; - } - - @Override - public int getChunkMin() { - return 0; - } - - @Override - public int getChunkMax() { - return store[0][0].length; - } - - @Override - public @NotNull UUID getWorldId() { - return worldUid; - } - - @Override - public boolean isTrue(int x, int y, int z) { - return store[x][z][y]; - } - - @Override - public void setTrue(int x, int y, int z) { - if (y >= store[0][0].length || y < 0) - return; - store[x][z][y] = true; - dirty = true; - } - - @Override - public void setFalse(int x, int y, int z) { - if (y >= store[0][0].length || y < 0) - return; - store[x][z][y] = false; - dirty = true; - } - - @Override - public void set(int x, int y, int z, boolean value) { - if (y >= store[0][0].length || y < 0) - return; - store[x][z][y] = value; - dirty = true; - } - - @Override - public boolean isEmpty() { - for (int x = 0; x < 16; x++) { - for (int z = 0; z < 16; z++) { - for (int y = 0; y < store[0][0].length; y++) { - if (store[x][z][y]) { - return false; - } - } - } - } - return true; - } - - private void writeObject(@NotNull ObjectOutputStream out) throws IOException { - out.writeInt(MAGIC_NUMBER); - out.writeInt(CURRENT_VERSION); - - out.writeLong(worldUid.getLeastSignificantBits()); - out.writeLong(worldUid.getMostSignificantBits()); - out.writeInt(cx); - out.writeInt(cz); - out.writeObject(store); - - dirty = false; - } - - private void readObject(@NotNull ObjectInputStream in) throws IOException, ClassNotFoundException { - throw new UnsupportedOperationException(); - } - - } - - private static class UnitTestObjectOutputStream extends ObjectOutputStream { - - public UnitTestObjectOutputStream(@NotNull OutputStream outputStream) throws IOException { - super(outputStream); - } - - @Override - public void writeUTF(@NotNull String str) throws IOException { - // Pretend to be the old class - if (str.equals(LegacyChunkStore.class.getName())) - str = "com.gmail.nossr50.util.blockmeta.chunkmeta.PrimitiveChunkStore"; - super.writeUTF(str); - } - - } - - @NotNull - private Block initMockBlock(int x, int y, int z) { - Block mockBlock = Mockito.mock(Block.class); - Mockito.when(mockBlock.getX()).thenReturn(x); - Mockito.when(mockBlock.getY()).thenReturn(y); - Mockito.when(mockBlock.getZ()).thenReturn(z); - Mockito.when(mockBlock.getWorld()).thenReturn(mockWorld); - return mockBlock; - } - - public static void recursiveDelete(@NotNull File directoryToBeDeleted) { - if (directoryToBeDeleted.isDirectory()) { - for (File file : directoryToBeDeleted.listFiles()) { - recursiveDelete(file); - } - } - directoryToBeDeleted.delete(); - } -} +} \ No newline at end of file diff --git a/src/test/java/com/gmail/nossr50/util/blockmeta/LegacyChunkStore.java b/src/test/java/com/gmail/nossr50/util/blockmeta/LegacyChunkStore.java new file mode 100644 index 000000000..d01b71e53 --- /dev/null +++ b/src/test/java/com/gmail/nossr50/util/blockmeta/LegacyChunkStore.java @@ -0,0 +1,130 @@ +package com.gmail.nossr50.util.blockmeta; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.UUID; +import org.bukkit.World; +import org.jetbrains.annotations.NotNull; + +/** + * Used for unit testing upgrades from the old ChunkStore class. + */ +class LegacyChunkStore implements ChunkStore, Serializable { + private static final long serialVersionUID = -1L; + transient private boolean dirty = false; + public boolean[][][] store; + private static final int CURRENT_VERSION = 7; + private static final int MAGIC_NUMBER = 0xEA5EDEBB; + private final int cx; + private final int cz; + private final @NotNull UUID worldUid; + + public LegacyChunkStore(@NotNull World world, int cx, int cz) { + this.cx = cx; + this.cz = cz; + this.worldUid = world.getUID(); + this.store = new boolean[16][16][world.getMaxHeight()]; + } + + @Override + public boolean isDirty() { + return dirty; + } + + @Override + public void setDirty(boolean dirty) { + this.dirty = dirty; + } + + @Override + public int getChunkX() { + return cx; + } + + @Override + public int getChunkZ() { + return cz; + } + + @Override + public int getChunkMin() { + return 0; + } + + @Override + public int getChunkMax() { + return store[0][0].length; + } + + @Override + public @NotNull UUID getWorldId() { + return worldUid; + } + + @Override + public boolean isTrue(int x, int y, int z) { + return store[x][z][y]; + } + + @Override + public void setTrue(int x, int y, int z) { + if (y >= store[0][0].length || y < 0) { + return; + } + store[x][z][y] = true; + dirty = true; + } + + @Override + public void setFalse(int x, int y, int z) { + if (y >= store[0][0].length || y < 0) { + return; + } + store[x][z][y] = false; + dirty = true; + } + + @Override + public void set(int x, int y, int z, boolean value) { + if (y >= store[0][0].length || y < 0) { + return; + } + store[x][z][y] = value; + dirty = true; + } + + @Override + public boolean isEmpty() { + for (int x = 0; x < 16; x++) { + for (int z = 0; z < 16; z++) { + for (int y = 0; y < store[0][0].length; y++) { + if (store[x][z][y]) { + return false; + } + } + } + } + return true; + } + + private void writeObject(@NotNull ObjectOutputStream out) throws IOException { + out.writeInt(MAGIC_NUMBER); + out.writeInt(CURRENT_VERSION); + + out.writeLong(worldUid.getLeastSignificantBits()); + out.writeLong(worldUid.getMostSignificantBits()); + out.writeInt(cx); + out.writeInt(cz); + out.writeObject(store); + + dirty = false; + } + + private void readObject(@NotNull ObjectInputStream in) + throws IOException, ClassNotFoundException { + throw new UnsupportedOperationException(); + } + +} diff --git a/src/test/java/com/gmail/nossr50/util/blockmeta/UnitTestObjectOutputStream.java b/src/test/java/com/gmail/nossr50/util/blockmeta/UnitTestObjectOutputStream.java new file mode 100644 index 000000000..5ad834517 --- /dev/null +++ b/src/test/java/com/gmail/nossr50/util/blockmeta/UnitTestObjectOutputStream.java @@ -0,0 +1,23 @@ +package com.gmail.nossr50.util.blockmeta; + +import java.io.IOException; +import java.io.ObjectOutputStream; +import java.io.OutputStream; +import org.jetbrains.annotations.NotNull; + +class UnitTestObjectOutputStream extends ObjectOutputStream { + + public UnitTestObjectOutputStream(@NotNull OutputStream outputStream) throws IOException { + super(outputStream); + } + + @Override + public void writeUTF(@NotNull String str) throws IOException { + // Pretend to be the old class + if (str.equals(LegacyChunkStore.class.getName())) { + str = "com.gmail.nossr50.util.blockmeta.chunkmeta.PrimitiveChunkStore"; + } + super.writeUTF(str); + } + +} diff --git a/src/test/java/com/gmail/nossr50/util/blockmeta/UserBlockTrackerTest.java b/src/test/java/com/gmail/nossr50/util/blockmeta/UserBlockTrackerTest.java new file mode 100644 index 000000000..d9279d05a --- /dev/null +++ b/src/test/java/com/gmail/nossr50/util/blockmeta/UserBlockTrackerTest.java @@ -0,0 +1,235 @@ +package com.gmail.nossr50.util.blockmeta; + +import static com.gmail.nossr50.util.blockmeta.BlockStoreTestUtils.LEGACY_WORLD_HEIGHT_MAX; +import static com.gmail.nossr50.util.blockmeta.BlockStoreTestUtils.LEGACY_WORLD_HEIGHT_MIN; +import static org.bukkit.Bukkit.getWorld; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.when; + +import com.gmail.nossr50.mcMMO; +import com.gmail.nossr50.util.BlockUtils; +import com.google.common.io.Files; +import java.io.File; +import java.io.IOException; +import java.util.UUID; +import org.bukkit.Bukkit; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.jetbrains.annotations.NotNull; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +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; + +/** + * Could be a lot better. But some tests are better than none! Tests the major things, still kinda + * unit-testy. Verifies that the serialization isn't completely broken. + */ +class UserBlockTrackerTest { + private static File tempDir; + + @BeforeAll + public static void setUpClass() { + tempDir = Files.createTempDir(); + } + + @AfterAll + public static void tearDownClass() { + recursiveDelete(tempDir); + } + + private World mockWorld; + + private MockedStatic bukkitMock; + private MockedStatic mcMMOMock; + + @BeforeEach + void setUpMock() { + UUID worldUUID = UUID.randomUUID(); + mockWorld = Mockito.mock(World.class); + when(mockWorld.getUID()).thenReturn(worldUUID); + when(mockWorld.getMaxHeight()).thenReturn(256); + when(mockWorld.getWorldFolder()).thenReturn(tempDir); + + bukkitMock = mockStatic(Bukkit.class); + bukkitMock.when(() -> getWorld(worldUUID)).thenReturn(mockWorld); + + mcMMOMock = mockStatic(mcMMO.class); + + when(mockWorld.getMinHeight()).thenReturn(LEGACY_WORLD_HEIGHT_MIN); + when(mockWorld.getMaxHeight()).thenReturn(LEGACY_WORLD_HEIGHT_MAX); + } + + @AfterEach + void teardownMock() { + bukkitMock.close(); + mcMMOMock.close(); + } + + @Test + void setIneligibleShouldThrowIndexOutOfBoundsException() { + when(mockWorld.getMinHeight()).thenReturn(-64); + final HashChunkManager hashChunkManager = new HashChunkManager(); + + // Top Block + int illegalMaxHeight = 256 + 1; + final Block illegalHeightBlock = initMockBlock(1337, illegalMaxHeight, -1337); + Assertions.assertThrows(IndexOutOfBoundsException.class, + () -> hashChunkManager.setIneligible(illegalHeightBlock)); + + int illegalMinHeight = -65; + final Block otherIllegalHeightBlock = initMockBlock(1337, illegalMinHeight, -1337); + Assertions.assertThrows(IndexOutOfBoundsException.class, + () -> hashChunkManager.setIneligible(otherIllegalHeightBlock)); + } + + @Test + void testSetEligibility() { + when(mockWorld.getMinHeight()).thenReturn(-64); + final HashChunkManager hashChunkManager = new HashChunkManager(); + int radius = 2; // Could be anything but drastically changes test time + + for (int x = -radius; x <= radius; x++) { + for (int y = mockWorld.getMinHeight(); y <= mockWorld.getMaxHeight(); y++) { + for (int z = -radius; z <= radius; z++) { + final Block testBlock = initMockBlock(x, y, z); + // mark ineligible + hashChunkManager.setIneligible(testBlock); + assertTrue(hashChunkManager.isIneligible(testBlock)); + + // mark eligible + hashChunkManager.setEligible(testBlock); + // Might as well test both isIneligible and isEligible while we are here + assertFalse(hashChunkManager.isIneligible(testBlock)); + assertTrue(hashChunkManager.isEligible(testBlock)); + } + } + } + + // TODO: Whatever is going on down here should be in its own test + // Bot Block + final Block bottomBlock = initMockBlock(1337, 0, -1337); + assertFalse(hashChunkManager.isIneligible(bottomBlock)); + + assertTrue(BlockUtils.isWithinWorldBounds(bottomBlock)); + hashChunkManager.setIneligible(bottomBlock); + assertTrue(hashChunkManager.isIneligible(bottomBlock)); + + // Top Block + final Block topBlock = initMockBlock(1337, 255, -1337); + assertFalse(hashChunkManager.isIneligible(topBlock)); + + assertTrue(BlockUtils.isWithinWorldBounds(topBlock)); + hashChunkManager.setIneligible(topBlock); + assertTrue(hashChunkManager.isIneligible(topBlock)); + } + + @Test + void testChunkCoords() throws IOException { + // TODO: Unfinished test? + for (int x = -96; x < 0; x++) { + int cx = x >> 4; + int ix = Math.abs(x) % 16; + //System.out.print(cx + ":" + ix + " "); + } + } + + @Test + void testSimpleRegionRejectsOutOfBounds() { + File file = new File(tempDir, "SimpleRegionRoundTrip.region"); + McMMOSimpleRegionFile region = new McMMOSimpleRegionFile(file, 0, 0); + Assertions.assertThrows(IndexOutOfBoundsException.class, + () -> region.getOutputStream(-1, 0)); + Assertions.assertThrows(IndexOutOfBoundsException.class, + () -> region.getOutputStream(0, -1)); + Assertions.assertThrows(IndexOutOfBoundsException.class, + () -> region.getOutputStream(32, 0)); + Assertions.assertThrows(IndexOutOfBoundsException.class, + () -> region.getOutputStream(0, 32)); + region.close(); + } + + @Test + void testChunkStoreRejectsOutOfBounds() { + ChunkStore chunkStore = new BitSetChunkStore(mockWorld, 0, 0); + Assertions.assertThrows(IndexOutOfBoundsException.class, + () -> chunkStore.setTrue(-1, 0, 0)); + Assertions.assertThrows(IndexOutOfBoundsException.class, + () -> chunkStore.setTrue(0, -1, 0)); + Assertions.assertThrows(IndexOutOfBoundsException.class, + () -> chunkStore.setTrue(0, 0, -1)); + Assertions.assertThrows(IndexOutOfBoundsException.class, + () -> chunkStore.setTrue(16, 0, 0)); + Assertions.assertThrows(IndexOutOfBoundsException.class, + () -> chunkStore.setTrue(0, mockWorld.getMaxHeight() + 1, 0)); + Assertions.assertThrows(IndexOutOfBoundsException.class, + () -> chunkStore.setTrue(0, mockWorld.getMinHeight() - 1, 0)); + Assertions.assertThrows(IndexOutOfBoundsException.class, + () -> chunkStore.setTrue(0, 0, 16)); + } + + @Test + void testRegressionChunkMirrorBug() { + final UserBlockTracker chunkManager = new HashChunkManager(); + Block mockBlockA = Mockito.mock(Block.class); + when(mockBlockA.getX()).thenReturn(15); + when(mockBlockA.getZ()).thenReturn(15); + when(mockBlockA.getY()).thenReturn(0); + when(mockBlockA.getWorld()).thenReturn(mockWorld); + Block mockBlockB = Mockito.mock(Block.class); + when(mockBlockB.getX()).thenReturn(-15); + when(mockBlockB.getZ()).thenReturn(-15); + when(mockBlockB.getY()).thenReturn(0); + when(mockBlockB.getWorld()).thenReturn(mockWorld); + + chunkManager.setIneligible(mockBlockA); + chunkManager.setEligible(mockBlockB); + assertTrue(chunkManager.isIneligible(mockBlockA)); + } + + @Test + void testUnload() { + final ChunkManager chunkManager = new HashChunkManager(); + Block mockBlockA = Mockito.mock(Block.class); + when(mockBlockA.getX()).thenReturn(15); + when(mockBlockA.getZ()).thenReturn(15); + when(mockBlockA.getY()).thenReturn(0); + when(mockBlockA.getWorld()).thenReturn(mockWorld); + Block mockBlockB = Mockito.mock(Block.class); + when(mockBlockB.getX()).thenReturn(-15); + when(mockBlockB.getZ()).thenReturn(-15); + when(mockBlockB.getY()).thenReturn(0); + when(mockBlockB.getWorld()).thenReturn(mockWorld); + + chunkManager.setIneligible(mockBlockA); + chunkManager.setEligible(mockBlockB); + assertTrue(chunkManager.isIneligible(mockBlockA)); + + chunkManager.chunkUnloaded(0, 0, mockWorld); + } + + @NotNull + private Block initMockBlock(int x, int y, int z) { + final Block mockBlock = Mockito.mock(Block.class); + when(mockBlock.getX()).thenReturn(x); + when(mockBlock.getY()).thenReturn(y); + when(mockBlock.getZ()).thenReturn(z); + when(mockBlock.getWorld()).thenReturn(mockWorld); + return mockBlock; + } + + public static void recursiveDelete(@NotNull File directoryToBeDeleted) { + if (directoryToBeDeleted.isDirectory()) { + for (File file : directoryToBeDeleted.listFiles()) { + recursiveDelete(file); + } + } + directoryToBeDeleted.delete(); + } +} diff --git a/src/test/java/com/gmail/nossr50/util/platform/MinecraftGameVersionTest.java b/src/test/java/com/gmail/nossr50/util/platform/MinecraftGameVersionTest.java index 11c0d4060..84c9adda2 100644 --- a/src/test/java/com/gmail/nossr50/util/platform/MinecraftGameVersionTest.java +++ b/src/test/java/com/gmail/nossr50/util/platform/MinecraftGameVersionTest.java @@ -1,6 +1,12 @@ package com.gmail.nossr50.util.platform; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + import com.gmail.nossr50.mcMMO; +import java.util.logging.Logger; +import java.util.stream.Stream; import org.bukkit.Bukkit; import org.jetbrains.annotations.NotNull; import org.junit.jupiter.api.Test; @@ -10,11 +16,6 @@ import org.junit.jupiter.params.provider.MethodSource; import org.mockito.MockedStatic; import org.mockito.Mockito; -import java.util.logging.Logger; -import java.util.stream.Stream; - -import static org.junit.jupiter.api.Assertions.*; - class MinecraftGameVersionTest { @Test @@ -81,7 +82,8 @@ class MinecraftGameVersionTest { * we will just simulate some "Spigot" version here, so that the test can * continue successfully. */ - String serverSoftwareVersion = "git-Spigot-12345-abcdef (MC: " + major + '.' + minor + '.' + patch + ')'; + String serverSoftwareVersion = + "git-Spigot-12345-abcdef (MC: " + major + '.' + minor + '.' + patch + ')'; // Set up a mock plugin for logging. mcMMO plugin = Mockito.mock(mcMMO.class); @@ -111,19 +113,19 @@ class MinecraftGameVersionTest { * These samples were taken directly from the historical * data of CraftBukkit's pom.xml file: * https://hub.spigotmc.org/stash/projects/SPIGOT/repos/craftbukkit/browse/pom.xml - * + * * We should be safe to assume that forks follow these conventions and do not mess * with this version number (Spigot, Paper and Tuinity do at least). */ return Stream.of( - Arguments.of("1.13.2-R0.1-SNAPSHOT", 1, 13, 2), - Arguments.of("1.13-R0.2-SNAPSHOT", 1, 13, 0), - Arguments.of("1.13.2-R0.1-SNAPSHOT", 1, 13, 2), - Arguments.of("1.13-pre7-R0.1-SNAPSHOT", 1, 13, 0), - Arguments.of("1.14-pre5-SNAPSHOT", 1, 14, 0), - Arguments.of("1.15-R0.1-SNAPSHOT", 1, 15, 0), - Arguments.of("1.16.5-R0.1-SNAPSHOT", 1, 16, 5), - Arguments.of("1.17-R0.1-SNAPSHOT", 1, 17, 0) + Arguments.of("1.13.2-R0.1-SNAPSHOT", 1, 13, 2), + Arguments.of("1.13-R0.2-SNAPSHOT", 1, 13, 0), + Arguments.of("1.13.2-R0.1-SNAPSHOT", 1, 13, 2), + Arguments.of("1.13-pre7-R0.1-SNAPSHOT", 1, 13, 0), + Arguments.of("1.14-pre5-SNAPSHOT", 1, 14, 0), + Arguments.of("1.15-R0.1-SNAPSHOT", 1, 15, 0), + Arguments.of("1.16.5-R0.1-SNAPSHOT", 1, 16, 5), + Arguments.of("1.17-R0.1-SNAPSHOT", 1, 17, 0) ); } 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 000000000..b9ebaac79 --- /dev/null +++ b/src/test/java/com/gmail/nossr50/util/random/ProbabilityTest.java @@ -0,0 +1,107 @@ +package com.gmail.nossr50.util.random; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.stream.Stream; +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; + +class ProbabilityTest { + + private static Stream provideProbabilitiesForWithinExpectations() { + return Stream.of( + // static probability, % of time for success + Arguments.of(new ProbabilityImpl(.05), 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(.999), 99.9), + Arguments.of(new ProbabilityImpl(0.0005), 0.05), + Arguments.of(new ProbabilityImpl(0.001), 0.1), + Arguments.of(new ProbabilityImpl(50.0), 100), + Arguments.of(new ProbabilityImpl(100.0), 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(new ProbabilityImpl(100).evaluate()); + } + } + + @Test + void testAlwaysLoseConstructor() { + for (int i = 0; i < 100000; i++) { + assertFalse(new ProbabilityImpl(0).evaluate()); + } + } + + @Test + void testAlwaysWinOfPercent() { + for (int i = 0; i < 100000; i++) { + assertTrue(Probability.ofPercent(100).evaluate()); + } + } + + @Test + void testAlwaysLoseOfPercent() { + for (int i = 0; i < 100000; i++) { + assertFalse(Probability.ofPercent(0).evaluate()); + } + } + + @ParameterizedTest + @MethodSource("provideProbabilitiesForWithinExpectations") + void testOddsExpectationsConstructor(Probability probability, double expectedWinPercent) { + assertExpectations(probability, expectedWinPercent); + } + + @ParameterizedTest + @MethodSource("provideOfPercentageProbabilitiesForWithinExpectations") + void testOddsExpectationsOfPercent(Probability probability, double expectedWinPercent) { + assertExpectations(probability, expectedWinPercent); + } + + private static void assertExpectations(Probability probability, double expectedWinPercent) { + double iterations = 2.0e7; + double winCount = 0; + + for (int i = 0; i < iterations; i++) { + if (probability.evaluate()) { + winCount++; + } + } + + double successPercent = (winCount / iterations) * 100; + System.out.println(successPercent + ", " + expectedWinPercent); + assertEquals(expectedWinPercent, successPercent, 0.05D); + } +} diff --git a/src/test/java/com/gmail/nossr50/util/random/ProbabilityTestUtils.java b/src/test/java/com/gmail/nossr50/util/random/ProbabilityTestUtils.java new file mode 100644 index 000000000..6a6efcd4a --- /dev/null +++ b/src/test/java/com/gmail/nossr50/util/random/ProbabilityTestUtils.java @@ -0,0 +1,24 @@ +package com.gmail.nossr50.util.random; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class ProbabilityTestUtils { + public static void assertProbabilityExpectations(double expectedWinPercent, + Probability probability) { + double iterations = 2.0e7; //20 million + double winCount = 0; + for (int i = 0; i < iterations; i++) { + if (probability.evaluate()) { + winCount++; + } + } + + double successPercent = (winCount / iterations) * 100; + System.out.println("Wins: " + winCount); + System.out.println("Fails: " + (iterations - winCount)); + System.out.println( + "Percentage succeeded: " + successPercent + ", Expected: " + expectedWinPercent); + assertEquals(expectedWinPercent, successPercent, 0.035D); + System.out.println("Variance is within tolerance levels!"); + } +} 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 000000000..324ffacb1 --- /dev/null +++ b/src/test/java/com/gmail/nossr50/util/random/ProbabilityUtilTest.java @@ -0,0 +1,188 @@ +package com.gmail.nossr50.util.random; + +import static com.gmail.nossr50.datatypes.skills.PrimarySkillType.ACROBATICS; +import static com.gmail.nossr50.datatypes.skills.PrimarySkillType.MINING; +import static com.gmail.nossr50.datatypes.skills.SubSkillType.ACROBATICS_DODGE; +import static com.gmail.nossr50.datatypes.skills.SubSkillType.AXES_ARMOR_IMPACT; +import static com.gmail.nossr50.datatypes.skills.SubSkillType.AXES_GREATER_IMPACT; +import static com.gmail.nossr50.datatypes.skills.SubSkillType.MINING_DOUBLE_DROPS; +import static com.gmail.nossr50.datatypes.skills.SubSkillType.TAMING_FAST_FOOD_SERVICE; +import static com.gmail.nossr50.datatypes.skills.SubSkillType.UNARMED_ARROW_DEFLECT; +import static com.gmail.nossr50.util.random.ProbabilityTestUtils.assertProbabilityExpectations; +import static com.gmail.nossr50.util.random.ProbabilityUtil.calculateCurrentSkillProbability; +import static java.util.logging.Logger.getLogger; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.when; + +import com.gmail.nossr50.MMOTestEnvironment; +import com.gmail.nossr50.datatypes.skills.SubSkillType; +import java.util.logging.Logger; +import java.util.stream.Stream; +import org.junit.jupiter.api.AfterEach; +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; + +class ProbabilityUtilTest extends MMOTestEnvironment { + private static final Logger logger = getLogger(ProbabilityUtilTest.class.getName()); + + final static double impactChance = 11D; + final static double greaterImpactChance = 0.007D; + final static double fastFoodChance = 45.5D; + + @BeforeEach + public void setupMocks() { + mockBaseEnvironment(logger); + when(advancedConfig.getImpactChance()).thenReturn(impactChance); + when(advancedConfig.getGreaterImpactChance()).thenReturn(greaterImpactChance); + when(advancedConfig.getFastFoodChance()).thenReturn(fastFoodChance); + } + + @AfterEach + public void tearDown() { + cleanUpStaticMocks(); + } + + 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 staticChanceSkillsShouldSucceedAsExpected(SubSkillType subSkillType, + double expectedWinPercent) + throws InvalidStaticChance { + Probability staticRandomChance = ProbabilityUtil.getStaticRandomChance(subSkillType); + assertProbabilityExpectations(expectedWinPercent, staticRandomChance); + } + + @Test + public void isSkillRNGSuccessfulShouldBehaveAsExpected() { + // Given + when(advancedConfig.getMaximumProbability(UNARMED_ARROW_DEFLECT)).thenReturn(20D); + when(advancedConfig.getMaxBonusLevel(UNARMED_ARROW_DEFLECT)).thenReturn(0); + + @SuppressWarnings("all") final Probability probability = ProbabilityUtil.getSkillProbability( + UNARMED_ARROW_DEFLECT, mmoPlayer); + assertEquals(0.2D, probability.getValue()); + assertProbabilityExpectations(20, probability); + } + + private static Stream provideSkillProbabilityTestData() { + return Stream.of( + // skillLevel, floor, ceiling, maxBonusLevel, expectedValue + + // 20% chance at skill level 1000 + Arguments.of(1000, 0, 20, 1000, 0.2), + // 10% chance at skill level 500 + Arguments.of(500, 0, 20, 1000, 0.1), + // 5% chance at skill level 250 + Arguments.of(250, 0, 20, 1000, 0.05), + // 0% chance at skill level 0 + Arguments.of(0, 0, 20, 1000, 0.0), + // 0% chance at skill level 1000 + Arguments.of(1000, 0, 0, 1000, 0.0), + // 1% chance at skill level 1000 + Arguments.of(1000, 0, 1, 1000, 0.01) + ); + } + + @ParameterizedTest + @MethodSource("provideSkillProbabilityTestData") + void testCalculateCurrentSkillProbability(double skillLevel, double floor, double ceiling, + double maxBonusLevel, + double expectedValue) { + // When + final Probability probability = calculateCurrentSkillProbability(skillLevel, floor, ceiling, + maxBonusLevel); + + // Then + assertEquals(expectedValue, probability.getValue()); + } + + @Test + public void getRNGDisplayValuesShouldReturn10PercentForDodge() { + // Given + when(advancedConfig.getMaximumProbability(ACROBATICS_DODGE)).thenReturn(20D); + when(advancedConfig.getMaxBonusLevel(ACROBATICS_DODGE)).thenReturn(1000); + mmoPlayer.modifySkill(ACROBATICS, 500); + + // When & Then + final String[] rngDisplayValues = ProbabilityUtil.getRNGDisplayValues(mmoPlayer, + ACROBATICS_DODGE); + assertEquals("10.00%", rngDisplayValues[0]); + } + + @Test + public void getRNGDisplayValuesShouldReturn20PercentForDodge() { + // Given + when(advancedConfig.getMaximumProbability(ACROBATICS_DODGE)).thenReturn(20D); + when(advancedConfig.getMaxBonusLevel(ACROBATICS_DODGE)).thenReturn(1000); + mmoPlayer.modifySkill(ACROBATICS, 1000); + + // When & then + final String[] rngDisplayValues = ProbabilityUtil.getRNGDisplayValues(mmoPlayer, + ACROBATICS_DODGE); + assertEquals("20.00%", rngDisplayValues[0]); + } + + @Test + public void getRNGDisplayValuesShouldReturn0PercentForDodge() { + // Given + when(advancedConfig.getMaximumProbability(ACROBATICS_DODGE)).thenReturn(20D); + when(advancedConfig.getMaxBonusLevel(ACROBATICS_DODGE)).thenReturn(1000); + mmoPlayer.modifySkill(ACROBATICS, 0); + + // When & then + final String[] rngDisplayValues = ProbabilityUtil.getRNGDisplayValues(mmoPlayer, + ACROBATICS_DODGE); + assertEquals("0.00%", rngDisplayValues[0]); + } + + @Test + public void getRNGDisplayValuesShouldReturn10PercentForDoubleDrops() { + // Given + when(advancedConfig.getMaximumProbability(MINING_DOUBLE_DROPS)).thenReturn(100D); + when(advancedConfig.getMaxBonusLevel(MINING_DOUBLE_DROPS)).thenReturn(1000); + mmoPlayer.modifySkill(MINING, 100); + + // When & Then + final String[] rngDisplayValues = ProbabilityUtil.getRNGDisplayValues(mmoPlayer, + MINING_DOUBLE_DROPS); + assertEquals("10.00%", rngDisplayValues[0]); + } + + @Test + public void getRNGDisplayValuesShouldReturn50PercentForDoubleDrops() { + // Given + when(advancedConfig.getMaximumProbability(MINING_DOUBLE_DROPS)).thenReturn(100D); + when(advancedConfig.getMaxBonusLevel(MINING_DOUBLE_DROPS)).thenReturn(1000); + mmoPlayer.modifySkill(MINING, 500); + + // When & Then + final String[] rngDisplayValues = ProbabilityUtil.getRNGDisplayValues(mmoPlayer, + MINING_DOUBLE_DROPS); + assertEquals("50.00%", rngDisplayValues[0]); + } + + @Test + public void getRNGDisplayValuesShouldReturn100PercentForDoubleDrops() { + // Given + when(advancedConfig.getMaximumProbability(MINING_DOUBLE_DROPS)).thenReturn(100D); + when(advancedConfig.getMaxBonusLevel(MINING_DOUBLE_DROPS)).thenReturn(1000); + mmoPlayer.modifySkill(MINING, 1000); + + // When & Then + final String[] rngDisplayValues = ProbabilityUtil.getRNGDisplayValues(mmoPlayer, + MINING_DOUBLE_DROPS); + assertEquals("100.00%", rngDisplayValues[0]); + } + +} 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 f28e7e842..000000000 --- a/src/test/java/com/gmail/nossr50/util/random/RandomChanceTest.java +++ /dev/null @@ -1,116 +0,0 @@ -//package com.gmail.nossr50.util.random; -// -//import com.gmail.nossr50.datatypes.player.McMMOPlayer; -//import com.gmail.nossr50.datatypes.skills.PrimarySkillType; -//import com.gmail.nossr50.datatypes.skills.SubSkillType; -//import com.gmail.nossr50.util.Permissions; -//import com.gmail.nossr50.util.player.UserManager; -//import org.bukkit.entity.Player; -//import org.jetbrains.annotations.NotNull; -//import org.junit.Assert; -//import org.junit.Before; -//import org.junit.Test; -//import org.junit.runner.RunWith; -//import org.mockito.Mockito; -//import org.powermock.api.mockito.PowerMockito; -//import org.powermock.core.classloader.annotations.PrepareForTest; -//import org.powermock.modules.junit4.PowerMockRunner; -// -//import static org.mockito.Mockito.mock; -// -////TODO: Rewrite the entire com.gmail.nossr50.util.random package, it was written in haste and it disgusts me -////TODO: Add more tests for the other types of random dice rolls -//@RunWith(PowerMockRunner.class) -//@PrepareForTest({RandomChanceUtil.class, UserManager.class}) -//public class RandomChanceTest { -// -// private Player luckyPlayer; -// private McMMOPlayer mmoPlayerLucky; -// -// private Player normalPlayer; -// private McMMOPlayer mmoPlayerNormal; -// -// private SubSkillType subSkillType; -// private PrimarySkillType primarySkillType; -// -// private final String testASCIIHeader = "---- mcMMO Tests ----"; -// -// @Before -// public void setUpMock() { -// primarySkillType = PrimarySkillType.HERBALISM; -// subSkillType = SubSkillType.HERBALISM_GREEN_THUMB; -// -// //TODO: Likely needs to be changed per skill if more tests were added -// PowerMockito.stub(PowerMockito.method(RandomChanceUtil.class, "getMaximumProbability", subSkillType.getClass())).toReturn(100D); -// PowerMockito.stub(PowerMockito.method(RandomChanceUtil.class, "getMaxBonusLevelCap", subSkillType.getClass())).toReturn(1000D); -// -// normalPlayer = mock(Player.class); -// luckyPlayer = mock(Player.class); -// -// mmoPlayerNormal = mock(McMMOPlayer.class); -// mmoPlayerLucky = mock(McMMOPlayer.class); -// -// PowerMockito.mockStatic(UserManager.class); -// Mockito.when(UserManager.getPlayer(normalPlayer)).thenReturn(mmoPlayerNormal); -// Mockito.when(UserManager.getPlayer(luckyPlayer)).thenReturn(mmoPlayerLucky); -// -// Mockito.when(mmoPlayerNormal.getPlayer()).thenReturn(normalPlayer); -// Mockito.when(mmoPlayerLucky.getPlayer()).thenReturn(luckyPlayer); -// -// //Lucky player has the lucky permission -// //Normal player doesn't have any lucky permission -// Mockito.when(Permissions.lucky(luckyPlayer, primarySkillType)).thenReturn(true); -// Mockito.when(Permissions.lucky(normalPlayer, primarySkillType)).thenReturn(false); -// -// Mockito.when(mmoPlayerNormal.getSkillLevel(primarySkillType)).thenReturn(800); -// Mockito.when(mmoPlayerLucky.getSkillLevel(primarySkillType)).thenReturn(800); -// } -// -// @Test -// public void testLuckyChance() { -// System.out.println(testASCIIHeader); -// System.out.println("Testing success odds to fall within expected values..."); -// assertEquals(80D, getSuccessChance(mmoPlayerNormal),0D); -// assertEquals(80D * RandomChanceUtil.LUCKY_MODIFIER, getSuccessChance(mmoPlayerLucky),0D); -// } -// -// @Test -// public void testNeverFailsSuccessLuckyPlayer() { -// System.out.println(testASCIIHeader); -// System.out.println("Test - Lucky Player with 80% base success should never fail (10,000 iterations)"); -// for(int x = 0; x < 10000; x++) { -// Assert.assertTrue(RandomChanceUtil.checkRandomChanceExecutionSuccess(luckyPlayer, SubSkillType.HERBALISM_GREEN_THUMB, true)); -// if(x == 10000-1) -// System.out.println("They never failed!"); -// } -// } -// -// @Test -// public void testFailsAboutExpected() { -// System.out.println(testASCIIHeader); -// System.out.println("Test - Player with 800 skill should fail about 20% of the time (100,000 iterations)"); -// double ratioDivisor = 1000; //1000 because we run the test 100,000 times -// double expectedFailRate = 20D; -// -// double win = 0, loss = 0; -// for(int x = 0; x < 100000; x++) { -// if(RandomChanceUtil.checkRandomChanceExecutionSuccess(normalPlayer, SubSkillType.HERBALISM_GREEN_THUMB, true)) { -// win++; -// } else { -// loss++; -// } -// } -// -// double lossRatio = (loss / ratioDivisor); -// Assert.assertEquals(lossRatio, expectedFailRate, 1D); -// } -// -// private double getSuccessChance(@NotNull McMMOPlayer mmoPlayer) { -// RandomChanceSkill randomChanceSkill = new RandomChanceSkill(mmoPlayer.getPlayer(), subSkillType, true); -// return RandomChanceUtil.calculateChanceOfSuccess(randomChanceSkill); -// } -// -// private void assertEquals(double expected, double actual, double delta) { -// Assert.assertEquals(expected, actual, delta); -// } -//} 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 4a295d5d3..000000000 --- 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 diff --git a/src/test/java/com/gmail/nossr50/util/text/StringUtilsTest.java b/src/test/java/com/gmail/nossr50/util/text/StringUtilsTest.java new file mode 100644 index 000000000..1656229e7 --- /dev/null +++ b/src/test/java/com/gmail/nossr50/util/text/StringUtilsTest.java @@ -0,0 +1,326 @@ +package com.gmail.nossr50.util.text; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + +import com.gmail.nossr50.datatypes.skills.SuperAbilityType; +import org.bukkit.Material; +import org.bukkit.entity.EntityType; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class StringUtilsTest { + + @BeforeEach + void setUp() { + // Clear caches before each test to ensure test isolation + clearCaches(); + } + + /** + * Utility method to clear all caches in StringUtils. Reflection is used since the caches are + * private. + */ + private void clearCaches() { + try { + java.lang.reflect.Field entityCache = StringUtils.class.getDeclaredField( + "formattedEntityStrings"); + entityCache.setAccessible(true); + ((java.util.Map) entityCache.get(null)).clear(); + + java.lang.reflect.Field superAbilityCache = StringUtils.class.getDeclaredField( + "formattedSuperAbilityStrings"); + superAbilityCache.setAccessible(true); + ((java.util.Map) superAbilityCache.get(null)).clear(); + + java.lang.reflect.Field materialCache = StringUtils.class.getDeclaredField( + "formattedMaterialStrings"); + materialCache.setAccessible(true); + ((java.util.Map) materialCache.get(null)).clear(); + } catch (NoSuchFieldException | IllegalAccessException e) { + fail("Failed to clear caches: " + e.getMessage()); + } + } + + // Tests for getCapitalized(String target) + @Test + void testGetCapitalized_NullInput() { + assertNull(StringUtils.getCapitalized(null)); + } + + @Test + void testGetCapitalized_EmptyString() { + assertEquals("", StringUtils.getCapitalized("")); + } + + @Test + void testGetCapitalized_SingleCharacter() { + assertEquals("A", StringUtils.getCapitalized("a")); + assertEquals("Z", StringUtils.getCapitalized("Z")); + } + + @Test + void testGetCapitalized_AllUppercase() { + assertEquals("Test", StringUtils.getCapitalized("TEST")); + } + + @Test + void testGetCapitalized_AllLowercase() { + assertEquals("Test", StringUtils.getCapitalized("test")); + } + + @Test + void testGetCapitalized_MixedCase() { + assertEquals("Test", StringUtils.getCapitalized("tEsT")); + } + + @Test + void testGetCapitalized_NonASCII() { + assertEquals("Ñandú", StringUtils.getCapitalized("ñandú")); + } + + // Tests for ticksToSeconds(double ticks) + @Test + void testTicksToSeconds_PositiveTicks() { + assertEquals("1.5", StringUtils.ticksToSeconds(30)); + } + + @Test + void testTicksToSeconds_ZeroTicks() { + assertEquals("0.0", StringUtils.ticksToSeconds(0)); + } + + @Test + void testTicksToSeconds_FractionalTicks() { + assertEquals("1.5", StringUtils.ticksToSeconds(30.0)); + assertEquals("1.5", StringUtils.ticksToSeconds(30.0)); + assertEquals("1.0", StringUtils.ticksToSeconds(20.0)); + assertEquals("0.1", StringUtils.ticksToSeconds(2.0)); + } + + @Test + void testTicksToSeconds_NegativeTicks() { + assertEquals("-1.0", StringUtils.ticksToSeconds(-20)); + } + + // Tests for getPrettySuperAbilityString(SuperAbilityType superAbilityType) + @Test + void testGetPrettySuperAbilityString_NullInput() { + assertThrows(NullPointerException.class, () -> { + StringUtils.getPrettySuperAbilityString(null); + }); + } + + @Test + void testGetPrettySuperAbilityString_ValidInput() { + SuperAbilityType superAbilityType = SuperAbilityType.SUPER_BREAKER; + String expected = "Super Breaker"; + String actual = StringUtils.getPrettySuperAbilityString(superAbilityType); + assertEquals(expected, actual); + } + + @Test + void testGetPrettySuperAbilityString_Caching() { + SuperAbilityType superAbilityType = SuperAbilityType.SUPER_BREAKER; + + // First call should compute and cache + String firstCall = StringUtils.getPrettySuperAbilityString(superAbilityType); + + // Second call should retrieve from cache + String secondCall = StringUtils.getPrettySuperAbilityString(superAbilityType); + + assertSame(firstCall, secondCall, "Cached value should be the same instance"); + } + + // Tests for getPrettyEntityTypeString(EntityType entityType) + @Test + void testGetPrettyEntityTypeString_ValidInput() { + EntityType zombie = EntityType.ZOMBIE; + String expected = "Zombie"; + String actual = StringUtils.getPrettyEntityTypeString(zombie); + assertEquals(expected, actual); + } + + @Test + void testGetPrettyEntityTypeString_WithUnderscores() { + EntityType entity = EntityType.SKELETON_HORSE; + String expected = "Skeleton Horse"; + String actual = StringUtils.getPrettyEntityTypeString(entity); + assertEquals(expected, actual); + } + + @Test + void testGetPrettyEntityTypeString_Caching() { + EntityType skeleton = EntityType.SKELETON; + + // First call should compute and cache + String firstCall = StringUtils.getPrettyEntityTypeString(skeleton); + + // Second call should retrieve from cache + String secondCall = StringUtils.getPrettyEntityTypeString(skeleton); + + assertSame(firstCall, secondCall, "Cached value should be the same instance"); + } + + // Tests for getFormattedMaterialString(Material material) + @Test + void testGetPrettyMaterialString_ValidInput() { + Material diamondSword = Material.DIAMOND_SWORD; + String expected = "Diamond Sword"; + String actual = StringUtils.getPrettyMaterialString(diamondSword); + assertEquals(expected, actual); + } + + @Test + void testGetPrettyMaterialString_WithUnderscores() { + Material goldenApple = Material.GOLDEN_APPLE; + String expected = "Golden Apple"; + String actual = StringUtils.getPrettyMaterialString(goldenApple); + assertEquals(expected, actual); + } + + @Test + void testGetPrettyMaterialString_Caching() { + Material ironPickaxe = Material.IRON_PICKAXE; + + // First call should compute and cache + String firstCall = StringUtils.getPrettyMaterialString(ironPickaxe); + + // Second call should retrieve from cache + String secondCall = StringUtils.getPrettyMaterialString(ironPickaxe); + + assertSame(firstCall, secondCall, "Cached value should be the same instance"); + } + + // Tests for buildStringAfterNthElement(String[] args, int index) + @Test + void testBuildStringAfterNthElement_IndexZero() { + String[] args = {"Hello", "World", "Test"}; + String expected = "Hello World Test"; + String actual = StringUtils.buildStringAfterNthElement(args, 0); + assertEquals(expected, actual); + } + + @Test + void testBuildStringAfterNthElement_IndexMiddle() { + String[] args = {"This", "is", "a", "test"}; + String expected = "a test"; + String actual = StringUtils.buildStringAfterNthElement(args, 2); + assertEquals(expected, actual); + } + + @Test + void testBuildStringAfterNthElement_IndexLast() { + String[] args = {"Only", "One"}; + String expected = "One"; + String actual = StringUtils.buildStringAfterNthElement(args, 1); + assertEquals(expected, actual); + } + + @Test + void testBuildStringAfterNthElement_IndexOutOfBounds() { + String[] args = {"Too", "Short"}; + String expected = ""; + String actual = StringUtils.buildStringAfterNthElement(args, 5); + assertEquals(expected, actual); + } + + @Test + void testBuildStringAfterNthElement_EmptyArray() { + String[] args = {}; + String expected = ""; + String actual = StringUtils.buildStringAfterNthElement(args, 0); + assertEquals(expected, actual); + } + + @Test + void testBuildStringAfterNthElement_ArgsWithSpaces() { + String[] args = {"Multiple", " ", "Spaces"}; + String expected = " Spaces"; + String actual = StringUtils.buildStringAfterNthElement(args, 1); + assertEquals(expected, actual); + } + + // Tests for isInt(String string) + @Test + void testIsInt_ValidIntegers() { + assertTrue(StringUtils.isInt("123")); + assertTrue(StringUtils.isInt("-456")); + assertTrue(StringUtils.isInt("0")); + } + + @Test + void testIsInt_InvalidIntegers() { + assertFalse(StringUtils.isInt("123.45")); + assertFalse(StringUtils.isInt("abc")); + assertFalse(StringUtils.isInt("")); + assertFalse(StringUtils.isInt(" ")); + assertFalse(StringUtils.isInt(null)); // This will throw NullPointerException + } + + // Tests for isDouble(String string) + @Test + void testIsDouble_ValidDoubles() { + assertTrue(StringUtils.isDouble("123.45")); + assertTrue(StringUtils.isDouble("-456.78")); + assertTrue(StringUtils.isDouble("0.0")); + assertTrue(StringUtils.isDouble("1e10")); + } + + @Test + void testIsDouble_InvalidDoubles() { + assertFalse(StringUtils.isDouble("abc")); + assertFalse(StringUtils.isDouble("")); + assertFalse(StringUtils.isDouble(" ")); + assertFalse(StringUtils.isDouble("123.45.67")); + } + + @Test + void testIsDouble_NullInput() { + assertThrows(NullPointerException.class, () -> { + StringUtils.isDouble(null); + }); + } + + @Test + void testCachingMechanism_EntityType() { + EntityType zombie = EntityType.ZOMBIE; + + String firstCall = StringUtils.getPrettyEntityTypeString(zombie); + String secondCall = StringUtils.getPrettyEntityTypeString(zombie); + + assertSame(firstCall, secondCall, "EntityType caching failed"); + } + + @Test + void testCachingMechanism_Material() { + Material diamondSword = Material.DIAMOND_SWORD; + + String firstCall = StringUtils.getPrettyMaterialString(diamondSword); + String secondCall = StringUtils.getPrettyMaterialString(diamondSword); + + assertSame(firstCall, secondCall, "Material caching failed"); + } + + // Tests for createPrettyString via public methods + @Test + void testCreatePrettyString_Spaces() { + String[] args = {"hello", "world"}; + String expected = "hello world"; + String actual = StringUtils.buildStringAfterNthElement(args, 0); + assertEquals(expected, actual); + } + + @Test + void testPrettify_Substrings() { + Material goldenApple = Material.GOLDEN_APPLE; + String expected = "Golden Apple"; + String actual = StringUtils.getPrettyMaterialString(goldenApple); + assertEquals(expected, actual); + } +} 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 cefbe7010..5f02eb356 100644 --- a/src/test/java/com/gmail/nossr50/util/text/TextUtilsTest.java +++ b/src/test/java/com/gmail/nossr50/util/text/TextUtilsTest.java @@ -6,13 +6,12 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; /** - * This Unit Test checks if Adventure was set up correctly and works as expected. - * Normally we can rely on this to be the case. However sometimes our dependencies - * lack so far behind that things stop working correctly. - * This test ensures that basic functionality is guaranteed to work as we would expect. - * + * 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 lack so far behind that things + * stop working correctly. This test ensures that basic functionality is guaranteed to work as we + * would expect. + *

* See https://github.com/mcMMO-Dev/mcMMO/pull/4446 - * */ class TextUtilsTest { diff --git a/src/test/resources/healthydb.users b/src/test/resources/healthydb.users index 7ce5ccbad..c2561b38d 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:3333:160:16:4444: +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: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: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 000000000..7ce5ccbad --- /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