1
0
mirror of https://github.com/mcMMO-Dev/mcMMO.git synced 2026-02-18 01:42:32 +01:00

Compare commits

...

82 Commits

Author SHA1 Message Date
Warrior
be613bc9b6 Fix archery entity tracking failing often on Folia (#5260) 2026-02-13 13:14:54 -08:00
nossr50
99c2ec2959 changelog update again 2026-02-07 15:02:07 -08:00
nossr50
3a7d605450 changelog update 2026-02-07 14:58:39 -08:00
dependabot[bot]
0e0e2efb6d Bump org.assertj:assertj-core from 3.25.3 to 3.27.7 (#5259)
Bumps [org.assertj:assertj-core](https://github.com/assertj/assertj) from 3.25.3 to 3.27.7.
- [Release notes](https://github.com/assertj/assertj/releases)
- [Commits](https://github.com/assertj/assertj/compare/assertj-build-3.25.3...assertj-build-3.27.7)

---
updated-dependencies:
- dependency-name: org.assertj:assertj-core
  dependency-version: 3.27.7
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-07 14:57:38 -08:00
Warrior
a6e12c4cc1 Replace use of getIngredientList/Map (#5257) 2026-02-07 14:56:01 -08:00
Momshroom
33597e1db1 Set max display of spear master to two decimals (#5258)
* Fixed NPE when party creation doesn't use password.  Solves bug reported here: https://discord.com/channels/526933440214597677/526938425161416727/1213131451235827753

Signed-off-by: Momshroom <Momshroom@gmail.com>

* Actually don't reduce sapling drop if KnockOnWood unlocked. (Prior fix didn't)

Signed-off-by: Momshroom <Momshroom@gmail.com>

* removed unnecessary getPlayer() calls.
clarified comment
clarified location variable name

Signed-off-by: Momshroom <Momshroom@gmail.com>

* made new method more generic.
Removed no longer needed dropString variable

Signed-off-by: Momshroom <Momshroom@gmail.com>

* Added new potions to alchemy. Borrowed some config info from here: https://discord.com/channels/526933440214597677/547110990278426629/1291771464726478869

Signed-off-by: Momshroom <Momshroom@gmail.com>

* Revert regression.  Fixes salvage permissions by material type

* Format Spear Mastery to 2 decimal places in /spears output, fixing floating point issue causing long output

---------

Signed-off-by: Momshroom <Momshroom@gmail.com>
2026-02-07 14:54:58 -08:00
nossr50
c94f10568d refactor a bunch of unused, outdated, or unnecessary tech debt for compatibility for older versions that are no longer supported or were never supported 2026-02-07 14:54:25 -08:00
Nick
db985bcc52 Add spears to fill<Material>ToolsWhiteList() methods (#5254)
These methods fill the matching `<material>Tools` HashSets. Adding
corresponding spear items will allow the `is<Material>Tool()` methods
to return `true` if checking a spear of the matching material. This is
to support the Repair and Salvage configurations pulling the
appropriate repair/salvage material type if one is not specified in the
plugin's configuration files.
2026-02-05 18:27:42 -08:00
nossr50
1b8897b8ab version is outdated errors tweaked a bit 2026-01-31 11:40:11 -08:00
nossr50
95026e6016 improved spears dmg detection and fixed more errors with Excellent Enchants 2026-01-31 11:20:35 -08:00
nossr50
7738c45b72 minimum MC version is now 1.20.4 2026-01-31 11:19:36 -08:00
nossr50
080d407c14 another fix for compatibility with Excellent Enchants 2026-01-27 13:03:50 -08:00
nossr50
8f8d7756ca back to dev versions 2026-01-26 11:39:43 -08:00
nossr50
e24b5b0b75 2.2.049 2026-01-26 11:33:11 -08:00
nossr50
8ac3198386 improved compatibility with Excellent Enchants 2026-01-26 11:23:45 -08:00
nossr50
4c33f76404 update changelog 2026-01-25 12:22:45 -08:00
Warrior
77dac78bec Fix leftover sync tp in taming subskill (#5248) 2026-01-25 11:22:31 -08:00
nossr50
9c9e5313ca prevent item stack size from going outside normal bounds 2026-01-17 13:38:29 -08:00
nossr50
db5654dbe6 Merge branch 'master' of https://github.com/mcMMO-Dev/mcMMO 2026-01-17 13:31:28 -08:00
nossr50
c14b82fff1 updated notes 2026-01-17 13:31:05 -08:00
nossr50
5a9390f88f allow combat abilities to activate with spear in off-hand 2026-01-17 13:27:14 -08:00
Dominykas
4a890a28a1 Add support for sweet berry bush harvesting and replanting (#5238)
* Add support for sweet berry bush harvesting and replanting

* Accidentally left my test code for torchflower replanting.
2026-01-17 12:51:39 -08:00
Warrior
8b7cffbe49 Bump mockito version to fix compiling on java 25 (#5247) 2026-01-17 12:38:28 -08:00
nossr50
921fa713b8 back to dev builds 2025-12-30 14:47:25 -08:00
Remski01
ebe49154b4 Fix copper XP in experience.yml (#5242)
This should fix that Copper does not gives xp.
2025-12-30 14:46:55 -08:00
nossr50
1036aabc32 2.2.048 hotfix for spear manager exception Fixes #5237 2025-12-14 16:35:54 -08:00
nossr50
e2f18a9e89 2.2.047 hotfix for spears combat offhand oddities 2025-12-14 14:42:59 -08:00
nossr50
694de2ff5f fix overlooked spears interaction with other melee skills 2025-12-14 14:36:41 -08:00
nossr50
cc1a581192 back to developer snapshots 2025-12-14 14:29:38 -08:00
Robert Alan Chapton
b15365e978 Spears update (#5236)
Spears update
2025-12-14 14:23:25 -08:00
nossr50
a907bfd624 oops 2025-12-14 13:32:36 -08:00
nossr50
257292b6cc test number who knows 2025-12-14 13:31:21 -08:00
nossr50
2f452afdc7 try this instead part 3 2025-12-14 13:17:59 -08:00
nossr50
283c6d9771 Technically we don't need this 2025-12-14 13:08:41 -08:00
nossr50
fc62946e27 Try this instead... 2025-12-14 13:07:11 -08:00
nossr50
6b6263d0b3 Add deploy to Nexus stage 2025-12-14 13:03:51 -08:00
nossr50
f9acdeaf14 empty commit, testing webhooks 2025-12-13 16:27:09 -08:00
nossr50
03bea40ad4 fix jenkins script 2025-12-13 16:21:34 -08:00
nossr50
401edf0bc9 no mvn wrapper 2025-12-13 16:10:58 -08:00
nossr50
085197abc0 let's try a Jenkinsfile 2025-12-13 16:03:36 -08:00
nossr50
98eb706361 test 2025-12-13 15:57:29 -08:00
nossr50
09dfe4fd11 Merge branch 'master' of https://github.com/mcMMO-Dev/mcMMO 2025-12-13 11:55:28 -08:00
るんく君
ced4ed2fd0 [Fix] isMagicHunterEnabled method doesn't considered the MagicHunter's permission (#5231) 2025-12-08 12:35:56 -08:00
Nadie
5c283fedb3 Change Protocollib's repo to use new namespace & group id (#5232) 2025-12-08 12:34:53 -08:00
Warrior
fae55c1edf Fix self damage awarding skill xp (#5233) 2025-12-08 12:34:09 -08:00
Tig3r98
d800aa9316 Update Italian Translation (#5230) 2025-11-30 13:37:49 -08:00
nossr50
1b49eb11b8 Spring-cleaning round 1: remove some more deprecated API invocations 2025-11-09 10:34:41 -08:00
nossr50
3533c50489 Spring-cleaning round 1: remove deprecated Player.updateInventory 2025-11-09 09:57:28 -08:00
nossr50
2a8be52be5 back to snapshots 2025-11-08 13:57:14 -08:00
nossr50
59093c5f22 2.2.045 2025-11-08 13:49:59 -08:00
nossr50
1f123a4eb2 Add missing permission nodes for copper repair and salvage Fixes #5225 2025-11-08 13:44:35 -08:00
nossr50
c96cb95443 Fixed bug where salvage and repair configs would re-add any deleted entry that existed in the default config Fixes #5223 2025-11-08 13:40:05 -08:00
nossr50
9f5994596a Fixed ageable cast class exception Fixes #5224
Fixed Herbalism not replanting certain crops
2025-11-08 13:27:53 -08:00
nossr50
ec6dce0cb2 back to snapshots 2025-11-02 12:30:55 -08:00
nossr50
80a61d2d89 2.2.044 Fix copper repair and salvage 2025-11-02 12:25:25 -08:00
nossr50
f71fe0de70 snapshots here we go 2025-10-05 13:55:04 -07:00
nossr50
eafa53e5b4 2.2.043 2025-10-05 13:46:32 -07:00
nossr50
5dfea51c5e slightly better logs 2025-10-05 13:46:13 -07:00
nossr50
00c0b2e5ec fix bug where armor stand could be renamed to heart symbols 2025-10-05 13:30:24 -07:00
nossr50
c79b3fe024 optimize imports 2025-10-05 13:19:17 -07:00
nossr50
24888d13c2 Fix potion names Fixes #5211 Fixes #5180 2025-10-05 13:18:35 -07:00
nossr50
2f624e329d misc optimization 2025-10-05 12:34:18 -07:00
nossr50
07d18e2eba 1.21.9 support for treasures.yml, experience.yml, fishing_treasures.yml, and settings for mannequins and a fix for armor stands 2025-10-05 12:27:20 -07:00
nossr50
c958a86aa3 add 1.21.9 support for repair, salvage, copper tool and armor (wip) 2025-10-04 14:20:32 -07:00
nossr50
22231dfa32 back to snapshots 2025-09-21 12:31:34 -07:00
nossr50
fdc652fd63 2.2.042 2025-09-21 12:24:42 -07:00
nossr50
c07b73d3d6 Merge branch 'master' of https://github.com/mcMMO-Dev/mcMMO 2025-09-21 12:20:06 -07:00
nossr50
d38d74f82a new event McMMOModifyBlockDropItemEvent and mcMMO now modifies the drop list in BlockDropItemEvent instead of spawning items
Fixes #5214
2025-09-21 12:19:55 -07:00
Justin
9a59200c0b Add null-safety and helper methods to AbilityAPI (#5217) 2025-09-21 10:53:32 -07:00
nossr50
8e049822a3 better phrasing 2025-08-30 12:08:14 -07:00
nossr50
06f979d7bf Reduce Blast Mining PVP damage Fixes #5213 2025-08-30 12:03:50 -07:00
nossr50
f78586675d different default for CustomSoundId in sounds.yml 2025-08-30 11:40:23 -07:00
nossr50
46bcd29998 update changelog with info about custom sound playing 2025-08-30 11:20:31 -07:00
Nathan V.
df69410e67 (Improvement) Implement playing sound by string ID (#5201)
* (improvement) implement playing sound by string ID

I've replaced enum-based sound playing events with string-based equivalents, which should open the door for server customization and other enhancements in the future

- Added SoundLookup class with different registry lookup methods depending on server version.
- Added the ability to configure what sounds are played depending on event, with a fallback built into SoundType.
- Removed getCrippleSound as SoundLookup can now fall back to the original default sound if the mace sound doesn't exist on the server's Minecraft version.
- Added a EnableCustomSounds config variable that will skip SoundLookup ID checking and just pass the sound string directly to the client, mainly due to the fact that it isn't possible to verify if resource pack values exist.
 - Cleaned up a few switch statements to match how the original getSound had it formatted.

I'd love to see/do a further expansion of sound configuration for each ability now that we can just fall back to generic, but that may be for another PR.

* Fix getIsEnabled using wrong key

* always use registry, simplify custom sound enabling logic, optimize reflection calls

* forgot we need this for legacy versions

---------

Co-authored-by: nossr50 <nossr50@gmail.com>
2025-08-30 11:15:26 -07:00
nossr50
99f7437d9d back to dev builds 2025-08-23 13:16:59 -07:00
nossr50
4bfbfa2de7 2.2.041 2025-08-23 13:12:58 -07:00
nossr50
724b66afaa expand Block Cracker to other blocks with cracked variants 2025-08-23 13:09:52 -07:00
nossr50
6ba4475a77 Fix Berserk block cracker not functioning Fixes #5207 2025-08-23 13:01:11 -07:00
nossr50
2c1c1fe53f update changelog 2025-08-23 12:38:30 -07:00
Warrior
ba673a02d0 Add early return for brewing stand hopper check (#5208) 2025-08-23 12:37:11 -07:00
handy
7cf4409c35 Add static to the method of the private class DatabaseAPI. (#5198) 2025-08-02 12:48:46 -07:00
Jake Ben-Tovim
f9513a8b40 fix(experience): parse diminished returns value from correct field (#5196) 2025-07-11 14:43:29 -07:00
132 changed files with 8257 additions and 5689 deletions

View File

@@ -1,4 +1,139 @@
Version 2.2.050
Minimum supported Minecraft version raised to 1.20.5 (see notes)
Improved Spears damage detection (see notes)
Spear abilities can now trigger from off-hand attacks with the Spear
Further improved compatibility with Excellent Enchants (fixed more errors)
Fixed Spears command showing too many decimal places in some circumstances (Thanks Momshroom)
(Codebase) Updated Recipe API to use alternative methods (Thanks Warriorrrr)
(Codebase) Removed a bunch of unused code
(Codebase) Refactored code around evaluating Minecraft server version
NOTES:
From 2.2.050 onwards, mcMMO will require Minecraft versions 1.20.5 or newer.
Every now and then I raise the minimum supported Minecraft version to reduce maintenance burden of supporting older versions.
mcMMO no longer monitors PlayerAnimationEvent, it turns out Spigot has a DamageType just for Spear damage, avoiding the need to track player arm swings.
I changed how mcMMO detects the game version slightly, now if it fails to determine the game version it will make the assumption you are on the minimum supported version and print an error, this is just a failsafe in case the version detection mechanism ever fails.
Version 2.2.049
Combat abilities work with spear in off-hand again (see notes)
Sweet berry bushes now work with Herbalism (thanks dnocturne)
Fixed copper items not giving XP for Repair (thanks Remski01)
Fixed rare edge case where mcMMO could drop items with stack size set outside normal bounds
Fixed a bug where tamed wolves could cause errors on Folia (thanks Warriorrrr)
Improved compatibility with Excellent Enchants (fixed error spam from Flame Walker)
(Codebase) Fixed unit tests when building mcMMO with Java 25 (thanks Warriorrrr)
NOTES:
As a semi-permanent work around, mcMMO keeps track of when players swing their weapon, if they have swung it recently enough combat skills will work even if you have a spear in your off-hand.
Prior to this patch, mcMMO disabled combat abilities when spear was in off-hand to prevent the off-hand spear charge from applying combat abilities from other skills, as mcMMO was unable to determine which item (mainhand vs offhand) caused the damage from the event information alone.
Version 2.2.048
Fixed error when loading Spears skill manager on older Minecraft versions
Fixed error when using /spears command on an older Minecraft version
Version 2.2.047
Fix bug where off-hand spears damage could be attributed to various combat skills and trigger their abilities
NOTE:
Sorry guys, noticed this right after pushing 2.2.046, for now melee combat skills won't trigger if you have a spear in your off-hand as a temporary work around to mcMMO being unable to differentiate between main hand and off hand damage.
I'm working on a more robust solution to this issue, so stay tuned.
What this means in laymen's terms is if you are using a sword main hand, and you have a spear off hand, mcMMO has temporarily disabled your main hand abilities from triggering to avoid issues where off hand spear damage benefits from it and triggers abilities belonging to other weapons.
Version 2.2.046
Added Spears combat skill
Added Spears to repair.vanilla.yml and salvage.vanilla.yml (see notes)
Added various permissions related to Spears
Added /spears skill command
Added Nautilus to taming XP in experience.yml
Added Camel_Husk to taming XP in experience.yml
Added Camel_Husk to combat XP in experience.yml
Added Parched to combat XP in experience.yml
Fixed bug where converting from SQL to FlatFile would not copy data for tridents, crossbows, maces, or spears
(Codebase) Added docker-based unit tests for SQL databases (see notes)
(Codebase) Large refactor to both SQLDatabaseManager and FlatFileDatabaseManager
(Codebase) Database related errors are now more descriptive and have had their logging improved
NOTES:
This update had a lot of changes behind the scenes, please report any bugs you find to our GitHub issues page!
You will need to manually update repair.vanilla.yml and salvage.vanilla.yml to get support for Spears, or...
If you want to update salvage/repair configs the easy way, you simply can delete these config files to have mcMMO regenerate them with the new entries.
If you don't want to delete them, you can find the default values for these config files in the defaults folder at plugins\mcMMO\defaults after running this mcMMO update at least once.
You can use this default file to copy paste if you please.
Docker is ONLY required for developers compiling mcMMO from source code and ONLY for running SQL-related unit tests.
mcMMO itself does NOT require Docker to run, and servers using prebuilt releases are completely unaffected.
New SQL database unit tests use Testcontainers to spin up temporary MySQL/MariaDB instances for testing purposes.
These containers are created at test time and are never used at runtime.
If you compile mcMMO locally and do not have Docker installed, SQL-related unit tests may fail.
In this case, you can safely compile with -DskipTests to skip unit tests entirely.
Skipping tests has no impact on mcMMO functionality when running on a server.
Known Issues:
I ran into an issue where having a spear in the offhand while the main hand is empty causes attacks to be incorrectly classified as unarmed. This allows unarmed abilities to apply to spear damage. As a temporary measure, Ive disabled unarmed skills from applying to combat when a spear is equipped in the offhand while I investigate a more robust solution.
Version 2.2.045
Green Thumb now replants some crops it was failing to replant before (see notes)
Green Thumb now replants harvested plants faster
Fixed an error that could happen when replanting crops with Green Thumb
Fixed a bug where salvage.vanilla.yml was readding deleted entries on server restart
Fixed a bug where repair.vanilla.yml was readding deleted entries on server restart
Added missing permission node 'mcmmo.ability.repair.copperrepair'
Added missing permission node 'mcmmo.ability.salvage.coppersalvage'
NOTES:
The delay from a plant being replanted from Green Thumb is intentional, and while looking into bugs it seemed maybe a tad slow, so I sped it up a bit.
Green Thumb still won't replant some stuff such as sugar canes, cacti, those are handled a bit differently, but I could add support for it in an upcoming patch if requested.
Version 2.2.044
Fixed copper armor and tools not working with Repair or Salvage
Version 2.2.043
Added support for the new copper tools and armor added in Minecraft 1.21.9
Added many missing buttons, trapdoors, doors, fence gates, etc to the ability/tool blacklists (see notes)
Added copper tools and armor to repair.vanilla.yml (see notes)
Added copper tools and armor to salvage.vanilla.yml (see notes)
Added copper tools and armor to fishing_treasures.yml (see notes)
Added Copper_Nugget to treasures.yml (see notes)
Added Copper_Nugget to experience.yml for Smelting XP
Added Copper_Golem to experience.yml for Combat XP
Fixed mcMMO custom potions not having their name set correctly (see notes)
Fixed ExploitFix.PreventArmorStandInteraction in experience.yml not being respected
Added ExploitFix.PreventMannequinInteraction to experience.yml to prevent mannequins from granting XP or other effects
Fixed bug where Armor Stands would get renamed to heart symbols upon breaking them (see notes)
Tweaked potions loaded msg during mcMMO startup to not include potions requiring newer game versions from being included in the total.
NOTES:
You don't need to update your experience.yml, that one updates automatically when you run mcMMO after an update.
You will need to manually update the following files manually repair.vanilla.yml, salvage.vanilla.yml, treasures.yml, and fishing_treasures.yml files to get support for copper tools and armor.
You can find the default config files in the defaults folder at plugins\mcMMO\defaults after running this mcMMO update at least once.
You can use this default file to copy paste if you please
OR if you haven't customizes these config files, simply delete them to have mcMMO regenerate them with the new entries.
mcMMO has an internal blacklist of blocks that abilities and tools won't activate or "ready" on, pretty much anything that is interactable should go on this list, and I performed an audit and there were quite a few missing entries, so I've added them in this update, what this means is you won't click on a button and have it ready your tool anymore, as it should have been doing.
Mannequins are treated the same way armor stands are treated, the default behavior is mcMMO won't process on them unless you turn on the setting under ExploitFix in experience.yml, in addition to this their default XP is set to 0.0
mcMMO had a setting 'ExploitFix.PreventArmorStandInteraction' to allow mcMMO to process abilities and XP on armor stands, but it was never hooked up! I fixed that mistake in this update.
The fix for potion names will only apply to newly created potions.
Armor stands that had already been renamed from the heart symbol bug will keep their names, but the bug shouldn't happen anymore
Version 2.2.042
mcMMO now listens to BlockDropItemEvent at LOW priority instead of HIGHEST
Bonus drops from mcMMO now simply modify quantity in BlockDropItemEvent instead of spawning new ItemStacks.
Added McMMOModifyBlockDropItemEvent event, this event is called when mcMMO modifies the quantity of an ItemStack during a BlockDropItemEvent, it is modifiable and cancellable.
You can now define custom sounds to be played in sounds.yml (Thank you JeBobs, see notes)
Added a cap to how much Blast Mining PVP damage can do to other players
Notes:
The new sounds.yml config file allows you to override the sounds played by mcMMO.
Simply define the ID of the sound you want to play for each sound.
For example, add an entry for Sounds.TOOL_READY.CustomSoundId into sounds.yml to override the sound played when a tool is "readied".
If you are on older versions (1.18, 1.19, etc), instead of registering an ID, you specify the Sound enum.
Those who are on newer versions, can define the ID of any sound registered with Paper/Spigot, this allows you to even play custom sounds so long as they are properly loaded on the server.
Vanilla minecraft sounds tend to have IDs like "minecraft:ui.toast.challenge_complete", you can google what these keys are.
Version 2.2.041
Fixed Berserk failing to crack blocks
Added 'Skills.Unarmed.Block_Cracker.Allow_Block_Cracker' to config.yml
Removed 'SmoothBrick_To_CrackedBrick', it has been replaced by `Allow_Block_Cracker`
Block Cracker can now crack deepslate bricks, deepslate tiles, polished blackstone bricks, and netherbricks
Optimizations for Hoppers & Alchemy (thanks Warriorrrr)
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)

43
Jenkinsfile vendored Normal file
View File

@@ -0,0 +1,43 @@
pipeline {
agent any
tools {
jdk 'jdk17'
// If you configured Maven as a Jenkins tool, add:
// maven 'Maven3'
}
options {
timestamps()
disableConcurrentBuilds()
}
stages {
stage('Checkout') {
steps {
checkout scm
}
}
stage('Build') {
steps {
sh 'mvn -V -B clean package'
}
}
stage('Deploy to Nexus') {
steps {
configFileProvider([configFile(fileId: 'maven-settings-nexus', variable: 'MAVEN_SETTINGS')]) {
sh 'mvn -s "$MAVEN_SETTINGS" -V -B deploy'
}
}
}
}
post {
success {
archiveArtifacts artifacts: 'target/mcMMO.jar', fingerprint: true
}
}
}

View File

@@ -23,7 +23,7 @@ If you are using maven, you can add mcMMO API to your plugin by adding it to pom
<dependency>
<groupId>com.gmail.nossr50.mcMMO</groupId>
<artifactId>mcMMO</artifactId>
<version>2.2.004</version>
<version>put-the-version-here</version>
</dependency>
```
### Builds

157
pom.xml
View File

@@ -1,8 +1,10 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.gmail.nossr50.mcMMO</groupId>
<artifactId>mcMMO</artifactId>
<version>2.2.041-SNAPSHOT</version>
<version>2.2.050-SNAPSHOT</version>
<name>mcMMO</name>
<url>https://github.com/mcMMO-Dev/mcMMO</url>
<scm>
@@ -13,8 +15,8 @@
</scm>
<properties>
<!-- <spigot.version>1.19-R0.1-SNAPSHOT</spigot.version>-->
<spigot.version>1.21.7-R0.1-SNAPSHOT</spigot.version>
<spigot.version>1.20.5-R0.1-SNAPSHOT</spigot.version>
<!-- <spigot.version>1.21.11-R0.1-SNAPSHOT</spigot.version>-->
<kyori.adventure.version>4.23.0</kyori.adventure.version>
<kyori.adventure.platform.version>4.4.1-SNAPSHOT</kyori.adventure.platform.version>
<kyori.option.version>1.1.0</kyori.option.version>
@@ -87,6 +89,17 @@
<propertiesEncoding>UTF-8</propertiesEncoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>properties</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.2.5</version>
@@ -95,6 +108,8 @@
<junitArtifactName>org.junit.jupiter:junit-jupiter</junitArtifactName>
<trimStackTrace>false</trimStackTrace>
<excludedGroups>skip</excludedGroups>
<!-- https://javadoc.io/doc/org.mockito/mockito-core/latest/org.mockito/org/mockito/Mockito.html#0.3 -->
<argLine>-javaagent:${org.mockito:mockito-core:jar}</argLine>
</configuration>
</plugin>
<plugin>
@@ -182,11 +197,13 @@
</relocation>
<relocation>
<pattern>co.aikar.commands</pattern>
<shadedPattern>com.gmail.nossr50.mcmmo.acf</shadedPattern> <!-- Replace this -->
<shadedPattern>com.gmail.nossr50.mcmmo.acf
</shadedPattern> <!-- Replace this -->
</relocation>
<relocation>
<pattern>co.aikar.locales</pattern>
<shadedPattern>com.gmail.nossr50.mcmmo.locales</shadedPattern> <!-- Replace this -->
<shadedPattern>com.gmail.nossr50.mcmmo.locales
</shadedPattern> <!-- Replace this -->
</relocation>
<relocation>
<pattern>org.apache.commons.logging</pattern>
@@ -194,7 +211,8 @@
</relocation>
<relocation>
<pattern>org.apache.juli</pattern>
<shadedPattern>com.gmail.nossr50.mcmmo.database.tomcat.juli</shadedPattern>
<shadedPattern>com.gmail.nossr50.mcmmo.database.tomcat.juli
</shadedPattern>
</relocation>
<relocation>
<pattern>org.apache.tomcat</pattern>
@@ -236,11 +254,6 @@
</pluginRepositories>
<repositories>
<!-- Protocol Lib Repository -->
<repository>
<id>dmulloy2-repo</id>
<url>https://repo.dmulloy2.net/repository/public/</url>
</repository>
<repository>
<id>spigot-repo</id>
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
@@ -288,14 +301,28 @@
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.25.3</version>
<version>3.27.7</version>
<scope>test</scope>
<exclusions>
<!-- Exclude bytebuddy, messes with tests on java 25+ -->
<exclusion>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.comphenix.protocol</groupId>
<groupId>net.dmulloy2</groupId>
<artifactId>ProtocolLib</artifactId>
<version>5.3.0</version>
<scope>compile</scope>
<exclusions>
<!-- Exclude bytebuddy, messes with tests on java 25+ -->
<exclusion>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
@@ -390,11 +417,11 @@
<version>3.0.2</version>
<scope>compile</scope>
</dependency>
<!-- <dependency>-->
<!-- <groupId>io.papermc.paper</groupId>-->
<!-- <artifactId>paper-api</artifactId>-->
<!-- <version>1.21.5-R0.1-SNAPSHOT</version>-->
<!-- </dependency>-->
<!-- <dependency>-->
<!-- <groupId>io.papermc.paper</groupId>-->
<!-- <artifactId>paper-api</artifactId>-->
<!-- <version>1.21.11-R0.1-SNAPSHOT</version>-->
<!-- </dependency>-->
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
@@ -431,28 +458,88 @@
</exclusion>
</exclusions>
</dependency>
<!-- JUnit 5 -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.11.0-M2</version>
<version>5.11.0</version>
<scope>test</scope>
</dependency>
<!-- Testcontainers core -->
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
<version>2.0.2</version>
<scope>test</scope>
</dependency>
<!-- Testcontainers JUnit Jupiter integration -->
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers-junit-jupiter</artifactId>
<version>2.0.2</version>
<scope>test</scope>
</dependency>
<!-- Log4j core for tests -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.25.2</version>
<scope>test</scope>
</dependency>
<!-- Log4j API -->
<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-api -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.25.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-slf4j-impl -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.25.2</version>
<scope>test</scope>
</dependency>
<!-- MySQL Testcontainers module -->
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers-mysql</artifactId>
<scope>test</scope>
</dependency>
<!-- MariaDB Testcontainers module -->
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers-mariadb</artifactId>
<scope>test</scope>
</dependency>
<!-- MySQL JDBC driver -->
<!-- https://mvnrepository.com/artifact/com.mysql/mysql-connector-j -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>9.5.0</version>
<scope>test</scope>
</dependency>
<!-- MariaDB JDBC driver -->
<!-- https://mvnrepository.com/artifact/org.mariadb.jdbc/mariadb-java-client -->
<dependency>
<groupId>org.mariadb.jdbc</groupId>
<artifactId>mariadb-java-client</artifactId>
<version>3.5.6</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>5.12.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-inline</artifactId>
<version>5.2.0</version>
<version>5.21.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jdbc</artifactId>
<version>10.1.24</version>
<version>11.0.14</version>
<scope>compile</scope>
</dependency>
<dependency>
@@ -463,7 +550,8 @@
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>33.2.0-jre</version> <!-- At this time Spigot is including 29.0 Guava classes that we are using -->
<version>33.2.0-jre
</version> <!-- At this time Spigot is including 29.0 Guava classes that we are using -->
<scope>compile</scope>
</dependency>
<dependency>
@@ -473,4 +561,15 @@
<scope>compile</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers-bom</artifactId>
<version>2.0.2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>

View File

@@ -7,41 +7,46 @@ import com.gmail.nossr50.util.player.UserManager;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
@SuppressWarnings("unused")
public final class AbilityAPI {
private AbilityAPI() {
}
public static boolean berserkEnabled(Player player) {
return UserManager.getPlayer(player).getAbilityMode(SuperAbilityType.BERSERK);
return hasAbilityEnabled(player, SuperAbilityType.BERSERK);
}
public static boolean gigaDrillBreakerEnabled(Player player) {
return UserManager.getPlayer(player).getAbilityMode(SuperAbilityType.GIGA_DRILL_BREAKER);
return hasAbilityEnabled(player, SuperAbilityType.GIGA_DRILL_BREAKER);
}
public static boolean greenTerraEnabled(Player player) {
return UserManager.getPlayer(player).getAbilityMode(SuperAbilityType.GREEN_TERRA);
return hasAbilityEnabled(player, SuperAbilityType.GREEN_TERRA);
}
public static boolean serratedStrikesEnabled(Player player) {
return UserManager.getPlayer(player).getAbilityMode(SuperAbilityType.SERRATED_STRIKES);
return hasAbilityEnabled(player, SuperAbilityType.SERRATED_STRIKES);
}
public static boolean skullSplitterEnabled(Player player) {
return UserManager.getPlayer(player).getAbilityMode(SuperAbilityType.SKULL_SPLITTER);
return hasAbilityEnabled(player, SuperAbilityType.SKULL_SPLITTER);
}
public static boolean superBreakerEnabled(Player player) {
return UserManager.getPlayer(player).getAbilityMode(SuperAbilityType.SUPER_BREAKER);
return hasAbilityEnabled(player, SuperAbilityType.SUPER_BREAKER);
}
public static boolean treeFellerEnabled(Player player) {
return UserManager.getPlayer(player).getAbilityMode(SuperAbilityType.TREE_FELLER);
return hasAbilityEnabled(player, SuperAbilityType.TREE_FELLER);
}
public static boolean isAnyAbilityEnabled(Player player) {
final McMMOPlayer mmoPlayer = UserManager.getPlayer(player);
if(mmoPlayer == null) {
return false;
}
for (SuperAbilityType ability : SuperAbilityType.values()) {
if (mmoPlayer.getAbilityMode(ability)) {
return true;
@@ -51,36 +56,57 @@ public final class AbilityAPI {
return false;
}
private static boolean hasAbilityEnabled(Player player, SuperAbilityType ability) {
McMMOPlayer mmoPlayer = UserManager.getPlayer(player);
return mmoPlayer != null && mmoPlayer.getAbilityMode(ability);
}
public static void resetCooldowns(Player player) {
UserManager.getPlayer(player).resetCooldowns();
McMMOPlayer mmoPlayer = UserManager.getPlayer(player);
if(mmoPlayer == null) {
return;
}
mmoPlayer.resetCooldowns();
}
public static void setBerserkCooldown(Player player, long cooldown) {
UserManager.getPlayer(player).setAbilityDATS(SuperAbilityType.BERSERK, cooldown);
setAbilityCooldown(player, SuperAbilityType.BERSERK, cooldown);
}
public static void setGigaDrillBreakerCooldown(Player player, long cooldown) {
UserManager.getPlayer(player).setAbilityDATS(SuperAbilityType.GIGA_DRILL_BREAKER, cooldown);
setAbilityCooldown(player, SuperAbilityType.GIGA_DRILL_BREAKER, cooldown);
}
public static void setGreenTerraCooldown(Player player, long cooldown) {
UserManager.getPlayer(player).setAbilityDATS(SuperAbilityType.GREEN_TERRA, cooldown);
setAbilityCooldown(player, SuperAbilityType.GREEN_TERRA, cooldown);
}
public static void setSerratedStrikesCooldown(Player player, long cooldown) {
UserManager.getPlayer(player).setAbilityDATS(SuperAbilityType.SERRATED_STRIKES, cooldown);
setAbilityCooldown(player, SuperAbilityType.SERRATED_STRIKES, cooldown);
}
public static void setSkullSplitterCooldown(Player player, long cooldown) {
UserManager.getPlayer(player).setAbilityDATS(SuperAbilityType.SKULL_SPLITTER, cooldown);
setAbilityCooldown(player, SuperAbilityType.SKULL_SPLITTER, cooldown);
}
public static void setSuperBreakerCooldown(Player player, long cooldown) {
UserManager.getPlayer(player).setAbilityDATS(SuperAbilityType.SUPER_BREAKER, cooldown);
setAbilityCooldown(player, SuperAbilityType.SUPER_BREAKER, cooldown);
}
public static void setTreeFellerCooldown(Player player, long cooldown) {
UserManager.getPlayer(player).setAbilityDATS(SuperAbilityType.TREE_FELLER, cooldown);
setAbilityCooldown(player, SuperAbilityType.TREE_FELLER, cooldown);
}
private static void setAbilityCooldown(Player player, SuperAbilityType ability, long cooldown) {
McMMOPlayer mmoPlayer = UserManager.getPlayer(player);
if(mmoPlayer == null) {
return;
}
mmoPlayer.setAbilityDATS(ability, cooldown);
}
public static boolean isBleeding(LivingEntity entity) {

View File

@@ -16,7 +16,7 @@ public class DatabaseAPI {
* @param offlinePlayer target player
* @return true if the player exists in the DB, false if they do not
*/
public boolean doesPlayerExistInDB(@NotNull OfflinePlayer offlinePlayer) {
public static boolean doesPlayerExistInDB(@NotNull OfflinePlayer offlinePlayer) {
PlayerProfile playerProfile = mcMMO.getDatabaseManager().loadPlayerProfile(offlinePlayer);
return playerProfile.isLoaded();
@@ -28,7 +28,7 @@ public class DatabaseAPI {
* @param uuid target player
* @return true if the player exists in the DB, false if they do not
*/
public boolean doesPlayerExistInDB(@NotNull UUID uuid) {
public static boolean doesPlayerExistInDB(@NotNull UUID uuid) {
PlayerProfile playerProfile = null;
try {
playerProfile = mcMMO.getDatabaseManager().loadPlayerProfile(uuid);
@@ -45,7 +45,7 @@ public class DatabaseAPI {
* @param playerName target player
* @return true if the player exists in the DB, false if they do not
*/
public boolean doesPlayerExistInDB(@NotNull String playerName) {
public static boolean doesPlayerExistInDB(@NotNull String playerName) {
PlayerProfile playerProfile = mcMMO.getDatabaseManager().loadPlayerProfile(playerName);
return playerProfile.isLoaded();

View File

@@ -1,30 +0,0 @@
package com.gmail.nossr50.commands.admin;
import com.gmail.nossr50.mcMMO;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
public class CompatibilityCommand implements CommandExecutor {
/**
* Executes the given command, returning its success.
* <br>
* 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
* @param s Alias of the command which was used
* @param strings Passed command arguments
* @return true if a valid command, otherwise false
*/
@Override
public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command,
@NotNull String s,
@NotNull String[] strings) {
mcMMO.getCompatibilityManager().reportCompatibilityStatus(commandSender);
return true;
}
}

View File

@@ -44,13 +44,6 @@ 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;
@@ -65,13 +58,6 @@ 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;

View File

@@ -73,7 +73,7 @@ public class AcrobaticsCommand extends SkillCommand {
protected List<Component> getTextComponents(Player player) {
List<Component> textComponents = new ArrayList<>();
TextComponentFactory.getSubSkillTextComponents(player, textComponents,
TextComponentFactory.appendSubSkillTextComponents(player, textComponents,
PrimarySkillType.ACROBATICS);
return textComponents;

View File

@@ -92,7 +92,7 @@ public class AlchemyCommand extends SkillCommand {
protected List<Component> getTextComponents(Player player) {
List<Component> textComponents = new ArrayList<>();
TextComponentFactory.getSubSkillTextComponents(player, textComponents,
TextComponentFactory.appendSubSkillTextComponents(player, textComponents,
PrimarySkillType.ALCHEMY);
return textComponents;

View File

@@ -93,7 +93,7 @@ public class ArcheryCommand extends SkillCommand {
protected List<Component> getTextComponents(Player player) {
List<Component> textComponents = new ArrayList<>();
TextComponentFactory.getSubSkillTextComponents(player, textComponents,
TextComponentFactory.appendSubSkillTextComponents(player, textComponents,
PrimarySkillType.ARCHERY);
return textComponents;

View File

@@ -119,7 +119,7 @@ public class AxesCommand extends SkillCommand {
protected List<Component> getTextComponents(Player player) {
final List<Component> textComponents = new ArrayList<>();
TextComponentFactory.getSubSkillTextComponents(player, textComponents,
TextComponentFactory.appendSubSkillTextComponents(player, textComponents,
PrimarySkillType.AXES);
return textComponents;

View File

@@ -68,7 +68,7 @@ public class CrossbowsCommand extends SkillCommand {
protected List<Component> getTextComponents(Player player) {
List<Component> textComponents = new ArrayList<>();
TextComponentFactory.getSubSkillTextComponents(player, textComponents,
TextComponentFactory.appendSubSkillTextComponents(player, textComponents,
PrimarySkillType.CROSSBOWS);
return textComponents;

View File

@@ -71,7 +71,7 @@ public class ExcavationCommand extends SkillCommand {
protected List<Component> getTextComponents(Player player) {
List<Component> textComponents = new ArrayList<>();
TextComponentFactory.getSubSkillTextComponents(player, textComponents,
TextComponentFactory.appendSubSkillTextComponents(player, textComponents,
PrimarySkillType.EXCAVATION);
return textComponents;

View File

@@ -1,13 +1,13 @@
package com.gmail.nossr50.commands.skills;
import static com.gmail.nossr50.util.Permissions.canUseSubSkill;
import com.gmail.nossr50.config.treasure.FishingTreasureConfig;
import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
import com.gmail.nossr50.datatypes.skills.SubSkillType;
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.Permissions;
import com.gmail.nossr50.util.random.Probability;
import com.gmail.nossr50.util.random.ProbabilityUtil;
import com.gmail.nossr50.util.skills.RankUtils;
@@ -118,16 +118,14 @@ public class FishingCommand extends SkillCommand {
@Override
protected void permissionsCheck(Player player) {
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,
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
&& Permissions.canUseSubSkill(player, SubSkillType.FISHING_MASTER_ANGLER);
canIceFish = Permissions.canUseSubSkill(player, SubSkillType.FISHING_ICE_FISHING);
canMasterAngler = canUseSubSkill(player, SubSkillType.FISHING_MASTER_ANGLER);
canIceFish = canUseSubSkill(player, SubSkillType.FISHING_ICE_FISHING);
}
@Override
@@ -185,7 +183,7 @@ public class FishingCommand extends SkillCommand {
protected List<Component> getTextComponents(Player player) {
List<Component> textComponents = new ArrayList<>();
TextComponentFactory.getSubSkillTextComponents(player, textComponents,
TextComponentFactory.appendSubSkillTextComponents(player, textComponents,
PrimarySkillType.FISHING);
return textComponents;

View File

@@ -187,7 +187,7 @@ public class HerbalismCommand extends SkillCommand {
protected List<Component> getTextComponents(Player player) {
List<Component> textComponents = new ArrayList<>();
TextComponentFactory.getSubSkillTextComponents(player, textComponents,
TextComponentFactory.appendSubSkillTextComponents(player, textComponents,
PrimarySkillType.HERBALISM);
return textComponents;

View File

@@ -23,7 +23,8 @@ public class MacesCommand extends SkillCommand {
super(PrimarySkillType.MACES);
}
String crippleChanceToApply, crippleChanceToApplyLucky, crippleLengthAgainstPlayers, crippleLengthAgainstMobs;
String crippleChanceToApply, crippleChanceToApplyLucky, crippleLengthAgainstPlayers,
crippleLengthAgainstMobs;
@Override
protected void dataCalculations(Player player, float skillValue) {
@@ -33,7 +34,6 @@ public class MacesCommand extends SkillCommand {
MacesManager.getCrippleTickDuration(true) / 20.0D);
crippleLengthAgainstMobs = String.valueOf(
MacesManager.getCrippleTickDuration(false) / 20.0D);
crippleChanceToApply =
mcMMO.p.getAdvancedConfig().getCrippleChanceToApplyOnHit(crippleRank) + "%";
crippleChanceToApplyLucky = String.valueOf(
@@ -77,7 +77,7 @@ public class MacesCommand extends SkillCommand {
protected List<Component> getTextComponents(Player player) {
List<Component> textComponents = new ArrayList<>();
TextComponentFactory.getSubSkillTextComponents(player, textComponents,
TextComponentFactory.appendSubSkillTextComponents(player, textComponents,
PrimarySkillType.MACES);
return textComponents;

View File

@@ -144,7 +144,7 @@ public class MiningCommand extends SkillCommand {
protected List<Component> getTextComponents(Player player) {
List<Component> textComponents = new ArrayList<>();
TextComponentFactory.getSubSkillTextComponents(player, textComponents,
TextComponentFactory.appendSubSkillTextComponents(player, textComponents,
PrimarySkillType.MINING);
return textComponents;

View File

@@ -134,7 +134,7 @@ public class RepairCommand extends SkillCommand {
protected List<Component> getTextComponents(Player player) {
List<Component> textComponents = new ArrayList<>();
TextComponentFactory.getSubSkillTextComponents(player, textComponents,
TextComponentFactory.appendSubSkillTextComponents(player, textComponents,
PrimarySkillType.REPAIR);
return textComponents;

View File

@@ -72,7 +72,7 @@ public class SalvageCommand extends SkillCommand {
protected List<Component> getTextComponents(Player player) {
List<Component> textComponents = new ArrayList<>();
TextComponentFactory.getSubSkillTextComponents(player, textComponents,
TextComponentFactory.appendSubSkillTextComponents(player, textComponents,
PrimarySkillType.SALVAGE);
return textComponents;

View File

@@ -97,7 +97,7 @@ public class SmeltingCommand extends SkillCommand {
protected List<Component> getTextComponents(Player player) {
List<Component> textComponents = new ArrayList<>();
TextComponentFactory.getSubSkillTextComponents(player, textComponents,
TextComponentFactory.appendSubSkillTextComponents(player, textComponents,
PrimarySkillType.SMELTING);
return textComponents;

View File

@@ -0,0 +1,85 @@
package com.gmail.nossr50.commands.skills;
import static com.gmail.nossr50.datatypes.skills.SubSkillType.SPEARS_MOMENTUM;
import static com.gmail.nossr50.datatypes.skills.SubSkillType.SPEARS_SPEARS_LIMIT_BREAK;
import static com.gmail.nossr50.datatypes.skills.SubSkillType.SPEARS_SPEAR_MASTERY;
import static com.gmail.nossr50.util.skills.SkillUtils.canUseSubskill;
import static com.gmail.nossr50.util.text.TextComponentFactory.appendSubSkillTextComponents;
import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
import com.gmail.nossr50.locale.LocaleLoader;
import com.gmail.nossr50.mcMMO;
import com.gmail.nossr50.skills.spears.SpearsManager;
import com.gmail.nossr50.util.player.UserManager;
import com.gmail.nossr50.util.skills.CombatUtils;
import com.gmail.nossr50.util.skills.RankUtils;
import com.gmail.nossr50.util.skills.SkillUtils;
import java.util.ArrayList;
import java.util.List;
import net.kyori.adventure.text.Component;
import org.bukkit.entity.Player;
public class SpearsCommand extends SkillCommand {
public SpearsCommand() {
super(PrimarySkillType.SPEARS);
}
String momentumChanceToApply, momentumChanceToApplyLucky, momentumDuration;
@Override
protected void dataCalculations(Player player, float skillValue) {
if (SkillUtils.canUseSubskill(player, SPEARS_MOMENTUM)) {
int momentumRank = RankUtils.getRank(player, SPEARS_MOMENTUM);
momentumDuration = String.valueOf(
SpearsManager.getMomentumTickDuration(momentumRank) / 20.0D);
momentumChanceToApply =
mcMMO.p.getAdvancedConfig().getMomentumChanceToApplyOnHit(momentumRank) + "%";
momentumChanceToApplyLucky = String.valueOf(
mcMMO.p.getAdvancedConfig().getMomentumChanceToApplyOnHit(momentumRank) * 1.33);
}
}
@Override
protected void permissionsCheck(Player player) {
}
@Override
protected List<String> statsDisplay(Player player, float skillValue, boolean hasEndurance,
boolean isLucky) {
final SpearsManager spearsManager = UserManager.getPlayer(player).getSpearsManager();
final double spearMasteryBonusDmg = spearsManager.getSpearMasteryBonusDamage();
List<String> messages = new ArrayList<>();
if (canUseSubskill(player, SPEARS_SPEARS_LIMIT_BREAK)) {
messages.add(getStatMessage(SPEARS_SPEARS_LIMIT_BREAK,
String.valueOf(CombatUtils.getLimitBreakDamageAgainstQuality(player,
SPEARS_SPEARS_LIMIT_BREAK, 1000))));
}
if (canUseSubskill(player, SPEARS_SPEAR_MASTERY)) {
messages.add(getStatMessage(SPEARS_SPEAR_MASTERY,
String.format("%.2f", spearMasteryBonusDmg)));
}
if (SkillUtils.canUseSubskill(player, SPEARS_MOMENTUM)) {
messages.add(getStatMessage(SPEARS_MOMENTUM, momentumChanceToApply)
+ (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus",
momentumChanceToApplyLucky) : ""));
messages.add(getStatMessage(true, true, SPEARS_MOMENTUM, momentumDuration));
}
return messages;
}
@Override
protected List<Component> getTextComponents(Player player) {
List<Component> textComponents = new ArrayList<>();
appendSubSkillTextComponents(player, textComponents, PrimarySkillType.SPEARS);
return textComponents;
}
}

View File

@@ -22,8 +22,8 @@ public class SwordsCommand extends SkillCommand {
private String serratedStrikesLengthEndurance;
private String rupturePureTickDamageAgainstPlayers, rupturePureTickDamageAgainstMobs,
ruptureExplosionDamageAgainstPlayers, ruptureExplosionDamageAgainstMobs,
ruptureLengthSecondsAgainstPlayers, ruptureLengthSecondsAgainstMobs, ruptureChanceToApply, ruptureChanceToApplyLucky;
ruptureLengthSecondsAgainstPlayers, ruptureLengthSecondsAgainstMobs,
ruptureChanceToApply, ruptureChanceToApplyLucky;
private boolean canCounter;
private boolean canSerratedStrike;
@@ -56,11 +56,6 @@ public class SwordsCommand extends SkillCommand {
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));
ruptureChanceToApply =
mcMMO.p.getAdvancedConfig().getRuptureChanceToApplyOnHit(ruptureRank) + "%";
ruptureChanceToApplyLucky = String.valueOf(
@@ -105,7 +100,6 @@ public class SwordsCommand extends SkillCommand {
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"));
}
@@ -134,7 +128,7 @@ public class SwordsCommand extends SkillCommand {
protected List<Component> getTextComponents(Player player) {
List<Component> textComponents = new ArrayList<>();
TextComponentFactory.getSubSkillTextComponents(player, textComponents,
TextComponentFactory.appendSubSkillTextComponents(player, textComponents,
PrimarySkillType.SWORDS);
return textComponents;

View File

@@ -115,7 +115,7 @@ public class TamingCommand extends SkillCommand {
protected List<Component> getTextComponents(Player player) {
List<Component> textComponents = new ArrayList<>();
TextComponentFactory.getSubSkillTextComponents(player, textComponents, this.skill);
TextComponentFactory.appendSubSkillTextComponents(player, textComponents, this.skill);
return textComponents;
}

View File

@@ -50,7 +50,7 @@ public class TridentsCommand extends SkillCommand {
protected List<Component> getTextComponents(Player player) {
List<Component> textComponents = new ArrayList<>();
TextComponentFactory.getSubSkillTextComponents(player, textComponents,
TextComponentFactory.appendSubSkillTextComponents(player, textComponents,
PrimarySkillType.TRIDENTS);
return textComponents;

View File

@@ -136,7 +136,7 @@ public class UnarmedCommand extends SkillCommand {
protected List<Component> getTextComponents(Player player) {
List<Component> textComponents = new ArrayList<>();
TextComponentFactory.getSubSkillTextComponents(player, textComponents,
TextComponentFactory.appendSubSkillTextComponents(player, textComponents,
PrimarySkillType.UNARMED);
return textComponents;

View File

@@ -123,7 +123,7 @@ public class WoodcuttingCommand extends SkillCommand {
protected List<Component> getTextComponents(Player player) {
List<Component> textComponents = new ArrayList<>();
TextComponentFactory.getSubSkillTextComponents(player, textComponents,
TextComponentFactory.appendSubSkillTextComponents(player, textComponents,
PrimarySkillType.WOODCUTTING);
return textComponents;

View File

@@ -11,6 +11,7 @@ import net.md_5.bungee.api.ChatColor;
public class AdvancedConfig extends BukkitConfig {
int[] defaultCrippleValues = new int[]{10, 15, 20, 25};
int[] defaultMomentumValues = new int[]{5, 10, 15, 20, 25, 30, 35, 40, 45, 50};
public AdvancedConfig(File dataFolder) {
super("advanced.yml", dataFolder);
@@ -884,7 +885,17 @@ public class AdvancedConfig extends BukkitConfig {
/* 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]);
return config.getDouble("Skills.Maces.Cripple.Chance_To_Apply_On_Hit.Rank_" + rank,
defaultCrippleValues[rank - 1]);
}
/* SPEARS */
public double getMomentumChanceToApplyOnHit(int rank) {
return config.getDouble("Skills.Spears.Momentum.Chance_To_Apply_On_Hit.Rank_" + rank,
defaultMomentumValues[rank - 1]);
}
public double getSpearMasteryRankDamageMultiplier() {
return config.getDouble("Skills.Spears.SpearMastery.Rank_Damage_Multiplier", 0.4D);
}
}

View File

@@ -8,12 +8,13 @@ import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.logging.Level;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.YamlConfiguration;
import org.jetbrains.annotations.NotNull;
public abstract class BukkitConfig {
boolean copyDefaults = true;
boolean copyDefaults;
protected final String fileName;
protected final File configFile;
protected YamlConfiguration defaultYamlConfig;
@@ -58,7 +59,7 @@ public abstract class BukkitConfig {
savedDefaults = true;
}
} catch (IOException e) {
e.printStackTrace();
mcMMO.p.getLogger().log(Level.SEVERE, "Unable to save config file: " + fileName, e);
}
}

View File

@@ -424,10 +424,6 @@ public class GeneralConfig extends BukkitConfig {
return config.getBoolean("MySQL.Server.SSL", true);
}
public boolean getMySQLDebug() {
return config.getBoolean("MySQL.Debug", false);
}
public boolean getMySQLPublicKeyRetrieval() {
return config.getBoolean("MySQL.Server.allowPublicKeyRetrieval", true);
}
@@ -872,8 +868,8 @@ public class GeneralConfig extends BukkitConfig {
}
/* Unarmed */
public boolean getUnarmedBlockCrackerSmoothbrickToCracked() {
return config.getBoolean("Skills.Unarmed.Block_Cracker.SmoothBrick_To_CrackedBrick", true);
public boolean isBlockCrackerAllowed() {
return config.getBoolean("Skills.Unarmed.Block_Cracker.Allow_Block_Cracker", true);
}
public boolean getUnarmedItemPickupDisabled() {

View File

@@ -29,7 +29,7 @@ public class SoundConfig extends BukkitConfig {
@Override
protected boolean validateKeys() {
for (SoundType soundType : SoundType.values()) {
if (config.getDouble("Sounds." + soundType.toString() + ".Volume") < 0) {
if (config.getDouble("Sounds." + soundType + ".Volume") < 0) {
LogUtils.debug(mcMMO.p.getLogger(),
"[mcMMO] Sound volume cannot be below 0 for " + soundType);
return false;
@@ -52,17 +52,22 @@ public class SoundConfig extends BukkitConfig {
}
public float getVolume(SoundType soundType) {
String key = "Sounds." + soundType.toString() + ".Volume";
String key = "Sounds." + soundType + ".Volume";
return (float) config.getDouble(key, 1.0);
}
public float getPitch(SoundType soundType) {
String key = "Sounds." + soundType.toString() + ".Pitch";
String key = "Sounds." + soundType + ".Pitch";
return (float) config.getDouble(key, 1.0);
}
public String getSound(SoundType soundType) {
final String key = "Sounds." + soundType + ".CustomSoundId";
return config.getString(key);
}
public boolean getIsEnabled(SoundType soundType) {
String key = "Sounds." + soundType.toString() + ".Enabled";
String key = "Sounds." + soundType + ".Enable";
return config.getBoolean(key, true);
}
}

View File

@@ -201,6 +201,10 @@ public class ExperienceConfig extends BukkitConfig {
return config.getBoolean("ExploitFix.PreventArmorStandInteraction", true);
}
public boolean isMannequinInteractionPrevented() {
return config.getBoolean("ExploitFix.PreventMannequinInteraction", true);
}
public boolean isFishingExploitingPrevented() {
return config.getBoolean("ExploitFix.Fishing", true);
}
@@ -298,7 +302,7 @@ public class ExperienceConfig extends BukkitConfig {
/* Diminished Returns */
public float getDiminishedReturnsCap() {
return (float) config.getDouble("Dimished_Returns.Guaranteed_Minimum_Percentage", 0.05D);
return (float) config.getDouble("Diminished_Returns.Guaranteed_Minimum_Percentage", 0.05D);
}
public boolean getDiminishedReturnsEnabled() {

View File

@@ -1,20 +1,21 @@
package com.gmail.nossr50.config.skills.alchemy;
import static com.gmail.nossr50.util.ItemUtils.setItemName;
import static com.gmail.nossr50.util.ItemUtils.customName;
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 net.kyori.adventure.text.Component;
import net.kyori.adventure.text.TextComponent;
import net.kyori.adventure.text.format.TextDecoration;
import org.bukkit.ChatColor;
import org.bukkit.Color;
import org.bukkit.Material;
@@ -46,9 +47,6 @@ public class PotionConfig extends LegacyConfigLoader {
private final List<ItemStack> concoctionsIngredientsTierSix = new ArrayList<>();
private final List<ItemStack> concoctionsIngredientsTierSeven = new ArrayList<>();
private final List<ItemStack> 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);
@@ -158,7 +156,7 @@ public class PotionConfig extends LegacyConfigLoader {
}
}
int totalPotions = potionsLoaded + incompatible + failures;
int totalPotions = potionsLoaded + failures;
mcMMO.p.getLogger()
.info("Loaded " + potionsLoaded + " of " + totalPotions + " Alchemy potions.");
@@ -255,15 +253,15 @@ public class PotionConfig extends LegacyConfigLoader {
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;
}
// if (isTrickyTrialsPotionEffect(parts[0]) && !mcMMO.getCompatibilityManager()
// .minecraftGameVersion()
// .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;
@@ -295,9 +293,7 @@ public class PotionConfig extends LegacyConfigLoader {
.getKeys(false)) {
// Breeze Rod was only for potions after 1.21.0
if (isTrickyTrialsIngredient(childIngredient)
&& !mcMMO.getCompatibilityManager()
.getMinecraftGameVersion()
.isAtLeast(1, 21, 0)) {
&& !mcMMO.getMinecraftGameVersion().isAtLeast(1, 21, 0)) {
continue;
}
ItemStack ingredient = loadIngredient(childIngredient);
@@ -356,8 +352,6 @@ public class PotionConfig extends LegacyConfigLoader {
// set base
setBasePotionType(potionMeta, potionType, extended, upgraded);
// Legacy only
setUpgradedAndExtendedProperties(potionType, potionMeta, upgraded, extended);
return true;
}
@@ -369,7 +363,9 @@ public class PotionConfig extends LegacyConfigLoader {
final String configuredName = section.getString("Name", null);
if (configuredName != null) {
setItemName(potionMeta, configuredName);
final TextComponent textComponent = Component.text(configuredName)
.decoration(TextDecoration.ITALIC, false);
customName(potionMeta, textComponent, configuredName);
}
}

View File

@@ -1,5 +1,20 @@
package com.gmail.nossr50.config.skills.repair;
import static com.gmail.nossr50.util.ItemUtils.isCopperArmor;
import static com.gmail.nossr50.util.ItemUtils.isCopperTool;
import static com.gmail.nossr50.util.ItemUtils.isDiamondArmor;
import static com.gmail.nossr50.util.ItemUtils.isDiamondTool;
import static com.gmail.nossr50.util.ItemUtils.isGoldArmor;
import static com.gmail.nossr50.util.ItemUtils.isGoldTool;
import static com.gmail.nossr50.util.ItemUtils.isIronArmor;
import static com.gmail.nossr50.util.ItemUtils.isIronTool;
import static com.gmail.nossr50.util.ItemUtils.isLeatherArmor;
import static com.gmail.nossr50.util.ItemUtils.isNetheriteArmor;
import static com.gmail.nossr50.util.ItemUtils.isNetheriteTool;
import static com.gmail.nossr50.util.ItemUtils.isStoneTool;
import static com.gmail.nossr50.util.ItemUtils.isStringTool;
import static com.gmail.nossr50.util.ItemUtils.isWoodTool;
import com.gmail.nossr50.config.BukkitConfig;
import com.gmail.nossr50.datatypes.skills.ItemType;
import com.gmail.nossr50.datatypes.skills.MaterialType;
@@ -13,6 +28,7 @@ import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import org.bukkit.Material;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.inventory.ItemStack;
@@ -62,27 +78,27 @@ public class RepairConfig extends BukkitConfig {
String repairMaterialTypeString = config.getString(
"Repairables." + key + ".MaterialType", "OTHER");
if (!config.contains("Repairables." + key + ".MaterialType") && itemMaterial != null) {
ItemStack repairItem = new ItemStack(itemMaterial);
if (!config.contains("Repairables." + key + ".MaterialType")) {
final ItemStack repairItem = new ItemStack(itemMaterial);
if (ItemUtils.isWoodTool(repairItem)) {
if (isWoodTool(repairItem)) {
repairMaterialType = MaterialType.WOOD;
} else if (ItemUtils.isStoneTool(repairItem)) {
} else if (isStoneTool(repairItem)) {
repairMaterialType = MaterialType.STONE;
} else if (ItemUtils.isStringTool(repairItem)) {
} else if (isStringTool(repairItem)) {
repairMaterialType = MaterialType.STRING;
} else if (ItemUtils.isLeatherArmor(repairItem)) {
} else if (isLeatherArmor(repairItem)) {
repairMaterialType = MaterialType.LEATHER;
} else if (ItemUtils.isIronArmor(repairItem) || ItemUtils.isIronTool(repairItem)) {
} else if (isIronArmor(repairItem) || isIronTool(repairItem)) {
repairMaterialType = MaterialType.IRON;
} else if (ItemUtils.isGoldArmor(repairItem) || ItemUtils.isGoldTool(repairItem)) {
} else if (isGoldArmor(repairItem) || isGoldTool(repairItem)) {
repairMaterialType = MaterialType.GOLD;
} else if (ItemUtils.isDiamondArmor(repairItem) || ItemUtils.isDiamondTool(
repairItem)) {
} else if (isDiamondArmor(repairItem) || isDiamondTool(repairItem)) {
repairMaterialType = MaterialType.DIAMOND;
} else if (ItemUtils.isNetheriteArmor(repairItem) || ItemUtils.isNetheriteTool(
repairItem)) {
} else if (isNetheriteArmor(repairItem) || isNetheriteTool(repairItem)) {
repairMaterialType = MaterialType.NETHERITE;
} else if (isCopperTool(repairItem) || isCopperArmor(repairItem)) {
repairMaterialType = MaterialType.COPPER;
}
} else {
try {
@@ -104,9 +120,7 @@ public class RepairConfig extends BukkitConfig {
}
// Maximum Durability
short maximumDurability = (itemMaterial != null ? itemMaterial.getMaxDurability()
: (short) config.getInt(
"Repairables." + key + ".MaximumDurability"));
short maximumDurability = itemMaterial.getMaxDurability();
if (maximumDurability <= 0) {
maximumDurability = (short) config.getInt(
@@ -153,17 +167,22 @@ public class RepairConfig extends BukkitConfig {
}
if (noErrorsInRepairable(reason)) {
Repairable repairable = RepairableFactory.getRepairable(
itemMaterial, repairMaterial, null, minimumLevel, maximumDurability,
repairItemType,
repairMaterialType, xpMultiplier, minimumQuantity);
repairables.add(repairable);
try {
final Repairable repairable = RepairableFactory.getRepairable(
itemMaterial, repairMaterial, null, minimumLevel, maximumDurability,
repairItemType,
repairMaterialType, xpMultiplier, minimumQuantity);
repairables.add(repairable);
} catch (Exception e) {
mcMMO.p.getLogger().log(Level.SEVERE,
"Error loading repairable from config entry: " + key, e);
}
}
}
//Report unsupported
StringBuilder stringBuilder = new StringBuilder();
if (notSupported.size() > 0) {
if (!notSupported.isEmpty()) {
stringBuilder.append(
"mcMMO found the following materials in the Repair config that are not supported by the version of Minecraft running on this server: ");

View File

@@ -15,7 +15,7 @@ public class RepairConfigManager {
Pattern pattern = Pattern.compile("repair\\.(?:.+)\\.yml");
File dataFolder = plugin.getDataFolder();
RepairConfig mainRepairConfig = new RepairConfig(REPAIR_VANILLA_YML, true);
RepairConfig mainRepairConfig = new RepairConfig(REPAIR_VANILLA_YML, false);
repairables.addAll(mainRepairConfig.getLoadedRepairables());
for (String fileName : dataFolder.list()) {

View File

@@ -1,5 +1,21 @@
package com.gmail.nossr50.config.skills.salvage;
import static com.gmail.nossr50.util.ItemUtils.isCopperArmor;
import static com.gmail.nossr50.util.ItemUtils.isCopperTool;
import static com.gmail.nossr50.util.ItemUtils.isDiamondArmor;
import static com.gmail.nossr50.util.ItemUtils.isDiamondTool;
import static com.gmail.nossr50.util.ItemUtils.isGoldArmor;
import static com.gmail.nossr50.util.ItemUtils.isGoldTool;
import static com.gmail.nossr50.util.ItemUtils.isIronArmor;
import static com.gmail.nossr50.util.ItemUtils.isIronTool;
import static com.gmail.nossr50.util.ItemUtils.isLeatherArmor;
import static com.gmail.nossr50.util.ItemUtils.isNetheriteArmor;
import static com.gmail.nossr50.util.ItemUtils.isNetheriteTool;
import static com.gmail.nossr50.util.ItemUtils.isPrismarineTool;
import static com.gmail.nossr50.util.ItemUtils.isStoneTool;
import static com.gmail.nossr50.util.ItemUtils.isStringTool;
import static com.gmail.nossr50.util.ItemUtils.isWoodTool;
import com.gmail.nossr50.config.BukkitConfig;
import com.gmail.nossr50.datatypes.database.UpgradeType;
import com.gmail.nossr50.datatypes.skills.ItemType;
@@ -27,8 +43,8 @@ public class SalvageConfig extends BukkitConfig {
private final HashSet<String> notSupported;
private Set<Salvageable> salvageables;
public SalvageConfig(String fileName, boolean copyDefaults) {
super(fileName, copyDefaults);
public SalvageConfig(String fileName) {
super(fileName, false);
notSupported = new HashSet<>();
loadKeys();
}
@@ -50,9 +66,9 @@ public class SalvageConfig extends BukkitConfig {
mcMMO.p.getLogger().log(
Level.INFO,
"Fixing incorrect Salvage quantities on Netherite gear, this will only run once...");
for (String namespacedkey : mcMMO.getMaterialMapStore().getNetheriteArmor()) {
for (String namespacedKey : mcMMO.getMaterialMapStore().getNetheriteArmor()) {
config.set(
"Salvageables." + namespacedkey.toUpperCase(Locale.ENGLISH)
"Salvageables." + namespacedKey.toUpperCase(Locale.ENGLISH)
+ ".MaximumQuantity",
4); //TODO: Doesn't make sense to default to 4 for everything
}
@@ -64,10 +80,9 @@ public class SalvageConfig extends BukkitConfig {
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.");
e.printStackTrace();
mcMMO.p.getLogger().log(Level.SEVERE,
"Unable to fix Salvage config, please delete the salvage yml file"
+ " to generate a new one.", e);
}
}
@@ -85,34 +100,32 @@ public class SalvageConfig extends BukkitConfig {
// Salvage Material Type
MaterialType salvageMaterialType = MaterialType.OTHER;
String salvageMaterialTypeString = config.getString(
final String salvageMaterialTypeString = config.getString(
"Salvageables." + key + ".MaterialType", "OTHER");
if (!config.contains("Salvageables." + key + ".MaterialType") && itemMaterial != null) {
ItemStack salvageItem = new ItemStack(itemMaterial);
if (!config.contains("Salvageables." + key + ".MaterialType")) {
final ItemStack salvageItem = new ItemStack(itemMaterial);
if (ItemUtils.isWoodTool(salvageItem)) {
if (isWoodTool(salvageItem)) {
salvageMaterialType = MaterialType.WOOD;
} else if (ItemUtils.isStoneTool(salvageItem)) {
} else if (isStoneTool(salvageItem)) {
salvageMaterialType = MaterialType.STONE;
} else if (ItemUtils.isStringTool(salvageItem)) {
} else if (isStringTool(salvageItem)) {
salvageMaterialType = MaterialType.STRING;
} else if (ItemUtils.isPrismarineTool(salvageItem)) {
} else if (isPrismarineTool(salvageItem)) {
salvageMaterialType = MaterialType.PRISMARINE;
} else if (ItemUtils.isLeatherArmor(salvageItem)) {
} else if (isLeatherArmor(salvageItem)) {
salvageMaterialType = MaterialType.LEATHER;
} else if (ItemUtils.isIronArmor(salvageItem) || ItemUtils.isIronTool(
salvageItem)) {
} else if (isIronArmor(salvageItem) || isIronTool(salvageItem)) {
salvageMaterialType = MaterialType.IRON;
} else if (ItemUtils.isGoldArmor(salvageItem) || ItemUtils.isGoldTool(
salvageItem)) {
} else if (isGoldArmor(salvageItem) || isGoldTool(salvageItem)) {
salvageMaterialType = MaterialType.GOLD;
} else if (ItemUtils.isDiamondArmor(salvageItem) || ItemUtils.isDiamondTool(
salvageItem)) {
} else if (isDiamondArmor(salvageItem) || isDiamondTool(salvageItem)) {
salvageMaterialType = MaterialType.DIAMOND;
} else if (ItemUtils.isNetheriteTool(salvageItem) || ItemUtils.isNetheriteArmor(
salvageItem)) {
} else if (isNetheriteTool(salvageItem) || isNetheriteArmor(salvageItem)) {
salvageMaterialType = MaterialType.NETHERITE;
} else if (isCopperTool(salvageItem) || isCopperArmor(salvageItem)) {
salvageMaterialType = MaterialType.COPPER;
}
} else {
try {
@@ -120,14 +133,12 @@ public class SalvageConfig extends BukkitConfig {
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");
String salvageMaterialName = config.getString("Salvageables." + key + ".SalvageMaterial");
Material salvageMaterial = (salvageMaterialName == null
? salvageMaterialType.getDefaultMaterial()
: Material.matchMaterial(salvageMaterialName));
@@ -138,16 +149,14 @@ public class SalvageConfig extends BukkitConfig {
}
// Maximum Durability
short maximumDurability = (itemMaterial != null ? itemMaterial.getMaxDurability()
: (short) config.getInt(
"Salvageables." + key + ".MaximumDurability"));
short maximumDurability = itemMaterial.getMaxDurability();
// Item Type
ItemType salvageItemType = ItemType.OTHER;
String salvageItemTypeString = config.getString("Salvageables." + key + ".ItemType",
"OTHER");
if (!config.contains("Salvageables." + key + ".ItemType") && itemMaterial != null) {
if (!config.contains("Salvageables." + key + ".ItemType")) {
ItemStack salvageItem = new ItemStack(itemMaterial);
if (ItemUtils.isMinecraftTool(salvageItem)) {
@@ -172,11 +181,11 @@ public class SalvageConfig extends BukkitConfig {
}
// Maximum Quantity
int maximumQuantity = itemMaterial != null ? SkillUtils.getRepairAndSalvageQuantities(
itemMaterial,
salvageMaterial) : config.getInt("Salvageables." + key + ".MaximumQuantity", 1);
int maximumQuantity = SkillUtils.getRepairAndSalvageQuantities(
itemMaterial,
salvageMaterial);
if (maximumQuantity <= 0 && itemMaterial != null) {
if (maximumQuantity <= 0) {
maximumQuantity = config.getInt("Salvageables." + key + ".MaximumQuantity", 1);
}
@@ -192,17 +201,23 @@ public class SalvageConfig extends BukkitConfig {
}
if (noErrorsInSalvageable(reason)) {
Salvageable salvageable = SalvageableFactory.getSalvageable(
itemMaterial, salvageMaterial, minimumLevel,
maximumQuantity, maximumDurability, salvageItemType, salvageMaterialType,
xpMultiplier);
salvageables.add(salvageable);
try {
final Salvageable salvageable = SalvageableFactory.getSalvageable(
itemMaterial, salvageMaterial, minimumLevel,
maximumQuantity, maximumDurability, salvageItemType,
salvageMaterialType,
xpMultiplier);
salvageables.add(salvageable);
} catch (Exception e) {
mcMMO.p.getLogger().log(Level.SEVERE,
"Error loading salvageable from config entry: " + key, e);
}
}
}
//Report unsupported
StringBuilder stringBuilder = new StringBuilder();
if (notSupported.size() > 0) {
if (!notSupported.isEmpty()) {
stringBuilder.append(
"mcMMO found the following materials in the Salvage config that are not supported by the version of Minecraft running on this server: ");

View File

@@ -16,7 +16,7 @@ public class SalvageConfigManager {
Pattern pattern = Pattern.compile("salvage\\.(?:.+)\\.yml");
File dataFolder = plugin.getDataFolder();
SalvageConfig mainSalvageConfig = new SalvageConfig(SALVAGE_VANILLA_YML, true);
SalvageConfig mainSalvageConfig = new SalvageConfig(SALVAGE_VANILLA_YML);
salvageables.addAll(mainSalvageConfig.getLoadedSalvageables());
for (String fileName : dataFolder.list()) {
@@ -34,7 +34,7 @@ public class SalvageConfigManager {
continue;
}
SalvageConfig salvageConfig = new SalvageConfig(fileName, false);
SalvageConfig salvageConfig = new SalvageConfig(fileName);
salvageables.addAll(salvageConfig.getLoadedSalvageables());
}
}

View File

@@ -99,7 +99,10 @@ public class TreasureConfig extends BukkitConfig {
type + "." + treasureName + ".Data");
if (material == null) {
reason.add("Invalid material: " + materialName);
LogUtils.debug(mcMMO.p.getLogger(),
String.format("Material '%s' for treasure '%s' is not recognized."
+ " Skipping...", materialName, treasureName));
continue;
}
if (amount <= 0) {

View File

@@ -28,8 +28,8 @@ public class DatabaseManagerFactory {
: "Flatfile") + " database");
}
return mcMMO.p.getGeneralConfig().getUseMySQL() ? new SQLDatabaseManager(logger,
MYSQL_DRIVER)
return mcMMO.p.getGeneralConfig().getUseMySQL()
? new SQLDatabaseManager(logger, MYSQL_DRIVER)
: new FlatFileDatabaseManager(userFilePath, logger, purgeTime, startingLevel);
}

View File

@@ -9,6 +9,7 @@ import static com.gmail.nossr50.database.FlatFileDatabaseManager.COOLDOWN_GREEN_
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_SPEARS;
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;
@@ -25,6 +26,7 @@ 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_SPEARS;
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;
@@ -45,6 +47,7 @@ import static com.gmail.nossr50.database.FlatFileDatabaseManager.SKILLS_HERBALIS
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_SPEARS;
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;
@@ -318,27 +321,26 @@ public class FlatFileDataProcessor {
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
ExpectedType.STRING;
//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,
SKILLS_ALCHEMY, SKILLS_CROSSBOWS, SKILLS_TRIDENTS, SKILLS_MACES, SKILLS_SPEARS,
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;
COOLDOWN_ARCHERY, COOLDOWN_MACES, COOLDOWN_SPEARS -> 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;
EXP_TRIDENTS, EXP_MACES, EXP_SPEARS -> ExpectedType.FLOAT;
case UUID_INDEX -> ExpectedType.UUID;
case OVERHAUL_LAST_LOGIN -> ExpectedType.LONG;
default -> throw new IndexOutOfBoundsException();

View File

@@ -9,6 +9,7 @@ import static com.gmail.nossr50.database.FlatFileDatabaseManager.COOLDOWN_GREEN_
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_SPEARS;
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;
@@ -24,6 +25,7 @@ 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_SPEARS;
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;
@@ -45,6 +47,7 @@ import static com.gmail.nossr50.database.FlatFileDatabaseManager.SKILLS_HERBALIS
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_SPEARS;
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;
@@ -114,18 +117,16 @@ public class FlatFileDataUtil {
throws IndexOutOfBoundsException {
//TODO: Add UUID recovery? Might not even be worth it.
return switch (index) {
//We'll keep using this value for legacy compatibility reasons (not sure if needed but don't care)
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
LEGACY_INVALID_OLD_USERNAME;
//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 ->
SKILLS_ALCHEMY, SKILLS_CROSSBOWS, SKILLS_TRIDENTS, SKILLS_MACES, SKILLS_SPEARS ->
String.valueOf(startingLevel);
case OVERHAUL_LAST_LOGIN -> String.valueOf(-1L);
case COOLDOWN_BERSERK, COOLDOWN_GIGA_DRILL_BREAKER, COOLDOWN_TREE_FELLER,
@@ -133,12 +134,12 @@ public class FlatFileDataUtil {
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,
COOLDOWN_SPEARS, 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";
EXP_TRIDENTS, EXP_MACES, EXP_SPEARS -> "0";
case UUID_INDEX ->
throw new IndexOutOfBoundsException(); //TODO: Add UUID recovery? Might not even be worth it.
default -> throw new IndexOutOfBoundsException();

View File

@@ -3,7 +3,6 @@ package com.gmail.nossr50.datatypes.database;
public enum UpgradeType {
ADD_FISHING,
ADD_BLAST_MINING_COOLDOWN,
ADD_SQL_INDEXES,
ADD_MOB_HEALTHBARS,
DROP_SQL_PARTY_NAMES,
DROP_SPOUT,

View File

@@ -1,10 +1,16 @@
package com.gmail.nossr50.datatypes.experience;
public enum XPGainSource {
/** From direct sources, either your own actions or actions done to you. */
SELF,
/** From Vampirism Kills */
VAMPIRISM, //From Vampirism kills
/** From Smelting, Brewing, etc... */
PASSIVE, //Smelting, Brewing, etc...
/** From shared XP from party members */
PARTY_MEMBERS, //From other members of a party
/** From commands or API */
COMMAND,
/** Uncategorized, Other Plugins, etc... */
CUSTOM, //Outside Sources
}

View File

@@ -40,6 +40,7 @@ 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.spears.SpearsManager;
import com.gmail.nossr50.skills.swords.SwordsManager;
import com.gmail.nossr50.skills.taming.TamingManager;
import com.gmail.nossr50.skills.tridents.TridentsManager;
@@ -63,6 +64,7 @@ import com.gmail.nossr50.util.sounds.SoundType;
import java.util.EnumMap;
import java.util.Map;
import java.util.UUID;
import java.util.logging.Level;
import net.kyori.adventure.identity.Identified;
import net.kyori.adventure.identity.Identity;
import org.bukkit.Bukkit;
@@ -171,73 +173,41 @@ public class McMMOPlayer implements Identified {
try {
initManager(primarySkillType);
} catch (InvalidSkillException e) {
e.printStackTrace();
mcMMO.p.getLogger().log(Level.SEVERE,
"Invalid skill while initializing skill managers for player "
+ player.getName()
+ ". Contact the plugin developers.", e);
}
}
}
//TODO: Add test
private void initManager(PrimarySkillType primarySkillType) throws InvalidSkillException {
switch (primarySkillType) {
case ACROBATICS:
skillManagers.put(primarySkillType, new AcrobaticsManager(this));
break;
case ALCHEMY:
skillManagers.put(primarySkillType, new AlchemyManager(this));
break;
case ARCHERY:
skillManagers.put(primarySkillType, new ArcheryManager(this));
break;
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;
case FISHING:
skillManagers.put(primarySkillType, new FishingManager(this));
break;
case HERBALISM:
skillManagers.put(primarySkillType, new HerbalismManager(this));
break;
case MINING:
skillManagers.put(primarySkillType, new MiningManager(this));
break;
case REPAIR:
skillManagers.put(primarySkillType, new RepairManager(this));
break;
case SALVAGE:
skillManagers.put(primarySkillType, new SalvageManager(this));
break;
case SMELTING:
skillManagers.put(primarySkillType, new SmeltingManager(this));
break;
case SWORDS:
skillManagers.put(primarySkillType, new SwordsManager(this));
break;
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!");
final SkillManager manager = switch (primarySkillType) {
case ACROBATICS -> new AcrobaticsManager(this);
case ALCHEMY -> new AlchemyManager(this);
case ARCHERY -> new ArcheryManager(this);
case AXES -> new AxesManager(this);
case CROSSBOWS -> new CrossbowsManager(this);
case EXCAVATION -> new ExcavationManager(this);
case FISHING -> new FishingManager(this);
case HERBALISM -> new HerbalismManager(this);
case MINING -> new MiningManager(this);
case REPAIR -> new RepairManager(this);
case SALVAGE -> new SalvageManager(this);
case SMELTING -> new SmeltingManager(this);
case SWORDS -> new SwordsManager(this);
case TAMING -> new TamingManager(this);
case TRIDENTS -> new TridentsManager(this);
case UNARMED -> new UnarmedManager(this);
case WOODCUTTING -> new WoodcuttingManager(this);
case MACES -> new MacesManager(this);
case SPEARS -> mcMMO.getMinecraftGameVersion().isAtLeast(1, 21, 11)
? new SpearsManager(this)
: null;
};
if (manager != null) {
skillManagers.put(primarySkillType, manager);
}
}
@@ -369,6 +339,10 @@ public class McMMOPlayer implements Identified {
return (SmeltingManager) skillManagers.get(PrimarySkillType.SMELTING);
}
public SpearsManager getSpearsManager() {
return (SpearsManager) skillManagers.get(PrimarySkillType.SPEARS);
}
public SwordsManager getSwordsManager() {
return (SwordsManager) skillManagers.get(PrimarySkillType.SWORDS);
}
@@ -1304,4 +1278,5 @@ public class McMMOPlayer implements Identified {
public void setChatMode(@NotNull ChatChannel chatChannel) {
this.chatChannel = chatChannel;
}
}

View File

@@ -87,7 +87,7 @@ public class PlayerProfile {
this.loaded = isLoaded;
}
public PlayerProfile(@NotNull String playerName, UUID uuid, boolean isLoaded, int startingLvl) {
public PlayerProfile(@NotNull String playerName, @Nullable UUID uuid, boolean isLoaded, int startingLvl) {
this(playerName, uuid, startingLvl);
this.loaded = isLoaded;
}

View File

@@ -8,6 +8,7 @@ public enum MaterialType {
WOOD,
STONE,
IRON,
COPPER,
GOLD,
DIAMOND,
NETHERITE,
@@ -45,6 +46,8 @@ public enum MaterialType {
}
case PRISMARINE:
return Material.PRISMARINE_CRYSTALS;
case COPPER:
return Material.COPPER_INGOT;
case OTHER:
default:

View File

@@ -24,6 +24,7 @@ public enum PrimarySkillType {
REPAIR,
SALVAGE,
SMELTING,
SPEARS,
SWORDS,
TAMING,
TRIDENTS,

View File

@@ -83,6 +83,11 @@ public enum SubSkillType {
SMELTING_SECOND_SMELT,
SMELTING_UNDERSTANDING_THE_ART(8),
/* Spears */
SPEARS_SPEARS_LIMIT_BREAK(10),
SPEARS_MOMENTUM(10),
SPEARS_SPEAR_MASTERY(8),
/* Swords */
SWORDS_COUNTER_ATTACK(1),
SWORDS_RUPTURE(4),

View File

@@ -93,6 +93,13 @@ public enum SuperAbilityType {
"Placeholder",
"Placeholder",
"Placeholder"),
SPEARS_SUPER_ABILITY(
"Placeholder",
"Placeholder",
"Placeholder",
"Placeholder",
"Placeholder",
"Placeholder"),
/**
* Has cooldown - but has to share a skill with Super Breaker, so needs special treatment
@@ -216,8 +223,8 @@ public enum SuperAbilityType {
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;
case EXPLOSIVE_SHOT, TRIDENTS_SUPER_ABILITY, SUPER_SHOTGUN, MACES_SUPER_ABILITY,
SPEARS_SUPER_ABILITY -> false;
};
}

View File

@@ -1,10 +1,8 @@
package com.gmail.nossr50.datatypes.skills.alchemy;
import static com.gmail.nossr50.util.PotionUtil.samePotionType;
import static java.util.Objects.requireNonNull;
import com.gmail.nossr50.mcMMO;
import com.gmail.nossr50.util.PotionUtil;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
@@ -80,12 +78,14 @@ public class AlchemyPotion {
return false;
}
if (!samePotionType(getAlchemyPotionMeta(), otherPotionMeta)) {
@NotNull PotionMeta potionMeta = getAlchemyPotionMeta();
if (!(potionMeta.getBasePotionType() == otherPotionMeta.getBasePotionType())) {
return false;
}
// Legacy only comparison, compare PotionData
if (!PotionUtil.isPotionDataEqual(getAlchemyPotionMeta(), otherPotionMeta)) {
@NotNull PotionMeta potionMeta1 = getAlchemyPotionMeta();
if (!(potionMeta1.getBasePotionType() == otherPotionMeta.getBasePotionType())) {
return false;
}

View File

@@ -0,0 +1,226 @@
package com.gmail.nossr50.events.items;
import static java.util.Objects.requireNonNull;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.entity.Item;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import org.bukkit.event.block.BlockDropItemEvent;
import org.jetbrains.annotations.NotNull;
/**
* Called when mcMMO is modifying the amount of bonus drops to add to an Item involved in a {@link BlockDropItemEvent}.
* <p>
* This event is called before mcMMO has modified the ItemStack quantity on the {@link Item} entity.
* <p>
* This event is called once per Item entity that is involved in the {@link BlockDropItemEvent}.
* <p>
* This event is called during mcMMO logic on the {@link BlockDropItemEvent}, and can be used to
* modify the quantity that mcMMO will add to the ItemStack.
* <p>
* This event is considered cancelled if it is either cancelled directly or if bonus drops are 0 or
* less.
*/
public class McMMOModifyBlockDropItemEvent extends Event implements Cancellable {
private final @NotNull BlockDropItemEvent blockDropItemEvent;
private final int originalBonusAmountToAdd;
private int modifiedItemStackQuantity;
private final @NotNull Item itemThatHasBonusDrops;
private boolean isCancelled = false;
private final int originalItemStackQuantity;
public McMMOModifyBlockDropItemEvent(@NotNull BlockDropItemEvent blockDropItemEvent,
@NotNull Item itemThatHasBonusDrops, int bonusDropsToAdd) {
super(false);
requireNonNull(blockDropItemEvent, "blockDropItemEvent cannot be null");
requireNonNull(itemThatHasBonusDrops, "itemThatHasBonusDrops cannot be null");
if (bonusDropsToAdd <= 0) {
throw new IllegalArgumentException("cannot instantiate a new"
+ " McMMOModifyBlockDropItemEvent with a bonusDropsToAdd that is <= 0");
}
this.blockDropItemEvent = blockDropItemEvent;
this.itemThatHasBonusDrops = itemThatHasBonusDrops;
this.originalItemStackQuantity = itemThatHasBonusDrops.getItemStack().getAmount();
this.originalBonusAmountToAdd = bonusDropsToAdd;
this.modifiedItemStackQuantity = itemThatHasBonusDrops.getItemStack().getAmount()
+ bonusDropsToAdd;
}
@Override
public boolean isCancelled() {
return isCancelled;
}
@Override
public void setCancelled(boolean cancel) {
this.isCancelled = cancel;
}
/**
* The original BlockDropItemEvent which caused this event to be fired.
* @return the original BlockDropItemEvent
*/
public @NotNull BlockDropItemEvent getBlockDropItemEvent() {
return blockDropItemEvent;
}
/**
* The original bonus mcMMO would have added before any modifications to this event from
* other plugins.
* @return the original bonus amount to add
*/
public int getOriginalBonusAmountToAdd() {
return originalBonusAmountToAdd;
}
/**
* The Item entity that is being modified by this event.
* This item returned by this call should not be modified, it is provided as a convenience.
* @return the Item entity that is having bonus drops added to it.
*/
public @NotNull Item getItem() {
return itemThatHasBonusDrops;
}
/**
* The modified ItemStack quantity that will be set on the Item entity if this event is not
* cancelled.
*
* @return the modified ItemStack quantity that will be set on the Item entity
*/
public int getModifiedItemStackQuantity() {
return modifiedItemStackQuantity;
}
/**
* The original ItemStack quantity of the Item entity before any modifications from this event.
* This is a reflection of the state of the Item when mcMMO fired this event.
* It is possible it has modified since then, so do not rely on this value to be the current.
* @return the original ItemStack quantity of the Item entity before any modifications from this event
*/
public int getOriginalItemStackQuantity() {
return originalItemStackQuantity;
}
/**
* The amount of bonus that will be added to the ItemStack quantity if this event is not
* cancelled.
* @return the amount of bonus that will be added to the ItemStack quantity
*/
public int getBonusAmountToAdd() {
return Math.max(0, modifiedItemStackQuantity - originalItemStackQuantity);
}
/**
* Set the amount of bonus that will be added to the ItemStack quantity if this event is not
* cancelled.
* @param bonus the amount of bonus that will be added to the ItemStack quantity
* @throws IllegalArgumentException if bonus is less than 0
*/
public void setBonusAmountToAdd(int bonus) {
if (bonus < 0) throw new IllegalArgumentException("bonus must be >= 0");
this.modifiedItemStackQuantity = originalItemStackQuantity + bonus;
}
/**
* Set the modified ItemStack quantity that will be set on the Item entity if this event is not
* cancelled. This CANNOT be lower than the original quantity of the ItemStack.
* @param modifiedItemStackQuantity the modified ItemStack quantity that will be set on the Item entity
* @throws IllegalArgumentException if modifiedItemStackQuantity is less than originalItemStackQuantity
*/
public void setModifiedItemStackQuantity(int modifiedItemStackQuantity) {
if (modifiedItemStackQuantity < originalItemStackQuantity) {
throw new IllegalArgumentException(
"modifiedItemStackQuantity cannot be less than the originalItemStackQuantity");
}
this.modifiedItemStackQuantity = modifiedItemStackQuantity;
}
public boolean isEffectivelyNoBonus() {
return modifiedItemStackQuantity == originalItemStackQuantity;
}
/**
* Delegate method for {@link BlockDropItemEvent}, gets the Player that is breaking the block
* involved in this event.
*
* @return The Player that is breaking the block involved in this event
*/
public @NotNull Player getPlayer() {
return blockDropItemEvent.getPlayer();
}
/**
* Delegate method for {@link BlockDropItemEvent#getBlock()}.
* Gets the Block involved in this event.
*
* @return the Block involved in this event
*/
public @NotNull Block getBlock() {
return blockDropItemEvent.getBlock();
}
/**
* Delegate method for {@link BlockDropItemEvent#getBlockState()}.
* Gets the BlockState of the block involved in this event.
*
* @return the BlockState of the block involved in this event
*/
public @NotNull BlockState getBlockState() {
return blockDropItemEvent.getBlockState();
}
private static final @NotNull HandlerList handlers = new HandlerList();
@Override
public @NotNull HandlerList getHandlers() {
return handlers;
}
public static @NotNull HandlerList getHandlerList() {
return handlers;
}
@Override
public @NotNull String toString() {
return "McMMOModifyBlockDropItemEvent{" +
"blockDropItemEvent=" + blockDropItemEvent +
", originalBonusAmountToAdd=" + originalBonusAmountToAdd +
", modifiedItemStackQuantity=" + modifiedItemStackQuantity +
", itemThatHasBonusDrops=" + itemThatHasBonusDrops +
", isCancelled=" + isCancelled +
", originalItemStackQuantity=" + originalItemStackQuantity +
'}';
}
@Override
public final boolean equals(Object o) {
if (!(o instanceof McMMOModifyBlockDropItemEvent that)) {
return false;
}
return originalBonusAmountToAdd == that.originalBonusAmountToAdd
&& modifiedItemStackQuantity == that.modifiedItemStackQuantity
&& isCancelled == that.isCancelled
&& originalItemStackQuantity == that.originalItemStackQuantity
&& blockDropItemEvent.equals(that.blockDropItemEvent)
&& itemThatHasBonusDrops.equals(
that.itemThatHasBonusDrops);
}
@Override
public int hashCode() {
int result = blockDropItemEvent.hashCode();
result = 31 * result + originalBonusAmountToAdd;
result = 31 * result + modifiedItemStackQuantity;
result = 31 * result + itemThatHasBonusDrops.hashCode();
result = 31 * result + Boolean.hashCode(isCancelled);
result = 31 * result + originalItemStackQuantity;
return result;
}
}

View File

@@ -1,12 +1,10 @@
package com.gmail.nossr50.listeners;
import static com.gmail.nossr50.util.Misc.getBlockCenter;
import static com.gmail.nossr50.util.MetadataConstants.METADATA_KEY_BONUS_DROPS;
import com.gmail.nossr50.api.ItemSpawnReason;
import com.gmail.nossr50.config.HiddenConfig;
import com.gmail.nossr50.config.WorldBlacklist;
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.SuperAbilityType;
@@ -14,6 +12,7 @@ import com.gmail.nossr50.datatypes.skills.ToolType;
import com.gmail.nossr50.events.fake.FakeBlockBreakEvent;
import com.gmail.nossr50.events.fake.FakeBlockDamageEvent;
import com.gmail.nossr50.events.fake.FakeEvent;
import com.gmail.nossr50.events.items.McMMOModifyBlockDropItemEvent;
import com.gmail.nossr50.mcMMO;
import com.gmail.nossr50.skills.alchemy.Alchemy;
import com.gmail.nossr50.skills.excavation.ExcavationManager;
@@ -26,7 +25,6 @@ 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;
@@ -35,6 +33,8 @@ import com.gmail.nossr50.util.sounds.SoundType;
import com.gmail.nossr50.worldguard.WorldGuardManager;
import com.gmail.nossr50.worldguard.WorldGuardUtils;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.bukkit.ChatColor;
import org.bukkit.GameMode;
import org.bukkit.Location;
@@ -62,6 +62,7 @@ import org.bukkit.event.block.BlockPistonRetractEvent;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.block.EntityBlockFormEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.metadata.MetadataValue;
public class BlockListener implements Listener {
private final mcMMO plugin;
@@ -70,88 +71,98 @@ public class BlockListener implements Listener {
this.plugin = plugin;
}
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = false)
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = false)
public void onBlockDropItemEvent(BlockDropItemEvent event) {
//Make sure we clean up metadata on these blocks
final Block block = event.getBlock();
if (event.isCancelled()) {
if (event.getBlock().hasMetadata(MetadataConstants.METADATA_KEY_BONUS_DROPS)) {
event.getBlock().removeMetadata(MetadataConstants.METADATA_KEY_BONUS_DROPS, plugin);
if (block.hasMetadata(METADATA_KEY_BONUS_DROPS)) {
block.removeMetadata(METADATA_KEY_BONUS_DROPS, plugin);
}
return;
}
int tileEntityTolerance = 1;
try {
int tileEntityTolerance = 1;
// beetroot hotfix, potentially other plants may need this fix
if (event.getBlock().getType() == Material.BEETROOTS) {
tileEntityTolerance = 2;
}
//Track how many "things" are being dropped
HashSet<Material> 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()) {
//Track unique materials
uniqueMaterials.add(item.getItemStack().getType());
//Count blocks as a second failsafe
if (item.getItemStack().getType().isBlock()) {
blockCount++;
// beetroot hotfix, potentially other plants may need this fix
final Material blockType = block.getType();
if (blockType == Material.BEETROOTS) {
tileEntityTolerance = 2;
}
}
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;
}
//Track how many "things" are being dropped
final Set<Material> 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;
//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()) {
ItemStack is = new ItemStack(item.getItemStack());
final List<Item> eventItems = event.getItems();
for (Item item : eventItems) {
//Track unique materials
uniqueMaterials.add(item.getItemStack().getType());
if (is.getAmount() <= 0) {
continue;
//Count blocks as a second failsafe
if (item.getItemStack().getType().isBlock()) {
blockCount++;
}
}
//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())) {
continue;
}
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 we suspect TEs might be duped only reward block
if (dontRewardTE) {
if (!is.getType().isBlock()) {
continue;
}
}
//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 (!block.getMetadata(METADATA_KEY_BONUS_DROPS).isEmpty()) {
final MetadataValue bonusDropMeta = block
.getMetadata(METADATA_KEY_BONUS_DROPS).get(0);
if (blockCount <= 1) {
for (final Item item : eventItems) {
final ItemStack eventItemStack = item.getItemStack();
int originalAmount = eventItemStack.getAmount();
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++) {
if (eventItemStack.getAmount() <= 0) {
continue;
}
ItemUtils.spawnItemNaturally(event.getPlayer(),
centeredLocation, is, ItemSpawnReason.BONUS_DROPS);
final Material itemType = eventItemStack.getType();
if (!mcMMO.p.getGeneralConfig()
.getDoubleDropsEnabled(PrimarySkillType.MINING, itemType)
&& !mcMMO.p.getGeneralConfig()
.getDoubleDropsEnabled(PrimarySkillType.HERBALISM, itemType)
&& !mcMMO.p.getGeneralConfig()
.getDoubleDropsEnabled(PrimarySkillType.WOODCUTTING, itemType)) {
continue;
}
//If we suspect TEs might be duped only reward block
if (dontRewardTE) {
if (!itemType.isBlock()) {
continue;
}
}
int amountToAddFromBonus = bonusDropMeta.asInt();
final McMMOModifyBlockDropItemEvent modifyDropEvent
= new McMMOModifyBlockDropItemEvent(event, item, amountToAddFromBonus);
plugin.getServer().getPluginManager().callEvent(modifyDropEvent);
if (!modifyDropEvent.isCancelled()
&& modifyDropEvent.getModifiedItemStackQuantity() > originalAmount) {
eventItemStack.setAmount(
Math.min(modifyDropEvent.getModifiedItemStackQuantity(),
item.getItemStack().getMaxStackSize()));
}
}
}
}
}
if (event.getBlock().hasMetadata(MetadataConstants.METADATA_KEY_BONUS_DROPS)) {
event.getBlock().removeMetadata(MetadataConstants.METADATA_KEY_BONUS_DROPS, plugin);
} finally {
if (block.hasMetadata(METADATA_KEY_BONUS_DROPS)) {
block.removeMetadata(METADATA_KEY_BONUS_DROPS, plugin);
}
}
}
@@ -231,11 +242,16 @@ public class BlockListener implements Listener {
return;
}
BlockState blockState = event.getNewState();
final BlockState newState = event.getNewState();
if (!newState.isPlaced()) {
// not backed by a real block
return;
}
if (ExperienceConfig.getInstance().isSnowExploitPrevented() && BlockUtils.shouldBeWatched(
blockState)) {
Block block = blockState.getBlock();
newState)) {
final Block block = newState.getBlock();
if (BlockUtils.isWithinWorldBounds(block)) {
BlockUtils.setUnnaturalBlock(block);
@@ -248,7 +264,7 @@ public class BlockListener implements Listener {
*/
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onBlockFormEvent(BlockFormEvent event) {
World world = event.getBlock().getWorld();
final World world = event.getBlock().getWorld();
/* WORLD BLACKLIST CHECK */
if (WorldBlacklist.isWorldBlacklisted(world)) {
@@ -256,12 +272,16 @@ public class BlockListener implements Listener {
}
if (ExperienceConfig.getInstance().preventStoneLavaFarming()) {
BlockState newState = event.getNewState();
final BlockState newState = event.getNewState();
if (!newState.isPlaced()) {
// not backed by a real block
return;
}
if (newState.getType() != Material.OBSIDIAN
&& ExperienceConfig.getInstance().doesBlockGiveSkillXP(
PrimarySkillType.MINING, newState.getType())) {
Block block = newState.getBlock();
final Block block = newState.getBlock();
if (BlockUtils.isWithinWorldBounds(block)) {
BlockUtils.setUnnaturalBlock(block);
}
@@ -696,7 +716,7 @@ public class BlockListener implements Listener {
if (mmoPlayer.getUnarmedManager().canUseBlockCracker()
&& BlockUtils.affectedByBlockCracker(block)) {
if (EventUtils.simulateBlockBreak(block, player)) {
mmoPlayer.getUnarmedManager().blockCrackerCheck(block.getState());
mmoPlayer.getUnarmedManager().blockCrackerCheck(block);
}
} else if (!event.getInstaBreak() && SuperAbilityType.BERSERK.blockCheck(block)
&& EventUtils.simulateBlockBreak(block, player)) {

View File

@@ -43,7 +43,6 @@ import org.bukkit.block.Block;
import org.bukkit.enchantments.Enchantment;
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;
@@ -89,13 +88,18 @@ import org.bukkit.potion.PotionEffectType;
import org.bukkit.projectiles.ProjectileSource;
public class EntityListener implements Listener {
private static final String MULTISHOT = "multishot";
private static final String PIERCING = "piercing";
private static final String DEEPSLATE_REDSTONE_ORE = "deepslate_redstone_ore";
private static final Set<String> ARMOR_STAND = Set.of("ARMOR_STAND", "armor_stand");
private static final Set<String> MANNEQUIN = Set.of("mannequin", "MANNEQUIN");
private final mcMMO pluginRef;
/**
* 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 NamespacedKey piercingEnchantment = NamespacedKey.minecraft(PIERCING);
private final static Set<EntityType> TRANSFORMABLE_ENTITIES
= Set.of(EntityType.SLIME, EntityType.MAGMA_CUBE);
@@ -205,7 +209,7 @@ public class EntityListener implements Listener {
CombatUtils.delayArrowMetaCleanup(arrow);
// If fired from an item with multi-shot, we need to track
if (ItemUtils.doesPlayerHaveEnchantmentInHands(player, "multishot")) {
if (ItemUtils.doesPlayerHaveEnchantmentInHands(player, MULTISHOT)) {
arrow.setMetadata(MetadataConstants.METADATA_KEY_MULTI_SHOT_ARROW,
MetadataConstants.MCMMO_METADATA_VALUE);
}
@@ -221,7 +225,7 @@ public class EntityListener implements Listener {
}
//Check both hands
if (ItemUtils.doesPlayerHaveEnchantmentInHands(player, "piercing")) {
if (ItemUtils.doesPlayerHaveEnchantmentInHands(player, PIERCING)) {
return;
}
@@ -282,7 +286,7 @@ public class EntityListener implements Listener {
entity.removeMetadata(MetadataConstants.METADATA_KEY_TRAVELING_BLOCK, pluginRef);
}
} else if ((block.getType() == Material.REDSTONE_ORE || block.getType().getKey().getKey()
.equalsIgnoreCase("deepslate_redstone_ore"))) {
.equalsIgnoreCase(DEEPSLATE_REDSTONE_ORE))) {
//Redstone ore fire this event and should be ignored
} else {
if (mcMMO.getUserBlockTracker().isIneligible(block)) {
@@ -352,11 +356,13 @@ public class EntityListener implements Listener {
return;
}
// Don't process this event for marked entities, for players this is handled above,
// However, for entities, we do not wanna cancel this event to allow plugins to observe changes
// properly
if (ExperienceConfig.getInstance().isArmorStandInteractionPrevented()
&& isArmorStandEntity(attacker)) {
return;
}
if (event.getEntity() instanceof ArmorStand) {
if (ExperienceConfig.getInstance().isMannequinInteractionPrevented()
&& isMannequinEntity(attacker)) {
return;
}
@@ -385,8 +391,8 @@ 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,
} else if (attacker instanceof TNTPrimed tntAttacker && defender instanceof Player) {
if (BlastMining.processBlastMiningExplosion(event, tntAttacker,
(Player) defender)) {
return;
}
@@ -1196,4 +1202,12 @@ public class EntityListener implements Listener {
}
}
}
public static boolean isMannequinEntity(Entity attacker) {
return MANNEQUIN.contains(attacker.getType().toString());
}
public static boolean isArmorStandEntity(Entity attacker) {
return ARMOR_STAND.contains(attacker.getType().toString());
}
}

View File

@@ -6,7 +6,6 @@ import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
import com.gmail.nossr50.datatypes.skills.SubSkillType;
import com.gmail.nossr50.events.fake.FakeBrewEvent;
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;
@@ -270,7 +269,6 @@ public class InventoryListener implements Listener {
}
event.setCancelled(true);
AlchemyPotionBrewer.scheduleUpdate(inventory);
AlchemyPotionBrewer.scheduleCheck(stand);
return;
default:
@@ -294,7 +292,6 @@ public class InventoryListener implements Listener {
event.setCurrentItem(cursor.clone());
event.setCursor(null);
AlchemyPotionBrewer.scheduleUpdate(inventory);
AlchemyPotionBrewer.scheduleCheck(stand);
} else if (click == ClickType.RIGHT) {
event.setCancelled(true);
@@ -308,7 +305,6 @@ public class InventoryListener implements Listener {
event.setCurrentItem(one);
event.setCursor(rest);
AlchemyPotionBrewer.scheduleUpdate(inventory);
AlchemyPotionBrewer.scheduleCheck(stand);
}
}
@@ -371,7 +367,6 @@ public class InventoryListener implements Listener {
}
event.setCancelled(true);
AlchemyPotionBrewer.scheduleUpdate(inventory);
}
}
@@ -406,39 +401,41 @@ public class InventoryListener implements Listener {
@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())) {
return;
}
}
final Inventory inventory = event.getDestination();
if (!(inventory instanceof BrewerInventory)) {
return;
}
/* WORLD BLACKLIST CHECK */
final Location sourceLocation = event.getSource().getLocation();
if (sourceLocation != null && WorldBlacklist.isWorldBlacklisted(sourceLocation.getWorld())) {
return;
}
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().getPreventHopperTransferBottles() && (
item.getType() == Material.POTION || item.getType() == Material.SPLASH_POTION
|| item.getType() == Material.LINGERING_POTION)) {
event.setCancelled(true);
return;
}
if (!mcMMO.p.getGeneralConfig().getEnabledForHoppers()) {
return;
}
final InventoryHolder holder = inventory.getHolder();
if (holder instanceof BrewingStand brewingStand) {
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().getPreventHopperTransferBottles() && (
item.getType() == Material.POTION || item.getType() == Material.SPLASH_POTION
|| item.getType() == Material.LINGERING_POTION)) {
event.setCancelled(true);
return;
}
int ingredientLevel = 1;
OfflinePlayer offlinePlayer = ContainerMetadataUtils.getContainerOwner(brewingStand);
@@ -449,8 +446,7 @@ public class InventoryListener implements Listener {
}
}
if (mcMMO.p.getGeneralConfig().getEnabledForHoppers()
&& AlchemyPotionBrewer.isValidIngredientByLevel(ingredientLevel, item)) {
if (AlchemyPotionBrewer.isValidIngredientByLevel(ingredientLevel, item)) {
AlchemyPotionBrewer.scheduleCheck(brewingStand);
}
}
@@ -510,9 +506,6 @@ public class InventoryListener implements Listener {
return;
}
}
mcMMO.p.getFoliaLib().getScheduler()
.runAtEntity(whoClicked, new PlayerUpdateInventoryTask((Player) whoClicked));
}
}

View File

@@ -168,6 +168,7 @@ public class PlayerListener implements Listener {
if (WorldBlacklist.isWorldBlacklisted(event.getEntity().getWorld())) {
return;
}
// world guard main flag check
if (WorldGuardUtils.isWorldGuardLoaded() && !WorldGuardManager.getInstance()
.hasMainFlag((Player) event.getEntity())) {
@@ -342,8 +343,8 @@ public class PlayerListener implements Listener {
FishingManager fishingManager = UserManager.getPlayer(player).getFishingManager();
switch (event.getState()) {
// CAUGHT_FISH happens for any item caught (including junk and treasure)
case CAUGHT_FISH:
//TODO Update to new API once available! Waiting for case CAUGHT_TREASURE
if (event.getCaught() != null) {
Item fishingCatch = (Item) event.getCaught();
@@ -488,8 +489,7 @@ public class PlayerListener implements Listener {
fishingManager.processExploiting(event.getHook().getLocation().toVector());
if (fishingManager.isExploitingFishing(
event.getHook().getLocation().toVector())) {
if (fishingManager.isExploitingFishing()) {
player.sendMessage(LocaleLoader.getString("Fishing.ScarcityTip",
ExperienceConfig.getInstance()
.getFishingExploitingOptionMoveRange()));
@@ -675,6 +675,10 @@ public class PlayerListener implements Listener {
*/
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
public void onPlayerInteractLowest(PlayerInteractEvent event) {
if (event.getAction() == Action.PHYSICAL) {
return;
}
/* WORLD BLACKLIST CHECK */
if (WorldBlacklist.isWorldBlacklisted(event.getPlayer().getWorld())) {
return;
@@ -737,7 +741,6 @@ public class PlayerListener implements Listener {
// Make sure the player knows what he's doing when trying to repair an enchanted item
if (repairManager.checkConfirmation(true)) {
repairManager.handleRepair(heldItem);
player.updateInventory();
}
}
/* SALVAGE CHECKS */
@@ -756,7 +759,6 @@ public class PlayerListener implements Listener {
if (salvageManager.checkConfirmation(true)) {
SkillUtils.removeAbilityBoostsFromInventory(player);
salvageManager.handleSalvage(clickedBlock.getLocation(), heldItem);
player.updateInventory();
}
}
@@ -819,6 +821,10 @@ public class PlayerListener implements Listener {
*/
@EventHandler(priority = EventPriority.MONITOR)
public void onPlayerInteractMonitor(PlayerInteractEvent event) {
if (event.getAction() == Action.PHYSICAL) {
return;
}
/* WORLD BLACKLIST CHECK */
if (WorldBlacklist.isWorldBlacklisted(event.getPlayer().getWorld())) {
return;
@@ -902,7 +908,6 @@ public class PlayerListener implements Listener {
HerbalismManager herbalismManager = mmoPlayer.getHerbalismManager();
// FakePlayerAnimationEvent fakeSwing = new FakePlayerAnimationEvent(event.getPlayer(), PlayerAnimationType.ARM_SWING); //PlayerAnimationEvent compat
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) {
@@ -926,7 +931,6 @@ public class PlayerListener implements Listener {
// Bukkit.getPluginManager().callEvent(fakeSwing);
player.getInventory().getItemInMainHand()
.setAmount(heldItem.getAmount() - 1);
player.updateInventory();
if (herbalismManager.processGreenThumbBlocks(blockState)
&& EventUtils.simulateBlockBreak(block, player)) {
blockState.update(true);

View File

@@ -56,14 +56,13 @@ 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.MinecraftGameVersionFactory;
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;
import com.gmail.nossr50.util.platform.PlatformManager;
import com.gmail.nossr50.util.platform.ServerSoftwareType;
import com.gmail.nossr50.util.platform.MinecraftGameVersion;
import com.gmail.nossr50.util.player.PlayerLevelUtils;
import com.gmail.nossr50.util.player.UserManager;
import com.gmail.nossr50.util.scoreboards.ScoreboardManager;
@@ -78,6 +77,7 @@ import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
import net.shatteredlands.shatt.backup.ZipLibrary;
import org.bstats.bukkit.Metrics;
@@ -86,16 +86,13 @@ import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.HandlerList;
import org.bukkit.metadata.FixedMetadataValue;
import org.bukkit.plugin.PluginDescriptionFile;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.plugin.java.JavaPluginLoader;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class mcMMO extends JavaPlugin {
/* Managers & Services */
private static PlatformManager platformManager;
private static ChunkManager chunkManager;
private static RepairableManager repairableManager;
private static SalvageableManager salvageableManager;
@@ -108,6 +105,7 @@ public class mcMMO extends JavaPlugin {
private static ChatManager chatManager;
private static CommandManager commandManager; //ACF
private static TransientEntityTracker transientEntityTracker;
private static MinecraftGameVersion minecraftGameVersion;
private SkillTools skillTools;
@@ -171,8 +169,19 @@ 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();
// Determine game version before moving forward
final String versionStr = Bukkit.getVersion();
try {
minecraftGameVersion = MinecraftGameVersionFactory.calculateGameVersion(versionStr);
} catch (Exception e) {
// if anything goes wrong with our calculations, assume they are running the minimum
// supported version and log the error
getLogger().warning("Could not determine Minecraft version from"
+ " server software version string: " + versionStr +
", Please report this bug to the devs!");
e.printStackTrace();
minecraftGameVersion = new MinecraftGameVersion(1, 20, 5);
}
//Folia lib plugin instance
foliaLib = new FoliaLib(this);
@@ -244,17 +253,16 @@ public class mcMMO extends JavaPlugin {
checkForOutdatedAPI();
if (serverAPIOutdated) {
foliaLib.getImpl().runTimer(
foliaLib.getScheduler().runTimer(
() -> getLogger().severe(
"You are running an outdated version of "
+ platformManager.getServerSoftware()
"You are potentially running an outdated version of your server software"
+ ", mcMMO will not work unless you update to a newer version!"),
20, 20 * 60 * 30);
if (platformManager.getServerSoftware() == ServerSoftwareType.CRAFT_BUKKIT) {
foliaLib.getImpl().runTimer(
if (!minecraftGameVersion.isAtLeast(1, 20, 4)) {
foliaLib.getScheduler().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."),
"This version of mcMMO requires at least Minecraft 1.20.4 to"
+ " function properly, please update your software or use an older version of mcMMO!"),
20, 20 * 60 * 30);
}
} else {
@@ -306,13 +314,11 @@ public class mcMMO extends JavaPlugin {
}
}
} catch (Throwable t) {
getLogger().severe("There was an error while enabling mcMMO!");
getLogger().log(Level.SEVERE, "There was an error while enabling mcMMO!", t);
if (!(t instanceof ExceptionInInitializerError)) {
t.printStackTrace();
} else {
getLogger().info(
"Please do not replace the mcMMO jar while the server is running.");
if (t instanceof ExceptionInInitializerError) {
getLogger().info("Please do not replace the mcMMO jar while the server"
+ " is running.");
}
getServer().getPluginManager().disablePlugin(this);
@@ -354,15 +360,15 @@ public class mcMMO extends JavaPlugin {
private void checkForOutdatedAPI() {
try {
Class<?> checkForClass = Class.forName("org.bukkit.event.block.BlockDropItemEvent");
checkForClass.getMethod("getItems");
Class<?> blockDropItemEvent = Class.forName("org.bukkit.event.block.BlockDropItemEvent");
blockDropItemEvent.getMethod("getItems");
Class.forName("net.md_5.bungee.api.chat.BaseComponent");
// 1.20.4 checks
Class<?> entityDamageEvent = Class.forName("org.bukkit.event.entity.EntityDamageEvent");
entityDamageEvent.getMethod("getDamageSource");
} 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("Your server software is missing APIs that mcMMO requires to function properly, please update your server software!");
}
}
@@ -399,7 +405,7 @@ public class mcMMO extends JavaPlugin {
formulaManager.saveFormula();
chunkManager.closeAll();
} catch (Exception e) {
e.printStackTrace();
getLogger().log(Level.SEVERE, "An error occurred while disabling mcMMO!", e);
}
if (generalConfig.getBackupsEnabled()) {
@@ -505,10 +511,6 @@ public class mcMMO extends JavaPlugin {
return upgradeManager;
}
public static @Nullable CompatibilityManager getCompatibilityManager() {
return platformManager.getCompatibilityManager();
}
@Deprecated
public static void setDatabaseManager(DatabaseManager databaseManager) {
mcMMO.databaseManager = databaseManager;
@@ -587,7 +589,6 @@ public class mcMMO extends JavaPlugin {
TreasureConfig.getInstance();
FishingTreasureConfig.getInstance();
HiddenConfig.getInstance();
mcMMO.p.getAdvancedConfig();
// init potion config
potionConfig = new PotionConfig();
@@ -597,16 +598,15 @@ public class mcMMO extends JavaPlugin {
SoundConfig.getInstance();
RankConfig.getInstance();
List<Repairable> repairables = new ArrayList<>();
// Load repair configs, make manager, and register them at this time
repairables.addAll(new RepairConfigManager(this).getLoadedRepairables());
final List<Repairable> repairables = new ArrayList<>(
new RepairConfigManager(this).getLoadedRepairables());
repairableManager = new SimpleRepairableManager(repairables.size());
repairableManager.registerRepairables(repairables);
// Load salvage configs, make manager and register them at this time
SalvageConfigManager sManager = new SalvageConfigManager(this);
List<Salvageable> salvageables = sManager.getLoadedSalvageables();
final List<Salvageable> salvageables = sManager.getLoadedSalvageables();
salvageableManager = new SimpleSalvageableManager(salvageables.size());
salvageableManager.registerSalvageables(salvageables);
}
@@ -756,10 +756,6 @@ public class mcMMO extends JavaPlugin {
return worldBlacklist;
}
public static PlatformManager getPlatformManager() {
return platformManager;
}
public static BukkitAudiences getAudiences() {
return audiences;
}
@@ -840,4 +836,13 @@ public class mcMMO extends JavaPlugin {
public @NotNull FoliaLib getFoliaLib() {
return foliaLib;
}
/**
* Get the {@link MinecraftGameVersion}
*
* @return the {@link MinecraftGameVersion}
*/
public static MinecraftGameVersion getMinecraftGameVersion() {
return minecraftGameVersion;
}
}

View File

@@ -172,10 +172,8 @@ public final class ShareHandler {
}
private static void awardDrop(Player winningPlayer, ItemStack drop) {
if (winningPlayer.getInventory().addItem(drop).size() != 0) {
if (!winningPlayer.getInventory().addItem(drop).isEmpty()) {
winningPlayer.getWorld().dropItem(winningPlayer.getLocation(), drop);
}
winningPlayer.updateInventory();
}
}

View File

@@ -49,12 +49,6 @@ public class McRankCommandDisplayTask extends CancellableRunnable {
sender.sendMessage(LocaleLoader.getString("Commands.mcrank.Player", playerName));
for (PrimarySkillType skill : SkillTools.NON_CHILD_SKILLS) {
// 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),

View File

@@ -1,18 +0,0 @@
package com.gmail.nossr50.runnables.player;
import com.gmail.nossr50.util.CancellableRunnable;
import org.bukkit.entity.Player;
@SuppressWarnings("deprecation")
public class PlayerUpdateInventoryTask extends CancellableRunnable {
private final Player player;
public PlayerUpdateInventoryTask(Player player) {
this.player = player;
}
@Override
public void run() {
player.updateInventory();
}
}

View File

@@ -12,6 +12,7 @@ import com.gmail.nossr50.util.skills.PerksUtils;
import com.gmail.nossr50.util.skills.SkillUtils;
import org.bukkit.Chunk;
import org.bukkit.World;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
public class AbilityDisableTask extends CancellableRunnable {
@@ -72,7 +73,7 @@ public class AbilityDisableTask extends CancellableRunnable {
}
}
private void resendChunkRadiusAt(Player player) {
private void resendChunkRadiusAt(Entity player) {
Chunk chunk = player.getLocation().getChunk();
World world = player.getWorld();

View File

@@ -159,13 +159,13 @@ public class AlchemyBrewTask extends CancellableRunnable {
private void finish() {
if (mmoPlayer == null) {
// Still need to finish brewing if the player is null
AlchemyPotionBrewer.finishBrewing(brewingStand, null, false);
AlchemyPotionBrewer.finishBrewing(brewingStand, null);
} else {
final McMMOPlayerBrewEvent event = new McMMOPlayerBrewEvent(mmoPlayer, brewingStand);
mcMMO.p.getServer().getPluginManager().callEvent(event);
if (!event.isCancelled()) {
AlchemyPotionBrewer.finishBrewing(brewingStand, mmoPlayer, false);
AlchemyPotionBrewer.finishBrewing(brewingStand, mmoPlayer);
}
}
@@ -175,7 +175,7 @@ public class AlchemyBrewTask extends CancellableRunnable {
public void finishImmediately() {
this.cancel();
AlchemyPotionBrewer.finishBrewing(brewingStand, mmoPlayer, true);
AlchemyPotionBrewer.finishBrewing(brewingStand, mmoPlayer);
Alchemy.brewingStandMap.remove(brewingStand.getLocation());
}

View File

@@ -51,8 +51,7 @@ public class DelayedCropReplant extends CancellableRunnable {
@Override
public void run() {
Block cropBlock = cropLocation.getBlock();
BlockState currentState = cropBlock.getState();
final BlockState blockState = cropLocation.getBlock().getState();
PlantAnchorType plantAnchorType = PlantAnchorType.NORMAL;
//Remove the metadata marking the block as recently replanted
@@ -64,51 +63,44 @@ public class DelayedCropReplant extends CancellableRunnable {
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))
//The space is not currently occupied by a block so we can fill it
cropBlock.setType(cropMaterial);
if (blockIsAirOrExpectedCrop(blockState)) {
// Modify the new state of the block, not any old snapshot of it
blockState.setType(cropMaterial);
final BlockData newData = blockState.getBlockData();
//Get new state (necessary?)
BlockState newState = cropBlock.getState();
BlockData newData = newState.getBlockData();
int age = 0;
//Crop age should always be 0 if the plant was immature
if (!wasImmaturePlant) {
age = desiredCropAge;
//Otherwise make the plant the desired age
}
// Immature plants should be age 0, others get the desired age
int age = wasImmaturePlant ? 0 : desiredCropAge;
if (newData instanceof Directional) {
//Cocoa Version
Directional directional = (Directional) newState.getBlockData();
// Cocoa Version
Directional directional = (Directional) blockState.getBlockData();
directional.setFacing(cropFace);
newState.setBlockData(directional);
blockState.setBlockData(directional);
if (newData instanceof Cocoa) {
plantAnchorType = PlantAnchorType.COCOA;
}
}
//Age the crop
Ageable ageable = (Ageable) newState.getBlockData();
ageable.setAge(age);
newState.setBlockData(ageable);
if (blockState.getBlockData() instanceof Ageable ageable) {
ageable.setAge(age);
blockState.setBlockData(ageable);
blockState.update(true, true);
newState.update(true, true);
//Play an effect
ParticleEffectUtils.playGreenThumbEffect(cropLocation);
mcMMO.p.getFoliaLib().getScheduler().runAtLocationLater(newState.getLocation(),
new PhysicsBlockUpdate(newState.getBlock(), cropFace, plantAnchorType), 1);
//Play an effect
ParticleEffectUtils.playGreenThumbEffect(cropLocation);
mcMMO.p.getFoliaLib().getScheduler().runAtLocationLater(blockState.getLocation(),
new PhysicsBlockUpdate(blockState.getBlock(), cropFace, plantAnchorType), 1);
}
}
}
private boolean blockIsAirOrExpectedCrop(BlockState blockState) {
return blockState.getType().equals(cropMaterial) || blockState.getType()
.equals(Material.AIR) || blockState.getType().equals(Material.CAVE_AIR);
}
private enum PlantAnchorType {
NORMAL,
COCOA

View File

@@ -32,7 +32,7 @@ public abstract class SkillManager {
* @param xpGainReason the reason for the XP gain
* @deprecated use applyXpGain(float, XPGainReason, XPGainSource)
*/
@Deprecated
@Deprecated(forRemoval = true)
public void applyXpGain(float xp, XPGainReason xpGainReason) {
mmoPlayer.beginXpGain(skill, xp, xpGainReason, XPGainSource.SELF);
}

View File

@@ -3,6 +3,7 @@ package com.gmail.nossr50.skills.acrobatics;
import com.gmail.nossr50.config.experience.ExperienceConfig;
import com.gmail.nossr50.datatypes.BlockLocationHistory;
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;
@@ -19,6 +20,8 @@ import com.gmail.nossr50.util.random.ProbabilityUtil;
import com.gmail.nossr50.util.skills.ParticleEffectUtils;
import com.gmail.nossr50.util.skills.RankUtils;
import com.gmail.nossr50.util.skills.SkillUtils;
import com.tcoded.folialib.wrapper.task.WrappedTask;
import java.util.function.Consumer;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
import org.bukkit.entity.LightningStrike;
@@ -118,10 +121,10 @@ public class AcrobaticsManager extends SkillManager {
if (count <= 5) {
applyXpGain((float) (damage * Acrobatics.dodgeXpModifier),
XPGainReason.PVE);
XPGainReason.PVE, XPGainSource.SELF);
mob.setMetadata(MetadataConstants.METADATA_KEY_DODGE_TRACKER,
new FixedMetadataValue(mcMMO.p, count + 1));
MobDodgeMetaCleanup metaCleanupTask = new MobDodgeMetaCleanup(mob,
final Consumer<WrappedTask> metaCleanupTask = new MobDodgeMetaCleanup(mob,
mcMMO.p);
mcMMO.p.getFoliaLib().getScheduler()
.runAtEntityTimer(mob, metaCleanupTask, 20,
@@ -129,7 +132,7 @@ public class AcrobaticsManager extends SkillManager {
}
} else {
applyXpGain((float) (damage * Acrobatics.dodgeXpModifier),
XPGainReason.PVE);
XPGainReason.PVE, XPGainSource.SELF);
}
}
}

View File

@@ -6,7 +6,6 @@ import com.gmail.nossr50.datatypes.skills.alchemy.AlchemyPotion;
import com.gmail.nossr50.datatypes.skills.alchemy.PotionStage;
import com.gmail.nossr50.events.fake.FakeBrewEvent;
import com.gmail.nossr50.mcMMO;
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;
@@ -18,11 +17,9 @@ import java.util.List;
import org.bukkit.Material;
import org.bukkit.block.BlockState;
import org.bukkit.block.BrewingStand;
import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.ClickType;
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;
@@ -164,8 +161,7 @@ public final class AlchemyPotionBrewer {
? 1 : mmoPlayer.getAlchemyManager().getTier());
}
public static void finishBrewing(BlockState brewingStand, @Nullable McMMOPlayer mmoPlayer,
boolean forced) {
public static void finishBrewing(BlockState brewingStand, @Nullable McMMOPlayer mmoPlayer) {
// Check if the brewing stand block state is an actual brewing stand
if (!(brewingStand instanceof BrewingStand)) {
return;
@@ -257,11 +253,6 @@ public final class AlchemyPotionBrewer {
}
}
}
// If the brewing was not forced by external conditions, schedule a new update
if (!forced) {
scheduleUpdate(inventory);
}
}
public static boolean transferItems(InventoryView view, int fromSlot, ClickType click) {
@@ -356,13 +347,4 @@ public final class AlchemyPotionBrewer {
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().getScheduler().runAtEntity(humanEntity,
new PlayerUpdateInventoryTask((Player) humanEntity));
}
}
}
}

View File

@@ -6,9 +6,10 @@ import com.gmail.nossr50.datatypes.skills.SubSkillType;
import com.gmail.nossr50.mcMMO;
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 java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import org.bukkit.Material;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
@@ -16,7 +17,7 @@ import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
public class Archery {
private static final List<TrackedEntity> trackedEntities = new ArrayList<>();
private static final Map<UUID, TrackedEntity> trackedEntities = new ConcurrentHashMap<>();
public static double skillShotMaxBonusDamage = mcMMO.p.getAdvancedConfig()
.getSkillShotDamageMax();
@@ -27,25 +28,12 @@ public class Archery {
.getArcheryDistanceMultiplier();
protected static void incrementTrackerValue(LivingEntity livingEntity) {
for (TrackedEntity trackedEntity : trackedEntities) {
if (trackedEntity.getLivingEntity().getEntityId() == livingEntity.getEntityId()) {
trackedEntity.incrementArrowCount();
return;
}
}
addToTracker(livingEntity); // If the entity isn't tracked yet
}
protected static void addToTracker(LivingEntity livingEntity) {
TrackedEntity trackedEntity = new TrackedEntity(livingEntity);
final TrackedEntity trackedEntity = trackedEntities.computeIfAbsent(livingEntity.getUniqueId(), k -> new TrackedEntity(livingEntity));
trackedEntity.incrementArrowCount();
trackedEntities.add(trackedEntity);
}
protected static void removeFromTracker(TrackedEntity trackedEntity) {
trackedEntities.remove(trackedEntity);
trackedEntities.remove(trackedEntity.getID());
}
/**
@@ -54,17 +42,11 @@ public class Archery {
* @param livingEntity The entity hit by the arrows
*/
public static void arrowRetrievalCheck(@NotNull LivingEntity livingEntity) {
for (Iterator<TrackedEntity> entityIterator = trackedEntities.iterator();
entityIterator.hasNext(); ) {
TrackedEntity trackedEntity = entityIterator.next();
if (trackedEntity.getID() == livingEntity.getUniqueId()) {
ItemUtils.spawnItems(null, livingEntity.getLocation(),
new ItemStack(Material.ARROW), trackedEntity.getArrowCount(),
ItemSpawnReason.ARROW_RETRIEVAL_ACTIVATED);
entityIterator.remove();
return;
}
final TrackedEntity trackedEntity = trackedEntities.remove(livingEntity.getUniqueId());
if (trackedEntity != null) {
ItemUtils.spawnItems(null, livingEntity.getLocation(),
new ItemStack(Material.ARROW), trackedEntity.getArrowCount(),
ItemSpawnReason.ARROW_RETRIEVAL_ACTIVATED);
}
}

View File

@@ -4,6 +4,7 @@ import com.gmail.nossr50.api.ItemSpawnReason;
import com.gmail.nossr50.config.experience.ExperienceConfig;
import com.gmail.nossr50.config.treasure.FishingTreasureConfig;
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;
@@ -27,7 +28,6 @@ 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.ProbabilityUtil;
import com.gmail.nossr50.util.skills.CombatUtils;
@@ -39,7 +39,6 @@ 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;
@@ -54,31 +53,24 @@ import org.bukkit.entity.Sheep;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import org.bukkit.inventory.meta.SkullMeta;
import org.bukkit.metadata.Metadatable;
import org.bukkit.util.BoundingBox;
import org.bukkit.util.Vector;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class FishingManager extends SkillManager {
public static final int FISHING_ROD_CAST_CD_MILLISECONDS = 100;
private final long FISHING_COOLDOWN_SECONDS = 1000L;
private long fishingRodCastTimestamp = 0L;
private long fishHookSpawnTimestamp = 0L;
private long lastWarned = 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 mmoPlayer) {
super(mmoPlayer, PrimarySkillType.FISHING);
//Ticks for minWait and maxWait never go below this value
// Ticks for minWait and maxWait never go below this value
int bonusCapMin = mcMMO.p.getAdvancedConfig().getFishingReductionMinWaitCap();
int bonusCapMax = mcMMO.p.getAdvancedConfig().getFishingReductionMaxWaitCap();
@@ -94,53 +86,18 @@ public class FishingManager extends SkillManager {
}
public boolean canMasterAngler() {
return mcMMO.getCompatibilityManager().getMasterAnglerCompatibilityLayer() != null
&& getSkillLevel() >= RankUtils.getUnlockLevel(SubSkillType.FISHING_MASTER_ANGLER)
return 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)
// return;
//
// 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) {
// fishingRod = getPlayer().getInventory().getItemInOffHand();
// }
//
// getPlayer().setFoodLevel(Math.max(getPlayer().getFoodLevel() - 1, 0));
// fishingRod.setDurability((short) (fishingRod.getDurability() + 5));
// getPlayer().updateInventory();
//
// if (lastWarnedExhaust + (1000) < currentTime)
// {
// getPlayer().sendMessage(LocaleLoader.getString("Fishing.Exhausting"));
// lastWarnedExhaust = currentTime;
// SoundManager.sendSound(getPlayer(), getPlayer().getLocation(), SoundType.TIRED);
// }
// }
//
// fishingRodCastTimestamp = System.currentTimeMillis();
// }
public void setFishHookReference(FishHook fishHook) {
if (fishHook.getMetadata(MetadataConstants.METADATA_KEY_FISH_HOOK_REF).size() > 0) {
public void setFishHookReference(Metadatable fishHook) {
if (!fishHook.getMetadata(MetadataConstants.METADATA_KEY_FISH_HOOK_REF).isEmpty()) {
return;
}
fishHook.setMetadata(MetadataConstants.METADATA_KEY_FISH_HOOK_REF,
MetadataConstants.MCMMO_METADATA_VALUE);
this.fishHookReference = fishHook;
fishHookSpawnTimestamp = System.currentTimeMillis();
fishingRodCastTimestamp = System.currentTimeMillis();
}
public boolean isFishingTooOften() {
@@ -179,21 +136,41 @@ public class FishingManager extends SkillManager {
}
}
/**
* Determines if the player is exploiting fishing by checking if they have caught
* more fish than the configured limit without moving their fishing spot.
* This method relies on internal state to determine if the player is exploiting fishing,
* and the centerOfCastVector parameter is no longer used and will be removed in
* a future version.
*
* @param centerOfCastVector unused
* @deprecated since 2.2.050, the parameter is no longer used and will be removed in
* a future version. The method now relies on internal state to determine if the player
* is exploiting fishing.
* @return true if the player is exploiting fishing, false otherwise
*/
@Deprecated(forRemoval = true, since = "2.2.050")
public boolean isExploitingFishing(Vector centerOfCastVector) {
return this.sameTarget && fishCaughtCounter >= ExperienceConfig.getInstance()
.getFishingExploitingOptionOverFishLimit();
}
/*Block targetBlock = getPlayer().getTargetBlock(BlockUtils.getTransparentBlocks(), 100);
if (!targetBlock.isLiquid()) {
return false;
}*/
/**
* Determines if the player is exploiting fishing by checking if they have caught
* more fish than the configured limit without moving their fishing spot.
*
* @return true if the player is exploiting fishing, false otherwise
*/
public boolean isExploitingFishing() {
return this.sameTarget && fishCaughtCounter >= ExperienceConfig.getInstance()
.getFishingExploitingOptionOverFishLimit();
}
public static BoundingBox makeBoundingBox(Vector centerOfCastVector) {
int exploitingRange = ExperienceConfig.getInstance().getFishingExploitingOptionMoveRange();
return BoundingBox.of(centerOfCastVector, exploitingRange / 2, 1, exploitingRange / 2);
return BoundingBox.of(centerOfCastVector,
(double) exploitingRange / 2, 1,
(double) exploitingRange / 2);
}
public void setFishingTarget() {
@@ -242,15 +219,6 @@ public class FishingManager extends SkillManager {
return mcMMO.p.getAdvancedConfig().getFishingVanillaXPModifier(getLootTier());
}
/**
* Gets the Shake Mob probability
*
* @return Shake Mob probability
*/
public double getShakeProbability() {
return getShakeChance();
}
/**
* Handle the Fisherman's Diet ability
*
@@ -292,102 +260,95 @@ public class FishingManager extends SkillManager {
* @param fishHook target fish hook
*/
public void processMasterAngler(@NotNull FishHook fishHook, int lureLevel) {
MasterAnglerCompatibilityLayer masterAnglerCompatibilityLayer = (MasterAnglerCompatibilityLayer) mcMMO.getCompatibilityManager()
.getMasterAnglerCompatibilityLayer();
int maxWaitTicks = fishHook.getMaxWaitTime();
int minWaitTicks = fishHook.getMinWaitTime();
if (masterAnglerCompatibilityLayer != null) {
int maxWaitTicks = masterAnglerCompatibilityLayer.getMaxWaitTime(fishHook);
int minWaitTicks = masterAnglerCompatibilityLayer.getMinWaitTime(fishHook);
int masterAnglerRank = RankUtils.getRank(mmoPlayer, SubSkillType.FISHING_MASTER_ANGLER);
int convertedLureBonus = 0;
int masterAnglerRank = RankUtils.getRank(mmoPlayer, SubSkillType.FISHING_MASTER_ANGLER);
int convertedLureBonus = 0;
//This avoids a Minecraft bug where lure levels above 3 break fishing
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 reducedMinWaitTime = getReducedTicks(minWaitTicks, minWaitReduction,
masterAnglerMinWaitLowerBound);
int reducedMaxWaitTime = getReducedTicks(maxWaitTicks, maxWaitReduction,
masterAnglerMaxWaitLowerBound);
boolean badValuesFix = false;
//If we find bad values correct it
if (reducedMaxWaitTime < reducedMinWaitTime) {
reducedMaxWaitTime = reducedMinWaitTime + 100;
badValuesFix = true;
}
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, minWaitLowerBound wait should never be lower than min wait.");
}
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);
}
mmoPlayer.getPlayer().sendMessage("");
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("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 minWaitLowerBound wait ticks "
+ masterAnglerMinWaitLowerBound);
mmoPlayer.getPlayer().sendMessage(
"Lowest possible min wait ticks " + masterAnglerMaxWaitLowerBound);
}
masterAnglerCompatibilityLayer.setMaxWaitTime(fishHook, reducedMaxWaitTime);
masterAnglerCompatibilityLayer.setMinWaitTime(fishHook, reducedMinWaitTime);
//This avoids a Minecraft bug where lure levels above 3 break fishing
if (lureLevel > 0) {
fishHook.setApplyLure(false);
convertedLureBonus = lureLevel * 100;
}
boolean boatBonus = isInBoat();
int minWaitReduction = getMasterAnglerTickMinWaitReduction(masterAnglerRank, boatBonus);
int maxWaitReduction = getMasterAnglerTickMaxWaitReduction(masterAnglerRank, boatBonus,
convertedLureBonus);
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) {
reducedMaxWaitTime = reducedMinWaitTime + 100;
badValuesFix = true;
}
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, minWaitLowerBound wait should never be lower than min wait.");
}
mmoPlayer.getPlayer().sendMessage(
"ALLOW STACK WITH LURE: " + fishHook.getApplyLure());
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);
}
mmoPlayer.getPlayer().sendMessage("");
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("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 minWaitLowerBound wait ticks "
+ masterAnglerMinWaitLowerBound);
mmoPlayer.getPlayer().sendMessage(
"Lowest possible min wait ticks " + masterAnglerMaxWaitLowerBound);
}
fishHook.setMaxWaitTime(reducedMaxWaitTime);
fishHook.setMinWaitTime(reducedMinWaitTime);
}
public int getReducedTicks(int ticks, int totalBonus, int tickBounds) {
@@ -435,6 +396,7 @@ public class FishingManager extends SkillManager {
public boolean isMagicHunterEnabled() {
return RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.FISHING_MAGIC_HUNTER)
&& RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.FISHING_TREASURE_HUNTER)
&& Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.FISHING_MAGIC_HUNTER)
&& Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.FISHING_TREASURE_HUNTER);
}
@@ -444,7 +406,6 @@ public class FishingManager extends SkillManager {
* @param fishingCatch The {@link Item} initially caught
*/
public void processFishing(@NotNull Item fishingCatch) {
this.fishingCatch = fishingCatch;
int fishXp = ExperienceConfig.getInstance()
.getXp(PrimarySkillType.FISHING, fishingCatch.getItemStack().getType());
int treasureXp = 0;
@@ -456,7 +417,6 @@ public class FishingManager extends SkillManager {
if (mcMMO.p.getGeneralConfig().getFishingDropsEnabled() && Permissions.isSubSkillEnabled(
player, SubSkillType.FISHING_TREASURE_HUNTER)) {
treasure = getFishingTreasure();
this.fishingCatch = null;
}
if (treasure != null) {
@@ -526,7 +486,7 @@ public class FishingManager extends SkillManager {
fishingCatch.setItemStack(treasureDrop);
}
applyXpGain(fishXp + treasureXp, XPGainReason.PVE);
applyXpGain(fishXp + treasureXp, XPGainReason.PVE, XPGainSource.SELF);
}
/**
@@ -539,10 +499,6 @@ public class FishingManager extends SkillManager {
return experience * getVanillaXpMultiplier();
}
public Location getHookLocation() {
return hookLocation;
}
/**
* Handle the Shake ability
*
@@ -596,8 +552,6 @@ public class FishingManager extends SkillManager {
drop.getAmount() - 1) : null);
drop.setAmount(1);
}
targetPlayer.updateInventory();
}
break;
@@ -633,7 +587,8 @@ public class FishingManager extends SkillManager {
// 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);
applyXpGain(ExperienceConfig.getInstance().getFishingShakeXP(), XPGainReason.PVE,
XPGainSource.SELF);
}
}
@@ -691,11 +646,6 @@ public class FishingManager extends SkillManager {
treasureDrop.setDurability((short) (Misc.getRandom().nextInt(maxDurability)));
}
//TODO: Add option to randomize the amount rewarded
/*if (treasureDrop.getAmount() > 1) {
treasureDrop.setAmount(Misc.getRandom().nextInt(treasureDrop.getAmount()) + 1);
}*/
treasure.setDrop(treasureDrop);
return treasure;

View File

@@ -2,7 +2,10 @@ 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.TICK_CONVERSION_FACTOR;
import static com.gmail.nossr50.util.Misc.getBlockCenter;
import static com.gmail.nossr50.util.Permissions.isSubSkillEnabled;
import static com.gmail.nossr50.util.skills.RankUtils.hasUnlockedSubskill;
import static com.gmail.nossr50.util.text.ConfigStringUtils.getMaterialConfigString;
import static java.util.Objects.requireNonNull;
@@ -29,7 +32,6 @@ 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.ProbabilityUtil;
@@ -61,17 +63,23 @@ import org.jetbrains.annotations.NotNull;
public class HerbalismManager extends SkillManager {
private final static HashMap<String, Integer> plantBreakLimits;
private static final String CACTUS_STR = "cactus";
private static final String CACTUS_ID = "cactus";
private static final String CACTUS_FLOWER_STR = "cactus_flower";
private static final String BAMBOO_ID = "bamboo";
private static final String SUGAR_CANE_ID = "sugar_cane";
private static final String KELP_ID = "kelp";
private static final String KELP_PLANT_ID = "kelp_plant";
private static final String CHORUS_PLANT_ID = "chorus_plant";
private static final String SWEET_BERRY_BUSH_ID = "sweet_berry_bush";
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);
plantBreakLimits.put(CACTUS_ID, 3);
plantBreakLimits.put(BAMBOO_ID, 20);
plantBreakLimits.put(SUGAR_CANE_ID, 3);
plantBreakLimits.put(KELP_ID, 26);
plantBreakLimits.put(KELP_PLANT_ID, 26);
plantBreakLimits.put(CHORUS_PLANT_ID, 22);
}
public HerbalismManager(McMMOPlayer mmoPlayer) {
@@ -79,7 +87,7 @@ public class HerbalismManager extends SkillManager {
}
public boolean canGreenThumbBlock(BlockState blockState) {
if (!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.HERBALISM_GREEN_THUMB)) {
if (!hasUnlockedSubskill(getPlayer(), SubSkillType.HERBALISM_GREEN_THUMB)) {
return false;
}
@@ -97,7 +105,7 @@ public class HerbalismManager extends SkillManager {
return false;
}
if (!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.HERBALISM_SHROOM_THUMB)) {
if (!hasUnlockedSubskill(getPlayer(), SubSkillType.HERBALISM_SHROOM_THUMB)) {
return false;
}
@@ -109,12 +117,12 @@ public class HerbalismManager extends SkillManager {
|| itemType == Material.RED_MUSHROOM)
&& inventory.contains(Material.BROWN_MUSHROOM, 1)
&& inventory.contains(Material.RED_MUSHROOM, 1)
&& Permissions.isSubSkillEnabled(player, SubSkillType.HERBALISM_SHROOM_THUMB);
&& isSubSkillEnabled(player, SubSkillType.HERBALISM_SHROOM_THUMB);
}
public void processBerryBushHarvesting(@NotNull BlockState blockState) {
/* Check if the player is harvesting a berry bush */
if (blockState.getType().toString().equalsIgnoreCase("sweet_berry_bush")) {
if (blockState.getType().toString().equalsIgnoreCase(SWEET_BERRY_BUSH_ID)) {
if (mmoPlayer.isDebugMode()) {
mmoPlayer.getPlayer().sendMessage("Processing sweet berry bush rewards");
}
@@ -166,7 +174,7 @@ public class HerbalismManager extends SkillManager {
public void run() {
BlockState blockState = block.getState();
if (blockState.getType().toString().equalsIgnoreCase("sweet_berry_bush")) {
if (blockState.getType().toString().equalsIgnoreCase(SWEET_BERRY_BUSH_ID)) {
if (blockState.getBlockData() instanceof Ageable ageable) {
if (ageable.getAge() <= 1) {
@@ -179,16 +187,16 @@ public class HerbalismManager extends SkillManager {
public boolean canUseHylianLuck() {
if (!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.HERBALISM_HYLIAN_LUCK)) {
if (!hasUnlockedSubskill(getPlayer(), SubSkillType.HERBALISM_HYLIAN_LUCK)) {
return false;
}
return Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.HERBALISM_HYLIAN_LUCK);
return isSubSkillEnabled(getPlayer(), SubSkillType.HERBALISM_HYLIAN_LUCK);
}
public boolean canActivateAbility() {
return mmoPlayer.getToolPreparationMode(ToolType.HOE) && Permissions.greenTerra(
getPlayer());
return mmoPlayer.getToolPreparationMode(ToolType.HOE)
&& Permissions.greenTerra(getPlayer());
}
public boolean isGreenTerraActive() {
@@ -378,8 +386,8 @@ public class HerbalismManager extends SkillManager {
public void checkDoubleDropsOnBrokenPlants(Player player, Collection<Block> brokenPlants) {
//Only proceed if skill unlocked and permission enabled
if (!RankUtils.hasUnlockedSubskill(player, SubSkillType.HERBALISM_DOUBLE_DROPS)
|| !Permissions.isSubSkillEnabled(player, SubSkillType.HERBALISM_DOUBLE_DROPS)) {
if (!hasUnlockedSubskill(player, SubSkillType.HERBALISM_DOUBLE_DROPS)
|| !isSubSkillEnabled(player, SubSkillType.HERBALISM_DOUBLE_DROPS)) {
return;
}
@@ -469,7 +477,7 @@ public class HerbalismManager extends SkillManager {
/*
* Unnatural Blocks
*/
//If its a Crop we need to reward XP when its fully grown
//If it's a Crop we need to reward XP when its fully grown
if (isAgeableAndFullyMature(plantData) && !isBizarreAgeable(plantData)) {
xpToReward += ExperienceConfig.getInstance()
.getXp(PrimarySkillType.HERBALISM, brokenBlockNewState.getType());
@@ -527,6 +535,10 @@ public class HerbalismManager extends SkillManager {
}
public boolean isAgeableMature(Ageable ageable) {
// Sweet berry bush is harvestable at age 2 and 3 (max is 3)
if (ageable.getMaterial() == Material.SWEET_BERRY_BUSH) {
return ageable.getAge() >= 2;
}
return ageable.getAge() == ageable.getMaximumAge()
&& ageable.getAge() != 0;
}
@@ -659,7 +671,7 @@ public class HerbalismManager extends SkillManager {
}
private boolean isCactus(Material material) {
return material.getKey().getKey().equalsIgnoreCase(CACTUS_STR)
return material.getKey().getKey().equalsIgnoreCase(CACTUS_ID)
|| material.getKey().getKey().equalsIgnoreCase(CACTUS_FLOWER_STR);
}
@@ -798,7 +810,6 @@ public class HerbalismManager extends SkillManager {
playerInventory.removeItem(new ItemStack(Material.BROWN_MUSHROOM));
playerInventory.removeItem(new ItemStack(Material.RED_MUSHROOM));
getPlayer().updateInventory();
if (!ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.HERBALISM_SHROOM_THUMB, mmoPlayer)) {
NotificationManager.sendPlayerInformation(getPlayer(),
@@ -822,7 +833,7 @@ public class HerbalismManager extends SkillManager {
mcMMO.p.getFoliaLib().getScheduler()
.runAtLocationLater(blockBreakEvent.getBlock().getLocation(),
new DelayedCropReplant(blockBreakEvent, cropState, desiredCropAge,
isImmature), 2 * Misc.TICK_CONVERSION_FACTOR);
isImmature), TICK_CONVERSION_FACTOR);
blockBreakEvent.getBlock().setMetadata(MetadataConstants.METADATA_KEY_REPLANT,
new RecentlyReplantedCropMeta(mcMMO.p, true));
}
@@ -861,6 +872,7 @@ public class HerbalismManager extends SkillManager {
case "beetroots" -> replantMaterial = Material.matchMaterial("BEETROOT_SEEDS");
case "cocoa" -> replantMaterial = Material.matchMaterial("COCOA_BEANS");
case "torchflower" -> replantMaterial = Material.matchMaterial("TORCHFLOWER_SEEDS");
case "sweet_berry_bush" -> replantMaterial = Material.matchMaterial("SWEET_BERRIES");
default -> {
return false;
}
@@ -914,9 +926,7 @@ public class HerbalismManager extends SkillManager {
//Immature plants will start over at 0
if (!isAgeableMature(ageable)) {
// blockBreakEvent.setCancelled(true);
startReplantTask(0, blockBreakEvent, blockState, true);
// blockState.setType(Material.AIR);
blockBreakEvent.setDropItems(false);
return true;
}
@@ -951,6 +961,17 @@ public class HerbalismManager extends SkillManager {
}
break;
case "sweet_berry_bush":
// Sweet berry bush has ages 0-3, where 2+ has berries
// Cap at age 1 to prevent instant re-harvest exploit with enough herbalism levels
if (greenTerra || greenThumbStage >= 2) {
finalAge = 1;
} else {
finalAge = 0;
}
break;
default:
return false;
}

View File

@@ -10,7 +10,8 @@ import org.bukkit.entity.TNTPrimed;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
public class BlastMining {
public final static int MAXIMUM_REMOTE_DETONATION_DISTANCE = 100;
public static final int MAXIMUM_REMOTE_DETONATION_DISTANCE = 100;
private static final double BLAST_MINING_PVP_DAMAGE_CAP = 24D;
public static double getBlastRadiusModifier(int rank) {
return mcMMO.p.getAdvancedConfig().getBlastRadiusModifier(rank);
@@ -41,17 +42,22 @@ public class BlastMining {
}
public static boolean processBlastMiningExplosion(EntityDamageByEntityEvent event,
TNTPrimed tnt, Player defender) {
if (!tnt.hasMetadata(MetadataConstants.METADATA_KEY_TRACKED_TNT)
TNTPrimed tntAttacker, Player defender) {
if (!tntAttacker.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());
tntAttacker.getMetadata(MetadataConstants.METADATA_KEY_TRACKED_TNT).get(0).asString());
if (!(player != null && player.equals(defender))) {
double cappedDamage = Math.min(event.getDamage(), BLAST_MINING_PVP_DAMAGE_CAP);
event.setDamage(Math.max(cappedDamage, 0D));
if (event.getFinalDamage() <= 0) {
event.setCancelled(true);
}
return false;
}
@@ -67,7 +73,7 @@ public class BlastMining {
event.setDamage(miningManager.processDemolitionsExpertise(event.getDamage()));
if (event.getFinalDamage() == 0) {
if (event.getFinalDamage() <= 0) {
event.setCancelled(true);
return false;
}

View File

@@ -121,7 +121,7 @@ public class MiningManager extends SkillManager {
Player player = getPlayer();
applyXpGain(ExperienceConfig.getInstance().getXp(PrimarySkillType.MINING, block),
XPGainReason.PVE);
XPGainReason.PVE, XPGainSource.SELF);
if (!Permissions.isSubSkillEnabled(player, SubSkillType.MINING_DOUBLE_DROPS)) {
return;

View File

@@ -2,6 +2,7 @@ package com.gmail.nossr50.skills.repair;
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;
@@ -212,7 +213,7 @@ public class RepairManager extends SkillManager {
* repairable.getXpMultiplier())
* ExperienceConfig.getInstance().getRepairXPBase()
* ExperienceConfig.getInstance().getRepairXP(repairable.getRepairMaterialType())),
XPGainReason.PVE);
XPGainReason.PVE, XPGainSource.SELF);
// BWONG BWONG BWONG
if (mcMMO.p.getGeneralConfig().getRepairAnvilUseSoundsEnabled()) {

View File

@@ -0,0 +1,121 @@
package com.gmail.nossr50.skills.spears;
import static com.gmail.nossr50.util.random.ProbabilityUtil.isStaticSkillRNGSuccessful;
import static com.gmail.nossr50.util.skills.RankUtils.getRank;
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 java.util.Locale;
import org.bukkit.NamespacedKey;
import org.bukkit.Registry;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class SpearsManager extends SkillManager {
private static @Nullable PotionEffectType swiftnessEffectType;
public SpearsManager(McMMOPlayer mmoPlayer) {
super(mmoPlayer, PrimarySkillType.SPEARS);
}
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;
}
/**
* Process Momentum activation.
*/
public void potentiallyApplyMomentum() {
// Lazy initialized to avoid some backwards compatibility issues
if (swiftnessEffectType == null) {
if (mockSpigotMatch("speed") == null) {
mcMMO.p.getLogger().severe("Unable to find the Speed PotionEffectType, " +
"mcMMO will not function properly.");
throw new IllegalStateException("Unable to find the Speed PotionEffectType!");
} else {
swiftnessEffectType = mockSpigotMatch("speed");
}
}
if (!canMomentumBeApplied()) {
return;
}
int momentumRank = getRank(getPlayer(), SubSkillType.SPEARS_MOMENTUM);
// Chance to activate on hit is influence by the CD
double momentumOdds = (mcMMO.p.getAdvancedConfig().getMomentumChanceToApplyOnHit(momentumRank)
* Math.min(mmoPlayer.getAttackStrength(), 1.0D));
if (isStaticSkillRNGSuccessful(PrimarySkillType.SPEARS, mmoPlayer, momentumOdds)) {
if (mmoPlayer.useChatNotifications()) {
NotificationManager.sendPlayerInformation(mmoPlayer.getPlayer(),
NotificationType.SUBSKILL_MESSAGE, "Spears.SubSkill.Momentum.Activated");
}
// Momentum is success, Momentum the target
getPlayer().addPotionEffect(swiftnessEffectType.createEffect(
getMomentumTickDuration(momentumRank),
getMomentumStrength()));
// TODO: Consider adding an effect here
// ParticleEffectUtils.playMomentumEffect(target);
}
}
public static int getMomentumTickDuration(int momentumRank) {
return 20 * (momentumRank * 2);
}
public static int getMomentumStrength() {
return 2;
}
private boolean canMomentumBeApplied() {
// TODO: Potentially it should overwrite the effect if we are providing a stronger one
if (swiftnessEffectType == null) {
return false;
}
final PotionEffect currentlyAppliedPotion = getPlayer()
.getPotionEffect(swiftnessEffectType);
if (currentlyAppliedPotion != null) {
if (isCurrentPotionEffectStronger(currentlyAppliedPotion)) {
return false;
}
}
if (!Permissions.canUseSubSkill(mmoPlayer.getPlayer(), SubSkillType.SPEARS_MOMENTUM)) {
return false;
}
return true;
}
private boolean isCurrentPotionEffectStronger(@NotNull PotionEffect potionEffect) {
if (potionEffect.getAmplifier() > getMomentumStrength()) {
return true;
}
if (potionEffect.getDuration() > getMomentumTickDuration(getRank(getPlayer(),
SubSkillType.SPEARS_MOMENTUM))) {
return true;
}
return false;
}
public double getSpearMasteryBonusDamage() {
return mcMMO.p.getAdvancedConfig().getSpearMasteryRankDamageMultiplier()
* getRank(getPlayer(), SubSkillType.SPEARS_SPEAR_MASTERY);
}
}

View File

@@ -304,7 +304,7 @@ public class TamingManager extends SkillManager {
Player owner = getPlayer();
wolf.teleport(owner);
mcMMO.p.getFoliaLib().getScheduler().teleportAsync(wolf, owner.getLocation());
NotificationManager.sendPlayerInformation(owner, NotificationType.SUBSKILL_MESSAGE,
"Taming.Listener.Wolf");
}
@@ -425,7 +425,6 @@ public class TamingManager extends SkillManager {
int itemAmountAfterPayingCost =
itemInMainHand.getAmount() - tamingSummon.getItemAmountRequired();
itemInMainHand.setAmount(itemAmountAfterPayingCost);
player.updateInventory();
}
} else {

View File

@@ -1,78 +0,0 @@
package com.gmail.nossr50.skills.unarmed;
import com.gmail.nossr50.mcMMO;
import com.gmail.nossr50.util.sounds.SoundManager;
import com.gmail.nossr50.util.sounds.SoundType;
import org.bukkit.entity.Player;
import org.bukkit.event.entity.EntityPickupItemEvent;
import org.bukkit.inventory.ItemStack;
public class Unarmed {
public static boolean blockCrackerSmoothBrick = mcMMO.p.getGeneralConfig()
.getUnarmedBlockCrackerSmoothbrickToCracked();
public static double berserkDamageModifier = 1.5;
public static void handleItemPickup(Player player, EntityPickupItemEvent event) {
ItemStack[] storageContents = player.getInventory().getStorageContents();
ItemStack itemDrop = event.getItem().getItemStack();
int heldItemSlotID = player.getInventory().getHeldItemSlot();
int amount = itemDrop.getAmount();
boolean grabbedItem = false;
for (int i = 0; i <= storageContents.length - 1; i++) {
if (amount <= 0) {
break;
}
if (i == heldItemSlotID) {
continue;
}
//EMPTY SLOT!
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()) {
//If we can fit this whole itemstack into this item
if (amount + storageContents[i].getAmount()
<= storageContents[i].getMaxStackSize()) {
ItemStack modifiedAmount = storageContents[i];
modifiedAmount.setAmount(amount + storageContents[i].getAmount());
player.getInventory().setItem(i, modifiedAmount);
grabbedItem = true;
amount = 0;
} else {
//Add what we can from this stack
ItemStack modifiedAmount = storageContents[i];
int amountThatCanFit =
storageContents[i].getMaxStackSize() - storageContents[i].getAmount();
modifiedAmount.setAmount(amountThatCanFit);
player.getInventory().setItem(i, modifiedAmount);
//Remove the amount we've added
grabbedItem = true;
amount -= amountThatCanFit;
}
}
}
if (amount <= 0) {
event.getItem().remove(); //Cleanup Item
} else {
event.getItem().getItemStack().setAmount(amount);
}
event.setCancelled(true);
if (grabbedItem) {
SoundManager.sendSound(player, player.getLocation(), SoundType.POP);
player.updateInventory();
}
}
}

View File

@@ -21,7 +21,7 @@ import com.gmail.nossr50.util.player.UserManager;
import com.gmail.nossr50.util.random.ProbabilityUtil;
import com.gmail.nossr50.util.skills.RankUtils;
import org.bukkit.Material;
import org.bukkit.block.BlockState;
import org.bukkit.block.Block;
import org.bukkit.entity.Item;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
@@ -29,6 +29,7 @@ import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
public class UnarmedManager extends SkillManager {
public static final double BERSERK_DMG_MODIFIER = 1.5;
public UnarmedManager(McMMOPlayer mmoPlayer) {
super(mmoPlayer, PrimarySkillType.UNARMED);
@@ -79,28 +80,33 @@ public class UnarmedManager extends SkillManager {
return Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.UNARMED_BLOCK_CRACKER);
}
public void blockCrackerCheck(@NotNull BlockState blockState) {
public void blockCrackerCheck(@NotNull Block block) {
if (!mcMMO.p.getGeneralConfig().isBlockCrackerAllowed()) {
return;
}
if (!ProbabilityUtil.isNonRNGSkillActivationSuccessful(SubSkillType.UNARMED_BLOCK_CRACKER,
mmoPlayer)) {
return;
}
switch (blockState.getType()) {
switch (block.getType()) {
case STONE_BRICKS:
if (!Unarmed.blockCrackerSmoothBrick) {
return;
}
blockState.getBlock().setType(Material.CRACKED_STONE_BRICKS);
blockState.update(true);
block.setType(Material.CRACKED_STONE_BRICKS);
return;
case INFESTED_STONE_BRICKS:
if (!Unarmed.blockCrackerSmoothBrick) {
return;
}
blockState.getBlock().setType(Material.INFESTED_CRACKED_STONE_BRICKS);
blockState.update(true);
block.setType(Material.INFESTED_CRACKED_STONE_BRICKS);
return;
case DEEPSLATE_BRICKS:
block.setType(Material.CRACKED_DEEPSLATE_BRICKS);
return;
case DEEPSLATE_TILES:
block.setType(Material.CRACKED_DEEPSLATE_TILES);
return;
case POLISHED_BLACKSTONE_BRICKS:
block.setType(Material.CRACKED_POLISHED_BLACKSTONE_BRICKS);
return;
case NETHER_BRICKS:
block.setType(Material.CRACKED_NETHER_BRICKS);
return;
default:
}
@@ -158,7 +164,7 @@ public class UnarmedManager extends SkillManager {
*/
public double berserkDamage(double damage) {
damage =
((damage * Unarmed.berserkDamageModifier) * mmoPlayer.getAttackStrength()) - damage;
((damage * BERSERK_DMG_MODIFIER) * mmoPlayer.getAttackStrength()) - damage;
return damage;
}

View File

@@ -18,6 +18,7 @@ import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.function.Predicate;
import net.kyori.adventure.text.Component;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.Material;
@@ -35,20 +36,20 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public final class ItemUtils {
// Reflection for setItemName only available in newer APIs
private static final Method setItemName;
// Use custom name if available
private static final Method customName;
static {
setItemName = getSetItemName();
customName = getCustomNameMethod();
}
private ItemUtils() {
// private constructor
}
private static Method getSetItemName() {
private static Method getCustomNameMethod() {
try {
return ItemMeta.class.getMethod("setItemName", String.class);
return ItemMeta.class.getMethod("customName", Component.class);
} catch (NoSuchMethodException e) {
return null;
}
@@ -60,17 +61,17 @@ public final class ItemUtils {
* @param itemMeta The item meta to set the name on
* @param name The name to set
*/
public static void setItemName(ItemMeta itemMeta, String name) {
if (setItemName != null) {
public static void customName(ItemMeta itemMeta, Component name, String fallbackName) {
if (customName != null) {
setItemNameModern(itemMeta, name);
} else {
itemMeta.setDisplayName(ChatColor.RESET + name);
itemMeta.setDisplayName(ChatColor.RESET + fallbackName);
}
}
private static void setItemNameModern(ItemMeta itemMeta, String name) {
private static void setItemNameModern(ItemMeta itemMeta, Component name) {
try {
setItemName.invoke(itemMeta, name);
customName.invoke(itemMeta, name);
} catch (IllegalAccessException | InvocationTargetException e) {
mcMMO.p.getLogger().severe("Failed to set item name: " + e.getMessage());
throw new RuntimeException(e);
@@ -165,20 +166,6 @@ public final class ItemUtils {
}
}
// TODO: Unit tests
public static boolean isCrossbow(@NotNull ItemStack item) {
return mcMMO.getMaterialMapStore().isCrossbow(item.getType().getKey().getKey());
}
// TODO: Unit tests
public static boolean isTrident(@NotNull ItemStack item) {
return mcMMO.getMaterialMapStore().isTrident(item.getType().getKey().getKey());
}
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;
@@ -275,6 +262,46 @@ public final class ItemUtils {
return null;
}
/**
* Checks if the item is a crossbow.
*
* @param item Item to check
* @return true if the item is a crossbow, false otherwise
*/
public static boolean isCrossbow(@NotNull ItemStack item) {
return mcMMO.getMaterialMapStore().isCrossbow(item.getType().getKey().getKey());
}
/**
* Checks if the item is a trident.
*
* @param item Item to check
* @return true if the item is a trident, false otherwise
*/
public static boolean isTrident(@NotNull ItemStack item) {
return mcMMO.getMaterialMapStore().isTrident(item.getType().getKey().getKey());
}
/**
* Checks if the item is a mace.
*
* @param item Item to check
* @return true if the item is a mace, false otherwise
*/
public static boolean isMace(@NotNull ItemStack item) {
return mcMMO.getMaterialMapStore().isMace(item.getType().getKey().getKey());
}
/**
* Checks if the item is a spear.
* @param item Item to check
*
* @return true if the item is a spear, false otherwise
*/
public static boolean isSpear(@NotNull ItemStack item) {
return mcMMO.getMaterialMapStore().isSpear(item.getType().getKey().getKey());
}
/**
* Checks if the item is a sword.
*
@@ -379,6 +406,10 @@ public final class ItemUtils {
return mcMMO.getMaterialMapStore().isIronArmor(item.getType().getKey().getKey());
}
public static boolean isCopperArmor(ItemStack item) {
return mcMMO.getMaterialMapStore().isCopperArmor(item.getType().getKey().getKey());
}
/**
* Checks to see if an item is a diamond armor piece.
*
@@ -451,6 +482,10 @@ public final class ItemUtils {
return mcMMO.getMaterialMapStore().isPrismarineTool(item.getType().getKey().getKey());
}
public static boolean isCopperTool(ItemStack item) {
return mcMMO.getMaterialMapStore().isCopperTool(item.getType().getKey().getKey());
}
/**
* Checks to see if an item is a gold tool.
*

View File

@@ -8,6 +8,7 @@ public class LogUtils {
public static final String DEBUG_STR = "[D] ";
public static void debug(@NotNull Logger logger, @NotNull String message) {
// Messages here will get filtered based on config settings via LogFilter
logger.info(DEBUG_STR + message);
}
}

View File

@@ -3,6 +3,7 @@ package com.gmail.nossr50.util;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Locale;
import java.util.Set;
import org.bukkit.Material;
import org.jetbrains.annotations.NotNull;
@@ -29,6 +30,8 @@ public class MaterialMapStore {
private final @NotNull HashSet<String> woodTools;
private final @NotNull HashSet<String> stoneTools;
private final @NotNull HashSet<String> leatherArmor;
private final @NotNull HashSet<String> copperTools;
private final @NotNull HashSet<String> copperArmor;
private final @NotNull HashSet<String> ironArmor;
private final @NotNull HashSet<String> ironTools;
private final @NotNull HashSet<String> stringTools;
@@ -48,9 +51,10 @@ public class MaterialMapStore {
private final @NotNull HashSet<String> tridents;
private final @NotNull HashSet<String> bows;
private final @NotNull HashSet<String> crossbows;
private final @NotNull HashSet<String> tools;
private final @NotNull HashSet<String> enchantables;
private final @NotNull HashSet<String> maces;
private final @NotNull HashSet<String> spears;
private final @NotNull HashSet<String> enchantables;
private final @NotNull HashSet<String> tools;
private final @NotNull HashSet<String> ores;
private final @NotNull HashSet<String> intendedToolPickAxe;
@@ -74,6 +78,7 @@ public class MaterialMapStore {
leatherArmor = new HashSet<>();
ironArmor = new HashSet<>();
copperArmor = new HashSet<>();
chainmailArmor = new HashSet<>();
goldArmor = new HashSet<>();
diamondArmor = new HashSet<>();
@@ -82,6 +87,7 @@ public class MaterialMapStore {
woodTools = new HashSet<>();
stoneTools = new HashSet<>();
copperTools = new HashSet<>();
ironTools = new HashSet<>();
goldTools = new HashSet<>();
diamondTools = new HashSet<>();
@@ -90,15 +96,15 @@ public class MaterialMapStore {
crossbows = new HashSet<>();
stringTools = new HashSet<>();
prismarineTools = new HashSet<>();
tools = new HashSet<>();
swords = new HashSet<>();
axes = new HashSet<>();
pickAxes = new HashSet<>();
shovels = new HashSet<>();
hoes = new HashSet<>();
tridents = new HashSet<>();
spears = new HashSet<>();
maces = new HashSet<>();
tools = new HashSet<>();
enchantables = new HashSet<>();
@@ -174,6 +180,10 @@ public class MaterialMapStore {
tierValue.put(id, 1);
}
for (String id : copperArmor) {
tierValue.put(id, 1);
}
for (String id : ironArmor) {
tierValue.put(id, 2);
}
@@ -421,6 +431,7 @@ public class MaterialMapStore {
private void fillArmors() {
fillLeatherArmorWhiteList();
fillCopperArmorWhiteList();
fillIronArmorWhiteList();
fillChainmailWhiteList();
fillGoldArmorWhiteList();
@@ -429,6 +440,7 @@ public class MaterialMapStore {
//Add all armors to armors hashset
armors.addAll(leatherArmor);
armors.addAll(copperArmor);
armors.addAll(ironArmor);
armors.addAll(chainmailArmor);
armors.addAll(goldArmor);
@@ -448,6 +460,7 @@ public class MaterialMapStore {
enchantables.addAll(bows);
enchantables.addAll(crossbows);
enchantables.addAll(maces);
enchantables.addAll(spears);
enchantables.add("shears");
enchantables.add("fishing_rod");
@@ -460,6 +473,7 @@ public class MaterialMapStore {
private void fillTools() {
fillWoodToolsWhiteList();
fillStoneToolsWhiteList();
fillCopperToolsWhiteList();
fillIronToolsWhiteList();
fillGoldToolsWhiteList();
fillDiamondToolsWhiteList();
@@ -472,6 +486,7 @@ public class MaterialMapStore {
fillShovels();
fillTridents();
fillMaces();
fillSpears();
fillStringTools();
fillPrismarineTools();
fillBows();
@@ -480,6 +495,7 @@ public class MaterialMapStore {
//Tools collection
tools.addAll(woodTools);
tools.addAll(stoneTools);
tools.addAll(copperTools);
tools.addAll(ironTools);
tools.addAll(goldTools);
tools.addAll(diamondTools);
@@ -489,6 +505,7 @@ public class MaterialMapStore {
tools.addAll(bows);
tools.addAll(crossbows);
tools.addAll(maces);
tools.addAll(spears);
}
private void fillBows() {
@@ -514,6 +531,16 @@ public class MaterialMapStore {
maces.add("mace");
}
private void fillSpears() {
spears.add("wooden_spear");
spears.add("stone_spear");
spears.add("copper_spear");
spears.add("iron_spear");
spears.add("golden_spear");
spears.add("diamond_spear");
spears.add("netherite_spear");
}
private void fillTridents() {
tridents.add("trident");
}
@@ -522,6 +549,7 @@ public class MaterialMapStore {
swords.add("wood_sword");
swords.add("wooden_sword");
swords.add("stone_sword");
swords.add("copper_sword");
swords.add("iron_sword");
swords.add("gold_sword");
swords.add("golden_sword");
@@ -533,6 +561,7 @@ public class MaterialMapStore {
axes.add("wood_axe");
axes.add("wooden_axe");
axes.add("stone_axe");
axes.add("copper_axe");
axes.add("iron_axe");
axes.add("gold_axe");
axes.add("golden_axe");
@@ -544,6 +573,7 @@ public class MaterialMapStore {
pickAxes.add("wood_pickaxe");
pickAxes.add("wooden_pickaxe");
pickAxes.add("stone_pickaxe");
pickAxes.add("copper_pickaxe");
pickAxes.add("iron_pickaxe");
pickAxes.add("gold_pickaxe");
pickAxes.add("golden_pickaxe");
@@ -555,6 +585,7 @@ public class MaterialMapStore {
hoes.add("wood_hoe");
hoes.add("wooden_hoe");
hoes.add("stone_hoe");
hoes.add("copper_hoe");
hoes.add("iron_hoe");
hoes.add("gold_hoe");
hoes.add("golden_hoe");
@@ -566,6 +597,7 @@ public class MaterialMapStore {
shovels.add("wood_shovel");
shovels.add("wooden_shovel");
shovels.add("stone_shovel");
shovels.add("copper_shovel");
shovels.add("iron_shovel");
shovels.add("gold_shovel");
shovels.add("golden_shovel");
@@ -580,6 +612,13 @@ public class MaterialMapStore {
leatherArmor.add("leather_boots");
}
private void fillCopperArmorWhiteList() {
copperArmor.add("copper_helmet");
copperArmor.add("copper_chestplate");
copperArmor.add("copper_leggings");
copperArmor.add("copper_boots");
}
private void fillIronArmorWhiteList() {
ironArmor.add("iron_helmet");
ironArmor.add("iron_chestplate");
@@ -634,6 +673,7 @@ public class MaterialMapStore {
woodTools.add("wooden_hoe");
woodTools.add("wooden_pickaxe");
woodTools.add("wooden_shovel");
woodTools.add("wooden_spear");
}
private void fillStoneToolsWhiteList() {
@@ -642,6 +682,16 @@ public class MaterialMapStore {
stoneTools.add("stone_hoe");
stoneTools.add("stone_pickaxe");
stoneTools.add("stone_shovel");
stoneTools.add("stone_spear");
}
private void fillCopperToolsWhiteList() {
copperTools.add("copper_sword");
copperTools.add("copper_axe");
copperTools.add("copper_hoe");
copperTools.add("copper_pickaxe");
copperTools.add("copper_shovel");
copperTools.add("copper_spear");
}
private void fillIronToolsWhiteList() {
@@ -650,6 +700,7 @@ public class MaterialMapStore {
ironTools.add("iron_hoe");
ironTools.add("iron_pickaxe");
ironTools.add("iron_shovel");
ironTools.add("iron_spear");
//Used for repair, remove in 2.2
//TODO: Remove in config update
@@ -671,6 +722,7 @@ public class MaterialMapStore {
goldTools.add("golden_hoe");
goldTools.add("golden_pickaxe");
goldTools.add("golden_shovel");
goldTools.add("golden_spear");
}
private void fillDiamondToolsWhiteList() {
@@ -679,6 +731,7 @@ public class MaterialMapStore {
diamondTools.add("diamond_hoe");
diamondTools.add("diamond_pickaxe");
diamondTools.add("diamond_shovel");
diamondTools.add("diamond_spear");
}
private void fillNetheriteToolsWhiteList() {
@@ -687,6 +740,7 @@ public class MaterialMapStore {
netheriteTools.add("netherite_hoe");
netheriteTools.add("netherite_pickaxe");
netheriteTools.add("netherite_shovel");
netheriteTools.add("netherite_spear");
}
private void fillGlassBlockWhiteList() {
@@ -841,6 +895,14 @@ public class MaterialMapStore {
return maces.contains(id);
}
public boolean isSpear(@NotNull Material material) {
return isSpear(material.getKey().getKey());
}
public boolean isSpear(@NotNull String id) {
return spears.contains(id);
}
public boolean isLeatherArmor(@NotNull Material material) {
return isLeatherArmor(material.getKey().getKey());
}
@@ -849,6 +911,14 @@ public class MaterialMapStore {
return leatherArmor.contains(id);
}
public boolean isCopperArmor(@NotNull Material material) {
return isCopperArmor(material.getKey().getKey());
}
public boolean isCopperArmor(@NotNull String id) {
return copperArmor.contains(id);
}
public boolean isIronArmor(@NotNull Material material) {
return isIronArmor(material.getKey().getKey());
}
@@ -905,6 +975,14 @@ public class MaterialMapStore {
return stoneTools.contains(id);
}
public boolean isCopperTool(@NotNull Material material) {
return isCopperTool(material.getKey().getKey());
}
public boolean isCopperTool(@NotNull String id) {
return copperTools.contains(id);
}
public boolean isIronTool(@NotNull Material material) {
return isIronTool(material.getKey().getKey());
}
@@ -1070,255 +1148,305 @@ public class MaterialMapStore {
mossyWhiteList.add("cobblestone_wall");
}
private void addCommonToBlackList(Set<String> blackList) {
// All things that should be on both the tools and ability blacklist get added here
addButtonsToBlackList(blackList);
addTrapdoorsToBlackList(blackList);
addFenceGatesToBlackList(blackList);
addBedsToBlacklist(blackList);
addPressurePlatesToBlackList(blackList);
addChestsToBlackList(blackList);
addGolemStatuesToBlackList(blackList);
addShelvesToBlackList(blackList);
addDoorsToBlackList(blackList);
addFencesToBlackList(blackList);
addSignsToBlackList(blackList);
addHangingSignsToBlackList(blackList);
addShulkerBoxesToBlackList(blackList);
addMiscInteractableToBlackList(blackList);
}
private void addButtonsToBlackList(Set<String> blackList) {
blackList.add("oak_button");
blackList.add("spruce_button");
blackList.add("birch_button");
blackList.add("jungle_button");
blackList.add("acacia_button");
blackList.add("dark_oak_button");
blackList.add("mangrove_button");
blackList.add("cherry_button");
blackList.add("pale_oak_button");
blackList.add("bamboo_button");
blackList.add("crimson_button");
blackList.add("warped_button");
// Non-wood buttons
blackList.add("stone_button");
blackList.add("polished_blackstone_button");
}
private void addTrapdoorsToBlackList(Set<String> blackList) {
// Wood Trapdoors
blackList.add("oak_trapdoor");
blackList.add("spruce_trapdoor");
blackList.add("birch_trapdoor");
blackList.add("jungle_trapdoor");
blackList.add("acacia_trapdoor");
blackList.add("dark_oak_trapdoor");
blackList.add("mangrove_trapdoor");
blackList.add("cherry_trapdoor");
blackList.add("pale_oak_trapdoor");
blackList.add("bamboo_trapdoor");
blackList.add("crimson_trapdoor");
blackList.add("warped_trapdoor");
// Copper Trapdoors
blackList.add("waxed_copper_trapdoor");
blackList.add("waxed_exposed_copper_trapdoor");
blackList.add("waxed_weathered_copper_trapdoor");
blackList.add("waxed_oxidized_copper_trapdoor");
blackList.add("copper_trapdoor");
blackList.add("exposed_copper_trapdoor");
blackList.add("weathered_copper_trapdoor");
blackList.add("oxidized_copper_trapdoor");
// Other Trapdoors
blackList.add("iron_trapdoor");
}
private void addFenceGatesToBlackList(Set<String> blackList) {
// Fence Gates
blackList.add("oak_fence_gate");
blackList.add("spruce_fence_gate");
blackList.add("birch_fence_gate");
blackList.add("jungle_fence_gate");
blackList.add("acacia_fence_gate");
blackList.add("dark_oak_fence_gate");
blackList.add("mangrove_fence_gate");
blackList.add("cherry_fence_gate");
blackList.add("pale_oak_fence_gate");
blackList.add("bamboo_fence_gate");
blackList.add("crimson_fence_gate");
blackList.add("warped_fence_gate");
}
private void addBedsToBlacklist(Set<String> blackList) {
blackList.add("black_bed");
blackList.add("blue_bed");
blackList.add("brown_bed");
blackList.add("cyan_bed");
blackList.add("gray_bed");
blackList.add("green_bed");
blackList.add("light_blue_bed");
blackList.add("light_gray_bed");
blackList.add("lime_bed");
blackList.add("magenta_bed");
blackList.add("orange_bed");
blackList.add("pink_bed");
blackList.add("purple_bed");
blackList.add("red_bed");
blackList.add("white_bed");
blackList.add("yellow_bed");
}
private void addPressurePlatesToBlackList(Set<String> blackList) {
blackList.add("oak_pressure_plate");
blackList.add("spruce_pressure_plate");
blackList.add("birch_pressure_plate");
blackList.add("jungle_pressure_plate");
blackList.add("acacia_pressure_plate");
blackList.add("dark_oak_pressure_plate");
blackList.add("mangrove_pressure_plate");
blackList.add("cherry_pressure_plate");
blackList.add("pale_oak_pressure_plate");
blackList.add("bamboo_pressure_plate");
blackList.add("crimson_pressure_plate");
blackList.add("warped_pressure_plate");
blackList.add("stone_pressure_plate");
blackList.add("light_weighted_pressure_plate");
blackList.add("heavy_weighted_pressure_plate");
blackList.add("polished_blackstone_pressure_plate");
}
private void addChestsToBlackList(Set<String> blackList) {
blackList.add("chest");
blackList.add("copper_chest");
blackList.add("waxed_copper_chest");
blackList.add("exposed_copper_chest");
blackList.add("weathered_copper_chest");
blackList.add("oxidized_copper_chest");
blackList.add("trapped_chest");
blackList.add("ender_chest");
}
private void addShelvesToBlackList(Set<String> blackList) {
blackList.add("oak_shelf");
blackList.add("spruce_shelf");
blackList.add("birch_shelf");
blackList.add("jungle_shelf");
blackList.add("acacia_shelf");
blackList.add("dark_oak_shelf");
blackList.add("mangrove_shelf");
blackList.add("cherry_shelf");
blackList.add("pale_oak_shelf");
blackList.add("bamboo_shelf");
blackList.add("crimson_shelf");
blackList.add("warped_shelf");
}
private void addGolemStatuesToBlackList(Set<String> blackList) {
blackList.add("copper_golem_statue");
blackList.add("waxed_copper_golem_statue");
blackList.add("exposed_copper_golem_statue");
blackList.add("weathered_copper_golem_statue");
blackList.add("oxidized_copper_golem_statue");
}
private void addDoorsToBlackList(Set<String> blackList) {
// Doors
blackList.add("oak_door");
blackList.add("spruce_door");
blackList.add("birch_door");
blackList.add("jungle_door");
blackList.add("acacia_door");
blackList.add("dark_oak_door");
blackList.add("mangrove_door");
blackList.add("cherry_door");
blackList.add("pale_oak_door");
blackList.add("bamboo_door");
blackList.add("crimson_door");
blackList.add("warped_door");
// Metal
blackList.add("iron_door");
blackList.add("copper_door");
blackList.add("exposed_copper_door");
blackList.add("weathered_copper_door");
blackList.add("oxidized_copper_door");
blackList.add("waxed_copper_door");
blackList.add("waxed_exposed_copper_door");
blackList.add("waxed_weathered_copper_door");
blackList.add("waxed_oxidized_copper_door");
}
private void addFencesToBlackList(Set<String> blackList) {
// Fences
blackList.add("oak_fence");
blackList.add("spruce_fence");
blackList.add("birch_fence");
blackList.add("jungle_fence");
blackList.add("acacia_fence");
blackList.add("dark_oak_fence");
blackList.add("mangrove_fence");
blackList.add("cherry_fence");
blackList.add("pale_oak_fence");
blackList.add("bamboo_fence");
blackList.add("crimson_fence");
blackList.add("warped_fence");
blackList.add("dispenser");
blackList.add("enchanting_table");
// Metal Fences
blackList.add("nether_brick_fence");
blackList.add("iron_bars");
}
private void addSignsToBlackList(Set<String> blackList) {
// Sign
blackList.add("oak_sign");
blackList.add("spruce_sign");
blackList.add("birch_sign");
blackList.add("jungle_sign");
blackList.add("acacia_sign");
blackList.add("dark_oak_sign");
blackList.add("mangrove_sign");
blackList.add("cherry_sign");
blackList.add("pale_oak_sign");
blackList.add("bamboo_sign");
blackList.add("crimson_sign");
blackList.add("warped_sign");
}
private void addHangingSignsToBlackList(Set<String> blackList) {
// Hanging Sign
blackList.add("oak_hanging_sign");
blackList.add("spruce_hanging_sign");
blackList.add("birch_hanging_sign");
blackList.add("jungle_hanging_sign");
blackList.add("acacia_hanging_sign");
blackList.add("dark_oak_hanging_sign");
blackList.add("mangrove_hanging_sign");
blackList.add("cherry_hanging_sign");
blackList.add("pale_oak_hanging_sign");
blackList.add("bamboo_hanging_sign");
blackList.add("crimson_hanging_sign");
blackList.add("warped_hanging_sign");
}
private void addShulkerBoxesToBlackList(Set<String> blackList) {
// Shulker Boxes
blackList.add("black_shulker_box");
blackList.add("blue_shulker_box");
blackList.add("brown_shulker_box");
blackList.add("cyan_shulker_box");
blackList.add("gray_shulker_box");
blackList.add("green_shulker_box");
blackList.add("light_blue_shulker_box");
blackList.add("lime_shulker_box");
blackList.add("magenta_shulker_box");
blackList.add("orange_shulker_box");
blackList.add("pink_shulker_box");
blackList.add("purple_shulker_box");
blackList.add("red_shulker_box");
blackList.add("light_gray_shulker_box");
blackList.add("white_shulker_box");
blackList.add("yellow_shulker_box");
blackList.add("shulker_box");
}
private void addMiscInteractableToBlackList(Set<String> blackList) {
blackList.add("bell");
blackList.add("barrel");
blackList.add("blast_furnace");
blackList.add("campfire");
blackList.add("soul_campfire");
blackList.add("cartography_table");
blackList.add("composter");
blackList.add("grindstone");
blackList.add("lectern");
blackList.add("loom");
blackList.add("scaffolding");
blackList.add("smoker");
blackList.add("stonecutter");
blackList.add("sweet_berry_bush");
blackList.add("smithing_table");
blackList.add("lodestone");
blackList.add("respawn_anchor");
blackList.add("chiseled_bookshelf");
blackList.add("brewing_stand");
blackList.add("bookshelf");
blackList.add("cake");
blackList.add("dispenser");
blackList.add("enchanting_table");
blackList.add("furnace");
blackList.add("jukebox");
blackList.add("lever");
blackList.add("note_block");
blackList.add("crafting_table");
blackList.add("beacon");
blackList.add("anvil");
blackList.add("dropper");
blackList.add("hopper");
blackList.add("armor_stand");
blackList.add("mannequin");
}
private void fillAbilityBlackList() {
abilityBlackList.add("warped_fence_gate");
abilityBlackList.add("crimson_fence_gate");
abilityBlackList.add("warped_pressure_plate");
abilityBlackList.add("crimson_pressure_plate");
abilityBlackList.add("warped_button");
abilityBlackList.add("crimson_button");
abilityBlackList.add("warped_door");
abilityBlackList.add("crimson_door");
abilityBlackList.add("warped_trapdoor");
abilityBlackList.add("crimson_trapdoor");
abilityBlackList.add("black_bed");
abilityBlackList.add("blue_bed");
abilityBlackList.add("brown_bed");
abilityBlackList.add("cyan_bed");
abilityBlackList.add("gray_bed");
abilityBlackList.add("green_bed");
abilityBlackList.add("light_blue_bed");
abilityBlackList.add("light_gray_bed");
abilityBlackList.add("lime_bed");
abilityBlackList.add("magenta_bed");
abilityBlackList.add("orange_bed");
abilityBlackList.add("pink_bed");
abilityBlackList.add("purple_bed");
abilityBlackList.add("red_bed");
abilityBlackList.add("white_bed");
abilityBlackList.add("yellow_bed");
abilityBlackList.add("brewing_stand");
abilityBlackList.add("bookshelf");
abilityBlackList.add("cake");
abilityBlackList.add("chest");
abilityBlackList.add("dispenser");
abilityBlackList.add("enchanting_table");
abilityBlackList.add("ender_chest");
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");
abilityBlackList.add("furnace");
abilityBlackList.add("jukebox");
abilityBlackList.add("lever");
abilityBlackList.add("note_block");
abilityBlackList.add("stone_button");
abilityBlackList.add("oak_button");
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");
abilityBlackList.add("acacia_sign");
abilityBlackList.add("acacia_wall_sign");
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");
abilityBlackList.add("spruce_wall_sign");
abilityBlackList.add("oak_sign");
abilityBlackList.add("oak_wall_sign");
abilityBlackList.add("crafting_table");
abilityBlackList.add("beacon");
abilityBlackList.add("anvil");
abilityBlackList.add("dropper");
abilityBlackList.add("hopper");
abilityBlackList.add("trapped_chest");
abilityBlackList.add("iron_door");
abilityBlackList.add("iron_trapdoor");
abilityBlackList.add("oak_door");
abilityBlackList.add("acacia_door");
abilityBlackList.add("spruce_door");
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");
abilityBlackList.add("armor_stand");
abilityBlackList.add("black_shulker_box");
abilityBlackList.add("blue_shulker_box");
abilityBlackList.add("brown_shulker_box");
abilityBlackList.add("cyan_shulker_box");
abilityBlackList.add("gray_shulker_box");
abilityBlackList.add("green_shulker_box");
abilityBlackList.add("light_blue_shulker_box");
abilityBlackList.add("lime_shulker_box");
abilityBlackList.add("magenta_shulker_box");
abilityBlackList.add("orange_shulker_box");
abilityBlackList.add("pink_shulker_box");
abilityBlackList.add("purple_shulker_box");
abilityBlackList.add("red_shulker_box");
abilityBlackList.add("light_gray_shulker_box");
abilityBlackList.add("white_shulker_box");
abilityBlackList.add("yellow_shulker_box");
abilityBlackList.add("shulker_box");
abilityBlackList.add("wall_sign"); //1.13 and lower?
abilityBlackList.add("sign"); //1.13 and lower?
abilityBlackList.add("cartography_table");
abilityBlackList.add("grindstone");
abilityBlackList.add("lectern");
abilityBlackList.add("loom");
abilityBlackList.add("scaffolding");
abilityBlackList.add("smoker");
abilityBlackList.add("stonecutter");
abilityBlackList.add("sweet_berry_bush");
abilityBlackList.add("bell");
abilityBlackList.add("barrel");
abilityBlackList.add("blast_furnace");
abilityBlackList.add("campfire");
abilityBlackList.add("soul_campfire");
abilityBlackList.add("composter");
abilityBlackList.add("lodestone");
abilityBlackList.add("respawn_anchor");
addCommonToBlackList(abilityBlackList);
}
private void fillToolBlackList() {
toolBlackList.add("chiseled_bookshelf");
toolBlackList.add("black_bed");
toolBlackList.add("blue_bed");
toolBlackList.add("brown_bed");
toolBlackList.add("cyan_bed");
toolBlackList.add("gray_bed");
toolBlackList.add("green_bed");
toolBlackList.add("light_blue_bed");
toolBlackList.add("light_gray_bed");
toolBlackList.add("lime_bed");
toolBlackList.add("magenta_bed");
toolBlackList.add("orange_bed");
toolBlackList.add("pink_bed");
toolBlackList.add("purple_bed");
toolBlackList.add("red_bed");
toolBlackList.add("white_bed");
toolBlackList.add("yellow_bed");
toolBlackList.add("brewing_stand");
toolBlackList.add("bookshelf");
toolBlackList.add("cake");
toolBlackList.add("chest");
toolBlackList.add("dispenser");
toolBlackList.add("enchanting_table");
toolBlackList.add("ender_chest");
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");
toolBlackList.add("furnace");
toolBlackList.add("jukebox");
toolBlackList.add("lever");
toolBlackList.add("note_block");
toolBlackList.add("stone_button");
toolBlackList.add("oak_button");
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");
toolBlackList.add("crafting_table");
toolBlackList.add("beacon");
toolBlackList.add("anvil");
toolBlackList.add("dropper");
toolBlackList.add("hopper");
toolBlackList.add("trapped_chest");
toolBlackList.add("iron_door");
toolBlackList.add("iron_trapdoor");
toolBlackList.add("oak_door");
toolBlackList.add("acacia_door");
toolBlackList.add("spruce_door");
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");
toolBlackList.add("armor_stand");
toolBlackList.add("black_shulker_box");
toolBlackList.add("blue_shulker_box");
toolBlackList.add("brown_shulker_box");
toolBlackList.add("cyan_shulker_box");
toolBlackList.add("gray_shulker_box");
toolBlackList.add("green_shulker_box");
toolBlackList.add("light_blue_shulker_box");
toolBlackList.add("lime_shulker_box");
toolBlackList.add("magenta_shulker_box");
toolBlackList.add("orange_shulker_box");
toolBlackList.add("pink_shulker_box");
toolBlackList.add("purple_shulker_box");
toolBlackList.add("red_shulker_box");
toolBlackList.add("light_gray_shulker_box");
toolBlackList.add("white_shulker_box");
toolBlackList.add("yellow_shulker_box");
toolBlackList.add("shulker_box");
toolBlackList.add("acacia_sign");
toolBlackList.add("acacia_hanging_sign");
toolBlackList.add("acacia_wall_sign");
toolBlackList.add("birch_sign");
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");
toolBlackList.add("spruce_sign");
toolBlackList.add("spruce_hanging_sign");
toolBlackList.add("spruce_wall_sign");
toolBlackList.add("oak_sign");
toolBlackList.add("oak_hanging_sign");
toolBlackList.add("oak_wall_sign");
toolBlackList.add("cherry_sign");
toolBlackList.add("cherry_hanging_sign");
toolBlackList.add("cherry_wall_sign");
addCommonToBlackList(toolBlackList);
// TODO: Organize later...
toolBlackList.add("stripped_cherry_log");
toolBlackList.add("stripped_cherry_wood");
toolBlackList.add("stripped_acacia_log");
@@ -1351,22 +1479,6 @@ public class MaterialMapStore {
toolBlackList.add("oak_log");
toolBlackList.add("oak_wood");
toolBlackList.add("spruce_log");
toolBlackList.add("bell");
toolBlackList.add("barrel");
toolBlackList.add("blast_furnace");
toolBlackList.add("campfire");
toolBlackList.add("soul_campfire");
toolBlackList.add("cartography_table");
toolBlackList.add("composter");
toolBlackList.add("grindstone");
toolBlackList.add("lectern");
toolBlackList.add("loom");
toolBlackList.add("smoker");
toolBlackList.add("stonecutter");
toolBlackList.add("lodestone");
toolBlackList.add("respawn_anchor");
toolBlackList.add("sweet_berry_bush");
toolBlackList.add("smithing_table");
}
public boolean isIntendedToolPickaxe(@NotNull Material material) {

View File

@@ -0,0 +1,36 @@
package com.gmail.nossr50.util;
import com.gmail.nossr50.mcMMO;
import com.gmail.nossr50.util.platform.MinecraftGameVersion;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.jetbrains.annotations.NotNull;
public class MinecraftGameVersionFactory {
public static @NotNull MinecraftGameVersion calculateGameVersion(
@NotNull String platformVersionString) {
int major = 0, minor = 0, patch = 0;
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);
if (versionMatch.find()) {
major = Integer.parseInt(versionMatch.group(1));
minor = Integer.parseInt(versionMatch.group(2));
if (versionMatch.group(3) != null) {
patch = Integer.parseInt(versionMatch.group(3));
}
}
LogUtils.debug(mcMMO.p.getLogger(), "Minecraft version determined to be - "
+ major + "."
+ minor + "."
+ patch);
return new MinecraftGameVersion(major, minor, patch);
}
}

View File

@@ -1,5 +1,8 @@
package com.gmail.nossr50.util;
import static com.gmail.nossr50.listeners.EntityListener.isArmorStandEntity;
import static com.gmail.nossr50.listeners.EntityListener.isMannequinEntity;
import com.gmail.nossr50.datatypes.MobHealthbarType;
import com.gmail.nossr50.datatypes.meta.OldName;
import com.gmail.nossr50.mcMMO;
@@ -40,8 +43,12 @@ public final class MobHealthbarUtils {
* @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 (isArmorStandEntity(target) || isMannequinEntity(target)) {
return;
}
if (mcMMO.isHealthBarPluginEnabled()
|| !mcMMO.p.getGeneralConfig().getMobHealthbarEnabled()) {
return;
}
@@ -54,13 +61,13 @@ public final class MobHealthbarUtils {
return;
}
String originalName = target.getName();
final String originalName = target.getName();
String oldName = target.getCustomName();
/*
* Store the name in metadata
*/
if (target.getMetadata(MetadataConstants.METADATA_KEY_OLD_NAME_KEY).size() <= 0) {
if (target.getMetadata(MetadataConstants.METADATA_KEY_OLD_NAME_KEY).isEmpty()) {
target.setMetadata(MetadataConstants.METADATA_KEY_OLD_NAME_KEY,
new OldName(originalName, plugin));
}

View File

@@ -1,6 +0,0 @@
package com.gmail.nossr50.util;
public enum PotionCompatibilityType {
PRE_1_20_5,
MODERN
}

View File

@@ -1,8 +1,5 @@
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;
@@ -10,34 +7,19 @@ 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.PotionEffect;
import org.bukkit.potion.PotionType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class PotionUtil {
public final class PotionUtil {
// Some of the old potion types got renamed, our configs can still contain these old names
private static final Map<String, String> 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
@@ -47,199 +29,48 @@ public class PotionUtil {
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;
}
}
private PotionUtil() {}
/**
* 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}
* <p>In 1.20.5+, "upgraded" and "extended" are represented by distinct {@link PotionType}
* constants (e.g. STRONG_HEALING, LONG_SWIFTNESS), not flags.
*
* @param name The partial name of the potion
* @return The potion type
* @param partialName potion type as a string, can be a substring of the potion type but must match
* against the potion's key or enum name
* @return The potion type, or null if no match
*/
private static PotionType matchLegacyPotionType(String name) {
public static @Nullable PotionType matchPotionType(String partialName, boolean isUpgraded, boolean isExtended) {
if (partialName == null || partialName.isEmpty()) {
return null;
}
final String updatedName = convertLegacyNames(partialName).toUpperCase(Locale.ENGLISH);
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;
}
// Allow matching by namespace key ("swiftness", "long_swiftness") or enum name
.filter(potionType -> {
final NamespacedKey key = potionType.getKey();
final String keyStr = key != null ? key.getKey() : "";
return keyStr.toUpperCase(Locale.ENGLISH).contains(updatedName)
|| potionType.name().toUpperCase(Locale.ENGLISH).contains(updatedName);
})
// Enforce strong/long selection by the enum name prefix convention
.filter(potionType -> isUpgraded == potionType.name().startsWith(STRONG + "_"))
.filter(potionType -> isExtended == potionType.name().startsWith(LONG + "_"))
.findAny()
.orElse(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
* Returns the NamespacedKey key string portion for this potion type (e.g. "swiftness").
*/
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 @NotNull String getKeyGetKey(@NotNull PotionType potionType) {
final NamespacedKey key = potionType.getKey();
return key != null ? key.getKey() : potionType.name();
}
public static String convertPotionConfigName(String legacyName) {
@@ -252,318 +83,91 @@ public class PotionUtil {
if (replacementName.contains("_II")) {
replacementName = replacementName.replace("_II", "");
replacementName = "STRONG_" + replacementName;
replacementName = STRONG + "_" + replacementName;
} else if (replacementName.contains("_EXTENDED")) {
replacementName = replacementName.replace("_EXTENDED", "");
replacementName = "LONG_" + replacementName;
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(@NotNull PotionMeta potionMeta) {
final PotionType base = potionMeta.getBasePotionType();
return base != null && base.name().startsWith(STRONG + "_");
}
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 isLong(@NotNull PotionMeta potionMeta) {
final PotionType base = potionMeta.getBasePotionType();
return base != null && base.name().startsWith(LONG + "_");
}
public static boolean isPotionTypeWater(@NotNull PotionMeta potionMeta) {
if (COMPATIBILITY_MODE == PotionCompatibilityType.PRE_1_20_5) {
return isPotionTypeWaterLegacy(potionMeta);
} else {
return isPotionTypeWaterModern(potionMeta);
return potionMeta.getBasePotionType() == PotionType.WATER;
}
public static boolean hasBasePotionEffects(@NotNull PotionMeta potionMeta) {
final PotionType base = potionMeta.getBasePotionType();
if (base == null) {
return false;
}
}
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<PotionEffectType> potionEffectTypeList = (List<PotionEffectType>) methodPotionTypeGetPotionEffects.invoke(
potionType);
return potionEffectTypeList != null && !potionEffectTypeList.isEmpty();
} catch (IllegalAccessException | InvocationTargetException ex) {
throw new RuntimeException(ex);
}
final List<PotionEffect> effects = base.getPotionEffects();
return effects != null && !effects.isEmpty();
}
/**
* 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
* <p>In 1.20.5+, "extended/upgraded" are encoded into {@link PotionType} variants. This method
* attempts to select the appropriate STRONG_/LONG_ variant when requested. If no such variant
* exists, it falls back to the provided base type.</p>
*/
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 setBasePotionType(@NotNull PotionMeta potionMeta,
@NotNull PotionType potionType, boolean extended, boolean upgraded) {
final PotionType resolved = resolveVariant(potionType, upgraded, extended);
potionMeta.setBasePotionType(resolved);
}
public static void setUpgradedAndExtendedProperties(PotionType potionType,
PotionMeta potionMeta,
boolean isUpgraded, boolean isExtended) {
if (potionDataClass == null || mcMMO.getCompatibilityManager().getMinecraftGameVersion()
.isAtLeast(1, 20, 5)) {
return;
private static @NotNull PotionType resolveVariant(@NotNull PotionType base, boolean upgraded,
boolean extended) {
// Apply the same prefix scheme your code already expects
String name = base.name();
// Avoid double-prefixing if caller already passed LONG_/STRONG_ variants
if (name.startsWith(STRONG + "_")) {
upgraded = false;
}
if (name.startsWith(LONG + "_")) {
extended = false;
}
if (upgraded) {
name = STRONG + "_" + name;
}
if (extended) {
name = LONG + "_" + name;
}
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);
}
return PotionType.valueOf(name);
} catch (IllegalArgumentException ignored) {
// Not all potion types have strong/long variants; just use the provided base.
return base;
}
}
}

View File

@@ -8,7 +8,6 @@ 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;
import com.gmail.nossr50.commands.chat.McChatSpy;
@@ -41,6 +40,7 @@ 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.SpearsCommand;
import com.gmail.nossr50.commands.skills.SwordsCommand;
import com.gmail.nossr50.commands.skills.TamingCommand;
import com.gmail.nossr50.commands.skills.TridentsCommand;
@@ -63,9 +63,8 @@ public final class CommandRegistrationManager {
private static void registerSkillCommands() {
for (PrimarySkillType primarySkillType : PrimarySkillType.values()) {
if (primarySkillType == PrimarySkillType.MACES
&& !mcMMO.getCompatibilityManager().getMinecraftGameVersion()
.isAtLeast(1, 21, 0)) {
if (primarySkillType == PrimarySkillType.SPEARS
&& !mcMMO.getMinecraftGameVersion().isAtLeast(1, 21, 11)) {
continue;
}
@@ -101,6 +100,7 @@ public final class CommandRegistrationManager {
case REPAIR -> command.setExecutor(new RepairCommand());
case SALVAGE -> command.setExecutor(new SalvageCommand());
case SMELTING -> command.setExecutor(new SmeltingCommand());
case SPEARS -> command.setExecutor(new SpearsCommand());
case SWORDS -> command.setExecutor(new SwordsCommand());
case TAMING -> command.setExecutor(new TamingCommand());
case TRIDENTS -> command.setExecutor(new TridentsCommand());
@@ -403,13 +403,6 @@ public final class CommandRegistrationManager {
command.setExecutor(new McmmoReloadLocaleCommand());
}
private static void registerCompatibilityCommand() {
PluginCommand command = mcMMO.p.getCommand("mmocompat"); //TODO: Localize
command.setDescription(LocaleLoader.getString("Commands.Description.mmocompat"));
command.setUsage(LocaleLoader.getString("Commands.Usage.0", "mmocompat"));
command.setExecutor(new CompatibilityCommand());
}
private static void registerXPBarCommand() {
PluginCommand command = mcMMO.p.getCommand("mmoxpbar"); //TODO: Localize
command.setDescription(LocaleLoader.getString("Commands.Description.mmoxpbar"));
@@ -465,8 +458,5 @@ public final class CommandRegistrationManager {
// Admin commands
registerReloadLocaleCommand();
// Misc
registerCompatibilityCommand();
}
}

View File

@@ -1,16 +0,0 @@
package com.gmail.nossr50.util.compat;
/**
* Compatibility Layers should be named after the functionality they serve
*/
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;
}
}

View File

@@ -1,163 +0,0 @@
package com.gmail.nossr50.util.compat;
import com.gmail.nossr50.locale.LocaleLoader;
import com.gmail.nossr50.mcMMO;
import com.gmail.nossr50.util.LogUtils;
import com.gmail.nossr50.util.compat.layers.bungee.AbstractBungeeSerializerCompatibilityLayer;
import com.gmail.nossr50.util.compat.layers.bungee.BungeeLegacySerializerCompatibilityLayer;
import com.gmail.nossr50.util.compat.layers.bungee.BungeeModernSerializerCompatibilityLayer;
import com.gmail.nossr50.util.compat.layers.skills.AbstractMasterAnglerCompatibility;
import com.gmail.nossr50.util.compat.layers.skills.MasterAnglerCompatibilityLayer;
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;
/**
* 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 CompatibilityManager {
private @NotNull HashMap<CompatibilityType, Boolean> supportedLayers;
private boolean isFullyCompatibleServerSoftware = true; //true if all compatibility layers load successfully
private final @NotNull MinecraftGameVersion minecraftGameVersion;
private final @NotNull NMSVersion nmsVersion;
/* Compatibility Layers */
private AbstractBungeeSerializerCompatibilityLayer bungeeSerializerCompatibilityLayer;
private AbstractMasterAnglerCompatibility masterAnglerCompatibility;
public CompatibilityManager(@NotNull MinecraftGameVersion minecraftGameVersion) {
LogUtils.debug(mcMMO.p.getLogger(), "Loading compatibility layers...");
this.minecraftGameVersion = minecraftGameVersion;
this.nmsVersion = determineNMSVersion();
init();
LogUtils.debug(mcMMO.p.getLogger(), "Finished loading compatibility layers.");
}
private void init() {
initSupportedLayersMap();
initCompatibilityLayers();
}
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
}
}
/**
* Initialize all necessary compatibility layers For any unsupported layers, load a dummy layer
*/
private void initCompatibilityLayers() {
initBungeeSerializerLayer();
initMasterAnglerLayer();
isFullyCompatibleServerSoftware = true;
}
private void initMasterAnglerLayer() {
if (minecraftGameVersion.isAtLeast(1, 16, 3)) {
masterAnglerCompatibility = new MasterAnglerCompatibilityLayer();
} else {
masterAnglerCompatibility = null;
}
}
private void initBungeeSerializerLayer() {
if (minecraftGameVersion.isAtLeast(1, 16, 0)) {
bungeeSerializerCompatibilityLayer = new BungeeModernSerializerCompatibilityLayer();
} else {
bungeeSerializerCompatibilityLayer = new BungeeLegacySerializerCompatibilityLayer();
}
supportedLayers.put(CompatibilityType.BUNGEE_SERIALIZER, true);
}
//TODO: move to text manager
public void reportCompatibilityStatus(@NotNull CommandSender commandSender) {
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)) {
commandSender.sendMessage(LocaleLoader.getString("mcMMO.Template.Prefix",
LocaleLoader.getString("Compatibility.Layer.Unsupported",
StringUtils.getCapitalized(compatibilityType.toString()))));
}
}
}
commandSender.sendMessage(LocaleLoader.getString("mcMMO.Template.Prefix",
"NMS Status - " + nmsVersion));
}
public boolean isCompatibilityLayerOperational(@NotNull CompatibilityType compatibilityType) {
return supportedLayers.get(compatibilityType);
}
public boolean isFullyCompatibleServerSoftware() {
return isFullyCompatibleServerSoftware;
}
public @NotNull NMSVersion getNmsVersion() {
return nmsVersion;
}
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)) {
return NMSVersion.NMS_1_17;
}
//Messy but it works
if (minecraftGameVersion.getMajorVersion().asInt() == 1) {
switch (minecraftGameVersion.getMinorVersion().asInt()) {
case 12:
return NMSVersion.NMS_1_12_2;
case 13:
return NMSVersion.NMS_1_13_2;
case 14:
return NMSVersion.NMS_1_14_4;
case 15:
return NMSVersion.NMS_1_15_2;
case 16:
if (minecraftGameVersion.getPatchVersion().asInt() == 1) {
return NMSVersion.NMS_1_16_1;
} else if (minecraftGameVersion.getPatchVersion().asInt() == 2) {
return NMSVersion.NMS_1_16_2;
} else if (minecraftGameVersion.getPatchVersion().asInt() == 3) {
return NMSVersion.NMS_1_16_3;
} else if (minecraftGameVersion.getPatchVersion().asInt() == 4) {
return NMSVersion.NMS_1_16_4;
} else if (minecraftGameVersion.getPatchVersion().asInt() >= 5) {
return NMSVersion.NMS_1_16_5;
}
case 17:
return NMSVersion.NMS_1_17;
}
}
return NMSVersion.UNSUPPORTED;
}
public AbstractBungeeSerializerCompatibilityLayer getBungeeSerializerCompatibilityLayer() {
return bungeeSerializerCompatibilityLayer;
}
public @Nullable AbstractMasterAnglerCompatibility getMasterAnglerCompatibilityLayer() {
return masterAnglerCompatibility;
}
public @NotNull MinecraftGameVersion getMinecraftGameVersion() {
return minecraftGameVersion;
}
}

View File

@@ -1,7 +0,0 @@
package com.gmail.nossr50.util.compat;
public enum CompatibilityType {
PERSISTENT_DATA,
BUNGEE_SERIALIZER,
MASTER_ANGLER,
}

View File

@@ -1,24 +0,0 @@
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
*/
public abstract class AbstractCompatibilityLayer implements CompatibilityLayer {
protected boolean noErrorsOnInitialize = true;
/**
* Initialize the CompatibilityLayer
*
* @return true if the CompatibilityLayer initialized and should be functional
*/
public abstract boolean initializeLayer();
@Override
public boolean noErrorsOnInitialize() {
return noErrorsOnInitialize;
}
}

View File

@@ -1,29 +0,0 @@
package com.gmail.nossr50.util.compat.layers;
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
*/
public abstract class AbstractNMSCompatibilityLayer extends AbstractCompatibilityLayer {
protected final @NotNull NMSVersion nmsVersion;
public AbstractNMSCompatibilityLayer(@NotNull NMSVersion nmsVersion) {
this.nmsVersion = nmsVersion;
}
/**
* Initialize the CompatibilityLayer
*
* @return true if the CompatibilityLayer initialized and should be functional
*/
public abstract boolean initializeLayer();
@Override
public boolean noErrorsOnInitialize() {
return noErrorsOnInitialize;
}
}

View File

@@ -1,42 +0,0 @@
//package com.gmail.nossr50.util.compat.layers.attackcooldown;
//
//import com.gmail.nossr50.util.nms.NMSVersion;
//import org.bukkit.entity.Player;
//import org.jetbrains.annotations.NotNull;
//
//import java.lang.reflect.InvocationTargetException;
//
//public class DummyPlayerAttackCooldownToolLayer extends PlayerAttackCooldownToolLayer {
// public DummyPlayerAttackCooldownToolLayer() {
// super(NMSVersion.UNSUPPORTED);
// }
//
// @Override
// public boolean initializeLayer() {
// return noErrorsOnInitialize;
// }
//
// @Override
// public float getAttackStrength(@NotNull Player player) throws InvocationTargetException, IllegalAccessException {
// return 1.0F; //Always full strength
// }
//
// @Override
// public float getCooldownValue(@NotNull Player player) throws InvocationTargetException, IllegalAccessException {
// return 0F;
// }
//
// @Override
// public void resetAttackStrength(@NotNull Player player) throws InvocationTargetException, IllegalAccessException {
// //Do nothing
// }
//
// @Override
// public int getCooldownFieldValue(@NotNull Player player) throws InvocationTargetException, IllegalAccessException {
// return 0;
// }
//
// @Override
// public void setCooldownFieldValue(@NotNull Player player, int fieldValue) throws InvocationTargetException, IllegalAccessException {
// }
//}

View File

@@ -1,30 +0,0 @@
package com.gmail.nossr50.util.compat.layers.attackcooldown;
import java.lang.reflect.InvocationTargetException;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
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
*
* @param player target player
* @return the float value of the player's attack strength
*/
float getAttackStrength(@NotNull Player player)
throws InvocationTargetException, IllegalAccessException;
float getCooldownValue(@NotNull Player player)
throws InvocationTargetException, IllegalAccessException;
void resetAttackStrength(@NotNull Player player)
throws InvocationTargetException, IllegalAccessException;
int getCooldownFieldValue(@NotNull Player player)
throws InvocationTargetException, IllegalAccessException;
void setCooldownFieldValue(@NotNull Player player, int fieldValue)
throws InvocationTargetException, IllegalAccessException;
}

View File

@@ -1,238 +0,0 @@
//package com.gmail.nossr50.util.compat.layers.attackcooldown;
//
//import com.gmail.nossr50.mcMMO;
//import com.gmail.nossr50.util.compat.layers.AbstractNMSCompatibilityLayer;
//import com.gmail.nossr50.util.nms.NMSConstants;
//import com.gmail.nossr50.util.nms.NMSVersion;
//import org.bukkit.entity.Player;
//import org.jetbrains.annotations.NotNull;
//import org.jetbrains.annotations.Nullable;
//
//import java.lang.reflect.Field;
//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
// *
// */
//public class PlayerAttackCooldownToolLayer extends AbstractNMSCompatibilityLayer implements PlayerAttackCooldownMethods {
//
// private final String cbNMSVersionPath;
//
// protected Class<?> craftPlayerClass;
// protected Class<?> entityHumanClass;
// protected Class<?> entityLivingClass;
//
// protected Method playerAttackCooldownMethod;
// protected Method playerAttackStrengthMethod;
// protected Method resetPlayerAttackCooldownMethod;
// protected Method setPlayerAttackStrengthMethod;
// protected Method getHandleMethod;
// protected Field attackCooldownField;
// protected String attackStrengthFieldName;
//
// public PlayerAttackCooldownToolLayer(@NotNull NMSVersion nmsVersion) {
// super(nmsVersion);
// mcMMO.p.getLogger().info("Loading Compatibility Layer... (Player Attack Cooldown Exploit Prevention)");
// 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) {
// cbNMSVersionPath = NMSConstants.getCraftBukkitVersionPath(nmsVersion);
// noErrorsOnInitialize = initializeLayer();
//
// if (noErrorsOnInitialize) {
// mcMMO.p.getLogger().info("Successfully Loaded Compatibility Layer! (Player Attack Cooldown Exploit Prevention)");
// }
// } else {
// mcMMO.p.getLogger().info("Failed to load - CL (Player Attack Cooldown Exploit Prevention) Could not find CB NMS path for CL");
// flagErrorsDuringStartup();
// mcMMO.p.getLogger().warning("Could not wire NMS package path for CraftBukkit!");
// cbNMSVersionPath = "";
// }
// }
// }
//
// public static boolean isCompatibleWithMinecraftVersion(@NotNull NMSVersion nmsVersion) {
// switch(nmsVersion) {
// case NMS_1_13_2:
// case NMS_1_14_4:
// case NMS_1_15_2:
// case NMS_1_16_4:
// case NMS_1_16_5:
// return true;
// default:
// return false;
// }
// }
//
// /**
// * Cache all reflection methods/types/classes needed for the NMS of this CompatibilityLayer
// * @param cooldownMethodName the cooldown method name
// * @param attackStrengthMethodName the attack strength method name
// * @param resetAttackCooldownMethodName the reset attack cooldown method name
// * @param getHandleMethodName the get handle method name
// * @return true if NMS was successfully wired
// */
// public boolean wireNMS(@NotNull String cooldownMethodName, @NotNull String attackStrengthMethodName, @NotNull String resetAttackCooldownMethodName, @NotNull String getHandleMethodName, @NotNull String attackStrengthFieldName) {
// entityHumanClass = initEntityHumanClass();
//
// if (entityHumanClass != null) {
// entityLivingClass = entityHumanClass.getSuperclass();
// }
//
// craftPlayerClass = initCraftPlayerClass();
// this.attackStrengthFieldName = attackStrengthFieldName;
//
// try {
// this.attackCooldownField = entityLivingClass.getDeclaredField(attackStrengthFieldName);
// this.attackCooldownField.setAccessible(true);
// } catch (NoSuchFieldException e) {
// e.printStackTrace();
// }
//
// try {
// this.playerAttackCooldownMethod = entityHumanClass.getMethod(cooldownMethodName);
// this.playerAttackStrengthMethod = entityHumanClass.getMethod(attackStrengthMethodName, float.class);
// this.resetPlayerAttackCooldownMethod = entityHumanClass.getMethod(resetAttackCooldownMethodName);
//
// if (craftPlayerClass != null) {
// this.getHandleMethod = craftPlayerClass.getMethod(getHandleMethodName);
// } else {
// return false;
// }
// return true;
// } catch (NoSuchMethodException e) {
// flagErrorsDuringStartup();
// e.printStackTrace();
// return false;
// }
// }
//
// /**
// * Get the cached player attack cooldown method
// * @return the cached player attack cooldown method
// */
// private @Nullable Method getPlayerAttackCooldownMethod() {
// return playerAttackCooldownMethod;
// }
//
// /**
// * Get the cached player attack strength method
// * @return the cached player attack strength method
// */
// private @Nullable Method getPlayerAttackStrengthMethod() {
// return playerAttackStrengthMethod;
// }
//
// /**
// * Get the cached player attack cooldown reset method
// * @return the cached player attack cooldown reset method
// */
// private @Nullable Method getResetPlayerAttackCooldownMethod() {
// return resetPlayerAttackCooldownMethod;
// }
//
// /**
// * Grab the CraftPlayer class type from NMS
// * @return the CraftPlayer class type from NMS
// */
// private @Nullable Class<?> initCraftPlayerClass() {
// try {
// return Class.forName(NMSConstants.getCraftPlayerClassPath(cbNMSVersionPath));
// } catch (ClassNotFoundException e) {
// flagErrorsDuringStartup();
// e.printStackTrace();
// return null;
// }
// }
//
// /**
// * Grab the EntityHuman class type from NMS
// * @return the EntityHuman class type from NMS
// */
// private @Nullable Class<?> initEntityHumanClass() {
// try {
// return Class.forName(NMSConstants.getEntityHumanClassPath(cbNMSVersionPath));
// } catch (ClassNotFoundException e) {
// flagErrorsDuringStartup();
// e.printStackTrace();
// return null;
// }
// }
//
// private void flagErrorsDuringStartup() {
// noErrorsOnInitialize = false;
// }
//
// /**
// * 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
// */
// @Override
// public float getAttackStrength(@NotNull Player player) throws InvocationTargetException, IllegalAccessException {
// Object craftPlayer = craftPlayerClass.cast(player);
// Object entityHuman = entityHumanClass.cast(getHandleMethod.invoke(craftPlayer));
//
// return (float) playerAttackStrengthMethod.invoke(entityHuman, 0F); //Add no adjustment ticks
// }
//
// @Override
// public float getCooldownValue(@NotNull Player player) throws InvocationTargetException, IllegalAccessException {
// Object craftPlayer = craftPlayerClass.cast(player);
// Object entityHuman = entityHumanClass.cast(getHandleMethod.invoke(craftPlayer));
//
// return (float) playerAttackCooldownMethod.invoke(entityHuman); //Add no adjustment ticks
// }
//
// @Override
// public void resetAttackStrength(@NotNull Player player) throws InvocationTargetException, IllegalAccessException {
// Object craftPlayer = craftPlayerClass.cast(player);
// Object entityHuman = entityHumanClass.cast(getHandleMethod.invoke(craftPlayer));
// Object entityLiving = entityLivingClass.cast(entityHuman);
//
// resetPlayerAttackCooldownMethod.invoke(entityLiving);
// }
//
// @Override
// public int getCooldownFieldValue(@NotNull Player player) throws InvocationTargetException, IllegalAccessException {
// Object craftPlayer = craftPlayerClass.cast(player);
// Object entityHuman = entityHumanClass.cast(getHandleMethod.invoke(craftPlayer));
// Object entityLiving = entityLivingClass.cast(entityHuman);
//
// return attackCooldownField.getInt(entityLiving);
// }
//
// @Override
// public void setCooldownFieldValue(@NotNull Player player, int fieldValue) throws InvocationTargetException, IllegalAccessException {
// Object craftPlayer = craftPlayerClass.cast(player);
// Object entityHuman = entityHumanClass.cast(getHandleMethod.invoke(craftPlayer));
//
// attackCooldownField.setInt(entityHuman, fieldValue);
// }
//
// @Override
// public boolean initializeLayer() {
// switch(nmsVersion) {
// case NMS_1_12_2:
// return wireNMS("dr", "n", "ds", "getHandle", "at");
// case NMS_1_13_2:
// return wireNMS("dG", "r", "dH", "getHandle", "at");
// case NMS_1_14_4:
// return wireNMS("dY", "s", "dZ", "getHandle", "at");
// case NMS_1_15_2:
// return wireNMS("ex", "s", "ey", "getHandle", "at");
// case NMS_1_16_4:
// return wireNMS("eR", "getAttackCooldown", "resetAttackCooldown", "getHandle", "at");
// default:
// throw new RuntimeException("Unexpected NMS version support in PlayerAttackCooldown compatibility layer initialization!");
// }
// }
//}
//

View File

@@ -1,11 +0,0 @@
package com.gmail.nossr50.util.compat.layers.bungee;
import net.kyori.adventure.text.Component;
import net.md_5.bungee.api.chat.BaseComponent;
import org.checkerframework.checker.nullness.qual.NonNull;
public abstract class AbstractBungeeSerializerCompatibilityLayer {
public abstract @NonNull Component deserialize(final @NonNull BaseComponent @NonNull [] input);
}

View File

@@ -1,14 +0,0 @@
package com.gmail.nossr50.util.compat.layers.bungee;
import net.kyori.adventure.text.Component;
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 {
@Override
public @NonNull Component deserialize(@NonNull BaseComponent @NonNull [] input) {
return BungeeComponentSerializer.legacy().deserialize(input);
}
}

View File

@@ -1,14 +0,0 @@
package com.gmail.nossr50.util.compat.layers.bungee;
import net.kyori.adventure.text.Component;
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 {
@Override
public @NonNull Component deserialize(@NonNull BaseComponent @NonNull [] input) {
return BungeeComponentSerializer.get().deserialize(input);
}
}

View File

@@ -1,6 +0,0 @@
package com.gmail.nossr50.util.compat.layers.skills;
import com.gmail.nossr50.util.compat.layers.AbstractCompatibilityLayer;
public abstract class AbstractMasterAnglerCompatibility extends AbstractCompatibilityLayer {
}

View File

@@ -1,79 +0,0 @@
package com.gmail.nossr50.util.compat.layers.skills;
import org.bukkit.entity.FishHook;
import org.jetbrains.annotations.NotNull;
public class MasterAnglerCompatibilityLayer extends AbstractMasterAnglerCompatibility {
@Override
public boolean initializeLayer() {
return true;
}
/**
* Get the minimum number of ticks one has to wait for a fish biting.
* <p>
* The default is 100 ticks (5 seconds).<br> Note that this is before applying lure.
*
* @return Minimum number of ticks one has to wait for a fish biting
*/
public int getMinWaitTime(@NotNull FishHook fishHook) {
return fishHook.getMinWaitTime();
}
/**
* Set the minimum number of ticks one has to wait for a fish biting.
* <p>
* The default is 100 ticks (5 seconds).<br> Note that this is before applying lure.
*
* @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);
}
/**
* Get the maximum number of ticks one has to wait for a fish biting.
* <p>
* The default is 600 ticks (30 seconds).<br> Note that this is before applying lure.
*
* @return Maximum number of ticks one has to wait for a fish biting
*/
public int getMaxWaitTime(@NotNull FishHook fishHook) {
return fishHook.getMaxWaitTime();
}
/**
* Set the maximum number of ticks one has to wait for a fish biting.
* <p>
* The default is 600 ticks (30 seconds).<br> Note that this is before applying lure.
*
* @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.
* <p>
* The default is true.<br> 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
*/
public boolean getApplyLure(@NotNull FishHook fishHook) {
return fishHook.getApplyLure();
}
/**
* Set whether the lure enchantment should be applied to reduce the wait time.
* <p>
* The default is true.<br> 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
*/
public void setApplyLure(@NotNull FishHook fishHook, boolean applyLure) {
fishHook.setApplyLure(applyLure);
}
}

View File

@@ -1,22 +0,0 @@
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
*/
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) {
this.minecraftGameVersion = minecraftGameVersion;
this.serverSoftwareType = serverSoftwareType;
this.compatibilityManager = compatibilityManager;
}
}

View File

@@ -1,31 +0,0 @@
package com.gmail.nossr50.util.platform;
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
*/
public class BukkitPlatform extends AbstractPlatform {
public BukkitPlatform(MinecraftGameVersion minecraftGameVersion) {
super(minecraftGameVersion, ServerSoftwareType.CRAFT_BUKKIT,
new CompatibilityManager(minecraftGameVersion));
}
@Override
public @NotNull ServerSoftwareType getServerSoftwareType() {
return super.serverSoftwareType;
}
@Override
public @NotNull CompatibilityManager getCompatibilityManager() {
return compatibilityManager;
}
@Override
public @NotNull MinecraftGameVersion getGameVersion() {
return super.minecraftGameVersion;
}
}

Some files were not shown because too many files have changed in this diff Show More