diff --git a/docs/changelog_v3.2.x.md b/docs/changelog_v3.2.x.md index c55bc2e1e..35bcf3910 100644 --- a/docs/changelog_v3.2.x.md +++ b/docs/changelog_v3.2.x.md @@ -4,6 +4,7 @@ ## Build logs - **[v3.3.x - Current](changelog_v3.3.x.md)** + - [v3.2.0 through v3.3.0-alpha.14](prison_changelogs.md) - [v3.2.0 - 2019-12-03](prison_changelog_v3.2.0.md)   [v3.2.1 - 2020-09-27](prison_changelog_v3.2.1.md)   [v3.2.2 - 2020-11-21](prison_changelog_v3.2.2.md)   diff --git a/docs/changelog_v3.3.x.md b/docs/changelog_v3.3.x.md index abeda4468..2a9af13a4 100644 --- a/docs/changelog_v3.3.x.md +++ b/docs/changelog_v3.3.x.md @@ -4,15 +4,130 @@ ## Build logs - **[v3.3.0-alpha - Current](changelog_v3.3.x.md)** - - [v3.2.0 through v3.2.10](prison_changelogs.md) + - [v3.2.0 through v3.3.0-alpha.14](prison_changelogs.md) These build logs represent the work that has been going on within prison. +# 3.3.0-alpha.14 2023-01-23 + + +**Prison v3.3.0-alpha.14 2023-01-23** + + +The following are significant changes that are included in the alpha.14 release since the alpha.13 release was posted. + +* Support for RevEnchants + + +* Added more flexibility in supporting Prison Event Listener priorities for block break events so prison is better suited to support more enchantment plugins under more conditions. Added ACCESS, ACCESSBLOCKBREAKS, and ACCESSMONITOR to provide far more flexibility when prison is NOT managing the block breakage. + + +* General improvements in how Auto Features manages the event listeners for all of the block break events. Includes some bug fixes and performance improvements too. + + +* Preparing to support ItemsAdder... will be available in next alpha release.* + + +* Prison Placeholders: Added a few more, fixed a few bugs, and improved documentation so its easier to understand how to use them. Added more features to the command `/prison placeholders stats`. The stats command can actually be used to troubleshoot issues with third-party plugins trying to use prison placeholders. + + +* Top-n reports and placeholders: bug fixes and added a few more features. + + +* Mine commands: refactor and improvements to some of the general mine commands. + + +* Prison Placeholders: general bug fixes and performance improvements with the placeholder cache. + + +* Prison's bstats: Expanded the reports that are being included. + + +* Prison Command Handler: ability to lockout players from commands and tab-completes based upon perms. + + +* Mines GUI Bug fixes: fixed a few issues. + + +* Issue with vault not working with essentials: Not able to access player's balances through vault and provided alternative paths to resolve this issue. + + +* Prison support new feature: tracking command usage along with average run times: `/prison support cmdStats`. + + +* Updates to a number of libraries that prison uses: +placeholderApi: v2.10.9 to v2.11.2 +XSeries: v9.0.0 to v9.2.0 +item-nbt-api: v2.10.0 to v2.11.1 + + +* Removal of support for MVDW placeholders since it's not able to support some of prison's advanced features, plus it's 100% redundant since PlaceholderAPI works in conjunction with it. No loss of service since PAPI is a better solution and works with MVDW. + + +* Added a Prison Backup feature that can make a backup of all the settings within prison's plugin directory (small zip file backups). It is setup to make a backup whenever it detects a change in the prison versions. In the future, it could be automated to make snapshots of all settings and player status so there can be abilities to "rollback" to a prior instance. + + +* Added new translations: Finnish, Chinese, + + +* Enhanced the player GUIs for mines and ranks to use NBT to control the options to simplify how the options work. Eliminated a lot of old code and added more flexibility. + + +* Enable the sellall command to be ran from the console or from a prison command. + + +* Enhanced the debug logging detail related to the auto features. Provides better logging for troubleshooting. + + +* Using a static global setting for decimal formatting to better control how numeric formatting works with various language settings. + + +* Able to now control suffocation in the mines, so you can now allow players to die if they logged out within a mine and they log back buried in rock. + + +* Able to control mine reset teleportation controls. + + +* Added direct support for translating placeholders through the Prison API so its easier to use externally through another plugin. + + +* Now able to set a prestige rank tag to use for players that do not have a prestige rank. This allows for better customization for chat prefixes. + + +* Fixed a bug when trying to move a mine from one world to another world. There was a conflict with an internal value not being cleared/reset. + + +* Fixed a Prison Mine Bomb bug that was making them incompatible with bukkit 1.8.8. + + +* Fixed a bug with how a vector's length was being calculated. Not sure how frequently this would have been used. + + +* Refactoring Prison Backpacks. Getting ready to hook them up to a new internal backpack cache to improve performance. Not yet completed. + + +* Fixed bug with /rankupmax and rewrote prestiges to better align it with the ranks module instead of relying upon the GUI code to manage it. + + +* Enhanced many mine and rank commands to apply changes to all ranks or all mines with one command to make it easier to customize prison. + + +* New feature setting (optional): Forced rankup as soon as the player earns enough money through sellall. + + +* New feature setting (optional): Forced sellall before performing a prestige. + + +* New feature setting (optional): Prevent access to prior mines when ranking up. This foces the player to only have access to mines that are linked to the current rank. This feature allows the use of Mine and TP access by rank instead of having to setup complex settings with perms through a permission plugin. + + + +--------------------------- + -# 3.3.0-alpha.13 2022-08-25 **3.3.0-alpha.13 2022-08-25** diff --git a/docs/knownissues_v3.3.x.md b/docs/knownissues_v3.3.x.md index b736e0fe2..e52ca610f 100644 --- a/docs/knownissues_v3.3.x.md +++ b/docs/knownissues_v3.3.x.md @@ -8,30 +8,56 @@ # TODO Items for v3.3.0-alpha.13 -- In the GUI menu, the config setting: Enchantment_effect_current_rank is off by 1. If D rank it shows E being unlocked. - CITYJD +- On the new cmdStats details, add nano run times for commands so we can include avg run times. -- Add `*all*` to `/mines set notification` - CITYJD +- Add a command usage count to commands. Then a simple report to list what commands were used, along with total command count of active commands. -- Auto-Forced-Rankups and prestiges when the player has enough money. Kikiisyourfriend - - a new autoFeatures entry +- Expand upon the config.yml command lockout so that if the player does not have access to a command, then suppress that command from all players, including command listings. Not all commands will be able to reject access due to the nature of the commands (all access to everyone) and/or the use of alt-perms (programmatic evaluation to the commands). - Josh-65 + + +- File save to new format - OmarG + - pre-req for turning off TP + - pre-req for custom mine shapes + + +- Ability to turn of TP on mine resets. OmarG + - Maybe have a special value for spawn to indicate it should TP? + - Could still have a spawn point, but just not tp during resets. + + +- custom mine shapes - Chain and Fiba1 and OmarG + - Have a new command to edit and save the mine's shapes + - edit would spawn red/yellow wool - remove blocks - save would only save the wool blocks. -- Enable Access to prior mines - kikiisyourfriend - - disable to prevent going back to prior rank mines. +- fix gui ranks to remove italics from the rank names. This may be the gui ranks and/or the gui prestiges. - Bryton + Cannot reproduce - No italics are being added by prison. -- DONE: prison_rank__linked_mines_rankname prison_r_lm_rankname provide a placeholder for the mine's tags. B0mer +- DONE: Gui prestiges - option to remove the gui prestige button. Not sure if any of the options in the config.sys really supports that. - Bryton + + + +- Prestige - needs improvements + DONE: rewrote the prestige handling to exist in the ranks module. Everything is handled properly now. The GUI is passed the correct lore so no rankup logic is in the gui anymore. Prechecks are now enabled too. + - DONE: Confirmation does not perform any prechecks to confirm if the player can even prestige + - DONE: Confirmation does not reflect prestige settins. It always shows that rank and balance will be reset, even if that is disabled. + - DONE: It's not clear how to confirm via chat + + +- when testing the block breakage with the SHIFT-click with the mine wand, I also saw that it processed the same block twice. The first time looked as if the drop was being canceled, then the second time the event was being canceled. Or vice-a-versa. I don't remember setting it up both ways. -- DONE: Mines tp: option to list all available mines per rank? Thaysa - bStats: - DONE: Remove Plugins & Prison Ladders - DONE: Add: modules, Economy (integrations), Perms (integrations), Placeholder (intg) - DONE: Add: Language - - + - Eliminate zero counts (don't report) + - validate that plugins listed in other reports are being removed from plugins a-z. + - `/ranks player` is not including all of the info for rank multipliers like it should have. @@ -55,7 +81,7 @@ -- DONE: Option to skip applying the rank cost multiplier to a specific ladder. + - For v3.3.0 release: @@ -66,7 +92,7 @@ - ranks and ladders - auto prestiges (unlimited) based upon formulas - new file formats - json ORM? - - DONE usind topn: archiving old players + - DONE using topn: archiving old players - DONE: more work on top-n rankings - /mines wguard - worldguard hints for mines (generate scripts to run?) - Use patterns that can be edited @@ -114,6 +140,8 @@ - Mine Resets - Glass block not being removed - harold + + - DONE?: Archive old players - budderman18 - archive all player files to a zip. Remove the originals. If player logs back on, then restore the archives. Prevent startup from adding these players back. - Archiving players in topN - this may address the archive needs. Part of the issue was related to performance calculations upon startup, which the new topn does address. @@ -248,6 +276,47 @@ https://github.com/Auxilor/EcoEnchants/blob/master/eco-core/core-plugin/src/main # Completed tasks + + +- DONE: prison commands if using ; for multi-commands, and if a space follows ; then it's not working. + + +- DONE: The command `/rankupmax` needs to be fixed - redonthehead + - DONE: `/rankupmax`, or `/rankupmax default` is fine, but replaced getting the next rank with the new code so it works better. + - DONE: `/rankupmax prestiges` is the same as `/prestige` and `/rankup prestiges`. Change so it will go through the default ladder, then prestige, then repeat if enough money. + + +- NOT AN ISSUE: In the GUI menu, the config setting: Enchantment_effect_current_rank is off by 1. If D rank it shows E being unlocked. - CITYJD + - Looking at the code where this is used (player ranks and prestiges), the intention of this setting is to highlight the player's next rank. So the settings name is wrong... It should be `Enchantment_effect_next_rank: true` + - Locate docs that covers this topic and make a note explaing what this is for and why the settings name is wrong. + + + +- DONE: Add `*all*` to `/mines set notification` - CITYJD + - Fixed a few other commands too to provide applying the command to all mines. + + + +- DONE: Force sellall before prestiges - kikiisyourfriend + +- DONE: Auto-Forced-Rankups and prestiges when the player has enough money. Kikiisyourfriend + - a new autoFeatures entry + +- DONE: Enable Access to prior mines - kikiisyourfriend + - disable to prevent going back to prior rank mines. + - See `prison-mines.access-to-prior-mines` in config.yml + + +- DONE: prison_rank__linked_mines_rankname prison_r_lm_rankname provide a placeholder for the mine's tags. B0mer + + +- DONE: Mines tp: option to list all available mines per rank? Thaysa + + +- DONE: Option to skip applying the rank cost multiplier to a specific ladder. + + + . DONE: Use of placeholders in gui mines is not working correctly - PassBl - Trying to use: - '&7Test Cost P1: &3%prison_rank__player_cost_formatted_p1%' - Using deluxe menus - may not be sending player info with placeholders? diff --git a/docs/prison_changelog_v3.3.0-alpha.14.md b/docs/prison_changelog_v3.3.0-alpha.14.md new file mode 100644 index 000000000..90628eeb1 --- /dev/null +++ b/docs/prison_changelog_v3.3.0-alpha.14.md @@ -0,0 +1,1985 @@ +[Prison Documents - Table of Contents](prison_docs_000_toc.md) + +## Prison Build Logs for v3.3.x + +## Build logs + - **[v3.3.0-alpha - Current](changelog_v3.3.x.md)** + - [v3.2.0 through v3.3.0-alpha.14](prison_changelogs.md) + + +These build logs represent the work that has been going on within prison. + + +# 3.3.0-alpha.14 2023-01-23 + + + +The following are significant changes that are included in the alpha.14 release since the alpha.13 release was posted. + +* Support for RevEnchants + + +* Added more flexibility in supporting Prison Event Listener priorities for block break events so prison is better suited to support more enchantment plugins under more conditions. Added ACCESS, ACCESSBLOCKBREAKS, and ACCESSMONITOR to provide far more flexibility when prison is NOT managing the block breakage. + + +* General improvements in how Auto Features manages the event listeners for all of the block break events. Includes some bug fixes and performance improvements too. + + +* Preparing to support ItemsAdder... will be available in next alpha release.* + + +* Prison Placeholders: Added a few more, fixed a few bugs, and improved documentation so its easier to understand how to use them. Added more features to the command `/prison placeholders stats`. The stats command can actually be used to troubleshoot issues with third-party plugins trying to use prison placeholders. + + +* Top-n reports and placeholders: bug fixes and added a few more features. + + +* Mine commands: refactor and improvements to some of the general mine commands. + + +* Prison Placeholders: general bug fixes and performance improvements with the placeholder cache. + + +* Prison's bstats: Expanded the reports that are being included. + + +* Prison Command Handler: ability to lockout players from commands and tab-completes based upon perms. + + +* Mines GUI Bug fixes: fixed a few issues. + + +* Issue with vault not working with essentials: Not able to access player's balances through vault and provided alternative paths to resolve this issue. + + +* Prison support new feature: tracking command usage along with average run times: `/prison support cmdStats`. + + +* Updates to a number of libraries that prison uses: +placeholderApi: v2.10.9 to v2.11.2 +XSeries: v9.0.0 to v9.2.0 +item-nbt-api: v2.10.0 to v2.11.1 + + +* Removal of support for MVDW placeholders since it's not able to support some of prison's advanced features, plus it's 100% redundant since PlaceholderAPI works in conjunction with it. No loss of service since PAPI is a better solution and works with MVDW. + + +* Added a Prison Backup feature that can make a backup of all the settings within prison's plugin directory (small zip file backups). It is setup to make a backup whenever it detects a change in the prison versions. In the future, it could be automated to make snapshots of all settings and player status so there can be abilities to "rollback" to a prior instance. + + +* Added new translations: Finnish, Chinese, + + +* Enhanced the player GUIs for mines and ranks to use NBT to control the options to simplify how the options work. Eliminated a lot of old code and added more flexibility. + + +* Enable the sellall command to be ran from the console or from a prison command. + + +* Enhanced the debug logging detail related to the auto features. Provides better logging for troubleshooting. + + +* Using a static global setting for decimal formatting to better control how numeric formatting works with various language settings. + + +* Able to now control suffocation in the mines, so you can now allow players to die if they logged out within a mine and they log back buried in rock. + + +* Able to control mine reset teleportation controls. + + +* Added direct support for translating placeholders through the Prison API so its easier to use externally through another plugin. + + +* Now able to set a prestige rank tag to use for players that do not have a prestige rank. This allows for better customization for chat prefixes. + + +* Fixed a bug when trying to move a mine from one world to another world. There was a conflict with an internal value not being cleared/reset. + + +* Fixed a Prison Mine Bomb bug that was making them incompatible with bukkit 1.8.8. + + +* Fixed a bug with how a vector's length was being calculated. Not sure how frequently this would have been used. + + +* Refactoring Prison Backpacks. Getting ready to hook them up to a new internal backpack cache to improve performance. Not yet completed. + + +* Fixed bug with /rankupmax and rewrote prestiges to better align it with the ranks module instead of relying upon the GUI code to manage it. + + +* Enhanced many mine and rank commands to apply changes to all ranks or all mines with one command to make it easier to customize prison. + + +* New feature setting (optional): Forced rankup as soon as the player earns enough money through sellall. + + +* New feature setting (optional): Forced sellall before performing a prestige. + + +* New feature setting (optional): Prevent access to prior mines when ranking up. This foces the player to only have access to mines that are linked to the current rank. This feature allows the use of Mine and TP access by rank instead of having to setup complex settings with perms through a permission plugin. + + + + +**Prison v3.3.0-alpha.14 2023-01-23** + + +* **Misc NBT stuff... Did not work out as planned so it has been commented out for now.** + + +* **Start to setup support for ItemsAdder but it's not hooked up yet so it does not do anything.** +Most of the parts are hooked up, but it just needs to support the ItemsAdder's event that lets other plugins know when everything is fully loaded and it's ready. + + +* **Prison placeholders: Added details to help understand how to use some of the more confusing placeholders.** +Fixed the grouping of two `prison_top_mine_block_line_` placeholders. + + +* **AutoFeatures Event Listeners: Add new feature where if a player tries to mine in a mine they don't have access to, that it will teleport them to a mine that is linked to their current rank.** + + +* **AutoFeatures Event Listeners: Minor tweaks to the ACCESS priority. Testing has been going well.** + + +* **AutoFeatures Event Listeners: Improved the reporting and refactored to reduce duplicate code.** + + +* **AutoFeatures event listeners: ACCESS priority: Hooked up ACCESS processing and cleaned up the code a little more.** + + +* **AutoFeatures event listeners: More work on getting ACCESS setup, focused on support for `/prison support listeners blockBreak` and to generate multiple listeners for the compounded priorities such as ACCESSBLOCKBREAKS and ACCESSMONITOR.** +Tested successfully the creation of multiple listeners. Have not yet hooked up the support for ACCESS. + + +* **AutoManager event listeners: refactored to prepare for the ACCESS priorities.** + + +* **AutoFeatures Event Listeners: More refactoring to simplify how the debugInfo is passed around.** + + +* **AutoFeatures refactoring: changes the setup of how the events deals with finding the mine the player is in.** +The code was looking up the mine twice, now it only searches for the mine once and reused it more efficiently. +This simplifies how some of the code works and allows for more simplification too. + + +* **Fix a few things with the RevEnchants listeners.** +They were not hooked up for the `/prison support listeners blockevents` and they were not being registered to actually enable. + + +**v3.3.0-alpha.13h3 2023-01-18** + + +* **Enhanced the command `/prison support listeners help` to format the columns for name and priority so they all align.** + + +* **Comment on an issue within EssenialsX that is purposefully generating stack traces within the console, and there is nothing prison can do about it.** +Plus, everything is working fine. +https://github.com/EssentialsX/Essentials/issues/3956 + + +* **Update docs to see if it supports GFM tables** + + +* **AutoFeatures Event Listeners: refactored how a the event is processed so they share more of the same code base. This helps to eliminate the chances for bugs to happen for a few listeners, and it also help to ensure that the behavior for all of the listeners are identical.** +If a event is marked as DISABLED, then the listener should never be loaded, but if it is, then it will quickly end the processing instead of allowing it to filter through all of the code. + + +* **AutoFeatures: Prepare for a few new priorities for the event listeners.** + + +* **AutoFeatures: Bug fix. Found that all events that were canceled were automatically being ignored, which was causing the MONITOR priority to be bypassed since MONITOR should be able to process what it needs to even on a canceled event.** + + +* **AutoFeatures: Have the external events register when the AutoManager is being setup. This eliminates the need to have it always check for registration on each event call.** + + +* **There was a report that TopN was failing with a NPE when Ranks was disabled. This was related to the PlayerManager not being initialized.** +Added code to ensure that TopN is shutdown, and does not try to run, if the Ranks Module, or PlayerManager is not loaded. +It looks like it could have been called through the bStats reporting... which is now fixed. + + +* **AutoFeatures refactoring: Cleaned up a lot of the code related to blockCounts, blockEvents, and zero-block resets (reset thresholds) and code related to the "monitor" priorities to better ensure they are handled correctly and better documented.** +This may fix a few obscure bugs, but not 100% sure if they have been encountered. +This also unbundles some of the functions so they are not hidden so deeply... this makes the code much easier to read and to know what's happening. + + +* **Setup a function to check if a BlockBreakPriority is considered a monitor level priority, which is useful when adding more non-block breaking priorities.** + + +* **Expand the comments to better explain the roles of MONITOR and BLOCKEVENTS priorities.** + + +* **Fix a problem with MONITOR and BLOCKEVENTS priorities where they were failing to process the event if the block was broke, of which should be permitted.** + + +* **Added RevEnchant's events to the special condition of not being able to identify the original block that was broken.** + + +* **Doc updates. Update info on Essentials Economy bypassing Vault and adding RevEnchants to the list of supported enchantment plugins have been added.** + + +* **Added support for RevEnchants ExplosiveEvent and JackHammerEvent.** + + +* **Adjustments to improve readability of the '/mines info' command.** + + +* **Simplify a few mine related commands to use the permission mines.set.** + + +* **Change command from '/mines set skipReset` to `/mines set resetSkip` to try to better align similar commands.** +Improved the help for the command too. Added support for '*all*' mines too. + + +**v3.3.0-alpha.13h2 2023-01-11** + + +* **Prison placeholder bug fix: the placeholder cache was causing placeholders to be rejected and locked out under certain conditions which were being triggered by new players joining the server for the first time.** +The cache was fixed by better identifying what constitutes a failed placeholder identifier. Enhanced the stats report to include fails too, which can be useful in finding internal errors with specific placeholders. + + +**v3.3.0-alpha.13h 2023-01-07** + + +* **Update bstats... will have to update the reports on the bstats page too.*** + + +* **Updated the language files to replace a bad text message which was missing.** + + +* **Placeholders bug fix: prison_top_rank_balance_* placeholders were fixed both in enabling processing for these placeholders, and also enabling the sequence.** + + +* **Placeholder Cache: Provide a way to clear the cache of all entries or just the invalid entries.** +This helps to debug potential issues since it does not require restarting the server to force a reassignment of mapped placeholderKeys. + + +* **Bug fix: Fixed an issue with the top-n player's balance not being hooked up to the return value of the function that was retrieving it.** + + +* **Issue with vault not working: Fixed a problem where prison was not able to communicate with an older version of vault** (spigot 1.12.2) while prison test servers could not duplicate the issue. +The allows an admin to configure their server to disable the use of vault when using the essentialsEconomy, SaneEconomy, or GemsEconomy. This will not work for any other economy. +Since vault was the problem, bypassing vault allows prison to communicate directly with the selected economies, which fixes the problem. + + +* **Prison Command Handler: Tab Completer:** Lockout players from the commands that have been excluded from players based upon perms. Such commands are now excluded from the suggested commands when the player is using the tab-complete. + + +* **Mines GUI bug fixes:** +Fixes an issue with the command `/mines tp` which was setup to test an alias on a test server, but was not changed back to the correct command. +Fixes the proper display of the linked rank to the mine. It was showing the "object" which was dumping more than just the rank tag to the GUI's lore. It now shows just the rank tag. + + +* **Added the tracking of command run times to the `/prison support cmdStats`.** + + +* **Update various libraries used in the gradle build:** +placeholderApi: v2.10.9 to v2.11.2 +XSeries: v9.0.0 to v9.2.0 +item-nbt-api: v2.10.0 to v2.11.1 +removal of mvdw from the gradle build since it was removed from prison a few months ago + + +* **Added a prison backup save command (renamed the original prison backup) and added a prison backup logs command that shows all entries in the backup log file.** +The contents of the backup log file has been added to the /prison support submit version command too. + + +* **Fixed the prison command stats to show the correct number of commands listed.** + + +* **Fix the use of `{br}` when using `/prison support submit version` so that it is now treated as `\n`. +Added to the `/prison support submit version` all listeners and the command stats too.** + + +* **Added a new command `/prison support cmdStats` which shows some basic stats on command usage.**8 + + +* **v3.3.0-alpha.13g 2022-12-28** + + +* **Added Finnish translations to prison!** +Thearex12 contributed a number of Finnish translations for prison in the following +modules: core (partial), mines, and sellall. More updates are in progress. +If anyone else would like to contribute another translation, please ping me, +RoyalBlueRanger, on our discord server. It can be a complete translation, or +a partial. Thanks! + + +* **There is a growing problem with the use of % symbols being processed multiple times with the Java String.format() which results in format escape error.** +First, the use of Output is new setup to handle it's own custom version of String.formatIO that will take any remaining percent symbol and encode it so it does not cause errors anymore, then right before passing it to bukkit, it will convert it back. This allows it to pass through as many String.format() functions as needed without resulting in to any problems. +The other fix, which is probably more significant, is that the Output functions no longer tries to run all messages through String.format() if there are no parameters to apply. This was causing the most issues. +To properly ensure the more complex message handling works correctly, the use of Output.stringFormat(() should be use to enable to the encoding of the percent symbols. + + +* **Fixed a typo in the config.yml that covered what the default values were for the includeCmdAltPerms and includeCmdPerms settings.** + + +* **Player GUI for mines and ranks was changed to include within the NBT codes, and enabled the mines TP command to be set in the NBT command tag.** +This will allow the NBT handler within the SpigotGUIMenuTools.processGUIPage(), of which it would just run the supplied command. This bypasses the need of using special code to extract the mine name or rank name to reconstruct a command. In short, this allows the TP On Click action to be self contained without the need for special handlers. +This is a fix for the fully customizable ranks and mines GUI menus for the players, where the mine name on lore line 1 was eliminated, and hence the old way was unable to identify what mine should initiate the tp event. But having the plain mine name on line one resulted in multiple redundancies of the mine's name, along with the mine's tag and the item's header. + + +* **New Feature: command lockout:** Updated to add debugging information to identify why a command is rejected for a player through logging in the console when prison is in debug mode. + + +* **New Feature: command lockout:** expanded to get this to work for commands, help listings, and aliases. There is now a setting where if enabled, it will expand the lockout from a command to all aliases of that command. Also on each command, it will will allow enabling (enabled by default) if either the command parms or parmAlts are used to exclude a player from a command. + + +* **New feature: command lockout for users based upon perms set in the config.yml.** +This is the first stage of getting this setup, where it locks out the running of a command. +Need to lockout the help next, which is what generates the command lists. + + +* **Enhancements to the player's gui for ranks and mines so it's less hard coded and now with more options.** +Parts of the GuiConfig.yml file will need to be removed so the new content can be generated the next time the gui configs are loaded. + + +* **Eliminate the stack trace because it makes it appear as if there is a non-handled error in prison. The error is already being shown in more detail.** + + +* **Sellall sell can now be ran from a command or the console by specifying the player's name.** +The player must be online for this work. An offline player cannot have their inventory modified or sold. + + +* **Chinese Translation Added!** +Thanks to M1032 on github #240, prison now has full Simplified Chinese translations! To use this translation, set the language code to zh-CH. + + +* **cleaned up the enchantment names** + + +* **Enabled more detailed logging when block break events are being ignored by the auto features.** +Mostly related to either the player not holding a pickaxe, or the block has already been broke, or exploded. +Now also showing information on what the player is holding, which will help identify why a block break event is behaving the way it is. + + +* **Set version to v3.3.0-alpha.13f - 2022-12-12** + + +* **Setup a static version of DecimalFormat which is needed to be used within all static functions.** If the DecimalFormatSymbols variable is set by a static function, then it will be replaced at the first chance by a non-static call. The static usage, if not set first by the non--static calls, cannot access the config.yml settings. This really is not a problem, since it would only be through unit tests when the gradle build is being processed that will need the alternative settings. + + +* **Setup the control over number formatting by using Prison as the single source of constructing a DecimalFormat object.** +This is done through manually setting the DecimalFormatSymbols to use en_US. It has also been enabled in config.yml to allow setting the language code that is used, to any value the admin may wish to use. It's a problem when en_US is not used, but someone may have a specific reason not to use en_US. Mostly the primary trouble is related to Minecraft not being able to properly display NBSP unicode characters. + + +* **Mine suffocation can now be enabled so if you turn off teleportation, then the players can now die.** + + +* **Mine reset teleportation can now be controlled within the config.yml file.** + +* **Prison API: Add support for direct prison placeholder support.** +Two new functions: one translates only one prison placeholder. The other function takes full text message and will translate multiple prison placeholders if they are wrapped in placeholder escape characters. + + +* **AutoFeatures: add failure reason when prison is unable to successfully process a block break event due to zero drops.** + + +**3.3.0-alpha.13e 2022-11-16** + + +* **New feature: Prestiges placeholder name and tag now can be assigned to a non-blank space for players that do not have a prestige rank.** +This applies to the base placeholders: prison_rank, prison_rank_laddername, prison_rank_tag, and prison_rank_tag_laddername. + + +* **Add the ability to format the percentage of prison_rankup_cost_percent with the NFormat placeholder attribute.** + + +***Fix issue with world not being removed, or replaced when the mine is converted to a virtual mine, or when the mine is moved to another world.** +The problem would be the config settings for the mine would save correctly, but upon the server restart, it would revert to the old world. The problem was with the non-saved world field not being reset correctly. This fixes the issue correctly so it's should work properly under all situations. + + +**3.3.0-alpha.13d 2022-11-02** +NOTE: Changes to PrisonBlock structures have been stashed and are not included in this alpha.13d release. + + +* **Added some mine info to the `/prison version command.*** + + +* **Mine Bombs bug fix: Was using a function that was incompatible with bukkit 1.8.8 and this fixes that issue.** +Using a prison compatibility function to provide the compatibility. +Added more information on why mine bombs are not working when prison is in debug mode. + + +**3.3.0-alpha.13c 2022-10-17** +NOTE: Changes to PrisonBlock structures have been stashed and are not included in this alpha.13c release. + + +* **Small updates to help prepare for the internal change to how PrisonBlocks are structured.** + + +* **Bug: Found a major bug in calculating a vector's length since x should have been squared, but instead it was multiplied by y.** +The use of vectors is limited within Prison, but when used, this could cause issues. + + +* **If inspection of other plugin's jars fail, then just ignore this issue and continue on processing.** + + +* **New prison backpacks: More work on getting them setup for testing the BackpackCache.** +Adding hooks to load from the old prison backpacks. + + +* **Fixed an issue with MINEPLAYER placeholders which resulted in false fast-fails when players would leave a mine.** +Once a placeholder would fail, even if it was working before, it would be impossible to reenable the placeholder value from being evaluated in the future due to the nature and purpose of the fast-fail. +The MINEPLAYER placeholders actually has three states: invalid placeholder (any invalid placeholder string), valid with mine object, and valid without mine object. So the valid without mine object was getting translated as invalid placeholder. +The fix was to allow even valid without mines to be processed by their respective block of code, but within each block of code had to add if-not-null checks to prevent other null pointer failures. +**Note:** This issue may have been related to other recent placeholder issues that have not been able to be resolved. + + +* **For some of the gui commands, like `/gui ranks`, `/gui prestiges`, and `/gui mines` the button now closes the gui instead of trying to run the command `/gui`.** + + +* **Add config settings to control the gui rankup buttons.** + + +* **Update many gui messages to use the newer message handler so the old deprecated functions can be removed eventually.** +There are still many more to do, but this covers a good start. + + +* **Move the mine bombs cooldown message to the spigot language files.** + + +* **Removed support for MVdWPlaceholder plugin.** +It generates way too many entries in the log, and there is zero support for it from the providers. +It's also unneeded since PlaceholderAPI works perfectly fine with it, so it's 100% pointless. + + +* **More refactoring of the old backpacks to get rid of bad code to make it easier to integrate in to a newer backpack framework.** +No behavioral changes should have occurred with this commit, and the prior commit too. + + +* **Refactor Prison's old backpacks to reduce duplicate code to prepare for use of the BackpackCache.** + + +* **Changed the command `/mines set notification` to work with both disable and disabled.** + + +* **Initial setup of BackpackCache code. Not test. Not hooked up yet to anything. But the cache should be functional.** + + +* **v3.3.0-alpha.13b 2022-09-07** + + +* **Prestige: Rewrote the prestige commands to move them from the generic spigot module to the ranks module where it should belong with the other rank related commands.** +All rank and prestige related logic was removed from the GUI. The new /prestige command was created in the ranks module. It now performs a precheck to ensure the player is able to prestige, and it now reflects the correct configurations as far as showing the player if their default ranks and monies will be reset. Confirmations were also fixed, where they were not working with the prior chat confirmation. The new gui uses a simplified process where it is given the default settings for the displayed lore. The only behavior the gui now has, is that if the player clicks on confirm, then it will rerun the prestige command with "confirm" added so the confirmation is bypassed. +This is working far better now. + + +* **Fixes issues with /rankupmax.** +Confirmation on prestiging does not work. + + +* **Modified a number of mines commands to add a global *all* feature to allow easier management of applying commands to more than one name at a time.** + + +* **Fix an issue with leading spaces in prison commands, especially right after using semi-colons to chain multiple commands.** + + +* **v3.3.0-alpha.13a 2022-09-01** + + +* **Cleaned up the /rankupmax command to improve on the messaging so it's not as spammy.** +Improvements with the /rankupmax prestiges command too. + + +* **Redone how the command `/rankupmax` works.** +The command `/rankupmax` and `/rankupmax default` has not changed, but has been improved to supply the correct next rank using the newer getNextRank function to ensure consistency. +The command `/rankupmax prestiges` used to only provide the same behavior as `/prestige` and `/rankup prestiges`. The new behavior is that `/rankupmax prestiges` will first perform `/rankupmax` then it will try `/rankup prestiges`. If completes successfully, then it will repeat both the rankupmax and prestiges, and etc. + + +* **Fixed an issue with the RankPlayer.getNextPlayerRank() which was not returning the first prestige rank if at end of default and no prestiges.** +Had to hook in to the LadderManager, routing through Platform, to get the presetiges ladder to pull the first prestige rank. +Adding this capability expands the functional usefulness of this function greatly. Now if this function returns a null, then it means the player is at the last possible rank. + + +* **Add to the platform the ability to get a specific RankLadder.** + + +* **New feature: Auto Forced Rankup. When using autosell, it will auto rankup the player when they have enough money.** +This includes both normal /rankup and /prestige. +This configuration setting is set within config.yml in prison-mines.forced-auto-rankups: true. + + +* **Enable access to prior mines, or prevent access to prior mines, based upon the player's rank.** +See `prison-mines.access-to-prior-mines` in config.yml + + +* **New feature for Prestige: Force a sellall before processing the prestige.** +This prevents the player from stashing a ton of high-value blocks in their inventory before prestiging. +This will not prevent the player from stashing blocks elsewhere. + + +**3.3.0-alpha.13 2022-08-25** + +Highlights of some of the changes included in this alpha.13 release. Please see the change logs for all details. + + +* Added a new tool: `mines tp list` which will show a player all of the mines they have access to. They can also click on a listed mine to generate the TP command. This command can also be ran from the console to inspect what players have access to. +* Fixed a recently introduced bug where if the server starts up, but someone has no ranks, it was not able to properly assign them their first default rank. It was leading to circular references. +* Fixed an issue with color codes not being translated correctly with placeholderAPI. +* Prison has a rank cost multiplier where ranks on different ladders can increase, or decrease, the cost of all ranks the player buys. So when they prestige, it makes ranks A-Z cost more each time. What's new is that now you can control which ladders these rank cost multipliers are applied to, such as not on prestiges, but only on default. +* Fixed calculations of the placeholder `prison_rank__player_cost_rankname`. It was not fully working with every possible rank on every possible ladder. Now it works correctly if trying to get the player's cost for even many prestige ranks out (it includes cals for all A-Z mines at multiple passes). +* Mine bombs: Changed to only allow mine bombs to be setoff withn mines the player has access to. Fixed an issue with color codes within the mine bomb's tags. +* Fixes issues with NBT, color codes with prison broadcast commands. +* Rewrote topN for better performance: `/topn`. Older players are archived within topN and can be queried: `/topn archive`. +* Update ladder details on a few commands. +* Update XSeries from v8.8.0 to v9.0.0 so prison now supports 1.19.x blocks. +* Bug fixes with first join events. Bug fix with a few guis. +* CMI update: If CMI is detected at startup, and delayed startup is not enabled, prison will go in a simple delayed startup mode to allow CMI a chance to enable it's economy through vault. This reduces the learning curve with CMI users. +* New feature: Prison will now make an auto backup of all files in it's directory when it detects a change in version. Can manually backup too. The backup stores temp files then removes them from the server, this helps keep the server clean. +* Update bstats: Gained control of the account and started to add useful custom reports to help zero in on what we need to help support. +* More work on block converts. Will be added in the next alpha releases. +* Bug fixes: mines gui fixes for virtual mines. Sellall bug fixes. Placeholders fixes. + + + + +* **Minor addition to bstats.** + + +* **Player Mine GUI had the wrong calculation for volume which also threw off blocks remaining and percent remaining.** +The calculation for volume was using the surface area and not the total number of blocks. + + +**v3.3.0-alpha.12L 2022-08-25** + + +* **Updates to the bstats....** + + +* **New placeholders: `prison_rank__linked_mine_tag_rankname` and alias `prison_r_lmt_rankname`.** +Similar to `prison_rank__linked_mine_rankname` but uses the mine's tag instead of the mine's name. + + +* **Mine TP list: use mine tags and clickable mines to teleport to them.** + + +* **Mines TP list. Added a new options to mines tp command to list all mines that the player actually has access to.** +Not finished with it... will add clickable links to them when in game. + + +* **There was an unused updated tool in prison. It's against my policy to auto update this plugin, which would need to be consented to anyway, but I feel that admins need to be in full control of updates and know what is included in the updates. There was identified a potential exploit called zip-slip-vulnerability that could hijack a server if malicious zip is extracted. Prison never used this tool, so it's been fully disabled with no intention of reenabling. It may be deleted in the near future.** + + +* **TopN bug fix: If a player was in an archived state, they were not being moved to active when they would login.** + + +* **If the player is holding the mine bomb in their off hand, then remove the inventory from their off hand.** + + +* **v3.3.0-alpha.12k** + + +* **Fixed an issue when starting the server an no ranks exist. Also fixes an issue when starting the server an a player has no rank.** +Was using a mix of really old code, and the latest code, which caused a conflict since neither was doing what it was really supposed to. + + +* **Added the custom bstats report for Prison Vault Plugins.** +This reports all plugins that have been integrated through Vault. This report does not impact any other plugins report. This is segmented by integration type. + + +* **Fixed bug when server starts up when no player ranks exist.** +It will now bypass the player validation until ranks have been configured. + + +* **v3.3.0-alpha.12j 2022-08-21** + + +* **Update bstats to remove old custom reports that are not wanted/needed anymore.** +Added 6 new placeholder reports that classifies placeholders ini various categories related to how they are used within prison. Any placeholder that appears in these lists, will not be included in the generic 4-category placeholder lists. +Added a few more simple pie charts to cover a lot of the details on ranks, ladders, and players. Simple is better so you can just glance at all of them, without having to drill down on each one. + + +* **v3.3.0-alpha.12i 2022-09-19** + + +* **TopN players - fixed an issue where topN was being processed before the offline players were validated and fixed.** +There was an issue with processing an invalid player that did not have a default rank. + + +* **v3.3.0-alpha.12h 2022-08-19** + + +* **Rankup costs: Minor clean up of existing code. Using the calculateTargetPlayerRank function within the RankPlayer object.** + + +* **PAPI Placeholders: Force color code translations on all resulting placeholders.** +There were a few issues where placeholder color codes were not being properly translated. This was not consistent with everyone. Not sure why it was working for most. +These changes are more in line with how chat handlers and MVdW placeholders works. + + +* **Ladder: apply rank cost multiplier to a ladder or not.** +This new feature enables you to disable all rank cost multipliers for a specific ladder. Normally that rank cost multiplier applies to all ladders, but now you can suppress it. It's for the whole ladder, and not on a per rank basis. + + +* **Fixed an issue with calculating the player's rank cost when they already on the presetiges ladder and calculating the higher prestige ranks.** +Appears as if this becomes an issue when at the last rank on the default ladder. + + +* **v3.3.0-alpha12g 2022-08-14** + + +* **Fxing of the calculations of the placeholder prison_rank__player_cost_rankname and related placeholders.** +The original implementation did not take in to consideration the prestige ranks in relation to the default rank. +The improvements in this calculation now generates a list of all ranks between the current rank and the target rank. So if a few prestige ranks out from the player's current prestige rank will result in calculating every rank in between including multiple passes through all default ranks. So if there are 26 default ranks, and the player is at rank A with no prestiges, then to calculate rank P4 would include the following ranks: +b --> z + p1 + a --> z + p2 + a --> z + p3 + a --> z + p4. +This results in a total of 107 ranks that must be collected, then the player's cost for each rank will have to be calculated. Then all of these must be added together to get the player's cost on rank P4. +This calculation has to be performed for each rank in it's entirety +Warning: this calculation on high prestige ranks will be a performance issue. If this becomes a problem on any particular server, then the only recommendation that can be provided is not to use any of the prison_rank__player_cost placeholders. + + +* **TopN : a few more adjustments to fix a few issues with duplicates and also with using values from within the topN to include in the report to help minimize the need to recalculate everything especially with archived entries.** + + +* **Mine bombs: Fixed an issue with the mine bomb names not always working with color codes.** +Honestly the wrong function was being used so how it even worked I don't know. lol + + +* **New topN functionality: far better performance, with regular updates.** +TopN now is a singleton and is self contained. When the singleton is instantiated, it then loads and setup the prisonTopN.json file on the first run. 30 seconds after the initial load, it then hits all players to load their balances in an async thread. +The command /ranks topn, or just /topn has new parameter: "archived". Any player who has not been online for more than 90 days will be marked as archived. The archived option will show just the archived players. +Setup new parameters within config.yml to control the topn behavior with the async task. + + +* **v3.3.0-alpha.12f 2022-08-08 ** (forgot to commit when made this version) + + +* **Mine Bombs: Only allow bombs to be placed when within a mine that the player has access to.** +This will help prevent wasted bombs. + + +* **Fixed an issue with nbt items not having a value for toString().** + + +* **Encode color codes for the prison utils broadcast command.** + + +* **Added an "invalid player name" message to the rankup commands.** +Also added missing messages to the zh_TW.properties file. + + +* **BlockEvents were changed to auto display the existing rows so it's easier for the end user to know which row to select.** +All they need to do is to enter the mine's name, then press enter to submit the command, and then the existing rows details will be shown. Then the user can select the row and complete the command. +Updated docs on block events. + + +* **BlockEvents were changed to auto display the existing rows so it's easier for the end user to know which row to select.** +All they need to do is to enter the mine's name, then press enter to submit the command, and then the existing rows details will be shown. Then the user can select the row and complete the command. + + +* **minor updates for disabled mine reset times. No functional changes were made.** + + +* **Fixed a potential NPE with giving the players overflow blocks, but not sure what the exact cause was, but looked like there was an issue with mapping to a spigot item stack.** + + + **CMI delayed startup: Added new feature to try to auto enable Prison's delayed startup if CMI is detected as an active plugin, and if the delayed startup is disabled within the config.yml.** +This is to help get more CMI users up and running without more effort, but yet still provide the ability to customize how it is triggered. +If CMI is active, there is NO WAY to disable a delayed startup check.* + +* **Added the the option for playerName to the `/rankup` command so the command can be scripted and ran from the console.** + + +* **There was another issue with using `/gui` related to no ladders being loaded.** +This fixes that problem, and it appears like the issue was caused by plugman messing things up. This does not "solve" the problem with ladders not being loaded, but prevents the NPE from happening. + + +* **There was an issue with `/prison reload gui` causing a NPE.** + + +* **Fixed the `/ranks topn` command (`/topn`) to sort the list of players before printing the list.** +The list was being set a server startup time, and if someone would rankup or prestige, it was not reflecting their new position. The list is also now sorted after each rankup. Sorting should be a low cost operation since the list used never is regenerated so the changes made during sorting is minimal at best. + + +* **Added the ability to control the prefix spaces on the unit names.** +NOTE: may need to enable the use of the `core_text__time_units_short` since the long units are not being used. May need to create another placeholder for short/long. It used to be short, so may need to use long with the new placeholder and convert the calcs to the short as the default. +This was requested by PassBL. + + +* **v3.3.0-alpha.12e** + + +* **Fixed issue rank null issues when showing ladder details.** + + +* **Prison backups: Fixed an issue with folders not existing when running the backups the first time.** + + +* **v3.3.0-alpha.12d 2022-07-25** + + +* **Added more information on ladder listing to show name, number of ranks, and rank cost multiplier.** + + +* **bStats update: Added a new bstats custom chart for auto features.** + + +* **Update some docs. Added docs for Prison Backups** +[Prison Backup Document](prison_docs_050_Prison_backups.md) + + +* **Upgrade XSeries from v8.8.0 to v9.0.0** + + +* **Fixed issue with prison version check triggering a backup upon startup.** +It was always bypassing the previous version check, so it was always creating another backup. + + +* **Update bstats by moving to its own class in its own package.** +Added 4 new custom charts to split the plugins in to 4 parts. + + +* **Fixed a few issues with the ranks gui where they were using the wrong message key (placeholder).** + + +* **Prison v3.3.0-alpha.12c** + + + +* **Prison bstats: setup 4 new bstats charts for prison. May change a few charts or add new ones in the near future.** +Got control over the prison bstats so can now add custom stats. + + +* **Prison backups: Created a Prison/backups/versions.log file which gets logs when a new prison version is detected on startup, which also performs a backup.** +All backups are also logged in the versions.log file too. + + +* **v3.3.0-alpha.12b** +- Added the fix for the placeholders. See next note. + + +* **Fixed an issue with placeholders not be properly evaluated; there were 3 sections and they were combined in to one so it would not bypass any.** + + +* **Possible bug fix with first join: it appears like it was inconsistant with running the rank commands. Fixed by rewriting how the first join event is handled.** + + + +* **Prison backups: Added new features where it is generating a stats file in the root of the zip file which contains all of the "prison support submit" items.** +This is just about ready, but lacking support for auto backups when prison versions change, or job submission to run auto backups at regular intervals. + + +* **Setup a prison backup command that will backup all files within the prison plugin folder.** +When finished, it will delete all temp files since they have been included in the backup. +The new command is `/prison support backup help`. + + +* **v3.3.0-alpha.12a** + + +* **Added a new set of intelligent placeholders: these show the tags for the default ladder and prestige ladder, for the "next" rank but are linked together.** +They only apply to the default ladder and the prestige ladders. The tags are only shown if the player has that rank, or if that will become their next rank. +These ONLY show the tags that will be appropriate when the next rank up. So if the can still rankup on the default ladder, then only the default rank shows the next ranks tag. If they are at the end of the default rank, then it will show the next rank on the prestiges ladder; if they do not have a rank there currently, then it will show the next prestige rank with the default rank showing the first rank on that ladder. + + +* **When the command handler starts up, it now logs the pluigin's root command and the command prefix which is used if there are duplicate commands found during bukkit command registration.** + + +* **Bug fix: Placeholders search was missing the assignment of the placeholderKey, which is what would like the search results on the raw placeholders, with the actual data that is tied back to the player.** +In otherwords, without the PlaceholderKey it was not possible to extract the player's data to be displayed within the command: /prison placeholders search. + + +* **Added constants for the default and prestiges ladder name so it does not have to be duplicated all over the place, which can lead to bugs with typos.** + + +* **Sellall bug fix: There wasn't a common point of refernce to check if sellall is enabled. Many locations were directly checking config.yml, but the new setting has been moved to the modules.yml file. ** +If config.yml has sellall enabled in there, it will be used as a secondary setting if the sellall setting in modules.yml is not defined or set to false. Eventually the config.yml setting will be removed. + + +* **Found that bStats was erroring out with the servers hitting the rate limit so this makes a few adjustments to try to get prison to work with bstats.** +Basically plugins that load last will be unable to report their stats since every single plugin that is using bstats submits on it's own, and therefore it quickly reaches the limits. + + +* **BlockConverters: More changes to block converters.** +Added defaults for auto blocking, and for auto features with support for *all* blocks. + + +* **Bug fix: mines gui was not able to handle virtual mines with the internal placeholders. +This bug fix was included with the deployment of alpha.12 to spigotmc.org. + + + +* **Pull Request from release.branch.v3.3.0-alpha.12 to Master - 2022-06-25** + + +This represents about six months of a lot of work with many bug fixes, performance improvements, and new features that have been introduced. The last two alphas were not pulled back to main, but they were released, This PR will preserve the released alpha as it has been published. + +Also, this helps to ensure that this work will not be lost in the event the bleeding branch is lost/removed. Hopefully it won't be, but a lot of work has gone in to it and it will be impossible to recreate the current state of the alpha release. + +This version, v3.3.0-alpha.12, has 300 commits and 323 changed files. The list of actual changes since v3.2.11 is substantial and the change log should be referenced. + +Highlights of some of the changes include (a sparse list): + +* new block model - full support for CustomItems custom blocks - updated XSeries which mean prison supports Spigot 1.19. +* major improvements to auto features - streamlined and new code - higher performance - many bugs eliminated - now supports drop canceling to make prison more compatible with other plugins +* better multi-language support - supports UTF-8 +* Improved rankup - rankup commands are now ran in batch and will not lag the server if players spam it +* rewrite of the async mine resets - next to impossible for mine resets to cause lag - Uses a new intelligence design that will throttle placing blocks as the server load increases, which makes it next to impossible for it to cause lag. +* Enhanced debugging tools - if a server owner is having issues, prison has more useful tools and logging to better identify where the issues are - new areas are not able to log details when in debug mode - debug mode now has a "count down timer" where if debug mode is 8enabled like /prison debug 10 then it will only allow 10 debug messages to print, then it will turn off debug mode automatically. This is very useful on very heavy servers when a lot of players are active... it prevents massive flooding of the console. +* Major rewrite of the placeholder code that identifies which placeholder raw text is tied to, so it can then retrieve and process the data. - Pre-cache that provides mapping to raw text, so once it is mapped, it can prevent the expensive costs of finding the correct placeholder - Added the beginning of tracking stats (through the pre-cache0 and will be adding an actual placeholder cache in the near future. +* Mine Bombs - fixes and enhancements +* Starting to create a new sellall module that will support multiple shops and custom blocks (not just XMaterial names) +* Block Converters - Will allow full customization on all block specific things within auto features - will eliminate all hard coded block +* Started to add NBT support. - Used in mine bombs - Starting to use in GUI's to simplify the complexity of hooking actions up with the menu items. +* Added rank scores and top-n players - Rank score is a fair way to score players within a rank. It's currently the percentage of money they have to rank up (0 to 100 percent), but once they cross the 100% threshold, then 10% of the excess subtracts from their rank score. This prevents camping at levels. +* There is more stuff, some major, a bunch of minor, and many bug fixes along the way. + + + + + +* **v3.3.0-alpha.12 2022-06-25** + + + +* **v3.3.0-alpha.11k 2022-06-20** +Plus luckperms doc update. + + +* **Mine resets: Fixed an issue when dealing with zero-block resets on a very small mine, such as a one block mine in that the 5 second delay was preventing from rapid resets.** +Bypass both 5 second cooldown on resets and blockmatching when 25 blocks or less for the mine size. +With running resets in async mode, with rapid resets for a one-block mine, the handling of the block breaks can occur out of order, which will trigger the block mismatch. + + +* **Fix issue: On the creation of a new mine, it would reset the mine a number of times. This fixes the problem by only allowing one reset every 5 seconds at the soonest.** + + + +* **Placeholder fix: The PAPI placeholder integrations should not be prefixing raw text with "prison_"; that is the task for PlaceholderIdentifier.** + + +* **minor items changed with the GUIs... no functional changes.** + + +* **Update a number of docs...** + + +* **Fixed an issue where if you try to use a % on a number it's causing String format errors.** +This now strips off % and $ if they are used. + + +* **Update Docs: LuckPerms groups and tracks... added images and fixes a few minor things too.** + + +* **Update some of the docs on setting up luckperms and tracks.** + + +* **v3.3.0-alpha.11j** + + +* **Since the chat event is handled within the spigot module, and since ranks and mines would just duplicate the processing since they both will hit the SpigotPlaceholder class, it made sense to handle the chat event directly within the spigot module.** + + +* **Updates to the prison placeholder handler. This fixes a bug with chat messages return a null value.** +These changes also allows the pre-cache to track invalid placeholders now, so it can fast-fail them so it does not have to waste CPU time trying to look up which placeholder key they are tied to. + + +* **v3.3.0-alpha.11i** +Getting ready to release alpha.12. + + +* **Placeholder stats: A new feature that is tracking usage counts with placeholders.** +This is not a placeholder cache that caches the results, but it caches the placeholder that is associated with text placeholder. The stats currently only tracks the total number of hits, and the average run time to calculate the placeholder. +The pre-cache will reduce some overhead costs. This also provides the framework to hooking up a formal placeholder cache. + + +* **Placeholders: changed the two top_player line placeholders that are the headings** + since they originally had _nnn_ pattern that is getting messed up in some settings. So removal of the nnn helped to getting it working. + + +* **GUI MInes: Update support for custom lore support within the gui configs.** + + +* **Update XSeries from v8.7.1 to v8.8.0 to better support the newest blocks.** + + +* **Updated item-nbt-api-plugin from v2.9.2 to v2.10.0.** + + +* **v3.3.0-alpha.11h 2022-06-14** + + +* **Prison Placeholders: General clean up of obsolete code.** +Since the new placeholder system is working well with the new class PlaceholderIdentifier, obsolete code that was commented out has been removed. +The obsolete class that used to be the key component to identifying placeholders was PlaceholderResults and is no longer used anywhere. It's core components were moved to PlaceholderIdentifier and therefore all references to this obsolete class has been eliminated. +At this time, PlaceholderResults has not been deleted, but will be at some future time. + + +* **Prison Placeholders: Major rewrite the handling of placeholders.** +Prison's placeholder handling was completely rewritten to better handle the matching of a placeholder text with the actual placeholder objects. Over the last few years, many new features were added to prison's placeholders, but the way they were implemented were through patching existing code. This rewrite starts from scratch on how placeholder are decoded. Placeholders are now only decoded once instead of being decoded when attempting to match each internal placeholder. The results are significant performance improvements and eliminates a lot of redundant code. Some new features were add, such as supporting more than one placeholder attribute at a time. Also it streamlines how parameters and data is passed from the outer most layers of prison to where the placeholders are calculated. + +Another major benefit of this rewrite, beside reduction of code complexity and performance improvements, is that it opens the door to being able to implement an internal placeholder cache. Some plugins request placeholder data once per tick, or 20 times per second. Multiply that by 50 online players, and you got prison performing the same calculation 1000 times per second. Caching could help reduce that to only one calculation per second (assuming a cache time to live value of 1 second. Caching will not always be so simple, or possible, or every placeholder. Player-based placeholders can't be cached like static mine placeholders (mine names and mine tags as an example). + + +* **Add support for Portuguese.** + + +* **BlockConverters: fix issue when block converters are not active.** + + +**v3.3.0-alpha.11g - 2022-06-11** + + +* **Disable the gui for autofeatures configs. They are so out of date, they were causing problems.** +Autofeatures should be manually edited. + + +* **Fix a problem when BlockConverters are disabled, and doing a reload on auto features, it's not able to find that config file so its throwing an exception.** + + +* **The build was failing intermittently on the continual integration (CI)** +pertaining to the item-nbt-api-plugin, so an entry to added to "lock it in" to the correct path within the mavenrepository.com repo. +This should prevent the resource from being paired with the wrong repo. + + +* **There is a situation when checking for new updates to the language files, that it needs to write the new file, but the old one has not been archived.** +This now checks to make sure the old one has been renamed, and if it hasn't, then it will rename it. + + +* **Added an entry for the sellall module in the modules.yml file.** +Code has been setup to check, with a default fall-back on to the sellall settings within config.yml file. The entry in config.yml has been commented out. +Either will work, but the setting within modules.yml will take priority. + + +* **Update XSeries to v8.7.1 from v8.6.2.** +Note that this does not add any of the newer 1.19 blocks or items. + + +* **GUI: Fixed some issues with the gui and admin perms. Added some admin perms to a few gui commands to lock them down.** +Found a serious issue with non-admins being able to edit rank costs and sellall item costs. The GUIs were not locked down and if the players knew the commands, they could edit the costs. + + +* **v3.3.0-alpha.11f 2022-06-06** + + +* **BlockConverters: minor changes.** + + +* **Bug fix: Backpacks were not working properly with just ".save()" but had to add ".setChanged()" too, otherwise minepacks will not actually save the status of the backpacks.** + + +* **BlockConverters: rename targets to outputs.** + + +* **BlockConversions: hooked up the code to not only filter and return the blockConversions for the player and the block, but to also return the item stacks from the results.** +This is just about ready to be used in the code. + + +* **Romanian Locale language files were placed in the wrong location.** +Oreoezi provide two new language files for the Romanian Locale, but they were placed in the wrong location. +They were added to "prison-core/out/production/resources/lang/core/" and ".../mines/". For them to actually +work correctly, without being deleted, need to be placed within the following path: +"prison-core/src/main/resources/lang/core/" and "prison-core/src/main/resources/lang/mines". +These should now be usable. Also the LocaleManager now has alternatives setup to default to en_US; future +alternative languages can be added in the future. + + +* **BlockConverters: add some validators to the BlockConverters.** +Reports various issues, fixes non-lowercase source block names, and also disables invalid settings. + + +* **BlockConverters: Adjusting around how they are setup, and how they are generated.** +BlockConverters are now in their own config file: blockConvertersConfig.json. +They are no longer being stacked/placed in the autoFeaturesConfig.yml file, so all the conversion code is no longer required. With it being json, it now can reflect the java classes without any special considerations on the conversion process. + + +* **BlockConverters: More work on these settings.** +Setting up to work with AutoFeaturesConfig.yml, but having second thoughts about adding these configs to that file since it will complicate the config details. + + +* **Fixed a bug on the smelting of coal_ore which was yielding 10 times too much, but this was never seen since a silk touch pickaxe would have to been used.** + + +* **Placeholder fix for `prison_mines_blocks_mined_minename` since it was not being incremented after the fixing of the autopickup=false and handle normal drops = true.** +Also found that the calculated field for the mine's total blocks mined was not being recalculated after load the mines from their save files. This now is working properly. + + +* **Major exploit fix: sellall was not indicating that the inventory was changed within the Minepacks backpacks,** +and therefore players were able to sellall of their inventory, logoff, and then when they log back on, it will be restored. +Now, all inventory changes are forcing a save for the backpacks. + + +* **Fixed an incorrect mapping to a message: auto features tool is worn out.** + + +* **v3.3.0-alpha.11e 2022-05-23** + + +* **Bug fix: Fixed an issue with sellall when the module sellall is not defined but sellall is enabled in the config.yml file.** + + +* **Bug fix: Minepacks has a new function in their API to force backpack changes to be saved.** +Before it could only be marked as changed, which was not enough to get it to save in all situations. Prison is now calling "save()" to ensure its behaving better now. +NOTE: releasing this fix with alpha.11d even though it has been added after being set to 11d. + + +* **Prison v3.3.0-alpha.11d 2022-05-22** + + +* **GUI messages: a few more updates and corrections** + + +* **GUI: More fixes to the gui messages... including moving all of the new gui specific messages out of prison-sellall module to the prison-core module so they will still be accessible if the prison-sellall module is disabled.** + + +* **GUI cleaned up by eliminating so many excessive uses of translating amp color codes to the native color codes.** +Found some locations where there were at least 7 layers of function calls, with each layer trying to translate the color codes, which of course was excessive. + + +* **Change the name of the SpigotSellallUtilMessages class to SpigotVariousGuiMessages due to the fact these messages are used in more than just sellall.** +It should be noted that eventually the non-sellall messages may have to be removed from the sellall module. + + +* **Spigot GUI Messages: Hook up more messages to prison's messaging system.** + + +* **Sellall messages: Start to setup the correct usage of the multi-language message handling through the new prison-sellall module.** +This fixes the messaging within the SellAllUtil class. + + +* **Move auto feature messages to the spigot message file so they can be customized.** +Removed the inventory full messages from the AutoFeaturesConifg.yml file. + + +* **The normalDrops processing was not hooked up to the newest way auto pickup is disabled, which was skipping normalDrops if auto pickup was disabled.** +The number of blocks in the normalDrops is now being passed back through the code so it can identify that it was successful and finalize the processing. + + +* **3.3.0-alpha.11c 2022-05-14** + + +* **GUI Menus enable NBT support.** +This is a major change. The details for the menus options and commands are now stored in NBT data so they do not have to rely on the item name, lore, or other tricks. +This is a first phase, and more work needs to be done to remove hooks with the item names for other menu options. Main set of changes has been done to the menu tools. + + +* **Changed placeholder attributes to print the raw value and placeholder.** +Changes to the logging to allow & to be encoded to the unicode string of +`U+0026` so it can bypass the color code conversions, then it is converted back +to an & before sending to bukkit. This works far better than trying to +use Java regEx quotes. + + +* **Fixed signs for sellall to enable them to work with any wood variant.** + + +* **3.3.0-alpha.11b 2022-05-02** + + +* **Placeholder fix for formatted time segments to use the values setup in the language files within core.** +This allows the placeholders to use the proper notations for singular and plural units of times as configured for each language. + + +* **Placeholder fix for rankup_cost and rankup_cost_remaining on both the formating of the percents and the bar.** +The percents were being displayed as an integer, so with rounding, they were very misleading since they would show 100% when they were really hitting 99.5% and higher. Also the bar is not working better, and if the percentage is less than 100%, then it will always show a RED segment at the end of the bar; it will ONLY show GREEN when it's 100% or higher. + + +* **Mine Bombs fix to allow color codes within the bomb's name.** +The color codes are removed for the sake of matching and selecting when giving to players so you don't have to use them in the commands. + + +* **Placeholder issues when not prefixed with "prison_" is being addressed by prefixing the identifier with "prison_" right away.** +This "is" addressed, but it's deep in the code and for some reason certain parts of the code is not making the connection to the correct placeholder without that prefix. So this really is not the desired way to address this, but it eliminates the problem. The reason why it's not the desired way, is because it's exposing buisness rules of how to handle the placeholders, outside of the placeholder core code. + + +* **Bug fix... with placeholder prison_rank__player_cost_remaining_rankname, and its variants,** + eliminate the calculation of including the current rank since that has already been paid for. Prior to this fix, it was only excluding prior ranks. + + +* **3.3.0-alpha.11a 2022-04-25** + + +* **Mine Bombs and NBT settings: this fixes mine bombs to work with NBT tags, which are being used to identify which items are actually mine bombs.** + + +* **Fixes the mine bomb usage of lore where the lore that is defined in the settings is no longer altered so it's now used verbatim.** +Also the check for mine bomb is removed from using the name, or first line of lore, and now tries to use NBT data. +But note, that the NBT data is not working correctly yet. + + +* **Fixed the usage of setting up the NBT library within the gradle config file.** +Fixed issue with unknown, or incompatible items were unable to be parsed by XMaterial which was resulting in failures. This fixes the problem by preventing the use of a partial created SpigotItemStack. + + +* **Hook up the NBT library to the SpigotItemStack class.** +This has not been tested yet to see how it works, especially between server resets. + + +* **Added NBT support to prison. This loads a NBT library to be used only with the spigot sub-project.** +This has not been hooked up to anything yet. + + +* **Placeholder fix: Problem with the placeholder getting a prestige rank that was one too high.** +The following placeholders were fixed: prison_rrt, prison_rankup_rank_tag, prison_rrt_laddername, prison_rankup_rank_tag_laddername + + +* **Hooked up the BlockConvertersNode to the yaml file IO code so it will save and load changes to the auto features configs for anything with the BlockConverters data type.** +Removed unused functions. + + +* **Mine reset potential bug fix: Some rare conditions was causing problems, so using another collection to pass the blocks, and getting the size prior to calling the function to prevent the problems from happening.** +This appeared to be happening when a mine was being reset multiple times, at the same time. The mine should never be resetting multiple times, at the same time. May need to add more controls to prevent it from happening. + + +* **Bug Fix: The IGNORE block type was not marked as a block, therefore could not be used within a mine.** + + +* **New feature: Block Converters. Setup the initial core settings for block converters within the auto features.** +The core internal structure is in place and so is the ability to write the data to the file system. +This has not been hooked up to anything yet. + + +* **Setup placeholder formatted time values to use the language config file.** +This set of values will "NOT" reload when the command `/prison reload locales` is ran. The server must be restarted to reload these values. + + +* **CustomItems getDrops() debug mode will list the results of the get drops.** +This will help track what's going on with the getDrops function since it's a complicated process. + + +* **Placeholders: prison_rankup_rank_tag (and the ladder variants) now shows the prestiges next rank when at the top rank in the default ladder.** +This only applies to the default ladder and only if the prestiges ladder is activated. + + +* **Pull out the setBlock and blockAt functions from the SpigotWorld class so that way it would properly track within Timings.** + + + +** v3.3.0-alpha.10 2022-04-02** + +** Release notes for the v3.3.0-alpha.10 release as posted to spigotmc.org and polymart.org: + +v3.3.0-alpha.10 + +This alpha.10 release includes many significant performance improvements and bug fixes. Although this is an alpha release, it is proving to be stable enough to use on a production server. Please make backups and test prior to using. This v3.3.0-alpha.10 release is "still" backwards compatible with v3.2.11 so you should be able to down-grade back to v3.2.11 without major issues. The breaking changes that will be in the final v3.3.0 release have not been applied yet to these alpha releases. + +Please see our discord server for the full listing of all bug fixes and improvements, there have been more than 70 updates since the alpha.9 release. The following is just a simple short list. + +- Many bug fixes. Some that even predates the v3.2.11 release. + +- Performance improvements: startup validations moved to an async thread. Slight delay between mine validations to allow other tasks to run (needed for less powerful servers). Improvements with sellall performance. + +- Added more support for Custom Items (custom blocks) + +- Added support for top-n players and added over 30 new placeholders. Top-n support for blocks mined and tokens earned will be added shortly too. + +- Upgraded internal libraries: bstats, XSeries, gradle, custom items, and a couple others. + +- Many fixes: Mine bombs, sellall, autosell, auto features, block even listening and handling. + + +* **Ran in to an issue with spigot versions < 1.13 where a data value outside of the normal range prevents XMaterial from mapping to a bukkit block.** +This change provides a better fallback which ignores the data value, which is the varient. The drawback of ignoring the varient type, which is outside the valid ranges anyway, is that it may not accurately reflect the intended block types. But at least this will prevent errors and being unable to map to any blocks. + + +* **Change to prison startup details reporting to elminate duplication.** +Near the end of the prison startup process, prison would run the `/prison version` command to provide additional information in the logs. This was duplicating some of the information that was already printed during the actual startup process. +Changes were made to only add the information that was missing so the whole command does not need to re reran. Overall this is a small impact, but a useful one. It does shift where these functions live and ran from. + + +* **ChatDisplay: An internal change that controls if a chat display object (multi-lined content, such as command output) displays the title.** +This will be useful when integrating in to other commands and workflows, such as redesigning how the startup reporting is handled. + + +* **v3.3.0-alpha.9g 2022-03-29** + + +* **auto features: Enable player toggle on sellall for auto feature's autosell.** + + +* **sellall reload - fixed issue where the reload was not chaning any online valus or settings.** + + +* **Mine bombs cooldown - ran in to a null value in the cooldown timers. Handles this situation now. ** + + +* **Sellall - added debug logging on the calculation of sell prices.** + + +* **Sellall bug fix on calculation boolean config values; it was not returning the correct value.** +This was found by a report that `/sellall hand` was not working. + + +* **Auto features bug fix: was paying the player, instead of just reporting the value when in debug mode.** + + +* **Update debug info in auto features to properly show it's within the BLOCKEVENTS priority processing.** + + +* **Topn calculations: handle a null being returned for the prestige ladder.** + + +* **Enabled a sellall feature to enable the old functionality where sellall ignores the Display Name or is not a valid prison block type.** + + +* **Fixed an NPE issue with checking to see if a block exists within a mine.** +This issue was impacting spigot versions less than 1.13. The problem is with data values being abnormal and out of the standard range. + + +* **Fixed a NPE on the topn calculations.** + + +* **auto features autosell when inventory is full when using the priority BLOCKEVENTS.** + + +* **topn fix: If next rank is null, then try to use the next prestige rank for the cost.** + + +* **v3.3.0-alpha.9f 2022-03-25** + + +* **Placeholders top player: added new placeholders based upon the _nnn_ pattern to identify the player.** + + +* **Top-n players listing: added an alternative line.** + + +* **Placeholder Bar Attributes: Now supports a non-positional keyword "reverse" which will take any bar graph and reverse it.** + + +* **AutoFeatures debugging: Some color change in the logging details for failures so they are easier to see.** + + +* **Prepare for the handling of STATSPLAYERS placeholders, which will be the ones that provides the placeholders for the top-n players.** +This handles the workflow on handling the placeholders. + + +* **Slight update on how the top-n players are printed... simplifies and also cleans it up the formatting.** + + +* **Updated the rankup accuracy to be greater than or equal to 1.0.** +And conditionally only report the accuracy_out_of_range if >= 1.0. + + +* **When validating the success of a rankup transaction's abiliity for the rankup cost to be applied, the validation is now checking to see if it's within a plus/minus of 1.0 from the target final balance of the player.** +This covers the inability of floats and doubles not being able to accurately repesent base 10 numbers all of the time, which the accuracy may be off by a small value such as 0.000001, but that will prevent an equality check from passing. +By checking that it's within a range of plus/minus one will help prevent false failures. + + +* **Fixed issue where ranking does not which rank is associated with each rank.** +Now the ranks will properly track the players at their ranks. + + +* **3.3.0-alpha.9e 2022-03-14** + + +* **Top-n: More work to enable. Now supports /ranks topn, with alias /topn.** +The rank-score and penalty is not yet enabled. Placeholders will be enabled after the command is fully functional. + + +* **Prison startup performance fix: On large servers with many players, the process of getting the player's balance from the economy plugin can cause significant delays if that plugin is not able to handle the load...** +so the validation of the players and the sorting of the top-n list is now ran in an async thread so it will not cause lag or delays on startup. + + +* **Prison version: including more information on ranks and add the ladder rank listing to the prison version command.** + + +* **Removed some old code from block event processing...** + + +* **Mine bombs getting a replacement blocks from the player's location.** + + +* **CustomItems drops: If custom items do not produce a drop, then default to dropping the block itself.** + + +* **Sellall: prevent selling with custom name items.** + + +* **PlayerCache earningsPerMinute: Sychronize to prevent an issue with concurrent mods.** + + +* **Mine bombs: Fix an issue with the generated mine bomb tool not being enchanted with the specified fortune, which also was effecting the durability and dig_speed too.** + + +* **Reworked how some of the registered event listeners are setup, which is needed for expanding to supporting other plugin's enchanments.** + + +* **Update the bstats configs for v3.0.0.** +Although it compiled without the bstats-base, it failed to run. I suspect my local cache for gradle was incorrectly providing objects when it shouldn't have. + + +* **Upgrade bstats to v3.0.0, was at v2.2.1.** +Hoping this will better report the proper usage. +Added more custom details on the graphs: player count, defaultRankCount, prestigesRankCount, otherRankCounts. +Set api version to v3.3. + + +* **BugFix: Prevent a possible NPE when blocks are null when calculating gravity effected blocks, and ensuring there is a location when trying to place blocks.** +Both of these should never be an issue, but based upon different conditions, they can become an issue. + + +* **Added an autoFeatures to enable/disable the use of CustomItems' getDrops().** + + +* **CustomItems integration: Adding support for getDrops() from CUI.** +This integrates custom blocks in to getting the SpigotBlock (an internal prison block). +It's not yet functional due to issues within CUI, but this is the initial setup. + + +* **Report that bedrock users are not getting their tokens.** +When in debug mode, if their balance is not correctly updated it will report it in the console. + + +* **v3.3.0-alpha.9d 2022-03-10** + + +* **Within the SpigotBlock, now has hooks to load CustomItems blocks when trying to convert an org.bukkit.Block to a SpigotBlock.** + + +* **For unbreakable blocks, reinforce that the location, which is the key, will not be null.** +The block sometimes can be null, so by having the seperate location will not cause a failure if the block is null. + + +* **Fixed an issue when checking if a block is unbreakable... it should not have been null, so this is a temp fix to prevent an error.** + + +* **CustomItems custom blocks: Hook up the new drops for CustomItems plugin.** + + +* **Update some of the gradle settings and fix the new custom items api.** + + +* **Upgrade XSeries from v8.5.0.1 to v8.6.2.** + + +* **Update CustomItems API from v4.1.3 to v4.1.15.** +This update adds support for prison to get the drops from the CustomItem blocks. + + +* **Changed the development environment and updated the java 1.8 to the latest release.** + + +* **v3.3.0-alpha.9c 2022-03-06** + + +* **Enable the ability to split messages in to multiple lines by using the placeholder `{br}`.** + + +* **Small adjustments to the MineReset handing of the targetBlock collections.** +Prevent their instantiation in the constructor since they are being lazy loaded. Also synchronizing on the adding of target block, since there was one report on an issue with that not being synchronized. + + +* **Added more validation checks and reporting on rankups and demotes.** +So if something goes wrong, it can hopefully identified and tracked. +If rank change failed, or if a refund failed, it will now better report these conditions. + + +* **Setup a return of success, or failure, on custom currency functions.** +GemsEconomy does not indicate if it was successful, but added code to check to see if it was successfully manually/indirectly. + + +* **Sync set blocks fixes. Isolate the targetBlocks and add a null check to ensure thre are no problems.** + + +* **RankLadder: removed obsolete code that was never used.** + + +* **Some initial setup for a rankScore.** +This is not hooked up yet, but the the core basics are there and should work soon. + + +* **Bug fix: Fixed an issue were a block would be added, or changed, and it would change all similar blocks in all mines to have the same percentage.** +This issue was intermittent and was caused by directly getting the block from the master list, without cloning it. The correction to this issue was to use a search function that would clone the block, but it also would compensate for custom blocks if the block's namespace was not initially provided. + + +* **Bug fix: Risk of a null on the blockHit, so add checks to ensure it's not before trying to process.** + + +* **Bug fix: The clickable delete code is that is generated is off by 1 on the inserted row.** +The row number needed to be reduced by one since the row number was incremented right before this final injection. + + +* **v3.3.0-alpha.9b 2022-02-28** + + +* **Fixed the command '/ranks ladder command remove' when specifying a row value that was too large.** +The message was only providing one value when it should have had two, and the first parameter was '%d' instead of '%1'. + + +* **PlayerCache: Unloading Players... when a player is being unloaded, and they are not in the cache, the unloading process is now able to indicate that the player should not be loaded.** +Also when trying to load a player, it will not attempt the load if the file does not exist. + + +* **Sellall bug fix... was using the wrapper to map it to an XMaterial which was causing NPEs.** +Using the prison's compatibility functions to perform the mapping, which will now provide a safer mapping that will not cause NPEs. + + +* **Module prison-sellall cleaned up gradle config to remove a few configs that are not needed.** + + +* **Fixed a bug with the blockEvent block filter for adding blocks, it was using the blockEvents collection instead of the prison blocks collection.** + + +* **Fix placeholder for prison_player_tool_lore to provide the actual tool's lore.** +The placeholder was not hooked up. + + +* **Mine manager when enabling mines after the delayed loading from multiverse-core delayed loading...** +put a slight delay on each submission of the startup air counts for each mine... spacing them out by one tick so they are not all trying to run at the same time. + + +* **v3.3.0-alpha.9 2022-02-27** + + +* **Bug fix: Sellall error: Resolve an issue with the off-hand not being removed when selling.** +Turned out that you can read all inventory slots, which includes the off-and slot, but when removing ItemStacks, the remove(ItemStack) function then ignores the off-hand slot. Has to directly remove from the off-hand slot. + + +* **Mine bombs: fixed issue with lore not being added.** +Was adding the wrong source; was adding the destination to the destination. + + +* **Mine Bombs: Add some basic validations when loading the mine bombs from the config files** + + +* **Mine Bombs: add a reload function for mine bombs.** +/prison reload bombs or /prison utils bomb reload + + +* **Removed warnings from the Vault economy wrapper since NPCs can actually initiate commands and NPC will always return nulls for OfflinePlayers....** therefore just return a value of zero. + + +* **New command added to '/prison support runCmd' to allow an OP process, such as a NPC in Citizens, to run a command as a player.** +For example this is handy for having an NPC open the player's GUIs such as mines or ranks. + + +* **v3.3.0-alpha.8h 2022-02-26** + + +* **Bug fix: Synchronized some of the collections that are needing it within the PlayerCache.** + + +* **Bug fix: Fixed an inventory glitch that was preventing items from being added to the inventory.** +Basically the inventory had items, but it was not updating the contents of the inventory on the client side. This was fixed by updating inventory when finished processing the adds. +If autosell on full inventory is enabled, and there are extra drops, then sell them all before they make it to the inventory. This works most of the time, but sometimes the inventory still fills up. This is now more of a characteristic than a bug. + + +* **3.3.0-alpha.8g 2022-02-25** + + +* **More adjustments to the block events so the config setting can be shown in the header of the /prison support listeners blockevent command.** + + +* **Setting up support for the BLOCKEVENTS on all block break event listeners.** +Changed around how the listeners are created to simplify and be more accurate in the event states. + + +* **Extracted the BlockBreakPriority enum to be an object on its own.** +Added BLOCKEVENT and added information on what the various priorities should do. This is in preparation to refactoring how events are processed. + + +* **Prison tokens: externalize the messages related to the admin tokens commands.** + + +* **For the admin commands for tokens, added an option to be able to suppress the messages.** + + +* **v3.3.0-alpha.8f 2022-02-23** + + +* **The creation of a new sellall module which will eventually contain the code to manage multiple shops that will be based upon ranks.** + + +* **Adjustments to the configuration of the mutex to better ensure that only one job is submitted for the reset, and to ensure other tasks are not locked up, or locked out.** +There was a report that the prior way was causing the mines to lockup. + + +* **v3.3.0-alpha.8e 2022-02-20** + + +* **Mine reset mutex is conditionally enabled to ensure the locks remain balanced.** +To ensure the mutex is enabled ASAP, its engaged outside of the normal location... it may only be a few nano-seconds savings, but with OP pickaxes mining with many players within one mine, the mutex must be enabled rapidly. + + +* **Bug Fix: Mine reset changes: Eliminate paged resets, some code that is not being use anymore, disabled the RESET_ASYNC type to be similar to RESET_SYNC since they are now the same, locked out checkZeroBlockResets so mines cannot reset multiple times at the same time using the MineStateMutex.** +The major issue here was that mines were being reset in the middle of a reset action. Used a preexisting MineStateMutex to secure the checkZeroBlockResets() function to prevent it from kicking off many resets. These multiple resets were happening because many players were triggering the resets... as a side effect, there were many situations of collections failing due to concurrent modification exceptions. + + +* **Getting the collection size was an issue by the time it was done processing the blocks, so getting them first may help prevent errors.** + + +* **Made many changes to the default configurations of the autoFeatures.** +This is to try to make it easier to use prison by using more of the settings that are most useful. +Added more comments to make it easier to understand these settings too. + + +* **Release v3.3.0-alpha.8d 2022-02-20** + + +- **Fixed issues with vault economy and withdrawing from a player's balance.** +It now also reports any errors that may be returned. + + +* **To prevent NPEs, isBlockAMatch has been changed to use the MineTargetPrisonBlock as a parameter and then internally, checking for nulls, it will extract the status data block.** +This was causing errors when processes were trying to access target blocks before they had a chance to initialize. + + +* **Address a rare condition where the mineTargetPrisonBlocks is being "accessed" before the system is done initializing the mine.** +This creates an empty collection, but it will prevent errors in the long run. + + +* **Add equals and hashCode to the MineTargetBlockKey so it can be better used in structures like HashMaps.** + + +* **Mine bombs: Added a {countdown} placeholder for use with the MineBomb's tagName field.** +A few other adjustments such as adding more "color" to the default bomb tagNames. + + +* **Added validation check to make sure the player's balance was decreased, or increased, successfully before actually applying the rank change.** +If the balance does not reflect the change, then the rank change will be prevented. + + +* **Slight adjustment to addBalance so as to help reduce out of synch possibilities.** +The access to economy hooks, has been moved in to the sychronized block. + + +* **v3.3.0-alpha.8c 2022-02-16** + + +* **Fixed a start up issue with multiverse-core in that it now runs the air-count processes so the mines can have their targetBlocks defined.** +Many issues were resulting from failure to get the target blocks. Not sure how it was working before, other than targetBlocks were not being used as much as they are now. + + +* **Fixed a potential error if targetBlocks are not loaded yet, or loaded at all for a given mine.** +Was causing NPEs.... + + +* **Added logging for when a delayed world comes online and list all mines that are activated.** + + +* **v3.3.0-alpha.8b** + + +* **Clean up the way the command tasks were being called.** +Added mine name to the blockEvent logging. + + +* **Fixed a reversal of some calculations when converting nano seconds to milliseconds.** + + +* **New feature: debug count down timer.** +Able to now set a debug count down timer where debugging is turned off after logging that number of entries. + + +* **Potential bug fix in better managing if sellall should be enabled by directly checking the configuration parameter that enables it.** +Better logging of sellall when inventory is full. + + +* **Commit some SellAllUtil comments that are useful for debugging timing issues.** +These are now disabled, but can be manually reenabled when needed. + + +* **Some changes to Sellall to provide more flexibility and to fix some potential bugs** +The isEnabled now uses the proper boolean settings to indicate if the sellall utility is enabled or not. Before it was trying to treat strings as boolean. + + +* **Add prison command descriptions that goes along with the placeholders.** +They are not yet hooked up, but they will provide more information to the admins on what the placeholders will provide, and also how they can use them since some of these will include examples of the formats. + + +* **Bug fix: The cancellation of the event was not being returned in the correct locations**, +so it was bypassing all of the before mine reset commands. The before mine commands will now run correctly. + + +* **Prison commands: reorganize some of the structures used for the prison commands.** +Hook up some of the logging to track run times for each command. + + +* **Prison commands: reorganize some of the structures used for the prison commands.** +Hook up some of the logging to track run times for each command. + + +* **Prevent the autosell happening just because someone is op.** +To make this work, and to prevent odd behaviors where OPs suddenly are not able to mine correctly, OP can no longer use the autosell based upon perms. + + +* **Setup the time durations on reporting of mine resets to use external settings.** +Enables the use of singular and plural unit names. + + +* **Rework how rankup commands are ran: in progress.** +This new way of dealing with rankup commands is to collect all commands that need to be ran, from all rankups, then run them in one group when the player is done being ranked up. +For most changes in rank, this will have zero effect on anything (mostly), but it has a huge impact with the **rankupmax** command. +When hooked up (which is is not), this will take all commands and run them in a sync task. So "every" command will run in a sync task. But each command will be monitored for run time, and if the runtime for one command exceeds a threshold, then the sync task will resubmit itself to run again after on tick. This will slow down the process of running all of the commands, but it will help prevent them from causing lag. +With tracking run times on each command, if prison is in debug-mode, then it will generate console logs identify how long it take to run each command. So if any given command is causing lag, then it would be possible to identify what the offending command is. + + +* **Fixed a problem before releasing... was not using the correct variable so the generated File object was not getting used.** + + +* **Bug fix: If a player cache file does not exist, it now prevents it from loading.** + + +* **Fixed an issue with the GUI, such that if the player does not have a rank on the ladder**, +that it will now force the creation of a PlayerRank object so it does not cause a NPE. + + +* **Mine bombs: Enable the use of color codes on the armor stands when setting off the bombs...** + + +* **Mine bombs: Added durability and digspeed enchantments to the mine bomb data.** +This will allow for greater flexibility in how the tool in hand behaves. + + +* **If using a mine bomb, then do not allow durability calculations to be used**, +since if the pseudo tool breaks, then what ever the player is holding will be removed, which is usually an item stack of mine bombs. + + +* **Mine Bombs: The mine bomb give command now is case insensitive.** + + +* **Mine Bombs: Add ability to set the Y offset.** +It defaults to a value of -1. This allows fine tuning of bombs to better position them to sink deeper in the mine to increase the number of blocks that are included. + + +* **Fix issue with mine bombs not dropping blocks.** +The underlying block changed and therefore so did the behavior of the equals() function. + + +* **Added various token functions to the prison spigot API class.** + + +***3.3.0-alpha.8 2022-02-12** + + +* **Enable debug mode from within the config.yml file.** +It was not hooked up before. This is useful for initial logging of the mine air-counts. + + +* **Redesigned the initial mine air-counts which not only identifies which blocks are within a mine upon startup, but it also establishes the number of air blocks in a mine to help ensure it's able to properly reset when the mine is empty.** + + +* **Bug fix: cleaned up the way PlayerCache files are managed.** +Eliminated a lot of old code and simplifed the logic to ensure the liklihood of preventing corruption of the player caches. There has been some reports that the files were not being properly tracked and stats were being replaced with new entries. This also fixes some performance issues by caching the files in the directories. So once loaded, the loaders no longer need to read the file listings, which could take a while with a lot of files. + + +* **Provide information on locale settings within the `/prison version` command.** +Falls back to the en_US properties file if the selected language file does not exist. +If the non en_US properties files are found to be missing a property, then the english property is used as a fallback. These fallbacks are not written back to the save files. + + +* **v3.3.0-alpha.7 2022-02-09** +Set this back on an alpha release schedule. The betas appear to have been pretty stable. + + +* **Disable the player's nms attempts to get their locale... spigot 1.17 and higher no longer can get that value.** +Just use the server's default value. + + +* **For the /prison support commands, the output is now sent to the player instead of just the console.** + + +* **Some minor changes to /prison debug to give it an alias of /prison support debug.** +Format a few of the messages to make it easier to understand. + + +* **Removed the backpack's object from the player's cache.** + Backpacks are too massive for the player's cache and needs thier own cache system. + + +* **On the command /ranks set tag, added the note that if a tag is removed from a rank, then the rank name will be used instead.** +Fixed the placeholder for rank tags so if it is null, it no longer show a null, but now it show the rank's name. + + +* **Fixed the generation of the player mined block count placeholders.** +Was missing one _ after generating the specific block related placeholder. + + +* **Upgrade gradle from v7.3 to v7.3.1 to v7.3.2 to v7.3.3** +This is at the latest release. + + +* **Upgrade gradle from v7.2 to v7.3** + - Changes to provide better security when runnign gradle to prevent injection attacks. + + +* **Upgrade gradle from v7.1 to v7.1.1 to v7.2.** + + +* **Upgrade gradle from v7.0.2 to v7.1.** +NOTE: There are a number of updates to apply for gradle. Will commit on the minor versions and final version. + + +* **Added a few new placeholders and a new placeholder type of PLAYERBLOCKS.** +Added raws to the player_block_total per mine. Added player_blocks_total and its raw counts, which is a PLAYERBLOCKS. + + +* **Added a few new placeholders and a new placeholder type of PLAYERBLOCKS.** +Added raws to the player_block_total per mine. Added player_blocks_total and its raw counts, which is a PLAYERBLOCKS. + + +* **Changed around the logging of messages related to the use of autofeatures autosell.** +Added permissions to enable autosell on a per block. + + +* **Update CustomItems api from v3.7.17 to v4.1.3.** +This newer version of the API still does not have a getDrops() function. + + +* **Add more support for CustomItems plugin.** +It appears like this is working really well with auto pickup. It should be noted that the CustomItems' API does not have a getDrops() so it's impossible to get the correctly configured drops for the block, so for now, it will only return the block itself and not any configured drops. +Sellall may need to be fixed and there could be some other areas that needs some fine tuning, but so far all is working well. + + +* **For CustomBlockIntegrations added getDrops().** +This has to be used instead of bukkit's getDrops() since that will return only the base item drops, which are the wrong items. +For CustomItems plugin, there currently isn't a getDrops() function in the CustomItems API so instead, the integration's getDrops() returns the block. + + +* **If cancelAllBlockEventBlockDrops is enabled when it's not valid on the server version, then it will print the error to console, then turn off this features** + + +* **CustomItems: Hook up on server startup the ability to check for custom blocks when scanning the mines to set the air counts and block counts.** + + +* **Clean up the formatting on `/mines block list` so it's easier to read and looks better.** + + +* **If fail on /mines reset, then needed a missing return so the mine reset success message won't follow the error message.** + + +* **Bug Fix: When mine reset time is disabled, set to -1, and then all mines are reset with '/mines reset `*all*` details' it would terminate the reset chain on that mine.** +This change allows the next mine to be reset by not trying to set this mine's next action... which is none because reset time is -1. + + +* **v3.3.0-beta.2 2022-02-03** + + +* **Added an error message when failed to add a prestige multiplier.** + + +* **New feature: cached adding of earnings for the default currency.** +This was causing a significant amount of lag/slow down when performing autosell, or spamming of sellall. The lag was in the economy plugin not being able to accept additions of money fast enough. +Now this simple cache, will wait 3 seconds before adding the player's earnings to the economy plugin. When it does, it will do so in an async thread so as to not impact any performance in bukkit's main thread. Also prison's getBalance() functions, which includes the use of all prison placeholders, will include the cached amount, which means the player's balances appear as if they are not being cached. +Still need to cache the custom currencies. + + +* **Update /ranks autoConfigure to set notifications to a radius of 25 blocks, and enabled skip resets at a limit of 90% with 24 skips.** +Also moved DARK_PRISMARINE down a few levels since it's not as valuable as the other blocks. + + +* **Bug fix: Correct the comparison of a prison ItemStack by using compareTo.** +The old code was using enums, so the check for equality of enums resulted in comparing pointers, which will never work. +Updated a few other parts of the code to use the compareTo function instead of the equals function since that may not work correctly all the time. + + +* **For command /mines set notification added *all* for mine name so all mines can be changed at the same time.** + + +* **Change notification alerts from runnign every 5 minutes to every hour.** +Got a few complaints within the last fewa days that the notifications are too frequent. + + +* **Modified SpigotPlayer to add getRankPlayer() and modified RankPlayer to add getRankLadder, with short cuts for default and prestige so you don't have to always refer to their names (reduce errors).** +This is to remove the "mess" from other functions that need to get these player objects, of which sometimes they are not going about it the correct way. + + +* **sellall multiplier add - Now reports if a multiplier cannot be added. Also now adds the multiplier based upon the actual rank name**, +of which it was what the user entered with the command, which may not match the actual rank name. + + +* **RankLadders - Added a boolean function to check if the ladder is the default ladder or prestiges ladder.** + + +* **sellall multiplier - Now able to list all multipliers.** +It lists them in a 5 column listing. + + +* **Add debug logging when calling the external events.** +Will have to revisit this when hooked up to multi-block events, otherwise it could overwhelm the logging. + + +* **Ladder rank cost multiplier has 100 percent limits removed.** +Value can be any positive or negative number now. + + +* **Update some documentation related to CMI Economy.** + + +* **Broadcast the prison welcome message to all online players when prison is loaded with no mines or ranks defined.** +The messag is loggd to console 8 sconds after prison loads. The broadcast messags are sent 16 seconds after logging the welcome message. +The intention is to help bring awareness to new mods/admins that there is an easy way to get started with prison. + + +* **Broadcast the failed ranks loading to all online players.** +Its important that they know ranks failed to load. + + +* **Release v3.3.0-beta.1 !! Hooray!!** 2022-01-29 2:11 PM EST + + +* **Added nano-second timing autosell to confirm if there is a performance issue.** +My initial testings are showing that sellall has significant chance of performance problems in that selling items takes way too long. Will address in the future. + + +* **Disable all ranks related commands within the GUI menus.** +GUI was bypassing safeguards that were in place when the ranks module failed to load. + + +* **Update the placeholderAPI docs to correct the formatting of the docs to match what they should be.** +Had to indent by two spaces. + + +* **Created updated documents for the placeholderAPI wiki.** +These are local copies of the content since the prior content was removed/vandelized. + + + +* **New Feature: Added support for Quests so that block breakage within mines can now be tracked and be applied towards quests.** + + +* **Bug fix: Lapis_ore appently does not drop lapis_laluzi when using the bukkit's getDrops() function, it instead drops blue_dye, then when it gets to the player's inventory, it is then converted to lapis_lazuli.** +Therefore, auto sell cannot sell lapis_ore drops unles blue_dye is within the shop. I added blue_dye with the same value of lapis_lazuli to the sellall shop. This allows it to be sold now through auto pickup and auto sell. + + + +* **Bug Fix: Damage was being applied all the time.** +Found a field being initialized with a value of 1 when it should have been 0. + + +* **Prevent sellall from loading if ranks does not load. Sellall uses too many rank functions to stand alone.** + + +* **Bug Fix: The new Ranks error message handler which intercepts all ranks messags was failing to load properly when prison startup was not set for a delayed startup,** + which was because the ranks gui command (/ranks) was always being set even when ranks module failed to load. Now /ranks gui loads only if ranks was successful in being started. + + +* **Initially setup to use the actionBar for the messages, but that is not working correctly with such high volume of messages.** +So disabled them for now, but will switch them over shortly... + + +* **Format the earnings amount properly, so it will have a consistant format.** +Once in a while, instead of showing a value like 165.00 it shows 165.000000000000001. This is caused by the fact that doubles are binary, not base-10 so it canot always show the correct values. + + +* **Deprecated the MessagesConfig class since it is not implemented correctly.** +The messages should have been handled through Prison's multi-language tool, of which this does not use. + + +* **Try to use a different way to identify the item stack, especially if the bukkit item stack does not exist.** +This was a random error when using gravel, sand, and dirt on spigot/paper 1.12.2. + + +* **Clean up some of the refrences to the new/old block models.** + + +* **Added the new command: '/sellall list' that will list all blocks and their prices.** + + +* **Added comments that usage of auto features cancel drops will not work from spigot v1.8 through 1.12.x.** +Should work with v1.13.x and newer. + + +* **Fix some block issues, mostly getting the correct block bukkit block and limit it to only one location and function that ultimately provides these hooks.** +This release appears to be more functional, but it still should not be used since it's not fully tested. + + +* **First pass at removing the old block model. Do not use this release!!** +This compiles and runs on the server. Most commands appear to work, including mine resets, but no visual confirmation has been performed in game yet. Since so much has been changed and it has not yet been tested in-game, this release should not be used until such rudementary testing can be performed. + + + + + +* **3.3.0-alpha.7 2022-01-22** + +A return to the v3.3.0 release track. The alpha.7 release represents a continuation of where we left off before. Once we got to alpha.6, it became apparent that it was critical to release before v3.3.0 was ready, so we returned to the v3.2.x track, including everything up to and including the v3.3.0-alpha.6. + + + + + + + + + + +# 3.2.11 2022-01-22 + + + +# v3.2.10 2021-08-22 + + + +# v3.2.9 2021-07-03 + +- release v3.2.9 + + +# v3.2.8.1 2021-06-18 + + +* **Note: Bug fixes for 3.2.8.** + +* **Fixed a failure on startup for new installations of prison.** +Basically it was unable to deploy the language files due to try-with-resources closing the initial zip connection. + + +# v3.2.8 2021-06-17 + +Prison V3.2.8 Release! +Prison now fully support Spigot 1.17 and Java 16! + + +**NOTE:** Since the start of the development on v3.3.0, Prison has had a few other releases under v3.2.7 and v3.2.8. The reason for these releases is that the major structures (and code) that would make prison v3.4.x, are not complete. Therefore, to get out new updates sooner than later, v3.2.7 and v3.2.8 have been release. + + +* **Released v3.2.8!** + + +* **v3.2.8-alpha.3 2021-06-16** + + +* **v3.2.8-alpha.2 2021-06-12** + +* **Spigot 1.17 release - v3.2.8-alpha.1 - 2021-06-11** +Only known issues: + * Unable to use nms to get the player's preferred language + +* **v3.2.8-alpha.1 2021-06-07** +Internally set the version, but will not release it until a few other things are finished. +The prison version is set to 3.2.8-alpha.1 to prepare for the release of prison that is compatible with Java 16 and Spigot 1.17. + + +NOTE: v3.2.8-alpha.1 is identical to v3.3.0-alpha.6. V3.3.0 is far from being ready to be released. So v3.2.8 will enable Java 16 and also Minecraft 1.17. + + +# v3.3.0-alpha.6 2021-06-07 + + +* **v3.3.0-alpha.6 2021-06-07** +Setting the version. The v3.3.0 release will be put on hold since focus will be to get v3.2.8 out which will support Java 16. It is unknown how many of the spigot 1.17 blocks will be initially supported. + +* **v3.3.0-alpha.5c - 2021-06-06** + +* **v3.3.0-alpha.5 2021-06-01** + +* **v3.3.0-alpha.4 2021-05-15** + + +* Next release will be v3.3.0-alpha.3 +Please note that the correct order of releases have been: +v3.2.6, v3.3.0-alpha.1, v3.3.0-alpha.2, v3.2.7, v3.3.0-alpha.3 + + +# v3.2.7 2021-05-02 + + +* **Set version to v3.2.7** + - Note that all changes that were made under v3.3.0-alpha.1 and v3.3.0-alpha.2 have been publicly released under v3.2.7 + + +* **3.3.0-alpha.2 2021-04-23** + + +* **v3.3.0-alpha.1 2021-04-16** + + +* **v3.3.0-alpha.0 2021-04-11** + + Start on the alpha.1 release. + diff --git a/docs/prison_changelogs.md b/docs/prison_changelogs.md index 73aa35c18..b39762745 100644 --- a/docs/prison_changelogs.md +++ b/docs/prison_changelogs.md @@ -10,6 +10,12 @@ These build logs represent the work that has been going on within prison. - Future updates will be under the v3.3.x release + - [v3.3.3-alpha.14 - 2023-01-23](prison_changelog_v3.3.0-alpha.14.md)   + + + - [v3.2.x - v3.2.6 2021-04-11](changelog_v3.2.x.md) + + - [v3.2.11 - 2022-01-22](prison_changelog_v3.2.11.md)   - [v3.2.10 - 2021-08-23](prison_changelog_v3.2.10.md)   - [v3.2.9 - 2021-07-03](prison_changelog_v3.2.9.md)   @@ -28,6 +34,3 @@ These build logs represent the work that has been going on within prison. - [v3.2.0 - 2019-12-03](prison_changelog_v3.2.0.md)   - - - diff --git a/docs/prison_docs_000_toc.md b/docs/prison_docs_000_toc.md index b28d516d3..b9b9c3e19 100644 --- a/docs/prison_docs_000_toc.md +++ b/docs/prison_docs_000_toc.md @@ -2,6 +2,7 @@
+*Documented updated: 2022-12-30* ## Project Related @@ -36,6 +37,10 @@ Prison supports Spigot 1.19.x, along with Java 17 and 18. At this time there ha ### Newer features and updates in Prison: +* Prison's AutoFeatures was redesigned to support more Event Listener Priorities. This means prison is more flexible and will work with more plugins, using them the way you want to. Some of the new priorities are `ACCESS` so you can use Prison's Mine and Teleport Access by Rank without having to use Prison's block handlers. This bypasses the need to configure WorldGuard regions for access to the mines that are linked to Prison Ranks. + +* Now supports RevEnchants, both with Prison handling the block break events, and with RevEnchants handling the events. + * Prison Backups: Prison now has a new feature that will backup (zip) all of the files within it's plugin directory. Prison now will perform an automated backup when it detects a change in Prison's version to help preserve settings from prior versions. See the new [Prison Backup Document](prison_docs_050_Prison_backups.md). @@ -130,7 +135,36 @@ Auto configure can get you up and running with as little as two commands. The f [Prison Auto Configure / Prison Quick Start Guide!](prison_docs_100_setting_up_auto_configure.md) - +
+ +# A Quick Word About the Prison Command Handler + +Prison has an advanced command handler that manages all of the commands. Programmatically, +the commands are not setup the same as a normal bukkit command, but instead, there are a +lot of more powerful features available through the Prison Command Handler. + +All commands will respond to the **help** keyword. It will show a list of all of the parameters +for the command, any permissions tied to the command, and other details too. If a document is +associated with the command, it can show a clickable link when used in-game (not many commands +have been linked to their docs yet). + +The Prison Command Handler also manages aliases, auto complete (tab complete), organizing +commands in a hierarchy so you can explore what commands are available by starting with the +root commands. For example, `/prison` is the core root command, and it will also show you +a listing of all other root commands. So `/prison` is a great place to begin exploring +the commands that are available. + +For the latest alpha releases, there is an exciting new command: `/prison support cmdStats`. +This new command will show you every prison command that was ran since the server was started, +along with how many times the command was used, and the average milliseconds it took Prison +to handle that command. Some commands, such as `/mines reset` are submitted and ran +asynchronously and so their average run times will not be able to be reflected in that +command. The `cmdStats` does not track "command" usage if it bypasses the Prison +Command Handler, such as when a mine automatically resets since the internal calls bypass the +Prison Command Handler. + +This is useful to give you an idea what commands your players and mods may be using. +
@@ -337,6 +371,9 @@ Get your prison setup quickly by running the command `/ranks autoCommand` which How to enable backpacks. +* [Troubleshooting](prison_docs_900_troubleshooting.md) + Mining issues. +
diff --git a/docs/prison_docs_010_setting_up_a_spigot_server.md b/docs/prison_docs_010_setting_up_a_spigot_server.md index 814fbc645..44751af85 100644 --- a/docs/prison_docs_010_setting_up_a_spigot_server.md +++ b/docs/prison_docs_010_setting_up_a_spigot_server.md @@ -13,7 +13,7 @@ Buildtools also allows easy setup of many test environments since all you would need to do is to just change the version. -*Documented updated: 2021-12-03* +*Documented updated: 2023-01-14*
@@ -25,7 +25,7 @@ there are many good resources out there. * First install a copy of Java that is accessible from the command line. - The current version of Java is version 17. Even if you are using jars and other plugins that were compiled with Java 1.8.x, it is recommended to use Java 17. - - If you feel like you must use Java 1.8, it’s strongly suggested to use only the latest version 1.8.0_x. + - If you feel like you must use Java 1.8, it's strongly suggested to use only the latest version 1.8.0_x. * You can download it from [Sun SE Development Kit 8]https://www.oracle.com/java/technologies/javase/javase-jdk8-downloads.html) for product that you need. @@ -59,7 +59,8 @@ there are many good resources out there. java -jar BuildTools.jar --rev 1.15.2 java -jar BuildTools.jar --rev 1.16.5 java -jar BuildTools.jar --rev 1.17.1 - java -jar BuildTools.jar --rev 1.18 + java -jar BuildTools.jar --rev 1.18.2 + java -jar BuildTools.jar --rev 1.19.3 ``` * For example, with BuildTools.jar being in a root directory, create a subdirectory and then start a build within that directory. The benefit is that you can use the same BuildTools.jar to build multiple different versions of spigot. This example starts off with building a v1.17.1 instance and then builds a 1.8.8 instance. Normally you wouldn't build multiple versions of spigot, but this shows how easy and flexible it is to build any version of spigot that has been released. @@ -67,12 +68,12 @@ there are many good resources out there. ``` mkdir spigot-1.17.1 cd spigot-1.17.1 - java -jar ../BuildTools.jar –rev 1.17.1 + java -jar ../BuildTools.jar --rev 1.17.1 cd .. mkdir spigot-1.8.8 cd spigot-1.8.8 - java -jar ../BuildTools.jar –rev 1.8.8 + java -jar ../BuildTools.jar --rev 1.8.8 ``` * **Updating BuildTools:** Once in a while you will be prompted to update the BuildTools.jar file. To do update it, all you need to do is to just download it, and replace the older one you were using. @@ -92,7 +93,7 @@ there are many good resources out there. * NOTE: At the time when this document was updated, Spigot 1.18 was just released. Because 1.18 requires Java 17, it is advisable to use that version of Java. Prison, because it is still being ran on older servers and under older environments, it must try to support the widest array of Spigot versions; therefore it is built with the latest version of Java 1.8.x, and built using Spigot 1.13.2. The environments in which Prison is built, should not impact how you build and run your server, of which it could easily be with Java 17 and Spigot 18. -* Windows example, if you’re still in the build directory: +* Windows example, if you're still in the build directory: ``` cd ../.. @@ -100,7 +101,7 @@ there are many good resources out there. copy /B builds\spigot-1.17.1\spigot-1.17.1.jar spigot-1.17.1_server ``` -* Linux example, if you’re still in the build directory: +* Linux example, if you're still in the build directory: ``` cd ../.. @@ -119,7 +120,7 @@ there are many good resources out there. pause ``` -* Let the server fully start for the first time, then stop it by entering “stop†in the open server console. The server is now ready to be customized. +* Let the server fully start for the first time, then stop it by entering 'stop' in the open server console. The server is now ready to be customized. This should give you a functional server for which to run the Prison plugin. diff --git a/docs/prison_docs_012_setting_up_prison_basics.md b/docs/prison_docs_012_setting_up_prison_basics.md index 5d4d0940f..2429d4229 100644 --- a/docs/prison_docs_012_setting_up_prison_basics.md +++ b/docs/prison_docs_012_setting_up_prison_basics.md @@ -7,7 +7,7 @@ This document provides a quick overview on how to install Prison and get it running. -*Documented updated: 2021-12-03* +*Documented updated: 2023-01-14*
@@ -122,6 +122,13 @@ Prison actually uses bukkit's permission interfaces. This makes it simple for P * **NOTE: A permissions plugin of your choice** - Required - Prison works with many different permission plugins through Vault. I strongly suggest LuckPerms since it is free and is under active development so bugs and performance issues will be addressed if they ever become an issue. If you choose to use another permission plugin, then please consider ones that work with Vault; Prison uses Vault to provide the flexibility of choosing from many different plugins. +* **NOTE: A Warning about Vault and Essentials Economy** - There was a problem where essential's economy was refusing to work thought vault. Since prison is able to directly support essentials economy, there is a new feature that can disable the use of vault for the economy, which will allow prison to directly communicate with Essentials Economy. Make sure your `config.yml` has the following configuration. It will be added to new prison installs, otherwise just copy and past it in anywhere. Also, if you rename the `config.yml` file and restart the server, prison will auto generate a new copy with these settings. + +```yaml +integrations: + prevent-economy-vault-usage: true +``` + * **Other Permission Plugins** There are many out there, and as developer of Prison, and through providing support, we don't hear of any issues with other permission plugins. The reason for this is because they probably just work well to begin with, and that Prison uses bukkit's permission interfaces. So it keeps things simple for setting up Prison. If you are just getting started with building a server, then we suggested keeping it simple with something like LuckPerms, but there are other permission plugins out there that can provide a whole new experience with your server, such as jobs and careers for your players. @@ -152,10 +159,17 @@ All of Prison's placeholders have an alias. An alias is a shortened name for a NOTE: You may also need to install the follow plugin for full support: ProtocolLib. -* **MVdWPlaceholder** - Suggested to Avoid - Prison does support this plugin, but since it is used mostly with premium plugins, we have no way to fully test this plugin to ensure it actually works correctly. We've heard very few people have used this plugin, but we've heard it does work well. Use at your own risk. -With this plugin, all placeholders are registered with it automatically when prison starts up, and all placeholders should be used as all lower case. Because prison has so many placeholders, with many that are expanded based upon ladders, ranks, and mine names, a modest prison server could generate and register well over 1000 placeholders. MVdWPlaceholder appears to be very verbose so you will see a lot of logging in the console when it starts up. +* **MVdWPlaceholder** - Not supported. + +**NOTE: Prison no longer supports MVdWPlaceholder** because it could not support all of the advanced features with placeholders that prison uses. Also, since prison generates so many possible placeholders, MVdW pollutes the console log with thousands of lines of useless information stating each variant of a placeholder has been registered. We also dropped support for this plugin because there is no way to contact the developer because they hide behind a pay-wall, and I'm not about to buy one of their other plugins to just tell them their so-called-free plugin is not working properly. + +But perhaps the biggest reason why I dropped support for MVdW is because it's 100% pointless. **PlaceholderAPI** works flawlessly with MVdW so there is absolutely no reason why prison needs to support MVdW anymore. If you need to use MVdW, then please keep using it, it works great with their other plugins. But you can use PlaceholderAPI along with it too. So there are zero reasons why you cannot use PlaceholderAPI, and everyone is happy. + +~~Suggested to Avoid - Prison does support this plugin, but since it is used mostly with premium plugins, we have no way to fully test this plugin to ensure it actually works correctly. We've heard very few people have used this plugin, but we've heard it does work well. Use at your own risk.~~ + +~~With this plugin, all placeholders are registered with it automatically when prison starts up, and all placeholders should be used as all lower case. Because prison has so many placeholders, with many that are expanded based upon ladders, ranks, and mine names, a modest prison server could generate and register well over 1000 placeholders. MVdWPlaceholder appears to be very verbose so you will see a lot of logging in the console when it starts up.~~ - It should also be noted that because of some of the limitations of MVdW, not all features of Prison's placeholder support will be supported. For example, you may not be able to reload placeholders, or use placeholder attributes to customize how placeholders are used. +~~It should also be noted that because of some of the limitations of MVdW, not all features of Prison's placeholder support will be supported. For example, you may not be able to reload placeholders, or use placeholder attributes to customize how placeholders are used.~~ @@ -197,6 +211,10 @@ With this plugin, all placeholders are registered with it automatically when pri [https://www.spigotmc.org/resources/crazy-enchantments.16470/](https://www.spigotmc.org/resources/crazy-enchantments.16470/) +* **RevEnchants** - Prison now supports RevEnchants through their ExplosiveEvent and JackHammerEvent! To enable prison to work better with RevEnchants, you can enable it within the `autoFeaturesConfig.yml` file. Prison supports RevEnchants v11.2 or newer. It may work with older versions, but if there are issues, we cannot provide support if the older version of RevEnchants is missing either of the events. + + + * **Zenchantments** - Optional - Some support is provided for zen, but it may not be 100%. More work needs to be done to improve the integration in to prison. This is an open source project. It identifies that it supports spigot 1.9 through 1.14 (different versions). [https://www.spigotmc.org/resources/zenchantments.12948/](https://www.spigotmc.org/resources/zenchantments.12948/). @@ -205,6 +223,65 @@ Warning: People have paid for this plugin only to find out after the fact that i If you purchase this plugin to use on your server, do so with great caution since it is not supported and it may not integrate with prison. [ * Not supported * Tokens * Not supported * ](https://www.spigotmc.org/resources/%E2%9A%A1%EF%B8%8F-tokens-%E2%9A%A1%EF%B8%8F-40-enchantments-%E2%AD%95-free-expansions-%E2%AD%95-25-off.79668/) + +### Enchantment Plugin Features Supported + +This table of supported Enchantment Plugins are plugins that have an event that Prison is able to hook in to for the purpose of communicating multiple block breakage. It should be noted that all of these events are related to block breakage, and originate from the original bukkit's **BlockBreakEvent**, but the other plugins takes the single block, then applies "effects" that expands the one block breakage to multiple blocks. These events are the mechanism for conveying the list of included blocks to Prison so Prison can do what it needs to do with the blocks. + + +| Plugin | Event | Settings ID | Cancel
Events | Cancel
Drops | External
Hooks | +| --- | --- | ----------- | :---: | :----: | :----: | +| Bukkit/Spigot | **BlockBreakEvent** | `blockBreakEventPriority` | **Yes** | **Yes** | **Yes** | +| Prison | **ExplosiveBlockBreakEvent** | `ProcessPrisons_ExplosiveBlockBreakEventsPriority` | **Yes** | *No* | *No* | +| TokenEnchant | **TEBlockExplodeEvent** | `TokenEnchantBlockExplodeEventPriority` | **Yes** | *No* | *No* | +| CrazyEnchants | **BlastUseEvent** | `CrazyEnchantsBlastUseEventPriority` | **Yes** | *No* | *No* | +| PrisonEnchants | **PEExplosionEvent** | `PrisonEnchantsExplosiveEventPriority` | **Yes** | *No* | *No* | +| RevEnchants | **ExplosiveEvent** | `RevEnchantsExplosiveEventPriority` | **Yes** | *No* | *No* | +| RevEnchants | **JackHammerEvent** | `RevEnchantsJackHammerEventPriority` | **Yes** | *No* | *No* | +| Zenchantments | **BlockShredEvent** | `ZenchantmentsBlockShredEventPriority` | **Yes** | **Yes** | **Yes** | + + + +**Notes:** +1. A value of *No* for **Cancel Drops** will always use **Cancel Event** instead. +2. **Cancel Drops** was added in Spigot 1.12.x so older versions of Spigot *must* use **Cancel Events** +3. **External Hooks** refers to custom hooks in to mcMMO, EZBlock, and Quests. See config settings within **AutoFeaturesConfig.yml**. It's strongly suggested to use **Cancel Drops** instead so you won't have to enable these features. These provides a hacky-fix for the limitations when using **Cancel Events** and may not be perfect. +4. Zenchantments is flexible in how it's **BlockShredEvent** works, mostly because it extends the bukkit **BlockBreakEvent**. The events can possibly mix with normal **BlockBreakEvent**s. +5. It may take some effort to find the ideal priorities to use for your environment to ensure everything works as you envision it. + + +### Event Listener Priorities + +The above listed supported Events are assigned one of the available Prison Event Priorities. This table illustrates what features are associated with each priority, which can be somewhat complex and confusing. + + +| Priority | Access | In
Mine | In
World | Ignores
Canceled
Events | Block
Break | Block
Count | Reset
Threshold | Block
Events | Mine
Sweeper | AutoSell | +| --- | :---: | :---: | :---: | :---: | :---: | :---: | :---: | :---: | :---: | +| DISABLED | *No* | *No* | *No* | *No* | *No* | *No* | *No* | *No* | *No* | *No* | +| ACCESS | **Yes** | **Yes** | *No* | *No* | *No* | *No* | *No* | *No* | *No* | *No* | +| ACCESSBLOCKEVENTS | **Yes** | **Yes** | *No* | *NoYes* | *No* | **Yes** | **Yes** | **Yes** | **Yes** | **Yes** | +| ACCESSMONITOR | **Yes** | **Yes** | *No* | *NoYes* | *No* | **Yes** | **Yes** | *No* | **Yes** | *No* | +| LOWEST | **Yes** | **Yes** | *No* | *No* | **Yes** | **Yes** | **Yes** | **Yes** | **Yes** | **Yes** | +| LOW | **Yes** | **Yes** | *No* | *No* | **Yes** | **Yes** | **Yes** | **Yes** | **Yes** | **Yes** | +| NORMAL | **Yes** | **Yes** | *No* | *No* | **Yes** | **Yes** | **Yes** | **Yes** | **Yes** | **Yes** | +| HIGH | **Yes** | **Yes** | *No* | *No* | **Yes** | **Yes** | **Yes** | **Yes** | **Yes** | **Yes** | +| HIGHEST | **Yes** | **Yes** | *No* | *No* | **Yes** | **Yes** | **Yes** | **Yes** | **Yes** | **Yes** | +| BLOCKEVENTS | *No* | **Yes** | *No* | **Yes** | *No* | **Yes** | **Yes** | **Yes** | **Yes** | **Yes** | +| MONITOR | *No* | **Yes** | *No* | **Yes** | *No* | **Yes** | **Yes** | *No* | **Yes** | *No* | +| *priority temp* | Access | In Mine | IN Wrld | IgCanEv | Blk Brk | Blk Cnt | ResetTh | BlkEvnt | MineSwp | AutoSel | + + +**Notes:** +1. **DISABLED** will prevent a listener from starting, and it will prevent any processing of that event. +2. **Access** managed by Prison requires the use of Access by Rank (perferred) or Access by Perms. It also will vary in effectives based upon the priority level in relation to other plugins, where any plugin that has a lower priority than Prison will bypass Prison's attempts to control access. +3. **ACCESSBLOCKEVENTS** and **ACCESSMONITOR** are able to have a duel behavior because these priorities will create two different listeners, each at a different priority, and each having a different purpose. +4. **Block Break** refers to Prison handling the whole block break processing and drops. +5. **Mine Sweeper** should never be used unless there is no other way to count all the broken blocks. +6. Support for outside of the mine for auto features maybe added soon. The way it will probably be supported would be through a list of worlds in which it should be active, plus the use of WG regions too. +7. The **MONITOR** priority, including ***BLOCKEVENTS*** will ignore all events that have been canceled and will process them anyway. Therefore **ACCESSBLOCKEVENTS** and **ACCESSMONITOR** will fail on the "access" part if the event is canceled when Prison gets ahold of it the first time, which will deny access to the mines, but it will also still process the event under the priority of MONITOR or BLOCKEVENTS. + + + ### Other Plugins diff --git a/docs/prison_docs_030_LuckPerms_Groups_Tracks.md b/docs/prison_docs_030_LuckPerms_Groups_Tracks.md index 2e8448b25..b2b27a9f5 100644 --- a/docs/prison_docs_030_LuckPerms_Groups_Tracks.md +++ b/docs/prison_docs_030_LuckPerms_Groups_Tracks.md @@ -7,7 +7,7 @@ This document provides an overview to help setup LuckPerms groups and tracks. -*Documented updated: 2022-06-19* +*Documented updated: 2022-12-29*
@@ -383,22 +383,48 @@ There should be no configuration changes needed for the plugin, and it should ju +
+ + +# Special Variation: Accessing Only One Mine at a Time by using MineAccessByRank + +_Warning: This is a non-standard way of configuring access to your mines. These settings will only allow a player to access only the current mine and will exclude them from accessing prior mines._ + +This setting will only allow players to access mines that are linked to their current rank. For example, if a player is at Rank C, then they cannot access the prior mines A nor B. This is a very restrictive configuration and is not generally typical of a prison server. + + +Enable MineAccesByRank on all mines: + +`/mines set mineAccessByRank *all* enable` + +Then in the Prison `config.yml` file, enable this setting, using a value of *false*: + +```yaml +prison-mines: + access-to-prior-mines: false +``` + +
# Special Variation: Accessing Only One Mine at a Time by using Permissions +_Warning: This is a non-standard way of configuring access to your mines. These settings will only allow a player to access only the current mine and will exclude them from accessing prior mines._ + +_Warning: It is not recommended to use Mine Access by Permissions; instead use MineAccessByRank._ + One special variation in configuring your server, would be if players can "only" access mines that are tied to their current rank. For example, if a player is at Rank C, then they cannot access the prior mines A nor B. This is a very restrictive configuration, which requires managing the permissions. -If you are using permissions for access, then the two you need to know about are: `mines.` and `mine..tp`. Such that mine A would require: `mines.a` and `mines.a.tp`. +If you are using permissions for access, then the two you need to know about are: `mines.` and `mine.tp.`. Such that mine A would require: `mines.a` and `mines.tp.a`. Add these two perms to all LuckPerm groups. You can use the LP editor, or manually with the following commands. Repeat for all groups. ``` /lp group a permission set mines.a true -/lp group a permission set mines.a.tp true +/lp group a permission set mines.tp.a true ``` @@ -461,7 +487,185 @@ To review a player's rank within prison use `/ranks player `. +
+ + +# Example of LuckPerms Commands to setup Tracks/Groups + +The following is a list of LuckPerm Commands, listed in order, that will setup the correct Tracks/Groups within LuckPerms. Then there is a prison command that will apply the correct LP Track to all existing players. + +This will allow perms to be inherited from lower ranks. + + +``` +/lp creategroup a +/lp group a setdisplayname A + +/lp creategroup b +/lp group b setdisplayname B +/lp group b parent add a + +/lp creategroup c +/lp group c setdisplayname C +/lp group c parent add b + +/lp creategroup d +/lp group d setdisplayname D +/lp group d parent add c + +/lp creategroup e +/lp group e setdisplayname E +/lp group e parent add d + +/lp creategroup f +/lp group f setdisplayname F +/lp group f parent add e + +/lp creategroup g +/lp group g setdisplayname G +/lp group g parent add f + +/lp creategroup h +/lp group h setdisplayname H +/lp group h parent add g + +/lp creategroup i +/lp group i setdisplayname I +/lp group i parent add h +/lp creategroup j +/lp group j setdisplayname J +/lp group j parent add i + +/lp creategroup k +/lp group k setdisplayname K +/lp group k parent add j + +/lp creategroup l +/lp group l setdisplayname L +/lp group l parent add k + +/lp creategroup m +/lp group m setdisplayname M +/lp group m parent add l + +/lp creategroup n +/lp group n setdisplayname N +/lp group n parent add m + +/lp creategroup o +/lp group o setdisplayname O +/lp group o parent add n + +/lp creategroup p +/lp group p setdisplayname P +/lp group p parent add o + +/lp creategroup q +/lp group q setdisplayname Q +/lp group q parent add p + +/lp creategroup r +/lp group r setdisplayname R +/lp group r parent add q + +/lp creategroup s +/lp group s setdisplayname S +/lp group s parent add r + +/lp creategroup t +/lp group t setdisplayname T +/lp group t parent add s + +/lp creategroup u +/lp group u setdisplayname U +/lp group u parent add t + +/lp creategroup v +/lp group v setdisplayname V +/lp group v parent add u + +/lp creategroup w +/lp group w setdisplayname W +/lp group w parent add v + +/lp creategroup x +/lp group x setdisplayname X +/lp group x parent add w + +/lp creategroup y +/lp group y setdisplayname Y +/lp group y parent add x + +/lp creategroup z +/lp group z setdisplayname Z +/lp group z parent add y + +/lp createtrack mine-ranks + +/lp track mine-ranks append a +/lp track mine-ranks append b +/lp track mine-ranks append c +/lp track mine-ranks append d +/lp track mine-ranks append e +/lp track mine-ranks append f +/lp track mine-ranks append g +/lp track mine-ranks append h +/lp track mine-ranks append i +/lp track mine-ranks append j +/lp track mine-ranks append k +/lp track mine-ranks append l +/lp track mine-ranks append m +/lp track mine-ranks append n +/lp track mine-ranks append o +/lp track mine-ranks append p +/lp track mine-ranks append q +/lp track mine-ranks append r +/lp track mine-ranks append s +/lp track mine-ranks append t +/lp track mine-ranks append u +/lp track mine-ranks append v +/lp track mine-ranks append w +/lp track mine-ranks append x +/lp track mine-ranks append y +/lp track mine-ranks append z +/lp track mine-ranks append a +/lp track mine-ranks append b +/lp track mine-ranks append c +/lp track mine-ranks append d +/lp track mine-ranks append e +/lp track mine-ranks append f +/lp track mine-ranks append g +/lp track mine-ranks append h +/lp track mine-ranks append i +/lp track mine-ranks append j +/lp track mine-ranks append k +/lp track mine-ranks append l +/lp track mine-ranks append m +/lp track mine-ranks append n +/lp track mine-ranks append o +/lp track mine-ranks append p +/lp track mine-ranks append q +/lp track mine-ranks append r +/lp track mine-ranks append s +/lp track mine-ranks append t +/lp track mine-ranks append u +/lp track mine-ranks append v +/lp track mine-ranks append w +/lp track mine-ranks append x +/lp track mine-ranks append y +/lp track mine-ranks append z + + +/ranks ladder command add default lp user {player} parent settrack mine-ranks {targetRank} + +``` + +To apply these to all preexisting players, the following command will reset everyone's current rank to their current rank, thus triggering the **ladder commands** to be ran so they will be setup with the correct LP Track. + +``` +/ranks set rank *all* *same* +```
diff --git a/docs/prison_docs_101_setting_up_mines.md b/docs/prison_docs_101_setting_up_mines.md index 8e467da68..e116ed6db 100644 --- a/docs/prison_docs_101_setting_up_mines.md +++ b/docs/prison_docs_101_setting_up_mines.md @@ -6,14 +6,22 @@ This document provides some highlights to how to setup mines. It is a work in progress so check back for more information. +*Documented updated: 2023-01-13* +
# Overview -This document should be able to provide the basic information to get your mines configured. There are many options available within Prison, and also through the use of other plugins, and these advanced topics are beyond the scope of this document. +This document should be able to provide the basic information to get your mines configured. There are many options available within Prison, and also through the use of other plugins, so advanced topics that blend multiple plugins, and their various settings, are beyond the scope of this document. + + +Prison has a list of suggested plugins that works well with Prison, and a few that do not work at all with Prison. Please see the following document for a list of suggested plugins. If you have a favorite plugin that works well with Prison and it's not in that list, then please reach out to us in our discord server and make a suggestion for it to be added. +[Setting up Prison - The Basics](prison_docs_012_setting_up_prison_basics.md) + Items to add to this document: +* Use of ***/mines backup help** this command will make an individual backup of a mine's config settings on the server's file system. This backup can manually be used to rollback any changes to a mine. Prison has a command **/prison support backup help** that will make a backup of all files within the server directory **plugins/Prison/**, of which it will include all mine backup files, then remove them from file system. Contact support on our discord server for help. * Use of **/mines set area** to change the mine size without deleting it. * Use of **/mines delete** how it works and how to recover a deleted mine. * Use of **/mines list** @@ -29,11 +37,16 @@ Items to add to this document: Prison now has a new set of features that can help you get up and running faster than ever! `/ranks autoConfigure`. It can auto create your ranks and virtual mines, A through Z, it will link the mines to the ranks, setup the basic rank commands to provide basic access permissions for your players, and assign blocks of increasing values to all mines. This command also enables the Mine Access Permission so it will be easier to control player's access to mining. -The Prison auto configure also now enables prison's **sellall** features and preloads about 98 default items to make it easier to get started with your sellall shop. +The Prison auto configure enables prison's **sellall** features and preloads about 98 default items to make it easier to get started with your sellall shop. It also enable the most popular auto features and links the generated mines to the generated ranks to simplify enabling access for the players. + +The auto configure will generate both ranks and mines with the names A through Z, and will link the ranks to the mines of the same names. Prison will setup all the generated mines as virtual mines, which includes the basic configurations that are most commonly used, plus it assigns blocks to each mine, in an increasing range of values. The accessMinesByRanks will also be enabled, which will help bypass the need to generate a WorldGuard region for players to have access to the mines, and will help reduce the need to configure so many perms since Prison will handle the complex relationships for you. +If you are trying to use Prison with another plugin, such as an enchantment plugin, then you may need to create WG regions because the other plugins would require them. Once the the auto configure command is completed, all you need to do is to use the command `/mines set area` on all mines to make them physical mines. Plus there are a new features to help provide the finishing touches in almost no time, such as setting liners for your mines. +The Prison auto configure is very powerful and allows you get up and running much faster, but it does not prevent you from customizing any aspect that you would desire. We strongly encourage everyone to at least start off with the auto configure, play around with it to see what prison can do with these simple setups, then it can help give you an idea of other customizations. It should be noted that auto configure only uses about 10% of the features available within Prison, so as useful as it may be in showing you how to get up and running quickly, there are many other possibilities available where your imagination may be the limiting factor on how your server can be customized to your desires. + Some of the commands of interest: @@ -43,10 +56,8 @@ Some of the commands of interest: - `/mines set size help` - `/mines set liner help` -Documentation pertaining to the use of the auto configuration will be coming soon. - -Keep in mind that in order to use the command `/ranks autoConfigure` you cannot have any mines or ranks defined yet. So before you create a test mine, go ahead and run the auto configure so at least that is complete. There is an option to force the generation of auto configure, but when forcing the generation, it will skip over any rank and any mine that is already configured, so it could cause a mess. +Keep in mind that in order to use the command `/ranks autoConfigure` you should not have any mines or ranks defined yet, which may cause some conflicts with mines and their ranks. So before you create a test mine, go ahead and run the auto configure so at least that is complete. There is an option to force the generation of auto configure, but when forcing the generation, it will skip over any rank and any mine that is already configured, so it could cause a mess. One thing you need to keep in mind, if you are using something like LuckPerm groups, you must define the groups within LuckPerms before you can actually use them, such as through a rankup command being ran. @@ -61,15 +72,17 @@ One thing you need to keep in mind, if you are using something like LuckPerm gro Please review the Prison's [Table of Contents](prison_docs_000_toc.md) for information on how to configure your server, and which plugins are required, or at least suggested. -It is also strongly suggested that you review the documentation on [Configuring and Using WorldGuard with LuckPerms to Protect Mines](prison_docs_626_configuring_worldguard_regions.md) since that explains a lot on how to setup the basics with your world, which will not be covered here. There will be references to this document, but this will be the only link provided. + +Prison now uses **mineAccessByRank** which eliminates the need to setup WorldGuard regions, unless you are using other plugins that require them. If you have a need to setup regions that will work with prison, then it is strongly suggested that you review the documentation on [Configuring and Using WorldGuard with LuckPerms to Protect Mines](prison_docs_626_configuring_worldguard_regions.md) since that explains a lot on how to setup the basics with your world, which will not be covered here. There will be references to this document, but this will be the only link provided. These instructions assume you are OP'd since that is part of the above document pertaining to WorldGuard. If not, go ahead and OP yourself. -To follow along with this documentation, you may want to crate your first mine as a test, with intentions of deleting it later. It may be easier to remove it, than to convert it over to a final product. The instructions here are informational, not focused on perfection. So after you figure out how to create your mines, you may want to provide more attention to the details to ensure they are perfect. But for now, the focus is on the commands. +To follow along with this documentation, you may want to crate your first mine as a test, with intentions of deleting it later. It may be easier to remove it, than to convert it over to a final product. The instructions here are informational, not focused on perfection. So after you figure out how to create your mines, you may want to provide more attention to the details to ensure they are perfect. But for now, the focus is on the commands and better understanding what is possible. + +Please note that all command provide in this document will be written as if they were entered within the game and will require the leading slash: `/`. If you use these commands within the console, then do not include the slash prefix. I always include the slash prefix in the documentation so the commands stand out as being commands. Personally, I actually prefer to use most commands in the console since there is more room to view the details. -Please note that all command provide in this document will be written as if they were entered within the game. If you use some of them from the console, then do not include the slash prefix. I always include the slash prefix in the documentation so the commands stand out as being commands. +It should also be strongly noted that you should never manually modify the save files for the mines, ranks, or ladders, since that could easily lead to corruption and undefined failures and problems. We cannot support misuse of the files. The primary reason for this concern is that Prison has a rich command interface that provides many checks and balances to ensure the commands are setup correctly. When prison starts up and the configuration files are loaded, those same validations are not performed so serious conflict could be caused by hand modification. That said, if you do adjust the commands by hand, keep in mind these file format of these save files are either yaml or json and therefore if your changes results in invalid yaml or json, then they will not be able to be loaded. We do not support hand edited config issues, but if we have time, we can possibly help identify where the errors are. Keep in mind that if you are having issues, copy and paste the config file that is having issues in to an online lint application: https://jsonlint.com/ or https://codebeautify.org/yaml-validator. There are many to choose from, and they usually help point out where the issue are and provide suggestions on how to fix the errors. -It should also be strongly noted that you should never modify the save files for the mines, ranks, or ladders, since that could easily lead to corruption and undefined failures and problems. We cannot support misuse of the files.
@@ -78,7 +91,10 @@ It should also be strongly noted that you should never modify the save files for Being OP'd, find a good location for your mines. -Also the following commands may help setup the environment. Optional of course. Having some block in your inventory can be useful for use as scaffolding or selecting. I personally like to use sealanterns because they are not a common block and they stand out well in low light conditions and are easier to see in screen prints. Giving yourself `/fly` and `/god` may not be necessary, but it could help if you need to find a good location, or if there are mobs in the area when you drop out of creative mode and back in to survival. +Also the following commands may help setup the environment. Optional of course. Having some block in your inventory can be useful for use as scaffolding or selecting. I personally like to use `sealanterns` because they are not a common block and they stand out well in low light conditions and are easier to see in screen prints. Giving yourself `/fly` and `/god` may not be necessary, but it could help if you need to find a good location, or if there are mobs in the area when you drop out of creative mode and back in to survival. + + +A few useful commands as OP: ``` /op @@ -90,6 +106,13 @@ Also the following commands may help setup the environment. Optional of course. ``` +

Command: /ranks autoConfigure

+ +If you ran the command `/ranks autoConfigure` then all of your mines have been generated and are virtual mines. A virtual mine is one that is fully configured, but it has not been "physically" placed in any world yet. So you can tweak the configurations on the mine, except for setting that relate to any locations within a world. All you have to do with these virtual mines, is to place them. + +Below are some of the settings for creating a mine, but since they are already created, you can skip over some of these settings and just jump to placing the mines. + +

The wand

Now give yourself a Prison wand. @@ -98,10 +121,16 @@ Now give yourself a Prison wand. /mines wand ``` +A mine wand will allow you to set the coordinates of a mine by clicking on a block. You cannot click in air, so you may have to place a block to define the coordinates. + + +A mine wand can also be used for debugging block break actions within a mine. If you are having issues with getting mines to work, it's one of the many built-in support tools that can help figure out what's going wrong, since a prison server can become very complex, especially when factoring in other plugins. Please contact us through our discord server for additional help if needed. + +

Laying Out the New Mine

-For the sake of this document, and to keep things simple, the mines we are creating will be very small and will not be deep within the ground. +For the sake of this document, and to keep things simple, the mines we are creating in these examples and screen prints will be very small and will not be deep within the ground. This will allow for easier understanding of the general layout of what is being created. First mark out the dimensions of your mine. As you can see here, I've marked my first mine out with sealanterns to show you how big it will be. You really only need to mark opposing corners since that defines a cuboidal region. I've cleared away some of the dirt so you can see the lower blocks. This mine will be 5 x 5 x 5 in size. @@ -123,11 +152,14 @@ Then create the mine with: /mines create test1 ``` -It will default to 100% air. So then follow up creating the new mine with a reset to confirm everything is replaced with air. +NOTE: the command `/mines create help` is intended for creating new mines. If you ran `/rank autoConfigure` then the mines already exist, and instead of using `/mines create` you just need to "set" or place the mines with `/mines set area help`. + + +It will default to 100% air. So then follow up creating the new mine with a reset to confirm everything is replaced with air. Mines that are precreated with `/ranks autoConfigure` already have assigned blocks. -

Reset the New Mine to Test it Exists

+

Reset the New Mine to Test if it Exists

Go ahead and reset the mine. All of the sealanterns that were used to mark the mine are now gone, and so are the two layers of dirt. That confirms success with our first mine since the only default block that exists in the mines when created is air. @@ -139,7 +171,7 @@ Go ahead and reset the mine. All of the sealanterns that were used to mark the -
+
@@ -168,6 +200,8 @@ Some of the highlights of these commands are as follows: * `/mines list` : Displays all mines on your server. * `/mines playerInventory` : Shows your current inventory in the console. Intended strictly for admins. * `/mines rename` : Renames a mine. + + * `/mines reset ` : Resets the mine. Forces a regeneration of all the blocks, even if the mine is in skip reset mode. `` should be the name of the mine, but can also be ** *all* ** to force all the mines to reset one after the other. If such action is performed, then all mine resets will be done through a submission with a slight delay between each reset, and it will prevent the running of the mine reset commands to prevent possible looping. `` should not be use directly without understanding what they do. * `/mines stats` : Toggles the display of stats that pertain to how long it takes to reset the mines. View /mines info or /mines list to see the stats. Use this command again to turn it off. @@ -181,43 +215,62 @@ Some of the highlights of these commands are as follows: * `/mines whereami` : Shows you what mine you are in, or how far away you are from other mines in the area. If you have a lot of mines, it's easy to lose track of where you are, and this may help get your bearings. + * `/mines block add` : Add a new block type to a mine. It's easier to start off with `/mines block search` and have it fill in the commands for you. +* `/mines block constraint` : Controls block generation within a mine, such as minimum number, maximum number, or which layers it can spawn at. +* `/mines block list` : Shows all blocks within a mine, including the constraints that have been placed on specific blocks. This command is also included in the command `/mines info all`. * `/mines block remove` : Remove a block type from a mine. +* `/mines block searchAll` : Search for a block type or item type based up on a search string. This includes all blocks, but also all items too. * `/mines block search` : Search for a block type based up on a search string. -* `/mines block set` : Edit the block's percentage within the mine. A percent of zero will remove. If the block does not already exist, it will be added. (Can replace add and remove). +* `/mines block setChance` : Edit the block's percentage within the mine. A percent of zero will remove the block as if the command `/mines block remove` was used. If the block does not already exist, it will be added. (Can replace add and remove). + -* `/mines blockEvent add` : -* `/mines blockEvent block add` : -* `/mines blockEvent block list` : +* `/mines blockEvent add` : This adds one or more commands to a block event. To add multiple commands, just add a semi-colon between the commands: `;`. +* `/mines blockEvent add placeholders` : This command lists all placeholders that can be used within a block event's commands. These placeholders will expand the flexibility of what other commands can be used. +* `/mines blockEvent block add` : Adding block type to a blockEvent acts as a filter and will only use this block even on a block type that is listed. * `/mines blockEvent block remove` : * `/mines blockEvent eventType` : -* `/mines blockEvent list` : -* `/mines blockEvent mode` : -* `/mines blockEvent percent` : -* `/mines blockEvent permission` : +* `/mines blockEvent list` : Use list to how all of the available blockEvents for a given mine. These blockEvent commands that edits a blockEvent are based upon the row number as listed with this command. +* `/mines blockEvent percent` : Sets the **percent** chance of running this blockEvent. Valid ranges are 100 % which is always ran (if it passes the filters), to as low as 0.00001 percent. +* `/mines blockEvent permission` : A BlockEvent permission will only allow a blockEvent to be ran if the player has this permission. This filter can be used with other filters, such as "triggered" and "blocks". * `/mines blockEvent remove` : -* `/mines blockEvent triggered` : +* `/mines blockEvent taskMode` : Identifies how a blockEvent is ran. Options are [inline, inlinePlayer, sync, syncPlayer]. "Player" modes runs the command as if the player entered the command and runs under their perms, while non-player modes run as admin as if ran from the console. Inline and sync mode may, or maynot be selectable. Most blockEvents are now ran in another thread and will not hang the BlockBreakEvent anymore, so inline or sync may not have an impact. +* `/mines blockEvent triggered` : For plugins such as TokenEnchant, their explosion event identifies which enchantment of theirs triggered the event. So this filter can apply a blockEvent to a very specific enchantment. + + +* `/mines set area` : This command places a virtual mine, or it allows you to redefine the area of the mine. Careful, this can wipe out builds if set incorrectly. This is a required command to set the area of the mine. A new feature is to use the current location of your feet to define a 1 x 1 x 1 region with `/mines set area feet`. Then you can use `/mines set size` to make it any size you want. +* `/mines set area virtual` : This command will remove a mine from a world, and make it virtual. A virtual mine can then be placed somewhere else, or even in a different world. Virtual mines will not try to go through resets, so it's a safe way to disable a mine if you're not ready for it to be active. + + +* `/mines set accessPermission` : Uses permission to enable access to the mine. This does not use the player's rank, which is the suggested method so as to reduce the number of perms that need to be configured and managed. +* `/mines set mineAccessByRank` : Uses the player's rank to control access to the mines. This is the preferred method of controlling access since it reduces the number of perms that Prison has to manage, and can help bypass the need of using WorldGuard regions to control the players. +* `/mines set tpAccessByRank` : Uses the player's rank to control the player's ability to teleport to the mine. See the command `/mines tp`. -* `/mines set area` : Redefine the area of the mine. Careful, this can wipe out builds if set incorrectly. This is a required command to set the area of the mine. A new feature is to use the current location of your feet to define a 1 x 1 x 1 region with `/mines set area feet`. Then you can use `/mines set size` to make it any size you want. * `/mines set liner` : A quick way to wrap your mine with a 2D Pattern in 3D space. This command also will `repair` the area around a mine, and will effectively erase a liner. There are six directions that can be specified for change: `north`, `south`, `east`, `west`, `top`, and `bottom`. `walls` also is a shortcut for `north`, `south`, `east`, and `west`. The patterns available are listed by the command. There is even a `force` setting that will allow the mine to be wrapped when in air, since the wrappings normally needs blocks in contact with the mine so it is able to conform to the terrain. -* `/mines set move` is a new command that is not yet enabled. It is still in development, but will be active soon. This command will move a whole mine as a single unit, be it a few blocks or many (not recommended). -* **Removed:** `/mines set norank` : Disconnect the mine from a rank. **Note:** This command has been changed to `/mines set rank none` to delete the rank from the mine. +* `/mines set mineSweeper` : If all else fails to get Prison to monitor and track blocks that are broken within a mine, mostly due to conflicts with other plugins, then this option can provide a last chance effort to monitor the progress within a mine. It is very rare that you would have to use this setting and the chances are that there are better ways to get the mines working correctly. The larger the mine, the more costly this setting is to enable. +* **Removed:** `/mines set move` is a new command that is not yet enabled. It is still in development, but will be active soon. This command will move a whole mine as a single unit, be it a few blocks or many (not recommended). The same effect of moving a mine can be done through the command: `/mine set size` but note it will possibly damage or destory the surrounding builds if not careful. + +* **Removed:** `/mines set norank` : Disconnect the mine from a rank. **Note:** This command has been changed to `/mines set rank *none*` to delete the rank from the mine. * `/mines set notificationPerm` : Enables or Disables notifications pertaining to mine resets to be seen only by players who have permission to that mine. The permissions used are `mines.notification.[mineName]` in all lower case. * `/mines set notification` : Can turn off the notifications on a per-mine basis. Or set the notification radius, or only notify players within the mine. This command cannot change the message. * `/mines set rank ` : Links a mine to a rank, otherwise there is no way within prison to identify which mines should be associated with a given rank. If **rankName** is **none** then it removes the associated rank from the mine (deletes the rank). This is not yet needed, but it will be used in the near future with new features, or enhancements to existing features. * `/mines set resetThreshold` : This allows you to set a percent remaining in the mine to use as a threshold for resets. For example if you set it to 20.5% then the mine will reset when it reaches 25.5% blocks remaining. When the mine resets, it will initiate the `zeroBlockResetDelay` functionality, of which it's not exactly "zero blocks" anymore. * `/mines set resetTime` : Changes the time between resets, as expressed in seconds. Applies to each mine independently. -* `/mines set resetPaging` : This is an advanced feature that can eliminate lag that might be experienced with the resetting of enormous large mines. A mine could be millions of blocks in size and without this setting it may take a few seconds, or longer to reset, and it could cause the ticks to fall far behind, even to the point of forcing a shutdown. This command instead will breakdown the mine's reset in to very small chunks that will prevent the TPS from slowing down, and it will allow other critical tasks to continue to run. The total length of time for the rest may be increased, but it will not hurt the server. Prison does not use async resets due to eventual corruption of the bukkit and spigot components. +* **Removed:** `/mines set resetPaging` : This no longer is a setting, since Prison always uses a more advanced type of paging that dynamically prevents server lag. This is an advanced feature that can eliminate lag that might be experienced with the resetting of enormous large mines. A mine could be millions of blocks in size and without this setting it may take a few seconds, or longer to reset, and it could cause the ticks to fall far behind, even to the point of forcing a shutdown. This command instead will breakdown the mine's reset in to very small chunks that will prevent the TPS from slowing down, and it will allow other critical tasks to continue to run. The total length of time for the rest may be increased, but it will not hurt the server. Prison does not use async resets due to eventual corruption of the bukkit and spigot components. * `/mines set size` : Allows you to resize a mine without redefining it with the prison selection wand. Just specify which direction to increase or decrease. It also uses the `/mines set liner repair` feature to fill in voids when reducing an edge. -* `/mines set skipReset` : When enabled, can prevent a mine from resetting if it has no activity. Can set a threshold before the mine is reset, such as 80% will require 20% of the blocks be mined before being reset. Can also set a bypassLimit so that if the reset is skipped X number of times, it will force a reset anyway. + +* `/mines set resetSkip` : When enabled, can prevent a mine from resetting if it has no activity. Can set a threshold before the mine is reset, such as 80% will require 20% of the blocks be mined before being reset. Can also set a bypassLimit so that if the reset is skipped X number of times, it will force a mine reset. This command is good for reducing server load for mines that are not that busy. + * `/mines set sortOrder` : Mines can be sorted for view within `/mines list` or the GUI. Setting the sortOrder allows you manually set the order in which the mines are listed. There is even the option to suppress (hide) mines from that list too by setting the sort order to a -1. * `/mines set spawn` : Sets the mines spawn point. Whatever you are looking at is what the players will be looking at when they tp to that spot. * `/mines set tag` : Set a mine tag value that can be used with placeholders. * `/mines set tracer` : Removes all blocks in a mine and replaces them with air, with the exception of the corners, of which are replace with pink_stained_glass. This function allows for easy viewing of the full mine without the blocks getting in the way. It also helps when setting the liner of the mine. Using `/mines reset` returns the mine to normal functionality, or it will reset on its own. * `/mines set zeroBlockResetDelay` : If the mine runs out of blocks, when enabled, it will force a manual reset after the specified delay. The delay can be zero for instant reset. + + Adding the term `help` to the end of any of the above listed commands will display additional information that is available for each command, including the parameters and also all permissions that are associated with the commands.
@@ -239,6 +292,7 @@ Let's first take a quick look at the new mine with this command. Let's view it Info on test1 mine +The command `/mines info all` provides more details such as the block lists, the commands tied to the mine, and blockEvents for the mine.

Select a Few Blocks

@@ -249,7 +303,10 @@ The easiest way to select blocks is to search for them. Let's add a few such as /mines block search cobble ``` -Block search for cobble +Block search for cobble + +Note: `/mines block searchAll` will also include items in the search results. Item are used with the sellall shop and the creation of Mine Bombs items. + When using the console with block search limits what you can do with the block search. If you are in game, you can click on a block type that is displayed, and it will auto fill out the block add command for you, such that all you need to do is add the percentage at then end of the command. Also in game, you can page through the results. @@ -311,18 +368,13 @@ Note: The new command `/mines set move` is not yet enabled. It is still in devel # Large Mines - Preventing Lag -Large mines present their special own special challenges, one of which is that they can take a long time to reset. Since bukkit cannot handle async resets of blocks because of world corruption, the updates must happen synchronously in the main server thread. For large mines, that can mean causing a significant amount of lag. - -To prevent lagging the server, Prison has a feature that can prevent any lag from happening while performing the reset. This feature is called **Reset Paging**. This feature doesn't have to be used with just large mines, but the reset process is a little more complex. When testing, it was actually found to be slightly faster than the normal reset method. +Large mines present their special own special challenges, one of which is that they can take a long time to reset. Since bukkit cannot handle async resets of blocks because of world corruption, the updates must happen synchronously in the main server thread. For large mines, that can mean causing a significant amount of lag. -To enable reset paging use the following commands to enable and disable it. +To prevent causing lag, Prison now implements a reset paging for all mines. This is an advanced feature that actively monitors the system performance and will auto page when the server load increases, or if the current reset is taking too long. Since this is an active paging feature, that dynamically adjusts for server loads, resetting a lot of mines at the same time, even super-huge mines, would be difficult to cause lag. Even if a lot of other tasks are running on the server, a mine reset cannot lockup the server. As the load increases, the mine resets may take longer to perform, but the ticks per second will not drop by much to cause lag. -``` -/mines set resetPaging enable -/mines set resetPaging disable -``` +Paging is where the number of blocks that need to be reset, are broken up in to smaller chunks, or pages. The page sizes are defined to be a certain size, but if performance becomes an issue, then those chunk sizes can be reduced to allow more of the other tasks to run so lag is minimized. This process is active and responds to dynamic server loads as they occur at any stage of the reset. This even will behave well if many mines try to reset at the same time... it can be viewed as like shuffling a deck of cards where one mine will reset a few blocks, then the other mine, and they will take turns until the mines are fully reset. In between each mine, other system tasks, or other plugins can get a chance to run so as to not hog all of the CPU power, which would otherwise lead to lag. -The way it works, is that it performs small pages of block updates and keeps an eye on how long it's taking. If the update goes beyond a set amount of time, such as 50 milliseconds, it stops the updates, and then schedules the remaining updates to run later, with no delay. That means if nothing else is trying to run within the main server thread, then it will continue to perform block updates. But if something else was waiting to run, then the mine update will pause and allow the other process to finish. This will prevent vital tasks from backing up because the mine reset yields to other tasks that need to run. +Prison's paging for mine resets are very much similar to Preemtive Multi-tasking, but instead of bukkit managing the paging, prison itself is managing it's own use of the server's processor to ensure other bukkit tasks, and other plugins, are able to get processing time. It when the bukkit tasks and other plugins are unable to get processing time is when lag becomes an issue and is obvious. @@ -480,6 +532,14 @@ With it enabled, it shows stats on mine resets in mine list, mine info, and when
+# Virtual Mines and Disabling Mines + +Mines can be change to virtual mines or disabled. More information to be provided on these subjects. Please contact us on our discord server for help if needed. + + +
+ + # Deleting Mines Mines can be deleted with the `/mines delete` command. diff --git a/docs/prison_docs_130_Prison_Mine_Bombs.md b/docs/prison_docs_130_Prison_Mine_Bombs.md index 53d4d2476..21cfa818e 100644 --- a/docs/prison_docs_130_Prison_Mine_Bombs.md +++ b/docs/prison_docs_130_Prison_Mine_Bombs.md @@ -5,17 +5,24 @@ # Prison Mine Bombs -Prison mine bombs... +Prison mine bombs can take on a lot of different sizes, shapes, and strengths. + + +A player can only use a Mine Bomb within a Prison mine, and they cannot activate it outside of a mine. + + +When a Mine Bomb goes off, it identifies a list of blocks that are included in the explosion event, and then it's passed on to prison to process the actual block breaks and apply any special conditions that goes along with those actions. + *Note: this document is a work in progress.* -*Documented updated: 2022-08-06* +*Documented updated: 2022-08-30*
-Commands: +# Commands: ``` /prison utils bomb list help @@ -39,8 +46,240 @@ The location of the configuration file is: `plugins/Prison/module_conf/mines/mineBombsConfig.json` -If this file does not exist, you can have prison auto generate it by using any of the above mine bomb commands. The best may be +If this file does not exist, you can have prison auto generate it by using any of the above mine bomb commands. + + +You can directly edit this file while the server is running, then use `/prison utils bomb reload` to reload it without restarting the server. + + +The format of this config file is JSON, so it very sensitive to typographical errors that breaks the JSON format. If you do mess it up, or if you need to reformat it so it looks pretty, you can use the online JSON lint tool: [JSON Lint Online](https://jsonlint.com/). + + +You can edit almost anything in this config file, except for the field `dataFormatVersion` which is used to identify if the underlying format has changed so prison can use the proper converters to ensure the settings are migrated to future formats. This currently is not being used, but as soon as a major change is made to the data structure, then this will become valuable. + +
+ + +# Config File - Bombs Map + +In the config file, "bombs" is the root hash (map, object, key-value-pairs) that contains all bombs. The bombs are keyed on their name, which must be unique. + + +There are no limitations on how many bombs you can create, or have active. You can have 1000's of bombs if you desire. + +
+ + +# Config File - Bomb Structure + +The config file for a bomb, contains all of the possible settings that can be used, even if they are not enabled or used. This may make for a verbose bomb listing, but it's part of the process for mapping between JSON and the java data. + + +## Bomb Name and nameTag + +Each bomb must have a name, which can include color codes, but the key name for the bomb is the name but minus color codes. It's the key name (without the color codes) becomes the identifier that is used in-game for selecting the bombs. Since bombs are used with commands, the name cannot contain any spaces. + + +Bomb names can include color codes, but it is suggested that the color codes are added to the nameTag. The nameTag can include a limited number of Mine Bomb placeholders to inject various information, such as the bomb name. Placeholders can be used more than once. + + +The list of Mine Bomb nameTag placeholders: + +* **{name}** Injects the bomb's name in to the nameTag. + +* **{countdown}** Provides a countdown that is refreshed dynamically. This can show the players how long they have before a bomb goes off. The **oofBomb** has an example of this placeholder.' + + +
+ + +## Bomb itemType + +The itemType identifies what the bomb will look like. It can be any item or block as long as the name matches the XSeries' XMaterial types. The itemType must also be valid for your version of Spigot that you're running. + + +You can find a list of XMaterial names here: + +[XSeries' XBlock](https://github.com/CryptoMorin/XSeries/blob/master/src/main/java/com/cryptomorin/xseries/XMaterial.java) + +
+ + + ## Bomb Shapes, Dimensions, and Positions + + + Most bombs may be round, but they can take on any shape. Prison supports a few different shapes, and the plan is to add more in the near future. To view the current list of shapes use the following command: + +`/prison utils bomb list shapes` + + +Explosive Shapes (field **explosionShape**): + +* **cube** a cubic bomb that has equal sized dimensions. The length is calculated from the bomb's radius: length = 2r + 1. The **height** may also effect the cube bomb (will have to look it up). + +* **sphere** a spherical bomb with a defined **radius**. + +* **sphereHollow** a spherical bomb that is defined by it's radius, but the center of the bomb is untouched and its size is defined by the **innerRadius**. The oofBomb is an example of a sphereHollow bomb, where at ground zero it's the safest place to stand. + +* **ring_x ring_y ring_z** Creates a hollow ring going through the specified plane. The **radius** defines the size of the ring, and the **innerRadius** defines the size of the hollow inner circle. + +* **disk_x disk_y disk_z** Similar to the **ring_** shapes, but instead of hollow, they are filled in. + + +The **radius** is not exactly what someone may think it is. Since we're dealing with Minecraft, we are stuck in block mode, therefore everything must be within whole blocks. So the radius is added to 1, but the total diameter is not 2(r + 1), but instead it is 2r + 1. So given the starting center point, the radius is added to that block. So with a radius == 1, the diameter will be 3. Radius == 5, diameter == 11. + + +The **placementAdjustmentY** is added to the y-axis to move the center of the bomb up when positive, or down when negative. Usually since a bomb is symmetrical, if just placed on the top of a mine, then 1/2 of it would go unused and wasted. So for some bombs it makes sense to adjust the height with a negative value so as to get move coverage. As with any bomb that has decent hight, it would make the most sense to place it in the very center of the mine to maximize the full volume of the explosion. + + +
+ + +## Removal Chance + + +To weaken an explosion, you can use the field **removalChance** which will randomly check each block to see if it's included in the explosion. Depending upon the percent chance, a few blocks can remain, or all can be removed. + +The values range from **100.0** to **0.0001**. At 100.0 percent, all blocks are removed and no chance calculations are performed. At 50.00 percent, then about half will be removed. At very, very low removal chances, it's possible that no blocks will be removed. + + +**Explosive Strength - Future Idea** + +Please note that the removal of a block has nothing to do with the hardness of the blocks. In the future, I may add explosive strength to Mine Bombs where the total explosion is calculated in terms of a strength value, then each block, starting at the radius and incorporating a proportatant equation, will determine if the block breaks, and how much of the explosive strength was consumed. This will ensure blocks at ground zero will have more odds of breaking, but blocks on the outer edge will have less of a chance, especially if the explosion runs out of explosive strength. So two identical bombs set off in sand stone (weak blocks) will have a larger blast area than the same bomb set off on obby. For the largest bombs, having such high explosive strength at ground zero, could even include breaking bedrock or even stronger materials. + + + +
+ + +## Virtual Tool + +When a block is broken, it is taken in to consideration what is hitting the block. Such as the player's hand, a wooden pickaxe, or a diamond pickaxe. But with Mine Bombs, the player is holding the bomb before they set it off, so when breaking the block, it is needed to include a "tool". + +This virtual tool is defined with four fields and it actually used to break the blocks. Since some explosions can include tens of thousands, or even millions of blocks (not recommended... lol) the tool never looses durability. Otherwise if it breaks 1/3 of the way while processing the explosion, then 2/3rds of the explosion will remain unbroken. + +**toolInHandName** Use XSeries' XMaterial names for this field. See the link above under **Bomb itemType**. + +**toolInHandFortuneLevel** sets the fortune level. Uses unsafe enchantments (unlimited). This can greatly impact the amount of the drops. + +**toolInHandDurabilityLevel** sets the durability level. Uses unsafe enchantments (unlimited). Since no wear happens, this really is not needed. + +**toolInHandDigSpeedLevel** sets the dig speed level. Uses unsafe enchantments (unlimited). Since the block break is instant, this really is not needed. + + +
+ + + +## Fuse delay ticks + +The fuse delay, in ticks, is the amount of time it takes from placing the bomb to when it goes off. + + +Within the **nameTag** field, you can use the placeholder `{countDown}` to display how much time is remaining. This placeholder can be used multiple times if desired. + + +Valid values are 0 through no limit. But if the server restarts before a bomb goes off, it may orphan the bomb, or actually the armor stand that is used to represent the detonation point. You would have to manually remove these orphaned armor stands with a command. + +(to do: provide command to remove the armor stands) + +
+ + +## Cooldown + +Once a bomb is used, the field **cooldownTicks** sets how long the player must wait before using that bomb again. A value of 0 has no cooldown. + + +Cooldowns apply to a specific bomb and so if a player has three different kinds in their inventory, they can rapidly set off each one without triggering the cooldowns. So if a player has a stack of 10 smallbombs and it has a cooldown of 10 seconds, then it will take at best, 100 seconds to set them all off. + +
+ + +## Item Removal Delay Ticks + +Just because the bomb goes off, does not mean the item that represents the bomb is removed. It must be manually removed from the game or it will just fall and sit at the bottom of the mine, and no one will be able to pick it up. + + +The field **itemRemovalDelayTicks** is the number of ticks that prison waits after setting off the bomb, before it removes the item from the game. This is important, since if it is removed as soon as the bomb goes off, the player may see it disappear before the explosion and block removal happens. But setting to a small value of ticks, the item can become lost in the visual effects so when it's removed, it's not noticeable. + +
+ +## Glowing + +Glowing does not work well on all versions of spigot. Some versions it's horrible and the whole armor stand glows, other versions does not glow at all. But if you are using a version of spigot where it only glows the itemType, then it's a cool effect. Glowing will allow you, and other players, to see it through other objects and blocks. Kind of like a massive warning of doom. + +Because it may not always work as expected, please test on your server and confirm if it's what like. If not, then disable the field **glowing** by setting to a value of false. + +
+ + +## Gravity + +Just like glowing, the effects may not be what you want. The idea was to place a bomb somewhere, even within the air, and have it ignore gravitational effects. Kind of like hovering, or like Wile e Coyote the moment before he realizes he's ran off the edge of a cliff and is about to fall. + +The reality is that in my testing, the mine bomb items just kind of float off in to space and it's totally a dud. But hey, it's a feature, so maybe you can find a cool way to use them, such as drifting mines that go off in 5 minutes (oh the waiting! lol) so you have no idea where it will wind up within a cavernous mine. + + +
+ + +## Autosell + +With super-large bombs that can produce many times the drops than what a player has the capacity to hold in their inventory, **autosell** will automatically sell every item that was included in that explosive drop. Even if auto feature's autosell is turned off, this will override that setting and sell it for the players. + +As a warning, if you have a super-large explosion, and it drops the blocks, the density of the block pile can overload the player's inventory to the point that it can cause glitching. It can also potentially cause lag too if the entity counts become too high. On my test server, with the oof bomb dropping overflows, it can be almost impossible to pickup all of the blocks, or you have to go in to inventory and move a stack of blocks to get them to popuplate within the player's inventory. So autosell on super huge explosions can eliminate all this mess. + +
+ + +## Sound and Visual Effects - Disclaimer + +Prison supports Spigot 1.8.8 through 1.19.x. Over the years, and with many different versions of minecraft, the names for sound and visual effects have changed. Because prison "tries" to support a wide range of versions, the demo mine bombs includes a variety of sound effects and visual effects for the wide range of versions just so something works. Therefore, it is perfectly normal for the demo mine bombs to show warnings that a particular effect does not exist. Just ignore them, or better yet, remove the ones that are not compatible for your version of spigot. + +Newer versions of spigot has a lot more sound and visual effects than older versions. Way more! + +To list what works on your server, run the following commands in the console. If you're using spigot 1.19.x, then this list will be huge and you will have to do a lot of scrolling. + + +``` +/prison utils bomb list help + +/prison utils bomb list sounds +/prison utils bomb list visuals +``` + +Also, internally, Prison is using the same data object to hold both the sound effects and the visual effects. Therefore the visual effects in the save file lists **volume** and **pitch**. You can ignore them and just use the default value of 1.0 for those fields. +
+ + +## Sound and Visual Effects + +The sound and visual effects are played at different points within the explosion event. These points are identified with **effectState** and the values are: + +* **placed** The starting point is when the bomb is place. An **offsetTicks** of zero runs the effect instantly. Positive values are ticks after placement with no restrictions on max value, but should be within reason. + +* **explode** The starting point for this state is when the bomb explodes. An **offsetTicks** of zero runs the effects when the bomb "explodes". A negative value will run the effect before the explosion. A position value will run the effect after the explosion. + + +* **finished** The starting point for this state is when everything is done. I'm not sure about the **offsetTicks** since finished should be done. + + + + +**offsetTicks** Depending upon what **effectState** is active, this value could be zero, negative, or positive. The purpose of the offsetTicks is to string out multiple effects that are played over time which will layer the visuals and audio effects to make them more intense and unique. + + + +**volumne**: Yeah, there's a typo in there... lol + +Default volume is 1.0. Less is quieter and higher is louder. + + +**pitch** Changes the pitch. 1.0 is the default. Less is lower, and higher is a much higher pitch. + +
diff --git a/docs/prison_docs_900_troubleshooting.md b/docs/prison_docs_900_troubleshooting.md new file mode 100644 index 000000000..620612417 --- /dev/null +++ b/docs/prison_docs_900_troubleshooting.md @@ -0,0 +1,121 @@ + +### Prison Documentation +[Prison Documents - Table of Contents](prison_docs_000_toc.md) + +# Prison Troubleshooting + + +There are a lot of thing that Prison is able to do, but there are even more ways to configure your server with many other plugins. Sometimes there can be conflicts with other plugins, or issues with the way things are configured. + + +This document provides some directions on how to troubleshoot and possible solutions. Topics are broken down in to a Question and Suggestion/Answer format. Follow the directions on how to proceed. + + +*Note: this document is a work in progress.* + + +*Documented updated: 2022-08-30* + +
+ +# Troubleshooting Contents + +* [Cannot Mine or Break Blocks within a Mine](#cannot-mine-or-break-blocks) + + +
+ + + +
+ +# Cannot Mine or Break Blocks + +A player has access to the mine, but yet they cannot break any blocks in that mine. + + +**The Need for Information** + +To help better understand your server's environment and settings, our support team may need the following information. This is a list of items and how to find them, or how to submit them. Some of these details may be needed to help address some of the questions and answers below too. + + +* **Upgrade Prison to the latest alpha release**: Generally, if you found a problem within Prison, so have others and there is a good chance it's been reported and even fixed. So if you have an older release of prison, or you think your issue is related to a bug within Prison, then upgrading to the latest alpha may solve it. The latest alpha release are posted on the Prison discord server, under the #alpha-version channel. To identify the current version of Prison, see the next item. + + +* **Prison Version information**: This information can quickly allow us to evaluate your setup, which can result in quick solutions to your issues. In the console you can use the command `/prison version` to view the details yourself. Or if you need to submit them, then run these two commands and copy and paste the provided URL to the support staff on the Prison discord server. +`/prison support setSupportName ` +`/prison support submit version` + + +* **Auto Feature Settings**: If you're using auto features settings, then we will need to know if auto features are enabled, and if auto features is setup to cancel the event or to cancel the drops. You can tell within the above commands, `/prison version`, or by looking at the autoFeaturesConfig.yml file. For these two settings, one must be true and the other false. Both cannoot be the same value. + + + **Cancel Event settings:** + + cancelAllBlockBreakEvents: true + cancelAllBlockEventBlockDrops: false + + + + **Cancel Drops settings:** + + cancelAllBlockBreakEvents: false + cancelAllBlockEventBlockDrops: true + +
+ + +#### Confirm Player Access to the Mine: + +* **Does the Player has access to the mine?** + + * Prison recommends MineAccessByRank: `/mines set mineAccessByRank help` + * Make sure the mine is linked to a rank: `/mines set rank help` + * The next alternative is AccessByPerms: `/mines set accessPermisssion help` + * Ensure the permission is not a group perm and is accessible through bukkit. If the perm cannot be accessed through bukkit, then it won't work. + * You can check that the perm is accessible through bukkit with `/ranks player perms` but they must be online, and it must be listed under the "(bukkit)" perms group. + * If neither MineAccessByRank and AccessByPerms are used, then access to the mines must be managed through a WorldGuard region, of which, WG must have a lower priority than prison and all the perms must be setup correctly with WG's region and also the permission plugin that you're using. + + +If you are unable to tell if the player has access to the mine, then access may be an issue. + + +To be clear, this question "Does the Player have access to the mine?" is related to personal access and not possible issues with items such as WorldGuard regions being omitted or misconfigured; that's a non-player issue. + + +If you think there is something wrong with player access, then please contact our support team on the Prison discord server. + +
+ + +#### Confirm WorldGuard is Setup Correctly: + +If you have Auto Features configured for **Cancel Drop Settings** (see the section under **The Need for Information**), or you are using an enchantment type plugin, then review the following points and questions: + + +* **If using the MineAccessByRank or AccessByPermisssion settings for your mines**: *Then Prison should have a lower priority than the WorldGuard regions that is setup for that mine. Otherwise, WorldGuard should have a lower priority than prison. + +To confirm, please use this command in the console: +`/prison support listeners blockBreak` + + +* **WorldGuard Region Configured Correctly**: If using WorldGuard regions, then they could be causing issues if they are misconfigured. Your world needs to have a global region with passthrough deny. Then the actual WG region needs to be setup properly. Here's what we have been suggesting: + +``` + +``` + + + + + + +
+ + + + + + +
+ diff --git a/gradle.properties b/gradle.properties index 0297303c1..0d2683ffa 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,7 +3,7 @@ ## # This is actually the "correct" place to define the version for the project. ## # Used within build.gradle with ${project.version}. ## # Can be overridden on the command line: gradle -Pversion=3.2.1-alpha.3 -version=3.3.0-alpha.13 +version=3.3.0-alpha.14 diff --git a/prison-core/src/main/java/tech/mcprison/prison/Prison.java b/prison-core/src/main/java/tech/mcprison/prison/Prison.java index 7c36a7f80..d1ee294a2 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/Prison.java +++ b/prison-core/src/main/java/tech/mcprison/prison/Prison.java @@ -20,9 +20,11 @@ import java.io.File; import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; +import java.util.Locale; import java.util.Optional; import com.google.common.eventbus.EventBus; @@ -109,6 +111,9 @@ public class Prison private List localeLoadInfo; + private static DecimalFormatSymbols dfSym; + private static boolean dfSymStatic = false; + private Prison() { super(); @@ -130,7 +135,70 @@ public static Prison get() { return instance; } + public DecimalFormat getDecimalFormat( String format ) { + DecimalFormat dFmt = new DecimalFormat( format, getDecimalFormatSymbols() ); + return dFmt; + } + public DecimalFormat getDecimalFormatInt() { + return getDecimalFormat("#,##0"); + } + public DecimalFormat getDecimalFormatDouble() { + return getDecimalFormat("#,##0.000"); + } + public static DecimalFormat getDecimalFormatStatic( String format ) { + DecimalFormat dFmt = new DecimalFormat( format, getDecimalFormatSymbolsStatic() ); + return dFmt; + } + public static DecimalFormat getDecimalFormatStaticInt() { + return getDecimalFormatStatic("#,##0"); + } + public static DecimalFormat getDecimalFormatStaticDouble() { + return getDecimalFormatStatic("#,##0.000"); + } + /** + *

This returns the prison's DecimalFormatSymbols, which controls how the + * DecimalFormat is used for various language settings. The en_US language + * settings uses a period for decimal place, and a comma for thousands separator. + * The issue is with UK, and other countries, that are using a non-breaking + * space for the thousands separator since minecraft cannot display that uni-code. + * It is shown as a square with NB on the first line, and SP on the second line. + *

+ * + *

For now, this hard codes prison to use en_US if the config.yml file does not + * have a setting "number-format-location: en_US". + * It should not use the "default-language" + * setting since there needs to be control between the two. + *

+ * + * @return + */ + private DecimalFormatSymbols getDecimalFormatSymbols() { + if ( dfSym == null || dfSymStatic ) { + + String location = getPlatform().getConfigString( "number-format-location", "en_US" ); + String[] loc = location.split("_"); + + Locale locale = new Locale( + loc != null && loc.length >= 1 ? loc[0] : "en", + loc != null && loc.length >= 2 ? loc[1] : "US" ); + +// Locale locale = new Locale( "en", "US" ); + dfSym = new DecimalFormatSymbols( locale ); + dfSymStatic = false; + } + return dfSym; + } + private static DecimalFormatSymbols getDecimalFormatSymbolsStatic() { + if ( dfSym == null ) { + + Locale locale = new Locale( "en", "US" ); + dfSym = new DecimalFormatSymbols( locale ); + dfSymStatic = true; + } + return dfSym; + } + /** * Lazy load LocalManager which ensures Prison is already loaded so * can get the default language to use from the plugin configs. @@ -285,7 +353,7 @@ public void displaySystemSettings( ChatDisplay display ) { long memoryFree = runtime.freeMemory(); long memoryUsed = memoryTotal - memoryFree; - DecimalFormat dFmt = new DecimalFormat("#,##0.000"); + DecimalFormat dFmt = getDecimalFormatDouble(); String memMax = PlaceholdersUtil.formattedIPrefixBinarySize( memoryMax, dFmt, " " ); String memTotal = PlaceholdersUtil.formattedIPrefixBinarySize( memoryTotal, dFmt, " " ); String memFree = PlaceholdersUtil.formattedIPrefixBinarySize( memoryFree, dFmt, " " ); @@ -329,7 +397,7 @@ public void displaySystemSettings( LinkedHashMap fields ) { long memoryFree = runtime.freeMemory(); long memoryUsed = memoryTotal - memoryFree; - DecimalFormat dFmt = new DecimalFormat("#,##0.000"); + DecimalFormat dFmt = getDecimalFormatDouble(); String memMax = PlaceholdersUtil.formattedIPrefixBinarySize( memoryMax, dFmt, " " ); String memTotal = PlaceholdersUtil.formattedIPrefixBinarySize( memoryTotal, dFmt, " " ); String memFree = PlaceholdersUtil.formattedIPrefixBinarySize( memoryFree, dFmt, " " ); @@ -376,7 +444,7 @@ public PrisonStatsUtil getPrisonStatsUtil() { public void displaySystemTPS( ChatDisplay display ) { - DecimalFormat iFmt = new DecimalFormat("#,##0"); + DecimalFormat iFmt = getDecimalFormatInt(); PrisonTPS prisonTPS = Prison.get().getPrisonTPS(); display.addText( "&7Prison TPS Average: %s Min: %s Max: %s%s " + "Interval: %s ticks Samples: %s", @@ -398,7 +466,7 @@ public void displaySystemTPS( ChatDisplay display ) { } public void getSystemTPS( LinkedHashMap fields ) { - //DecimalFormat iFmt = new DecimalFormat("#,##0"); + //DecimalFormat iFmt = getDecimalFormatInt(); PrisonTPS prisonTPS = Prison.get().getPrisonTPS(); fields.put( "tps", prisonTPS.getAverageTPSFormatted() ); @@ -426,8 +494,8 @@ private void getPrisonDiskSpaceUsage( ChatDisplay display, calculatePrisonDiskUsage( diskStats, prisonFolder ); - DecimalFormat dFmt = new DecimalFormat("#,##0.000"); - DecimalFormat iFmt = new DecimalFormat("#,##0"); + DecimalFormat dFmt = getDecimalFormatDouble(); + DecimalFormat iFmt = getDecimalFormatInt(); String prisonFileCount = iFmt.format( diskStats.getFileCount() ); String prisonFolderCount = iFmt.format( diskStats.getFolderCount() ); @@ -450,8 +518,8 @@ public void getPrisonDiskSpaceUsage( LinkedHashMap fields ) { calculatePrisonDiskUsage( diskStats, prisonFolder ); - DecimalFormat dFmt = new DecimalFormat("#,##0.000"); - DecimalFormat iFmt = new DecimalFormat("#,##0"); + DecimalFormat dFmt = getDecimalFormatDouble(); + DecimalFormat iFmt = getDecimalFormatInt(); String prisonFileCount = iFmt.format( diskStats.getFileCount() ); // String prisonFolderCount = iFmt.format( diskStats.getFolderCount() ); diff --git a/prison-core/src/main/java/tech/mcprison/prison/PrisonCommand.java b/prison-core/src/main/java/tech/mcprison/prison/PrisonCommand.java index 6e9504e81..56db240b5 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/PrisonCommand.java +++ b/prison-core/src/main/java/tech/mcprison/prison/PrisonCommand.java @@ -28,16 +28,19 @@ import java.util.Optional; import java.util.Set; import java.util.TreeMap; +import java.util.TreeSet; import java.util.UUID; import tech.mcprison.prison.autofeatures.AutoFeaturesFileConfig.AutoFeatures; import tech.mcprison.prison.autofeatures.AutoFeaturesWrapper; +import tech.mcprison.prison.backpacks.BackpackConverterOldPrisonBackpacks; import tech.mcprison.prison.backups.PrisonBackups; import tech.mcprison.prison.backups.PrisonBackups.BackupTypes; import tech.mcprison.prison.cache.PlayerCachePlayerData; import tech.mcprison.prison.commands.Arg; import tech.mcprison.prison.commands.Command; import tech.mcprison.prison.commands.CommandPagedData; +import tech.mcprison.prison.commands.RegisteredCommand; import tech.mcprison.prison.commands.Wildcard; import tech.mcprison.prison.discord.PrisonPasteChat; import tech.mcprison.prison.internal.CommandSender; @@ -597,6 +600,7 @@ public void placeholdersTestCommand(CommandSender sender, builder.add( String.format( "&7 Original: \\Q%s\\E", text)); + builder.add( String.format( "&7 Translated: %s", translated)); display.addComponent(builder.build()); @@ -724,7 +728,7 @@ public void placeholdersSearchCommand(CommandSender sender, } - DecimalFormat dFmt = new DecimalFormat("#,##0"); + DecimalFormat dFmt = Prison.get().getDecimalFormatInt(); builder.add( String.format( "&7 Results: &c%s &7Original patterns: &3%s", dFmt.format(placeholders.size()), patterns )); @@ -762,8 +766,9 @@ public void placeholdersListCommand(CommandSender sender ChatDisplay display = new ChatDisplay("Placeholders List"); display.addText( "&a Placeholders are case insensitive, but are registered in all lowercase."); - display.addText( "&a Chat based placeholders use { }, but others may use other escape codes like %% %%."); - display.addText( "&a Mine based placeholders uses the mine name to replace 'minename'."); + display.addText( "&a Placeholder escape characters may be { } or % %. If one does not work, try the other."); + display.addText( "&a Placeholders that include 'rankname', 'laddername', or 'minename' should be"); + display.addText( "&a replaced with the appropriate rank names, ladder names, or mine names."); for ( String disabledModule : Prison.get().getModuleManager().getDisabledModules() ) { display.addText( "&a &cDisabled Module: &7%s&a. Related placeholders maybe listed but are non-functional. ", @@ -785,11 +790,24 @@ public void placeholdersListCommand(CommandSender sender @Command(identifier = "prison placeholders stats", description = "List all placeholders that have been requested since server startup.", onlyPlayers = false, permissions = "prison.placeholder") - public void placeholdersStatsCommand(CommandSender sender + public void placeholdersStatsCommand(CommandSender sender, + @Arg(name = "options", description = "Options for the cache. " + + "[resetCache] this will clear the placeholder " + + "cache of all placeholders and all placeholders will have to be reidentified. " + + "[removeErrors] all cached placeholders that have been marked as invalid will " + + "be removed from the cache and will have to be reevaluated if used again.", + def = "." ) String options ) { ChatDisplay display = new ChatDisplay("Placeholders List"); + if ( options != null && !".".equals(options) ) { + boolean resetCache = "resetCache".equalsIgnoreCase( options ); + boolean removeErrors = "removeErrors".equalsIgnoreCase( options ); + + PlaceholdersStats.getInstance().clearCache( resetCache, removeErrors ); + } + ArrayList stats = PlaceholdersStats.getInstance().generatePlaceholderReport(); for (String stat : stats) { @@ -963,6 +981,12 @@ public void autoFeaturesInformation(CommandSender sender) { display.addText( "&b options.blockBreakEvents.CrazyEnchantsBlastUseEventPriority: %s", afw.getMessage( AutoFeatures.CrazyEnchantsBlastUseEventPriority ) ); + display.addText( "&b options.blockBreakEvents.RevEnchantsExplosiveEventPriority: %s", + afw.getMessage( AutoFeatures.RevEnchantsExplosiveEventPriority ) ); + + display.addText( "&b options.blockBreakEvents.RevEnchantsJackHammerEventPriority: %s", + afw.getMessage( AutoFeatures.RevEnchantsJackHammerEventPriority ) ); + display.addText( "&b options.blockBreakEvents.ZenchantmentsBlockShredEventPriority: %s", afw.getMessage( AutoFeatures.ZenchantmentsBlockShredEventPriority ) ); @@ -1153,6 +1177,65 @@ public void findCommand(CommandSender sender, command, registered ); } + + + @Command(identifier = "prison support cmdStats", + description = "Stats on Prison command stats. Only shows actual commands that are used.", + onlyPlayers = false, permissions = "prison.debug" ) + public void statsCommand(CommandSender sender ) { + + List cmds = getCommandStats(); + for (String cmd : cmds) { + + Output.get().logInfo( cmd ); + } + } + + private List getCommandStats() { + List results = new ArrayList<>(); + + DecimalFormat iFmt = Prison.get().getDecimalFormatInt(); + DecimalFormat dFmt = Prison.get().getDecimalFormatDouble(); + + TreeSet allCmds = Prison.get().getCommandHandler().getAllRegisteredCommands(); + + results.add( "Prison Command Stats:" ); + results.add( + Output.stringFormat( " &a&n%-40s&r &a&n%7s&r &a&n%-11s&r", + " Commands ", " Usage ", " Avg ms ") ); + + int count = 0; + int totals = 0; + double totalDuration = 0d; + for (RegisteredCommand cmd : allCmds) { + + if ( cmd.getUsageCount() > 0 ) { + + double duration = cmd.getUsageRunTimeNanos() / (double) cmd.getUsageCount() / 1000000.0d; + + results.add( Output.stringFormat( " &2%-40s &2%7s &2%11s", + cmd.getCompleteLabel(), + iFmt.format( cmd.getUsageCount() ), + dFmt.format( duration ) + ) ); + count++; + totals += cmd.getUsageCount(); + totalDuration += cmd.getUsageRunTimeNanos(); + } + } + + results.add( Output.stringFormat(" &3Total Registered Prison Commands: &7%9s", iFmt.format( allCmds.size() )) ); + results.add( Output.stringFormat(" &3Total Prison Commands Listed: &7%9s", iFmt.format( count )) ); + results.add( Output.stringFormat(" &3Total Prison Command Usage: &7%9s", iFmt.format( totals )) ); + + double avgDuration = totalDuration / (double) count / 1000000.0d; + results.add( Output.stringFormat(" &3Average Command Duration ms: &7%9s", dFmt.format( avgDuration )) ); + + results.add( " &d&oNOTE: Async Commands like '/mines reset' will not show actual runtime values. " ); + + + return results; + } @Command(identifier = "prison support runCmd", @@ -1233,7 +1316,41 @@ public void supportSubmitVersion(CommandSender sender StringBuilder text = Prison.get().getPrisonStatsUtil().getSupportSubmitVersionData(); + + int idx = text.indexOf("{br}"); + while ( idx != -1 ) { + // Convert `{br}` to `\n`: + text.replace(idx, idx+4, "\n"); + + idx = text.indexOf("{br}"); + } + + + // Add all of the listeners details: + text.append( "\n\n" ); + text.append( + Prison.get().getPrisonStatsUtil().getSupportSubmitListenersData( "all" ) + ); + + // Include the command stats: + text.append( "\n\n" ); + List cmdStats = getCommandStats(); + for (String cmd : cmdStats) { + text.append( cmd ).append( "\n" ); + } + + + // Include Prison backup logs: + text.append( "\n\n" ); + text.append( "Prison Backup Logs:" ).append( "\n" ); + List backupLogs = getPrisonBackupLogs(); + + for (String log : backupLogs) { + text.append( Output.decodePercentEncoding(log) ).append( "\n" ); + } + + PrisonPasteChat pasteChat = new PrisonPasteChat( getSupportName(), getSupportURLs() ); String helpURL = pasteChat.post( text.toString() ); @@ -1376,6 +1493,26 @@ public void supportSubmitMines(CommandSender sender } + + + + @Command(identifier = "prison backpacks listOld", + description = "Using the new prison backpack cache interface, this will list existing " + + "backpacks under the old prison backpack system. ", + onlyPlayers = false, permissions = "prison.debug" ) + public void backpacksListOldCmd(CommandSender sender + ) { + + BackpackConverterOldPrisonBackpacks converter = new BackpackConverterOldPrisonBackpacks(); + + converter.convertOldBackpacks(); + + + } + + + + // // private StringBuilder getSupportSubmitVersionData() { // ChatDisplay display = displayVersion("ALL"); @@ -1473,7 +1610,7 @@ public void supportSubmitMines(CommandSender sender // // private void addFileToText( File file, StringBuilder sb ) // { -// DecimalFormat dFmt = new DecimalFormat("#,##0"); +// DecimalFormat dFmt = Prison.get().getDecimalFormatInt(); // SimpleDateFormat sdFmt = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss" ); // // sb.append( "\n" ); @@ -1713,7 +1850,7 @@ public void supportListenersDump(CommandSender sender, } - @Command(identifier = "prison support backup", + @Command(identifier = "prison support backup save", description = "This will make a backup of all Prison settings by creating a new " + "zip file which will be stored in the directory plugins/Prison/backups. " + "After creating the backup, this will delete all temp files, backup files, etc.. " + @@ -1734,7 +1871,32 @@ public void supportBackupPrison( CommandSender sender, sender.sendMessage( "Backup finished." ); } + + @Command(identifier = "prison support backup logs", + description = "This will list Prison backup logs that are in the file " + + "`plugins/Prison/backup/versions.log`", + onlyPlayers = false, permissions = "prison.debug" ) + public void supportBackupList( CommandSender sender ) { + + ChatDisplay display = new ChatDisplay("Prison Backup Logs:"); + + List backupLogs = getPrisonBackupLogs(); + + for (String log : backupLogs) { + display.addText(log); + } + + display.send(sender); + + } + + private List getPrisonBackupLogs() { + PrisonBackups prisonBackup = new PrisonBackups(); + List backupLogs = prisonBackup.backupReport02BackupLog(); + return backupLogs; + } + @Command(identifier = "prison tokens balance", description = "Prison tokens: a player's current balance.", // aliases = "tokens bal", @@ -1785,7 +1947,7 @@ public void tokensBalance(CommandSender sender, coreTokensBalanceViewMsg( sender, player.getName(), tokens ); -// DecimalFormat dFmt = new DecimalFormat("#,##0"); +// DecimalFormat dFmt = Prison.get().getDecimalFormatInt(); // String tokensMsg = dFmt.format( tokens ); // // String message = String.format( "&3%s has %s tokens.", player.getName(), tokensMsg ); @@ -1829,7 +1991,7 @@ public void tokensAdd( CommandSender sender, return; } -// DecimalFormat dFmt = new DecimalFormat("#,##0"); +// DecimalFormat dFmt = Prison.get().getDecimalFormatInt(); if ( amount <= 0 ) { @@ -1927,7 +2089,7 @@ public void tokensRemove( CommandSender sender, return; } -// DecimalFormat dFmt = new DecimalFormat("#,##0"); +// DecimalFormat dFmt = Prison.get().getDecimalFormatInt(); if ( amount <= 0 ) { @@ -2015,7 +2177,7 @@ public void tokensSet( CommandSender sender, return; } -// DecimalFormat dFmt = new DecimalFormat("#,##0"); +// DecimalFormat dFmt = Prison.get().getDecimalFormatInt(); Player player = getPlayer( playerName ); diff --git a/prison-core/src/main/java/tech/mcprison/prison/PrisonCommandMessages.java b/prison-core/src/main/java/tech/mcprison/prison/PrisonCommandMessages.java index 5903b215a..cc6ebeae2 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/PrisonCommandMessages.java +++ b/prison-core/src/main/java/tech/mcprison/prison/PrisonCommandMessages.java @@ -43,7 +43,7 @@ protected void coreTokensBalanceCannotViewOthersMsg( CommandSender sender ) { protected void coreTokensBalanceViewMsg( CommandSender sender, String name, long tokens ) { - DecimalFormat dFmt = new DecimalFormat("#,##0"); + DecimalFormat dFmt = Prison.get().getDecimalFormatInt(); String tokensMsg = dFmt.format( tokens ); Prison.get().getLocaleManager() @@ -55,7 +55,7 @@ protected void coreTokensBalanceViewMsg( CommandSender sender, String name, long protected void coreTokensAddInvalidAmountMsg( CommandSender sender, long tokens ) { - DecimalFormat dFmt = new DecimalFormat("#,##0"); + DecimalFormat dFmt = Prison.get().getDecimalFormatInt(); String tokensMsg = dFmt.format( tokens ); Prison.get().getLocaleManager() @@ -68,7 +68,7 @@ protected void coreTokensAddInvalidAmountMsg( CommandSender sender, long tokens protected String coreTokensAddedAmountMsg( String name, long tokens, long amount ) { - DecimalFormat dFmt = new DecimalFormat("#,##0"); + DecimalFormat dFmt = Prison.get().getDecimalFormatInt(); String tokensMsg = dFmt.format( tokens ); String amountMsg = dFmt.format( amount ); @@ -82,7 +82,7 @@ protected String coreTokensAddedAmountMsg( protected String coreTokensRemovedAmountMsg( String name, long tokens, long amount ) { - DecimalFormat dFmt = new DecimalFormat("#,##0"); + DecimalFormat dFmt = Prison.get().getDecimalFormatInt(); String tokensMsg = dFmt.format( tokens ); String amountMsg = dFmt.format( amount ); @@ -96,7 +96,7 @@ protected String coreTokensRemovedAmountMsg( protected String coreTokensSetAmountMsg( String name, long tokens ) { - DecimalFormat dFmt = new DecimalFormat("#,##0"); + DecimalFormat dFmt = Prison.get().getDecimalFormatInt(); String tokensMsg = dFmt.format( tokens ); return Prison.get().getLocaleManager() diff --git a/prison-core/src/main/java/tech/mcprison/prison/autofeatures/AutoFeaturesFileConfig.java b/prison-core/src/main/java/tech/mcprison/prison/autofeatures/AutoFeaturesFileConfig.java index fecbffd13..0d3ea8fb8 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/autofeatures/AutoFeaturesFileConfig.java +++ b/prison-core/src/main/java/tech/mcprison/prison/autofeatures/AutoFeaturesFileConfig.java @@ -119,6 +119,9 @@ public enum AutoFeatures { CrazyEnchantsBlastUseEventPriority(blockBreakEvents, "DISABLED"), + RevEnchantsExplosiveEventPriority(blockBreakEvents, "DISABLED"), + RevEnchantsJackHammerEventPriority(blockBreakEvents, "DISABLED"), + ZenchantmentsBlockShredEventPriority(blockBreakEvents, "DISABLED"), PrisonEnchantsExplosiveEventPriority(blockBreakEvents, "DISABLED"), @@ -129,6 +132,27 @@ public enum AutoFeatures { "Use the following event priorities with the blockBreakEvents: " + "DISABLED, LOWEST, LOW, NORMAL, HIGH, HIGHEST, BLOCKEVENTS, MONITOR" ), + blockBreakEvents__ReadMe2(blockBreakEvents, + "MONITOR: Processed even if event is canceled. Includes block counts, " + + "Mine Sweeper, and check reset-threshold (zero-block) conditions " + + "to force a mine reset. " + + "BLOCKEVENTS: Similar to MONITOR but includes Prison Block Events, " + + "and sellall on full inventory if enabled." ), + + blockBreakEvents__ReadMe3(blockBreakEvents, + "ACCESS: Processed as a LOWEST priority and will check to see if the " + + "player has access to the mine. If they do not have access, then the " + + "event will be canceled. No other processing is performed. " + + "ACCESSBLOCKEVENTS combines two priorities: ACCESS and BLOCKEVENTS. " + + "ACCESSMONITOR combines two priorities: ACCESS and MONITOR." ), + + + eventPriorityACCESSFailureTPToCurrentMine(blockBreakEvents, true ), + + blockBreakEvents__ReadMe4(blockBreakEvents, + "ACCESS failure: if 'TPToCurrentMine' is enabled, then a failure with the " + + "ACCESS priority will TP the player back to the mine that is linked to " + + "their current rank using '/mines tp' with no mine specified." ), general(options), @@ -1001,6 +1025,9 @@ public TreeMap getBstatsDetails() { bStatsDetailPriority( AutoFeatures.ProcessPrisons_ExplosiveBlockBreakEventsPriority, tm ); bStatsDetailPriority( AutoFeatures.TokenEnchantBlockExplodeEventPriority, tm ); bStatsDetailPriority( AutoFeatures.CrazyEnchantsBlastUseEventPriority, tm ); + bStatsDetailPriority( AutoFeatures.RevEnchantsExplosiveEventPriority, tm ); + bStatsDetailPriority( AutoFeatures.RevEnchantsJackHammerEventPriority, tm ); + bStatsDetailPriority( AutoFeatures.ZenchantmentsBlockShredEventPriority, tm ); bStatsDetailPriority( AutoFeatures.PrisonEnchantsExplosiveEventPriority, tm ); diff --git a/prison-core/src/main/java/tech/mcprison/prison/backpacks/BackpackCache.java b/prison-core/src/main/java/tech/mcprison/prison/backpacks/BackpackCache.java new file mode 100644 index 000000000..34a62c2eb --- /dev/null +++ b/prison-core/src/main/java/tech/mcprison/prison/backpacks/BackpackCache.java @@ -0,0 +1,421 @@ +package tech.mcprison.prison.backpacks; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.SortedMap; +import java.util.TreeMap; + +import tech.mcprison.prison.cache.PlayerCacheStats; +import tech.mcprison.prison.internal.Player; +import tech.mcprison.prison.tasks.PrisonTaskSubmitter; + +public class BackpackCache { + + public static final String BACKPACK_CACHE_WRITE_DELAY_CONFIG_NAME = "backpack.cache.write_delay"; + public static final long BACKPACK_CACHE_WRITE_DELAY_VALUE_MS = 60000; // 60 seconds + + public static final String BACKPACK_CACHE_TIME_TO_LIVE_CONFIG_NAME = "backpack.cache.time_to_live"; + public static final long BACKPACK_CACHE_TIME_TO_LIVE_VALUE_MS = 30 * 60 * 1000; // 30 mins + + private static BackpackCache instance; + + private BackpackCacheFiles cacheFiles; + private BackpackCacheEvents cacheEvents; + + +// private long writeDelay = 0L; + + private PlayerCacheStats stats; + + + private SortedMap players; + + private Map tasks; + + private BackpackCacheRunnable saveAllTask; + + + + private BackpackCache() { + super(); + + this.players = Collections.synchronizedSortedMap( new TreeMap<>() ); + + this.tasks = Collections.synchronizedMap( new HashMap<>() ); + + this.cacheFiles = new BackpackCacheFiles(); + + + this.stats = new PlayerCacheStats(); + + } + + public static BackpackCache getInstance() { + if ( instance == null ) { + synchronized ( BackpackCache.class ) + { + if ( instance == null ) { + + instance = new BackpackCache(); + instance.internalInititalize(); + } + } + } + return instance; + } + + + + private void internalInititalize() { + + // The BackpackCacheEvents self-registers with Prison's eventBus: + cacheEvents = new BackpackCacheEvents(); + + saveAllTask = submitCacheRefresh(); + + } + + /** + *

The plugin is shutting down so flush all dirty cache items, but first + * disable the caching so as any changes are passed through directly to the + * database. + *

+ * + *

Since the plugin is shutting down, flush the cache synchronously in this + * thread. Do not submit, or the database may be shutdown before all dirty + * cache items can be saved. + *

+ */ + public static void onDisable() { + getInstance().onDisableInternal(); + + } + + /** + *

This shuts down the cache and unloads all the players while + * updating the database if they have uncommitted values. This also + * will cancel any outstanding tasks and then flush the uncommitted + * values if they still exist. + *

+ * + *

This function runs all database transactions synchronously so as to + * ensure all data is written to the database before the server is + * terminated. + *

+ * + */ + private void onDisableInternal() { + + // Shutdown the save all task so it won't reload players or try to refresh data: + PrisonTaskSubmitter.cancelTask( saveAllTask.getTaskId() ); + + // Shutdown the timerTasks +// PrisonTaskSubmitter.cancelTask( checkTimersTask.getTaskId() ); + + + // save all dirty cache items and purge cache: + if ( getPlayers().size() > 0 ) { + + + Set keys = getPlayers().keySet(); + + synchronized ( getPlayers() ) { + + for ( String key : keys ) { + // Remove the player from the cache and get the playerData: + BackpackCachePlayerData playerData = getPlayers().remove( key ); + + if ( playerData != null ) { + + // Note: Since we are logging online time, then all players that are + // in the cache are considered constantly dirty and needs to be + // saved. + + // Since the disable function has been called, we can only assume the + // server is shutting down. We need to save dirty player caches, but + // they must be done in-line so the shutdown process will wait for all + // players to be saved. + + getCacheFiles().toJsonFile( playerData ); + + if ( playerData.getTask() != null ) { + + synchronized( getTasks() ) { + + getTasks().remove( playerData.getTask() ); + } + + PrisonTaskSubmitter.cancelTask( playerData.getTask().getTaskId() ); + } + } + } + } + + } + + // Cancel and flush any uncompleted tasks that are scheduled to run: + if ( getTasks().size() > 0 ) { + + + Set keys = getTasks().keySet(); + + for ( BackpackCacheRunnable key : keys ) { + + if ( !key.isCancelled() ) { + // Cancel the task: + key.cancel(); + + // Remove the task and get the player data: + BackpackCachePlayerData playerData = null; + + synchronized( getTasks() ) { + + playerData = getTasks().remove( key ); + } + + if ( playerData != null && + playerData.getTask() != null && + playerData.getTask().getTaskId() > 0 ) { + + PrisonTaskSubmitter.cancelTask( playerData.getTask().getTaskId() ); + } + + } + } + + } + + // Shutdown the connections: + + } + + + + public void addPlayerData( BackpackCachePlayerData playerData ) { + + if ( playerData != null ) { + getStats().incrementLoadPlayers(); + + synchronized ( getPlayers() ) { + + getPlayers().put( playerData.getPlayerUuid(), playerData ); + } + + } + } + + public BackpackCachePlayerData removePlayerData( BackpackCachePlayerData playerData ) { + BackpackCachePlayerData removed = playerData; + if ( playerData != null ) { + getStats().incrementRemovePlayers(); + + synchronized ( getPlayers() ) { + + removed = getPlayers().remove( playerData.getPlayerUuid() ); + } + } + return removed; + } + + + /** + *

This function will return a null if the player is not loaded in the cache. + * Null is a valid value even if the player is online. + * This function should NEVER be used + * for any critical data such as tracking blocks, time, earnings, or inventory. + * Examples of acceptable loss would be with messaging. Loss of a few messages is + * not that critical, and actually would be a very rare situation. Example, if a + * player is mining then their cache should already be loaded so calling this function + * should never find the situation where the player's cache entry does not exist. + *

+ * + *

Since this function will fail with the return a null if the player is not loaded, + * this function will not cause blocking on the runnable thread. + *

+ * + *

If the player is not loaded, and a null is returned, then an async task + * will be submitted to load it. + *

+ * + * @param player + * @return + */ + public BackpackCachePlayerData getOnlinePlayer( Player player ) { + BackpackCachePlayerData playerData = getPlayer( player ); + + return playerData; + } + + private BackpackCachePlayerData getPlayer( Player player ) { + return getPlayer( player, true ); + } + + + /** + *

This returns the cached player object. If they have not been loaded + * yet, then this will load the player object while waiting for it. + *

+ * + *

This used to return a null while submitting a loadPlayer task. + *

+ * + * @param player + * @return The cached player object. If null, then may indicate the player is + * actively being loaded, so try again later. + */ + private BackpackCachePlayerData getPlayer( Player player, boolean loadIfNotInCache ) { + BackpackCachePlayerData playerData = null; + getStats().incrementGetPlayers(); + + if ( player != null && player.getUUID() != null ) { + + String playerUuid = player.getUUID().toString(); + + + if ( getPlayers().containsKey( playerUuid ) ) { + + // Note: if the player has not been loaded yet, this will return a null: + synchronized ( getPlayers() ) { + + playerData = getPlayers().get( playerUuid ); + } + } + else if ( loadIfNotInCache ) { + + // Load the player's existing balance: + playerData = getCacheFiles().fromJson( player ); + + // NOTE: playerData.isOnline() is dynamic and tied back to the Player object. + // So if they are offline, an OfflinePlayer, then it will automatically + // track that. Also if the PlayerData object does not have a reference + /// to Player, then it's automatically considered offline. + + // Save it to the cache: + addPlayerData( playerData ); +// runLoadPlayerNow( player ); +// submitAsyncLoadPlayer( player ); + } + + if ( playerData != null ) { + + if ( playerData.getPlayer() == null || !playerData.getPlayer().equals( player ) ) { + + playerData.setPlayer( player ); + } + +// playerData.updateLastSeen(); + } + } + + return playerData; + } + + + protected void submitAsyncLoadPlayer( Player player ) { + + if ( player != null ) { + + BackpackCacheLoadPlayerTask task = new BackpackCacheLoadPlayerTask( player ); + + // Submit task to run right away: + int taskId = PrisonTaskSubmitter.runTaskLaterAsync( task, 0 ); + task.setTaskId( taskId ); + } + } + + +// /** +// *

This loads the player cache object inline. It does not run it as a +// * task in another thread. +// *

+// * +// *

This is not used anywhere. +// *

+// * +// * @param player +// */ +// protected void runLoadPlayerNow( Player player ) { +// +// if ( player != null ) { +// +// PlayerCacheLoadPlayerTask task = new PlayerCacheLoadPlayerTask( player ); +// +// task.run(); +//// // Submit task to run right away: +//// int taskId = PrisonTaskSubmitter.runTaskLaterAsync( task, 0 ); +//// task.setTaskId( taskId ); +// } +// } + + + protected void submitAsyncUnloadPlayer( Player player ) { + + BackpackCachePlayerData playerData = getPlayer( player, false ); + + if ( playerData != null ) { + + // Submit to unload right away with no delay: + BackpackCacheUnloadPlayerTask task = new BackpackCacheUnloadPlayerTask( playerData ); + int taskId = PrisonTaskSubmitter.runTaskLaterAsync( task, 0 ); + task.setTaskId( taskId ); + } + } + + + + /** + * Submit task to run only once. Should be started when this cache initializes. + * + */ + public BackpackCacheRunnable submitCacheRefresh() { + + BackpackCacheSaveAllPlayersTask task = new BackpackCacheSaveAllPlayersTask(); + + // Submit Timer Task to start running in 10 minutes (6000 ticks) and then + // refresh stats every 5 minutes (3000 ticks): + int taskId = PrisonTaskSubmitter.runTaskTimerAsync( task, 6000, 3000 ); + task.setTaskId( taskId ); + + return task; + } + + + + public BackpackCacheFiles getCacheFiles() { + return cacheFiles; + } + public void setCacheFiles(BackpackCacheFiles cacheFiles) { + this.cacheFiles = cacheFiles; + } + + public BackpackCacheEvents getCacheEvents() { + return cacheEvents; + } + public void setCacheEvents(BackpackCacheEvents cacheEvents) { + this.cacheEvents = cacheEvents; + } + + public PlayerCacheStats getStats() { + return stats; + } + public void setStats(PlayerCacheStats stats) { + this.stats = stats; + } + + public SortedMap getPlayers() { + return players; + } + public void setPlayers(SortedMap players) { + this.players = players; + } + + public Map getTasks() { + return tasks; + } + public void setTasks(Map tasks) { + this.tasks = tasks; + } + +} diff --git a/prison-core/src/main/java/tech/mcprison/prison/backpacks/BackpackCacheEvents.java b/prison-core/src/main/java/tech/mcprison/prison/backpacks/BackpackCacheEvents.java new file mode 100644 index 000000000..2b4e3a1c7 --- /dev/null +++ b/prison-core/src/main/java/tech/mcprison/prison/backpacks/BackpackCacheEvents.java @@ -0,0 +1,40 @@ +package tech.mcprison.prison.backpacks; + +import com.google.common.eventbus.Subscribe; + +import tech.mcprison.prison.Prison; +import tech.mcprison.prison.internal.Player; +import tech.mcprison.prison.internal.events.player.PlayerJoinEvent; +import tech.mcprison.prison.internal.events.player.PlayerKickEvent; +import tech.mcprison.prison.internal.events.player.PlayerQuitEvent; + +public class BackpackCacheEvents { + + public BackpackCacheEvents() { + super(); + + Prison.get().getEventBus().register(this); + } + + + @Subscribe + public void onPlayerJoin(PlayerJoinEvent event) { + + Player player = event.getPlayer(); + BackpackCache.getInstance().submitAsyncLoadPlayer( player ); + } + + @Subscribe + public void onPlayerQuit(PlayerQuitEvent event) { + + Player player = event.getPlayer(); + BackpackCache.getInstance().submitAsyncUnloadPlayer( player ); + } + + @Subscribe + public void onPlayerKicked(PlayerKickEvent event) { + + Player player = event.getPlayer(); + BackpackCache.getInstance().submitAsyncUnloadPlayer( player ); + } +} diff --git a/prison-core/src/main/java/tech/mcprison/prison/backpacks/BackpackCacheFiles.java b/prison-core/src/main/java/tech/mcprison/prison/backpacks/BackpackCacheFiles.java new file mode 100644 index 000000000..0109b0ddb --- /dev/null +++ b/prison-core/src/main/java/tech/mcprison/prison/backpacks/BackpackCacheFiles.java @@ -0,0 +1,25 @@ +package tech.mcprison.prison.backpacks; + +import tech.mcprison.prison.cache.CoreCacheData; +import tech.mcprison.prison.cache.CoreCacheFiles; +import tech.mcprison.prison.internal.Player; + +public class BackpackCacheFiles + extends CoreCacheFiles +{ + public static final String FILE_BACKPACK_CACHE_PATH = "data_storage/backpackCache"; + + + public BackpackCacheFiles() { + super( FILE_BACKPACK_CACHE_PATH ); + + } + + public BackpackCachePlayerData fromJson( Player player ) { + + CoreCacheData results = fromJson( player, BackpackCachePlayerData.class ); + + return (BackpackCachePlayerData) results; + } + +} diff --git a/prison-core/src/main/java/tech/mcprison/prison/backpacks/BackpackCacheLoadPlayerTask.java b/prison-core/src/main/java/tech/mcprison/prison/backpacks/BackpackCacheLoadPlayerTask.java new file mode 100644 index 000000000..7d1de58a2 --- /dev/null +++ b/prison-core/src/main/java/tech/mcprison/prison/backpacks/BackpackCacheLoadPlayerTask.java @@ -0,0 +1,32 @@ +package tech.mcprison.prison.backpacks; + +import tech.mcprison.prison.internal.Player; + +public class BackpackCacheLoadPlayerTask + extends BackpackCacheTask +{ + + private Player player; + + public BackpackCacheLoadPlayerTask( Player player ) { + super( null ); + + this.player = player; + } + + public void run() { + + BackpackCache bCache = BackpackCache.getInstance(); + + BackpackCachePlayerData playerData = bCache.getCacheFiles().fromJson( player ); + + if ( playerData != null ) { + + synchronized ( bCache.getPlayers() ) { + + } + } + + } + +} diff --git a/prison-core/src/main/java/tech/mcprison/prison/backpacks/BackpackCachePlayerData.java b/prison-core/src/main/java/tech/mcprison/prison/backpacks/BackpackCachePlayerData.java new file mode 100644 index 000000000..28d692698 --- /dev/null +++ b/prison-core/src/main/java/tech/mcprison/prison/backpacks/BackpackCachePlayerData.java @@ -0,0 +1,122 @@ +package tech.mcprison.prison.backpacks; + +import java.io.File; +import java.util.Set; +import java.util.TreeMap; + +import tech.mcprison.prison.cache.CoreCacheData; +import tech.mcprison.prison.internal.Player; + +public class BackpackCachePlayerData + implements CoreCacheData { + + private transient Player player; + + private String playerUuid; + private String playerName; + + private transient File playerFile = null; + +// /** +// * This Object lock is used to synchronized the public side of this class +// * and the protected side of this class which is the database transaction +// * side of things. +// */ +// @SuppressWarnings( "unused" ) +// private transient final Object lock = new Object(); + + private transient BackpackCacheRunnable task = null; + + + private TreeMap backpacks; + + + private transient boolean dirty = false; + + + public BackpackCachePlayerData() { + super(); + + this.backpacks = new TreeMap<>(); + } + + public BackpackCachePlayerData( Player player, File playerFile ) { + this(); + + this.player = player; + + + this.playerUuid = player.getUUID().toString(); + this.playerName = player.getName(); + + this.playerFile = playerFile; + + } + + public String toString() { + StringBuilder sb = new StringBuilder(); + + sb.append( getPlayerName() ).append( ": " ); + + Set keys = getBackpacks().keySet(); + for (String key : keys) { + PlayerBackpack bp = getBackpacks().get(key); + + sb.append( "[" ).append( bp.getBackpackType() ) + .append( " " ).append( bp.getName() ) + .append( " size: ").append( bp.getInventorySize() ) + .append( "] " ); + } + + return sb.toString(); + } + + protected Player getPlayer() { + return player; + } + protected void setPlayer( Player player ) { + this.player = player; + } + + public TreeMap getBackpacks() { + return backpacks; + } + public void setBackpacks(TreeMap backpacks) { + this.backpacks = backpacks; + } + + public File getPlayerFile() { + return playerFile; + } + public void setPlayerFile( File playerFile ) { + this.playerFile = playerFile; + } + + public String getPlayerUuid() { + return playerUuid; + } + public void setPlayerUuid( String playerUuid ) { + this.playerUuid = playerUuid; + } + + public String getPlayerName() { + return playerName; + } + public void setPlayerName( String playerName ) { + this.playerName = playerName; + } + + public BackpackCacheRunnable getTask() { + return task; + } + public void setTask(BackpackCacheRunnable task) { + this.task = task; + } + + public boolean isDirty() { + return dirty; + } + public void setDirty( boolean dirty ) { + this.dirty = dirty; + } +} diff --git a/prison-core/src/main/java/tech/mcprison/prison/backpacks/BackpackCacheRunnable.java b/prison-core/src/main/java/tech/mcprison/prison/backpacks/BackpackCacheRunnable.java new file mode 100644 index 000000000..cd55ca89d --- /dev/null +++ b/prison-core/src/main/java/tech/mcprison/prison/backpacks/BackpackCacheRunnable.java @@ -0,0 +1,32 @@ +package tech.mcprison.prison.backpacks; + +import tech.mcprison.prison.tasks.PrisonRunnable; + +public abstract class BackpackCacheRunnable + implements PrisonRunnable { + + private int taskId = 0; + private boolean cancelled = false; + + public BackpackCacheRunnable() { + super(); + + } + + public int getTaskId() { + return taskId; + } + public void setTaskId( int taskId ) { + this.taskId = taskId; + } + + public void cancel() { + setCancelled( true ); + } + public boolean isCancelled() { + return cancelled; + } + public void setCancelled( boolean cancelled ) { + this.cancelled = cancelled; + } +} diff --git a/prison-core/src/main/java/tech/mcprison/prison/backpacks/BackpackCacheSaveAllPlayersTask.java b/prison-core/src/main/java/tech/mcprison/prison/backpacks/BackpackCacheSaveAllPlayersTask.java new file mode 100644 index 000000000..6d2ba01be --- /dev/null +++ b/prison-core/src/main/java/tech/mcprison/prison/backpacks/BackpackCacheSaveAllPlayersTask.java @@ -0,0 +1,91 @@ +package tech.mcprison.prison.backpacks; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import tech.mcprison.prison.Prison; +import tech.mcprison.prison.internal.Player; +import tech.mcprison.prison.output.Output; + +public class BackpackCacheSaveAllPlayersTask + extends BackpackCacheRunnable +{ + public static long LAST_SEEN_INTERVAL_30_MINUTES = 30 * 60 * 1000; + + @Override + public void run() + { + + BackpackCache bCache = BackpackCache.getInstance(); + + + List onlinePlayersList = Prison.get().getPlatform().getOnlinePlayers(); + Set onlinePlayers = new HashSet<>(); + for ( Player player : onlinePlayersList ) { + onlinePlayers.add( player.getUUID().toString() ); + } + + + List purge = new ArrayList<>(); + + Set keys = bCache.getPlayers().keySet(); + + for ( String key : keys ) + { + BackpackCachePlayerData playerData = null; + + synchronized ( bCache.getPlayers() ) { + + playerData = bCache.getPlayers().get( key ); + } + + if ( playerData != null ) { + + // If a cached item is found with the player being offline, then + // purge them from the cache. They were usually added only because + // some process had to inspect their stats, so they are safe to remove. + String uuid = playerData.getPlayerUuid(); + if ( uuid != null && !onlinePlayers.contains( uuid ) ) { + purge.add( playerData ); + } + + if ( playerData.isDirty() ) { + + try + { + playerData.setDirty( false ); + bCache.getCacheFiles().toJsonFile( playerData ); + } + catch ( Exception e ) + { + String message = String.format( + "PlayerCache: Error trying to save a player's " + + "cache data. Will try again later. " + + "%s", e.getMessage() ); + Output.get().logError( message, e ); + } + } + } + + } + + synchronized ( bCache.getPlayers() ) { + + for ( BackpackCachePlayerData playerData : purge ) { + try { + if ( !playerData.isDirty() ) { + + bCache.getPlayers().remove( playerData.getPlayerUuid() ); + } + } + catch ( Exception e ) { + // Ignore any possible errors. They will be addressed on the next + // run of this task. + } + } + } + + } +} diff --git a/prison-core/src/main/java/tech/mcprison/prison/backpacks/BackpackCacheStats.java b/prison-core/src/main/java/tech/mcprison/prison/backpacks/BackpackCacheStats.java new file mode 100644 index 000000000..d6ca4d846 --- /dev/null +++ b/prison-core/src/main/java/tech/mcprison/prison/backpacks/BackpackCacheStats.java @@ -0,0 +1,161 @@ +package tech.mcprison.prison.backpacks; + +public class BackpackCacheStats { + + private long startMs; + + private boolean enabled = false; + + private int loadBackpack = 0; + private int unloadBackpack = 0; + private int removeBackpack = 0; + private int getBackpack = 0; + + private int submitDatabaseUpdate = 0; + private int synchronizeBackpacks = 0; + + + private Object lock1 = new Object(); + private Object lock2 = new Object(); + private Object lock3 = new Object(); + private Object lock4 = new Object(); + private Object lock5 = new Object(); + private Object lock6 = new Object(); + + public BackpackCacheStats() { + super(); + + this.startMs = System.currentTimeMillis(); + } + + + /** + *

If enabled, stats will be collected. + *

+ * + * @return + */ + public boolean isEnabled() { + return enabled; + } + public void setEnabled( boolean enabled ) { + this.enabled = enabled; + } + public void toggleEnabled() { + this.enabled = !this.enabled; + } + + public String displayStats() { + StringBuilder sb = new StringBuilder(); + + sb.append( "BackpackCache stats: loadPlayer=" ).append( getLoadBackpack() ) + .append( " unloadPlayer=" ).append( getUnloadBackpack() ) + .append( " removePlayer=" ).append( getRemoveBackpack() ) + .append( " getPlayer=" ).append( getGetBackpack() ) + + .append( " submitDatabaseUpdate=" ).append( getSubmitDatabaseUpdate() ) + .append( " synchronizeDatabase=" ).append( getSynchronizeBackpacks() ) + + ; + + return sb.toString(); + } + + + public void incrementGetBackpacks() { + if ( enabled ) { + synchronized ( lock1 ) { + getBackpack++; + } + } + } + public void incrementRemoveBackpacks() { + if ( enabled ) { + synchronized ( lock2 ) { + removeBackpack++; + } + } + } + public void incrementLoadBackpacks() { + if ( enabled ) { + synchronized ( lock3 ) { + loadBackpack++; + } + } + } + public void incrementUnloadBackpacks() { + if ( enabled ) { + synchronized ( lock4 ) { + unloadBackpack++; + } + } + } + + + public void incrementSubmitDatabaseUpdate() { + if ( enabled ) { + synchronized ( lock5 ) { + submitDatabaseUpdate++; + } + } + } + public void incrementSubmitSynchronizeBackpacks() { + if ( enabled ) { + synchronized ( lock6 ) { + synchronizeBackpacks++; + } + } + } + + + + public long getStartMs() { + return startMs; + } + public void setStartMs(long startMs) { + this.startMs = startMs; + } + + public int getLoadBackpack() { + return loadBackpack; + } + public void setLoadBackpack(int loadBackpack) { + this.loadBackpack = loadBackpack; + } + + public int getUnloadBackpack() { + return unloadBackpack; + } + public void setUnloadBackpack(int unloadBackpack) { + this.unloadBackpack = unloadBackpack; + } + + public int getRemoveBackpack() { + return removeBackpack; + } + public void setRemoveBackpack(int removeBackpack) { + this.removeBackpack = removeBackpack; + } + + public int getGetBackpack() { + return getBackpack; + } + public void setGetBackpack(int getBackpack) { + this.getBackpack = getBackpack; + } + + public int getSubmitDatabaseUpdate() { + return submitDatabaseUpdate; + } + public void setSubmitDatabaseUpdate(int submitDatabaseUpdate) { + this.submitDatabaseUpdate = submitDatabaseUpdate; + } + + public int getSynchronizeBackpacks() { + return synchronizeBackpacks; + } + public void setSynchronizeBackpack(int synchronizeBackpacks) { + this.synchronizeBackpacks = synchronizeBackpacks; + } + +} diff --git a/prison-core/src/main/java/tech/mcprison/prison/backpacks/BackpackCacheTask.java b/prison-core/src/main/java/tech/mcprison/prison/backpacks/BackpackCacheTask.java new file mode 100644 index 000000000..4c645d75d --- /dev/null +++ b/prison-core/src/main/java/tech/mcprison/prison/backpacks/BackpackCacheTask.java @@ -0,0 +1,19 @@ +package tech.mcprison.prison.backpacks; + +import tech.mcprison.prison.cache.PlayerCacheRunnable; + +public abstract class BackpackCacheTask + extends PlayerCacheRunnable +{ + private final BackpackCachePlayerData backpackData; + + public BackpackCacheTask( BackpackCachePlayerData backpackData ) { + super(); + + this.backpackData = backpackData; + } + + public BackpackCachePlayerData getBackpackData() { + return backpackData; + } +} diff --git a/prison-core/src/main/java/tech/mcprison/prison/backpacks/BackpackCacheUnloadPlayerTask.java b/prison-core/src/main/java/tech/mcprison/prison/backpacks/BackpackCacheUnloadPlayerTask.java new file mode 100644 index 000000000..d97829ff7 --- /dev/null +++ b/prison-core/src/main/java/tech/mcprison/prison/backpacks/BackpackCacheUnloadPlayerTask.java @@ -0,0 +1,30 @@ +package tech.mcprison.prison.backpacks; + +public class BackpackCacheUnloadPlayerTask + extends BackpackCacheTask +{ + + public BackpackCacheUnloadPlayerTask( BackpackCachePlayerData backpackData ) { + super( backpackData ); + + } + + public void run() { + + BackpackCache bCache = BackpackCache.getInstance(); + + // Remove from the player cache: + BackpackCachePlayerData removed = null; + + synchronized ( bCache.getPlayers() ) { + + removed = bCache.removePlayerData( getBackpackData() ); + } + + if ( removed != null ) { + + bCache.getCacheFiles().toJsonFile( removed ); + } + + } +} diff --git a/prison-core/src/main/java/tech/mcprison/prison/backpacks/BackpackConverterOldPrisonBackpacks.java b/prison-core/src/main/java/tech/mcprison/prison/backpacks/BackpackConverterOldPrisonBackpacks.java new file mode 100644 index 000000000..a0d41b08c --- /dev/null +++ b/prison-core/src/main/java/tech/mcprison/prison/backpacks/BackpackConverterOldPrisonBackpacks.java @@ -0,0 +1,33 @@ +package tech.mcprison.prison.backpacks; + +import java.util.List; + +import tech.mcprison.prison.Prison; +import tech.mcprison.prison.internal.Player; +import tech.mcprison.prison.output.Output; + +public class BackpackConverterOldPrisonBackpacks { + + public void convertOldBackpacks() { + + List offlinePlayers = Prison.get().getPlatform().getOfflinePlayers(); + + for (Player player : offlinePlayers) { + + List oldBackpacks = Prison.get().getPlatform().getPlayerOldBackpacks( player ); + + if ( oldBackpacks.size() > 0 ) { + + BackpackCachePlayerData playerBackpacks = BackpackCache.getInstance().getPlayers().get( player.getName() ); + + Output.get().logInfo( playerBackpacks.toString() ); + + Output.get().logInfo( " Old backpack size:", oldBackpacks.size() ); + } + + + } + + } + +} diff --git a/prison-core/src/main/java/tech/mcprison/prison/backpacks/BackpackEnums.java b/prison-core/src/main/java/tech/mcprison/prison/backpacks/BackpackEnums.java new file mode 100644 index 000000000..ffccc9333 --- /dev/null +++ b/prison-core/src/main/java/tech/mcprison/prison/backpacks/BackpackEnums.java @@ -0,0 +1,28 @@ +package tech.mcprison.prison.backpacks; + +public class BackpackEnums { + + public enum BackpackType { + inventory, // Uses standard inventory object, up to 6 rows, 9 stacks each + silo; // Up to 54 silos per backpack, which will use a chest to display + } + + public enum BackpackFeatures { + soulboundBackpack, // If player dies, they keep the backpack + soulboundItems, // if soulboundBackpack is enabled, this will preserve items within + virtual, // if not virtual, then the itemType must exist in their inventory + tradable, // Able to trade/sell whole backpack with contents + droppable, // able to remove the backpack item from inventory + enablePickup, // normally picked up items go in to backpack + enableSellall, // sellall will sell from backpack + enablePlayerToggle, // player pickup toggleable + enableSellallToggle, // player sellall toggleable + enchanted, // show enchant glow on item + placeable, // Able to place backpack as a chest - may need to supply empty chests + + allowMultiples, // If this feature is not set, then a player can only have one backpack of a given type + loreStats, // Update lore on backpack item with stats: blocks and counts + restrictView, // Prevent viewing through open inventory. Use with loreStats. + allowRename, // Allow players to rename their backpacks + } +} diff --git a/prison-core/src/main/java/tech/mcprison/prison/backpacks/PlayerBackpack.java b/prison-core/src/main/java/tech/mcprison/prison/backpacks/PlayerBackpack.java new file mode 100644 index 000000000..c31cc281d --- /dev/null +++ b/prison-core/src/main/java/tech/mcprison/prison/backpacks/PlayerBackpack.java @@ -0,0 +1,142 @@ +package tech.mcprison.prison.backpacks; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.TreeMap; + +import tech.mcprison.prison.backpacks.BackpackEnums.BackpackFeatures; +import tech.mcprison.prison.backpacks.BackpackEnums.BackpackType; +import tech.mcprison.prison.internal.ItemStack; + +public class PlayerBackpack { + + private String playerName; + private String playerUuid; + + private String name; + private String itemType; // XMaterial + + private Set features; + + // either inventory or silos... not both... not neither: + private BackpackType backpackType; + + private List inventory; +// private Inventory inventory; + private int inventorySize; + + + // if max of 54 silos, then can use a double-chest to view as GUI and + // show the itemStacks with quantity being added lore? + private TreeMap silos; + private int maxSiloSlots; + private int maxSiloSize; + private int maxTotalSize; // all silos combined + + public PlayerBackpack() { + super(); + + this.inventory = new ArrayList<>(); + this.silos = new TreeMap<>(); + + } + + public PlayerBackpack( String playerName, String playerUuid, + BackpackType backpackType, + String backpackName, String itemType ) { + this(); + + this.playerName = playerName; + this.playerUuid = playerUuid; + + this.backpackType = backpackType; + this.name = backpackName; + this.itemType = itemType; + } + + public String getPlayerName() { + return playerName; + } + public void setPlayerName(String playerName) { + this.playerName = playerName; + } + + public String getPlayerUuid() { + return playerUuid; + } + public void setPlayerUuid(String playerUuid) { + this.playerUuid = playerUuid; + } + + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + + public String getItemType() { + return itemType; + } + public void setItemType(String itemType) { + this.itemType = itemType; + } + + public Set getFeatures() { + return features; + } + public void setFeatures(Set features) { + this.features = features; + } + + public BackpackType getBackpackType() { + return backpackType; + } + public void setBackpackType(BackpackType backpackType) { + this.backpackType = backpackType; + } + + public List getInventory() { + return inventory; + } + public void setInventory(List inventory) { + this.inventory = inventory; + } + + public int getInventorySize() { + return inventorySize; + } + public void setInventorySize(int inventorySize) { + this.inventorySize = inventorySize; + } + + public TreeMap getSilos() { + return silos; + } + public void setSilos(TreeMap silos) { + this.silos = silos; + } + + public int getMaxSiloSlots() { + return maxSiloSlots; + } + public void setMaxSiloSlots(int maxSiloSlots) { + this.maxSiloSlots = maxSiloSlots; + } + + public int getMaxSiloSize() { + return maxSiloSize; + } + public void setMaxSiloSize(int maxSiloSize) { + this.maxSiloSize = maxSiloSize; + } + + public int getMaxTotalSize() { + return maxTotalSize; + } + public void setMaxTotalSize(int maxTotalSize) { + this.maxTotalSize = maxTotalSize; + } + +} diff --git a/prison-core/src/main/java/tech/mcprison/prison/backpacks/PlayerBackpackSiloData.java b/prison-core/src/main/java/tech/mcprison/prison/backpacks/PlayerBackpackSiloData.java new file mode 100644 index 000000000..338888ada --- /dev/null +++ b/prison-core/src/main/java/tech/mcprison/prison/backpacks/PlayerBackpackSiloData.java @@ -0,0 +1,45 @@ +package tech.mcprison.prison.backpacks; + +import tech.mcprison.prison.internal.ItemStack; + +public class PlayerBackpackSiloData { + + private String itemType; // key + private ItemStack itemSample; // quantity of 1 + private int count; + private boolean locked; // locks the itemType in to this silo even when count == 0 + + public PlayerBackpackSiloData() { + super(); + + } + + public String getItemType() { + return itemType; + } + public void setItemType(String itemType) { + this.itemType = itemType; + } + + public ItemStack getItemSample() { + return itemSample; + } + public void setItemSample(ItemStack itemSample) { + this.itemSample = itemSample; + } + + public int getCount() { + return count; + } + public void setCount(int count) { + this.count = count; + } + + public boolean isLocked() { + return locked; + } + public void setLocked(boolean locked) { + this.locked = locked; + } + +} diff --git a/prison-core/src/main/java/tech/mcprison/prison/backups/PrisonBackups.java b/prison-core/src/main/java/tech/mcprison/prison/backups/PrisonBackups.java index e789a2885..45678bd39 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/backups/PrisonBackups.java +++ b/prison-core/src/main/java/tech/mcprison/prison/backups/PrisonBackups.java @@ -12,7 +12,7 @@ import java.util.List; import tech.mcprison.prison.Prison; -import tech.mcprison.prison.cache.PlayerCacheFiles; +import tech.mcprison.prison.cache.CoreCacheFiles; import tech.mcprison.prison.file.ZipFileIO; import tech.mcprison.prison.output.Output; import tech.mcprison.prison.util.PrisonStatsUtil; @@ -20,7 +20,8 @@ public class PrisonBackups { public static final String FILE_BACKUP_DIRECTORY_PATH = "backups"; - public static final String FILE_BACKUP_VERSIONS_FILE = FILE_BACKUP_DIRECTORY_PATH + "/versions.log"; + public static final String FILEBACKUP_VERSIONS_FILE_NAME = "/versions.log"; + public static final String FILE_BACKUP_VERSIONS_FILE = FILE_BACKUP_DIRECTORY_PATH + FILEBACKUP_VERSIONS_FILE_NAME; public static final String VERSIONS_FILE_VERSION_PREFIX = "New_Prison_Version:"; public static final String VERSIONS_FILE_BACKUP_MADE_PREFIX = "Backup:"; @@ -40,7 +41,7 @@ public class PrisonBackups { private ArrayList filesToDelete; private ArrayList filesWithErrors; - private DecimalFormat dFmt = new DecimalFormat("#,##0.000"); + private DecimalFormat dFmt; private SimpleDateFormat sdFmt = new SimpleDateFormat( "yyyy-MM-dd_kk-mm" ); private SimpleDateFormat sdsFmt = new SimpleDateFormat( "yyyy-MM-dd kk:mm:ss.SSS" ); @@ -54,6 +55,8 @@ public enum BackupTypes { public PrisonBackups() { super(); + this.dFmt = Prison.get().getDecimalFormatDouble(); + this.filesBackups = new ArrayList<>(); this.filesToBackup = new ArrayList<>(); this.filesToDelete = new ArrayList<>(); @@ -261,7 +264,7 @@ public String startBackup( BackupTypes backupType, String notes ) { public String backupReport01() { -// DecimalFormat dFmt = new DecimalFormat("#,##0.000"); +// DecimalFormat dFmt = Prison.get().getDecimalFormatDouble(); long stop = System.nanoTime(); double runTimeMs = ( stop - getStartTimeNanos() ) / 1000000.0d; @@ -291,6 +294,27 @@ public String backupReport01() { return msg1; } + + public List backupReport02BackupLog() { + List results = new ArrayList<>(); + + File backupDir = getBackupDirectoryFile(); + + File backupLogFile = new File( backupDir, FILEBACKUP_VERSIONS_FILE_NAME ); + + try { + results = Files.readAllLines( backupLogFile.toPath() ); + } + catch (IOException e) { + results.add( + Output.stringFormat( "\n\nError reading %s. [%s]", + backupLogFile.toString(), e.getMessage() ) ); + } + + return results; + } + + public StringBuilder backupReportVersionData() { return Prison.get().getPrisonStatsUtil().getSupportSubmitVersionData(); } @@ -407,8 +431,8 @@ else if ( file.isFile() ) { String fName = file.getName(); boolean isDeleteable = - fName.endsWith( PlayerCacheFiles.FILE_SUFFIX_BACKUP ) || - fName.endsWith( PlayerCacheFiles.FILE_SUFFIX_TEMP ) || + fName.endsWith( CoreCacheFiles.FILE_SUFFIX_BACKUP ) || + fName.endsWith( CoreCacheFiles.FILE_SUFFIX_TEMP ) || fName.endsWith( ".del" ) || fName.startsWith( "_archived_" ) || fName.contains( ".json.ver_" ) && fName.endsWith( ".txt" ) diff --git a/prison-core/src/main/java/tech/mcprison/prison/cache/CoreCacheData.java b/prison-core/src/main/java/tech/mcprison/prison/cache/CoreCacheData.java new file mode 100644 index 000000000..6fd790099 --- /dev/null +++ b/prison-core/src/main/java/tech/mcprison/prison/cache/CoreCacheData.java @@ -0,0 +1,11 @@ +package tech.mcprison.prison.cache; + +import java.io.File; + +public interface CoreCacheData { + + public File getPlayerFile(); + + public void setPlayerFile( File inputFile ); + +} diff --git a/prison-core/src/main/java/tech/mcprison/prison/cache/CoreCacheFiles.java b/prison-core/src/main/java/tech/mcprison/prison/cache/CoreCacheFiles.java new file mode 100644 index 000000000..c8fd65cb1 --- /dev/null +++ b/prison-core/src/main/java/tech/mcprison/prison/cache/CoreCacheFiles.java @@ -0,0 +1,435 @@ +package tech.mcprison.prison.cache; + +import java.io.File; +import java.io.FileFilter; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.TreeMap; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonIOException; +import com.google.gson.JsonSyntaxException; + +import tech.mcprison.prison.Prison; +import tech.mcprison.prison.internal.Player; +import tech.mcprison.prison.output.Output; + +public abstract class CoreCacheFiles { + + public static final String FILE_SUFFIX_JSON = ".json"; + public static final String FILE_PREFIX_BACKUP = ".backup_"; + public static final String FILE_SUFFIX_BACKUP = ".bu"; + public static final String FILE_SUFFIX_TEMP = ".temp"; + public static final String FILE_TIMESTAMP_FORMAT = "_yyyy-MM-dd_HH-mm-ss"; + + private final String cachePath; + private File cacheDirectory = null; + + private Gson gson = null; + private TreeMap playerFiles; + + + public CoreCacheFiles( String cachePath ) { + super(); + + this.cachePath = cachePath; + } + + public String getCachePath() { + return cachePath; + } + + /** + *

This constructs the Gson engine using the optional pretty + * printing to help make it human readable. + *

+ * + * @return + */ + protected Gson getGson() { + if ( gson == null ) { + gson = new GsonBuilder().setPrettyPrinting().create(); + } + return gson; + } + + protected void renamePlayerFileToBU(File playerFile) { + String buFileName = FILE_PREFIX_BACKUP + + playerFile.getName().replace( FILE_SUFFIX_TEMP, FILE_SUFFIX_BACKUP ); + + File backupFile = new File( playerFile.getParent(), buFileName ); + + playerFile.renameTo( backupFile ); + + } + + protected File createTempFile(File file) { + SimpleDateFormat sdf = new SimpleDateFormat( FILE_TIMESTAMP_FORMAT ); + String name = file.getName() + sdf.format( new Date() ) + FILE_SUFFIX_TEMP; + + return new File( file.getParentFile(), name); + } + + /** + *

This loads the PlayerCachePlayerData object from a saved json file. + *

+ * + *

Since this deals with the actual file name, the "knowledge" on how to + * properly generate that file name is contained within this class and should + * never be exposed since it may not be correct and can lead to errors. + *

+ * + */ + protected CoreCacheData fromJsonFile(File inputFile, Class classOfT ) { + CoreCacheData results = null; + + if ( inputFile.exists() ) { + + try ( + FileReader fr = new FileReader( inputFile ); + ) { + + results = (CoreCacheData) getGson().fromJson( fr, classOfT ); + + if ( results != null ) { + + results.setPlayerFile( inputFile ); + } + } + catch ( IOException e ) + { + e.printStackTrace(); + } + catch ( JsonSyntaxException | JsonIOException e ) + { + e.printStackTrace(); + } + } + + return results; + } + + + + /** + *

This function will take a Prison Player object, and load the correct PlayerCache + * file. The file name has a prefix of the first part of the player's UUID and then + * followed by the player's name. But it is important to understand that the Player's + * name part is totally ignored since player could change their name at any time. + *

+ * + *

By using the Player's UUID and player name, it constructs the file's full name. + * Then it takes the prefix, of the first 14 characters of the UUID, and gets all of + * the File objects within the cache directory. Since minecraft UUIDs are generated + * from random numbers, the first 14 characters "should" be unique. If the returned + * Files are not unique, then each returned File object is loaded so the the correct + * file can be selected by the internal UUID. Odds are there will never be duplicates, + * but if there is, it will handle it. + *

+ * + *

If the supplied Player is not in the cache, a new PlayerCachePlayerData object + * is created for the player (keyed on the player's UUID and name) and then it is + * saved to the cache directory. + *

+ * + *

Although the Player's file name prefix will always match it's data file, their + * name portion of the file can be dynamic. It is important that if the Player changes + * their name, that their save cached file will be change within this function. + * This process will only happen the first time the player is loaded from the cache + * (which can vary, such as at server startup or they logoff and they are cleared from + * the cache, then added back when they login the next time). So this function will + * rename the cache file to reflect the player's current name. + *

+ * + * @param player + * @return + */ + public CoreCacheData fromJson( Player player, Class classOfT ) { + CoreCacheData results = null; + +// // This is the "target" file name for the player, based upon their +// // current name. The saved cache file may not be named exactly the same, +// // and if it's not, then their existing cache file will be renamed +// // within the function getCachedFileMatch() + String playerFileName = getPlayerFileName( player ); + + File playerFile = getCachedFileMatch( playerFileName ); + + + if ( playerFile.exists() ) { + + results = fromJsonFile( playerFile, classOfT ); + } + + + // New player and file does not exist so create it. + if ( results == null ) { + results = new PlayerCachePlayerData( player, playerFile ); + + // Then save it: + toJsonFile( results ); + } + + return results; + } + + + /** + *

For generating a json String object from a cache data object type. + *

+ * + * @param player + * @return + */ + public String toJson(CoreCacheData cacheData) { + return getGson().toJson( cacheData ); + } + + /** + *

This function serializes the provided core cache data object to the + * json file, using the core cache data object as the source for the + * json data, and the File object that is stored in that object too. + *

+ * + *

If the player changes their name while they are online, and if that change + * actually percolates through to bukkit, the caching system will never attempt + * to change the Player's cached file while it's active. It will rename the + * file upon loading in to the cache the next time they are activated. + *

+ * + *

This function first saves the new player data to a temp file. If that + * was successful, then it deletes the original file, and renames the temp + * file back to the original name. + *

+ * + * @param player + */ + public void toJsonFile(CoreCacheData cacheData) { + + if ( cacheData != null ) { + + File playerFile = cacheData.getPlayerFile(); + File outTemp = createTempFile( playerFile ); + + if ( !getPlayerFiles().containsKey( playerFile.getName() )) { + getPlayerFiles().put( playerFile.getName(), playerFile ); + } + + boolean success = false; + + try ( + FileWriter fw = new FileWriter( outTemp ); + ){ + getGson().toJson( cacheData, fw ); + + success = true; + } + catch ( JsonIOException | IOException e ) { + e.printStackTrace(); + } + + // If there is a significant change in file size, or the new file is smaller than the + // old, then rename it to a backup and keep it. If it is smaller, then something went wrong + // because player cache data should always increase, with the only exception being + // the player cache. + if ( playerFile.exists() ) { + long pfSize = playerFile.length(); + long tmpSize = outTemp.length(); + + if ( tmpSize < pfSize ) { + + renamePlayerFileToBU( playerFile ); + } + } + + if ( success && ( !playerFile.exists() || playerFile.delete()) ) { + outTemp.renameTo( playerFile ); + } + else { + + boolean removed = false; + if ( outTemp.exists() ) { + removed = outTemp.delete(); + } + + String message = String.format( + "Unable to rename PlayerCache temp file. It was %sremoved: %s", + (removed ? "" : "not "), outTemp.getAbsolutePath() ); + + Output.get().logWarn( message ); + } + } + } + + /** + *

Constructs a File object for a specific player. + *

+ * + * @param playerFileName + * @return + */ + protected File getPlayerFile(String playerFileName) { + return new File( getPlayerFilePath(), playerFileName ); + } + + protected TreeMap getPlayerFiles() { + // load the player's files: + if ( playerFiles == null ) { + + playerFiles = new TreeMap<>(); + + FileFilter fileFilter = (file) -> { + + String fname = file.getName(); + boolean isTemp = fname.startsWith( FILE_PREFIX_BACKUP ) || + fname.endsWith( FILE_SUFFIX_BACKUP ) || + fname.endsWith( FILE_SUFFIX_TEMP ); + + return !file.isDirectory() && !isTemp && + fname.endsWith( FILE_SUFFIX_JSON ); + }; + + + File[] files = getPlayerFilePath().listFiles( fileFilter ); + for ( File f : files ) + { + String fileNamePrefix = getFileNamePrefix( f.getName() ); + getPlayerFiles().put( fileNamePrefix, f ); + } + + } + + return playerFiles; + } + + + + /** + *

This function will take the project's data folder and construct the the path + * to the directory, if it does not exist, to where the player cache files are stored. + *

+ * + * @return + */ + public File getPlayerFilePath() { + if ( cacheDirectory == null ) { + + cacheDirectory = new File( Prison.get().getDataFolder(), getCachePath() ); + cacheDirectory.mkdirs(); + + } + return cacheDirectory; + } + + /** + *

This function returns the file name which is constructed by + * using the player's UUID and their name. The player's name is not + * used in the selection of a player's file, only the UUID prefix. + *

+ * + *

The UUID prefix is based upon the HEX representation of the + * the UUID, and includes the first 13 characters which includes one + * hyphen. Since the minecraft UUID is based upon random numbers + * (type 4 UUID), then odds are great that file name prefixes will + * be unique, but they don't have to be. + *

+ * + *

Its a high importance that file names can be found based upon + * Player information, hence the UUID prefix. Plus it's very important + * to be able to have the files human readable so admins can find + * specific player files if they need to; hence the player name suffix. + *

+ * + * @param player + * @return + */ + private String getPlayerFileName( Player player ) { + String UUIDString = player.getUUID().toString(); + String uuidFragment = getFileNamePrefix( UUIDString ); + + return uuidFragment + "_" + player.getName() + FILE_SUFFIX_JSON; + } + + /** + *

This function returns the first 13 characters of the supplied + * file name, or UUID String. The hyphen is around the 12 or 13th position, + * so it may or may not include it. + *

+ * + * @param playerFileName + * @return + */ + String getFileNamePrefix( String UUIDString ) { + return UUIDString.substring( 0, 14 ); + } + + + + /** + *

Potentially there could be more than one result, but considering if a player + * changes their name, then it should only return only one entry. The reason for + * this, is that the file name should be based upon the player's UUID, which is the + * first 13 characters of the file, and the name itself, which follows, should + * never be part of the "key". + *

+ * + * @param playerFile + * @param playerFileName + * @return + */ + private File getCachedFileMatch( String playerFileName ) + { + File results = null; + + String fileNamePrefix = getFileNamePrefix( playerFileName ); + + results = getPlayerFiles().get( fileNamePrefix ); + + if ( results == null ) { + + // This is the "target" file name for the player, based upon their + // current name. The saved cache file may not be named exactly the same, + // and if it's not, then their existing cache file needs to be + // renamed. + results = getPlayerFile( playerFileName ); + + // NOTE: because the file was NOT found in the directory, then we can assume + // this is a new player therefore we won't have an issue with the player's + // name changing. + getPlayerFiles().put( fileNamePrefix, results ); + } + else if ( !playerFileName.equalsIgnoreCase( results.getName() )) { + + // File name changed!!! Need to rename the file in the file system, and + // update what is in the playerFiles map!! + + File newFile = getPlayerFile( playerFileName ); + + if ( results.exists() ) { + // rename what's on the file system: + results.renameTo( newFile ); + } + + // Replace what's in the map: + getPlayerFiles().put( fileNamePrefix, newFile ); + + results = newFile; + } + +// NavigableMap files = getPlayerFiles().tailMap( fileNamePrefix, true ); +// Set keys = files.keySet(); +// for ( String key : keys ) { +// if ( !key.startsWith( fileNamePrefix ) ) { +// break; +// } +// +// results.add( files.get( key ) ); +// } + + return results; + } +} diff --git a/prison-core/src/main/java/tech/mcprison/prison/cache/PlayerCacheFiles.java b/prison-core/src/main/java/tech/mcprison/prison/cache/PlayerCacheFiles.java index db120784f..ee99ba8bb 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/cache/PlayerCacheFiles.java +++ b/prison-core/src/main/java/tech/mcprison/prison/cache/PlayerCacheFiles.java @@ -1,22 +1,6 @@ package tech.mcprison.prison.cache; -import java.io.File; -import java.io.FileFilter; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.TreeMap; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonIOException; -import com.google.gson.JsonSyntaxException; - -import tech.mcprison.prison.Prison; import tech.mcprison.prison.internal.Player; -import tech.mcprison.prison.output.Output; /** *

This class is intended to be kept online and active for the full @@ -35,415 +19,21 @@ * */ public class PlayerCacheFiles + extends CoreCacheFiles { - public static final String FILE_SUFFIX_JSON = ".json"; - public static final String FILE_PREFIX_BACKUP = ".backup_"; - public static final String FILE_SUFFIX_BACKUP = ".bu"; - public static final String FILE_SUFFIX_TEMP = ".temp"; - public static final String FILE_TIMESTAMP_FORMAT = "_yyyy-MM-dd_HH-mm-ss"; - public static final String FILE_PLAYERCACHE_PATH = "data_storage/playerCache"; - - - private Gson gson = null; - - private File playerCacheDirectory = null; - - - private TreeMap playerFiles; + public static final String FILE_PLAYER_CACHE_PATH = "data_storage/playerCache"; public PlayerCacheFiles() { - super(); - - } - - /** - *

This constructs the Gson engine using the optional pretty - * printing to help make it human readable. - *

- * - * @return - */ - private Gson getGson() { - if ( gson == null ) { - gson = new GsonBuilder().setPrettyPrinting().create(); - } - return gson; - } - - /** - *

For generating a json String object from the player's data. - *

- * - * @param player - * @return - */ - public String toJson( PlayerCachePlayerData player ) { - return getGson().toJson( player ); - } - - /** - *

This function serializes the provided Player's object to the - * json file, using the player data object as the source for the - * json data, and the File object that is stored in that object too. - *

- * - *

If the player changes their name while they are online, and if that change - * actually percolates through to bukkit, the caching system will never attempt - * to change the Player's cached file while it's active. It will rename the - * file upon loading in to the cache the next time they are activated. - *

- * - *

This function first saves the new player data to a temp file. If that - * was successful, then it deletes the original file, and renames the temp - * file back to the original name. - *

- * - * @param player - */ - public void toJsonFile( PlayerCachePlayerData player) { - - if ( player != null ) { - - File playerFile = player.getPlayerFile(); - File outTemp = createTempFile( playerFile ); - - if ( !getPlayerFiles().containsKey( playerFile.getName() )) { - getPlayerFiles().put( playerFile.getName(), playerFile ); - } - - boolean success = false; - - try ( - FileWriter fw = new FileWriter( outTemp ); - ){ - getGson().toJson( player, fw ); - - success = true; - } - catch ( JsonIOException | IOException e ) { - e.printStackTrace(); - } - - // If there is a significant change in file size, or the new file is smaller than the - // old, then rename it to a backup and keep it. If it is smaller, then something went wrong - // because player cache data should always increase, with the only exception being - // the player cache. - if ( playerFile.exists() ) { - long pfSize = playerFile.length(); - long tmpSize = outTemp.length(); - - if ( tmpSize < pfSize ) { - - renamePlayerFileToBU( playerFile ); - } - } - - if ( success && ( !playerFile.exists() || playerFile.delete()) ) { - outTemp.renameTo( playerFile ); - } - else { - - boolean removed = false; - if ( outTemp.exists() ) { - removed = outTemp.delete(); - } - - String message = String.format( - "Unable to rename PlayerCache temp file. It was %sremoved: %s", - (removed ? "" : "not "), outTemp.getAbsolutePath() ); - - Output.get().logWarn( message ); - } - } - } - - private void renamePlayerFileToBU( File playerFile ) - { - String buFileName = FILE_PREFIX_BACKUP + - playerFile.getName().replace( FILE_SUFFIX_TEMP, FILE_SUFFIX_BACKUP ); - - File backupFile = new File( playerFile.getParent(), buFileName ); - - playerFile.renameTo( backupFile ); + super( FILE_PLAYER_CACHE_PATH ); } - private File createTempFile( File file ) { - SimpleDateFormat sdf = new SimpleDateFormat( FILE_TIMESTAMP_FORMAT ); - String name = file.getName() + sdf.format( new Date() ) + FILE_SUFFIX_TEMP; - - return new File( file.getParentFile(), name); - } - - /** - *

This loads the PlayerCachePlayerData object from a saved json file. - *

- * - *

Since this deals with the actual file name, the "knowledge" on how to - * properly generate that file name is contained within this class and should - * never be exposed since it may not be correct and can lead to errors. - *

- * - */ - private PlayerCachePlayerData fromJsonFile( File inputFile ) { - PlayerCachePlayerData results = null; - - if ( inputFile.exists() ) { - - try ( - FileReader fr = new FileReader( inputFile ); - ) { - - results = getGson().fromJson( - fr, PlayerCachePlayerData.class ); - - if ( results != null ) { - - results.setPlayerFile( inputFile ); - } - } - catch ( IOException e ) - { - e.printStackTrace(); - } - catch ( JsonSyntaxException | JsonIOException e ) - { - e.printStackTrace(); - } - } - - return results; - } - - /** - *

This function returns the file name which is constructed by - * using the player's UUID and their name. The player's name is not - * used in the selection of a player's file, only the UUID prefix. - *

- * - *

The UUID prefix is based upon the HEX representation of the - * the UUID, and includes the first 13 characters which includes one - * hyphen. Since the minecraft UUID is based upon random numbers - * (type 4 UUID), then odds are great that file name prefixes will - * be unique, but they don't have to be. - *

- * - *

Its a high importance that file names can be found based upon - * Player information, hence the UUID prefix. Plus it's very important - * to be able to have the files human readable so admins can find - * specific player files if they need to; hence the player name suffix. - *

- * - * @param player - * @return - */ - private String getPlayerFileName( Player player ) { - String UUIDString = player.getUUID().toString(); - String uuidFragment = getFileNamePrefix( UUIDString ); - - return uuidFragment + "_" + player.getName() + FILE_SUFFIX_JSON; - } - - /** - *

This function returns the first 13 characters of the supplied - * file name, or UUID String. The hyphen is around the 12 or 13th position, - * so it may or may not include it. - *

- * - * @param playerFileName - * @return - */ - private String getFileNamePrefix( String UUIDString ) { - return UUIDString.substring( 0, 14 ); - } - - - /** - *

This function will take the project's data folder and construct the the path - * to the directory, if it does not exist, to where the player cache files are stored. - *

- * - * @return - */ - public File getPlayerFilePath() { - if ( playerCacheDirectory == null ) { - - playerCacheDirectory = new File( Prison.get().getDataFolder(), FILE_PLAYERCACHE_PATH ); - playerCacheDirectory.mkdirs(); - - } - return playerCacheDirectory; - } - - /** - *

Constructs a File object for a specific player. - *

- * - * @param playerFileName - * @return - */ - private File getPlayerFile( String playerFileName ) { - return new File( getPlayerFilePath(), playerFileName ); - } - - - /** - *

This function will take a Prison Player object, and load the correct PlayerCache - * file. The file name has a prefix of the first part of the player's UUID and then - * followed by the player's name. But it is important to understand that the Player's - * name part is totally ignored since player could change their name at any time. - *

- * - *

By using the Player's UUID and player name, it constructs the file's full name. - * Then it takes the prefix, of the first 14 characters of the UUID, and gets all of - * the File objects within the cache directory. Since minecraft UUIDs are generated - * from random numbers, the first 14 characters "should" be unique. If the returned - * Files are not unique, then each returned File object is loaded so the the correct - * file can be selected by the internal UUID. Odds are there will never be duplicates, - * but if there is, it will handle it. - *

- * - *

If the supplied Player is not in the cache, a new PlayerCachePlayerData object - * is created for the player (keyed on the player's UUID and name) and then it is - * saved to the cache directory. - *

- * - *

Although the Player's file name prefix will always match it's data file, their - * name portion of the file can be dynamic. It is important that if the Player changes - * their name, that their save cached file will be change within this function. - * This process will only happen the first time the player is loaded from the cache - * (which can vary, such as at server startup or they logoff and they are cleared from - * the cache, then added back when they login the next time). So this function will - * rename the cache file to reflect the player's current name. - *

- * - * @param player - * @return - */ public PlayerCachePlayerData fromJson( Player player ) { - PlayerCachePlayerData results = null; - -// // This is the "target" file name for the player, based upon their -// // current name. The saved cache file may not be named exactly the same, -// // and if it's not, then their existing cache file will be renamed -// // within the function getCachedFileMatch() - String playerFileName = getPlayerFileName( player ); - - File playerFile = getCachedFileMatch( playerFileName ); - - - if ( playerFile.exists() ) { - - results = fromJsonFile( playerFile ); - } - - - // New player and file does not exist so create it. - if ( results == null ) { - results = new PlayerCachePlayerData( player, playerFile ); - - // Then save it: - toJsonFile( results ); - } - - return results; - } - - - - private TreeMap getPlayerFiles() { - // load the player's files: - if ( playerFiles == null ) { - - playerFiles = new TreeMap<>(); - - FileFilter fileFilter = (file) -> { - - String fname = file.getName(); - boolean isTemp = fname.startsWith( FILE_PREFIX_BACKUP ) || - fname.endsWith( FILE_SUFFIX_BACKUP ) || - fname.endsWith( FILE_SUFFIX_TEMP ); - - return !file.isDirectory() && !isTemp && - fname.endsWith( FILE_SUFFIX_JSON ); - }; - - - File[] files = getPlayerFilePath().listFiles( fileFilter ); - for ( File f : files ) - { - String fileNamePrefix = getFileNamePrefix( f.getName() ); - getPlayerFiles().put( fileNamePrefix, f ); - } - - } - - return playerFiles; - } - - /** - *

Potentially there could be more than one result, but considering if a player - * changes their name, then it should only return only one entry. The reason for - * this, is that the file name should be based upon the player's UUID, which is the - * first 13 characters of the file, and the name itself, which follows, should - * never be part of the "key". - *

- * - * @param playerFile - * @param playerFileName - * @return - */ - private File getCachedFileMatch( String playerFileName ) - { - File results = null; - - String fileNamePrefix = getFileNamePrefix( playerFileName ); - - results = getPlayerFiles().get( fileNamePrefix ); - - if ( results == null ) { - - // This is the "target" file name for the player, based upon their - // current name. The saved cache file may not be named exactly the same, - // and if it's not, then their existing cache file needs to be - // renamed. - results = getPlayerFile( playerFileName ); - - // NOTE: because the file was NOT found in the directory, then we can assume - // this is a new player therefore we won't have an issue with the player's - // name changing. - getPlayerFiles().put( fileNamePrefix, results ); - } - else if ( !playerFileName.equalsIgnoreCase( results.getName() )) { - - // File name changed!!! Need to rename the file in the file system, and - // update what is in the playerFiles map!! - - File newFile = getPlayerFile( playerFileName ); - - if ( results.exists() ) { - // rename what's on the file system: - results.renameTo( newFile ); - } - - // Replace what's in the map: - getPlayerFiles().put( fileNamePrefix, newFile ); - - results = newFile; - } -// NavigableMap files = getPlayerFiles().tailMap( fileNamePrefix, true ); -// Set keys = files.keySet(); -// for ( String key : keys ) { -// if ( !key.startsWith( fileNamePrefix ) ) { -// break; -// } -// -// results.add( files.get( key ) ); -// } + CoreCacheData results = fromJson( player, PlayerCachePlayerData.class ); - return results; + return (PlayerCachePlayerData) results; } } diff --git a/prison-core/src/main/java/tech/mcprison/prison/cache/PlayerCachePlayerData.java b/prison-core/src/main/java/tech/mcprison/prison/cache/PlayerCachePlayerData.java index cf33074ca..9352102c8 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/cache/PlayerCachePlayerData.java +++ b/prison-core/src/main/java/tech/mcprison/prison/cache/PlayerCachePlayerData.java @@ -24,7 +24,8 @@ * @author RoyalBlueRanger * */ -public class PlayerCachePlayerData { +public class PlayerCachePlayerData + implements CoreCacheData { public static final long SESSION_TIMEOUT_MINING_MS = 1000 * 15; // 15 seconds diff --git a/prison-core/src/main/java/tech/mcprison/prison/chat/FancyMessage.java b/prison-core/src/main/java/tech/mcprison/prison/chat/FancyMessage.java index c469709b0..9003b9c00 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/chat/FancyMessage.java +++ b/prison-core/src/main/java/tech/mcprison/prison/chat/FancyMessage.java @@ -612,6 +612,9 @@ public String toJSONString() { } jsonString = string.toString(); dirty = false; + + jsonString = Output.decodePercentEncoding(jsonString); + return jsonString; } diff --git a/prison-core/src/main/java/tech/mcprison/prison/commands/BaseCommands.java b/prison-core/src/main/java/tech/mcprison/prison/commands/BaseCommands.java index 5154d9a44..3260f727b 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/commands/BaseCommands.java +++ b/prison-core/src/main/java/tech/mcprison/prison/commands/BaseCommands.java @@ -71,6 +71,25 @@ public Player getPlayer( CommandSender sender, String playerName, UUID uuid ) { return result; } + public Player getOnlinePlayer( CommandSender sender, String playerName ) { + Player result = null; + + playerName = playerName != null && !playerName.trim().isEmpty() ? + playerName : sender != null ? sender.getName() : null; + + //Output.get().logInfo("RanksCommands.getPlayer :: playerName = " + playerName ); + + if ( playerName != null ) { + Optional opt = Prison.get().getPlatform().getPlayer( playerName ); + + if ( opt.isPresent() ) { + result = opt.get(); + } + + } + return result; + } + // public double getPlayerBalance( Player player ) { // diff --git a/prison-core/src/main/java/tech/mcprison/prison/commands/CommandAccessResults.java b/prison-core/src/main/java/tech/mcprison/prison/commands/CommandAccessResults.java new file mode 100644 index 000000000..46a8f7bc5 --- /dev/null +++ b/prison-core/src/main/java/tech/mcprison/prison/commands/CommandAccessResults.java @@ -0,0 +1,107 @@ +package tech.mcprison.prison.commands; + +import tech.mcprison.prison.internal.CommandSender; +import tech.mcprison.prison.output.Output; + +public class CommandAccessResults { + + private CommandSender sender; + + private String command; + private String perm; + + private boolean access = true; + + private CommandAccessRejectionReason rejectionReason; + + public enum CommandAccessRejectionReason { + UNKNOWN__NOT_CHECKED, + ACCESS_PERMITTED, + + REJECTION__COMMAND_PERMISSIONS, + REJECTION__COMMAND_ALT_PERMISSIONS, + REJECTION__CONFIG_YAML; + } + + public CommandAccessResults( CommandSender sender ) { + super(); + + this.sender = sender; + this.perm = ""; + + this.access = true; + this.rejectionReason = CommandAccessRejectionReason.UNKNOWN__NOT_CHECKED; + } + + public void setAccessPermitted() { + setAccess( true ); + setRejectionReason( CommandAccessRejectionReason.ACCESS_PERMITTED); + } + public void rejectCommandPermission( String command, String perm ) { + setCommand( command ); + setPerm( perm ); + setAccess( false ); + setRejectionReason( CommandAccessRejectionReason.REJECTION__COMMAND_PERMISSIONS); + } + public void rejectCommandAltPermission( String command, String perm ) { + setCommand( command ); + setPerm( perm ); + setAccess( false ); + setRejectionReason( CommandAccessRejectionReason.REJECTION__COMMAND_ALT_PERMISSIONS); + } + public void rejectConfigYaml( String command, String perm ) { + setCommand( command ); + setPerm( perm ); + setAccess( false ); + setRejectionReason( CommandAccessRejectionReason.REJECTION__CONFIG_YAML); + } + + public void debugAccess() { + if ( Output.get().isDebug() ) { + String msg = String.format( "Command Access for %s: %b [%s] Perm: [%s] Reason: %s]", + getSender().getName(), + isAccess(), + getCommand() == null ? "" : getCommand(), + getPerm() == null ? "" : getPerm(), + getRejectionReason().name() + ); + + Output.get().logInfo( msg ); + } + } + + public CommandSender getSender() { + return sender; + } + public void setSender(CommandSender sender) { + this.sender = sender; + } + + public String getCommand() { + return command; + } + public void setCommand(String command) { + this.command = command; + } + + public String getPerm() { + return perm; + } + public void setPerm(String perm) { + this.perm = perm; + } + + public boolean isAccess() { + return access; + } + public void setAccess(boolean access) { + this.access = access; + } + + public CommandAccessRejectionReason getRejectionReason() { + return rejectionReason; + } + public void setRejectionReason(CommandAccessRejectionReason rejectionReason) { + this.rejectionReason = rejectionReason; + } +} diff --git a/prison-core/src/main/java/tech/mcprison/prison/commands/CommandHandler.java b/prison-core/src/main/java/tech/mcprison/prison/commands/CommandHandler.java index c7acef60b..f5357509b 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/commands/CommandHandler.java +++ b/prison-core/src/main/java/tech/mcprison/prison/commands/CommandHandler.java @@ -20,6 +20,7 @@ import java.lang.reflect.Method; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -135,7 +136,11 @@ private String formatArgument(CommandArgument argument) { } @Override - public ChatDisplay getHelpMessage(RegisteredCommand command) { + public ChatDisplay getHelpMessage(CommandSender sender, RegisteredCommand command) { + + if ( !hasCommandAccess(sender, command, command.getLabel(), new String[0] ) ) { + return null; + } ChatDisplay chatDisplay = new ChatDisplay( String.format( "Cmd: &7%s", @@ -252,24 +257,36 @@ public ChatDisplay getHelpMessage(RegisteredCommand command) { List subcommands = command.getSuffixes(); if (subcommands.size() > 0) { - chatDisplay.addText(ChatColor.DARK_AQUA + "Subcommands:"); + // Force a sorting by use of a TreeSet. Collections.sort() would not work. TreeSet subCommandSet = new TreeSet<>(); for (RegisteredCommand scommand : subcommands) { - String subCmd = scommand.getUsage(); - - int subCmdSubCnt = scommand.getSuffixes().size(); - String subCommands = (subCmdSubCnt == 0 ? "" : - ChatColor.DARK_AQUA + "(" + subCmdSubCnt + " Subcommands)"); - String isAlias = scommand.isAlias() ? ChatColor.DARK_AQUA + " Alias" : ""; + String sLabel = scommand.getCompleteLabel(); + + if ( hasCommandAccess(sender, scommand, sLabel, new String[0] ) ) { + + String subCmd = scommand.getUsage(); + + int subCmdSubCnt = scommand.getSuffixes().size(); + String subCommands = (subCmdSubCnt == 0 ? "" : + ChatColor.DARK_AQUA + "(" + subCmdSubCnt + " Subcommands)"); + + String isAlias = scommand.isAlias() ? ChatColor.DARK_AQUA + " Alias" : ""; + + subCommandSet.add( + String.format( "%s %s %s", subCmd, subCommands, isAlias )); + } - subCommandSet.add( - String.format( "%s %s %s", subCmd, subCommands, isAlias )); } - - for (String subCmd : subCommandSet) { - chatDisplay.addText(subCmd); + + // Only if there are entries to show, then include the header and the details + if ( subCommandSet.size() > 0 ) { + chatDisplay.addText(ChatColor.DARK_AQUA + "Subcommands:"); + + for (String subCmd : subCommandSet) { + chatDisplay.addText(subCmd); + } } } @@ -670,25 +687,25 @@ private RegisteredCommand commandRegisterConfig( Method method, Command commandA RegisteredCommand mainCommand = getRootCommands().get( rootPluginCommand ); - for (int i = 1; i < identifiers.length; i++) { - - String suffix = identifiers[i]; - if ( mainCommand.doesSuffixCommandExist(suffix) ) { - mainCommand = mainCommand.getSuffixCommand(suffix); - } - else { - RegisteredCommand newCommand = new RegisteredCommand(suffix, this, mainCommand); - newCommand.setAlias( alias != null ); - mainCommand.addSuffixCommand(suffix, newCommand); - - // Must add all new RegisteredCommand objects to both getAllRegisteredCommands() and - // getTabCompleterData(). - getAllRegisteredCommands().add( newCommand ); - getTabCompleaterData().add( newCommand ); - - mainCommand = newCommand; - } + for (int i = 1; i < identifiers.length; i++) { + + String suffix = identifiers[i]; + if ( mainCommand.doesSuffixCommandExist(suffix) ) { + mainCommand = mainCommand.getSuffixCommand(suffix); + } + else { + RegisteredCommand newCommand = new RegisteredCommand(suffix, this, mainCommand ); + newCommand.setAlias( alias != null ); + mainCommand.addSuffixCommand(suffix, newCommand); + + // Must add all new RegisteredCommand objects to both getAllRegisteredCommands() and + // getTabCompleterData(). + getAllRegisteredCommands().add( newCommand ); + getTabCompleaterData().add( newCommand ); + + mainCommand = newCommand; } + } // Associate the last RegisteredCommand (mainCommand) with the rootPCommand since that is // the leaf-node that will be tied to the registered command, especially with aliases: @@ -747,7 +764,144 @@ public static String[] addConfigAliases( String label, String[] aliases ) } return results; } + + /*** + *

+ * This function is strictly for non-ops, and if a player has a given perm that + * is specified in the config file, then it will lock that player out of that + * command. This is intended to force overrides on commands for the commands + * that do not have their own perms. + *

+ * @return + */ + public boolean hasCommandAccess( CommandSender sender, RegisteredCommand rootCommand, + String label, String[] args ) { + + CommandAccessResults results = new CommandAccessResults( sender ); + + hasCommandAccess( sender, rootCommand, label, args, results ); + + if ( results.isAccess() ) { + results.setAccessPermitted(); + } + + if ( !results.isAccess() ) { + // Debug logging if prison is in debug mode: + results.debugAccess(); + } + + return results.isAccess(); + } + + private void hasCommandAccess( CommandSender sender, RegisteredCommand rootCommand, + String label, String[] args, + CommandAccessResults results ) { + +// boolean results = true; + + if ( !sender.isOp() ) { + + String exRAKey = "prisonCommandHandler.exclude-non-ops.exclude-related-aliases"; + boolean excludeRelatedAliases = getConfigBoolean( exRAKey ); + + String sLabelAlias = !excludeRelatedAliases || rootCommand.getParentOfAlias() == null ? + null : rootCommand.getParentOfAlias().getCompleteLabel(); + + + commandAccessPermChecks( sender, rootCommand, label, results ); + + if ( results.isAccess() && sLabelAlias != null ) { + + commandAccessPermChecks( sender, rootCommand.getParentOfAlias(), sLabelAlias, results ); + } + + } + + // If we get to this point, and the result is true (the player has access the + // specified command so far), and there are more args, we need to next + // take the args[0] and append it to the label, and then test it again. + // This needs to continue until the generated command is rejected, or + // it passes it's clean and the player has full access to the command(s). + if ( results.isAccess() && args.length > 0 ) { + String newSuffix = args[0]; + String newLabel = label + " " + newSuffix; + String[] newArgs = Arrays.copyOfRange( args, 1, args.length ); + + RegisteredCommand newSuffixCommand = rootCommand.getSuffixCommand( newSuffix ); + + if ( newSuffixCommand != null ) { + + hasCommandAccess( sender, newSuffixCommand, + newLabel, newArgs, results ); + } + } + + } + + private void commandAccessPermChecks(CommandSender sender, RegisteredCommand rootCommand, String label, + CommandAccessResults results) { + + // Must first check to see if the command is setup for excludes, and if + // not then exit with a value of true: + String configKey = "prisonCommandHandler.exclude-non-ops.commands." + + label.replace( " ", "." ); + + List excludePerms = getConfigStringArray( configKey + ".perms" ); + boolean includeCommandPerms = getConfigBoolean( configKey + ".includeCmdPerms" ); + boolean includeCommandAltPerms = getConfigBoolean( configKey + ".includeCmdAltPerms" ); + + if ( excludePerms != null && excludePerms.size() > 0 ) { + + // first check the command perms first: + if ( includeCommandPerms ) { + + for ( String perm : rootCommand.getPermissions() ) { + + if ( sender.hasPermission( perm ) ) { + results.rejectCommandPermission( label, perm ); + break; + } + } + } + + if ( results.isAccess() && includeCommandAltPerms ) { + + // first check the command altPerms next: + for ( String altPerm : rootCommand.getAltPermissions() ) { + + if ( sender.hasPermission( altPerm ) ) { + results.rejectCommandAltPermission( label, altPerm ); + break; + } + } + } + + // If results has not been set to false, then check the exclude-non-ops: + if ( results.isAccess() ) { + + if ( excludePerms != null && excludePerms.size() > 0 && excludePerms.get( 0 ) instanceof String ) { + + for ( Object permObj : excludePerms) { + if ( permObj instanceof String ) { + if ( sender.hasPermission( permObj.toString() ) ) { + results.rejectConfigYaml( label, permObj.toString() ); + break; + } + } + } + } + + } + } + } + private boolean getConfigBoolean( String configKey ) { + return Prison.get().getPlatform().getConfigBooleanFalse( configKey ); + } + private List getConfigStringArray( String configKey ) { + return Prison.get().getPlatform().getConfigStringArray( configKey ); + } + public boolean onCommand(CommandSender sender, PluginCommand command, String label, String[] args) { @@ -757,13 +911,19 @@ public boolean onCommand(CommandSender sender, PluginCommand command, String lab " : No root command found. " ); return false; } - + if (rootCommand.isOnlyPlayers() && !(sender instanceof Player)) { Prison.get().getLocaleManager().getLocalizable("cantAsConsole") .sendTo(sender, LogLevel.ERROR); return true; } + else if ( !hasCommandAccess( sender, rootCommand, label, args ) ) { + // The player does not have access to this command. + // Who cares! Just exit and do nothing. Never log this. + return true; + } + else { try { @@ -784,6 +944,32 @@ public boolean onCommand(CommandSender sender, PluginCommand command, String lab return true; } + + /** + *

This function is similar to onCommand, but it does not run any commands. + * It only validates if a player has access to the commands. + *

+ * @param registeredCommand + * + * @return + */ + public boolean checkCommand( CommandSender sender, + RegisteredCommand registeredCommand, + String label, String... args ) { + boolean hasAccess = true; + + if ( sender != null && + registeredCommand != null && + !hasCommandAccess( sender, registeredCommand, label, args ) ) { + + // The player does not have access to this command. + // Who cares! Just exit and do nothing. Never log this. + hasAccess = false; + } + + + return hasAccess; + } public Map getRegisteredCommands() { return registeredCommands; diff --git a/prison-core/src/main/java/tech/mcprison/prison/commands/HelpHandler.java b/prison-core/src/main/java/tech/mcprison/prison/commands/HelpHandler.java index 525562117..6d2038c31 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/commands/HelpHandler.java +++ b/prison-core/src/main/java/tech/mcprison/prison/commands/HelpHandler.java @@ -18,11 +18,12 @@ package tech.mcprison.prison.commands; +import tech.mcprison.prison.internal.CommandSender; import tech.mcprison.prison.output.ChatDisplay; public interface HelpHandler { - public ChatDisplay getHelpMessage(RegisteredCommand command); + public ChatDisplay getHelpMessage(CommandSender sender, RegisteredCommand command); public String getUsageNoParameters(RegisteredCommand command); diff --git a/prison-core/src/main/java/tech/mcprison/prison/commands/RegisteredCommand.java b/prison-core/src/main/java/tech/mcprison/prison/commands/RegisteredCommand.java index 4e36bceee..f8deaecf7 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/commands/RegisteredCommand.java +++ b/prison-core/src/main/java/tech/mcprison/prison/commands/RegisteredCommand.java @@ -42,6 +42,9 @@ public class RegisteredCommand private RegisteredCommand parent; private boolean alias = false; + private int usageCount; + private long usageRunTimeNanos; + private String junitTest = null; private String description; @@ -78,6 +81,9 @@ public RegisteredCommand(String label, CommandHandler handler, RegisteredCommand this.parent = parent; this.registeredAliases = new ArrayList<>(); + + this.usageCount = 0; + this.usageRunTimeNanos = 0; } /** @@ -153,7 +159,13 @@ public String getCompleteLabel() { * @param sender * @param args */ - void execute(CommandSender sender, String[] args) { + protected void execute(CommandSender sender, String[] args) { + + // First ensure the player is not locked out of this command: + if ( !handler.hasCommandAccess(sender, this, getLabel(), args) ) { + return; + } + if (!testPermission(sender)) { Prison.get().getLocaleManager().getLocalizable("noPermission") .sendTo(sender, LogLevel.ERROR); @@ -182,21 +194,26 @@ void execute(CommandSender sender, String[] args) { // (args == null ? "null" : args.length) + // " args[0] == " + args[0]); - executeMethod(sender, args); + // all checks were passed, and this is where the + // command is executed... + executeMethod( sender, args ); } else { // Strip first arg, then recursively try again String[] nargs = new String[args.length - 1]; System.arraycopy(args, 1, nargs, 0, args.length - 1); - command.execute(sender, nargs); + command.execute( sender, nargs ); } - } else { - executeMethod(sender, args); + } + else { + // all checks were passed, and this is where the + // command is executed... + executeMethod( sender, args ); } } - private void executeMethod(CommandSender sender, String[] args) { + private void executeMethod(CommandSender sender, String[] args ) { if (!set) { sendHelpMessage(sender); return; @@ -205,6 +222,9 @@ private void executeMethod(CommandSender sender, String[] args) { ArrayList resultArgs = new ArrayList(); resultArgs.add(sender); + long nanosStart = 0; + long nanosEnd = 0; + Arguments arguments; try { arguments = new Arguments(args, flagsByName); @@ -227,10 +247,28 @@ private void executeMethod(CommandSender sender, String[] args) { try { try { + // The command is ran here with the invoke... + + // Record that the command has been "ran", which does not mean it was successful: + incrementUsageCount(); + nanosStart = System.nanoTime(); + method.invoke(getMethodInstance(), resultArgs.toArray()); + + nanosEnd = System.nanoTime(); + + long nanosDuration = nanosEnd - nanosStart; + this.usageRunTimeNanos += nanosDuration; + } catch ( IllegalArgumentException | InvocationTargetException e) { - if (e.getCause() instanceof CommandError) { + + nanosEnd = System.nanoTime(); + + long nanosDuration = nanosEnd - nanosStart; + this.usageRunTimeNanos += nanosDuration; + + if (e.getCause() instanceof CommandError) { CommandError ce = (CommandError) e.getCause(); Output.get().sendError(sender, ce.getColorizedMessage()); if (ce.showUsage()) { @@ -304,8 +342,8 @@ public List getFlags() { return flags; } - public ChatDisplay getHelpMessage() { - return handler.getHelpHandler().getHelpMessage(this); + public ChatDisplay getHelpMessage( CommandSender sender ) { + return handler.getHelpHandler().getHelpMessage( sender, this ); } public String getLabel() { @@ -387,7 +425,11 @@ public boolean isSet() { public void sendHelpMessage(CommandSender sender) { - getHelpMessage().send( sender ); + ChatDisplay chatDisp = getHelpMessage( sender ); + + if ( chatDisp != null ) { + chatDisp.send( sender ); + } } void set(Object methodInstance, Method method) { @@ -568,4 +610,22 @@ public int compareTo( RegisteredCommand arg0 ) return getUsage().compareTo( arg0.getUsage() ); } + + public void incrementUsageCount() { + usageCount++; + } + public int getUsageCount() { + return usageCount; + } + public void setUsageCount(int usageCount) { + this.usageCount = usageCount; + } + + public long getUsageRunTimeNanos() { + return usageRunTimeNanos; + } + public void setUsageRunTimeNanos(long usageRunTimeNanos) { + this.usageRunTimeNanos = usageRunTimeNanos; + } + } diff --git a/prison-core/src/main/java/tech/mcprison/prison/commands/RootCommand.java b/prison-core/src/main/java/tech/mcprison/prison/commands/RootCommand.java index c6aedbb3e..05992fc6c 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/commands/RootCommand.java +++ b/prison-core/src/main/java/tech/mcprison/prison/commands/RootCommand.java @@ -24,8 +24,8 @@ public class RootCommand extends RegisteredCommand { private PluginCommand root; - RootCommand(PluginCommand root, CommandHandler handler) { - super(root.getLabel(), handler, null); + RootCommand(PluginCommand root, CommandHandler handler ) { + super(root.getLabel(), handler, null ); this.root = root; } @@ -33,7 +33,8 @@ public PluginCommand getBukkitCommand() { return root; } - @Override void set(Object methodInstance, Method method) { + @Override + protected void set(Object methodInstance, Method method) { super.set(methodInstance, method); root.setDescription(getDescription()); root.setUsage(getUsage()); diff --git a/prison-core/src/main/java/tech/mcprison/prison/commands/TabCompleaterData.java b/prison-core/src/main/java/tech/mcprison/prison/commands/TabCompleaterData.java index 18a85a134..ea32b10e2 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/commands/TabCompleaterData.java +++ b/prison-core/src/main/java/tech/mcprison/prison/commands/TabCompleaterData.java @@ -6,6 +6,9 @@ import java.util.Set; import java.util.TreeMap; +import tech.mcprison.prison.Prison; +import tech.mcprison.prison.internal.CommandSender; + public class TabCompleaterData { private String name; @@ -13,9 +16,13 @@ public class TabCompleaterData private boolean leafNode; + private RegisteredCommand registeredCommand; + public TabCompleaterData() { this( "", null ); + this.registeredCommand = null; + setLeafNode( false ); } private TabCompleaterData( String name, String[] args ) { @@ -26,9 +33,13 @@ private TabCompleaterData( String name, String[] args ) { this.leafNode = ( args == null || args.length == 0 ); - if ( !this.leafNode ) { - add( args ); - } + this.registeredCommand = null; + + // Cannot build out child nodes here... has to be done within the + // addCommand() function. +// if ( !this.leafNode ) { +// add( args ); +// } } /** @@ -48,21 +59,34 @@ private TabCompleaterData( String name, String[] args ) { * * @param usage */ - private void add( String... usage ) { + private void addCommand( RegisteredCommand registeredCommand, String... usage ) { if ( usage.length > 0 ) { String name = usage[0]; String key = name.toLowerCase(); + String[] subArray = Arrays.copyOfRange( usage, 1, usage.length ); + // If getData() does not contain a key, then add it before processing it: if ( !getData().containsKey( key ) ) { TabCompleaterData tcd = new TabCompleaterData( name, subArray ); getData().put( key, tcd ); } - else { - getData().get( key ).add( subArray ); + +// else { +// TabCompleaterData tcd = getData().get( key ); +// tcd.addCommand( registeredCommand, subArray ); +// } + + TabCompleaterData tcd = getData().get( key ); + tcd.addCommand( registeredCommand, subArray ); + + boolean storeRegisteredCommand = usage.length == 1; + if ( storeRegisteredCommand ) { + tcd.setRegisteredCommand( registeredCommand ); } + } @@ -86,7 +110,7 @@ public void add( RegisteredCommand registeredCommand ) { String[] usage = usageStr.split( " " ); - add( usage ); + addCommand( registeredCommand, usage ); // if ( usage.length > 0 ) { // String key = usage[0]; @@ -116,11 +140,15 @@ public void add( RegisteredCommand registeredCommand ) { * @return */ public List check( String alias, String... args ) { + return check( null, alias, args ); + } + + public List check( CommandSender commandSender, String alias, String... args ) { List results = new ArrayList<>(); if ( alias != null ) { if ( getData().containsKey( alias ) ) { - results.addAll( getData().get( alias.toLowerCase() ).check( args ) ); + results.addAll( getData().get( alias.toLowerCase() ).checkLabel( commandSender, alias, args ) ); } } @@ -130,9 +158,11 @@ public List check( String alias, String... args ) { } - private List check( String... args ) { + private List checkLabel( CommandSender commandSender, String label, String... args ) { List results = new ArrayList<>(); + String newLabel = label + " "; + if ( args == null || args.length == 0 || args.length == 1 && args[0].length() == 0 ) { @@ -140,7 +170,14 @@ private List check( String... args ) { // Must get each child's name: Set keys = getData().keySet(); for ( String key : keys ) { - results.add( getData().get( key ).getName() ); + + TabCompleaterData tabComplete = getData().get( key ); + + if ( tabComplete.validateAccess( commandSender, newLabel + key, "" ) ) { + + results.add( getData().get( key ).getName() ); + } + } } @@ -158,7 +195,9 @@ else if ( args.length > 1 String[] subArray = Arrays.copyOfRange( args, 1, args.length ); - results.addAll( getData().get( key ).check( subArray ) ); + TabCompleaterData tabComplete = getData().get( key ); + + results.addAll( tabComplete.checkLabel( commandSender, newLabel + key, subArray ) ); } } else { @@ -171,7 +210,14 @@ else if ( args.length > 1 for ( String key : keys ) { if ( key.startsWith( prefix )) { - results.add( getData().get( key ).getName() ); + TabCompleaterData tabComplete = getData().get( key ); + + String[] subArray = Arrays.copyOfRange( args, 1, args.length ); + if ( tabComplete.validateAccess( commandSender, newLabel + key, subArray ) ) { + + results.add( getData().get( key ).getName() ); + } + } } } @@ -179,6 +225,19 @@ else if ( args.length > 1 return results; } + + private boolean validateAccess( CommandSender commandSender, String label, String... args ) { + boolean hasAccess = true; + + // Unit tests will have null for commandSender so skip the command access validation: + if ( commandSender != null && !commandSender.isOp() ) { + + hasAccess = Prison.get().getCommandHandler() + .checkCommand(commandSender, getRegisteredCommand(), label, args ); + } + + return hasAccess; + } public String getName() { @@ -202,4 +261,11 @@ public void setLeafNode( boolean leafNode ) { this.leafNode = leafNode; } + public RegisteredCommand getRegisteredCommand() { + return registeredCommand; + } + public void setRegisteredCommand(RegisteredCommand registeredCommand) { + this.registeredCommand = registeredCommand; + } + } diff --git a/prison-core/src/main/java/tech/mcprison/prison/discord/PrisonPasteChat.java b/prison-core/src/main/java/tech/mcprison/prison/discord/PrisonPasteChat.java index 3ac2fc252..a88baaed2 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/discord/PrisonPasteChat.java +++ b/prison-core/src/main/java/tech/mcprison/prison/discord/PrisonPasteChat.java @@ -17,6 +17,7 @@ import com.google.gson.Gson; import com.google.gson.JsonObject; +import tech.mcprison.prison.Prison; import tech.mcprison.prison.output.Output; import tech.mcprison.prison.util.Text; @@ -163,7 +164,7 @@ protected String cleanText( String text, boolean keepColorCodes ) // // Injects the size back in to the text without changing the total length of the text: // int size = cleanedText.length(); -// DecimalFormat dFmt = new DecimalFormat("#,##0"); +// DecimalFormat dFmt = Prison.get().getDecimalFormatInt(); // String sizeString = (dFmt.format( size ) + " bytes ") // .substring( 0, SUBMISSION_SIZE_PLACEHOLDER.length() ); // @@ -179,7 +180,7 @@ private String addHeaders( String text ) { // Injects the size back in to the text without changing the total length of the text: int size = text.length(); - DecimalFormat dFmt = new DecimalFormat("#,##0"); + DecimalFormat dFmt = Prison.get().getDecimalFormatInt(); String sizeString = (dFmt.format( size ) + " bytes ") .substring( 0, SUBMISSION_SIZE_PLACEHOLDER.length() ); diff --git a/prison-core/src/main/java/tech/mcprison/prison/file/FileCollection.java b/prison-core/src/main/java/tech/mcprison/prison/file/FileCollection.java index a94d97860..e1323e123 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/file/FileCollection.java +++ b/prison-core/src/main/java/tech/mcprison/prison/file/FileCollection.java @@ -38,7 +38,11 @@ public String getName() { return collDir.getName(); } - /** + public File getCollDir() { + return collDir; + } + + /** *

Refresh is a function that will clear the databaseMap collection if it contains anything, * then load all possible FileDatabase objects, ignoring those that been virtually deleted. *

diff --git a/prison-core/src/main/java/tech/mcprison/prison/file/FileDatabase.java b/prison-core/src/main/java/tech/mcprison/prison/file/FileDatabase.java index eaa08d66b..93485f5b4 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/file/FileDatabase.java +++ b/prison-core/src/main/java/tech/mcprison/prison/file/FileDatabase.java @@ -25,7 +25,11 @@ public FileDatabase(File dbDir) { refresh(); } - /** + public File getDbDir() { + return dbDir; + } + + /** *

Refresh is a function that will clear the collectionMap collection if it contains anything, * then load all possible FileCollection objects, ignoring those that been virtually deleted. *

diff --git a/prison-core/src/main/java/tech/mcprison/prison/file/JsonFileIO.java b/prison-core/src/main/java/tech/mcprison/prison/file/JsonFileIO.java index a899101e5..55e23a387 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/file/JsonFileIO.java +++ b/prison-core/src/main/java/tech/mcprison/prison/file/JsonFileIO.java @@ -42,6 +42,17 @@ public Gson getGson() return gson; } + public Gson getGsonExposed() + { + return new GsonBuilder() + .excludeFieldsWithoutExposeAnnotation() + .disableHtmlEscaping() + .setPrettyPrinting() + .create(); + } + + + /** *

This constructs a player file named based upon the UUID followed * by the player's name. This format is used so it's easier to identify @@ -99,6 +110,16 @@ public void saveJsonFile( File file, FileIOData data ) } } + public void saveJsonExposedFile( File file, FileIOData data ) + { + if ( file != null && data != null ) + { + String json = getGsonExposed().toJson( data ); + + saveFile( file, json ); + } + } + /** * This function will try to load the given file, of which the contents should be * JSon. If it is successful then the resulting object will represent the file. diff --git a/prison-core/src/main/java/tech/mcprison/prison/gui/PrisonCoreGuiMessages.java b/prison-core/src/main/java/tech/mcprison/prison/gui/PrisonCoreGuiMessages.java index 02cd410d9..35904f79d 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/gui/PrisonCoreGuiMessages.java +++ b/prison-core/src/main/java/tech/mcprison/prison/gui/PrisonCoreGuiMessages.java @@ -142,14 +142,14 @@ protected String guiPagePriorMsg() { protected String guiPriceMsg( Double price ) { - DecimalFormat dFmt = new DecimalFormat( "#,##0.00" ); + DecimalFormat dFmt = Prison.get().getDecimalFormat( "#,##0.00" ); String value = price == null ? dFmt.format(0) : dFmt.format(price); return guiPriceMsg( value ); } protected String guiPriceMsg( Integer price ) { - DecimalFormat dFmt = new DecimalFormat( "#,##0" ); + DecimalFormat dFmt = Prison.get().getDecimalFormatInt(); String value = price == null ? dFmt.format(0) : dFmt.format(price); return guiPriceMsg( value ); @@ -165,7 +165,7 @@ protected String guiPriceMsg( String price ) { protected String guiConfirmMsg( String prestigeName, double value ) { - DecimalFormat dFmt = new DecimalFormat( "#,##0.0" ); + DecimalFormat dFmt = Prison.get().getDecimalFormat( "#,##0.0" ); String valueStr = dFmt.format(value); return Prison.get().getLocaleManager() @@ -176,7 +176,7 @@ protected String guiConfirmMsg( String prestigeName, double value ) { protected String guiDelayMsg( int value ) { - DecimalFormat dFmt = new DecimalFormat( "#,##0" ); + DecimalFormat dFmt = Prison.get().getDecimalFormatInt(); String valueStr = dFmt.format(value); return guiDelayMsg( valueStr ); @@ -191,7 +191,7 @@ protected String guiDelayMsg( String value ) { protected String guiMultiplierMsg( double value ) { - DecimalFormat dFmt = new DecimalFormat( "#,##0.0" ); + DecimalFormat dFmt = Prison.get().getDecimalFormat( "#,##0.0" ); String valueStr = dFmt.format(value); return guiMultiplierMsg( valueStr ); diff --git a/prison-core/src/main/java/tech/mcprison/prison/internal/Scheduler.java b/prison-core/src/main/java/tech/mcprison/prison/internal/Scheduler.java index 25124660f..edb833768 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/internal/Scheduler.java +++ b/prison-core/src/main/java/tech/mcprison/prison/internal/Scheduler.java @@ -65,6 +65,11 @@ public interface Scheduler { */ public int runTaskTimerAsync(Runnable run, long delay, long interval); + + public void dispatchCommand( Player player, String command ); + + public void performCommand( Player player, String command ); + /** * Cancel a certain task. * diff --git a/prison-core/src/main/java/tech/mcprison/prison/internal/block/PrisonBlock.java b/prison-core/src/main/java/tech/mcprison/prison/internal/block/PrisonBlock.java index 6264743bb..70215ca7b 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/internal/block/PrisonBlock.java +++ b/prison-core/src/main/java/tech/mcprison/prison/internal/block/PrisonBlock.java @@ -56,7 +56,12 @@ public class PrisonBlock public enum PrisonBlockType { minecraft, CustomItems, - heads + ItemsAdder, + heads; + + public boolean isCustomBlockType() { + return this != minecraft; + } } /** diff --git a/prison-core/src/main/java/tech/mcprison/prison/internal/block/PrisonBlockStatusData.java b/prison-core/src/main/java/tech/mcprison/prison/internal/block/PrisonBlockStatusData.java index d92a4def0..8844ecc11 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/internal/block/PrisonBlockStatusData.java +++ b/prison-core/src/main/java/tech/mcprison/prison/internal/block/PrisonBlockStatusData.java @@ -201,8 +201,8 @@ public void transferStats( PrisonBlockStatusData oldBlock ) { public String toPlaceholderString() { StringBuilder sb = new StringBuilder(); - DecimalFormat dFmt = new DecimalFormat("#,##0"); - DecimalFormat fFmt = new DecimalFormat("#,##0.00"); + DecimalFormat dFmt = Prison.get().getDecimalFormatInt(); + DecimalFormat fFmt = Prison.get().getDecimalFormat("#,##0.00"); String percent = fFmt.format(getChance()); @@ -345,37 +345,37 @@ private boolean checkGravityAffects( String blockName ) switch ( blockName ) { - case "sand": - case "red_sand": - case "gravel": - - case "white_concrete_powder": - case "orange_concrete_powder": - case "magenta_concrete_powder": - case "light_blue_concrete_powder": - case "yellow_concrete_powder": - case "lime_concrete_powder": - case "pink_concrete_powder": - case "gray_concrete_powder": - case "light_gray_concrete_powder": - case "cyan_concrete_powder": - case "purple_concrete_powder": - case "blue_concrete_powder": - case "brown_concrete_powder": - case "green_concrete_powder": - case "red_concrete_powder": - case "black_concrete_powder": - - case "anvil": - case "chipped_anvil": - case "damaged_anvil": - - case "scaffolding": - case "pointed_dripstone": - case "dragon_egg": - { - results = true; - } + case "sand": + case "red_sand": + case "gravel": + + case "white_concrete_powder": + case "orange_concrete_powder": + case "magenta_concrete_powder": + case "light_blue_concrete_powder": + case "yellow_concrete_powder": + case "lime_concrete_powder": + case "pink_concrete_powder": + case "gray_concrete_powder": + case "light_gray_concrete_powder": + case "cyan_concrete_powder": + case "purple_concrete_powder": + case "blue_concrete_powder": + case "brown_concrete_powder": + case "green_concrete_powder": + case "red_concrete_powder": + case "black_concrete_powder": + + case "anvil": + case "chipped_anvil": + case "damaged_anvil": + + case "scaffolding": + case "pointed_dripstone": + case "dragon_egg": + { + results = true; + } } } return results; diff --git a/prison-core/src/main/java/tech/mcprison/prison/internal/platform/Platform.java b/prison-core/src/main/java/tech/mcprison/prison/internal/platform/Platform.java index c82d190d4..b2508c19d 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/internal/platform/Platform.java +++ b/prison-core/src/main/java/tech/mcprison/prison/internal/platform/Platform.java @@ -25,6 +25,7 @@ import java.util.TreeSet; import java.util.UUID; +import tech.mcprison.prison.backpacks.PlayerBackpack; import tech.mcprison.prison.commands.PluginCommand; import tech.mcprison.prison.file.YamlFileIO; import tech.mcprison.prison.internal.CommandSender; @@ -40,6 +41,7 @@ import tech.mcprison.prison.modules.ModuleElementType; import tech.mcprison.prison.output.ChatDisplay; import tech.mcprison.prison.placeholders.Placeholders; +import tech.mcprison.prison.ranks.data.RankLadder; import tech.mcprison.prison.ranks.data.RankPlayer; import tech.mcprison.prison.store.Storage; import tech.mcprison.prison.util.Location; @@ -444,4 +446,13 @@ public void autoCreateMineLinerAssignment( List rankMineNames, public void listAllMines(CommandSender sender, Player player); + + public void sellall(RankPlayer rankPlayer); + + + public RankLadder getRankLadder( String ladderName ); + + + public List getPlayerOldBackpacks( Player player ); + } diff --git a/prison-core/src/main/java/tech/mcprison/prison/output/Output.java b/prison-core/src/main/java/tech/mcprison/prison/output/Output.java index 9694787c5..7b19517d0 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/output/Output.java +++ b/prison-core/src/main/java/tech/mcprison/prison/output/Output.java @@ -37,6 +37,9 @@ */ public class Output extends OutputMessages { + + public static final String PERCENT_ENCODING = "%"; + public static final String PERCENT_DECODING = "%"; private static Output instance; @@ -201,6 +204,45 @@ public String format(String message, LogLevel level, Object... args) { return getLogPrefix(level) + String.format(message, args); } + /** + *

This version of String format should be used in place of the standard + * Java String.format() function since if there is a percent remaining in + * the results, it will then encode it so it does not trigger a Java + * format error where it thinks the % is an escape character for the + * the String.format() command. This class, when actually logging the + * message, will convert the encoded percent back to a normal percent. + *

+ * + *

This is a potential problem due to the number of times one message + * may be passed through a String.format(). This prevents a properly + * escaped percent, of `%%` from being a single percent to be used as + * a encoded escape for formatting. + *

+ * + * @param message + * @param args + * @return + */ + public static String stringFormat( String message, Object... args ) { + + String msg = args == null || args.length == 0 ? + message : + String.format(message, args); + + if ( msg.contains( PERCENT_ENCODING ) ) { + msg = msg.replace( PERCENT_DECODING, PERCENT_ENCODING ); + } + + return msg; + } + + public static String decodePercentEncoding( String message ) { + if ( message.contains( PERCENT_ENCODING ) ) { + message = message.replace( PERCENT_ENCODING, PERCENT_DECODING ); + } + return message; + } + /** * Log a message with a specified {@link LogLevel} */ @@ -227,10 +269,20 @@ else if ( Prison.get() == null || Prison.get().getPlatform() == null ) { } else { try { + + String msg = args == null || args.length == 0 ? + message : + String.format(message, args); + + msg = decodePercentEncoding( msg ); +// if ( msg.contains( PERCENT_ENCODING ) ) { +// msg = msg.replace( PERCENT_ENCODING, PERCENT_DECODING ); +// } + Prison.get().getPlatform().log( prefixTemplatePrison + " " + getLogColorCode(level) + - String.format(message, args)); + msg); } catch ( MissingFormatArgumentException e ) { @@ -260,14 +312,15 @@ else if ( Prison.get() == null || Prison.get().getPlatform() == null ) { String errorMessage = "Error with Java format usage (eg %s): " + " LogLevel: " + level.name() + " message: [" + message + "] params: [" + sb.toString() + "]" + - " error: [" + e.getMessage() + "]"; + " error: [" + e.getMessage() + "] " + + " Escape with backslash or double percent [\\b \\n \\f \\r \\t \\\\ %%]"; Prison.get().getPlatform().logCore( prefixTemplatePrison + " " + getLogColorCode(LogLevel.ERROR) + errorMessage ); - e.printStackTrace(); + //e.printStackTrace(); } } } diff --git a/prison-core/src/main/java/tech/mcprison/prison/output/TextComponent.java b/prison-core/src/main/java/tech/mcprison/prison/output/TextComponent.java index 7336b483b..b92b7095d 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/output/TextComponent.java +++ b/prison-core/src/main/java/tech/mcprison/prison/output/TextComponent.java @@ -31,7 +31,7 @@ public class TextComponent extends DisplayComponent { protected String text; public TextComponent(String text, Object... args) { - this.text = String.format(text, args); + this.text = Output.stringFormat(text, args); } @Override public String text() { diff --git a/prison-core/src/main/java/tech/mcprison/prison/placeholders/PlaceholderAttributeNumberFormat.java b/prison-core/src/main/java/tech/mcprison/prison/placeholders/PlaceholderAttributeNumberFormat.java index 3a43e1d82..73c163e36 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/placeholders/PlaceholderAttributeNumberFormat.java +++ b/prison-core/src/main/java/tech/mcprison/prison/placeholders/PlaceholderAttributeNumberFormat.java @@ -5,6 +5,7 @@ import org.apache.commons.lang3.StringUtils; +import tech.mcprison.prison.Prison; import tech.mcprison.prison.output.Output; import tech.mcprison.prison.placeholders.PlaceholderManager.NumberTransformationUnitTypes; import tech.mcprison.prison.util.Text; @@ -182,7 +183,7 @@ public String format( Double value ) { try { // & will not work in the DecimalFormat so replace it with ^|^ then replace after formatting: String fmt = getFormat();//.replace( "&", "^|^" ); - DecimalFormat dFmt = new DecimalFormat( fmt ); + DecimalFormat dFmt = Prison.get().getDecimalFormat( fmt ); switch ( getUnitType() ) { diff --git a/prison-core/src/main/java/tech/mcprison/prison/placeholders/PlaceholderManager.java b/prison-core/src/main/java/tech/mcprison/prison/placeholders/PlaceholderManager.java index a3ee1a437..ed75add67 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/placeholders/PlaceholderManager.java +++ b/prison-core/src/main/java/tech/mcprison/prison/placeholders/PlaceholderManager.java @@ -566,9 +566,9 @@ public enum PrisonPlaceHolders { - prison_tmbl_header_minename(PlaceholderFlags.MINES, PlaceholderFlags.ALIAS), + prison_tmbl_header_minename(PlaceholderFlags.STATSMINES, PlaceholderFlags.ALIAS), prison_tmbl_nnn_minename(PlaceholderFlags.STATSMINES, PlaceholderFlags.ALIAS), - prison_tmbl_totals_minename(PlaceholderFlags.MINES, PlaceholderFlags.ALIAS), + prison_tmbl_totals_minename(PlaceholderFlags.STATSMINES, PlaceholderFlags.ALIAS), prison_tmbn_nnn_minename(PlaceholderFlags.STATSMINES, PlaceholderFlags.ALIAS), prison_tmbc_nnn_minename(PlaceholderFlags.STATSMINES, PlaceholderFlags.ALIAS), @@ -578,9 +578,9 @@ public enum PrisonPlaceHolders { prison_tmbt_nnn_minename(PlaceholderFlags.STATSMINES, PlaceholderFlags.ALIAS), - prison_top_mine_block_line_header_minename(prison_tmbl_header_minename, PlaceholderFlags.MINES), + prison_top_mine_block_line_header_minename(prison_tmbl_header_minename, PlaceholderFlags.STATSMINES), prison_top_mine_block_line_nnn_minename(prison_tmbl_nnn_minename, PlaceholderFlags.STATSMINES), - prison_top_mine_block_line_totals_minename(prison_tmbl_totals_minename, PlaceholderFlags.MINES), + prison_top_mine_block_line_totals_minename(prison_tmbl_totals_minename, PlaceholderFlags.STATSMINES), prison_top_mine_block_name_nnn_minename(prison_tmbn_nnn_minename, PlaceholderFlags.STATSMINES), prison_top_mine_block_chance_nnn_minename(prison_tmbc_nnn_minename, PlaceholderFlags.STATSMINES), @@ -786,6 +786,35 @@ public static List getAllChatList( boolean omitSuppressable) { int pos = results.size(); results.add( " &7" + type.name() ); + + // placeholders are per-player specific, and do not work on entities or in Holographic Displays + if ( type == PlaceholderFlags.PLAYER ) { + results.add( " &cNOTE: PLAYER placeholders are player specific and do not " + + "work on entities or with Holographic Displays."); + results.add( " &cThe rankup costs are based only on the player's rank, " + + "and not their current balance (see RANKPLAYERS)."); + } + else if ( type == PlaceholderFlags.MINEPLAYERS ) { + results.add( " &cNOTE: MINEPLAYERS placeholders are player specific and do not " + + "work on entities or with Holographic Displays."); + } + else if ( type == PlaceholderFlags.RANKPLAYERS ) { + results.add( " &cNOTE: RANKPLAYERS placeholders are player specific and do not " + + "work on entities or with Holographic Displays."); + results.add( " &cThese placeholders provide adjusted rank cost values that " + + "are player specific unlike the PLAYER placeholders."); + } + else if ( type == PlaceholderFlags.STATSPLAYERS ) { + results.add( " &cNOTE: 'prison_top_player_' placeholders are ranked by " + + "Prestige Ranks, Default Ranks, then player's rank score.."); + results.add( " &cRank score is based upon their balance, but if " + + "the player can rankup, but choses not to, then their " ); + results.add( " &crank score is penalized to prevent rank-camping."); + } + else if ( type == PlaceholderFlags.STATSRANKS ) { + results.add( " &cNOTE: 'prison_top_rank_' is similar to 'prison_top_player_' " + + "(see STATSPLAYERS) but for the named rank."); + } int count = 0; diff --git a/prison-core/src/main/java/tech/mcprison/prison/placeholders/PlaceholderStatsData.java b/prison-core/src/main/java/tech/mcprison/prison/placeholders/PlaceholderStatsData.java index 250f7f034..9524708b0 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/placeholders/PlaceholderStatsData.java +++ b/prison-core/src/main/java/tech/mcprison/prison/placeholders/PlaceholderStatsData.java @@ -8,9 +8,14 @@ public class PlaceholderStatsData { // private PrisonPlaceHolders placeholder; private int hits = 0; + private int failHits = 0; private long totalDurationNanos = 0L; + /** + * A failedMatch will be identified if a placeholder key cannot be located for + * the placeholder pattern. + */ private boolean failedMatch; private transient final Object lock; @@ -25,7 +30,67 @@ public PlaceholderStatsData( String placeholderId ) { this.failedMatch = false; } - public void logHit( long nanoStart, long nanoEnd ) { + public String toString() { + StringBuilder sb = new StringBuilder(); + + sb.append("PlaceholderStatsData: ").append( placeholderId ) + .append( " placeholderKey: " ).append( + placeholderKey == null ? "-null-" : + placeholderKey.getKey() + ":" + placeholderKey.getPlaceholder().name() + ); + sb.append( " failedMatch: " ).append( failedMatch ); + + return sb.toString(); + } + + /** + *

This function will update the placeholderStats for both successful and failed + * hits. This function will update the cached stats' placeholderKey if + * the PlaceholderIdentifier has been matched. + *

+ * + *

If a placeholderKey has not been found for the identifier, then this + * cached stats entry will mark the identifier as a failed lookup so + * on future hits, it will not waste time trying to lookup bad placeholders. + *

+ * + * @param pId + * @param nanoStart + * @param nanoEnd + */ + public void updateStats(PlaceholderIdentifier pId, long nanoStart, long nanoEnd) { + + + // If the stats placeholderKey is null, and one has been identified with the pId, + // then set the placeholderKey. + if ( getPlaceholderKey() == null && pId.getPlaceholderKey() != null ) { + setPlaceholderKey( pId.getPlaceholderKey() ); + } + + // Since a match was not found, try to record that the match failed. + // The success may vary between players, but as long as there is a placeholderKey + // Associated with the stats and identifier, it will not become a perm failure. + if ( !pId.isFoundAMatch() ) { + + logFailedHit(nanoStart, nanoEnd); + } + else { + + // Successfully found... so log it: + logHit( nanoStart, nanoEnd ); + } + + } + + + /** + *

This is logging a successful hit for the placeholder. + *

+ * + * @param nanoStart + * @param nanoEnd + */ + private void logHit( long nanoStart, long nanoEnd ) { long durationNano = nanoEnd - nanoStart; synchronized ( lock ) { @@ -34,6 +99,33 @@ public void logHit( long nanoStart, long nanoEnd ) { } } + /** + *

This function records that a match to find the correct placeholder key + * failed and should be recored as a failed match, but ONLY if the + * placeholderKey is null (no associations). + * A failed match bypasses look ups on future placeholder matches. + *

+ * + *

A placeholder cannot be marked as failed if it contains + * an actual placeholder key. A placeholder key will be assigned even if + * an associated player is not valid within prison. + *

+ * + */ + private void logFailedHit( long nanoStart, long nanoEnd ) { + long durationNano = nanoEnd - nanoStart; + + synchronized ( lock ) { + failHits++; + totalDurationNanos += durationNano; + + if ( placeholderKey == null && !failedMatch ) { + failedMatch = true; + } + } + } + + public double getAverageDurationMs() { double avgMs = totalDurationNanos / hits / 1000000.0d; @@ -57,9 +149,16 @@ public void setPlaceholderKey(PlaceHolderKey placeholderKey) { public int getHits() { return hits; } - public void setHits(int hits) { - this.hits = hits; +// private void setHits(int hits) { +// this.hits = hits; +// } + + public int getFailHits() { + return failHits; } +// private void setFailHits(int failHits) { +// this.failHits = failHits; +// } public long getTotalDurationNanos() { return totalDurationNanos; @@ -68,12 +167,13 @@ public void setTotalDurationNanos(long totalDurationNanos) { this.totalDurationNanos = totalDurationNanos; } + public boolean isFailedMatch() { return failedMatch; } - public void setFailedMatch(boolean failedMatch) { - this.failedMatch = failedMatch; - } +// private void setFailedMatch(boolean failedMatch) { +// this.failedMatch = failedMatch; +// } } diff --git a/prison-core/src/main/java/tech/mcprison/prison/placeholders/PlaceholdersStats.java b/prison-core/src/main/java/tech/mcprison/prison/placeholders/PlaceholdersStats.java index 716de89b7..bee6b1cf0 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/placeholders/PlaceholdersStats.java +++ b/prison-core/src/main/java/tech/mcprison/prison/placeholders/PlaceholdersStats.java @@ -3,8 +3,12 @@ import java.text.DecimalFormat; import java.util.ArrayList; import java.util.Collections; +import java.util.List; import java.util.TreeMap; +import tech.mcprison.prison.Prison; +import tech.mcprison.prison.output.Output; + public class PlaceholdersStats { private static PlaceholdersStats stats; @@ -32,6 +36,19 @@ public static PlaceholdersStats getInstance() { } + /** + *

This function will take the initial PlaceholderIdentifier, which has not yet been + * mapped to a placeholderKey, and try to see if there is an entry within the + * placeholder cache. If there is, then it will use the cache version, and if that + * cache version contains a placeholderKey, then it will be copied to the pId. + *

+ * + *

If there is no cache entry, then one will be created, but it will be lacking + * a placeholderKey initially. + *

+ * @param pId + * @return + */ public PlaceholderStatsData getStats( PlaceholderIdentifier pId ) { PlaceholderStatsData results = null; @@ -39,17 +56,21 @@ public PlaceholderStatsData getStats( PlaceholderIdentifier pId ) { if ( pId != null ) { String key = pId.getIdentifier(); + // If there is a placeholder cache entry, then get it from the cache: if ( getPlaceholders().containsKey(key) ) { results = getPlaceholders().get( key ); - - if ( results.getPlaceholderKey() != null ) { + + // NOTE: the results may have a placeholderKey assigned, if it does, then + // assign to the pId: + if ( results != null && results.getPlaceholderKey() != null ) { pId.setPlaceholderKey( results.getPlaceholderKey() ); } - } else { + // Else create a new cache entry: + results = new PlaceholderStatsData( key ); - getPlaceholders().put( key, results ); +// getPlaceholders().put( key, results ); // Store this new stats object in the cache. If there is a placeholder fail, then // this will help prevent going through all of the calculations for future @@ -57,6 +78,7 @@ public PlaceholderStatsData getStats( PlaceholderIdentifier pId ) { getPlaceholders().put( key, results ); } + } return results; @@ -84,26 +106,9 @@ public PlaceholderStatsData setStats( PlaceholderIdentifier pId, PlaceholderStat if ( pId != null && stats != null ) { - //String key = pId.getIdentifier(); - - if ( stats.getPlaceholderKey() == null && pId.getPlaceholderKey() != null ) { - stats.setPlaceholderKey( pId.getPlaceholderKey() ); - } - - stats.logHit( nanoStart, nanoEnd ); - - - if ( !pId.isFoundAMatch() ) { - stats.setFailedMatch( true ); - } - - -// // If it contains -// if ( !getPlaceholders().containsKey(key) ) { -// -// -// } + // Update all of the stats details, including if it should mark the stats as a failure. + stats.updateStats( pId, nanoStart, nanoEnd ); } return results; @@ -113,11 +118,11 @@ public PlaceholderStatsData setStats( PlaceholderIdentifier pId, PlaceholderStat public ArrayList generatePlaceholderReport() { ArrayList results = new ArrayList<>(); - DecimalFormat iFmt = new DecimalFormat( "#,##0" ); - DecimalFormat dFmt = new DecimalFormat( "#,##0.0000" ); + DecimalFormat iFmt = Prison.get().getDecimalFormatInt(); + DecimalFormat dFmt = Prison.get().getDecimalFormat( "#,##0.0000" ); results.add( - "&7 Hits Avg/Hit ms Placeholder" ); + "&7 &n Hits&r &n Fails&r &nAvg/Hit ms&r &nPlaceholder used:internal &r" ); ArrayList keys = new ArrayList<>( getPlaceholders().keySet() ); Collections.sort( keys ); @@ -125,16 +130,21 @@ public ArrayList generatePlaceholderReport() { PlaceholderStatsData stats = getPlaceholders().get(key); int hits = stats.getHits(); + int fails = stats.getFailHits(); long totalDurationNano = stats.getTotalDurationNanos(); - double avgMs = totalDurationNano / (double) hits / 1000000d; + double avgMs = totalDurationNano / (double) (hits + fails) / 1000000d; boolean valid = stats.getPlaceholderKey() != null; String message = String.format( - "&3%10s %10s %s %s", + "&3%10s %10s %10s &2%s%s &c%s", iFmt.format( hits ), + iFmt.format( fails ), dFmt.format( avgMs ), key, + stats.getPlaceholderKey() == null ? + "" : + "&7:&b" + stats.getPlaceholderKey().getPlaceholder().name(), ( valid ? "" : stats.isFailedMatch() ? "&cInvalid: bypassing lookups." : @@ -146,6 +156,33 @@ public ArrayList generatePlaceholderReport() { return results; } + + public void clearCache(boolean resetCache, boolean removeErrors) { + + List removeKeys = new ArrayList<>(); + + ArrayList keys = new ArrayList<>( getPlaceholders().keySet() ); + for (String key : keys) { + PlaceholderStatsData stats = getPlaceholders().get(key); + + if ( resetCache || removeErrors && stats.isFailedMatch() ) { + removeKeys.add( key ); + } + } + + for (String key : removeKeys) { + getPlaceholders().remove( key ); + } + + + Output.get().logInfo( "PlaceholderStats: Cache was purged of %s placeholders. Removed: %s ", + resetCache ? "all" : + removeErrors ? "invalid" : "some", + Prison.getDecimalFormatStaticInt().format( removeKeys.size() ) + ); + + } + public TreeMap getPlaceholders() { return placeholders; @@ -154,5 +191,4 @@ public void setPlaceholders(TreeMap placeholders) this.placeholders = placeholders; } - } diff --git a/prison-core/src/main/java/tech/mcprison/prison/placeholders/PlaceholdersUtil.java b/prison-core/src/main/java/tech/mcprison/prison/placeholders/PlaceholdersUtil.java index b5ec676b1..a1efb18b4 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/placeholders/PlaceholdersUtil.java +++ b/prison-core/src/main/java/tech/mcprison/prison/placeholders/PlaceholdersUtil.java @@ -4,6 +4,7 @@ import java.util.ArrayList; import java.util.List; +import tech.mcprison.prison.Prison; import tech.mcprison.prison.util.Text; public class PlaceholdersUtil @@ -94,7 +95,7 @@ public static String formattedTime( double timeSec ) { // // double secs = (double)(timeSec / TIME_SECOND); // timeSec -= (secs * TIME_SECOND); -// DecimalFormat dFmt = new DecimalFormat("#0"); +// DecimalFormat dFmt = Prison.get().getDecimalFormat("#0"); // sb.append( dFmt.format( secs )); // // y,m,w,d,h,m,s // sb.append( prefixesTimeUnits.get(6) ).append( " " ); @@ -116,7 +117,7 @@ public static String formattedTime( double timeSec ) { */ public static String formattedMetricSISize( double amount ) { - DecimalFormat dFmt = new DecimalFormat("#,##0.00"); + DecimalFormat dFmt = Prison.get().getDecimalFormat("#,##0.00"); return formattedMetricSISize( amount, dFmt, " " ); } @@ -156,7 +157,7 @@ private static double divBy1000( double amount, StringBuilder unit, String units public static String formattedPrefixBinarySize( double amount ) { - DecimalFormat dFmt = new DecimalFormat("#,##0.00"); + DecimalFormat dFmt = Prison.get().getDecimalFormat("#,##0.00"); return formattedIPrefixBinarySize( amount, dFmt, " " ); } diff --git a/prison-core/src/main/java/tech/mcprison/prison/ranks/data/RankPlayer.java b/prison-core/src/main/java/tech/mcprison/prison/ranks/data/RankPlayer.java index cf02b33f4..26c6508d9 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/ranks/data/RankPlayer.java +++ b/prison-core/src/main/java/tech/mcprison/prison/ranks/data/RankPlayer.java @@ -782,6 +782,13 @@ public void setRanksRefs( HashMap ranksRefs ) { * it finds a match with the target rank. *

* + *

If the setting prison-mines.access-to-prior-mines is true, as found in the + * config.yml file, then prior ranks on the target ladder is search if the + * current rank is not a match to the targetRank. Setting this setting to + * false will allow admins to use Mine Access by Rank but only for their + * current rank. + *

+ * * @param targetRank * @return */ @@ -800,13 +807,21 @@ public boolean hasAccessToRank( Rank targetRank ) { rank.getLadder().equals( targetRank.getLadder() ) ) { hasAccess = rank.equals( targetRank ); - Rank priorRank = rank.getRankPrior(); - - while ( !hasAccess && priorRank != null ) { + + // If access-to-prior-mines is enabled (defaults to true if does not exist), + // then search prior ranks on this ladder until a match with target is found. + if ( Prison.get().getPlatform() + .getConfigBooleanTrue( "prison-mines.access-to-prior-mines" ) ) { + + Rank priorRank = rank.getRankPrior(); - hasAccess = priorRank.equals( targetRank ); - priorRank = priorRank.getRankPrior(); + while ( !hasAccess && priorRank != null ) { + + hasAccess = priorRank.equals( targetRank ); + priorRank = priorRank.getRankPrior(); + } } + } } } @@ -1414,6 +1429,19 @@ public boolean isSneaking() { return false; } + + /** + *

This function will return the next rank that they player will have upon + * rankup. This includes going from the end of the default ladder to the next + * rank on prestiges ladder. + *

+ * + *

If this function return a null value, then the player has reached the + * end of the game, and they are at the top-most rank. + *

+ * + * @return + */ public PlayerRank getNextPlayerRank() { PlayerRank rankCurrent = getPlayerRankDefault(); @@ -1448,7 +1476,12 @@ public PlayerRank getNextPlayerRank() { // if they don't have a current prestige rank, then use the lowest rank: if ( prestigeRankCurrent == null ) { - RankLadder rLadder = getRankLadder( RankLadder.PRESTIGES ); + + RankLadder rLadder = Prison.get().getPlatform().getRankLadder( RankLadder.PRESTIGES ); + + // If the player does not have a presetige rank, the getRankLadder will return null. + +// RankLadder rLadder = getRankLadder( RankLadder.PRESTIGES ); nRank = rLadder == null ? null : rLadder.getLowestRank().orElse(null); } @@ -1623,7 +1656,7 @@ public static String printRankScoreLine1Header() { public String printRankScoreLine1( int rankPostion ) { - DecimalFormat dFmt = new DecimalFormat("#,##0.00"); + DecimalFormat dFmt = Prison.get().getDecimalFormat("#,##0.00"); PlayerRank prestRank = getPlayerRankPrestiges(); PlayerRank defRank = getPlayerRankDefault(); @@ -1669,7 +1702,7 @@ public static String printRankScoreLine2Header() { public String printRankScoreLine2( int rankPostion ) { - DecimalFormat dFmt = new DecimalFormat("#,##0.00"); + DecimalFormat dFmt = Prison.get().getDecimalFormat("#,##0.00"); PlayerRank prestRank = getPlayerRankPrestiges(); PlayerRank defRank = getPlayerRankDefault(); diff --git a/prison-core/src/main/java/tech/mcprison/prison/ranks/data/StatsRankPlayerBalance.java b/prison-core/src/main/java/tech/mcprison/prison/ranks/data/StatsRankPlayerBalance.java index 821658333..0455673ba 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/ranks/data/StatsRankPlayerBalance.java +++ b/prison-core/src/main/java/tech/mcprison/prison/ranks/data/StatsRankPlayerBalance.java @@ -63,7 +63,7 @@ public StatsRankPlayerBalanceData getTopStats( int position ) { // check to see if the stats should be refreshed: refresh(); - playerStats.get( position - 1 ); + stats = playerStats.get( position - 1 ); } return stats; } diff --git a/prison-core/src/main/java/tech/mcprison/prison/tasks/PrisonCommandTaskData.java b/prison-core/src/main/java/tech/mcprison/prison/tasks/PrisonCommandTaskData.java index eba6dca18..3c4c20f8d 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/tasks/PrisonCommandTaskData.java +++ b/prison-core/src/main/java/tech/mcprison/prison/tasks/PrisonCommandTaskData.java @@ -5,6 +5,7 @@ import java.util.Arrays; import java.util.List; +import tech.mcprison.prison.Prison; import tech.mcprison.prison.PrisonAPI; import tech.mcprison.prison.internal.Player; import tech.mcprison.prison.output.Output; @@ -300,7 +301,7 @@ public String getDebugDetails() { long nanoTotal = 0; - DecimalFormat dFmt = new DecimalFormat( "#,000.0000" ); + DecimalFormat dFmt = Prison.get().getDecimalFormat( "#,000.0000" ); for ( Long elapsedNano : elapsedTimes ) { @@ -428,6 +429,11 @@ public void runTask( Player player ) { long start = System.nanoTime(); + + // was failing with leading spaces after spliting after a ";" so trim to fix it: + task = task == null ? "" : task.trim(); + + // Apply the custom placeholders: for ( PrisonCommandTaskPlaceholderData cPlaceholder : getCustomPlaceholders() ) { if ( cPlaceholder.contains( task ) ) { diff --git a/prison-core/src/main/java/tech/mcprison/prison/util/Location.java b/prison-core/src/main/java/tech/mcprison/prison/util/Location.java index 19ffde5c3..2c2a83a20 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/util/Location.java +++ b/prison-core/src/main/java/tech/mcprison/prison/util/Location.java @@ -148,6 +148,14 @@ public void setBlockAsync( PrisonBlock prisonBlock ) { world.setBlockAsync( prisonBlock, this ); } + /** + *

The edge identifies if a block is along the edge, or corner, of a mine. + * It's these blocks that becomes the pink glass tracer blocks when + * when enabling the tracer on a mine. + *

+ * + * @return + */ public boolean isEdge() { return isEdge; } diff --git a/prison-core/src/main/java/tech/mcprison/prison/util/PrisonJarReporter.java b/prison-core/src/main/java/tech/mcprison/prison/util/PrisonJarReporter.java index 374d19779..c59fc3c9c 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/util/PrisonJarReporter.java +++ b/prison-core/src/main/java/tech/mcprison/prison/util/PrisonJarReporter.java @@ -14,7 +14,6 @@ import java.util.List; import java.util.TreeMap; import java.util.zip.ZipEntry; -import java.util.zip.ZipException; import java.util.zip.ZipFile; import tech.mcprison.prison.Prison; @@ -207,14 +206,20 @@ public void scanForJars() { } } - catch ( ZipException e ) + catch ( Exception e ) { - e.printStackTrace(); - } - catch ( IOException e ) - { - e.printStackTrace(); + // Ignore all errors. + // These are not our plugins, so if there is a problem, then it really does not matter + } +// catch ( ZipException e ) +// { +// e.printStackTrace(); +// } +// catch ( IOException e ) +// { +// e.printStackTrace(); +// } } diff --git a/prison-core/src/main/java/tech/mcprison/prison/util/PrisonStatsUtil.java b/prison-core/src/main/java/tech/mcprison/prison/util/PrisonStatsUtil.java index 692770c62..56857746c 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/util/PrisonStatsUtil.java +++ b/prison-core/src/main/java/tech/mcprison/prison/util/PrisonStatsUtil.java @@ -220,7 +220,7 @@ private List listFiles(String path, String fileSuffix) { } private void addFileToText(File file, StringBuilder sb) { - DecimalFormat dFmt = new DecimalFormat("#,##0"); + DecimalFormat dFmt = Prison.get().getDecimalFormatInt(); SimpleDateFormat sdFmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); sb.append("\n"); diff --git a/prison-core/src/main/java/tech/mcprison/prison/util/PrisonTPS.java b/prison-core/src/main/java/tech/mcprison/prison/util/PrisonTPS.java index 84e4326e9..aab73a7a5 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/util/PrisonTPS.java +++ b/prison-core/src/main/java/tech/mcprison/prison/util/PrisonTPS.java @@ -4,6 +4,7 @@ import java.util.ArrayList; import java.util.List; +import tech.mcprison.prison.Prison; import tech.mcprison.prison.tasks.PrisonRunnable; import tech.mcprison.prison.tasks.PrisonTaskSubmitter; @@ -200,7 +201,7 @@ public class PrisonTPS private transient long lastPollNano = System.nanoTime(); - private final DecimalFormat tpsFmt = new DecimalFormat("#,##0.00"); + private final DecimalFormat tpsFmt = Prison.get().getDecimalFormat("#,##0.00"); public static final Object tpsLock = new Object(); diff --git a/prison-core/src/main/java/tech/mcprison/prison/util/Text.java b/prison-core/src/main/java/tech/mcprison/prison/util/Text.java index 2429735de..01088b199 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/util/Text.java +++ b/prison-core/src/main/java/tech/mcprison/prison/util/Text.java @@ -89,10 +89,14 @@ public class Text //#([A-Fa-f0-9]){6} - private static DecimalFormat dFmt = new DecimalFormat("#,##0.00"); - private static DecimalFormat iFmt = new DecimalFormat("#,##0"); + private static DecimalFormat dFmt = Prison.getDecimalFormatStatic("#,##0.00"); + private static DecimalFormat iFmt = Prison.getDecimalFormatStaticInt(); - + static { + if ( Prison.get() != null ) { + + } + } protected Text() { super(); @@ -336,12 +340,16 @@ else if (b[i] == prefix && "0123456789AaBbCcDdEeFfKkLlMmNnOoRr#xX".indexOf(b[i + } /** - * Translates color codes (a-f) (A-F) (0-9), prefixed by an ampersand, into Minecraft-readable - * color codes.

Use of this method is discouraged. Implementations are recommended to + *

Translates color codes (a-f) (A-F) (0-9), prefixed by an ampersand, into Minecraft-readable + * color codes. + *

+ * + *

Use of this method is discouraged. Implementations are recommended to * translate color codes using their native internal's APIs. This assumes that the server mod will * accept vanilla Minecraft color codes, although implementations such as Sponge do not do this. * However, because there are some practical uses for a method like this, it exists in a * non-deprecated but discouraged state. + *

* * @param text The text to translate. * @return The translated string. @@ -623,8 +631,8 @@ public static String pluralize(String baseNoun, int quantity) { public static String formatTimeDaysHhMmSs( long timeMs ) { - DecimalFormat iFmt = new DecimalFormat("#,##0"); - DecimalFormat tFmt = new DecimalFormat("00"); + DecimalFormat iFmt = Prison.getDecimalFormatStaticInt(); + DecimalFormat tFmt = Prison.getDecimalFormatStatic("00"); // SimpleDateFormat sdFmt = new SimpleDateFormat( "HH:mm:ss" ); // long _sec = 1000; diff --git a/prison-core/src/main/java/tech/mcprison/prison/util/Vector.java b/prison-core/src/main/java/tech/mcprison/prison/util/Vector.java index 6c404219c..46c93e2ee 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/util/Vector.java +++ b/prison-core/src/main/java/tech/mcprison/prison/util/Vector.java @@ -236,7 +236,7 @@ public double length() { * @return the magnitude */ public double lengthSquared() { - return x * y + y * y + z * z; + return x * x + y * y + z * z; } /** diff --git a/prison-core/src/main/resources/lang/core/fi_FI.properties b/prison-core/src/main/resources/lang/core/fi_FI.properties new file mode 100644 index 000000000..424e2488a --- /dev/null +++ b/prison-core/src/main/resources/lang/core/fi_FI.properties @@ -0,0 +1,185 @@ +# +# Prison is a Minecraft plugin for the prison game mode. +# Copyright (C) 2021 The Prison Team +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +## +## Prison Supports Unicode (UTF-8) encoding in these properties files. BUt you must +## follow these instructions to ensure everything works properly. +## +## 1. You should only edit these files using a UTF-8 editor. On windows use NotePad, not WordPad. +## WordPad will save as plain text. To confirm the save was successful: save, close the editor, +## then reopen to confirm the encoding was preserved. +## +## 2. When running on Windows, you must enable utf-8 encoding in minecraft's console. Windows +## defaults to a characterpage 1252. To enable window's use of utf-8, you need to change the +## encoding prior to launching spigot/paper: +## chcp 65001 +## +## Full example of a windows script, which hooks for java debugging: +## rem Note: chcp 65001 enables utf-8 in windows, when normally windows uses characterpage 1252 +## chcp 65001 +## java -Dfile.encoding="UTF-8" -Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005 -Xms1g -Xmx4g -jar spigot-1.8.8.jar nogui --log-strip-color +## pause +## +## 3. When viewing the logs/latest.log files you must use an editor such as NotePad instead of WordPad. +## +## 4. Unicode is properly displayed in game, in console, in the logs, and with paste.helpch.at when using +## /prison support submit. +## + + +# NOTE: A messages__version is an arbitrary integer that will be manually incremented within Prison +# when there are changes to these messages. This value represents when message content is +# changed, fixed, or added to. This value may not be increased if the change is very small and +# insignificant, such as a space or a couple of letters. +# +# messages__auto_refresh=true indicates that this file will automatically be replaced if +# Prison detects a messages__version difference. The old file will be deleted (renamed) and +# a new copy will be placed in the directory to be used. If this value is set to false, then +# Prison will not refresh this file and there could be issues with the display of other messages. +# If auto refresh is set to false, we are not held responsible for possible issues that can +# arise from inaccurate messages. If set to false, then you are responsible for maintaining +# the messages on your own. +# +# If you make changes to this file, and you have messages__auto_refresh=false, then those +# changes will be replaced when this file is updated. Since the old file is renamed, and +# not deleted, you can manually merge your changes back in to the new update. The old +# renamed files will never be deleted by prison; you can remove them when you feel like it +# is safe to do so. +# +# Please consider helping Prison, and everyone else who may use Prison, by contributing all +# translations to other languages. They should be faithful translations, and not something +# for the sake of humor or changes just for cosmetic styling. If you have something you would +# like to share, please contact a staff member on our Discord server. +#Thanks for your contributions! +# +messages__version=9 +messages__auto_refresh=true + + +core_output__prefix_template=| %1 | &7 +core_output__prefix_template_prison=Prison +core_output__prefix_template_info=Info +core_output__prefix_template_warning=Varoitus +core_output__prefix_template_error=Error +core_output__prefix_template_debug=Debug + +core_output__color_code_info=&3 +core_output__color_code_warning=&c +core_output__color_code_error=&c +core_output__color_code_debug=&9 + +core_output__error_startup_failure=Prison: (Sending to System.err due to Output.log Logger failure): +core_output__error_incorrect_number_of_parameters=Log Failure (%1): Incorrect number of parameters: [%2] Original raw message: [%3] Arguments: %4 + + +core_text__prefix=&3 +core_text__just_now=nytten +core_text__ago=sitten +core_text__from_now=tästä lähtien +core_text__and=ja +core_text__time_units_prefix_spacer= +core_text__time_units_singular=vuosi,kuukausi,viikko,päivä,tunti,minuutti,sekuntti +core_text__time_units_plural=vuodet,kuukaudet,viikot,päivät,tunnit,minuutit,sekuntit +core_text__time_units_short=y,m,w,d,h,m,s + + +core_tokens__name_required=Prison Tokens=A player's name is required when used from console. +core_tokens__cannot_view_others_balances=Prison Tokens: You do not have permission to view other player's balances. +core_tokens__view_balance=&3%1 has %2 tokens. +core_tokens__add_invalid_amount=Prison Tokens: Määrää ei tunnistettu: '%1'. Pitää olla ylempi kuin nolla. +core_tokens__added_amount=&3%1 on &7%2 &3tokeneita lisättyä &7%3&3. +core_tokens__removed_amount=&3%1 nyt on &7%2 &3tokeneita poistettua &7%3&3. +core_tokens__set_amount=&3%1 on nyt &7%2 &3tokenia. + + +core_runCmd__name_required=pelaajan nimi vaaditaan. +core_runCmd__command_required=komento vaaditaan. + + +core_prison_utf8_test=test + + +# The following are the original messages and they will eventually be replaced. + +includeError=[%1] has an invalid value. +excludeError=[%1] has an invalid value. +cantAsConsole=You can't do this as console. +missingArgument=The argument [%1] is not defined (it has no default value). +missingFlagArgument=The flag -%1 does not have the required parameters. +undefinedFlagArgument=The argument [%1] to the flag -%2 is not defined. +internalErrorOccurred=An internal error occurred while attempting to perform this command. +noPermission=You lack the necessary permissions to perform this command. +blockParseError=The parameter [%1] is not a valid block. +numberParseError=The parameter [%1] is not a number. +numberTooLow=The parameter [%1] must be equal or greater than %2. +numberTooHigh=The parameter [%1] must be equal or less than %2. +numberRangeError=The parameter [%1] must be equal or greater than %2 and less than or equal to %3. +tooFewCharacters=The parameter [%1] must be equal or greater than %2 characters. +tooManyCharacters=The parameter [%1] must be equal or less than %2 characters. +playerNotOnline=The player %1 is not online. +worldNotFound=The world %1 was not found. + + + + + +core_gui__click_to_decrease=&3Click to decrease. +core_gui__click_to_increase=&3Click to increase. + + +core_gui__click_to_cancel=&3Click to cancel. +core_gui__click_to_close=&3Click to close. +core_gui__click_to_confirm=&3Click to confirm. +core_gui__click_to_delete=&3Click to delete. +core_gui__click_to_disable=&3Click to disable. +core_gui__click_to_edit=&3Click to edit. +core_gui__click_to_enable=&3Click to enable. +core_gui__click_to_open=&3Click to open. + + +core_gui__left_click_to_confirm=&3Left-Click to confirm. +core_gui__left_click_to_reset=&3Left-Click to reset. +core_gui__left_click_to_open=&3Left-Click to open. +core_gui__left_click_to_edit=&3Left-Click to edit. + + +core_gui__right_click_to_cancel=&3Right-Click to cancel. +core_gui__right_click_to_delete=&3Right-Click to delete. +core_gui__right_click_to_disable=&3Right-Click to disable. +core_gui__right_click_to_enable=&3Right-Click to enable. +core_gui__right_click_to_toggle=&3Right-Click to toggle. + + +core_gui__right_click_and_shift_to_delete=&3Right-Click and shift to delete. +core_gui__right_click_and_shift_to_disable=&3Right-Click and shift to disable. +core_gui__right_click_and_shift_to_toggle=&3Right-Click and shift to toggle. + + +core_gui__page_next=&3Next page. +core_gui__page_prior=&3Prior page. + + +core_gui__money_earned=&3You earned &a$%1 +core_gui__price=&3Price: %1 +core_gui__confirm=&3Confirm: %1 %2 +core_gui__delay=&3Delay: %1 secs +core_gui__multiplier=&3Multiplier: x %1 +core_gui__value=&3Value: %1 +core_gui__permission=&3Permission: &7%1 +core_gui__prestige_name=&3Prestige name: %1 + diff --git a/prison-core/src/main/resources/lang/core/zh-CN.properties b/prison-core/src/main/resources/lang/core/zh-CN.properties new file mode 100644 index 000000000..3d48d2fc8 --- /dev/null +++ b/prison-core/src/main/resources/lang/core/zh-CN.properties @@ -0,0 +1,180 @@ + +# +# Prison is a Minecraft plugin for the prison game mode. +# Copyright (C) 2021 The Prison Team +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +## +## Prison Supports Unicode (UTF-8) encoding in these properties files. BUt you must +## follow these instructions to ensure everything works properly. +## +## 1. You should only edit these files using a UTF-8 editor. On windows use NotePad, not WordPad. +## WordPad will save as plain text. To confirm the save was successful: save, close the editor, +## then reopen to confirm the encoding was preserved. +## +## 2. When running on Windows, you must enable utf-8 encoding in minecraft's console. Windows +## defaults to a characterpage 1252. To enable window's use of utf-8, you need to change the +## encoding prior to launching spigot/paper: +## chcp 65001 +## +## Full example of a windows script, which hooks for java debugging: +## rem Note: chcp 65001 enables utf-8 in windows, when normally windows uses characterpage 1252 +## chcp 65001 +## java -Dfile.encoding="UTF-8" -Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005 -Xms1g -Xmx4g -jar spigot-1.8.8.jar nogui --log-strip-color +## pause +## +## 3. When viewing the logs/latest.log files you must use an editor such as NotePad instead of WordPad. +## +## 4. Unicode is properly displayed in game, in console, in the logs, and with paste.helpch.at when using +## /prison support submit. +## + + +# NOTE: A messages__version is an arbitrary integer that will be manually incremented within Prison +# when there are changes to these messages. This value represents when message content is +# changed, fixed, or added to. This value may not be increased if the change is very small and +# insignificant, such as a space or a couple of letters. +# +# messages__auto_refresh=true indicates that this file will automatically be replaced if +# Prison detects a messages__version difference. The old file will be deleted (renamed) and +# a new copy will be placed in the directory to be used. If this value is set to false, then +# Prison will not refresh this file and there could be issues with the display of other messages. +# If auto refresh is set to false, we are not held responsible for possible issues that can +# arise from inaccurate messages. If set to false, then you are responsible for maintaining +# the messages on your own. +# +# If you make changes to this file, and you have messages__auto_refresh=false, then those +# changes will be replaced when this file is updated. Since the old file is renamed, and +# not deleted, you can manually merge your changes back in to the new update. The old +# renamed files will never be deleted by prison; you can remove them when you feel like it +# is safe to do so. +# +# Please consider helping Prison, and everyone else who may use Prison, by contributing all +# translations to other languages. They should be faithful translations, and not something +# for the sake of humor or changes just for cosmetic styling. If you have something you would +# like to share, please contact a staff member on our Discord server. +#Thanks for your contributions! +# +messages__version=7 +messages__auto_refresh=true + + +core_output__prefix_template=| %1 | &7 +core_output__prefix_template_prison=监狱 +core_output__prefix_template_info=ä¿¡æ¯ +core_output__prefix_template_warning=警告 +core_output__prefix_template_error=错误 +core_output__prefix_template_debug=Debug + +core_output__color_code_info=&3 +core_output__color_code_warning=&c +core_output__color_code_error=&c +core_output__color_code_debug=&9 + +core_output__error_startup_failure=监狱: (Sending to System.err due to Output.log Logger failure): +core_output__error_incorrect_number_of_parameters= 日志失败(%1): Incorrect number of parameters: [%2] Original raw message: [%3] Arguments: %4 + + +core_text__prefix=&3 +core_text__just_now=现在 +core_text__ago=ä»¥å‰ +core_text__from_now=åŽ +core_text__and=å’Œ +core_text__time_units_singular=å¹´ã€æœˆã€å‘¨ã€æ—¥ã€æ—¶ã€åˆ†ã€ç§’ +core_text__time_units_plural=å¹´ã€æœˆã€å‘¨ã€æ—¥ã€æ—¶ã€åˆ†ã€ç§’ +core_text__time_units_short=å¹´ã€æœˆã€å‘¨ã€æ—¥ã€æ—¶ã€åˆ†ã€ç§’ + + +core_tokens__name_required=Prison Tokens=A player's name is required when used from console. +core_tokens__cannot_view_others_balances=Prison Tokens: You do not have permission to view other player's balances. +core_tokens__view_balance=&3%1 has %2 tokens. +core_tokens__add_invalid_amount=Prison Tokens: Invalid amount: '%1'. Must be greater than zero. +core_tokens__added_amount=&3%1 now has &7%2 &3tokens after adding &7%3&3. +core_tokens__removed_amount=&3%1 now has &7%2 &3tokens after removing &7%3&3. +core_tokens__set_amount=&3%1 now has &7%2 &3tokens. + + +core_runCmd__name_required=A valid player name is required. +core_runCmd__command_required=A command is required. + +# The following are the original messages and they will eventually be replaced. + +includeError=[%1] 具有无效值 +excludeError=[%1] 具有无效值 +cantAsConsole=您ä¸èƒ½åœ¨æŽ§åˆ¶å°æ‰§è¡Œæ­¤æ“作 +missingArgument=未定义å‚æ•°[%1](它没有默认值) +missingFlagArgument=标志-%1没有所需的å‚æ•° +undefinedFlagArgument=未定义标志-%2çš„å‚æ•°[%1] +internalErrorOccurred=å°è¯•æ‰§è¡Œæ­¤å‘½ä»¤æ—¶å‘生内部错误 +noPermission=你缺少执行该命令的æƒé™ +blockParseError=å‚æ•°[%1]ä¸æ˜¯æœ‰æ•ˆçš„æ–¹å— +numberParseError=å‚æ•°[%1]ä¸æ˜¯æ•°å­— +numberTooLow=å‚æ•°[%1]必须等于或大于%2 +numberTooHigh=å‚æ•°[%1]必须等于或å°äºŽ%2 +numberRangeError=å‚æ•°[%1]必须等于或大于%2且å°äºŽæˆ–等于%3 +tooFewCharacters=å‚æ•°[%1]必须等于或大于%2 +tooManyCharacters=å‚æ•°[%1]必须等于或å°äºŽ%2 +playerNotOnline=玩家%1ä¸åœ¨çº¿ +worldNotFound=找ä¸åˆ°ä¸–ç•Œ%1 + + + + + +core_gui__click_to_decrease=&3点击å‡å°‘ +core_gui__click_to_increase=&3点击增加 + + +core_gui__click_to_cancel=&3å•å‡»ä»¥å–消。 +core_gui__click_to_close=&3å•å‡»ä»¥å…³é—­ +core_gui__click_to_confirm=&3点击确认 +core_gui__click_to_delete=&3å•å‡»ä»¥åˆ é™¤ +core_gui__click_to_disable=&3å•å‡»ä»¥ç¦ç”¨ +core_gui__click_to_edit=&3点击编辑 +core_gui__click_to_enable=&3å•å‡»ä»¥å¯ç”¨ +core_gui__click_to_open=&3å•å‡»æ‰“å¼€ + + +core_gui__left_click_to_confirm=&3左键å•å‡»ç¡®è®¤ +core_gui__left_click_to_reset=&3左键å•å‡»ä»¥é‡ç½® +core_gui__left_click_to_open=&3左键å•å‡»æ‰“å¼€ +core_gui__left_click_to_edit=&3左键å•å‡»è¿›è¡Œç¼–辑 + + +core_gui__right_click_to_cancel=&3å³é”®å•å‡»ä»¥å–消 +core_gui__right_click_to_delete=&3å³é”®å•å‡»ä»¥åˆ é™¤ +core_gui__right_click_to_disable=&3å³é”®å•å‡»ä»¥ç¦ç”¨ +core_gui__right_click_to_enable=&3å³é”®å•å‡»ä»¥å¯ç”¨ +core_gui__right_click_to_toggle=&3å³é”®å•å‡»ä»¥åˆ‡æ¢ + + +core_gui__right_click_and_shift_to_delete=&3å³é”®å•å‡»å¹¶æŒ‰ä½shift键以删除 +core_gui__right_click_and_shift_to_disable=&3å³é”®å•å‡»å¹¶æŒ‰ä½shift键以ç¦ç”¨ +core_gui__right_click_and_shift_to_toggle=&3å³é”®å•å‡»å¹¶æŒ‰ä½shifté”®åˆ‡æ¢ + + +core_gui__page_next=&3下一页 +core_gui__page_prior=&3上一页 + + +core_gui__price=&3价格:%1 +core_gui__confirm=&3确认:%1%2 +core_gui__delay=&3延迟:%1秒 +core_gui__multiplier=&3å€æ•°ï¼šx%1 +core_gui__value=&3值:%1 +core_gui__permission=&3æƒé™ï¼š&7%1 +core_gui__prestige_name=&3声望å称:%1 + diff --git a/prison-core/src/main/resources/lang/mines/de_DE.properties b/prison-core/src/main/resources/lang/mines/de_DE.properties index 1ead9ee64..b8c0f73f4 100644 --- a/prison-core/src/main/resources/lang/mines/de_DE.properties +++ b/prison-core/src/main/resources/lang/mines/de_DE.properties @@ -51,7 +51,7 @@ -messages__version=3 +messages__version=4 messages__auto_refresh=true @@ -92,7 +92,7 @@ missing_world=&7Die Welt, in der die Mine erstellt wurde, kann nicht gefunden we mines_mtp__unable_to_teleport=Sorry. You're unable to teleport there. mines_mtp__unable_to_teleport_others=&3You cannot teleport other players to a mine. Ignoring parameter. mines_mtp__no_target_mine_found=No target mine found. &3Resubmit teleport request with a mine name. -mines_mtp__player_must_be_in_game=mines_mtp__player_must_be_in_game +mines_mtp__player_must_be_in_game=You can only teleport players that are online and in the game. mines_mtp__player_must_be_in_game=&3Specified player is not in the game so they cannot be teleported. mines_mtp__cannot_use_virtual_mines=&cInvalid option. This mine is a virtual mine&7. Use &a/mines set area &7to enable the mine. mines_mtp__teleport_failed=&3Telport failed. Are you sure you're a Player? diff --git a/prison-core/src/main/resources/lang/mines/en_US.properties b/prison-core/src/main/resources/lang/mines/en_US.properties index 3159ad152..3f86d76e8 100644 --- a/prison-core/src/main/resources/lang/mines/en_US.properties +++ b/prison-core/src/main/resources/lang/mines/en_US.properties @@ -51,7 +51,7 @@ -messages__version=3 +messages__version=4 messages__auto_refresh=true @@ -93,7 +93,7 @@ block_search_blank=&7Enter a value to search for a block.&7. mines_mtp__unable_to_teleport=Sorry. You're unable to teleport there. mines_mtp__unable_to_teleport_others=&3You cannot teleport other players to a mine. Ignoring parameter. mines_mtp__no_target_mine_found=No target mine found. &3Resubmit teleport request with a mine name. -mines_mtp__player_must_be_in_game=mines_mtp__player_must_be_in_game +mines_mtp__player_must_be_in_game=You can only teleport players that are online and in the game. mines_mtp__player_must_be_in_game=&3Specified player is not in the game so they cannot be teleported. mines_mtp__cannot_use_virtual_mines=&cInvalid option. This mine is a virtual mine&7. Use &a/mines set area &7to enable the mine. mines_mtp__teleport_failed=&3Telport failed. Are you sure you're a Player? diff --git a/prison-core/src/main/resources/lang/mines/es_ES.properties b/prison-core/src/main/resources/lang/mines/es_ES.properties index 6cfa3b940..c6bbeb44f 100644 --- a/prison-core/src/main/resources/lang/mines/es_ES.properties +++ b/prison-core/src/main/resources/lang/mines/es_ES.properties @@ -51,7 +51,7 @@ -messages__version=3 +messages__version=4 messages__auto_refresh=true @@ -92,7 +92,7 @@ missing_world=&7El mundo en el que se ha creado la mina no se ha podido encontra mines_mtp__unable_to_teleport=Sorry. You're unable to teleport there. mines_mtp__unable_to_teleport_others=&3You cannot teleport other players to a mine. Ignoring parameter. mines_mtp__no_target_mine_found=No target mine found. &3Resubmit teleport request with a mine name. -mines_mtp__player_must_be_in_game=mines_mtp__player_must_be_in_game +mines_mtp__player_must_be_in_game=You can only teleport players that are online and in the game. mines_mtp__player_must_be_in_game=&3Specified player is not in the game so they cannot be teleported. mines_mtp__cannot_use_virtual_mines=&cInvalid option. This mine is a virtual mine&7. Use &a/mines set area &7to enable the mine. mines_mtp__teleport_failed=&3Telport failed. Are you sure you're a Player? diff --git a/prison-core/src/main/resources/lang/mines/fi_FI.properties b/prison-core/src/main/resources/lang/mines/fi_FI.properties new file mode 100644 index 000000000..0600f57f3 --- /dev/null +++ b/prison-core/src/main/resources/lang/mines/fi_FI.properties @@ -0,0 +1,99 @@ +# NOTE: A messages__version is an arbitrary integer that will be manually incremented within Prison +# when there are changes to these messages. This value represents when message content is +# changed, fixed, or added to. This value may not be increased if the change is very small and +# insignificant, such as a space or a couple of letters. +# +# messages__auto_refresh=true indicates that this file will automatically be replaced if +# Prison detects a messages__version difference. The old file will be deleted (renamed) and +# a new copy will be placed in the directory to be used. If this value is set to false, then +# Prison will not refresh this file and there could be issues with the display of other messages. +# If auto refresh is set to false, we are not held responsible for possible issues that can +# arise from inaccurate messages. If set to false, then you are responsible for maintaining +# the messages on your own. +# +# If you make changes to this file, and you have messages__auto_refresh=false, then those +# changes will be replaced when this file is updated. Since the old file is renamed, and +# not deleted, you can manually merge your changes back in to the new update. The old +# renamed files will never be deleted by prison; you can remove them when you feel like it +# is safe to do so. +# +# Please consider helping Prison, and everyone else who may use Prison, by contributing all +# translations to other languages. They should be faithful translations, and not something +# for the sake of humor or changes just for cosmetic styling. If you have something you would +# like to share, please contact a staff member on our Discord server. +#Thanks for your contributions! +# + +## +## Prison Supports Unicode (UTF-8) encoding in these properties files. BUt you must +## follow these instructions to ensure everything works properly. +## +## 1. You should only edit these files using a UTF-8 editor. On windows use NotePad, not WordPad. +## WordPad will save as plain text. To confirm the save was successful: save, close the editor, +## then reopen to confirm the encoding was preserved. +## +## 2. When running on Windows, you must enable utf-8 encoding in minecraft's console. Windows +## defaults to a characterpage 1252. To enable window's use of utf-8, you need to change the +## encoding prior to launching spigot/paper: +## chcp 65001 +## +## Full example of a windows script, which hooks for java debugging: +## rem Note: chcp 65001 enables utf-8 in windows, when normally windows uses characterpage 1252 +## chcp 65001 +## java -Dfile.encoding="UTF-8" -Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005 -Xms1g -Xmx4g -jar spigot-1.8.8.jar nogui --log-strip-color +## pause +## +## 3. When viewing the logs/latest.log files you must use an editor such as NotePad instead of WordPad. +## +## 4. Unicode is properly displayed in game, in console, in the logs, and with paste.helpch.at when using +## /prison support submit. +## + + + +messages__version=4 +messages__auto_refresh=true + + + +# The following are the original messages and they will eventually be replaced. + +reset_warning=&7Mine %1 resettaa &3%2&7. +reset_message=&7mine %1 on resetattu. +not_allowed=&7Et voi mainata täällä. +autosmelt_enable=&bAutosmelt &7on &akäytössä&7. +autosmelt_disable=&bAutosmelt &7on &cdisabloitu&7. +autoblock_enable=&bAutoblock &7on &aenabloitu&7. +autoblock_disable=&bAutoblock &7on &cdisabloitu&7. +autopickup_enable=&bAutopickup &7on &aenabloitu&7. +autopickup_disable=&bAutopickup &7on &cdisabloitu&7. +teleported=&7Teleporttaa minelle &3%1&7. +mine_reset=&7mine &3%1&7 on resetattu. +mine_reset_fail=&7Ei pystytty resetoimaan mainia &3%1&7. &8Katso consolesta lisätietoa. +mine_created=&7Onnistuneesti luotu maini!. +mine_deleted=&7Onnistuneesti poistettu maini!. +select_bounds=&7Sinun pitää valita mainin alue ekana. &8Tee /mines wand jotta voit tehdä niin. +world_diff=&7Et voi tehdä maineja kahden mailman väliin.. +mine_exists=&7Maini sillä nimellä on jo olemassa. +mine_does_not_exist=&7Maini sillä nimellä ei löydy. +spawn_set=&7Mainin spawni on asetettu. +spawn_removed=&7Mainin spawni on onnistuneesti poistettu. +spawnpoint_same_world=&cspawnpoint &7pitää olla samassa mailmassa kuin maini. +not_a_block=&c%1 &7ei ole blockki. +block_already_added=&7Tämä blockki on jo lisätty mainiin.. +mine_full=&cMaini on jo täynnä. +block_added=&7Lisätty &3%1 &7mainiin &3%2&7. +block_set=&7Vaihdettu blocki &3%1 &7mainissa &3%2&7. +block_not_removed=&7Tämä blocki ei ole minessa. +block_deleted=&7Blocki &3%1 &7on poistettu mainista &3%2&7. +mine_redefined=&7onnistuneesti &3redefined &7maini. +missing_world=&7Mailma jossa mainit luotiin ei löydy.. +block_search_blank=&7Kirjoita arvo etsiessäsi blockia&7. + +mines_mtp__unable_to_teleport=Et voi teleporttaa siihen. +mines_mtp__unable_to_teleport_others=&3Et voi teleporata toisen pelaajan mainiin. +mines_mtp__no_target_mine_found=Mainia ei löytynyt. &3Yritä uudestaan eri nimellä. +mines_mtp__player_must_be_in_game=You can only teleport players that are online and in the game. +mines_mtp__player_must_be_in_game=&3Pelaaja ei ole pelissä. +mines_mtp__cannot_use_virtual_mines=&cInvalid option. This mine is a virtual mine&7. Use &a/mines set area &7to enable the mine. +mines_mtp__teleport_failed=&3Teleporttaus epäonnistui, oletko pelaaja? diff --git a/prison-core/src/main/resources/lang/mines/hu_HU.properties b/prison-core/src/main/resources/lang/mines/hu_HU.properties index 53bdccfa7..8748e42d6 100644 --- a/prison-core/src/main/resources/lang/mines/hu_HU.properties +++ b/prison-core/src/main/resources/lang/mines/hu_HU.properties @@ -51,7 +51,7 @@ -messages__version=3 +messages__version=4 messages__auto_refresh=true @@ -92,7 +92,7 @@ missing_world=&7Nem található meg a világ, amelyet a bányát hoztak létre. mines_mtp__unable_to_teleport=Sorry. You're unable to teleport there. mines_mtp__unable_to_teleport_others=&3You cannot teleport other players to a mine. Ignoring parameter. mines_mtp__no_target_mine_found=No target mine found. &3Resubmit teleport request with a mine name. -mines_mtp__player_must_be_in_game=mines_mtp__player_must_be_in_game +mines_mtp__player_must_be_in_game=You can only teleport players that are online and in the game. mines_mtp__player_must_be_in_game=&3Specified player is not in the game so they cannot be teleported. mines_mtp__cannot_use_virtual_mines=&cInvalid option. This mine is a virtual mine&7. Use &a/mines set area &7to enable the mine. mines_mtp__teleport_failed=&3Telport failed. Are you sure you're a Player? diff --git a/prison-core/src/main/resources/lang/mines/it_IT.properties b/prison-core/src/main/resources/lang/mines/it_IT.properties index 293a87e32..ee9efefba 100644 --- a/prison-core/src/main/resources/lang/mines/it_IT.properties +++ b/prison-core/src/main/resources/lang/mines/it_IT.properties @@ -51,7 +51,7 @@ -messages__version=3 +messages__version=4 messages__auto_refresh=true @@ -92,7 +92,7 @@ missing_world=&7Il mondo nel quale è stata creata la miniera non è stato trova mines_mtp__unable_to_teleport=Sorry. You're unable to teleport there. mines_mtp__unable_to_teleport_others=&3You cannot teleport other players to a mine. Ignoring parameter. mines_mtp__no_target_mine_found=No target mine found. &3Resubmit teleport request with a mine name. -mines_mtp__player_must_be_in_game=mines_mtp__player_must_be_in_game +mines_mtp__player_must_be_in_game=You can only teleport players that are online and in the game. mines_mtp__player_must_be_in_game=&3Specified player is not in the game so they cannot be teleported. mines_mtp__cannot_use_virtual_mines=&cInvalid option. This mine is a virtual mine&7. Use &a/mines set area &7to enable the mine. mines_mtp__teleport_failed=&3Telport failed. Are you sure you're a Player? diff --git a/prison-core/src/main/resources/lang/mines/nl_BE.properties b/prison-core/src/main/resources/lang/mines/nl_BE.properties index 64f5480bf..921617ad9 100644 --- a/prison-core/src/main/resources/lang/mines/nl_BE.properties +++ b/prison-core/src/main/resources/lang/mines/nl_BE.properties @@ -51,14 +51,14 @@ -messages__version=3 +messages__version=4 messages__auto_refresh=true # The following are the original messages and they will eventually be replaced. -reset_warning=&Alle mijnen %1 worden hersteld in &3%2&7. +reset_warning=&7Alle mijnen %1 worden hersteld in &3%2&7. reset_message=&7Alle mijnen %1 zijn hersteld. not_allowed=&7Je mag hier niet mijnen. autosmelt_enable=&bAutosmelt &7is aangezet. @@ -90,7 +90,7 @@ missing_world=&7De wereld van deze mijn kon niet worden gevonden. mines_mtp__unable_to_teleport=Sorry. You're unable to teleport there. mines_mtp__unable_to_teleport_others=&3You cannot teleport other players to a mine. Ignoring parameter. mines_mtp__no_target_mine_found=No target mine found. &3Resubmit teleport request with a mine name. -mines_mtp__player_must_be_in_game=mines_mtp__player_must_be_in_game +mines_mtp__player_must_be_in_game=You can only teleport players that are online and in the game. mines_mtp__player_must_be_in_game=&3Specified player is not in the game so they cannot be teleported. mines_mtp__cannot_use_virtual_mines=&cInvalid option. This mine is a virtual mine&7. Use &a/mines set area &7to enable the mine. mines_mtp__teleport_failed=&3Telport failed. Are you sure you're a Player? diff --git a/prison-core/src/main/resources/lang/mines/nl_NL.properties b/prison-core/src/main/resources/lang/mines/nl_NL.properties index 64f5480bf..1013398f9 100644 --- a/prison-core/src/main/resources/lang/mines/nl_NL.properties +++ b/prison-core/src/main/resources/lang/mines/nl_NL.properties @@ -51,7 +51,7 @@ -messages__version=3 +messages__version=4 messages__auto_refresh=true @@ -90,7 +90,7 @@ missing_world=&7De wereld van deze mijn kon niet worden gevonden. mines_mtp__unable_to_teleport=Sorry. You're unable to teleport there. mines_mtp__unable_to_teleport_others=&3You cannot teleport other players to a mine. Ignoring parameter. mines_mtp__no_target_mine_found=No target mine found. &3Resubmit teleport request with a mine name. -mines_mtp__player_must_be_in_game=mines_mtp__player_must_be_in_game +mines_mtp__player_must_be_in_game=You can only teleport players that are online and in the game. mines_mtp__player_must_be_in_game=&3Specified player is not in the game so they cannot be teleported. mines_mtp__cannot_use_virtual_mines=&cInvalid option. This mine is a virtual mine&7. Use &a/mines set area &7to enable the mine. mines_mtp__teleport_failed=&3Telport failed. Are you sure you're a Player? diff --git a/prison-core/src/main/resources/lang/mines/pt_PT.properties b/prison-core/src/main/resources/lang/mines/pt_PT.properties index f37cc42c9..b1dd86d80 100644 --- a/prison-core/src/main/resources/lang/mines/pt_PT.properties +++ b/prison-core/src/main/resources/lang/mines/pt_PT.properties @@ -51,7 +51,7 @@ -messages__version=3 +messages__version=4 messages__auto_refresh=true @@ -93,7 +93,7 @@ block_search_blank=&7Insere um valor para procurar pelo bloco.&7. mines_mtp__unable_to_teleport=Desculpa não és capaz de te teletransportar para alí. mines_mtp__unable_to_teleport_others=&3Não podes teletransportar outros jogadores para a mina. Ignoring parameter. mines_mtp__no_target_mine_found=Mina especifica não encontrada. &3Reenvia o pedido de teletransporte com o nome de uma mina. -mines_mtp__player_must_be_in_game=mines_mtp__player_must_be_in_game +mines_mtp__player_must_be_in_game=You can only teleport players that are online and in the game. mines_mtp__player_must_be_in_game=&3Jogador especifico não está no servidor por isso não pode ser teletransportado. mines_mtp__cannot_use_virtual_mines=&cOpção invalida a mina é uma mina virtual&7. Usa &a/mines set area &7para ativares a mina. mines_mtp__teleport_failed=&3O teletransporte falhou. Tens a certeza que és um jogador? diff --git a/prison-core/src/main/resources/lang/mines/ro_RO.properties b/prison-core/src/main/resources/lang/mines/ro_RO.properties index 46c5b39c9..c875ef329 100644 --- a/prison-core/src/main/resources/lang/mines/ro_RO.properties +++ b/prison-core/src/main/resources/lang/mines/ro_RO.properties @@ -22,6 +22,8 @@ #MulÈ›umim pentru contribuÈ›ii! # + + ## ## Prison acceptă standardul Unicode (UTF-8) în aceste fiÈ™iere, însă trebuie să ## urmăresti aceste instrucÈ›iuni dacă vrei să meargă totul corespunzător. @@ -46,6 +48,16 @@ ## 4. Jocul reprezintă Unicode corect, la fel si în consolă, în loguri, È™i cu paste.helpch.at dacă folosiÈ›i ## /prison support submit. ## + + + +messages__version=4 +messages__auto_refresh=true + + + +# The following are the original messages and they will eventually be replaced. + reset_warning=&7Mina %1 va fi resetată &3%2&7. reset_message=&7Mina %1 a fost resetată. not_allowed=&7Nu ai voie să minezi aici. @@ -76,3 +88,12 @@ block_not_removed=&7Acel block nu este în mină. block_deleted=&7Block-ul &3%1 &7a fost scos din mina &3%2&7. mine_redefined=&7Mina a fost &3redefinită &7cu succes. missing_world=&7Lumea în care a fost creată mina nu există. +block_search_blank=&7Enter a value to search for a block.&7. + +mines_mtp__unable_to_teleport=Sorry. You're unable to teleport there. +mines_mtp__unable_to_teleport_others=&3You cannot teleport other players to a mine. Ignoring parameter. +mines_mtp__no_target_mine_found=No target mine found. &3Resubmit teleport request with a mine name. +mines_mtp__player_must_be_in_game=You can only teleport players that are online and in the game. +mines_mtp__player_must_be_in_game=&3Specified player is not in the game so they cannot be teleported. +mines_mtp__cannot_use_virtual_mines=&cInvalid option. This mine is a virtual mine&7. Use &a/mines set area &7to enable the mine. +mines_mtp__teleport_failed=&3Telport failed. Are you sure you're a Player? diff --git a/prison-core/src/main/resources/lang/mines/zh-CN.properties b/prison-core/src/main/resources/lang/mines/zh-CN.properties new file mode 100644 index 000000000..b30302b63 --- /dev/null +++ b/prison-core/src/main/resources/lang/mines/zh-CN.properties @@ -0,0 +1,100 @@ +# NOTE: A messages__version is an arbitrary integer that will be manually incremented within Prison +# when there are changes to these messages. This value represents when message content is +# changed, fixed, or added to. This value may not be increased if the change is very small and +# insignificant, such as a space or a couple of letters. +# +# messages__auto_refresh=true indicates that this file will automatically be replaced if +# Prison detects a messages__version difference. The old file will be deleted (renamed) and +# a new copy will be placed in the directory to be used. If this value is set to false, then +# Prison will not refresh this file and there could be issues with the display of other messages. +# If auto refresh is set to false, we are not held responsible for possible issues that can +# arise from inaccurate messages. If set to false, then you are responsible for maintaining +# the messages on your own. +# +# If you make changes to this file, and you have messages__auto_refresh=false, then those +# changes will be replaced when this file is updated. Since the old file is renamed, and +# not deleted, you can manually merge your changes back in to the new update. The old +# renamed files will never be deleted by prison; you can remove them when you feel like it +# is safe to do so. +# +# Please consider helping Prison, and everyone else who may use Prison, by contributing all +# translations to other languages. They should be faithful translations, and not something +# for the sake of humor or changes just for cosmetic styling. If you have something you would +# like to share, please contact a staff member on our Discord server. +#Thanks for your contributions! +# + +## +## Prison Supports Unicode (UTF-8) encoding in these properties files. BUt you must +## follow these instructions to ensure everything works properly. +## +## 1. You should only edit these files using a UTF-8 editor. On windows use NotePad, not WordPad. +## WordPad will save as plain text. To confirm the save was successful: save, close the editor, +## then reopen to confirm the encoding was preserved. +## +## 2. When running on Windows, you must enable utf-8 encoding in minecraft's console. Windows +## defaults to a characterpage 1252. To enable window's use of utf-8, you need to change the +## encoding prior to launching spigot/paper: +## chcp 65001 +## +## Full example of a windows script, which hooks for java debugging: +## rem Note: chcp 65001 enables utf-8 in windows, when normally windows uses characterpage 1252 +## chcp 65001 +## java -Dfile.encoding="UTF-8" -Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005 -Xms1g -Xmx4g -jar spigot-1.8.8.jar nogui --log-strip-color +## pause +## +## 3. When viewing the logs/latest.log files you must use an editor such as NotePad instead of WordPad. +## +## 4. Unicode is properly displayed in game, in console, in the logs, and with paste.helpch.at when using +## /prison support submit. +## + + + +messages__version=3 +messages__auto_refresh=true + + + +# The following are the original messages and they will eventually be replaced. + +reset_warning=&7矿区%1将在&3%2分钟åŽ&7é‡ç½® +reset_message=&7矿区%1å·²ç»é‡ç½® +not_allowed=&7你没有在此处挖矿所需è¦çš„æƒé™ +autosmelt_enable=&bAutoMelt&7å·²å¯ç”¨&7 +autosmelt_disable=&bAutoMelt&7å·²ç¦ç”¨&7 +autoblock_enable=&bAutoblock&7å·²å¯ç”¨&7. +autoblock_disable=&bAutoblock &7å·²ç¦ç”¨&7 +autopickup_enable=&bAutopickup&7å·²å¯ç”¨&7 +autopickup_disable=&bAutopickup &7&7å·²ç¦ç”¨&7 +teleported=&7正在传é€åˆ°çŸ¿åŒº&3%1&7 +mine_reset=&7矿区&3%1&7å·²é‡ç½®ã€‚ +mine_reset_fail=&7无法é‡ç½®çŸ¿åŒº&3%1&7&8有关详细信æ¯ï¼Œè¯·æŸ¥çœ‹æŽ§åˆ¶å°ã€‚ +mine_created=&7å·²æˆåŠŸåˆ›å»ºçŸ¿åŒº +mine_deleted=&7å·²æˆåŠŸåˆ é™¤çŸ¿åŒº +select_bounds=&7您首先需è¦é€‰æ‹©çŸ¿åŒºè¾¹ç•Œ&8输入/mines wand 以选择 +world_diff=&7您无法在两个ä¸åŒçš„世界上创建矿区 +mine_exists=&7åŒå的矿区已ç»å­˜åœ¨ +mine_does_not_exist=&7没有å«è¿™ä¸ªå字的矿区 +spawn_set=&7矿区出生点已设置 +spawn_removed=&7矿区出生点已移除 +spawnpoint_same_world=&7&c出生点&7必须与矿区ä½äºŽåŒä¸€ä¸ª&c世界&7中 +not_a_block=&c%1 &7ä¸æ˜¯ä¸€ä¸ªæ–¹å—,请检查拼写 +block_already_added=&7该方å—å·²æˆåŠŸæ·»åŠ åˆ°çŸ¿åŒºä¸­ +mine_full=&c矿区满了 &7试ç€é™ä½Žè¯¥æ–¹å—或其他方å—的百分比,以腾出一些空间 +block_added=&7将方å—&3%1 &7添加到矿区&3%2&7. +block_set=&7更改了方å—3%2&7在矿区&3%1&7。 +block_not_removed=&7那个方å—ä¸åœ¨è¿™ä¸ªçŸ¿åŒºé‡Œ +block_deleted=&7从矿区&3%1&7中移除了方å—&3%1&7。 +mine_redefined=&7æˆåŠŸçš„&3改å˜äº†&7矿区. +missing_world=&7找ä¸åˆ°è¿™ä¸ªçŸ¿åŒºæ‰€åœ¨çš„世界 +block_search_blank=&7输入信æ¯ä»¥æœç´¢æ–¹å—&7 + +mines_mtp__unable_to_teleport=很抱歉,但是你无法传é€åˆ°é‚£é‡Œ +mines_mtp__unable_to_teleport_others=&3ä½ ä¸èƒ½å°†å…¶ä»–玩家传é€åˆ°çŸ¿åŒº +mines_mtp__no_target_mine_found=没有å‘现目标矿区 +mines_mtp__player_must_be_in_game=玩家必须在游æˆä¸­ +mines_mtp__player_must_be_in_game=&3指定的玩家ä¸åœ¨æ¸¸æˆä¸­ï¼Œå› æ­¤æ— æ³•ä¼ é€ +mines_mtp__cannot_use_virtual_mines=&c无效选项。此矿区是虚拟矿区&7。使用&a/mines set area&7å¯ç”¨çŸ¿åŒº +mines_mtp__teleport_failed=&3ä¼ é€å¤±è´¥ã€‚你确定你是一å玩家å—? + diff --git a/prison-core/src/main/resources/lang/mines/zh_TW.properties b/prison-core/src/main/resources/lang/mines/zh_TW.properties index 1d85f0401..ea87cda68 100644 --- a/prison-core/src/main/resources/lang/mines/zh_TW.properties +++ b/prison-core/src/main/resources/lang/mines/zh_TW.properties @@ -51,7 +51,7 @@ -messages__version=4 +messages__version=5 messages__auto_refresh=true @@ -93,7 +93,7 @@ block_search_blank=&7請輸入值以æœç´¢æ–¹å¡Šã€‚&7 mines_mtp__unable_to_teleport=Sorry. You're unable to teleport there. mines_mtp__unable_to_teleport_others=&3You cannot teleport other players to a mine. Ignoring parameter. mines_mtp__no_target_mine_found=No target mine found. &3Resubmit teleport request with a mine name. -mines_mtp__player_must_be_in_game=mines_mtp__player_must_be_in_game +mines_mtp__player_must_be_in_game=You can only teleport players that are online and in the game. mines_mtp__player_must_be_in_game=&3Specified player is not in the game so they cannot be teleported. mines_mtp__cannot_use_virtual_mines=&cInvalid option. This mine is a virtual mine&7. Use &a/mines set area &7to enable the mine. mines_mtp__teleport_failed=&3Telport failed. Are you sure you're a Player? diff --git a/prison-core/src/main/resources/lang/ranks/en_US.properties b/prison-core/src/main/resources/lang/ranks/en_US.properties index 02b52d679..c75503fd7 100644 --- a/prison-core/src/main/resources/lang/ranks/en_US.properties +++ b/prison-core/src/main/resources/lang/ranks/en_US.properties @@ -50,7 +50,7 @@ ## -messages__version=26 +messages__version=27 messages__auto_refresh=true ranks_rankup__rankup_no_player_name=You have @@ -59,7 +59,7 @@ ranks_rankup__rankup_you_are=You are ranks_rankup__rankup_success=Congratulations! %1 ranked up to rank '%2'. %3 ranks_rankup__demote_success=Unfortunately, %1 has been demoted to rank '%2'. %3 ranks_rankup__log_rank_change=%1 initiated rank change: %2 -ranks_rankup__rankup_cant_afford=You don't have enough money to rank up! The next rank costs %1 %2. +ranks_rankup__rankup_cant_afford=You don't have enough money to rank up! The next rank costs %1%2. ranks_rankup__rankup_lowest=%1 already at the lowest rank! ranks_rankup__rankup_highest=%1 already at the highest rank! ranks_rankup__rankup_failure=Generic rankup failure. Review rankup details to identify why. @@ -91,12 +91,21 @@ ranks_rankup__error_no_lower_rank_on_ladder=&c[ERROR] The ladder %1 has no ranks ranks_rankup__error_player_not_on_default_ladder=&c[ERROR] The player is not on the default ladder. Player: %1 ranks_rankup__not_at_last_rank=&cYou aren't at the last rank! +ranks_rankup__at_last_rank=&cYou at the last rank! ranks_rankup__not_able_to_prestige=&7[&3Sorry&7] &3You were not able to &6Prestige! ranks_rankup__not_able_to_reset_rank=&7Unable to reset your rank on the default ladder. ranks_rankup__balance_set_to_zero=&7Your balance has been set to zero. -ranks_rankup__prestige_successful=&7[&3Congratulations&7] &3You've &6Prestige&3 to %1&c! +ranks_rankup__prestige_successful=&7[&3Congratulations&7] &3You've &6Prestiged&3 to %1&c! ranks_rankup__prestige_failure=&7[&3Sorry&7] &3You were not able to &6Prestige&3 to %1&c! +ranks_rankup__confirm_prestige_line_1=&3Confirm Prestige: %1 +ranks_rankup__confirm_prestige_line_2=&3 Cost: &7%1 +ranks_rankup__confirm_prestige_line_3=&3 Balance: &7%1%2 +ranks_rankup__confirm_prestige_line_4=&3 Default Rank will be reset. +ranks_rankup__confirm_prestige_line_5=&3 Balance will be reset. +ranks_rankup__confirm_prestige_line_6=&3Confirm with command: '&7/prestige %1confirm&3' +ranks_rankup__confirm_prestige_line_7=&3Confirm by clicking on the green block + ranks_rankup__invalid_charge_value=&3Invalid value for chargePlayer. Valid values are: %1 %2 ranks_rankup__invalid_refund_value=&3Invalid value for refundPlayer. Valid values are: %1 %2 diff --git a/prison-core/src/main/resources/lang/ranks/pt_PT.properties b/prison-core/src/main/resources/lang/ranks/pt_PT.properties index f75dfecea..baa641ee2 100644 --- a/prison-core/src/main/resources/lang/ranks/pt_PT.properties +++ b/prison-core/src/main/resources/lang/ranks/pt_PT.properties @@ -50,7 +50,7 @@ ## -messages__version=4 +messages__version=5 messages__auto_refresh=true ranks_rankup__rankup_no_player_name=Tu têns @@ -59,13 +59,14 @@ ranks_rankup__rankup_you_are=Tu és ranks_rankup__rankup_success=Parabéns! %1 subiste para o rank '%2'. %3 ranks_rankup__demote_success=Infelizmente, %1 desceu para o rank '%2'. %3 ranks_rankup__log_rank_change=%1 iniciado alteraçao de rank: %2 -ranks_rankup__rankup_cant_afford=Não tens dinheiro suficiente para fazeres rankup. O proximo rankup custa %1 %2. +ranks_rankup__rankup_cant_afford=Não tens dinheiro suficiente para fazeres rankup. O proximo rankup custa %1%2. ranks_rankup__rankup_lowest=%1 já estás no rank mais baixo! ranks_rankup__rankup_highest=%1 já estás no rank mais alto! ranks_rankup__rankup_failure=Falha genérica no rankup. Reve os detalhes do rankup para identificar o motivo. ranks_rankup__rankup_failed_to_load_player=Erro a carregar info do player. ranks_rankup__rankup_failed_to_load_ladder=Erro a carregar a ladder. ranks_rankup__rankup_failed_to_assign_rank=Erro a dar o rank. +ranks_rankup__rankup_failed_to_assign_rank_with_refund=Failed to assign a rank. Review rankup details to identify why. Refunds have been applied. ranks_rankup__rankup_failed_to_save_player_file=Falha ao recuperar ou gravar dados. Os teus arquivos podem estar corrompidos. Reposta a um administrador. ranks_rankup__rankup_no_ranks=Não existe ranks nesta ladder. ranks_rankup__rankup_rank_does_not_exist=O rank %1 não existe neste server. @@ -80,6 +81,7 @@ ranks_rankup__rankup_failure_invalid_ladder=A ladder '%1' não existe. ranks_rankup__rankup_failure_must_be_online_player=&3Tu tens de ser um player para usares este comando, e/ou o player tem de estar online. ranks_rankup__no_permission=Tu precisas de permissão '%1' para dares rankup nesta ladder. ranks_rankup__cannot_run_from_console=&7 Não é possível fazer rank na consola. Veja &3/rankup para ajuda&7. +ranks_rankup__invalid_player_name=&7Invalid player name. '%1' ranks_rankup__internal_failure=&7Modo invalido de rankup. Falha interna. Reporta ao admin. ranks_rankup__error_no_default_ladder=&c[ERROR] Não existe uma ladder default! Reporta ao admin! ranks_rankup__error_no_lower_rank=&c[ERROR] Não consgues ter rank mais baixo! Reporta ao admin! @@ -89,12 +91,21 @@ ranks_rankup__error_no_lower_rank_on_ladder=&c[ERROR] A ladder %1 não tem ranks ranks_rankup__error_player_not_on_default_ladder=&c[ERROR] O player nao está numa default ladder. Player: %1 ranks_rankup__not_at_last_rank=&cTu não estas no rank mais baixo! +ranks_rankup__at_last_rank=&cYou at the last rank! ranks_rankup__not_able_to_prestige=&7[&3Sorry&7] &3Tu não conseguiste fazer &6Prestige! ranks_rankup__not_able_to_reset_rank=&7Incapaz de resetar o rank para a default ladder. ranks_rankup__balance_set_to_zero=&7O teu dinheiro foi posto a 0. ranks_rankup__prestige_successful=&7[&3Parabéns&7] &3Tu consegiste o &6Prestige&3 to %1&c! ranks_rankup__prestige_failure=&7[&3Sorry&7] &3Não conseguiste fazer o &6Prestige&3 to %1&c! +ranks_rankup__confirm_prestige_line_1=&3Confirm Prestige: %1 +ranks_rankup__confirm_prestige_line_2=&3 Cost: &7%1 +ranks_rankup__confirm_prestige_line_3=&3 Balance: &7%1%2 +ranks_rankup__confirm_prestige_line_4=&3 Default Rank will be reset. +ranks_rankup__confirm_prestige_line_5=&3 Balance will be reset. +ranks_rankup__confirm_prestige_line_6=&3Confirm with command: '&7/prestige %1confirm&3' +ranks_rankup__confirm_prestige_line_7=&3Confirm by clicking on the green block + ranks_rankup__invalid_charge_value=&3Valor inválido para chargePlayer. Os valores válidos são: %1 %2 ranks_rankup__invalid_refund_value=&3Valor inválido para refundPlayer. Os valores válidos são: %1 %2 diff --git a/prison-core/src/main/resources/lang/ranks/zh-CN.properties b/prison-core/src/main/resources/lang/ranks/zh-CN.properties new file mode 100644 index 000000000..ee73dd57d --- /dev/null +++ b/prison-core/src/main/resources/lang/ranks/zh-CN.properties @@ -0,0 +1,331 @@ +# NOTE: A messages__version is an arbitrary integer that will be manually incremented within Prison +# when there are changes to these messages. This value represents when message content is +# changed, fixed, or added to. This value may not be increased if the change is very small and +# insignificant, such as a space or a couple of letters. +# +# messages__auto_refresh=true indicates that this file will automatically be replaced if +# Prison detects a messages__version difference. The old file will be deleted (renamed) and +# a new copy will be placed in the directory to be used. If this value is set to false, then +# Prison will not refresh this file and there could be issues with the display of other messages. +# If auto refresh is set to false, we are not held responsible for possible issues that can +# arise from inaccurate messages. If set to false, then you are responsible for maintaining +# the messages on your own. +# +# If you make changes to this file, and you have messages__auto_refresh=false, then those +# changes will be replaced when this file is updated. Since the old file is renamed, and +# not deleted, you can manually merge your changes back in to the new update. The old +# renamed files will never be deleted by prison; you can remove them when you feel like it +# is safe to do so. +# +# Please consider helping Prison, and everyone else who may use Prison, by contributing all +# translations to other languages. They should be faithful translations, and not something +# for the sake of humor or changes just for cosmetic styling. If you have something you would +# like to share, please contact a staff member on our Discord server. +#Thanks for your contributions! +# + +## +## Prison Supports Unicode (UTF-8) encoding in these properties files. BUt you must +## follow these instructions to ensure everything works properly. +## +## 1. You should only edit these files using a UTF-8 editor. On windows use NotePad, not WordPad. +## WordPad will save as plain text. To confirm the save was successful: save, close the editor, +## then reopen to confirm the encoding was preserved. +## +## 2. When running on Windows, you must enable utf-8 encoding in minecraft's console. Windows +## defaults to a characterpage 1252. To enable window's use of utf-8, you need to change the +## encoding prior to launching spigot/paper: +## chcp 65001 +## +## Full example of a windows script, which hooks for java debugging: +## rem Note: chcp 65001 enables utf-8 in windows, when normally windows uses characterpage 1252 +## chcp 65001 +## java -Dfile.encoding="UTF-8" -Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005 -Xms1g -Xmx4g -jar spigot-1.8.8.jar nogui --log-strip-color +## pause +## +## 3. When viewing the logs/latest.log files you must use an editor such as NotePad instead of WordPad. +## +## 4. Unicode is properly displayed in game, in console, in the logs, and with paste.helpch.at when using +## /prison support submit. +## + + +messages__version=24 +messages__auto_refresh=true + +ranks_rankup__rankup_no_player_name=ä½ å·²ç» +ranks_rankup__rankup_no_player_name_broadcast=æŸäºº +ranks_rankup__rankup_you_are=你是 +ranks_rankup__rankup_success=%1å‡çº§åˆ°äº†'%2' %3 +ranks_rankup__demote_success=%1 下é™è‡³ '%2' %3 +ranks_rankup__log_rank_change=%1 已更改阶级:%2 +ranks_rankup__rankup_cant_afford=你没有足够的钱æ¥å‡çº§ï¼ä¸‹ä¸€ä¸ªé˜¶çº§éœ€è¦%1%2 +ranks_rankup__rankup_lowest=%1 å·²ç»å¤„äºŽæœ€ä½Žçº§åˆ«ï¼ +ranks_rankup__rankup_highest=%1 å·²ç»å¤„äºŽæœ€é«˜çº§åˆ«ï¼ +ranks_rankup__rankup_failure=阶级æå‡å¤±è´¥ï¼Œè¯·é‡æ–°æ£€æŸ¥æ¥ç¡®å®šåŽŸå›  +ranks_rankup__rankup_failed_to_load_player=无法加载玩家 +ranks_rankup__rankup_failed_to_load_ladder=阶级晋å‡å¤±è´¥ +ranks_rankup__rankup_failed_to_assign_rank=分é…阶级失败,请é‡æ–°æ£€æŸ¥æ¥ç¡®å®šåŽŸå›  +ranks_rankup__rankup_failed_to_assign_rank_with_refund=分é…阶级失败. é‡æ–°æ£€æŸ¥é˜¶çº§æå‡æ¥ç¡®å®šåŽŸå› . å·²ç»ä¸ºæ‚¨é€€æ¬¾. +ranks_rankup__rankup_failed_to_save_player_file=无法检索或写入数æ®ï¼Œæ‚¨çš„文件å¯èƒ½å·²æŸå,通知æœåŠ¡å™¨ç®¡ç†å‘˜ +ranks_rankup__rankup_no_ranks=这个矿区上没有阶级 +ranks_rankup__rankup_rank_does_not_exist=阶级%1ä¸å­˜åœ¨ +ranks_rankup__rankup_rank_is_not_in_ladder=阶级%2中ä¸å­˜åœ¨é˜¶çº§%1 +ranks_rankup__rankup_currency_is_not_supported=任何已加载的ç»æµŽå‰ç½®éƒ½ä¸æ”¯æŒè´§å¸%1 +ranks_rankup__rankup_ladder_removed=已删除阶级%1 +ranks_rankup__rankup_failure_removing_ladder=å‡çº§å¤±è´¥ï¼Œå› ä¸ºæ— æ³•ä»Žé˜¶çº§%1中删除玩家(无法从“默认â€é˜¶çº§ä¸­åˆ é™¤çŽ©å®¶ï¼‰ +ranks_rankup__rankup_in_progress_failure=无法正常å‡çº§ï¼Œæ­¤é˜¶çº§ä¸å­˜åœ¨ + +ranks_rankup__rankup_failure_to_get_rankplayer=ä½ çš„æ•°æ®ä¸å­˜åœ¨ï¼æœåŠ¡å™¨æ²¡æœ‰æ‚¨çš„记录,请å°è¯•é‡æ–°åŠ å…¥ï¼Œæˆ–与æœåŠ¡å™¨ç®¡ç†å‘˜è”系以获å–帮助 +ranks_rankup__rankup_failure_invalid_ladder=阶级'%1'ä¸å­˜åœ¨ +ranks_rankup__rankup_failure_must_be_online_player=&3您必须是游æˆä¸­åœ¨çº¿çš„玩家æ‰èƒ½è¿è¡Œæ­¤å‘½ä»¤ +ranks_rankup__no_permission=您需è¦æƒé™'%1'æ‰èƒ½åœ¨æ­¤é˜¶çº§ä¸Šå‡çº§ +ranks_rankup__cannot_run_from_console=&7无法在控制å°ä¸Šå‡çº§ï¼Œè¾“å…¥&3/rankup help æ¥æŸ¥çœ‹å¸®åŠ©&7 +ranks_rankup__internal_failure=&7rankup模å¼æ— æ•ˆï¼Œå†…部故障,请报告 +ranks_rankup__error_no_default_ladder=&c[错误]没有默认阶级ï¼è¯·å°†æ­¤æŠ¥å‘Šç»™ç®¡ç†å‘˜ï¼ +ranks_rankup__error_no_lower_rank=&c[错误]无法获å–最低阶级ï¼è¯·å°†æ­¤æŠ¥å‘Šç»™ç®¡ç†å‘˜ï¼ + +ranks_rankup__error_no_ladder=&c[错误]阶级%1ä¸å­˜åœ¨ï¼è¯·å°†æ­¤æŠ¥å‘Šç»™ç®¡ç†å‘˜ï¼ +ranks_rankup__error_no_lower_rank_on_ladder=&c[错误]阶级%1没有级别ï¼è¯·å°†æ­¤æŠ¥å‘Šç»™ç®¡ç†å‘˜ï¼ + +ranks_rankup__error_player_not_on_default_ladder=&c[错误]玩家ä¸åœ¨é»˜è®¤é˜¶çº§ä¸Šï¼ŒçŽ©å®¶ï¼š%1 +ranks_rankup__not_at_last_rank=&cä½ ä¸æ˜¯æœ€åŽä¸€ä¸ªé˜¶çº§ï¼ +ranks_rankup__not_able_to_prestige=&7[&3抱歉&7]&3您无法&6å£°æœ›ï¼ +ranks_rankup__not_able_to_reset_rank=&7无法é‡ç½®æ‚¨åœ¨é»˜è®¤é˜¶çº§ä¸Šçš„级别 + +ranks_rankup__balance_set_to_zero=&7您的余é¢å·²è®¾ç½®ä¸ºé›¶ +ranks_rankup__prestige_successful=&7[&3æ­å–œ&7]&3您已ç»&6声望&3到%1&cï¼ +ranks_rankup__prestige_failure=&7[&3抱歉&7] &3您无法将&6声望&3添加到%1&cï¼ +ranks_rankup__invalid_charge_value=&3chargePlayer的值无效,有效值为:%1%2 +ranks_rankup__invalid_refund_value=&3ReturnPlayer的值无效,有效值为:%1%2 + + +ranks_rankutil__failure_internal=无法为执行RankupLayer内部检查æœåŠ¡å™¨æ—¥å¿—:%1 +ranks_rankutil__failure_saving_player_data=ä¿å­˜çŽ©å®¶æ–‡ä»¶æ—¶å‡ºé”™ + + +ranks_firstJoinHandler__no_ranks_on_server=æœåŠ¡å™¨ä¸Šæ²¡æœ‰é˜¶çº§ï¼æ–°çŽ©å®¶å°†æ²¡æœ‰é˜¶çº§ +ranks_firstJoinHandler__could_not_save_player=无法ä¿å­˜çŽ©å®¶æ–‡ä»¶ +ranks_firstJoinHandler__success=欢迎ï¼%1刚刚加入æœåŠ¡å™¨å¹¶è¢«åˆ†é…了默认阶级 + + +ranks_prisonRanks__failure_no_economy_status=&cæ— ç»æµŽæ’件 +ranks_prisonRanks__failure_no_economy=没有ç»æµŽæ’件 %1 +ranks_prisonRanks__failure_loading_ranks_status=&c加载阶级文件失败:%1 +ranks_prisonRanks__failure_loading_ranks=无法加载阶级文件 1 +ranks_prisonRanks__failure_loading_ladders_status=&c加载阶级文件失败:%1 +ranks_prisonRanks__failure_loading_ladders=无法加载阶级文件 %1 +ranks_prisonRanks__failure_loading_players_status=&c加载玩家文件失败:%1 +ranks_prisonRanks__failure_loading_players=无法加载玩家文件 %1 +ranks_prisonRanks__failed_loading_players=&c加载玩家失败:%1 +ranks_prisonRanks__failed_to_load_player_file=无法加载玩家文件 %1. + +ranks_prisonRanks__status_loaded_ranks=已加载%1个阶级,默认阶级:%2 声望阶级:%3 其他阶级:%4 +ranks_prisonRanks__status_loaded_ladders=已加载%1个阶级 +ranks_prisonRanks__status_loaded_players=已加载%1个玩家 + +ranks_prisonRanks__failure_with_ladder=&c未能从%1加载%2级别, 找ä¸åˆ°ä»¥å‰çš„阶级 +ranks_prisonRanks__failure_with_ladder_create=创造 +ranks_prisonRanks__failure_with_ladder_save=ä¿å­˜ +ranks_prisonRanks__failure_with_ladder_default=默认 +ranks_prisonRanks__failure_with_ladder_prestiges=声望 + +ranks_prisonRanks__added_new_player=&7监狱:&7å·²ç»åœ¨åœ¨æœåŠ¡å™¨ä¸Šæ‰¾åˆ°&c新玩家&3%1&7并将他添加到监狱 +ranks_prisonRanks__added_and_fixed_players=监狱阶级加载:将玩家 %1 添加到监狱,修å¤äº†å在默认阶级上没有排å的玩家 %2 + + +ranks_rank__failure_loading_ranks=&aFailure:装载&7分æžé˜¶çº§æ–‡æ¡£æ—¶å‡ºçŽ°å¼‚常,阶级id=%1,å称=%2[%3] + +ranks_rankManager__failure_loading_rankManager=&a失败:加载阶级%1(阶级id:%2):&7无法加载RankManager,因此无法访问任何阶级 +ranks_rankManager__failure_duplicate_rank=&a失败:RankLadder加载失败:阶级“%1â€å·²é“¾æŽ¥åˆ°é˜¶çº§%2â€ï¼Œä½†å·²å°è¯•æ·»åŠ åˆ°â€œ%3â€é˜¶çº§ï¼Œæ­¤åˆ—组将ä¸ä¼šç»‘定到阶级“%4†+ + +ranks_rankManager__remove_rank_warning=移除阶级警告:ä¸å­˜åœ¨å…¶ä»–阶级,因此被移除阶级的玩家将在该阶级上没有级别 +ranks_rankManager__cannot_save_player_file=移除库:无法ä¿å­˜çŽ©å®¶æ–‡ä»¶ +ranks_rankManager__player_is_now=玩家%1现在是%2 +ranks_rankManager__cannot_save_ladder_file=RemoveBank:无法ä¿å­˜é˜¶çº§%1 +ranks_rankManager__failure_no_economy=ç»æµŽå‰ç½®ï¼š&7è´§å¸&a%1&7注册为阶级&a%2&7,但ä¸å—任何ç»æµŽæ’ä»¶çš„æ”¯æŒ +ranks_rankManager__ranks_by_ladders=&7按阶级排列: + + +ranks_ladderManager__cannot_save_ladder_file=&cLadderManager,ä¿å­˜é˜¶çº§ï¼šæ— æ³•ä¿å­˜é˜¶çº§&7%1&3错误=[&7%2&3]†+ + +ranks_playerManager__cannot_save_player_file=ä¿å­˜çŽ©å®¶æ–‡ä»¶æ—¶å‡ºé”™ï¼š%1 +ranks_playerManager__cannot_add_new_player=PlayerManager.getPlayer(): 无法添加新的玩家å称:%1,%2 +ranks_playerManager__cannot_save_new_player_file=无法为玩家%1创建新的玩家数æ®ï¼Œç›®æ ‡æ–‡ä»¶å:%2 +ranks_playerManager__no_player_name_available=<ä¸å¯æµ‹é‡ï¼ž +ranks_playerManager__cannot_load_player_file=无法加载玩家:%1 +ranks_playerManager__failed_to_load_economy_currency=无法加载ç»æµŽæ’件以获å–è´§å¸ä¸º%2的玩家%1çš„ä½™é¢ +ranks_playerManager__failed_to_load_economy=无法加载ç»æµŽæ’件数æ®ä»¥èŽ·å–玩家%1çš„ä½™é¢ +ranks_playerManager__last_rank_message_for__prison_rankup_rank_tag_default= + + + +ranks_commandCommands__command_add_cannot_use_percent_symbols=&7ä¸èƒ½å°†ç™¾åˆ†æ¯”符å·ç”¨ä½œå ä½ç¬¦è½¬ä¹‰å­—ç¬¦ï¼›å¿…é¡»æ”¹ç”¨ï½›ï½ +ranks_commandCommands__command_add_placeholders=&7阶级命令的自定义å ä½ç¬¦ä¸ºï¼š&3%1 +ranks_commandCommands__rank_does_not_exist=阶级“%1â€ä¸å­˜åœ¨ +ranks_commandCommands__command_add_duplicate=未将é‡å¤çš„命令“%1â€æ·»åŠ åˆ°é˜¶çº§â€œ%2†+ranks_commandCommands__command_add_success=已将命令“%1â€æ·»åŠ åˆ°é˜¶çº§â€œ%2†+ +ranks_commandCommands__command_remove_sucess=已从阶级“%2â€ä¸­åˆ é™¤æŒ‡ä»¤â€œ%1†+ranks_commandCommands__command_remove_failed=阶级ä¸åŒ…å«è¯¥å‘½ä»¤ï¼Œæ²¡æœ‰ä¿®æ”¹ + +ranks_commandCommands__command_list_contains_none=阶级“%1â€ä¸åŒ…å«å‘½ä»¤ +ranks_commandCommands__command_list_cmd_header=阶级%1çš„å‡é˜¶æŒ‡ä»¤ +ranks_commandCommands__command_list_click_cmd_to_remove=&8å•å‡»å‘½ä»¤å°†å…¶åˆ é™¤ +ranks_commandCommands__command_list_click_to_remove=å•å‡»ä»¥åˆ é™¤ +ranks_commandCommands__command_list_add_button=&7[&a+&7]添加新命令 +ranks_commandCommands__command_list_add_new_command_tool_tip=&7添加新命令 +ranks_commandCommands__command_row_number_must_be_greater_than_zero=&7请æ供有效行å·è¡Œ=[&b%1&7] +ranks_commandCommands__command_row_number_too_high=&7请æä¾›ä¸å¤§äºŽ&b%1&7的有效行å·è¡Œ=[&b%2&7] + + + +ranks_commandCommands__ladder_command_add_placeholders=&7阶级命令的自定义papiå˜é‡ä¸ºï¼š&3%1 +ranks_commandCommands__ladder_ladder_does_not_exist=阶级“%1â€ä¸å­˜åœ¨ +ranks_commandCommands__ladder_command_add_duplicate=未将é‡å¤çš„命令“%1â€æ·»åŠ åˆ°é˜¶çº§â€œ%2†+ranks_commandCommands__ladder_command_add_success=已将命令“%1â€æ·»åŠ åˆ°é˜¶çº§â€œ%2†+ +ranks_commandCommands__ladder_command_remove_sucess=已从阶级“%2â€ä¸­åˆ é™¤å‘½ä»¤â€œ%1†+ranks_commandCommands__ladder_command_remove_failed=阶级ä¸åŒ…å«è¯¥å‘½ä»¤ï¼Œä»€ä¹ˆéƒ½æ²¡æœ‰æ”¹å˜ + +ranks_commandCommands__ladder_command_list_contains_none=阶级“%1â€ä¸åŒ…å«ä»»ä½•å‘½ä»¤ +ranks_commandCommands__ladder_command_list_cmd_header=%1阶级的å‡çº§å‘½ä»¤ + + + +ranks_LadderCommands__ladder_already_exists=å为“%1â€çš„阶级已存在 +ranks_LadderCommands__ladder_creation_error=创建阶级“%1â€æ—¶å‡ºé”™&8检查控制å°ä»¥äº†è§£è¯¦ç»†ä¿¡æ¯ +ranks_LadderCommands__ladder_created=已创建阶级“%1†+ranks_LadderCommands__ladder_could_not_save=无法ä¿å­˜é˜¶çº§ +ranks_LadderCommands__ladder_does_not_exist=阶级“%1â€ä¸å­˜åœ¨ +ranks_LadderCommands__rank_does_not_exist=阶级“%1â€ä¸å­˜åœ¨ +ranks_LadderCommands__ladder_already_has_rank=阶级“%1â€å·²åŒ…å«é˜¶çº§â€œ%2†+ranks_LadderCommands__ladder_added_rank=已将阶级“%1â€æ·»åŠ åˆ°é˜¶çº§â€œ%2â€çš„ä½ç½®%3 +ranks_LadderCommands__ladder_deleted=阶级“%1â€å·²è¢«åˆ é™¤ +ranks_LadderCommands__ladder_cannot_delete_default=无法删除默认阶级 +ranks_LadderCommands__ladder_cannot_delete_prestiges=ä¸èƒ½åˆ é™¤å£°æœ›é˜¶çº§ +ranks_LadderCommands__ladder_cannot_delete_with_ranks=如果阶级ä»æœ‰ä¸Žä¹‹ç»‘定的阶级,则无法删除该阶级,删除所有绑定的阶级,然åŽé‡è¯• +ranks_LadderCommands__ladder_error=删除阶级时出错&8检查控制å°ä»¥äº†è§£è¯¦ç»†ä¿¡æ¯ +ranks_LadderCommands__ladder_error_adding=å‘阶级添加级别时出错&8检查控制å°ä»¥äº†è§£è¯¦ç»†ä¿¡æ¯ +ranks_LadderCommands__ladder_error_removing=从阶级中删除级别时出错&8检查控制å°ä»¥äº†è§£è¯¦ç»†ä¿¡æ¯ +ranks_LadderCommands__ladder_error_saving=ä¿å­˜é˜¶çº§æ—¶å‡ºé”™ +ranks_LadderCommands__move_rank_notice=å°è¯•ä»Žå…¶åŽŸå§‹é˜¶çº§ä¸­åˆ é™¤æŒ‡å®šçš„级别,然åŽå°†å…¶æ·»åŠ å›žæŒ‡å®šä½ç½®çš„目标阶级,阶级ä¸ä¼šä¸¢å¤± +ranks_LadderCommands__ladder_removed_rank_from_ladder=已从阶级“%2â€ä¸­åˆ é™¤é˜¶çº§â€œ%1†+ + +ranks_LadderCommands__ladder_has_ranks=&7此阶级包å«ä»¥ä¸‹çº§åˆ«ï¼š +ranks_LadderCommands__ladder_default_rank=&b(&9默认阶级&b)&7- +ranks_LadderCommands__ladder_see_ranks_list=&3有关阶级的详细信æ¯ï¼Œè¯·å‚è§&f/ranks list&b [ladderName]&3 +ranks_LadderCommands__ladder_has_no_perms=&3阶级“&7%1&3â€ä¸åŒ…å«æƒé™æˆ–æƒé™ç»„ +ranks_LadderCommands__ladder_set_rank_cost_multiplier=&3阶级“&7%1&3â€å·²ä¿å­˜ +ranks_LadderCommands__ladder_rank_cost_multiplier_no_change=&3梯形图“&7%1&3â€æœªæ›´æ–°ï¼Œé˜¶çº§èŠ±è´¹çš„钱未更改[%2] +ranks_LadderCommands__ladder_rank_cost_multiplier_out_of_range=&3阶级花费的钱超出范围,必须介于-100%å’Œ100%之间[%1] + + +ranks_rankCommands__rank_already_exists=&3å为&7%1&3的阶级已存在,请å°è¯•ä½¿ç”¨å…¶ä»–å称 +ranks_rankCommands__rank_name_required=&3阶级å称是必需的,ä¸èƒ½åŒ…å«æ ¼å¼ä»£ç  +ranks_rankCommands__ladder_does_not_exist=&3å为“&7%1&3â€çš„阶级ä¸å­˜åœ¨ +ranks_rankCommands__ladder_has_no_ranks=&3没有任何级别存在于阶级“&7%1&3â€å†… +ranks_rankCommands__ladder_has_no_ranks_text=&3---这阶级没有级别--- +ranks_rankCommands__rank_does_not_exist=&3阶级“&7%1&3â€ä¸å­˜åœ¨ +ranks_rankCommands__rank_cannot_be_created=&3无法创建阶级 +ranks_rankCommands__rank_created_successfully=&3您的新阶级“&7%1&3â€æ˜¯åœ¨é˜¶çº§â€œ&7%2&3â€ä¸­åˆ›å»ºçš„,使用的标记值为“&7%3&3†+ranks_rankCommands__error_saving_ladder=&3无法将“&7%1&3â€é˜¶çº§ä¿å­˜åˆ°ç£ç›˜ï¼Œæœ‰å…³è¯¦ç»†ä¿¡æ¯ï¼Œè¯·æŸ¥çœ‹æŽ§åˆ¶å° +ranks_rankCommands__error_writting_ladder=&3无法将“&7%1&3â€æ¢¯å½¢å›¾ä¿å­˜åˆ°ç£ç›˜ï¼Œæœ‰å…³è¯¦ç»†ä¿¡æ¯ï¼Œè¯·æŸ¥çœ‹æŽ§åˆ¶å° + + +ranks_rankCommands__auto_config_preexisting_warning=&3您正在å°è¯•è¿è¡Œ&7/ranks autoConfigure&3,其中已设置了矿区或阶级,阶级数=&7%1&3,矿区数=&3%2&3,请使用&7help&3关键字è¿è¡Œæ­¤å‘½ä»¤ï¼Œæœ‰å…³è¯¦ç»†ä¿¡æ¯å’Œå…¶ä»–自定义选项:&7/ranks autoConfigure help&3,由于生æˆçš„æ•°æ®é‡å¾ˆå¤§ï¼Œæœ€å¥½ä»Ž&7console&3è¿è¡Œæ­¤å‘½ä»¤ï¼Œæ·»åŠ é€‰é¡¹â€œ&7force&3â€ä»¥å¼ºåˆ¶è¿è¡Œæ­¤è¿›ç¨‹ï¼Œå¦‚果与先å‰å­˜åœ¨çš„阶级或矿区存在冲çªï¼Œæ­¤è¿‡ç¨‹å°†å°½å¯èƒ½å°†æ–°é˜¶çº§å’ŒçŸ¿åŒºä¸ŽçŽ°æœ‰é˜¶çº§å’ŒçŸ¿åŒºåˆå¹¶ï¼Œå­˜åœ¨æŸäº›ä¸œè¥¿å¯èƒ½æ— æ³•æ­£ç¡®åˆå¹¶çš„风险,åˆå¹¶æ—¶ï¼Œå°†æ›¿æ¢æ‰€æœ‰æ–¹å—,但在控制å°ä¸­ï¼Œå¦‚æžœè¦é‡æ–°åˆ›å»ºå®ƒä»¬ï¼Œå°†æ‰“å°åŽŸå§‹å—列表以供å‚考,为了安全起è§ï¼Œè¯·åœ¨è¿è¡Œå‰å¤‡ä»½&7plugins/Prison/&3目录,, +ranks_rankCommands__auto_config_force_warning=&a警告! &3在å¯ç”¨&7force&3的情况下è¿è¡Œè‡ªåŠ¨é…ç½® +ranks_rankCommands__auto_config_invalid_options=&3无效选项,使用%1å’Œ3,行:&3%2 +ranks_rankCommands__auto_config_skip_rank_warning=&a警告&3阶级&7%1&3已存在,如果å¯ç”¨ï¼Œå°†ä¸Žç”ŸæˆçŸ¿åŒºä»¥åŠæ‰€æœ‰å…¶ä»–功能一起跳过 + +ranks_rankCommands__auto_config_no_ranks_created=阶级自动é…置:未创建任何阶级 +ranks_rankCommands__auto_config_ranks_created=阶级自动é…置:已创建%1个阶级 +ranks_rankCommands__auto_config_no_rank_cmds_created=阶级自动é…置:未创建阶级命令 +ranks_rankCommands__auto_config_ladder_rank_cost_multiplier_info=“声望â€é˜¶çº§å·²å¯ç”¨ï¼Œä»¥åº”用将应用于“所有â€é˜¶çº§èŠ±è´¹çš„基础阶级æˆæœ¬ä¹˜æ•°%1,该乘数将éšç€é˜¶æ¢¯ä¸Šçš„æ¯ä¸ªç§©è€Œå¢žåŠ  +ranks_rankCommands__auto_config_ladder_rank_cost_multiplier_command_example='å¯ä»¥ä½¿ç”¨ä»¥ä¸‹å‘½ä»¤è°ƒæ•´æˆ–ç¦ç”¨åŸºæœ¬é˜¶çº§èŠ±è´¹ä¹˜æ•°ï¼š/ranks ladder rankCostMultiplier +ranks_rankCommands__auto_config_rank_cmds_created=阶级自动é…置:%1个阶级命令已创建 + +ranks_rankCommands__auto_config_no_mines_created=阶级自动é…置:未创建任何矿区 +ranks_rankCommands__auto_config_mines_created=阶级自动é…置:已创建%1个矿区 + +ranks_rankCommands__auto_config_no_linkage=阶级自动é…置:未链接任何矿区和阶级 +ranks_rankCommands__auto_config_linkage_count=阶级自动é…置:%1已链接阶级和矿区 + + +ranks_rankCommands__rank_cannot_remove=无法删除此阶级,因为它是默认阶段中的唯一阶级 +s_rankCommands__rank_was_removed=å·²æˆåŠŸåˆ é™¤é˜¶çº§â€œ%1†+ranks_rankCommands__rank_delete_error=由于错误,无法删除阶级“%1†+ + +ranks_rankCommands__ranks_list_header=&3在&7%1&3阶级中的等级 +ranks_rankCommands__ranks_list_ladder_cost_multplier=&3阶级æ¯çº§èŠ±è´¹ï¼š&7%1 +ranks_rankCommands__ranks_list_ladder_edit_cost_multplier=编辑此阶级为级别花费...... + +ranks_rankCommands__ranks_list_click_to_edit=&7å•å‡»é˜¶çº§çš„åç§°æŸ¥çœ‹æ›´å¤šä¿¡æ¯ +ranks_rankCommands__ranks_list_command_count= &c命令: &3%1 +ranks_rankCommands__ranks_list_currency=è´§å¸ &3: &2%1 +ranks_rankCommands__ranks_list_click_to_view=&7ç‚¹å‡»æŸ¥çœ‹ä¿¡æ¯ +ranks_rankCommands__ranks_list_click_to_view2=&7ç‚¹å‡»æŸ¥çœ‹ä¿¡æ¯ +ranks_rankCommands__ranks_list_create_new_rank=&7创建新的阶级 +ranks_rankCommands__ranks_list_you_may_try=&8ä½ å¯ä»¥è¯•è¯• + + + +ranks_rankCommands__ranks_info_header=阶级 %1 +ranks_rankCommands__ranks_info_name=&3阶级åå­—: &7%1 +ranks_rankCommands__ranks_info_tag=&3阶级标签: &7%1 &3Raw: &7\Q%2\E +ranks_rankCommands__ranks_info_ladder=&3阶级: &7%1 +ranks_rankCommands__ranks_info_not_linked_to_mines=&3该阶级与任何矿区无关 +ranks_rankCommands__ranks_info_linked_mines=&3与此阶级相关的矿区:%1 +ranks_rankCommands__ranks_info_cost=&3花费: &7$%1 +ranks_rankCommands__ranks_info_currency=&3è´§å¸ï¼š&7<&a%1&7> +ranks_rankCommands__ranks_info_players_with_rank=&7具有此阶级的玩家:%1 +ranks_rankCommands__ranks_info_rank_id=&6阶级 ID: &7%1 +ranks_rankCommands__ranks_info_rank_delete_message=&7[&c-&7] 删除 +ranks_rankCommands__ranks_info_rank_delete_tool_tip=&7å•å‡»å¯åˆ é™¤æ­¤æŽ’å。\n&æ­¤æ“作无法撤消 + + +ranks_rankCommands__rank_set_cost_success=å·²æˆåŠŸå°†é˜¶çº§â€œ%1â€çš„花费设置为%2 + + +ranks_rankCommands__set_currency_not_specified=必须指定货å¸å称,或者必须为“无â€ï¼Œ%1'无效 +ranks_rankCommands__set_currency_no_currency_to_clear=阶级“%1â€æ²¡æœ‰è´§å¸ï¼Œå› æ­¤æ— æ³•æ¸…除 +ranks_rankCommands__set_currency_cleared=å·²æˆåŠŸæ¸…除阶级“%1â€çš„è´§å¸ï¼Œæ­¤é˜¶çº§ä¸å†å…·æœ‰è‡ªå®šä¹‰è´§å¸ +ranks_rankCommands__set_currency_no_active_support=没有ç»æµŽæ’件的支æŒâ€œ%1â€è´§å¸ +ranks_rankCommands__set_currency_successful=å·²æˆåŠŸå°†é˜¶çº§â€œ%1â€çš„è´§å¸è®¾ç½®ä¸º%2 + + +ranks_rankCommands__set_tag_invalid=&c标记å必须是有效值。è¦åˆ é™¤ï¼Œè¯·ä½¿ç”¨å€¼&anone&c +ranks_rankCommands__set_tag_no_change=&c新的标记å与原æ¥çš„相åŒã€‚没有进行任何更改 +ranks_rankCommands__set_tag_cleared=&c已清除阶级%1的标记å +ranks_rankCommands__set_tag_success=&c阶级%2的标记å已更改为%1。 + + +ranks_rankCommands__player_must_be_online=&3您必须是游æˆä¸­åœ¨çº¿çš„玩家æ‰èƒ½è¿è¡Œæ­¤å‘½ä»¤ +ranks_rankCommands__player_ladder_info=&7阶级&b%1&7当å‰é˜¶çº§ï¼š&b%2 +ranks_rankCommands__player_ladder_highest_rank=è¿™æ˜¯æœ€é«˜çº§åˆ«ï¼ +ranks_rankCommands__player_ladder_next_rank=&7下一个阶级:&b%1&7&c$&b%2 +ranks_rankCommands__player_ladder_next_rank_currency=&7 è´§å¸: &2%1 +ranks_rankCommands__player_balance_default=&7&b%1&7的当å‰ä½™é¢ä¸º&b%2 +ranks_rankCommands__player_balance_others=&7&b%1å’Œ7的当å‰ä½™é¢ä¸º&b%2å’Œ2%3 +ranks_rankCommands__player_perms_offline=&7 注æ„:&3玩家处于离线模å¼ï¼Œå› æ­¤æƒé™ä¸å¯ç”¨ +ranks_rankCommands__player_sellall_multiplier=&7 Sellall:&b%1%2 +ranks_rankCommands__player_not_accurate=&5(&2ä¸å‡†ç¡®çš„&5) +ranks_rankCommands__player_admin_only=&8[ä»…é™ç®¡ç†å‘˜] +ranks_rankCommands__player_past_names=&7通过玩家å字和日期更改: +ranks_rankCommands__player_perms=&7玩家æƒé™ï¼š +ranks_rankCommands__player_op=&cOP +ranks_rankCommands__player_player=&3玩家 +ranks_rankCommands__player_online=&3在线 +ranks_rankCommands__player_offline=&3离线 +ranks_rankCommands__player_prison_offline_player=&3 +ranks_rankCommands__player_prison_player=&3监狱离线玩家 +ranks_rankCommands__player_no_ranks_found=&3未找到&c%1的阶级 + + +ranks_rankCommands__players_invalid_ladder=阶级“%1â€ä¸å­˜åœ¨ï¼Œæˆ–ä¸æ˜¯â€œå…¨éƒ¨â€ +ranks_rankCommands__players_invalid_action=æ“作“%1â€æ— æ•ˆï¼Œ[玩家,全部,全部] + diff --git a/prison-core/src/main/resources/lang/ranks/zh_TW.properties b/prison-core/src/main/resources/lang/ranks/zh_TW.properties index 69b58c5af..9e76d8333 100644 --- a/prison-core/src/main/resources/lang/ranks/zh_TW.properties +++ b/prison-core/src/main/resources/lang/ranks/zh_TW.properties @@ -50,7 +50,7 @@ ## -messages__version=7 +messages__version=8 messages__auto_refresh=true ranks_rankup__rankup_no_player_name=您已經 @@ -59,7 +59,7 @@ ranks_rankup__rankup_you_are=你是 ranks_rankup__rankup_success=æ­å–œ! %1 您已å‡åˆ°ä¸‹å€‹éšŽç´š '%2' %3 ranks_rankup__demote_success=抱歉, %1 您已é™å›žä¸Šå€‹éšŽç´š '%2' %3 ranks_rankup__log_rank_change=%1 您的階級已改變: %2 -ranks_rankup__rankup_cant_afford=您沒有足夠的金錢到下個階級 åˆ°ä¸‹å€‹éšŽç´šéœ€è¦ %1 %2 +ranks_rankup__rankup_cant_afford=您沒有足夠的金錢到下個階級 åˆ°ä¸‹å€‹éšŽç´šéœ€è¦ %1%2 ranks_rankup__rankup_lowest=%1 已是最低階級! ranks_rankup__rankup_highest=%1 已是最高階級! ranks_rankup__rankup_failure=階級æå‡å¤±æ•— è«‹é‡æ–°æª¢æŸ¥ä¾†ç™¼ç¾å•é¡Œ @@ -91,12 +91,21 @@ ranks_rankup__error_no_lower_rank_on_ladder=&c[ERROR] The ladder %1 has no ranks ranks_rankup__error_player_not_on_default_ladder=&c[ERROR] The player is not on the default ladder. Player: %1 ranks_rankup__not_at_last_rank=&c你沒有在上個階級! +ranks_rankup__at_last_rank=&cYou at the last rank! ranks_rankup__not_able_to_prestige=&7[&3抱歉&7] &3您ä¸èƒ½ä½¿ç”¨ &6è²æœ›! ranks_rankup__not_able_to_reset_rank=&7無法é‡è£½æ‚¨çš„é è¨­éšŽ ranks_rankup__balance_set_to_zero=&72您的錢已設置為零 ranks_rankup__prestige_successful=&7[&3æ­å–œ&7] &3您的 &6è²æœ›&3 å‡è‡³ %1&c! ranks_rankup__prestige_failure=&7[&3抱歉&7] &3您的 &6è²æœ›&3 é™è‡³ %1&c! +ranks_rankup__confirm_prestige_line_1=&3Confirm Prestige: %1 +ranks_rankup__confirm_prestige_line_2=&3 Cost: &7%1 +ranks_rankup__confirm_prestige_line_3=&3 Balance: &7%1%2 +ranks_rankup__confirm_prestige_line_4=&3 Default Rank will be reset. +ranks_rankup__confirm_prestige_line_5=&3 Balance will be reset. +ranks_rankup__confirm_prestige_line_6=&3Confirm with command: '&7/prestige %1confirm&3' +ranks_rankup__confirm_prestige_line_7=&3Confirm by clicking on the green block + ranks_rankup__invalid_charge_value=&3chargePlayer çš„ 值無效 有效值為: %1 %2 ranks_rankup__invalid_refund_value=&3refundPlayer çš„ 值無效 有效值為: %1 %2 diff --git a/prison-core/src/main/resources/lang/sellall/fi_FI.properties b/prison-core/src/main/resources/lang/sellall/fi_FI.properties new file mode 100644 index 000000000..059de9f6b --- /dev/null +++ b/prison-core/src/main/resources/lang/sellall/fi_FI.properties @@ -0,0 +1,67 @@ +# NOTE: A messages__version is an arbitrary integer that will be manually incremented within Prison +# when there are changes to these messages. This value represents when message content is +# changed, fixed, or added to. This value may not be increased if the change is very small and +# insignificant, such as a space or a couple of letters. +# +# messages__auto_refresh=true indicates that this file will automatically be replaced if +# Prison detects a messages__version difference. The old file will be deleted (renamed) and +# a new copy will be placed in the directory to be used. If this value is set to false, then +# Prison will not refresh this file and there could be issues with the display of other messages. +# If auto refresh is set to false, we are not held responsible for possible issues that can +# arise from inaccurate messages. If set to false, then you are responsible for maintaining +# the messages on your own. +# +# If you make changes to this file, and you have messages__auto_refresh=false, then those +# changes will be replaced when this file is updated. Since the old file is renamed, and +# not deleted, you can manually merge your changes back in to the new update. The old +# renamed files will never be deleted by prison; you can remove them when you feel like it +# is safe to do so. +# +# Please consider helping Prison, and everyone else who may use Prison, by contributing all +# translations to other languages. They should be faithful translations, and not something +# for the sake of humor or changes just for cosmetic styling. If you have something you would +# like to share, please contact a staff member on our Discord server. +#Thanks for your contributions! +# + +## +## Prison Supports Unicode (UTF-8) encoding in these properties files. BUt you must +## follow these instructions to ensure everything works properly. +## +## 1. You should only edit these files using a UTF-8 editor. On windows use NotePad, not WordPad. +## WordPad will save as plain text. To confirm the save was successful: save, close the editor, +## then reopen to confirm the encoding was preserved. +## +## 2. When running on Windows, you must enable utf-8 encoding in minecraft's console. Windows +## defaults to a characterpage 1252. To enable window's use of utf-8, you need to change the +## encoding prior to launching spigot/paper: +## chcp 65001 +## +## Full example of a windows script, which hooks for java debugging: +## rem Note: chcp 65001 enables utf-8 in windows, when normally windows uses characterpage 1252 +## chcp 65001 +## java -Dfile.encoding="UTF-8" -Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005 -Xms1g -Xmx4g -jar spigot-1.8.8.jar nogui --log-strip-color +## pause +## +## 3. When viewing the logs/latest.log files you must use an editor such as NotePad instead of WordPad. +## +## 4. Unicode is properly displayed in game, in console, in the logs, and with paste.helpch.at when using +## /prison support submit. +## + +messages__version=1 +messages__auto_refresh=true + + +sellall_function__message=&dNormaali viesti + + + +sellall_spigot_utils__money_earned=&3Tienasit &a$%1 +sellall_spigot_utils__only_sellall_signs_are_enabled=&3Voit vain myydä kylteillä, komento disabloitu. +sellall_spigot_utils__rate_limit_exceeded=&3Hidasta.. +sellall_spigot_utils__shop_is_empty=&3Anteeksi, tämä myynti kauppa on tyhjä.. +sellall_spigot_utils__you_have_nothing_to_sell=&3Anteeksi, sinulla ei ole myytävää. + +sellall_spigot_utils__sellall_is_disabled=&3Anteeksi, sellall on disabloitu + diff --git a/prison-core/src/main/resources/lang/sellall/zh_CN.properties b/prison-core/src/main/resources/lang/sellall/zh_CN.properties new file mode 100644 index 000000000..1034dec30 --- /dev/null +++ b/prison-core/src/main/resources/lang/sellall/zh_CN.properties @@ -0,0 +1,67 @@ +# NOTE: A messages__version is an arbitrary integer that will be manually incremented within Prison +# when there are changes to these messages. This value represents when message content is +# changed, fixed, or added to. This value may not be increased if the change is very small and +# insignificant, such as a space or a couple of letters. +# +# messages__auto_refresh=true indicates that this file will automatically be replaced if +# Prison detects a messages__version difference. The old file will be deleted (renamed) and +# a new copy will be placed in the directory to be used. If this value is set to false, then +# Prison will not refresh this file and there could be issues with the display of other messages. +# If auto refresh is set to false, we are not held responsible for possible issues that can +# arise from inaccurate messages. If set to false, then you are responsible for maintaining +# the messages on your own. +# +# If you make changes to this file, and you have messages__auto_refresh=false, then those +# changes will be replaced when this file is updated. Since the old file is renamed, and +# not deleted, you can manually merge your changes back in to the new update. The old +# renamed files will never be deleted by prison; you can remove them when you feel like it +# is safe to do so. +# +# Please consider helping Prison, and everyone else who may use Prison, by contributing all +# translations to other languages. They should be faithful translations, and not something +# for the sake of humor or changes just for cosmetic styling. If you have something you would +# like to share, please contact a staff member on our Discord server. +#Thanks for your contributions! +# + +## +## Prison Supports Unicode (UTF-8) encoding in these properties files. BUt you must +## follow these instructions to ensure everything works properly. +## +## 1. You should only edit these files using a UTF-8 editor. On windows use NotePad, not WordPad. +## WordPad will save as plain text. To confirm the save was successful: save, close the editor, +## then reopen to confirm the encoding was preserved. +## +## 2. When running on Windows, you must enable utf-8 encoding in minecraft's console. Windows +## defaults to a characterpage 1252. To enable window's use of utf-8, you need to change the +## encoding prior to launching spigot/paper: +## chcp 65001 +## +## Full example of a windows script, which hooks for java debugging: +## rem Note: chcp 65001 enables utf-8 in windows, when normally windows uses characterpage 1252 +## chcp 65001 +## java -Dfile.encoding="UTF-8" -Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005 -Xms1g -Xmx4g -jar spigot-1.8.8.jar nogui --log-strip-color +## pause +## +## 3. When viewing the logs/latest.log files you must use an editor such as NotePad instead of WordPad. +## +## 4. Unicode is properly displayed in game, in console, in the logs, and with paste.helpch.at when using +## /prison support submit. +## + +messages__version=1 +messages__auto_refresh=true + + +sellall_function__message=&d示例 &7æ¶ˆæ¯ + + + +sellall_spigot_utils__money_earned=&3你赚了 &a$%1 +sellall_spigot_utils__only_sellall_signs_are_enabled=&3ä½ åªèƒ½é€šè¿‡å‘Šç¤ºç‰Œè¿›è¡Œå‡ºå”®çŸ¿ç‰©ï¼Œå› ä¸ºæŒ‡ä»¤å‡ºå”®è¢«ç¦ç”¨äº† +sellall_spigot_utils__rate_limit_exceeded=&3请慢点,出售次数超过é™åˆ¶ +sellall_spigot_utils__shop_is_empty=&3抱歉,但这个出售商店是空的 +sellall_spigot_utils__you_have_nothing_to_sell=&3你没有什么å¯å–çš„ + +sellall_spigot_utils__sellall_is_disabled=&3sellallå·²ç¦ç”¨ + diff --git a/prison-core/src/main/resources/lang/spigot/en_US.properties b/prison-core/src/main/resources/lang/spigot/en_US.properties index fae35647b..a53f646b3 100644 --- a/prison-core/src/main/resources/lang/spigot/en_US.properties +++ b/prison-core/src/main/resources/lang/spigot/en_US.properties @@ -49,7 +49,7 @@ ## /prison support submit. ## -messages__version=5 +messages__version=6 messages__auto_refresh=true ## Click to do something @@ -287,7 +287,7 @@ spigot_message_gui_backpack_too_many=Sorry, there are too many Backpacks and the spigot_message_gui_close_success=GUI closed with success. spigot_message_gui_error=Can't open GUI, disabled or error. spigot_message_gui_error_empty=Can't open GUI, it's empty. -spigot_message_gui_ladder_empty=Sorry, there aren't Ladders to show. +spigot_message_gui_ladder_empty=Sorry, there aren't Ladders to show. [%1] spigot_message_gui_ladder_too_many=Sorry, there are too many Ladders and the GUI can't show them. spigot_message_gui_mines_empty=Sorry, there aren't Mines to show. spigot_message_gui_mines_too_many=Sorry, there are too many Mines for the GUI to show. @@ -314,3 +314,8 @@ spigot_auto_manager__inventory_is_full=&cWARNING! Your inventory's full! spigot_auto_manager__is_full_dropping_item__ignore__not_useds=&cWARNING! Your inventory's full and you're dropping items! spigot_auto_manager__inventory_is_full_losing_items=&cWARNING! Your inventory's full and you're losing items! + + +spigot_minebombs__cooldown_delay=You cannot use another Prison Mine Bomb for %1 seconds. + + diff --git a/prison-core/src/main/resources/lang/spigot/pt_PT.properties b/prison-core/src/main/resources/lang/spigot/pt_PT.properties index 3e8e5cf74..2c2272449 100644 --- a/prison-core/src/main/resources/lang/spigot/pt_PT.properties +++ b/prison-core/src/main/resources/lang/spigot/pt_PT.properties @@ -49,7 +49,7 @@ ## /prison support submit. ## -messages__version=1 +messages__version=2 messages__auto_refresh=true ## Click to do something @@ -293,7 +293,7 @@ spigot_message_gui_backpack_too_many=Desculpa, há muitas Backpack e a GUI não spigot_message_gui_close_success=GUI fechada com sucesso. spigot_message_gui_error=Impossível abrir GUI, desativada ou erro. spigot_message_gui_error_empty=Não é possível abrir a GUI, está vazia. -spigot_message_gui_ladder_empty=Desculpa, não há Ladders para show. +spigot_message_gui_ladder_empty=Desculpa, não há Ladders para show. [%1] spigot_message_gui_ladder_too_many=Desculpa, existem muitas Ladders e a GUI não pode mostrá-las. spigot_message_gui_mines_empty=Desculpa, não há Minas para show. spigot_message_gui_mines_too_many=Desculpa, existem muitas minas para a GUI para show. @@ -309,6 +309,9 @@ spigot_message_gui_sellall_empty=Desculpa, não há nada para mostrar. spigot_message_gui_too_high=Desculpa, mas o valor é muito alto (acima do máximo possível). spigot_message_gui_too_low_value=Desculpa, mas o valor é muito baixo (abaixo do mínimo possível). + + + spigot_blockbreak_mines__mine_is_being_reset__please_wait=Mina %1 está a ser resetada... por favor aguarde. spigot_blockbreak_core__validate_event__your_tool_is_worn_out=&cA tua ferramenta está gasta e não pode ser utilizada. @@ -318,3 +321,6 @@ spigot_auto_manager__is_full_dropping_item__ignore__not_useds=&cAVISO! O teu inv spigot_auto_manager__inventory_is_full_losing_items=&cAVISO! O teu inventário está cheio e você estás a perder items! + +spigot_minebombs__cooldown_delay=You cannot use another Prison Mine Bomb for %1 seconds. + diff --git a/prison-core/src/main/resources/lang/spigot/zh-CN.properties b/prison-core/src/main/resources/lang/spigot/zh-CN.properties new file mode 100644 index 000000000..0f067c215 --- /dev/null +++ b/prison-core/src/main/resources/lang/spigot/zh-CN.properties @@ -0,0 +1,316 @@ +# NOTE: A messages__version is an arbitrary integer that will be manually incremented within Prison +# when there are changes to these messages. This value represents when message content is +# changed, fixed, or added to. This value may not be increased if the change is very small and +# insignificant, such as a space or a couple of letters. +# +# messages__auto_refresh=true indicates that this file will automatically be replaced if +# Prison detects a messages__version difference. The old file will be deleted (renamed) and +# a new copy will be placed in the directory to be used. If this value is set to false, then +# Prison will not refresh this file and there could be issues with the display of other messages. +# If auto refresh is set to false, we are not held responsible for possible issues that can +# arise from inaccurate messages. If set to false, then you are responsible for maintaining +# the messages on your own. +# +# If you make changes to this file, and you have messages__auto_refresh=false, then those +# changes will be replaced when this file is updated. Since the old file is renamed, and +# not deleted, you can manually merge your changes back in to the new update. The old +# renamed files will never be deleted by prison; you can remove them when you feel like it +# is safe to do so. +# +# Please consider helping Prison, and everyone else who may use Prison, by contributing all +# translations to other languages. They should be faithful translations, and not something +# for the sake of humor or changes just for cosmetic styling. If you have something you would +# like to share, please contact a staff member on our Discord server. +#Thanks for your contributions! +# + +## +## Prison Supports Unicode (UTF-8) encoding in these properties files. BUt you must +## follow these instructions to ensure everything works properly. +## +## 1. You should only edit these files using a UTF-8 editor. On windows use NotePad, not WordPad. +## WordPad will save as plain text. To confirm the save was successful: save, close the editor, +## then reopen to confirm the encoding was preserved. +## +## 2. When running on Windows, you must enable utf-8 encoding in minecraft's console. Windows +## defaults to a characterpage 1252. To enable window's use of utf-8, you need to change the +## encoding prior to launching spigot/paper: +## chcp 65001 +## +## Full example of a windows script, which hooks for java debugging: +## rem Note: chcp 65001 enables utf-8 in windows, when normally windows uses characterpage 1252 +## chcp 65001 +## java -Dfile.encoding="UTF-8" -Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005 -Xms1g -Xmx4g -jar spigot-1.8.8.jar nogui --log-strip-color +## pause +## +## 3. When viewing the logs/latest.log files you must use an editor such as NotePad instead of WordPad. +## +## 4. Unicode is properly displayed in game, in console, in the logs, and with paste.helpch.at when using +## /prison support submit. +## + +messages__version=5 +messages__auto_refresh=true + +## Click to do something +spigot_gui_lore_click_to_add=点击以添加 +spigot_gui_lore_click_to_add_backpack=点击以添加背包 +#spigot_gui_lore_click_to_cancel=点击以å–消 +#spigot_gui_lore_click_to_close=点击以关闭 +#spigot_gui_lore_click_to_confirm=点击以确认 +#spigot_gui_lore_click_to_decrease=点击以å‡å°‘ +#spigot_gui_lore_click_to_delete=点击以删除 +#spigot_gui_lore_click_to_disable=点击以ç¦ç”¨ +#spigot_gui_lore_click_to_edit=点击以编辑 +#spigot_gui_lore_click_to_enable=点击以å¯ç”¨ +#spigot_gui_lore_click_to_increase=点击以增加 +spigot_gui_lore_click_to_manage_rank=点击以管ç†ç­‰çº§ +#spigot_gui_lore_click_to_open=点击以打开 +spigot_gui_lore_click_to_rankup=点击以å‡çº§ +spigot_gui_lore_click_to_rename=点击以é‡å‘½å +spigot_gui_lore_click_to_select=点击以选择 +spigot_gui_lore_click_to_start_block_setup=ç‚¹å‡»ä»¥æ·»åŠ æ–¹å— +spigot_gui_lore_click_to_teleport=ç‚¹å‡»ä»¥ä¼ é€ +spigot_gui_lore_click_to_use=点击以使用 + +## Left-Click to do something. +#spigot_gui_lore_click_left_to_confirm=左键点击确认 +#spigot_gui_lore_click_left_to_reset=左键点击以é‡ç½® +#spigot_gui_lore_click_left_to_open=左键点击打开 +#spigot_gui_lore_click_left_to_edit=左键点击进行编辑 + +## Right-Click to do something. +#spigot_gui_lore_click_right_to_cancel=å³é”®ç‚¹å‡»ä»¥å–消 +#spigot_gui_lore_click_right_to_delete=å³é”®ç‚¹å‡»ä»¥åˆ é™¤ +#spigot_gui_lore_click_right_to_disable=å³é”®ç‚¹å‡»ä»¥ç¦ç”¨ +#spigot_gui_lore_click_right_to_enable=å³é”®ç‚¹å‡»ä»¥å¯ç”¨ +#spigot_gui_lore_click_right_to_toggle=å³é”®ç‚¹å‡»ä»¥åˆ‡æ¢ + +## Shift and Right-Click to do something +#spigot_gui_lore_click_right_and_shift_to_delete=按ä½Shift键并å³é”®ç‚¹å‡»ä»¥åˆ é™¤ +#spigot_gui_lore_click_right_and_shift_to_disable=按ä½Shift键并å³é”®ç‚¹å‡»ä»¥ç¦ç”¨ +#spigot_gui_lore_click_right_and_shift_to_toggle=按ä½Shift键并点击鼠标å³é”®è¿›è¡Œåˆ‡æ¢ + +## Titles or data naming. +spigot_gui_lore_backpack_id=背包ID: +spigot_gui_lore_blocks=æ–¹å—: +spigot_gui_lore_blocktype=æ–¹å—类型: +spigot_gui_lore_chance=机会: +spigot_gui_lore_command=命令: +spigot_gui_lore_currency=è´§å¸: +#spigot_gui_lore_delay=延迟: +spigot_gui_lore_id=ID: +spigot_gui_lore_info=ä¿¡æ¯: +spigot_gui_lore_minename=我的åå­—: +#spigot_gui_lore_multiplier=乘数: +spigot_gui_lore_name=åå­—: +spigot_gui_lore_owner=所有者: +spigot_gui_lore_percentage=百分比: +#spigot_gui_lore_permission=æƒé™ï¼š +spigot_gui_lore_players_at_rank=该等级的玩家: +#spigot_gui_lore_prestige_name=声望å称: +#spigot_gui_lore_price=价格: +spigot_gui_lore_radius=åŠå¾„: +spigot_gui_lore_rank_tag=等级标签: +spigot_gui_lore_reset_time=é‡ç½®æ—¶é—´ï¼ˆs): +spigot_gui_lore_size=尺寸: +spigot_gui_lore_show_item=显示项目: +spigot_gui_lore_spawnpoint=出生点设置: +spigot_gui_lore_volume=体积: +#spigot_gui_lore_value=价值: +spigot_gui_lore_world=世界: + +## Simple actions or status. +spigot_gui_lore_disabled=ç¦æ­¢ +spigot_gui_lore_enabled=å¼€å¯ +spigot_gui_lore_locked=é”定 +#spigot_gui_lore_next_page=下一页 +#spigot_gui_lore_prior_page=上一页 +spigot_gui_lore_rankup=å‡çº§ +spigot_gui_lore_selected=选择 +spigot_gui_lore_unlocked=è§£é” + +## Descriptions. +spigot_gui_lore_add_backpack_instruction_1=请至少添加一项 +spigot_gui_lore_add_backpack_instruction_2=如果你没有背包 +spigot_gui_lore_add_backpack_instruction_3=ä¸ä¼šè¢«ä¿å­˜ +spigot_gui_lore_prestige_warning_1=声望将é‡ç½®ï¼š +spigot_gui_lore_prestige_warning_2=- 等级 +spigot_gui_lore_prestige_warning_3=- å‡è¡¡ +spigot_gui_lore_ranks_setup_1=æ²¡æœ‰ç­‰çº§ï¼ +spigot_gui_lore_ranks_setup_2=如果你想继续安装。 +spigot_gui_lore_ranks_setup_3=从A到Z的所有等级和矿场将被制造 +spigot_gui_lore_ranks_setup_4=默认值为[æ•°æ®åˆ é™¤] +spigot_gui_lore_ranks_setup_5=你还å¯ä»¥ä½¿ç”¨ï¼š +spigot_gui_lore_ranks_setup_6=/ranks autoConfigure full ! +spigot_gui_lore_ranks_setup_7=请将X替æ¢ä¸ºèµ·å§‹ä»·æ ¼ï¼Œä»¥åŠ +spigot_gui_lore_ranks_setup_8=multiplier, default price = 50000, multiplier = 1.5. +spigot_gui_lore_sellall_delay_use_1=请等待一下å†ä½¿ç”¨ +spigot_gui_lore_sellall_delay_use_2=the &3/sellall sell &8命令. +spigot_gui_lore_set_mine_delay_instruction_1=设置矿场延迟 +spigot_gui_lore_set_mine_delay_instruction_2=before reset when it +spigot_gui_lore_set_mine_delay_instruction_3=åˆ°è¾¾é›¶ä¸ªæ–¹å— +spigot_gui_lore_show_item_description_1=This's the item +spigot_gui_lore_show_item_description_2=显示在玩家的GUI中 +spigot_gui_lore_show_item_description_3=/mines GUI +spigot_gui_lore_skip_reset_instruction_1=跳过é‡ç½®ï¼Œå¦‚果: +spigot_gui_lore_skip_reset_instruction_2=æ–¹å—ä¸å¤Ÿ +spigot_gui_lore_skip_reset_instruction_3=已被开采 + +## Button names or single line descriptions. +spigot_gui_lore_autofeatures_button_description=Manage AutoFeatures. +spigot_gui_lore_backpacks_button_description=Manage BackPacks. +spigot_gui_lore_disable_notifications=ç¦ç”¨é€šçŸ¥ +spigot_gui_lore_enable_radius_mode=å¯ç”¨åŠå¾„æ¨¡å¼ +spigot_gui_lore_enable_within_mode=å¯ç”¨ç™½åå•æ¨¡å¼ +spigot_gui_lore_mines_button_description=管ç†çŸ¿åœº +spigot_gui_lore_no_multipliers=[!] æ²¡æœ‰ä¹˜æ•°ï¼ +spigot_gui_lore_ranks_button_description=等级管ç†å™¨GUI +spigot_gui_lore_rankup_if_enough_money=如果你有足够的钱 +spigot_gui_lore_sellall_button_description=管ç†SellAll +spigot_gui_lore_sellall_edit_info=编辑SellAllè´§å¸ +spigot_gui_lore_tp_to_mine=点击传é€åˆ°æˆ‘ + +## Messages +spigot_message_missing_permission=对ä¸èµ·ï¼Œä½ æ²¡æœ‰ä½¿ç”¨è¯¥åŠŸèƒ½çš„æƒé™ï¼ +spigot_message_chat_event_time_end=你没时间了,事件å–æ¶ˆäº†ï¼ +spigot_message_event_cancelled=事件å–消。 +spigot_message_command_wrong_format=对ä¸èµ·ï¼Œå‘½ä»¤æ ¼å¼é”™è¯¯ã€‚ +spigot_message_console_error=抱歉,你必须是玩家æ‰èƒ½ä½¿ç”¨å®ƒã€‚ + +## Ladder Messages +spigot_message_ladder_default_empty=抱歉,默认等级为空。 + +## Mine Messages +spigot_message_mines_disabled=对ä¸èµ·ï¼ŒçŸ¿åœºè¢«ç¦ç”¨äº†ã€‚ +spigot_message_mines_name_chat_1=请填写你想è¦ä½¿ç”¨çš„&6MinName&7å’Œ&6submit&7 +spigot_message_mines_name_chat_2=输入&cclose&7å–消或等待&c30秒&7 +spigot_message_mines_name_chat_cancelled=é‡å‘½å我的&cclosed&7,什么都没有改å˜ï¼ +spigot_message_mines_item_show_edit_success=我的显示项目编辑æˆåŠŸ +spigot_message_mines_or_gui_disabled=抱歉,矿场GUIå·²ç¦ç”¨ + +## Backpack Messages +spigot_message_backpack_cant_own=对ä¸èµ·ï¼Œä½ ä¸èƒ½æ‹¥æœ‰èƒŒåŒ… +spigot_message_backpack_delete_error=抱歉,无法删除背包 +spigot_message_backpack_delete_success=背包删除æˆåŠŸ +spigot_message_backpack_format_error=抱歉,命令格å¼ä¸æ­£ç¡®ï¼Œå¯èƒ½ç¼ºå°‘一些å‚æ•° +spigot_message_backpack_limit_decrement_fail=背包é™åˆ¶ä¸èƒ½ä¸ºè´Ÿ +spigot_message_backpack_limit_edit_success=背包é™åˆ¶ç¼–辑æˆåŠŸ +spigot_message_backpack_limit_not_number=对ä¸èµ·ï¼ŒèƒŒåŒ…é™åˆ¶ä¸æ˜¯ä¸€ä¸ªæ•°å­— +spigot_message_backpack_limit_reached=对ä¸èµ·ï¼Œä½ ä¸èƒ½æ‹¥æœ‰æ›´å¤šçš„背包 +spigot_message_backpack_missing_playername=抱歉,请添加有效的玩家å称 +spigot_message_backpack_resize_success=如果背包存在,它æˆåŠŸåœ°è°ƒæ•´äº†å¤§å° +spigot_message_backpack_size_must_be_multiple_of_9=背包大å°å¿…须是9çš„å€æ•°ï¼Œä¸”ä¸å¾—超过64ï¼ + + +## Prestige Messages +spigot_message_prestiges_disabled=抱歉,已ç¦ç”¨ +spigot_message_prestiges_empty=对ä¸èµ·ï¼Œæ²¡æœ‰å£°æœ› +spigot_message_prestiges_or_gui_disabled=抱歉,已ç¦ç”¨å£°æœ›æˆ–GUI +spigot_message_prestiges_confirm=确认&7:键入è¦ç¡®è®¤çš„å•è¯&a确认&7 +spigot_message_prestiges_cancel=å–消&7:键入è¦å–消的å•è¯&cå–消&7,&c你有30秒 +spigot_message_prestiges_cancelled=声望å–消了 +spigot_message_prestiges_cancelled_wrong_keyword=声望&cå–消选中&7,你没有输入:&a确定&7。 + +## Ranks Messages +spigot_message_ranks_disabled=抱歉,等级已ç¦ç”¨ +spigot_message_ranks_or_gui_disabled=抱歉,已ç¦ç”¨ç­‰çº§æˆ–GUI +spigot_message_ranks_tag_chat_rename_1=请填写你è¦ä½¿ç”¨çš„&6tag&7å’Œ&6submit&7 +spigot_message_ranks_tag_chat_rename_2=输入&cclose&7å–消或等待&c30秒&7 +spigot_message_ranks_tag_chat_cancelled=é‡å‘½å标签&cclosed&7ï¼Œæ²¡æœ‰ä»»ä½•æ›´æ”¹ï¼ + +## SellAll Messages +spigot_message_sellall_auto_already_enabled=Sellall自动已å¯ç”¨ +spigot_message_sellall_auto_already_disabled=Sellall自动已ç¦ç”¨ +spigot_message_sellall_auto_disabled=SellAll自动ç¦ç”¨æˆåŠŸ +spigot_message_sellall_auto_disabled_cant_use=抱歉,你需è¦å¯ç”¨SellAllæ‰èƒ½ä½¿ç”¨æ­¤åŠŸèƒ½ã€‚ +spigot_message_sellall_auto_enabled=SellAll自动å¯ç”¨å¹¶æˆåŠŸã€‚ +spigot_message_sellall_auto_perusertoggleable_enabled=æˆåŠŸå¯ç”¨äº†Sellall Auto perUserToggleable +spigot_message_sellall_auto_perusertoggleable_disabled=æˆåŠŸç¦ç”¨äº†Sellall Auto perUserToggleable +spigot_message_sellall_auto_perusertoggleable_already_enabled=Sellall自动perUserToggleableå·²å¯ç”¨ +spigot_message_sellall_auto_perusertoggleable_already_disabled=Sellall自动perUserToggleableå·²ç¦ç”¨ +spigot_message_sellall_boolean_input_invalid=布尔值无效(有效值为True或False) +spigot_message_sellall_cant_find_item_config=抱歉,在é…置中找ä¸åˆ°ä½ çš„项目 +spigot_message_sellall_currency_chat_1=&3开始为SellAll设置新货å¸ï¼ +spigot_message_sellall_currency_chat_2=输入&Cå–消&7å–消 +spigot_message_sellall_currency_chat_3=键入&3默认值&7ä»¥è®¾ç½®ä¸ºé»˜è®¤è´§å¸ +spigot_message_sellall_currency_chat_4=键入&a当å‰å称&7ä»¥è®¾ç½®æ–°è´§å¸ +spigot_message_sellall_currency_edit_success=SellAllè´§å¸ç¼–辑æˆåŠŸ +spigot_message_sellall_currency_not_found=对ä¸èµ·ï¼Œæ‰¾ä¸åˆ°è´§å¸ +spigot_message_sellall_hand_disabled=æˆåŠŸåœ°ç¦ç”¨äº†Selall +spigot_message_sellall_hand_enabled=Sellall手动å¯ç”¨å¹¶æˆåŠŸ +spigot_message_sellall_hand_is_disabled=SellAll Handå·²ç¦ç”¨ +spigot_message_sellall_item_add_success=项目添加æˆåŠŸ +spigot_message_sellall_item_already_added=你已添加此项目,请改用“编辑â€å‘½ä»¤ +spigot_message_sellall_item_delete_success=项目已æˆåŠŸåˆ é™¤ +spigot_message_sellall_item_edit_success=SellAll项目编辑æˆåŠŸ +spigot_message_sellall_item_id_not_found=抱歉,项目å称/ID无效 +spigot_message_sellall_item_missing_name=请添加项目å称/IDå‚æ•° +spigot_message_sellall_item_missing_price=请将项值添加到å‚数中 +spigot_message_sellall_item_not_found=é…置中未找到SellAll项 +spigot_message_sellall_default_values_success=æˆåŠŸè®¾ç½®æ‰€æœ‰é»˜è®¤å€¼ +spigot_message_sellall_delay_already_enabled=SellAll延迟已å¯ç”¨ +spigot_message_sellall_delay_already_disabled=SellAll延迟已ç¦ç”¨ +spigot_message_sellall_delay_disabled=æˆåŠŸç¦ç”¨SellAll延迟 +spigot_message_sellall_delay_disabled_cant_use=抱歉,请å¯ç”¨SellAll Delay以使用此 +spigot_message_sellall_delay_edit_success=Sellall延迟编辑æˆåŠŸ +spigot_message_sellall_delay_enabled=æˆåŠŸå¯ç”¨SellAll延迟 +spigot_message_sellall_delay_not_number=SellAll延迟编å·æ— æ•ˆ +#spigot_message_sellall_delay_wait=Sellall延迟已å¯ç”¨ï¼Œè¯·æ…¢ç‚¹ +spigot_message_sellall_gui_disabled=SellAll GUIå·²ç¦ç”¨ã€‚ +#spigot_message_sellall_money_earned=你赢得了&a$ +spigot_message_sellall_multiplier_add_success=æˆåŠŸå¢žåŠ äº†SellAll出售价格 +spigot_message_sellall_multiplier_are_disabled=抱歉,SellAll出售已ç¦ç”¨ +spigot_message_sellall_multiplier_cant_find=抱歉,找ä¸åˆ°SellAll出售价格 +spigot_message_sellall_multiplier_delete_success=æˆåŠŸåˆ é™¤SellAll出售价格 +spigot_message_sellall_multiplier_disabled=æˆåŠŸç¦ç”¨æ‰€æœ‰ä¹˜æ•° +spigot_message_sellall_multiplier_edit_success=SellAll乘数编辑æˆåŠŸ +spigot_message_sellall_multiplier_enabled=æˆåŠŸå¯ç”¨SellAll乘数 +#spigot_message_sellall_sell_empty=对ä¸èµ·ï¼ŒSellAllå•†åº—æ²¡æœ‰å•†å“ +#spigot_message_sellall_sell_nothing_sellable=对ä¸èµ·ï¼Œä½ æ²¡æœ‰ä»€ä¹ˆå¯å–çš„ +#spigot_message_sellall_sell_sign_only=ä½ å¯ä»¥ä½¿ç”¨SellAll-Sell-only-with-Signs +spigot_message_sellall_sell_sign_notify=You sold trough a sign with success +spigot_message_sellall_trigger_already_disabled=SellAll触å‘器已ç¦ç”¨ +spigot_message_sellall_trigger_already_enabled=SellAll触å‘器已å¯ç”¨ +spigot_message_sellall_trigger_disabled=æˆåŠŸç¦ç”¨SellAll触å‘器 +spigot_message_sellall_trigger_enabled=æˆåŠŸå¯ç”¨SellAll触å‘器 +spigot_message_sellall_trigger_is_disabled=抱歉,SellAll触å‘器已ç¦ç”¨ +spigot_message_sellall_trigger_item_add_success=æˆåŠŸæ·»åŠ SellAll项目触å‘器 +spigot_message_sellall_trigger_item_cant_find=é…置中未找到SellAll项触å‘器项 +spigot_message_sellall_trigger_item_delete_success=SellAll项目触å‘器已æˆåŠŸåˆ é™¤ +spigot_message_sellall_trigger_item_missing=请将项目å称/ID添加到命令中 + +## GUI Message +spigot_message_gui_backpack_disabled=无法打开GUI,背包已ç¦ç”¨ +spigot_message_gui_backpack_empty=对ä¸èµ·ï¼Œæ²¡æœ‰èƒŒåŒ…å¯ä¾›å±•ç¤º +spigot_message_gui_backpack_too_many=抱歉,背包太多,GUI无法显示 +spigot_message_gui_close_success=GUIæˆåŠŸå…³é—­ +spigot_message_gui_error=无法打开GUI,请ç¦ç”¨ +spigot_message_gui_error_empty=无法打开或出错,GUI,它是空的 +spigot_message_gui_ladder_empty=对ä¸èµ·ï¼Œæ²¡æœ‰ç­‰çº§å¯ä¾›å±•ç¤º +spigot_message_gui_ladder_too_many=抱歉,等级太多,GUI无法显示它们 +spigot_message_gui_mines_empty=对ä¸èµ·ï¼Œæ²¡æœ‰çŸ¿åœºè¦å±•ç¤º +spigot_message_gui_mines_too_many=很抱歉,GUI显示的矿场太多...... +spigot_message_gui_prestiges_empty=抱歉,没有声望å¯æ˜¾ç¤º +spigot_message_gui_prestiges_too_many=抱歉,声望太多,GUI无法显示它们 +spigot_message_gui_ranks_empty=抱歉,此等级中没有è¦æ˜¾ç¤ºçš„级别 +spigot_message_gui_ranks_rankup_commands_empty=抱歉,没有è¦æ˜¾ç¤ºçš„å‡çº§å‘½ä»¤ +spigot_message_gui_ranks_rankup_commands_too_many=抱歉,å‡çº§å‘½ä»¤å¤ªå¤šï¼ŒGUI无法显示它们 +spigot_message_gui_ranks_too_many=抱歉,等级太多,GUI无法显示它们 +spigot_message_gui_reload_success=GUIé‡æ–°åŠ è½½æˆåŠŸï¼ +#spigot_message_gui_sellall_disabled=抱歉,SellAllå·²ç¦ç”¨ +spigot_message_gui_sellall_empty=对ä¸èµ·ï¼Œæ²¡ä»€ä¹ˆå¯çœ‹çš„ +spigot_message_gui_too_high=很抱歉,该值太高(高于最大å¯èƒ½å€¼ï¼‰ +spigot_message_gui_too_low_value=抱歉,但该值太低(低于å¯èƒ½çš„最å°å€¼ï¼‰ + + + + +spigot_blockbreak_mines__mine_is_being_reset__please_wait=正在é‡ç½®%1…请ç¨å€™ + +spigot_blockbreak_core__validate_event__your_tool_is_worn_out=&c你的工具磨æŸäº†ï¼Œä¸èƒ½ç”¨äº† + +spigot_auto_manager__inventory_is_full=&cä½ çš„èƒŒåŒ…æ»¡äº†ï¼ +spigot_auto_manager__is_full_dropping_item__ignore__not_useds=&c你的背包已满,你正在丢弃物å“ï¼ +spigot_auto_manager__inventory_is_full_losing_items=&c你的背包已满,你正在丢失物å“ï¼ + diff --git a/prison-core/src/test/java/tech/mcprison/prison/TestPlatform.java b/prison-core/src/test/java/tech/mcprison/prison/TestPlatform.java index ca8897c18..31b0a4b7b 100644 --- a/prison-core/src/test/java/tech/mcprison/prison/TestPlatform.java +++ b/prison-core/src/test/java/tech/mcprison/prison/TestPlatform.java @@ -29,6 +29,7 @@ import java.util.UUID; import tech.mcprison.prison.PrisonCommand.RegisteredPluginsData; +import tech.mcprison.prison.backpacks.PlayerBackpack; import tech.mcprison.prison.commands.PluginCommand; import tech.mcprison.prison.file.FileStorage; import tech.mcprison.prison.file.YamlFileIO; @@ -48,8 +49,9 @@ import tech.mcprison.prison.modules.ModuleElementType; import tech.mcprison.prison.output.ChatDisplay; import tech.mcprison.prison.placeholders.PlaceholderManager.PlaceholderFlags; -import tech.mcprison.prison.ranks.data.RankPlayer; import tech.mcprison.prison.placeholders.Placeholders; +import tech.mcprison.prison.ranks.data.RankLadder; +import tech.mcprison.prison.ranks.data.RankPlayer; import tech.mcprison.prison.store.Storage; import tech.mcprison.prison.util.ChatColor; import tech.mcprison.prison.util.Location; @@ -506,4 +508,19 @@ public void checkPlayerDefaultRank( RankPlayer rPlayer ) { public void listAllMines(CommandSender sender, Player player) { } + + @Override + public void sellall( RankPlayer rankPlayer ) { + + } + + @Override + public RankLadder getRankLadder(String ladderName) { + return null; + } + + @Override + public List getPlayerOldBackpacks( Player player ) { + return null; + } } diff --git a/prison-core/src/test/java/tech/mcprison/prison/TestScheduler.java b/prison-core/src/test/java/tech/mcprison/prison/TestScheduler.java index 2ad6dd8c4..b3182ee53 100644 --- a/prison-core/src/test/java/tech/mcprison/prison/TestScheduler.java +++ b/prison-core/src/test/java/tech/mcprison/prison/TestScheduler.java @@ -1,5 +1,6 @@ package tech.mcprison.prison; +import tech.mcprison.prison.internal.Player; import tech.mcprison.prison.internal.Scheduler; /** @@ -21,6 +22,16 @@ public class TestScheduler implements Scheduler { @Override public int runTaskTimerAsync(Runnable run, long delay, long interval) { return 0; } + + @Override + public void dispatchCommand(Player player, String command) { + + } + + @Override + public void performCommand(Player player, String command) { + + } @Override public void cancelTask(int taskId) { diff --git a/prison-mines/src/main/java/tech/mcprison/prison/mines/MinesListener.java b/prison-mines/src/main/java/tech/mcprison/prison/mines/MinesListener.java index f41385fbc..4058eab05 100644 --- a/prison-mines/src/main/java/tech/mcprison/prison/mines/MinesListener.java +++ b/prison-mines/src/main/java/tech/mcprison/prison/mines/MinesListener.java @@ -2,6 +2,7 @@ import com.google.common.eventbus.Subscribe; +import tech.mcprison.prison.Prison; import tech.mcprison.prison.internal.Player; import tech.mcprison.prison.internal.events.player.PlayerSuffocationEvent; import tech.mcprison.prison.internal.events.world.PrisonWorldLoadEvent; @@ -33,6 +34,14 @@ public void onWorldLoadListener( PrisonWorldLoadEvent e ) { } + + /** + *

If a player is suffocating, and if they are within a mine, then based upon the config + * settings, the play may not experience suffocation, and they may be teleported to + * the mine's spawn location, or the center of the mine. + *

+ * @param e + */ @Subscribe public void onPlayerSuffocationListener( PlayerSuffocationEvent e ) { @@ -40,19 +49,29 @@ public void onPlayerSuffocationListener( PlayerSuffocationEvent e ) { Mine mine = PrisonMines.getInstance().findMineLocation( player ); if ( mine != null ) { - e.setCanceled( true ); - // Submit the teleport task to run in 3 ticks. This will allow the suffocation - // event to be canceled. If the player moves then they don't need to be teleported - // so it will be canceled. - MineTeleportWarmUpTask mineTeleportWarmUp = new MineTeleportWarmUpTask( - player, mine, "spawn", 0.5 ); - mineTeleportWarmUp.setMessageSuccess( - "&7You have been teleported out of the mine to prevent suffocating." ); - mineTeleportWarmUp.setMessageFailed( null ); + // If players can't be suffocated in mines, then cancel the suffocation event: + if ( !Prison.get().getPlatform().getConfigBooleanFalse( "prison-mines.enable-suffocation-in-mines" ) ) { + + e.setCanceled( true ); + } - PrisonTaskSubmitter.runTaskLater( mineTeleportWarmUp, 3 ); -// mine.teleportPlayerOut( player ); + + if ( Prison.get().getPlatform().getConfigBooleanTrue( "prison-mines.tp-to-spawn-on-mine-resets" ) ) { + + // Submit the teleport task to run in 3 ticks. This will allow the suffocation + // event to be canceled. If the player moves then they don't need to be teleported + // so it will be canceled. + MineTeleportWarmUpTask mineTeleportWarmUp = new MineTeleportWarmUpTask( + player, mine, "spawn", 0.5 ); + mineTeleportWarmUp.setMessageSuccess( + "&7You have been teleported out of the mine to prevent suffocating." ); + mineTeleportWarmUp.setMessageFailed( null ); + + PrisonTaskSubmitter.runTaskLater( mineTeleportWarmUp, 3 ); +// mine.teleportPlayerOut( player ); + } + // // // // To "move" the player out of the mine, they are elevated by one block above the surface diff --git a/prison-mines/src/main/java/tech/mcprison/prison/mines/commands/MinesBlockCommands.java b/prison-mines/src/main/java/tech/mcprison/prison/mines/commands/MinesBlockCommands.java index dd14006c9..f4ae83f64 100644 --- a/prison-mines/src/main/java/tech/mcprison/prison/mines/commands/MinesBlockCommands.java +++ b/prison-mines/src/main/java/tech/mcprison/prison/mines/commands/MinesBlockCommands.java @@ -161,8 +161,8 @@ protected BulletedListComponent getBlocksList( Mine m, CommandPagedData cmdPageD BulletedListComponent.BulletedListBuilder builder = new BulletedListComponent.BulletedListBuilder(); - DecimalFormat iFmt = new DecimalFormat( "#,##0" ); - DecimalFormat dFmt = new DecimalFormat( "#,##0.00" ); + DecimalFormat iFmt = Prison.get().getDecimalFormatInt(); + DecimalFormat dFmt = Prison.get().getDecimalFormat( "#,##0.00" ); double totalChance = 0.0d; int count = 0; @@ -658,8 +658,8 @@ public void listBlockCommand(CommandSender sender, return; } - DecimalFormat dFmt = new DecimalFormat("#,##0"); - DecimalFormat fFmt = new DecimalFormat("#,##0.00"); + DecimalFormat dFmt = Prison.get().getDecimalFormatInt(); + DecimalFormat fFmt = Prison.get().getDecimalFormat("#,##0.00"); ChatDisplay chatDisplay = new ChatDisplay("&bMine: &3" + m.getName()); diff --git a/prison-mines/src/main/java/tech/mcprison/prison/mines/commands/MinesCommands.java b/prison-mines/src/main/java/tech/mcprison/prison/mines/commands/MinesCommands.java index 7faefd31b..505fbcae0 100644 --- a/prison-mines/src/main/java/tech/mcprison/prison/mines/commands/MinesCommands.java +++ b/prison-mines/src/main/java/tech/mcprison/prison/mines/commands/MinesCommands.java @@ -128,8 +128,10 @@ public void addBlockCommand(CommandSender sender, @Override - @Command(identifier = "mines block set", permissions = "mines.block", onlyPlayers = false, - description = "Changes the percentage of a block in a mine.") + @Command(identifier = "mines block setChance", permissions = "mines.block", onlyPlayers = false, + description = "Changes the percent chance of a block spawning within in a mine. " + + "This chance is not cryptographically precise. The actual percentage will " + + "also vary based upon block constraints and other factors.") public void setBlockCommand(CommandSender sender, @Arg(name = "mineName", description = "The name of the mine to edit.") String mineName, @@ -152,7 +154,11 @@ public void delBlockCommand(CommandSender sender, } @Command(identifier = "mines block search", permissions = "mines.block", - description = "Searches for a block to add to a mine.") + description = "Searches for a block to add to a mine. " + + "This does not include items: see the command '/mines block searchAll'. " + + "These block and item names are based upon XSeries's XMaterial block names " + + "and are used to provide a uniform and consistant naming convention for " + + "all versions of minecraft & spigot.") public void searchBlockCommand(CommandSender sender, @Arg(name = "search", def = " ", description = "Any part of the block's name or ID.") String search, @@ -179,7 +185,7 @@ public void searchBlockAllCommand(CommandSender sender, @Override @Command(identifier = "mines block list", permissions = "mines.block", - description = "Searches for a block to add to a mine.") + description = "Lists all of the blocks assigned to a mine.") public void listBlockCommand(CommandSender sender, @Arg(name = "mineName", description = "The name of the mine to view.") String mineName ) { @@ -887,8 +893,8 @@ public void allMinesInfoDetails( StringBuilder sb ) { private ChatDisplay mineInfoDetails( CommandSender sender, boolean isMineStats, Mine m, CommandPagedData cmdPageData ) { - DecimalFormat dFmt = new DecimalFormat("#,##0"); - DecimalFormat fFmt = new DecimalFormat("#,##0.00"); + DecimalFormat dFmt = Prison.get().getDecimalFormatInt(); + DecimalFormat fFmt = Prison.get().getDecimalFormat("#,##0.00"); ChatDisplay chatDisplay = new ChatDisplay("&bMine: &3" + m.getName()); @@ -942,7 +948,7 @@ else if ( !mineAccessByRank && tpAccessByRank ) { if ( !mineAccessByRank ) { RowComponent row = new RowComponent(); - row.addTextComponent( "&3Mine Access Permission: &7%s &3(Should use Access by Rank)", + row.addTextComponent( "&3Mine Access Permission: &7%s &3(Consider using Access by Rank)", ( m.getAccessPermission() == null ? "&2none" : m.getAccessPermission() ) ); chatDisplay.addComponent( row ); } @@ -967,8 +973,7 @@ else if ( !mineAccessByRank && tpAccessByRank ) { } - if ( !m.isVirtual() ) { - } + if ( !m.isVirtual() ) { @@ -989,17 +994,11 @@ else if ( !mineAccessByRank && tpAccessByRank ) { String spawnPoint = m.getSpawn() != null ? m.getSpawn().toBlockCoordinates() : "&cnot set"; chatDisplay.addText("&3Spawnpoint: &7%s", spawnPoint); - if ( cmdPageData.isShowAll() || isMineStats ) { - RowComponent rowStats = new RowComponent(); - rowStats.addTextComponent( " -- &7 Stats :: " ); - rowStats.addTextComponent( m.statsMessage() ); - - chatDisplay.addComponent(rowStats); - } } + // chatDisplay.text("&3Size: &7%d&8x&7%d&8x&7%d", Math.round(m.getBounds().getWidth()), // Math.round(m.getBounds().getHeight()), Math.round(m.getBounds().getLength())); @@ -1055,34 +1054,37 @@ else if ( !mineAccessByRank && tpAccessByRank ) { else { RowComponent row = new RowComponent(); double rtMinutes = resetTime / 60.0D; - row.addTextComponent( "&3Reset time: &7%s &3Secs (&7%.2f &3Mins)", - Integer.toString(resetTime), rtMinutes ); - chatDisplay.addComponent( row ); - } - - { - RowComponent row = new RowComponent(); - row.addTextComponent( "&3Mine Reset Count: &7%s ", + row.addTextComponent( + "&3Reset time: &7%s &3Secs (&7%.2f &3Mins) Reset Count: &7%s ", + Integer.toString(resetTime), + rtMinutes, dFmt.format(m.getResetCount()) ); - -// if ( m.isUsePagingOnReset() ) { -// row.addTextComponent( " &7-= &5Reset Paging Enabled &7=-" ); -// } -// else if ( cmdPageData.isShowAll() ) { -// row.addTextComponent( " &7-= &3Reset Paging Disabled &7=-" ); -// } - chatDisplay.addComponent( row ); - -// double resetTimeSeconds = m.getStatsResetTimeMS() / 1000.0; -// if ( !m.isUsePagingOnReset() && resetTimeSeconds > 0.5 ) { -// String resetTimeSec = PlaceholdersUtil.formattedTime( resetTimeSeconds ); -// chatDisplay.addText("&5 Warning: &3Reset time is &7%s&3, which is high. " + -// "It is recommened that you try to enable &7/mines set resetPaging help", -// resetTimeSec ); -// } } +// { +// RowComponent row = new RowComponent(); +// row.addTextComponent( "&3Mine Reset Count: &7%s ", +// dFmt.format(m.getResetCount()) ); +// +//// if ( m.isUsePagingOnReset() ) { +//// row.addTextComponent( " &7-= &5Reset Paging Enabled &7=-" ); +//// } +//// else if ( cmdPageData.isShowAll() ) { +//// row.addTextComponent( " &7-= &3Reset Paging Disabled &7=-" ); +//// } +// +// chatDisplay.addComponent( row ); +// +//// double resetTimeSeconds = m.getStatsResetTimeMS() / 1000.0; +//// if ( !m.isUsePagingOnReset() && resetTimeSeconds > 0.5 ) { +//// String resetTimeSec = PlaceholdersUtil.formattedTime( resetTimeSeconds ); +//// chatDisplay.addText("&5 Warning: &3Reset time is &7%s&3, which is high. " + +//// "It is recommened that you try to enable &7/mines set resetPaging help", +//// resetTimeSec ); +//// } +// } + if ( !m.isVirtual() && resetTime > 0 ) { RowComponent row = new RowComponent(); @@ -1091,31 +1093,32 @@ else if ( !mineAccessByRank && tpAccessByRank ) { (targetResetTime - System.currentTimeMillis()) / 1000d); double rtMinutes = remaining / 60.0D; - row.addTextComponent( "&3Time Remaining Until Reset: &7%s &3Secs (&7%.2f &3Mins)", + row.addTextComponent( "&3Time Until Next Reset: &7%s &3Secs (&7%.2f &3Mins)", dFmt.format( remaining ), rtMinutes ); chatDisplay.addComponent( row ); } - if ( resetTime > 0 ) - { - RowComponent row = new RowComponent(); - row.addTextComponent( "&3Notification Mode: &7%s &7%s", - m.getNotificationMode().name(), - ( m.getNotificationMode() == MineNotificationMode.radius ? - dFmt.format( m.getNotificationRadius() ) + " blocks" : "" ) ); - chatDisplay.addComponent( row ); - } - if ( resetTime > 0 && m.isUseNotificationPermission() || - resetTime > 0 && !m.isUseNotificationPermission() && cmdPageData.isShowAll() ) { - RowComponent row = new RowComponent(); - row.addTextComponent( "&3Notifications Filtered by Permissions: %s", - ( m.isUseNotificationPermission() ? - m.getMineNotificationPermissionName() : "&dDisabled" ) ); - chatDisplay.addComponent( row ); - } + if ( !m.isVirtual() ) { + if ( m.getResetThresholdPercent() == 0 && cmdPageData.isShowAll() ) { + RowComponent row = new RowComponent(); + row.addTextComponent( "&3Reset Threshold: &cDISABLED"); + chatDisplay.addComponent( row ); + } + else if ( m.getResetThresholdPercent() > 0 ) { + RowComponent row = new RowComponent(); + + double blocks = m.getBounds().getTotalBlockCount() * + m.getResetThresholdPercent() / 100.0d; + row.addTextComponent( "&3Reset Threshold: &7%s &3Percent (&7%s &3blocks)", + fFmt.format( m.getResetThresholdPercent() ), + dFmt.format( blocks ) ); + chatDisplay.addComponent( row ); + } + + } @@ -1123,17 +1126,18 @@ else if ( !mineAccessByRank && tpAccessByRank ) { if ( m.isZeroBlockResetDisabled() && cmdPageData.isShowAll() ) { RowComponent row = new RowComponent(); - row.addTextComponent( "&3Zero Blocks Reset Delay: &cDISABLED"); + row.addTextComponent( "&3Reset Delay: &cDISABLED"); chatDisplay.addComponent( row ); } else if ( !m.isZeroBlockResetDisabled() ) { RowComponent row = new RowComponent(); if ( m.getResetThresholdPercent() == 0 ) { - row.addTextComponent( "&3Zero Blocks Reset Delay: &7%s &3Seconds", + row.addTextComponent( "&3Reset Delay (zero blocks): &7%s &3Seconds", fFmt.format( m.getZeroBlockResetDelaySec() )); } else { - row.addTextComponent( "&7Threshold &3Reset Delay: &7%s &3Seconds", + row.addTextComponent( "&3Reset Delay (&s Percent Threshold): &7%s &3Seconds", + fFmt.format( m.getResetThresholdPercent() ), fFmt.format( m.getZeroBlockResetDelaySec() )); } chatDisplay.addComponent( row ); @@ -1141,47 +1145,55 @@ else if ( !m.isZeroBlockResetDisabled() ) { } - - if ( !m.isVirtual() ) { - if ( m.getResetThresholdPercent() == 0 && cmdPageData.isShowAll() ) { - RowComponent row = new RowComponent(); - row.addTextComponent( "&3Reset Threshold: &cDISABLED"); - chatDisplay.addComponent( row ); - } - else if ( m.getResetThresholdPercent() > 0 ) { - RowComponent row = new RowComponent(); - - double blocks = m.getBounds().getTotalBlockCount() * - m.getResetThresholdPercent() / 100.0d; - row.addTextComponent( "&3Reset Threshold: &7%s &3Percent (&7%s &3blocks)", - fFmt.format( m.getResetThresholdPercent() ), - dFmt.format( blocks ) ); - chatDisplay.addComponent( row ); - } - - } + if ( resetTime > 0 && m.isSkipResetEnabled() ) { RowComponent row = new RowComponent(); - row.addTextComponent( "&3Skip Reset: &2Enabled&3: &3Threshold: &7%s &3Skip Limit: &7%s", - fFmt.format( m.getSkipResetPercent() ), dFmt.format( m.getSkipResetBypassLimit() )); + row.addTextComponent( + "&3Reset Skip: &2Enabled&3: &3Threshold: &7%s &3SkipLimit: &7%s &3SkipCount: &7%s", + fFmt.format( m.getSkipResetPercent() ), + dFmt.format( m.getSkipResetBypassLimit() ), + dFmt.format( m.getSkipResetBypassCount() ) ); chatDisplay.addComponent( row ); - if ( m.getSkipResetBypassCount() > 0 ) { - RowComponent row2 = new RowComponent(); - row2.addTextComponent( " &3Skipping Enabled: Skip Count: &7%s", - dFmt.format( m.getSkipResetBypassCount() )); - chatDisplay.addComponent( row2 ); - } +// if ( m.getSkipResetBypassCount() > 0 ) { +// RowComponent row2 = new RowComponent(); +// row2.addTextComponent( " &3Skipping Enabled: Skip Count: &7%s", +// dFmt.format( m.getSkipResetBypassCount() )); +// chatDisplay.addComponent( row2 ); +// } } else if ( resetTime > 0 && cmdPageData.isShowAll() ) { RowComponent row = new RowComponent(); - row.addTextComponent( "&3Skip Mine Reset if no Activity: &cnot set"); + row.addTextComponent( "&3Reset Skip if no Mining Activity: &cnot enabled"); + chatDisplay.addComponent( row ); + } + + + + if ( resetTime > 0 ) + { + RowComponent row = new RowComponent(); + row.addTextComponent( "&3Notification Mode: &7%s &7%s", + m.getNotificationMode().name(), + ( m.getNotificationMode() == MineNotificationMode.radius ? + dFmt.format( m.getNotificationRadius() ) + " blocks" : "" ) ); + chatDisplay.addComponent( row ); + } + + if ( resetTime > 0 && m.isUseNotificationPermission() || + resetTime > 0 && !m.isUseNotificationPermission() && cmdPageData.isShowAll() ) { + RowComponent row = new RowComponent(); + row.addTextComponent( "&3Notifications Filtered by Permissions: %s", + ( m.isUseNotificationPermission() ? + m.getMineNotificationPermissionName() : "&dDisabled" ) ); chatDisplay.addComponent( row ); } + + if ( m.isMineSweeperEnabled() ) { @@ -1215,6 +1227,43 @@ else if ( cmdPageData.isShowAll() ) { + + String statsMsg = m.statsMessage(); + if ( !m.isVirtual() && (cmdPageData.isShowAll() || isMineStats) && + statsMsg != null && statsMsg.length() > 0 ) { + + int idx = statsMsg.indexOf("BlockUpdateTime:"); + int idx2 = statsMsg.indexOf("ResetPages:", idx); + + String stats1 = statsMsg.substring(0, idx ); + String stats2 = statsMsg.substring( idx, idx2 ); + String stats3 = statsMsg.substring( idx2 ); + + { + RowComponent rowStats = new RowComponent(); + rowStats.addTextComponent( " -- &7 Reset Stats :: &3" ); + rowStats.addTextComponent( stats1 ); + chatDisplay.addComponent(rowStats); + } + { + RowComponent rowStats = new RowComponent(); + rowStats.addTextComponent( " -- &7 Reset Stats :: &3" ); + rowStats.addTextComponent( stats2 ); + chatDisplay.addComponent(rowStats); + } + { + RowComponent rowStats = new RowComponent(); + rowStats.addTextComponent( " -- &7 Reset Stats :: &3" ); + rowStats.addTextComponent( stats3 ); + chatDisplay.addComponent(rowStats); + } + + +// rowStats.addTextComponent( m.statsMessage() ); + } + + + if ( m.getResetCommands() != null && m.getResetCommands().size() > 0 ) { // RowComponent row = new RowComponent(); // row.addTextComponent( "&3Reset Commands: &7%s ", @@ -1461,8 +1510,8 @@ private BulletedListComponent getMinesLineItemList( PrisonSortableResults sorted new BulletedListComponent.BulletedListBuilder(); - DecimalFormat dFmt = new DecimalFormat("#,##0"); - DecimalFormat fFmt = new DecimalFormat("#,##0.00"); + DecimalFormat dFmt = Prison.get().getDecimalFormatInt(); + DecimalFormat fFmt = Prison.get().getDecimalFormat("#,##0.00"); int count = 0; @@ -1686,43 +1735,66 @@ private BulletedListComponent getMinesLineItemList( PrisonSortableResults sorted } /** - *

The following command will change the mine's time between resets. But it will - * not be applied until after the next reset. + *

The following command will skip the mines normally scheduled reset. *

* * @param sender * @param mineName * @param time */ - @Command(identifier = "mines set skipReset", permissions = "mines.skipreset", - description = "Set a mine to skip the reset if not enough blocks have been mined.") + @Command(identifier = "mines set resetSkip", permissions = "mines.set", + description = "Set a mine to skip the reset if not enough blocks have been mined. " + + "The threshold value should be higher than the resetThreshold. If the " + + "percent remaining is higher than the resetSkip threshold, then Prison will" + + "skip the current reset. After skipping the reset 'bypassLimit' number of times, " + + "then prison will reset the mine to return it to a clean state. " + + "The reset skipping is not influenced by the 'resetThreshold' or the 'resetDelay', " + + "but all of them are related to fine tuning a mine's behavior. " + + "Also see '/mines set resetThreshold help' and " + + "'/mines set resetDelay'.") public void skipResetCommand(CommandSender sender, - @Arg(name = "mineName", description = "The name of the mine to edit.") String mineName, - @Arg(name = "enabled", description = "Enable the skip reset processing: 'Enabled' or 'Disable'", + @Arg(name = "mineName", description = "The mine name to edit, " + + "or '*all*' to apply to all mines.") String mineName, + @Arg(name = "enabled", description = "Enable the skip reset processing: 'Enabled' or 'Disabled' " + + "[enable, enabled, disable, disabled]", def = "disabled") String enabled, - @Arg(name = "percent", description = "Percent threshold before resetting.", def = "80" ) String percent, - @Arg(name = "bypassLimit", description = "Limit number of skips before bypassing and performing a reset", - def = "50") String bypassLimit + @Arg(name = "percent", description = "If percent remaining in the mine is higher than " + + "this threshold percentage, then the reset will be skipped.", def = "80" ) String percent, + @Arg(name = "bypassLimit", description = "Max number of resets that are bypassed before forcing a reset", + def = "10") String bypassLimit ) { - if (performCheckMineExists(sender, mineName)) { - setLastMineReferenced(mineName); + if ( "*all*".equalsIgnoreCase( mineName ) || + performCheckMineExists(sender, mineName) + ) { + + if ( !"*all*".equalsIgnoreCase( mineName ) ) { + + setLastMineReferenced(mineName); + } - if ( enabled == null || !"enabled".equalsIgnoreCase( enabled ) && !"disabled".equalsIgnoreCase( enabled )) { - Output.get().sendWarn( sender,"&7Invalid &benabled&7 value. Must be either &benabled&7 or " + - "&bdisabled&7. Was &b%s&7.", (enabled == null ? "&c-blank-" : enabled) ); + if ( enabled == null || ! + !"enabled".equalsIgnoreCase( enabled ) && + !"enable".equalsIgnoreCase( enabled ) && + !"disabled".equalsIgnoreCase( enabled ) && + !"disable".equalsIgnoreCase( enabled ) + ) { + + Output.get().sendWarn( sender,"&7Invalid &benabled&7 value. Must be [" + + "&benable&7, &benabled&7, &bdisable&7, &bdisabled&7]. " + + "Was &b%s&7.", (enabled == null ? "&c-blank-" : enabled) ); return; } PrisonMines pMines = PrisonMines.getInstance(); - Mine m = pMines.getMine(mineName); + // if ( !m.isEnabled() ) { // sender.sendMessage( "&cMine is disabled&7. Use &a/mines info &7for possible cause." ); // return; // } - boolean skipEnabled = "enabled".equalsIgnoreCase( enabled ); + boolean skipEnabled = "enabled".equalsIgnoreCase( enabled ) || "enable".equalsIgnoreCase( enabled ); double skipPercent = 80.0d; int skipBypassLimit = 50; @@ -1751,17 +1823,42 @@ public void skipResetCommand(CommandSender sender, "Was &b%s&7.", (bypassLimit == null ? "-blank-" : bypassLimit) ); } - m.setSkipResetEnabled( skipEnabled ); - m.setSkipResetPercent( skipPercent ); - m.setSkipResetBypassLimit( skipBypassLimit ); + int updates = 0; + String mName = "&7*all*&r"; + + if ( "*all*".equalsIgnoreCase(mineName) ) { + + for ( Mine m : pMines.getMines() ) { + + m.setSkipResetEnabled( skipEnabled ); + m.setSkipResetPercent( skipPercent ); + m.setSkipResetBypassLimit( skipBypassLimit ); + + pMines.getMineManager().saveMine( m ); + updates++; + } + } + else { + + Mine m = pMines.getMine(mineName); + m.setSkipResetEnabled( skipEnabled ); + m.setSkipResetPercent( skipPercent ); + m.setSkipResetBypassLimit( skipBypassLimit ); + + mName = m.getTag(); + + pMines.getMineManager().saveMine( m ); + updates++; + } - pMines.getMineManager().saveMine( m ); // User's message: String message = String.format( "&7mines skipreset for &b%s&7: &b%s&7 " + - "threshold: &b%.2f&7 percent bypassLimit: &b%d", - m.getTag(), (skipEnabled ? "enabled" : "disabled"), - skipPercent, skipBypassLimit ); + "threshold: &b%.2f&7 percent bypassLimit: &b%d " + + "Mines Updated: %d", + mName, (skipEnabled ? "enabled" : "disabled"), + skipPercent, skipBypassLimit, + updates ); Output.get().sendInfo( sender, message ); // Server Log message: @@ -1782,23 +1879,84 @@ public void skipResetCommand(CommandSender sender, * @param mineName * @param time */ - @Command(identifier = "mines set resetTime", permissions = "mines.resettime", + @Command(identifier = "mines set resetTime", permissions = "mines.set", description = "Set a mine's auto reset time as expressed in seconds.") public void resetTimeCommand(CommandSender sender, @Arg(name = "mineName", description = "The name of the mine to edit.") String mineName, @Arg(name = "time", description = "Time in seconds for the mine to auto reset. " + "With a minimum value of "+ MineData.MINE_RESET__TIME_SEC__MINIMUM + " seconds. " + - "Using 'disable' will turn off the auto reset." ) String time + "Using '*disable*' will turn off the auto reset. Use of " + + "*default* will set the time to " + + MineData.MINE_RESET__TIME_SEC__DEFAULT + " seconds. " + + "[*default* *disable*]" ) String time ) { + + int resetTime = MineData.MINE_RESET__TIME_SEC__DEFAULT; + + PrisonMines pMines = PrisonMines.getInstance(); + if ( "*disable*".equalsIgnoreCase( time ) ) { + resetTime = -1; + } + else if ( "*default*".equalsIgnoreCase( time ) ) { + // use the default time + } + else { + try { + if ( time != null && time.trim().length() > 0 ) { + resetTime = Integer.parseInt( time ); + } + } + catch ( NumberFormatException e ) { + Output.get().sendWarn( sender, + "&7Invalid resetTime value for &b%s&7. Must be an integer value of &b%d &7or greater. [&b%s&7]", + mineName, MineData.MINE_RESET__TIME_SEC__MINIMUM, time ); + return; + } + } + if ( resetTime < MineData.MINE_RESET__TIME_SEC__MINIMUM ) { + Output.get().sendWarn( sender, + "&7Invalid resetTime value for &b%s&7. Must be an integer value of &b%d&7 or greater. [&b%d&7]", + mineName, MineData.MINE_RESET__TIME_SEC__MINIMUM, resetTime ); + return; + } + + if ( "*all*".equalsIgnoreCase( mineName ) ) { + + for ( Mine mine : pMines.getMines() ) { + if ( mine.getResetTime() != resetTime ) { + + mine.setResetTime( resetTime ); + + pMines.getMineManager().saveMine( mine ); + + if ( resetTime == -1 ) { + + Output.get().logInfo( "&7Automatic resets have been disabled for mine %s.", mine.getTag() ); + } + else { + // User's message: + Output.get().sendInfo( sender, "&7mines set resettime: &b%s &7resetTime set to &b%d", + mine.getTag(), resetTime ); + + // Server Log message: + Player player = getPlayer( sender ); + Output.get().logInfo( "&bmines set resettime&7: &b%s &7set &b%s &7resetTime to &b%d", + (player == null ? "console" : player.getDisplayName()), mine.getTag(), resetTime ); + } + } + } + + return; + } + if (performCheckMineExists(sender, mineName)) { setLastMineReferenced(mineName); - PrisonMines pMines = PrisonMines.getInstance(); Mine m = pMines.getMine(mineName); - if ( "disable".equalsIgnoreCase( time ) ) { + if ( "*disable*".equalsIgnoreCase( time ) ) { m.setResetTime( -1 ); @@ -1809,41 +1967,31 @@ public void resetTimeCommand(CommandSender sender, return; } - try { - int resetTime = MineData.MINE_RESET__TIME_SEC__DEFAULT; - - if ( time != null && time.trim().length() > 0 ) { - resetTime = Integer.parseInt( time ); - } - - if ( resetTime < MineData.MINE_RESET__TIME_SEC__MINIMUM ) { - Output.get().sendWarn( sender, - "&7Invalid resetTime value for &b%s&7. Must be an integer value of &b%d&7 or greater. [&b%d&7]", - mineName, MineData.MINE_RESET__TIME_SEC__MINIMUM, resetTime ); - } else { + +// if ( resetTime < MineData.MINE_RESET__TIME_SEC__MINIMUM ) { +// Output.get().sendWarn( sender, +// "&7Invalid resetTime value for &b%s&7. Must be an integer value of &b%d&7 or greater. [&b%d&7]", +// mineName, MineData.MINE_RESET__TIME_SEC__MINIMUM, resetTime ); +// } else + { // if ( !m.isEnabled() ) { // sender.sendMessage( "&cMine is disabled&7. Use &a/mines info &7for possible cause." ); // return; // } - - m.setResetTime( resetTime ); - - pMines.getMineManager().saveMine( m ); - - // User's message: - Output.get().sendInfo( sender, "&7mines set resettime: &b%s &7resetTime set to &b%d", m.getTag(), resetTime ); - - // Server Log message: - Player player = getPlayer( sender ); - Output.get().logInfo( "&bmines set resettime&7: &b%s &7set &b%s &7resetTime to &b%d", - (player == null ? "console" : player.getDisplayName()), m.getTag(), resetTime ); - } - } - catch ( NumberFormatException e ) { - Output.get().sendWarn( sender, - "&7Invalid resetTime value for &b%s&7. Must be an integer value of &b%d &7or greater. [&b%s&7]", - mineName, MineData.MINE_RESET__TIME_SEC__MINIMUM, time ); - } + + m.setResetTime( resetTime ); + + pMines.getMineManager().saveMine( m ); + + // User's message: + Output.get().sendInfo( sender, "&7mines set resettime: &b%s &7resetTime set to &b%d", m.getTag(), resetTime ); + + // Server Log message: + Player player = getPlayer( sender ); + Output.get().logInfo( "&bmines set resettime&7: &b%s &7set &b%s &7resetTime to &b%d", + (player == null ? "console" : player.getDisplayName()), m.getTag(), resetTime ); + } + } } @@ -1865,7 +2013,7 @@ public void resetTimeCommand(CommandSender sender, * @param mineName * @param time */ - @Command(identifier = "mines set zeroBlockResetDelay", permissions = "mines.zeroblockresetdelay", + @Command(identifier = "mines set resetDelay", permissions = "mines.set", description = "Set a mine's delay before reset when it reaches zero blocks.") public void zeroBlockResetDelayCommand(CommandSender sender, @Arg(name = "mineName", description = "The name of the mine to edit.") String mineName, @@ -1906,7 +2054,7 @@ public void zeroBlockResetDelayCommand(CommandSender sender, pMines.getMineManager().saveMine( m ); - DecimalFormat dFmt = new DecimalFormat("#,##0.00"); + DecimalFormat dFmt = Prison.get().getDecimalFormat("#,##0.00"); // User's message: if ( m.isZeroBlockResetDisabled() ) { Output.get().sendInfo( sender, "&7Mine &b%s Zero Block Reset Delay: &cDISABLED", @@ -1944,7 +2092,7 @@ public void zeroBlockResetDelayCommand(CommandSender sender, * @param mineName * @param time */ - @Command(identifier = "mines set resetThreshold", permissions = "mines.resetThreshold", + @Command(identifier = "mines set resetThreshold", permissions = "mines.set", description = "Triggers a mine reset once this threshold is crossed and the remaining " + "block percentage is less than or equal to this value") public void resetThresholdPercentCommand(CommandSender sender, @@ -1995,8 +2143,8 @@ public void resetThresholdPercentCommand(CommandSender sender, m.getBounds().getTotalBlockCount() * m.getResetThresholdPercent() / 100.0d; - DecimalFormat dFmt = new DecimalFormat("#,##0"); - DecimalFormat fFmt = new DecimalFormat("#,##0.00"); + DecimalFormat dFmt = Prison.get().getDecimalFormatInt(); + DecimalFormat fFmt = Prison.get().getDecimalFormat("#,##0.00"); // User's message: String message = String.format( "&7The Reset Threshold Percent for mine &b%s&7 was set to &b%s&7, " + @@ -2015,11 +2163,13 @@ public void resetThresholdPercentCommand(CommandSender sender, - @Command(identifier = "mines set notification", permissions = "mines.notification", + @Command(identifier = "mines set notification", permissions = "mines.set", description = "Set a mine's notification mode.") public void setNotificationCommand(CommandSender sender, - @Arg(name = "mineName", description = "The name of the mine to edit.") String mineName, - @Arg(name = "mode", def="displayOptions", description = "The notification mode to use: disabled, within, radius") + @Arg(name = "mineName", description = "The name of the mine to edit, or '*all*' to " + + "apply to all mines. [*all*]") String mineName, + @Arg(name = "mode", def="displayOptions", description = "The notification mode " + + "to use: [disabled within radius]") String mode, @Arg(name = "radius", def="0", description = "The distance from the center of the mine to notify players of a reset." ) String radius @@ -2045,7 +2195,7 @@ public void setNotificationCommand(CommandSender sender, if ( noteRadius < 1 ) { noteRadius = MineData.MINE_RESET__BROADCAST_RADIUS_BLOCKS; - DecimalFormat dFmt = new DecimalFormat("#,##0"); + DecimalFormat dFmt = Prison.get().getDecimalFormatInt(); Output.get().sendWarn( sender, "&7Invalid radius value. " + "Must be an positive non-zero integer. Using the default value: &b%s &7[&b%s&7]", dFmt.format(MineData.MINE_RESET__BROADCAST_RADIUS_BLOCKS), radius ); @@ -2107,7 +2257,7 @@ private boolean changeMineNotification( CommandSender sender, String mineName, pMines.getMineManager().saveMine( m ); success = true; - DecimalFormat dFmt = new DecimalFormat("#,##0"); + DecimalFormat dFmt = Prison.get().getDecimalFormatInt(); // message: notification mode changed Output.get().sendInfo( sender, "&7Notification mode was changed for &b%s&7: &b%s %s", mineName, m.getNotificationMode().name(), @@ -2123,7 +2273,7 @@ private boolean changeMineNotification( CommandSender sender, String mineName, } - @Command(identifier = "mines set notificationPerm", permissions = "mines.notification", + @Command(identifier = "mines set notificationPerm", permissions = "mines.set", description = "Enable or disable a mine's notification permission. If enabled, then players " + "must have the mine's permission to get messages for reset. This filter " + "can be combined with the other notification settings.", @@ -2233,17 +2383,53 @@ public void setMinePermissionCommand(CommandSender sender, @Command(identifier = "mines set rank", permissions = "mines.set", description = "Links a mine to a rank or removes the rank.") public void setMineRankCommand(CommandSender sender, - @Arg(name = "mineName", description = "The name of the mine.") String mineName, - @Arg(name = "rankName", description = "Then rank name to link to this mine. " + - "Use 'none' to remove the rank.") + @Arg(name = "mineName", description = "The name of the mine, or '*all*' for all mines.") String mineName, + @Arg(name = "rankName", def="*mine*", description = "Then rank name to link to this mine. " + + "Use '*none*' to remove the rank. If using '*all*' for mine name, then rank name defaults to " + + "*mineName* and will try to set the given rank name to the mine name. This is an " + + "automatic assignment when '*all*' is used for the mine name. If a rank name does " + + "not exist that matches the mine name, then it will be skipped. [*none* *mineName*]") String rankName ) { + + PrisonMines pMines = PrisonMines.getInstance(); + + if ( mineName != null && "*all*".equalsIgnoreCase( mineName ) ) { + + for ( Mine mine : pMines.getMines() ) { + if ( "*none*".equalsIgnoreCase( rankName ) && mine.getRank() != null ) { + // First unlink the preexisting mine and rank: + String removedRankName = mine.getRank().getName(); + + // unlinkModuleElement will do the saving + Prison.get().getPlatform().unlinkModuleElements( mine, mine.getRank() ); + + sender.sendMessage( String.format( "&3Rank &7%s &3has been removed from mine &7%s", + removedRankName, mine.getTag() )); + } + else if ( "*mineName*".equalsIgnoreCase( rankName ) ) { + + boolean success = Prison.get().getPlatform().linkModuleElements( mine, + ModuleElementType.RANK, mine.getName() ); + + if ( !success ) { + sender.sendMessage( String.format( + "&3Invalid Rank Name for mine %s: &7%s", mine.getName(), mine.getName() )); + } + else { + sender.sendMessage( String.format( "&3Rank &7%s &3has been linked to mine &7%s", + rankName, mine.getTag() )); + } + } + } + + return; + } if (performCheckMineExists(sender, mineName)) { setLastMineReferenced(mineName); - PrisonMines pMines = PrisonMines.getInstance(); Mine m = pMines.getMine(mineName); @@ -2265,7 +2451,7 @@ public void setMineRankCommand(CommandSender sender, } - if ( !"none".equalsIgnoreCase( rankName ) ) { + if ( !"*none*".equalsIgnoreCase( rankName ) ) { boolean success = Prison.get().getPlatform().linkModuleElements( m, ModuleElementType.RANK, rankName ); @@ -2404,10 +2590,15 @@ else if ( source == null || "virtual".equalsIgnoreCase( source ) ) { return; } + // Setting bounds to null will also set spawn to null, the two world fields to null, and + // make the mine virtual and disale the mine too: m.setBounds( null ); - m.setSpawn( null ); - - m.setVirtual( true ); +// m.setSpawn( null ); +// +// m.setWorld( null ); +// m.setWorldName( null ); +// +// m.setVirtual( true ); m.getJobStack().clear(); @@ -2435,9 +2626,18 @@ else if ( source == null || "virtual".equalsIgnoreCase( source ) ) { return; } - DecimalFormat dFmt = new DecimalFormat("#,##0"); + DecimalFormat dFmt = Prison.get().getDecimalFormatInt(); Bounds selectedBounds = selection.asBounds(); + if ( Output.get().isDebug() ) { + String msg = String.format( "MinesSetArea Preset: Mine: %s Bounds: %s - %s ", + m.getName(), + selectedBounds.getMin().toWorldCoordinates(), + selectedBounds.getMax().toWorldCoordinates() + ); + Output.get().logInfo( msg ); + } + if ( selectedBounds.getTotalBlockCount() > 50000 && (options == null || !options.toLowerCase().contains( "confirm" ) && !options.toLowerCase().contains( "yes" )) ) { @@ -2459,10 +2659,22 @@ else if ( options.toLowerCase().contains( "confirm" ) || boolean wasVirtual = m.isVirtual(); - // Setting the bounds when it's virtual will configure all the internals: + + // Before setting the bounds, clear everything by setting them to nulls: + // Setting bounds to null will also set spawn to null, the two world fields to null, and + // make the mine virtual and disable the mine too: + m.setBounds( null ); + + m.getJobStack().clear(); + + + // Setting the bounds when it's virtual will configure all the internals: m.setBounds(selectedBounds); + + + if ( wasVirtual ) { @@ -2484,44 +2696,47 @@ else if ( options.toLowerCase().contains( "confirm" ) || //pMines.getMineManager().clearCache(); // adjustSize to zero to reset set all liners: - m.adjustSize( Edges.walls, 0 ); - - if ( options.length() > 0 ) { - String[] opts = options.split( " " ); + if ( m.getLinerData() != null ) { - // Try to set the size of the wall: Increase by: - if ( opts.length > 0 ) { - try { - int size = Integer.parseInt( opts[0] ); - setSizeCommand( sender, mineName, "walls", size ); - } - catch ( Exception e ) { - // ignore error - } - } + m.adjustSize( Edges.walls, 0 ); - // Try to set the size of the bottom: Increase by: - if ( opts.length > 1 ) { - try { - int size = Integer.parseInt( opts[1] ); - setSizeCommand( sender, mineName, "bottom", size ); - } - catch ( Exception e ) { - // ignore error + if ( options.length() > 0 ) { + String[] opts = options.split( " " ); + + // Try to set the size of the wall: Increase by: + if ( opts.length > 0 ) { + try { + int size = Integer.parseInt( opts[0] ); + setSizeCommand( sender, mineName, "walls", size ); + } + catch ( Exception e ) { + // ignore error + } } - } - - // Try to set the size of the wall: Increase by: - if ( opts.length > 2 ) { - try { - int size = Integer.parseInt( opts[2] ); - setSizeCommand( sender, mineName, "top", size ); + + // Try to set the size of the bottom: Increase by: + if ( opts.length > 1 ) { + try { + int size = Integer.parseInt( opts[1] ); + setSizeCommand( sender, mineName, "bottom", size ); + } + catch ( Exception e ) { + // ignore error + } } - catch ( Exception e ) { - // ignore error + + // Try to set the size of the wall: Increase by: + if ( opts.length > 2 ) { + try { + int size = Integer.parseInt( opts[2] ); + setSizeCommand( sender, mineName, "top", size ); + } + catch ( Exception e ) { + // ignore error + } } + } - } } @@ -2844,24 +3059,44 @@ else if ( linerPattern == LinerPatterns.remove ) { "the submission delay will be. Enable '/mines stats' to monitor run time of " + "the sweep, then use '/mines info' to view them.") public void setMineSweeperCommand(CommandSender sender, - @Arg(name = "mineName", description = "The name of the mine to edit.") String mineName, + @Arg(name = "mineName", description = "The name of the mine to edit, or '*all*' to " + + "apply the change to all mines. [*all*]") String mineName, @Arg(name = "mineSweeper", def="disabled", description = "Enable or disable the mineSweeper tasks [disable, enable]") String mineSweeper ) { + + if ( mineSweeper == null || !"disable".equalsIgnoreCase( mineSweeper ) && + !"enable".equalsIgnoreCase( mineSweeper ) ) { + sender.sendMessage( "&cInvalid paging option&7. Use &adisable&7 or &aenable&7" ); + return; + } + + PrisonMines pMines = PrisonMines.getInstance(); + + if ( mineName != null && "*all*".equalsIgnoreCase( mineName ) ) { + + for ( Mine mine : pMines.getMines() ) { + if ( "disable".equalsIgnoreCase( mineSweeper ) && mine.isMineSweeperEnabled() ) { + mine.setMineSweeperEnabled( false ); + pMines.getMineManager().saveMine( mine ); + sender.sendMessage( String.format( "&7Mine Sweeper has been disabled for mine %s.", mine.getTag()) ); + } + else if ( "enable".equalsIgnoreCase( mineSweeper ) && !mine.isMineSweeperEnabled() ) { + mine.setMineSweeperEnabled( true ); + pMines.getMineManager().saveMine( mine ); + sender.sendMessage( String.format( "&7Mine Sweeper has been enabled for mine %s.", mine.getTag()) ); + } + } + + return; + } if (performCheckMineExists(sender, mineName)) { setLastMineReferenced(mineName); - PrisonMines pMines = PrisonMines.getInstance(); Mine m = pMines.getMine(mineName); - if ( mineSweeper == null || !"disable".equalsIgnoreCase( mineSweeper ) && - !"enable".equalsIgnoreCase( mineSweeper ) ) { - sender.sendMessage( "&cInvalid paging option&7. Use &adisable&7 or &aenable&7" ); - return; - } - if ( "disable".equalsIgnoreCase( mineSweeper ) && m.isMineSweeperEnabled() ) { m.setMineSweeperEnabled( false ); pMines.getMineManager().saveMine( m ); @@ -3194,7 +3429,7 @@ else if ( !mine.isVirtual() && mine.getBounds().within( player.getLocation(), if ( lookingAtMine != null ) { double distance = lookingAtMine.getBounds().getDistance3d( player.getLocation() ); - DecimalFormat dFmt = new DecimalFormat("#,##0.0"); + DecimalFormat dFmt = Prison.get().getDecimalFormat("#,##0.0"); sender.sendMessage( String.format( "&3You are looking at mine &7%s &3which is &7%s &3blocks away.", lookingAtMine.getTag(), dFmt.format( distance ) ) ); } @@ -3302,7 +3537,7 @@ private void generateBlockEventListing( Mine m, ChatDisplay display, boolean inc BulletedListComponent.BulletedListBuilder builder = new BulletedListComponent.BulletedListBuilder(); - DecimalFormat dFmt = new DecimalFormat("0.00000"); + DecimalFormat dFmt = Prison.get().getDecimalFormat("0.00000"); int rowNumber = 0; for (MineBlockEvent blockEvent : m.getBlockEvents()) { @@ -3724,7 +3959,7 @@ public void blockEventPercent(CommandSender sender, // Save the mine: pMines.getMineManager().saveMine( m ); - DecimalFormat dFmt = new DecimalFormat("0.00000"); + DecimalFormat dFmt = Prison.get().getDecimalFormat("0.00000"); Output.get().sendInfo(sender, "&7BlockEvent percentage &b%s&7 was changed for mine '&b%s&7'. " + "Was &b%s&7. Command '&b%s&7'", dFmt.format( chance ), m.getTag(), @@ -4268,7 +4503,7 @@ public void blockEventBlockAdd(CommandSender sender, display.addText("&8Select a block from this mine by using the block's row number:"); display.addText("&8 " + commandBlockEvent + " [rowBlockName]"); - DecimalFormat dFmt = new DecimalFormat("0.00000"); + DecimalFormat dFmt = Prison.get().getDecimalFormat("0.00000"); // Display a list of blocks for the mine: int blockRow = 0; @@ -4430,7 +4665,7 @@ public void blockEventBlockRemove(CommandSender sender, display.addText("&8Select a block filter from this mine by using the block's row number:"); display.addText("&8 " + commandBlockEvent + " [rowBlockName]"); -// DecimalFormat dFmt = new DecimalFormat("0.00000"); +// DecimalFormat dFmt = Prison.get().getDecimalFormat("0.00000"); // Display a list of blocks for the mine: int blockRow = 0; @@ -4532,7 +4767,7 @@ public void blockEventBlockRemove(CommandSender sender, @Command(identifier = "mines command list", description = "Lists the commands for a mine.", - onlyPlayers = false, permissions = "mines.command") + onlyPlayers = false, permissions = "mines.set") public void commandList(CommandSender sender, @Arg(name = "mineName") String mineName) { @@ -4599,7 +4834,7 @@ private ChatDisplay minesCommandList( Mine m ) @Command(identifier = "mines command remove", description = "Removes a command from a mine.", - onlyPlayers = false, permissions = "mines.command") + onlyPlayers = false, permissions = "mines.set") public void commandRemove(CommandSender sender, @Arg(name = "mineName") String mineName, @Arg(name = "row", @@ -4665,7 +4900,7 @@ public void commandRemove(CommandSender sender, } @Command(identifier = "mines command add", description = "Adds a command to a mine with NO placeholders.", - onlyPlayers = false, permissions = "mines.command") + onlyPlayers = false, permissions = "mines.set") public void commandAdd(CommandSender sender, @Arg(name = "mineName", description = "mine name, or 'placeholders' for a list of possible placeholders that " + "you can use with blockEvents") String mineName, diff --git a/prison-mines/src/main/java/tech/mcprison/prison/mines/data/MineData.java b/prison-mines/src/main/java/tech/mcprison/prison/mines/data/MineData.java index 249892b60..9fddfe96a 100644 --- a/prison-mines/src/main/java/tech/mcprison/prison/mines/data/MineData.java +++ b/prison-mines/src/main/java/tech/mcprison/prison/mines/data/MineData.java @@ -164,6 +164,7 @@ public abstract class MineData public enum MineNotificationMode { disabled, + disable, within, radius, @@ -184,6 +185,10 @@ public static MineNotificationMode fromString(String mode, MineNotificationMode } } + if ( results == disable ) { + results = disabled; + } + return results; } } @@ -405,8 +410,16 @@ public Bounds getBounds() { *

(Re)defines the boundaries for this mine. *

* + *

If the bounds is null, then need to clear both world fields, set to a + * virtual mine, and then disable the mine. Failure to clean this up by changing + * these fields actually will lock the mine in to a specific world and would not + * allow it to be moved to another world. If bounds is set to null, then + * spawn is also set to null because a virtual mine cannot have a spawn location. + *

+ * *

This function used to set the world name every time the bounds would - * change. The world name MUST NEVER be changed. If world is null then it will screw + * change. The world name MUST NEVER be changed, unless bounds is null. + * If world is null then it will screw * up the original location of when the was created. World name is set * in the document loader under Mine.loadFromDocument as the first field * that is set when restoring from the file. @@ -417,9 +430,20 @@ public Bounds getBounds() { public void setBounds(Bounds bounds) { this.bounds = bounds; - if ( bounds != null && ( isVirtual() || !getWorld().isPresent() || + // if Bounds is null, then clear out the world fields and set mine to virtual and disable the mine: + if ( bounds == null ) { + + setSpawn( null ); + + setWorld( null ); + setWorldName( null ); + setVirtual( true ); + setEnabled( false ); + } + + else if ( isVirtual() || !getWorld().isPresent() || getWorldName() == null || getWorldName().trim().length() == 0 || - getWorldName().equalsIgnoreCase( "Virtually-Undefined" )) ) { + getWorldName().equalsIgnoreCase( "Virtually-Undefined" ) ) { World world = bounds.getMin().getWorld(); @@ -442,7 +466,7 @@ public void setBounds(Bounds bounds) { } // The world name MUST NEVER be changed. If world is null then it will screw - // up the original location of when the was created. World name is set + // up the original location of when the mine was created. World name is set // in the document loader under Mine.loadFromDocument as the first field // that is set when restoring from the file. //this.worldName = bounds.getMin().getWorld().getName(); diff --git a/prison-mines/src/main/java/tech/mcprison/prison/mines/data/MineReset.java b/prison-mines/src/main/java/tech/mcprison/prison/mines/data/MineReset.java index 04fc997af..214b745f6 100644 --- a/prison-mines/src/main/java/tech/mcprison/prison/mines/data/MineReset.java +++ b/prison-mines/src/main/java/tech/mcprison/prison/mines/data/MineReset.java @@ -197,7 +197,7 @@ protected void initialize() { // // // Tie to the command stats mode so it logs it if stats are enabled: // if ( PrisonMines.getInstance().getMineManager().isMineStats() ) { -// DecimalFormat dFmt = new DecimalFormat("#,##0"); +// DecimalFormat dFmt = Prison.get().getDecimalFormatInt(); // Output.get().logInfo("&cMine reset: &7" + getTag() + // "&c Blocks: &7" + dFmt.format( getBounds().getTotalBlockCount() ) + // statsMessage() ); @@ -340,8 +340,8 @@ protected void initialize() { public String statsMessage() { StringBuilder sb = new StringBuilder(); - DecimalFormat dFmt = new DecimalFormat("#,##0.000"); - DecimalFormat iFmt = new DecimalFormat("#,##0"); + DecimalFormat dFmt = Prison.get().getDecimalFormatDouble(); + DecimalFormat iFmt = Prison.get().getDecimalFormatInt(); sb.append( "&3 ResetTime: &7" ); sb.append( dFmt.format(getStatsResetTimeMS() / 1000.0d )).append( " s " ); @@ -819,7 +819,7 @@ public void generateBlockListAsync() { //// // Tie to the command stats mode so it logs it if stats are enabled: //// if ( PrisonMines.getInstance().getMineManager().isMineStats() || //// getCurrentJob().getResetActions().contains( MineResetActions.DETAILS ) ) { -//// DecimalFormat dFmt = new DecimalFormat("#,##0"); +//// DecimalFormat dFmt = Prison.get().getDecimalFormatInt(); //// Output.get().logInfo("&cMine reset: &7" + getTag() + //// "&c Blocks: &7" + dFmt.format( getBounds().getTotalBlockCount() ) + //// statsMessage() ); @@ -893,8 +893,12 @@ public void asynchronouslyResetFinalize( List jobResetActions // such as could happen if there is lag or a lot going on within the server, // this will TP anyone out who would otherwise suffocate. I hope! lol - MineTeleportTask teleportTask = new MineTeleportTask( (Mine) this ); - teleportTask.submitTaskSync(); + + if ( Prison.get().getPlatform().getConfigBooleanTrue( "prison-mines.tp-to-spawn-on-mine-resets" ) ) { + MineTeleportTask teleportTask = new MineTeleportTask( (Mine) this ); + teleportTask.submitTaskSync(); + } + // teleportAllPlayersOut(); // setStatsTeleport2TimeMS( @@ -946,7 +950,7 @@ public void asynchronouslyResetFinalize( List jobResetActions // Tie to the command stats mode so it logs it if stats are enabled: if ( PrisonMines.getInstance().getMineManager().isMineStats() || getCurrentJob().getResetActions().contains( MineResetActions.DETAILS ) ) { - DecimalFormat dFmt = new DecimalFormat("#,##0"); + DecimalFormat dFmt = Prison.get().getDecimalFormatInt(); Output.get().logInfo("&cMine reset: &7" + getTag() + "&c Blocks: &7" + dFmt.format( getBounds().getTotalBlockCount() ) + statsMessage() ); @@ -986,8 +990,12 @@ public boolean resetAsynchonouslyInitiate( MineResetType resetType ) { canceled = event.isCanceled(); if (!canceled) { - MineTeleportTask teleportTask = new MineTeleportTask( (Mine) this ); - teleportTask.submitTaskSync(); + + if ( Prison.get().getPlatform().getConfigBooleanTrue( "prison-mines.tp-to-spawn-on-mine-resets" ) ) { + MineTeleportTask teleportTask = new MineTeleportTask( (Mine) this ); + teleportTask.submitTaskSync(); + } + // try { // teleportAllPlayersOut(); //// setStatsTeleport1TimeMS( @@ -1343,7 +1351,9 @@ public void refreshAirCountSyncTaskSetLocation( Location targetBlock, try { // Location targetBlock = new Location(world, x, y, z); - boolean containsCustomBlocks = getPrisonBlockTypes().contains( PrisonBlockType.CustomItems ); + boolean containsCustomBlocks = + getPrisonBlockTypes().contains( PrisonBlockType.CustomItems ) || + getPrisonBlockTypes().contains( PrisonBlockType.ItemsAdder ); Block tBlock = targetBlock.getBlockAt( containsCustomBlocks ); diff --git a/prison-mines/src/main/java/tech/mcprison/prison/mines/data/MineScheduler.java b/prison-mines/src/main/java/tech/mcprison/prison/mines/data/MineScheduler.java index 8ded47dfa..cf68899db 100644 --- a/prison-mines/src/main/java/tech/mcprison/prison/mines/data/MineScheduler.java +++ b/prison-mines/src/main/java/tech/mcprison/prison/mines/data/MineScheduler.java @@ -623,7 +623,7 @@ private void processBlockEventDetails( Player player, PrisonBlock prisonBlock, perms.trim().length() == 0 ) { - DecimalFormat dFmt = new DecimalFormat( "#,##0.0000" ); + DecimalFormat dFmt = Prison.get().getDecimalFormat( "#,##0.0000" ); PrisonBlockStatusData originalBlock = targetBlock.getPrisonBlock(); diff --git a/prison-mines/src/main/java/tech/mcprison/prison/mines/data/OnStartupRefreshBlockBreakCountSyncTask.java b/prison-mines/src/main/java/tech/mcprison/prison/mines/data/OnStartupRefreshBlockBreakCountSyncTask.java index c02cf30a8..7c866ab23 100644 --- a/prison-mines/src/main/java/tech/mcprison/prison/mines/data/OnStartupRefreshBlockBreakCountSyncTask.java +++ b/prison-mines/src/main/java/tech/mcprison/prison/mines/data/OnStartupRefreshBlockBreakCountSyncTask.java @@ -3,6 +3,7 @@ import java.text.DecimalFormat; import java.util.List; +import tech.mcprison.prison.Prison; import tech.mcprison.prison.output.Output; import tech.mcprison.prison.tasks.PrisonRunnable; import tech.mcprison.prison.util.Location; @@ -110,8 +111,8 @@ public void run() { mine.setAirCountTimestamp( System.currentTimeMillis() ); if ( Output.get().isDebug() ) { - DecimalFormat dFmt = new DecimalFormat("#,##0.000"); - DecimalFormat iFmt = new DecimalFormat("#,##0"); + DecimalFormat dFmt = Prison.get().getDecimalFormatDouble(); + DecimalFormat iFmt = Prison.get().getDecimalFormatInt(); String message = String.format( "MineReset startup air-count: Mine: %-6s " + " blocks: %10s pages: %s elapsed %s ms", diff --git a/prison-mines/src/main/java/tech/mcprison/prison/mines/features/MineBlockEvent.java b/prison-mines/src/main/java/tech/mcprison/prison/mines/features/MineBlockEvent.java index cf5ad9b9d..cf07a7670 100644 --- a/prison-mines/src/main/java/tech/mcprison/prison/mines/features/MineBlockEvent.java +++ b/prison-mines/src/main/java/tech/mcprison/prison/mines/features/MineBlockEvent.java @@ -36,9 +36,16 @@ public enum BlockEventType { PEExplosive, // PrisonEnchant: Pulsi_'s plugin PrisonExplosion, + RevEnExplosion, + RevEnJackHammer, + eventTypeAll( all ), eventBlockBreak( blockBreak ), - eventTEXplosion( TEXplosion ) + eventTEXplosion( TEXplosion ), + + eventRevEnExplosion( RevEnExplosion ), + eventRevEnJackHammer( RevEnJackHammer ), + ; private final BlockEventType primaryEventType; @@ -151,7 +158,7 @@ public String toSaveString() { } nFmt.format( getChance() ); -// DecimalFormat dFmt = new DecimalFormat("0.00000"); +// DecimalFormat dFmt = Prison.get().getDecimalFormat("0.00000"); return nFmt.format( getChance() ) + "|" + (getPermission() == null || getPermission().trim().length() == 0 ? diff --git a/prison-mines/src/main/java/tech/mcprison/prison/mines/managers/MineManager.java b/prison-mines/src/main/java/tech/mcprison/prison/mines/managers/MineManager.java index 441d300a6..91e6ea570 100644 --- a/prison-mines/src/main/java/tech/mcprison/prison/mines/managers/MineManager.java +++ b/prison-mines/src/main/java/tech/mcprison/prison/mines/managers/MineManager.java @@ -788,10 +788,12 @@ public String getTranslateMinesPlaceholder( PlaceholderIdentifier identifier ) { mine = getMine( placeHolderKey.getData() ); } - if ( mine != null || placeHolderKey.getPlaceholder().hasFlag( PlaceholderFlags.PLAYERBLOCKS )) { - DecimalFormat dFmt = new DecimalFormat("#,##0.00"); - DecimalFormat iFmt = new DecimalFormat("#,##0"); -// DecimalFormat fFmt = new DecimalFormat("#,##0.00"); + if ( mine != null || + placeHolderKey.getPlaceholder().hasFlag( PlaceholderFlags.PLAYERBLOCKS ) || + placeHolderKey.getPlaceholder().hasFlag( PlaceholderFlags.MINEPLAYERS )) { + DecimalFormat dFmt = Prison.get().getDecimalFormat("#,##0.00"); + DecimalFormat iFmt = Prison.get().getDecimalFormatInt(); +// DecimalFormat fFmt = Prison.get().getDecimalForma("#,##0.00"); identifier.setFoundAMatch( true ); @@ -800,7 +802,10 @@ public String getTranslateMinesPlaceholder( PlaceholderIdentifier identifier ) { case prison_mines_name_minename: case prison_mn_pm: case prison_mines_name_playermines: - results = mine.getName(); + if ( mine != null ) { + results = mine.getName(); + } + break; case prison_mt_minename: @@ -808,14 +813,17 @@ public String getTranslateMinesPlaceholder( PlaceholderIdentifier identifier ) { case prison_mt_pm: case prison_mines_tag_playermines: // getTag() now defaults to the mine's name if it does not exist: - results = mine.getTag(); + if ( mine != null ) { + results = mine.getTag(); + } + break; case prison_mi_minename: case prison_mines_interval_minename: case prison_mi_pm: case prison_mines_interval_playermines: - { + if ( mine != null ) { if ( attributeNFormat != null ) { results = attributeNFormat.format( (long) mine.getResetTime() ); @@ -833,7 +841,7 @@ public String getTranslateMinesPlaceholder( PlaceholderIdentifier identifier ) { case prison_mif_pm: case prison_mines_interval_formatted_playermines: - { + if ( mine != null ) { if ( attributeNFormat != null ) { results = attributeNFormat.format( (long) mine.getResetTime() ); @@ -852,7 +860,7 @@ public String getTranslateMinesPlaceholder( PlaceholderIdentifier identifier ) { case prison_mines_timeleft_playermines: // NOTE: timeleft can vary based upon server loads: - if ( !mine.isVirtual() ) + if ( mine != null && !mine.isVirtual() ) { if ( attributeNFormat != null ) { @@ -869,7 +877,7 @@ public String getTranslateMinesPlaceholder( PlaceholderIdentifier identifier ) { case prison_mtlb_pm: case prison_mines_timeleft_bar_playermines: // NOTE: timeleft can vary based upon server loads: - if ( !mine.isVirtual() ) { + if ( mine != null && !mine.isVirtual() ) { results = getRemainingTimeBar( mine, attributeBar ); } @@ -881,7 +889,7 @@ public String getTranslateMinesPlaceholder( PlaceholderIdentifier identifier ) { case prison_mines_timeleft_formatted_playermines: // NOTE: timeleft can vary based upon server loads: - if ( !mine.isVirtual() ) + if ( mine != null && !mine.isVirtual() ) { if ( attributeNFormat != null ) { @@ -899,7 +907,7 @@ public String getTranslateMinesPlaceholder( PlaceholderIdentifier identifier ) { case prison_ms_pm: case prison_mines_size_playermines: - if ( !mine.isVirtual() ) + if ( mine != null && !mine.isVirtual() ) { if ( attributeNFormat != null ) { @@ -918,7 +926,7 @@ public String getTranslateMinesPlaceholder( PlaceholderIdentifier identifier ) { case prison_mr_pm: case prison_mines_remaining_playermines: - if ( !mine.isVirtual() ) { + if ( mine != null && !mine.isVirtual() ) { int remainingBlocks = mine.getRemainingBlockCount(); { @@ -940,7 +948,7 @@ public String getTranslateMinesPlaceholder( PlaceholderIdentifier identifier ) { case prison_mrb_pm: case prison_mines_remaining_bar_playermines: - if ( !mine.isVirtual() ) { + if ( mine != null && !mine.isVirtual() ) { int totalBlocks = mine.getBounds().getTotalBlockCount(); int blocksRemaining = mine.getRemainingBlockCount(); @@ -957,7 +965,7 @@ public String getTranslateMinesPlaceholder( PlaceholderIdentifier identifier ) { case prison_mines_percent_playermines: // mine.refreshAirCount(); // async & delayed : Very high cost - if ( !mine.isVirtual() ) { + if ( mine != null && !mine.isVirtual() ) { double percentRemaining = mine.getPercentRemainingBlockCount(); results = dFmt.format( percentRemaining ); @@ -968,7 +976,7 @@ public String getTranslateMinesPlaceholder( PlaceholderIdentifier identifier ) { case prison_mines_player_count_minename: case prison_mpc_pm: case prison_mines_player_count_playermines: - if ( !mine.isVirtual() ) + if ( mine != null && !mine.isVirtual() ) { if ( attributeNFormat != null ) { @@ -985,7 +993,7 @@ public String getTranslateMinesPlaceholder( PlaceholderIdentifier identifier ) { case prison_mines_blocks_mined_minename: case prison_mbm_pm: case prison_mines_blocks_mined_playermines: - if ( !mine.isVirtual() ) + if ( mine != null && !mine.isVirtual() ) { // getBlockBreakCount(); @@ -1005,7 +1013,7 @@ public String getTranslateMinesPlaceholder( PlaceholderIdentifier identifier ) { case prison_mines_reset_count_minename: case prison_mrc_pm: case prison_mines_reset_count_playermines: - { + if ( mine != null ){ if ( attributeNFormat != null ) { results = attributeNFormat.format( (long) mine.getResetCount() ); @@ -1237,7 +1245,7 @@ public String getTranslateMinesPlaceholder( PlaceholderIdentifier identifier ) { case prison_player_blocks_total_minename: case prison_pbtr_minename: case prison_player_blocks_total_raw_minename: - if ( !mine.isVirtual() && player != null ) + if ( mine != null && !mine.isVirtual() && player != null ) { long blocksTotalByMine = PlayerCache.getInstance() .getPlayerBlocksTotalByMine( player, mine.getName() ); diff --git a/prison-ranks/src/main/java/tech/mcprison/prison/ranks/RankUtil.java b/prison-ranks/src/main/java/tech/mcprison/prison/ranks/RankUtil.java index edc8a3338..642d26442 100644 --- a/prison-ranks/src/main/java/tech/mcprison/prison/ranks/RankUtil.java +++ b/prison-ranks/src/main/java/tech/mcprison/prison/ranks/RankUtil.java @@ -900,8 +900,8 @@ else if (LadderManager.LADDER_DEFAULT.equalsIgnoreCase( results.getLadder().getN private void logTransactionResults( RankupResults results ) { StringBuilder sb = new StringBuilder(); - DecimalFormat dFmt = new DecimalFormat("#,##0.00"); - DecimalFormat iFmt = new DecimalFormat("#,##0"); + DecimalFormat dFmt = Prison.get().getDecimalFormat("#,##0.00"); + DecimalFormat iFmt = Prison.get().getDecimalFormatInt(); Rank oRank = results.getOriginalRank(); PlayerRank opRank = results.getPlayerRankOriginal(); @@ -966,7 +966,7 @@ private void logTransactionResults( RankupResults results ) case accuracy_out_of_range: sb.append( "=" ); - DecimalFormat sFmt = new DecimalFormat("#,##0.00000000"); + DecimalFormat sFmt = Prison.get().getDecimalFormat("#,##0.00000000"); sb.append( sFmt.format( results.getRankupCostFinalAccuracy() ) ); break; diff --git a/prison-ranks/src/main/java/tech/mcprison/prison/ranks/commands/LadderCommands.java b/prison-ranks/src/main/java/tech/mcprison/prison/ranks/commands/LadderCommands.java index 2da228046..4e166ba48 100644 --- a/prison-ranks/src/main/java/tech/mcprison/prison/ranks/commands/LadderCommands.java +++ b/prison-ranks/src/main/java/tech/mcprison/prison/ranks/commands/LadderCommands.java @@ -99,7 +99,7 @@ public void ladderList(CommandSender sender) { BulletedListComponent.BulletedListBuilder list = new BulletedListComponent.BulletedListBuilder(); -// DecimalFormat dFmt = new DecimalFormat( "#,##0.0000" ); +// DecimalFormat dFmt = Prison.get().getDecimalFormat( "#,##0.0000" ); // String header = String.format( // "&d%-12s %16s %5s %12s %12s", diff --git a/prison-ranks/src/main/java/tech/mcprison/prison/ranks/commands/LadderCommandsMessages.java b/prison-ranks/src/main/java/tech/mcprison/prison/ranks/commands/LadderCommandsMessages.java index c08c64ce6..66b5c5498 100644 --- a/prison-ranks/src/main/java/tech/mcprison/prison/ranks/commands/LadderCommandsMessages.java +++ b/prison-ranks/src/main/java/tech/mcprison/prison/ranks/commands/LadderCommandsMessages.java @@ -2,6 +2,7 @@ import java.text.DecimalFormat; +import tech.mcprison.prison.Prison; import tech.mcprison.prison.commands.BaseCommands; import tech.mcprison.prison.internal.CommandSender; import tech.mcprison.prison.ranks.PrisonRanks; @@ -178,7 +179,7 @@ protected void ladderSetRankCostMultiplierSavedMsg( CommandSender sender, String double rankCostMultiplier, double oldRankCostMultiplier ) { - DecimalFormat fFmt = new DecimalFormat("#,##0.00000"); + DecimalFormat fFmt = Prison.get().getDecimalFormat("#,##0.00000"); PrisonRanks.getInstance().getRanksMessages() .getLocalizable( "ranks_LadderCommands__ladder_set_rank_cost_multiplier" ) @@ -193,7 +194,7 @@ protected void ladderSetRankCostMultiplierNoChangeMsg( CommandSender sender, Str double rankCostMultiplier ) { - DecimalFormat fFmt = new DecimalFormat("#,##0.00000"); + DecimalFormat fFmt = Prison.get().getDecimalFormat("#,##0.00000"); PrisonRanks.getInstance().getRanksMessages() .getLocalizable( "ranks_LadderCommands__ladder_rank_cost_multiplier_no_change" ) @@ -207,7 +208,7 @@ protected void ladderSetRankCostMultiplierOutOfRangeMsg( CommandSender sender, double rankCostMultiplier ) { - DecimalFormat fFmt = new DecimalFormat("#,##0.00000"); + DecimalFormat fFmt = Prison.get().getDecimalFormat("#,##0.00000"); PrisonRanks.getInstance().getRanksMessages() .getLocalizable( "ranks_LadderCommands__ladder_rank_cost_multiplier_out_of_range" ) diff --git a/prison-ranks/src/main/java/tech/mcprison/prison/ranks/commands/RankUpCommand.java b/prison-ranks/src/main/java/tech/mcprison/prison/ranks/commands/RankUpCommand.java index bfd5072b1..415f7b93f 100644 --- a/prison-ranks/src/main/java/tech/mcprison/prison/ranks/commands/RankUpCommand.java +++ b/prison-ranks/src/main/java/tech/mcprison/prison/ranks/commands/RankUpCommand.java @@ -26,6 +26,7 @@ import tech.mcprison.prison.commands.Command; import tech.mcprison.prison.internal.CommandSender; import tech.mcprison.prison.internal.Player; +import tech.mcprison.prison.internal.Scheduler; import tech.mcprison.prison.internal.platform.Platform; import tech.mcprison.prison.output.Output; import tech.mcprison.prison.output.Output.DebugTarget; @@ -67,28 +68,73 @@ public RankUpCommand() { description = "Ranks up to the max rank that the player can afford. If the player has the " + "perm ranks.rankupmax.prestige it will try to rankup prestige once it maxes out " + "on the default ladder.", - altPermissions = {"ranks.rankupmax.[ladderName]", "ranks.rankupmax.prestige"}, + altPermissions = {"ranks.rankupmax.default", "ranks.rankupmax.prestige", "ranks.rankupmax.[ladderName]"}, onlyPlayers = false) public void rankUpMax(CommandSender sender, @Arg(name = "ladder", description = "The ladder to rank up on.", def = "default") String ladder ) { - // Not supposed to check perms here... But it is a simple check, and it if works... - if ( sender.hasPermission("ranks.rankupmax." + ladder) - // || sender.hasPermission("ranks.rankupmax.prestiges") + String perms = "ranks.rankupmax."; + String permsLadder = perms + ladder; + + boolean isPrestigesEnabled = Prison.get().getPlatform().getConfigBooleanFalse( "prestiges" ) || + Prison.get().getPlatform().getConfigBooleanFalse( "prestige.enabled" ); + + boolean isLadderPrestiges = ladder.equalsIgnoreCase(LadderManager.LADDER_PRESTIGES); +// boolean isLadderDefault = ladder.equalsIgnoreCase(LadderManager.LADDER_DEFAULT); + + if ( (isPrestigesEnabled && isLadderPrestiges || + !isLadderPrestiges ) && + sender.hasPermission( permsLadder) ) { Output.get().logDebug( DebugTarget.rankup, - "Rankup: cmd '/rankupmax %s' Passed perm check: ranks.rankupmax.%s", - ladder, ladder ); + "Rankup: cmd '/rankupmax %s' Passed perm check: %s", + ladder, permsLadder ); + + boolean success = false; List cmdTasks = new ArrayList<>(); + StringBuilder sbRanks = new StringBuilder(); + - rankUpPrivate(sender, "", ladder, RankupModes.MAX_RANKS, "ranks.rankupmax.", cmdTasks ); + RankupModes mode = RankupModes.MAX_RANKS; + + if ( !LadderManager.LADDER_PRESTIGES.equalsIgnoreCase( ladder ) && + !LadderManager.LADDER_DEFAULT.equalsIgnoreCase( ladder )) { + + success = rankUpPrivate(sender, "", ladder, mode, perms, cmdTasks, sbRanks ); + } + else { + + // Run rankupmax on the default ladder only: + success = rankUpPrivate(sender, "", LadderManager.LADDER_DEFAULT, mode, perms, cmdTasks, sbRanks ); + + // If they specified the prestiges ladder, then try to prestige that one rank: + if ( success && LadderManager.LADDER_PRESTIGES.equalsIgnoreCase( ladder ) ) { + + success = rankUpPrivate(sender, "", LadderManager.LADDER_PRESTIGES, RankupModes.ONE_RANK, perms, cmdTasks, sbRanks ); + } + } + + // submit cmdTasks - Player player = getPlayer( sender, null ); - submitCmdTasks( player, cmdTasks ); + if ( cmdTasks.size() > 0 ) { + + Player player = getPlayer( sender, null ); + submitCmdTasks( player, cmdTasks ); + } + + if ( sbRanks.length() > 0 ) { + ranksRankupMaxSuccessMsg( sender, sbRanks ); + } + + // If the ran rankupmax for prestiges, and the last prestige was successful, then + // try it all again! + if ( success && LadderManager.LADDER_PRESTIGES.equalsIgnoreCase( ladder ) ) { + rankUpMax( sender, ladder ); + } } else { Output.get().logDebug( DebugTarget.rankup, @@ -99,10 +145,14 @@ public void rankUpMax(CommandSender sender, } - @Command(identifier = "rankup", description = "Ranks up to the next rank.", - permissions = "ranks.user", altPermissions = "ranks.rankup.[ladderName]", onlyPlayers = false) + @Command(identifier = "rankup", description = "Ranks up to the next rank. All players have access to " + + "the ability to rankup on the default ladder so no perms are required, but any other ladder " + + "requires the correct perms.", + permissions = "ranks.user", + altPermissions = {"ranks.rankup.default", "ranks.rankup.prestiges", "ranks.rankup.[ladderName]"}, + onlyPlayers = false) public void rankUp(CommandSender sender, - @Arg(name = "ladder", description = "The ladder to rank up on.", def = "default") String ladder, + @Arg(name = "ladder", description = "The ladder to rank up on. Defaults to 'default'.", def = "default") String ladder, @Arg(name = "playerName", description = "Provides the player's name for the rankup, but" + "this can only be provided by a non-player such as console or ran from a script.", def = "") String playerName ) { @@ -116,47 +166,231 @@ public void rankUp(CommandSender sender, return; } - Output.get().logDebug( DebugTarget.rankup, - "Rankup: cmd '/rankup %s%s' Processing ranks.rankup.%s", - ladder, - ( playerName.length() == 0 ? "" : " " + playerName ), - ladder - ); - - List cmdTasks = new ArrayList<>(); - - rankUpPrivate(sender, playerName, ladder, RankupModes.ONE_RANK, "ranks.rankup.", cmdTasks ); + String perms = "ranks.rankup."; + String permsLadder = perms + ladder; - // submit cmdTasks - Player player = getPlayer( sender, playerName ); - submitCmdTasks( player, cmdTasks ); + boolean isPrestigesEnabled = Prison.get().getPlatform().getConfigBooleanFalse( "prestiges" ) || + Prison.get().getPlatform().getConfigBooleanFalse( "prestige.enabled" ); + + boolean isLadderPrestiges = ladder.equalsIgnoreCase(LadderManager.LADDER_PRESTIGES); + boolean isLadderDefault = ladder.equalsIgnoreCase(LadderManager.LADDER_DEFAULT); + if ( isLadderDefault || + + (isPrestigesEnabled && isLadderPrestiges || + !isLadderPrestiges ) && + sender.hasPermission( permsLadder) + ) { + Output.get().logDebug( DebugTarget.rankup, + "Rankup: cmd '/rankup %s%s' Passed perm check: %s", + ladder, + ( playerName.length() == 0 ? "" : " " + playerName ), + permsLadder ); + + +// Output.get().logDebug( DebugTarget.rankup, +// "Rankup: cmd '/rankup %s%s' Processing %s", +// ladder, +// ( playerName.length() == 0 ? "" : " " + playerName ), +// permsLadder +// ); + + List cmdTasks = new ArrayList<>(); + + rankUpPrivate(sender, playerName, ladder, RankupModes.ONE_RANK, perms, cmdTasks, null ); + + // submit cmdTasks + Player player = getPlayer( sender, playerName ); + submitCmdTasks( player, cmdTasks ); + } + else { + Output.get().logDebug( DebugTarget.rankup, + "Rankup: Failed: cmd '/rankup %s' Does not have the permission %s", + ladder, permsLadder ); + rankupMaxNoPermissionMsg( sender, permsLadder ); + } + } + - private void rankUpPrivate(CommandSender sender, String playerName, String ladder, RankupModes mode, - String permission, List cmdTasks ) { - - // RETRIEVE THE LADDER + @Command(identifier = "prestige", description = "This will prestige the player. Prestiging is generally when " + + "the player's default rank is reset to the lowest rank, their money is rest to zero, and they " + + "start the mining and the ranking up process all over again. As a trade off for their reset " + + "of ranks, they get a new prestige rank with the costs of the default ranks being increased.", + permissions = "ranks.user", + altPermissions = {"ranks.rankup.prestiges"}, + onlyPlayers = false) + public void prestigeCmd(CommandSender sender, + @Arg(name = "playerName", def = "", + description = "Provides the player's name for the prestige, but " + + "this can only be provided by a non-player such as console or ran from a script. " + + "Players cannot run Prestige for other players.") + String playerName, + @Arg(name = "confirm", def = "", + description = "If confirmations are enabled, then the prestige command " + + "must be repeated with the addition of 'confirm'. If the prestige command is ran by a " + + "non-player, such as console or from script, then the confirmation will be skipped, or " + + "the word 'confirm' can be appended to the initial command. If 'confirm' is supplied, even " + + "if the setting 'prestige.confirmation-enabled: true' is enabled, then confirmations will " + + "be skipped (acts like a bypass)." ) + String confirm + ) { + + boolean isConfirmed = ( confirm != null && confirm.toLowerCase().contains("confirm") ); + if ( !isConfirmed && playerName != null && playerName.toLowerCase().equals( "confirm" ) ) { + isConfirmed = true; + playerName = ""; + } + + boolean isPlayer = sender.isPlayer(); + + if ( isPlayer ) { + playerName = sender.getName(); + } + + + if ( !isPlayer && playerName.length() == 0 ) { + Output.get().logInfo( rankupCannotRunFromConsoleMsg() ); + return; + } + + RankPlayer rPlayer = getRankPlayer(sender, null, playerName); + + if ( rPlayer == null ) { + rankupInvalidPlayerNameMsg( sender, playerName ); + return; + } + + + String perms = "ranks.rankup."; + String permsLadder = perms + LadderManager.LADDER_PRESTIGES; - // This player has to have permission to rank up on this ladder. - if (!(ladder.equalsIgnoreCase(LadderManager.LADDER_PRESTIGES) && - (Prison.get().getPlatform().getConfigBooleanFalse( "prestiges" ) || - Prison.get().getPlatform().getConfigBooleanFalse( "prestige.enabled" ))) && - !ladder.equalsIgnoreCase(LadderManager.LADDER_DEFAULT) && - !sender.hasPermission(permission + ladder.toLowerCase())) { + boolean isPrestigesEnabled = Prison.get().getPlatform().getConfigBooleanFalse( "prestiges" ) || + Prison.get().getPlatform().getConfigBooleanFalse( "prestige.enabled" ); + + boolean isResetDefaultLadder = Prison.get().getPlatform().getConfigBooleanFalse( "prestige.resetDefaultLadder" ); + boolean isResetMoney = Prison.get().getPlatform().getConfigBooleanFalse( "prestige.resetMoney" ); + boolean isConfirmationEnabled = Prison.get().getPlatform().getConfigBooleanFalse( "prestige.confirmation-enabled" ); + boolean isConfirmGUI = Prison.get().getPlatform().getConfigBooleanFalse( "prestige.prestige-confirm-gui" ); + //boolean isforceSellall = Prison.get().getPlatform().getConfigBooleanFalse( "prestige.force-sellall" ); + +// boolean isLadderPrestiges = ladder.equalsIgnoreCase(LadderManager.LADDER_PRESTIGES); + + PlayerRank nextRank = rPlayer.getNextPlayerRank(); + Rank nRank = nextRank == null ? null : nextRank.getRank(); + + if ( nRank == null ) { + // You're at the last possible rank. + rankupNotAbleToPrestigeMsg( sender ); + rankupAtLastRankMsg( sender ); + return; + } + + if ( !nRank.getLadder().getName().equals( LadderManager.LADDER_PRESTIGES ) ) { + + // your next rank is not a Prestiges rank + rankupNotAbleToPrestigeMsg( sender ); + rankupNotAtLastRankMsg( sender ); + + return; + } + + String currency = nextRank.getCurrency(); + + if ( rPlayer.getBalance( currency ) < nextRank.getRankCost() ) { + + // You do not have enough to prestige yet + ranksRankupCannotAffordMsg( sender, nextRank ); + ranksRankupPlayerBalanceMsg( sender, rPlayer.getBalance( currency ), currency ); + return; + } - Output.get().logDebug( DebugTarget.rankup, - "Rankup: rankUpPrivate: failed rankup perm check"); + if ( isConfirmationEnabled && !isConfirmed ) { + if ( isConfirmGUI && isPlayer ) { + + // call the gui prestige confirmation: +// callGuiPrestigeConfirmation( sender, ); + String guiConfirmParms = + prestigeConfirmationGUIMsg( sender, rPlayer, nextRank, isResetDefaultLadder, isResetMoney ); + + String guiConfirmCmd = "gui prestigeConfirm " + guiConfirmParms; +// Output.get().logInfo( guiConfirmCmd ); + + submitCmdTask( rPlayer, guiConfirmCmd ); + + } + else { + + prestigeConfirmationMsg( sender, rPlayer, nextRank, isResetDefaultLadder, isResetMoney, isPlayer ); + } + return; + } + + if ( isPrestigesEnabled && + sender.hasPermission( permsLadder) + ) { + Output.get().logDebug( DebugTarget.rankup, + "Rankup: cmd '/prestige %s%s' Passed perm check: %s", + (playerName.length() == 0 ? "" : " " + playerName ), + (confirm == null ? "" : " " + confirm ), + permsLadder ); + + + List cmdTasks = new ArrayList<>(); - rankupMaxNoPermissionMsg( sender, permission + ladder ); - return; + String ladder = nRank.getLadder().getName(); + rankUpPrivate(sender, playerName, ladder, RankupModes.ONE_RANK, perms, cmdTasks, null ); + + // submit cmdTasks + Player player = getPlayer( sender, playerName ); + submitCmdTasks( player, cmdTasks ); } + + } + + + private boolean rankUpPrivate(CommandSender sender, String playerName, String ladder, RankupModes mode, + String permission, + List cmdTasks, + StringBuilder sbRanks ) { + + boolean rankupSuccess = false; + + // RETRIEVE THE LADDER + +// // Perms have already been checked on the RankupModes.MAX_RANKS: +// if ( mode != RankupModes.MAX_RANKS ) { +// +// boolean isPrestigesEnabled = Prison.get().getPlatform().getConfigBooleanFalse( "prestiges" ) || +// Prison.get().getPlatform().getConfigBooleanFalse( "prestige.enabled" ); +// +// boolean isLadderPrestiges = ladder.equalsIgnoreCase(LadderManager.LADDER_PRESTIGES); +// boolean isLadderDefault = ladder.equalsIgnoreCase(LadderManager.LADDER_DEFAULT); +// +// String permCheck = permission + ladder.toLowerCase(); +// +// // This player has to have permission to rank up on this ladder, but +// // ignore if either the default or prestiges ladder. This only is to check for +// // other ladders. +// if (!( isLadderPrestiges && isPrestigesEnabled ) && +// !isLadderDefault && +// !sender.hasPermission( permCheck )) { +// +// Output.get().logDebug( DebugTarget.rankup, +// "Rankup: rankUpPrivate: failed rankup perm check. Missing perm: %s", +// permCheck ); +// +// rankupMaxNoPermissionMsg( sender, permCheck ); +// return false; +// } +// +// } // if ( mode == null ) { Output.get().logInfo( rankupInternalFailureMsg() ); - return; + return false; } @@ -166,7 +400,7 @@ private void rankUpPrivate(CommandSender sender, String playerName, String ladde if ( !sender.isPlayer() && playerName.length() == 0 ) { Output.get().logInfo( rankupCannotRunFromConsoleMsg() ); - return; + return false; } @@ -175,7 +409,7 @@ private void rankUpPrivate(CommandSender sender, String playerName, String ladde if ( player == null ) { rankupInvalidPlayerNameMsg( sender, playerName ); - return; + return false; } @@ -184,7 +418,7 @@ private void rankUpPrivate(CommandSender sender, String playerName, String ladde ladder = confirmLadder( sender, ladder ); if ( ladder == null ) { // ladder cannot be null, - return; + return false; } LadderManager lm = PrisonRanks.getInstance().getLadderManager(); @@ -192,39 +426,70 @@ private void rankUpPrivate(CommandSender sender, String playerName, String ladde if ( targetLadder == null ){ rankupErrorNoLadderMsg( sender, ladder ); - return; + return false; } if (!targetLadder.getLowestRank().isPresent()){ rankupErrorNoRankOnLadderMsg( sender, ladder ); - return; + return false; } - RankPlayerFactory rankPlayerFactory = new RankPlayerFactory(); RankPlayer rankPlayer = getRankPlayer( sender, player.getUUID(), player.getName() ); - PlayerRank playerRankCurrent = rankPlayerFactory.getRank( rankPlayer, ladder ); - PlayerRank playerRankTarget = null; - // If the player does not have a rank on the current ladder, then assign the - // default rank for the ladder to be their next rank. - if ( playerRankCurrent == null ) { + + // Get the player's next rank on default ladder, or if at end then it will return the next + // prestiges rank. + PlayerRank playerRankTarget = rankPlayer.getNextPlayerRank(); + + + // If the nextRank is null or the ladder does not match selected ladder, then exit: + if ( playerRankTarget == null || playerRankTarget.getRank() == null || + !playerRankTarget.getRank().getLadder().getName().equalsIgnoreCase( ladder ) ) { + + return false; + } + + + RankPlayerFactory rankPlayerFactory = new RankPlayerFactory(); + + + + // If the target ladder is either default or prestiges, then use the getNextPlayerRank() value + // that is provided. Only use the following code if not these two ladders. + if ( !ladder.equalsIgnoreCase( LadderManager.LADDER_DEFAULT ) && + !ladder.equalsIgnoreCase( LadderManager.LADDER_PRESTIGES ) ) { - playerRankTarget = rankPlayer.calculateTargetPlayerRank( - targetLadder.getLowestRank().get() ); + + PlayerRank playerRankCurrent = rankPlayerFactory.getRank( rankPlayer, ladder ); +// PlayerRank playerRankCurrent = rankPlayer.getPlayerRankDefault(); + + // If the player does not have a rank on the current ladder, then assign the + // default rank for the ladder to be their next rank. + if ( playerRankCurrent == null ) { + + playerRankTarget = rankPlayer.calculateTargetPlayerRank( + targetLadder.getLowestRank().get() ); + // playerRankTarget = rankPlayerFactory.createPlayerRank( // targetLadder.getLowestRank().get() ); - } - else { - - playerRankTarget = rankPlayer.calculateTargetPlayerRank( playerRankCurrent.getRank() ); + } + else { + + playerRankTarget = rankPlayer.calculateTargetPlayerRank( playerRankCurrent.getRank() ); // playerRankTarget = playerRankCurrent.getTargetPlayerRankForPlayer( rankPlayer, // playerRankCurrent.getRank() ); + } + } + + + + Output.get().logDebug( DebugTarget.rankup, @@ -235,7 +500,7 @@ private void rankUpPrivate(CommandSender sender, String playerName, String ladde // If a player has a rank on the ladder get their rank, otherwise null: Rank pRankTarget = playerRankTarget.getRank(); - Rank pRankAfter = null; +// Rank pRankAfter = null; boolean canPrestige = false; // If the player is trying to prestige, then the following must be ran to setup the prestige checks: @@ -245,12 +510,12 @@ private void rankUpPrivate(CommandSender sender, String playerName, String ladde if ( rankLadder == null ){ rankupErrorNoDefaultLadderMsg( sender ); - return; + return false; } if (!rankLadder.getLowestRank().isPresent()){ rankupErrorNoLowerRankMsg( sender ); - return; + return false; } // gets the rank on the default ladder. Used if ladder is not default. @@ -264,9 +529,16 @@ private void rankUpPrivate(CommandSender sender, String playerName, String ladde // The last rank will never have a rankNext (it will be null): if ( playersRankOnDefaultLadder.getRankNext() != null ) { rankupNotAtLastRankMsg( sender ); - return; + return false; + } + + // If force sellall, then perform the sellall here: + if ( Prison.get().getPlatform().getConfigBooleanFalse( "prestige.force-sellall" ) ) { + + Prison.get().getPlatform().sellall( rankPlayer ); } + // IF everything's ready, this will be true if and only if pRank is not null, // and the prestige method will start canPrestige = true; @@ -276,7 +548,6 @@ private void rankUpPrivate(CommandSender sender, String playerName, String ladde // Get currency if it exists, otherwise it will be null if the Rank has no currency: String currency = rankPlayer == null || pRankTarget == null ? null : pRankTarget.getCurrency(); - boolean rankupWithSuccess = false; if (rankPlayer != null ) { @@ -284,37 +555,45 @@ private void rankUpPrivate(CommandSender sender, String playerName, String ladde RankupResults results = new RankUtil().rankupPlayer(player, rankPlayer, ladder, sender.getName(), cmdTasks ); - processResults( sender, player.getName(), results, null, ladder, currency ); + + processResults( sender, player.getName(), results, null, ladder, currency, sbRanks ); // If the last rankup attempt was successful and they are trying to rankup as many times as possible: - if (results.getStatus() == RankupStatus.RANKUP_SUCCESS && mode == RankupModes.MAX_RANKS && - !ladder.equals(LadderManager.LADDER_PRESTIGES)) { - rankUpPrivate( sender, playerName, ladder, mode, permission, cmdTasks ); + // Note they used to restrict rankupmax from working on prestige ladder... + if (results.getStatus() == RankupStatus.RANKUP_SUCCESS && mode == RankupModes.MAX_RANKS ) { +// if (results.getStatus() == RankupStatus.RANKUP_SUCCESS && mode == RankupModes.MAX_RANKS && +// !ladder.equals(LadderManager.LADDER_PRESTIGES)) { + rankUpPrivate( sender, playerName, ladder, mode, permission, cmdTasks, sbRanks ); } if (results.getStatus() == RankupStatus.RANKUP_SUCCESS){ - rankupWithSuccess = true; + rankupSuccess = true; } // Get the player rank after - PlayerRank playerRankAfter = rankPlayerFactory.getRank( rankPlayer, ladder ); +// PlayerRank playerRankAfter = rankPlayer.getNextPlayerRank(); +// PlayerRank playerRankAfter = rankPlayerFactory.getRank( rankPlayer, ladder ); - if ( playerRankAfter != null ) { - - pRankAfter = playerRankAfter.getRank(); - } +// if ( playerRankAfter != null ) { +// +// pRankAfter = playerRankAfter.getRank(); +// } // Prestige method if canPrestige and a successful rankup. // pRankTarget now contains the target rank prior to processing the rankup. SO it should be // the same as pRankAfter, but if it is wrong, then rankupWithSuccess will not be true. So ignore... - if ( canPrestige && rankupWithSuccess && pRankAfter != null ) { - prestigePlayer( sender, player, rankPlayer, pRankAfter, lm ); + if ( canPrestige && rankupSuccess ) { + prestigePlayer( sender, rankPlayer, lm, cmdTasks, sbRanks ); +// prestigePlayer( sender, player, rankPlayer, pRankAfter, lm ); + } else if ( canPrestige ) { rankupNotAbleToPrestigeMsg( sender ); } } + + return rankupSuccess; } /** @@ -339,8 +618,10 @@ else if ( canPrestige ) { * @param pRankAfter * @param lm */ - private void prestigePlayer(CommandSender sender, Player player, RankPlayer rankPlayer, - Rank pRankAfter, LadderManager lm ) { + private void prestigePlayer(CommandSender sender, RankPlayer rankPlayer, +// Rank pRankAfter, + LadderManager lm, + List cmdTasks, StringBuilder sbRanks ) { Output.get().logDebug( DebugTarget.rankup, "Rankup: prestigePlayer: "); @@ -356,24 +637,33 @@ private void prestigePlayer(CommandSender sender, Player player, RankPlayer rank // if (willPrestige && rankupWithSuccess && pRankAfter != null && pRank != pRankAfter) { // Set the player rank to the first one of the default ladder + + RankLadder ladder = lm.getLadder(LadderManager.LADDER_DEFAULT); + Rank dRank = ladder.getLowestRank().get(); + setPlayerRank( rankPlayer, ladder, dRank, sender, cmdTasks, sbRanks ); + + +// String ladderName = LadderManager.LADDER_DEFAULT; +// String defaultRank = lm.getLadder(LadderManager.LADDER_DEFAULT).getLowestRank().get().getName(); +// +// setPlayerRank( rankPlayer, defaultRank, ladderName, sender ); + // Call the function directly and skip using dispatch commands: - setRank( sender, player.getName(), - lm.getLadder(LadderManager.LADDER_DEFAULT).getLowestRank().get().getName(), - LadderManager.LADDER_DEFAULT ); +// setRank( sender, player.getName(), +// lm.getLadder(LadderManager.LADDER_DEFAULT).getLowestRank().get().getName(), +// LadderManager.LADDER_DEFAULT ); -// PrisonAPI.dispatchCommand("ranks set rank " + player.getName() + " " + -// lm.getLadder("default").getLowestRank().get().getName() + " default"); - // Get that rank - RankPlayerFactory rankPlayerFactory = new RankPlayerFactory(); + PlayerRank playerRankSecond = rankPlayer.getPlayerRankDefault(); + + - PlayerRank playerRankSecond = rankPlayerFactory.getRank( rankPlayer, LadderManager.LADDER_DEFAULT); if ( playerRankSecond != null ) { Rank pRankSecond = playerRankSecond.getRank(); // Check if the ranks match - if (pRankSecond != lm.getLadder(LadderManager.LADDER_DEFAULT).getLowestRank().get()) { + if ( !pRankSecond.equals( lm.getLadder(LadderManager.LADDER_DEFAULT).getLowestRank().get()) ) { rankupNotAbleToResetRankMsg( sender ); success = false; @@ -394,7 +684,16 @@ private void prestigePlayer(CommandSender sender, Player player, RankPlayer rank prestigePlayerBalanceSetToZeroMsg( sender ); } - String title = pRankAfter.getTag() == null ? pRankAfter.getName() : pRankAfter.getTag(); + + + PlayerRank newPrestigeRank = rankPlayer.getPlayerRankPrestiges(); + Rank newPRank = newPrestigeRank == null || newPrestigeRank.getRank() == null ? + null : + newPrestigeRank.getRank(); + + String title = newPRank == null || newPRank.getTag() == null ? + newPRank.getName() : + newPRank.getTag(); if ( success ) { // Send a message to the player because he did prestige! @@ -457,7 +756,7 @@ public void promotePlayer(CommandSender sender, // submit cmdTasks... submitCmdTasks( player, cmdTasks ); - processResults( sender, player.getName(), results, null, ladder, currency ); + processResults( sender, player.getName(), results, null, ladder, currency, null ); } } else { @@ -518,7 +817,7 @@ public void demotePlayer(CommandSender sender, // submit cmdTasks submitCmdTasks( player, cmdTasks ); - processResults( sender, player.getName(), results, null, ladder, currency ); + processResults( sender, player.getName(), results, null, ladder, currency, null ); } } else { @@ -609,7 +908,7 @@ public void setPlayerRank( RankPlayer rankPlayer, Rank pRank ) { processResults( rankPlayer, rankPlayer.getName(), results, pRank.getName(), pRank.getLadder().getName(), - pRank.getCurrency() ); + pRank.getCurrency(), null ); } } @@ -638,11 +937,29 @@ public void setPlayerRankFirstJoin( RankPlayer rankPlayer, Rank pRank ) { processResults( rankPlayer, rankPlayer.getName(), results, pRank.getName(), pRank.getLadder().getName(), - pRank.getCurrency() ); + pRank.getCurrency(), null ); } } + private void setPlayerRank( RankPlayer rankPlayer, RankLadder ladder, Rank pRank, + CommandSender sender, + List cmdTasks, StringBuilder sbRanks ) { + + // Get currency if it exists, otherwise it will be null if the Rank has no currency: + String currency = rankPlayer == null || pRank == null ? null : pRank.getCurrency(); + + + RankupResults results = new RankUtil().setRank( rankPlayer, rankPlayer, + ladder.getName(), pRank.getName(), + rankPlayer.getName(), sender.getName(), cmdTasks ); + + + processResults( sender, rankPlayer.getName(), results, pRank.getName(), ladder.getName(), + currency, sbRanks ); + + } + private void setPlayerRank( Player player, String rank, String ladderName, CommandSender sender ) { UUID playerUuid = player.getUUID(); @@ -669,7 +986,7 @@ private void setPlayerRank( Player player, String rank, String ladderName, Comma // submit cmdTasks submitCmdTasks( player, cmdTasks ); - processResults( sender, player.getName(), results, rank, ladderName, currency ); + processResults( sender, player.getName(), results, rank, ladderName, currency, null ); } } @@ -706,16 +1023,18 @@ public RankPlayer getRankPlayer( CommandSender sender, UUID playerUuid, String p public void processResults( CommandSender sender, String playerName, RankupResults results, - String rank, String ladder, String currency ) { + String rank, String ladder, String currency, + StringBuilder sbRanks ) { switch (results.getStatus()) { case RANKUP_SUCCESS: - ranksRankupSuccessMsg( sender, playerName, results ); + + ranksRankupSuccessMsg( sender, playerName, results, sbRanks ); break; case DEMOTE_SUCCESS: - ranksRankupSuccessMsg( sender, playerName, results ); + ranksRankupSuccessMsg( sender, playerName, results, null ); break; case RANKUP_CANT_AFFORD: @@ -794,6 +1113,16 @@ public void processResults( CommandSender sender, String playerName, } } + private void submitCmdTask( Player player, String command ) { + + Scheduler scheduler = Prison.get().getPlatform().getScheduler(); + + scheduler.performCommand( player, command ); +// scheduler.dispatchCommand( player, command ); + +// PrisonCommandTaskData task = new PrisonCommandTaskData( errorPrefix, command ); +// PrisonCommandTasks.submitTasks( player, task ); + } private void submitCmdTasks( Player player, List cmdTasks ) { diff --git a/prison-ranks/src/main/java/tech/mcprison/prison/ranks/commands/RankUpCommandMessages.java b/prison-ranks/src/main/java/tech/mcprison/prison/ranks/commands/RankUpCommandMessages.java index f66e78bdb..c0782abae 100644 --- a/prison-ranks/src/main/java/tech/mcprison/prison/ranks/commands/RankUpCommandMessages.java +++ b/prison-ranks/src/main/java/tech/mcprison/prison/ranks/commands/RankUpCommandMessages.java @@ -5,6 +5,7 @@ import tech.mcprison.prison.Prison; import tech.mcprison.prison.commands.BaseCommands; import tech.mcprison.prison.internal.CommandSender; +import tech.mcprison.prison.localization.LocaleManager; import tech.mcprison.prison.localization.Localizable; import tech.mcprison.prison.output.Output; import tech.mcprison.prison.ranks.PrisonRanks; @@ -90,6 +91,12 @@ protected void rankupNotAtLastRankMsg( CommandSender sender ) { .sendTo( sender ); } + protected void rankupAtLastRankMsg( CommandSender sender ) { + PrisonRanks.getInstance().getRanksMessages() + .getLocalizable( "ranks_rankup__at_last_rank" ) + .sendTo( sender ); + } + protected void rankupNotAbleToPrestigeMsg( CommandSender sender ) { PrisonRanks.getInstance().getRanksMessages() .getLocalizable( "ranks_rankup__not_able_to_prestige" ) @@ -124,6 +131,127 @@ protected void prestigePlayerFailureMsg( CommandSender sender, String tag ) { .sendTo( sender ); } + protected String prestigeConfirmationGUIMsg( CommandSender sender, + RankPlayer rPlayer, PlayerRank targetRank, + boolean isResetDefaultLadder, boolean isConfirmationEnabled ) { + StringBuilder sb = new StringBuilder(); + DecimalFormat dFmt = Prison.get().getDecimalFormat("#,##0.00"); + + String currency = targetRank.getCurrency(); + double balance = rPlayer.getBalance( currency ); + + LocaleManager rMsg = PrisonRanks.getInstance().getRanksMessages(); + + String tag = targetRank.getRank().getTag(); + if ( tag == null ) { + tag = targetRank.getRank().getName(); + } + sb.append( rMsg.getLocalizable( "ranks_rankup__confirm_prestige_line_1" ) + .withReplacements( tag ) + .localize().replace(" ", "_") ).append( " " ); + + sb.append( rMsg.getLocalizable( "ranks_rankup__confirm_prestige_line_2" ) + .withReplacements( + dFmt.format( targetRank.getRankCost()) ) + .localize().replace(" ", "_") ).append( " " ); + + sb.append( rMsg.getLocalizable( "ranks_rankup__confirm_prestige_line_3" ) + .withReplacements( + dFmt.format( balance), + currency == null || currency.trim().length() == 0 ? + "" : " " + currency ) + .localize().replace(" ", "_") ).append( " " ); + + if ( isResetDefaultLadder ) { + sb.append( rMsg.getLocalizable( "ranks_rankup__confirm_prestige_line_4" ) + .localize().replace(" ", "_") ).append( " " ); + } + + if ( isConfirmationEnabled ) { + sb.append( rMsg.getLocalizable( "ranks_rankup__confirm_prestige_line_5" ) + .localize().replace(" ", "_") ).append( " " ); + } + + sb.append( rMsg.getLocalizable( "ranks_rankup__confirm_prestige_line_7" ) + .localize().replace(" ", "_") ); + + return sb.toString(); + } + + protected void prestigeConfirmationMsg( CommandSender sender, + RankPlayer rPlayer, PlayerRank targetRank, + boolean isResetDefaultLadder, boolean isResetMoney, + boolean isPlayer ) { + DecimalFormat dFmt = Prison.get().getDecimalFormat("#,##0.00"); + + String currency = targetRank.getCurrency(); + double balance = rPlayer.getBalance( currency ); + + LocaleManager rMsg = PrisonRanks.getInstance().getRanksMessages(); + + + String tag = targetRank.getRank().getTag(); + if ( tag == null ) { + tag = targetRank.getRank().getName(); + } + rMsg.getLocalizable( "ranks_rankup__confirm_prestige_line_1" ) + .withReplacements( tag ) + .sendTo( sender ); + + + rMsg.getLocalizable( "ranks_rankup__confirm_prestige_line_2" ) + .withReplacements( + dFmt.format( targetRank.getRankCost()) ) + .sendTo( sender ); + + rMsg.getLocalizable( "ranks_rankup__confirm_prestige_line_3" ) + .withReplacements( + dFmt.format( balance), + currency == null || currency.trim().length() == 0 ? + "" : " " + currency ) + .sendTo( sender ); + + if ( isResetDefaultLadder ) { + rMsg.getLocalizable( "ranks_rankup__confirm_prestige_line_4" ) + .sendTo( sender ); + } + + if ( isResetMoney ) { + rMsg.getLocalizable( "ranks_rankup__confirm_prestige_line_4" ) + .sendTo( sender ); + } + + rMsg.getLocalizable( "ranks_rankup__confirm_prestige_line_5" ) + .sendTo( sender ); + + String playerName = !isPlayer ? rPlayer.getName() + " " : ""; + rMsg.getLocalizable( "ranks_rankup__confirm_prestige_line_6" ) + .withReplacements( playerName ) + .sendTo( sender ); + + +// ranks_rankup__confirm_prestige_line_1=&3Confirm Prestige: %s +// ranks_rankup__confirm_prestige_line_2=&3 Cost: &7%1 +// ranks_rankup__confirm_prestige_line_3=&3 Default Rank will be reset. +// ranks_rankup__confirm_prestige_line_4=&3 Balance will be reset. +// ranks_rankup__confirm_prestige_line_5=&3Confirm with command: '&7/prestiges confirm&3' +// ranks_rankup__confirm_prestige_line_6=&3Confirm by clicking on the green block + + } + + protected void ranksRankupPlayerBalanceMsg( CommandSender sender, + double balance, String currency ) { + DecimalFormat dFmt = Prison.get().getDecimalFormat("#,##0.00"); + + LocaleManager rMsg = PrisonRanks.getInstance().getRanksMessages(); + + rMsg.getLocalizable( "ranks_rankup__confirm_prestige_line_3" ) + .withReplacements( + dFmt.format( balance), + currency == null || currency.trim().length() == 0 ? + "" : " " + currency ) + .sendTo( sender ); + } protected void ranksPromotePlayerMustBeOnlineMsg( CommandSender sender ) { PrisonRanks.getInstance().getRanksMessages() @@ -168,9 +296,21 @@ protected void ranksRankupFailureToGetRankPlayerMsg( CommandSender sender ) { protected void ranksRankupSuccessMsg( CommandSender sender, String playerName, - RankupResults results ) { + RankupResults results, + StringBuilder sbRanks ) { + +// PlayerRank tpRank = results.getPlayerRankTarget(); + Rank tRank = results.getTargetRank(); + // If sbRanks is not null, then just log the rank tag and exit. + // Do not generate any other messages. + if ( sbRanks != null && tRank != null ) { + + sbRanks.append( tRank.getTag() ).append( " " ); + return; + } + String messageId = results.getStatus() == RankupStatus.DEMOTE_SUCCESS ? "ranks_rankup__demote_success" : "ranks_rankup__rankup_success" ; @@ -178,10 +318,6 @@ protected void ranksRankupSuccessMsg( CommandSender sender, String playerName, String messagNoPlayerName = PrisonRanks.getInstance().getRanksMessages() .getLocalizable( "ranks_rankup__rankup_no_player_name" ).localize(); -// PlayerRank tpRank = results.getPlayerRankTarget(); - Rank tRank = results.getTargetRank(); - - Localizable localManager = PrisonRanks.getInstance().getRanksMessages() .getLocalizable( messageId ) .withReplacements( @@ -218,21 +354,53 @@ protected void ranksRankupSuccessMsg( CommandSender sender, String playerName, localManager.sendTo( sender ); } } + + protected void ranksRankupMaxSuccessMsg( CommandSender sender, StringBuilder ranks ) { + + Localizable localManagerLog = PrisonRanks.getInstance().getRanksMessages() + .getLocalizable( "ranks_rankup__log_rank_change" ) + .withReplacements( + + sender.getName(), ranks.toString() + ); + + // Print to console for record: + Output.get().logInfo( localManagerLog.localize() ); + + + if ( Prison.get().getPlatform().getConfigBooleanFalse( "broadcast-rankups" ) ) { + + localManagerLog.broadcast(); + + } + else { + + localManagerLog.sendTo( sender ); + } + } protected void ranksRankupCannotAffordMsg( CommandSender sender, RankupResults results ) { - DecimalFormat dFmt = new DecimalFormat("#,##0.00"); - PlayerRank tpRank = results.getPlayerRankTarget(); - Rank tRank = results.getTargetRank(); + + ranksRankupCannotAffordMsg( sender, tpRank ); + } + + protected void ranksRankupCannotAffordMsg( CommandSender sender, + PlayerRank tpRank ) { + + DecimalFormat dFmt = Prison.get().getDecimalFormat("#,##0.00"); + + Rank tRank = tpRank.getRank(); PrisonRanks.getInstance().getRanksMessages() .getLocalizable( "ranks_rankup__rankup_cant_afford" ) .withReplacements( dFmt.format( tpRank == null ? 0 : tpRank.getRankCost()), - tRank == null || tRank.getCurrency() == null ? "" : results.getTargetRank().getCurrency() + tRank == null || tRank.getCurrency() == null ? "" : + " " +tRank.getCurrency() ) .sendTo( sender ); } diff --git a/prison-ranks/src/main/java/tech/mcprison/prison/ranks/commands/RanksCommands.java b/prison-ranks/src/main/java/tech/mcprison/prison/ranks/commands/RanksCommands.java index f3f3abe79..1185492f6 100644 --- a/prison-ranks/src/main/java/tech/mcprison/prison/ranks/commands/RanksCommands.java +++ b/prison-ranks/src/main/java/tech/mcprison/prison/ranks/commands/RanksCommands.java @@ -858,7 +858,7 @@ private ChatDisplay listRanksOnLadder( RankLadder ladder, boolean hasPerm, RankP BulletedListComponent.BulletedListBuilder builder = new BulletedListComponent.BulletedListBuilder(); - DecimalFormat fFmt = new DecimalFormat("#,##0.0000"); + DecimalFormat fFmt = Prison.get().getDecimalFormat("#,##0.0000"); // Here's the deal... With color codes, Java's String.format() cannot detect the correct // length of a tag. So go through all tags, strip the colors, and see how long they are. @@ -1212,7 +1212,7 @@ private ChatDisplay rankInfoDetails( CommandSender sender, Rank rank, String opt // Add the raw ladder rank multiplier here: - DecimalFormat fFmt = new DecimalFormat("#,##0.0000"); + DecimalFormat fFmt = Prison.get().getDecimalFormat("#,##0.0000"); // The following is the rank adjusted rank multiplier @@ -1472,10 +1472,10 @@ public void rankPlayer(CommandSender sender, List msgs = new ArrayList<>(); - DecimalFormat iFmt = new DecimalFormat("#,##0"); - DecimalFormat dFmt = new DecimalFormat("#,##0.00"); - DecimalFormat fFmt = new DecimalFormat("0.0000"); - DecimalFormat pFmt = new DecimalFormat("#,##0.0000"); + DecimalFormat iFmt = Prison.get().getDecimalFormatInt(); + DecimalFormat dFmt = Prison.get().getDecimalFormat("#,##0.00"); + DecimalFormat fFmt = Prison.get().getDecimalFormat("0.0000"); + DecimalFormat pFmt = Prison.get().getDecimalFormat("#,##0.0000"); SimpleDateFormat sdFmt = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss" ); @@ -1518,7 +1518,7 @@ public void rankPlayer(CommandSender sender, if ( rankPlayer != null ) { -// DecimalFormat iFmt = new DecimalFormat("#,##0"); +// DecimalFormat iFmt = Prison.get().getDecimalFormatInt(); // // SimpleDateFormat sdFmt = new SimpleDateFormat( "HH:mm:ss" ); @@ -1804,8 +1804,8 @@ public void rankPlayer(CommandSender sender, // private String formatTimeMs( long timeMs ) { // -// DecimalFormat iFmt = new DecimalFormat("#,##0"); -// DecimalFormat tFmt = new DecimalFormat("00"); +// DecimalFormat iFmt = Prison.get().getDecimalFormatInt(); +// DecimalFormat tFmt = Prison.get().getDecimalFormat("00"); //// SimpleDateFormat sdFmt = new SimpleDateFormat( "HH:mm:ss" ); // // long _sec = 1000; @@ -2127,7 +2127,7 @@ public void rankTopN(CommandSender sender, int posStart = (page - 1) * pageSize; int posEnd = posStart + pageSize; -// DecimalFormat dFmt = new DecimalFormat("#,##0.00"); +// DecimalFormat dFmt = Prison.get().getDecimalFormat("#,##0.00"); // if ( sort ) { diff --git a/prison-ranks/src/main/java/tech/mcprison/prison/ranks/commands/RanksCommandsMessages.java b/prison-ranks/src/main/java/tech/mcprison/prison/ranks/commands/RanksCommandsMessages.java index 4fbcc41a0..0b540619e 100644 --- a/prison-ranks/src/main/java/tech/mcprison/prison/ranks/commands/RanksCommandsMessages.java +++ b/prison-ranks/src/main/java/tech/mcprison/prison/ranks/commands/RanksCommandsMessages.java @@ -2,6 +2,7 @@ import java.text.DecimalFormat; +import tech.mcprison.prison.Prison; import tech.mcprison.prison.commands.BaseCommands; import tech.mcprison.prison.internal.CommandSender; import tech.mcprison.prison.output.LogLevel; @@ -138,7 +139,7 @@ protected void autoConfigNoRanksCreatedMsg( CommandSender sender ) { protected void autoConfigLadderRankCostMultiplierInfoMsg( CommandSender sender, double rankCostMultiplier ) { - DecimalFormat dFmt = new DecimalFormat("0.0000"); + DecimalFormat dFmt = Prison.get().getDecimalFormat("0.0000"); PrisonRanks.getInstance().getRanksMessages() .getLocalizable( "ranks_rankCommands__auto_config_ladder_rank_cost_multiplier_info" ) @@ -245,7 +246,7 @@ protected String ranksListHeaderMsg( String ladderName) { protected String ranksListLadderCostMultiplierMsg( double multiplier ) { - DecimalFormat fFmt = new DecimalFormat("#,##0.0000"); + DecimalFormat fFmt = Prison.get().getDecimalFormat("#,##0.0000"); return PrisonRanks.getInstance().getRanksMessages() .getLocalizable( "ranks_rankCommands__ranks_list_ladder_cost_multplier" ) @@ -369,7 +370,7 @@ protected String ranksInfoLinkedMinesMsg( String mines ) { } protected String ranksInfoCostMsg( double cost ) { - DecimalFormat dFmt = new DecimalFormat("#,##0.00"); + DecimalFormat dFmt = Prison.get().getDecimalFormat("#,##0.00"); return PrisonRanks.getInstance().getRanksMessages() .getLocalizable( "ranks_rankCommands__ranks_info_cost" ) .withReplacements( @@ -386,7 +387,7 @@ protected String ranksInfoCurrencyMsg( String currency ) { } protected String ranksInfoPlayersWithRankMsg( double playerCount ) { - DecimalFormat dFmt = new DecimalFormat("#,##0"); + DecimalFormat dFmt = Prison.get().getDecimalFormatInt(); return PrisonRanks.getInstance().getRanksMessages() .getLocalizable( "ranks_rankCommands__ranks_info_players_with_rank" ) .withReplacements( @@ -416,7 +417,7 @@ protected String ranksInfoRankDeleteToolTipMsg() { protected void rankSetCostSuccessfulMsg( CommandSender sender, String rankName, double cost ) { - DecimalFormat dFmt = new DecimalFormat("#,##0.00"); + DecimalFormat dFmt = Prison.get().getDecimalFormat("#,##0.00"); PrisonRanks.getInstance().getRanksMessages() .getLocalizable( "ranks_rankCommands__rank_set_cost_success" ) .withReplacements( diff --git a/prison-ranks/src/main/java/tech/mcprison/prison/ranks/data/TopNPlayers.java b/prison-ranks/src/main/java/tech/mcprison/prison/ranks/data/TopNPlayers.java index e19114800..869cd16c0 100644 --- a/prison-ranks/src/main/java/tech/mcprison/prison/ranks/data/TopNPlayers.java +++ b/prison-ranks/src/main/java/tech/mcprison/prison/ranks/data/TopNPlayers.java @@ -101,15 +101,26 @@ public File getSaveFile() { return saveFile; } + /** + *

Starts the async task to process the topN players on a regular basis. + * This task can only be submitted if the Ranks module is enabled, which will + * mean that the PlayerManager will be not null. + *

+ * + */ private void launchTopNPlayerUpdateAsyncTask() { - Long delayTicks = Prison.get().getPlatform().getConfigLong( - "topNPlayers.refresh.delay-ticks", DELAY_THIRTY_SECONDS_TICKS ); - Long intervalTicks = Prison.get().getPlatform().getConfigLong( - "topNPlayers.refresh.interval-ticks", INTERVAL_FIVE_MINUTES_TICKS ); - + if ( PrisonRanks.getInstance().getPlayerManager() != null ) { + + Long delayTicks = Prison.get().getPlatform().getConfigLong( + "topNPlayers.refresh.delay-ticks", DELAY_THIRTY_SECONDS_TICKS ); + Long intervalTicks = Prison.get().getPlatform().getConfigLong( + "topNPlayers.refresh.interval-ticks", INTERVAL_FIVE_MINUTES_TICKS ); + + + TopNPlayerUpdateAsyncTask.submitTaskTimerAsync( this, delayTicks, intervalTicks ); + } - TopNPlayerUpdateAsyncTask.submitTaskTimerAsync( this, delayTicks, intervalTicks ); } /** @@ -123,8 +134,28 @@ private void launchTopNPlayerUpdateAsyncTask() { * then this class will be marked as dirty so this loader would know that * it needs to update the save file. It will then save it changes. *

+ * + *

Since topN players is tied to the Ranks module, if the Ranks module is not + * active, then do not try to load the save file since topN cannot work without + * Prison actively processing, and managing, a player and their Prison Rank. + *

+ * */ public void loadSaveFile() { + + // If Ranks module is not loaded, then do not try to load any save file: + if ( PrisonRanks.getInstance().getPlayerManager() != null ) { + // Ranks is not loaded, so reset to empties: + + // Load from file was successful! + setTopNList( new ArrayList<>() ); + setTopNMap( new TreeMap<>() ); + setArchivedList( new ArrayList<>() ); + setArchivedMap( new TreeMap<>() ); + + return; + } + JsonFileIO jfio = new JsonFileIO(); TopNPlayers temp = (TopNPlayers) jfio.readJsonFile( getSaveFile(), this ); @@ -142,7 +173,7 @@ public void loadSaveFile() { // Since loading from a file, some players may now need to be archived: checkArchives(); } - else { + else { // load from file was not successful, probably because there is no file. // So create a new collection of players from the PlayerManager: List players = PrisonRanks.getInstance().getPlayerManager().getPlayers(); @@ -156,7 +187,6 @@ public void loadSaveFile() { // when adding the player data. } - // Sort: sortTopN(); @@ -166,31 +196,45 @@ public void loadSaveFile() { } } + /** + *

This function will force a reload of all players. If something should happen and the + * stats for a player(s) gets messed up, then this would help reset and recalculate everything. + *

+ * + *

TopN is only available if the Ranks module is loaded. If the Ranks Module is not + * active, then this function will bypass any calculation, or reloading of anything. + *

+ * + */ public void forceReloadAllPlayers() { - getTopNList().clear(); - getTopNMap().clear(); - - getArchivedList().clear(); - getArchivedMap().clear(); - - - // load from file was not successful, probably because there is no file. - // So create a new collection of players from the PlayerManager: - List players = PrisonRanks.getInstance().getPlayerManager().getPlayers(); - - for (RankPlayer rankPlayer : players) { + if ( PrisonRanks.getInstance().getPlayerManager() != null ) { + + getTopNList().clear(); + getTopNMap().clear(); + + getArchivedList().clear(); + getArchivedMap().clear(); + + + // load from file was not successful, probably because there is no file. + // So create a new collection of players from the PlayerManager: + List players = PrisonRanks.getInstance().getPlayerManager().getPlayers(); + + for (RankPlayer rankPlayer : players) { + + addPlayerData( rankPlayer ); + } + + this.dirty = true; + + // Sort: + sortTopN(); + + saveToJson(); - addPlayerData( rankPlayer ); } - this.dirty = true; - - // Sort: - sortTopN(); - - saveToJson(); - } public void saveToJson() { @@ -289,6 +333,10 @@ private void addPlayerData( TopNPlayersData topN, PlayerState activePlayerState public void refreshAndSort() { + if ( PrisonRanks.getInstance().getPlayerManager() == null ) { + return; + } + if ( !calculatedRankScores ) { calculateAllRankScores( getTopNList() ); @@ -391,23 +439,26 @@ public void refreshAndSort() { private void calculateAllRankScores( ArrayList topNList ) { - for ( TopNPlayersData topN : topNList ) { - - RankPlayer rPlayer = topN.getrPlayer(); + if ( PrisonRanks.getInstance().getPlayerManager() != null ) { - if ( rPlayer == null ) { - UUID nullUuid = null; - rPlayer = PrisonRanks.getInstance().getPlayerManager().getPlayer( nullUuid, topN.getName() ); - topN.setrPlayer(rPlayer); - } - - if ( rPlayer != null ) { - rPlayer.calculateRankScore(); + for ( TopNPlayersData topN : topNList ) { + + RankPlayer rPlayer = topN.getrPlayer(); + + if ( rPlayer == null ) { + UUID nullUuid = null; + rPlayer = PrisonRanks.getInstance().getPlayerManager().getPlayer( nullUuid, topN.getName() ); + topN.setrPlayer(rPlayer); + } + + if ( rPlayer != null ) { + rPlayer.calculateRankScore(); + + // This will not update lastSeen: + topN.updateRankPlayer( rPlayer ); + } - // This will not update lastSeen: - topN.updateRankPlayer( rPlayer ); } - } } @@ -480,13 +531,19 @@ else if ( getArchivedMap().containsKey( key ) ) { * any of the other player's balances or status, so this has a low-cost sorting. *

* + *

If the Ranks module is not loaded, then this function will be ignored. + *

+ * * @param rPlayer */ public void updatePlayerData( RankPlayer rPlayer ) { - addPlayerData( rPlayer); - - sortTopN(); + if ( PrisonRanks.getInstance().getPlayerManager() != null ) { + + addPlayerData( rPlayer); + + sortTopN(); + } } public int getTopNSize() { @@ -510,46 +567,53 @@ public RankPlayer getTopNRankArchivedPlayer( int rankPosition ) { * a null value. *

* + *

Since TopN is only available when the Ranks module is active, this function + * will bypass any processing if the Ranks module is not loaded, and it will return + * a null value. + *

+ * * @param rankPosition * @return */ private RankPlayer getTopNRankPlayer( int rankPosition, boolean archived ) { RankPlayer rPlayer = null; - ArrayList tList = - archived ? - getArchivedList() : - getTopNList(); - - if ( rankPosition >= 0 && tList.size() > rankPosition ) { - - TopNPlayersData topN = tList.get( rankPosition ); + if ( PrisonRanks.getInstance().getPlayerManager() != null ) { - rPlayer = topN.getrPlayer(); + ArrayList tList = + archived ? + getArchivedList() : + getTopNList(); - if ( rPlayer == null ) { + if ( rankPosition >= 0 && tList.size() > rankPosition ) { - UUID nullUuid = null; - rPlayer = PrisonRanks.getInstance().getPlayerManager() - .getPlayer( nullUuid, topN.getName() ); - } - - // The topN has the last extracted values, so copy them to the rPlayer if - // it has not been updated. This would be good for the archives. - if ( rPlayer != null && topN.getRankScore() != 0 && rPlayer.getRankScore() == 0 ) { - - rPlayer.setRankScore( topN.getRankScore() ); - rPlayer.setRankScorePenalty( topN.getRankScorePenalty() ); + TopNPlayersData topN = tList.get( rankPosition ); + + rPlayer = topN.getrPlayer(); + + if ( rPlayer == null && PrisonRanks.getInstance().getPlayerManager() != null ) { + + UUID nullUuid = null; + rPlayer = PrisonRanks.getInstance().getPlayerManager() + .getPlayer( nullUuid, topN.getName() ); + } - rPlayer.setRankScoreBalance( topN.getBalance() ); - rPlayer.setRankScoreCurrency( topN.getBalanceCurrency() ); + // The topN has the last extracted values, so copy them to the rPlayer if + // it has not been updated. This would be good for the archives. + if ( rPlayer != null && topN.getRankScore() != 0 && rPlayer.getRankScore() == 0 ) { + + rPlayer.setRankScore( topN.getRankScore() ); + rPlayer.setRankScorePenalty( topN.getRankScorePenalty() ); + + rPlayer.setRankScoreBalance( topN.getBalance() ); + rPlayer.setRankScoreCurrency( topN.getBalanceCurrency() ); + + } } - } - return rPlayer; } diff --git a/prison-ranks/src/main/java/tech/mcprison/prison/ranks/managers/LadderManager.java b/prison-ranks/src/main/java/tech/mcprison/prison/ranks/managers/LadderManager.java index 2e9d420f0..b2613746c 100644 --- a/prison-ranks/src/main/java/tech/mcprison/prison/ranks/managers/LadderManager.java +++ b/prison-ranks/src/main/java/tech/mcprison/prison/ranks/managers/LadderManager.java @@ -23,6 +23,7 @@ import java.util.List; import java.util.stream.Collectors; +import tech.mcprison.prison.Prison; import tech.mcprison.prison.output.Output; import tech.mcprison.prison.ranks.PrisonRanks; import tech.mcprison.prison.ranks.data.Rank; @@ -350,7 +351,7 @@ public String printRankLadderInfoHeader() { public String printRankLadderInfoDetail( RankLadder ladder ) { - DecimalFormat dFmt = new DecimalFormat( "#,##0.0000" ); + DecimalFormat dFmt = Prison.get().getDecimalFormat( "#,##0.0000" ); int rankCount = ladder.getRanks() == null ? 0 : ladder.getRanks().size(); diff --git a/prison-ranks/src/main/java/tech/mcprison/prison/ranks/managers/PlayerManager.java b/prison-ranks/src/main/java/tech/mcprison/prison/ranks/managers/PlayerManager.java index e8d0e4c6e..1856f2336 100644 --- a/prison-ranks/src/main/java/tech/mcprison/prison/ranks/managers/PlayerManager.java +++ b/prison-ranks/src/main/java/tech/mcprison/prison/ranks/managers/PlayerManager.java @@ -279,7 +279,9 @@ public RankPlayer getPlayer(UUID uid, String playerName) { RankPlayer results = null; boolean dirty = false; - if ( playerName != null && getPlayersByName().containsKey( playerName ) ) { + playerName = playerName == null ? "" : playerName.trim(); + + if ( !playerName.isEmpty() && getPlayersByName().containsKey( playerName ) ) { results = getPlayersByName().get( playerName ); } @@ -287,7 +289,8 @@ public RankPlayer getPlayer(UUID uid, String playerName) { for ( RankPlayer rankPlayer : players ) { if ( uid != null && rankPlayer.getUUID().equals(uid) || - uid == null && playerName != null && playerName.trim().isEmpty() && + + !playerName.isEmpty() && rankPlayer.getDisplayName() != null && rankPlayer.getDisplayName().equalsIgnoreCase( playerName ) ) { @@ -317,21 +320,8 @@ public RankPlayer getPlayer(UUID uid, String playerName) { // Save if dirty (change or new): if ( dirty && results != null ) { savePlayer( results ); -// try { -// } -// catch ( IOException e ) { -// -// String errorMessage = cannotAddNewPlayer( playerName, e.getMessage() ); -// -// if ( !getPlayerErrors().contains( errorMessage ) ) { -// -// getPlayerErrors().add( errorMessage ); -// Output.get().logError( errorMessage ); -// } -// } } - return results; } @@ -449,6 +439,13 @@ public String getPlayerRankName( RankPlayer rankPlayer, String ladderName ) { } } + if ( sb.length() == 0 && LadderManager.LADDER_PRESTIGES.equals( ladderName ) ) { + // Use config setting for no-prestige-value ladder rank: + + String prestigeEmpty = Prison.get().getPlatform().getConfigString("prestige.no-prestige-value", ""); + sb.append( prestigeEmpty ); + } + return sb.toString(); } @@ -538,6 +535,13 @@ public String getPlayerRankTag( RankPlayer rankPlayer, String ladderName ) { } } + if ( sb.length() == 0 && LadderManager.LADDER_PRESTIGES.equals( ladderName ) ) { + // Use config setting for no-prestige-value ladder rank: + + String prestigeEmpty = Prison.get().getPlatform().getConfigString("prestige.no-prestige-value", ""); + sb.append( prestigeEmpty ); + } + return sb.toString(); } @@ -579,7 +583,7 @@ public String getPlayerNextRankCost( RankPlayer rankPlayer, String ladderName, StringBuilder sb = new StringBuilder(); if ( !rankPlayer.getLadderRanks().isEmpty()) { - DecimalFormat dFmt = new DecimalFormat("#,##0"); + DecimalFormat dFmt = Prison.get().getDecimalFormatInt(); RankPlayerFactory rankPlayerFactory = new RankPlayerFactory(); @@ -662,11 +666,12 @@ private Rank getNextPrestigeRank( RankPlayer rankPlayer, boolean isDefault, Rank return results; } - public String getPlayerNextRankCostPercent( RankPlayer rankPlayer, String ladderName ) { + public String getPlayerNextRankCostPercent( RankPlayer rankPlayer, String ladderName, + PlaceholderAttributeNumberFormat attributeNFormat ) { StringBuilder sb = new StringBuilder(); if ( !rankPlayer.getLadderRanks().isEmpty()) { - DecimalFormat dFmt = new DecimalFormat("#,##0.00"); + DecimalFormat dFmt = Prison.get().getDecimalFormat("#,##0.00"); RankPlayerFactory rankPlayerFactory = new RankPlayerFactory(); @@ -706,7 +711,15 @@ public String getPlayerNextRankCostPercent( RankPlayer rankPlayer, String ladder (cost == 0.0d || balance > cost ? 100.0 : balance / cost * 100.0 ) ); - sb.append( dFmt.format( percent )); + + if ( attributeNFormat != null ) { + + sb.append( attributeNFormat.format( cost ) ); + } + else { + + sb.append( dFmt.format( percent )); + } } } } @@ -722,7 +735,7 @@ public String getPlayerNextRankCostBar( RankPlayer rankPlayer, String ladderName if ( !rankPlayer.getLadderRanks().isEmpty()) { -// DecimalFormat dFmt = new DecimalFormat("#,##0.00"); +// DecimalFormat dFmt = Prison.get().getDecimalFormat("#,##0.00"); RankPlayerFactory rankPlayerFactory = new RankPlayerFactory(); @@ -788,7 +801,7 @@ public String getPlayerNextRankCostRemaining( RankPlayer rankPlayer, String ladd StringBuilder sb = new StringBuilder(); if ( !rankPlayer.getLadderRanks().isEmpty()) { - DecimalFormat dFmt = new DecimalFormat("#,##0.00"); + DecimalFormat dFmt = Prison.get().getDecimalFormat("#,##0.00"); RankPlayerFactory rankPlayerFactory = new RankPlayerFactory(); @@ -858,7 +871,7 @@ public String getPlayerNextRankCostRemainingPercent( RankPlayer rankPlayer, Stri StringBuilder sb = new StringBuilder(); if ( !rankPlayer.getLadderRanks().isEmpty()) { - DecimalFormat dFmt = new DecimalFormat("#,##0"); + DecimalFormat dFmt = Prison.get().getDecimalFormatInt(); RankPlayerFactory rankPlayerFactory = new RankPlayerFactory(); @@ -922,7 +935,7 @@ public String getPlayerNextRankCostRemainingBar( RankPlayer rankPlayer, String l StringBuilder sb = new StringBuilder(); if ( !rankPlayer.getLadderRanks().isEmpty()) { - // DecimalFormat dFmt = new DecimalFormat("#,##0"); + // DecimalFormat dFmt = Prison.get().getDecimalFormatInt(); RankPlayerFactory rankPlayerFactory = new RankPlayerFactory(); @@ -1019,7 +1032,7 @@ private String getPlayerBalance( RankPlayer rankPlayer, String ladderName, // } if ( !rankPlayer.getLadderRanks().isEmpty()) { - DecimalFormat dFmt = new DecimalFormat("#,##0"); + DecimalFormat dFmt = Prison.get().getDecimalFormatInt(); RankPlayerFactory rankPlayerFactory = new RankPlayerFactory(); @@ -1062,7 +1075,7 @@ private String getPlayerAverageEarningsPerMinute( RankPlayer rankPlayer, String if ( !rankPlayer.getLadderRanks().isEmpty()) { - DecimalFormat dFmt = new DecimalFormat("#,##0"); + DecimalFormat dFmt = Prison.get().getDecimalFormatInt(); double epm = PlayerCache.getInstance().getPlayerEarningsPerMinute( rankPlayer ); @@ -1088,7 +1101,7 @@ private String getPlayerTokenBalance( RankPlayer rankPlayer, int formatMode, PlaceholderAttributeNumberFormat attributeNFormat ) { StringBuilder sb = new StringBuilder(); - DecimalFormat dFmt = new DecimalFormat("#,##0"); + DecimalFormat dFmt = Prison.get().getDecimalFormatInt(); long tokens = rankPlayer.getPlayerCachePlayerData().getTokens(); @@ -1137,7 +1150,7 @@ private String getPlayerTokenAverageEarningsPerMinute( RankPlayer rankPlayer, if ( !rankPlayer.getLadderRanks().isEmpty()) { - DecimalFormat dFmt = new DecimalFormat("#,##0"); + DecimalFormat dFmt = Prison.get().getDecimalFormatInt(); double tpm = rankPlayer.getPlayerCachePlayerData().getAverageTokensPerMinute(); @@ -1522,7 +1535,7 @@ public String getTranslatePlayerPlaceHolder( PlaceholderIdentifier identifier ) case prison_rankup_cost_percent: case prison_rcp_laddername: case prison_rankup_cost_percent_laddername: - results = getPlayerNextRankCostPercent( rankPlayer, ladderName ); + results = getPlayerNextRankCostPercent( rankPlayer, ladderName, attributeNFormat ); break; case prison_rcb: @@ -1666,7 +1679,7 @@ public String getTranslatePlayerPlaceHolder( PlaceholderIdentifier identifier ) if ( placeHolder == PrisonPlaceHolders.prison_pbtf || placeHolder == PrisonPlaceHolders.prison_player_blocks_total_formatted ) { - DecimalFormat iFmt = new DecimalFormat("#,##0"); + DecimalFormat iFmt = Prison.get().getDecimalFormatInt(); results = iFmt.format( blocksTotal ); } else { diff --git a/prison-ranks/src/main/java/tech/mcprison/prison/ranks/managers/RankManager.java b/prison-ranks/src/main/java/tech/mcprison/prison/ranks/managers/RankManager.java index 71db7695a..b0d816a6e 100644 --- a/prison-ranks/src/main/java/tech/mcprison/prison/ranks/managers/RankManager.java +++ b/prison-ranks/src/main/java/tech/mcprison/prison/ranks/managers/RankManager.java @@ -24,6 +24,7 @@ import java.util.Optional; import java.util.TreeMap; +import tech.mcprison.prison.Prison; import tech.mcprison.prison.PrisonAPI; import tech.mcprison.prison.integration.EconomyCurrencyIntegration; import tech.mcprison.prison.internal.CommandSender; @@ -679,7 +680,7 @@ private String getRankCost( Rank rank, PlaceholderAttributeNumberFormat attribut double cost = rank.getRawRankCost(); String resultsx = null; - DecimalFormat dFmt = new DecimalFormat("#,##0"); + DecimalFormat dFmt = Prison.get().getDecimalFormatInt(); if ( attributeNFormat != null ) { resultsx = attributeNFormat.format( cost ); } @@ -720,11 +721,15 @@ public String getTranslateRanksPlaceHolder( PlaceholderIdentifier identifier ) { String results = null; PrisonPlaceHolders placeHolder = placeHolderKey.getPlaceholder(); - DecimalFormat dFmt = new DecimalFormat("#,##0"); + DecimalFormat dFmt = Prison.get().getDecimalFormatInt(); + boolean isStatsPlayers = placeHolder.hasFlag( PlaceholderFlags.STATSPLAYERS ); + boolean isStatsRank = placeHolder.hasFlag( PlaceholderFlags.STATSRANKS ); - if ( !placeHolder.hasFlag( PlaceholderFlags.STATSPLAYERS ) && - rank != null && rankPlayer != null ) { + if ( !( isStatsPlayers ) && + rank != null && + ( rankPlayer != null || + rankPlayer == null && isStatsRank ) ) { identifier.setFoundAMatch( true ); @@ -1086,7 +1091,7 @@ else if ( placeHolder == PrisonPlaceHolders.prison_top_player_penalty_raw_nnn_tp case prison_top_rank_balance_name_nnn_rankname: case prison_trbn_nnn_rankname: { - StatsRankPlayerBalanceData stats = rank.getStatsPlayerBlance().getTopStats( 1 ); + StatsRankPlayerBalanceData stats = rank.getStatsPlayerBlance().getTopStats( sequence ); if ( stats != null ) { results = stats.getPlayer() == null ? "" : stats.getPlayer().getName(); @@ -1101,7 +1106,7 @@ else if ( placeHolder == PrisonPlaceHolders.prison_top_player_penalty_raw_nnn_tp case prison_top_rank_balance_score_nnn_rankname: case prison_trbs_nnn_rankname: { - StatsRankPlayerBalanceData stats = rank.getStatsPlayerBlance().getTopStats( 1 ); + StatsRankPlayerBalanceData stats = rank.getStatsPlayerBlance().getTopStats( sequence ); if ( stats != null ) { results = dFmt.format( stats.getScore()); @@ -1116,7 +1121,7 @@ else if ( placeHolder == PrisonPlaceHolders.prison_top_player_penalty_raw_nnn_tp case prison_top_rank_balance_balance_nnn_rankname: case prison_trbb_nnn_rankname: { - StatsRankPlayerBalanceData stats = rank.getStatsPlayerBlance().getTopStats( 1 ); + StatsRankPlayerBalanceData stats = rank.getStatsPlayerBlance().getTopStats( sequence ); if ( stats != null ) { results = stats.getPlayer() == null ? "" : diff --git a/prison-ranks/src/main/java/tech/mcprison/prison/ranks/tasks/RanksStartupPlayerValidationsAsyncTask.java b/prison-ranks/src/main/java/tech/mcprison/prison/ranks/tasks/RanksStartupPlayerValidationsAsyncTask.java index a4cdf427c..f0a7d8754 100644 --- a/prison-ranks/src/main/java/tech/mcprison/prison/ranks/tasks/RanksStartupPlayerValidationsAsyncTask.java +++ b/prison-ranks/src/main/java/tech/mcprison/prison/ranks/tasks/RanksStartupPlayerValidationsAsyncTask.java @@ -42,6 +42,9 @@ public void run() { // Start up the TopNPlayer's collections after all players have been loaded: // NOTE: getting the instance of TopNPlayers must be done "after" player validation. // So that thread needs to initiate it after done validating and fixing all players. + // NOTE: since TopN is based upon Ranks and the associated players, if Ranks module + // is disabled, TopN will not run. Make sure 100% that the PlayerManager has been + // setup before trying to call TopNPlayers.getInstance() or it will never work/start. TopNPlayers.getInstance(); diff --git a/prison-spigot/build.gradle b/prison-spigot/build.gradle index b7349d3bb..4be483662 100644 --- a/prison-spigot/build.gradle +++ b/prison-spigot/build.gradle @@ -41,12 +41,14 @@ repositories { maven { url = "https://repo.codemc.org/repository/maven-public/" } //maven { url = "https://repo.inventivetalent.org/content/groups/public/" } - maven { - url = "https://repo.mvdw-software.be/content/groups/public/" - content { - includeGroup 'be.maximvdw' - } - } + +// NOTE: mvdw support has been removed from prison since PAPI works with it: +// maven { +// url = "https://repo.mvdw-software.be/content/groups/public/" +// content { +// includeGroup 'be.maximvdw' +// } +// } maven { url = 'https://repo.extendedclip.com/content/repositories/placeholderapi/' content { @@ -72,7 +74,7 @@ repositories { } - // maven { url 'https://jitpack.io' } + maven { url 'https://jitpack.io' } // maven { url = 'https://repo.pcgamingfreaks.at/repository/maven-everything' } @@ -104,7 +106,8 @@ dependencies { implementation 'org.apache.commons:commons-lang3:3.12.0' - compileOnly 'me.clip:placeholderapi:2.10.9' + compileOnly 'me.clip:placeholderapi:2.11.2' + //compileOnly 'me.clip:placeholderapi:2.10.9' // Repo may be hosted: https://hub.spigotmc.org/nexus/content/groups/public/ // But do not see v5.0 @@ -116,7 +119,8 @@ dependencies { // implementation 'com.github.cryptomorin:xseries:b95d195482' // https://mvnrepository.com/artifact/com.github.cryptomorin/XSeries - implementation 'com.github.cryptomorin:XSeries:9.0.0' + implementation 'com.github.cryptomorin:XSeries:9.2.0' + //implementation 'com.github.cryptomorin:XSeries:9.0.0' //implementation 'com.github.cryptomorin:XSeries:8.8.0' @@ -140,9 +144,9 @@ dependencies { compileOnly 'net.milkbowl.vault:VaultAPI:1.7' - compileOnly('be.maximvdw:MVdWPlaceholderAPI:2.5.2-SNAPSHOT'){ - exclude group: 'org.spigotmc' - } +// compileOnly('be.maximvdw:MVdWPlaceholderAPI:2.5.2-SNAPSHOT'){ +// exclude group: 'org.spigotmc' +// } // compileOnly 'com.sk89q.worldguard:worldguard-bukkit:7.0.1' @@ -150,10 +154,17 @@ dependencies { // NOTE: This maven repo was failing to be accessable during online builds. So added to the /lib. // https://www.spigotmc.org/resources/nbt-api.7939/ // https://mvnrepository.com/artifact/de.tr7zw/item-nbt-api-plugin - implementation 'de.tr7zw:item-nbt-api-plugin:2.10.0' + implementation 'de.tr7zw:item-nbt-api-plugin:2.11.1' +// implementation 'de.tr7zw:item-nbt-api-plugin:2.10.0' // implementation 'de.tr7zw:item-nbt-api-plugin:2.9.2' + // https://github.com/LoneDev6/API-ItemsAdder#-packages + // https://github.com/LoneDev6/API-ItemsAdder/tags + compileOnly 'com.github.LoneDev6:API-ItemsAdder:3.2.5' + + + compileOnly fileTree(dir: 'lib', include: ['*.jar'], exclude: ['Spiget_v1.4.2.prison-build.jar', // 'CrazyEnchantments-plugin-api.v1.8-Dev-Build-v8.jar', @@ -207,12 +218,15 @@ shadowJar { // include(dependency('org.bstats:bstats-base:2.2.1')) // include(dependency('org.bstats:bstats-bukkit:2.2.1')) - include(dependency('me.clip:placeholderapi:2.10.9')) + include(dependency('me.clip:placeholderapi:2.11.2')) + //include(dependency('me.clip:placeholderapi:2.10.9')) - include(dependency('com.github.cryptomorin:XSeries:9.0.0')) + include(dependency('com.github.cryptomorin:XSeries:9.2.0')) + //include(dependency('com.github.cryptomorin:XSeries:9.0.0')) //include(dependency('com.github.cryptomorin:XSeries:8.8.0')) - include(dependency('de.tr7zw:item-nbt-api-plugin:2.10.0')) + include(dependency('de.tr7zw:item-nbt-api-plugin:2.11.1')) + //include(dependency('de.tr7zw:item-nbt-api-plugin:2.10.0')) //include(dependency('org.inventivetalent.spiget-update:bukkit:1.4.2-SNAPSHOT')) //include(dependency('me.badbones69:crazyenchantments-plugin:1.8-Dev-Build-v8')) diff --git a/prison-spigot/lib/RevEnchantsApi_v11.2.jar b/prison-spigot/lib/RevEnchantsApi_v11.2.jar new file mode 100644 index 000000000..c0347b510 Binary files /dev/null and b/prison-spigot/lib/RevEnchantsApi_v11.2.jar differ diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/SpigotListener.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/SpigotListener.java index 772c02ab8..632d15fc5 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/SpigotListener.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/SpigotListener.java @@ -43,7 +43,6 @@ import tech.mcprison.prison.Prison; import tech.mcprison.prison.internal.events.Cancelable; -import tech.mcprison.prison.internal.events.player.PlayerChatEvent; import tech.mcprison.prison.internal.events.player.PlayerPickUpItemEvent; import tech.mcprison.prison.internal.events.player.PlayerSuffocationEvent; import tech.mcprison.prison.internal.events.player.PrisonPlayerInteractEvent; @@ -56,7 +55,6 @@ import tech.mcprison.prison.spigot.compat.SpigotCompatibility; import tech.mcprison.prison.spigot.game.SpigotPlayer; import tech.mcprison.prison.spigot.game.SpigotWorld; -import tech.mcprison.prison.util.ChatColor; import tech.mcprison.prison.util.Location; import tech.mcprison.prison.util.Text; diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/SpigotPlatform.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/SpigotPlatform.java index 9e945d4da..cc6d16eb1 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/SpigotPlatform.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/SpigotPlatform.java @@ -19,6 +19,7 @@ package tech.mcprison.prison.spigot; import java.io.File; +import java.text.DecimalFormat; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -58,6 +59,8 @@ import tech.mcprison.prison.PrisonCommand.RegisteredPluginsData; import tech.mcprison.prison.autofeatures.AutoFeaturesFileConfig.AutoFeatures; import tech.mcprison.prison.autofeatures.AutoFeaturesWrapper; +import tech.mcprison.prison.backpacks.BackpackEnums.BackpackType; +import tech.mcprison.prison.backpacks.PlayerBackpack; import tech.mcprison.prison.chat.FancyMessage; import tech.mcprison.prison.commands.PluginCommand; import tech.mcprison.prison.convert.ConversionManager; @@ -106,8 +109,11 @@ import tech.mcprison.prison.spigot.autofeatures.events.AutoManagerCrazyEnchants; import tech.mcprison.prison.spigot.autofeatures.events.AutoManagerPrisonEnchants; import tech.mcprison.prison.spigot.autofeatures.events.AutoManagerPrisonsExplosiveBlockBreakEvents; +import tech.mcprison.prison.spigot.autofeatures.events.AutoManagerRevEnchantsExplosiveEvent; +import tech.mcprison.prison.spigot.autofeatures.events.AutoManagerRevEnchantsJackHammerEvent; import tech.mcprison.prison.spigot.autofeatures.events.AutoManagerTokenEnchant; import tech.mcprison.prison.spigot.autofeatures.events.AutoManagerZenchantments; +import tech.mcprison.prison.spigot.backpacks.BackpacksUtil; import tech.mcprison.prison.spigot.block.BlockBreakPriority; import tech.mcprison.prison.spigot.block.SpigotItemStack; import tech.mcprison.prison.spigot.commands.PrisonSpigotSellAllCommands; @@ -121,9 +127,11 @@ import tech.mcprison.prison.spigot.placeholder.SpigotPlaceholders; import tech.mcprison.prison.spigot.scoreboard.SpigotScoreboardManager; import tech.mcprison.prison.spigot.sellall.SellAllBlockData; +import tech.mcprison.prison.spigot.sellall.SellAllUtil; import tech.mcprison.prison.spigot.spiget.BluesSpigetSemVerComparator; import tech.mcprison.prison.spigot.util.ActionBarUtil; import tech.mcprison.prison.spigot.util.SpigotYamlFileIO; +import tech.mcprison.prison.spigot.utils.tasks.PlayerAutoRankupTask; import tech.mcprison.prison.store.Storage; import tech.mcprison.prison.util.Bounds.Edges; import tech.mcprison.prison.util.Location; @@ -410,6 +418,28 @@ else if ( oPlayer == null || oPlayer.getName() == null ) { command.getUsage(), Collections.emptyList() ) { + /** + *

This is the entry point where bukkit passes control over to prison for the + * commands to be executed. + *

+ * + *

This will prevent any command that a player is using from being ran in the + * the excluded worlds. See config.yml file and the section: + * `prisonCommandHandler.exclude-worlds` + *

+ * + *

There are two types of players that run commands... The primary one is + * an online player. Otherwise it's a CommandSender. + *

+ * + *

When the command is actually resolved and the onCommmand() is ran, the + * first thing it checks is to ensure that the command is not within the + * `prisonCommandHander.exclude-non-ops.commands` list of commands, and if it is, then + * it will check all perms agains the CommandSender. The perms it checks are + * the perms tied to the command and the perms listed under the + * `prisonCommandHandler.exclude-non-ops.commands`. + *

+ */ @Override public boolean execute(CommandSender sender, String commandLabel, String[] args) { if (sender instanceof org.bukkit.entity.Player) { @@ -433,8 +463,9 @@ public boolean execute(CommandSender sender, String commandLabel, String[] args) public List tabComplete( CommandSender sender, String alias, String[] args ) throws IllegalArgumentException { + SpigotCommandSender pSender = new SpigotCommandSender( sender ); - List results = Prison.get().getCommandHandler().getTabCompleaterData().check( alias, args ); + List results = Prison.get().getCommandHandler().getTabCompleaterData().check( pSender, alias, args ); // StringBuilder sb = new StringBuilder(); @@ -2056,6 +2087,38 @@ public List getActiveFeatures( boolean showLaddersAndRanks ) { } + Module minesModule = Prison.get().getModuleManager().getModule( "Mines" ).orElseGet( null ); + if ( minesModule != null && + minesModule.getStatus().getStatus() == ModuleStatus.Status.ENABLED ) { + + DecimalFormat dFmt = Prison.get().getDecimalFormatInt(); + + int minesEnabled = 0; + int minesVirtual = 0; + int minesDeleted = 0; + int minesBlocks = 0; + + List mines = PrisonMines.getInstance().getMines(); + for (Mine mine : mines) { + + minesEnabled += mine.isEnabled() ? 1 : 0; + minesVirtual += mine.isVirtual() ? 1 : 0; + minesDeleted += mine.isDeleted() ? 1 : 0; + + minesBlocks += mine.isEnabled() ? mine.getBounds().getTotalBlockCount() : 0; + } + + double blksPerMine = minesEnabled == 0 ? 0 : minesBlocks / (double) minesEnabled; + + String mineDetails = String.format( + "&7Mines Info: &9Enabled: &b%d &9Virtual: &b%d &9Deleted: &b%d &9AvgBlocks/Mine: &b%s", + minesEnabled, minesVirtual, minesDeleted, + dFmt.format(blksPerMine) ); + + results.add( mineDetails ); + } + + // Load the autoFeaturesConfig.yml and blockConvertersConfig.json files: AutoFeaturesWrapper afw = AutoFeaturesWrapper.getInstance(); @@ -2118,6 +2181,26 @@ public List getActiveFeatures( boolean showLaddersAndRanks ) { (isTebeEnabled ? "&2Enabled" : "&cDisabled") ) ); + + String reeePriority = afw.getMessage( AutoFeatures.RevEnchantsExplosiveEventPriority ); + boolean isReeeEnabled = reeePriority != null && !"DISABLED".equalsIgnoreCase( reeePriority ); + BlockBreakPriority reeEventPriority = BlockBreakPriority.fromString( reeePriority ); + results.add( String.format("%s. RevEnchant '&7ExplosiveEvent&3' Priority:&b %s %s", + (isReeeEnabled ? "" : "+" ), + reeEventPriority.name(), + (isReeeEnabled ? "&2Enabled" : "&cDisabled") + ) ); + + String rejhePriority = afw.getMessage( AutoFeatures.RevEnchantsJackHammerEventPriority ); + boolean isRejheEnabled = rejhePriority != null && !"DISABLED".equalsIgnoreCase( rejhePriority ); + BlockBreakPriority rejhEventPriority = BlockBreakPriority.fromString( rejhePriority ); + results.add( String.format("%s. RevEnchant '&7JackHammerEvent&3' Priority:&b %s %s", + (isRejheEnabled ? "" : "+" ), + rejhEventPriority.name(), + (isRejheEnabled ? "&2Enabled" : "&cDisabled") + ) ); + + String cebuePriority = afw.getMessage( AutoFeatures.CrazyEnchantsBlastUseEventPriority ); boolean isCebueEnabled = cebuePriority != null && !"DISABLED".equalsIgnoreCase( cebuePriority ); BlockBreakPriority cebuEventPriority = BlockBreakPriority.fromString( cebuePriority ); @@ -2304,6 +2387,7 @@ else if ( !isBasic ) { display.addText(""); + // Active Modules:x's root Command: &3/prison"); @@ -2488,9 +2572,11 @@ public String dumpEventListenersBlockBreakEvents() { sb.append( "&2. . Prison Internal BlockBreakEvents: " + "tech.mcprison.prison.spigot.SpigotListener\n" ); sb.append( "&2. . Auto Features: " + - "AutoManagerBlockBreakEvents$AutoManagerBlockBreakEventListener\n" ); + "tmpsae.AutoManagerBlockBreakEvents$AutoManagerBlockBreakEventListener\n" ); sb.append( "&2. . Prison's multi-block explosions (bombs): " + - "AutoManagerPrisonsExplosiveBlockBreakEvents$AutoManagerExplosiveBlockBreakEventListener\n" ); + "tmpsae.AutoManagerPrisonsExplosiveBlockBreakEvents$AutoManagerExplosiveBlockBreakEventListener\n" ); + sb.append( "&2. . Prison Abbrv: '&3tmps.&2' = '&3tech..==..mcprison.prison.spigot.&2' & " + + "'&3tmpsae.&2' = '&3tmps..==..autofeatures.events.&2'\n" ); // sb.append( "&2. . Auto Feature Core: Non-AutoManager: " + @@ -2516,10 +2602,25 @@ public String dumpEventListenersBlockBreakEvents() { AutoManagerTokenEnchant tokenEnchant = new AutoManagerTokenEnchant(); tokenEnchant.dumpEventListeners( sb ); + AutoManagerRevEnchantsExplosiveEvent revEnchExplosive = new AutoManagerRevEnchantsExplosiveEvent(); + revEnchExplosive.dumpEventListeners( sb ); + + AutoManagerRevEnchantsJackHammerEvent revEnchJackHammer = new AutoManagerRevEnchantsJackHammerEvent(); + revEnchJackHammer.dumpEventListeners( sb ); + AutoManagerZenchantments zenchantments = new AutoManagerZenchantments(); zenchantments.dumpEventListeners( sb ); - return sb.toString(); + + // Shorten the prison package names: + // 'tmps.' = 'tech.mcprison.prison.spigot.' + // 'tmpsae.' = 'tmps.autofeatures.events.' + String results = sb.toString() + .replace( "tech.mcprison.prison.spigot.", "tmps." ) + .replace( "tmps.autofeatures.events.", "tmpsae." ) + .replace( "..==..", "." ); + + return results; } @Override @@ -2589,12 +2690,26 @@ public List dumpEventListenersList( String eventType, HandlerList handle results.add( String.format( "&8All registered EventListeners (%d):", listeners.length )); + int nMaxLen = 0; + int pMaxLen = 0; + // First find the max length of the name and priority: + for ( RegisteredListener eventListner : listeners ) { + String plugin = eventListner.getPlugin().getName(); + EventPriority priority = eventListner.getPriority(); + if ( plugin.length() > nMaxLen ) { + nMaxLen = plugin.length(); + } + if ( priority.name().length() > pMaxLen ) { + pMaxLen = priority.name().length(); + } + } + for ( RegisteredListener eventListner : listeners ) { String plugin = eventListner.getPlugin().getName(); EventPriority priority = eventListner.getPriority(); String listener = eventListner.getListener().getClass().getName(); - String message = String.format( "&3. Plugin: &7%s %s &3(%s)", + String message = String.format( "&3. Plugin: &7%-" + nMaxLen + "s %-" + pMaxLen + "s &3(%s)", plugin, priority.name(), listener); results.add( message ); @@ -2905,4 +3020,81 @@ private void listMines(tech.mcprison.prison.internal.CommandSender sender, } + @Override + public void sellall( RankPlayer rankPlayer ) { + + if ( SpigotPrison.getInstance().isSellAllEnabled() ) { + + Player player = getPlayer( rankPlayer.getUUID() ).orElse(null); + + if ( player != null ) { + + SpigotPlayer sPlayer = (SpigotPlayer) player; + + final long nanoStart = System.nanoTime(); + boolean success = SellAllUtil.get().sellAllSell( sPlayer.getWrapper(), + false, false, false, true, true, false); + final long nanoStop = System.nanoTime(); + double milliTime = (nanoStop - nanoStart) / 1000000d; + + if ( Output.get().isDebug() ) { + + DecimalFormat dFmt = Prison.get().getDecimalFormat("#,##0.00"); + Output.get().logDebug( "(SpigotPlatform autosell: " + (success ? "success" : "failed") + + " ms: " + dFmt.format( milliTime ) + ") "); + } + + PlayerAutoRankupTask.autoSubmitPlayerRankupTask( sPlayer, null ); + + } + } + } + + + @Override + public RankLadder getRankLadder(String ladderName) { + + RankLadder results = PrisonRanks.getInstance().getLadderManager().getLadder( ladderName ); + return results; + } + + + @Override + public List getPlayerOldBackpacks( Player player ) { + List backpacks = new ArrayList<>(); + + + + SpigotPlayer sPlayer = (SpigotPlayer) + getPlayer( player.getName() ).orElse(null); + + + if ( sPlayer != null && getConfigBooleanFalse( "backpacks" ) && BackpacksUtil.isEnabled() ) { + + BackpacksUtil backpackUtil = BackpacksUtil.get(); + + UUID playerUuid = player.getUUID(); + + for ( String backpackId : backpackUtil.getBackpacksIDs( sPlayer.getWrapper() ) ) { + + PlayerBackpack backpack = new PlayerBackpack( player.getName(), playerUuid.toString(), + BackpackType.inventory, + backpackId, XMaterial.CHEST.name() ); + + int size = backpackUtil.getBackpackSize( playerUuid, backpackId ); + backpack.setInventorySize(size); + + List inventory = backpackUtil.getPrisonBackpackContents( playerUuid, backpackId ); + backpack.setInventory( inventory ); + + + + backpacks.add( backpack ); + + } + } + + return backpacks; + } + } diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/SpigotPrison.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/SpigotPrison.java index 0500e4926..53003fd97 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/SpigotPrison.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/SpigotPrison.java @@ -86,7 +86,6 @@ import tech.mcprison.prison.spigot.permissions.LuckPermissions; import tech.mcprison.prison.spigot.permissions.LuckPerms5; import tech.mcprison.prison.spigot.permissions.VaultPermissions; -import tech.mcprison.prison.spigot.placeholder.MVdWPlaceholderIntegration; import tech.mcprison.prison.spigot.placeholder.PlaceHolderAPIIntegration; import tech.mcprison.prison.spigot.sellall.SellAllUtil; import tech.mcprison.prison.spigot.slime.SlimeBlockFunEventListener; @@ -907,7 +906,13 @@ private void initCommandMap() { private void initIntegrations() { - registerIntegration(new VaultEconomy()); + String preventEconomyVaultUsageKey = "integrations.prevent-economy-vault-usage"; + boolean preventEconomyVaultUsage = Prison.get().getPlatform().getConfigBooleanFalse(preventEconomyVaultUsageKey); + + if ( !preventEconomyVaultUsage ) { + registerIntegration(new VaultEconomy()); + } + registerIntegration(new EssentialsEconomy()); registerIntegration(new SaneEconomy()); registerIntegration(new GemsEconomy()); @@ -916,7 +921,7 @@ private void initIntegrations() { registerIntegration(new LuckPerms5()); registerIntegration(new LuckPermissions()); - registerIntegration(new MVdWPlaceholderIntegration()); +// registerIntegration(new MVdWPlaceholderIntegration()); registerIntegration(new PlaceHolderAPIIntegration()); registerIntegration(new CustomItems()); @@ -951,17 +956,17 @@ public boolean isPluginEnabled( String pluginName ) { */ public void reloadIntegrationsPlaceholders() { - MVdWPlaceholderIntegration ph1 = new MVdWPlaceholderIntegration(); +// MVdWPlaceholderIntegration ph1 = new MVdWPlaceholderIntegration(); PlaceHolderAPIIntegration ph2 = new PlaceHolderAPIIntegration(); - registerIntegration(ph1); +// registerIntegration(ph1); registerIntegration(ph2); - ph1.deferredInitialization(); +// ph1.deferredInitialization(); ph2.deferredInitialization(); } - private void registerIntegration(Integration integration) { + public void registerIntegration(Integration integration) { boolean isRegistered = isIntegrationRegistered( integration ); String version = ( isRegistered ? Bukkit.getPluginManager() diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/SpigotScheduler.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/SpigotScheduler.java index 5b07194a5..f290b4cc4 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/SpigotScheduler.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/SpigotScheduler.java @@ -18,8 +18,13 @@ package tech.mcprison.prison.spigot; +import org.bukkit.Bukkit; import org.bukkit.scheduler.BukkitScheduler; + +import tech.mcprison.prison.Prison; +import tech.mcprison.prison.internal.Player; import tech.mcprison.prison.internal.Scheduler; +import tech.mcprison.prison.spigot.game.SpigotPlayer; /** * @author Faizaan A. Datoo @@ -53,6 +58,32 @@ public int runTaskTimer(Runnable run, long delay, long interval) { public int runTaskTimerAsync(Runnable run, long delay, long interval) { return scheduler.runTaskTimerAsynchronously(plugin, run, delay, interval).getTaskId(); } + + @Override + public void dispatchCommand(Player player, String command) { + + if ( player != null && player instanceof SpigotPlayer ) { + SpigotPlayer sPlayer = (SpigotPlayer) player; + + Bukkit.dispatchCommand( sPlayer.getWrapper(), command ); + } + } + + @Override + public void performCommand(Player player, String command) { + + if ( player != null ) { + + Player p = Prison.get().getPlatform().getPlayer( player.getUUID() ).orElse( null ); + + if ( p != null && p instanceof SpigotPlayer ) { + + SpigotPlayer sPlayer = (SpigotPlayer) p; + + sPlayer.getWrapper().performCommand( command ); + } + } + } @Override public void cancelTask(int taskId) { diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/SpigotUtil.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/SpigotUtil.java index 40d0eab94..e991cbefd 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/SpigotUtil.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/SpigotUtil.java @@ -249,21 +249,22 @@ public static HashMap addItemToPlayerInventory( if (bpUtil.isMultipleBackpacksEnabled()) { for (String id : bpUtil.getBackpacksIDs(player)) { if (overflow.size() > 0) { - if (id == null) { - Inventory inv = bpUtil.getBackpack(player); - overflow = inv.addItem(overflow.values().toArray(new ItemStack[0])); - bpUtil.setInventory(player, inv); - } else { +// if (id == null) { +// Inventory inv = bpUtil.getBackpack(player); +// overflow = inv.addItem(overflow.values().toArray(new ItemStack[0])); +// bpUtil.setInventory(player, inv); +// } else { Inventory inv = bpUtil.getBackpack(player, id); overflow = inv.addItem(overflow.values().toArray(new ItemStack[0])); bpUtil.setInventory(player, inv, id); - } +// } } } } else { - Inventory inv = bpUtil.getBackpack(player); + String id = null; + Inventory inv = bpUtil.getBackpack(player, id); overflow = inv.addItem(overflow.values().toArray(new ItemStack[0])); - bpUtil.setInventory(player, inv); + bpUtil.setInventory(player, inv, id); } } } @@ -386,9 +387,10 @@ public static int itemStackRemoveAll(Player player, XMaterial xMat ) { // Insert overflow in to Prison's backpack: if ( SpigotPrison.getInstance().getConfig().getString("backpacks").equalsIgnoreCase("true")) { - Inventory inv = BackpacksUtil.get().getBackpack(player); + String id = null; + Inventory inv = BackpacksUtil.get().getBackpack(player, id); removed += itemStackRemoveAll( xMat, inv ); - BackpacksUtil.get().setInventory( player, inv ); + BackpacksUtil.get().setInventory( player, inv, id ); } diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/api/PrisonMinesBlockBreakEvent.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/api/PrisonMinesBlockBreakEvent.java index fce14d27f..f979ef8a5 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/api/PrisonMinesBlockBreakEvent.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/api/PrisonMinesBlockBreakEvent.java @@ -126,17 +126,29 @@ public class PrisonMinesBlockBreakEvent private List unprocessedRawBlocks; + + private StringBuilder debugInfo; + - public PrisonMinesBlockBreakEvent( Block theBlock, Player player, - SpigotBlock spigotBlock, SpigotPlayer spigotPlayer, - BlockBreakPriority bbPriority, -// boolean monitor, boolean blockEventsOnly, - BlockEventType blockEventType, String triggered) { + public PrisonMinesBlockBreakEvent( + Block theBlock, Player player, + Mine mine, +// SpigotBlock spigotBlock, SpigotPlayer spigotPlayer, + BlockBreakPriority bbPriority, +// boolean monitor, boolean blockEventsOnly, + BlockEventType blockEventType, String triggered, + StringBuilder debugInfo ) { super( theBlock, player ); - this.spigotBlock = spigotBlock; - this.spigotPlayer = spigotPlayer; + this.mine = mine; + + // Need to wrap in a Prison block so it can be used with the mines: + SpigotBlock sBlock = SpigotBlock.getSpigotBlock( theBlock ); + SpigotPlayer sPlayer = new SpigotPlayer( player ); + + this.spigotBlock = sBlock; + this.spigotPlayer = sPlayer; this.itemInHand = SpigotCompatibility.getInstance().getPrisonItemInMainHand( player ); @@ -154,13 +166,17 @@ public PrisonMinesBlockBreakEvent( Block theBlock, Player player, this.bukkitDrops = new ArrayList<>(); + this.debugInfo = debugInfo; + } public PrisonMinesBlockBreakEvent( Block theBlock, Player player, Mine mine, SpigotBlock spigotBlock, List explodedBlocks, BlockEventType blockEventType, - String triggered ) + String triggered, + StringBuilder debugInfo + ) { super( theBlock, player ); @@ -180,6 +196,8 @@ public PrisonMinesBlockBreakEvent( Block theBlock, Player player, this.bukkitDrops = new ArrayList<>(); + this.debugInfo = debugInfo; + } /** @@ -399,4 +417,11 @@ public static HandlerList getHandlerList() { return handlers; } + public StringBuilder getDebugInfo() { + return debugInfo; + } + public void setDebugInfo(StringBuilder debugInfo) { + this.debugInfo = debugInfo; + } + } diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/api/PrisonSpigotAPI.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/api/PrisonSpigotAPI.java index cccccd0b7..a20dc07c9 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/api/PrisonSpigotAPI.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/api/PrisonSpigotAPI.java @@ -4,8 +4,10 @@ import java.util.List; import java.util.Optional; import java.util.TreeMap; +import java.util.UUID; import org.bukkit.Material; +import org.bukkit.OfflinePlayer; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.entity.Player; @@ -32,6 +34,7 @@ import tech.mcprison.prison.spigot.game.SpigotPlayer; import tech.mcprison.prison.spigot.game.SpigotWorld; import tech.mcprison.prison.spigot.sellall.SellAllUtil; +import tech.mcprison.prison.util.ChatColor; import tech.mcprison.prison.util.Location; /** @@ -624,4 +627,49 @@ public void setTokensAdmin( Player player, long amount ) { } + /** + *

This function will translate placeholders, but only the specified placeholder. + * This cannot contain any placeholder escape characters. + *

+ * + * @param player + * @param identifier + * @return + */ + public String getPrisonPlaceholder( OfflinePlayer player, String identifier) { + +// if ( !identifier.toLowerCase().startsWith( PlaceholderManager.PRISON_PLACEHOLDER_PREFIX_EXTENDED ) ) { +// identifier = PlaceholderManager.PRISON_PLACEHOLDER_PREFIX_EXTENDED + identifier; +// } + + UUID playerUuid = player.getUniqueId(); + String results = Prison.get().getPlatform().getPlaceholders() + .placeholderTranslate( playerUuid, player.getName(), identifier ); + + return ChatColor.translateAlternateColorCodes( '&', results); + } + + /** + *

This function will translate placeholders, and text with placeholders within the text. + * You can use any placeholder escape character as long as they are: `% %` or `{ }`. + * This can contain multiple placeholders too. This can also include placeholder attributes. + *

+ * + * @param player + * @param identifier + * @return + */ + public String getPrisonPlaceholderFullText( OfflinePlayer player, String identifier) { + +// if ( !identifier.toLowerCase().startsWith( PlaceholderManager.PRISON_PLACEHOLDER_PREFIX_EXTENDED ) ) { +// identifier = PlaceholderManager.PRISON_PLACEHOLDER_PREFIX_EXTENDED + identifier; +// } + + UUID playerUuid = player.getUniqueId(); + String results = Prison.get().getPlatform().getPlaceholders() + .placeholderTranslateText( playerUuid, player.getName(), identifier ); + + return ChatColor.translateAlternateColorCodes( '&', results); + } + } diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/autofeatures/AutoManagerFeatures.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/autofeatures/AutoManagerFeatures.java index 1d0ca15ef..f74b5c5b3 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/autofeatures/AutoManagerFeatures.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/autofeatures/AutoManagerFeatures.java @@ -18,6 +18,8 @@ import org.bukkit.entity.ArmorStand; import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; +import org.bukkit.event.HandlerList; +import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; @@ -29,18 +31,26 @@ import tech.mcprison.prison.internal.block.PrisonBlock; import tech.mcprison.prison.internal.block.PrisonBlock.PrisonBlockType; import tech.mcprison.prison.mines.data.Mine; +import tech.mcprison.prison.output.ChatDisplay; import tech.mcprison.prison.output.Output; import tech.mcprison.prison.output.Output.DebugTarget; import tech.mcprison.prison.spigot.SpigotPrison; import tech.mcprison.prison.spigot.SpigotUtil; import tech.mcprison.prison.spigot.api.PrisonMinesBlockBreakEvent; +import tech.mcprison.prison.spigot.block.BlockBreakPriority; import tech.mcprison.prison.spigot.block.OnBlockBreakEventCore; +import tech.mcprison.prison.spigot.block.OnBlockBreakExternalEvents; import tech.mcprison.prison.spigot.block.SpigotBlock; import tech.mcprison.prison.spigot.block.SpigotItemStack; import tech.mcprison.prison.spigot.compat.SpigotCompatibility; +import tech.mcprison.prison.spigot.game.SpigotHandlerList; import tech.mcprison.prison.spigot.game.SpigotPlayer; import tech.mcprison.prison.spigot.sellall.SellAllUtil; import tech.mcprison.prison.spigot.spiget.BluesSpigetSemVerComparator; +import tech.mcprison.prison.spigot.utils.tasks.PlayerAutoRankupTask; +import tech.mcprison.prison.tasks.PrisonCommandTaskData; +import tech.mcprison.prison.tasks.PrisonCommandTaskData.TaskMode; +import tech.mcprison.prison.tasks.PrisonCommandTasks; import tech.mcprison.prison.util.Text; /** @@ -66,12 +76,238 @@ public AutoManagerFeatures() { setup(); } + public enum EventListenerCancelBy { + none, + event, + drops; + } private void setup() { + + // Register all external events such as mcMMO, EZBlocks, and Quests: + OnBlockBreakExternalEvents.getInstance().registerAllExternalEvents(); + } + /** + *

NOTE: Check for the ACCESS priority and if someone does not have access, then return + * with a cancel on the event. Both ACCESSBLOCKEVENTS and ACCESSMONITOR will be + * converted to just ACCESS at this point, and the other part will run under either + * BLOCKEVENTS or MONITOR. + *

+ * + * @param pmEvent + * @param start + * @return + */ + protected boolean checkIfNoAccess( PrisonMinesBlockBreakEvent pmEvent, double start ) { + boolean results = false; + + // NOTE: Check for the ACCESS priority and if someone does not have access, then return + // with a cancel on the event. Both ACCESSBLOCKEVENTS and ACCESSMONITOR will be + // converted to just ACCESS at this point, and the other part will run under either + // BLOCKEVENTS or MONITOR. + if ( pmEvent.getBbPriority() == BlockBreakPriority.ACCESS && pmEvent.getMine() != null && + !pmEvent.getMine().hasMiningAccess( pmEvent.getSpigotPlayer() )) { + + String message = String.format( "(&cACCESS fail: player %s does not have access to " + + "mine %s&3. Event canceled) ", + pmEvent.getSpigotPlayer().getName(), + pmEvent.getMine().getTag() ); + pmEvent.getDebugInfo().append( message ); + + printDebugInfo( pmEvent, start ); + + + if ( pmEvent.getSpigotPlayer() != null && + isBoolean( AutoFeatures.eventPriorityACCESSFailureTPToCurrentMine ) ) { + // run the `/mines tp` command for the player which will TP them to a + // mine they can access: + + String debugInfo = String.format( + "ACCESS failed: teleport %s to valid mine.", + pmEvent.getSpigotPlayer().getName() ); + + PrisonCommandTaskData cmdTask = new PrisonCommandTaskData( debugInfo, + "mines tp", 0 ); + cmdTask.setTaskMode( TaskMode.syncPlayer ); + + PrisonCommandTasks.submitTasks( pmEvent.getSpigotPlayer(), cmdTask ); + + } + + results = true; + } + + return results; + } + + /** + *

Prints out the debugInfo if it has anything to print. + *

+ * + * @param pmEvent + * @param start + */ + protected void printDebugInfo( PrisonMinesBlockBreakEvent pmEvent, double start ) { + if ( pmEvent != null && pmEvent.getDebugInfo().length() > 0 ) { + + long stop = System.nanoTime(); + pmEvent.getDebugInfo().append( " [" ).append( (stop - start) / 1000000d ).append( " ms]" ); + + Output.get().logDebug( DebugTarget.blockBreak, pmEvent.getDebugInfo().toString() ); + } + } + + + /** + *

This provides for the basic dump of the event listeners. + *

+ * + * @param handlers + * @param bbPriority + * @param sb + */ + protected void dumpEventListenersCore( String title, HandlerList handlers, BlockBreakPriority bbPriority, + StringBuilder sb ) { + + String cdTitle = String.format( + "%s (&7%s&2)", + title, + ( bbPriority == null ? "--none--" : bbPriority.name()) ); + + ChatDisplay eventDisplay = Prison.get().getPlatform().dumpEventListenersChatDisplay( + cdTitle, + new SpigotHandlerList( handlers ) ); + + if ( eventDisplay != null ) { + sb.append( eventDisplay.toStringBuilder() ); + sb.append( "\n" ); + } + + + if ( bbPriority.isComponentCompound() ) { + StringBuilder sbCP = new StringBuilder(); + for ( BlockBreakPriority bbp : bbPriority.getComponentPriorities() ) { + if ( sbCP.length() > 0 ) { + sbCP.append( ", " ); + } + sbCP.append( "'" ).append( bbp.name() ).append( "'" ); + } + + String msg = String.format( "&2Note '&7%s&2' is a compound of: [&7%s&2]", + bbPriority.name(), + sbCP ); + + sb.append( msg ).append( "\n" ); + } + + + } + + /** + *

For the event handlers that implement the BlockBreakEvent, this allows + * the other plugins to also process the event if forced. + *

+ * + * @param pmEvent + * @param debugInfo + * @param e + */ + protected void processPMBBExternalEvents( PrisonMinesBlockBreakEvent pmEvent, + BlockBreakEvent e ) { + + if ( pmEvent.getMine() != null || pmEvent.getMine() == null && + !isBoolean( AutoFeatures.pickupLimitToMines ) ) { + + // check all external events such as mcMMO and EZBlocks: + pmEvent.getDebugInfo().append( + OnBlockBreakExternalEvents.getInstance().checkAllExternalEvents( e ) ); + + } + + } + + + protected EventListenerCancelBy processPMBBEvent(PrisonMinesBlockBreakEvent pmEvent ) { + + EventListenerCancelBy cancelBy = EventListenerCancelBy.none; + + // This is where the processing actually happens: + if ( pmEvent.getMine() != null || pmEvent.getMine() == null && + !isBoolean( AutoFeatures.pickupLimitToMines ) ) { + + pmEvent.getDebugInfo().append( "(normal processing initiating) " ); + + // Set the mine's PrisonBlockTypes for the block. Used to identify custom blocks. + // Needed since processing of the block will lose track of which mine it came from. + if ( pmEvent.getMine() != null ) { + pmEvent.getSpigotBlock().setPrisonBlockTypes( pmEvent.getMine().getPrisonBlockTypes() ); + } + + // check all external events such as mcMMO and EZBlocks: +// debugInfo.append( +// OnBlockBreakExternalEvents.getInstance().checkAllExternalEvents( e ) ); + + List explodedBlocks = new ArrayList<>(); + pmEvent.setExplodedBlocks( explodedBlocks ); +// String triggered = null; + +// PrisonMinesBlockBreakEvent pmbbEvent = new PrisonMinesBlockBreakEvent( e.getBlock(), e.getPlayer(), +// pmEvent.getMine(), sBlock, explodedBlocks, BlockEventType.blockBreak, triggered ); + Bukkit.getServer().getPluginManager().callEvent( pmEvent ); + if ( pmEvent.isCancelled() ) { + pmEvent.getDebugInfo().append( + "(normal processing: PrisonMinesBlockBreakEvent was canceled by another plugin!) " ); + } + else { + + // Cancel drops if so configured: + if ( isBoolean( AutoFeatures.cancelAllBlockEventBlockDrops ) ) { + + cancelBy = EventListenerCancelBy.drops; + + } + + // doAction returns a boolean that indicates if the event should be canceled or not: + if ( doAction( pmEvent ) ) { +// if ( doAction( sBlock, pmEvent.getMine(), pmEvent.getPlayer(), debugInfo ) ) { + + if ( isBoolean( AutoFeatures.cancelAllBlockBreakEvents ) ) { + cancelBy = EventListenerCancelBy.event; + } + else { + + pmEvent.getDebugInfo().append( "(event not canceled) " ); + } + + finalizeBreakTheBlocks( pmEvent ); + + doBlockEvents( pmEvent ); + + } + else { + + pmEvent.getDebugInfo().append( "(doAction failed without details) " ); + } + + } + + + pmEvent.getDebugInfo().append( "(normal processing completed) " ); + } + else { + + pmEvent.getDebugInfo().append( "(logic bypass) " ); + } + return cancelBy; + } + + + + /** *

If the fortune level is zero, then this function will always return a value of one. *

@@ -167,8 +403,8 @@ protected short getFortune(SpigotItemStack itemInHand){ * */ @Override - public boolean doAction( PrisonMinesBlockBreakEvent pmEvent, StringBuilder debugInfo ) { - return applyAutoEvents( pmEvent, debugInfo ); + public boolean doAction( PrisonMinesBlockBreakEvent pmEvent ) { + return applyAutoEvents( pmEvent ); } @@ -205,7 +441,7 @@ public boolean doAction( PrisonMinesBlockBreakEvent pmEvent, StringBuilder debug - private int applyAutoEventsDetails( PrisonMinesBlockBreakEvent pmEvent, StringBuilder debugInfo ) { + private int applyAutoEventsDetails( PrisonMinesBlockBreakEvent pmEvent ) { int totalDrops = 0; Player player = pmEvent.getPlayer(); @@ -254,15 +490,15 @@ private int applyAutoEventsDetails( PrisonMinesBlockBreakEvent pmEvent, StringBu if ( Output.get().isDebug( DebugTarget.blockBreak ) ) { - debugInfo.append( "(applyAutoEvents: " ) + pmEvent.getDebugInfo().append( "(applyAutoEvents: " ) .append( pmEvent.getSpigotBlock().getBlockName() ); if ( !isAutoFeaturesEnabled ) { - debugInfo.append("isAutoFeaturesEnabled=false (disabled)"); + pmEvent.getDebugInfo().append("isAutoFeaturesEnabled=false (disabled)"); } else { - debugInfo + pmEvent.getDebugInfo() .append( " Pickup [") .append( isAutoPickup ? "enabled: " : "disabled:" ) .append( lorePickup ? "lore " : "" ) @@ -289,7 +525,7 @@ private int applyAutoEventsDetails( PrisonMinesBlockBreakEvent pmEvent, StringBu } - debugInfo + pmEvent.getDebugInfo() .append( ")" ); } @@ -302,7 +538,7 @@ private int applyAutoEventsDetails( PrisonMinesBlockBreakEvent pmEvent, StringBu if ( isAutoPickup ) { // processing auto pickup - totalDrops = autoFeaturePickup( pmEvent, isAutoSmelt, isAutoBlock, debugInfo ); + totalDrops = autoFeaturePickup( pmEvent, isAutoSmelt, isAutoBlock, pmEvent.getDebugInfo() ); // count = autoFeaturePickup( pmEvent.getSpigotBlock(), player, itemInHand, isAutoSmelt, isAutoBlock, debugInfo ); // Cannot set to air yet, or auto smelt and auto block will only get AIR: @@ -312,7 +548,7 @@ private int applyAutoEventsDetails( PrisonMinesBlockBreakEvent pmEvent, StringBu // Need to check to see if normal drops should be processed: if ( configNormalDrop ) { - debugInfo + pmEvent.getDebugInfo() .append( "(NormalDrop handling enabled: " ) .append( "normalDropSmelt[" ) .append( configNormalDropSmelt ? "enabled" : "disabled" ) @@ -324,11 +560,11 @@ private int applyAutoEventsDetails( PrisonMinesBlockBreakEvent pmEvent, StringBu // process normal drops here: - totalDrops = calculateNormalDrop( pmEvent, debugInfo ); + totalDrops = calculateNormalDrop( pmEvent ); } else { - debugInfo.append(" [Warning: normalDrop handling is disabled] " ); + pmEvent.getDebugInfo().append(" [Warning: normalDrop handling is disabled] " ); } } @@ -406,14 +642,14 @@ private int applyAutoEventsDetails( PrisonMinesBlockBreakEvent pmEvent, StringBu * @param e * @param mine */ - private boolean applyAutoEvents( PrisonMinesBlockBreakEvent pmEvent, StringBuilder debugInfo ) { + private boolean applyAutoEvents( PrisonMinesBlockBreakEvent pmEvent ) { // boolean success = false; - int totalDrops = applyAutoEventsDetails( pmEvent, debugInfo ); + int totalDrops = applyAutoEventsDetails( pmEvent ); - debugInfo.append( "(autoEvents totalDrops: " + totalDrops + ") "); + pmEvent.getDebugInfo().append( "(autoEvents totalDrops: " + totalDrops + ") "); - return applyDropsBlockBreakage( pmEvent, totalDrops, debugInfo ); + return applyDropsBlockBreakage( pmEvent, totalDrops ); // debugInfo.append( "(doAction autoManager applyAutoEvents multi-blocks: " + pmEvent.getExplodedBlocks().size() + ") "); // @@ -536,8 +772,8 @@ protected int autoPickup( PrisonMinesBlockBreakEvent pmEvent, } - DecimalFormat fFmt = new DecimalFormat("#,##0.0000"); - DecimalFormat dFmt = new DecimalFormat("#,##0.00"); + DecimalFormat fFmt = Prison.get().getDecimalFormat("#,##0.0000"); + DecimalFormat dFmt = Prison.get().getDecimalFormat("#,##0.00"); double autosellTotal = 0; double autosellUnsellableCount = 0; @@ -674,7 +910,7 @@ protected int autoPickup( PrisonMinesBlockBreakEvent pmEvent, - public int calculateNormalDrop( PrisonMinesBlockBreakEvent pmEvent, StringBuilder debugInfo ) { + public int calculateNormalDrop( PrisonMinesBlockBreakEvent pmEvent ) { // Count should be the total number of items that are to be "dropped". // So effectively it will be the sum of all bukkitDrops counts. @@ -696,7 +932,7 @@ public int calculateNormalDrop( PrisonMinesBlockBreakEvent pmEvent, StringBuilde if (drops != null && drops.size() > 0 ) { - debugInfo.append( "[normalDrops]" ); + pmEvent.getDebugInfo().append( "[normalDrops]" ); // Need better drop calculation that is not using the getDrops function. short fortuneLevel = getFortune( pmEvent.getItemInHand() ); @@ -723,13 +959,13 @@ public int calculateNormalDrop( PrisonMinesBlockBreakEvent pmEvent, StringBuilde if ( isBoolean( AutoFeatures.normalDropSmelt ) ) { - debugInfo.append( "(normSmelting: itemStacks)" ); + pmEvent.getDebugInfo().append( "(normSmelting: itemStacks)" ); normalDropSmelt( drops ); } if ( isBoolean( AutoFeatures.normalDropBlock ) ) { - debugInfo.append( "(normBlocking: itemStacks)" ); + pmEvent.getDebugInfo().append( "(normBlocking: itemStacks)" ); normalDropBlock( drops ); } @@ -763,7 +999,7 @@ public int calculateNormalDrop( PrisonMinesBlockBreakEvent pmEvent, StringBuilde autosellTotal += amount; if ( amount != 0 ) { - debugInfo.append( "(sold: " + itemStack.getName() + " qty: " + itemStack.getAmount() + " value: " + amount + ") "); + pmEvent.getDebugInfo().append( "(sold: " + itemStack.getName() + " qty: " + itemStack.getAmount() + " value: " + amount + ") "); // Set to zero quantity since they have all been sold. itemStack.setAmount( 0 ); @@ -781,7 +1017,7 @@ public int calculateNormalDrop( PrisonMinesBlockBreakEvent pmEvent, StringBuilde double amount = SellAllUtil.get().sellAllSell( player, itemStack, true, false, false ); autosellTotal += amount; - debugInfo.append( "(adding: " + itemStack.getName() + " qty: " + itemStack.getAmount() + " value: " + amount + ") "); + pmEvent.getDebugInfo().append( "(adding: " + itemStack.getName() + " qty: " + itemStack.getAmount() + " value: " + amount + ") "); } dropAtBlock( itemStack, pmEvent.getSpigotBlock() ); @@ -793,7 +1029,7 @@ public int calculateNormalDrop( PrisonMinesBlockBreakEvent pmEvent, StringBuilde if ( count > 0 || autosellTotal > 0 ) { - debugInfo.append( "[normalDrops total: qty: " + count + " value: " + autosellTotal + ") "); + pmEvent.getDebugInfo().append( "[normalDrops total: qty: " + count + " value: " + autosellTotal + ") "); } @@ -1051,8 +1287,8 @@ protected void dropExtra( HashMap extra, Player player if ( amount > 0d ) { - DecimalFormat fFmt = new DecimalFormat("#,##0.0000"); - DecimalFormat dFmt = new DecimalFormat("#,##0.00"); + DecimalFormat fFmt = Prison.get().getDecimalFormat("#,##0.0000"); + DecimalFormat dFmt = Prison.get().getDecimalFormat("#,##0.00"); debugInfo.append( "[dropExtra sellall: value: " + dFmt.format( amount ) ); @@ -1064,6 +1300,9 @@ protected void dropExtra( HashMap extra, Player player } debugInfo.append( " ] " ); + + SpigotPlayer sPlayer = new SpigotPlayer( player ); + PlayerAutoRankupTask.autoSubmitPlayerRankupTask( sPlayer, debugInfo ); } } @@ -1723,7 +1962,8 @@ protected void normalDropSmelt( List drops ) { Set xMats = new HashSet<>(); for ( SpigotItemStack sItemStack : drops ) { - if ( sItemStack.getMaterial().getBlockType() == PrisonBlockType.CustomItems ) { + if ( sItemStack.getMaterial().getBlockType() == PrisonBlockType.CustomItems || + sItemStack.getMaterial().getBlockType() == PrisonBlockType.ItemsAdder ) { // cannot smelt custom blocks so skip XMaterial: continue; } @@ -1864,7 +2104,8 @@ protected void normalDropBlock( List drops ) { Set xMats = new HashSet<>(); for ( SpigotItemStack sItemStack : drops ) { - if ( sItemStack.getMaterial().getBlockType() == PrisonBlockType.CustomItems ) { + if ( sItemStack.getMaterial().getBlockType() == PrisonBlockType.CustomItems || + sItemStack.getMaterial().getBlockType() == PrisonBlockType.ItemsAdder ) { // cannot block custom blocks so skip XMaterial: continue; } diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/autofeatures/events/AutoManagerBlockBreakEvents.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/autofeatures/events/AutoManagerBlockBreakEvents.java index 075b84026..65c296129 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/autofeatures/events/AutoManagerBlockBreakEvents.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/autofeatures/events/AutoManagerBlockBreakEvents.java @@ -1,35 +1,26 @@ package tech.mcprison.prison.spigot.autofeatures.events; -import java.util.ArrayList; -import java.util.List; - import org.bukkit.Bukkit; import org.bukkit.block.Block; import org.bukkit.entity.Player; import org.bukkit.event.Event; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; +import org.bukkit.event.HandlerList; import org.bukkit.event.Listener; import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.inventory.ItemStack; import org.bukkit.plugin.EventExecutor; import org.bukkit.plugin.PluginManager; -import tech.mcprison.prison.Prison; import tech.mcprison.prison.autofeatures.AutoFeaturesFileConfig.AutoFeatures; import tech.mcprison.prison.autofeatures.AutoFeaturesWrapper; import tech.mcprison.prison.mines.features.MineBlockEvent.BlockEventType; -import tech.mcprison.prison.output.ChatDisplay; import tech.mcprison.prison.output.Output; -import tech.mcprison.prison.output.Output.DebugTarget; import tech.mcprison.prison.spigot.SpigotPrison; import tech.mcprison.prison.spigot.api.PrisonMinesBlockBreakEvent; import tech.mcprison.prison.spigot.autofeatures.AutoManagerFeatures; import tech.mcprison.prison.spigot.block.BlockBreakPriority; -import tech.mcprison.prison.spigot.block.OnBlockBreakExternalEvents; -import tech.mcprison.prison.spigot.block.SpigotBlock; -import tech.mcprison.prison.spigot.game.SpigotHandlerList; -import tech.mcprison.prison.spigot.game.SpigotPlayer; public class AutoManagerBlockBreakEvents @@ -40,8 +31,12 @@ public class AutoManagerBlockBreakEvents public AutoManagerBlockBreakEvents() { super(); - } + public AutoManagerBlockBreakEvents( BlockBreakPriority bbPriority ) { + super(); + + this.bbPriority = bbPriority; + } public BlockBreakPriority getBbPriority() { @@ -55,28 +50,30 @@ public void setBbPriority( BlockBreakPriority bbPriority ) { public void registerEvents() { initialize(); - } public class AutoManagerBlockBreakEventListener extends AutoManagerBlockBreakEvents implements Listener { + + public AutoManagerBlockBreakEventListener( BlockBreakPriority bbPriority ) { + super( bbPriority ); + } @EventHandler(priority=EventPriority.NORMAL) public void onBlockBreak( BlockBreakEvent e, BlockBreakPriority bbPriority ) { - if ( isDisabled( e.getBlock().getLocation().getWorld().getName() ) ) { + if ( isDisabled( e.getBlock().getLocation().getWorld().getName() ) || + bbPriority.isDisabled() ) { return; } handleBlockBreakEvent( e, bbPriority ); -// genericBlockEventAutoManager( e ); } @Override protected int checkBonusXp(Player player, Block block, ItemStack item) { - // TODO Auto-generated method stub return 0; } } @@ -95,33 +92,23 @@ public void initialize() { Output.get().logInfo( "AutoManager: Trying to register BlockBreakEvent" ); String eP = getMessage( AutoFeatures.blockBreakEventPriority ); - setBbPriority( BlockBreakPriority.fromString( eP ) ); + BlockBreakPriority bbPriority = BlockBreakPriority.fromString( eP ); + + setBbPriority( bbPriority ); + if ( getBbPriority() != BlockBreakPriority.DISABLED ) { - - SpigotPrison prison = SpigotPrison.getInstance(); - PluginManager pm = Bukkit.getServer().getPluginManager(); - EventPriority ePriority = getBbPriority().getBukkitEventPriority(); - - AutoManagerBlockBreakEventListener autoManagerlListener = - new AutoManagerBlockBreakEventListener(); - - - pm.registerEvent(BlockBreakEvent.class, autoManagerlListener, ePriority, - new EventExecutor() { - public void execute(Listener l, Event e) { - if ( l instanceof AutoManagerBlockBreakEventListener && - e instanceof BlockBreakEvent ) { - - ((AutoManagerBlockBreakEventListener)l) - .onBlockBreak( (BlockBreakEvent)e, getBbPriority() ); - } - } - }, - prison); - - prison.getRegisteredBlockListeners().add( autoManagerlListener ); - + if ( bbPriority.isComponentCompound() ) { + + for (BlockBreakPriority subBBPriority : bbPriority.getComponentPriorities()) { + + createListener( subBBPriority ); + } + } + else { + + createListener(bbPriority); + } } @@ -131,6 +118,32 @@ public void execute(Listener l, Event e) { } } + private void createListener( BlockBreakPriority bbPriority ) { + + SpigotPrison prison = SpigotPrison.getInstance(); + PluginManager pm = Bukkit.getServer().getPluginManager(); + EventPriority ePriority = bbPriority.getBukkitEventPriority(); + + AutoManagerBlockBreakEventListener autoManagerListener = + new AutoManagerBlockBreakEventListener( bbPriority ); + + + pm.registerEvent(BlockBreakEvent.class, autoManagerListener, ePriority, + new EventExecutor() { + public void execute(Listener l, Event e) { + if ( l instanceof AutoManagerBlockBreakEventListener && + e instanceof BlockBreakEvent ) { + + ((AutoManagerBlockBreakEventListener)l) + .onBlockBreak( (BlockBreakEvent)e, getBbPriority() ); + } + } + }, + prison); + + prison.getRegisteredBlockListeners().add( autoManagerListener ); + } + // /** // *

If one BlockBreak related event needs to be unregistered, then this function will @@ -173,27 +186,52 @@ public void dumpEventListeners( StringBuilder sb ) { // Check to see if the class BlockBreakEvent even exists: try { + HandlerList handlers = BlockBreakEvent.getHandlerList(); + String eP = getMessage( AutoFeatures.blockBreakEventPriority ); BlockBreakPriority bbPriority = BlockBreakPriority.fromString( eP ); - String title = String.format( - "BlockBreakEvent (%s)", - ( bbPriority == null ? "--none--" : bbPriority.name()) ); - - ChatDisplay eventDisplay = Prison.get().getPlatform().dumpEventListenersChatDisplay( - title, - new SpigotHandlerList( BlockBreakEvent.getHandlerList()) ); - - if ( eventDisplay != null ) { - sb.append( eventDisplay.toStringBuilder() ); - sb.append( "\n" ); - } + dumpEventListenersCore( "BlockBreakEvent", handlers, bbPriority, sb ); + + + + +// String title = String.format( +// "BlockBreakEvent (%s)", +// ( bbPriority == null ? "--none--" : bbPriority.name()) ); +// +// ChatDisplay eventDisplay = Prison.get().getPlatform().dumpEventListenersChatDisplay( +// title, +// new SpigotHandlerList( handlers ) ); +// +// if ( eventDisplay != null ) { +// sb.append( eventDisplay.toStringBuilder() ); +// sb.append( "\n" ); +// } +// +// if ( bbPriority.isComponentCompound() ) { +// StringBuilder sbCP = new StringBuilder(); +// for ( BlockBreakPriority bbp : bbPriority.getComponentPriorities() ) { +// if ( sbCP.length() > 0 ) { +// sbCP.append( ", " ); +// } +// sbCP.append( "'" ).append( bbp.name() ).append( "'" ); +// } +// +// String msg = String.format( "Note '%s' is a compound of: [%s]", +// bbPriority.name(), +// sbCP ); +// +// sb.append( msg ).append( "\n" ); +// } } catch ( Exception e ) { Output.get().logInfo( "AutoManager: BlockBreakEvent failed to load. [%s]", e.getMessage() ); } } + + /** *

This genericBlockEvent handles the basics of a BlockBreakEvent to see if it has happened @@ -207,26 +245,33 @@ public void dumpEventListeners( StringBuilder sb ) { */ private void handleBlockBreakEvent( BlockBreakEvent e, BlockBreakPriority bbPriority ) { -// boolean monitor, boolean blockEventsOnly, -// boolean autoManager ) { - if ( e instanceof PrisonMinesBlockBreakEvent ) { return; } + PrisonMinesBlockBreakEvent pmEvent = null; long start = System.nanoTime(); - if ( e.isCancelled() || ignoreMinesBlockBreakEvent( e, e.getPlayer(), e.getBlock()) ) { + // If the event is canceled, it still needs to be processed because of the + // MONITOR events: + // An event will be "canceled" and "ignored" if the block + // BlockUtils.isUnbreakable(), or if the mine is activly resetting. + // The event will also be ignored if the block is outside of a mine + // or if the targetBlock has been set to ignore all block events which + // means the block has already been processed. + MinesEventResults eventResults = ignoreMinesBlockBreakEvent( e, + e.getPlayer(), e.getBlock() ); + if ( eventResults.isIgnoreEvent() ) { return; } // Register all external events such as mcMMO and EZBlocks: - OnBlockBreakExternalEvents.getInstance().registerAllExternalEvents(); +// OnBlockBreakExternalEvents.getInstance().registerAllExternalEvents(); StringBuilder debugInfo = new StringBuilder(); - debugInfo.append( String.format( "&9### ** genericBlockEvent ** ### " + + debugInfo.append( String.format( "&9### ** handleBlockBreakEvent ** ### " + "(event: BlockBreakEvent, config: %s, priority: %s, canceled: %s) ", bbPriority.name(), bbPriority.getBukkitEventPriority().name(), @@ -234,19 +279,43 @@ private void handleBlockBreakEvent( BlockBreakEvent e, BlockBreakPriority bbPrio ) ); - if ( bbPriority != BlockBreakPriority.MONITOR && !e.isCancelled() || bbPriority == BlockBreakPriority.MONITOR ) { + // Process all priorities if the event has not been canceled, and + // process the MONITOR priority even if the event was canceled: + if ( !bbPriority.isMonitor() && !e.isCancelled() || + bbPriority.isMonitor() ) { // Need to wrap in a Prison block so it can be used with the mines: - SpigotBlock sBlock = SpigotBlock.getSpigotBlock(e.getBlock()); - SpigotPlayer sPlayer = new SpigotPlayer(e.getPlayer()); +// SpigotBlock sBlock = SpigotBlock.getSpigotBlock(e.getBlock()); +// SpigotPlayer sPlayer = new SpigotPlayer(e.getPlayer()); BlockEventType eventType = BlockEventType.blockBreak; String triggered = null; - PrisonMinesBlockBreakEvent pmEvent = new PrisonMinesBlockBreakEvent( e.getBlock(), e.getPlayer(), - sBlock, sPlayer, bbPriority, eventType, triggered ); + pmEvent = new PrisonMinesBlockBreakEvent( + e.getBlock(), + e.getPlayer(), + eventResults.getMine(), +// sBlock, sPlayer, + bbPriority, eventType, triggered, + debugInfo ); - if ( !validateEvent( pmEvent, debugInfo ) ) { + + // NOTE: Check for the ACCESS priority and if someone does not have access, then return + // with a cancel on the event. Both ACCESSBLOCKEVENTS and ACCESSMONITOR will be + // converted to just ACCESS at this point, and the other part will run under either + // BLOCKEVENTS or MONITOR. + // This check has to be performed after creating the pmEvent object since it uses + // a lot of the internal variables and objects. There is not much of an impact since + // the validateEvent() has not been ran yet. + if ( checkIfNoAccess( pmEvent, start ) ) { + + e.setCancelled( true ); + + return; + } + + // Validate the event. + if ( !validateEvent( pmEvent ) ) { // The event has not passed validation. All logging and Errors have been recorded // so do nothing more. This is to just prevent normal processing from occurring. @@ -255,104 +324,141 @@ private void handleBlockBreakEvent( BlockBreakEvent e, BlockBreakPriority bbPrio e.setCancelled( true ); } + + debugInfo.append( "(doAction failed validation) " ); } - else if ( pmEvent.getBbPriority() == BlockBreakPriority.MONITOR ) { - // Stop here, and prevent additional processing. Monitors should never process the event beyond this. + + // The validation was successful, but stop processing for the MONITOR priorities. + // Note that BLOCKEVENTS processing occured already within validateEvent(): + else if ( pmEvent.getBbPriority().isMonitor() ) { + // Stop here, and prevent additional processing. + // Monitors should never process the event beyond this. } + // This is where the processing actually happens: - else if ( pmEvent.getMine() != null || pmEvent.getMine() == null && - !isBoolean( AutoFeatures.pickupLimitToMines ) ) { - debugInfo.append( "(normal processing initiating) " ); + else { - // Set the mine's PrisonBlockTypes for the block. Used to identify custom blocks. - // Needed since processing of the block will lose track of which mine it came from. - if ( pmEvent.getMine() != null ) { - sBlock.setPrisonBlockTypes( pmEvent.getMine().getPrisonBlockTypes() ); - } +// debugInfo.append( "(normal processing initiating) " ); // check all external events such as mcMMO and EZBlocks: - debugInfo.append( - OnBlockBreakExternalEvents.getInstance().checkAllExternalEvents( e ) ); + if ( e instanceof BlockBreakEvent ) { + processPMBBExternalEvents( pmEvent, e ); + } - List explodedBlocks = new ArrayList<>(); - pmEvent.setExplodedBlocks( explodedBlocks ); -// String triggered = null; -// PrisonMinesBlockBreakEvent pmbbEvent = new PrisonMinesBlockBreakEvent( e.getBlock(), e.getPlayer(), -// pmEvent.getMine(), sBlock, explodedBlocks, BlockEventType.blockBreak, triggered ); - Bukkit.getServer().getPluginManager().callEvent( pmEvent ); - if ( pmEvent.isCancelled() ) { - debugInfo.append( "(normal processing: &6PrisonMinesBlockBreakEvent was canceled&9) " ); - } - else { - - // Cancel drops if so configured: - if ( isBoolean( AutoFeatures.cancelAllBlockEventBlockDrops ) ) { - - try - { - e.setDropItems( false ); - } - catch ( NoSuchMethodError e1 ) - { - String message = String.format( - "Warning: The autoFeaturesConfig.yml setting `cancelAllBlockEventBlockDrops` " + - "is not valid for this version of Spigot. It's only vaid for spigot v1.12.x and higher. " + - "Modify the config settings and set this value to `false`. For now, it is temporarily " + - "disabled. [%s]", - e1.getMessage() ); - Output.get().logWarn( message ); - - AutoFeaturesWrapper.getInstance().getAutoFeaturesConfig() - .setFeature( AutoFeatures.cancelAllBlockEventBlockDrops, false ); - } - } - - // doAction returns a boolean that indicates if the event should be canceled or not: - if ( doAction( pmEvent, debugInfo ) ) { -// if ( doAction( sBlock, pmEvent.getMine(), pmEvent.getPlayer(), debugInfo ) ) { + EventListenerCancelBy cancelBy = EventListenerCancelBy.none; + + cancelBy = processPMBBEvent( pmEvent ); - if ( isBoolean( AutoFeatures.cancelAllBlockBreakEvents ) ) { - e.setCancelled( true ); - } - else { - - debugInfo.append( "(event was not canceled) " ); - } - - // Break the blocks - finalizeBreakTheBlocks( pmEvent ); - - // Block counts and blockEvents - doBlockEvents( pmEvent ); - - } - else { - - debugInfo.append( "&c(doAction failed without details)&9 " ); - } + + if ( cancelBy == EventListenerCancelBy.event ) { + + e.setCancelled( true ); + debugInfo.append( "(event canceled) " ); + } + else if ( cancelBy == EventListenerCancelBy.drops ) { + try + { + e.setDropItems( false ); + debugInfo.append( "(drop canceled) " ); + } + catch ( NoSuchMethodError e1 ) + { + String message = String.format( + "Warning: The autoFeaturesConfig.yml setting `cancelAllBlockEventBlockDrops` " + + "is not valid for this version of Spigot. It's only vaid for spigot v1.12.x and higher. " + + "Modify the config settings and set this value to `false`. For now, it is temporarily " + + "disabled. [%s]", + e1.getMessage() ); + Output.get().logWarn( message ); + + AutoFeaturesWrapper.getInstance().getAutoFeaturesConfig() + .setFeature( AutoFeatures.cancelAllBlockEventBlockDrops, false ); + } - } + } + } +// // Set the mine's PrisonBlockTypes for the block. Used to identify custom blocks. +// // Needed since processing of the block will lose track of which mine it came from. +// if ( pmEvent.getMine() != null ) { +// sBlock.setPrisonBlockTypes( pmEvent.getMine().getPrisonBlockTypes() ); +// } - debugInfo.append( "(normal processing completed) " ); - } - else { +// +// List explodedBlocks = new ArrayList<>(); +// pmEvent.setExplodedBlocks( explodedBlocks ); +//// String triggered = null; +// +// PrisonMinesBlockBreakEvent pmbbEvent = new PrisonMinesBlockBreakEvent( e.getBlock(), e.getPlayer(), +// pmEvent.getMine(), sBlock, explodedBlocks, BlockEventType.blockBreak, triggered ); +// Bukkit.getServer().getPluginManager().callEvent( pmEvent ); +// if ( pmEvent.isCancelled() ) { +// debugInfo.append( "(normal processing: &6PrisonMinesBlockBreakEvent was canceled by another plugin&9) " ); +// } +// else { +// +// // Cancel drops if so configured: +// if ( isBoolean( AutoFeatures.cancelAllBlockEventBlockDrops ) ) { +// +// try +// { +// e.setDropItems( false ); +// } +// catch ( NoSuchMethodError e1 ) +// { +// String message = String.format( +// "Warning: The autoFeaturesConfig.yml setting `cancelAllBlockEventBlockDrops` " + +// "is not valid for this version of Spigot. It's only vaid for spigot v1.12.x and higher. " + +// "Modify the config settings and set this value to `false`. For now, it is temporarily " + +// "disabled. [%s]", +// e1.getMessage() ); +// Output.get().logWarn( message ); +// +// AutoFeaturesWrapper.getInstance().getAutoFeaturesConfig() +// .setFeature( AutoFeatures.cancelAllBlockEventBlockDrops, false ); +// } +// } +// +// // doAction returns a boolean that indicates if the event should be canceled or not: +// if ( doAction( pmEvent, debugInfo ) ) { +//// if ( doAction( sBlock, pmEvent.getMine(), pmEvent.getPlayer(), debugInfo ) ) { +// +// if ( isBoolean( AutoFeatures.cancelAllBlockBreakEvents ) ) { +// e.setCancelled( true ); +// } +// else { +// +// debugInfo.append( "(event was not canceled) " ); +// } +// +// // Break the blocks +// finalizeBreakTheBlocks( pmEvent ); +// +// // Block counts and blockEvents +// doBlockEvents( pmEvent ); +// +// } +// else { +// +// debugInfo.append( "&c(doAction failed without details)&9 " ); +// } +// +// } - debugInfo.append( "(logic bypass) " ); - } + +// debugInfo.append( "(normal processing completed) " ); +// } +// else { +// +// debugInfo.append( "(logic bypass) " ); +// } } - - if ( debugInfo.length() > 0 ) { - - long stop = System.nanoTime(); - debugInfo.append( " [" ).append( (stop - start) / 1000000d ).append( " ms]" ); - - Output.get().logDebug( DebugTarget.blockBreak, debugInfo.toString() ); - } + + printDebugInfo( pmEvent, start ); } protected int checkBonusXp( Player player, Block block, ItemStack item ) { diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/autofeatures/events/AutoManagerCrazyEnchants.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/autofeatures/events/AutoManagerCrazyEnchants.java index 37a587746..8baa62e26 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/autofeatures/events/AutoManagerCrazyEnchants.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/autofeatures/events/AutoManagerCrazyEnchants.java @@ -6,26 +6,20 @@ import org.bukkit.event.Event; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; +import org.bukkit.event.HandlerList; import org.bukkit.event.Listener; import org.bukkit.inventory.ItemStack; import org.bukkit.plugin.EventExecutor; import org.bukkit.plugin.PluginManager; import me.badbones69.crazyenchantments.api.events.BlastUseEvent; -import tech.mcprison.prison.Prison; import tech.mcprison.prison.autofeatures.AutoFeaturesFileConfig.AutoFeatures; import tech.mcprison.prison.mines.features.MineBlockEvent.BlockEventType; -import tech.mcprison.prison.output.ChatDisplay; import tech.mcprison.prison.output.Output; -import tech.mcprison.prison.output.Output.DebugTarget; import tech.mcprison.prison.spigot.SpigotPrison; import tech.mcprison.prison.spigot.api.PrisonMinesBlockBreakEvent; import tech.mcprison.prison.spigot.autofeatures.AutoManagerFeatures; import tech.mcprison.prison.spigot.block.BlockBreakPriority; -import tech.mcprison.prison.spigot.block.OnBlockBreakExternalEvents; -import tech.mcprison.prison.spigot.block.SpigotBlock; -import tech.mcprison.prison.spigot.game.SpigotHandlerList; -import tech.mcprison.prison.spigot.game.SpigotPlayer; import tech.mcprison.prison.spigot.integrations.IntegrationCrazyEnchantmentsPickaxes; public class AutoManagerCrazyEnchants @@ -43,6 +37,15 @@ public AutoManagerCrazyEnchants() { } + public AutoManagerCrazyEnchants( BlockBreakPriority bbPriority ) { + super(); + + this.crazyEnchantEnabled = null; + + this.bbPriority = bbPriority; + } + + public BlockBreakPriority getBbPriority() { return bbPriority; } @@ -61,11 +64,16 @@ public void registerEvents() { public class AutoManagerBlastUseEventListener extends AutoManagerCrazyEnchants implements Listener { + + public AutoManagerBlastUseEventListener( BlockBreakPriority bbPriority ) { + super( bbPriority ); + } @EventHandler(priority=EventPriority.NORMAL) public void onCrazyEnchantsBlockExplode( BlastUseEvent e, BlockBreakPriority bbPriority) { - if ( isDisabled( e.getPlayer().getLocation().getWorld().getName() ) ) { + if ( isDisabled( e.getPlayer().getLocation().getWorld().getName() ) || + bbPriority.isDisabled() ) { return; } @@ -78,11 +86,13 @@ public void onCrazyEnchantsBlockExplode( BlastUseEvent e, BlockBreakPriority bbP public void initialize() { String eP = getMessage( AutoFeatures.CrazyEnchantsBlastUseEventPriority ); - setBbPriority( BlockBreakPriority.fromString( eP ) ); + + BlockBreakPriority bbPriority = BlockBreakPriority.fromString( eP ); + setBbPriority( bbPriority ); // boolean isEventEnabled = eP != null && !"DISABLED".equalsIgnoreCase( eP ); - if ( getBbPriority() == BlockBreakPriority.DISABLED ) { + if ( bbPriority == BlockBreakPriority.DISABLED ) { return; } @@ -96,27 +106,21 @@ public void initialize() { Output.get().logInfo( "AutoManager: Trying to register CrazyEnchants" ); - SpigotPrison prison = SpigotPrison.getInstance(); - PluginManager pm = Bukkit.getServer().getPluginManager(); - EventPriority ePriority = getBbPriority().getBukkitEventPriority(); - - - AutoManagerBlastUseEventListener autoManagerlListener = - new AutoManagerBlastUseEventListener(); - - pm.registerEvent(BlastUseEvent.class, autoManagerlListener, ePriority, - new EventExecutor() { - public void execute(Listener l, Event e) { - - BlastUseEvent buEvent = (BlastUseEvent) e; - - ((AutoManagerBlastUseEventListener)l) - .onCrazyEnchantsBlockExplode( buEvent, getBbPriority() ); - } - }, - prison); - prison.getRegisteredBlockListeners().add( autoManagerlListener ); - + if ( getBbPriority() != BlockBreakPriority.DISABLED ) { + if ( bbPriority.isComponentCompound() ) { + + for (BlockBreakPriority subBBPriority : bbPriority.getComponentPriorities()) { + + createListener( subBBPriority ); + } + } + else { + + createListener(bbPriority); + } + + } + } catch ( ClassNotFoundException e ) { @@ -127,6 +131,32 @@ public void execute(Listener l, Event e) { Output.get().logInfo( "AutoManager: CrazyEnchants failed to load. [%s]", e.getMessage() ); } } + + + private void createListener(BlockBreakPriority bbPriority) { + + SpigotPrison prison = SpigotPrison.getInstance(); + PluginManager pm = Bukkit.getServer().getPluginManager(); + EventPriority ePriority = bbPriority.getBukkitEventPriority(); + + + AutoManagerBlastUseEventListener autoManagerListener = + new AutoManagerBlastUseEventListener( bbPriority ); + + pm.registerEvent(BlastUseEvent.class, autoManagerListener, ePriority, + new EventExecutor() { + public void execute(Listener l, Event e) { + + BlastUseEvent buEvent = (BlastUseEvent) e; + + ((AutoManagerBlastUseEventListener)l) + .onCrazyEnchantsBlockExplode( buEvent, getBbPriority() ); + } + }, + prison); + + prison.getRegisteredBlockListeners().add( autoManagerListener ); + } @Override @@ -170,21 +200,47 @@ public void dumpEventListeners( StringBuilder sb ) { Class.forName( "me.badbones69.crazyenchantments.api.events.BlastUseEvent", false, this.getClass().getClassLoader() ); - BlockBreakPriority bbPriority = BlockBreakPriority.fromString( eP ); - - String title = String.format( - "BlastUseEvent (%s)", - ( bbPriority == null ? "--none--" : bbPriority.name()) ); + HandlerList handlers = BlastUseEvent.getHandlerList(); - ChatDisplay eventDisplay = Prison.get().getPlatform().dumpEventListenersChatDisplay( - title, - new SpigotHandlerList( BlastUseEvent.getHandlerList()) ); +// String eP = getMessage( AutoFeatures.blockBreakEventPriority ); + BlockBreakPriority bbPriority = BlockBreakPriority.fromString( eP ); + + dumpEventListenersCore( "BlastUseEvent", handlers, bbPriority, sb ); + - if ( eventDisplay != null ) { - sb.append( eventDisplay.toStringBuilder() ); - sb.append( "\n" ); - } +// BlockBreakPriority bbPriority = BlockBreakPriority.fromString( eP ); +// +// +// String title = String.format( +// "BlastUseEvent (%s)", +// ( bbPriority == null ? "--none--" : bbPriority.name()) ); +// +// ChatDisplay eventDisplay = Prison.get().getPlatform().dumpEventListenersChatDisplay( +// title, +// new SpigotHandlerList( BlastUseEvent.getHandlerList()) ); +// +// if ( eventDisplay != null ) { +// sb.append( eventDisplay.toStringBuilder() ); +// sb.append( "\n" ); +// } +// +// +// if ( bbPriority.isComponentCompound() ) { +// StringBuilder sbCP = new StringBuilder(); +// for ( BlockBreakPriority bbp : bbPriority.getComponentPriorities() ) { +// if ( sbCP.length() > 0 ) { +// sbCP.append( ", " ); +// } +// sbCP.append( "'" ).append( bbp.name() ).append( "'" ); +// } +// +// String msg = String.format( "Note '%s' is a compound of: [%s]", +// bbPriority.name(), +// sbCP ); +// +// sb.append( msg ).append( "\n" ); +// } } catch ( ClassNotFoundException e ) { // CrazyEnchants is not loaded... so ignore. @@ -208,22 +264,25 @@ public void dumpEventListeners( StringBuilder sb ) { */ public void handleBlastUseEvent( BlastUseEvent e, BlockBreakPriority bbPriority ) { -// boolean monitor, boolean blockEventsOnly, -// boolean autoManager ) { - + PrisonMinesBlockBreakEvent pmEvent = null; long start = System.nanoTime(); - if ( e.isCancelled() || ignoreMinesBlockBreakEvent( e, e.getPlayer(), e.getBlockList().get( 0 )) ) { + // If the event is canceled, it still needs to be processed because of the + // MONITOR events: + // An event will be "canceled" and "ignored" if the block + // BlockUtils.isUnbreakable(), or if the mine is activly resetting. + // The event will also be ignored if the block is outside of a mine + // or if the targetBlock has been set to ignore all block events which + // means the block has already been processed. + MinesEventResults eventResults = ignoreMinesBlockBreakEvent( e, + e.getPlayer(), e.getBlockList().get( 0 ) ); + if ( eventResults.isIgnoreEvent() ) { return; } - - - // Register all external events such as mcMMO and EZBlocks: - OnBlockBreakExternalEvents.getInstance().registerAllExternalEvents(); StringBuilder debugInfo = new StringBuilder(); - debugInfo.append( String.format( "### ** genericBlastUseEvent ** ### " + + debugInfo.append( String.format( "### ** handleBlastUseEvent ** ### " + "(event: BlastUseEvent, config: %s, priority: %s, canceled: %s) ", bbPriority.name(), bbPriority.getBukkitEventPriority().name(), @@ -232,34 +291,47 @@ public void handleBlastUseEvent( BlastUseEvent e, BlockBreakPriority bbPriority // NOTE that check for auto manager has happened prior to accessing this function. - if ( bbPriority != BlockBreakPriority.MONITOR && !e.isCancelled() || bbPriority == BlockBreakPriority.MONITOR && - e.getBlockList().size() > 0 ) { - - String eP = getMessage( AutoFeatures.CrazyEnchantsBlastUseEventPriority ); - boolean isCEBlockExplodeEnabled = eP != null && !"DISABLED".equalsIgnoreCase( eP ); + // Process all priorities if the event has not been canceled, and + // process the MONITOR priority even if the event was canceled: + if ( !bbPriority.isMonitor() && !e.isCancelled() || + bbPriority.isMonitor() && + e.getBlockList().size() > 0 ) { - - Block bukkitBlock = e.getBlockList().get( 0 ); - // Need to wrap in a Prison block so it can be used with the mines: - SpigotBlock sBlock = SpigotBlock.getSpigotBlock( bukkitBlock ); - SpigotPlayer sPlayer = new SpigotPlayer(e.getPlayer()); + Block bukkitBlock = e.getBlockList().get( 0 ); BlockEventType eventType = BlockEventType.CEXplosion; String triggered = null; - PrisonMinesBlockBreakEvent pmEvent = new PrisonMinesBlockBreakEvent( bukkitBlock, e.getPlayer(), - sBlock, sPlayer, bbPriority, eventType, triggered ); - + pmEvent = new PrisonMinesBlockBreakEvent( + bukkitBlock, + e.getPlayer(), + eventResults.getMine(), + bbPriority, eventType, triggered, + debugInfo ); + + + // NOTE: Check for the ACCESS priority and if someone does not have access, then return + // with a cancel on the event. Both ACCESSBLOCKEVENTS and ACCESSMONITOR will be + // converted to just ACCESS at this point, and the other part will run under either + // BLOCKEVENTS or MONITOR. + // This check has to be performed after creating the pmEvent object since it uses + // a lot of the internal variables and objects. There is not much of an impact since + // the validateEvent() has not been ran yet. + if ( checkIfNoAccess( pmEvent, start ) ) { + + e.setCancelled( true ); + return; + } for ( int i = 1; i < e.getBlockList().size(); i++ ) { pmEvent.getUnprocessedRawBlocks().add( e.getBlockList().get( i ) ); } - if ( !validateEvent( pmEvent, debugInfo ) ) { + if ( !validateEvent( pmEvent ) ) { // The event has not passed validation. All logging and Errors have been recorded // so do nothing more. This is to just prevent normal processing from occurring. @@ -268,98 +340,70 @@ public void handleBlastUseEvent( BlastUseEvent e, BlockBreakPriority bbPriority e.setCancelled( true ); } + + debugInfo.append( "(doAction failed validation) " ); } - else if ( pmEvent.getBbPriority() == BlockBreakPriority.MONITOR ) { - // Stop here, and prevent additional processing. Monitors should never process the event beyond this. + + // The validation was successful, but stop processing for the MONITOR priorities. + // Note that BLOCKEVENTS processing occured already within validateEvent(): + else if ( pmEvent.getBbPriority().isMonitor() ) { + // Stop here, and prevent additional processing. + // Monitors should never process the event beyond this. } - // now process all blocks (non-monitor): - else if ( isCEBlockExplodeEnabled && - ( pmEvent.getMine() != null || pmEvent.getMine() == null && !isBoolean( AutoFeatures.pickupLimitToMines )) ) { - - - if ( pmEvent.getExplodedBlocks().size() > 0 ) { - -// String triggered = null; - - - // Warning: BlastUseEvent does not identify the block the player actually hit, so the dummyBlock - // is just a random first block from the explodedBlocks list and may not be the block - // that initiated the explosion event. -// SpigotBlock dummyBlock = explodedBlocks.get( 0 ); - -// PrisonMinesBlockBreakEvent pmbbEvent = new PrisonMinesBlockBreakEvent( dummyBlock.getWrapper(), e.getPlayer(), -// mine, dummyBlock, explodedBlocks, BlockEventType.CEXplosion, triggered ); - Bukkit.getServer().getPluginManager().callEvent(pmEvent); - if ( pmEvent.isCancelled() ) { - debugInfo.append( "(normal processing: PrisonMinesBlockBreakEvent was canceled) " ); - } - else { - -// // Cancel drops if so configured: -// if ( isBoolean( AutoFeatures.cancelAllBlockEventBlockDrops ) ) { -// -// try -// { -// e.setDropItems( false ); -// } -// catch ( NoSuchMethodError e1 ) -// { -// String message = String.format( -// "Warning: The autoFeaturesConfig.yml setting `cancelAllBlockEventBlockDrops` " + -// "is not valid for this version of Spigot. Modify the config settings and set " + -// "this value to `false`. [%s]", -// e1.getMessage() ); -// Output.get().logWarn( message ); -// } -// } - - if ( doAction( pmEvent, debugInfo ) ) { - - if ( isBoolean( AutoFeatures.cancelAllBlockBreakEvents ) ) { - - e.setCancelled( true ); - } - else { - - debugInfo.append( "(event was not canceled) " ); - } - - finalizeBreakTheBlocks( pmEvent ); - - doBlockEvents( pmEvent ); - - } - - else { - - debugInfo.append( "(doAction failed without details) " ); - } - - } - } + else { + + // This is where the processing actually happens: + +// if ( e instanceof BlockBreakEvent ) { +// processPMBBExternalEvents( pmEvent, debugInfo, e ); +// } + + + + EventListenerCancelBy cancelBy = EventListenerCancelBy.none; + cancelBy = processPMBBEvent( pmEvent ); - debugInfo.append( "(normal processing) " ); - } - else { - debugInfo.append( "(logic bypass) " ); + // NOTE: you cannot cancel a crazy enchant's drops, so this will + // always cancel the event. + if ( cancelBy != EventListenerCancelBy.none ) { + + e.setCancelled( true ); + debugInfo.append( "(event canceled) " ); + } +// else if ( cancelBy == EventListenerCancelBy.drops ) { +// try +// { +// e.setDropItems( false ); +// debugInfo.append( "(drop canceled) " ); +// } +// catch ( NoSuchMethodError e1 ) +// { +// String message = String.format( +// "Warning: The autoFeaturesConfig.yml setting `cancelAllBlockEventBlockDrops` " + +// "is not valid for this version of Spigot. It's only vaid for spigot v1.12.x and higher. " + +// "Modify the config settings and set this value to `false`. For now, it is temporarily " + +// "disabled. [%s]", +// e1.getMessage() ); +// Output.get().logWarn( message ); +// +// AutoFeaturesWrapper.getInstance().getAutoFeaturesConfig() +// .setFeature( AutoFeatures.cancelAllBlockEventBlockDrops, false ); +// } +// +// } } + } - if ( debugInfo.length() > 0 ) { - - long stop = System.nanoTime(); - debugInfo.append( " [" ).append( (stop - start) / 1000000d ).append( " ms]" ); - - Output.get().logDebug( DebugTarget.blockBreak, debugInfo.toString() ); - } + printDebugInfo( pmEvent, start ); } @Override diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/autofeatures/events/AutoManagerPrisonEnchants.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/autofeatures/events/AutoManagerPrisonEnchants.java index 8b7986bac..bf5b992f7 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/autofeatures/events/AutoManagerPrisonEnchants.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/autofeatures/events/AutoManagerPrisonEnchants.java @@ -6,26 +6,20 @@ import org.bukkit.event.Event; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; +import org.bukkit.event.HandlerList; import org.bukkit.event.Listener; import org.bukkit.inventory.ItemStack; import org.bukkit.plugin.EventExecutor; import org.bukkit.plugin.PluginManager; import me.pulsi_.prisonenchants.events.PEExplosionEvent; -import tech.mcprison.prison.Prison; import tech.mcprison.prison.autofeatures.AutoFeaturesFileConfig.AutoFeatures; import tech.mcprison.prison.mines.features.MineBlockEvent.BlockEventType; -import tech.mcprison.prison.output.ChatDisplay; import tech.mcprison.prison.output.Output; -import tech.mcprison.prison.output.Output.DebugTarget; import tech.mcprison.prison.spigot.SpigotPrison; import tech.mcprison.prison.spigot.api.PrisonMinesBlockBreakEvent; import tech.mcprison.prison.spigot.autofeatures.AutoManagerFeatures; import tech.mcprison.prison.spigot.block.BlockBreakPriority; -import tech.mcprison.prison.spigot.block.OnBlockBreakExternalEvents; -import tech.mcprison.prison.spigot.block.SpigotBlock; -import tech.mcprison.prison.spigot.game.SpigotHandlerList; -import tech.mcprison.prison.spigot.game.SpigotPlayer; public class AutoManagerPrisonEnchants extends AutoManagerFeatures @@ -36,7 +30,13 @@ public class AutoManagerPrisonEnchants public AutoManagerPrisonEnchants() { super(); } - + + public AutoManagerPrisonEnchants( BlockBreakPriority bbPriority ) { + super(); + + this.bbPriority = bbPriority; + } + public BlockBreakPriority getBbPriority() { return bbPriority; @@ -60,10 +60,15 @@ public class AutoManagerPEExplosiveEventListener extends AutoManagerPrisonEnchants implements Listener { + public AutoManagerPEExplosiveEventListener( BlockBreakPriority bbPriority ) { + super( bbPriority ); + } + @EventHandler(priority=EventPriority.NORMAL) public void onPrisonEnchantsExplosiveEvent( PEExplosionEvent e, BlockBreakPriority bbPriority ) { - if ( isDisabled( e.getBlockBroken().getLocation().getWorld().getName() ) ) { + if ( isDisabled( e.getBlockBroken().getLocation().getWorld().getName() ) || + bbPriority.isDisabled() ) { return; } @@ -81,7 +86,9 @@ public void onPrisonEnchantsExplosiveEvent( PEExplosionEvent e, BlockBreakPriori public void initialize() { String eP = getMessage( AutoFeatures.PrisonEnchantsExplosiveEventPriority ); - setBbPriority( BlockBreakPriority.fromString( eP ) ); + BlockBreakPriority bbPriority = BlockBreakPriority.fromString( eP ); + + setBbPriority( bbPriority ); // boolean isEventEnabled = eP != null && !"DISABLED".equalsIgnoreCase( eP ); @@ -99,29 +106,20 @@ public void initialize() { Output.get().logInfo( "AutoManager: Trying to register Pulsi_'s PrisonEnchants" ); - - - SpigotPrison prison = SpigotPrison.getInstance(); - PluginManager pm = Bukkit.getServer().getPluginManager(); - EventPriority ePriority = getBbPriority().getBukkitEventPriority(); - - AutoManagerPEExplosiveEventListener autoManagerlListener = - new AutoManagerPEExplosiveEventListener(); - - pm.registerEvent(PEExplosionEvent.class, autoManagerlListener, ePriority, - new EventExecutor() { - public void execute(Listener l, Event e) { - - PEExplosionEvent peeEvent = (PEExplosionEvent) e; - - ((AutoManagerPEExplosiveEventListener)l) - .onPrisonEnchantsExplosiveEvent( peeEvent, getBbPriority() ); - } - }, - prison); - prison.getRegisteredBlockListeners().add( autoManagerlListener ); - - + if ( getBbPriority() != BlockBreakPriority.DISABLED ) { + if ( bbPriority.isComponentCompound() ) { + + for (BlockBreakPriority subBBPriority : bbPriority.getComponentPriorities()) { + + createListener( subBBPriority ); + } + } + else { + + createListener(bbPriority); + } + + } } catch ( ClassNotFoundException e ) { @@ -133,6 +131,29 @@ public void execute(Listener l, Event e) { } } + private void createListener(BlockBreakPriority bbPriority) { + + SpigotPrison prison = SpigotPrison.getInstance(); + PluginManager pm = Bukkit.getServer().getPluginManager(); + EventPriority ePriority = bbPriority.getBukkitEventPriority(); + + AutoManagerPEExplosiveEventListener autoManagerListener = + new AutoManagerPEExplosiveEventListener( bbPriority ); + + pm.registerEvent(PEExplosionEvent.class, autoManagerListener, ePriority, + new EventExecutor() { + public void execute(Listener l, Event e) { + + PEExplosionEvent peeEvent = (PEExplosionEvent) e; + + ((AutoManagerPEExplosiveEventListener)l) + .onPrisonEnchantsExplosiveEvent( peeEvent, getBbPriority() ); + } + }, + prison); + prison.getRegisteredBlockListeners().add( autoManagerListener ); + } + @Override @@ -176,20 +197,46 @@ public void dumpEventListeners( StringBuilder sb ) { Class.forName( "me.pulsi_.prisonenchants.events.PEExplosionEvent", false, this.getClass().getClassLoader() ); - BlockBreakPriority bbPriority = BlockBreakPriority.fromString( eP ); - String title = String.format( - "Pulsi_'s PEExplosionEvent (%s)", - ( bbPriority == null ? "--none--" : bbPriority.name())); + HandlerList handlers = PEExplosionEvent.getHandlerList(); - ChatDisplay eventDisplay = Prison.get().getPlatform().dumpEventListenersChatDisplay( - title, - new SpigotHandlerList( PEExplosionEvent.getHandlerList()) ); +// String eP = getMessage( AutoFeatures.blockBreakEventPriority ); + BlockBreakPriority bbPriority = BlockBreakPriority.fromString( eP ); - if ( eventDisplay != null ) { - sb.append( eventDisplay.toStringBuilder() ); - sb.append( "\n" ); - } + dumpEventListenersCore( "Pulsi_'s PEExplosionEvent", handlers, bbPriority, sb ); + + +// BlockBreakPriority bbPriority = BlockBreakPriority.fromString( eP ); +// +// String title = String.format( +// "Pulsi_'s PEExplosionEvent (%s)", +// ( bbPriority == null ? "--none--" : bbPriority.name())); +// +// ChatDisplay eventDisplay = Prison.get().getPlatform().dumpEventListenersChatDisplay( +// title, +// new SpigotHandlerList( PEExplosionEvent.getHandlerList()) ); +// +// if ( eventDisplay != null ) { +// sb.append( eventDisplay.toStringBuilder() ); +// sb.append( "\n" ); +// } +// +// +// if ( bbPriority.isComponentCompound() ) { +// StringBuilder sbCP = new StringBuilder(); +// for ( BlockBreakPriority bbp : bbPriority.getComponentPriorities() ) { +// if ( sbCP.length() > 0 ) { +// sbCP.append( ", " ); +// } +// sbCP.append( "'" ).append( bbp.name() ).append( "'" ); +// } +// +// String msg = String.format( "Note '%s' is a compound of: [%s]", +// bbPriority.name(), +// sbCP ); +// +// sb.append( msg ).append( "\n" ); +// } } catch ( ClassNotFoundException e ) { // PrisonEnchants is not loaded... so ignore. @@ -213,24 +260,26 @@ public void dumpEventListeners( StringBuilder sb ) { */ public void handlePEExplosionEvent( PEExplosionEvent e, BlockBreakPriority bbPriority) { - -// , boolean monitor, boolean blockEventsOnly, -// boolean autoManager ) { - + PrisonMinesBlockBreakEvent pmEvent = null; long start = System.nanoTime(); - if ( e.isCancelled() || processMinesBlockBreakEvent( e, e.getPlayer(), e.getBlockBroken()) ) { + // If the event is canceled, it still needs to be processed because of the + // MONITOR events: + // An event will be "canceled" and "ignored" if the block + // BlockUtils.isUnbreakable(), or if the mine is activly resetting. + // The event will also be ignored if the block is outside of a mine + // or if the targetBlock has been set to ignore all block events which + // means the block has already been processed. + MinesEventResults eventResults = ignoreMinesBlockBreakEvent( e, + e.getPlayer(), e.getBlockBroken()); + if ( eventResults.isIgnoreEvent() ) { return; } - - - // Register all external events such as mcMMO and EZBlocks: - OnBlockBreakExternalEvents.getInstance().registerAllExternalEvents(); StringBuilder debugInfo = new StringBuilder(); - debugInfo.append( String.format( "### ** genericExplosiveEvent (Pulsi) ** ### " + + debugInfo.append( String.format( "### ** handlePEEExplosionEvent (Pulsi) ** ### " + "(event: PEExplosionEvent, config: %s, priority: %s, canceled: %s) ", bbPriority.name(), bbPriority.getBukkitEventPriority().name(), @@ -238,28 +287,40 @@ public void handlePEExplosionEvent( PEExplosionEvent e, BlockBreakPriority bbPri ) ); - if ( bbPriority != BlockBreakPriority.MONITOR && !e.isCancelled() || bbPriority == BlockBreakPriority.MONITOR ) { - - - - String eP = getMessage( AutoFeatures.PrisonEnchantsExplosiveEventPriority ); - boolean isPEExplosiveEnabled = eP != null && !"DISABLED".equalsIgnoreCase( eP ); - + // Process all priorities if the event has not been canceled, and + // process the MONITOR priority even if the event was canceled: + if ( !bbPriority.isMonitor() && !e.isCancelled() || + bbPriority.isMonitor() ) { - // Need to wrap in a Prison block so it can be used with the mines: - SpigotBlock sBlock = SpigotBlock.getSpigotBlock(e.getBlockBroken()); - SpigotPlayer sPlayer = new SpigotPlayer(e.getPlayer()); BlockEventType eventType = BlockEventType.PEExplosive; String triggered = null; // e.getTriggeredBy(); - PrisonMinesBlockBreakEvent pmEvent = new PrisonMinesBlockBreakEvent( e.getBlockBroken(), e.getPlayer(), - sBlock, sPlayer, bbPriority, eventType, triggered ); + pmEvent = new PrisonMinesBlockBreakEvent( + e.getBlockBroken(), + e.getPlayer(), + eventResults.getMine(), + bbPriority, eventType, triggered, + debugInfo ); + + // NOTE: Check for the ACCESS priority and if someone does not have access, then return + // with a cancel on the event. Both ACCESSBLOCKEVENTS and ACCESSMONITOR will be + // converted to just ACCESS at this point, and the other part will run under either + // BLOCKEVENTS or MONITOR. + // This check has to be performed after creating the pmEvent object since it uses + // a lot of the internal variables and objects. There is not much of an impact since + // the validateEvent() has not been ran yet. + if ( checkIfNoAccess( pmEvent, start ) ) { + + e.setCancelled( true ); + return; + } + pmEvent.setUnprocessedRawBlocks( e.getExplodedBlocks() ); - if ( !validateEvent( pmEvent, debugInfo ) ) { + if ( !validateEvent( pmEvent ) ) { // The event has not passed validation. All logging and Errors have been recorded // so do nothing more. This is to just prevent normal processing from occurring. @@ -268,92 +329,69 @@ public void handlePEExplosionEvent( PEExplosionEvent e, BlockBreakPriority bbPri e.setCancelled( true ); } + + debugInfo.append( "(doAction failed validation) " ); } - else if ( pmEvent.getBbPriority() == BlockBreakPriority.MONITOR ) { - // Stop here, and prevent additional processing. Monitors should never process the event beyond this. + + // The validation was successful, but stop processing for the MONITOR priorities. + // Note that BLOCKEVENTS processing occurred already within validateEvent(): + else if ( pmEvent.getBbPriority().isMonitor() ) { + // Stop here, and prevent additional processing. + // Monitors should never process the event beyond this. } - - // now process all blocks (non-monitor): - else if ( isPEExplosiveEnabled && - ( pmEvent.getMine() != null || pmEvent.getMine() == null && !isBoolean( AutoFeatures.pickupLimitToMines )) ) { - if ( pmEvent.getExplodedBlocks().size() > 0 ) { - -// String triggered = null; - - -// PrisonMinesBlockBreakEvent pmbbEvent = new PrisonMinesBlockBreakEvent( dummyBlock.getWrapper(), e.getPlayer(), -// mine, dummyBlock, explodedBlocks, BlockEventType.PEExplosive, triggered ); - Bukkit.getServer().getPluginManager().callEvent(pmEvent); - if ( pmEvent.isCancelled() ) { - debugInfo.append( "(normal processing: PrisonMinesBlockBreakEvent was canceled) " ); - } - else { - -// // Cancel drops if so configured: -// if ( isBoolean( AutoFeatures.cancelAllBlockEventBlockDrops ) ) { -// -// try -// { -// e.setDropItems( false ); -// } -// catch ( NoSuchMethodError e1 ) -// { -// String message = String.format( -// "Warning: The autoFeaturesConfig.yml setting `cancelAllBlockEventBlockDrops` " + -// "is not valid for this version of Spigot. Modify the config settings and set " + -// "this value to `false`. [%s]", -// e1.getMessage() ); -// Output.get().logWarn( message ); -// } -// } - - if ( doAction( pmEvent, debugInfo ) ) { - - if ( isBoolean( AutoFeatures.cancelAllBlockBreakEvents ) ) { - - e.setCancelled( true ); - } - else { - - debugInfo.append( "(event was not canceled) " ); - } - - finalizeBreakTheBlocks( pmEvent ); - - doBlockEvents( pmEvent ); - - } - - else { - - debugInfo.append( "(doAction failed without details) " ); - } - - } - } + // This is where the processing actually happens: + else { +// debugInfo.append( "(normal processing initiating) " ); - debugInfo.append( "(normal processing) " ); - } - else { + // check all external events such as mcMMO and EZBlocks: +// if ( e instanceof BlockBreakEvent ) { +// processPMBBExternalEvents( pmEvent, debugInfo, e ); +// } + + + EventListenerCancelBy cancelBy = EventListenerCancelBy.none; - debugInfo.append( "(logic bypass) " ); + cancelBy = processPMBBEvent( pmEvent ); + + + if ( cancelBy != EventListenerCancelBy.none ) { + + e.setCancelled( true ); + debugInfo.append( "(event canceled) " ); + } +// else if ( cancelBy == EventListenerCancelBy.drops ) { +// try +// { +// e.setDropItems( false ); +// debugInfo.append( "(drop canceled) " ); +// } +// catch ( NoSuchMethodError e1 ) +// { +// String message = String.format( +// "Warning: The autoFeaturesConfig.yml setting `cancelAllBlockEventBlockDrops` " + +// "is not valid for this version of Spigot. It's only vaid for spigot v1.12.x and higher. " + +// "Modify the config settings and set this value to `false`. For now, it is temporarily " + +// "disabled. [%s]", +// e1.getMessage() ); +// Output.get().logWarn( message ); +// +// AutoFeaturesWrapper.getInstance().getAutoFeaturesConfig() +// .setFeature( AutoFeatures.cancelAllBlockEventBlockDrops, false ); +// } +// +// } } + + } - if ( debugInfo.length() > 0 ) { - - long stop = System.nanoTime(); - debugInfo.append( " [" ).append( (stop - start) / 1000000d ).append( " ms]" ); - - Output.get().logDebug( DebugTarget.blockBreak, debugInfo.toString() ); - } - + printDebugInfo( pmEvent, start ); } @Override @@ -362,4 +400,5 @@ protected int checkBonusXp( Player player, Block block, ItemStack item ) { return bonusXp; } + } diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/autofeatures/events/AutoManagerPrisonsExplosiveBlockBreakEvents.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/autofeatures/events/AutoManagerPrisonsExplosiveBlockBreakEvents.java index 2f15e72e6..d50418cb0 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/autofeatures/events/AutoManagerPrisonsExplosiveBlockBreakEvents.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/autofeatures/events/AutoManagerPrisonsExplosiveBlockBreakEvents.java @@ -6,27 +6,23 @@ import org.bukkit.event.Event; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; +import org.bukkit.event.HandlerList; import org.bukkit.event.Listener; +import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.inventory.ItemStack; import org.bukkit.plugin.EventExecutor; import org.bukkit.plugin.PluginManager; -import tech.mcprison.prison.Prison; import tech.mcprison.prison.autofeatures.AutoFeaturesFileConfig.AutoFeatures; +import tech.mcprison.prison.autofeatures.AutoFeaturesWrapper; import tech.mcprison.prison.mines.features.MineBlockEvent.BlockEventType; -import tech.mcprison.prison.output.ChatDisplay; import tech.mcprison.prison.output.Output; -import tech.mcprison.prison.output.Output.DebugTarget; import tech.mcprison.prison.spigot.SpigotPrison; import tech.mcprison.prison.spigot.api.ExplosiveBlockBreakEvent; import tech.mcprison.prison.spigot.api.PrisonMinesBlockBreakEvent; import tech.mcprison.prison.spigot.autofeatures.AutoManagerFeatures; import tech.mcprison.prison.spigot.block.BlockBreakPriority; -import tech.mcprison.prison.spigot.block.OnBlockBreakExternalEvents; -import tech.mcprison.prison.spigot.block.SpigotBlock; import tech.mcprison.prison.spigot.block.SpigotItemStack; -import tech.mcprison.prison.spigot.game.SpigotHandlerList; -import tech.mcprison.prison.spigot.game.SpigotPlayer; public class AutoManagerPrisonsExplosiveBlockBreakEvents extends AutoManagerFeatures @@ -38,6 +34,12 @@ public AutoManagerPrisonsExplosiveBlockBreakEvents() { super(); } + public AutoManagerPrisonsExplosiveBlockBreakEvents( BlockBreakPriority bbPriority ) { + super(); + + this.bbPriority = bbPriority; + } + public BlockBreakPriority getBbPriority() { return bbPriority; @@ -57,11 +59,16 @@ public void registerEvents() { public class AutoManagerExplosiveBlockBreakEventListener extends AutoManagerPrisonsExplosiveBlockBreakEvents implements Listener { - + + public AutoManagerExplosiveBlockBreakEventListener( BlockBreakPriority bbPriority ) { + super( bbPriority ); + } + @EventHandler(priority=EventPriority.NORMAL) public void onPrisonsExplosiveBlockBreakEvent( ExplosiveBlockBreakEvent e, BlockBreakPriority bbPriority ) { - if ( isDisabled( e.getBlock().getLocation().getWorld().getName() ) ) { + if ( isDisabled( e.getBlock().getLocation().getWorld().getName() ) || + bbPriority.isDisabled() ) { return; } @@ -74,7 +81,9 @@ public void onPrisonsExplosiveBlockBreakEvent( ExplosiveBlockBreakEvent e, Block public void initialize() { String eP = getMessage( AutoFeatures.ProcessPrisons_ExplosiveBlockBreakEventsPriority ); - setBbPriority( BlockBreakPriority.fromString( eP ) ); + BlockBreakPriority bbPriority = BlockBreakPriority.fromString( eP ); + + setBbPriority( bbPriority ); // boolean isEventEnabled = eP != null && !"DISABLED".equalsIgnoreCase( eP ); @@ -86,28 +95,20 @@ public void initialize() { Output.get().logInfo( "AutoManager: Trying to register ExplosiveBlockBreakEvent Listener" ); - - SpigotPrison prison = SpigotPrison.getInstance(); - PluginManager pm = Bukkit.getServer().getPluginManager(); - EventPriority ePriority = getBbPriority().getBukkitEventPriority(); - - - AutoManagerExplosiveBlockBreakEventListener autoManagerlListener = - new AutoManagerExplosiveBlockBreakEventListener(); - - pm.registerEvent(ExplosiveBlockBreakEvent.class, autoManagerlListener, ePriority, - new EventExecutor() { - public void execute(Listener l, Event e) { - - ExplosiveBlockBreakEvent ebbEvent = (ExplosiveBlockBreakEvent) e; - - ((AutoManagerExplosiveBlockBreakEventListener)l) - .onPrisonsExplosiveBlockBreakEvent( ebbEvent, getBbPriority() ); - } - }, - prison); - prison.getRegisteredBlockListeners().add( autoManagerlListener ); - + if ( getBbPriority() != BlockBreakPriority.DISABLED ) { + if ( bbPriority.isComponentCompound() ) { + + for (BlockBreakPriority subBBPriority : bbPriority.getComponentPriorities()) { + + createListener( subBBPriority ); + } + } + else { + + createListener(bbPriority); + } + + } } catch ( Exception e ) { @@ -115,6 +116,31 @@ public void execute(Listener l, Event e) { } } + private void createListener(BlockBreakPriority bbPriority) { + + SpigotPrison prison = SpigotPrison.getInstance(); + PluginManager pm = Bukkit.getServer().getPluginManager(); + EventPriority ePriority = bbPriority.getBukkitEventPriority(); + + + AutoManagerExplosiveBlockBreakEventListener autoManagerListener = + new AutoManagerExplosiveBlockBreakEventListener( bbPriority ); + + pm.registerEvent(ExplosiveBlockBreakEvent.class, autoManagerListener, ePriority, + new EventExecutor() { + public void execute(Listener l, Event e) { + + ExplosiveBlockBreakEvent ebbEvent = (ExplosiveBlockBreakEvent) e; + + ((AutoManagerExplosiveBlockBreakEventListener)l) + .onPrisonsExplosiveBlockBreakEvent( ebbEvent, getBbPriority() ); + } + }, + prison); + + prison.getRegisteredBlockListeners().add( autoManagerListener ); + } + @Override @@ -155,21 +181,47 @@ public void dumpEventListeners( StringBuilder sb ) { // Check to see if the class ExplosiveEvent even exists: try { - BlockBreakPriority bbPriority = BlockBreakPriority.fromString( eP ); - String title = String.format( - "ExplosiveBlockBreakEvent (%s)", - ( bbPriority == null ? "--none--" : bbPriority.name()) ); + HandlerList handlers = ExplosiveBlockBreakEvent.getHandlerList(); +// String eP = getMessage( AutoFeatures.blockBreakEventPriority ); + BlockBreakPriority bbPriority = BlockBreakPriority.fromString( eP ); - ChatDisplay eventDisplay = Prison.get().getPlatform().dumpEventListenersChatDisplay( - title, - new SpigotHandlerList( ExplosiveBlockBreakEvent.getHandlerList()) ); - - if ( eventDisplay != null ) { - sb.append( eventDisplay.toStringBuilder() ); - sb.append( "\n" ); - } + dumpEventListenersCore( "ExplosiveBlockBreakEvent", handlers, bbPriority, sb ); + + +// BlockBreakPriority bbPriority = BlockBreakPriority.fromString( eP ); +// +// String title = String.format( +// "ExplosiveBlockBreakEvent (%s)", +// ( bbPriority == null ? "--none--" : bbPriority.name()) ); +// +// +// ChatDisplay eventDisplay = Prison.get().getPlatform().dumpEventListenersChatDisplay( +// title, +// new SpigotHandlerList( ExplosiveBlockBreakEvent.getHandlerList()) ); +// +// if ( eventDisplay != null ) { +// sb.append( eventDisplay.toStringBuilder() ); +// sb.append( "\n" ); +// } +// +// +// if ( bbPriority.isComponentCompound() ) { +// StringBuilder sbCP = new StringBuilder(); +// for ( BlockBreakPriority bbp : bbPriority.getComponentPriorities() ) { +// if ( sbCP.length() > 0 ) { +// sbCP.append( ", " ); +// } +// sbCP.append( "'" ).append( bbp.name() ).append( "'" ); +// } +// +// String msg = String.format( "Note '%s' is a compound of: [%s]", +// bbPriority.name(), +// sbCP ); +// +// sb.append( msg ).append( "\n" ); +// } } catch ( Exception e ) { Output.get().logInfo( "AutoManager: PrisonEnchants failed to load. [%s]", e.getMessage() ); @@ -178,23 +230,27 @@ public void dumpEventListeners( StringBuilder sb ) { protected void handleExplosiveBlockBreakEvent( ExplosiveBlockBreakEvent e, BlockBreakPriority bbPriority ) { -// boolean monitor, boolean blockEventsOnly, -// boolean autoManager ) { - + PrisonMinesBlockBreakEvent pmEvent = null; long start = System.nanoTime(); - if ( e.isCancelled() || ignoreMinesBlockBreakEvent( e, e.getPlayer(), e.getBlock()) ) { + // If the event is canceled, it still needs to be processed because of the + // MONITOR events: + // An event will be "canceled" and "ignored" if the block + // BlockUtils.isUnbreakable(), or if the mine is activly resetting. + // The event will also be ignored if the block is outside of a mine + // or if the targetBlock has been set to ignore all block events which + // means the block has already been processed. + MinesEventResults eventResults = ignoreMinesBlockBreakEvent( e, + e.getPlayer(), e.getBlock()); + + if ( eventResults.isIgnoreEvent() ) { return; } - // Register all external events such as mcMMO and EZBlocks: - OnBlockBreakExternalEvents.getInstance().registerAllExternalEvents(); - StringBuilder debugInfo = new StringBuilder(); - - debugInfo.append( String.format( "### ** genericExplosiveEvent (Prisons's bombs) ** ### " + + debugInfo.append( String.format( "### ** handleExplosiveBlockBreakEvent (Prisons's bombs) ** ### " + "(event: ExplosiveBlockBreakEvent, config: %s, priority: %s, canceled: %s) ", bbPriority.name(), bbPriority.getBukkitEventPriority().name(), @@ -202,23 +258,35 @@ protected void handleExplosiveBlockBreakEvent( ExplosiveBlockBreakEvent e, Block ) ); - if ( bbPriority != BlockBreakPriority.MONITOR && !e.isCancelled() || bbPriority == BlockBreakPriority.MONITOR ) { + // Process all priorities if the event has not been canceled, and + // process the MONITOR priority even if the event was canceled: + if ( !bbPriority.isMonitor() && !e.isCancelled() || + bbPriority.isMonitor() ) { - String eP = getMessage( AutoFeatures.ProcessPrisons_ExplosiveBlockBreakEventsPriority ); - boolean isPPrisonExplosiveBlockBreakEnabled = eP != null && !"DISABLED".equalsIgnoreCase( eP ); - - - // Need to wrap in a Prison block so it can be used with the mines: - SpigotBlock sBlock = SpigotBlock.getSpigotBlock(e.getBlock()); - SpigotPlayer sPlayer = new SpigotPlayer(e.getPlayer()); - BlockEventType eventType = BlockEventType.PrisonExplosion; String triggered = e.getTriggeredBy(); - PrisonMinesBlockBreakEvent pmEvent = new PrisonMinesBlockBreakEvent( e.getBlock(), e.getPlayer(), - sBlock, sPlayer, bbPriority, eventType, triggered ); - + pmEvent = new PrisonMinesBlockBreakEvent( + e.getBlock(), + e.getPlayer(), + eventResults.getMine(), + bbPriority, eventType, triggered, + debugInfo ); + + + // NOTE: Check for the ACCESS priority and if someone does not have access, then return + // with a cancel on the event. Both ACCESSBLOCKEVENTS and ACCESSMONITOR will be + // converted to just ACCESS at this point, and the other part will run under either + // BLOCKEVENTS or MONITOR. + // This check has to be performed after creating the pmEvent object since it uses + // a lot of the internal variables and objects. There is not much of an impact since + // the validateEvent() has not been ran yet. + if ( checkIfNoAccess( pmEvent, start ) ) { + + e.setCancelled( true ); + return; + } // If this event is fired, but yet there are no exploded blocks, then do not set // forceIfAirBlock to true so this event is skipped. @@ -229,7 +297,6 @@ protected void handleExplosiveBlockBreakEvent( ExplosiveBlockBreakEvent e, Block } - // Warning: toolInHand really needs to be defined in the event if the source is a // Mine Bomb, otherwise auto features will detect the player is holding // a mine bomb which is not a pickaxe so the drops will be ZERO. If they @@ -250,7 +317,7 @@ protected void handleExplosiveBlockBreakEvent( ExplosiveBlockBreakEvent e, Block pmEvent.setCalculateDurability( false ); } - if ( !validateEvent( pmEvent, debugInfo ) ) { + if ( !validateEvent( pmEvent ) ) { // The event has not passed validation. All logging and Errors have been recorded // so do nothing more. This is to just prevent normal processing from occurring. @@ -259,94 +326,68 @@ protected void handleExplosiveBlockBreakEvent( ExplosiveBlockBreakEvent e, Block e.setCancelled( true ); } + + debugInfo.append( "(doAction failed validation) " ); } - else if ( pmEvent.getBbPriority() == BlockBreakPriority.MONITOR ) { - // Stop here, and prevent additional processing. Monitors should never process the event beyond this. - } + + // The validation was successful, but stop processing for the MONITOR priorities. + // Note that BLOCKEVENTS processing occured already within validateEvent(): + else if ( pmEvent.getBbPriority().isMonitor() ) { + // Stop here, and prevent additional processing. + // Monitors should never process the event beyond this. + } - - // now process all blocks (non-monitor): - else if ( isPPrisonExplosiveBlockBreakEnabled && - ( pmEvent.getMine() != null || pmEvent.getMine() == null && - !isBoolean( AutoFeatures.pickupLimitToMines )) ) { - - if ( pmEvent.getExplodedBlocks().size() > 0 ) { - - // String triggered = null; - - - // PrisonMinesBlockBreakEvent pmbbEvent = new PrisonMinesBlockBreakEvent( dummyBlock.getWrapper(), e.getPlayer(), - // mine, dummyBlock, explodedBlocks, BlockEventType.PEExplosive, triggered ); - Bukkit.getServer().getPluginManager().callEvent(pmEvent); - if ( pmEvent.isCancelled() ) { - debugInfo.append( "(normal processing: PrisonMinesBlockBreakEvent was canceled) " ); + // This is where the processing actually happens: + else { + +// debugInfo.append( "(normal processing initiating) " ); + + // check all external events such as mcMMO and EZBlocks: + if ( e instanceof BlockBreakEvent ) { + processPMBBExternalEvents( pmEvent, e ); + } + + + EventListenerCancelBy cancelBy = EventListenerCancelBy.none; + + cancelBy = processPMBBEvent( pmEvent ); + + + if ( cancelBy == EventListenerCancelBy.event ) { + + e.setCancelled( true ); + debugInfo.append( "(event canceled) " ); + } + else if ( cancelBy == EventListenerCancelBy.drops ) { + try + { + e.setDropItems( false ); + debugInfo.append( "(drop canceled) " ); } - else { - - // Cancel drops if so configured: - if ( isBoolean( AutoFeatures.cancelAllBlockEventBlockDrops ) ) { - - try - { - e.setDropItems( false ); - } - catch ( NoSuchMethodError e1 ) - { - String message = String.format( - "Warning: The autoFeaturesConfig.yml setting `cancelAllBlockEventBlockDrops` " + - "is not valid for this version of Spigot. Modify the config settings and set " + - "this value to `false`. [%s]", - e1.getMessage() ); - Output.get().logWarn( message ); - } - } - - if ( doAction( pmEvent, debugInfo ) ) { - - if ( isBoolean( AutoFeatures.cancelAllBlockBreakEvents ) ) { - - e.setCancelled( true ); - } - else { - - debugInfo.append( "(event was not canceled) " ); - } - - finalizeBreakTheBlocks( pmEvent ); - - doBlockEvents( pmEvent ); - - } - - else { - - debugInfo.append( "(doAction failed without details) " ); - } + catch ( NoSuchMethodError e1 ) + { + String message = String.format( + "Warning: The autoFeaturesConfig.yml setting `cancelAllBlockEventBlockDrops` " + + "is not valid for this version of Spigot. It's only vaid for spigot v1.12.x and higher. " + + "Modify the config settings and set this value to `false`. For now, it is temporarily " + + "disabled. [%s]", + e1.getMessage() ); + Output.get().logWarn( message ); + AutoFeaturesWrapper.getInstance().getAutoFeaturesConfig() + .setFeature( AutoFeatures.cancelAllBlockEventBlockDrops, false ); } - } - - - debugInfo.append( "(normal processing) " ); - } - else { - - debugInfo.append( "(logic bypass) " ); - } - - } - - if ( debugInfo.length() > 0 ) { + + } + } - long stop = System.nanoTime(); - debugInfo.append( " [" ).append( (stop - start) / 1000000d ).append( " ms]" ); - Output.get().logDebug( DebugTarget.blockBreak, debugInfo.toString() ); } + printDebugInfo( pmEvent, start ); } @Override @@ -355,4 +396,5 @@ protected int checkBonusXp( Player player, Block block, ItemStack item ) { return bonusXp; } + } diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/autofeatures/events/AutoManagerRevEnchantsExplosiveEvent.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/autofeatures/events/AutoManagerRevEnchantsExplosiveEvent.java new file mode 100644 index 000000000..f5cbcc8c5 --- /dev/null +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/autofeatures/events/AutoManagerRevEnchantsExplosiveEvent.java @@ -0,0 +1,411 @@ +package tech.mcprison.prison.spigot.autofeatures.events; + +import org.bukkit.Bukkit; +import org.bukkit.block.Block; +import org.bukkit.entity.Player; +import org.bukkit.event.Event; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.HandlerList; +import org.bukkit.event.Listener; +import org.bukkit.inventory.ItemStack; +import org.bukkit.plugin.EventExecutor; +import org.bukkit.plugin.PluginManager; + +import me.revils.revenchants.events.ExplosiveEvent; +import tech.mcprison.prison.autofeatures.AutoFeaturesFileConfig.AutoFeatures; +import tech.mcprison.prison.mines.features.MineBlockEvent.BlockEventType; +import tech.mcprison.prison.output.Output; +import tech.mcprison.prison.spigot.SpigotPrison; +import tech.mcprison.prison.spigot.api.PrisonMinesBlockBreakEvent; +import tech.mcprison.prison.spigot.autofeatures.AutoManagerFeatures; +import tech.mcprison.prison.spigot.block.BlockBreakPriority; + +public class AutoManagerRevEnchantsExplosiveEvent + extends AutoManagerFeatures + implements PrisonEventManager +{ + + private BlockBreakPriority bbPriority; + + public AutoManagerRevEnchantsExplosiveEvent() { + super(); + } + + public AutoManagerRevEnchantsExplosiveEvent( BlockBreakPriority bbPriority ) { + super(); + + this.bbPriority = bbPriority; + } + + + public BlockBreakPriority getBbPriority() { + return bbPriority; + } + public void setBbPriority( BlockBreakPriority bbPriority ) { + this.bbPriority = bbPriority; + } + + @Override + public void registerEvents() { + + initialize(); + + } + + + public class AutoManagerRevEnchantsExplosiveEventListener + extends AutoManagerRevEnchantsExplosiveEvent + implements Listener { + + public AutoManagerRevEnchantsExplosiveEventListener( BlockBreakPriority bbPriority ) { + super( bbPriority ); + } + + @EventHandler(priority=EventPriority.NORMAL) + public void onRevEnchantsExplosive( + ExplosiveEvent e, BlockBreakPriority bbPriority) { + + if ( isDisabled( e.getPlayer().getLocation().getWorld().getName() ) || + bbPriority.isDisabled() ) { + return; + } + + handleRevEnchantsExplosiveEvent( e, bbPriority ); + } + } + + + @Override + public void initialize() { + + String eP = getMessage( AutoFeatures.RevEnchantsExplosiveEventPriority ); + BlockBreakPriority bbPriority = BlockBreakPriority.fromString( eP ); + + setBbPriority( bbPriority ); + +// boolean isEventEnabled = eP != null && !"DISABLED".equalsIgnoreCase( eP ); + + if ( getBbPriority() == BlockBreakPriority.DISABLED ) { + return; + } + + // Check to see if the class ExplosiveEvent even exists: + try { + Output.get().logInfo( "AutoManager: checking if loaded: RevEnchants ExplosiveEvent" ); + + Class.forName( "me.revils.revenchants.events.ExplosiveEvent", false, + this.getClass().getClassLoader() ); + + Output.get().logInfo( "AutoManager: Trying to register RevEnchants ExplosiveEvent" ); + + if ( getBbPriority() != BlockBreakPriority.DISABLED ) { + if ( bbPriority.isComponentCompound() ) { + + for (BlockBreakPriority subBBPriority : bbPriority.getComponentPriorities()) { + + createListener( subBBPriority ); + } + } + else { + + createListener(bbPriority); + } + + } + } + catch ( ClassNotFoundException e ) { + // CrazyEnchants is not loaded... so ignore. + Output.get().logInfo( "AutoManager: RevEnchants ExplosiveEvent is not loaded" ); + } + catch ( Exception e ) { + Output.get().logInfo( "AutoManager: RevEnchants ExplosiveEvent failed to load. [%s]", e.getMessage() ); + } + } + + private void createListener( BlockBreakPriority bbPriority ) { + + SpigotPrison prison = SpigotPrison.getInstance(); + PluginManager pm = Bukkit.getServer().getPluginManager(); + EventPriority ePriority = bbPriority.getBukkitEventPriority(); + + + AutoManagerRevEnchantsExplosiveEventListener autoManagerListener = + new AutoManagerRevEnchantsExplosiveEventListener( bbPriority ); + + pm.registerEvent( + ExplosiveEvent.class, + autoManagerListener, ePriority, + new EventExecutor() { + public void execute(Listener l, Event e) { + + ExplosiveEvent exEvent = (ExplosiveEvent) e; + + ((AutoManagerRevEnchantsExplosiveEventListener)l) + .onRevEnchantsExplosive( exEvent, getBbPriority() ); + } + }, + prison); + prison.getRegisteredBlockListeners().add( autoManagerListener ); + } + + + @Override + public void unregisterListeners() { + +// super.unregisterListeners(); + } + + @Override + public void dumpEventListeners() { + + StringBuilder sb = new StringBuilder(); + + dumpEventListeners( sb ); + + if ( sb.length() > 0 ) { + + + for ( String line : sb.toString().split( "\n" ) ) { + + Output.get().logInfo( line ); + } + } + + } + + + @Override + public void dumpEventListeners( StringBuilder sb ) { + + String eP = getMessage( AutoFeatures.RevEnchantsExplosiveEventPriority ); + boolean isEventEnabled = eP != null && !"DISABLED".equalsIgnoreCase( eP ); + + if ( !isEventEnabled ) { + return; + } + + // Check to see if the class BlastUseEvent even exists: + try { + + Class.forName( "me.revils.revenchants.events.ExplosiveEvent", false, + this.getClass().getClassLoader() ); + + + HandlerList handlers = ExplosiveEvent.getHandlerList(); + +// String eP = getMessage( AutoFeatures.blockBreakEventPriority ); + BlockBreakPriority bbPriority = BlockBreakPriority.fromString( eP ); + + dumpEventListenersCore( "ExplosiveEvent", handlers, bbPriority, sb ); + + +// +// BlockBreakPriority bbPriority = BlockBreakPriority.fromString( eP ); +// +// +// String title = String.format( +// "ExplosiveEvent (%s)", +// ( bbPriority == null ? "--none--" : bbPriority.name()) ); +// +// ChatDisplay eventDisplay = Prison.get().getPlatform().dumpEventListenersChatDisplay( +// title, +// new SpigotHandlerList( ExplosiveEvent.getHandlerList()) ); +// +// if ( eventDisplay != null ) { +// sb.append( eventDisplay.toStringBuilder() ); +// sb.append( "\n" ); +// } +// +// +// if ( bbPriority.isComponentCompound() ) { +// StringBuilder sbCP = new StringBuilder(); +// for ( BlockBreakPriority bbp : bbPriority.getComponentPriorities() ) { +// if ( sbCP.length() > 0 ) { +// sbCP.append( ", " ); +// } +// sbCP.append( "'" ).append( bbp.name() ).append( "'" ); +// } +// +// String msg = String.format( "Note '%s' is a compound of: [%s]", +// bbPriority.name(), +// sbCP ); +// +// sb.append( msg ).append( "\n" ); +// } + } + catch ( ClassNotFoundException e ) { + // CrazyEnchants is not loaded... so ignore. + } + catch ( Exception e ) { + Output.get().logInfo( "AutoManager: RevEnchants ExplosiveEvent failed to load. [%s]", e.getMessage() ); + } + } + + + /** + *

Since there are multiple blocks associated with this event, pull out the player first and + * get the mine, then loop through those blocks to make sure they are within the mine. + *

+ * + *

The logic in this function is slightly different compared to genericBlockEvent() because this + * event contains multiple blocks so it's far more efficient to process the player data once. + * So that basically needed a slight refactoring. + *

+ * + * @param e + */ + public void handleRevEnchantsExplosiveEvent( ExplosiveEvent e, BlockBreakPriority bbPriority ) { + + PrisonMinesBlockBreakEvent pmEvent = null; + long start = System.nanoTime(); + + // If the event is canceled, it still needs to be processed because of the + // MONITOR events: + // An event will be "canceled" and "ignored" if the block + // BlockUtils.isUnbreakable(), or if the mine is actively resetting. + // The event will also be ignored if the block is outside of a mine + // or if the targetBlock has been set to ignore all block events which + // means the block has already been processed. + MinesEventResults eventResults = ignoreMinesBlockBreakEvent( e, + e.getPlayer(), e.getBlocks().get( 0 ) ); + if ( eventResults.isIgnoreEvent() ) { + return; + } + + + StringBuilder debugInfo = new StringBuilder(); + + debugInfo.append( String.format( "### ** handleRevEnchantsExplosiveEvent ** ### " + + "(event: ExplosiveEvent, config: %s, priority: %s, canceled: %s) ", + bbPriority.name(), + bbPriority.getBukkitEventPriority().name(), + (e.isCancelled() ? "TRUE " : "FALSE") + ) ); + + + // NOTE that check for auto manager has happened prior to accessing this function. + + // Process all priorities if the event has not been canceled, and + // process the MONITOR priority even if the event was canceled: + if ( !bbPriority.isMonitor() && !e.isCancelled() || + bbPriority.isMonitor() && + e.getBlocks().size() > 0 ) { + + + + Block bukkitBlock = e.getBlocks().get( 0 ); + + BlockEventType eventType = BlockEventType.RevEnExplosion; + String triggered = null; + + + pmEvent = new PrisonMinesBlockBreakEvent( + bukkitBlock, + e.getPlayer(), + eventResults.getMine(), + bbPriority, eventType, triggered, + debugInfo ); + + + // NOTE: Check for the ACCESS priority and if someone does not have access, then return + // with a cancel on the event. Both ACCESSBLOCKEVENTS and ACCESSMONITOR will be + // converted to just ACCESS at this point, and the other part will run under either + // BLOCKEVENTS or MONITOR. + // This check has to be performed after creating the pmEvent object since it uses + // a lot of the internal variables and objects. There is not much of an impact since + // the validateEvent() has not been ran yet. + if ( checkIfNoAccess( pmEvent, start ) ) { + + e.setCancelled( true ); + return; + } + + + for ( int i = 1; i < e.getBlocks().size(); i++ ) { + pmEvent.getUnprocessedRawBlocks().add( e.getBlocks().get( i ) ); + } + + + if ( !validateEvent( pmEvent ) ) { + + // The event has not passed validation. All logging and Errors have been recorded + // so do nothing more. This is to just prevent normal processing from occurring. + + if ( pmEvent.isCancelOriginalEvent() ) { + + e.setCancelled( true ); + } + + debugInfo.append( "(doAction failed validation) " ); + } + + + + // The validation was successful, but stop processing for the MONITOR priorities. + // Note that BLOCKEVENTS processing occured already within validateEvent(): + else if ( pmEvent.getBbPriority().isMonitor() ) { + // Stop here, and prevent additional processing. + // Monitors should never process the event beyond this. + } + + + + // This is where the processing actually happens: + else { + +// debugInfo.append( "(normal processing initiating) " ); + + // check all external events such as mcMMO and EZBlocks: +// if ( e instanceof BlockBreakEvent ) { +// processPMBBExternalEvents( pmEvent, debugInfo, e ); +// } +// + + EventListenerCancelBy cancelBy = EventListenerCancelBy.none; + + cancelBy = processPMBBEvent( pmEvent ); + + + if ( cancelBy != EventListenerCancelBy.none ) { + + e.setCancelled( true ); + debugInfo.append( "(event canceled) " ); + } +// else if ( cancelBy == EventListenerCancelBy.drops ) { +// try +// { +// e.setDropItems( false ); +// debugInfo.append( "(drop canceled) " ); +// } +// catch ( NoSuchMethodError e1 ) +// { +// String message = String.format( +// "Warning: The autoFeaturesConfig.yml setting `cancelAllBlockEventBlockDrops` " + +// "is not valid for this version of Spigot. It's only vaid for spigot v1.12.x and higher. " + +// "Modify the config settings and set this value to `false`. For now, it is temporarily " + +// "disabled. [%s]", +// e1.getMessage() ); +// Output.get().logWarn( message ); +// +// AutoFeaturesWrapper.getInstance().getAutoFeaturesConfig() +// .setFeature( AutoFeatures.cancelAllBlockEventBlockDrops, false ); +// } +// +// } + } + + + } + + printDebugInfo( pmEvent, start ); + } + + @Override + protected int checkBonusXp( Player player, Block block, ItemStack item ) { + int bonusXp = 0; + + return bonusXp; + } + +} diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/autofeatures/events/AutoManagerRevEnchantsJackHammerEvent.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/autofeatures/events/AutoManagerRevEnchantsJackHammerEvent.java new file mode 100644 index 000000000..50d69b806 --- /dev/null +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/autofeatures/events/AutoManagerRevEnchantsJackHammerEvent.java @@ -0,0 +1,411 @@ +package tech.mcprison.prison.spigot.autofeatures.events; + +import org.bukkit.Bukkit; +import org.bukkit.block.Block; +import org.bukkit.entity.Player; +import org.bukkit.event.Event; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.HandlerList; +import org.bukkit.event.Listener; +import org.bukkit.inventory.ItemStack; +import org.bukkit.plugin.EventExecutor; +import org.bukkit.plugin.PluginManager; + +import me.revils.revenchants.events.JackHammerEvent; +import tech.mcprison.prison.autofeatures.AutoFeaturesFileConfig.AutoFeatures; +import tech.mcprison.prison.mines.features.MineBlockEvent.BlockEventType; +import tech.mcprison.prison.output.Output; +import tech.mcprison.prison.spigot.SpigotPrison; +import tech.mcprison.prison.spigot.api.PrisonMinesBlockBreakEvent; +import tech.mcprison.prison.spigot.autofeatures.AutoManagerFeatures; +import tech.mcprison.prison.spigot.block.BlockBreakPriority; + +public class AutoManagerRevEnchantsJackHammerEvent + extends AutoManagerFeatures + implements PrisonEventManager { + + private BlockBreakPriority bbPriority; + + public AutoManagerRevEnchantsJackHammerEvent() { + super(); + } + + public AutoManagerRevEnchantsJackHammerEvent( BlockBreakPriority bbPriority ) { + super(); + + this.bbPriority = bbPriority; + } + + + public BlockBreakPriority getBbPriority() { + return bbPriority; + } + public void setBbPriority( BlockBreakPriority bbPriority ) { + this.bbPriority = bbPriority; + } + + @Override + public void registerEvents() { + + initialize(); + + } + + + + public class AutoManagerRevEnchantsJackHammerEventListener + extends AutoManagerRevEnchantsJackHammerEvent + implements Listener { + + public AutoManagerRevEnchantsJackHammerEventListener( BlockBreakPriority bbPriority ) { + super( bbPriority ); + } + + @EventHandler(priority=EventPriority.NORMAL) + public void onRevEnchantsJackHammer( + JackHammerEvent e, BlockBreakPriority bbPriority) { + + if ( isDisabled( e.getPlayer().getLocation().getWorld().getName() ) || + bbPriority.isDisabled()) { + return; + } + + handleRevEnchantsJackHammerEvent( e, bbPriority ); + } + } + + + @Override + public void initialize() { + + String eP = getMessage( AutoFeatures.RevEnchantsJackHammerEventPriority ); + + BlockBreakPriority bbPriority = BlockBreakPriority.fromString( eP ); + + setBbPriority( bbPriority ); + + // boolean isEventEnabled = eP != null && !"DISABLED".equalsIgnoreCase( eP ); + + if ( getBbPriority() == BlockBreakPriority.DISABLED ) { + return; + } + + // Check to see if the class JackHammerEvent even exists: + try { + Output.get().logInfo( "AutoManager: checking if loaded: RevEnchants JackHammerEvent" ); + + Class.forName( "me.revils.revenchants.events.JackHammerEvent", false, + this.getClass().getClassLoader() ); + + Output.get().logInfo( "AutoManager: Trying to register RevEnchants JackHammerEvent" ); + + if ( getBbPriority() != BlockBreakPriority.DISABLED ) { + if ( bbPriority.isComponentCompound() ) { + + for (BlockBreakPriority subBBPriority : bbPriority.getComponentPriorities()) { + + createListener( subBBPriority ); + } + } + else { + + createListener(bbPriority); + } + + } + + } + catch ( ClassNotFoundException e ) { + // CrazyEnchants is not loaded... so ignore. + Output.get().logInfo( "AutoManager: RevEnchants JackHammerEvent is not loaded" ); + } + catch ( Exception e ) { + Output.get().logInfo( "AutoManager: RevEnchants JackHammerEvent failed to load. [%s]", e.getMessage() ); + } + } + + private void createListener( BlockBreakPriority bbPriority ) { + + SpigotPrison prison = SpigotPrison.getInstance(); + PluginManager pm = Bukkit.getServer().getPluginManager(); + EventPriority ePriority = bbPriority.getBukkitEventPriority(); + + + AutoManagerRevEnchantsJackHammerEventListener autoManagerlListener = + new AutoManagerRevEnchantsJackHammerEventListener( bbPriority ); + + pm.registerEvent( + JackHammerEvent.class, + autoManagerlListener, ePriority, + new EventExecutor() { + public void execute(Listener l, Event e) { + + JackHammerEvent exEvent = (JackHammerEvent) e; + + ((AutoManagerRevEnchantsJackHammerEventListener)l) + .onRevEnchantsJackHammer( exEvent, getBbPriority() ); + } + }, + prison); + prison.getRegisteredBlockListeners().add( autoManagerlListener ); + } + + + @Override + public void unregisterListeners() { + + // super.unregisterListeners(); + } + + @Override + public void dumpEventListeners() { + + StringBuilder sb = new StringBuilder(); + + dumpEventListeners( sb ); + + if ( sb.length() > 0 ) { + + + for ( String line : sb.toString().split( "\n" ) ) { + + Output.get().logInfo( line ); + } + } + + } + + + @Override + public void dumpEventListeners( StringBuilder sb ) { + + String eP = getMessage( AutoFeatures.RevEnchantsJackHammerEventPriority ); + boolean isEventEnabled = eP != null && !"DISABLED".equalsIgnoreCase( eP ); + + if ( !isEventEnabled ) { + return; + } + + // Check to see if the class BlastUseEvent even exists: + try { + + Class.forName( "me.revils.revenchants.events.JackHammerEvent", false, + this.getClass().getClassLoader() ); + + + + HandlerList handlers = JackHammerEvent.getHandlerList(); + +// String eP = getMessage( AutoFeatures.blockBreakEventPriority ); + BlockBreakPriority bbPriority = BlockBreakPriority.fromString( eP ); + + dumpEventListenersCore( "JackHammerEvent", handlers, bbPriority, sb ); + + +// BlockBreakPriority bbPriority = BlockBreakPriority.fromString( eP ); +// +// +// String title = String.format( +// "JackHammerEvent (%s)", +// ( bbPriority == null ? "--none--" : bbPriority.name()) ); +// +// ChatDisplay eventDisplay = Prison.get().getPlatform().dumpEventListenersChatDisplay( +// title, +// new SpigotHandlerList( JackHammerEvent.getHandlerList()) ); +// +// if ( eventDisplay != null ) { +// sb.append( eventDisplay.toStringBuilder() ); +// sb.append( "\n" ); +// } +// +// +// if ( bbPriority.isComponentCompound() ) { +// StringBuilder sbCP = new StringBuilder(); +// for ( BlockBreakPriority bbp : bbPriority.getComponentPriorities() ) { +// if ( sbCP.length() > 0 ) { +// sbCP.append( ", " ); +// } +// sbCP.append( "'" ).append( bbp.name() ).append( "'" ); +// } +// +// String msg = String.format( "Note '%s' is a compound of: [%s]", +// bbPriority.name(), +// sbCP ); +// +// sb.append( msg ).append( "\n" ); +// } + } + catch ( ClassNotFoundException e ) { + // CrazyEnchants is not loaded... so ignore. + } + catch ( Exception e ) { + Output.get().logInfo( "AutoManager: RevEnchants JackHammerEnchants failed to load. [%s]", e.getMessage() ); + } + } + + + /** + *

Since there are multiple blocks associated with this event, pull out the player first and + * get the mine, then loop through those blocks to make sure they are within the mine. + *

+ * + *

The logic in this function is slightly different compared to genericBlockEvent() because this + * event contains multiple blocks so it's far more efficient to process the player data once. + * So that basically needed a slight refactoring. + *

+ * + * @param e + */ + public void handleRevEnchantsJackHammerEvent( JackHammerEvent e, BlockBreakPriority bbPriority ) { + + PrisonMinesBlockBreakEvent pmEvent = null; + long start = System.nanoTime(); + + // If the event is canceled, it still needs to be processed because of the + // MONITOR events: + // An event will be "canceled" and "ignored" if the block + // BlockUtils.isUnbreakable(), or if the mine is activly resetting. + // The event will also be ignored if the block is outside of a mine + // or if the targetBlock has been set to ignore all block events which + // means the block has already been processed. + MinesEventResults eventResults = ignoreMinesBlockBreakEvent( e, + e.getPlayer(), e.getBlocks().get( 0 ) ); + if ( eventResults.isIgnoreEvent() ) { + return; + } + + + StringBuilder debugInfo = new StringBuilder(); + + debugInfo.append( String.format( "### ** handleRevEnchantsJackHammerEvent ** ### " + + "(event: JackHammerEvent, config: %s, priority: %s, canceled: %s) ", + bbPriority.name(), + bbPriority.getBukkitEventPriority().name(), + (e.isCancelled() ? "TRUE " : "FALSE") + ) ); + + + // NOTE that check for auto manager has happened prior to accessing this function. + + // Process all priorities if the event has not been canceled, and + // process the MONITOR priority even if the event was canceled: + if ( !bbPriority.isMonitor() && !e.isCancelled() || + bbPriority.isMonitor() && + e.getBlocks().size() > 0 ) { + + + + Block bukkitBlock = e.getBlocks().get( 0 ); + + BlockEventType eventType = BlockEventType.RevEnJackHammer; + String triggered = null; + + + pmEvent = new PrisonMinesBlockBreakEvent( + bukkitBlock, e.getPlayer(), + eventResults.getMine(), + bbPriority, eventType, triggered, + debugInfo ); + + + // NOTE: Check for the ACCESS priority and if someone does not have access, then return + // with a cancel on the event. Both ACCESSBLOCKEVENTS and ACCESSMONITOR will be + // converted to just ACCESS at this point, and the other part will run under either + // BLOCKEVENTS or MONITOR. + // This check has to be performed after creating the pmEvent object since it uses + // a lot of the internal variables and objects. There is not much of an impact since + // the validateEvent() has not been ran yet. + if ( checkIfNoAccess( pmEvent, start ) ) { + + e.setCancelled( true ); + return; + } + + + for ( int i = 1; i < e.getBlocks().size(); i++ ) { + pmEvent.getUnprocessedRawBlocks().add( e.getBlocks().get( i ) ); + } + + + if ( !validateEvent( pmEvent ) ) { + + // The event has not passed validation. All logging and Errors have been recorded + // so do nothing more. This is to just prevent normal processing from occurring. + + if ( pmEvent.isCancelOriginalEvent() ) { + + e.setCancelled( true ); + } + + debugInfo.append( "(doAction failed validation) " ); + } + + + + // The validation was successful, but stop processing for the MONITOR priorities. + // Note that BLOCKEVENTS processing occured already within validateEvent(): + else if ( pmEvent.getBbPriority().isMonitor() ) { + // Stop here, and prevent additional processing. + // Monitors should never process the event beyond this. + } + + + // This is where the processing actually happens: + else { + +// debugInfo.append( "(normal processing initiating) " ); + + // check all external events such as mcMMO and EZBlocks: +// if ( e instanceof BlockBreakEvent ) { +// processPMBBExternalEvents( pmEvent, debugInfo, e ); +// } + + + EventListenerCancelBy cancelBy = EventListenerCancelBy.none; + + cancelBy = processPMBBEvent( pmEvent ); + + + if ( cancelBy != EventListenerCancelBy.none ) { + + e.setCancelled( true ); + debugInfo.append( "(event canceled) " ); + } +// else if ( cancelBy == EventListenerCancelBy.drops ) { +// try +// { +// e.setDropItems( false ); +// debugInfo.append( "(drop canceled) " ); +// } +// catch ( NoSuchMethodError e1 ) +// { +// String message = String.format( +// "Warning: The autoFeaturesConfig.yml setting `cancelAllBlockEventBlockDrops` " + +// "is not valid for this version of Spigot. It's only vaid for spigot v1.12.x and higher. " + +// "Modify the config settings and set this value to `false`. For now, it is temporarily " + +// "disabled. [%s]", +// e1.getMessage() ); +// Output.get().logWarn( message ); +// +// AutoFeaturesWrapper.getInstance().getAutoFeaturesConfig() +// .setFeature( AutoFeatures.cancelAllBlockEventBlockDrops, false ); +// } +// +// } + } + + + } + + printDebugInfo( pmEvent, start ); + } + + @Override + protected int checkBonusXp( Player player, Block block, ItemStack item ) { + int bonusXp = 0; + + return bonusXp; + } + +} diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/autofeatures/events/AutoManagerTokenEnchant.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/autofeatures/events/AutoManagerTokenEnchant.java index 7bb9ed080..0c7468bda 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/autofeatures/events/AutoManagerTokenEnchant.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/autofeatures/events/AutoManagerTokenEnchant.java @@ -6,6 +6,7 @@ import org.bukkit.event.Event; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; +import org.bukkit.event.HandlerList; import org.bukkit.event.Listener; import org.bukkit.inventory.ItemStack; import org.bukkit.plugin.EventExecutor; @@ -13,20 +14,13 @@ import com.vk2gpz.tokenenchant.event.TEBlockExplodeEvent; -import tech.mcprison.prison.Prison; import tech.mcprison.prison.autofeatures.AutoFeaturesFileConfig.AutoFeatures; import tech.mcprison.prison.mines.features.MineBlockEvent.BlockEventType; -import tech.mcprison.prison.output.ChatDisplay; import tech.mcprison.prison.output.Output; -import tech.mcprison.prison.output.Output.DebugTarget; import tech.mcprison.prison.spigot.SpigotPrison; import tech.mcprison.prison.spigot.api.PrisonMinesBlockBreakEvent; import tech.mcprison.prison.spigot.autofeatures.AutoManagerFeatures; import tech.mcprison.prison.spigot.block.BlockBreakPriority; -import tech.mcprison.prison.spigot.block.OnBlockBreakExternalEvents; -import tech.mcprison.prison.spigot.block.SpigotBlock; -import tech.mcprison.prison.spigot.game.SpigotHandlerList; -import tech.mcprison.prison.spigot.game.SpigotPlayer; public class AutoManagerTokenEnchant extends AutoManagerFeatures @@ -42,6 +36,12 @@ public AutoManagerTokenEnchant() { this.teExplosionTriggerEnabled = true; } + public AutoManagerTokenEnchant( BlockBreakPriority bbPriority ) { + this(); + + this.bbPriority = bbPriority; + } + public BlockBreakPriority getBbPriority() { return bbPriority; @@ -61,9 +61,14 @@ public class AutoManagerTokenEnchantEventListener extends AutoManagerTokenEnchant implements Listener { + public AutoManagerTokenEnchantEventListener( BlockBreakPriority bbPriority ) { + super( bbPriority ); + } + @EventHandler(priority=EventPriority.LOW) public void onTEBlockExplode( TEBlockExplodeEvent e, BlockBreakPriority bbPriority) { - if ( isDisabled( e.getBlock().getLocation().getWorld().getName() ) ) { + if ( isDisabled( e.getBlock().getLocation().getWorld().getName() ) || + bbPriority.isDisabled() ) { return; } @@ -77,7 +82,9 @@ public void onTEBlockExplode( TEBlockExplodeEvent e, BlockBreakPriority bbPriori public void initialize() { String eP = getMessage( AutoFeatures.TokenEnchantBlockExplodeEventPriority ); - setBbPriority( BlockBreakPriority.fromString( eP ) ); + BlockBreakPriority bbPriority = BlockBreakPriority.fromString( eP ); + + setBbPriority( bbPriority ); // boolean isEventEnabled = eP != null && !"DISABLED".equalsIgnoreCase( eP ); @@ -94,26 +101,21 @@ public void initialize() { Output.get().logInfo( "AutoManager: Trying to register TokenEnchant" ); - SpigotPrison prison = SpigotPrison.getInstance(); - PluginManager pm = Bukkit.getServer().getPluginManager(); - EventPriority ePriority = getBbPriority().getBukkitEventPriority(); - - - AutoManagerTokenEnchantEventListener autoManagerlListener = - new AutoManagerTokenEnchantEventListener(); - pm.registerEvent(TEBlockExplodeEvent.class, autoManagerlListener, ePriority, - new EventExecutor() { - public void execute(Listener l, Event e) { - ((AutoManagerTokenEnchantEventListener)l) - .onTEBlockExplode( (TEBlockExplodeEvent)e, getBbPriority() ); + if ( getBbPriority() != BlockBreakPriority.DISABLED ) { + if ( bbPriority.isComponentCompound() ) { + + for (BlockBreakPriority subBBPriority : bbPriority.getComponentPriorities()) { + + createListener( subBBPriority ); + } } - }, - prison); - prison.getRegisteredBlockListeners().add( autoManagerlListener ); - - - + else { + + createListener(bbPriority); + } + + } @@ -188,6 +190,27 @@ public void execute(Listener l, Event e) { Output.get().logInfo( "AutoManager: TokenEnchant failed to load. [%s]", e.getMessage() ); } } + + private void createListener( BlockBreakPriority bbPriority ) { + + SpigotPrison prison = SpigotPrison.getInstance(); + PluginManager pm = Bukkit.getServer().getPluginManager(); + EventPriority ePriority = bbPriority.getBukkitEventPriority(); + + + AutoManagerTokenEnchantEventListener autoManagerListener = + new AutoManagerTokenEnchantEventListener( bbPriority ); + + pm.registerEvent(TEBlockExplodeEvent.class, autoManagerListener, ePriority, + new EventExecutor() { + public void execute(Listener l, Event e) { + ((AutoManagerTokenEnchantEventListener)l) + .onTEBlockExplode( (TEBlockExplodeEvent)e, getBbPriority() ); + } + }, + prison); + prison.getRegisteredBlockListeners().add( autoManagerListener ); + } @Override @@ -232,20 +255,47 @@ public void dumpEventListeners( StringBuilder sb ) { Class.forName( "com.vk2gpz.tokenenchant.event.TEBlockExplodeEvent", false, this.getClass().getClassLoader() ); - BlockBreakPriority bbPriority = BlockBreakPriority.fromString( eP ); - - String title = String.format( - "TEBlockExplodeEvent (%s)", - ( bbPriority == null ? "--none--" : bbPriority.name()) ); - ChatDisplay eventDisplay = Prison.get().getPlatform().dumpEventListenersChatDisplay( - title, - new SpigotHandlerList( TEBlockExplodeEvent.getHandlerList()) ); + HandlerList handlers = TEBlockExplodeEvent.getHandlerList(); + +// String eP = getMessage( AutoFeatures.blockBreakEventPriority ); + BlockBreakPriority bbPriority = BlockBreakPriority.fromString( eP ); - if ( eventDisplay != null ) { - sb.append( eventDisplay.toStringBuilder() ); - sb.append( "\n" ); - } + dumpEventListenersCore( "BlockBreakEvent", handlers, bbPriority, sb ); + + + +// BlockBreakPriority bbPriority = BlockBreakPriority.fromString( eP ); +// +// String title = String.format( +// "TEBlockExplodeEvent (%s)", +// ( bbPriority == null ? "--none--" : bbPriority.name()) ); +// +// ChatDisplay eventDisplay = Prison.get().getPlatform().dumpEventListenersChatDisplay( +// title, +// new SpigotHandlerList( TEBlockExplodeEvent.getHandlerList()) ); +// +// if ( eventDisplay != null ) { +// sb.append( eventDisplay.toStringBuilder() ); +// sb.append( "\n" ); +// } +// +// +// if ( bbPriority.isComponentCompound() ) { +// StringBuilder sbCP = new StringBuilder(); +// for ( BlockBreakPriority bbp : bbPriority.getComponentPriorities() ) { +// if ( sbCP.length() > 0 ) { +// sbCP.append( ", " ); +// } +// sbCP.append( "'" ).append( bbp.name() ).append( "'" ); +// } +// +// String msg = String.format( "Note '%s' is a compound of: [%s]", +// bbPriority.name(), +// sbCP ); +// +// sb.append( msg ).append( "\n" ); +// } } catch ( ClassNotFoundException e ) { // TokenEnchant is not loaded... so ignore. @@ -269,22 +319,25 @@ public void dumpEventListeners( StringBuilder sb ) { */ public void handleTEBlockExplodeEvent( TEBlockExplodeEvent e, BlockBreakPriority bbPriority ) { -// , boolean monitor, boolean blockEventsOnly, -// boolean autoManager ) { - + PrisonMinesBlockBreakEvent pmEvent = null; long start = System.nanoTime(); - if ( e.isCancelled() || ignoreMinesBlockBreakEvent( e, e.getPlayer(), e.getBlock()) ) { + // If the event is canceled, it still needs to be processed because of the + // MONITOR events: + // An event will be "canceled" and "ignored" if the block + // BlockUtils.isUnbreakable(), or if the mine is activly resetting. + // The event will also be ignored if the block is outside of a mine + // or if the targetBlock has been set to ignore all block events which + // means the block has already been processed. + MinesEventResults eventResults = ignoreMinesBlockBreakEvent( e, e.getPlayer(), + e.getBlock()); + if ( eventResults.isIgnoreEvent() ) { return; } - - // Register all external events such as mcMMO and EZBlocks: - OnBlockBreakExternalEvents.getInstance().registerAllExternalEvents(); - + StringBuilder debugInfo = new StringBuilder(); - debugInfo.append( String.format( "### ** genericBlockExplodeEvent ** ### " + "(event: TEBlockExplodeEvent, config: %s, priority: %s, canceled: %s) ", bbPriority.name(), @@ -293,26 +346,37 @@ public void handleTEBlockExplodeEvent( TEBlockExplodeEvent e, BlockBreakPriority ) ); - - if ( bbPriority != BlockBreakPriority.MONITOR && !e.isCancelled() || bbPriority == BlockBreakPriority.MONITOR ) { - + // Process all priorities if the event has not been canceled, and + // process the MONITOR priority even if the event was canceled: + if ( !bbPriority.isMonitor() && !e.isCancelled() || + bbPriority.isMonitor() ) { - - String eP = getMessage( AutoFeatures.TokenEnchantBlockExplodeEventPriority ); - boolean isTEExplosiveEnabled = eP != null && !"DISABLED".equalsIgnoreCase( eP ); - - - // Need to wrap in a Prison block so it can be used with the mines: - SpigotBlock sBlock = SpigotBlock.getSpigotBlock(e.getBlock()); - SpigotPlayer sPlayer = new SpigotPlayer(e.getPlayer()); - BlockEventType eventType = BlockEventType.TEXplosion; - String triggered = checkCEExplosionTriggered( e ); + String triggered = checkTEBlockExplodeEventTriggered( e ); - PrisonMinesBlockBreakEvent pmEvent = new PrisonMinesBlockBreakEvent( e.getBlock(), e.getPlayer(), - sBlock, sPlayer, bbPriority, eventType, triggered ); + pmEvent = new PrisonMinesBlockBreakEvent( + e.getBlock(), + e.getPlayer(), + eventResults.getMine(), + bbPriority, eventType, triggered, + debugInfo ); + + // NOTE: Check for the ACCESS priority and if someone does not have access, then return + // with a cancel on the event. Both ACCESSBLOCKEVENTS and ACCESSMONITOR will be + // converted to just ACCESS at this point, and the other part will run under either + // BLOCKEVENTS or MONITOR. + // This check has to be performed after creating the pmEvent object since it uses + // a lot of the internal variables and objects. There is not much of an impact since + // the validateEvent() has not been ran yet. + if ( checkIfNoAccess( pmEvent, start ) ) { + + e.setCancelled( true ); + return; + } + + // NOTE: Token Enchant will pass the event's block to prison, but that block may // have already been processed by prison. Therefore the PrisonMinesBlockBreakEvent // must enable the feature setForceIfAirBlock( true ). That block will not be used a @@ -321,7 +385,7 @@ public void handleTEBlockExplodeEvent( TEBlockExplodeEvent e, BlockBreakPriority pmEvent.setUnprocessedRawBlocks( e.blockList() ); - if ( !validateEvent( pmEvent, debugInfo ) ) { + if ( !validateEvent( pmEvent ) ) { // The event has not passed validation. All logging and Errors have been recorded // so do nothing more. This is to just prevent normal processing from occurring. @@ -330,99 +394,72 @@ public void handleTEBlockExplodeEvent( TEBlockExplodeEvent e, BlockBreakPriority e.setCancelled( true ); } + + debugInfo.append( "(doAction failed validation) " ); } - else if ( pmEvent.getBbPriority() == BlockBreakPriority.MONITOR ) { - // Stop here, and prevent additional processing. Monitors should never process the event beyond this. - } + // The validation was successful, but stop processing for the MONITOR priorities. + // Note that BLOCKEVENTS processing occured already within validateEvent(): + else if ( pmEvent.getBbPriority().isMonitor() ) { + // Stop here, and prevent additional processing. + // Monitors should never process the event beyond this. + } - // now process all blocks (non-monitor): - else if ( isTEExplosiveEnabled && - ( pmEvent.getMine() != null || pmEvent.getMine() == null && - !isBoolean( AutoFeatures.pickupLimitToMines )) ) { + + // This is where the processing actually happens: + else { - if ( pmEvent.getExplodedBlocks().size() > 0 ) { - -// String triggered = checkCEExplosionTriggered( e ); -// -// -// PrisonMinesBlockBreakEvent pmbbEvent = new PrisonMinesBlockBreakEvent( e.getBlock(), e.getPlayer(), -// mine, block, explodedBlocks, BlockEventType.TEXplosion, triggered ); - Bukkit.getServer().getPluginManager().callEvent( pmEvent ); - if ( pmEvent.isCancelled() ) { - debugInfo.append( "(normal processing: PrisonMinesBlockBreakEvent was canceled) " ); - } - else { - - // Cancel drops if so configured: - if ( isBoolean( AutoFeatures.cancelAllBlockEventBlockDrops ) ) { - - try - { - e.setYield( 0 ); -// e.setDropItems( false ); - } - catch ( NoSuchMethodError e1 ) - { - String message = String.format( - "Warning: The autoFeaturesConfig.yml setting `cancelAllBlockEventBlockDrops` " + - "is not valid for this version of Spigot. Modify the config settings and set " + - "this value to `false`. [%s]", - e1.getMessage() ); - Output.get().logWarn( message ); - } - } - - // This is where the processing actually happens: - if ( doAction( pmEvent, debugInfo ) ) { - - if ( isBoolean( AutoFeatures.cancelAllBlockBreakEvents ) ) { - - e.setCancelled( true ); - } - else { - - debugInfo.append( "(event was not canceled) " ); - } - - finalizeBreakTheBlocks( pmEvent ); - - doBlockEvents( pmEvent ); - - } - - else { - - debugInfo.append( "(doAction failed without details) " ); - } - - } - - } +// debugInfo.append( "(normal processing initiating) " ); + // check all external events such as mcMMO and EZBlocks: +// if ( e instanceof BlockBreakEvent ) { +// processPMBBExternalEvents( pmEvent, debugInfo, e ); +// } - debugInfo.append( "(normal processing) " ); - } - else { - debugInfo.append( "(logic bypass) " ); + EventListenerCancelBy cancelBy = EventListenerCancelBy.none; + + cancelBy = processPMBBEvent( pmEvent ); + + + if ( cancelBy != EventListenerCancelBy.none ) { + + e.setCancelled( true ); + debugInfo.append( "(event canceled) " ); + } +// else if ( cancelBy == EventListenerCancelBy.drops ) { +// try +// { +// e.setDropItems( false ); +// debugInfo.append( "(drop canceled) " ); +// } +// catch ( NoSuchMethodError e1 ) +// { +// String message = String.format( +// "Warning: The autoFeaturesConfig.yml setting `cancelAllBlockEventBlockDrops` " + +// "is not valid for this version of Spigot. It's only vaid for spigot v1.12.x and higher. " + +// "Modify the config settings and set this value to `false`. For now, it is temporarily " + +// "disabled. [%s]", +// e1.getMessage() ); +// Output.get().logWarn( message ); +// +// AutoFeaturesWrapper.getInstance().getAutoFeaturesConfig() +// .setFeature( AutoFeatures.cancelAllBlockEventBlockDrops, false ); +// } +// +// } } + } - if ( debugInfo.length() > 0 ) { - - long stop = System.nanoTime(); - debugInfo.append( " [" ).append( (stop - start) / 1000000d ).append( " ms]" ); - - Output.get().logDebug( DebugTarget.blockBreak, debugInfo.toString() ); - } + printDebugInfo( pmEvent, start ); } - private String checkCEExplosionTriggered( TEBlockExplodeEvent e ) + private String checkTEBlockExplodeEventTriggered( TEBlockExplodeEvent e ) { String triggered = null; diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/autofeatures/events/AutoManagerZenchantments.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/autofeatures/events/AutoManagerZenchantments.java index 7340c5eb9..bb016a7a4 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/autofeatures/events/AutoManagerZenchantments.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/autofeatures/events/AutoManagerZenchantments.java @@ -1,35 +1,26 @@ package tech.mcprison.prison.spigot.autofeatures.events; -import java.util.ArrayList; -import java.util.List; - import org.bukkit.Bukkit; import org.bukkit.block.Block; import org.bukkit.entity.Player; import org.bukkit.event.Event; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; +import org.bukkit.event.HandlerList; import org.bukkit.event.Listener; import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.inventory.ItemStack; import org.bukkit.plugin.EventExecutor; import org.bukkit.plugin.PluginManager; -import tech.mcprison.prison.Prison; import tech.mcprison.prison.autofeatures.AutoFeaturesFileConfig.AutoFeatures; import tech.mcprison.prison.autofeatures.AutoFeaturesWrapper; import tech.mcprison.prison.mines.features.MineBlockEvent.BlockEventType; -import tech.mcprison.prison.output.ChatDisplay; import tech.mcprison.prison.output.Output; -import tech.mcprison.prison.output.Output.DebugTarget; import tech.mcprison.prison.spigot.SpigotPrison; import tech.mcprison.prison.spigot.api.PrisonMinesBlockBreakEvent; import tech.mcprison.prison.spigot.autofeatures.AutoManagerFeatures; import tech.mcprison.prison.spigot.block.BlockBreakPriority; -import tech.mcprison.prison.spigot.block.OnBlockBreakExternalEvents; -import tech.mcprison.prison.spigot.block.SpigotBlock; -import tech.mcprison.prison.spigot.game.SpigotHandlerList; -import tech.mcprison.prison.spigot.game.SpigotPlayer; import zedly.zenchantments.BlockShredEvent; public class AutoManagerZenchantments @@ -42,6 +33,12 @@ public AutoManagerZenchantments() { super(); } + public AutoManagerZenchantments( BlockBreakPriority bbPriority ) { + super(); + + this.bbPriority = bbPriority; + } + public BlockBreakPriority getBbPriority() { return bbPriority; @@ -62,6 +59,10 @@ public class AutoManagerBlockShredEventListener extends AutoManagerZenchantments implements Listener { + public AutoManagerBlockShredEventListener( BlockBreakPriority bbPriority ) { + super( bbPriority ); + } + @EventHandler(priority=EventPriority.NORMAL) public void onBlockShredBreak( BlockShredEvent e, BlockBreakPriority bbPriority ) { @@ -81,7 +82,9 @@ public void onBlockShredBreak( BlockShredEvent e, BlockBreakPriority bbPriority public void initialize() { String eP = getMessage( AutoFeatures.ZenchantmentsBlockShredEventPriority ); - setBbPriority( BlockBreakPriority.fromString( eP ) ); + BlockBreakPriority bbPriority = BlockBreakPriority.fromString( eP ); + + setBbPriority( bbPriority ); // boolean isEventEnabled = eP != null && !"DISABLED".equalsIgnoreCase( eP ); @@ -98,30 +101,20 @@ public void initialize() { Output.get().logInfo( "AutoManager: Trying to register Zenchantments" ); - SpigotPrison prison = SpigotPrison.getInstance(); - PluginManager pm = Bukkit.getServer().getPluginManager(); - EventPriority ePriority = getBbPriority().getBukkitEventPriority(); - - AutoManagerBlockShredEventListener autoManagerlListener = - new AutoManagerBlockShredEventListener(); - - pm.registerEvent(BlockShredEvent.class, autoManagerlListener, ePriority, - new EventExecutor() { - public void execute(Listener l, Event e) { - if ( l instanceof AutoManagerBlockShredEventListener && - e instanceof BlockShredEvent ) { - - AutoManagerBlockShredEventListener lmon = - (AutoManagerBlockShredEventListener) l; - - BlockShredEvent event = (BlockShredEvent) e; - lmon.onBlockShredBreak( event, getBbPriority() ); - } + if ( getBbPriority() != BlockBreakPriority.DISABLED ) { + if ( bbPriority.isComponentCompound() ) { + + for (BlockBreakPriority subBBPriority : bbPriority.getComponentPriorities()) { + + createListener( subBBPriority ); + } } - }, - prison); - prison.getRegisteredBlockListeners().add( autoManagerlListener ); - + else { + + createListener(bbPriority); + } + + } } catch ( ClassNotFoundException e ) { @@ -132,6 +125,33 @@ public void execute(Listener l, Event e) { Output.get().logInfo( "AutoManager: Zenchantments failed to load. [%s]", e.getMessage() ); } } + + private void createListener( BlockBreakPriority bbPriority ) { + + SpigotPrison prison = SpigotPrison.getInstance(); + PluginManager pm = Bukkit.getServer().getPluginManager(); + EventPriority ePriority = bbPriority.getBukkitEventPriority(); + + AutoManagerBlockShredEventListener autoManagerListener = + new AutoManagerBlockShredEventListener( bbPriority ); + + pm.registerEvent(BlockShredEvent.class, autoManagerListener, ePriority, + new EventExecutor() { + public void execute(Listener l, Event e) { + if ( l instanceof AutoManagerBlockShredEventListener && + e instanceof BlockShredEvent ) { + + AutoManagerBlockShredEventListener lmon = + (AutoManagerBlockShredEventListener) l; + + BlockShredEvent event = (BlockShredEvent) e; + lmon.onBlockShredBreak( event, getBbPriority() ); + } + } + }, + prison); + prison.getRegisteredBlockListeners().add( autoManagerListener ); + } @Override public void unregisterListeners() { @@ -174,23 +194,49 @@ public void dumpEventListeners( StringBuilder sb ) { Class.forName( "zedly.zenchantments.BlockShredEvent", false, this.getClass().getClassLoader() ); - BlockBreakPriority bbPriority = BlockBreakPriority.fromString( eP ); - String title = String.format( - "BlockShredEvent (%s)", - ( bbPriority == null ? "--none--" : bbPriority.name()) ); + HandlerList handlers = BlockShredEvent.getHandlerList(); + +// String eP = getMessage( AutoFeatures.blockBreakEventPriority ); + BlockBreakPriority bbPriority = BlockBreakPriority.fromString( eP ); + dumpEventListenersCore( "BlockBreakEvent", handlers, bbPriority, sb ); - ChatDisplay eventDisplay = Prison.get().getPlatform().dumpEventListenersChatDisplay( - title, - new SpigotHandlerList( BlockShredEvent.getHandlerList()) ); + - if ( eventDisplay != null ) { - sb.append( eventDisplay.toStringBuilder() ); - sb.append( "NOTE: Zenchantments uses the same HandlerList as BlockBreakEvent so " + - "listeners are combined due to this bug.\n" ); - sb.append( "\n" ); - } +// BlockBreakPriority bbPriority = BlockBreakPriority.fromString( eP ); +// +// String title = String.format( +// "BlockShredEvent (%s)", +// ( bbPriority == null ? "--none--" : bbPriority.name()) ); +// +// +// ChatDisplay eventDisplay = Prison.get().getPlatform().dumpEventListenersChatDisplay( +// title, +// new SpigotHandlerList( BlockShredEvent.getHandlerList()) ); +// +// if ( eventDisplay != null ) { +// sb.append( eventDisplay.toStringBuilder() ); +// sb.append( "NOTE: Zenchantments uses the same HandlerList as BlockBreakEvent so " + +// "listeners are combined due to this bug.\n" ); +// sb.append( "\n" ); +// } +// +// if ( bbPriority.isComponentCompound() ) { +// StringBuilder sbCP = new StringBuilder(); +// for ( BlockBreakPriority bbp : bbPriority.getComponentPriorities() ) { +// if ( sbCP.length() > 0 ) { +// sbCP.append( ", " ); +// } +// sbCP.append( "'" ).append( bbp.name() ).append( "'" ); +// } +// +// String msg = String.format( "Note '%s' is a compound of: [%s]", +// bbPriority.name(), +// sbCP ); +// +// sb.append( msg ).append( "\n" ); +// } } catch ( ClassNotFoundException e ) { // Zenchantments is not loaded... so ignore. @@ -212,26 +258,29 @@ public void dumpEventListeners( StringBuilder sb ) { */ private void handleZenchantmentsBlockBreakEvent( BlockBreakEvent e, BlockBreakPriority bbPriority ) { -// boolean monitor, boolean blockEventsOnly, -// boolean autoManager ) { - if ( e instanceof PrisonMinesBlockBreakEvent ) { return; } + PrisonMinesBlockBreakEvent pmEvent = null; long start = System.nanoTime(); - if ( e.isCancelled() || ignoreMinesBlockBreakEvent( e, e.getPlayer(), e.getBlock()) ) { + // If the event is canceled, it still needs to be processed because of the + // MONITOR events: + // An event will be "canceled" and "ignored" if the block + // BlockUtils.isUnbreakable(), or if the mine is activly resetting. + // The event will also be ignored if the block is outside of a mine + // or if the targetBlock has been set to ignore all block events which + // means the block has already been processed. + MinesEventResults eventResults = ignoreMinesBlockBreakEvent( e, + e.getPlayer(), e.getBlock()); + if ( eventResults.isIgnoreEvent() ) { return; } - - - // Register all external events such as mcMMO and EZBlocks: - OnBlockBreakExternalEvents.getInstance().registerAllExternalEvents(); StringBuilder debugInfo = new StringBuilder(); - debugInfo.append( String.format( "### ** genericBlockEvent ** ### " + + debugInfo.append( String.format( "### ** handleZenchantmentsBlockBreakEvent ** ### " + "(event: BlockBreakEvent, config: %s, priority: %s, canceled: %s) ", bbPriority.name(), bbPriority.getBukkitEventPriority().name(), @@ -239,19 +288,38 @@ private void handleZenchantmentsBlockBreakEvent( BlockBreakEvent e, BlockBreakPr ) ); - if ( bbPriority != BlockBreakPriority.MONITOR && !e.isCancelled() || bbPriority == BlockBreakPriority.MONITOR ) { + // Process all priorities if the event has not been canceled, and + // process the MONITOR priority even if the event was canceled: + if ( !bbPriority.isMonitor() && !e.isCancelled() || + bbPriority.isMonitor() ) { + - // Need to wrap in a Prison block so it can be used with the mines: - SpigotBlock sBlock = SpigotBlock.getSpigotBlock(e.getBlock()); - SpigotPlayer sPlayer = new SpigotPlayer(e.getPlayer()); - BlockEventType eventType = BlockEventType.blockBreak; String triggered = null; - PrisonMinesBlockBreakEvent pmEvent = new PrisonMinesBlockBreakEvent( e.getBlock(), e.getPlayer(), - sBlock, sPlayer, bbPriority, eventType, triggered ); + pmEvent = new PrisonMinesBlockBreakEvent( + e.getBlock(), + e.getPlayer(), + eventResults.getMine(), + bbPriority, eventType, triggered, + debugInfo ); - if ( !validateEvent( pmEvent, debugInfo ) ) { + + // NOTE: Check for the ACCESS priority and if someone does not have access, then return + // with a cancel on the event. Both ACCESSBLOCKEVENTS and ACCESSMONITOR will be + // converted to just ACCESS at this point, and the other part will run under either + // BLOCKEVENTS or MONITOR. + // This check has to be performed after creating the pmEvent object since it uses + // a lot of the internal variables and objects. There is not much of an impact since + // the validateEvent() has not been ran yet. + if ( checkIfNoAccess( pmEvent, start ) ) { + + e.setCancelled( true ); + return; + } + + + if ( !validateEvent( pmEvent ) ) { // The event has not passed validation. All logging and Errors have been recorded // so do nothing more. This is to just prevent normal processing from occurring. @@ -260,103 +328,67 @@ private void handleZenchantmentsBlockBreakEvent( BlockBreakEvent e, BlockBreakPr e.setCancelled( true ); } + + debugInfo.append( "(doAction failed validation) " ); } - else if ( pmEvent.getBbPriority() == BlockBreakPriority.MONITOR ) { - // Stop here, and prevent additional processing. Monitors should never process the event beyond this. + // The validation was successful, but stop processing for the MONITOR priorities. + // Note that BLOCKEVENTS processing occured already within validateEvent(): + else if ( pmEvent.getBbPriority().isMonitor() ) { + // Stop here, and prevent additional processing. + // Monitors should never process the event beyond this. } - - // This is where the processing actually happens: - else if ( pmEvent.getMine() != null || pmEvent.getMine() == null && - !isBoolean( AutoFeatures.pickupLimitToMines ) ) { - debugInfo.append( "(normal processing initiating) " ); + + else { - // Set the mine's PrisonBlockTypes for the block. Used to identify custom blocks. - // Needed since processing of the block will lose track of which mine it came from. - if ( pmEvent.getMine() != null ) { - sBlock.setPrisonBlockTypes( pmEvent.getMine().getPrisonBlockTypes() ); - } + // This is where the processing actually happens: - // check all external events such as mcMMO and EZBlocks: - debugInfo.append( - OnBlockBreakExternalEvents.getInstance().checkAllExternalEvents( e ) ); - List explodedBlocks = new ArrayList<>(); - pmEvent.setExplodedBlocks( explodedBlocks ); -// String triggered = null; + if ( e instanceof BlockBreakEvent ) { + processPMBBExternalEvents( pmEvent, e ); + } -// PrisonMinesBlockBreakEvent pmbbEvent = new PrisonMinesBlockBreakEvent( e.getBlock(), e.getPlayer(), -// pmEvent.getMine(), sBlock, explodedBlocks, BlockEventType.blockBreak, triggered ); - Bukkit.getServer().getPluginManager().callEvent( pmEvent ); - if ( pmEvent.isCancelled() ) { - debugInfo.append( "(normal processing: PrisonMinesBlockBreakEvent was canceled) " ); - } - else { - - // Cancel drops if so configured: - if ( isBoolean( AutoFeatures.cancelAllBlockEventBlockDrops ) ) { - - try - { - e.setDropItems( false ); - } - catch ( NoSuchMethodError e1 ) - { - String message = String.format( - "Warning: The autoFeaturesConfig.yml setting `cancelAllBlockEventBlockDrops` " + - "is not valid for this version of Spigot. It's only vaid for spigot v1.12.x and higher. " + - "Modify the config settings and set this value to `false`. For now, it is temporarily " + - "disabled. [%s]", - e1.getMessage() ); - Output.get().logWarn( message ); - - AutoFeaturesWrapper.getInstance().getAutoFeaturesConfig() - .setFeature( AutoFeatures.cancelAllBlockEventBlockDrops, false ); - } - } - - // doAction returns a boolean that indicates if the event should be canceled or not: - if ( doAction( pmEvent, debugInfo ) ) { -// if ( doAction( sBlock, pmEvent.getMine(), pmEvent.getPlayer(), debugInfo ) ) { - - if ( isBoolean( AutoFeatures.cancelAllBlockBreakEvents ) ) { - e.setCancelled( true ); - } - else { - - debugInfo.append( "(event was not canceled) " ); - } - - finalizeBreakTheBlocks( pmEvent ); - - doBlockEvents( pmEvent ); - - } - else { - - debugInfo.append( "(doAction failed without details) " ); - } - - } - debugInfo.append( "(normal processing completed) " ); - } - else { + EventListenerCancelBy cancelBy = EventListenerCancelBy.none; - debugInfo.append( "(logic bypass) " ); + cancelBy = processPMBBEvent( pmEvent ); + + + if ( cancelBy == EventListenerCancelBy.event ) { + + e.setCancelled( true ); + debugInfo.append( "(event canceled) " ); + } + else if ( cancelBy == EventListenerCancelBy.drops ) { + try + { + e.setDropItems( false ); + debugInfo.append( "(drop canceled) " ); + } + catch ( NoSuchMethodError e1 ) + { + String message = String.format( + "Warning: The autoFeaturesConfig.yml setting `cancelAllBlockEventBlockDrops` " + + "is not valid for this version of Spigot. It's only vaid for spigot v1.12.x and higher. " + + "Modify the config settings and set this value to `false`. For now, it is temporarily " + + "disabled. [%s]", + e1.getMessage() ); + Output.get().logWarn( message ); + + AutoFeaturesWrapper.getInstance().getAutoFeaturesConfig() + .setFeature( AutoFeatures.cancelAllBlockEventBlockDrops, false ); + } + + } } + } - if ( debugInfo.length() > 0 ) { - - long stop = System.nanoTime(); - debugInfo.append( " [" ).append( (stop - start) / 1000000d ).append( " ms]" ); - - Output.get().logDebug( DebugTarget.blockBreak, debugInfo.toString() ); - } + printDebugInfo( pmEvent, start ); } + @Override protected int checkBonusXp( Player player, Block block, ItemStack item ) { @@ -364,4 +396,5 @@ protected int checkBonusXp( Player player, Block block, ItemStack item ) { return bonusXp; } + } diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/backpacks/BackpacksListeners.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/backpacks/BackpacksListeners.java index d380712b0..880241c65 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/backpacks/BackpacksListeners.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/backpacks/BackpacksListeners.java @@ -81,17 +81,17 @@ private void saveBackpackEdited(InventoryCloseEvent e) { id = title.substring(e.getPlayer().getName().length() + 13); } } catch (IndexOutOfBoundsException ignored){} - if (id != null){ +// if (id != null){ if (BackpacksUtil.backpackEdited.contains(e.getPlayer().getName())){ BackpacksUtil.get().setInventory((Player) e.getPlayer(), e.getInventory(), id); BackpacksUtil.get().removeFromEditedBackpack((Player) e.getPlayer()); } - } else { - if (BackpacksUtil.backpackEdited.contains(e.getPlayer().getName())) { - BackpacksUtil.get().setInventory((Player) e.getPlayer(), e.getInventory()); - BackpacksUtil.get().removeFromEditedBackpack((Player) e.getPlayer()); - } - } +// } else { +// if (BackpacksUtil.backpackEdited.contains(e.getPlayer().getName())) { +// BackpacksUtil.get().setInventory((Player) e.getPlayer(), e.getInventory(), null); +// BackpacksUtil.get().removeFromEditedBackpack((Player) e.getPlayer()); +// } +// } } } @@ -107,15 +107,17 @@ private void backpackEditEvent(InventoryClickEvent e) { id = title.substring(e.getWhoClicked().getName().length() + 13); } } catch (IndexOutOfBoundsException ignored){} - if (id != null){ - if (title.equalsIgnoreCase(e.getWhoClicked().getName() + " -> Backpack-" + id)){ + String backpackId = id == null ? + "" : "-" + id; +// if (id != null){ + if (title.equalsIgnoreCase(e.getWhoClicked().getName() + " -> Backpack" + backpackId)){ BackpacksUtil.get().addToEditedBackpack((Player) e.getWhoClicked()); } - } else { - if (title != null && title.equalsIgnoreCase(e.getWhoClicked().getName() + " -> Backpack")) { - BackpacksUtil.get().addToEditedBackpack((Player) e.getWhoClicked()); - } - } +// } else { +// if (title != null && title.equalsIgnoreCase(e.getWhoClicked().getName() + " -> Backpack")) { +// BackpacksUtil.get().addToEditedBackpack((Player) e.getWhoClicked()); +// } +// } } } diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/backpacks/BackpacksUtil.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/backpacks/BackpacksUtil.java index 97542afce..1140f941a 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/backpacks/BackpacksUtil.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/backpacks/BackpacksUtil.java @@ -12,6 +12,7 @@ import org.bukkit.OfflinePlayer; import org.bukkit.Sound; import org.bukkit.configuration.Configuration; +import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.Player; @@ -25,9 +26,9 @@ import tech.mcprison.prison.gui.PrisonCoreGuiMessages; import tech.mcprison.prison.spigot.SpigotPrison; import tech.mcprison.prison.spigot.SpigotUtil; +import tech.mcprison.prison.spigot.block.SpigotItemStack; import tech.mcprison.prison.spigot.compat.Compatibility; import tech.mcprison.prison.spigot.compat.SpigotCompatibility; -import tech.mcprison.prison.spigot.configs.BackpacksConfig; import tech.mcprison.prison.spigot.game.SpigotPlayer; /** @@ -121,17 +122,18 @@ public OfflinePlayer getBackpackOwnerOffline(String name){ return getOfflinePlayer(name); } - /** - * Get Backpack owner OfflinePlayer by name and backpack ID. - * - * @param name - PlayerName - * @param id - InventoryID - * - * @return OfflinePlayer - * */ - public OfflinePlayer getBackpackOwnerOffline(String name, String id){ - return getOfflinePlayer(name, id); - } + // The following is exactly the same as the function without the id.... +// /** +// * Get Backpack owner OfflinePlayer by name and backpack ID. +// * +// * @param name - PlayerName +// * @param id - InventoryID +// * +// * @return OfflinePlayer +// * */ +// public OfflinePlayer getBackpackOwnerOffline(String name, String id){ +// return getOfflinePlayer(name, id); +// } /** * Get Backpack Player by name. @@ -303,16 +305,16 @@ public void setBackpackSize(OfflinePlayer p, int size, String id){ backpackResize(p, size, id); } - /** - * Get a backpack size depending on the owner. - * - * @param p - Player - * - * @return backPackSize - Integer - * */ - public int getBackpackSize(Player p){ - return getSize(p); - } +// /** +// * Get a backpack size depending on the owner. +// * +// * @param p - Player +// * +// * @return backPackSize - Integer +// * */ +// public int getBackpackSize(Player p){ +// return getSize(p); +// } /** * Get a backpack size depending on the owner. @@ -326,6 +328,26 @@ public int getBackpackSize(Player p, String id){ return getSize(p, id); } +// /** +// * Get Prison Backpacks Inventory. +// * Also if you need to modify it you can do it just by using BackPacksUtil getInventory(player) +// * modify your inventory as you'd usually with spigot inventories +// * and then use BackPacksUtil setInventory(player, inventory) is recommended. +// * +// * EXAMPLE for adding item: +// * Inventory inv = BackPacksUtil.getInventory(p); +// * ItemStack item = new ItemStack(Material.COAL_ORE, 1); +// * inv.addItem(item) +// * BackPacksUtil.setInventory(inv); +// * +// * @param p - player +// * +// * @return inv - Inventory/Backpack. +// * */ +// public Inventory getBackpack(Player p){ +// return getBackpackOwn(p, null); +// } + /** * Get Prison Backpacks Inventory. * Also if you need to modify it you can do it just by using BackPacksUtil getInventory(player) @@ -338,15 +360,6 @@ public int getBackpackSize(Player p, String id){ * inv.addItem(item) * BackPacksUtil.setInventory(inv); * - * @param p - player - * - * @return inv - Inventory/Backpack. - * */ - public Inventory getBackpack(Player p){ - return getBackpackOwn(p); - } - - /** * Get Prison backpack of a Player + ID, because a player can have more than one Inventory. * * @param p - Player @@ -358,14 +371,15 @@ public Inventory getBackpack(Player p, String id){ return getBackpackOwn(p, id); } - /** - * Open backpack. - * - * @param p - Player - * */ - public void openBackpack(Player p){ - openBackpackMethod(p); - } +// /** +// * Open backpack. +// * +// * @param p - Player +// * */ +// public void openBackpack(Player p){ +// String id = null; +// openBackpackMethod(p, id); +// } /** * Open backpack by ID. @@ -392,15 +406,15 @@ public Inventory getBackpack(Player p, Inventory inv){ return getBackpackCustom(p, inv); } - /** - * Merge another inventory into the backpack inventory. - * - * @param p - player - * @param inv - Inventory - * */ - public void setInventory(Player p, Inventory inv){ - saveInventory(p, inv); - } +// /** +// * Merge another inventory into the backpack inventory. +// * +// * @param p - player +// * @param inv - Inventory +// * */ +// public void setInventory(Player p, Inventory inv){ +// saveInventory(p, inv, null); +// } /** * Merge another inventory into the backpack inventory by ID. @@ -413,29 +427,29 @@ public void setInventory(Player p, Inventory inv, String id){ saveInventory(p, inv, id); } - /** - * Add an item to the backpack inventory - * NOT TESTED! - * - * RECOMMENDED WAY: - * If you need to modify the inventory you can do it just by using BackPacksUtil getInventory(player), - * modify your inventory as you'd usually with spigot inventories, - * and then use BackPacksUtil setInventory(player, inventory) is recommended. - * - * EXAMPLE for adding item: - * Inventory inv = BackPacksUtil.getInventory(p); - * ItemStack item = new ItemStack(Material.COAL_ORE, 1); - * inv.addItem(item); - * BackPacksUtil.setInventory(inv); - * - * @param p - player - * @param item - itemstack - * - * @return HashMap with items that didn't fit. - * */ - public HashMap addItem(Player p, ItemStack item){ - return addItemToBackpack(p, item); - } +// /** +// * Add an item to the backpack inventory +// * NOT TESTED! +// * +// * RECOMMENDED WAY: +// * If you need to modify the inventory you can do it just by using BackPacksUtil getInventory(player), +// * modify your inventory as you'd usually with spigot inventories, +// * and then use BackPacksUtil setInventory(player, inventory) is recommended. +// * +// * EXAMPLE for adding item: +// * Inventory inv = BackPacksUtil.getInventory(p); +// * ItemStack item = new ItemStack(Material.COAL_ORE, 1); +// * inv.addItem(item); +// * BackPacksUtil.setInventory(inv); +// * +// * @param p - player +// * @param item - itemstack +// * +// * @return HashMap with items that didn't fit. +// * */ +// public HashMap addItem(Player p, ItemStack item){ +// return addItemToBackpack(p, item, null); +// } /** * Add an item to the backpack inventory @@ -462,29 +476,29 @@ public HashMap addItem(Player p, ItemStack item, String id){ return addItemToBackpack(p, item, id); } - /** - * Remove item from backpack - * NOT TESTED! - * - * RECOMMENDED WAY: - * If you need to modify the inventory you can do it just by using BackPacksUtil getInventory(player), - * modify your inventory as you'd usually with spigot inventories, - * and then use BackPacksUtil setInventory(player, inventory) is recommended. - * - * EXAMPLE for removing item: - * Inventory inv = BackPacksUtil.getInventory(p); - * ItemStack item = new ItemStack(Material.COAL_ORE, 1); - * inv.removeItem(item); - * BackPacksUtil.setInventory(inv); - * - * @param p - player - * @param item - itemstack - * - * @return HashMap with items that couldn't be removed. - * */ - public HashMap removeItem(Player p, ItemStack item){ - return removeItemFromBackpack(p, item); - } +// /** +// * Remove item from backpack +// * NOT TESTED! +// * +// * RECOMMENDED WAY: +// * If you need to modify the inventory you can do it just by using BackPacksUtil getInventory(player), +// * modify your inventory as you'd usually with spigot inventories, +// * and then use BackPacksUtil setInventory(player, inventory) is recommended. +// * +// * EXAMPLE for removing item: +// * Inventory inv = BackPacksUtil.getInventory(p); +// * ItemStack item = new ItemStack(Material.COAL_ORE, 1); +// * inv.removeItem(item); +// * BackPacksUtil.setInventory(inv); +// * +// * @param p - player +// * @param item - itemstack +// * +// * @return HashMap with items that couldn't be removed. +// * */ +// public HashMap removeItem(Player p, ItemStack item){ +// return removeItemFromBackpack(p, item, null); +// } /** * Remove item from backpack @@ -734,11 +748,11 @@ private boolean backpacksLimitSet(OfflinePlayer p, int limit) { return true; } - private void backpackConfigUpdater() { - BackpacksConfig bpTemp = new BackpacksConfig(); - bpTemp.initialize(); - backpacksConfig = bpTemp.getFileBackpacksConfig(); - } +// private void backpackConfigUpdater() { +// BackpacksConfig bpTemp = new BackpacksConfig(); +// bpTemp.initialize(); +// backpacksConfig = bpTemp.getFileBackpacksConfig(); +// } private static BackpacksUtil getInstance() { if (instance == null && SpigotPrison.getInstance().getConfig().getString("backpacks") != null && SpigotPrison.getInstance().getConfig().getString("backpacks").equalsIgnoreCase("true")){ @@ -942,42 +956,83 @@ private void backpackResize(OfflinePlayer p, int size, String id) { updateCachedBackpack(); } - private int getSize(Player p) { - updateCachedBackpack(); - - int backPackSize = backpackDefaultSize; - - try { - backPackSize = Integer.parseInt(backpacksDataConfig.getString("Inventories." + p.getUniqueId() + ".Items.Size")); - } catch (NumberFormatException ignored){} - - if (backPackSize % 9 != 0){ - backPackSize = (int) Math.ceil((float)backPackSize / 9) * 9; - } - - if (backPackSize == 0) backPackSize = 9; - - return getBackpackPermSize(p, backPackSize); - } +// private int getSize(Player p) { +// updateCachedBackpack(); +// +// int backPackSize = backpackDefaultSize; +// +// try { +// backPackSize = Integer.parseInt(backpacksDataConfig.getString("Inventories." + p.getUniqueId() + ".Items.Size")); +// } catch (NumberFormatException ignored){} +// +// if (backPackSize % 9 != 0){ +// backPackSize = (int) Math.ceil((float)backPackSize / 9) * 9; +// } +// +// if (backPackSize == 0) backPackSize = 9; +// +// return getBackpackPermSize(p, backPackSize); +// } + public int getBackpackSize( UUID playerUuid, String id ) { + String backpackId = id == null ? + "" : "-" + id; + + int backpackSize = backpackDefaultSize; + + try { + String size = backpacksDataConfig.getString("Inventories." + playerUuid + ".Items" + backpackId + ".Size"); + + backpackSize = Integer.parseInt( size ); + } catch (NumberFormatException ignored){} + + if (backpackSize % 9 != 0){ + backpackSize = (int) Math.ceil( backpackSize / 9.0d ) * 9; + } + + if (backpackSize == 0) backpackSize = 9; + + return backpackSize; + } + private int getSize(Player p, String id) { +// String backpackId = id == null ? +// "" : "-" + id; + updateCachedBackpack(); - int backPackSize = backpackDefaultSize; - - try { - backPackSize = Integer.parseInt(backpacksDataConfig.getString("Inventories." + p.getUniqueId() + ".Items-" + id + ".Size")); - } catch (NumberFormatException ignored){} - - if (backPackSize % 9 != 0){ - backPackSize = (int) Math.ceil((float)backPackSize / 9) * 9; - } - - if (backPackSize == 0) backPackSize = 9; + int backPackSize = getBackpackSize( p.getUniqueId(), id ); + +// int backPackSize = backpackDefaultSize; +// +// try { +// String size = backpacksDataConfig.getString("Inventories." + p.getUniqueId() + ".Items" + backpackId + ".Size"); +// +// backPackSize = Integer.parseInt( size ); +// } catch (NumberFormatException ignored){} +// +// if (backPackSize % 9 != 0){ +// backPackSize = (int) Math.ceil((float)backPackSize / 9) * 9; +// } +// +// if (backPackSize == 0) backPackSize = 9; return getBackpackPermSize(p, backPackSize); } + /** + *

This function will check for the largest backpack size permitted + * for a player by using the perm `prison.backpack.size.`. If a perm + * exists, then it will set a max size for the player, which will set the + * max size for the backpack if the backpack size is greater than the perm. + * If a player does not have this perm, then the backpack size will not be + * limited. + *

+ * + * @param p + * @param backPackSize + * @return + */ private int getBackpackPermSize(Player p, int backPackSize) { SpigotPlayer sPlayer = new SpigotPlayer(p); List perms = sPlayer.getPermissions("prison.backpack.size."); @@ -995,71 +1050,122 @@ private int getBackpackPermSize(Player p, int backPackSize) { return backPackSize; } - private Inventory getBackpackOwn(Player p) { - - updateCachedBackpack(); - - int size = getBackpackSize(p); - Inventory inv = Bukkit.createInventory(p, size, SpigotPrison.format("&3" + p.getName() + " -> Backpack")); - - // Get the Items config section - Set slots; - try { - slots = backpacksDataConfig.getConfigurationSection("Inventories." + p.getUniqueId() + ".Items").getKeys(false); - } catch (NullPointerException ex){ - return inv; - } - if (slots.size() != 0) { - for (String slot : slots) { - ItemStack finalItem = backpacksDataConfig.getItemStack("Inventories." + p.getUniqueId() + ".Items." + slot + ".ITEMSTACK"); - if (finalItem != null) { - int slotNumber = Integer.parseInt(slot); - if (size > slotNumber) { - inv.setItem(slotNumber, finalItem); - } - } - } - } - - return inv; - } +// private Inventory getBackpackOwn(Player p) { +// +// updateCachedBackpack(); +// +// int size = getBackpackSize(p, null); +// Inventory inv = Bukkit.createInventory(p, size, SpigotPrison.format("&3" + p.getName() + " -> Backpack")); +// +// // Get the Items config section +// Set slots; +// try { +// slots = backpacksDataConfig.getConfigurationSection("Inventories." + p.getUniqueId() + ".Items").getKeys(false); +// } catch (NullPointerException ex){ +// return inv; +// } +// if (slots.size() != 0) { +// for (String slot : slots) { +// ItemStack finalItem = backpacksDataConfig.getItemStack("Inventories." + p.getUniqueId() + ".Items." + slot + ".ITEMSTACK"); +// if (finalItem != null) { +// int slotNumber = Integer.parseInt(slot); +// if (size > slotNumber) { +// inv.setItem(slotNumber, finalItem); +// } +// } +// } +// } +// +// return inv; +// } + /** + *

This function returns prison based objects. + *

+ * + * @param player + * @param id + * @return + */ + public List getPrisonBackpackContents( UUID playerUuid, String id ) { + List contents = new ArrayList<>(); + + String backpackId = id == null ? + "" : "-" + id; + + updateCachedBackpack(); + + int size = getBackpackSize( playerUuid, id); + + // Get the Items config section + Set slots; + try { + slots = backpacksDataConfig.getConfigurationSection( + "Inventories." + playerUuid + ".Items" + backpackId).getKeys(false); + } catch (NullPointerException ex){ + return contents; + } + + if (slots.size() != 0) { + for (String slot : slots) { + ItemStack finalItem = backpacksDataConfig.getItemStack( + "Inventories." + playerUuid + ".Items" + backpackId + "." + slot + ".ITEMSTACK"); + if (finalItem != null) { + int slotNumber = Integer.parseInt(slot); + if (size > slotNumber) { + + contents.add( new SpigotItemStack( finalItem )); + } + } + } + } + + return contents; + } + private Inventory getBackpackOwn(Player p, String id) { - updateCachedBackpack(); - - int size = getBackpackSize(p, id); - Inventory inv = Bukkit.createInventory(p, size, SpigotPrison.format("&3" + p.getName() + " -> Backpack-" + id)); - - // Get the Items config section - Set slots; - try { - slots = backpacksDataConfig.getConfigurationSection("Inventories." + p.getUniqueId() + ".Items-" + id).getKeys(false); - } catch (NullPointerException ex){ - return inv; - } - if (slots.size() != 0) { - for (String slot : slots) { - ItemStack finalItem = backpacksDataConfig.getItemStack("Inventories." + p.getUniqueId() + ".Items-" + id + "." + slot + ".ITEMSTACK"); - if (finalItem != null) { - int slotNumber = Integer.parseInt(slot); - if (size > slotNumber) { - inv.setItem(slotNumber, finalItem); - } - } - } - } - - return inv; - } - - private void openBackpackMethod(Player p) { - playOpenBackpackSound(p); - Inventory inv = getBackpack(p); - p.openInventory(inv); - if (!openBackpacks.contains(p.getName())){ - openBackpacks.add(p.getName()); - } - } + String backpackId = id == null ? + "" : "-" + id; + + updateCachedBackpack(); + + int size = getBackpackSize(p, id); + + Inventory inv = Bukkit.createInventory(p, size, SpigotPrison.format("&3" + p.getName() + " -> Backpack" + backpackId)); + + // Get the Items config section + Set slots; + try { + slots = backpacksDataConfig.getConfigurationSection( + "Inventories." + p.getUniqueId() + ".Items" + backpackId).getKeys(false); + } catch (NullPointerException ex){ + return inv; + } + if (slots.size() != 0) { + for (String slot : slots) { + ItemStack finalItem = backpacksDataConfig.getItemStack( + "Inventories." + p.getUniqueId() + ".Items" + backpackId + "." + slot + ".ITEMSTACK"); + if (finalItem != null) { + int slotNumber = Integer.parseInt(slot); + if (size > slotNumber) { + inv.setItem(slotNumber, finalItem); + } + } + } + } + + return inv; + } + +// private void openBackpackMethod(Player p) { +// playOpenBackpackSound(p); +// String id = null; +// Inventory inv = getBackpack(p, id); +// p.openInventory(inv); +// if (!openBackpacks.contains(p.getName())){ +// openBackpacks.add(p.getName()); +// } +// } private void openBackpackMethod(Player p, String id) { playOpenBackpackSound(p); @@ -1094,68 +1200,71 @@ private Inventory getBackpackCustom(Player p, Inventory inv) { return inv; } - private void saveInventory(Player p, Inventory inv) { - updateCachedBackpack(); - - // Set dimensions if null or error. - boolean needToSetNewDimensions = checkDimensionError(p); - boolean needToSetNewOwner = checkBackpackOwnerMissing(p); - boolean needToSetNewOwnerID = checkBackpackOwnerIDMissing(p); - - if (inv.getContents() != null){ - - int backpackSize = getBackpackSize(p); - int slot = 0; - - try { - backpacksDataConfig.set("Inventories." + p.getUniqueId() + ".Items", null); - backpacksDataConfig.save(backpacksFile); - } catch (IOException ex){ - ex.printStackTrace(); - return; - } - - updateCachedBackpack(); - - backpacksDataConfig.set("Inventories." + p.getUniqueId() + ".Items.Size", backpackSize); - - for (ItemStack item : inv.getContents()){ - if (item != null){ - - backpacksDataConfig.set("Inventories." + p.getUniqueId() + ".Items." + slot + ".ITEMSTACK", item); - - slot++; - } - } - - oldDataVersionUpdater(p, false, true, true); - - try { - backpacksDataConfig.save(backpacksFile); - } catch (IOException ex){ - ex.printStackTrace(); - } - } else { - // If it's null just delete the whole stored inventory. - oldDataVersionUpdater(p, needToSetNewDimensions, needToSetNewOwner, needToSetNewOwnerID); - try { - backpacksDataConfig.set("Inventories." + p.getUniqueId().toString() + ".Items", null); - backpacksDataConfig.save(backpacksFile); - } catch (IOException ex){ - ex.printStackTrace(); - } - } - - updateCachedBackpack(); - } +// private void saveInventory(Player p, Inventory inv) { +// updateCachedBackpack(); +// +// // Set dimensions if null or error. +// boolean needToSetNewDimensions = checkDimensionError(p, null); +// boolean needToSetNewOwner = checkBackpackOwnerMissing(p); +// boolean needToSetNewOwnerID = checkBackpackOwnerIDMissing(p); +// +// if (inv.getContents() != null){ +// +// int backpackSize = getBackpackSize(p, null); +// int slot = 0; +// +// try { +// backpacksDataConfig.set("Inventories." + p.getUniqueId() + ".Items", null); +// backpacksDataConfig.save(backpacksFile); +// } catch (IOException ex){ +// ex.printStackTrace(); +// return; +// } +// +// updateCachedBackpack(); +// +// backpacksDataConfig.set("Inventories." + p.getUniqueId() + ".Items.Size", backpackSize); +// +// for (ItemStack item : inv.getContents()){ +// if (item != null){ +// +// backpacksDataConfig.set("Inventories." + p.getUniqueId() + ".Items." + slot + ".ITEMSTACK", item); +// +// slot++; +// } +// } +// +// oldDataVersionUpdater(p, null, false, true, true); +// +// try { +// backpacksDataConfig.save(backpacksFile); +// } catch (IOException ex){ +// ex.printStackTrace(); +// } +// } else { +// // If it's null just delete the whole stored inventory. +// oldDataVersionUpdater(p, null, needToSetNewDimensions, needToSetNewOwner, needToSetNewOwnerID); +// try { +// backpacksDataConfig.set("Inventories." + p.getUniqueId().toString() + ".Items", null); +// backpacksDataConfig.save(backpacksFile); +// } catch (IOException ex){ +// ex.printStackTrace(); +// } +// } +// +// updateCachedBackpack(); +// } private void saveInventory(Player p, Inventory inv, String id) { + String backpackId = id == null ? + "" : "-" + id; + updateCachedBackpack(); // Set dimensions if null or error. boolean needToSetNewDimensions = checkDimensionError(p, id); - boolean needToSetNewOwner = checkBackpackOwnerMissing(p, id); - boolean needToSetNewOwnerID = checkBackpackOwnerIDMissing(p, id); + boolean needToSetNewOwner = checkBackpackOwnerMissing(p); + boolean needToSetNewOwnerID = checkBackpackOwnerIDMissing(p); if (inv.getContents() != null){ @@ -1163,7 +1272,7 @@ private void saveInventory(Player p, Inventory inv, String id) { int slot = 0; try { - backpacksDataConfig.set("Inventories." + p.getUniqueId() + ".Items-" + id, null); + backpacksDataConfig.set("Inventories." + p.getUniqueId() + ".Items" + backpackId, null); backpacksDataConfig.save(backpacksFile); } catch (IOException ex){ ex.printStackTrace(); @@ -1172,14 +1281,14 @@ private void saveInventory(Player p, Inventory inv, String id) { updateCachedBackpack(); - backpacksDataConfig.set("Inventories." + p.getUniqueId() + ".Items-" + id + ".Size", backpackSize); + backpacksDataConfig.set("Inventories." + p.getUniqueId() + ".Items" + backpackId + ".Size", backpackSize); oldDataVersionUpdater(p, id, false, true, true); for (ItemStack item : inv.getContents()){ if (item != null){ - backpacksDataConfig.set("Inventories." + p.getUniqueId() + ".Items-" + id + "." + slot + ".ITEMSTACK", item); + backpacksDataConfig.set("Inventories." + p.getUniqueId() + ".Items" + backpackId + "." + slot + ".ITEMSTACK", item); slot++; } @@ -1195,7 +1304,7 @@ private void saveInventory(Player p, Inventory inv, String id) { // If it's null just delete the whole stored inventory. oldDataVersionUpdater(p, id, needToSetNewDimensions, needToSetNewOwner, needToSetNewOwnerID); try { - backpacksDataConfig.set("Inventories." + p.getUniqueId().toString() + ".Items-" + id, null); + backpacksDataConfig.set("Inventories." + p.getUniqueId().toString() + ".Items" + backpackId, null); backpacksDataConfig.save(backpacksFile); } catch (IOException ex){ ex.printStackTrace(); @@ -1205,21 +1314,26 @@ private void saveInventory(Player p, Inventory inv, String id) { updateCachedBackpack(); } - private void oldDataVersionUpdater(Player p, boolean needToSetNewDimensions, boolean needToSetNewOwner, boolean needToSetNewOwnerID) { - if (needToSetNewDimensions){ - backpacksDataConfig.set("Inventories." + p.getUniqueId() + ".Items.Size", Integer.parseInt(backpacksConfig.getString("Options.BackPack_Default_Size"))); - } - if (needToSetNewOwner){ - backpacksDataConfig.set("Inventories." + p.getUniqueId() + ".PlayerName", p.getName()); - } - if (needToSetNewOwnerID){ - backpacksDataConfig.set("Inventories." + p.getUniqueId() + ".UniqueID", p.getUniqueId().toString()); - } - } +// private void oldDataVersionUpdater(Player p, boolean needToSetNewDimensions, boolean needToSetNewOwner, boolean needToSetNewOwnerID) { +// if (needToSetNewDimensions){ +// backpacksDataConfig.set("Inventories." + p.getUniqueId() + ".Items.Size", +// Integer.parseInt(backpacksConfig.getString("Options.BackPack_Default_Size"))); +// } +// if (needToSetNewOwner){ +// backpacksDataConfig.set("Inventories." + p.getUniqueId() + ".PlayerName", p.getName()); +// } +// if (needToSetNewOwnerID){ +// backpacksDataConfig.set("Inventories." + p.getUniqueId() + ".UniqueID", p.getUniqueId().toString()); +// } +// } private void oldDataVersionUpdater(Player p, String id, boolean needToSetNewDimensions, boolean needToSetNewOwner, boolean needToSetNewOwnerID) { - if (needToSetNewDimensions){ - backpacksDataConfig.set("Inventories." + p.getUniqueId() + ".Items-" + id + ".Size", Integer.parseInt(backpacksConfig.getString("Options.BackPack_Default_Size"))); + String backpackId = id == null ? + "" : "-" + id; + + if (needToSetNewDimensions){ + backpacksDataConfig.set("Inventories." + p.getUniqueId() + ".Items" + backpackId + ".Size", + Integer.parseInt(backpacksConfig.getString("Options.BackPack_Default_Size"))); } if (needToSetNewOwner){ backpacksDataConfig.set("Inventories." + p.getUniqueId() + ".PlayerName", p.getName()); @@ -1229,12 +1343,13 @@ private void oldDataVersionUpdater(Player p, String id, boolean needToSetNewDime } } - private HashMap addItemToBackpack(Player p, ItemStack item) { - Inventory inv = getBackpack(p); - HashMap overflow = inv.addItem(item); - setInventory(p, inv); - return overflow; - } +// private HashMap addItemToBackpack(Player p, ItemStack item) { +// String id = null; +// Inventory inv = getBackpack(p, id); +// HashMap overflow = inv.addItem(item); +// setInventory(p, inv); +// return overflow; +// } private HashMap addItemToBackpack(Player p, ItemStack item, String id) { Inventory inv = getBackpack(p, id); @@ -1243,12 +1358,13 @@ private HashMap addItemToBackpack(Player p, ItemStack item, return overflow; } - private HashMap removeItemFromBackpack(Player p, ItemStack item) { - Inventory inv = getBackpack(p); - HashMap underflow = inv.removeItem(item); - setInventory(p, inv); - return underflow; - } +// private HashMap removeItemFromBackpack(Player p, ItemStack item) { +// String id = null; +// Inventory inv = getBackpack(p, id ); +// HashMap underflow = inv.removeItem(item); +// setInventory(p, inv); +// return underflow; +// } private HashMap removeItemFromBackpack(Player p, ItemStack item, String id) { Inventory inv = getBackpack(p, id); @@ -1356,24 +1472,35 @@ private int getNumberOfBackpacksOwnedByPlayer(Player p) { return backpacksNumber; } - private boolean checkDimensionError(Player p) { - try{ - if (backpacksDataConfig.getString("Inventories." + p.getUniqueId() + ".Items" + ".Size") == null){ - return true; - } - Integer.parseInt(backpacksDataConfig.getString("Inventories." + p.getUniqueId() + ".Items" + ".Size")); - } catch (NumberFormatException ex){ - return true; - } - return false; - } +// private boolean checkDimensionError(Player p) { +// try{ +// if (backpacksDataConfig.getString("Inventories." + p.getUniqueId() + ".Items" + ".Size") == null){ +// return true; +// } +// Integer.parseInt(backpacksDataConfig.getString("Inventories." + p.getUniqueId() + ".Items" + ".Size")); +// } catch (NumberFormatException ex){ +// return true; +// } +// return false; +// } + /** + * This function ONLY checks to confirm if the config setting is an integer!? \ + * + * @param p + * @param id + * @return + */ private boolean checkDimensionError(Player p, String id) { + String backpackId = id == null ? + "" : "-" + id; try{ - if (backpacksDataConfig.getString("Inventories." + p.getUniqueId() + ".Items-" + id + ".Size") == null){ + String size = backpacksDataConfig.getString("Inventories." + p.getUniqueId() + ".Items" + backpackId + ".Size"); + + if ( size == null){ return true; } - Integer.parseInt(backpacksDataConfig.getString("Inventories." + p.getUniqueId() + ".Items-" + id + ".Size")); + Integer.parseInt( size ); } catch (NumberFormatException ex){ return true; } @@ -1384,40 +1511,45 @@ private boolean checkBackpackOwnerMissing(Player p) { return backpacksDataConfig.getString("Inventories." + p.getUniqueId() + ".PlayerName") == null; } - private boolean checkBackpackOwnerMissing(Player p, String id) { - return backpacksDataConfig.getString("Inventories." + p.getUniqueId() + ".PlayerName") == null; - } +// private boolean checkBackpackOwnerMissing(Player p, String id) { +// return backpacksDataConfig.getString("Inventories." + p.getUniqueId() + ".PlayerName") == null; +// } private boolean checkBackpackOwnerIDMissing(Player p) { return backpacksDataConfig.getString("Inventories." + p.getUniqueId() + ".UniqueID") == null; } - private boolean checkBackpackOwnerIDMissing(Player p, String id) { - return backpacksDataConfig.getString("Inventories." + p.getUniqueId() + ".UniqueID") == null; - } +// private boolean checkBackpackOwnerIDMissing(Player p, String id) { +// return backpacksDataConfig.getString("Inventories." + p.getUniqueId() + ".UniqueID") == null; +// } - private OfflinePlayer getOfflinePlayer(String name) { - if (name != null) { - updateCachedBackpack(); - if (backpacksDataConfig.getConfigurationSection("Inventories") != null) { - for (String uniqueID : backpacksDataConfig.getConfigurationSection("Inventories").getKeys(false)) { - if (backpacksDataConfig.getString("Inventories." + uniqueID + ".PlayerName").equalsIgnoreCase(name) && backpacksDataConfig.getString("Inventories." + uniqueID + ".UniqueID") != null) { - return Bukkit.getOfflinePlayer(UUID.fromString(backpacksDataConfig.getString("Inventories." + uniqueID + ".UniqueID"))); - } - } - } - } - return null; - } +// private OfflinePlayer getOfflinePlayer(String name) { +// if (name != null) { +// updateCachedBackpack(); +// if (backpacksDataConfig.getConfigurationSection("Inventories") != null) { +// for (String uniqueID : backpacksDataConfig.getConfigurationSection("Inventories").getKeys(false)) { +// if (backpacksDataConfig.getString("Inventories." + uniqueID + ".PlayerName").equalsIgnoreCase(name) && backpacksDataConfig.getString("Inventories." + uniqueID + ".UniqueID") != null) { +// return Bukkit.getOfflinePlayer(UUID.fromString(backpacksDataConfig.getString("Inventories." + uniqueID + ".UniqueID"))); +// } +// } +// } +// } +// return null; +// } - private OfflinePlayer getOfflinePlayer(String name, String id) { + // what the hell? two functions with different parms but the damn exact same code???? +// private OfflinePlayer getOfflinePlayer(String name, String id) { + private OfflinePlayer getOfflinePlayer(String name) { if (name != null) { updateCachedBackpack(); - if (backpacksDataConfig.getConfigurationSection("Inventories") != null) { - for (String uniqueID : backpacksDataConfig.getConfigurationSection("Inventories").getKeys(false)) { - if (backpacksDataConfig.getString("Inventories." + uniqueID + ".PlayerName") != null && backpacksDataConfig.getString("Inventories." + uniqueID + ".UniqueID") != null){ - if (backpacksDataConfig.getString("Inventories." + uniqueID + ".PlayerName").equalsIgnoreCase(name)){ - return Bukkit.getOfflinePlayer(UUID.fromString(backpacksDataConfig.getString("Inventories." + uniqueID + ".UniqueID"))); + ConfigurationSection inventories = backpacksDataConfig.getConfigurationSection("Inventories"); + if (inventories != null) { + for (String uniqueID : inventories.getKeys(false)) { + String playerName = inventories.getString(uniqueID + ".PlayerName"); + String uuid = inventories.getString(uniqueID + ".UniqueID"); + if (playerName != null && uuid != null){ + if (playerName.equalsIgnoreCase(name)){ + return Bukkit.getOfflinePlayer(UUID.fromString(uuid)); } } } diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/block/BlockBreakPriority.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/block/BlockBreakPriority.java index 8d0df0060..544a9f659 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/block/BlockBreakPriority.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/block/BlockBreakPriority.java @@ -1,5 +1,8 @@ package tech.mcprison.prison.spigot.block; +import java.util.ArrayList; +import java.util.List; + import org.bukkit.event.EventPriority; /** @@ -25,20 +28,37 @@ public enum BlockBreakPriority { DISABLED( null ), - BLOCKEVENTS( EventPriority.HIGHEST ), LOWEST( EventPriority.LOWEST ), LOW( EventPriority.LOW ), NORMAL( EventPriority.NORMAL ), HIGH( EventPriority.HIGH ), HIGHEST( EventPriority.HIGHEST ), - MONITOR( EventPriority.MONITOR ) + + BLOCKEVENTS( EventPriority.HIGHEST ), + MONITOR( EventPriority.MONITOR ), + + ACCESS( EventPriority.LOWEST ), + ACCESSBLOCKEVENTS( EventPriority.HIGHEST, ACCESS, BLOCKEVENTS ), + ACCESSMONITOR( EventPriority.MONITOR, ACCESS, MONITOR ), ; private final EventPriority bukkitEventPriority; + private final List componentPriorities; + private BlockBreakPriority( EventPriority bukkitEventPriority ) { this.bukkitEventPriority = bukkitEventPriority; + + this.componentPriorities = new ArrayList<>(); + } + + private BlockBreakPriority( EventPriority bukkitEventPriority, BlockBreakPriority... components ) { + this( bukkitEventPriority ); + + for (BlockBreakPriority bbPriority : components) { + this.componentPriorities.add( bbPriority ); + } } public static BlockBreakPriority fromString( String value ) { @@ -57,7 +77,28 @@ public static BlockBreakPriority fromString( String value ) { return results; } + public boolean isMonitor() { + return this == MONITOR || + this == BLOCKEVENTS || + this == ACCESSBLOCKEVENTS || + this == ACCESSMONITOR + ; + } + + public boolean isDisabled() { + return this == DISABLED; + } + + public boolean isComponentCompound() { + return getComponentPriorities().size() > 0 + ; + } + public EventPriority getBukkitEventPriority() { return bukkitEventPriority; } -} \ No newline at end of file + + public List getComponentPriorities() { + return componentPriorities; + } +} diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/block/OnBlockBreakEventCore.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/block/OnBlockBreakEventCore.java index 5f8dbed56..0d0c02134 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/block/OnBlockBreakEventCore.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/block/OnBlockBreakEventCore.java @@ -13,6 +13,8 @@ import org.bukkit.inventory.meta.ItemMeta; import me.pulsi_.prisonenchants.events.PEExplosionEvent; +import me.revils.revenchants.events.ExplosiveEvent; +import me.revils.revenchants.events.JackHammerEvent; import tech.mcprison.prison.Prison; import tech.mcprison.prison.autofeatures.AutoFeaturesFileConfig; import tech.mcprison.prison.autofeatures.AutoFeaturesFileConfig.AutoFeatures; @@ -34,6 +36,7 @@ import tech.mcprison.prison.spigot.game.SpigotPlayer; import tech.mcprison.prison.spigot.sellall.SellAllUtil; import tech.mcprison.prison.spigot.utils.BlockUtils; +import tech.mcprison.prison.spigot.utils.tasks.PlayerAutoRankupTask; import tech.mcprison.prison.util.Text; public abstract class OnBlockBreakEventCore @@ -153,26 +156,63 @@ public enum ItemLoreEnablers { - protected boolean ignoreMinesBlockBreakEvent( Cancellable event, Player player, Block block ) { + protected MinesEventResults ignoreMinesBlockBreakEvent( Cancellable event, Player player, Block block ) { MinesEventResults eventResults = ignoreMinesBlockBreakEvent( player, block ); if ( eventResults.isCancelEvent() ) { event.setCancelled( eventResults.isCancelEvent() ); } - return eventResults.isIgnoreEvent(); + +// return eventResults.isIgnoreEvent(); + return eventResults; } - protected boolean processMinesBlockBreakEvent( PEExplosionEvent event, Player player, Block block ) { + /** + *

Note that this function is required since ExplosiveEvent does not implement the + * interface Cancellable. + *

+ * + * @param event + * @param player + * @param block + * @return + */ + protected MinesEventResults ignoreMinesBlockBreakEvent( ExplosiveEvent event, Player player, Block block ) { MinesEventResults eventResults = ignoreMinesBlockBreakEvent( player, block ); if ( eventResults.isCancelEvent() ) { event.setCancelled( eventResults.isCancelEvent() ); } - return eventResults.isIgnoreEvent(); +// return eventResults.isIgnoreEvent(); + return eventResults; } + protected MinesEventResults ignoreMinesBlockBreakEvent( JackHammerEvent event, Player player, Block block ) { + + MinesEventResults eventResults = ignoreMinesBlockBreakEvent( player, block ); + + if ( eventResults.isCancelEvent() ) { + event.setCancelled( eventResults.isCancelEvent() ); + } +// return eventResults.isIgnoreEvent(); + return eventResults; + } + + protected MinesEventResults ignoreMinesBlockBreakEvent( PEExplosionEvent event, Player player, Block block ) { + + MinesEventResults eventResults = ignoreMinesBlockBreakEvent( player, block ); + + if ( eventResults.isCancelEvent() ) { + event.setCancelled( eventResults.isCancelEvent() ); + } +// return eventResults.isIgnoreEvent(); + return eventResults; + } + + + /** *

This processes the block finalizations, which are counting the block breakage, @@ -188,16 +228,26 @@ protected void doBlockEvents( PrisonMinesBlockBreakEvent pmEvent ) if ( pmEvent.getMine() != null ) { - // apply to ALL blocks including exploded: - applyBlockFinalizations( pmEvent, pmEvent.getTargetBlock() ); + // Count the blocks that were mined: + countBlocksMined( pmEvent, pmEvent.getTargetBlock() ); + + // process the prison blockEvents commands: + processPrisonBlockEventCommands( pmEvent, pmEvent.getTargetBlock() ); for ( MineTargetPrisonBlock teBlock : pmEvent.getTargetExplodedBlocks() ) { - applyBlockFinalizations( pmEvent, teBlock ); + // Count the blocks that were mined: + countBlocksMined( pmEvent, teBlock ); + + // process the prison blockEvents commands: + processPrisonBlockEventCommands( pmEvent, teBlock ); } checkZeroBlockReset( pmEvent.getMine() ); + + // Check Mine Sweeper: + checkMineSweeper( pmEvent.getMine() ); } } @@ -282,26 +332,41 @@ private List finalizeBreakTheBlocksCollectEm( PrisonMinesBlockBreak * @param debugInfo * @return */ - protected boolean validateEvent( PrisonMinesBlockBreakEvent pmEvent, StringBuilder debugInfo ) + protected boolean validateEvent( PrisonMinesBlockBreakEvent pmEvent ) { boolean results = true; + StringBuilder debugInfo = pmEvent.getDebugInfo(); SpigotBlock sBlockHit = pmEvent.getSpigotBlock(); - - Mine mine = findMine( pmEvent.getPlayer(), sBlockHit, - pmEvent.getUnprocessedRawBlocks(), pmEvent ); - - pmEvent.setMine( mine ); + + // Mine should already be set: + // Mine mine = findMine( pmEvent.getPlayer(), sBlockHit, +// pmEvent.getUnprocessedRawBlocks(), pmEvent ); +// +// pmEvent.setMine( mine ); + Mine mine = pmEvent.getMine(); debugInfo.append( "mine=" + (mine == null ? "none" : mine.getName()) + " " ); debugInfo.append( sBlockHit.getLocation().toWorldCoordinates() ).append( " " ); + + SpigotItemStack itemInHand = pmEvent.getItemInHand(); + debugInfo.append( "itemInHand=[" + + ( itemInHand == null ? "AIR" : itemInHand.getDebugInfo()) + "] "); + + // Since BlastUseEvent (crazy enchant) does not identify the block that is initially // broke, an explosion for them is greater than 1. + // Same applies to the RevEnchant events where they do not identify the original block + // that caused the "explosion". + boolean hasOriginalBLockIncluded = + pmEvent.getBlockEventType() == BlockEventType.CEXplosion || + pmEvent.getBlockEventType() == BlockEventType.RevEnExplosion || + pmEvent.getBlockEventType() == BlockEventType.RevEnJackHammer; boolean isExplosionEvent = pmEvent.getUnprocessedRawBlocks().size() > - (pmEvent.getBlockEventType() == BlockEventType.CEXplosion ? 0 : 1); + (hasOriginalBLockIncluded ? 0 : 1); // validate the blocks, if there are some. Add them to the exploded blocks list if ( mine != null ) { @@ -317,6 +382,7 @@ protected boolean validateEvent( PrisonMinesBlockBreakEvent pmEvent, StringBuild MineTargetPrisonBlock targetBlock = mine.getTargetPrisonBlock( sBlockHit ); pmEvent.setTargetBlock( targetBlock ); + // NOTE: I have no idea why 25 blocks and less should be bypassed for validation: boolean bypassMatchedBlocks = pmEvent.getMine().getBounds().getTotalBlockCount() <= 25; if ( bypassMatchedBlocks ) { debugInfo.append( "(TargetBlock match requirement is disabled [blocks<=25]) " ); @@ -324,13 +390,32 @@ protected boolean validateEvent( PrisonMinesBlockBreakEvent pmEvent, StringBuild boolean matchedBlocks = isBlockAMatch( targetBlock, sBlockHit ); + // If MONITOR or BLOCKEVENTS or etc... and block does not match, and if the block is AIR, + // and the block has not been mined before, then allow the breakage by + // setting bypassMatchedBlocks to true to allow normal processing: + if ( !matchedBlocks && + !targetBlock.isMined() && + sBlockHit.isAir() && + pmEvent.getBbPriority().isMonitor() ) { + bypassMatchedBlocks = true; + } + // If ignore all block events has been set on this target block, then shutdown. // Same if this block was already included in an explosion... prevent it from spawning // more explosions, which could result in a chain reaction. if ( targetBlock != null && (targetBlock.isIgnoreAllBlockEvents() || targetBlock.isExploded()) ) { - debugInfo.setLength( 0 ); + +// debugInfo.setLength( 0 ); + debugInfo.append( "(Primary TargetBlock forcedFastFail validateEvent [ "); + if ( targetBlock.isIgnoreAllBlockEvents() ) { + debugInfo.append( "ignoreAllBlockEvents " ); + } + if ( targetBlock.isExploded() ) { + debugInfo.append( "alreadyExploded" ); + } + debugInfo.append( "]) " ); pmEvent.setForceIfAirBlock( false ); @@ -619,7 +704,9 @@ else if ( targetExplodedBlock.isMined() ) { pmEvent.setCancelOriginalEvent( true ); // Ignore event and clear debugInfo: - debugInfo.setLength( 0 ); +// debugInfo.setLength( 0 ); + + debugInfo.append( "(TargetBlock forcedFastFail validateEvent [BlockAlreadyMined]) " ); return results; } @@ -664,87 +751,155 @@ else if ( targetExplodedBlock.isMined() ) { } - - if ( results && pmEvent.getBbPriority() == BlockBreakPriority.BLOCKEVENTS ) { - - - // This is true if the player cannot toggle the autosell, and it's - // true if they can, and the have it enabled: - boolean isPlayerAutosellEnabled = SellAllUtil.get() != null && - SellAllUtil.get().checkIfPlayerAutosellIsActive( - pmEvent.getSpigotPlayer().getWrapper() ) - ; +// // Process BLOCKEVENTS and ACCESSBLOCKEVENTs here... +// // Include autosell on full inventory if isAutoSellIfInventoryIsFullForBLOCKEVENTSPriority +// // is enabled. +// // Includes running block events, mine sweeper, and zero-block (reset-threshold) reset. +// if ( results && +// (pmEvent.getBbPriority() == BlockBreakPriority.BLOCKEVENTS || +// pmEvent.getBbPriority() == BlockBreakPriority.ACCESSBLOCKEVENTS ) ) { +// +// debugInfo.append( "(BLOCKEVENTS processing) " ); +// +// // This is true if the player cannot toggle the autosell, and it's +// // true if they can, and the have it enabled: +// boolean isPlayerAutosellEnabled = SellAllUtil.get() != null && +// SellAllUtil.get().checkIfPlayerAutosellIsActive( +// pmEvent.getSpigotPlayer().getWrapper() ) +// ; +// +// // AutoSell on full inventory when using BLOCKEVENTS: +// if ( isBoolean( AutoFeatures.isAutoSellIfInventoryIsFullForBLOCKEVENTSPriority ) && +// SpigotPrison.getInstance().isSellAllEnabled() && +// isPlayerAutosellEnabled && +// pmEvent.getSpigotPlayer().isInventoryFull() ) { +// +// +// final long nanoStart = System.nanoTime(); +// boolean success = SellAllUtil.get().sellAllSell( pmEvent.getPlayer(), +// false, false, false, true, true, false); +// final long nanoStop = System.nanoTime(); +// double milliTime = (nanoStop - nanoStart) / 1000000d; +// +// DecimalFormat dFmt = Prison.get().getDecimalFormat("#,##0.00"); +// debugInfo.append( "(autosell BLOCKEVENTS: " + (success ? "success" : "failed") + +// " ms: " + dFmt.format( milliTime ) + ") "); +// +// PlayerAutoRankupTask.autoSubmitPlayerRankupTask( pmEvent.getSpigotPlayer(), debugInfo ); +// +// } +// +// +// // Process block counts and then block events: +// countBlocksMined( pmEvent, sBlockHit ); +// processPrisonBlockEventCommands( pmEvent, sBlockHit ); +// +// debugInfo.append( "(primary block: block counts and block events) " ); +// +// if ( pmEvent.getExplodedBlocks().size() > 0 ) { +// +// for ( SpigotBlock sBlock : pmEvent.getExplodedBlocks() ) { +// +// countBlocksMined( pmEvent, sBlock ); +// processPrisonBlockEventCommands( pmEvent, sBlock ); +// } +// +// debugInfo.append( "(" + +// pmEvent.getExplodedBlocks().size() + +// " Exploded Blocks: block counts and block events) " ); +// } +// +// // Check Mine Sweeper: +// checkMineSweeper( pmEvent.getMine() ); +// +// // Check zero-block reset (reset-threshold): +// checkZeroBlockReset( pmEvent.getMine() ); +// +// // why return false? +//// results = false; +// } + else if ( results && pmEvent.getBbPriority().isMonitor() && mine == null ) { + // bypass all processing since the block break is outside any mine: - // AutoSell on full inventory when using BLOCKEVENTS: - if ( isBoolean( AutoFeatures.isAutoSellIfInventoryIsFullForBLOCKEVENTSPriority ) && - SpigotPrison.getInstance().isSellAllEnabled() && - isPlayerAutosellEnabled && - pmEvent.getSpigotPlayer().isInventoryFull() ) { - - - final long nanoStart = System.nanoTime(); - boolean success = SellAllUtil.get().sellAllSell( pmEvent.getPlayer(), - false, false, false, true, true, false); - final long nanoStop = System.nanoTime(); - double milliTime = (nanoStop - nanoStart) / 1000000d; - - DecimalFormat dFmt = new DecimalFormat("#,##0.00"); - debugInfo.append( "(autosellBLOCKEVENTS: " + (success ? "success" : "failed") + - " ms: " + dFmt.format( milliTime ) + ") "); - - } + debugInfo.append( "(MONITOR bypassed: no mine) " ); + results = false; + } + + // Performs the MONITOR block counts, zero-block, and mine sweeper: + else if ( results && pmEvent.getBbPriority().isMonitor() && mine != null ) { - String triggered = null; - doActionBlockEventOnly( sBlockHit, mine, pmEvent.getPlayer(), - BlockEventType.blockBreak, triggered ); + // Process BLOCKEVENTS and ACCESSBLOCKEVENTs here... + // Include autosell on full inventory if isAutoSellIfInventoryIsFullForBLOCKEVENTSPriority + // is enabled. + // Includes running block events, mine sweeper, and zero-block (reset-threshold) reset. + if ( pmEvent.getBbPriority() == BlockBreakPriority.BLOCKEVENTS || + pmEvent.getBbPriority() == BlockBreakPriority.ACCESSBLOCKEVENTS ) { - debugInfo.append( "(actionBlockEventOnly singluar) " ); - - if ( pmEvent.getExplodedBlocks().size() > 0 ) { + debugInfo.append( "(BLOCKEVENTS processing) " ); - for ( SpigotBlock sBlock : pmEvent.getExplodedBlocks() ) { + // This is true if the player cannot toggle the autosell, and it's + // true if they can, and the have it enabled: + boolean isPlayerAutosellEnabled = SellAllUtil.get() != null && + SellAllUtil.get().checkIfPlayerAutosellIsActive( + pmEvent.getSpigotPlayer().getWrapper() ) + ; + + // AutoSell on full inventory when using BLOCKEVENTS: + if ( isBoolean( AutoFeatures.isAutoSellIfInventoryIsFullForBLOCKEVENTSPriority ) && + SpigotPrison.getInstance().isSellAllEnabled() && + isPlayerAutosellEnabled && + pmEvent.getSpigotPlayer().isInventoryFull() ) { + + + final long nanoStart = System.nanoTime(); + boolean success = SellAllUtil.get().sellAllSell( pmEvent.getPlayer(), + false, false, false, true, true, false); + final long nanoStop = System.nanoTime(); + double milliTime = (nanoStop - nanoStart) / 1000000d; + + DecimalFormat dFmt = Prison.get().getDecimalFormat("#,##0.00"); + debugInfo.append( "(autosell BLOCKEVENTS: " + (success ? "success" : "failed") + + " ms: " + dFmt.format( milliTime ) + ") "); + + PlayerAutoRankupTask.autoSubmitPlayerRankupTask( pmEvent.getSpigotPlayer(), debugInfo ); - doActionBlockEventOnly( sBlock, mine, pmEvent.getPlayer(), - pmEvent.getBlockEventType(), pmEvent.getTriggered() ); } - - debugInfo.append( "(actionBlockEventOnly - " + - pmEvent.getExplodedBlocks().size() + - " Exploded Blocks - finalized) " ); } - results = false; - } - else if ( results && pmEvent.getBbPriority() == BlockBreakPriority.MONITOR && mine == null ) { - // bypass all processing since the block break is outside any mine: - - debugInfo.append( "(bypassed monitor no mine) " ); - results = false; - } - else if ( results && pmEvent.getBbPriority() == BlockBreakPriority.MONITOR && mine != null ) { - - doActionMonitor( sBlockHit, mine ); + countBlocksMined( pmEvent, sBlockHit ); + processPrisonBlockEventCommands( pmEvent, sBlockHit ); - debugInfo.append( "(monitor - singular) " ); + debugInfo.append( "(MONITOR - singular) " ); if ( pmEvent.getExplodedBlocks().size() > 0 ) { for ( SpigotBlock sBlock : pmEvent.getExplodedBlocks() ) { - doActionMonitor( sBlock, mine ); + countBlocksMined( pmEvent, sBlock ); + processPrisonBlockEventCommands( pmEvent, sBlock ); } - debugInfo.append( "(monitor - " + + debugInfo.append( "(MONITOR - " + pmEvent.getExplodedBlocks().size() + " Exploded Blocks - finalized) " ); } - // should be true at this point: + + // submit a mine sweeper task. It will only run if it is enabled and another + // mine sweeper task has not been submitted. + mine.submitMineSweeperTask(); + + // Checks to see if the mine ran out of blocks, and if it did, then + // it will reset the mine: + mine.checkZeroBlockReset(); + + // should be true at this point: (already is true): //results = true; } + if ( results && isBoolean( AutoFeatures.cancelAllBlockEventBlockDrops ) ) { clearBukkitDrops( pmEvent.getBukkitDrops(), pmEvent.getTargetBlock() ); @@ -861,58 +1016,100 @@ else if ( results && pmEvent.getBbPriority() == BlockBreakPriority.MONITOR && mi + + - public void doActionMonitor( SpigotBlock block, Mine mine ) { - if ( mine != null ) { + + /** + *

Performs block counts. + *

+ * + * @param block + * @param mine + */ + private void countBlocksMined( PrisonMinesBlockBreakEvent pmEvent, SpigotBlock block ) { + + if ( pmEvent.getMine() != null && block != null ) { + + Mine mine = pmEvent.getMine(); // Good chance the block was already counted, but just in case it wasn't: MineTargetPrisonBlock targetBlock = mine.getTargetPrisonBlock( block ); - // Record the block break: + // Record the block break counts: + countBlocksMined( pmEvent, targetBlock ); + + } + } + + private boolean countBlocksMined( PrisonMinesBlockBreakEvent pmEvent, + MineTargetPrisonBlock targetBlock ) { + boolean results = false; + + if ( targetBlock != null && + pmEvent.getMine() != null && + targetBlock.getPrisonBlock() != null && + !targetBlock.isCounted() ) { + + Mine mine = pmEvent.getMine(); + + + // Increment the block break counts if they have not been processed before. + // Since the function return true if it can count the block, then we can + // then have the player counts be incremented. if ( mine.incrementBlockMiningCount( targetBlock ) ) { + results = true; - // submit a mine sweeper task. It will only run if it is enabled and another - // mine sweeper task has not been submitted. - mine.submitMineSweeperTask(); + // Now in AutoManagerFeatures.autoPickup and calculateNormalDrop: + PlayerCache.getInstance().addPlayerBlocks( pmEvent.getSpigotPlayer(), + mine.getName(), targetBlock.getPrisonBlock(), 1 ); - // Checks to see if the mine ran out of blocks, and if it did, then - // it will reset the mine: - mine.checkZeroBlockReset(); } - } + return results; } - public void doActionBlockEventOnly( SpigotBlock spigotBlock, Mine mine, Player player, - BlockEventType blockEventType, String triggered ) { - if ( mine != null && spigotBlock != null ) { + + private void processPrisonBlockEventCommands( + PrisonMinesBlockBreakEvent pmEvent, SpigotBlock spigotBlock ) { + + if ( pmEvent.getMine() != null && spigotBlock != null ) { + Mine mine = pmEvent.getMine(); + MineTargetPrisonBlock targetBlock = mine.getTargetPrisonBlock( spigotBlock ); - if ( targetBlock != null && targetBlock.getPrisonBlock() != null && !targetBlock.isCounted() ) { - + if ( targetBlock != null ) { -// String targetBlockName = mine == null ? -// spigotBlock.getPrisonBlock().getBlockName() -// : targetBlock.getPrisonBlock().getBlockName(); - - // Process mine block break events: - - if ( mine.incrementBlockMiningCount( targetBlock ) ) { - - SpigotPlayer sPlayer = new SpigotPlayer( player ); - PlayerCache.getInstance().addPlayerBlocks( sPlayer, mine.getName(), targetBlock.getPrisonBlock(), 1 ); - - - PrisonBlock prisonBlock = spigotBlock.getPrisonBlock(); - mine.processBlockBreakEventCommands( prisonBlock, targetBlock, sPlayer, blockEventType, triggered ); - } - + processPrisonBlockEventCommands( pmEvent, targetBlock ); } } } + private void processPrisonBlockEventCommands( PrisonMinesBlockBreakEvent pmEvent, + MineTargetPrisonBlock targetBlock ) { + + // Do not allow MONITOR or ACCESSMONITOR to process the block events: + if ( targetBlock != null && pmEvent.getMine() != null && + pmEvent.getBbPriority() != BlockBreakPriority.MONITOR && + pmEvent.getBbPriority() != BlockBreakPriority.ACCESSMONITOR ) { + + Mine mine = pmEvent.getMine(); + + SpigotBlock sBlock = (SpigotBlock) targetBlock.getMinedBlock(); + PrisonBlock pBlock = sBlock == null ? null : sBlock.getPrisonBlock(); + + mine.processBlockBreakEventCommands( pBlock, + targetBlock, + pmEvent.getSpigotPlayer(), + pmEvent.getBlockEventType(), + pmEvent.getTriggered() ); + + } + + } + // public boolean doActionX( PrisonMinesBlockBreakEvent pmEvent, StringBuilder debugInfo ) { // boolean cancel = false; @@ -966,28 +1163,30 @@ public void doActionBlockEventOnly( SpigotBlock spigotBlock, Mine mine, Player p * @param e * @param teExplosiveBlocks */ - public boolean doAction( PrisonMinesBlockBreakEvent pmEvent, StringBuilder debugInfo ) { + public boolean doAction( PrisonMinesBlockBreakEvent pmEvent ) { AutoManagerFeatures aMan = SpigotPrison.getInstance().getAutoFeatures(); - int totalDrops = aMan.calculateNormalDrop( pmEvent, debugInfo ); + int totalDrops = aMan.calculateNormalDrop( pmEvent ); - debugInfo.append( "(normalDrops totalDrops: " + totalDrops + ") "); + pmEvent.getDebugInfo().append( "(normalDrops totalDrops: " + totalDrops + ") "); - return applyDropsBlockBreakage( pmEvent, totalDrops, debugInfo ); + return applyDropsBlockBreakage( pmEvent, totalDrops ); } - public boolean applyDropsBlockBreakage( PrisonMinesBlockBreakEvent pmEvent, int totalDrops, StringBuilder debugInfo ) { + public boolean applyDropsBlockBreakage( PrisonMinesBlockBreakEvent pmEvent, int totalDrops ) { boolean success = false; // The explodedBlocks list have already been validated as being within the mine: - debugInfo.append( "(applyDropsBlockBreakage multi-blocks: " + pmEvent.getTargetExplodedBlocks().size() + ") "); + pmEvent.getDebugInfo().append( "(applyDropsBlockBreakage multi-blocks: " + pmEvent.getTargetExplodedBlocks().size() + ") "); // Process the blockBreakage which actually breaks the block, calculates and gives the player xp, // calculates the durability, applies food exhaustion: - processBlockBreakage( pmEvent, debugInfo ); + processBlockBreakage( pmEvent ); + +// forcedAutoRankups( pmEvent, debugInfo ); // autosellPerBlockBreak( pmEvent.getPlayer() ); @@ -998,12 +1197,21 @@ public boolean applyDropsBlockBreakage( PrisonMinesBlockBreakEvent pmEvent, int if ( totalDrops > 0 ) { success = true; } + else { + pmEvent.getDebugInfo().append( "(fail:totalDrops=0) "); + } return success; } +// private void forcedAutoRankups(PrisonMinesBlockBreakEvent pmEvent, StringBuilder debugInfo) { +// +// PlayerAutoRankupTask.autoSubmitPlayerRankupTask( pmEvent.getSpigotPlayer(), debugInfo ); +// +// } + // /** // *

This function is processed when auto manager is disabled and process crazy enchant explosions // * is enabled. This function is overridden in AutoManager when auto manager is enabled. @@ -1086,7 +1294,7 @@ public boolean applyDropsBlockBreakage( PrisonMinesBlockBreakEvent pmEvent, int - public void processBlockBreakage( PrisonMinesBlockBreakEvent pmEvent, StringBuilder debugInfo ) + private void processBlockBreakage( PrisonMinesBlockBreakEvent pmEvent ) { // If this block is not in the mine (if null) and it has not been broke before @@ -1097,8 +1305,8 @@ public void processBlockBreakage( PrisonMinesBlockBreakEvent pmEvent, StringBuil // Calculate XP for all blocks if enabled: - int totalXp = xpCalculateXP( pmEvent, debugInfo ); - xpGivePlayerXp( pmEvent.getSpigotPlayer(), totalXp, debugInfo ); + int totalXp = xpCalculateXP( pmEvent ); + xpGivePlayerXp( pmEvent.getSpigotPlayer(), totalXp, pmEvent.getDebugInfo() ); int blocksMined = (pmEvent.getTargetBlock() == null ? 0 : 1 ) + pmEvent.getTargetExplodedBlocks().size(); @@ -1119,7 +1327,9 @@ public void processBlockBreakage( PrisonMinesBlockBreakEvent pmEvent, StringBuil } calculateAndApplyDurability( pmEvent.getPlayer(), pmEvent.getItemInHand(), - blocksMined, durabilityResistance, debugInfo ); + blocksMined, + durabilityResistance, + pmEvent.getDebugInfo() ); } @@ -1201,35 +1411,44 @@ public void processBlockBreakage( PrisonMinesBlockBreakEvent pmEvent, StringBuil // mine.checkZeroBlockReset(); // } // } - - private void applyBlockFinalizations( PrisonMinesBlockBreakEvent pmEvent, MineTargetPrisonBlock targetBlock ) { - - if ( targetBlock != null ) { - - Mine mine = pmEvent.getMine(); - - // Increment the block break counts if they have not been processed before. - // Since the function return true if it can count the block, then we can - // then have the player counts be incremented. - if ( mine.incrementBlockMiningCount( targetBlock ) ) { - - // Now in AutoManagerFeatures.autoPickup and calculateNormalDrop: +// +// private void applyBlockFinalizations( PrisonMinesBlockBreakEvent pmEvent, +// MineTargetPrisonBlock targetBlock ) { +// +// if ( targetBlock != null ) { +// +// Mine mine = pmEvent.getMine(); +// +// // Increment the block break counts if they have not been processed before. +// // Since the function return true if it can count the block, then we can +// // then have the player counts be incremented. +// if ( mine.incrementBlockMiningCount( targetBlock ) ) { +// +// // Now in AutoManagerFeatures.autoPickup and calculateNormalDrop: // PlayerCache.getInstance().addPlayerBlocks( pmEvent.getSpigotPlayer(), // mine.getName(), targetBlock.getPrisonBlock(), 1 ); - - } - - - SpigotBlock sBlock = (SpigotBlock) targetBlock.getMinedBlock(); - PrisonBlock pBlock = sBlock == null ? null : sBlock.getPrisonBlock(); - - mine.processBlockBreakEventCommands( pBlock, - targetBlock, pmEvent.getSpigotPlayer(), pmEvent.getBlockEventType(), pmEvent.getTriggered() ); - - } - } - - protected int xpCalculateXP( PrisonMinesBlockBreakEvent pmEvent, StringBuilder debugInfo ) { +// +// } +// +// // Do not allow MONITOR or ACCESSMONITOR to process the block events: +// if ( pmEvent.getBbPriority() != BlockBreakPriority.MONITOR && +// pmEvent.getBbPriority() != BlockBreakPriority.ACCESSMONITOR ) { +// +// SpigotBlock sBlock = (SpigotBlock) targetBlock.getMinedBlock(); +// PrisonBlock pBlock = sBlock == null ? null : sBlock.getPrisonBlock(); +// +// mine.processBlockBreakEventCommands( pBlock, +// targetBlock, pmEvent.getSpigotPlayer(), pmEvent.getBlockEventType(), pmEvent.getTriggered() ); +// +// } +// +// } +// +// //TODO What about zero-block reset and mine sweeper? +// +// } +// + protected int xpCalculateXP( PrisonMinesBlockBreakEvent pmEvent ) { int xp = 0; if (isBoolean(AutoFeatures.isCalculateXPEnabled) ) { @@ -1262,7 +1481,7 @@ protected int xpCalculateXP( PrisonMinesBlockBreakEvent pmEvent, StringBuilder d String message = String.format( "(XP calcs: blocks: %d xp: %d bonusXp: %d) ", totalBlocks, totalXp, totalBonusXp ); - debugInfo.append( message ); + pmEvent.getDebugInfo().append( message ); } } @@ -1284,7 +1503,8 @@ private int xpCalculateBlockXP( MineTargetPrisonBlock targetBlock, SpigotPlayer } return xp; } - private int xpCalculateBonusXP( MineTargetPrisonBlock targetBlock, SpigotPlayer player, ItemStack itemInHand ) + private int xpCalculateBonusXP( MineTargetPrisonBlock targetBlock, SpigotPlayer player, + ItemStack itemInHand ) { int xp = 0; diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/block/OnBlockBreakEventListener.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/block/OnBlockBreakEventListener.java index 080a3e22a..6fa167d13 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/block/OnBlockBreakEventListener.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/block/OnBlockBreakEventListener.java @@ -17,6 +17,8 @@ import tech.mcprison.prison.spigot.autofeatures.events.AutoManagerCrazyEnchants; import tech.mcprison.prison.spigot.autofeatures.events.AutoManagerPrisonEnchants; import tech.mcprison.prison.spigot.autofeatures.events.AutoManagerPrisonsExplosiveBlockBreakEvents; +import tech.mcprison.prison.spigot.autofeatures.events.AutoManagerRevEnchantsExplosiveEvent; +import tech.mcprison.prison.spigot.autofeatures.events.AutoManagerRevEnchantsJackHammerEvent; import tech.mcprison.prison.spigot.autofeatures.events.AutoManagerTokenEnchant; import tech.mcprison.prison.spigot.autofeatures.events.AutoManagerZenchantments; import tech.mcprison.prison.spigot.autofeatures.events.PrisonDebugBlockInspector; @@ -108,6 +110,10 @@ public class OnBlockBreakEventListener private AutoManagerPrisonEnchants peEvents; private AutoManagerTokenEnchant teEvents; private AutoManagerZenchantments zcEvents; + + private AutoManagerRevEnchantsExplosiveEvent reEEvents; + private AutoManagerRevEnchantsJackHammerEvent reJHEvents; + private PrisonDebugBlockInspector pdBlockInspector; @@ -222,6 +228,12 @@ private void registerEvents() { zcEvents = new AutoManagerZenchantments(); zcEvents.registerEvents(); + reEEvents = new AutoManagerRevEnchantsExplosiveEvent(); + reEEvents.registerEvents(); + + reJHEvents = new AutoManagerRevEnchantsJackHammerEvent(); + reJHEvents.registerEvents(); + pdBlockInspector = new PrisonDebugBlockInspector(); pdBlockInspector.init(); } diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/block/OnBlockBreakMines.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/block/OnBlockBreakMines.java index 83bfa5cbc..059dac480 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/block/OnBlockBreakMines.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/block/OnBlockBreakMines.java @@ -41,11 +41,20 @@ public OnBlockBreakMines() { public class MinesEventResults { private boolean cancelEvent = false; private boolean ignoreEvent = false; + private Mine mine = null; public MinesEventResults() { super(); } + + public Mine getMine() { + return mine; + } + public void setMine(Mine mine) { + this.mine = mine; + } + public boolean isCancelEvent() { return cancelEvent; } @@ -141,7 +150,21 @@ public Mine findMine( UUID playerUUID, SpigotBlock sBlock, List altBlocks // } + /** + *

If the event is canceled, it still needs to be processed because of the MONITOR events: + * An event will be "canceled" and "ignored" if the block + * BlockUtils.isUnbreakable(), or if the mine is activly resetting. + * The event will also be ignored if the block is outside of a mine + * or if the targetBlock has been set to ignore all block events which + * means the block has already been processed. + *

+ * + * @param player + * @param block + * @return + */ protected MinesEventResults ignoreMinesBlockBreakEvent( Player player, Block block ) { + MinesEventResults results = new MinesEventResults(); SpigotBlock sBlock = SpigotBlock.getSpigotBlock( block ); @@ -151,6 +174,7 @@ protected MinesEventResults ignoreMinesBlockBreakEvent( Player player, Block blo } Mine mine = findMine( player, sBlock, null, null ); + results.setMine( mine ); if ( mine == null ) { // Prison is unable to process blocks outside of mines right now, so exit: @@ -166,20 +190,25 @@ protected MinesEventResults ignoreMinesBlockBreakEvent( Player player, Block blo results.setCancelEvent( true ); results.setIgnoreEvent( true ); } - MineTargetPrisonBlock targetBlock = mine.getTargetPrisonBlock( sBlock ); - - // If ignore all block events, then exit this function without logging anything: - if ( targetBlock != null && targetBlock.isIgnoreAllBlockEvents() ) { + else { - // Do not cancel the event... let other plugins deal with it... prison does not care about this block. - //event.setCancelled( true ); - results.setIgnoreEvent( true ); + MineTargetPrisonBlock targetBlock = mine.getTargetPrisonBlock( sBlock ); + + // If ignore all block events, then exit this function without logging anything: + if ( targetBlock != null && targetBlock.isIgnoreAllBlockEvents() ) { + + // Do not cancel the event... let other plugins deal with it... prison does not care about this block. + //event.setCancelled( true ); + results.setIgnoreEvent( true ); + } } + } return results; } + // /** // *

Warning... this is a temp copy of the real function and will be removed // * if PEExplosionEvent adds the interface Cancellable. @@ -226,13 +255,15 @@ protected MinesEventResults ignoreMinesBlockBreakEvent( Player player, Block blo // return processEvent; // } + /** + *

If mine is not null, then it will check for a zero-block reset (reset-threshold). + *

+ * + * @param mine + */ public void checkZeroBlockReset( Mine mine ) { if ( mine != null ) { - // submit a mine sweeper task. It will only run if it is enabled and another - // mine sweeper task has not been submitted. - mine.submitMineSweeperTask(); - // Checks to see if the mine ran out of blocks, and if it did, then // it will reset the mine: mine.checkZeroBlockReset(); @@ -240,6 +271,24 @@ public void checkZeroBlockReset( Mine mine ) { } + /** + *

If mine is not null, then it will perform a mine sweeper + * for the mine, if it is enabled. + *

+ * + * @param mine + */ + public void checkMineSweeper( Mine mine ) { + if ( mine != null ) { + + // submit a mine sweeper task. It will only run if it is enabled and another + // mine sweeper task has not been submitted. + mine.submitMineSweeperTask(); + } + } + + + /** *

Checks only if the names match. Does not check locations within any worlds. *

@@ -310,7 +359,8 @@ public boolean collectBukkitDrops( List bukkitDrops, MineTarget { boolean results = false; - if ( targetBlock != null && targetBlock.getPrisonBlock().getBlockType() == PrisonBlockType.CustomItems ) { + if ( targetBlock != null && + targetBlock.getPrisonBlock().getBlockType().isCustomBlockType() ) { List cbIntegrations = PrisonAPI.getIntegrationManager().getCustomBlockIntegrations(); diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/block/SpigotBlock.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/block/SpigotBlock.java index 8422f5e28..0ace4bf8c 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/block/SpigotBlock.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/block/SpigotBlock.java @@ -189,6 +189,7 @@ public PrisonBlock getPrisonBlock() { // return results; } + @SuppressWarnings("unused") private PrisonBlock getPrisonBlockFromCustomBlockIntegration( PrisonBlockType blockType ) { PrisonBlock results = null; @@ -198,6 +199,7 @@ private PrisonBlock getPrisonBlockFromCustomBlockIntegration( PrisonBlockType bl // No special processing for minecraft types since that will be the fallback later on: case CustomItems: + case ItemsAdder: { CustomBlockIntegration customItemsIntegration = PrisonAPI.getIntegrationManager().getCustomBlockIntegration( blockType ); @@ -210,6 +212,19 @@ private PrisonBlock getPrisonBlockFromCustomBlockIntegration( PrisonBlockType bl break; +// case ItemsAdder: +// { +// CustomBlockIntegration customItemsIntegration = +// PrisonAPI.getIntegrationManager().getCustomBlockIntegration( blockType ); +// // NOTE: This would be the situation where the admin added the Custom Items plugin, added blocks +// // then removed the plugin. So if it's null, ignore it. +// if ( customItemsIntegration != null ) { +// results = customItemsIntegration.getCustomBlock( this ); +// } +// } +// +// break; + default: break; } @@ -246,6 +261,7 @@ public void setPrisonBlock( PrisonBlock prisonBlock ) { break; case CustomItems: + case ItemsAdder: { CustomBlockIntegration customItemsIntegration = PrisonAPI.getIntegrationManager().getCustomBlockIntegration( prisonBlock.getBlockType() ); diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/block/SpigotBlockSetAsynchronously.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/block/SpigotBlockSetAsynchronously.java index 84bf8fff8..f7a3ddae4 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/block/SpigotBlockSetAsynchronously.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/block/SpigotBlockSetAsynchronously.java @@ -28,6 +28,7 @@ public void setBlockAsync( PrisonBlock prisonBlock, Location location ) { break; case CustomItems: + case ItemsAdder: { CustomBlockIntegration customItemsIntegration = PrisonAPI.getIntegrationManager().getCustomBlockIntegration( prisonBlock.getBlockType() ); diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/block/SpigotItemStack.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/block/SpigotItemStack.java index 3f7ca702b..9c8b13e23 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/block/SpigotItemStack.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/block/SpigotItemStack.java @@ -4,9 +4,11 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; import org.bukkit.Bukkit; import org.bukkit.Material; +import org.bukkit.enchantments.Enchantment; import org.bukkit.inventory.meta.ItemMeta; import com.cryptomorin.xseries.XMaterial; @@ -17,6 +19,7 @@ import tech.mcprison.prison.internal.block.PrisonBlock; import tech.mcprison.prison.output.Output; import tech.mcprison.prison.spigot.SpigotUtil; +import tech.mcprison.prison.spigot.compat.SpigotCompatibility; import tech.mcprison.prison.util.Text; public class SpigotItemStack @@ -428,4 +431,70 @@ public Map serialize() return results; } + + /** + *

This function will return information on the item in the item stack, which is for + * debugging purposes, such as displayed within the autoFeatures debug info. + *

+ * + * @return + */ + public String getDebugInfo() { + StringBuilder sb = new StringBuilder(); + + sb.append( getName() ); + + ItemMeta meta = getMeta(); + if ( meta != null && + meta.getEnchants() != null && + meta.getEnchants().size() > 0 ) { + sb.append( " " ); + + StringBuilder sbE = new StringBuilder(); + Set keys = meta.getEnchants().keySet(); + for (Enchantment key : keys) { + if ( sbE.length() > 0 ) { + sbE.append(","); + } + String name = key.toString(); + name = name.substring(name.indexOf(" ") + 1, name.length() - 1); + + Integer level = meta.getEnchants().get(key); + sbE.append( name ); + sbE.append(":"); + sbE.append( level ); + } + + if ( sbE.length() > 0 ) { + sb.append("("); + sb.append( sbE ); + sb.append(")"); + } + } + + if ( SpigotCompatibility.getInstance().hasDurability( this ) ) { + int durabilityMax = SpigotCompatibility.getInstance().getDurabilityMax( this ); + int durability = SpigotCompatibility.getInstance().getDurability( this ); + + sb.append(" durability:"); + sb.append(durabilityMax); + sb.append(":"); + sb.append(durability); + } + + if ( getAmount() != 1 ) { + sb.append( " amount=" ); + sb.append( getAmount() ); + } + + sb.append( " " ); + if ( isAir() ) { + sb.append( "::AIR" ); + } + else if ( isBlock() ) { + sb.append( "::BLOCK" ); + } + + return sb.toString(); + } } diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/bstats/PrisonBStats.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/bstats/PrisonBStats.java index b92915184..c4fc01adb 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/bstats/PrisonBStats.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/bstats/PrisonBStats.java @@ -41,6 +41,7 @@ public class PrisonBStats { // private List reportVault; private List reportEnchantments; private List reportAdminTools; + private List reportConflicts; private TreeSet pluginsUsed; @@ -60,6 +61,7 @@ public PrisonBStats( SpigotPrison spigotPrison ) { // this.reportVault = new ArrayList<>(); this.reportEnchantments = new ArrayList<>(); this.reportAdminTools = new ArrayList<>(); + this.reportConflicts = new ArrayList<>(); this.pluginsUsed = new TreeSet<>(); @@ -182,14 +184,18 @@ public void initMetricsOnEnable() { }) ); getbStatsMetrics().addCustomChart( new SimplePie( "prison_total_active_player_counts", () -> { - - int playerCountActive = TopNPlayers.getInstance().getTopNSize(); + + int playerCountActive = PrisonRanks.getInstance().getPlayerManager() == null ? + -1 : + TopNPlayers.getInstance().getTopNSize(); return Integer.toString( playerCountActive ); }) ); getbStatsMetrics().addCustomChart( new SimplePie( "prison_total_archived_player_counts", () -> { - int playerCountArchived = TopNPlayers.getInstance().getArchivedSize(); + int playerCountArchived = PrisonRanks.getInstance().getPlayerManager() == null ? + -1 : + TopNPlayers.getInstance().getArchivedSize(); return Integer.toString( playerCountArchived ); }) ); @@ -322,15 +328,16 @@ public void initMetricsOnEnable() { createNewBstatReport( "enchantment_plugins", reportEnchantments, plugins, pluginsUsed ); createNewBstatReport( "admin_tools_plugins", reportAdminTools, plugins, pluginsUsed ); + createNewBstatReport( "potential_conflicts_plugins", reportConflicts, plugins, pluginsUsed ); //this.reportVault = new ArrayList<>(); "prison_integrated_vault_plugins" - TreeMap pluginsAtoE = getSubsetOfPlugins(plugins, 'a', 'f', false, pluginsUsed ); - TreeMap pluginsFtoM = getSubsetOfPlugins(plugins, 'f', 'n', false, pluginsUsed ); - TreeMap pluginsNtoS = getSubsetOfPlugins(plugins, 'n', 't', false, pluginsUsed ); - TreeMap pluginsTto9 = getSubsetOfPlugins(plugins, 't', 'z', true, pluginsUsed ); +// TreeMap pluginsAtoE = getSubsetOfPlugins(plugins, 'a', 'f', false, pluginsUsed ); +// TreeMap pluginsFtoM = getSubsetOfPlugins(plugins, 'f', 'n', false, pluginsUsed ); +// TreeMap pluginsNtoS = getSubsetOfPlugins(plugins, 'n', 't', false, pluginsUsed ); +// TreeMap pluginsTto9 = getSubsetOfPlugins(plugins, 't', 'z', true, pluginsUsed ); // Remove "plugins" - Too much info on one report // DrilldownPie mlcPrisonPlugins = new DrilldownPie("plugins", () -> { @@ -379,72 +386,72 @@ public void initMetricsOnEnable() { getbStatsMetrics().addCustomChart( mlcPrisonVaultPlugins ); - DrilldownPie mlcPrisonPluginsAtoE = new DrilldownPie("plugins_a_to_e", () -> { - Map> map = new HashMap<>(); - - for (String pluginName : pluginsAtoE.keySet() ) { - RegisteredPluginsData pluginData = pluginsAtoE.get( pluginName ); - - Map entry = new HashMap<>(); - entry.put( pluginData.getPluginVersion(), 1 ); - - map.put( pluginData.getPluginName(), entry ); - } - - return map; - }); - getbStatsMetrics().addCustomChart( mlcPrisonPluginsAtoE ); +// DrilldownPie mlcPrisonPluginsAtoE = new DrilldownPie("plugins_a_to_e", () -> { +// Map> map = new HashMap<>(); +// +// for (String pluginName : pluginsAtoE.keySet() ) { +// RegisteredPluginsData pluginData = pluginsAtoE.get( pluginName ); +// +// Map entry = new HashMap<>(); +// entry.put( pluginData.getPluginVersion(), 1 ); +// +// map.put( pluginData.getPluginName(), entry ); +// } +// +// return map; +// }); +// getbStatsMetrics().addCustomChart( mlcPrisonPluginsAtoE ); - DrilldownPie mlcPrisonPluginsFtoM = new DrilldownPie("plugins_f_to_m", () -> { - Map> map = new HashMap<>(); - - for (String pluginName : pluginsFtoM.keySet() ) { - RegisteredPluginsData pluginData = pluginsFtoM.get( pluginName ); - - Map entry = new HashMap<>(); - entry.put( pluginData.getPluginVersion(), 1 ); - - map.put( pluginData.getPluginName(), entry ); - } - - return map; - }); - getbStatsMetrics().addCustomChart( mlcPrisonPluginsFtoM ); +// DrilldownPie mlcPrisonPluginsFtoM = new DrilldownPie("plugins_f_to_m", () -> { +// Map> map = new HashMap<>(); +// +// for (String pluginName : pluginsFtoM.keySet() ) { +// RegisteredPluginsData pluginData = pluginsFtoM.get( pluginName ); +// +// Map entry = new HashMap<>(); +// entry.put( pluginData.getPluginVersion(), 1 ); +// +// map.put( pluginData.getPluginName(), entry ); +// } +// +// return map; +// }); +// getbStatsMetrics().addCustomChart( mlcPrisonPluginsFtoM ); - DrilldownPie mlcPrisonPluginsNtoS = new DrilldownPie("plugins_n_to_s", () -> { - Map> map = new HashMap<>(); - - for (String pluginName : pluginsNtoS.keySet() ) { - RegisteredPluginsData pluginData = pluginsNtoS.get( pluginName ); - - Map entry = new HashMap<>(); - entry.put( pluginData.getPluginVersion(), 1 ); - - map.put( pluginData.getPluginName(), entry ); - } - - return map; - }); - getbStatsMetrics().addCustomChart( mlcPrisonPluginsNtoS ); +// DrilldownPie mlcPrisonPluginsNtoS = new DrilldownPie("plugins_n_to_s", () -> { +// Map> map = new HashMap<>(); +// +// for (String pluginName : pluginsNtoS.keySet() ) { +// RegisteredPluginsData pluginData = pluginsNtoS.get( pluginName ); +// +// Map entry = new HashMap<>(); +// entry.put( pluginData.getPluginVersion(), 1 ); +// +// map.put( pluginData.getPluginName(), entry ); +// } +// +// return map; +// }); +// getbStatsMetrics().addCustomChart( mlcPrisonPluginsNtoS ); - DrilldownPie mlcPrisonPluginsTto9 = new DrilldownPie("plugins_t_to_z_plus_others", () -> { - Map> map = new HashMap<>(); - - for (String pluginName : pluginsTto9.keySet() ) { - RegisteredPluginsData pluginData = pluginsTto9.get( pluginName ); - - Map entry = new HashMap<>(); - entry.put( pluginData.getPluginVersion(), 1 ); - - map.put( pluginData.getPluginName(), entry ); - } - - return map; - }); - getbStatsMetrics().addCustomChart( mlcPrisonPluginsTto9 ); +// DrilldownPie mlcPrisonPluginsTto9 = new DrilldownPie("plugins_t_to_z_plus_others", () -> { +// Map> map = new HashMap<>(); +// +// for (String pluginName : pluginsTto9.keySet() ) { +// RegisteredPluginsData pluginData = pluginsTto9.get( pluginName ); +// +// Map entry = new HashMap<>(); +// entry.put( pluginData.getPluginVersion(), 1 ); +// +// map.put( pluginData.getPluginName(), entry ); +// } +// +// return map; +// }); +// getbStatsMetrics().addCustomChart( mlcPrisonPluginsTto9 ); @@ -471,58 +478,58 @@ public void initMetricsOnEnable() { } - /** - *

This function will split up a list of active plugins in to sub-groups. - * This is controlled by the rangeLow through rangeHigh parameters. - * The parameter includeNonAlpha will include all other plugins where their - * names do not begin with an alpha character; this is a catch-all to prevent plugins - * from being omitted. - *

- * - *

The parameter pluginsUsed is a set plugins that have already been - * included in other reports so therefore should be omitted from these reports. - *

- * - * @param plugins - * @param rangeLow - * @param rangeHigh - * @param includeNonAlpha - * @param pluginsUsed - * @return - */ - private TreeMap getSubsetOfPlugins( - TreeMap plugins, - char rangeLow, char rangeHigh, - boolean includeNonAlpha, - TreeSet pluginsUsed ) { - - TreeMap results = new TreeMap<>(); - - Set keys = plugins.keySet(); - for (String key : keys) { - - if ( !pluginsUsed.contains( key ) ) { - - char keyFirstChar = key.toLowerCase().charAt(0); - - if ( Character.isAlphabetic(keyFirstChar) ) { - - if ( Character.compare(keyFirstChar, rangeLow) >= 0 && Character.compare( keyFirstChar, rangeHigh) < 0 ) { - - results.put( key, plugins.get(key) ); - } - } - else { - - // Add all non-alpha plugins to this result: - results.put( key, plugins.get(key) ); - } - } - - } - - return results; - } +// /** +// *

This function will split up a list of active plugins in to sub-groups. +// * This is controlled by the rangeLow through rangeHigh parameters. +// * The parameter includeNonAlpha will include all other plugins where their +// * names do not begin with an alpha character; this is a catch-all to prevent plugins +// * from being omitted. +// *

+// * +// *

The parameter pluginsUsed is a set plugins that have already been +// * included in other reports so therefore should be omitted from these reports. +// *

+// * +// * @param plugins +// * @param rangeLow +// * @param rangeHigh +// * @param includeNonAlpha +// * @param pluginsUsed +// * @return +// */ +// private TreeMap getSubsetOfPlugins( +// TreeMap plugins, +// char rangeLow, char rangeHigh, +// boolean includeNonAlpha, +// TreeSet pluginsUsed ) { +// +// TreeMap results = new TreeMap<>(); +// +// Set keys = plugins.keySet(); +// for (String key : keys) { +// +// if ( !pluginsUsed.contains( key ) ) { +// +// char keyFirstChar = key.toLowerCase().charAt(0); +// +// if ( Character.isAlphabetic(keyFirstChar) ) { +// +// if ( Character.compare(keyFirstChar, rangeLow) >= 0 && Character.compare( keyFirstChar, rangeHigh) < 0 ) { +// +// results.put( key, plugins.get(key) ); +// } +// } +// else { +// +// // Add all non-alpha plugins to this result: +// results.put( key, plugins.get(key) ); +// } +// } +// +// } +// +// return results; +// } /** @@ -586,12 +593,14 @@ private void setupPluginReports() { reportPermissions.add( "LPC" ); reportPermissions.add( "PermissionsEx" ); + reportEconomy.add( "Essentials" ); reportEconomy.add( "Economy_CMI" ); + reportEconomy.add( "CMIEInjector" ); reportEconomy.add( "GemsEconomy" ); reportEconomy.add( "SDFEconomy" ); reportEconomy.add( "SaneEconomy" ); - reportEconomy.add( "Tokens" ); +// reportEconomy.add( "Tokens" ); reportEconomy.add( "Ultimate_Economy" ); reportEconomy.add( "XConomy" ); @@ -602,6 +611,7 @@ private void setupPluginReports() { reportPlaceholders.add( "AnimatedScoreboard" ); reportPlaceholders.add( "DecentHolograms" ); reportPlaceholders.add( "DeluxeMenus" ); + reportPlaceholders.add( "EconomyShopGUI" ); reportPlaceholders.add( "EssentialsChat" ); reportPlaceholders.add( "HolographicDisplays" ); reportPlaceholders.add( "HolographicExtension" ); @@ -610,10 +620,11 @@ private void setupPluginReports() { reportPlaceholders.add( "RealScoreboard" ); reportPlaceholders.add( "TAB" ); reportPlaceholders.add( "TabList" ); + + reportPlaceholders.add( "ajLeaderBoards" ); + reportPlaceholders.add( "FeatherBoard" ); - //reportVault.add( "" ); - reportEnchantments.add( "AdvancedEnchantmens" ); reportEnchantments.add( "CrazyEnchantments" ); @@ -623,26 +634,60 @@ private void setupPluginReports() { reportEnchantments.add( "PrisonEnchants" ); reportEnchantments.add( "RevEnchants" ); + reportEnchantments.add( "mcMMO" ); - reportAdminTools.add( "WorldEdit" ); - reportAdminTools.add( "WorldGuard" ); + + + reportAdminTools.add( "Citizens" ); + reportAdminTools.add( "CoreProtect" ); + reportAdminTools.add( "CMI" ); + reportAdminTools.add( "CMILib" ); + reportAdminTools.add( "EssentialsSpawn" ); + reportAdminTools.add( "FastAsyncWorldEdit" ); reportAdminTools.add( "Multiverse-Core" ); reportAdminTools.add( "Multiverse" ); reportAdminTools.add( "Multiworld" ); reportAdminTools.add( "MyCommand" ); - reportAdminTools.add( "CMI" ); - reportAdminTools.add( "CMIEInjector" ); - reportAdminTools.add( "FastAsyncWorldEdit" ); - reportAdminTools.add( "VoidGen" ); + reportAdminTools.add( "NBTAPI" ); + reportAdminTools.add( "PlayerKits" ); + reportAdminTools.add( "PlotSquared" ); + reportAdminTools.add( "SkinsRestorer" ); reportAdminTools.add( "Skript" ); - reportAdminTools.add( "PlugMan" ); // Just to get an idea of how many may be causing issues reportAdminTools.add( "ViaBackwards" ); reportAdminTools.add( "ViaRewind" ); reportAdminTools.add( "ViaVersion" ); - reportAdminTools.add( "Citizens" ); - reportAdminTools.add( "NBTAPI" ); + reportAdminTools.add( "VoidGen" ); + reportAdminTools.add( "WorldEdit" ); + reportAdminTools.add( "WorldGuard" ); + reportAdminTools.add( "WorldGuardExtraFlags" ); + + reportAdminTools.add( "ConsoleSpamFix" ); + reportAdminTools.add( "GriefPrevention" ); + + + + reportConflicts.add( "AutoSell" ); + reportConflicts.add( "CataMines" ); + reportConflicts.add( "DeluxeMines" ); + reportConflicts.add( "EZPrestige" ); + reportConflicts.add( "EZRanksPro" ); + reportConflicts.add( "JetsPrisonCells" ); + reportConflicts.add( "MineCrates" ); + reportConflicts.add( "MineBomb" ); + reportConflicts.add( "MineBuddy" ); + reportConflicts.add( "MineChess" ); + reportConflicts.add( "MineResetLite" ); + reportConflicts.add( "MineResetLitePlus" ); + reportConflicts.add( "NonSquareMines" ); + reportConflicts.add( "PlugMan" ); // Just to get an idea of how many may be causing issues + reportConflicts.add( "PrisonControl" ); + reportConflicts.add( "PrisonGames" ); + reportConflicts.add( "PrivateMines" ); + reportConflicts.add( "Rankup" ); + reportConflicts.add( "Tokens" ); } + public Metrics getbStatsMetrics() { return bStatsMetrics; } diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/commands/PrisonSpigotBackpackCommands.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/commands/PrisonSpigotBackpackCommands.java index 9913c3c4d..4d07b0d54 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/commands/PrisonSpigotBackpackCommands.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/commands/PrisonSpigotBackpackCommands.java @@ -25,7 +25,8 @@ public class PrisonSpigotBackpackCommands extends PrisonSpigotBaseCommands { @Command(identifier = "backpack", description = "Backpacks", onlyPlayers = false) private void backpackMainCommand(CommandSender sender, - @Arg(name = "ID", def = "null", description = "Leave empty if you want to open your main backpack, add an ID if you've more than one.") String id){ + @Arg(name = "ID", def = "null", + description = "Leave empty if you want to open your main backpack, add an ID if you've more than one.") String id){ if (sender.hasPermission("prison.admin") || sender.isOp()){ String registeredCmd = Prison.get().getCommandHandler().findRegisteredCommand("backpack help"); @@ -96,7 +97,7 @@ private void deleteBackpackCommand(CommandSender sender, if (isOnlinePlayer) { success = BackpacksUtil.get().resetBackpack(Bukkit.getPlayerExact(name), id); } else { - success = BackpacksUtil.get().resetBackpack(BackpacksUtil.get().getBackpackOwnerOffline(name, id), id); + success = BackpacksUtil.get().resetBackpack(BackpacksUtil.get().getBackpackOwnerOffline(name), id); } } if (success) { @@ -108,9 +109,9 @@ private void deleteBackpackCommand(CommandSender sender, @Command(identifier = "backpack set size", description = "Resize a player's backpack.", permissions = "prison.admin", onlyPlayers = false) private void resizeBackpackCommand(CommandSender sender, - @Arg(name = "Owner", description = "The backpack owner name", def = "null") String name, - @Arg(name = "Backpack size", description = "Backpack size multiple of 9", def = "9") String size, - @Arg(name = "id", description = "The backpack ID optional", def = "null") String id){ + @Arg(name = "Owner", description = "The backpack owner name", def = "null") String name, + @Arg(name = "Backpack size", description = "Backpack size multiple of 9", def = "9") String size, + @Arg(name = "id", description = "The backpack ID optional", def = "null") String id){ if (name.equalsIgnoreCase("null")){ Output.get().sendWarn(sender, SpigotPrison.format(messages.getString(MessagesConfig.StringID.spigot_message_backpack_missing_playername))); @@ -149,7 +150,7 @@ private void resizeBackpackCommand(CommandSender sender, } else { - BackpacksUtil.get().setBackpackSize(BackpacksUtil.get().getBackpackOwnerOffline(name, id), sizeInt, id); + BackpacksUtil.get().setBackpackSize(BackpacksUtil.get().getBackpackOwnerOffline(name), sizeInt, id); } } @@ -157,15 +158,17 @@ private void resizeBackpackCommand(CommandSender sender, Output.get().sendInfo(sender, SpigotPrison.format(messages.getString(MessagesConfig.StringID.spigot_message_backpack_resize_success))); } - @Command(identifier = "backpack limit", permissions = "prison.admin", description = "Backpacks limit for player, to use this multiple backpacks must be enabled from the backpacks config or it won't have effect.", onlyPlayers = false) + @Command(identifier = "backpack limit", permissions = "prison.admin", + description = "Backpacks limit for player, to use this multiple backpacks must be enabled from the backpacks config or it won't have effect.", onlyPlayers = false) private void backpackLimitMainCommand(CommandSender sender){ sender.dispatchCommand("backpack limit help"); } - @Command(identifier = "backpack limit set", permissions = "prison.admin", description = "Set backpacks limit of a player, to use this multiple backpacks must be enabled or it won't have effect.", onlyPlayers = false) + @Command(identifier = "backpack limit set", + permissions = "prison.admin", description = "Set backpacks limit of a player, to use this multiple backpacks must be enabled or it won't have effect.", onlyPlayers = false) private void setBackpackLimitCommand(CommandSender sender, - @Arg(name = "Owner", description = "The backpack owner name", def = "null") String name, - @Arg(name = "Limit", description = "The Backpacks limit that a player can own", def = "null") String limit) { + @Arg(name = "Owner", description = "The backpack owner name", def = "null") String name, + @Arg(name = "Limit", description = "The Backpacks limit that a player can own", def = "null") String limit) { if (name.equalsIgnoreCase("null") || limit.equalsIgnoreCase("null")){ Output.get().sendWarn(sender, SpigotPrison.format(messages.getString(MessagesConfig.StringID.spigot_message_command_wrong_format))); @@ -189,10 +192,12 @@ private void setBackpackLimitCommand(CommandSender sender, Output.get().sendInfo(sender, SpigotPrison.format(messages.getString(MessagesConfig.StringID.spigot_message_backpack_limit_edit_success))); } - @Command(identifier = "backpack limit add", permissions = "prison.admin", description = "Increment backpacks limit of a player, multiple backpacks must be enabled or this won't take effect.", onlyPlayers = false) + @Command(identifier = "backpack limit add", + permissions = "prison.admin", + description = "Increment backpacks limit of a player, multiple backpacks must be enabled or this won't take effect.", onlyPlayers = false) private void addBackpackLimitCommand(CommandSender sender, - @Arg(name = "Owner", description = "The backpack owner name", def = "null") String name, - @Arg(name = "Limit", description = "The Backpacks increment value", def = "null") String limit) { + @Arg(name = "Owner", description = "The backpack owner name", def = "null") String name, + @Arg(name = "Limit", description = "The Backpacks increment value", def = "null") String limit) { if (name.equalsIgnoreCase("null") || limit.equalsIgnoreCase("null")){ Output.get().sendWarn(sender, SpigotPrison.format(messages.getString(MessagesConfig.StringID.spigot_message_command_wrong_format))); @@ -218,10 +223,11 @@ private void addBackpackLimitCommand(CommandSender sender, Output.get().sendInfo(sender, SpigotPrison.format(messages.getString(MessagesConfig.StringID.spigot_message_backpack_limit_edit_success))); } - @Command(identifier = "backpack limit decrement", permissions = "prison.admin", description = "Decrement backpacks limit of a player, to use this multiple backpacks must be enabled or it won't have effect.", onlyPlayers = false) + @Command(identifier = "backpack limit decrement", permissions = "prison.admin", + description = "Decrement backpacks limit of a player, to use this multiple backpacks must be enabled or it won't have effect.", onlyPlayers = false) private void decrementBackpackLimitCommand(CommandSender sender, - @Arg(name = "Owner", description = "The backpack owner name", def = "null") String name, - @Arg(name = "Value", description = "The Backpacks decrement value", def = "null") String limit) { + @Arg(name = "Owner", description = "The backpack owner name", def = "null") String name, + @Arg(name = "Value", description = "The Backpacks decrement value", def = "null") String limit) { if (name.equalsIgnoreCase("null") || limit.equalsIgnoreCase("null")){ Output.get().sendWarn(sender, SpigotPrison.format(messages.getString(MessagesConfig.StringID.spigot_message_command_wrong_format))); @@ -257,7 +263,8 @@ private void decrementBackpackLimitCommand(CommandSender sender, Output.get().sendInfo(sender, SpigotPrison.format(messages.getString(MessagesConfig.StringID.spigot_message_backpack_limit_edit_success))); } - @Command(identifier = "backpack admin", description = "Open backpack admin GUI", permissions = "prison.admin", onlyPlayers = true) + @Command(identifier = "backpack admin", description = "Open backpack admin GUI", + permissions = "prison.admin", onlyPlayers = true) private void openBackpackAdminGUI(CommandSender sender){ Player p = getSpigotPlayer(sender); @@ -273,7 +280,8 @@ private void openBackpackAdminGUI(CommandSender sender){ @Command(identifier = "gui backpack", description = "Backpack as a GUI", onlyPlayers = true) private void backpackGUIOpenCommand(CommandSender sender, - @Arg(name = "Backpack-ID", def = "null", description = "If user have more than backpack, he'll be able to choose another backpack on ID") String id){ + @Arg(name = "Backpack-ID", def = "null", + description = "If user have more than backpack, he'll be able to choose another backpack on ID") String id){ Player p = getSpigotPlayer(sender); @@ -303,7 +311,7 @@ private void backpackGUIOpenCommand(CommandSender sender, if (!id.equalsIgnoreCase("null") && getBoolean(BackpacksUtil.get().getBackpacksConfig().getString("Options.Multiple-BackPacks-For-Player-Enabled"))){ BackpacksUtil.get().openBackpack(p, id); } else { - BackpacksUtil.get().openBackpack(p); + BackpacksUtil.get().openBackpack(p, (String) null ); } } diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/commands/PrisonSpigotBaseCommands.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/commands/PrisonSpigotBaseCommands.java index 729a9b43b..141a2b09a 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/commands/PrisonSpigotBaseCommands.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/commands/PrisonSpigotBaseCommands.java @@ -3,6 +3,7 @@ import org.bukkit.configuration.Configuration; import org.bukkit.entity.Player; +import tech.mcprison.prison.commands.BaseCommands; import tech.mcprison.prison.internal.CommandSender; import tech.mcprison.prison.spigot.SpigotPrison; import tech.mcprison.prison.spigot.configs.MessagesConfig; @@ -11,10 +12,15 @@ /** * @author RoyalBlueRanger */ -public class PrisonSpigotBaseCommands { +public class PrisonSpigotBaseCommands + extends BaseCommands { private final MessagesConfig messages = SpigotPrison.getInstance().getMessagesConfig(); + public PrisonSpigotBaseCommands() { + super( "SpigotBaseCommands"); + } + public MessagesConfig getMessages() { return messages; } diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/commands/PrisonSpigotGUICommands.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/commands/PrisonSpigotGUICommands.java index 5bfece03a..f2a9b8a8d 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/commands/PrisonSpigotGUICommands.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/commands/PrisonSpigotGUICommands.java @@ -69,7 +69,7 @@ private void prisonManagerPrestiges( CommandSender sender, "prestiges are shown on multiple pages. The page parameter starts with " + "page 1.", def = "1" ) int page ) { - cmdPrisonManagerPrestiges( sender, page, "gui prestiges", "gui" ); + cmdPrisonManagerPrestiges( sender, page, "gui prestiges", "close" ); } protected void cmdPrisonManagerPrestiges( CommandSender sender, int page, String cmdPage, String cmdReturn ) { @@ -122,7 +122,7 @@ private void prisonManagerMines(CommandSender sender, "page 1.", def = "1" ) int page ) { - cmdPrisonManagerMines( sender, page, "gui mines", "gui" ); + cmdPrisonManagerMines( sender, page, "gui mines", "close" ); } protected void cmdPrisonManagerMines( CommandSender sender, int page, String cmdPage, String cmdReturn ) { @@ -205,7 +205,7 @@ private void prisonManagerRanks(CommandSender sender, "page 1.", def = "1" ) int page ) { - cmdPrisonManagerRanks( sender, page, "gui ranks", "gui" ); + cmdPrisonManagerRanks( sender, page, "gui ranks", "close" ); } protected void cmdPrisonManagerRanks(CommandSender sender, int page, String cmdPage, String cmdReturn ) { Player player = getSpigotPlayer(sender); @@ -323,7 +323,7 @@ private void prisonManagerLadders(CommandSender sender, "page 1.", def = "1" ) int page ) { - cmdPrisonManagerLadders( sender, page, "gui ladders", "gui" ); + cmdPrisonManagerLadders( sender, page, "gui ladders", "close" ); } protected void cmdPrisonManagerLadders(CommandSender sender, int page, String cmdPage, String cmdReturn ) { diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/commands/PrisonSpigotPrestigeCommands.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/commands/PrisonSpigotPrestigeCommands.java index 8d14087bf..de747116b 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/commands/PrisonSpigotPrestigeCommands.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/commands/PrisonSpigotPrestigeCommands.java @@ -1,22 +1,21 @@ package tech.mcprison.prison.spigot.commands; +import java.util.ArrayList; +import java.util.List; import java.util.Optional; -import org.bukkit.Bukkit; import org.bukkit.entity.Player; import tech.mcprison.prison.Prison; +import tech.mcprison.prison.commands.Arg; import tech.mcprison.prison.commands.Command; +import tech.mcprison.prison.commands.Wildcard; import tech.mcprison.prison.internal.CommandSender; import tech.mcprison.prison.modules.Module; -import tech.mcprison.prison.modules.ModuleManager; import tech.mcprison.prison.output.Output; import tech.mcprison.prison.ranks.PrisonRanks; -import tech.mcprison.prison.ranks.data.RankLadder; -import tech.mcprison.prison.ranks.managers.LadderManager; import tech.mcprison.prison.spigot.SpigotPrison; import tech.mcprison.prison.spigot.configs.MessagesConfig; -import tech.mcprison.prison.spigot.gui.ListenersPrisonManager; import tech.mcprison.prison.spigot.gui.rank.SpigotConfirmPrestigeGUI; /** @@ -49,110 +48,145 @@ public void prestigesGUICommand(CommandSender sender) { } } - @Command(identifier = "prestige", onlyPlayers = true) - public void prestigesPrestigeCommand(CommandSender sender) { - if ( isPrisonConfig( "prestiges" ) || isPrisonConfig( "prestige.enabled" ) ) { - - - Optional ranksModule = Prison.get().getModuleManager().getModule( PrisonRanks.MODULE_NAME ); - if ( !ranksModule.isPresent() || ranksModule.isPresent() && !ranksModule.get().isEnabled() ) { - - Output.get().sendWarn( sender, "The command '/prestige' is disabled because the Ranks module is not active." ); - return; - } - - - prisonManagerPrestige(sender); - } - } - - @Command( identifier = "gui prestige", description = "GUI Prestige", + @Command( identifier = "gui prestigeConfirm", + description = "GUI Prestige Confirmation screeen. Use the command `/prestige help` instead of " + + "trying to call this directly. This is strictly a 'dumb' internal GUI that has " + + "no validation logic.", aliases = {"prisonmanager prestige"} ) - public void prisonManagerPrestige(CommandSender sender ) { - - if ( isPrisonConfig( "prestige.enabled" ) ) { - - - Optional ranksModule = Prison.get().getModuleManager().getModule( PrisonRanks.MODULE_NAME ); - if ( !ranksModule.isPresent() || ranksModule.isPresent() && !ranksModule.get().isEnabled() ) { - - Output.get().sendWarn( sender, "The command '/gui prestiges' is disabled because the Ranks module is not active." ); - return; - } - - if ( PrisonRanks.getInstance().getLadderManager().getLadder("prestiges") == null ) { - Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "ranks ladder create prestiges"); - } - - PrisonRanks rankPlugin; - - ModuleManager modMan = Prison.get().getModuleManager(); - Module module = modMan == null ? null : modMan.getModule( PrisonRanks.MODULE_NAME ).orElse( null ); - - if ( module != null ) { - - rankPlugin = (PrisonRanks) module; - - LadderManager lm = null; - if (rankPlugin != null) { - lm = rankPlugin.getLadderManager(); - - RankLadder ladderDefault = lm.getLadder("default"); - if ( ( ladderDefault == null || - !(ladderDefault.getLowestRank().isPresent()) || - ladderDefault.getLowestRank().get().getName() == null)) { - Output.get().sendInfo(sender, SpigotPrison.format(messages.getString(MessagesConfig.StringID.spigot_message_ladder_default_empty))); - return; - } - - RankLadder ladderPrestiges = lm.getLadder("prestiges"); - if ( ( ladderPrestiges == null || - !(ladderPrestiges.getLowestRank().isPresent()) || - ladderPrestiges.getLowestRank().get().getName() == null)) { - Output.get().sendInfo(sender, SpigotPrison.format(messages.getString(MessagesConfig.StringID.spigot_message_prestiges_empty))); - return; - } - } - - - if ( isPrisonConfig( "prestige.confirmation-enabled") && isPrisonConfig( "prestige.prestige-confirm-gui") ) { - try { - - Player player = getSpigotPlayer( sender ); - - SpigotConfirmPrestigeGUI gui = new SpigotConfirmPrestigeGUI( player ); - gui.open(); - } catch (Exception ex) { - prestigeByChat( sender ); - } - } - else if ( isPrisonConfig( "prestige.confirmation-enabled") ) { - prestigeByChat( sender ); - } - else { - // Bypassing prestige confirmations: - Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "rankup prestiges"); - } - } - } - else { - sender.sendMessage( "Prestiges are disabled. Refresh and then reconfigure config.yml and try again." ); - } + public void prisonManagerPrestige(CommandSender sender, + @Wildcard(join=true) + @Arg(name = "lores", def = "", + description = "This field represents a list lore values that will be " + + "shown in the prestige confirmation GUI. This should not be used directly." ) + String lores) { + + if ( lores == null || lores.trim().length() == 0 ) { + sender.sendMessage( "Invalid use of `/gui prestigeConfirm`. Please use `/prestige` instead." ); + return; + } + + List lore = new ArrayList<>(); + + for ( String loreRaw : lores.split( " " ) ) { + String loreValue = loreRaw.replace( "_", " ").trim(); + if ( loreValue.length() > 0 ) { + lore.add( loreValue ); + } + } + + Player player = getSpigotPlayer( sender ); + + SpigotConfirmPrestigeGUI gui = new SpigotConfirmPrestigeGUI( player, lore ); + gui.open(); + } - private void prestigeByChat(CommandSender sender) { - - ListenersPrisonManager listenersPrisonManager = ListenersPrisonManager.get(); - listenersPrisonManager.chatEventActivator(); - - Output.get().sendInfo(sender, messages.getString(MessagesConfig.StringID.spigot_gui_lore_prestige_warning_1) + " " - + messages.getString(MessagesConfig.StringID.spigot_gui_lore_prestige_warning_2) + " " + messages.getString(MessagesConfig.StringID.spigot_gui_lore_prestige_warning_3)); - Output.get().sendInfo(sender, "&a" + messages.getString(MessagesConfig.StringID.spigot_message_prestiges_confirm)); - Output.get().sendInfo(sender, "&c" + messages.getString(MessagesConfig.StringID.spigot_message_prestiges_cancel)); - - final Player player = getSpigotPlayer( sender ); - listenersPrisonManager.chatInteractData(player, ListenersPrisonManager.ChatMode.Prestige); - } +// @Command(identifier = "prestige", onlyPlayers = true) +// public void prestigesPrestigeCommand(CommandSender sender) { +// +// if ( isPrisonConfig( "prestiges" ) || isPrisonConfig( "prestige.enabled" ) ) { +// +// +// Optional ranksModule = Prison.get().getModuleManager().getModule( PrisonRanks.MODULE_NAME ); +// if ( !ranksModule.isPresent() || ranksModule.isPresent() && !ranksModule.get().isEnabled() ) { +// +// Output.get().sendWarn( sender, "The command '/prestige' is disabled because the Ranks module is not active." ); +// return; +// } +// +// +// prisonManagerPrestige(sender); +// } +// } + +// @Command( identifier = "gui prestige", description = "GUI Prestige", +// aliases = {"prisonmanager prestige"} ) +// public void prisonManagerPrestige(CommandSender sender ) { +// +// if ( isPrisonConfig( "prestige.enabled" ) ) { +// +// +// Optional ranksModule = Prison.get().getModuleManager().getModule( PrisonRanks.MODULE_NAME ); +// if ( !ranksModule.isPresent() || ranksModule.isPresent() && !ranksModule.get().isEnabled() ) { +// +// Output.get().sendWarn( sender, "The command '/gui prestiges' is disabled because the Ranks module is not active." ); +// return; +// } +// +// if ( PrisonRanks.getInstance().getLadderManager().getLadder("prestiges") == null ) { +// Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "ranks ladder create prestiges"); +// } +// +// PrisonRanks rankPlugin; +// +// ModuleManager modMan = Prison.get().getModuleManager(); +// Module module = modMan == null ? null : modMan.getModule( PrisonRanks.MODULE_NAME ).orElse( null ); +// +// if ( module != null ) { +// +// rankPlugin = (PrisonRanks) module; +// +// LadderManager lm = null; +// if (rankPlugin != null) { +// lm = rankPlugin.getLadderManager(); +// +// RankLadder ladderDefault = lm.getLadder("default"); +// if ( ( ladderDefault == null || +// !(ladderDefault.getLowestRank().isPresent()) || +// ladderDefault.getLowestRank().get().getName() == null)) { +// Output.get().sendInfo(sender, SpigotPrison.format(messages.getString(MessagesConfig.StringID.spigot_message_ladder_default_empty))); +// return; +// } +// +// RankLadder ladderPrestiges = lm.getLadder("prestiges"); +// if ( ( ladderPrestiges == null || +// !(ladderPrestiges.getLowestRank().isPresent()) || +// ladderPrestiges.getLowestRank().get().getName() == null)) { +// Output.get().sendInfo(sender, SpigotPrison.format(messages.getString(MessagesConfig.StringID.spigot_message_prestiges_empty))); +// return; +// } +// } +// +// +// if ( isPrisonConfig( "prestige.confirmation-enabled") && isPrisonConfig( "prestige.prestige-confirm-gui") ) { +// try { +// +// Player player = getSpigotPlayer( sender ); +// +// SpigotConfirmPrestigeGUI gui = new SpigotConfirmPrestigeGUI( player ); +// gui.open(); +// } catch (Exception ex) { +// prestigeByChat( sender ); +// } +// } +// else if ( isPrisonConfig( "prestige.confirmation-enabled") ) { +// prestigeByChat( sender ); +// } +// else { +// // Bypassing prestige confirmations: +// Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "rankup prestiges"); +// } +// } +// } +// else { +// sender.sendMessage( "Prestiges are disabled. Refresh and then reconfigure config.yml and try again." ); +// } +// } + +// private void prestigeByChat(CommandSender sender) { +// +// ListenersPrisonManager listenersPrisonManager = ListenersPrisonManager.get(); +// listenersPrisonManager.chatEventActivator(); +// +// Output.get().sendInfo(sender, messages.getString(MessagesConfig.StringID.spigot_gui_lore_prestige_warning_1) + " " +// + messages.getString(MessagesConfig.StringID.spigot_gui_lore_prestige_warning_2) + " " + messages.getString(MessagesConfig.StringID.spigot_gui_lore_prestige_warning_3)); +// +// Output.get().sendInfo(sender, "&a" + messages.getString(MessagesConfig.StringID.spigot_message_prestiges_confirm)); +// Output.get().sendInfo(sender, "&c" + messages.getString(MessagesConfig.StringID.spigot_message_prestiges_cancel)); +// +// final Player player = getSpigotPlayer( sender ); +// listenersPrisonManager.chatInteractData(player, ListenersPrisonManager.ChatMode.Prestige); +// } } diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/commands/PrisonSpigotSellAllCommands.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/commands/PrisonSpigotSellAllCommands.java index 4c376d10b..d4108c081 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/commands/PrisonSpigotSellAllCommands.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/commands/PrisonSpigotSellAllCommands.java @@ -24,10 +24,12 @@ import tech.mcprison.prison.spigot.SpigotPrison; import tech.mcprison.prison.spigot.compat.Compatibility; import tech.mcprison.prison.spigot.configs.MessagesConfig; +import tech.mcprison.prison.spigot.game.SpigotOfflinePlayer; import tech.mcprison.prison.spigot.game.SpigotPlayer; import tech.mcprison.prison.spigot.gui.sellall.SellAllAdminBlocksGUI; import tech.mcprison.prison.spigot.sellall.SellAllBlockData; import tech.mcprison.prison.spigot.sellall.SellAllUtil; +import tech.mcprison.prison.spigot.utils.tasks.PlayerAutoRankupTask; /** * @author GABRYCA @@ -236,20 +238,57 @@ private void sellAllAutoSellPerUserToggleable(CommandSender sender, } } - @Command(identifier = "sellall sell", description = "SellAll sell command.", onlyPlayers = true) + @Command(identifier = "sellall sell", description = "SellAll sell command.", onlyPlayers = false) public void sellAllSellCommand(CommandSender sender, - @Arg(name = "notification", def="", - description = "Notification about the sellall transaction. Defaults to normal. " + - "'silent' suppresses results. [silent]") String notification ){ + @Arg(name = "player", def = "", description = "An online player name to sell their inventory - " + + "Only console or prison commands can include this parameter") String playerName, + @Arg(name = "notification", def="", + description = "Notification about the sellall transaction. Defaults to normal. " + + "'silent' suppresses results. [silent]") String notification ){ if (!isEnabled()) return; Player p = getSpigotPlayer(sender); + - if (p == null){ - Output.get().sendInfo(sender, "&cSorry but you can't use that from the console!"); + boolean isOp = sender.isOp(); + + tech.mcprison.prison.internal.Player sPlayerAlt = getOnlinePlayer( sender, playerName ); + if ( sPlayerAlt == null ){ + // If sPlayerAlt is null then the value in playerName is really intended for notification: + notification = playerName; + } + + if ( isOp && !sender.isPlayer() && sPlayerAlt != null ) { + // Only if OP and a valid player name was provided, then OP is trying to run this + // for another player + + if ( !sPlayerAlt.isOnline() ) { + sender.sendMessage( "Player is not online." ); + return; + } + + // Set the active player to who OP specified: + p = ((SpigotPlayer) sPlayerAlt).getWrapper(); + } + + + else if (p == null){ + + if ( getPlayer( sender, playerName ) != null ) { + + Output.get().sendInfo(sender, "&cSorry but the specified player must be online " + + "[/sellall sell %s]", playerName ); + } + else { + + Output.get().sendInfo(sender, "&cSorry but you can't use that from the console!"); + } + + return; } + SellAllUtil sellAllUtil = SellAllUtil.get(); if (sellAllUtil == null){ @@ -269,6 +308,9 @@ public void sellAllSellCommand(CommandSender sender, boolean notifications = (notification != null && "silent".equalsIgnoreCase( notification )); sellAllUtil.sellAllSell(p, false, notifications, true, true, false, true); + + SpigotPlayer sPlayer = new SpigotPlayer( p ); + PlayerAutoRankupTask.autoSubmitPlayerRankupTask( sPlayer, null ); } @Command(identifier = "sellall hand", description = "Sell only what is in your hand if sellable.", @@ -340,6 +382,11 @@ public void sellAllSell(Player p){ } sellAllUtil.sellAllSell(p, true, false, true, true, false, true); + + + SpigotPlayer sPlayer = new SpigotPlayer( p ); + PlayerAutoRankupTask.autoSubmitPlayerRankupTask( sPlayer, null ); + } @Command(identifier = "sellall delaysell", description = "Like SellAll Sell command but this will be delayed for some " + @@ -375,11 +422,14 @@ public void sellAllSellWithDelayCommand(CommandSender sender){ } if (!sellAllUtil.isAutoSellEarningNotificationDelayEnabled){ - sellAllSellCommand(sender, "silent"); + sellAllSellCommand(sender, null, "silent"); return; } sellAllUtil.sellAllSell(p, false, false, false, false, true, false); + + SpigotPlayer sPlayer = new SpigotPlayer( p ); + PlayerAutoRankupTask.autoSubmitPlayerRankupTask( sPlayer, null ); } @@ -655,7 +705,7 @@ private void sellAllMultiplierCommand(CommandSender sender){ TreeMap mults = new TreeMap<>( sellAllUtil.getPrestigeMultipliers() ); // TreeMap items = new TreeMap<>( sellAllUtil.getSellAllBlocks() ); - DecimalFormat fFmt = new DecimalFormat("#,##0.00"); + DecimalFormat fFmt = Prison.get().getDecimalFormat("#,##0.00"); Set keys = mults.keySet(); @@ -929,7 +979,7 @@ private void sellAllListItems( CommandSender sender ) { } TreeMap items = new TreeMap<>( sellAllUtil.getSellAllBlocks() ); - DecimalFormat fFmt = new DecimalFormat("#,##0.00"); + DecimalFormat fFmt = Prison.get().getDecimalFormat("#,##0.00"); Set keys = items.keySet(); diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/configs/GuiConfig.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/configs/GuiConfig.java index 938920fa6..904f97b4c 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/configs/GuiConfig.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/configs/GuiConfig.java @@ -58,12 +58,20 @@ public void initialize() { changeCount++; } - if ( conf.getList( "EditableLore.README" ) == null ) { + if ( conf.getList( "EditableLore.README-Updated-2022-12-22" ) == null ) { List lore = new ArrayList<>(); lore.add(" "); lore.add("&8-----------------------"); lore.add("&7 WARNING!! DO NOT EDIT THESE!!"); - lore.add("&7 THESE ARE JUST INFORMATIONAL NOTES AND WILL BE IGNORED BY PRISON."); + lore.add("&7 - THESE ARE JUST INFORMATIONAL NOTES AND WILL BE IGNORED BY PRISON."); + lore.add(" "); + lore.add("&7 PLEASE READ - IMPORTANT CHANGESE!!"); + lore.add("&7 - You can safely remove other 'EditableLore.README*' notes since they "); + lore.add("&7 are now obsolete."); + lore.add("&7 - Remove everything under 'EditableLore.Mines' and then reload the GUI: "); + lore.add("&7 /prison reload gui "); + lore.add("&7 The Mines LORE layout has been updated and this will help apply the "); + lore.add("&7 new update to your configs"); lore.add("&8-----------------------"); lore.add("&7 There are three types of placeholders that will work with EditableLore:"); lore.add("&7 1. GUI placeholders"); @@ -74,11 +82,14 @@ public void initialize() { lore.add("&7so they can be nested in the prison placeholders: "); lore.add("&7 "); lore.add("&7 For Ranks ONLY: "); - lore.add("&7 {rankName} {rankTag} {rankPrice} {rankMultiplier} {ladderName} {linkedMines}"); - lore.add("&7 Not yet available in Ranks: {mineName} {mineTag} "); + lore.add("&7 {rankName} {rankTag} {rankPrice} {rankMultiplier}"); + lore.add("&7 {ladderName} {linkedMines}"); + lore.add("&7 {linkedMines}"); lore.add("&7 "); lore.add("&7 For Mines ONLY: "); - lore.add("&7 {mineName} {mineTag} {mineSize} {mineVolume} {mineRemaining} {mineRemaingPercent} "); + lore.add("&7 {mineName} {mineTag} {mineSize} {mineVolume} "); + lore.add("&7 {mineRemaining} {mineRemaingPercent} "); + lore.add("&7 {clickToTeleport} {lockStatus} {playerCount} {linkedRank} "); lore.add("&8-----------------------"); lore.add("&7Prison placeholders can include any that are within these placeholder "); lore.add("&7Groups: PLAYER, RANKS, RANKPLAYERS, MINES, STATSMINES, and STATSRANKS"); @@ -94,7 +105,7 @@ public void initialize() { lore.add("&8-----------------------"); - conf.set("EditableLore.README", lore); + conf.set("EditableLore.README-Updated-2022-12-22", lore); changeCount++; } @@ -140,11 +151,15 @@ public void initialize() { lore.add(" "); lore.add("&8-----------------------"); lore.add("&3Mine: &a{mineName} &r{mineTag}"); + lore.add("&3Rank: &a{linkedRank}"); lore.add(" "); lore.add("&3Size: &a{mineSize}"); lore.add("&3Volume: &a{mineVolume}"); lore.add("&3Blocks Remaining: &a{mineRemaining} &a{mineRemainingPercent}%"); + lore.add("&3Players in Mine: &a{playerCount}"); lore.add(" "); + lore.add(" {clickToTeleport}"); + lore.add(" {lockStatus}"); lore.add("&8-----------------------"); conf.set("EditableLore.Mines", lore); diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/configs/MessagesConfig.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/configs/MessagesConfig.java index fa9109509..14d29f89d 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/configs/MessagesConfig.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/configs/MessagesConfig.java @@ -121,7 +121,7 @@ public void reload(){ public enum StringID { - spigot_gui_lore_click_to_add, +// spigot_gui_lore_click_to_add, spigot_gui_lore_click_to_add_backpack, // spigot_gui_lore_click_to_cancel, // spigot_gui_lore_click_to_close, @@ -132,14 +132,14 @@ public enum StringID { // spigot_gui_lore_click_to_edit, // spigot_gui_lore_click_to_enable, // spigot_gui_lore_click_to_increase, - spigot_gui_lore_click_to_manage_rank, +// spigot_gui_lore_click_to_manage_rank, // spigot_gui_lore_click_to_open, - spigot_gui_lore_click_to_rankup, - spigot_gui_lore_click_to_rename, - spigot_gui_lore_click_to_select, - spigot_gui_lore_click_to_start_block_setup, - spigot_gui_lore_click_to_teleport, - spigot_gui_lore_click_to_use, +// spigot_gui_lore_click_to_rankup, +// spigot_gui_lore_click_to_rename, +// spigot_gui_lore_click_to_select, +// spigot_gui_lore_click_to_start_block_setup, +// spigot_gui_lore_click_to_teleport, +// spigot_gui_lore_click_to_use, // spigot_gui_lore_click_left_to_confirm, // spigot_gui_lore_click_left_to_edit, @@ -156,42 +156,42 @@ public enum StringID { // spigot_gui_lore_click_right_and_shift_to_disable, // spigot_gui_lore_click_right_and_shift_to_toggle, - spigot_gui_lore_backpack_id, - spigot_gui_lore_blocks, - spigot_gui_lore_blocktype, - spigot_gui_lore_chance, - spigot_gui_lore_command, +// spigot_gui_lore_backpack_id, +// spigot_gui_lore_blocks, +// spigot_gui_lore_blocktype, +// spigot_gui_lore_chance, +// spigot_gui_lore_command, spigot_gui_lore_currency, // spigot_gui_lore_delay, - spigot_gui_lore_id, - spigot_gui_lore_info, - spigot_gui_lore_minename, +// spigot_gui_lore_id, +// spigot_gui_lore_info, +// spigot_gui_lore_minename, // spigot_gui_lore_multiplier, - spigot_gui_lore_name, - spigot_gui_lore_owner, - spigot_gui_lore_percentage, +// spigot_gui_lore_name, +// spigot_gui_lore_owner, +// spigot_gui_lore_percentage, // spigot_gui_lore_permission, - spigot_gui_lore_players_at_rank, +// spigot_gui_lore_players_at_rank, // spigot_gui_lore_prestige_name, // spigot_gui_lore_price, - spigot_gui_lore_radius, - spigot_gui_lore_rank_tag, - spigot_gui_lore_reset_time, - spigot_gui_lore_show_item, - spigot_gui_lore_size, - spigot_gui_lore_spawnpoint, - spigot_gui_lore_volume, +// spigot_gui_lore_radius, +// spigot_gui_lore_rank_tag, +// spigot_gui_lore_reset_time, +// spigot_gui_lore_show_item, +// spigot_gui_lore_size, +// spigot_gui_lore_spawnpoint, +// spigot_gui_lore_volume, // spigot_gui_lore_value, - spigot_gui_lore_world, +// spigot_gui_lore_world, spigot_gui_lore_disabled, spigot_gui_lore_enabled, - spigot_gui_lore_locked, +// spigot_gui_lore_locked, // spigot_gui_lore_next_page, // spigot_gui_lore_prior_page, spigot_gui_lore_rankup, - spigot_gui_lore_selected, - spigot_gui_lore_unlocked, +// spigot_gui_lore_selected, +// spigot_gui_lore_unlocked, spigot_gui_lore_add_backpack_instruction_1, spigot_gui_lore_add_backpack_instruction_2, @@ -209,28 +209,28 @@ public enum StringID { spigot_gui_lore_ranks_setup_8, spigot_gui_lore_sellall_delay_use_1, spigot_gui_lore_sellall_delay_use_2, - spigot_gui_lore_set_mine_delay_instruction_1, - spigot_gui_lore_set_mine_delay_instruction_2, - spigot_gui_lore_set_mine_delay_instruction_3, - spigot_gui_lore_show_item_description_1, - spigot_gui_lore_show_item_description_2, - spigot_gui_lore_show_item_description_3, - spigot_gui_lore_skip_reset_instruction_1, - spigot_gui_lore_skip_reset_instruction_2, - spigot_gui_lore_skip_reset_instruction_3, +// spigot_gui_lore_set_mine_delay_instruction_1, +// spigot_gui_lore_set_mine_delay_instruction_2, +// spigot_gui_lore_set_mine_delay_instruction_3, +// spigot_gui_lore_show_item_description_1, +// spigot_gui_lore_show_item_description_2, +// spigot_gui_lore_show_item_description_3, +// spigot_gui_lore_skip_reset_instruction_1, +// spigot_gui_lore_skip_reset_instruction_2, +// spigot_gui_lore_skip_reset_instruction_3, spigot_gui_lore_autofeatures_button_description, spigot_gui_lore_backpacks_button_description, - spigot_gui_lore_disable_notifications, - spigot_gui_lore_enable_radius_mode, - spigot_gui_lore_enable_within_mode, +// spigot_gui_lore_disable_notifications, +// spigot_gui_lore_enable_radius_mode, +// spigot_gui_lore_enable_within_mode, spigot_gui_lore_mines_button_description, spigot_gui_lore_no_multipliers, spigot_gui_lore_ranks_button_description, - spigot_gui_lore_rankup_if_enough_money, +// spigot_gui_lore_rankup_if_enough_money, spigot_gui_lore_sellall_button_description, spigot_gui_lore_sellall_edit_info, - spigot_gui_lore_tp_to_mine, +// spigot_gui_lore_tp_to_mine, spigot_message_missing_permission, @@ -261,7 +261,7 @@ public enum StringID { spigot_message_backpack_size_must_be_multiple_of_9, spigot_message_prestiges_disabled, - spigot_message_prestiges_empty, +// spigot_message_prestiges_empty, spigot_message_prestiges_or_gui_disabled, spigot_message_prestiges_confirm, spigot_message_prestiges_cancel, @@ -342,16 +342,16 @@ public enum StringID { spigot_message_gui_backpack_too_many, spigot_message_gui_close_success, spigot_message_gui_error, - spigot_message_gui_error_empty, - spigot_message_gui_ladder_empty, +// spigot_message_gui_error_empty, +// spigot_message_gui_ladder_empty, spigot_message_gui_ladder_too_many, spigot_message_gui_mines_empty, spigot_message_gui_mines_too_many, spigot_message_gui_prestiges_empty, spigot_message_gui_prestiges_too_many, - spigot_message_gui_ranks_empty, - spigot_message_gui_ranks_rankup_commands_empty, - spigot_message_gui_ranks_rankup_commands_too_many, +// spigot_message_gui_ranks_empty, +// spigot_message_gui_ranks_rankup_commands_empty, +// spigot_message_gui_ranks_rankup_commands_too_many, spigot_message_gui_ranks_too_many, spigot_message_gui_reload_success, // spigot_message_gui_sellall_disabled, diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/customblock/CustomItems.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/customblock/CustomItems.java index 689756d4a..96aabd3dc 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/customblock/CustomItems.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/customblock/CustomItems.java @@ -19,7 +19,7 @@ import tech.mcprison.prison.util.Location; /** - * Custom Items 3.7.11 — New API features + * Custom Items 3.7.11 New API features This version adds two new features to the Custom Items API: listCustomItemIDs and listBlockCustomItemIDs * */ diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/customblock/PrisonItemAdderStartupListener.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/customblock/PrisonItemAdderStartupListener.java new file mode 100644 index 000000000..988c02b75 --- /dev/null +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/customblock/PrisonItemAdderStartupListener.java @@ -0,0 +1,62 @@ +package tech.mcprison.prison.spigot.customblock; + +import org.bukkit.Bukkit; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.plugin.PluginManager; + +import dev.lone.itemsadder.api.Events.ItemsAdderLoadDataEvent; +import tech.mcprison.prison.output.Output; +import tech.mcprison.prison.spigot.SpigotPrison; + +public class PrisonItemAdderStartupListener + implements Listener { + + + public PrisonItemAdderStartupListener() { + super(); + + initialize(); + } + + public void initialize() { + + + // Check to see if the class BlastUseEvent even exists: + try { + Output.get().logInfo( "PrisonItemAdderStartupListener: checking if loaded: ItemsAdder" ); + + Class.forName( "dev.lone.itemsadder.api.Events.ItemsAdderLoadDataEvent", false, + this.getClass().getClassLoader() ); + + Output.get().logInfo( "PrisonItemAdderStartupListener: Trying to register ItemsAdder" ); + + + SpigotPrison prison = SpigotPrison.getInstance(); + PluginManager pm = Bukkit.getServer().getPluginManager(); + + pm.registerEvents( this, prison); + + + } + catch ( ClassNotFoundException e ) { + // CrazyEnchants is not loaded... so ignore. + Output.get().logInfo( "PrisonItemAdderStartupListener: ItemsAdder is not loaded" ); + } + catch ( Exception e ) { + Output.get().logInfo( + "PrisonItemAdderStartupListener: ItemsAdder failed to load. [%s]", e.getMessage() ); + } + + } + + @EventHandler + public void onItemsAdderStartup( ItemsAdderLoadDataEvent e ) { + + SpigotPrison prison = SpigotPrison.getInstance(); + + PrisonItemsAdder pia = new PrisonItemsAdder(); + + prison.registerIntegration( pia ); + } +} diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/customblock/PrisonItemsAdder.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/customblock/PrisonItemsAdder.java new file mode 100644 index 000000000..da8153d09 --- /dev/null +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/customblock/PrisonItemsAdder.java @@ -0,0 +1,194 @@ +package tech.mcprison.prison.spigot.customblock; + +import java.util.ArrayList; +import java.util.List; + +import tech.mcprison.prison.integration.CustomBlockIntegration; +import tech.mcprison.prison.internal.ItemStack; +import tech.mcprison.prison.internal.Player; +import tech.mcprison.prison.internal.block.Block; +import tech.mcprison.prison.internal.block.PrisonBlock; +import tech.mcprison.prison.internal.block.PrisonBlock.PrisonBlockType; +import tech.mcprison.prison.output.Output; +import tech.mcprison.prison.spigot.SpigotPrison; +import tech.mcprison.prison.spigot.SpigotUtil; +import tech.mcprison.prison.spigot.block.SpigotItemStack; +import tech.mcprison.prison.spigot.game.SpigotPlayer; +import tech.mcprison.prison.util.Location; + +public class PrisonItemsAdder + extends CustomBlockIntegration { + + private PrisonItemsAdderWrapper itemsAdderWrapper; + + public PrisonItemsAdder() { + super("ItemsAdder", "ItemsAdder", PrisonBlockType.ItemsAdder, "itemsadder:" ); + } + + + + + @Override + public void integrate() { + + // BluesSpigetSemVerComparator semVer = new BluesSpigetSemVerComparator(); + + if ( isRegistered()) { + try { + + this.itemsAdderWrapper = new PrisonItemsAdderWrapper(); + + + List prisonBlocks = getCustomBlockList(); + for ( PrisonBlock block : prisonBlocks ) + { + Output.get().logInfo( "#### Custom Block: " + block.toString() ); + } + + String message = String.format( + "Enabling ItemsAdder v%s custom blocks loaded: %d", + getVersion(), + prisonBlocks.size() ); + + Output.get().logInfo( "&7" + message + "enabled." ); + + + } + catch ( NoClassDefFoundError | IllegalStateException e ) { + // ignore this exception since it means the plugin was not loaded + } + catch ( Exception e ) { + e.printStackTrace(); + } + } + + } + + + @Override + public boolean hasIntegrated() { + return (itemsAdderWrapper != null); + } + + @Override + public String getCustomBlockId( Block block ) { + return itemsAdderWrapper.getCustomBlockId( block ); + } + + + public String getCustomBlockId( org.bukkit.block.Block spigotBlock ) { + + return itemsAdderWrapper.getCustomBlockId( spigotBlock ); + } + + /** + *

This function is supposed to identify if the given block is a custom block, and + * if it is a custom block, then this function will return the correct PrisonBlock + * to match it's type. The PrisonBlock that will be returned, will come from the + * collection of valid blocks that were generated upon server startup. + *

+ * + *

If there is no match, then this function will return a null. + *

+ * + *

It's also important to know that the original block that is retrieved from + * PrisonBlockTypes.getBlockTypesByName() is cloned prior to returning it to this + * function, so it's safe to do anything you want with it. + *

+ * + * @param block + * @return The matched and cloned PrisonBlock, otherwise it will return a null if no match. + */ + @Override + public PrisonBlock getCustomBlock( Block block ) { + PrisonBlock results = null; + + String customBlockId = getCustomBlockId( block ); + + if ( customBlockId != null ) { + results = SpigotPrison.getInstance().getPrisonBlockTypes() + .getBlockTypesByName( customBlockId ); + + if ( results != null ) { + + Location loc = new Location( block.getLocation() ); + results.setLocation( loc ); + } + } + + return results; + } + + public PrisonBlock getCustomBlock( org.bukkit.block.Block spigotBlock ) { + PrisonBlock results = null; + + String customBlockId = getCustomBlockId( spigotBlock ); + + if ( customBlockId != null ) { + results = SpigotPrison.getInstance().getPrisonBlockTypes() + .getBlockTypesByName( customBlockId ); + + if ( results != null ) { + Location loc = SpigotUtil.bukkitLocationToPrison( spigotBlock.getLocation() ); + + results.setLocation( loc ); + } + +// SpigotBlock sBlock = new SpigotBlock(); + } + + return results; + } + + + @Override + public Block setCustomBlockId( Block block, String customId, boolean doBlockUpdate ) { + return itemsAdderWrapper.setCustomBlockId( block, customId, doBlockUpdate ); + } + + + @Override + public void setCustomBlockIdAsync( PrisonBlock prisonBlock, Location location ) { + itemsAdderWrapper.setCustomBlockIdAsync( prisonBlock, location ); + } + + @Override + public List getDrops( Player player, PrisonBlock prisonBlock, ItemStack tool ) { + + SpigotPlayer sPlayer = player != null && player instanceof SpigotPlayer ? + (SpigotPlayer) player : null; + SpigotItemStack sTool = tool != null && tool instanceof SpigotItemStack ? + (SpigotItemStack) tool : null; + + List results = itemsAdderWrapper.getDrops( prisonBlock, sPlayer, sTool ); + + return results; + } + + @Override + public List getCustomBlockList() + { + List results = new ArrayList<>(); + + for ( String block : itemsAdderWrapper.getCustomBlockList() ) { + + PrisonBlock prisonBlock = new PrisonBlock( getBlockType(), block ); + + prisonBlock.setValid( true ); + prisonBlock.setBlock( true ); + + results.add( prisonBlock ); + } + + return results; + } + + + + @Override + public String getPluginSourceURL() { + return "https://polymart.org/resource/itemsadder-custom-items-etc.1851"; + } + + +} diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/customblock/PrisonItemsAdderWrapper.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/customblock/PrisonItemsAdderWrapper.java new file mode 100644 index 000000000..b327280e3 --- /dev/null +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/customblock/PrisonItemsAdderWrapper.java @@ -0,0 +1,249 @@ +package tech.mcprison.prison.spigot.customblock; + +import java.util.ArrayList; +import java.util.List; + +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.scheduler.BukkitRunnable; + +import dev.lone.itemsadder.api.CustomBlock; +import dev.lone.itemsadder.api.CustomStack; +import dev.lone.itemsadder.api.ItemsAdder; +import tech.mcprison.prison.autofeatures.AutoFeaturesFileConfig.AutoFeatures; +import tech.mcprison.prison.autofeatures.AutoFeaturesWrapper; +import tech.mcprison.prison.internal.block.Block; +import tech.mcprison.prison.internal.block.PrisonBlock; +import tech.mcprison.prison.internal.block.PrisonBlock.PrisonBlockType; +import tech.mcprison.prison.output.Output; +import tech.mcprison.prison.spigot.SpigotPrison; +import tech.mcprison.prison.spigot.block.SpigotBlock; +import tech.mcprison.prison.spigot.block.SpigotItemStack; +import tech.mcprison.prison.spigot.game.SpigotPlayer; +import tech.mcprison.prison.util.Location; + +public class PrisonItemsAdderWrapper { + + private boolean supportsDrops = false; + + private final SpigotPrison plugin; + + public PrisonItemsAdderWrapper() { + this.plugin = SpigotPrison.getInstance(); + } + + public String getCustomBlockId( Block block ) { + + org.bukkit.block.Block spigotBlock = ((SpigotBlock) block).getWrapper(); + + return getCustomBlockId( spigotBlock ); + //return CustomItemsAPI.getCustomItemIDAtBlock( spigotBlock ); + } + + public String getCustomBlockId( org.bukkit.block.Block spigotBlock ) { + + CustomBlock cBlock = CustomBlock.byAlreadyPlaced(spigotBlock); + + return ( cBlock == null ? null : cBlock.getDisplayName() ); + //return CustomItemsAPI.getCustomItemIDAtBlock( spigotBlock ); + } + + + /** + *

This should only be called when running in the bukkit synchronous thread. + *

+ * + * @param block + * @param customId + * @param doBlockUpdate + * @return + */ + public Block setCustomBlockId( Block block, String customId, boolean doBlockUpdate ) { + + String cBlockId = getCustomBlockId( block ); + + SpigotBlock sBlock = (SpigotBlock) block; + + CustomBlock cBlock = CustomBlock.place( cBlockId, sBlock.getWrapper().getLocation() ); + + return SpigotBlock.getSpigotBlock( cBlock.getBlock() ); + + +// org.bukkit.block.Block spigotBlock = ((SpigotBlock) block).getWrapper(); + + // So to prevent this from causing lag, we will only get back the block with no updates + // This will allow this function to exit: +// org.bukkit.block.Block resultBlock = +// CustomItemsAPI.setCustomItemIDAtBlock( spigotBlock, customId, doBlockUpdate ); + +// return SpigotBlock.getSpigotBlock( resultBlock ); + } + + + /** + *

This should only be ran through an asynchronous thread since it will submit a task + * on the bukkit synchronous thread to perform the actual update. This does not need to + * return a block. + *

+ * + * @param prisonBlock + * @param location + * @param doBlockUpdate + * @return + */ + public void setCustomBlockIdAsync( PrisonBlock prisonBlock, Location location ) + { + + new BukkitRunnable() { + @Override + public void run() { + + + String cBlockId = getCustomBlockId( prisonBlock ); + + SpigotBlock sBlock = (SpigotBlock) location.getBlockAt(); + + @SuppressWarnings("unused") + CustomBlock cBlock = CustomBlock.place( cBlockId, sBlock.getWrapper().getLocation() ); + + + // No physics update: + +// SpigotBlock sBlock = (SpigotBlock) location.getBlockAt(); +// +// org.bukkit.block.Block spigotBlock = sBlock.getWrapper(); + //org.bukkit.block.Block spigotBlock = ((SpigotBlock) prisonBlock).getWrapper(); + + // Request the block change, but we don't need the results so ignore it +// org.bukkit.block.Block resultBlock = +// CustomItemsAPI.setCustomItemIDAtBlock( spigotBlock, prisonBlock.getBlockName(), true ); + + } + }.runTaskLater( getPlugin(), 0 ); + + } + + /** + * + */ + public List getDrops( PrisonBlock prisonBlock, SpigotPlayer player, SpigotItemStack tool ) { + List results = new ArrayList<>(); + + if ( isSupportsDrops() && + AutoFeaturesWrapper.getInstance().isBoolean( AutoFeatures.isUseCustomBlocksCustomItemsGetDrops ) && + prisonBlock instanceof SpigotBlock ) { + + SpigotBlock sBlock = (SpigotBlock) prisonBlock; + + org.bukkit.block.Block bBlock = sBlock.getWrapper(); + Player bPlayer = player.getWrapper(); + ItemStack bTool = tool.getBukkitStack(); + + boolean includeSelfBlock = false; + + if ( bBlock != null && bTool != null ) { + + + + List drops = CustomBlock.getLoot( bBlock, bTool, includeSelfBlock ); + StringBuilder sb = new StringBuilder(); + + if ( drops != null ) { + + for (ItemStack iStack : drops ) { + SpigotItemStack sItemStack = new SpigotItemStack( iStack ); + + results.add( sItemStack ); + + sb.append( "[" ).append( sItemStack.toString() ).append( "]" ); + } + } + + + String message = String.format( + "PrisonItemsAdder.getDrops() results for block: %s " + + "player: %s tool: %s drops: %s ", + bBlock == null ? "null" : prisonBlock.getBlockName(), + bPlayer == null ? "null" : player.getName(), + bTool == null ? "null" : bTool.toString(), + sb.toString() + ); + + Output.get().logDebug( message ); + } + else { + if ( Output.get().isDebug() ) { + String message = String.format( + "PrisonItemsAdder.getDrops(): failed to provide non-null inputs. " + + "block: %s player: %s tool: %s", + bBlock == null ? "null" : prisonBlock.getBlockName(), + bPlayer == null ? "null" : player.getName(), + bTool == null ? "null" : tool.getName() + ); + + Output.get().logDebug( message ); + } + } + + } + + if ( results.size() == 0 ) { + + String itemsAdderBlockId = getCustomBlockId( prisonBlock ); + + org.bukkit.inventory.ItemStack bItemStack = + CustomBlock.getInstance( itemsAdderBlockId ).getItemStack(); + + SpigotItemStack sItemStack = new SpigotItemStack( bItemStack ); + + // Fix itemStack's displayName and set to the correct BlockType: + sItemStack.setPrisonBlock( prisonBlock ); + + results.add( sItemStack ); + } + + return results; + } + + + public List getCustomBlockList() { + List customList = new ArrayList<>(); + +// List customListx = new ArrayList<>( CustomBlock.getNamespacedIdsInRegistry() ); + + + List allItems = ItemsAdder.getAllItems(); + + for ( CustomStack cStack : allItems ) { + if ( cStack.isBlock() ) { + String namespace = cStack.getNamespacedID(); + String name = cStack.getDisplayName(); + + Output.get().logDebug( + "ItemsAdder: namespacedID: %s displayName: %s PrisonBlock: %s:%s", + namespace, + name, + PrisonBlockType.ItemsAdder, + name + ); + + customList.add( namespace ); + } + } + + return customList; + } + + public SpigotPrison getPlugin() { + return plugin; + } + + public boolean isSupportsDrops() { + return supportsDrops; + } + public void setSupportsDrops(boolean supportsDrops) { + this.supportsDrops = supportsDrops; + } + + +} diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/economies/EssEconomyWrapper.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/economies/EssEconomyWrapper.java index ff19a4a2f..b1cf349d8 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/economies/EssEconomyWrapper.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/economies/EssEconomyWrapper.java @@ -9,7 +9,29 @@ import tech.mcprison.prison.internal.Player; /** - * A non-static wrapper of Essentials' annoyingly static {@link net.ess3.api.Economy} API. + *

A non-static wrapper of Essentials' annoyingly static {@link net.ess3.api.Economy} API. + *

+ * + *

Warning: There is a known issue with essentials where internally + * they are generating a NPE when trying it initially look up + * a player when their names do not match, or their UUIDs have + * been changed due to changing to an offline server. Basically + * it's an issue that has been troubling essentials for a while + * now (a few years), so they are internally generating a + * stack trace when they detect a certain condition. This + * stack trace is not able to be caught and suppressed by Prison, + * so as such, it may appear frequently within the servers + * console. The bottom line is that essentials still works + * even through they are generating this stack trace (they want + * to log a certain kind of condition) and prison still works. + * It just produces a ton of confusing garbage. It is unknown + * when they will fix their code and remove it. + *

+ * + *

View this issue 3956 with the comment title: "Problem: EssentialsX is flooding + * my console with UUID errors!" + * https://github.com/EssentialsX/Essentials/issues/3956 + *

* * @author Faizaan A. Datoo */ diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/economies/VaultEconomyWrapper.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/economies/VaultEconomyWrapper.java index ae0f20c35..b34c0f9a8 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/economies/VaultEconomyWrapper.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/economies/VaultEconomyWrapper.java @@ -7,6 +7,7 @@ import org.bukkit.plugin.RegisteredServiceProvider; import net.milkbowl.vault.economy.EconomyResponse; +import tech.mcprison.prison.Prison; import tech.mcprison.prison.internal.Player; import tech.mcprison.prison.output.Output; import tech.mcprison.prison.spigot.SpigotUtil; @@ -208,7 +209,7 @@ else if (economy != null) { results = response.transactionSuccess(); if ( !results ) { - DecimalFormat dFmt = new DecimalFormat("#,##0.00"); + DecimalFormat dFmt = Prison.get().getDecimalFormat("#,##0.00"); String message = String.format( "VaultEconomy.addBalance failed: %s amount: %s " + "balance: %s error: %s", @@ -256,7 +257,7 @@ public boolean removeBalance(Player player, double amount) { results = response.transactionSuccess(); if ( !results ) { - DecimalFormat dFmt = new DecimalFormat("#,##0.00"); + DecimalFormat dFmt = Prison.get().getDecimalFormat("#,##0.00"); String message = String.format( "VaultEconomy.removeBalance failed: %s amount: %s " + "balance: %s error: %s", diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/game/SpigotOfflinePlayer.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/game/SpigotOfflinePlayer.java index ac9f715c6..758ca41a6 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/game/SpigotOfflinePlayer.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/game/SpigotOfflinePlayer.java @@ -18,12 +18,16 @@ import tech.mcprison.prison.internal.inventory.Inventory; import tech.mcprison.prison.internal.scoreboard.Scoreboard; import tech.mcprison.prison.output.Output; +import tech.mcprison.prison.ranks.PrisonRanks; +import tech.mcprison.prison.ranks.data.RankPlayer; import tech.mcprison.prison.util.Gamemode; import tech.mcprison.prison.util.Location; public class SpigotOfflinePlayer implements OfflineMcPlayer { + private RankPlayer rankPlayer; + private OfflinePlayer offlinePlayer; public SpigotOfflinePlayer(OfflinePlayer offlinePlayer) { @@ -324,6 +328,13 @@ public void setTitle( String title, String subtitle, int fadeIn, int stay, int f public void setActionBar( String actionBar ) { } + public RankPlayer getRankPlayer() { + if ( rankPlayer == null ) { + rankPlayer = PrisonRanks.getInstance().getPlayerManager().getPlayer( this ); + } + return rankPlayer; + } + @Override public PlayerCache getPlayerCache() { return PlayerCache.getInstance(); diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/game/SpigotWorld.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/game/SpigotWorld.java index dd11d45d9..fc899a239 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/game/SpigotWorld.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/game/SpigotWorld.java @@ -161,6 +161,61 @@ public void setBlocksSynchronously( List tBlocks, MineRes } + +// public String getBlockSignature( Location location ) { +// String results = null; +// +// if ( getWrapper() != null ) { +// +// SpigotBlock block = (SpigotBlock) getBlockAt( location ); +// +// StringBuilder sb = new StringBuilder(); +// sb.append( block.getWrapper().getType().name() ) +// .append( ":" ) +//// .append( location.toWorldCoordinates() ) +//// .append( "::" ) +// .append( block.getWrapper().getBlockData() ); +// +// results = sb.toString(); +// } +// +// return results; +// } + +// public void getTestBlock() { +// +// PrisonNBTUtil nbtUtil = new PrisonNBTUtil(); +// +// NBTItem nbtItemStack = nbtUtil.getNBT( bstack ); +// +// nbtItemStack. +// } + +// public void setBlockFromString( String blockString, Location location ) { +// +// String[] parts = blockString.split("::"); +// String blockNameFormal = parts[0]; +// String worldCoordinates = parts[1]; +// String blockData = parts[2]; +// +// Location targetLocation = location; +// if ( targetLocation == null ) { +// targetLocation = Location.decodeWorldCoordinates(worldCoordinates); +// } +// +// SpigotBlock block = (SpigotBlock) getBlockAt( targetLocation ); +// +// Prison.get().getPlatform().getPrisonBlock(blockNameFormal); +//// block.setType(Material.getMaterial(parts[0])); +// +// BlockData targetBlockData = +// SpigotPrison.getInstance().getServer().createBlockData( blockData ); +// +// block.getWrapper().setBlockData( targetBlockData ); +// +// } + + public org.bukkit.World getWrapper() { return bukkitWorld; } diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/ListenersPrisonManager.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/ListenersPrisonManager.java index 1bc40011e..cb91343e8 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/ListenersPrisonManager.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/ListenersPrisonManager.java @@ -25,9 +25,6 @@ import com.cryptomorin.xseries.XMaterial; import tech.mcprison.prison.Prison; -import tech.mcprison.prison.autofeatures.AutoFeaturesFileConfig; -import tech.mcprison.prison.autofeatures.AutoFeaturesFileConfig.AutoFeatures; -import tech.mcprison.prison.autofeatures.AutoFeaturesWrapper; import tech.mcprison.prison.mines.PrisonMines; import tech.mcprison.prison.mines.data.Mine; import tech.mcprison.prison.modules.Module; @@ -46,14 +43,9 @@ import tech.mcprison.prison.spigot.compat.SpigotCompatibility; import tech.mcprison.prison.spigot.configs.MessagesConfig; import tech.mcprison.prison.spigot.game.SpigotPlayer; -import tech.mcprison.prison.spigot.gui.autofeatures.SpigotAutoBlockGUI; -import tech.mcprison.prison.spigot.gui.autofeatures.SpigotAutoFeaturesGUI; -import tech.mcprison.prison.spigot.gui.autofeatures.SpigotAutoPickupGUI; -import tech.mcprison.prison.spigot.gui.autofeatures.SpigotAutoSmeltGUI; import tech.mcprison.prison.spigot.gui.backpacks.BackpacksAdminGUI; import tech.mcprison.prison.spigot.gui.backpacks.BackpacksAdminListGUI; import tech.mcprison.prison.spigot.gui.backpacks.BackpacksAdminPlayerListGUI; -import tech.mcprison.prison.spigot.gui.guiutility.SpigotGUIComponents; import tech.mcprison.prison.spigot.gui.mine.SpigotBlocksListGUI; import tech.mcprison.prison.spigot.gui.mine.SpigotBlocksMineListGUI; import tech.mcprison.prison.spigot.gui.mine.SpigotMineBlockPercentageGUI; @@ -69,6 +61,7 @@ import tech.mcprison.prison.spigot.gui.rank.SpigotRankPriceGUI; import tech.mcprison.prison.spigot.gui.rank.SpigotRankUPCommandsGUI; import tech.mcprison.prison.spigot.gui.rank.SpigotRanksGUI; +import tech.mcprison.prison.spigot.gui.rank.SpigotGUIMessages; import tech.mcprison.prison.spigot.gui.sellall.SellAllAdminAutoSellGUI; import tech.mcprison.prison.spigot.gui.sellall.SellAllAdminBlocksGUI; import tech.mcprison.prison.spigot.gui.sellall.SellAllAdminGUI; @@ -77,13 +70,16 @@ import tech.mcprison.prison.spigot.gui.sellall.SellAllPrestigesSetMultiplierGUI; import tech.mcprison.prison.spigot.gui.sellall.SellAllPriceGUI; import tech.mcprison.prison.spigot.sellall.SellAllUtil; +import tech.mcprison.prison.spigot.utils.tasks.PlayerAutoRankupTask; import tech.mcprison.prison.util.Text; /** * @author GABRYCA * @author RoyalBlueRanger */ -public class ListenersPrisonManager implements Listener { +public class ListenersPrisonManager + extends SpigotGUIMessages + implements Listener { private static ListenersPrisonManager instance; public static List activeGui = new ArrayList<>(); @@ -103,7 +99,7 @@ public class ListenersPrisonManager implements Listener { public enum ChatMode{ RankName, MineName, - Prestige, +// Prestige, SellAll_Currency } @@ -212,9 +208,17 @@ public void onPlayerInteractEvent(PlayerInteractEvent e){ for (XMaterial xMaterialConf : items) { if (xMaterialConf == inHandXMaterial) { sellAllUtil.sellAllSell(p, false, false, true, false, false, true); + + SpigotPlayer sPlayer = new SpigotPlayer( p ); + PlayerAutoRankupTask.autoSubmitPlayerRankupTask( sPlayer, null ); + return; } else if (xMaterialConf == SpigotUtil.getXMaterial(p.getInventory().getItemInMainHand().getType())) { sellAllUtil.sellAllSell(p, false, false, true, false, false, true); + + SpigotPlayer sPlayer = new SpigotPlayer( p ); + PlayerAutoRankupTask.autoSubmitPlayerRankupTask( sPlayer, null ); + return; } } @@ -833,7 +837,8 @@ private void backpacksList(Player p, String buttonNameMain, String[] parts) { } } else if (buttonNameMain.equalsIgnoreCase("Backpack")){ - BackpacksUtil.get().openBackpack(p); + String id = null; + BackpacksUtil.get().openBackpack(p, id); } else { BackpacksUtil.get().openBackpack(p, buttonNameMain.substring(9)); } @@ -1275,7 +1280,7 @@ private void sellAllAdminGUI(InventoryClickEvent e, Player p, String buttonNameM } else { if (sellAllConfig.getConfigurationSection("Multiplier").getKeys(false).size() == 0) { - Output.get().sendWarn(new SpigotPlayer(p), messages.getString(MessagesConfig.StringID.spigot_message_gui_error_empty)); + guiRanksErrorEmptyMsg( new SpigotPlayer(p) ); e.setCancelled(true); return; } else { @@ -1806,25 +1811,53 @@ private void playerPrestigesGUI(InventoryClickEvent e, Player p, String buttonNa private void prestigeConfirmationGUI(InventoryClickEvent e, Player p, String buttonNameMain) { + String playerName = p.getName(); + // Check the button name and do the actions. if (buttonNameMain.equalsIgnoreCase("Confirm: Prestige")){ - Output.get().logDebug( DebugTarget.rankup, "rankup: GUI: 'Confirm: Prestige' calling: '/rankup prestiges'" ); + + Output.get().logDebug( DebugTarget.rankup, "rankup: /gui prestigeConfirm: Prestige has been Confirmed. " + + " calling: '/prestige " + playerName + " confirm'" ); // Execute the command. - String registeredCmd = Prison.get().getCommandHandler().findRegisteredCommand( "rankup" ); - - Bukkit.dispatchCommand(p, registeredCmd + " prestiges"); - // Close the inventory. - p.closeInventory(); - } else if (buttonNameMain.equalsIgnoreCase("Cancel: Don't Prestige")){ - Output.get().logDebug( DebugTarget.rankup, "rankup: GUI/: 'Cancel: Don't Prestige' sendInfo: 'cancelled'" ); + String registeredCmd = Prison.get().getCommandHandler().findRegisteredCommand( "prestige" ); + String command = registeredCmd + " " + playerName + " confirm"; + + Bukkit.dispatchCommand(p, command ); + + } + else if (buttonNameMain.equalsIgnoreCase("Cancel: Don't Prestige")){ + + Output.get().logDebug( DebugTarget.rankup, "rankup: /gui prestigeConfirm: Prestige has been canceled " + + "for " + playerName + "." ); + // Send a message to the player. - Output.get().sendInfo(new SpigotPlayer(p), "&cCancelled"); - // Close the inventory. - p.closeInventory(); +// Output.get().sendInfo(new SpigotPlayer(p), "&cCancelled"); } + // Close the inventory. + p.closeInventory(); + +// // Check the button name and do the actions. +// if (buttonNameMain.equalsIgnoreCase("Confirm: Prestige")){ +// Output.get().logDebug( DebugTarget.rankup, "rankup: GUI: 'Confirm: Prestige' calling: '/rankup prestiges'" ); +// +// // Execute the command. +// String registeredCmd = Prison.get().getCommandHandler().findRegisteredCommand( "rankup" ); +// +// Bukkit.dispatchCommand(p, registeredCmd + " prestiges"); +// // Close the inventory. +// p.closeInventory(); +// } else if (buttonNameMain.equalsIgnoreCase("Cancel: Don't Prestige")){ +// Output.get().logDebug( DebugTarget.rankup, "rankup: GUI/: 'Cancel: Don't Prestige' sendInfo: 'cancelled'" ); +// +// // Send a message to the player. +// Output.get().sendInfo(new SpigotPlayer(p), "&cCancelled"); +// // Close the inventory. +// p.closeInventory(); +// } +// // Cancel the event. e.setCancelled(true); } @@ -2843,10 +2876,10 @@ private void radiusGUI(InventoryClickEvent e, Player p, String[] parts) { private void modeAction(AsyncPlayerChatEvent e, Player p, String message) { switch(mode){ - case Prestige:{ - prestigeAction(e, p, message); - break; - } +// case Prestige:{ +// prestigeAction(e, p, message); +// break; +// } case SellAll_Currency:{ sellAllCurrencyChat(e, p, message); break; @@ -2883,21 +2916,21 @@ private void sellAllCurrencyChat(AsyncPlayerChatEvent e, Player p, String messag isChatEventActive = false; } - private void prestigeAction(AsyncPlayerChatEvent e, Player p, String message) { - - // Check the chat message and do the actions - if (message.equalsIgnoreCase("cancel")) { - Output.get().sendInfo(new SpigotPlayer(p), messages.getString(MessagesConfig.StringID.spigot_message_prestiges_cancelled)); - } else if (message.equalsIgnoreCase("confirm")) { - Bukkit.getScheduler().runTask(SpigotPrison.getInstance(), () -> Bukkit.getServer().dispatchCommand(p, "rankup prestiges")); - } else { - Output.get().sendInfo(new SpigotPlayer(p), messages.getString(MessagesConfig.StringID.spigot_message_prestiges_cancelled_wrong_keyword)); - } - // Cancel the event - e.setCancelled(true); - // Set the event to false, because it got deactivated - isChatEventActive = false; - } +// private void prestigeAction(AsyncPlayerChatEvent e, Player p, String message) { +// +// // Check the chat message and do the actions +// if (message.equalsIgnoreCase("cancel")) { +// Output.get().sendInfo(new SpigotPlayer(p), messages.getString(MessagesConfig.StringID.spigot_message_prestiges_cancelled)); +// } else if (message.equalsIgnoreCase("confirm")) { +// Bukkit.getScheduler().runTask(SpigotPrison.getInstance(), () -> Bukkit.getServer().dispatchCommand(p, "rankup prestiges")); +// } else { +// Output.get().sendInfo(new SpigotPlayer(p), messages.getString(MessagesConfig.StringID.spigot_message_prestiges_cancelled_wrong_keyword)); +// } +// // Cancel the event +// e.setCancelled(true); +// // Set the event to false, because it got deactivated +// isChatEventActive = false; +// } private void mineAction(AsyncPlayerChatEvent e, Player p, String message) { diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/SpigotGUIMenuTools.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/SpigotGUIMenuTools.java index 7067f1439..e5279fe08 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/SpigotGUIMenuTools.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/SpigotGUIMenuTools.java @@ -27,6 +27,9 @@ public class SpigotGUIMenuTools public static final String GUI_MENU_TOOLS_NBT_ENABLED = "guiNBT"; public static final String GUI_MENU_TOOLS_NBT_COMMAND = "guiNBTCommand"; + + public static final String GUI_MENU_TOOLS_NBT_RANK_NAME = "guiNBTRankName"; + public static final String GUI_MENU_TOOLS_NBT_MINE_NAME = "guiNBTMineName"; private static SpigotGUIMenuTools instance; diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/backpacks/BackpacksAdminListGUI.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/backpacks/BackpacksAdminListGUI.java index 8a7603317..ee74a5f76 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/backpacks/BackpacksAdminListGUI.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/backpacks/BackpacksAdminListGUI.java @@ -1,29 +1,31 @@ package tech.mcprison.prison.spigot.gui.backpacks; -import com.cryptomorin.xseries.XMaterial; +import java.util.Set; + import org.bukkit.configuration.Configuration; import org.bukkit.entity.Player; + +import com.cryptomorin.xseries.XMaterial; + import tech.mcprison.prison.spigot.backpacks.BackpacksUtil; -import tech.mcprison.prison.spigot.configs.MessagesConfig; import tech.mcprison.prison.spigot.gui.guiutility.Button; import tech.mcprison.prison.spigot.gui.guiutility.ButtonLore; import tech.mcprison.prison.spigot.gui.guiutility.PrisonGUI; -import tech.mcprison.prison.spigot.gui.guiutility.SpigotGUIComponents; - -import java.util.Set; +import tech.mcprison.prison.spigot.gui.rank.SpigotGUIMessages; /** * @author AnonymousGCA (GABRYCA) * */ -public class BackpacksAdminListGUI extends SpigotGUIComponents { +public class BackpacksAdminListGUI + extends SpigotGUIMessages { private final Player p; private final String playerBackpackName; private final Configuration backpacksData = BackpacksUtil.get().getBackpacksData(); private final String loreShiftAndRightClickToDelete = guiRightClickShiftToDeleteMsg(); - private final String loreInfo = messages.getString(MessagesConfig.StringID.spigot_gui_lore_info); - private final String lorePlayerOwner = messages.getString(MessagesConfig.StringID.spigot_gui_lore_owner); - private final String loreBackpackID = messages.getString(MessagesConfig.StringID.spigot_gui_lore_backpack_id); + private final String loreInfo = guiRanksLoreInfoMsg(); + private final String lorePlayerOwner = guiRanksLoreOwnerMsg(); + private final String loreBackpackID = guiRanksLoreBackpackIdMsg(); public BackpacksAdminListGUI(Player p, String playerBackpackName){ this.p = p; diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/mine/SpigotBlocksListGUI.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/mine/SpigotBlocksListGUI.java index a8980a93b..8261be131 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/mine/SpigotBlocksListGUI.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/mine/SpigotBlocksListGUI.java @@ -10,16 +10,16 @@ import tech.mcprison.prison.internal.block.PrisonBlock; import tech.mcprison.prison.internal.block.PrisonBlockTypes; import tech.mcprison.prison.spigot.SpigotUtil; -import tech.mcprison.prison.spigot.configs.MessagesConfig; import tech.mcprison.prison.spigot.gui.guiutility.Button; import tech.mcprison.prison.spigot.gui.guiutility.ButtonLore; import tech.mcprison.prison.spigot.gui.guiutility.PrisonGUI; -import tech.mcprison.prison.spigot.gui.guiutility.SpigotGUIComponents; +import tech.mcprison.prison.spigot.gui.rank.SpigotGUIMessages; /** * @author GABRYCA */ -public class SpigotBlocksListGUI extends SpigotGUIComponents { +public class SpigotBlocksListGUI + extends SpigotGUIMessages { private final Player p; private final String mineName; @@ -40,7 +40,7 @@ public void open(){ // Create the inventory PrisonGUI gui = new PrisonGUI(p, dimension, "&3Mines -> BlocksList"); - ButtonLore lore = new ButtonLore(messages.getString(MessagesConfig.StringID.spigot_gui_lore_click_to_start_block_setup), null); + ButtonLore lore = new ButtonLore(guiRanksLoreClickToStartBlockSetupMsg(), null); // This will skip all BlockTypes that are invalid for the versions of MC that the server is running: PrisonBlockTypes prisonBlockTypes = Prison.get().getPlatform().getPrisonBlockTypes(); diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/mine/SpigotBlocksMineListGUI.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/mine/SpigotBlocksMineListGUI.java index 039035bd3..66a36c883 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/mine/SpigotBlocksMineListGUI.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/mine/SpigotBlocksMineListGUI.java @@ -1,23 +1,25 @@ package tech.mcprison.prison.spigot.gui.mine; -import com.cryptomorin.xseries.XMaterial; +import java.util.List; + import org.bukkit.entity.Player; + +import com.cryptomorin.xseries.XMaterial; + import tech.mcprison.prison.Prison; import tech.mcprison.prison.internal.block.PrisonBlock; import tech.mcprison.prison.internal.block.PrisonBlockTypes; import tech.mcprison.prison.spigot.SpigotUtil; -import tech.mcprison.prison.spigot.configs.MessagesConfig; import tech.mcprison.prison.spigot.gui.guiutility.Button; import tech.mcprison.prison.spigot.gui.guiutility.ButtonLore; import tech.mcprison.prison.spigot.gui.guiutility.PrisonGUI; -import tech.mcprison.prison.spigot.gui.guiutility.SpigotGUIComponents; - -import java.util.List; +import tech.mcprison.prison.spigot.gui.rank.SpigotGUIMessages; /** * @author GABRYCA */ -public class SpigotBlocksMineListGUI extends SpigotGUIComponents { +public class SpigotBlocksMineListGUI + extends SpigotGUIMessages { private final Player p; private final String mineName; @@ -38,7 +40,7 @@ public void open(){ // Create the inventory PrisonGUI gui = new PrisonGUI(p, dimension, "&3Select -> ShowBlock"); - ButtonLore lore = new ButtonLore(messages.getString(MessagesConfig.StringID.spigot_gui_lore_click_to_select), null); + ButtonLore lore = new ButtonLore( guiRanksLoreClickToSelectMsg(), null); // This will skip all BlockTypes that are invalid for the versions of MC that the server is running: PrisonBlockTypes prisonBlockTypes = Prison.get().getPlatform().getPrisonBlockTypes(); diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/mine/SpigotMineBlockPercentageGUI.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/mine/SpigotMineBlockPercentageGUI.java index 57a80989c..f37b2dfb2 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/mine/SpigotMineBlockPercentageGUI.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/mine/SpigotMineBlockPercentageGUI.java @@ -6,16 +6,16 @@ import tech.mcprison.prison.internal.block.PrisonBlock; import tech.mcprison.prison.spigot.SpigotUtil; -import tech.mcprison.prison.spigot.configs.MessagesConfig; import tech.mcprison.prison.spigot.gui.guiutility.Button; import tech.mcprison.prison.spigot.gui.guiutility.ButtonLore; import tech.mcprison.prison.spigot.gui.guiutility.PrisonGUI; -import tech.mcprison.prison.spigot.gui.guiutility.SpigotGUIComponents; +import tech.mcprison.prison.spigot.gui.rank.SpigotGUIMessages; /** * @author GABRYCA (AnonymousGCA) */ -public class SpigotMineBlockPercentageGUI extends SpigotGUIComponents { +public class SpigotMineBlockPercentageGUI + extends SpigotGUIMessages { private final Player p; private final String mineName; @@ -40,7 +40,7 @@ public void open() { ButtonLore confirmButtonLore = new ButtonLore(createLore( guiClickToConfirmMsg(), guiRightClickToCancelMsg() ), - createLore(messages.getString(MessagesConfig.StringID.spigot_gui_lore_percentage) + " " + val)); + createLore( guiRanksLorePercentageMsg() + " " + val)); ButtonLore changeIncreaseValueLore = new ButtonLore( guiClickToIncreaseMsg(), null); diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/mine/SpigotMineInfoGUI.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/mine/SpigotMineInfoGUI.java index e4d5dc642..858c17949 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/mine/SpigotMineInfoGUI.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/mine/SpigotMineInfoGUI.java @@ -6,18 +6,18 @@ import tech.mcprison.prison.mines.data.Mine; import tech.mcprison.prison.spigot.SpigotUtil; -import tech.mcprison.prison.spigot.configs.MessagesConfig; import tech.mcprison.prison.spigot.gui.SpigotGUIMenuTools; import tech.mcprison.prison.spigot.gui.SpigotGUIMenuTools.GUIMenuPageData; import tech.mcprison.prison.spigot.gui.guiutility.Button; import tech.mcprison.prison.spigot.gui.guiutility.ButtonLore; import tech.mcprison.prison.spigot.gui.guiutility.PrisonGUI; -import tech.mcprison.prison.spigot.gui.guiutility.SpigotGUIComponents; +import tech.mcprison.prison.spigot.gui.rank.SpigotGUIMessages; /** * @author GABRYCA */ -public class SpigotMineInfoGUI extends SpigotGUIComponents { +public class SpigotMineInfoGUI + extends SpigotGUIMessages { private final Player p; private final Mine mine; @@ -43,29 +43,36 @@ public void open(){ guiLeftClickToResetMsg(), guiRightClickToToggleMsg(), guiRightClickShiftToToggleMsg() ), - createLore(messages.getString(MessagesConfig.StringID.spigot_gui_lore_skip_reset_instruction_1), - messages.getString(MessagesConfig.StringID.spigot_gui_lore_skip_reset_instruction_2), - messages.getString(MessagesConfig.StringID.spigot_gui_lore_skip_reset_instruction_3), + createLore( + guiRanksLoreSkipResetInstruction1Msg(), + guiRanksLoreSkipResetInstruction2Msg(), + guiRanksLoreSkipResetInstruction3Msg(), "", - messages.getString(MessagesConfig.StringID.spigot_gui_lore_set_mine_delay_instruction_1), - messages.getString(MessagesConfig.StringID.spigot_gui_lore_set_mine_delay_instruction_2), - messages.getString(MessagesConfig.StringID.spigot_gui_lore_set_mine_delay_instruction_3))); + guiRanksLoreSetMineDelayInstruction1Msg(), + guiRanksLoreSetMineDelayInstruction2Msg(), + guiRanksLoreSetMineDelayInstruction3Msg() )); - ButtonLore mineSpawnLore = new ButtonLore(messages.getString(MessagesConfig.StringID.spigot_gui_lore_click_to_use), messages.getString(MessagesConfig.StringID.spigot_gui_lore_spawnpoint)); + ButtonLore mineSpawnLore = new ButtonLore( + guiRanksLoreClickToUseMsg(), + guiRanksLoreSpawnPointMsg()); ButtonLore minesNotificationsLore = new ButtonLore( guiClickToOpenMsg(), guiClickToEditMsg() ); - ButtonLore minesTpLore = new ButtonLore(messages.getString(MessagesConfig.StringID.spigot_gui_lore_click_to_teleport), messages.getString(MessagesConfig.StringID.spigot_gui_lore_tp_to_mine)); + ButtonLore minesTpLore = new ButtonLore( + guiRanksLoreClickToTeleportMsg(), + guiRanksLoreTpToMineMsg() ); ButtonLore blocksOfTheMineLore = new ButtonLore( guiClickToOpenMsg(), - messages.getString(MessagesConfig.StringID.spigot_gui_lore_blocks)); + guiRanksLoreBlocksMsg()); ButtonLore mineResetTimeLore = new ButtonLore(createLore( guiClickToOpenMsg() ), createLore( - messages.getString(MessagesConfig.StringID.spigot_gui_lore_reset_time) + " &7" + mine.getResetTime())); + guiRanksLoreResetTimeMsg() + " &7" + mine.getResetTime())); - ButtonLore mineRenameLore = new ButtonLore(messages.getString(MessagesConfig.StringID.spigot_gui_lore_click_to_rename), messages.getString(MessagesConfig.StringID.spigot_gui_lore_minename) + " " + mineName); + ButtonLore mineRenameLore = new ButtonLore( + guiRanksLoreClickToRenameMsg(), + guiRanksLoreMineNameMsg() + " " + mineName); // ButtonLore closeGUILore = new ButtonLore(messages.getString(MessagesConfig.StringID.spigot_gui_lore_click_to_close), null); // Create the button, set the material, amount, lore and name @@ -91,10 +98,10 @@ public void open(){ // Lore ButtonLore mineShowItemLore = new ButtonLore(createLore( guiClickToEditMsg() ), createLore( - messages.getString(MessagesConfig.StringID.spigot_gui_lore_show_item) + " &7" + xMaterial.name(), - messages.getString(MessagesConfig.StringID.spigot_gui_lore_show_item_description_1), - messages.getString(MessagesConfig.StringID.spigot_gui_lore_show_item_description_2), - messages.getString(MessagesConfig.StringID.spigot_gui_lore_show_item_description_3) + guiRanksLoreShowItemMsg() + " &7" + xMaterial.name(), + guiRanksLoreShowItemDescription1Msg(), + guiRanksLoreShowItemDescription2Msg(), + guiRanksLoreShowItemDescription3Msg() )); // ItemStack diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/mine/SpigotMineNotificationRadiusGUI.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/mine/SpigotMineNotificationRadiusGUI.java index 962d0169e..3ea9a531a 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/mine/SpigotMineNotificationRadiusGUI.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/mine/SpigotMineNotificationRadiusGUI.java @@ -1,17 +1,19 @@ package tech.mcprison.prison.spigot.gui.mine; -import com.cryptomorin.xseries.XMaterial; import org.bukkit.entity.Player; -import tech.mcprison.prison.spigot.configs.MessagesConfig; + +import com.cryptomorin.xseries.XMaterial; + import tech.mcprison.prison.spigot.gui.guiutility.Button; import tech.mcprison.prison.spigot.gui.guiutility.ButtonLore; import tech.mcprison.prison.spigot.gui.guiutility.PrisonGUI; -import tech.mcprison.prison.spigot.gui.guiutility.SpigotGUIComponents; +import tech.mcprison.prison.spigot.gui.rank.SpigotGUIMessages; /** * @author GABRYCA (AnonymousGCA) */ -public class SpigotMineNotificationRadiusGUI extends SpigotGUIComponents { +public class SpigotMineNotificationRadiusGUI + extends SpigotGUIMessages { private final Player p; private final String mineName; @@ -36,7 +38,7 @@ public void open() { ButtonLore confirmButtonLore = new ButtonLore(createLore( guiLeftClickToConfirmMsg() ), createLore( - messages.getString(MessagesConfig.StringID.spigot_gui_lore_radius) + " " + val, + guiRanksLoreRadiusMsg() + " " + val, guiRightClickToCancelMsg() )); ButtonLore changeIncreaseValueLore = new ButtonLore( guiClickToIncreaseMsg(), null); diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/mine/SpigotMineNotificationsGUI.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/mine/SpigotMineNotificationsGUI.java index 90368b47a..56f26608a 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/mine/SpigotMineNotificationsGUI.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/mine/SpigotMineNotificationsGUI.java @@ -7,16 +7,16 @@ import tech.mcprison.prison.mines.PrisonMines; import tech.mcprison.prison.mines.data.Mine; -import tech.mcprison.prison.spigot.configs.MessagesConfig; import tech.mcprison.prison.spigot.gui.guiutility.Button; import tech.mcprison.prison.spigot.gui.guiutility.ButtonLore; import tech.mcprison.prison.spigot.gui.guiutility.PrisonGUI; -import tech.mcprison.prison.spigot.gui.guiutility.SpigotGUIComponents; +import tech.mcprison.prison.spigot.gui.rank.SpigotGUIMessages; /** * @author GABRYCA */ -public class SpigotMineNotificationsGUI extends SpigotGUIComponents { +public class SpigotMineNotificationsGUI + extends SpigotGUIMessages { private final Player p; private final String mineName; @@ -37,9 +37,12 @@ public void open() { Mine m = pMines.getMine(mineName); String enabledOrDisabled = m.getNotificationMode().name(); - ButtonLore modeWithinLore = new ButtonLore(messages.getString(MessagesConfig.StringID.spigot_gui_lore_click_to_select), messages.getString(MessagesConfig.StringID.spigot_gui_lore_enable_within_mode)); - ButtonLore modeRadiusLore = new ButtonLore(messages.getString(MessagesConfig.StringID.spigot_gui_lore_click_to_select), messages.getString(MessagesConfig.StringID.spigot_gui_lore_enable_radius_mode)); - ButtonLore disabledModeLore = new ButtonLore(messages.getString(MessagesConfig.StringID.spigot_gui_lore_click_to_select), messages.getString(MessagesConfig.StringID.spigot_gui_lore_disable_notifications)); + ButtonLore modeWithinLore = new ButtonLore( + guiRanksLoreClickToSelectMsg(), guiRanksLoreEnableWithinModeMsg() ); + ButtonLore modeRadiusLore = new ButtonLore( + guiRanksLoreClickToSelectMsg(), guiRanksLoreEnableRadiusModeMsg() ); + ButtonLore disabledModeLore = new ButtonLore( + guiRanksLoreClickToSelectMsg(), guiRanksLoreDisableNotificationsMsg() ); ButtonLore closeGUILore = new ButtonLore( guiClickToCloseMsg(), null); // Add button. @@ -49,17 +52,17 @@ public void open() { if (enabledOrDisabled.equalsIgnoreCase("disabled")){ // Add the selected lore - disabledModeLore.addLineLoreDescription( messages.getString(MessagesConfig.StringID.spigot_gui_lore_selected) ); + disabledModeLore.addLineLoreDescription( guiRanksLoreSelecteMsg() ); } else if (enabledOrDisabled.equalsIgnoreCase("within")){ // Add the selected lore - modeWithinLore.addLineLoreDescription( messages.getString(MessagesConfig.StringID.spigot_gui_lore_selected) ); + modeWithinLore.addLineLoreDescription( guiRanksLoreSelecteMsg() ); } else if (enabledOrDisabled.equalsIgnoreCase("radius")){ // Add the selected lore - modeRadiusLore.addLineLoreDescription( messages.getString(MessagesConfig.StringID.spigot_gui_lore_selected) ); + modeRadiusLore.addLineLoreDescription( guiRanksLoreSelecteMsg() ); } diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/mine/SpigotMineResetTimeGUI.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/mine/SpigotMineResetTimeGUI.java index 4fd611bbb..8d9295c04 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/mine/SpigotMineResetTimeGUI.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/mine/SpigotMineResetTimeGUI.java @@ -1,17 +1,19 @@ package tech.mcprison.prison.spigot.gui.mine; -import com.cryptomorin.xseries.XMaterial; import org.bukkit.entity.Player; -import tech.mcprison.prison.spigot.configs.MessagesConfig; + +import com.cryptomorin.xseries.XMaterial; + import tech.mcprison.prison.spigot.gui.guiutility.Button; import tech.mcprison.prison.spigot.gui.guiutility.ButtonLore; import tech.mcprison.prison.spigot.gui.guiutility.PrisonGUI; -import tech.mcprison.prison.spigot.gui.guiutility.SpigotGUIComponents; +import tech.mcprison.prison.spigot.gui.rank.SpigotGUIMessages; /** * @author GABRYCA */ -public class SpigotMineResetTimeGUI extends SpigotGUIComponents { +public class SpigotMineResetTimeGUI + extends SpigotGUIMessages { private final Player p; private final String mineName; @@ -35,7 +37,7 @@ public void open() { ButtonLore confirmButtonLore = new ButtonLore(createLore( guiLeftClickToConfirmMsg(), guiRightClickToCancelMsg() ), - createLore(messages.getString(MessagesConfig.StringID.spigot_gui_lore_reset_time) + " " + val)); + createLore( guiRanksLoreResetTimeMsg() + " " + val)); ButtonLore changeIncreaseValueLore = new ButtonLore( guiClickToIncreaseMsg(), null); diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/mine/SpigotMinesBlocksGUI.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/mine/SpigotMinesBlocksGUI.java index 96f6bd971..87af6340c 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/mine/SpigotMinesBlocksGUI.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/mine/SpigotMinesBlocksGUI.java @@ -8,17 +8,17 @@ import tech.mcprison.prison.mines.PrisonMines; import tech.mcprison.prison.mines.data.Mine; import tech.mcprison.prison.spigot.SpigotUtil; -import tech.mcprison.prison.spigot.configs.MessagesConfig; import tech.mcprison.prison.spigot.gui.guiutility.Button; import tech.mcprison.prison.spigot.gui.guiutility.ButtonLore; import tech.mcprison.prison.spigot.gui.guiutility.PrisonGUI; -import tech.mcprison.prison.spigot.gui.guiutility.SpigotGUIComponents; +import tech.mcprison.prison.spigot.gui.rank.SpigotGUIMessages; /** * @author GABRYCA * @author RoyalBlueRanger (rBluer) */ -public class SpigotMinesBlocksGUI extends SpigotGUIComponents { +public class SpigotMinesBlocksGUI + extends SpigotGUIMessages { private final Player p; private final String mineName; @@ -26,9 +26,9 @@ public class SpigotMinesBlocksGUI extends SpigotGUIComponents { // Global Strings. private final String loreShiftRightClickToDelete = guiRightClickShiftToDeleteMsg(); private final String loreClickToEditBlock = guiClickToEditMsg(); - private final String loreInfo = messages.getString(MessagesConfig.StringID.spigot_gui_lore_info); - private final String loreChance = messages.getString(MessagesConfig.StringID.spigot_gui_lore_chance); - private final String loreBlockType = messages.getString(MessagesConfig.StringID.spigot_gui_lore_blocktype); + private final String loreInfo = guiRanksLoreInfoMsg(); + private final String loreChance = guiRanksLoreChanceMsg(); + private final String loreBlockType = guiRanksLoreBlockTypeMsg(); public SpigotMinesBlocksGUI(Player p, String mineName){ this.p = p; @@ -43,7 +43,7 @@ public void open(){ // Get Mine Mine m = PrisonMines.getInstance().getMine(mineName); - ButtonLore addBlockLore = new ButtonLore(messages.getString(MessagesConfig.StringID.spigot_gui_lore_click_to_add), null); + ButtonLore addBlockLore = new ButtonLore( guiRanksLoreClickToAddMsg(), null); // Add the button to the GUI. gui.addButton(new Button(dimension - 1, XMaterial.LIME_STAINED_GLASS_PANE, addBlockLore, "&aAdd " + mineName)); diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/mine/SpigotMinesGUI.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/mine/SpigotMinesGUI.java index 1a23be812..3493c0a1e 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/mine/SpigotMinesGUI.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/mine/SpigotMinesGUI.java @@ -8,25 +8,26 @@ import com.cryptomorin.xseries.XMaterial; +import tech.mcprison.prison.Prison; import tech.mcprison.prison.internal.block.PrisonBlock; import tech.mcprison.prison.mines.PrisonMines; import tech.mcprison.prison.mines.data.Mine; import tech.mcprison.prison.mines.data.PrisonSortableResults; import tech.mcprison.prison.mines.managers.MineManager.MineSortOrder; -import tech.mcprison.prison.spigot.configs.MessagesConfig; import tech.mcprison.prison.spigot.gui.PrisonSetupGUI; import tech.mcprison.prison.spigot.gui.SpigotGUIMenuTools; import tech.mcprison.prison.spigot.gui.SpigotGUIMenuTools.GUIMenuPageData; import tech.mcprison.prison.spigot.gui.guiutility.Button; import tech.mcprison.prison.spigot.gui.guiutility.ButtonLore; import tech.mcprison.prison.spigot.gui.guiutility.PrisonGUI; -import tech.mcprison.prison.spigot.gui.guiutility.SpigotGUIComponents; +import tech.mcprison.prison.spigot.gui.rank.SpigotGUIMessages; /** * @author GABRYCA * @author RoyalBlueRanger (rBluer) */ -public class SpigotMinesGUI extends SpigotGUIComponents { +public class SpigotMinesGUI + extends SpigotGUIMessages { private final Player p; // private int counter; @@ -79,13 +80,13 @@ public void open(){ // Global Strings. String loreLeftClickOpen = guiLeftClickToOpenMsg(); String loreShiftRightClickToDelete = guiRightClickShiftToDeleteMsg(); - String loreInfo = messages.getString(MessagesConfig.StringID.spigot_gui_lore_info); - String loreWorld = messages.getString(MessagesConfig.StringID.spigot_gui_lore_world); - String loreSpawnPoint = messages.getString(MessagesConfig.StringID.spigot_gui_lore_spawnpoint); - String loreResetTime = messages.getString(MessagesConfig.StringID.spigot_gui_lore_reset_time); - String loreSizeOfMine = messages.getString(MessagesConfig.StringID.spigot_gui_lore_size); - String loreVolume = messages.getString(MessagesConfig.StringID.spigot_gui_lore_volume); - String loreBlocks = messages.getString(MessagesConfig.StringID.spigot_gui_lore_blocks); + String loreInfo = guiRanksLoreInfoMsg(); + String loreWorld = guiRanksLoreWorldMsg(); + String loreSpawnPoint = guiRanksLoreSpawnPointMsg(); + String loreResetTime = guiRanksLoreResetTimeMsg(); + String loreSizeOfMine = guiRanksLoreSizeMsg(); + String loreVolume = guiRanksLoreVolumeMsg(); + String loreBlocks = guiRanksLoreBlocksMsg(); for ( Mine m : minesDisplay ) @@ -111,7 +112,7 @@ public void open(){ minesLore.addLineLoreDescription("&7" + loreBlocks); // Init some variables and do the actions - DecimalFormat dFmt = new DecimalFormat("##0.00"); + DecimalFormat dFmt = Prison.get().getDecimalFormat("##0.00"); double totalChance = 0.0d; for (PrisonBlock block : m.getPrisonBlocks()) { @@ -159,7 +160,7 @@ public void open(){ // minesLore.addLineLoreDescription("&7" + loreBlocks); // // // Init some variables and do the actions -// DecimalFormat dFmt = new DecimalFormat("##0.00"); +// DecimalFormat dFmt = Prison.get().getDecimalFormat("##0.00"); // double totalChance = 0.0d; // // diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/mine/SpigotPlayerMinesGUI.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/mine/SpigotPlayerMinesGUI.java index 6967f8c0d..f3161c9ad 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/mine/SpigotPlayerMinesGUI.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/mine/SpigotPlayerMinesGUI.java @@ -9,7 +9,9 @@ import com.cryptomorin.xseries.XMaterial; +import de.tr7zw.nbtapi.NBTItem; import me.clip.placeholderapi.PlaceholderAPI; +import tech.mcprison.prison.Prison; import tech.mcprison.prison.mines.PrisonMines; import tech.mcprison.prison.mines.data.Mine; import tech.mcprison.prison.mines.data.PrisonSortableResults; @@ -17,28 +19,29 @@ import tech.mcprison.prison.output.Output; import tech.mcprison.prison.spigot.SpigotUtil; import tech.mcprison.prison.spigot.configs.GuiConfig; -import tech.mcprison.prison.spigot.configs.MessagesConfig; import tech.mcprison.prison.spigot.game.SpigotPlayer; import tech.mcprison.prison.spigot.gui.SpigotGUIMenuTools; import tech.mcprison.prison.spigot.gui.SpigotGUIMenuTools.GUIMenuPageData; import tech.mcprison.prison.spigot.gui.guiutility.Button; import tech.mcprison.prison.spigot.gui.guiutility.ButtonLore; import tech.mcprison.prison.spigot.gui.guiutility.PrisonGUI; -import tech.mcprison.prison.spigot.gui.guiutility.SpigotGUIComponents; +import tech.mcprison.prison.spigot.gui.rank.SpigotGUIMessages; +import tech.mcprison.prison.spigot.nbt.PrisonNBTUtil; import tech.mcprison.prison.util.Text; /** * @author GABRYCA * @author RoyalBlueRanger (rBluer) */ -public class SpigotPlayerMinesGUI extends SpigotGUIComponents { +public class SpigotPlayerMinesGUI + extends SpigotGUIMessages { private final Player p; private final SpigotPlayer spigotPlayer; private final String permissionWarpPlugin = guiConfig.getString("Options.Mines.PermissionWarpPlugin"); - private final String statusUnlockedMine = messages.getString(MessagesConfig.StringID.spigot_gui_lore_unlocked); - private final String clickToTeleport = messages.getString(MessagesConfig.StringID.spigot_gui_lore_click_to_teleport); - private final String statusLockedMine = messages.getString(MessagesConfig.StringID.spigot_gui_lore_locked); + private final String statusUnlockedMine = guiRanksLoreUnlockedMsg(); + private final String clickToTeleport = guiRanksLoreClickToTeleportMsg(); + private final String statusLockedMine = guiRanksLoreLockedMsg(); private int page; private String cmdPage; @@ -95,10 +98,11 @@ public void open() { guiConfig = guiConfigClass.getFileGuiConfig(); String permission = Text.translateAmpColorCodes(permissionWarpPlugin); - // Create GUI. + // Create GUI but use the gui title as defined within the ConfigGui.yml file: PrisonGUI gui = new PrisonGUI(p, guiPageData.getDimension(), guiConfig.getString("Options.Titles.PlayerMinesGUI")); - + + // Load the generic mine LORE that would be displayed first: List configCustomLore = guiConfig.getStringList("EditableLore.Mines"); @@ -110,6 +114,7 @@ public void open() { ButtonLore minesLore = new ButtonLore(); + // If a mine has custom LORE, then try to load it: String mineLoreKey = "EditableLore.Mine." + m.getName(); List mineLore = new ArrayList<>( configCustomLore ); List mineLore2 = guiConfig.getStringList( mineLoreKey ); @@ -125,15 +130,35 @@ public void open() { // Get Mine Name. String mineName = m.getName(); - // Add mineName lore for TP. - minesLore.addLineLoreAction( "&3" + mineName ); +// // Add mineName lore for TP. +// minesLore.addLineLoreAction( "&3" + mineName ); + + boolean hasMineAccess = m.hasMiningAccess(spigotPlayer); + String permMineAccess = permission + m.getName(); + boolean hasPermMine = p.hasPermission( permMineAccess ); + String permAccess = permission.substring(0, permission.length() - 1); + boolean hasPerm = p.hasPermission( permAccess ); + + String lockStatus = statusLockedMine; // If the player has permission to access the mine, then see if there is a custom // block set for the mine... otherwise it will use XMaterial.COAL_ORE: - if (m.hasMiningAccess(spigotPlayer) || p.hasPermission(permission + m.getName()) || - p.hasPermission(permission.substring(0, permission.length() - 1))) + if ( hasMineAccess || + hasPermMine || + hasPerm ) { + + if ( !hasMineAccess ) { + Output.get().logInfo( + "GUI Player Mines: Has access to mine %s through perms: %s=%s OR %s=%s", + m.getName(), + permMineAccess, Boolean.toString(hasPermMine), + permAccess, Boolean.toString(hasPerm) + ); + } + + // Default to COAL_ORE since the player has access to the mine: xMat = XMaterial.COAL_ORE; @@ -160,15 +185,17 @@ public void open() { } } + lockStatus = statusUnlockedMine; + // material = ( mineMaterial == null ? Material.COAL_ORE : mineMaterial); - minesLore.addLineLoreDescription( statusUnlockedMine ); - minesLore.addLineLoreAction( clickToTeleport ); +// minesLore.addLineLoreDescription( statusUnlockedMine ); +// minesLore.addLineLoreAction( clickToTeleport ); } else { xMat = XMaterial.REDSTONE_BLOCK; // material = XMaterial.REDSTONE_BLOCK.parseMaterial(); - minesLore.addLineLoreDescription( statusLockedMine ); +// minesLore.addLineLoreDescription( statusLockedMine ); } // Get mine Tag, but make sure it is valid and the mine's name is not null: @@ -179,7 +206,7 @@ public void open() { mineTag = m.getTag(); } - DecimalFormat iFmt = new DecimalFormat( "#,##0" ); + DecimalFormat iFmt = Prison.get().getDecimalFormatInt(); for (String stringValue : mineLore) { @@ -195,6 +222,18 @@ public void open() { stringValue = stringValue.replace( "{mineRemaining}", iFmt.format( remaining )); stringValue = stringValue.replace( "{mineRemainingPercent}", iFmt.format( m.getPercentRemainingBlockCount() )); + stringValue = stringValue.replace( "{clickToTeleport}", clickToTeleport ); + stringValue = stringValue.replace( "{lockStatus}", lockStatus ); + + stringValue = stringValue.replace( "{playerCount}", iFmt.format( m.getPlayerCount()) ); + + if ( m.getRank() == null ) { + stringValue = stringValue.replace( "{linkedRank}", "Not linked" ); + } + else { + stringValue = stringValue.replace( "{linkedRank}", m.getRank().getTag() ); + } + minesLore.addLineLoreAction( stringValue ); } @@ -207,10 +246,26 @@ public void open() { minesLore.setLoreAction( lores ); } + + + Button itemMine = new Button(null, xMat, minesLore, "&3" + mineTag); + + String mineTeleportCommand = + Output.stringFormat( + "mines tp %s %s", + m.getName(), + p.getName() ); + // Before adding the button, add an NBT tag for the command and rank name: + PrisonNBTUtil nbtUtil = new PrisonNBTUtil(); + NBTItem nbtItem = nbtUtil == null ? null : nbtUtil.getNBT( itemMine.getButtonItem()); + nbtUtil.setNBTString(nbtItem, SpigotGUIMenuTools.GUI_MENU_TOOLS_NBT_ENABLED, "true"); + nbtUtil.setNBTString(nbtItem, SpigotGUIMenuTools.GUI_MENU_TOOLS_NBT_COMMAND, mineTeleportCommand ); + nbtUtil.setNBTString(nbtItem, SpigotGUIMenuTools.GUI_MENU_TOOLS_NBT_MINE_NAME, m.getName() ); + // Add the button to the inventory. - gui.addButton(new Button(null, xMat, minesLore, "&3" + mineTag)); + gui.addButton( itemMine ); // String mineTag = m.getTag(); diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/rank/SpigotConfirmPrestigeGUI.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/rank/SpigotConfirmPrestigeGUI.java index c852e82c9..95c3b9a6a 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/rank/SpigotConfirmPrestigeGUI.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/rank/SpigotConfirmPrestigeGUI.java @@ -1,10 +1,11 @@ package tech.mcprison.prison.spigot.gui.rank; +import java.util.List; + import org.bukkit.entity.Player; import com.cryptomorin.xseries.XMaterial; -import tech.mcprison.prison.spigot.configs.MessagesConfig; import tech.mcprison.prison.spigot.gui.guiutility.Button; import tech.mcprison.prison.spigot.gui.guiutility.ButtonLore; import tech.mcprison.prison.spigot.gui.guiutility.PrisonGUI; @@ -15,31 +16,52 @@ */ public class SpigotConfirmPrestigeGUI extends SpigotGUIComponents { - private final Player p; + private final Player player; + private final List lore; - public SpigotConfirmPrestigeGUI(Player p) { - this.p = p; + public SpigotConfirmPrestigeGUI(Player player, List lore ) { + this.player = player; + this.lore = lore; } - + public void open(){ - - // Create the inventory - int dimension = 9; - PrisonGUI gui = new PrisonGUI(p, dimension, "&3Prestige -> Confirmation"); - - ButtonLore confirmLore = new ButtonLore(createLore( - guiClickToConfirmMsg()), createLore( - messages.getString(MessagesConfig.StringID.spigot_gui_lore_prestige_warning_1), - messages.getString(MessagesConfig.StringID.spigot_gui_lore_prestige_warning_2), - messages.getString(MessagesConfig.StringID.spigot_gui_lore_prestige_warning_3))); - - ButtonLore cancelLore = new ButtonLore( guiClickToCancelMsg(), null); - - - // Create the button, set up the material, amount, lore and name - gui.addButton(new Button(2, XMaterial.EMERALD_BLOCK, confirmLore, "&3Confirm: Prestige" )); - gui.addButton(new Button(6, XMaterial.REDSTONE_BLOCK, cancelLore, "&3Cancel: Don't Prestige" )); - - gui.open(); + + // Create the inventory + int dimension = 9; + PrisonGUI gui = new PrisonGUI( player, dimension, "&3Prestige -> Confirmation"); + + ButtonLore confirmLore = new ButtonLore(createLore( + guiClickToConfirmMsg()), lore ); + + ButtonLore cancelLore = new ButtonLore( guiClickToCancelMsg(), null); + + + // Create the button, set up the material, amount, lore and name + gui.addButton(new Button(2, XMaterial.EMERALD_BLOCK, confirmLore, "&3Confirm: Prestige" )); + gui.addButton(new Button(6, XMaterial.REDSTONE_BLOCK, cancelLore, "&3Cancel: Don't Prestige" )); + + gui.open(); } + +// public void open(){ +// +// // Create the inventory +// int dimension = 9; +// PrisonGUI gui = new PrisonGUI(p, dimension, "&3Prestige -> Confirmation"); +// +// ButtonLore confirmLore = new ButtonLore(createLore( +// guiClickToConfirmMsg()), createLore( +// messages.getString(MessagesConfig.StringID.spigot_gui_lore_prestige_warning_1), +// messages.getString(MessagesConfig.StringID.spigot_gui_lore_prestige_warning_2), +// messages.getString(MessagesConfig.StringID.spigot_gui_lore_prestige_warning_3))); +// +// ButtonLore cancelLore = new ButtonLore( guiClickToCancelMsg(), null); +// +// +// // Create the button, set up the material, amount, lore and name +// gui.addButton(new Button(2, XMaterial.EMERALD_BLOCK, confirmLore, "&3Confirm: Prestige" )); +// gui.addButton(new Button(6, XMaterial.REDSTONE_BLOCK, cancelLore, "&3Cancel: Don't Prestige" )); +// +// gui.open(); +// } } diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/rank/SpigotGUIMessages.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/rank/SpigotGUIMessages.java new file mode 100644 index 000000000..bec585c42 --- /dev/null +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/rank/SpigotGUIMessages.java @@ -0,0 +1,345 @@ +package tech.mcprison.prison.spigot.gui.rank; + +import tech.mcprison.prison.internal.CommandSender; +import tech.mcprison.prison.spigot.SpigotPrison; +import tech.mcprison.prison.spigot.gui.guiutility.SpigotGUIComponents; + +public class SpigotGUIMessages + extends SpigotGUIComponents { + + + protected void exampleMsg( CommandSender sender, String parameter ) { + SpigotPrison.getInstance().getLocaleManager() + .getLocalizable( "spigot_examples__" ) + .withReplacements( + parameter ) + .sendTo( sender ); + } + + protected String exampleReturnMsg( String parameter ) { + return SpigotPrison.getInstance().getLocaleManager() + .getLocalizable( "spigot_examples__" ) + .withReplacements( + parameter ) + .localize(); + } + + + + protected void guiRanksNoRanksMsg( CommandSender sender ) { + SpigotPrison.getInstance().getLocaleManager() + .getLocalizable( "spigot_message_gui_ranks_empty" ) + .sendTo( sender ); + } + + protected String guiRanksClickToManageRankMsg() { + return SpigotPrison.getInstance().getLocaleManager() + .getLocalizable( "spigot_gui_lore_click_to_manage_rank" ) + .localize(); + } + + protected String guiRanksLoreInfoMsg() { + return SpigotPrison.getInstance().getLocaleManager() + .getLocalizable( "spigot_gui_lore_info" ) + .localize(); + } + + protected String guiRanksLoreIdMsg() { + return SpigotPrison.getInstance().getLocaleManager() + .getLocalizable( "spigot_gui_lore_id" ) + .localize(); + } + + protected String guiRanksLoreNameMsg() { + return SpigotPrison.getInstance().getLocaleManager() + .getLocalizable( "spigot_gui_lore_name" ) + .localize(); + } + + protected String guiRanksLoreRankTagMsg() { + return SpigotPrison.getInstance().getLocaleManager() + .getLocalizable( "spigot_gui_lore_rank_tag" ) + .localize(); + } + + protected String guiRanksLorePlayersWithRankMsg() { + return SpigotPrison.getInstance().getLocaleManager() + .getLocalizable( "spigot_gui_lore_players_at_rank" ) + .localize(); + } + + + protected String guiRanksLoreCommandMsg() { + return SpigotPrison.getInstance().getLocaleManager() + .getLocalizable( "spigot_gui_lore_command" ) + .localize(); + } + + protected String guiRanksLoreOwnerMsg() { + return SpigotPrison.getInstance().getLocaleManager() + .getLocalizable( "spigot_gui_lore_owner" ) + .localize(); + } + + protected String guiRanksLoreBackpackIdMsg() { + return SpigotPrison.getInstance().getLocaleManager() + .getLocalizable( "spigot_gui_lore_backpack_id" ) + .localize(); + } + + protected String guiRanksLoreChanceMsg() { + return SpigotPrison.getInstance().getLocaleManager() + .getLocalizable( "spigot_gui_lore_chance" ) + .localize(); + } + + protected String guiRanksLoreBlockTypeMsg() { + return SpigotPrison.getInstance().getLocaleManager() + .getLocalizable( "spigot_gui_lore_blocktype" ) + .localize(); + } + + protected String guiRanksLoreClickToAddMsg() { + return SpigotPrison.getInstance().getLocaleManager() + .getLocalizable( "spigot_gui_lore_click_to_add" ) + .localize(); + } + + protected String guiRanksLoreClickToUseMsg() { + return SpigotPrison.getInstance().getLocaleManager() + .getLocalizable( "spigot_gui_lore_click_to_use" ) + .localize(); + } + + protected String guiRanksLoreWorldMsg() { + return SpigotPrison.getInstance().getLocaleManager() + .getLocalizable( "spigot_gui_lore_world" ) + .localize(); + } + + protected String guiRanksLoreSpawnPointMsg() { + return SpigotPrison.getInstance().getLocaleManager() + .getLocalizable( "spigot_gui_lore_spawnpoint" ) + .localize(); + } + + protected String guiRanksLoreResetTimeMsg() { + return SpigotPrison.getInstance().getLocaleManager() + .getLocalizable( "spigot_gui_lore_reset_time" ) + .localize(); + } + + protected String guiRanksLoreSizeMsg() { + return SpigotPrison.getInstance().getLocaleManager() + .getLocalizable( "spigot_gui_lore_size" ) + .localize(); + } + + protected String guiRanksLoreVolumeMsg() { + return SpigotPrison.getInstance().getLocaleManager() + .getLocalizable( "spigot_gui_lore_volume" ) + .localize(); + } + + protected String guiRanksLoreBlocksMsg() { + return SpigotPrison.getInstance().getLocaleManager() + .getLocalizable( "spigot_gui_lore_blocks" ) + .localize(); + } + + protected String guiRanksLoreSkipResetInstruction1Msg() { + return SpigotPrison.getInstance().getLocaleManager() + .getLocalizable( "spigot_gui_lore_skip_reset_instruction_1" ) + .localize(); + } + + protected String guiRanksLoreSkipResetInstruction2Msg() { + return SpigotPrison.getInstance().getLocaleManager() + .getLocalizable( "spigot_gui_lore_skip_reset_instruction_2" ) + .localize(); + } + + protected String guiRanksLoreSkipResetInstruction3Msg() { + return SpigotPrison.getInstance().getLocaleManager() + .getLocalizable( "spigot_gui_lore_skip_reset_instruction_3" ) + .localize(); + } + + protected String guiRanksLoreSetMineDelayInstruction1Msg() { + return SpigotPrison.getInstance().getLocaleManager() + .getLocalizable( "spigot_gui_lore_set_mine_delay_instruction_1" ) + .localize(); + } + + protected String guiRanksLoreSetMineDelayInstruction2Msg() { + return SpigotPrison.getInstance().getLocaleManager() + .getLocalizable( "spigot_gui_lore_set_mine_delay_instruction_2" ) + .localize(); + } + + protected String guiRanksLoreSetMineDelayInstruction3Msg() { + return SpigotPrison.getInstance().getLocaleManager() + .getLocalizable( "spigot_gui_lore_set_mine_delay_instruction_3" ) + .localize(); + } + + protected String guiRanksLoreClickToTeleportMsg() { + return SpigotPrison.getInstance().getLocaleManager() + .getLocalizable( "spigot_gui_lore_click_to_teleport" ) + .localize(); + } + + protected String guiRanksLoreTpToMineMsg() { + return SpigotPrison.getInstance().getLocaleManager() + .getLocalizable( "spigot_gui_lore_tp_to_mine" ) + .localize(); + } + + protected String guiRanksLoreClickToRenameMsg() { + return SpigotPrison.getInstance().getLocaleManager() + .getLocalizable( "spigot_gui_lore_click_to_rename" ) + .localize(); + } + + protected String guiRanksLoreMineNameMsg() { + return SpigotPrison.getInstance().getLocaleManager() + .getLocalizable( "spigot_gui_lore_minename" ) + .localize(); + } + + protected String guiRanksLoreShowItemMsg() { + return SpigotPrison.getInstance().getLocaleManager() + .getLocalizable( "spigot_gui_lore_show_item" ) + .localize(); + } + + protected String guiRanksLoreShowItemDescription1Msg() { + return SpigotPrison.getInstance().getLocaleManager() + .getLocalizable( "spigot_gui_lore_show_item_description_1" ) + .localize(); + } + + protected String guiRanksLoreShowItemDescription2Msg() { + return SpigotPrison.getInstance().getLocaleManager() + .getLocalizable( "spigot_gui_lore_show_item_description_2" ) + .localize(); + } + + protected String guiRanksLoreShowItemDescription3Msg() { + return SpigotPrison.getInstance().getLocaleManager() + .getLocalizable( "spigot_gui_lore_show_item_description_3" ) + .localize(); + } + + protected String guiRanksLoreUnlockedMsg() { + return SpigotPrison.getInstance().getLocaleManager() + .getLocalizable( "spigot_gui_lore_unlocked" ) + .localize(); + } + + protected String guiRanksLoreLockedMsg() { + return SpigotPrison.getInstance().getLocaleManager() + .getLocalizable( "spigot_gui_lore_locked" ) + .localize(); + } + + protected String guiRanksLoreClickToSelectMsg() { + return SpigotPrison.getInstance().getLocaleManager() + .getLocalizable( "spigot_gui_lore_click_to_select" ) + .localize(); + } + + protected String guiRanksLoreEnableWithinModeMsg() { + return SpigotPrison.getInstance().getLocaleManager() + .getLocalizable( "spigot_gui_lore_enable_within_mode" ) + .localize(); + } + + protected String guiRanksLoreEnableRadiusModeMsg() { + return SpigotPrison.getInstance().getLocaleManager() + .getLocalizable( "spigot_gui_lore_enable_radius_mode" ) + .localize(); + } + + protected String guiRanksLoreDisableNotificationsMsg() { + return SpigotPrison.getInstance().getLocaleManager() + .getLocalizable( "spigot_gui_lore_disable_notifications" ) + .localize(); + } + + protected String guiRanksLoreSelecteMsg() { + return SpigotPrison.getInstance().getLocaleManager() + .getLocalizable( "spigot_gui_lore_selected" ) + .localize(); + } + + protected String guiRanksLoreRadiusMsg() { + return SpigotPrison.getInstance().getLocaleManager() + .getLocalizable( "spigot_gui_lore_radius" ) + .localize(); + } + + protected String guiRanksLorePercentageMsg() { + return SpigotPrison.getInstance().getLocaleManager() + .getLocalizable( "spigot_gui_lore_percentage" ) + .localize(); + } + + protected String guiRanksLoreClickToStartBlockSetupMsg() { + return SpigotPrison.getInstance().getLocaleManager() + .getLocalizable( "spigot_gui_lore_click_to_start_block_setup" ) + .localize(); + } + + + + protected void guiRanksLadderIsEmptyMsg( CommandSender sender, String ladderName ) { + SpigotPrison.getInstance().getLocaleManager() + .getLocalizable( "spigot_message_gui_ladder_empty" ) + .withReplacements( + ladderName ) + .sendTo( sender ); + } + + + protected String guiRanksLoreClickToRankupMsg() { + return SpigotPrison.getInstance().getLocaleManager() + .getLocalizable( "spigot_gui_lore_click_to_rankup" ) + .localize(); + } + + protected String guiRanksLoreRankupIfEnoughMoneyMsg() { + return SpigotPrison.getInstance().getLocaleManager() + .getLocalizable( "spigot_gui_lore_rankup_if_enough_money" ) + .localize(); + } + + + + protected void guiRanksPrestigesLadderIsEmptyMsg( CommandSender sender ) { + SpigotPrison.getInstance().getLocaleManager() + .getLocalizable( "spigot_message_prestiges_empty" ) + .sendTo( sender ); + } + + + protected void guiRanksRankupCommandsEmptyMsg( CommandSender sender ) { + SpigotPrison.getInstance().getLocaleManager() + .getLocalizable( "spigot_message_gui_ranks_rankup_commands_empty" ) + .sendTo( sender ); + } + + protected void guiRanksErrorEmptyMsg( CommandSender sender ) { + SpigotPrison.getInstance().getLocaleManager() + .getLocalizable( "spigot_message_gui_error_empty" ) + .sendTo( sender ); + } + + protected void guiRanksRankupCommandsTooManyMsg( CommandSender sender ) { + SpigotPrison.getInstance().getLocaleManager() + .getLocalizable( "spigot_message_gui_ranks_rankup_commands_too_many" ) + .sendTo( sender ); + } + + +} diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/rank/SpigotLaddersGUI.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/rank/SpigotLaddersGUI.java index f66041e75..f74411182 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/rank/SpigotLaddersGUI.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/rank/SpigotLaddersGUI.java @@ -6,24 +6,21 @@ import com.cryptomorin.xseries.XMaterial; -import tech.mcprison.prison.output.Output; import tech.mcprison.prison.ranks.PrisonRanks; import tech.mcprison.prison.ranks.data.RankLadder; import tech.mcprison.prison.ranks.managers.LadderManager; -import tech.mcprison.prison.spigot.SpigotPrison; -import tech.mcprison.prison.spigot.configs.MessagesConfig; import tech.mcprison.prison.spigot.game.SpigotPlayer; import tech.mcprison.prison.spigot.gui.SpigotGUIMenuTools; import tech.mcprison.prison.spigot.gui.SpigotGUIMenuTools.GUIMenuPageData; import tech.mcprison.prison.spigot.gui.guiutility.Button; import tech.mcprison.prison.spigot.gui.guiutility.ButtonLore; import tech.mcprison.prison.spigot.gui.guiutility.PrisonGUI; -import tech.mcprison.prison.spigot.gui.guiutility.SpigotGUIComponents; /** * @author GABRYCA */ -public class SpigotLaddersGUI extends SpigotGUIComponents { +public class SpigotLaddersGUI + extends SpigotGUIMessages { private final Player p; @@ -53,7 +50,7 @@ public void open(){ // If the inventory is empty if (lm == null || lm.getLadders().size() == 0){ - Output.get().sendWarn(new SpigotPlayer(p), messages.getString(MessagesConfig.StringID.spigot_message_gui_ladder_empty)); + guiRanksLadderIsEmptyMsg( new SpigotPlayer(p), "" ); p.closeInventory(); return; } diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/rank/SpigotPlayerPrestigesGUI.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/rank/SpigotPlayerPrestigesGUI.java index fd372e1da..139a8e11c 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/rank/SpigotPlayerPrestigesGUI.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/rank/SpigotPlayerPrestigesGUI.java @@ -24,19 +24,18 @@ import tech.mcprison.prison.ranks.managers.LadderManager; import tech.mcprison.prison.ranks.managers.PlayerManager; import tech.mcprison.prison.spigot.SpigotPrison; -import tech.mcprison.prison.spigot.configs.MessagesConfig; import tech.mcprison.prison.spigot.game.SpigotPlayer; import tech.mcprison.prison.spigot.gui.SpigotGUIMenuTools; import tech.mcprison.prison.spigot.gui.SpigotGUIMenuTools.GUIMenuPageData; import tech.mcprison.prison.spigot.gui.guiutility.Button; import tech.mcprison.prison.spigot.gui.guiutility.ButtonLore; import tech.mcprison.prison.spigot.gui.guiutility.PrisonGUI; -import tech.mcprison.prison.spigot.gui.guiutility.SpigotGUIComponents; /** * @author GABRYCA */ -public class SpigotPlayerPrestigesGUI extends SpigotGUIComponents { +public class SpigotPlayerPrestigesGUI + extends SpigotGUIMessages { private final Player player; private PrisonRanks rankPlugin; @@ -144,7 +143,8 @@ public void open() { // Create the inventory and set up the owner, dimensions or number of slots, and title // int dimension = (int) (Math.ceil(ladder.getRanks().size() / 9D) * 9) + 9; - PrisonGUI gui = new PrisonGUI(getPlayer(), guiPageData.getDimension(), guiConfig.getString("Options.Titles.PlayerPrestigesGUI")); + PrisonGUI gui = new PrisonGUI(getPlayer(), guiPageData.getDimension(), + guiConfig.getString("Options.Titles.PlayerPrestigesGUI")); // dead code: // if ( ladder == null ){ @@ -153,7 +153,7 @@ public void open() { // } if (!ladder.getLowestRank().isPresent()){ - Output.get().sendWarn(new SpigotPlayer(player), messages.getString(MessagesConfig.StringID.spigot_message_prestiges_empty)); + guiRanksPrestigesLadderIsEmptyMsg( new SpigotPlayer(player) ); return; } @@ -181,7 +181,7 @@ public void open() { int hackyCounterEnchant = 0; // Global strings. - String loreInfo = messages.getString(MessagesConfig.StringID.spigot_gui_lore_info); + String loreInfo = guiRanksLoreInfoMsg(); // String lorePrice3 = messages.getString(MessagesConfig.StringID.spigot_gui_lore_price); // Global boolean. @@ -242,12 +242,17 @@ public void open() { SpigotGUIMenuTools.getInstance().addMenuPageButtonsStandard( gui, guiPageData ); + + if (Prison.get().getPlatform().getConfigBooleanTrue( "ranks.gui-prestiges-include-rankup-button") ) { + + ButtonLore rankupLore = new ButtonLore( guiRanksLoreClickToRankupMsg(), + guiRanksLoreRankupIfEnoughMoneyMsg() ); + Button rankupButton = new Button(0, XMaterial.EMERALD_BLOCK, rankupLore, "&aPrestige" ); + // NOTE: Button position will be properly assigned in the setButtonNextAvilable: + gui.addButton( guiPageData.setButtonNextAvailable( rankupButton ) ); + + } - ButtonLore rankupLore = new ButtonLore(messages.getString(MessagesConfig.StringID.spigot_gui_lore_click_to_rankup), messages.getString(MessagesConfig.StringID.spigot_gui_lore_rankup_if_enough_money)); - Button rankupButton = new Button(0, XMaterial.EMERALD_BLOCK, rankupLore, "&aPrestige" ); - // NOTE: Button position will be properly assigned in the setButtonNextAvilable: - gui.addButton( guiPageData.setButtonNextAvailable( rankupButton ) ); - // Open GUI. diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/rank/SpigotPlayerRanksGUI.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/rank/SpigotPlayerRanksGUI.java index ab41bf0c6..d59b2aec3 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/rank/SpigotPlayerRanksGUI.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/rank/SpigotPlayerRanksGUI.java @@ -28,14 +28,12 @@ import tech.mcprison.prison.ranks.managers.LadderManager; import tech.mcprison.prison.ranks.managers.PlayerManager; import tech.mcprison.prison.spigot.SpigotPrison; -import tech.mcprison.prison.spigot.configs.MessagesConfig; import tech.mcprison.prison.spigot.game.SpigotPlayer; import tech.mcprison.prison.spigot.gui.SpigotGUIMenuTools; import tech.mcprison.prison.spigot.gui.SpigotGUIMenuTools.GUIMenuPageData; import tech.mcprison.prison.spigot.gui.guiutility.Button; import tech.mcprison.prison.spigot.gui.guiutility.ButtonLore; import tech.mcprison.prison.spigot.gui.guiutility.PrisonGUI; -import tech.mcprison.prison.spigot.gui.guiutility.SpigotGUIComponents; import tech.mcprison.prison.spigot.nbt.PrisonNBTUtil; import tech.mcprison.prison.util.Text; @@ -43,7 +41,8 @@ * @author GABRYCA * @author RoyalBlueRanger (rBluer) */ -public class SpigotPlayerRanksGUI extends SpigotGUIComponents { +public class SpigotPlayerRanksGUI + extends SpigotGUIMessages { private final Player player; @@ -130,14 +129,14 @@ public void open() { // Ensure ladder is present and that it has a rank: if ( ladder == null || !ladder.getLowestRank().isPresent()){ - Output.get().sendWarn(new SpigotPlayer(getPlayer()), messages.getString(MessagesConfig.StringID.spigot_message_gui_ladder_empty) + " [" + guiConfig.getString("Options.Ranks.Ladder") + "]"); + guiRanksLadderIsEmptyMsg( new SpigotPlayer(getPlayer()), guiConfig.getString("Options.Ranks.Ladder") ); getPlayer().closeInventory(); return; } // Get the dimensions and if needed increases them if (ladder.getRanks().size() == 0) { - Output.get().sendWarn(new SpigotPlayer(getPlayer()), messages.getString(MessagesConfig.StringID.spigot_message_gui_ranks_empty)); + guiRanksNoRanksMsg( new SpigotPlayer(getPlayer()) ); return; } @@ -178,8 +177,8 @@ public void open() { boolean enchantmentEffectEnabled = getBoolean(guiConfig.getString("Options.Ranks.Enchantment_effect_current_rank")); // Decimal Rank cost format. - DecimalFormat formatDecimal = new DecimalFormat("###,##0.00"); - DecimalFormat mFmt = new DecimalFormat("###,##0.0000"); + DecimalFormat formatDecimal = Prison.get().getDecimalFormat("###,##0.00"); + DecimalFormat mFmt = Prison.get().getDecimalFormat("###,##0.0000"); boolean showNumber = getBoolean(guiConfig.getString("Options.Ranks.Number_of_Rank_Player_GUI")); // PlayerRank pRank = rankPlayerFactory.getRank( getRankPlayer(), ladder, true ); @@ -202,6 +201,20 @@ public void open() { double rankPrice = calPRank.getRankCost(); double rankMultiplier = calPRank.getRankMultiplier(); + StringBuilder sbMines = new StringBuilder(); + if ( rank.getMines() != null && rank.getMines().size() > 0 ) { + + for (ModuleElement mine : rank.getMines() ) { + if ( sbMines.length() > 0 ) { + sbMines.append( " " ); + } + sbMines.append( mine.getTag() ); + } + } + else { + sbMines.append( "&3None" ); + } + for ( String stringValue : rankLore ) { String currency = (rank.getCurrency() == null || @@ -219,14 +232,6 @@ public void open() { stringValue = stringValue.replace("{rankMultiplier}", mFmt.format( rankMultiplier )); stringValue = stringValue.replace("{ladderName}", rank.getLadder().getName()); - StringBuilder sbMines = new StringBuilder(); - for ( ModuleElement mine : rank.getMines() ) - { - if ( sbMines.length() > 0 ) { - sbMines.append( ", " ); - } - sbMines.append( mine.getName() ); - } stringValue = stringValue.replace("{linkedMines}", sbMines.toString() ); ranksLore.addLineLoreAction(stringValue); @@ -261,6 +266,15 @@ public void open() { } } + + // Before adding the button, add an NBT tag for the command and rank name: + PrisonNBTUtil nbtUtil = new PrisonNBTUtil(); + NBTItem nbtItem = nbtUtil == null ? null : nbtUtil.getNBT( itemRank.getButtonItem()); + nbtUtil.setNBTString(nbtItem, SpigotGUIMenuTools.GUI_MENU_TOOLS_NBT_ENABLED, "true"); +// nbtUtil.setNBTString(nbtItem, SpigotGUIMenuTools.GUI_MENU_TOOLS_NBT_COMMAND, noCommmand ); + nbtUtil.setNBTString(nbtItem, SpigotGUIMenuTools.GUI_MENU_TOOLS_NBT_RANK_NAME, rank.getName() ); + + gui.addButton(itemRank); // rank = rank.getRankNext(); @@ -273,23 +287,35 @@ public void open() { SpigotGUIMenuTools.getInstance().addMenuPageButtonsStandard( gui, guiPageData ); - - // Add Rankup button: Using NBTs: - String rankupTitle = ladderName.equalsIgnoreCase("prestiges") ? "Prestige" : "Rankup"; - ButtonLore rankupLore = new ButtonLore(messages.getString(MessagesConfig.StringID.spigot_gui_lore_click_to_rankup), messages.getString(MessagesConfig.StringID.spigot_gui_lore_rankup_if_enough_money)); - Button rankupButton = new Button( 0, XMaterial.EMERALD_BLOCK, rankupLore, rankupTitle ); - String rankupCommand = "rankup " + (ladderName.equalsIgnoreCase("default") ? "" : ladderName); - - PrisonNBTUtil nbtUtil = new PrisonNBTUtil(); - NBTItem nbtItem = nbtUtil == null ? null : nbtUtil.getNBT(rankupButton.getButtonItem()); - nbtUtil.setNBTString(nbtItem, SpigotGUIMenuTools.GUI_MENU_TOOLS_NBT_ENABLED, "true"); - nbtUtil.setNBTString(nbtItem, SpigotGUIMenuTools.GUI_MENU_TOOLS_NBT_COMMAND, rankupCommand); - + if ( LadderManager.LADDER_DEFAULT.equalsIgnoreCase( ladderName ) && + Prison.get().getPlatform().getConfigBooleanTrue( "ranks.gui-default-include-rankup-button") || + LadderManager.LADDER_PRESTIGES.equalsIgnoreCase( ladderName ) && + Prison.get().getPlatform().getConfigBooleanTrue( "ranks.gui-prestiges-include-rankup-button") || + !LadderManager.LADDER_DEFAULT.equalsIgnoreCase( ladderName ) && + !LadderManager.LADDER_PRESTIGES.equalsIgnoreCase( ladderName ) && + Prison.get().getPlatform().getConfigBooleanTrue( "ranks.gui-others-include-rankup-button") + ) { + + // Add Rankup button: Using NBTs: + String rankupTitle = ladderName.equalsIgnoreCase("prestiges") ? "Prestige" : "Rankup"; + + ButtonLore rankupLore = new ButtonLore( guiRanksLoreClickToRankupMsg(), + guiRanksLoreRankupIfEnoughMoneyMsg()); + + Button rankupButton = new Button( 0, XMaterial.EMERALD_BLOCK, rankupLore, rankupTitle ); + String rankupCommand = "rankup " + (ladderName.equalsIgnoreCase("default") ? "" : ladderName); + + PrisonNBTUtil nbtUtil = new PrisonNBTUtil(); + NBTItem nbtItem = nbtUtil == null ? null : nbtUtil.getNBT(rankupButton.getButtonItem()); + nbtUtil.setNBTString(nbtItem, SpigotGUIMenuTools.GUI_MENU_TOOLS_NBT_ENABLED, "true"); + nbtUtil.setNBTString(nbtItem, SpigotGUIMenuTools.GUI_MENU_TOOLS_NBT_COMMAND, rankupCommand); + // SpigotPrison.format(messages.getString(MessagesConfig.StringID.spigot_gui_lore_rankup))); - // NOTE: Button position will be properly assigned in the setButtonNextAvilable: - gui.addButton( guiPageData.setButtonNextAvailable( rankupButton ) ); - - + // NOTE: Button position will be properly assigned in the setButtonNextAvilable: + gui.addButton( guiPageData.setButtonNextAvailable( rankupButton ) ); + + } + // Open GUI. gui.open(); diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/rank/SpigotRankManagerGUI.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/rank/SpigotRankManagerGUI.java index 140c5387c..e687ef08a 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/rank/SpigotRankManagerGUI.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/rank/SpigotRankManagerGUI.java @@ -6,23 +6,23 @@ import com.cryptomorin.xseries.XMaterial; +import tech.mcprison.prison.Prison; import tech.mcprison.prison.placeholders.PlaceholdersUtil; import tech.mcprison.prison.ranks.PrisonRanks; import tech.mcprison.prison.ranks.data.PlayerRank; import tech.mcprison.prison.ranks.data.Rank; import tech.mcprison.prison.ranks.data.RankPlayer; import tech.mcprison.prison.ranks.data.RankPlayerFactory; -import tech.mcprison.prison.spigot.configs.MessagesConfig; import tech.mcprison.prison.spigot.game.SpigotPlayer; import tech.mcprison.prison.spigot.gui.guiutility.Button; import tech.mcprison.prison.spigot.gui.guiutility.ButtonLore; import tech.mcprison.prison.spigot.gui.guiutility.PrisonGUI; -import tech.mcprison.prison.spigot.gui.guiutility.SpigotGUIComponents; /** * @author GABRYCA */ -public class SpigotRankManagerGUI extends SpigotGUIComponents { +public class SpigotRankManagerGUI + extends SpigotGUIMessages { private final Player p; private final Rank rank; @@ -45,7 +45,7 @@ public void open() { ButtonLore rankupCommandsLore = new ButtonLore( guiLeftClickToOpenMsg(), null); // Decimal Rank cost format. - DecimalFormat formatDecimal = new DecimalFormat("###,##0.00"); + DecimalFormat formatDecimal = Prison.get().getDecimalFormat("###,##0.00"); RankPlayerFactory rankPlayerFactory = new RankPlayerFactory(); @@ -62,14 +62,12 @@ public void open() { ButtonLore editPriceLore = new ButtonLore( createLore( guiLeftClickToOpenMsg()), - createLore( - messages.getString(MessagesConfig.StringID.spigot_gui_lore_info), + createLore( guiRanksLoreInfoMsg(), guiPriceMsg( rankCost) )); ButtonLore editTagLore = new ButtonLore(createLore( guiLeftClickToOpenMsg() ), - createLore( - messages.getString(MessagesConfig.StringID.spigot_gui_lore_info), - messages.getString(MessagesConfig.StringID.spigot_gui_lore_rank_tag) + " " + rank.getTag())); + createLore( guiRanksLoreInfoMsg(), + guiRanksLoreRankTagMsg() + " " + rank.getTag())); ButtonLore closeGUILore = new ButtonLore( guiClickToCloseMsg(), null); diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/rank/SpigotRankUPCommandsGUI.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/rank/SpigotRankUPCommandsGUI.java index 9ff9009b2..c8f398838 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/rank/SpigotRankUPCommandsGUI.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/rank/SpigotRankUPCommandsGUI.java @@ -4,28 +4,26 @@ import com.cryptomorin.xseries.XMaterial; -import tech.mcprison.prison.output.Output; import tech.mcprison.prison.ranks.data.Rank; -import tech.mcprison.prison.spigot.configs.MessagesConfig; import tech.mcprison.prison.spigot.game.SpigotPlayer; import tech.mcprison.prison.spigot.gui.guiutility.Button; import tech.mcprison.prison.spigot.gui.guiutility.ButtonLore; import tech.mcprison.prison.spigot.gui.guiutility.PrisonGUI; -import tech.mcprison.prison.spigot.gui.guiutility.SpigotGUIComponents; /** * @author GABRYCA */ -public class SpigotRankUPCommandsGUI extends SpigotGUIComponents { +public class SpigotRankUPCommandsGUI + extends SpigotGUIMessages { private final Player p; private final Rank rank; // Global Strings. private final String shiftRightClickToDelete = guiRightClickShiftToDeleteMsg(); - private final String loreInfo = messages.getString(MessagesConfig.StringID.spigot_gui_lore_info); - private final String loreCommand = messages.getString(MessagesConfig.StringID.spigot_gui_lore_command); - + private final String loreInfo = guiRanksLoreInfoMsg(); + private final String loreCommand = guiRanksLoreCommandMsg(); + public SpigotRankUPCommandsGUI(Player p, Rank rank) { this.p = p; this.rank = rank; @@ -39,7 +37,7 @@ public void open() { } if (rank.getRankUpCommands().size() == 0){ - Output.get().sendWarn(new SpigotPlayer(p), messages.getString(MessagesConfig.StringID.spigot_message_gui_ranks_rankup_commands_empty)); + guiRanksRankupCommandsEmptyMsg( new SpigotPlayer(p) ); return; } @@ -48,14 +46,14 @@ public void open() { // If the inventory is empty if (dimension == 0){ - Output.get().sendWarn(new SpigotPlayer(p), messages.getString(MessagesConfig.StringID.spigot_message_gui_error_empty)); + guiRanksErrorEmptyMsg( new SpigotPlayer(p) ); p.closeInventory(); return; } // If the dimension's too big, don't open the GUI if (dimension > 54){ - Output.get().sendWarn(new SpigotPlayer(p), messages.getString(MessagesConfig.StringID.spigot_message_gui_ranks_rankup_commands_too_many)); + guiRanksRankupCommandsTooManyMsg( new SpigotPlayer(p) ); p.closeInventory(); return; } diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/rank/SpigotRanksGUI.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/rank/SpigotRanksGUI.java index 833f664a6..cb392ec87 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/rank/SpigotRanksGUI.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/rank/SpigotRanksGUI.java @@ -7,23 +7,22 @@ import com.cryptomorin.xseries.XMaterial; -import tech.mcprison.prison.output.Output; +import tech.mcprison.prison.Prison; import tech.mcprison.prison.placeholders.PlaceholdersUtil; import tech.mcprison.prison.ranks.data.Rank; import tech.mcprison.prison.ranks.data.RankLadder; -import tech.mcprison.prison.spigot.configs.MessagesConfig; import tech.mcprison.prison.spigot.game.SpigotPlayer; import tech.mcprison.prison.spigot.gui.SpigotGUIMenuTools; import tech.mcprison.prison.spigot.gui.SpigotGUIMenuTools.GUIMenuPageData; import tech.mcprison.prison.spigot.gui.guiutility.Button; import tech.mcprison.prison.spigot.gui.guiutility.ButtonLore; import tech.mcprison.prison.spigot.gui.guiutility.PrisonGUI; -import tech.mcprison.prison.spigot.gui.guiutility.SpigotGUIComponents; /** * @author GABRYCA */ -public class SpigotRanksGUI extends SpigotGUIComponents { +public class SpigotRanksGUI + extends SpigotGUIMessages { private final Player p; private final RankLadder ladder; @@ -53,7 +52,7 @@ public void open(){ // Get the dimensions and if needed increases them if (ladder == null || ladder.getRanks().size() == 0) { - Output.get().sendWarn(new SpigotPlayer(p), messages.getString(MessagesConfig.StringID.spigot_message_gui_ranks_empty)); + guiRanksNoRanksMsg( new SpigotPlayer(p) ); return; } @@ -75,16 +74,16 @@ public void open(){ // Global Strings. String loreShiftRightClickDelete = guiRightClickShiftToDeleteMsg(); - String loreClickToManageRank = messages.getString(MessagesConfig.StringID.spigot_gui_lore_click_to_manage_rank); - String loreInfo = messages.getString(MessagesConfig.StringID.spigot_gui_lore_info); - String loreId = messages.getString(MessagesConfig.StringID.spigot_gui_lore_id); - String loreName = messages.getString(MessagesConfig.StringID.spigot_gui_lore_name); - String loreTag2 = messages.getString(MessagesConfig.StringID.spigot_gui_lore_rank_tag); + String loreClickToManageRank = guiRanksClickToManageRankMsg(); + String loreInfo = guiRanksLoreInfoMsg(); + String loreId = guiRanksLoreIdMsg(); + String loreName = guiRanksLoreNameMsg(); + String loreTag2 = guiRanksLoreRankTagMsg(); // String lorePrice3 = messages.getString(MessagesConfig.StringID.spigot_gui_lore_price); - String lorePlayersWithRank = messages.getString(MessagesConfig.StringID.spigot_gui_lore_players_at_rank); + String lorePlayersWithRank = guiRanksLorePlayersWithRankMsg(); // Decimal Rank cost format. - DecimalFormat formatDecimal = new DecimalFormat("###,##0.00"); + DecimalFormat formatDecimal = Prison.get().getDecimalFormat("###,##0.00"); // Only loop over the blocks that we need to show: for ( Rank rank : ranksDisplay ) diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/nbt/PrisonNBTUtil.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/nbt/PrisonNBTUtil.java index 7fa01561c..07b8f68f7 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/nbt/PrisonNBTUtil.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/nbt/PrisonNBTUtil.java @@ -6,8 +6,23 @@ import de.tr7zw.nbtapi.NBTItem; import tech.mcprison.prison.output.Output; +/** + *

This class manages the use of NBTs within prison so it's a common interface + * that is consistent and works properly. + *

+ * + *

This class has debug logging, but by default it is turned off to keep it from + * getting to be too verbose in the logs. The idea is that once a section of code + * is working then it does not need to have debugging enabled. So this is used + * more for testing new sections of code. + *

+ * + * @author Blue + * + */ public class PrisonNBTUtil { + private boolean enableDebugLogging = false; public NBTItem getNBT( ItemStack bukkitStack ) { NBTItem nbtItemStack = null; @@ -16,7 +31,10 @@ public NBTItem getNBT( ItemStack bukkitStack ) { try { nbtItemStack = new NBTItem( bukkitStack, true ); - nbtDebugLog( nbtItemStack, "getNbt" ); + if ( isEnableDebugLogging() ) { + nbtDebugLog( nbtItemStack, "getNbt" ); + } + } catch (Exception e) { // ignore - the bukkit item stack is not compatible with the NBT library } @@ -32,7 +50,7 @@ private void nbtDebugLog( NBTItem nbtItem, String desc ) { int sysId = System.identityHashCode(iStack); - String message = String.format( + String message = Output.stringFormat( "NBT %s ItemStack for %s: %s sysId: %d", desc, iStack.hasItemMeta() && iStack.getItemMeta().hasDisplayName() ? @@ -72,8 +90,19 @@ public void setNBTString( NBTItem nbtItem, String key, String value ) { if ( nbtItem != null ) { nbtItem.setString( key, value ); - nbtDebugLog( nbtItem, "setNBTString" ); + + if ( isEnableDebugLogging() ) { + nbtDebugLog( nbtItem, "setNBTString" ); + } } } + + + public boolean isEnableDebugLogging() { + return enableDebugLogging; + } + public void setEnableDebugLogging(boolean enableDebugLogging) { + this.enableDebugLogging = enableDebugLogging; + } } diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/placeholder/MVdWPlaceholderIntegration.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/placeholder/MVdWPlaceholderIntegration.java index e479e9630..44c020524 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/placeholder/MVdWPlaceholderIntegration.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/placeholder/MVdWPlaceholderIntegration.java @@ -1,23 +1,5 @@ package tech.mcprison.prison.spigot.placeholder; -import java.util.List; -import java.util.function.Function; - -import org.bukkit.Bukkit; - -import tech.mcprison.prison.PrisonAPI; -import tech.mcprison.prison.internal.Player; -import tech.mcprison.prison.mines.PrisonMines; -import tech.mcprison.prison.mines.managers.MineManager; -import tech.mcprison.prison.output.Output; -import tech.mcprison.prison.placeholders.PlaceHolderKey; -import tech.mcprison.prison.placeholders.PlaceholderIdentifier; -import tech.mcprison.prison.placeholders.PlaceholderIntegration; -import tech.mcprison.prison.ranks.PrisonRanks; -import tech.mcprison.prison.ranks.managers.PlayerManager; -import tech.mcprison.prison.ranks.managers.RankManager; -import tech.mcprison.prison.util.Text; - /** *

This hooks up the registration when the Prison plugin starts to run. * The MVdWPlaceholderIntegrationWrapper sets up the registrations. It should @@ -35,186 +17,187 @@ * */ public class MVdWPlaceholderIntegration - extends PlaceholderIntegration { +// extends PlaceholderIntegration + { - private MVdWPlaceholderIntegrationWrapper placeholderWrapper; +// private MVdWPlaceholderIntegrationWrapper placeholderWrapper; +// +// public MVdWPlaceholderIntegration() { +// super( "MVdWPlaceholderAPI", "MVdWPlaceholderAPI" ); +// } - public MVdWPlaceholderIntegration() { - super( "MVdWPlaceholderAPI", "MVdWPlaceholderAPI" ); - } +// @Override +// public void integrate() { +// if ( isRegistered()) { +// try { +// if ( Bukkit.getPluginManager().isPluginEnabled(getProviderName())) { +// +// +// // The integration was written for MVdW v3.0.0, but if used with older versions +// // it will fail. +// +// // This will fail if the version of mvdw is v2.x.x, which is what we want: +// Class.forName("be.maximvdw.placeholderapi.PlaceholderAPI", false, getClass().getClassLoader()); +// +// MVdWPlaceholderIntegrationWrapper wrap = new MVdWPlaceholderIntegrationWrapper(getProviderName()); +// +// placeholderWrapper = wrap; +// +// PrisonAPI.getIntegrationManager().addDeferredInitialization( this ); +// } +// } +// catch ( NoClassDefFoundError e ) { +// // ignore this exception since it means the plugin was not loaded +// Output.get().logWarn( "Attempted to enable the MVdWPlaceholderIntegration but it failed to find the " + +// "class 'be.maximvdw.placeholderapi.PlaceholderAPI'. This could happen when using " + +// "MVdWPlaceholderApi v2.x.x. Prison ONLY support MVdW v3.x.x. " + +// "&c****&7 Try using PlaceholderAPI (papi) instead. &c****" ); +// } +// catch ( IllegalStateException e ) { +// // ignore ... plugin is not loaded +// } +// catch ( Exception e ) { +// e.printStackTrace(); +// } +// } +// } - @Override - public void integrate() { - if ( isRegistered()) { - try { - if ( Bukkit.getPluginManager().isPluginEnabled(getProviderName())) { - - - // The integration was written for MVdW v3.0.0, but if used with older versions - // it will fail. - - // This will fail if the version of mvdw is v2.x.x, which is what we want: - Class.forName("be.maximvdw.placeholderapi.PlaceholderAPI", false, getClass().getClassLoader()); - - MVdWPlaceholderIntegrationWrapper wrap = new MVdWPlaceholderIntegrationWrapper(getProviderName()); - - placeholderWrapper = wrap; - - PrisonAPI.getIntegrationManager().addDeferredInitialization( this ); - } - } - catch ( NoClassDefFoundError e ) { - // ignore this exception since it means the plugin was not loaded - Output.get().logWarn( "Attempted to enable the MVdWPlaceholderIntegration but it failed to find the " + - "class 'be.maximvdw.placeholderapi.PlaceholderAPI'. This could happen when using " + - "MVdWPlaceholderApi v2.x.x. Prison ONLY support MVdW v3.x.x. " + - "&c****&7 Try using PlaceholderAPI (papi) instead. &c****" ); - } - catch ( IllegalStateException e ) { - // ignore ... plugin is not loaded - } - catch ( Exception e ) { - e.printStackTrace(); - } - } - } - - /** - *

Register both the player and mines placeholders with the MVdW plugin. - *

- */ - @Override - public void deferredInitialization() - { - boolean registered = false; - if ( PrisonRanks.getInstance() != null && PrisonRanks.getInstance().isEnabled() ) { - - PlayerManager pm = PrisonRanks.getInstance().getPlayerManager(); - if ( pm != null ) { - List placeholderPlayerKeys = pm.getTranslatedPlaceHolderKeys(); - - for ( PlaceHolderKey placeHolderKey : placeholderPlayerKeys ) { - if ( !placeHolderKey.getPlaceholder().isSuppressed() ) { - - - registerPlaceholder(placeHolderKey.getKey(), - player -> { - - PlaceholderIdentifier identifier = new PlaceholderIdentifier( placeHolderKey.getPlaceholder().name() ); - identifier.setPlayer( player.getUUID(), player.getName() ); - - if ( identifier.checkPlaceholderKey(placeHolderKey) ) { - - pm.getTranslatePlayerPlaceHolder( identifier ); - } - - - return Text.translateAmpColorCodes( identifier.getText() ); - }); - if ( !registered ) { - registered = true; - } - } - } - } - - RankManager rm = PrisonRanks.getInstance().getRankManager(); - if ( rm != null ) { - List placeholderPlayerKeys = rm.getTranslatedPlaceHolderKeys(); - - for ( PlaceHolderKey placeHolderKey : placeholderPlayerKeys ) { - if ( !placeHolderKey.getPlaceholder().isSuppressed() ) { - - - registerPlaceholder(placeHolderKey.getKey(), - player -> { - - PlaceholderIdentifier identifier = new PlaceholderIdentifier( placeHolderKey.getPlaceholder().name() ); - identifier.setPlayer( player.getUUID(), player.getName() ); - - if ( identifier.checkPlaceholderKey(placeHolderKey) ) { - - rm.getTranslateRanksPlaceHolder( identifier ); - } - - - return Text.translateAmpColorCodes( identifier.getText() ); - }); - if ( !registered ) { - registered = true; - } - } - } - } - } - - - if ( PrisonMines.getInstance() != null && PrisonMines.getInstance().isEnabled() ) { - MineManager mm = PrisonMines.getInstance().getMineManager(); - if ( mm != null ) { - List placeholderMinesKeys = mm.getTranslatedPlaceHolderKeys(); - - for ( PlaceHolderKey placeHolderKey : placeholderMinesKeys ) { - if ( !placeHolderKey.getPlaceholder().isSuppressed() ) { - - registerPlaceholder(placeHolderKey.getKey(), - player -> { - - PlaceholderIdentifier identifier = new PlaceholderIdentifier( placeHolderKey.getPlaceholder().name() ); - identifier.setPlayer( player.getUUID(), player.getName() ); - - if ( identifier.checkPlaceholderKey(placeHolderKey) ) { - - mm.getTranslateMinesPlaceholder( identifier ); - } - - return Text.translateAmpColorCodes( identifier.getText() ); - } ); - if ( !registered ) { - registered = true; - } - } - } - } - } - -// if ( registered ) { -// Output.get().logWarn( "Prison registered all placeholders with MVdWPlaceholderAPI, " + -// "but unfortunately MVdWPlaceholderAPI does not support dynamic placeholders " + -// "that are available for customizations within prison. Please try adding " + -// "Vault and PlaceholderAPI (papi) to your setup, if they do not already exist, " + -// "to enable these features."); +// /** +// *

Register both the player and mines placeholders with the MVdW plugin. +// *

+// */ +// @Override +// public void deferredInitialization() +// { +// boolean registered = false; +// if ( PrisonRanks.getInstance() != null && PrisonRanks.getInstance().isEnabled() ) { +// +// PlayerManager pm = PrisonRanks.getInstance().getPlayerManager(); +// if ( pm != null ) { +// List placeholderPlayerKeys = pm.getTranslatedPlaceHolderKeys(); +// +// for ( PlaceHolderKey placeHolderKey : placeholderPlayerKeys ) { +// if ( !placeHolderKey.getPlaceholder().isSuppressed() ) { +// +// +// registerPlaceholder(placeHolderKey.getKey(), +// player -> { +// +// PlaceholderIdentifier identifier = new PlaceholderIdentifier( placeHolderKey.getPlaceholder().name() ); +// identifier.setPlayer( player.getUUID(), player.getName() ); +// +// if ( identifier.checkPlaceholderKey(placeHolderKey) ) { +// +// pm.getTranslatePlayerPlaceHolder( identifier ); +// } +// +// +// return Text.translateAmpColorCodes( identifier.getText() ); +// }); +// if ( !registered ) { +// registered = true; +// } +// } +// } +// } +// +// RankManager rm = PrisonRanks.getInstance().getRankManager(); +// if ( rm != null ) { +// List placeholderPlayerKeys = rm.getTranslatedPlaceHolderKeys(); +// +// for ( PlaceHolderKey placeHolderKey : placeholderPlayerKeys ) { +// if ( !placeHolderKey.getPlaceholder().isSuppressed() ) { +// +// +// registerPlaceholder(placeHolderKey.getKey(), +// player -> { +// +// PlaceholderIdentifier identifier = new PlaceholderIdentifier( placeHolderKey.getPlaceholder().name() ); +// identifier.setPlayer( player.getUUID(), player.getName() ); +// +// if ( identifier.checkPlaceholderKey(placeHolderKey) ) { +// +// rm.getTranslateRanksPlaceHolder( identifier ); +// } +// +// +// return Text.translateAmpColorCodes( identifier.getText() ); +// }); +// if ( !registered ) { +// registered = true; +// } +// } +// } +// } // } - } - - - @Override - public void registerPlaceholder(String placeholder, Function action) { - if (placeholderWrapper != null) { - placeholderWrapper.registerPlaceholder( placeholder, action ); - } - } - - @Override - public boolean hasIntegrated() { - return (placeholderWrapper != null); - } - - @Override - public void disableIntegration() { - placeholderWrapper = null; - } - - @Override - public String getAlternativeInformation() { - return null; - } - - - @Override - public String getPluginSourceURL() { - return "https://www.spigotmc.org/resources/mvdwplaceholderapi.11182/"; - } +// +// +// if ( PrisonMines.getInstance() != null && PrisonMines.getInstance().isEnabled() ) { +// MineManager mm = PrisonMines.getInstance().getMineManager(); +// if ( mm != null ) { +// List placeholderMinesKeys = mm.getTranslatedPlaceHolderKeys(); +// +// for ( PlaceHolderKey placeHolderKey : placeholderMinesKeys ) { +// if ( !placeHolderKey.getPlaceholder().isSuppressed() ) { +// +// registerPlaceholder(placeHolderKey.getKey(), +// player -> { +// +// PlaceholderIdentifier identifier = new PlaceholderIdentifier( placeHolderKey.getPlaceholder().name() ); +// identifier.setPlayer( player.getUUID(), player.getName() ); +// +// if ( identifier.checkPlaceholderKey(placeHolderKey) ) { +// +// mm.getTranslateMinesPlaceholder( identifier ); +// } +// +// return Text.translateAmpColorCodes( identifier.getText() ); +// } ); +// if ( !registered ) { +// registered = true; +// } +// } +// } +// } +// } +// +//// if ( registered ) { +//// Output.get().logWarn( "Prison registered all placeholders with MVdWPlaceholderAPI, " + +//// "but unfortunately MVdWPlaceholderAPI does not support dynamic placeholders " + +//// "that are available for customizations within prison. Please try adding " + +//// "Vault and PlaceholderAPI (papi) to your setup, if they do not already exist, " + +//// "to enable these features."); +//// } +// } +// +// +// @Override +// public void registerPlaceholder(String placeholder, Function action) { +// if (placeholderWrapper != null) { +// placeholderWrapper.registerPlaceholder( placeholder, action ); +// } +// } +// +// @Override +// public boolean hasIntegrated() { +// return (placeholderWrapper != null); +// } +// +// @Override +// public void disableIntegration() { +// placeholderWrapper = null; +// } +// +// @Override +// public String getAlternativeInformation() { +// return null; +// } +// +// +// @Override +// public String getPluginSourceURL() { +// return "https://www.spigotmc.org/resources/mvdwplaceholderapi.11182/"; +// } } diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/placeholder/MVdWPlaceholderIntegrationWrapper.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/placeholder/MVdWPlaceholderIntegrationWrapper.java index 98606f626..187005edc 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/placeholder/MVdWPlaceholderIntegrationWrapper.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/placeholder/MVdWPlaceholderIntegrationWrapper.java @@ -1,27 +1,19 @@ package tech.mcprison.prison.spigot.placeholder; -import java.util.function.Function; - -import org.bukkit.Bukkit; - -import be.maximvdw.placeholderapi.PlaceholderAPI; -import tech.mcprison.prison.internal.Player; -import tech.mcprison.prison.spigot.game.SpigotPlayer; - /** * Register the non-suppressed place holders for prison. */ public class MVdWPlaceholderIntegrationWrapper { - public MVdWPlaceholderIntegrationWrapper(String providerName) { - super(); - } - - public void registerPlaceholder(String placeholder, Function action) { - PlaceholderAPI.registerPlaceholder( - Bukkit.getPluginManager().getPlugin("Prison"), placeholder, - e -> action.apply(new SpigotPlayer(e.getPlayer()))); - } +// public MVdWPlaceholderIntegrationWrapper(String providerName) { +// super(); +// } +// +// public void registerPlaceholder(String placeholder, Function action) { +// PlaceholderAPI.registerPlaceholder( +// Bukkit.getPluginManager().getPlugin("Prison"), placeholder, +// e -> action.apply(new SpigotPlayer(e.getPlayer()))); +// } } diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/placeholder/SpigotPlaceholders.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/placeholder/SpigotPlaceholders.java index f9400dee3..d95853d7b 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/placeholder/SpigotPlaceholders.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/placeholder/SpigotPlaceholders.java @@ -222,14 +222,18 @@ private String processPlaceholderIdentifier( PlaceholderIdentifier identifier ) String results = null; + // If past usage of this identifier resulted in a failure (no placeholderKey) then + // skip processing... if ( !stats.isFailedMatch() ) { if ( identifier.getPlaceholderKey() == null ) { + // Lookup the correct placeholderKey: results = processPlaceholderSearchForPlaceholderKey( identifier ); } else { + // Use the existing placeholderKey: results = processPlaceholderHavePlaceholderKey( identifier ); } @@ -237,6 +241,8 @@ private String processPlaceholderIdentifier( PlaceholderIdentifier identifier ) long nanoEnd = System.nanoTime(); + // Save the stats to the placeholderCache, and store the placeholderKey if not already + // stored in the cache. PlaceholdersStats.getInstance().setStats( identifier, stats, nanoStart, nanoEnd ); diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/sellall/SellAllUtil.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/sellall/SellAllUtil.java index 66296e8c2..8a3c8859b 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/sellall/SellAllUtil.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/sellall/SellAllUtil.java @@ -374,7 +374,7 @@ public double getPlayerMultiplier(Player p){ multiplier += multiplierExtraByPerms; // long tPoint3 = System.nanoTime(); -// DecimalFormat dFmt = new DecimalFormat( "0.0000" ); +// DecimalFormat dFmt = Prison.get().getDecimalFormat( "0.0000" ); // String debugMsg = "{sellallMult::" + dFmt.format( multiplier ) + ":t1=" + // dFmt.format( (tPoint2 - tPoint1)/1000000d ) + // ":t2=" + dFmt.format( (tPoint3 - tPoint2)/1000000 ) + "}"; @@ -440,7 +440,7 @@ public double getSellMoney(Player p, HashMap xMaterialIntege double total = earned * multiplier; if ( debug ) { - DecimalFormat dFmt = new DecimalFormat( "#,##0.00" ); + DecimalFormat dFmt = Prison.get().getDecimalFormat( "#,##0.00" ); sb.append( " earned: " ).append( dFmt.format(earned) ) .append( " mult: " ).append( dFmt.format(multiplier) ) .append( " total: " ).append( dFmt.format(total) ); @@ -558,7 +558,9 @@ private HashMap getHashMapOfPlayerInventories(Player p) { xMaterialIntegerHashMap = addInventoryToHashMap(xMaterialIntegerHashMap, backpacksUtil.getBackpack(p, id)); } } else { - xMaterialIntegerHashMap = addInventoryToHashMap(xMaterialIntegerHashMap, backpacksUtil.getBackpack(p)); + String id = null; + xMaterialIntegerHashMap = addInventoryToHashMap(xMaterialIntegerHashMap, + backpacksUtil.getBackpack(p, id)); } } @@ -1459,7 +1461,8 @@ public void removeSellableItems(Player p){ backpacksUtil.setInventory(p, removeSellableItems(p, backpacksUtil.getBackpack(p, id)), id); } } else { - backpacksUtil.setInventory(p, removeSellableItems(p, backpacksUtil.getBackpack(p))); + String id = null; + backpacksUtil.setInventory(p, removeSellableItems(p, backpacksUtil.getBackpack(p, id)), id); } } @@ -1494,7 +1497,7 @@ public void removeFromDelay(Player p){ public void removeFromAutoSellDelayAndNotify(Player p){ if (autoSellEarningsNotificationWaiting.containsKey(p) && autoSellEarningsNotificationWaiting.get(p) > 0.00){ - DecimalFormat fFmt = new DecimalFormat("#,##0.00"); + DecimalFormat fFmt = Prison.get().getDecimalFormat("#,##0.00"); String amt = fFmt.format( autoSellEarningsNotificationWaiting.get(p) ); String message = sellallAmountEarnedMsg( amt ); @@ -1802,7 +1805,7 @@ public boolean sellAllSell(Player p, boolean isUsingSign, boolean completelySile addDelayedEarningAutoSellNotification(p, money); } else if (notifyPlayerEarned){ - DecimalFormat fFmt = new DecimalFormat("#,##0.00"); + DecimalFormat fFmt = Prison.get().getDecimalFormat("#,##0.00"); String amt = fFmt.format( money ); String message = sellallAmountEarnedMsg( amt ); @@ -1886,7 +1889,7 @@ public double sellAllSell(Player p, SpigotItemStack itemStack, addDelayedEarningAutoSellNotification(p, money); } else if (notifyPlayerEarned){ - DecimalFormat fFmt = new DecimalFormat("#,##0.00"); + DecimalFormat fFmt = Prison.get().getDecimalFormat("#,##0.00"); String amt = fFmt.format( money ); String message = sellallAmountEarnedMsg( amt ) ; @@ -1902,7 +1905,7 @@ else if (notifyPlayerEarned){ } -// DecimalFormat dFmt = new DecimalFormat( "0.0000" ); +// DecimalFormat dFmt = Prison.get().getDecimalFormat( "0.0000" ); // String debugMsg = "{sellAllSell::" + dFmt.format( money ) + // ":t1=" + dFmt.format( (tPoint2 - tPoint1)/1000000d ) + // ":t2=" + dFmt.format( (tPoint3 - tPoint2)/1000000d ) + @@ -2015,7 +2018,7 @@ public ArrayList sellAllSell(Player p, ArrayList itemStack addDelayedEarningAutoSellNotification(p, money); } } else if (notifyPlayerEarned){ - DecimalFormat fFmt = new DecimalFormat("#,##0.00"); + DecimalFormat fFmt = Prison.get().getDecimalFormat("#,##0.00"); String amt = fFmt.format( money ); String message = sellallAmountEarnedMsg( amt ); diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/slime/SlimeBlockFunEventData.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/slime/SlimeBlockFunEventData.java index e0601f985..39a9a92b9 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/slime/SlimeBlockFunEventData.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/slime/SlimeBlockFunEventData.java @@ -4,6 +4,7 @@ import org.bukkit.entity.Player; +import tech.mcprison.prison.Prison; import tech.mcprison.prison.util.Text; public class SlimeBlockFunEventData { @@ -23,8 +24,8 @@ public class SlimeBlockFunEventData { private double recordBoost = 0.0; private double recordVelocity = 0.0; - private DecimalFormat sFmt = new DecimalFormat("#,##0.0"); - private DecimalFormat dFmt = new DecimalFormat("#,##0.00"); + private DecimalFormat sFmt = Prison.get().getDecimalFormat("#,##0.0"); + private DecimalFormat dFmt = Prison.get().getDecimalFormat("#,##0.00"); public SlimeBlockFunEventData( Long playerUUIDLSB, double y ) { super(); diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/slime/SlimeBlockFunEventListener.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/slime/SlimeBlockFunEventListener.java index d90b0dd46..8b4f44971 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/slime/SlimeBlockFunEventListener.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/slime/SlimeBlockFunEventListener.java @@ -16,6 +16,7 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.util.Vector; +import tech.mcprison.prison.Prison; import tech.mcprison.prison.spigot.SpigotPrison; import tech.mcprison.prison.spigot.compat.SpigotCompatibility; @@ -131,7 +132,7 @@ private Vector calculateVelocityY( double boost, Vector velocityOriginal, Player if ( velocityY > 1024.0 ) { - DecimalFormat f4Fmt = new DecimalFormat("#,##0.0000"); + DecimalFormat f4Fmt = Prison.get().getDecimalFormat("#,##0.0000"); player.sendMessage( "SlimeFun: Exceeded max velocity!! velY:" + f4Fmt.format( velocityY ) ); diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/utils/PrisonBombListener.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/utils/PrisonBombListener.java index ed2dc5c3e..f0e88deff 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/utils/PrisonBombListener.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/utils/PrisonBombListener.java @@ -8,7 +8,6 @@ import org.bukkit.event.block.Action; import org.bukkit.event.player.PlayerDropItemEvent; import org.bukkit.event.player.PlayerInteractEvent; -import org.bukkit.inventory.EquipmentSlot; import de.tr7zw.nbtapi.NBTItem; import tech.mcprison.prison.bombs.MineBombData; @@ -17,6 +16,8 @@ import tech.mcprison.prison.output.Output; import tech.mcprison.prison.spigot.block.OnBlockBreakMines; import tech.mcprison.prison.spigot.block.SpigotBlock; +import tech.mcprison.prison.spigot.compat.Compatibility.EquipmentSlot; +import tech.mcprison.prison.spigot.compat.SpigotCompatibility; import tech.mcprison.prison.spigot.game.SpigotPlayer; import tech.mcprison.prison.util.Location; @@ -75,9 +76,10 @@ public void onInteract( PlayerInteractEvent event ) { String bombName = nbtItem.getString( MineBombs.MINE_BOMBS_NBT_BOMB_KEY ); - if ( Output.get().isDebug() && nbtItem != null ) { - Output.get().logInfo( "PrisonBombListener.onInteract ntb: %s :: %s", - bombName, nbtItem.toString() ); + if ( Output.get().isDebug() ) { + Output.get().logInfo( "PrisonBombListener.onInteract bombName: &7%s&r &3:: nbt: &r%s", + bombName, + (nbtItem == null ? "&a-no-nbt-" : nbtItem.toString()) ); } Player player = event.getPlayer(); @@ -104,7 +106,10 @@ public void onInteract( PlayerInteractEvent event ) { if ( bomb == null ) { - + if ( Output.get().isDebug() ) { + Output.get().logInfo( "MineBombs: The bomb named '%s' cannot be mapped to a mine bomb.", + bombName ); + } return; } @@ -130,17 +135,28 @@ public void onInteract( PlayerInteractEvent event ) { if ( mine == null ) { // player is not in a mine, so do not allow them to trigger a mine bomb: + if ( Output.get().isDebug() ) { + Output.get().logInfo( "MineBombs: Cannot mine bombs use outside of mines." ); + } + event.setCancelled( true ); return; } else if ( !mine.hasMiningAccess( sPlayer ) ) { // Player does not have access to the mine, so don't allow them to trigger a mine bomb: + if ( Output.get().isDebug() ) { + Output.get().logInfo( "MineBombs: Player %s&r does not have access to Mine %s&r.", + sPlayer.getName(), mine.getName()); + } + event.setCancelled( true ); return; } - EquipmentSlot hand = event.getHand(); + // getHand() is not available with bukkit 1.8.8 so use the compatibility functions: + EquipmentSlot hand = SpigotCompatibility.getInstance().getHand(event); +// EquipmentSlot hand = event.getHand(); // Output.get().logInfo( "### PrisonBombListener: PlayerInteractEvent 02 " ); if ( getPrisonUtilsMineBombs().setBombInHand( player, bomb, sBlock, hand ) ) { @@ -154,8 +170,6 @@ else if ( !mine.hasMiningAccess( sPlayer ) ) { - - } } diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/utils/PrisonUtilsMineBombs.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/utils/PrisonUtilsMineBombs.java index 198a7ede8..3341b3053 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/utils/PrisonUtilsMineBombs.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/utils/PrisonUtilsMineBombs.java @@ -1,6 +1,5 @@ package tech.mcprison.prison.spigot.utils; -import java.text.DecimalFormat; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -10,7 +9,7 @@ import org.bukkit.Effect; import org.bukkit.Particle; import org.bukkit.entity.Player; -import org.bukkit.inventory.EquipmentSlot; +//import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemStack; import com.cryptomorin.xseries.XMaterial; @@ -34,6 +33,7 @@ import tech.mcprison.prison.spigot.block.PrisonItemStackNotSupportedRuntimeException; import tech.mcprison.prison.spigot.block.SpigotBlock; import tech.mcprison.prison.spigot.block.SpigotItemStack; +import tech.mcprison.prison.spigot.compat.Compatibility.EquipmentSlot; import tech.mcprison.prison.spigot.compat.SpigotCompatibility; import tech.mcprison.prison.spigot.game.SpigotPlayer; import tech.mcprison.prison.spigot.game.SpigotWorld; @@ -43,7 +43,7 @@ import tech.mcprison.prison.util.Text; public class PrisonUtilsMineBombs - extends PrisonUtilsMineBombsTasks + extends PrisonUtilsMineBombsMessages { public static final String MINE_BOMBS_LORE_1 = "&4Prison Mine Bomb:"; public static final String MINE_BOMBS_LORE_2_PREFIX = " &7"; @@ -131,7 +131,12 @@ public void utilsMineBombs( CommandSender sender, int radius = 3; - radius = Integer.parseInt( radiusSize ); + try { + radius = Integer.parseInt( radiusSize ); + } catch (NumberFormatException e) { + Output.get().logInfo( "Prison utils bomb: invalid value for radius [%s] defaulting to %d", + radiusSize, radius); + } MineBombs mBombs = MineBombs.getInstance(); @@ -745,7 +750,8 @@ public MineBombData getBombItem( String bombName ) { * @return */ public boolean setBombInHand( Player player, - MineBombData bomb, SpigotBlock sBlock, EquipmentSlot hand ) { + MineBombData bomb, SpigotBlock sBlock, + tech.mcprison.prison.spigot.compat.Compatibility.EquipmentSlot hand ) { boolean isABomb = false; // MineBombData bomb = getBombItem( player ); @@ -958,13 +964,15 @@ else if ( bomb != null ) { else { - float cooldownSeconds = cooldownTicks / 20.0f; - DecimalFormat dFmt = new DecimalFormat( "0.0" ); + mineBombsCoolDownMsg( sPlayer, cooldownTicks ); - String message = - String.format( "You cannot use another Prison Mine Bomb for %s seconds.", - dFmt.format( cooldownSeconds ) ); - sPlayer.sendMessage( message ); +// float cooldownSeconds = cooldownTicks / 20.0f; +// DecimalFormat dFmt = Prison.get().getDecimalFormat( "0.0" ); +// +// String message = +// String.format( "You cannot use another Prison Mine Bomb for %s seconds.", +// dFmt.format( cooldownSeconds ) ); +// sPlayer.sendMessage( message ); } diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/utils/PrisonUtilsMineBombsMessages.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/utils/PrisonUtilsMineBombsMessages.java new file mode 100644 index 000000000..3daf4ac78 --- /dev/null +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/utils/PrisonUtilsMineBombsMessages.java @@ -0,0 +1,45 @@ +package tech.mcprison.prison.spigot.utils; + +import java.text.DecimalFormat; + +import tech.mcprison.prison.Prison; +import tech.mcprison.prison.internal.CommandSender; +import tech.mcprison.prison.spigot.SpigotPrison; + +public abstract class PrisonUtilsMineBombsMessages + extends PrisonUtilsMineBombsTasks +{ + public PrisonUtilsMineBombsMessages() { + super(); + } + + protected void exampleMsg( CommandSender sender, String mineName ) { + SpigotPrison.getInstance().getLocaleManager() + .getLocalizable( "spigot_minebombs__" ) + .withReplacements( + mineName ) + .sendTo( sender ); + } + + protected String exampleReturnMsg( String mineTagName ) { + return SpigotPrison.getInstance().getLocaleManager() + .getLocalizable( "spigot_minebombs__" ) + .withReplacements( + mineTagName ) + .localize(); + } + + + protected void mineBombsCoolDownMsg( CommandSender sender, double cooldownTicks ) { + + double cooldownSeconds = cooldownTicks / 20.0f; + DecimalFormat dFmt = Prison.get().getDecimalFormat( "0.0" ); + + SpigotPrison.getInstance().getLocaleManager() + .getLocalizable( "spigot_minebombs__cooldown_delay" ) + .withReplacements( + dFmt.format(cooldownSeconds) ) + .sendTo( sender ); + } + +} diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/utils/PrisonUtilsMineBombsTasks.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/utils/PrisonUtilsMineBombsTasks.java index 071101d6a..a50a06d04 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/utils/PrisonUtilsMineBombsTasks.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/utils/PrisonUtilsMineBombsTasks.java @@ -20,6 +20,7 @@ import com.cryptomorin.xseries.XSound; import com.cryptomorin.xseries.particles.ParticleDisplay; +import tech.mcprison.prison.Prison; import tech.mcprison.prison.bombs.MineBombData; import tech.mcprison.prison.bombs.MineBombEffectsData; import tech.mcprison.prison.bombs.MineBombEffectsData.EffectState; @@ -496,7 +497,7 @@ public PlacedMineBombItemTask( MineBombData bomb, this.isDyanmicTag = bomb.getNameTag().contains( "{countdown}" ); this.tagName = ""; - this.dFmt = new DecimalFormat( "0.0" ); + this.dFmt = Prison.get().getDecimalFormat( "0.0" ); initializeArmorStand(); } diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/utils/tasks/PlayerAutoRankupTask.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/utils/tasks/PlayerAutoRankupTask.java new file mode 100644 index 000000000..7f5a60d61 --- /dev/null +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/utils/tasks/PlayerAutoRankupTask.java @@ -0,0 +1,62 @@ +package tech.mcprison.prison.spigot.utils.tasks; + +import java.util.ArrayList; +import java.util.List; + +import tech.mcprison.prison.Prison; +import tech.mcprison.prison.ranks.data.PlayerRank; +import tech.mcprison.prison.ranks.data.RankPlayer; +import tech.mcprison.prison.spigot.game.SpigotPlayer; +import tech.mcprison.prison.spigot.utils.tasks.PrisonUtilsTaskTypes.PrisonUtilsTaskTypRunCommand; + +public class PlayerAutoRankupTask { + + + /** + *

If the config.yml settings 'prison-mines.forced-auto-rankups' is enabled, + * then it will check to see if the player has enough money to rankup. + * This will perform all rankups; `/rankup` and `/prestige`. The prestige is + * actually just `/rankup prestiges [playerName]`. + *

+ * + * @param sPlayer + */ + public static void autoSubmitPlayerRankupTask( SpigotPlayer sPlayer, StringBuilder debugInfo ) { + + if ( Prison.get().getPlatform().getConfigBooleanFalse( "prison-mines.forced-auto-rankups" ) ) { + + RankPlayer rPlayer = sPlayer.getRankPlayer(); + + PlayerRank nextRank = rPlayer.getNextPlayerRank(); + + if ( nextRank != null ) { + + String currency = nextRank.getCurrency(); + double balance = rPlayer.getBalance( currency ); + + double rankBalance = nextRank.getRankCost(); + + if ( balance >= rankBalance ) { + + if ( debugInfo != null ) { + debugInfo.append( "(forcing auto rankup) " ); + } + + String cmd = + String.format( "rankup %s %s", + nextRank.getRank().getLadder().getName(), + rPlayer.getName() ); + + List tasks = new ArrayList<>(); + PrisonUtilsTaskTypRunCommand task = new PrisonUtilsTaskTypRunCommand( rPlayer, cmd ); + tasks.add( task ); + + PrisonUtilsTask taskRunner = new PrisonUtilsTask( tasks ); + taskRunner.submit(); + + } + } + + } + } +} diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/utils/tasks/PrisonUtilsTaskTypes.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/utils/tasks/PrisonUtilsTaskTypes.java index 1c751f5a6..f87217ddf 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/utils/tasks/PrisonUtilsTaskTypes.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/utils/tasks/PrisonUtilsTaskTypes.java @@ -144,6 +144,7 @@ public boolean isAsyc() { return false; } + @SuppressWarnings("unused") private Player getPlayer() { return player; } diff --git a/prison-spigot/src/main/resources/config.yml b/prison-spigot/src/main/resources/config.yml index a7b6c7414..a1caed820 100644 --- a/prison-spigot/src/main/resources/config.yml +++ b/prison-spigot/src/main/resources/config.yml @@ -47,12 +47,47 @@ show-alerts: true # Confirmation requires action from the player. If GUI is disabled, then it will use # the command based confiration. If confirm-enabled is false, then no confirmation # will be used. +# The value for prestige.no-prestige-value is use when a player has no prestige rank with +# the base placeholders: prison_rank, prison_rank_laddername, prison_rank_tag, and +# prison_rank_tag_laddername. If not defined, an empty String is used. prestige: enabled: true resetMoney: true resetDefaultLadder: true confirmation-enabled: true prestige-confirm-gui: true + force-sellall: false + no-prestige-value: "" + + +ranks: + gui-default-include-rankup-button: true + gui-prestiges-include-rankup-button: true + gui-others-include-rankup-button: true + + + +# WARNING: Never use the following setting to disable the vault-economy +# integration unless directed by Prison support to do so. +# WARNING: Prison will not allow the Ranks module to be enabled if a valid +# economy cannot be found and enabled succesfully. Use of this setting +# may prevent prison from finding a workable economy to use. +# This setting, integrations.prevent-economy-vault-usage, will prevent +# the use of vault for any economy transactions. Prison primarily uses vault, +# so enabling this setting could be dangerous. +# Where it can be useful, is if prison cannot communicate through vault, +# but is able to successfully communicate directly with the +# EssentialsEconomy, SaneEconomy, or GemsEconomy. Enabling this setting +# will NOT work for any other plugins. +# To test vault, run the following commands when vault economy has been +# succesfully loaded. Run these command in the console: +# /balance +# /ranks player +# Compare the total balance for the specified player from both commands. +# They should match. If not, then there is an issue with vault. +# Please contact the Prison support team through our discord server. +integrations: + prevent-economy-vault-usage: false @@ -119,6 +154,29 @@ placeholder: default-language: en_US + +# Prison defaults to a location code of en_US for the formatting of numbers +# which uses a "." for the decimal position, and "," for the thousands separator. +# Prison overries the use of the server's and Java's location code, for the +# exclusive purpose of formatting numbers, of which may not be +# controllable by admins if they are using a hosted server. +# This allows separation between the default_language codes and the +# number formatting language code. +# The problem with using some other locations, such as en_UK, is that they +# may use a Non-Blanking SPace (NBSP) for the thousands separator, of which +# Minecraft cannot display that uni-code correctly and shows it as a +# squre with the letters NB on the first line, and SP on the second. +# Examples of number formatting patterns and the results: +# #,##0 and #,##0.000 +# 1,000 and 1,000.123 +# This controls number formatting of the symbols used throughout all of +# prison. This is the only way to control the symbols used. This does not +# change the use of any of the number formatting patterns. +number-format-location: en_US + + + + # The storage engine that Prison should use to store data. # The only valid storageType is json. storageType: "json" @@ -141,7 +199,6 @@ top-stats: hesitancy-delay-penalty: true -# NEW: # Prison mines reset gap is the number of milliseconds that are used to # space out the mine resets when starting the server. This value should # not be changed unless you understand what you are doing. This value @@ -150,6 +207,23 @@ top-stats: # if more than one mine tries to reset at the same time, or close to each # other. This may be changed to ticks in the near future. #prison-mines-reset-gap: 5000 +# +# The tp-warmup will delay the player's attempt to teleport out of a mine, +# where the delay is in ticks and if they move more than the max distance +# in blocks, then the TP will be canceled. +# +# access-to-prior-mines defaults to true, and if enabled, players will +# have access to mine in the mines that are tied to ranks that preceeded +# their current rank. Note, that mines must be tied to ranks to allow +# this to work., +# +# tp-to-spawn-on-mine-resets: if enabled, players will be TP'd to the mine's +# spawn location when the mine resets or if they suffocate in the mine. +# If spawn is not set, then they will be tp'd to the top center of the mine. +# +# enable-suffocation-in-mines: defaults to false so players will not suffocate +# if they get stuck in a block. Normally this is not an issue since they will +# be TP'd out, but if that is disabled, then they risk suffocation. prison-mines: reset-gap-ms: 5000 @@ -164,7 +238,10 @@ prison-mines: enabled: false movementMaxDistance: 1.0 delayInTicks: 20 - + forced-auto-rankups: false + access-to-prior-mines: true + tp-to-spawn-on-mine-resets: true + enable-suffocation-in-mines: false # Warning: Do not use the following option. This could break the natural Bukkit @@ -245,10 +322,47 @@ prison-events: priority: LOW + +# The prisonCommandHander allows you to fine tune the Prison Command Handler +# by adding aliases for any command, prevent non-op players from using specific +# commands, viewing the command's' help, or list the blocked commands. +# +# Commands must be listed in a hierarchy format. For example the command +# `/mines tp` must be listed under the appropreiate sections as: +# mines: +# tp: +# +# For the exclude-non-ops there is a global setting that will apply the +# restriction to specified command, plus their aliases. If set to false, +# then each alias would have to be listed for them to be excluded. +# +# For each exclude-non-ops entry, you can specify the includeCmdPerms and +# the includeCmdAltPerms, both of which defaults to false. You would have +# to explicity enable them to prevent them from applying; use a value of true. +# +# For the includeCmdPerms, all perms included in the command are tested for +# each player, and if there is a hit then the command is excluded for that player. +# For the includeCmdAltPerms all are tested too, but no translations are +# applied so most may not produce any hits. +# The listed perms for each command are tested as is, with no translations. +# If the given player has a hit on the perm, then they are excluded from +# being able to use the command. +# +# OPs, including console, are bypassed and cannot be excluded from any command. +# prisonCommandHandler: exclude-worlds: - lobby - plotWorld + exclude-non-ops: + exclude-related-aliases: true + commands: + mines: + tp: + includeCmdPerms: true + includeCmdAltPerms: true + perms: + - prison.exclude.test aliases: mines: tp: diff --git a/prison-spigot/src/main/resources/plugin.yml b/prison-spigot/src/main/resources/plugin.yml index 159dbda26..9e1e90088 100644 --- a/prison-spigot/src/main/resources/plugin.yml +++ b/prison-spigot/src/main/resources/plugin.yml @@ -63,7 +63,7 @@ permissions: description: Access to the /mines rename command. mines.set: - description: Access to the /mines set command. + description: Access to various /mines set commands. mines.block: description: Access to the /mines block command. @@ -83,30 +83,18 @@ permissions: mines.list: description: Access to the /mines list command. - mines.skipreset: - description: Access to the /mines set skipReset command. - - mines.zeroblockresetdelay: - description: Access to the /mines set zeroBlockResetDelay command. - mines.stats: description: Access to the /mines stats command. mines.whereami: description: Access to the /mines whereami command. - mines.resettime: - description: Access to the /mines set resetTime command. - mines.notification: description: Access to the /mines set notification command. mines.tp: description: Access to the /mines tp command. - mines.command: - description: Access to the /mines command command. - mines.admin: description: Contains all the commands for managing mines. default: op @@ -120,11 +108,8 @@ permissions: mines.wand: true mines.list: true mines.reset: true - mines.skipreset: true - mines.zeroblockresetdelay: true mines.stats: true mines.whereami: true - mines.resettime: true mines.notification: true mines.tp: true mines.command: true