diff --git a/docs/changelog_v3.3.x.md b/docs/changelog_v3.3.x.md index 0c3a4a436..4ef8cd627 100644 --- a/docs/changelog_v3.3.x.md +++ b/docs/changelog_v3.3.x.md @@ -4,7 +4,7 @@ ## Change logs - **[v3.3.0-alpha - Current](changelog_v3.3.x.md)** - - [v3.2.0 through v3.3.0-alpha.16](prison_changelogs.md) + - [v3.2.0 through v3.3.0-alpha.17](prison_changelogs.md) * [Known Issues - Open](knownissues_v3.2.x.md) * [Known Issues - Resolved](knownissues_v3.2.x_resolved.md) @@ -14,7 +14,337 @@ These change logs represent the work that has been going on within prison. -# 3.3.0-alpha.16 2023-11-18 +# 3.3.0-alpha.17 2024-04-20 + + + + + + + + + +# 3.3.0-alpha.17 2024-04-20 + +**v3.3.0-alpha.17** 2024-04-20 + + + +* **Mines messages: Secondary placeholders. Added support for mines' messages to be able to support secondary placeholders within the language files. NOTE: Not usable at this time.** +But... this is basically useless. Within the mines language files, the vast majority of all messages are related to admin messages and are not viewable by the players. +Therefore the admin-only messages will not support the secondary placeholders since the players will never see them. +At this time, there are no messages that supports the use of these secondary placeholders, although the feature has been enabled for mines. +If a need is required, then please reach out and request such features should be enabled. At this time, effort and work will not be performed blindly upon items that will never be used, so if you see a need for this, I'd be happy to add them since you would have a need. + + + +* **Placeholder bug: The placeholder 'prison_rankup_cost_percent' uses the calculated value of a percentage, but when used with the placeholder attribute, it was found to use the price instead.** As such, the actual value returned for the placeholder was incorrect. + + +* **Player Manager: Secondary Placeholders: Setup the secondary placeholder support on the PlayerManager, but it has not been enabled yet** since secondary placeholders on placeholders do not make a lot of sense because each placeholder is only one value and they cannot contain alternative text. At least not yet. + + +* **Localizable: Secondary placeholders: Rewrote the whole support of secondary placeholders related to players.*** +Expanded the support by making them generic so other data sources can also have their own custom set of placeholders too. Such as mines. +This now supports a new interface that will provide the generic support. +Player's commands have been modified to pass a RankPlayer object, which supports the new interface. Non-player commands have not been converted since players will never see those messages (such as admin commands). + + +* **Added a comment in the ranks message files indicating that there is now some support for player based placeholders to farther customize messages.** +This also fixes an issue with the broadcast messages to use the intended player instead of the target player who is being sent the message. + + + +* **Localization: If admin adds extra parameters, or other parsing failures, happens on a message, the error will now be trapped and logged to the console without formatting.** + + + +* **Economy: For economies that prison supports that has a method to check if the player has an account, prison now tries to check if there is an account for the player before trying to use the economy.** +This could potentially prevent issues or run time failures. + + +* **Prison API: Added a few new functions to work with ItemStacks.** + + + +* **Players: Shift the function of getting a player object to the Player classes, such as CommandSender.** +This is to simplify the code and to put the functionality in one location. + + + +* **Sellall: New command: '/sellall items inspect'** +This new command will inspect what the player is holding, and dump the details so the admin can see exactly how an item/block is created, including lore and enchantments. +Eventually this information can be used to enhance the ability to sell and buy non-standard items by allowing the admins to filter on lore, enchantments, and/or NBTs. + + + +* **SpigotPlayer: Fixed a potential issue if trying to use getRankPlayer() if the ranks module is not enabled.** +Added a check to ensure it's active. +We have not seen any reports of issues related to this. + + + +* **Prison Player: Added a new sendMessage function using Lists of Strings. ** +Added a new function getPlatformPlayer() which gets a bukkit player object if the player is online. This will consolidate a lot of other duplicate code. + + +* **Mine Bombs: wrapped up the changes to enable the placement of a mine bomb when using the BlockPlaceEvent which is used when using a block for the bomb's item.** + + +* **Prison ItemStack: remove enchantments from the core ItemStack since prison cannot properly represent it in versions lower than 1.13.x**, plus it was wrong for all spigot versions greater than 1.12.x. +Added the proper enchantment functions to the SpigotItemStack object. + + +* **Initial setup of sellall lore filtering** +A little clean up. + + +**3.3.0-alpha.16c 2024-03-11** + + +* **PlaceholderAPI: Upgrade from v2.11.2 to v2.11.5** + + +* **XSeries: Upgrade from v9.8.0 to v9.9.0** + + +* **Mine bombs: add support for BlockPlacementEvent so if someone is using a Block they can use it as the mine bomb's item.** + + +* **Prison's NBT: Add support for using NBTs with bukkit's Block.** + + +* **Add support for getting the "hand" from the BlockPlaceEvent.** + + +* **Prison support listeners: added support for listening to and providing dumps for PlayerDropItemEvent, PlayerPickupItemEvent, and BlockPlaceEvent.** + + +* **Promote & Demote: Improved upon reporting issues with the command.** +There were few situations where the command would exit without reporting why, which was leading to difficulties with using the command effectively. + + +* **New feature: TopN customization now possible. The messages and placeholders that you can use are located in the core multi-language files.** +See the bottom of the files for instructions on usage. +TopN data is set to delay load so it does not lengthen the startup process. As such, it now reports that the data is being loaded so it is now clear why there are no entries in the list initially. + + +* **Mines: eliminate a field no longer used: includeInLayerCalculations.** +This was obsoleted with better use of logic. + + +* **Mine resets: Reworked how prison is selecting random blocks per layer, to properly include constraints.** +The addition of various new features in the past made a mess of the logic, so it's been cleaned up greatly so it now makes sense and should work properly now. +There is a slight risk, that as blocks are removed from a layer due to reaching it's max constraint value, that future random selections were missing blocks selections and was then inserting AIR. This fixed code now will insert a filler block which has been selected with no constraints, and the largest chance value. + + +* **mines block layerStats: rewrote to improve and get rid of the collection manipulations.** +Found potential problem with air being inserted in to mines. +Renamed a lot of uses of Location objects to include the name "location" in their variable names instead of "block". + + +* **Mines block layer: Added colors for same IDs so it's easier to read.** Added a check that sees what block actually exists. If counts of what should have spawned match whats in the mine for that layer, then it shows only one number. It shows two numbers if a block's intended spawn does not match what's in the mine. + + +* **Mine reset: added a force to the reset so it will ignore an existing mine reset and allow a new one to begin.*** +When a mine is being reset, there is no way to actually cancel it. So this allows a large mine to undergo multiple concurrent resets. Use at your own risk. + + + +* **Bug fix: the check for the time the reset has been going on was incorrect and was fixed.** +Also all the code for submitting the reset task was moved in to the mutext. Now, if the reset got hung up, this will properly terminate it and resubmit it. + + +* **File format: Eliminate the check for file types since there is only one.** +Currently there isn't a setting to specify what it should be. + + +* **Mines block layerStats: Added a new command that shows which blocks are in each layer in the mine.** +There are a lot of future enhancements that can be added to this command, such as checking the actual blocks to see if they are still there, or if there was a problem with the spawning of the blocks. + + +* **Block lists: Added the total chance percentage to be displayed with the blocks.** + + +* **File output technique: Changes to how the "replace" existing files works.** +If the file does not exist, then it opens it to create it, otherwise it truncates it. + + +* **Mine bombs: Ability to prevent a bomb's blocks from count towards the player's block totals.** + + +* **Sellall and autosell: Refinements were made to the handling of the sellall settings to better stabilize the use of the commands.** Setting status for the players were moved to the player objects and is now used in all of the related calculations so there is better stability and consistency. + + +* **Mines import: prevent the processing of an importing of a mine if there are problems with the mine's name, or locations.** + + +* **AutoSell: Bug fix: When autosell and sell on inventory is full was all turned off, it would still sell.** +This fixes some of the logic to simplify the code, and to fix those issues. + + +* **Mine skip reset messaging: Did not have it hooked up in the correct location, so the skip messages were not happening.** + + +* **Mine reset: Under heavy load when performing a mine import, there were seen occasionally errors with concurrent modification errors.** +Code was changed to minimize that possibility. + + +* **Sellall and GUI message failures: a number of messages that would indicate the player does not have access to that command were changed to remove the permission from the message.** +This was requested by a couple of admins because they did not want the players to see the internal workings that would otherwise control how the software would behave. + + + +* **Mine imports: Fix some minor issues to get this to work even better.** + + +* **Mine skip reset: If a mine is reset, send a message to players, but only if the message is defined and not empty: 'skip_reset_message='** + + + +* **Player sellall Multipliers: Fixed the ranks multiplier to include all ranks that are defined within the sellall multipliers.** +Added a new function that will gather and list all multipliers that go in to the calculation of the player's total multipliers, which includes the rank multipliers (the sellall multipliers) and also permission based multipliers. +This detailed list of the individual multipliers, is viewable for each player that is online with the command `/ranks player ` and reveals the actual details of how it's calculated. + + + +**3.3.0-alpha.16b 2024-02-24** + + +* **Import Mines: Added the ability to import mines from JetPrisonMines config files.** +`/mines import jetprisonmines help` + + +* **Prison Command Handler: using config.yml you can now change all of prison's root commands with 'prisonCommandHandler.command-roots'.** +Can now map 'prison', 'mines', 'ranks', 'gui', 'sellall' to all new command that you want. + + +* **File saving: alternative technique for saving files. Do not use!** +This is a more dangerous technique that could possibly result in lost configurations. This is being provided as a degraded service if the fail-safe technique is not working ideally on a degraded server. +This should never be used, unless directed by a prison support admin. + + + +* **Prison startup bug: There was an issue with the prison startup when there was an error and prison tried to log the error**, only to find that resources that were needed for logging were not yet loaded nor were their dependencies. This fixes some of the entanglements to allow the error messages to be properly logged. + + +* **Bug fix: GUI configuration: Found a problem that when configuring the gui initial settings, that there were problems when trying to access mines and ranks when they don't yet exist.** + + +* **Add prison debug option to filter on blockConstraints when regenerating the blocks within the mines.** + + +* **Bug fix: prison support submit: if the bukkit system cannot extract a file from the jar**, such as plugin.yml, this will prevent the failure of the command. This will allow the command to continue being processed, but may just skip the extraction. + + + +* **Placeholders: Top player rank was using the wrong ladder, which was incorrectly the prestiges rank and not the default rank.** +Correcting the rank fixed the problem. This only was an issue if the player did not have a prestige rank. + + + +* **Mines set resetTime: fix typo in the description where it shows '*all' instead of '*all*'.** + + +* **ranks ladder: applyRanksCostMultiplier command was changed to allow the value of 'true' to be used along with the value of 'apply'.** This helps to eliminate some confusion on how the command works. + + +* **Bug fix: Prison command handler. When players are de-op'd, and they do the commands such as `/ranks help` or `/mines help` it was incorrectly showing other sub commands they did not have access to.** +This now shows the correct sub commands that they have access to. + + +* **Placeholders: topn players - bug fix. If a player did not have a prestige rank, then it would cause a NPE when using the `prison_top_player_rank_prestiges_nnn_tp` placeholder.** +Just check to ensure its not null... if it is, then return an empty string. + + +* **Bug fix: Player manager startup: fixed a problem where all players were being updated** even though they did not have a name change. Only when name changes are detected are the files updated or when a new player is found. + + +* **Add debug statements to identify how each block was calculated during a mine reset.** + + +* **Bug fix: block constraints: fix an issue with the selection of lower limits.** + + +* **updated the help on the `/mines block constraint` to indicate that the layer count is originating from the top, not the bottom.** + + +* **alpha.16a - 2023-12-28** + NOTE: I just noticed that alpha.16a was never committed. So this is not the correct location of when it was set with the local builds. + + +* **Mines: Fixes an issue for when mines are disabled and they are being checked in other processes to see if they are active.** +If the instance of PrisonMines is null, then it will create a temp instance just to prevent an NPE. + + +* **Mines unit tests: Setup a new constructor for mines that is only to be used with unit tests which allows the mines to be created,** but it does not initialize them since such tasks and processes are not needed in the unit tests. +As a side effect, these two unit test run much faster since it's not trying to setup tasks. + + +* **Prison Block change: Add support for display name, which is optional.** +Setup sellall so it can use the display name now, so renamed items will not be mistaken for vanilla minecraft items. +More work needs to be done to hook up displayName to other features, such as sellall and add prison block to mines. + + +* **Bug fix: Fixed the command `/mines set accessPermission` where it was apply the given perm to all mines.** + Likewise, all mines parameter was failing to do anything. + + +* **NOTE: This alpha version "should" support spigot 20.0.4.** +After a few days, if no other issues surface pertaining to 20.0.4, or other related plugins, this will be released as a public release. + + +* **Fix issue with BlockEvent's SellAll when isAutoSellIfInventoryIsFullForBLOCKEVENTSPriority feature is enabled.** +This was not using the correct new functions that checks to see if a player can use autsell, or if they have it temporarily toggled off. This also checks to see if the player has the correct perms, if perms are enabled for the sellall event. + + +* **Breaking change in XSeries: GRASS has been changed to SHORT_GRASS for v20.0.4!** It's disappointing to say the least that after all of these damn years, XSeries screwed up and pushed a breaking change to their repo. They should have kept GRASS so they would have remained compatible will all past code and configs that had to refer to GRASS directly, but nope... they opted for causing problems. Very disappointing. +Setup a converter to automatically convert all GRASS to SHORT_GRASS as the mines are loaded. + + + +* **Upgrade XSeries from v9.7.0 to v9.8.0.** +* **Upgrade nbt-api from v2.12.0 to v2.12.2.** + + +* **config.yml - changed the default values for remapping aliases and restricting players from using commands.** +The default, which used `/mines tp` was actually causing conflict with normal usage. + + +* **AutoFeatures auto permissions: enable the ability to 'disable' the perms.** Any op'd player, if perms are enabled, will have these auto features enabled. There is no other way around this, since this is the correct behavior of OP'd players. + + +* **Mine resets: If a mine reset takes longer than 4 minutes, then that is probably a failure and the mine reset did not complete.** Therefore, reset the mine reset mutex and try again. This allows a "crashed" mine reset to auto fix itself if it can. The 4 minute wait time is LONG, but it will prevent a normal reset from being canceled and restarted in the middle of a restart. + + +* **Performance: Changed the defaults for the mine reset settings to help improve the performance on larger servers.** +The older settings would allow other commands to backup and it would appear as if there was lag happening, TPS would rarely drop below 20. This helps to keep performance a little more responsive. +The side effect is that there will need to be more "chunks" submitted which could possibly result in longer wall-time for mine resets. + + +* **Mine resets: If a suggested block is null, then set it to air. This was causing an NPE under some conditions.** + + +* **BlockEvents: Added the ability to update block events** +instead of deleting them and re-adding them. Follow directions when using '/mines blockevent update help', or whenever a block event listing is shown in game, you can now click on the commands to auto populate the block event update command... then just edit the needed changes and submit. + + +* **Upgrade XSeries to v9.7.0 from v9.4.0.** + + +* **Bug Fix: Mine resets and block constraints.** +This fixes a few issues with block constrains using min and max, along with exclude from top and bottom too. + + +* **Bug Fix: GUI ranks, mines, and prestiges were not using the default item name correctly.** It was using the template correctly, but was not translating the use of placeholders. Only name and tag are supported. +Mines: `{mineName}` and `{mineTag}` +Ranks and prestiges: `{rankName}` and `{rankTag}` + + +* **Mines: Added support for '*all*' for mine names for the following mine commands: resetDelay, resetThreshhold, notificationPerm, and accessPermission** + + +* **Localizable: Bug fix. Blanks were being removed by the use of trim() so the spaces were being ignored.** **v3.3.0-alpha.16 2023-11-18** diff --git a/docs/knownissues_v3.3.x.md b/docs/knownissues_v3.3.x.md index 1d6b7bff6..f3fc65e06 100644 --- a/docs/knownissues_v3.3.x.md +++ b/docs/knownissues_v3.3.x.md @@ -13,6 +13,14 @@ Resolved issues have been relocated to: * [Known Issues - Resolved](knownissues_v3.2.x_resolved.md) +# TODO Items for v3.3.0-alpha.16 + + +DONE: Added support for BlockPlaceEvent to allow this - editid - Mine bombs cannot be placed in a mine that is protected by world guard, which is + reporting that the player does not have access. Had to allow players to place blocks in + mines, which is not appropriate. + + # TODO Items for v3.3.0-alpha.15 diff --git a/docs/prison_changelog_v3.3.0-alpha.16.md b/docs/prison_changelog_v3.3.0-alpha.16.md index 9df2c680e..69d13a70e 100644 --- a/docs/prison_changelog_v3.3.0-alpha.16.md +++ b/docs/prison_changelog_v3.3.0-alpha.16.md @@ -23,13 +23,13 @@ The following is a highlight of changes for the alpha.16 release since the alpha * Auto Features: Many updates and enhancements. -* Sellall: Many updates and enhancements from API to GUI and autofeatures integration. +* Sellall: Many updates and enhancements from API to GUI and auto features integration. - Streamlined to work with prison's custom blocks instead of just XMaterial items. - New functionality to improve managing what's been sold, or just getting their value. Extended a lot of this new functionality to the prison APIs. - Added many new default items - Changed all of the commands under sellall to better organize like commands in to sub-commands - Rank multipliers now works for all ranks, not just prestiges. New commands to reset all multipliers for ladders (which is great if you have a few thousand prestige ranks). - - If blocks could not be sold through auto features autosell, it will generate debug mmessages so it's easier to track why blocks are not being sold. + - If blocks could not be sold through auto features autosell, it will generate debug messages so it's easier to track why blocks are not being sold. - Able to disable the "nothing to sell" message so it stops spamming the player. - For different server configs, where there are issues that prevent autosell from being used, such as other plugins placing blocks in the player's inventory, you can now force a sellall after the block break event is finished being processed. - Sellall Multipliers - Many new features and commands. Explore with `/sellall multiplier` and use the keyword `help` on each command for more details. The multiplier list can use different column widths to better support thousands of prestige ranks. @@ -64,7 +64,7 @@ The following is a highlight of changes for the alpha.16 release since the alpha * Mines - - - Mine tracer now has an option to 'clear' the whole mine, mark jjust the 'corners', or the standard full tracer. + - Mine tracer now has an option to 'clear' the whole mine, mark just the 'corners', or the standard full tracer. - Found and fixed a sync task that was a possible cause of jitters. This helps when the server is under a heavy load. - Added a `/mtop` command. `/mines top` which teleports a player to the top of the mine they are in. diff --git a/docs/prison_changelogs.md b/docs/prison_changelogs.md index f0badc17a..5b67fdb73 100644 --- a/docs/prison_changelogs.md +++ b/docs/prison_changelogs.md @@ -22,6 +22,7 @@ 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.17 - 2024-04-20](prison_changelog_v3.3.0-alpha.17.md)   - [v3.3.3-alpha.16 - 2023-11-18](prison_changelog_v3.3.0-alpha.16.md)   - [v3.3.3-alpha.15 - 2023-07-07](prison_changelog_v3.3.0-alpha.15.md)   - [v3.3.3-alpha.14 - 2023-01-23](prison_changelog_v3.3.0-alpha.14.md)   diff --git a/docs/prison_chnagelog_v3.3.0-alpha.17.md b/docs/prison_chnagelog_v3.3.0-alpha.17.md new file mode 100644 index 000000000..08b51b908 --- /dev/null +++ b/docs/prison_chnagelog_v3.3.0-alpha.17.md @@ -0,0 +1,655 @@ +[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.17](prison_changelogs.md) + + +These build logs represent the work that has been going on within prison. + + +# 3.3.0-alpha.17 2024-04-21 + + + +The following is a highlight of changes for the alpha.17 release since the alpha.16 release. + + +* Mines: Added more support for the use of '*all*' for mine names so more of the mine commands will be able to apply to all mines. + + +* **Upgrade XSeries to v9.7.0 from v9.4.0.** +* **Upgrade XSeries from v9.7.0 to v9.8.0.** +* **XSeries: Upgrade from v9.8.0 to v9.9.0** + +* **Upgrade nbt-api from v2.12.0 to v2.12.2.** + +* **PlaceholderAPI: Upgrade from v2.11.2 to v2.11.5** + + + +* **Breaking change in XSeries: GRASS has been changed to SHORT_GRASS for v20.0.4!** It's disappointing to say the least that after all of these years, XSeries screwed up and pushed a breaking change to their repo. They should have kept GRASS so they would have remained compatible will all past code and configs that had to refer to GRASS directly, but nope... they opted for causing problems. Very disappointing. +Setup a converter to automatically convert all GRASS to SHORT_GRASS as the mines are loaded. + + + +* **Bug Fix: Mine resets and block constraints.** +This fixes a few issues with block constrains using min and max, along with exclude from top and bottom too. + + +* **Bug Fix: GUI ranks, mines, and prestiges were not using the default item name correctly.** It was using the template correctly, but was not translating the use of placeholders. Only name and tag are supported. +Mines: `{mineName}` and `{mineTag}` +Ranks and prestiges: `{rankName}` and `{rankTag}` + + + +* **config.yml - changed the default values for remapping aliases and restricting players from using commands.** +The default, which used `/mines tp` was actually causing conflict with normal usage. + + +* **AutoFeatures auto permissions: enable the ability to 'disable' the perms.** Any op'd player, if perms are enabled, will have these auto features enabled. There is no other way around this, since this is the correct behavior of OP'd players. + + +* **Mine resets: If a mine reset takes longer than 4 minutes, then that is probably a failure and the mine reset did not complete.** Therefore, reset the mine reset mutex and try again. This allows a "crashed" mine reset to auto fix itself if it can. The 4 minute wait time is LONG, but it will prevent a normal reset from being canceled and restarted in the middle of a restart. + + +* **Performance: Changed the defaults for the mine reset settings to help improve the performance on larger servers.** +The older settings would allow other commands to backup and it would appear as if there was lag happening, TPS would rarely drop below 20. This helps to keep performance a little more responsive. +The side effect is that there will need to be more "chunks" submitted which could possibly result in longer wall-time for mine resets. + + +* **Mine resets: If a suggested block is null, then set it to air. This was causing an NPE under some conditions.** + + +* **BlockEvents: Added the ability to update block events** +instead of deleting them and re-adding them. Follow directions when using '/mines blockevent update help', or whenever a block event listing is shown in game, you can now click on the commands to auto populate the block event update command... then just edit the needed changes and submit. + + + +* **Mines: Fixes an issue for when mines are disabled and they are being checked in other processes to see if they are active.** +If the instance of PrisonMines is null, then it will create a temp instance just to prevent an NPE. + + + +* **Prison Block change: Add support for display name, which is optional.** +Setup sellall so it can use the display name now, so renamed items will not be mistaken for vanilla minecraft items. +More work needs to be done to hook up displayName to other features, such as sellall and add prison block to mines. + + +* **Bug fix: Fixed the command `/mines set accessPermission` where it was apply the given perm to all mines.** + Likewise, all mines parameter was failing to do anything. + + +* **NOTE: This alpha version "should" support spigot 20.0.4.** +After a few days, if no other issues surface pertaining to 20.0.4, or other related plugins, this will be released as a public release. + + +* **Fix issue with BlockEvent's SellAll when isAutoSellIfInventoryIsFullForBLOCKEVENTSPriority feature is enabled.** +This was not using the correct new functions that checks to see if a player can use autsell, or if they have it temporarily toggled off. This also checks to see if the player has the correct perms, if perms are enabled for the sellall event. + + + + +* **alpha.16a - 2023-12-28** + NOTE: I just noticed that alpha.16a was never committed. So this is not the correct location of when it was set with the local builds. + + + +* **updated the help on the `/mines block constraint` to indicate that the layer count is originating from the top, not the bottom.** + + +* **Bug fix: Player manager startup: fixed a problem where all players were being updated** even though they did not have a name change. Only when name changes are detected are the files updated or when a new player is found. + + +* **Mines set resetTime: fix typo in the description where it shows '*all' instead of '*all*'.** + + +* **ranks ladder: applyRanksCostMultiplier command was changed to allow the value of 'true' to be used along with the value of 'apply'.** This helps to eliminate some confusion on how the command works. + + +* **Bug fix: Prison command handler. When players are de-op'd, and they do the commands such as `/ranks help` or `/mines help` it was incorrectly showing other sub commands they did not have access to.** +This now shows the correct sub commands that they have access to. + + +* **Placeholders: topn players - bug fix. If a player did not have a prestige rank, then it would cause a NPE when using the `prison_top_player_rank_prestiges_nnn_tp` placeholder.** +Just check to ensure its not null... if it is, then return an empty string. + + + +* **Bug fix: prison support submit: if the bukkit system cannot extract a file from the jar**, such as plugin.yml, this will prevent the failure of the command. This will allow the command to continue being processed, but may just skip the extraction. + + + +* **Placeholders: Top player rank was using the wrong ladder, which was incorrectly the prestiges rank and not the default rank.** +Correcting the rank fixed the problem. This only was an issue if the player did not have a prestige rank. + + + +* **Bug fix: GUI configuration: Found a problem that when configuring the gui initial settings, that there were problems when trying to access mines and ranks when they don't yet exist.** + + + + +* **File saving: alternative technique for saving files. Do not use!** +This is a more dangerous technique that could possibly result in lost configurations. This is being provided as a degraded service if the fail-safe technique is not working ideally on a degraded server. +This should never be used, unless directed by a prison support admin. + + + +* **Prison startup bug: There was an issue with the prison startup when there was an error and prison tried to log the error**, only to find that resources that were needed for logging were not yet loaded nor were their dependencies. This fixes some of the entanglements to allow the error messages to be properly logged. + + + +* **Import Mines: Added the ability to import mines from JetPrisonMines config files.** +`/mines import jetprisonmines help` + + +* **Prison Command Handler: using config.yml you can now change all of prison's root commands with 'prisonCommandHandler.command-roots'.** +Can now map 'prison', 'mines', 'ranks', 'gui', 'sellall' to all new command that you want. + + + + +**3.3.0-alpha.16b 2024-02-24** + + + +* **Mine imports: Fix some minor issues to get this to work even better.** + +* **Mines import: prevent the processing of an importing of a mine if there are problems with the mine's name, or locations.** + + + +* **Mine skip reset: If a mine is reset, send a message to players, but only if the message is defined and not empty: 'skip_reset_message='** + + + +* **Player sellall Multipliers: Fixed the ranks multiplier to include all ranks that are defined within the sellall multipliers.** +Added a new function that will gather and list all multipliers that go in to the calculation of the player's total multipliers, which includes the rank multipliers (the sellall multipliers) and also permission based multipliers. +This detailed list of the individual multipliers, is viewable for each player that is online with the command `/ranks player ` and reveals the actual details of how it's calculated. + + + +* **AutoSell: Bug fix: When autosell and sell on inventory is full was all turned off, it would still sell.** +This fixes some of the logic to simplify the code, and to fix those issues. + + +* **Mine skip reset messaging: Did not have it hooked up in the correct location, so the skip messages were not happening.** + + +* **Mine reset: Under heavy load when performing a mine import, there were seen occasionally errors with concurrent modification errors.** +Code was changed to minimize that possibility. + + +* **Sellall and GUI message failures: a number of messages that would indicate the player does not have access to that command were changed to remove the permission from the message.** +This was requested by a couple of admins because they did not want the players to see the internal workings that would otherwise control how the software would behave. + + + +* **Block lists: Added the total chance percentage to be displayed with the blocks.** + + +* **File output technique: Changes to how the "replace" existing files works.** +If the file does not exist, then it opens it to create it, otherwise it truncates it. + + +* **Mine bombs: Ability to prevent a bomb's blocks from count towards the player's block totals.** + + +* **Sellall and autosell: Refinements were made to the handling of the sellall settings to better stabilize the use of the commands.** Setting status for the players were moved to the player objects and is now used in all of the related calculations so there is better stability and consistency. + + + +* **Bug fix: the check for the time the reset has been going on was incorrect and was fixed.** +Also all the code for submitting the reset task was moved in to the mutext. Now, if the reset got hung up, this will properly terminate it and resubmit it. + + +* **File format: Eliminate the check for file types since there is only one.** +Currently there isn't a setting to specify what it should be. + + +* **Mines block layerStats: Added a new command that shows which blocks are in each layer in the mine.** +There are a lot of future enhancements that can be added to this command, such as checking the actual blocks to see if they are still there, or if there was a problem with the spawning of the blocks. + + +* **Mines block layer: Added colors for same IDs so it's easier to read.** Added a check that sees what block actually exists. If counts of what should have spawned match whats in the mine for that layer, then it shows only one number. It shows two numbers if a block's intended spawn does not match what's in the mine. + + +* **Mine reset: added a force to the reset so it will ignore an existing mine reset and allow a new one to begin.*** +When a mine is being reset, there is no way to actually cancel it. So this allows a large mine to undergo multiple concurrent resets. Use at your own risk. + + + +* **Mine resets: Reworked how prison is selecting random blocks per layer, to properly include constraints.** +The addition of various new features in the past made a mess of the logic, so it's been cleaned up greatly so it now makes sense and should work properly now. +There is a slight risk, that as blocks are removed from a layer due to reaching it's max constraint value, that future random selections were missing blocks selections and was then inserting AIR. This fixed code now will insert a filler block which has been selected with no constraints, and the largest chance value. + + +* **mines block layerStats: rewrote to improve and get rid of the collection manipulations.** +Found potential problem with air being inserted in to mines. +Renamed a lot of uses of Location objects to include the name "location" in their variable names instead of "block". + + + +* **New feature: TopN customization now possible. The messages and placeholders that you can use are located in the core multi-language files.** +See the bottom of the files for instructions on usage. +TopN data is set to delay load so it does not lengthen the startup process. As such, it now reports that the data is being loaded so it is now clear why there are no entries in the list initially. + + + +* **Prison support listeners: added support for listening to and providing dumps for PlayerDropItemEvent, PlayerPickupItemEvent, and BlockPlaceEvent.** + + +* **Promote & Demote: Improved upon reporting issues with the command.** +There were few situations where the command would exit without reporting why, which was leading to difficulties with using the command effectively. + + +* **Mine bombs: add support for BlockPlacementEvent so if someone is using a Block they can use it as the mine bomb's item.** + + +* **Prison's NBT: Add support for using NBTs with bukkit's Block.** + + + +* **PlaceholderAPI: Upgrade from v2.11.2 to v2.11.5** + + +* **XSeries: Upgrade from v9.8.0 to v9.9.0** + + + +**3.3.0-alpha.16c 2024-03-11** + + + +* **Mine Bombs: wrapped up the changes to enable the placement of a mine bomb when using the BlockPlaceEvent which is used when using a block for the bomb's item.** + + +* **Prison ItemStack: remove enchantments from the core ItemStack since prison cannot properly represent it in versions lower than 1.13.x**, plus it was wrong for all spigot versions greater than 1.12.x. +Added the proper enchantment functions to the SpigotItemStack object. + + + + +* **Sellall: New command: '/sellall items inspect'** +This new command will inspect what the player is holding, and dump the details so the admin can see exactly how an item/block is created, including lore and enchantments. +Eventually this information can be used to enhance the ability to sell and buy non-standard items by allowing the admins to filter on lore, enchantments, and/or NBTs. + + + +* **SpigotPlayer: Fixed a potential issue if trying to use getRankPlayer() if the ranks module is not enabled.** +Added a check to ensure it's active. +We have not seen any reports of issues related to this. + + + + + +* **Prison API: Added a few new functions to work with ItemStacks.** + + + + +* **Localization: If admin adds extra parameters, or other parsing failures, happens on a message, the error will now be trapped and logged to the console without formatting.** + + + +* **Economy: For economies that prison supports that has a method to check if the player has an account, prison now tries to check if there is an account for the player before trying to use the economy.** +This could potentially prevent issues or run time failures. + + +* **Player Manager: Secondary Placeholders: Setup the secondary placeholder support on the PlayerManager, but it has not been enabled yet** since secondary placeholders on placeholders do not make a lot of sense because each placeholder is only one value and they cannot contain alternative text. At least not yet. + + +* **Localizable: Secondary placeholders: Rewrote the whole support of secondary placeholders related to players.*** +Expanded the support by making them generic so other data sources can also have their own custom set of placeholders too. Such as mines. +This now supports a new interface that will provide the generic support. +Player's commands have been modified to pass a RankPlayer object, which supports the new interface. Non-player commands have not been converted since players will never see those messages (such as admin commands). + + + +* **Placeholder bug: The placeholder 'prison_rankup_cost_percent' uses the calculated value of a percentage, but when used with the placeholder attribute, it was found to use the price instead.** As such, the actual value returned for the placeholder was incorrect. + + + +* **Mines messages: Secondary placeholders. Added support for mines' messages to be able to support secondary placeholders within the language files. NOTE: Not usable at this time.** +But... this is basically useless. Within the mines language files, the vast majority of all messages are related to admin messages and are not viewable by the players. +Therefore the admin-only messages will not support the secondary placeholders since the players will never see them. +At this time, there are no messages that supports the use of these secondary placeholders, although the feature has been enabled for mines. +If a need is required, then please reach out and request such features should be enabled. At this time, effort and work will not be performed blindly upon items that will never be used, so if you see a need for this, I'd be happy to add them since you would have a need. + + + + + + +* * * * * * * * * * * + + + +* **Mines messages: Secondary placeholders. Added support for mines' messages to be able to support secondary placeholders within the language files. NOTE: Not usable at this time.** +But... this is basically useless. Within the mines language files, the vast majority of all messages are related to admin messages and are not viewable by the players. +Therefore the admin-only messages will not support the secondary placeholders since the players will never see them. +At this time, there are no messages that supports the use of these secondary placeholders, although the feature has been enabled for mines. +If a need is required, then please reach out and request such features should be enabled. At this time, effort and work will not be performed blindly upon items that will never be used, so if you see a need for this, I'd be happy to add them since you would have a need. + + + +* **Placeholder bug: The placeholder 'prison_rankup_cost_percent' uses the calculated value of a percentage, but when used with the placeholder attribute, it was found to use the price instead.** As such, the actual value returned for the placeholder was incorrect. + + +* **Player Manager: Secondary Placeholders: Setup the secondary placeholder support on the PlayerManager, but it has not been enabled yet** since secondary placeholders on placeholders do not make a lot of sense because each placeholder is only one value and they cannot contain alternative text. At least not yet. + + +* **Localizable: Secondary placeholders: Rewrote the whole support of secondary placeholders related to players.*** +Expanded the support by making them generic so other data sources can also have their own custom set of placeholders too. Such as mines. +This now supports a new interface that will provide the generic support. +Player's commands have been modified to pass a RankPlayer object, which supports the new interface. Non-player commands have not been converted since players will never see those messages (such as admin commands). + + +* **Added a comment in the ranks message files indicating that there is now some support for player based placeholders to farther customize messages.** +This also fixes an issue with the broadcast messages to use the intended player instead of the target player who is being sent the message. + + + +* **Localization: If admin adds extra parameters, or other parsing failures, happens on a message, the error will now be trapped and logged to the console without formatting.** + + + +* **Economy: For economies that prison supports that has a method to check if the player has an account, prison now tries to check if there is an account for the player before trying to use the economy.** +This could potentially prevent issues or run time failures. + + +* **Prison API: Added a few new functions to work with ItemStacks.** + + + +* **Players: Shift the function of getting a player object to the Player classes, such as CommandSender.** +This is to simplify the code and to put the functionality in one location. + + + +* **Sellall: New command: '/sellall items inspect'** +This new command will inspect what the player is holding, and dump the details so the admin can see exactly how an item/block is created, including lore and enchantments. +Eventually this information can be used to enhance the ability to sell and buy non-standard items by allowing the admins to filter on lore, enchantments, and/or NBTs. + + + +* **SpigotPlayer: Fixed a potential issue if trying to use getRankPlayer() if the ranks module is not enabled.** +Added a check to ensure it's active. +We have not seen any reports of issues related to this. + + + +* **Prison Player: Added a new sendMessage function using Lists of Strings. ** +Added a new function getPlatformPlayer() which gets a bukkit player object if the player is online. This will consolidate a lot of other duplicate code. + + +* **Mine Bombs: wrapped up the changes to enable the placement of a mine bomb when using the BlockPlaceEvent which is used when using a block for the bomb's item.** + + +* **Prison ItemStack: remove enchantments from the core ItemStack since prison cannot properly represent it in versions lower than 1.13.x**, plus it was wrong for all spigot versions greater than 1.12.x. +Added the proper enchantment functions to the SpigotItemStack object. + + +* **Initial setup of sellall lore filtering** +A little clean up. + + +**3.3.0-alpha.16c 2024-03-11** + + +* **PlaceholderAPI: Upgrade from v2.11.2 to v2.11.5** + + +* **XSeries: Upgrade from v9.8.0 to v9.9.0** + + +* **Mine bombs: add support for BlockPlacementEvent so if someone is using a Block they can use it as the mine bomb's item.** + + +* **Prison's NBT: Add support for using NBTs with bukkit's Block.** + + +* **Add support for getting the "hand" from the BlockPlaceEvent.** + + +* **Prison support listeners: added support for listening to and providing dumps for PlayerDropItemEvent, PlayerPickupItemEvent, and BlockPlaceEvent.** + + +* **Promote & Demote: Improved upon reporting issues with the command.** +There were few situations where the command would exit without reporting why, which was leading to difficulties with using the command effectively. + + +* **New feature: TopN customization now possible. The messages and placeholders that you can use are located in the core multi-language files.** +See the bottom of the files for instructions on usage. +TopN data is set to delay load so it does not lengthen the startup process. As such, it now reports that the data is being loaded so it is now clear why there are no entries in the list initially. + + +* **Mines: eliminate a field no longer used: includeInLayerCalculations.** +This was obsoleted with better use of logic. + + +* **Mine resets: Reworked how prison is selecting random blocks per layer, to properly include constraints.** +The addition of various new features in the past made a mess of the logic, so it's been cleaned up greatly so it now makes sense and should work properly now. +There is a slight risk, that as blocks are removed from a layer due to reaching it's max constraint value, that future random selections were missing blocks selections and was then inserting AIR. This fixed code now will insert a filler block which has been selected with no constraints, and the largest chance value. + + +* **mines block layerStats: rewrote to improve and get rid of the collection manipulations.** +Found potential problem with air being inserted in to mines. +Renamed a lot of uses of Location objects to include the name "location" in their variable names instead of "block". + + +* **Mines block layer: Added colors for same IDs so it's easier to read.** Added a check that sees what block actually exists. If counts of what should have spawned match whats in the mine for that layer, then it shows only one number. It shows two numbers if a block's intended spawn does not match what's in the mine. + + +* **Mine reset: added a force to the reset so it will ignore an existing mine reset and allow a new one to begin.*** +When a mine is being reset, there is no way to actually cancel it. So this allows a large mine to undergo multiple concurrent resets. Use at your own risk. + + + +* **Bug fix: the check for the time the reset has been going on was incorrect and was fixed.** +Also all the code for submitting the reset task was moved in to the mutext. Now, if the reset got hung up, this will properly terminate it and resubmit it. + + +* **File format: Eliminate the check for file types since there is only one.** +Currently there isn't a setting to specify what it should be. + + +* **Mines block layerStats: Added a new command that shows which blocks are in each layer in the mine.** +There are a lot of future enhancements that can be added to this command, such as checking the actual blocks to see if they are still there, or if there was a problem with the spawning of the blocks. + + +* **Block lists: Added the total chance percentage to be displayed with the blocks.** + + +* **File output technique: Changes to how the "replace" existing files works.** +If the file does not exist, then it opens it to create it, otherwise it truncates it. + + +* **Mine bombs: Ability to prevent a bomb's blocks from count towards the player's block totals.** + + +* **Sellall and autosell: Refinements were made to the handling of the sellall settings to better stabilize the use of the commands.** Setting status for the players were moved to the player objects and is now used in all of the related calculations so there is better stability and consistency. + + +* **Mines import: prevent the processing of an importing of a mine if there are problems with the mine's name, or locations.** + + +* **AutoSell: Bug fix: When autosell and sell on inventory is full was all turned off, it would still sell.** +This fixes some of the logic to simplify the code, and to fix those issues. + + +* **Mine skip reset messaging: Did not have it hooked up in the correct location, so the skip messages were not happening.** + + +* **Mine reset: Under heavy load when performing a mine import, there were seen occasionally errors with concurrent modification errors.** +Code was changed to minimize that possibility. + + +* **Sellall and GUI message failures: a number of messages that would indicate the player does not have access to that command were changed to remove the permission from the message.** +This was requested by a couple of admins because they did not want the players to see the internal workings that would otherwise control how the software would behave. + + + +* **Mine imports: Fix some minor issues to get this to work even better.** + + +* **Mine skip reset: If a mine is reset, send a message to players, but only if the message is defined and not empty: 'skip_reset_message='** + + + +* **Player sellall Multipliers: Fixed the ranks multiplier to include all ranks that are defined within the sellall multipliers.** +Added a new function that will gather and list all multipliers that go in to the calculation of the player's total multipliers, which includes the rank multipliers (the sellall multipliers) and also permission based multipliers. +This detailed list of the individual multipliers, is viewable for each player that is online with the command `/ranks player ` and reveals the actual details of how it's calculated. + + + +**3.3.0-alpha.16b 2024-02-24** + + +* **Import Mines: Added the ability to import mines from JetPrisonMines config files.** +`/mines import jetprisonmines help` + + +* **Prison Command Handler: using config.yml you can now change all of prison's root commands with 'prisonCommandHandler.command-roots'.** +Can now map 'prison', 'mines', 'ranks', 'gui', 'sellall' to all new command that you want. + + +* **File saving: alternative technique for saving files. Do not use!** +This is a more dangerous technique that could possibly result in lost configurations. This is being provided as a degraded service if the fail-safe technique is not working ideally on a degraded server. +This should never be used, unless directed by a prison support admin. + + + +* **Prison startup bug: There was an issue with the prison startup when there was an error and prison tried to log the error**, only to find that resources that were needed for logging were not yet loaded nor were their dependencies. This fixes some of the entanglements to allow the error messages to be properly logged. + + +* **Bug fix: GUI configuration: Found a problem that when configuring the gui initial settings, that there were problems when trying to access mines and ranks when they don't yet exist.** + + +* **Add prison debug option to filter on blockConstraints when regenerating the blocks within the mines.** + + +* **Bug fix: prison support submit: if the bukkit system cannot extract a file from the jar**, such as plugin.yml, this will prevent the failure of the command. This will allow the command to continue being processed, but may just skip the extraction. + + + +* **Placeholders: Top player rank was using the wrong ladder, which was incorrectly the prestiges rank and not the default rank.** +Correcting the rank fixed the problem. This only was an issue if the player did not have a prestige rank. + + + +* **Mines set resetTime: fix typo in the description where it shows '*all' instead of '*all*'.** + + +* **ranks ladder: applyRanksCostMultiplier command was changed to allow the value of 'true' to be used along with the value of 'apply'.** This helps to eliminate some confusion on how the command works. + + +* **Bug fix: Prison command handler. When players are de-op'd, and they do the commands such as `/ranks help` or `/mines help` it was incorrectly showing other sub commands they did not have access to.** +This now shows the correct sub commands that they have access to. + + +* **Placeholders: topn players - bug fix. If a player did not have a prestige rank, then it would cause a NPE when using the `prison_top_player_rank_prestiges_nnn_tp` placeholder.** +Just check to ensure its not null... if it is, then return an empty string. + + +* **Bug fix: Player manager startup: fixed a problem where all players were being updated** even though they did not have a name change. Only when name changes are detected are the files updated or when a new player is found. + + +* **Add debug statements to identify how each block was calculated during a mine reset.** + + +* **Bug fix: block constraints: fix an issue with the selection of lower limits.** + + +* **updated the help on the `/mines block constraint` to indicate that the layer count is originating from the top, not the bottom.** + + +* **alpha.16a - 2023-12-28** + NOTE: I just noticed that alpha.16a was never committed. So this is not the correct location of when it was set with the local builds. + + +* **Mines: Fixes an issue for when mines are disabled and they are being checked in other processes to see if they are active.** +If the instance of PrisonMines is null, then it will create a temp instance just to prevent an NPE. + + +* **Mines unit tests: Setup a new constructor for mines that is only to be used with unit tests which allows the mines to be created,** but it does not initialize them since such tasks and processes are not needed in the unit tests. +As a side effect, these two unit test run much faster since it's not trying to setup tasks. + + +* **Prison Block change: Add support for display name, which is optional.** +Setup sellall so it can use the display name now, so renamed items will not be mistaken for vanilla minecraft items. +More work needs to be done to hoo up displayName to other features, such as sellall and add prison block to mines. + + +* **Bug fix: Fixed the command `/mines set accessPermission` where it was apply the given perm to all mines.** + Likewise, all mines parameter was failing to do anything. + + +* **NOTE: This alpha version "should" support spigot 20.0.4.** +After a few days, if no other issues surface pertaining to 20.0.4, or other related plugins, this will be released as a public release. + + +* **Fix issue with BlockEvent's SellAll when isAutoSellIfInventoryIsFullForBLOCKEVENTSPriority feature is enabled.** +This was not using the correct new functions that checks to see if a player can use autsell, or if they have it temporarily toggled off. This also checks to see if the player has the correct perms, if perms are enabled for the sellall event. + + +* **Breaking change in XSeries: GRASS has been changed to SHORT_GRASS for v20.0.4!** It's disappointing to say the least that after all of these damn years, XSeries screwed up and pushed a breaking change to their repo. They should have kept GRASS so they would have remained compatible will all past code and configs that had to refer to GRASS directly, but nope... they opted for causing problems. Very disappointing. +Setup a converter to automatically convert all GRASS to SHORT_GRASS as the mines are loaded. + + + +* **Upgrade XSeries from v9.7.0 to v9.8.0.** +* **Upgrade nbt-api from v2.12.0 to v2.12.2.** + + +* **config.yml - changed the default values for remapping aliases and restricting players from using commands.** +The default, which used `/mines tp` was actually causing conflict with normal usage. + + +* **AutoFeatures auto permissions: enable the ability to 'disable' the perms.** Any op'd player, if perms are enabled, will have these auto features enabled. There is no other way around this, since this is the correct behavior of OP'd players. + + +* **Mine resets: If a mine reset takes longer than 4 minutes, then that is probably a failure and the mine reset did not complete.** Therefore, reset the mine reset mutex and try again. This allows a "crashed" mine reset to auto fix itself if it can. The 4 minute wait time is LONG, but it will prevent a normal reset from being canceled and restarted in the middle of a restart. + + +* **Performance: Changed the defaults for the mine reset settings to help improve the performance on larger servers.** +The older settings would allow other commands to backup and it would appear as if there was lag happening, TPS would rarely drop below 20. This helps to keep performance a little more responsive. +The side effect is that there will need to be more "chunks" submitted which could possibly result in longer wall-time for mine resets. + + +* **Mine resets: If a suggested block is null, then set it to air. This was causing an NPE under some conditions.** + + +* **BlockEvents: Added the ability to update block events** +instead of deleting them and re-adding them. Follow directions when using '/mines blockevent update help', or whenever a block event listing is shown in game, you can now click on the commands to auto populate the block event update command... then just edit the needed changes and submit. + + +* **Upgrade XSeries to v9.7.0 from v9.4.0.** + + +* **Bug Fix: Mine resets and block constraints.** +This fixes a few issues with block constrains using min and max, along with exclude from top and bottom too. + + +* **Bug Fix: GUI ranks, mines, and prestiges were not using the default item name correctly.** It was using the template correctly, but was not translating the use of placeholders. Only name and tag are supported. +Mines: `{mineName}` and `{mineTag}` +Ranks and prestiges: `{rankName}` and `{rankTag}` + + +* **Mines: Added support for '*all*' for mine names for the following mine commands: resetDelay, resetThreshhold, notificationPerm, and accessPermission** + + +* **Localizable: Bug fix. Blanks were being removed by the use of trim() so the spaces were being ignored.** + + +**v3.3.0-alpha.16 2023-11-18** + +* Update change logs for v3.3.0-alpha.16 + + + + diff --git a/docs/prison_docs_101_setting_up_mines.md b/docs/prison_docs_101_setting_up_mines.md index 15594f294..50c61b391 100644 --- a/docs/prison_docs_101_setting_up_mines.md +++ b/docs/prison_docs_101_setting_up_mines.md @@ -6,7 +6,7 @@ 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* +*Documented updated: 2024-03-11*
@@ -22,6 +22,12 @@ Prison has a list of suggested plugins that works well with Prison, and a few th [Setting up Prison - The Basics](prison_docs_012_setting_up_prison_basics.md) +**New Command:** + +`/mines block layerStats help` +This new command will provide a layer by layer inspection of what blocks were assigned to a mine, versus what is actually in the mine currently. This is useful when confirming block constraints are working correctly, or if another block was not spawning as expected, such that there is too much AIR. + + 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. @@ -353,6 +359,30 @@ Example of a mine reset including a sealantern. Notice that there is still 19.5 +
+ + +# Allowing Players to place blocks in mines + +Normally, players are not allowed to place blocks in mines. Prison will identify that the blocks placed by players were not placed by Prison during the last mine reset, and therefore will fast-fail and ignore that block. + +By default though, prison will cancel the event, no matter what setting you have for general events, such as cancel events, or canceling the drops. + +To override this behavior, so players can actually break blocks within mines, you need to change the autoFeaturesConfig.yml file's setting: + +`ifBlockIsAlreadyCountedThenCancelEvent: false` + +You can then reload the settings without restarting the server: + `/prison reload autoFeatures` + + +By default, this setting is set to "true" so older installs of Prison will not break when they upgrade to a version that supports this feature. + +Just because prison is now ignoring the block break, this does not mean the player can break the block. This technically means that prison is doing nothing with it; not even canceling the event. So other plugins will be allowed to process the block. For example, WorldGuard may reject the player's access and prevent block breakage, and then WorldGuard will cancel the event. + +To address this issue, you would need to setup a WorldGuard region covering the whole mine, and then allowing the players to break blocks within the mine. This will allow the block to pass through to other plugins. If not other plugin does anything with the block, then bukkit will break the block normally at the end of handling the BlockBreakEvent. + +
diff --git a/docs/prison_docs_111_mine_commands.md b/docs/prison_docs_111_mine_commands.md index 346b73749..a3748cd00 100644 --- a/docs/prison_docs_111_mine_commands.md +++ b/docs/prison_docs_111_mine_commands.md @@ -6,6 +6,7 @@ This document provides information how to setup and use Mine Commands. +*Documented updated: 2024-03-11*
@@ -21,6 +22,14 @@ My personal goals to use this new feature was to dynamically build a large fores - Blue + +**New Command:** + +`/mines block layerStats help` +This new command will provide a layer by layer inspection of what blocks were assigned to a mine, versus what is actually in the mine currently. This is useful when confirming block constraints are working correctly, or if another block was not spawning as expected, such that there is too much AIR. + + +
diff --git a/gradle.properties b/gradle.properties index 01d7ea2a1..481a40c90 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.16 +version=3.3.0-alpha.17 diff --git a/prison-core/build.gradle b/prison-core/build.gradle index 8c84bad53..6dd5be946 100644 --- a/prison-core/build.gradle +++ b/prison-core/build.gradle @@ -32,6 +32,8 @@ repositories { dependencies { implementation 'org.apache.commons:commons-lang3:3.12.0' + + // https://github.com/InstantlyMoist/privatebin-java-api //implementation 'com.github.InstantlyMoist:privatebin-java-api:1.0.2' //implementation 'org.json:json:20230227' 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 d1ee294a2..8c8b4d5a5 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/Prison.java +++ b/prison-core/src/main/java/tech/mcprison/prison/Prison.java @@ -213,7 +213,13 @@ public LocaleManager getLocaleManager() { if ( this.localeManager == null ) { - this.localeManager = new LocaleManager(this, "lang/core"); + synchronized ( this ) { + if ( this.localeManager == null ) { + + this.localeManager = new LocaleManager(this, "lang/core"); + } + } + } return localeManager; } @@ -228,7 +234,13 @@ public LocaleManager getLocaleManager() { public File getModuleDataFolder() { if ( moduleDataFolder == null ) { - this.moduleDataFolder = Module.setupModuleDataFolder( "core" ); + if ( this.localeManager == null ) { + if ( moduleDataFolder == null ) { + + this.moduleDataFolder = Module.setupModuleDataFolder( "core" ); + + } + } } return moduleDataFolder; } @@ -237,18 +249,37 @@ public void setupJUnitInstance( Platform platform ) { this.platform = platform; } + + + + /** + * Initializes prison-core. In the implementations, this should be called when the plugin is + * enabled. After this is called, every getter in this class will return a value. + *

+ * Note that modules should not call this method. This is solely for the implementations. + */ + public void init(Platform platform, String minecraftVersion ) { + long startTime = System.currentTimeMillis(); + + + this.platform = platform; + this.minecraftVersion = minecraftVersion; + + } + + /** * Initializes prison-core. In the implementations, this should be called when the plugin is * enabled. After this is called, every getter in this class will return a value. *

* Note that modules should not call this method. This is solely for the implementations. */ - public boolean init(Platform platform, String minecraftVersion, File dataFolder ) { + public boolean init( File dataFolder ) { long startTime = System.currentTimeMillis(); - this.platform = platform; - this.minecraftVersion = minecraftVersion; +// this.platform = platform; +// this.minecraftVersion = minecraftVersion; this.dataFolder = dataFolder; 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 fe810f237..863195490 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/PrisonCommand.java +++ b/prison-core/src/main/java/tech/mcprison/prison/PrisonCommand.java @@ -1126,7 +1126,7 @@ public void toggleDebug(CommandSender sender, @Arg(name = "targets", def = " ", description = "Optional. Enable or disable a debugging target, or set a count down timer. " + "[on, off, targets, (count-down-timer), selective, jarScan, " + - "testPlayerUtil, testLocale, rankup, player= ] " + + "testPlayerUtil, testLocale, rankup, blockConstraints, player= ] " + "Use 'targets' to list all available targets. Use 'on' or 'off' to toggle " + "on and off individual targets, or 'all' targets if no target is specified. " + "If any targets are enabled, then debug in general will be enabled. Selective will only " + @@ -1535,7 +1535,21 @@ public void supportSubmitVersion(CommandSender sender PrisonPasteChat pasteChat = new PrisonPasteChat( getSupportName(), getSupportURLs() ); - String helpURL = pasteChat.post( text.toString() ); + String helpURL = "(Failure in running the commmand.)"; + + try { + helpURL = pasteChat.post( text.toString() ); + } + catch (Exception e) { + Output.get().logRaw( + + String.format( + "Failed to paste support info to the support server: %s " + + "raw message: [%s]", + e.getMessage(), + text.toString() + ) ); + } getSupportURLs().put( "Submit version:", helpURL ); @@ -2019,7 +2033,8 @@ public void supportListenersDump(CommandSender sender, description = "Provides a detailed list of all registered event listeners for" + "the various event types. BlockBreak listeners will include all " + "listeners that are being monitored within auto features. " + - "[all, blockBreak, chat, playerInteract]" + "[all, blockBreak, blockPlace, chat, playerDropItem, " + + "playerPickupItem, playerInteract]" ) String listener ) { 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 b093c7a5a..bc2a9213e 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 @@ -262,6 +262,13 @@ public enum AutoFeatures { permissionAutoSmelt(permissions, "prison.automanager.smelt"), permissionAutoBlock(permissions, "prison.automanager.block"), + permissionAuto__readme(permissions, "If permmissions are enabled, of which they are by default, " + + "and 'isAutoFeaturesEnabled' is enabled, then all OPs will automatically " + + "enable auto pickup, auto smelt, and auto block because bukkit will always " + + "test 'true' for any permmission when OP'd. There is no way around this, " + + "other than just turning off these perms, which is not advisable because " + + "players should not be playing as OP'd. To disable these perms, then " + + "use a value of 'disable'."), lore(options), diff --git a/prison-core/src/main/java/tech/mcprison/prison/bombs/MineBombData.java b/prison-core/src/main/java/tech/mcprison/prison/bombs/MineBombData.java index 9f2744a9d..b31b7169f 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/bombs/MineBombData.java +++ b/prison-core/src/main/java/tech/mcprison/prison/bombs/MineBombData.java @@ -203,6 +203,12 @@ public class MineBombData { + /** + * + */ + private boolean applyToPlayersBlockCount = true; + + /** *

Internal just to indicated if a mine bomb is activated or not. * This has not purpose if used in a save file. @@ -274,6 +280,9 @@ public MineBombData( String name, String itemType, String explosionShape, this.autosell = false; this.customModelData = 0; + + this.applyToPlayersBlockCount = true; + } @@ -326,6 +335,7 @@ public MineBombData clone() { cloned.getPreventedMines().add( mine ); } + cloned.setApplyToPlayersBlockCount( isApplyToPlayersBlockCount() ); for ( MineBombEffectsData soundEffect : getSoundEffects() ) { @@ -541,6 +551,13 @@ public void setActivated( boolean activated ) { this.activated = activated; } + public boolean isApplyToPlayersBlockCount() { + return applyToPlayersBlockCount; + } + public void setApplyToPlayersBlockCount(boolean applyToPlayersBlockCount) { + this.applyToPlayersBlockCount = applyToPlayersBlockCount; + } + public TreeSet getSoundEffects() { return soundEffects; } diff --git a/prison-core/src/main/java/tech/mcprison/prison/bombs/MineBombsConfigData.java b/prison-core/src/main/java/tech/mcprison/prison/bombs/MineBombsConfigData.java index 14861671c..2f39f4dec 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/bombs/MineBombsConfigData.java +++ b/prison-core/src/main/java/tech/mcprison/prison/bombs/MineBombsConfigData.java @@ -16,7 +16,7 @@ public class MineBombsConfigData * data. *

*/ - public static final int MINE_BOMB_DATA_FORMAT_VERSION = 2; + public static final int MINE_BOMB_DATA_FORMAT_VERSION = 3; private int dataFormatVersion = 0; 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 3260f727b..48de15a3e 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 @@ -23,10 +23,10 @@ public void setCmdGroup( String cmdGroup ) { } - public Player getPlayer( CommandSender sender ) { - Optional player = Prison.get().getPlatform().getPlayer( sender.getName() ); - return player.isPresent() ? player.get() : null; - } +// public Player getPlayer( CommandSender sender ) { +// Optional player = Prison.get().getPlatform().getPlayer( sender.getName() ); +// return player.isPresent() ? player.get() : null; +// } /** *

Gets a player by name. If the player is not online, then try to get them from 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 f5357509b..c30b7f975 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 @@ -52,6 +52,8 @@ public class CommandHandler { + private String rootCommmand; + private String commandFallback; // public static final String COMMAND_PRIMARY_ROOT_COMMAND = "prison"; // public static final String COMMAND_FALLBACK_PREFIX = "prison"; public static final String COMMAND_HELP_TEXT = "help"; @@ -98,14 +100,30 @@ public CommandHandler() { registerArgumentHandler(PrisonBlock.class, new BlockArgumentHandler()); + this.rootCommmand = remapRootCmdIdentifiers( DefaultSettings.COMMAND_PRIMARY_ROOT_COMMAND ); + this.commandFallback = remapRootCmdIdentifiers( DefaultSettings.COMMAND_FALLBACK_PREFIX ); + Output.get().logInfo( "&3Root command: &7/%s &3fallback-prefix: &7%s", - DefaultSettings.COMMAND_PRIMARY_ROOT_COMMAND, DefaultSettings.COMMAND_FALLBACK_PREFIX ); + rootCommmand, commandFallback ); +// Output.get().logInfo( "&3Root command: &7/%s &3fallback-prefix: &7%s", +// DefaultSettings.COMMAND_PRIMARY_ROOT_COMMAND, DefaultSettings.COMMAND_FALLBACK_PREFIX ); } - private PermissionHandler permissionHandler = (sender, permissions) -> { + public String getRootCommmand() { + return rootCommmand; + } + + public String getCommandFallback() { + return commandFallback; + } + + + + + private PermissionHandler permissionHandler = (sender, permissions) -> { for (String perm : permissions) { if (!sender.hasPermission(perm)) { return false; @@ -290,8 +308,11 @@ public ChatDisplay getHelpMessage(CommandSender sender, RegisteredCommand comman } } - if ( command.getLabel().equalsIgnoreCase( DefaultSettings.COMMAND_PRIMARY_ROOT_COMMAND ) && + + if ( command.getLabel().equalsIgnoreCase( getRootCommmand() ) && rootCommands.size() > 1 ) { +// if ( command.getLabel().equalsIgnoreCase( DefaultSettings.COMMAND_PRIMARY_ROOT_COMMAND ) && +// rootCommands.size() > 1 ) { ArrayList rootCommandsMessages = buildHelpRootCommands(); if ( rootCommandsMessages.size() > 1 ) { @@ -367,19 +388,20 @@ private ArrayList buildHelpRootCommands() { ArrayList message = new ArrayList<>(); message.add(ChatColor.DARK_AQUA + "Root Commands:"); - // Force a sorting by use of a TreeSet. Collections.sort() would not work. - TreeSet rootCommandSet = new TreeSet<>(); - // Try adding in all other root commands: - Set rootKeys = getRootCommands().keySet(); - - for ( PluginCommand rootKey : rootKeys ) { - StringBuilder sbAliases = new StringBuilder(); - - // Do not list aliases: - if ( !(rootKey.getRegisteredCommand().isAlias() && rootKey.getRegisteredCommand().getParentOfAlias() != null) ) { + // Force a sorting by use of a TreeSet. Collections.sort() would not work. + TreeSet rootCommandSet = new TreeSet<>(); + + // Try adding in all other root commands: + Set rootKeys = getRootCommands().keySet(); + + for ( PluginCommand rootKey : rootKeys ) { + StringBuilder sbAliases = new StringBuilder(); + + // Do not list aliases: + if ( !(rootKey.getRegisteredCommand().isAlias() && rootKey.getRegisteredCommand().getParentOfAlias() != null) ) { // String isAlias = rootKey.getRegisteredCommand().isAlias() ? ChatColor.DARK_AQUA + " Alias" : ""; - + // if ( rootKey.getRegisteredCommand().getRegisteredAliases().size() > 0 ) { // for ( RegisteredCommand alias : rootKey.getRegisteredCommand().getRegisteredAliases() ) { // @@ -391,22 +413,22 @@ private ArrayList buildHelpRootCommands() { // new StringBuilder().append( ChatColor.DARK_AQUA ). // append( "Aliases: " ).append( ChatColor.AQUA )); // } - String rootCmd = - String.format( "%s %s", - rootKey.getUsage(), sbAliases.toString() ); - - rootCommandSet.add( rootCmd ); - } + String rootCmd = + String.format( "%s %s", + rootKey.getUsage(), sbAliases.toString() ); + + rootCommandSet.add( rootCmd ); + } - - } - - for (String rootCmd : rootCommandSet) { - message.add(rootCmd); - } - - return message; - } + + } + + for (String rootCmd : rootCommandSet) { + message.add(rootCmd); + } + + return message; + } /** * This builds a list of all the aliases that exist. @@ -647,11 +669,15 @@ private RegisteredCommand commandRegisterConfig( Method method, Command commandA private RegisteredCommand commandRegisterConfig( Method method, Command commandAnno, Object methodInstance, String alias ) { - String[] identifiers = ( alias == null ? commandAnno.identifier() : alias).split(" "); + + String cmdIdentifiers = remapRootCmdIdentifiers( commandAnno.identifier() ); + String cmdAlias = remapRootCmdIdentifiers( alias ); + + String[] identifiers = ( cmdAlias == null ? cmdIdentifiers : cmdAlias).split(" "); - if (identifiers.length == 0) { - throw new RegisterCommandMethodException(method, "Invalid identifiers"); - } + if (identifiers.length == 0) { + throw new RegisterCommandMethodException(method, "Invalid identifiers"); + } String label = identifiers[0]; @@ -738,7 +764,28 @@ private RegisteredCommand commandRegisterConfig( Method method, Command commandA } - public static String[] addConfigAliases( String label, String[] aliases ) + public static String remapRootCmdIdentifiers(String identifier) { + + if ( identifier != null ) { + + int idx = identifier.indexOf( " " ); + String root = idx == -1 ? identifier : identifier.substring( 0, idx ); + + String key = "prisonCommandHandler.command-roots." + root; + + String newRoot = Prison.get().getPlatform().getConfigString( key ); + + if ( newRoot != null && !root.equals(newRoot) ) { + + identifier = newRoot + + (idx == -1 ? "" : identifier.substring(idx)); + } + } + + return identifier; + } + + public static String[] addConfigAliases( String label, String[] aliases ) { String[] results = aliases; @@ -801,19 +848,28 @@ private void hasCommandAccess( CommandSender sender, RegisteredCommand rootComma 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 ); + boolean hasAccess = rootCommand.testPermission(sender); - if ( results.isAccess() && sLabelAlias != null ) { - - commandAccessPermChecks( sender, rootCommand.getParentOfAlias(), sLabelAlias, results ); + if ( !hasAccess ) { + results.setAccess( false ); + } + else { + + 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 ); + } } + } diff --git a/prison-core/src/main/java/tech/mcprison/prison/file/FileIO.java b/prison-core/src/main/java/tech/mcprison/prison/file/FileIO.java index f6564604a..3975f1b0c 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/file/FileIO.java +++ b/prison-core/src/main/java/tech/mcprison/prison/file/FileIO.java @@ -4,6 +4,7 @@ import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; +import java.nio.file.StandardOpenOption; import java.text.SimpleDateFormat; import java.util.Arrays; import java.util.Date; @@ -85,31 +86,89 @@ protected void saveFile( File file, String data ) // String tempFileName = file.getName() + "." + getTimestampFormat() + ".tmp"; // File tempFile = new File(file.getParentFile(), tempFileName); - try - { - // Write as a .tmp file: + boolean disableAdvancedSaves = + Prison.get().getPlatform().getConfigBooleanFalse( + "storage.file.disable-advanced-saves.enabled" ); + + if ( !disableAdvancedSaves ) { - // Add json data to lines, splitting on \n: - List lines = Arrays.asList( data.split( "\n" )); + try + { + // Write as a .tmp file: + + // Add json data to lines, splitting on \n: + List lines = Arrays.asList( data.split( "\n" )); + + // Write as an UTF-8 stream: + Files.write( tempFile.toPath(), lines, StandardCharsets.UTF_8 ); + +// Files.write( tempFile.toPath(), data.getBytes() ); + + // If original target exists, then delete it: + if ( file.exists() ) + { + file.delete(); + } + + tempFile.renameTo( file ); + } + catch ( IOException e ) + { + logException( "Failed to create file", file, e ); + } + } + else { - // Write as an UTF-8 stream: - Files.write( tempFile.toPath(), lines, StandardCharsets.UTF_8 ); + boolean keepTempFiles = + Prison.get().getPlatform().getConfigBooleanFalse( + "storage.file.disable-advanced-saves.debug-keep-temp-files" ); + try + { + // Write as a .tmp file: + + // Add json data to lines, splitting on \n: + List lines = Arrays.asList( data.split( "\n" )); + + + // Write to both temp file and the actual file: + + // Write as an UTF-8 stream: + Files.write( tempFile.toPath(), lines, StandardCharsets.UTF_8 ); + + boolean exists = file.exists(); + + StandardOpenOption sooW = StandardOpenOption.WRITE; + StandardOpenOption sooTe = exists ? + StandardOpenOption.TRUNCATE_EXISTING : + StandardOpenOption.CREATE; + + Files.write( file.toPath(), lines, StandardCharsets.UTF_8, sooW, sooTe ); + + // Files.write( tempFile.toPath(), data.getBytes() ); - - // If original target exists, then delete it: - if ( file.exists() ) + + // If original target exists, then delete it: +// if ( file.exists() ) +// { +// file.delete(); +// } +// +// tempFile.renameTo( file ); + + + if ( !keepTempFiles ) { + tempFile.delete(); + } + + } + catch ( IOException e ) { - file.delete(); + logException( "Failed to create file", file, e ); } - - tempFile.renameTo( file ); - } - catch ( IOException e ) - { - logException( "Failed to create file", file, e ); } + } } diff --git a/prison-core/src/main/java/tech/mcprison/prison/internal/CommandSender.java b/prison-core/src/main/java/tech/mcprison/prison/internal/CommandSender.java index de11fcc05..50b5a53c7 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/internal/CommandSender.java +++ b/prison-core/src/main/java/tech/mcprison/prison/internal/CommandSender.java @@ -18,6 +18,10 @@ package tech.mcprison.prison.internal; +import java.util.List; + +import tech.mcprison.prison.ranks.data.RankPlayer; + /** * Represents any entity that may send commands and receive output. * @@ -37,18 +41,18 @@ public interface CommandSender /** * Returns the name of the command sender. */ - String getName(); + public String getName(); /** * Force a commandSender to send a command */ - void dispatchCommand(String command); + public void dispatchCommand(String command); /** * Returns true if the command sender can show colors to the viewer. * This is not always the case, especially when using command blocks and online consoles. */ - boolean doesSupportColors(); + public boolean doesSupportColors(); /** * Sends a message to the command sender. @@ -57,7 +61,7 @@ public interface CommandSender * * @param message The message to send. May include color codes, amp-prefixed. */ - void sendMessage(String message); + public void sendMessage(String message); /** * Sends multiple messages to the command sender. @@ -66,14 +70,23 @@ public interface CommandSender * @param messages The array containing each message. * @see #sendMessage(String) */ - void sendMessage(String[] messages); + public void sendMessage(String[] messages); + /** + * Sends multiple messages to the command sender. + * Each message will be shown on its own line. + * + * @param messages The List containing each message. + * @see #sendMessage(String) + */ + public void sendMessage(List messages); + /** * Send a raw JSON message to the sender. * * @param json The JSON message. Must be in proper format. */ - void sendRaw(String json); + public void sendRaw(String json); // public boolean isOp(); @@ -90,4 +103,22 @@ public interface CommandSender public boolean isPlayer(); + public List getSellAllMultiplierListings(); + + + /** + *

Returns an instance of a Platform player object, which is is + * different than just a RankPlayer since it was built with the wrapper of + * SpigotPlayer (when running on spigot). So this object is actually backed + * by the the actual player object too. + *

+ * + * @return Player + */ + public Player getPlatformPlayer(); + + + public RankPlayer getRankPlayer(); + + } diff --git a/prison-core/src/main/java/tech/mcprison/prison/internal/ItemStack.java b/prison-core/src/main/java/tech/mcprison/prison/internal/ItemStack.java index 880d0cb85..c49d47b4b 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/internal/ItemStack.java +++ b/prison-core/src/main/java/tech/mcprison/prison/internal/ItemStack.java @@ -20,9 +20,7 @@ import java.util.ArrayList; import java.util.Arrays; -import java.util.HashMap; import java.util.List; -import java.util.Map; import org.apache.commons.lang3.StringUtils; @@ -41,14 +39,14 @@ public class ItemStack { private int amount; private PrisonBlock material; private List lore; - private Map enchantments; +// private Map enchantments; protected ItemStack() { super(); this.lore = new ArrayList<>(); - this.enchantments = new HashMap<>(); +// this.enchantments = new HashMap<>(); } public ItemStack(String displayName, int amount, PrisonBlock material, String... lore) { @@ -56,7 +54,7 @@ public ItemStack(String displayName, int amount, PrisonBlock material, String... this.amount = amount; this.material = material; this.lore = new ArrayList<>(Arrays.asList(lore)); - this.enchantments = new HashMap<>(); +// this.enchantments = new HashMap<>(); } public ItemStack(int amount, PrisonBlock material, String... lore) { @@ -114,21 +112,21 @@ public void setLore( List lore ) { this.lore = lore; } - public Map getEnchantments() { - return enchantments; - } - - public void addEnchantment(int enchantment, int level) { - enchantments.put(enchantment, level); - } - - public boolean hasEnchantments() { - return !enchantments.isEmpty(); - } - - public boolean hasEnchantment(int enchantment) { - return enchantments.containsKey(enchantment); - } +// public Map getEnchantments() { +// return enchantments; +// } +// +// public void addEnchantment(Object enchantment, int level) { +// enchantments.put(enchantment, level); +// } +// +// public boolean hasEnchantments() { +// return !enchantments.isEmpty(); +// } +// +// public boolean hasEnchantment(int enchantment) { +// return enchantments.containsKey(enchantment); +// } @Override public boolean equals(Object o) { if (this == o) { @@ -157,6 +155,8 @@ public boolean hasEnchantment(int enchantment) { @Override public String toString() { return "ItemStack{" + "displayName='" + displayName + '\'' + ", amount=" + amount - + ", material=" + material + ", lore=" + lore + ", enchantments=" + enchantments + '}'; + + ", material=" + material + ", lore=" + lore + + "}"; + //", enchantments=" + enchantments + '}'; } } diff --git a/prison-core/src/main/java/tech/mcprison/prison/internal/Player.java b/prison-core/src/main/java/tech/mcprison/prison/internal/Player.java index c9b44fced..a0c7e61ae 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/internal/Player.java +++ b/prison-core/src/main/java/tech/mcprison/prison/internal/Player.java @@ -78,12 +78,12 @@ public interface Player /** * Adds an {@link ItemStack} to the player's inventory. */ - void give(ItemStack itemStack); + public void give(ItemStack itemStack); /** * Returns the player's current {@link Location}. */ - Location getLocation(); + public Location getLocation(); /** @@ -105,31 +105,31 @@ public interface Player * * @param location The new {@link Location}. */ - void teleport(Location location); + public void teleport(Location location); /** * @return Returns true if the player is online, false otherwise. */ - boolean isOnline(); + public boolean isOnline(); /** * Sets the player's visible scoreboard. * * @param scoreboard The {@link Scoreboard} to show the player. */ - void setScoreboard(Scoreboard scoreboard); + public void setScoreboard(Scoreboard scoreboard); /** * Returns the player's current {@link Gamemode} */ - Gamemode getGamemode(); + public Gamemode getGamemode(); /** * Changes the player's {@link Gamemode} to the specified value * * @param gamemode the new gamemode */ - void setGamemode(Gamemode gamemode); + public void setGamemode(Gamemode gamemode); /** * Returns this player's locale. @@ -137,10 +137,11 @@ public interface Player * @return An {@link Optional} containing the locale of this player, or empty if it couldn't be * retrieved. */ - Optional getLocale(); + public Optional getLocale(); - @Override default boolean doesSupportColors() { + @Override + public default boolean doesSupportColors() { return true; } @@ -149,7 +150,7 @@ public interface Player * inventory. May not be necessary on all platforms but should be used where ever the player inventory * is modified */ - void updateInventory(); + public void updateInventory(); // /** @@ -176,5 +177,7 @@ public interface Player public void incrementMinecraftStatsMineBlock( Player player, String blockName, int quantity ); public void incrementMinecraftStatsDropCount( Player player, String blockName, int quantity); + +// public RankPlayer getRankPlayer(); } diff --git a/prison-core/src/main/java/tech/mcprison/prison/internal/block/MineTargetPrisonBlock.java b/prison-core/src/main/java/tech/mcprison/prison/internal/block/MineTargetPrisonBlock.java index 7af56bcf7..f812ed5fd 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/internal/block/MineTargetPrisonBlock.java +++ b/prison-core/src/main/java/tech/mcprison/prison/internal/block/MineTargetPrisonBlock.java @@ -24,6 +24,10 @@ public class MineTargetPrisonBlock private boolean ignoreAllBlockEvents = false; + private transient boolean checkAir; + private transient boolean checkSame; + + public MineTargetPrisonBlock( PrisonBlockStatusData prisonBlock, World world, @@ -42,6 +46,19 @@ public MineTargetPrisonBlock( this.isCorner = isCorner; } + public MineTargetPrisonBlock( + PrisonBlockStatusData prisonBlock, + Location targetLocation ) { + this( prisonBlock, targetLocation.getWorld(), + targetLocation.getBlockX(), + targetLocation.getBlockY(), + targetLocation.getBlockZ(), + targetLocation.isEdge(), + targetLocation.isCorner() + ); + + } + @Override public String toString() { return "MineTargetPrisonBlock: key= " + getBlockKey().toString() + @@ -191,6 +208,20 @@ public void setIgnoreAllBlockEvents( boolean ignoreAllBlockEvents ) { this.ignoreAllBlockEvents = ignoreAllBlockEvents; } + public boolean isCheckAir() { + return checkAir; + } + public void setCheckAir(boolean checkAir) { + this.checkAir = checkAir; + } + + public boolean isCheckSame() { + return checkSame; + } + public void setCheckSame(boolean checkSame) { + this.checkSame = checkSame; + } + @Override public int compareTo( MineTargetPrisonBlock block ) { return block.getBlockKey().compareTo( block.getBlockKey() ); 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 2f997747a..be4af9ed8 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 @@ -45,6 +45,7 @@ public class PrisonBlock private Double salePrice = null; private Double purchasePrice = null; + private boolean loreAllowed = false; static { @@ -77,6 +78,11 @@ public boolean isCustomBlockType() { public PrisonBlock( String blockName ) { this( PrisonBlockType.minecraft, blockName, 0, 0); } + public PrisonBlock( String blockName, String displayName ) { + this( PrisonBlockType.minecraft, blockName, 0, 0); + + setDisplayName( displayName ); + } public PrisonBlock( PrisonBlockType blockType, String blockName ) { this( blockType, blockName, 0, 0); } @@ -169,8 +175,16 @@ public String getBlockNameFormal() { * @return */ public String getBlockNameSearch() { - return getBlockType() != PrisonBlockType.minecraft ? - getBlockType().name() + ":" + getBlockName() : getBlockName(); + + String blockType = getBlockType() != PrisonBlockType.minecraft ? + getBlockType().name() + ":" : ""; + + String blockName = getBlockName().toLowerCase(); + + String displayName = getDisplayName() != null ? + ":" + getDisplayName().toLowerCase() : ""; + + return blockType + blockName + displayName; } @@ -359,7 +373,17 @@ public int compareTo( PrisonBlock block ) results = 1; } else { - results = getBlockName().compareToIgnoreCase( block.getBlockName() ); + + results = getBlockType() == block.getBlockType() ? 0 : 1; + + if ( results == 0 ) { + + results = getBlockName().compareToIgnoreCase( block.getBlockName() ); + + if ( results == 0 && getDisplayName() != null && block.getDisplayName() != null ) { + results = getDisplayName().compareToIgnoreCase( block.getDisplayName() ); + } + } } return results; @@ -503,4 +527,11 @@ public ItemStack getItemStack( int blockQuantity ) { return results; } + public boolean isLoreAllowed() { + return loreAllowed; + } + public void setLoreAllowed(boolean loreAllowed) { + this.loreAllowed = loreAllowed; + } + } 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 8844ecc11..0dab4b8d0 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 @@ -1,6 +1,8 @@ package tech.mcprison.prison.internal.block; import java.text.DecimalFormat; +import java.util.ArrayList; +import java.util.List; import tech.mcprison.prison.Prison; import tech.mcprison.prison.internal.block.PrisonBlock.PrisonBlockType; @@ -12,6 +14,9 @@ public abstract class PrisonBlockStatusData { private PrisonBlockType blockType; private String blockName; + // displayName is an optional custom name + private String displayName; + private double chance; private int constraintMin; @@ -37,13 +42,32 @@ public abstract class PrisonBlockStatusData { private boolean gravity = false; +// private transient boolean includeInLayerCalculations; + + + private transient String altAlias; + private transient String altColorCode; + private transient int altCountVirtual; + private transient int altCountPhysical; + + + public PrisonBlockStatusData( + PrisonBlockType blockType, String blockName, String displayName, + double chance, long blockCountTotal ) { + this( blockType, blockName, chance, blockCountTotal ); + + this.displayName = displayName; + } - public PrisonBlockStatusData( PrisonBlockType blockType, String blockName, double chance, long blockCountTotal ) { + public PrisonBlockStatusData( + PrisonBlockType blockType, String blockName, double chance, long blockCountTotal ) { super(); this.blockType = blockType; this.blockName = blockName; + this.displayName = null; + this.chance = chance; this.constraintMin = 0; @@ -65,10 +89,18 @@ public PrisonBlockStatusData( PrisonBlockType blockType, String blockName, doubl this.rangeBlockCountHighLimit = -1; this.gravity = checkGravityAffects( blockName ); + +// this.includeInLayerCalculations = true; } + /** + *

Checks to see if both the blockType and the blockName are equal, + * and if there is a displayName set, then both need to have their + * displayName is also set to the same value. + *

+ */ @Override public boolean equals( Object obj ) { @@ -77,7 +109,15 @@ public boolean equals( Object obj ) if ( obj instanceof PrisonBlockStatusData ) { PrisonBlockStatusData pbsBlock = (PrisonBlockStatusData) obj; - results = getBlockName().equalsIgnoreCase( pbsBlock.getBlockName() ); + results = getBlockType() == getBlockType() && + getBlockName().equalsIgnoreCase( pbsBlock.getBlockName() ); + + if ( results ) { + + results = getDisplayName() == null && pbsBlock.getDisplayName() == null || + getDisplayName() != null && pbsBlock.getDisplayName() != null && + getDisplayName().equalsIgnoreCase( pbsBlock.getDisplayName() ); + } } return results; @@ -402,6 +442,13 @@ public void setBlockName( String blockName ) { this.blockName = blockName; } + public String getDisplayName() { + return displayName; + } + public void setDisplayName(String displayName) { + this.displayName = displayName; + } + public PrisonBlockType getBlockType() { return blockType; } @@ -507,4 +554,139 @@ public void setGravity( boolean gravity ) { this.gravity = gravity; } + + +// public boolean isIncludeInLayerCalculations() { +// return includeInLayerCalculations; +// } +// public void setIncludeInLayerCalculations(boolean includeInLayerCalculations) { +// this.includeInLayerCalculations = includeInLayerCalculations; +// } + + + /** + *

This is only used when calculating which blocks should be placed + * in each layer, one layer at a time. This would be used if a block is + * usable for a layer, but it has exceeded it's max constraint, so a + * value of 'false' would then prevent this block from being used, but + * will allow the stats to continue to collect the max usable range + * in which this block could be placed. + *

+ * + * @param targetBlocks + * @return + */ + public int getRandomBlockPositionInRangeUnmatched( + List targetBlocks) { + return getRandomBlockPositionInRange( targetBlocks, false ); + } + + public int getRandomBlockPositionInRangeMatched( + List targetBlocks) { + return getRandomBlockPositionInRange( targetBlocks, true ); + } + + /** + *

This function will select a block position from the + * targetBlocks list that is either of the same block type, or + * that is not equal to the same block type. This is to + * find valid blocks to either replace, or to add to the + * list without randomly trying to select a block to try. + *

+ * + * @param targetBlocks + * @param matched + * @return + */ + private int getRandomBlockPositionInRange( + List targetBlocks, + boolean matched) { + int position = -1; + + int rangeLow = getRangeBlockCountLowLimit(); + int rangeHigh = getRangeBlockCountHighLimit(); + + List choices = new ArrayList<>(); + + for ( int i = rangeLow; i < rangeHigh && i < targetBlocks.size(); i++ ) { + String bName = targetBlocks.get( i ).getPrisonBlock().getBlockName(); + + if ( matched == getBlockName().equals( bName ) ) { + choices.add( i ); + } + } + + if ( choices.size() > 0 ) { + int p = (int) (Math.random() * choices.size()); + + position = choices.get( p ); + } + + return position; + } + + public void setAltValues( int i ) { + + String codes = "abcdefghijklmnopqrstuvwxyz"; + String colors = "12345789abcde"; + + int codePos = i % codes.length(); + int codeFactor = i / codes.length(); + + String code = codePos == codes.length() ? + codes.substring( codePos ) : + codes.substring( codePos, codePos + 1 ); + + String alias = code + + (codeFactor == 0 ? + "" : + codeFactor); + setAltAlias( alias ); + + int colorPos = i % colors.length(); + String color = colorPos == colors.length() ? + colors.substring( colorPos ) : + colors.substring( colorPos, colorPos + 1 ); + setAltColorCode( "&" + color ); + + setAltCountVirtual( 0 ); + setAltCountPhysical( 0 ); + + } + + public void resetAltValues() { + + setAltCountVirtual( 0 ); + setAltCountPhysical( 0 ); + + } + + public String getAltAlias() { + return altAlias; + } + public void setAltAlias(String altAlias) { + this.altAlias = altAlias; + } + + public String getAltColorCode() { + return altColorCode; + } + public void setAltColorCode(String altColorCode) { + this.altColorCode = altColorCode; + } + + public int getAltCountVirtual() { + return altCountVirtual; + } + public void setAltCountVirtual(int altCountVirtual) { + this.altCountVirtual = altCountVirtual; + } + + public int getAltCountPhysical() { + return altCountPhysical; + } + public void setAltCountPhysical(int altCountPhysical) { + this.altCountPhysical = altCountPhysical; + } + } 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 d0ac90ea1..94c3d8f51 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 @@ -359,6 +359,9 @@ public void autoCreateMineLinerAssignment( List rankMineNames, boolean forceLinersBottom, boolean forceLinersWalls ); + public String autoCreateMineLinerAssignment(ModuleElement eMine, + boolean forceLinersBottom, boolean forceLinersWalls); + public void autoCreateConfigureMines(); @@ -383,6 +386,18 @@ public void autoCreateMineLinerAssignment( List rankMineNames, public String dumpEventListenersPlayerInteractEvents(); + + + public String dumpEventListenersBlockPlaceEvents(); + + + public String dumpEventListenersPlayerDropItemEvents(); + + + public String dumpEventListenersPlayerPickupItemEvents(); + + + public void testPlayerUtil( UUID uuid ); @@ -477,4 +492,8 @@ public void autoCreateMineLinerAssignment( List rankMineNames, public String getRankByFileName(String name); + + public Map loadYaml(File file); + + } diff --git a/prison-core/src/main/java/tech/mcprison/prison/localization/Localizable.java b/prison-core/src/main/java/tech/mcprison/prison/localization/Localizable.java index cd0504a27..9b32423e0 100755 --- a/prison-core/src/main/java/tech/mcprison/prison/localization/Localizable.java +++ b/prison-core/src/main/java/tech/mcprison/prison/localization/Localizable.java @@ -42,6 +42,10 @@ import tech.mcprison.prison.internal.World; import tech.mcprison.prison.output.LogLevel; import tech.mcprison.prison.output.Output; +import tech.mcprison.prison.placeholders.PlaceholderStringCoverter; +import tech.mcprison.prison.ranks.data.PlayerRank; +import tech.mcprison.prison.ranks.data.Rank; +import tech.mcprison.prison.ranks.data.RankPlayer; /** * Represents an object which has the potential to be localized in one of @@ -248,7 +252,7 @@ private String localizeIn(String locale, boolean recursive, String... fallbacks) // If the entry has been marked with "*none*" or an empty String then return an empty String: if ( LocaleManager.IGNORE_TEXT_NO_MESSAGE_INTENDED.equalsIgnoreCase(message) || - message != null && message.trim().length() == 0 ) { + message != null && message.length() == 0 ) { return ""; } @@ -347,9 +351,14 @@ public String localize() { * @since 1.0 */ public String localizeFor(CommandSender sender) { - return sender instanceof Player ? - localizeIn(getParent().getLocale((Player) sender)) : - localize(); + String results = + sender instanceof Player ? + localizeIn(getParent().getLocale((Player) sender)) : + localize(); + + results = applySecondaryPlaceholders( sender, results ); + + return results; } /** @@ -370,7 +379,17 @@ public void sendTo(CommandSender sender, LogLevel level) { String message = localizeFor(sender); if ( message != null && !message.isEmpty() ) { - Output.get().sendMessage(sender, message, level); + try { + Output.get().sendMessage(sender, message, level); + } + catch (Exception e) { + Output.get().logRaw( + "Tried to send a formatted mmessage to a player but it ended in " + + "failure. Was the original message edited and an extra parameter added? " + + "raw message: [" + + message + + "]"); + } } } @@ -386,11 +405,22 @@ public void sendTo(CommandSender sender, LogLevel level) { * * @param sender The {@link CommandSender} to send this {@link Localizable} to */ - public void sendTo(CommandSender sender) { + public void sendTo(CommandSender sender ) { + PlaceholderStringCoverter placeholderConverter = null; + sendTo( sender, placeholderConverter ); + } + public void sendTo(CommandSender sender, PlaceholderStringCoverter placeholderConverter ) { String message = localize(); if ( message != null && !message.isEmpty() ) { + if ( placeholderConverter != null ) { + message = placeholderConverter.convertStringPlaceholders(message); + } +// message = applySecondaryPlaceholders( +// (playerStats != null ? playerStats : sender ), +// message ); + sendTo(sender, LogLevel.PLAIN); } } @@ -402,12 +432,16 @@ public void sendTo(CommandSender sender) { * @since 1.0 */ public void broadcast() { + PlaceholderStringCoverter placeholderConverter = null; + broadcast( placeholderConverter ); + } + public void broadcast( PlaceholderStringCoverter placeholderConverter ) { String message = localize(); if ( message != null && !message.isEmpty() ) { for (Player player : Prison.get().getPlatform().getOnlinePlayers()) { - sendTo(player); + sendTo(player, placeholderConverter); } Output.get().logInfo( message ); } @@ -449,4 +483,103 @@ private String fromNullableString(String nullable) { // PLAIN, INFO, WARN, ERROR // } + + /** + *

This function will provide support for secondary placeholders for all player related placeholders. + * These secondary placeholders are in addition to the preexisting positional placeholders + * that are hard coded for the specific parameters. + *

+ * + *

These secondary placeholders can be inserted anywhere in the message. + *

+ * + *
    + *
  • {player}
  • + *
  • {rank_default}
  • + *
  • {rank_tag_default}
  • + *
  • {rank_next_default}
  • + *
  • {rank_next_tag_default}
  • + *
  • {rank_prestiges}
  • + *
  • {rank_tag_prestiges}
  • + *
  • {rank_next_prestiges}
  • + *
  • {rank_next_tag_prestiges}
  • + * + *
  • {player} {rank_default} {rank_tag_default} {rank_next_default} {rank_next_tag_default}
  • + *
  • {rank_prestiges} {rank_tag_prestiges} {rank_next_prestiges} {rank_next_tag_prestiges}
  • + *
+ * + * @param rankPlayer + * @param results + * @return + */ + public String applySecondaryPlaceholders( CommandSender sender, String results ) { + + if ( results != null && !results.isEmpty() && + sender != null && sender instanceof Player ) { + RankPlayer rankPlayer = sender.getRankPlayer(); + + if ( rankPlayer != null ) { + + + results = applySecondaryPlaceholdersCheck( "{player}", rankPlayer.getName(), results ); + + if ( rankPlayer.getPlayerRankDefault() != null ) { + PlayerRank rankP = rankPlayer.getPlayerRankDefault(); + Rank rank = rankP == null ? null : rankP.getRank(); + Rank rankNext = rank == null ? null : rank.getRankNext(); + + results = applySecondaryPlaceholdersCheck( "{rank_default}", + rank == null ? "" : rank.getName(), results ); + results = applySecondaryPlaceholdersCheck( "{rank_tag_default}", + rank == null ? "" : rank.getTag(), results ); + + results = applySecondaryPlaceholdersCheck( "{rank_next_default}", + rankNext == null ? "" : rankNext.getName(), results ); + results = applySecondaryPlaceholdersCheck( "{rank_next_tag_default}", + rankNext == null ? "" : rankNext.getTag(), results ); + } + + if ( rankPlayer.getPlayerRankPrestiges() != null ) { + + PlayerRank rankP = rankPlayer.getPlayerRankPrestiges(); + Rank rank = rankP == null ? null : rankP.getRank(); + Rank rankNext = rank == null ? null : rank.getRankNext(); + + results = applySecondaryPlaceholdersCheck( "{rank_prestiges}", + rank == null ? "" : rank.getName(), results ); + results = applySecondaryPlaceholdersCheck( "{rank_tag_prestiges}", + rank == null ? "" : rank.getTag(), results ); + + results = applySecondaryPlaceholdersCheck( "{rank_next_prestiges}", + rankNext == null ? "" : rankNext.getName(), results ); + results = applySecondaryPlaceholdersCheck( "{rank_next_tag_prestiges}", + rankNext == null ? "" : rankNext.getTag(), results ); + } + + } + } + + + return results; + } + + /** + *

Ths function will perform individual replacements of the given placeholders, but + * if the placeholder does not exist, then it will not change anything with the results + * and it will be just passed through. + *

+ * + * @param placeholder + * @param value + * @param results + * @return + */ + private String applySecondaryPlaceholdersCheck( String placeholder, String value, String results) { + + if ( results.contains( placeholder ) && value != null ) { + results = results.replace( placeholder, value ); + } + + return results; + } } 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 85b5ef47d..f89c3a5c6 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 @@ -81,8 +81,9 @@ public enum DebugTarget { targetBlockMismatch, - rankup + rankup, // support + blockConstraints ; public static DebugTarget fromString( String target ) { @@ -141,7 +142,13 @@ private Output() { public static Output get() { if (instance == null) { - new Output(); + synchronized ( Output.class ) { + if (instance == null) { + + new Output(); + + } + } } return instance; } @@ -376,6 +383,17 @@ public void logError(String message, Throwable... throwable) { } } + /** + *

This will log a message to the console without any conversion of color codes or + * anything else. Expect issues with color formatting. + *

+ * + * @param message + */ + public void logRaw( String message ) { + Prison.get().getPlatform().logPlain(message); + } + public void logDebug(String message, Object... args) { logDebug( message, null, args ); } diff --git a/prison-core/src/main/java/tech/mcprison/prison/placeholders/PlaceholderStringCoverter.java b/prison-core/src/main/java/tech/mcprison/prison/placeholders/PlaceholderStringCoverter.java new file mode 100644 index 000000000..e445873c7 --- /dev/null +++ b/prison-core/src/main/java/tech/mcprison/prison/placeholders/PlaceholderStringCoverter.java @@ -0,0 +1,14 @@ +package tech.mcprison.prison.placeholders; + +public interface PlaceholderStringCoverter { + + /** + *

This returns a String list of all available placeholders that can be used. + *

+ * @return + */ + public String getStringPlaceholders(); + + public String convertStringPlaceholders( String source ); + +} 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 06af55f65..189df8e1c 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 @@ -39,6 +39,7 @@ import tech.mcprison.prison.internal.inventory.Inventory; import tech.mcprison.prison.internal.scoreboard.Scoreboard; import tech.mcprison.prison.output.Output; +import tech.mcprison.prison.placeholders.PlaceholderStringCoverter; import tech.mcprison.prison.placeholders.PlaceholdersUtil; import tech.mcprison.prison.util.Gamemode; import tech.mcprison.prison.util.Location; @@ -50,7 +51,8 @@ * @author Faizaan A. Datoo */ public class RankPlayer - implements Player { + extends RankPlayerMessages + implements Player, PlaceholderStringCoverter { public static final long DELAY_THREE_SECONDS = 20 * 3; // 3 seconds in ticks @@ -906,6 +908,11 @@ public void sendMessage( String[] messages ) { Output.get().logError( "RankPlayer.sendMessage: Cannot send messages to offline players." ); } + @Override + public void sendMessage( List messages ) { + Output.get().logError( "RankPlayer.sendMessage: Cannot send messages to offline players." ); + } + @Override public void sendRaw( String json ) { Output.get().logError( "RankPlayer.sendRaw: Cannot send messages to offline players." ); @@ -968,7 +975,7 @@ public Optional getLocale() { @Override public boolean isOp() { - Player player = getPlayer(); + Player player = getPlatformPlayer(); return (player != null ? player.isOp() : false ); } @@ -981,14 +988,14 @@ public boolean isOp() { */ @Override public boolean isPlayer() { - Player player = getPlayer(); + Player player = getPlatformPlayer(); return (player != null ? player.isPlayer() : false ); } @Override public void updateInventory() { - Player player = getPlayer(); + Player player = getPlatformPlayer(); if ( player != null ) { player.updateInventory(); @@ -999,7 +1006,7 @@ public void updateInventory() { public Inventory getInventory() { Inventory results = null; - Player player = getPlayer(); + Player player = getPlatformPlayer(); if ( player != null ) { results = player.getInventory(); @@ -1013,15 +1020,9 @@ public Inventory getInventory() { // // } - /** - *

Player is not cached in this class, so if using it in a function - * make a local variable to save it instead of calling this function multiple - * times since it is a high impact lookup. - *

- * - * @return - */ - private Player getPlayer() { + + @Override + public Player getPlatformPlayer() { Player player = null; Optional oPlayer = Prison.get().getPlatform().getPlayer( uid ); @@ -1029,12 +1030,19 @@ private Player getPlayer() { if ( oPlayer.isPresent() ) { player = oPlayer.get(); } + return player; } + + @Override + public RankPlayer getRankPlayer() { + return this; + } + @Override public void recalculatePermissions() { - Player player = getPlayer(); + Player player = getPlatformPlayer(); if ( player != null ) { player.recalculatePermissions(); } @@ -1042,13 +1050,13 @@ public void recalculatePermissions() { @Override public List getPermissions() { - Player player = getPlayer(); + Player player = getPlatformPlayer(); return (player == null ? new ArrayList<>() : player.getPermissions() ); } @Override public List getPermissions( String prefix ) { - Player player = getPlayer(); + Player player = getPlatformPlayer(); return (player == null ? new ArrayList<>() : player.getPermissions( prefix ) ); } @@ -1071,7 +1079,7 @@ public List getPermissions( String prefix ) { public double getSellAllMultiplier() { double results = 1.0; - Player player = getPlayer(); + Player player = getPlatformPlayer(); if ( player != null ) { results = player.getSellAllMultiplier(); } @@ -1690,16 +1698,19 @@ private void calculateRankScore( String currency, double cost, double playerBala // } public static String printRankScoreLine1Header() { - String header = String.format( - "Rank %-16s %-9s %-6s %-9s %-9s %-9s", - "Player", - "Prestiges", - "Rank", - "Balance", - "Rank-Score", - "Penalty" - - ); + + String header = coreTopNLine1HeaderMsg(); + +// String header = String.format( +// "Rank %-16s %-9s %-6s %-9s %-9s %-9s", +// "Player", +// "Prestiges", +// "Rank", +// "Balance", +// "Rank-Score", +// "Penalty" +// +// ); return header; } @@ -1707,28 +1718,55 @@ public String printRankScoreLine1( int rankPostion ) { DecimalFormat dFmt = Prison.get().getDecimalFormat("#,##0.00"); - PlayerRank prestRank = getPlayerRankPrestiges(); + PlayerRank prestigeRank = getPlayerRankPrestiges(); PlayerRank defRank = getPlayerRankDefault(); - String prestRankTag = prestRank == null ? "---" : prestRank.getRank().getTag(); + String prestigeRankName = prestigeRank == null ? "" : prestigeRank.getRank().getName(); + String defaultRankName = defRank == null ? "" : defRank.getRank().getName(); + + String prestRankTag = prestigeRank == null ? "---" : prestigeRank.getRank().getTag(); String defRankTag = defRank == null ? "---" : defRank.getRank().getTag(); String prestRankTagNc = Text.stripColor(prestRankTag); String defRankTagNc = Text.stripColor(defRankTag); - String balanceStr = PlaceholdersUtil.formattedKmbtSISize( getRankScoreBalance(), dFmt, " " ); + String balanceFmtStr = dFmt.format( getRankScoreBalance() ); + String balanceKmbtStr = PlaceholdersUtil.formattedKmbtSISize( getRankScoreBalance(), dFmt, " " ); + String balanceMetricStr = PlaceholdersUtil.formattedMetricSISize( getRankScoreBalance(), dFmt, " " ); + + String rankPositionStr = Integer.toString(rankPostion); + String rankScoreStr = rankPostion > 0 ? Integer.toString(rankPostion) : ""; String sPenaltyStr = PlaceholdersUtil.formattedKmbtSISize( getRankScorePenalty(), dFmt, " " ); - String message = String.format( - " %-3s %-18s %-7s %-7s %9s %9s %9s", - (rankPostion > 0 ? Integer.toString(rankPostion) : ""), - getName(), - prestRankTagNc, - defRankTagNc, - balanceStr, - dFmt.format( getRankScore() ), - sPenaltyStr + String playerName = getName(); + + String message = coreTopNLine1DetailMsg( + + playerName, + rankPositionStr, + rankScoreStr, + sPenaltyStr, + prestigeRankName, + defaultRankName, + prestRankTag, + defRankTag, + prestRankTagNc, + defRankTagNc, + balanceFmtStr, + balanceKmbtStr, + balanceMetricStr + ); +// String message = String.format( +// " %-3s %-18s %-7s %-7s %9s %9s %9s", +// rankScoreStr, +// getName(), +// prestRankTagNc, +// defRankTagNc, +// balanceKmbtStr, +// dFmt.format( getRankScore() ), +// sPenaltyStr +// ); message = message .replace(prestRankTagNc, prestRankTag + "&r") @@ -1738,46 +1776,82 @@ public String printRankScoreLine1( int rankPostion ) { } public static String printRankScoreLine2Header() { - String header = String.format( - "Rank %s %s %-15s %9s", - "Ranks", - "Rank-Score", - "Player", - "Balance" - - ); + + String header = coreTopNLine2HeaderMsg(); +// String header = String.format( +// "Rank %s %s %-15s %9s", +// "Ranks", +// "Rank-Score", +// "Player", +// "Balance" +// +// ); return header; } public String printRankScoreLine2( int rankPostion ) { - + DecimalFormat dFmt = Prison.get().getDecimalFormat("#,##0.00"); - PlayerRank prestRank = getPlayerRankPrestiges(); + PlayerRank prestigeRank = getPlayerRankPrestiges(); PlayerRank defRank = getPlayerRankDefault(); - String prestRankTag = prestRank == null ? "---" : prestRank.getRank().getTag(); + String prestigeRankName = prestigeRank == null ? "" : prestigeRank.getRank().getName(); + String defaultRankName = defRank == null ? "" : defRank.getRank().getName(); + + String prestRankTag = prestigeRank == null ? "---" : prestigeRank.getRank().getTag(); String defRankTag = defRank == null ? "---" : defRank.getRank().getTag(); String prestRankTagNc = Text.stripColor(prestRankTag); String defRankTagNc = Text.stripColor(defRankTag); - String balanceStr = PlaceholdersUtil.formattedKmbtSISize( getRankScoreBalance(), dFmt, " " ); -// String sPenaltyStr = PlaceholdersUtil.formattedKmbtSISize( getRankScorePenalty(), dFmt, " " ); - - String ranks = prestRankTagNc + defRankTagNc; - String message = String.format( - " %-3s %-9s %6s %-17s %9s", - (rankPostion > 0 ? Integer.toString(rankPostion) : ""), - ranks, - dFmt.format( getRankScore() ), - getName(), - balanceStr - ); + String balanceFmtStr = dFmt.format( getRankScoreBalance() ); + String balanceKmbtStr = PlaceholdersUtil.formattedKmbtSISize( getRankScoreBalance(), dFmt, " " ); + String balanceMetricStr = PlaceholdersUtil.formattedMetricSISize( getRankScoreBalance(), dFmt, " " ); - message = message - .replace(prestRankTagNc, prestRankTag + "&r") - .replace(defRankTagNc, defRankTag + "&r"); + String rankPositionStr = Integer.toString(rankPostion); + String rankScoreStr = rankPostion > 0 ? Integer.toString(rankPostion) : ""; + String sPenaltyStr = PlaceholdersUtil.formattedKmbtSISize( getRankScorePenalty(), dFmt, " " ); + + String playerName = getName(); + +// DecimalFormat dFmt = Prison.get().getDecimalFormat("#,##0.00"); +// +// PlayerRank prestRank = getPlayerRankPrestiges(); +// PlayerRank defRank = getPlayerRankDefault(); +// +// String prestRankTag = prestRank == null ? "---" : prestRank.getRank().getTag(); +// String defRankTag = defRank == null ? "---" : defRank.getRank().getTag(); +// +// String prestRankTagNc = Text.stripColor(prestRankTag); +// String defRankTagNc = Text.stripColor(defRankTag); +// +// String balanceKmbtStr = PlaceholdersUtil.formattedKmbtSISize( getRankScoreBalance(), dFmt, " " ); +//// String sPenaltyStr = PlaceholdersUtil.formattedKmbtSISize( getRankScorePenalty(), dFmt, " " ); +// +// String ranks = prestRankTagNc + defRankTagNc; + + String message = coreTopNLine2DetailMsg( + playerName, + rankPositionStr, + rankScoreStr, sPenaltyStr, + prestigeRankName, defaultRankName, + prestRankTag, defRankTag, + prestRankTagNc, defRankTagNc, + balanceFmtStr, balanceKmbtStr, balanceMetricStr ); + +// String message = String.format( +// " %-3s %-9s %6s %-17s %9s", +// (rankPostion > 0 ? Integer.toString(rankPostion) : ""), +// ranks, +// dFmt.format( getRankScore() ), +// getName(), +// balanceKmbtStr +// ); +// +// message = message +// .replace(prestRankTagNc, prestRankTag + "&r") +// .replace(defRankTagNc, defRankTag + "&r"); return message; } @@ -1826,6 +1900,120 @@ public void setRankScorePenalty( double rankScorePenalty ) { this.rankScorePenalty = rankScorePenalty; } + @Override + public List getSellAllMultiplierListings() { + + Player player = Prison.get().getPlatform().getPlayer(getUUID()).orElse(null); + + return player == null ? new ArrayList<>() : player.getSellAllMultiplierListings(); + } + + + @Override + public String getStringPlaceholders() { + String results = + "{player} {rank_default} {rank_tag_default} {rank_next_default} {rank_next_tag_default} " + + "{rank_prestiges} {rank_tag_prestiges} {rank_next_prestiges} {rank_next_tag_prestiges}"; + + return results; + } + + /** + *

This function will provide support for secondary placeholders for all player related placeholders. + * These secondary placeholders are in addition to the preexisting positional placeholders + * that are hard coded for the specific parameters. + *

+ * + *

These secondary placeholders can be inserted anywhere in the message. + *

+ * + *
    + *
  • {player}
  • + *
  • {rank_default}
  • + *
  • {rank_tag_default}
  • + *
  • {rank_next_default}
  • + *
  • {rank_next_tag_default}
  • + *
  • {rank_prestiges}
  • + *
  • {rank_tag_prestiges}
  • + *
  • {rank_next_prestiges}
  • + *
  • {rank_next_tag_prestiges}
  • + * + *
  • {player} {rank_default} {rank_tag_default} {rank_next_default} {rank_next_tag_default}
  • + *
  • {rank_prestiges} {rank_tag_prestiges} {rank_next_prestiges} {rank_next_tag_prestiges}
  • + *
+ * + * @param rankPlayer + * @param results + * @return + */ + @Override + public String convertStringPlaceholders(String results) { + + RankPlayer rankPlayer = this; + + if ( rankPlayer != null ) { + + results = applySecondaryPlaceholdersCheck( "{player}", rankPlayer.getName(), results ); + + if ( rankPlayer.getPlayerRankDefault() != null ) { + PlayerRank rankP = rankPlayer.getPlayerRankDefault(); + Rank rank = rankP == null ? null : rankP.getRank(); + Rank rankNext = rank == null ? null : rank.getRankNext(); + + results = applySecondaryPlaceholdersCheck( "{rank_default}", + rank == null ? "" : rank.getName(), results ); + results = applySecondaryPlaceholdersCheck( "{rank_tag_default}", + rank == null ? "" : rank.getTag(), results ); + + results = applySecondaryPlaceholdersCheck( "{rank_next_default}", + rankNext == null ? "" : rankNext.getName(), results ); + results = applySecondaryPlaceholdersCheck( "{rank_next_tag_default}", + rankNext == null ? "" : rankNext.getTag(), results ); + } + + if ( rankPlayer.getPlayerRankPrestiges() != null ) { + + PlayerRank rankP = rankPlayer.getPlayerRankPrestiges(); + Rank rank = rankP == null ? null : rankP.getRank(); + Rank rankNext = rank == null ? null : rank.getRankNext(); + + results = applySecondaryPlaceholdersCheck( "{rank_prestiges}", + rank == null ? "" : rank.getName(), results ); + results = applySecondaryPlaceholdersCheck( "{rank_tag_prestiges}", + rank == null ? "" : rank.getTag(), results ); + + results = applySecondaryPlaceholdersCheck( "{rank_next_prestiges}", + rankNext == null ? "" : rankNext.getName(), results ); + results = applySecondaryPlaceholdersCheck( "{rank_next_tag_prestiges}", + rankNext == null ? "" : rankNext.getTag(), results ); + } + + } + + return results; + } + + + /** + *

Ths function will perform individual replacements of the given placeholders, but + * if the placeholder does not exist, then it will not change anything with the results + * and it will be just passed through. + *

+ * + * @param placeholder + * @param value + * @param results + * @return + */ + private String applySecondaryPlaceholdersCheck( String placeholder, String value, String results) { + + if ( results.contains( placeholder ) && value != null ) { + results = results.replace( placeholder, value ); + } + + return results; + } + // public long getRankScoreCooldown() { // return rankScoreCooldown; // } diff --git a/prison-core/src/main/java/tech/mcprison/prison/ranks/data/RankPlayerMessages.java b/prison-core/src/main/java/tech/mcprison/prison/ranks/data/RankPlayerMessages.java new file mode 100644 index 000000000..eef69d38c --- /dev/null +++ b/prison-core/src/main/java/tech/mcprison/prison/ranks/data/RankPlayerMessages.java @@ -0,0 +1,248 @@ +package tech.mcprison.prison.ranks.data; + +import tech.mcprison.prison.Prison; + +public class RankPlayerMessages { + + + protected String coreOutputErrorIncorrectNumberOfParametersMsg ( + String levelName, String errorMessage, + String originalMessage, String arguments ) { + return Prison.get().getLocaleManager() + .getLocalizable( "core_output__error_incorrect_number_of_parameters" ) + .withReplacements( levelName, errorMessage, + originalMessage, arguments ) + .localize(); + } + + + protected static String coreTopNLine1HeaderMsg() { + String header = Prison.get().getLocaleManager() + .getLocalizable( "core_ranks_topn__player_line_1_header_format" ) + .localize(); + header = header.replace( "[", "%" ).replace( "]", "s" ); + + String[] values = coreTopNLine1HeaderValuesMsg(); + + String results = String.format( + header, + (Object[]) values + ); + return results; + } + + private static String[] coreTopNLine1HeaderValuesMsg () { + String[] results = null; + String values = Prison.get().getLocaleManager() + .getLocalizable( "core_ranks_topn__player_line_1_header_values" ) + .localize(); + results = values.split(", "); + + return results; + } + + + + protected static String coreTopNLine2HeaderMsg() { + String header = Prison.get().getLocaleManager() + .getLocalizable( "core_ranks_topn__player_line_2_header_format" ) + .localize(); + header = header.replace( "[", "%" ).replace( "]", "s" ); + + String[] values = coreTopNLine2HeaderValuesMsg(); + + String results = String.format( + header, + (Object[]) values + ); + return results; + } + + private static String[] coreTopNLine2HeaderValuesMsg () { + String[] results = null; + String values = Prison.get().getLocaleManager() + .getLocalizable( "core_ranks_topn__player_line_2_header_values" ) + .localize(); + results = values.split(", "); + + return results; + } + + + protected static String coreTopNLine1DetailMsg( + String playerName, + String rankPositionStr, + String rankScoreStr, String sPenaltyStr, + String prestigeRankName, String defaultRankName, + String prestRankTag, String defRankTag, + String prestRankTagNc, String defRankTagNc, + String balanceFmtStr, String balanceKmbtStr, String balanceMetricStr) { + + String detail = Prison.get().getLocaleManager() + .getLocalizable( "core_ranks_topn__player_line_1_detail_format" ) + .localize(); + detail = detail.replace( "[", "%" ).replace( "]", "s" ); + + String[] values = coreTopNLine1DetailValuesMsg( + playerName, + rankPositionStr, + rankScoreStr, + sPenaltyStr, + prestigeRankName, + defaultRankName, + prestRankTag, + defRankTag, + prestRankTagNc, + defRankTagNc, + balanceFmtStr, + balanceKmbtStr, + balanceMetricStr + ); + + String results = String.format( + detail, + (Object[]) values + ); + return results; + } + + private static String[] coreTopNLine1DetailValuesMsg( + String playerName, + String rankPositionStr, + String rankScoreStr, String sPenaltyStr, + String prestigeRankName, String defaultRankName, + String prestRankTag, String defRankTag, + String prestRankTagNc, String defRankTagNc, + String balanceFmtStr, String balanceKmbtStr, String balanceMetricStr + ) { + + String[] results = null; + + String values = Prison.get().getLocaleManager() + .getLocalizable( "core_ranks_topn__player_line_1_detail_values" ) + .localize(); + + String[] tmp = values.split(","); + results = new String[tmp.length]; + + for ( int i = 0; i < tmp.length; i++ ) { + String value = tmp[i]; + + results[i] = value + .replace( "{playerName}", playerName ) + .replace( "{rankPosition}", rankPositionStr ) + .replace( "{rankScore}", rankScoreStr ) + .replace( "{rankScorePenalty}", sPenaltyStr ) + + .replace( "{prestigeRank}", prestigeRankName ) + .replace( "{defaultRank}", defaultRankName ) + .replace( "{prestigeDefaultRank}", prestigeRankName + defaultRankName ) + + .replace( "{prestigeRankTag}", prestRankTag + "&r" ) + .replace( "{defaultRankTag}", defRankTag + "&r" ) + .replace( "{prestigeDefaultRankTag}", prestRankTag + defRankTag + "&r" ) + + .replace( "{prestigeRankTagNoColor}", prestRankTagNc ) + .replace( "{defaultRankTagNoColor}", defRankTagNc ) + .replace( "{prestigeDefaultRankTagNoColor}", prestRankTagNc + defRankTagNc ) + + .replace( "{balanceFmt}", balanceFmtStr ) + .replace( "{balanceKmbt}", balanceKmbtStr ) + .replace( "{balanceMetric}", balanceMetricStr ) + .trim(); + + } + + return results; + } + + protected static String coreTopNLine2DetailMsg( + String playerName, + String rankPositionStr, + String rankScoreStr, String sPenaltyStr, + String prestigeRankName, String defaultRankName, + String prestRankTag, String defRankTag, + String prestRankTagNc, String defRankTagNc, + String balanceFmtStr, String balanceKmbtStr, String balanceMetricStr) { + + String detail = Prison.get().getLocaleManager() + .getLocalizable( "core_ranks_topn__player_line_2_detail_format" ) + .localize(); + detail = detail.replace( "[", "%" ).replace( "]", "s" ); + + String[] values = coreTopNLine2DetailValuesMsg( + playerName, + rankPositionStr, + rankScoreStr, + sPenaltyStr, + prestigeRankName, + defaultRankName, + prestRankTag, + defRankTag, + prestRankTagNc, + defRankTagNc, + balanceFmtStr, + balanceKmbtStr, + balanceMetricStr + ); + + String results = String.format( + detail, + (Object[]) values + ); + return results; + } + + private static String[] coreTopNLine2DetailValuesMsg( + String playerName, + String rankPositionStr, + String rankScoreStr, String sPenaltyStr, + String prestigeRankName, String defaultRankName, + String prestRankTag, String defRankTag, + String prestRankTagNc, String defRankTagNc, + String balanceFmtStr, String balanceKmbtStr, String balanceMetricStr + ) { + + String[] results = null; + + String values = Prison.get().getLocaleManager() + .getLocalizable( "core_ranks_topn__player_line_2_detail_values" ) + .localize(); + + String[] tmp = values.split(","); + results = new String[tmp.length]; + + for ( int i = 0; i < tmp.length; i++ ) { + String value = tmp[i]; + + + results[i] = value + .replace( "{playerName}", playerName ) + .replace( "{rankPosition}", rankPositionStr ) + .replace( "{rankScore}", rankScoreStr ) + .replace( "{rankScorePenalty}", sPenaltyStr ) + + .replace( "{prestigeRank}", prestigeRankName ) + .replace( "{defaultRank}", defaultRankName ) + .replace( "{prestigeDefaultRank}", prestigeRankName + defaultRankName ) + + .replace( "{prestigeRankTag}", prestRankTag + "&r" ) + .replace( "{defaultRankTag}", defRankTag + "&r" ) + .replace( "{prestigeDefaultRankTag}", prestRankTag + defRankTag + "&r" ) + + .replace( "{prestigeRankTagNoColor}", prestRankTagNc ) + .replace( "{defaultRankTagNoColor}", defRankTagNc ) + .replace( "{prestigeDefaultRankTagNoColor}", prestRankTagNc + defRankTagNc ) + + .replace( "{balanceFmt}", balanceFmtStr ) + .replace( "{balanceKmbt}", balanceKmbtStr ) + .replace( "{balanceMetric}", balanceMetricStr ) + .trim() + ; + + } + + return results; + } + +} diff --git a/prison-core/src/main/java/tech/mcprison/prison/util/Bounds.java b/prison-core/src/main/java/tech/mcprison/prison/util/Bounds.java index 0bcb4dba5..707f2b3bf 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/util/Bounds.java +++ b/prison-core/src/main/java/tech/mcprison/prison/util/Bounds.java @@ -37,6 +37,10 @@ public class Bounds { private final int totalBlockCount; + private final int blockCountPerLayer; + + private final int totalLayers; + public enum Edges { top, @@ -135,10 +139,14 @@ public Bounds(Location min, Location max) { this.center = new Location(this.min.getWorld(), centerX, centerY, centerZ ); + + this.totalLayers = (getyBlockMax() - getyBlockMin() + 1); + + this.blockCountPerLayer = (getxBlockMax() - getxBlockMin() + 1) * + (getzBlockMax() - getzBlockMin() + 1); + this.totalBlockCount = - (getyBlockMax() - getyBlockMin() + 1) * - (getxBlockMax() - getxBlockMin() + 1) * - (getzBlockMax() - getzBlockMin() + 1); + totalLayers * blockCountPerLayer; } @@ -279,10 +287,14 @@ public Bounds( Bounds bounds, Edges edge, int amount ) { this.center = new Location(this.min.getWorld(), centerX, centerY, centerZ ); + + this.totalLayers = (getyBlockMax() - getyBlockMin() + 1); + + this.blockCountPerLayer = (getxBlockMax() - getxBlockMin() + 1) * + (getzBlockMax() - getzBlockMin() + 1); + this.totalBlockCount = - (getyBlockMax() - getyBlockMin() + 1) * - (getxBlockMax() - getxBlockMin() + 1) * - (getzBlockMax() - getzBlockMin() + 1); + totalLayers * blockCountPerLayer; } @@ -550,6 +562,14 @@ public double getzMax() return zMax; } + public int getBlockCountPerLayer() { + return blockCountPerLayer; + } + + public int getTotalLayers() { + return totalLayers; + } + public int getTotalBlockCount() { return totalBlockCount; diff --git a/prison-core/src/main/java/tech/mcprison/prison/util/ExampleJavaDoubleVsBigDecimal.java b/prison-core/src/main/java/tech/mcprison/prison/util/ExampleJavaDoubleVsBigDecimal.java index 807cd35db..b3cd94e07 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/util/ExampleJavaDoubleVsBigDecimal.java +++ b/prison-core/src/main/java/tech/mcprison/prison/util/ExampleJavaDoubleVsBigDecimal.java @@ -27,6 +27,24 @@ public static void main( String[] args ) { for (String line : out) { System.out.println( line ); } + + System.out.println(); + System.out.println(); + System.out.println(); + + double a = 1.0; + double b = 0.014; + double c = a - b; + double d = c * 100d; + double e = d / 100d; + double f = ((a * 100d) - (b * 100d)) / 100.0d; + + System.out.println( + String.format( "a = %f b = %f c = %f d = %f e = %f f = %f" , + a, b, c, d, e, f ) ); + + System.out.println( c ); + System.out.println( f ); } 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 a597c11ae..1b00164f5 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 @@ -338,6 +338,12 @@ public StringBuilder getSupportSubmitListenersData( String listenerType ) { sb.append( Prison.get().getPlatform().dumpEventListenersBlockBreakEvents() ); } + if ( "blockPlace".equalsIgnoreCase( listenerType ) || "all".equalsIgnoreCase( listenerType ) ) { + + sb.append( "||Listeners blockPlace||" ); + sb.append( Prison.get().getPlatform().dumpEventListenersBlockPlaceEvents() ); + } + if ( "chat".equalsIgnoreCase( listenerType ) || "all".equalsIgnoreCase( listenerType ) ) { sb.append( "||Listeners chat||" ); @@ -356,6 +362,19 @@ public StringBuilder getSupportSubmitListenersData( String listenerType ) { sb.append( Prison.get().getPlatform().dumpEventListenersPlayerInteractEvents() ); } + if ( "playerDropItem".equalsIgnoreCase( listenerType ) || "all".equalsIgnoreCase( listenerType ) ) { + + sb.append( "||Listeners playerDropItem||" ); + sb.append( Prison.get().getPlatform().dumpEventListenersPlayerDropItemEvents() ); + } + + if ( "playerPickupItem".equalsIgnoreCase( listenerType ) || "all".equalsIgnoreCase( listenerType ) ) { + + sb.append( "||Listeners playerPickupItem||" ); + sb.append( Prison.get().getPlatform().dumpEventListenersPlayerPickupItemEvents() ); + } + + return sb; } diff --git a/prison-core/src/main/resources/lang/core/de_DE.properties b/prison-core/src/main/resources/lang/core/de_DE.properties index e426fcec9..6697897e9 100644 --- a/prison-core/src/main/resources/lang/core/de_DE.properties +++ b/prison-core/src/main/resources/lang/core/de_DE.properties @@ -79,7 +79,7 @@ # like to share, please contact a staff member on our Discord server. #Thanks for your contributions! # -messages__version=8 +messages__version=9 messages__auto_refresh=true @@ -192,3 +192,31 @@ core_gui__value=&3Value: %1 core_gui__permission=&3Permission: &7%1 core_gui__prestige_name=&3Prestige name: %1 + + + + +# For format, the edit codes need to be within []. A number defines the width +# and negative numbers will left justify the values with padding. An empty [] +# will not add any padding. All values are treated as strings. +# Header values will be used as is. Detail values identifies the placeholder to use. +# Important: Every [] must be paired with a value or it will produce a runtime error: +# 'Incorrect number of parameters: [Format specifier %s] +core_ranks_topn__player_line_1_header_format=[4] [-18] [-10] [11] [-8] [-12] +core_ranks_topn__player_line_1_header_values=Rank, Player, PreDefRanks, Balance, r-Score, Penalty +core_ranks_topn__player_line_2_header_format=[4] [-10] [7] [-18] [9] +core_ranks_topn__player_line_2_header_values=Rank, Ranks, r-Score, Player, Balance + +# For detail_values you can use any of the following placeholders, but they must pair up +# with the detail_format's []. +# {playerName}, {rankPosition}, {rankScore}, {rankScorePenalty}, +# {prestigeRank}, {defaultRank}, {prestigeDefaultRank}, +# {prestigeRankTag}, {defaultRankTag}, {prestigeDefaultRankTag}, +# {prestigeRankTagNoColor}, {defaultRankTagNoColor}, {prestigeDefaultRankTagNoColor}, +# {balanceFmt}, {balanceKmbt}, {balanceMetric} +core_ranks_topn__player_line_1_detail_format= [-4] [-18] [-12] [10] [7] [10] +core_ranks_topn__player_line_1_detail_values={rankPosition}, {playerName}, {prestigeDefaultRankTagNoColor}, {balanceKmbt}, {rankScore}, {rankScorePenalty} +core_ranks_topn__player_line_2_detail_format= [-3] [-10] [7] [-18] [9] +core_ranks_topn__player_line_2_detail_values={rankPosition}, {prestigeDefaultRankTagNoColor}, {rankScore}, {playerName}, {balanceKmbt} + + diff --git a/prison-core/src/main/resources/lang/core/en_GB.properties b/prison-core/src/main/resources/lang/core/en_GB.properties index 12a920078..c464867c9 100644 --- a/prison-core/src/main/resources/lang/core/en_GB.properties +++ b/prison-core/src/main/resources/lang/core/en_GB.properties @@ -76,7 +76,7 @@ # like to share, please contact a staff member on our Discord server. #Thanks for your contributions! # -messages__version=8 +messages__version=9 messages__auto_refresh=true @@ -192,3 +192,31 @@ core_gui__value=&3Value: %1 core_gui__permission=&3Permission: &7%1 core_gui__prestige_name=&3Prestige name: %1 + + + + +# For format, the edit codes need to be within []. A number defines the width +# and negative numbers will left justify the values with padding. An empty [] +# will not add any padding. All values are treated as strings. +# Header values will be used as is. Detail values identifies the placeholder to use. +# Important: Every [] must be paired with a value or it will produce a runtime error: +# 'Incorrect number of parameters: [Format specifier %s] +core_ranks_topn__player_line_1_header_format=[4] [-18] [-10] [11] [-8] [-12] +core_ranks_topn__player_line_1_header_values=Rank, Player, PreDefRanks, Balance, r-Score, Penalty +core_ranks_topn__player_line_2_header_format=[4] [-10] [7] [-18] [9] +core_ranks_topn__player_line_2_header_values=Rank, Ranks, r-Score, Player, Balance + +# For detail_values you can use any of the following placeholders, but they must pair up +# with the detail_format's []. +# {playerName}, {rankPosition}, {rankScore}, {rankScorePenalty}, +# {prestigeRank}, {defaultRank}, {prestigeDefaultRank}, +# {prestigeRankTag}, {defaultRankTag}, {prestigeDefaultRankTag}, +# {prestigeRankTagNoColor}, {defaultRankTagNoColor}, {prestigeDefaultRankTagNoColor}, +# {balanceFmt}, {balanceKmbt}, {balanceMetric} +core_ranks_topn__player_line_1_detail_format= [-4] [-18] [-12] [10] [7] [10] +core_ranks_topn__player_line_1_detail_values={rankPosition}, {playerName}, {prestigeDefaultRankTagNoColor}, {balanceKmbt}, {rankScore}, {rankScorePenalty} +core_ranks_topn__player_line_2_detail_format= [-3] [-10] [7] [-18] [9] +core_ranks_topn__player_line_2_detail_values={rankPosition}, {prestigeDefaultRankTagNoColor}, {rankScore}, {playerName}, {balanceKmbt} + + diff --git a/prison-core/src/main/resources/lang/core/en_US.properties b/prison-core/src/main/resources/lang/core/en_US.properties index c5499c0d2..6d0e97f29 100644 --- a/prison-core/src/main/resources/lang/core/en_US.properties +++ b/prison-core/src/main/resources/lang/core/en_US.properties @@ -76,7 +76,7 @@ # like to share, please contact a staff member on our Discord server. #Thanks for your contributions! # -messages__version=9 +messages__version=10 messages__auto_refresh=true @@ -192,3 +192,32 @@ core_gui__value=&3Value: %1 core_gui__permission=&3Permission: &7%1 core_gui__prestige_name=&3Prestige name: %1 + + + + +# For format, the edit codes need to be within []. A number defines the width +# and negative numbers will left justify the values with padding. An empty [] +# will not add any padding. All values are treated as strings. +# Header values will be used as is. Detail values identifies the placeholder to use. +# Important: Every [] must be paired with a value or it will produce a runtime error: +# 'Incorrect number of parameters: [Format specifier %s] +core_ranks_topn__player_line_1_header_format=[4] [-18] [-10] [11] [-8] [-12] +core_ranks_topn__player_line_1_header_values=Rank, Player, PreDefRanks, Balance, r-Score, Penalty +core_ranks_topn__player_line_2_header_format=[4] [-10] [7] [-18] [9] +core_ranks_topn__player_line_2_header_values=Rank, Ranks, r-Score, Player, Balance + +# For detail_values you can use any of the following placeholders, but they must pair up +# with the detail_format's []. +# {playerName}, {rankPosition}, {rankScore}, {rankScorePenalty}, +# {prestigeRank}, {defaultRank}, {prestigeDefaultRank}, +# {prestigeRankTag}, {defaultRankTag}, {prestigeDefaultRankTag}, +# {prestigeRankTagNoColor}, {defaultRankTagNoColor}, {prestigeDefaultRankTagNoColor}, +# {balanceFmt}, {balanceKmbt}, {balanceMetric} +core_ranks_topn__player_line_1_detail_format= [-4] [-18] [-12] [10] [7] [10] +core_ranks_topn__player_line_1_detail_values={rankPosition}, {playerName}, {prestigeDefaultRankTagNoColor}, {balanceKmbt}, {rankScore}, {rankScorePenalty} +core_ranks_topn__player_line_2_detail_format= [-3] [-10] [7] [-18] [9] +core_ranks_topn__player_line_2_detail_values={rankPosition}, {prestigeDefaultRankTagNoColor}, {rankScore}, {playerName}, {balanceKmbt} + + + diff --git a/prison-core/src/main/resources/lang/core/es_ES.properties b/prison-core/src/main/resources/lang/core/es_ES.properties index b6e6fbcde..68f1693de 100644 --- a/prison-core/src/main/resources/lang/core/es_ES.properties +++ b/prison-core/src/main/resources/lang/core/es_ES.properties @@ -76,7 +76,7 @@ # like to share, please contact a staff member on our Discord server. #Thanks for your contributions! # -messages__version=8 +messages__version=9 messages__auto_refresh=true @@ -192,3 +192,31 @@ core_gui__value=&3Value: %1 core_gui__permission=&3Permission: &7%1 core_gui__prestige_name=&3Prestige name: %1 + + + + +# For format, the edit codes need to be within []. A number defines the width +# and negative numbers will left justify the values with padding. An empty [] +# will not add any padding. All values are treated as strings. +# Header values will be used as is. Detail values identifies the placeholder to use. +# Important: Every [] must be paired with a value or it will produce a runtime error: +# 'Incorrect number of parameters: [Format specifier %s] +core_ranks_topn__player_line_1_header_format=[4] [-18] [-10] [11] [-8] [-12] +core_ranks_topn__player_line_1_header_values=Rank, Player, PreDefRanks, Balance, r-Score, Penalty +core_ranks_topn__player_line_2_header_format=[4] [-10] [7] [-18] [9] +core_ranks_topn__player_line_2_header_values=Rank, Ranks, r-Score, Player, Balance + +# For detail_values you can use any of the following placeholders, but they must pair up +# with the detail_format's []. +# {playerName}, {rankPosition}, {rankScore}, {rankScorePenalty}, +# {prestigeRank}, {defaultRank}, {prestigeDefaultRank}, +# {prestigeRankTag}, {defaultRankTag}, {prestigeDefaultRankTag}, +# {prestigeRankTagNoColor}, {defaultRankTagNoColor}, {prestigeDefaultRankTagNoColor}, +# {balanceFmt}, {balanceKmbt}, {balanceMetric} +core_ranks_topn__player_line_1_detail_format= [-4] [-18] [-12] [10] [7] [10] +core_ranks_topn__player_line_1_detail_values={rankPosition}, {playerName}, {prestigeDefaultRankTagNoColor}, {balanceKmbt}, {rankScore}, {rankScorePenalty} +core_ranks_topn__player_line_2_detail_format= [-3] [-10] [7] [-18] [9] +core_ranks_topn__player_line_2_detail_values={rankPosition}, {prestigeDefaultRankTagNoColor}, {rankScore}, {playerName}, {balanceKmbt} + + diff --git a/prison-core/src/main/resources/lang/core/fi_FI.properties b/prison-core/src/main/resources/lang/core/fi_FI.properties index 831d6af77..724ddc12d 100644 --- a/prison-core/src/main/resources/lang/core/fi_FI.properties +++ b/prison-core/src/main/resources/lang/core/fi_FI.properties @@ -76,7 +76,7 @@ # like to share, please contact a staff member on our Discord server. #Thanks for your contributions! # -messages__version=9 +messages__version=10 messages__auto_refresh=true @@ -192,3 +192,31 @@ core_gui__value=&3Value: %1 core_gui__permission=&3Permission: &7%1 core_gui__prestige_name=&3Prestige name: %1 + + + + +# For format, the edit codes need to be within []. A number defines the width +# and negative numbers will left justify the values with padding. An empty [] +# will not add any padding. All values are treated as strings. +# Header values will be used as is. Detail values identifies the placeholder to use. +# Important: Every [] must be paired with a value or it will produce a runtime error: +# 'Incorrect number of parameters: [Format specifier %s] +core_ranks_topn__player_line_1_header_format=[4] [-18] [-10] [11] [-8] [-12] +core_ranks_topn__player_line_1_header_values=Rank, Player, PreDefRanks, Balance, r-Score, Penalty +core_ranks_topn__player_line_2_header_format=[4] [-10] [7] [-18] [9] +core_ranks_topn__player_line_2_header_values=Rank, Ranks, r-Score, Player, Balance + +# For detail_values you can use any of the following placeholders, but they must pair up +# with the detail_format's []. +# {playerName}, {rankPosition}, {rankScore}, {rankScorePenalty}, +# {prestigeRank}, {defaultRank}, {prestigeDefaultRank}, +# {prestigeRankTag}, {defaultRankTag}, {prestigeDefaultRankTag}, +# {prestigeRankTagNoColor}, {defaultRankTagNoColor}, {prestigeDefaultRankTagNoColor}, +# {balanceFmt}, {balanceKmbt}, {balanceMetric} +core_ranks_topn__player_line_1_detail_format= [-4] [-18] [-12] [10] [7] [10] +core_ranks_topn__player_line_1_detail_values={rankPosition}, {playerName}, {prestigeDefaultRankTagNoColor}, {balanceKmbt}, {rankScore}, {rankScorePenalty} +core_ranks_topn__player_line_2_detail_format= [-3] [-10] [7] [-18] [9] +core_ranks_topn__player_line_2_detail_values={rankPosition}, {prestigeDefaultRankTagNoColor}, {rankScore}, {playerName}, {balanceKmbt} + + diff --git a/prison-core/src/main/resources/lang/core/fr_FR.properties b/prison-core/src/main/resources/lang/core/fr_FR.properties index 9997d0444..cfa59876b 100644 --- a/prison-core/src/main/resources/lang/core/fr_FR.properties +++ b/prison-core/src/main/resources/lang/core/fr_FR.properties @@ -76,7 +76,7 @@ # like to share, please contact a staff member on our Discord server. #Thanks for your contributions! # -messages__version=9 +messages__version=10 messages__auto_refresh=true @@ -192,3 +192,31 @@ core_gui__value=&3Valeur: %1 core_gui__permission=&3Permission: &7%1 core_gui__prestige_name=&3Nom de prestige: %1 + + + + +# For format, the edit codes need to be within []. A number defines the width +# and negative numbers will left justify the values with padding. An empty [] +# will not add any padding. All values are treated as strings. +# Header values will be used as is. Detail values identifies the placeholder to use. +# Important: Every [] must be paired with a value or it will produce a runtime error: +# 'Incorrect number of parameters: [Format specifier %s] +core_ranks_topn__player_line_1_header_format=[4] [-18] [-10] [11] [-8] [-12] +core_ranks_topn__player_line_1_header_values=Rank, Player, PreDefRanks, Balance, r-Score, Penalty +core_ranks_topn__player_line_2_header_format=[4] [-10] [7] [-18] [9] +core_ranks_topn__player_line_2_header_values=Rank, Ranks, r-Score, Player, Balance + +# For detail_values you can use any of the following placeholders, but they must pair up +# with the detail_format's []. +# {playerName}, {rankPosition}, {rankScore}, {rankScorePenalty}, +# {prestigeRank}, {defaultRank}, {prestigeDefaultRank}, +# {prestigeRankTag}, {defaultRankTag}, {prestigeDefaultRankTag}, +# {prestigeRankTagNoColor}, {defaultRankTagNoColor}, {prestigeDefaultRankTagNoColor}, +# {balanceFmt}, {balanceKmbt}, {balanceMetric} +core_ranks_topn__player_line_1_detail_format= [-4] [-18] [-12] [10] [7] [10] +core_ranks_topn__player_line_1_detail_values={rankPosition}, {playerName}, {prestigeDefaultRankTagNoColor}, {balanceKmbt}, {rankScore}, {rankScorePenalty} +core_ranks_topn__player_line_2_detail_format= [-3] [-10] [7] [-18] [9] +core_ranks_topn__player_line_2_detail_values={rankPosition}, {prestigeDefaultRankTagNoColor}, {rankScore}, {playerName}, {balanceKmbt} + + diff --git a/prison-core/src/main/resources/lang/core/hu_HU.properties b/prison-core/src/main/resources/lang/core/hu_HU.properties index fee17ae76..2d5d92351 100644 --- a/prison-core/src/main/resources/lang/core/hu_HU.properties +++ b/prison-core/src/main/resources/lang/core/hu_HU.properties @@ -76,7 +76,7 @@ # like to share, please contact a staff member on our Discord server. #Thanks for your contributions! # -messages__version=8 +messages__version=9 messages__auto_refresh=true @@ -192,3 +192,31 @@ core_gui__value=&3Value: %1 core_gui__permission=&3Permission: &7%1 core_gui__prestige_name=&3Prestige name: %1 + + + + +# For format, the edit codes need to be within []. A number defines the width +# and negative numbers will left justify the values with padding. An empty [] +# will not add any padding. All values are treated as strings. +# Header values will be used as is. Detail values identifies the placeholder to use. +# Important: Every [] must be paired with a value or it will produce a runtime error: +# 'Incorrect number of parameters: [Format specifier %s] +core_ranks_topn__player_line_1_header_format=[4] [-18] [-10] [11] [-8] [-12] +core_ranks_topn__player_line_1_header_values=Rank, Player, PreDefRanks, Balance, r-Score, Penalty +core_ranks_topn__player_line_2_header_format=[4] [-10] [7] [-18] [9] +core_ranks_topn__player_line_2_header_values=Rank, Ranks, r-Score, Player, Balance + +# For detail_values you can use any of the following placeholders, but they must pair up +# with the detail_format's []. +# {playerName}, {rankPosition}, {rankScore}, {rankScorePenalty}, +# {prestigeRank}, {defaultRank}, {prestigeDefaultRank}, +# {prestigeRankTag}, {defaultRankTag}, {prestigeDefaultRankTag}, +# {prestigeRankTagNoColor}, {defaultRankTagNoColor}, {prestigeDefaultRankTagNoColor}, +# {balanceFmt}, {balanceKmbt}, {balanceMetric} +core_ranks_topn__player_line_1_detail_format= [-4] [-18] [-12] [10] [7] [10] +core_ranks_topn__player_line_1_detail_values={rankPosition}, {playerName}, {prestigeDefaultRankTagNoColor}, {balanceKmbt}, {rankScore}, {rankScorePenalty} +core_ranks_topn__player_line_2_detail_format= [-3] [-10] [7] [-18] [9] +core_ranks_topn__player_line_2_detail_values={rankPosition}, {prestigeDefaultRankTagNoColor}, {rankScore}, {playerName}, {balanceKmbt} + + diff --git a/prison-core/src/main/resources/lang/core/it_IT.properties b/prison-core/src/main/resources/lang/core/it_IT.properties index 7868eee2f..3ad654dc4 100644 --- a/prison-core/src/main/resources/lang/core/it_IT.properties +++ b/prison-core/src/main/resources/lang/core/it_IT.properties @@ -76,7 +76,7 @@ # like to share, please contact a staff member on our Discord server. #Thanks for your contributions! # -messages__version=8 +messages__version=9 messages__auto_refresh=true @@ -192,3 +192,31 @@ core_gui__value=&3Value: %1 core_gui__permission=&3Permission: &7%1 core_gui__prestige_name=&3Prestige name: %1 + + + + +# For format, the edit codes need to be within []. A number defines the width +# and negative numbers will left justify the values with padding. An empty [] +# will not add any padding. All values are treated as strings. +# Header values will be used as is. Detail values identifies the placeholder to use. +# Important: Every [] must be paired with a value or it will produce a runtime error: +# 'Incorrect number of parameters: [Format specifier %s] +core_ranks_topn__player_line_1_header_format=[4] [-18] [-10] [11] [-8] [-12] +core_ranks_topn__player_line_1_header_values=Rank, Player, PreDefRanks, Balance, r-Score, Penalty +core_ranks_topn__player_line_2_header_format=[4] [-10] [7] [-18] [9] +core_ranks_topn__player_line_2_header_values=Rank, Ranks, r-Score, Player, Balance + +# For detail_values you can use any of the following placeholders, but they must pair up +# with the detail_format's []. +# {playerName}, {rankPosition}, {rankScore}, {rankScorePenalty}, +# {prestigeRank}, {defaultRank}, {prestigeDefaultRank}, +# {prestigeRankTag}, {defaultRankTag}, {prestigeDefaultRankTag}, +# {prestigeRankTagNoColor}, {defaultRankTagNoColor}, {prestigeDefaultRankTagNoColor}, +# {balanceFmt}, {balanceKmbt}, {balanceMetric} +core_ranks_topn__player_line_1_detail_format= [-4] [-18] [-12] [10] [7] [10] +core_ranks_topn__player_line_1_detail_values={rankPosition}, {playerName}, {prestigeDefaultRankTagNoColor}, {balanceKmbt}, {rankScore}, {rankScorePenalty} +core_ranks_topn__player_line_2_detail_format= [-3] [-10] [7] [-18] [9] +core_ranks_topn__player_line_2_detail_values={rankPosition}, {prestigeDefaultRankTagNoColor}, {rankScore}, {playerName}, {balanceKmbt} + + diff --git a/prison-core/src/main/resources/lang/core/nl_BE.properties b/prison-core/src/main/resources/lang/core/nl_BE.properties index bec93ed55..8a5e13c54 100644 --- a/prison-core/src/main/resources/lang/core/nl_BE.properties +++ b/prison-core/src/main/resources/lang/core/nl_BE.properties @@ -76,7 +76,7 @@ # like to share, please contact a staff member on our Discord server. #Thanks for your contributions! # -messages__version=8 +messages__version=9 messages__auto_refresh=true @@ -149,7 +149,15 @@ worldNotFound=De wereld %1 kon niet worden gevonden. 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. @@ -175,8 +183,41 @@ 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 + + + + +# For format, the edit codes need to be within []. A number defines the width +# and negative numbers will left justify the values with padding. An empty [] +# will not add any padding. All values are treated as strings. +# Header values will be used as is. Detail values identifies the placeholder to use. +# Important: Every [] must be paired with a value or it will produce a runtime error: +# 'Incorrect number of parameters: [Format specifier %s] +core_ranks_topn__player_line_1_header_format=[4] [-18] [-10] [11] [-8] [-12] +core_ranks_topn__player_line_1_header_values=Rank, Player, PreDefRanks, Balance, r-Score, Penalty +core_ranks_topn__player_line_2_header_format=[4] [-10] [7] [-18] [9] +core_ranks_topn__player_line_2_header_values=Rank, Ranks, r-Score, Player, Balance + +# For detail_values you can use any of the following placeholders, but they must pair up +# with the detail_format's []. +# {playerName}, {rankPosition}, {rankScore}, {rankScorePenalty}, +# {prestigeRank}, {defaultRank}, {prestigeDefaultRank}, +# {prestigeRankTag}, {defaultRankTag}, {prestigeDefaultRankTag}, +# {prestigeRankTagNoColor}, {defaultRankTagNoColor}, {prestigeDefaultRankTagNoColor}, +# {balanceFmt}, {balanceKmbt}, {balanceMetric} +core_ranks_topn__player_line_1_detail_format= [-4] [-18] [-12] [10] [7] [10] +core_ranks_topn__player_line_1_detail_values={rankPosition}, {playerName}, {prestigeDefaultRankTagNoColor}, {balanceKmbt}, {rankScore}, {rankScorePenalty} +core_ranks_topn__player_line_2_detail_format= [-3] [-10] [7] [-18] [9] +core_ranks_topn__player_line_2_detail_values={rankPosition}, {prestigeDefaultRankTagNoColor}, {rankScore}, {playerName}, {balanceKmbt} + + + diff --git a/prison-core/src/main/resources/lang/core/nl_NL.properties b/prison-core/src/main/resources/lang/core/nl_NL.properties index 270b1fc24..9560116bf 100644 --- a/prison-core/src/main/resources/lang/core/nl_NL.properties +++ b/prison-core/src/main/resources/lang/core/nl_NL.properties @@ -76,7 +76,7 @@ # like to share, please contact a staff member on our Discord server. #Thanks for your contributions! # -messages__version=8 +messages__version=9 messages__auto_refresh=true @@ -192,3 +192,31 @@ core_gui__value=&3Value: %1 core_gui__permission=&3Permission: &7%1 core_gui__prestige_name=&3Prestige name: %1 + + + + +# For format, the edit codes need to be within []. A number defines the width +# and negative numbers will left justify the values with padding. An empty [] +# will not add any padding. All values are treated as strings. +# Header values will be used as is. Detail values identifies the placeholder to use. +# Important: Every [] must be paired with a value or it will produce a runtime error: +# 'Incorrect number of parameters: [Format specifier %s] +core_ranks_topn__player_line_1_header_format=[4] [-18] [-10] [11] [-8] [-12] +core_ranks_topn__player_line_1_header_values=Rank, Player, PreDefRanks, Balance, r-Score, Penalty +core_ranks_topn__player_line_2_header_format=[4] [-10] [7] [-18] [9] +core_ranks_topn__player_line_2_header_values=Rank, Ranks, r-Score, Player, Balance + +# For detail_values you can use any of the following placeholders, but they must pair up +# with the detail_format's []. +# {playerName}, {rankPosition}, {rankScore}, {rankScorePenalty}, +# {prestigeRank}, {defaultRank}, {prestigeDefaultRank}, +# {prestigeRankTag}, {defaultRankTag}, {prestigeDefaultRankTag}, +# {prestigeRankTagNoColor}, {defaultRankTagNoColor}, {prestigeDefaultRankTagNoColor}, +# {balanceFmt}, {balanceKmbt}, {balanceMetric} +core_ranks_topn__player_line_1_detail_format= [-4] [-18] [-12] [10] [7] [10] +core_ranks_topn__player_line_1_detail_values={rankPosition}, {playerName}, {prestigeDefaultRankTagNoColor}, {balanceKmbt}, {rankScore}, {rankScorePenalty} +core_ranks_topn__player_line_2_detail_format= [-3] [-10] [7] [-18] [9] +core_ranks_topn__player_line_2_detail_values={rankPosition}, {prestigeDefaultRankTagNoColor}, {rankScore}, {playerName}, {balanceKmbt} + + diff --git a/prison-core/src/main/resources/lang/core/pt_PT.properties b/prison-core/src/main/resources/lang/core/pt_PT.properties index 9c87f5f9d..c3776f21d 100644 --- a/prison-core/src/main/resources/lang/core/pt_PT.properties +++ b/prison-core/src/main/resources/lang/core/pt_PT.properties @@ -76,7 +76,7 @@ # like to share, please contact a staff member on our Discord server. #Thanks for your contributions! # -messages__version=3 +messages__version=5 messages__auto_refresh=true @@ -101,6 +101,7 @@ core_text__just_now=just now core_text__ago=ago core_text__from_now=from now core_text__and=and +core_text__time_units_prefix_spacer= core_text__time_units_singular=year,month,week,day,hour,minute,second core_text__time_units_plural=years,months,weeks,days,hours,minutes,seconds core_text__time_units_short=y,m,w,d,h,m,s @@ -182,6 +183,7 @@ core_gui__page_next=&3Pagina seguinte. core_gui__page_prior=&3Pagina anterior. +core_gui__money_earned=&3You earned &a$%1 core_gui__price=&3Preco: %1 core_gui__confirm=&3Confirmar: %1 %2 core_gui__delay=&3Atrado: %1 secs @@ -190,3 +192,31 @@ core_gui__value=&3Valor: %1 core_gui__permission=&3Permissão: &7%1 core_gui__prestige_name=&3Nome do Prestige: %1 + + + + +# For format, the edit codes need to be within []. A number defines the width +# and negative numbers will left justify the values with padding. An empty [] +# will not add any padding. All values are treated as strings. +# Header values will be used as is. Detail values identifies the placeholder to use. +# Important: Every [] must be paired with a value or it will produce a runtime error: +# 'Incorrect number of parameters: [Format specifier %s] +core_ranks_topn__player_line_1_header_format=[4] [-18] [-10] [11] [-8] [-12] +core_ranks_topn__player_line_1_header_values=Rank, Player, PreDefRanks, Balance, r-Score, Penalty +core_ranks_topn__player_line_2_header_format=[4] [-10] [7] [-18] [9] +core_ranks_topn__player_line_2_header_values=Rank, Ranks, r-Score, Player, Balance + +# For detail_values you can use any of the following placeholders, but they must pair up +# with the detail_format's []. +# {playerName}, {rankPosition}, {rankScore}, {rankScorePenalty}, +# {prestigeRank}, {defaultRank}, {prestigeDefaultRank}, +# {prestigeRankTag}, {defaultRankTag}, {prestigeDefaultRankTag}, +# {prestigeRankTagNoColor}, {defaultRankTagNoColor}, {prestigeDefaultRankTagNoColor}, +# {balanceFmt}, {balanceKmbt}, {balanceMetric} +core_ranks_topn__player_line_1_detail_format= [-4] [-18] [-12] [10] [7] [10] +core_ranks_topn__player_line_1_detail_values={rankPosition}, {playerName}, {prestigeDefaultRankTagNoColor}, {balanceKmbt}, {rankScore}, {rankScorePenalty} +core_ranks_topn__player_line_2_detail_format= [-3] [-10] [7] [-18] [9] +core_ranks_topn__player_line_2_detail_values={rankPosition}, {prestigeDefaultRankTagNoColor}, {rankScore}, {playerName}, {balanceKmbt} + + diff --git a/prison-core/src/main/resources/lang/core/ro_RO.properties b/prison-core/src/main/resources/lang/core/ro_RO.properties index 647284ad2..1c7170fa5 100644 --- a/prison-core/src/main/resources/lang/core/ro_RO.properties +++ b/prison-core/src/main/resources/lang/core/ro_RO.properties @@ -76,7 +76,7 @@ # -messages__version=3 +messages__version=4 messages__auto_refresh=true @@ -192,3 +192,32 @@ core_gui__value=&3Value: %1 core_gui__permission=&3Permission: &7%1 core_gui__prestige_name=&3Prestige name: %1 + + + + +# For format, the edit codes need to be within []. A number defines the width +# and negative numbers will left justify the values with padding. An empty [] +# will not add any padding. All values are treated as strings. +# Header values will be used as is. Detail values identifies the placeholder to use. +# Important: Every [] must be paired with a value or it will produce a runtime error: +# 'Incorrect number of parameters: [Format specifier %s] +core_ranks_topn__player_line_1_header_format=[4] [-18] [-10] [11] [-8] [-12] +core_ranks_topn__player_line_1_header_values=Rank, Player, PreDefRanks, Balance, r-Score, Penalty +core_ranks_topn__player_line_2_header_format=[4] [-10] [7] [-18] [9] +core_ranks_topn__player_line_2_header_values=Rank, Ranks, r-Score, Player, Balance + +# For detail_values you can use any of the following placeholders, but they must pair up +# with the detail_format's []. +# {playerName}, {rankPosition}, {rankScore}, {rankScorePenalty}, +# {prestigeRank}, {defaultRank}, {prestigeDefaultRank}, +# {prestigeRankTag}, {defaultRankTag}, {prestigeDefaultRankTag}, +# {prestigeRankTagNoColor}, {defaultRankTagNoColor}, {prestigeDefaultRankTagNoColor}, +# {balanceFmt}, {balanceKmbt}, {balanceMetric} +core_ranks_topn__player_line_1_detail_format= [-4] [-18] [-12] [10] [7] [10] +core_ranks_topn__player_line_1_detail_values={rankPosition}, {playerName}, {prestigeDefaultRankTagNoColor}, {balanceKmbt}, {rankScore}, {rankScorePenalty} +core_ranks_topn__player_line_2_detail_format= [-3] [-10] [7] [-18] [9] +core_ranks_topn__player_line_2_detail_values={rankPosition}, {prestigeDefaultRankTagNoColor}, {rankScore}, {playerName}, {balanceKmbt} + + + diff --git a/prison-core/src/main/resources/lang/core/zh-CN.properties b/prison-core/src/main/resources/lang/core/zh-CN.properties index cfeca845d..86f6b9a6a 100644 --- a/prison-core/src/main/resources/lang/core/zh-CN.properties +++ b/prison-core/src/main/resources/lang/core/zh-CN.properties @@ -1,4 +1,3 @@ - # # Prison is a Minecraft plugin for the prison game mode. # Copyright (C) 2021 The Prison Team @@ -77,7 +76,7 @@ # like to share, please contact a staff member on our Discord server. #Thanks for your contributions! # -messages__version=7 +messages__version=8 messages__auto_refresh=true @@ -101,7 +100,8 @@ core_text__prefix=&3 core_text__just_now=现在 core_text__ago=ä»¥å‰ core_text__from_now=åŽ -core_text__and=å’Œ +core_text__and=å +core_text__time_units_prefix_spacer= ’Œ core_text__time_units_singular=å¹´ã€æœˆã€å‘¨ã€æ—¥ã€æ—¶ã€åˆ†ã€ç§’ core_text__time_units_plural=å¹´ã€æœˆã€å‘¨ã€æ—¥ã€æ—¶ã€åˆ†ã€ç§’ core_text__time_units_short=å¹´ã€æœˆã€å‘¨ã€æ—¥ã€æ—¶ã€åˆ†ã€ç§’ @@ -119,6 +119,10 @@ 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. + +core_prison_utf8_test=\u041F\u0440\u0438\u0432\u0435\u0442! \u0414\u0430\u0432\u0430\u0439 \u043F\u043E\u0441\u043C\u043E\u0442\u0440\u0438\u043C, \u0440\u0430\u0431\u043E\u0442\u0430\u0435\u0442 \u043B\u0438? Test 01 + + # The following are the original messages and they will eventually be replaced. includeError=[%1] 具有无效值 @@ -179,6 +183,7 @@ core_gui__page_next=&3下一页 core_gui__page_prior=&3上一页 +core_gui__money_earned=&3You earned &a$%1 core_gui__price=&3价格:%1 core_gui__confirm=&3确认:%1%2 core_gui__delay=&3延迟:%1秒 @@ -187,3 +192,32 @@ core_gui__value=&3值:%1 core_gui__permission=&3æƒé™ï¼š&7%1 core_gui__prestige_name=&3声望å称:%1 + + + + +# For format, the edit codes need to be within []. A number defines the width +# and negative numbers will left justify the values with padding. An empty [] +# will not add any padding. All values are treated as strings. +# Header values will be used as is. Detail values identifies the placeholder to use. +# Important: Every [] must be paired with a value or it will produce a runtime error: +# 'Incorrect number of parameters: [Format specifier %s] +core_ranks_topn__player_line_1_header_format=[4] [-18] [-10] [11] [-8] [-12] +core_ranks_topn__player_line_1_header_values=Rank, Player, PreDefRanks, Balance, r-Score, Penalty +core_ranks_topn__player_line_2_header_format=[4] [-10] [7] [-18] [9] +core_ranks_topn__player_line_2_header_values=Rank, Ranks, r-Score, Player, Balance + +# For detail_values you can use any of the following placeholders, but they must pair up +# with the detail_format's []. +# {playerName}, {rankPosition}, {rankScore}, {rankScorePenalty}, +# {prestigeRank}, {defaultRank}, {prestigeDefaultRank}, +# {prestigeRankTag}, {defaultRankTag}, {prestigeDefaultRankTag}, +# {prestigeRankTagNoColor}, {defaultRankTagNoColor}, {prestigeDefaultRankTagNoColor}, +# {balanceFmt}, {balanceKmbt}, {balanceMetric} +core_ranks_topn__player_line_1_detail_format= [-4] [-18] [-12] [10] [7] [10] +core_ranks_topn__player_line_1_detail_values={rankPosition}, {playerName}, {prestigeDefaultRankTagNoColor}, {balanceKmbt}, {rankScore}, {rankScorePenalty} +core_ranks_topn__player_line_2_detail_format= [-3] [-10] [7] [-18] [9] +core_ranks_topn__player_line_2_detail_values={rankPosition}, {prestigeDefaultRankTagNoColor}, {rankScore}, {playerName}, {balanceKmbt} + + + diff --git a/prison-core/src/main/resources/lang/core/zh_TW.properties b/prison-core/src/main/resources/lang/core/zh_TW.properties index 99880acb3..0d605c9e4 100644 --- a/prison-core/src/main/resources/lang/core/zh_TW.properties +++ b/prison-core/src/main/resources/lang/core/zh_TW.properties @@ -76,7 +76,7 @@ # like to share, please contact a staff member on our Discord server. #Thanks for your contributions! # -messages__version=8 +messages__version=9 messages__auto_refresh=true @@ -192,3 +192,32 @@ core_gui__value=&3Value: %1 core_gui__permission=&3Permission: &7%1 core_gui__prestige_name=&3Prestige name: %1 + + + + +# For format, the edit codes need to be within []. A number defines the width +# and negative numbers will left justify the values with padding. An empty [] +# will not add any padding. All values are treated as strings. +# Header values will be used as is. Detail values identifies the placeholder to use. +# Important: Every [] must be paired with a value or it will produce a runtime error: +# 'Incorrect number of parameters: [Format specifier %s] +core_ranks_topn__player_line_1_header_format=[4] [-18] [-10] [11] [-8] [-12] +core_ranks_topn__player_line_1_header_values=Rank, Player, PreDefRanks, Balance, r-Score, Penalty +core_ranks_topn__player_line_2_header_format=[4] [-10] [7] [-18] [9] +core_ranks_topn__player_line_2_header_values=Rank, Ranks, r-Score, Player, Balance + +# For detail_values you can use any of the following placeholders, but they must pair up +# with the detail_format's []. +# {playerName}, {rankPosition}, {rankScore}, {rankScorePenalty}, +# {prestigeRank}, {defaultRank}, {prestigeDefaultRank}, +# {prestigeRankTag}, {defaultRankTag}, {prestigeDefaultRankTag}, +# {prestigeRankTagNoColor}, {defaultRankTagNoColor}, {prestigeDefaultRankTagNoColor}, +# {balanceFmt}, {balanceKmbt}, {balanceMetric} +core_ranks_topn__player_line_1_detail_format= [-4] [-18] [-12] [10] [7] [10] +core_ranks_topn__player_line_1_detail_values={rankPosition}, {playerName}, {prestigeDefaultRankTagNoColor}, {balanceKmbt}, {rankScore}, {rankScorePenalty} +core_ranks_topn__player_line_2_detail_format= [-3] [-10] [7] [-18] [9] +core_ranks_topn__player_line_2_detail_values={rankPosition}, {prestigeDefaultRankTagNoColor}, {rankScore}, {playerName}, {balanceKmbt} + + + 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 da99ff80f..502cddbd9 100644 --- a/prison-core/src/main/resources/lang/mines/de_DE.properties +++ b/prison-core/src/main/resources/lang/mines/de_DE.properties @@ -60,7 +60,7 @@ # -messages__version=4 +messages__version=5 messages__auto_refresh=true @@ -69,6 +69,7 @@ messages__auto_refresh=true reset_warning=&7Alle Minen %1 wurden zurückgesetzt in &3%2&7. reset_message=&7Alle Minen %1 wurden zurückgesetzt. +skip_reset_message= not_allowed=&7Hier darfst du nicht verminen. autosmelt_enable=&bAutosmelt &7wurde aktiviert. autosmelt_disable=&bAutosmelt &7wurde deaktiviert. 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 d7c409967..b21d897fe 100644 --- a/prison-core/src/main/resources/lang/mines/en_US.properties +++ b/prison-core/src/main/resources/lang/mines/en_US.properties @@ -60,7 +60,7 @@ # -messages__version=4 +messages__version=5 messages__auto_refresh=true @@ -69,6 +69,7 @@ messages__auto_refresh=true reset_warning=&7Mine %1 will reset in &3%2&7. reset_message=&7The mine %1 has been reset. +skip_reset_message= not_allowed=&7You are not allowed to mine here. autosmelt_enable=&bAutosmelt &7has been &aenabled&7. autosmelt_disable=&bAutosmelt &7has been &cdisabled&7. 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 11692e63a..e2baf94f9 100644 --- a/prison-core/src/main/resources/lang/mines/es_ES.properties +++ b/prison-core/src/main/resources/lang/mines/es_ES.properties @@ -60,7 +60,7 @@ # -messages__version=4 +messages__version=5 messages__auto_refresh=true @@ -69,6 +69,7 @@ messages__auto_refresh=true reset_warning=&7Todas las minas %1 se reiniciarán en &3%2&7. reset_message=&7Todas las minas %1 han sido reiniciadas. +skip_reset_message= not_allowed=&7No tienes permitido minar aquí. autosmelt_enable=&7La &bFundición Automática &7ha sido &aactivada&7. autosmelt_disable=&7La &bFundición Automática &7ha sido &cdesactivada&7. diff --git a/prison-core/src/main/resources/lang/mines/fi_FI.properties b/prison-core/src/main/resources/lang/mines/fi_FI.properties index 4d8607849..a17a07eae 100644 --- a/prison-core/src/main/resources/lang/mines/fi_FI.properties +++ b/prison-core/src/main/resources/lang/mines/fi_FI.properties @@ -60,7 +60,7 @@ # -messages__version=4 +messages__version=5 messages__auto_refresh=true @@ -69,6 +69,7 @@ messages__auto_refresh=true reset_warning=&7Mine %1 resettaa &3%2&7. reset_message=&7mine %1 on resetattu. +skip_reset_message= not_allowed=&7Et voi mainata täällä. autosmelt_enable=&bAutosmelt &7on &akäytössä&7. autosmelt_disable=&bAutosmelt &7on &cdisabloitu&7. diff --git a/prison-core/src/main/resources/lang/mines/fr_FR.properties b/prison-core/src/main/resources/lang/mines/fr_FR.properties index d6cf696c7..fccacf7cb 100644 --- a/prison-core/src/main/resources/lang/mines/fr_FR.properties +++ b/prison-core/src/main/resources/lang/mines/fr_FR.properties @@ -60,7 +60,7 @@ # -messages__version=4 +messages__version=5 messages__auto_refresh=true @@ -69,6 +69,7 @@ messages__auto_refresh=true reset_warning=&7La mine %1 va se réinitialiser dans &3%2&7. reset_message=&7La mine %1 a été réinitialisée. +skip_reset_message= not_allowed=&7Tu n'es pas autorisé à miner ici. autosmelt_enable=&bL'Autosmelt &7a été &aactivé&7. autosmelt_disable=&bL'Autosmelt &7a été &cdésactivé&7. 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 e1d896577..cd2424220 100644 --- a/prison-core/src/main/resources/lang/mines/hu_HU.properties +++ b/prison-core/src/main/resources/lang/mines/hu_HU.properties @@ -60,7 +60,7 @@ # -messages__version=4 +messages__version=5 messages__auto_refresh=true @@ -69,6 +69,7 @@ messages__auto_refresh=true reset_warning=&7Minden %1 bánya újratöltve &3%2&7. reset_message=&7Az összes %1 bánya vissza lett állítva. +skip_reset_message= not_allowed=&7A bányászás nem megengedett. autosmelt_enable=&bAz auto. égetés &7engedélyezve. autosmelt_disable=&bAz auto. égetés &7letiltva. 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 e3e9aea98..2c5b126ff 100644 --- a/prison-core/src/main/resources/lang/mines/it_IT.properties +++ b/prison-core/src/main/resources/lang/mines/it_IT.properties @@ -60,7 +60,7 @@ # -messages__version=4 +messages__version=5 messages__auto_refresh=true @@ -69,6 +69,7 @@ messages__auto_refresh=true reset_warning=&7Tutte le miniere %1 stanno per essere resettate tra &3%2&7. reset_message=&7Tutte le miniere %1 sono state resettate. +skip_reset_message= not_allowed=&7Non sei ammesso a scvare qua. autosmelt_enable=&bAutoFusione &7è stata &aabilitata&7. autosmelt_disable=&bAutoFusione &7è stata &cdisabilitata&7. 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 e56e952e1..41c35aa61 100644 --- a/prison-core/src/main/resources/lang/mines/nl_BE.properties +++ b/prison-core/src/main/resources/lang/mines/nl_BE.properties @@ -60,7 +60,7 @@ # -messages__version=4 +messages__version=5 messages__auto_refresh=true @@ -69,6 +69,7 @@ messages__auto_refresh=true reset_warning=&7Alle mijnen %1 worden hersteld in &3%2&7. reset_message=&7Alle mijnen %1 zijn hersteld. +skip_reset_message= not_allowed=&7Je mag hier niet mijnen. autosmelt_enable=&bAutosmelt &7is aangezet. autosmelt_disable=&bAutosmelt &7is afgezet. 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 3ae2e01cb..b93443167 100644 --- a/prison-core/src/main/resources/lang/mines/nl_NL.properties +++ b/prison-core/src/main/resources/lang/mines/nl_NL.properties @@ -60,7 +60,7 @@ # -messages__version=4 +messages__version=5 messages__auto_refresh=true @@ -69,6 +69,7 @@ messages__auto_refresh=true reset_warning=&Alle mijnen %1 worden hersteld in &3%2&7. reset_message=&7Alle mijnen %1 zijn hersteld. +skip_reset_message= not_allowed=&7Je mag hier niet mijnen. autosmelt_enable=&bAutosmelt &7is aangezet. autosmelt_disable=&bAutosmelt &7is afgezet. 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 ede5b9ef7..af7aa2c7b 100644 --- a/prison-core/src/main/resources/lang/mines/pt_PT.properties +++ b/prison-core/src/main/resources/lang/mines/pt_PT.properties @@ -60,7 +60,7 @@ # -messages__version=4 +messages__version=5 messages__auto_refresh=true @@ -69,6 +69,7 @@ messages__auto_refresh=true reset_warning=&7A Mina %1 vai resetar em &3%2&7. reset_message=&7A mina %1 resetou. +skip_reset_message= not_allowed=&7Não podes minerar aqui. autosmelt_enable=&bAutosmelt &7foi &aativado&7. autosmelt_disable=&bAutosmelt &7foi &cdisativado&7. 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 97432e42f..cfb6d17c9 100644 --- a/prison-core/src/main/resources/lang/mines/ro_RO.properties +++ b/prison-core/src/main/resources/lang/mines/ro_RO.properties @@ -60,7 +60,7 @@ # -messages__version=4 +messages__version=5 messages__auto_refresh=true @@ -69,6 +69,7 @@ messages__auto_refresh=true reset_warning=&7Mina %1 va fi resetată &3%2&7. reset_message=&7Mina %1 a fost resetată. +skip_reset_message= not_allowed=&7Nu ai voie să minezi aici. autosmelt_enable=&bAutosmelt-ul &7a fost &aactivat&7. autosmelt_disable=&bAutosmelt-ul &7a fost &cdezactivat&7. diff --git a/prison-core/src/main/resources/lang/mines/zh-CN.properties b/prison-core/src/main/resources/lang/mines/zh-CN.properties index 29973987e..d5e632a9b 100644 --- a/prison-core/src/main/resources/lang/mines/zh-CN.properties +++ b/prison-core/src/main/resources/lang/mines/zh-CN.properties @@ -60,7 +60,7 @@ # -messages__version=3 +messages__version=4 messages__auto_refresh=true @@ -69,6 +69,7 @@ messages__auto_refresh=true reset_warning=&7矿区%1将在&3%2分钟åŽ&7é‡ç½® reset_message=&7矿区%1å·²ç»é‡ç½® +skip_reset_message= not_allowed=&7你没有在此处挖矿所需è¦çš„æƒé™ autosmelt_enable=&bAutoMelt&7å·²å¯ç”¨&7 autosmelt_disable=&bAutoMelt&7å·²ç¦ç”¨&7 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 1ad538fbb..78a6e3e5d 100644 --- a/prison-core/src/main/resources/lang/mines/zh_TW.properties +++ b/prison-core/src/main/resources/lang/mines/zh_TW.properties @@ -60,7 +60,7 @@ # -messages__version=5 +messages__version=6 messages__auto_refresh=true @@ -69,6 +69,7 @@ messages__auto_refresh=true reset_warning=&7礦場 %1 將在 &3%2&7 分é˜å¾Œé‡ç½® reset_message=&7礦場 %1 已經é‡ç½® +skip_reset_message= not_allowed=&7您沒有權é™åœ¨æ­¤æŒ–礦 autosmelt_enable=&b自動冶煉 &7已被 &a啟用&7 autosmelt_disable=&b自動冶煉 &7已被 &cåœç”¨&7 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 8d0fc484d..9807416d3 100644 --- a/prison-core/src/main/resources/lang/ranks/en_US.properties +++ b/prison-core/src/main/resources/lang/ranks/en_US.properties @@ -61,6 +61,17 @@ # NOTE: You can add line feeds to your messages by inserting the placeholder '{br}'. # +## NOTE: Prison now supports the use of secondary placeholders on all "player" related messages. +## Just add these placeholders, in any position, combination, or quantity, to any +## message's text. +## {player} {rank_default} {rank_tag_default} {rank_next_default} {rank_next_tag_default} +## {rank_prestiges} {rank_tag_prestiges} {rank_next_prestiges} {rank_next_tag_prestiges} +## Player based messages are generally messages sent to player. Not all messages are able +## to support these secondary placeholders; if you find one that is not supported, please +## contact RoyalBlueRanger in a support thread on the Prison discord server and I may +## be able to enable them. + + messages__version=29 messages__auto_refresh=true diff --git a/prison-core/src/main/resources/lang/ranks/fr_FR.properties b/prison-core/src/main/resources/lang/ranks/fr_FR.properties index 6f5e7f54e..d5284ec1b 100644 --- a/prison-core/src/main/resources/lang/ranks/fr_FR.properties +++ b/prison-core/src/main/resources/lang/ranks/fr_FR.properties @@ -58,6 +58,19 @@ # these are a very low level static component of the fallback messaging system within Prison. # You will have to restart the server if you make any changes to the messages with these prefixes. # +# NOTE: You can add line feeds to your messages by inserting the placeholder '{br}'. +# + +## NOTE: Prison now supports the use of secondary placeholders on all "player" related messages. +## Just add these placeholders, in any position, combination, or quantity, to any +## message's text. +## {player} {rank_default} {rank_tag_default} {rank_next_default} {rank_next_tag_default} +## {rank_prestiges} {rank_tag_prestiges} {rank_next_prestiges} {rank_next_tag_prestiges} +## Player based messages are generally messages sent to player. Not all messages are able +## to support these secondary placeholders; if you find one that is not supported, please +## contact RoyalBlueRanger in a support thread on the Prison discord server and I may +## be able to enable them. + messages__version=28 messages__auto_refresh=true 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 c6f5ada05..13c0a863c 100644 --- a/prison-core/src/main/resources/lang/ranks/pt_PT.properties +++ b/prison-core/src/main/resources/lang/ranks/pt_PT.properties @@ -58,6 +58,19 @@ # these are a very low level static component of the fallback messaging system within Prison. # You will have to restart the server if you make any changes to the messages with these prefixes. # +# NOTE: You can add line feeds to your messages by inserting the placeholder '{br}'. +# + +## NOTE: Prison now supports the use of secondary placeholders on all "player" related messages. +## Just add these placeholders, in any position, combination, or quantity, to any +## message's text. +## {player} {rank_default} {rank_tag_default} {rank_next_default} {rank_next_tag_default} +## {rank_prestiges} {rank_tag_prestiges} {rank_next_prestiges} {rank_next_tag_prestiges} +## Player based messages are generally messages sent to player. Not all messages are able +## to support these secondary placeholders; if you find one that is not supported, please +## contact RoyalBlueRanger in a support thread on the Prison discord server and I may +## be able to enable them. + messages__version=6 messages__auto_refresh=true diff --git a/prison-core/src/main/resources/lang/ranks/zh-CN.properties b/prison-core/src/main/resources/lang/ranks/zh-CN.properties index 9111dfdcb..9a53f49c5 100644 --- a/prison-core/src/main/resources/lang/ranks/zh-CN.properties +++ b/prison-core/src/main/resources/lang/ranks/zh-CN.properties @@ -58,6 +58,19 @@ # these are a very low level static component of the fallback messaging system within Prison. # You will have to restart the server if you make any changes to the messages with these prefixes. # +# NOTE: You can add line feeds to your messages by inserting the placeholder '{br}'. +# + +## NOTE: Prison now supports the use of secondary placeholders on all "player" related messages. +## Just add these placeholders, in any position, combination, or quantity, to any +## message's text. +## {player} {rank_default} {rank_tag_default} {rank_next_default} {rank_next_tag_default} +## {rank_prestiges} {rank_tag_prestiges} {rank_next_prestiges} {rank_next_tag_prestiges} +## Player based messages are generally messages sent to player. Not all messages are able +## to support these secondary placeholders; if you find one that is not supported, please +## contact RoyalBlueRanger in a support thread on the Prison discord server and I may +## be able to enable them. + messages__version=25 messages__auto_refresh=true 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 88443d906..45cce31bc 100644 --- a/prison-core/src/main/resources/lang/ranks/zh_TW.properties +++ b/prison-core/src/main/resources/lang/ranks/zh_TW.properties @@ -58,6 +58,19 @@ # these are a very low level static component of the fallback messaging system within Prison. # You will have to restart the server if you make any changes to the messages with these prefixes. # +# NOTE: You can add line feeds to your messages by inserting the placeholder '{br}'. +# + +## NOTE: Prison now supports the use of secondary placeholders on all "player" related messages. +## Just add these placeholders, in any position, combination, or quantity, to any +## message's text. +## {player} {rank_default} {rank_tag_default} {rank_next_default} {rank_next_tag_default} +## {rank_prestiges} {rank_tag_prestiges} {rank_next_prestiges} {rank_next_tag_prestiges} +## Player based messages are generally messages sent to player. Not all messages are able +## to support these secondary placeholders; if you find one that is not supported, please +## contact RoyalBlueRanger in a support thread on the Prison discord server and I may +## be able to enable them. + messages__version=9 messages__auto_refresh=true 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 a1d5ca6d6..74eb4933e 100644 --- a/prison-core/src/test/java/tech/mcprison/prison/TestPlatform.java +++ b/prison-core/src/test/java/tech/mcprison/prison/TestPlatform.java @@ -385,7 +385,13 @@ public void autoCreateMineLinerAssignment( List rankMineNames, boolean forceLinersBottom, boolean forceLinersWalls ) { } - + + @Override + public String autoCreateMineLinerAssignment(ModuleElement eMine, + boolean forceLinersBottom, boolean forceLinersWalls) { + return null; + } + @Override public void autoCreateConfigureMines() { @@ -562,4 +568,26 @@ public String getLadderByFileName(String name) { public String getRankByFileName(String name) { return "a"; } + + public Map loadYaml(File file) { + return new TreeMap(); + } + + @Override + public String dumpEventListenersBlockPlaceEvents() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String dumpEventListenersPlayerDropItemEvents() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String dumpEventListenersPlayerPickupItemEvents() { + // TODO Auto-generated method stub + return null; + } } diff --git a/prison-core/src/test/java/tech/mcprison/prison/TestPlayer.java b/prison-core/src/test/java/tech/mcprison/prison/TestPlayer.java index 7ef2a4d27..6cf0b48c4 100644 --- a/prison-core/src/test/java/tech/mcprison/prison/TestPlayer.java +++ b/prison-core/src/test/java/tech/mcprison/prison/TestPlayer.java @@ -32,6 +32,7 @@ import tech.mcprison.prison.internal.block.Block; import tech.mcprison.prison.internal.inventory.Inventory; import tech.mcprison.prison.internal.scoreboard.Scoreboard; +import tech.mcprison.prison.ranks.data.RankPlayer; import tech.mcprison.prison.util.Gamemode; import tech.mcprison.prison.util.Location; @@ -251,5 +252,26 @@ public void incrementMinecraftStatsMineBlock( Player player, String blockName, i public void incrementMinecraftStatsDropCount( Player player, String blockName, int quantity) { } + + @Override + public List getSellAllMultiplierListings() { + return new ArrayList<>(); + } + + + @Override + public void sendMessage(List messages) { + + } + + @Override + public Player getPlatformPlayer() { + return null; + } + + @Override + public RankPlayer getRankPlayer() { + return null; + } } diff --git a/prison-core/src/test/java/tech/mcprison/prison/discord/PrisonSupportFilesTest.java b/prison-core/src/test/java/tech/mcprison/prison/discord/PrisonSupportFilesTest.java index 69d495bdd..830ebc306 100644 --- a/prison-core/src/test/java/tech/mcprison/prison/discord/PrisonSupportFilesTest.java +++ b/prison-core/src/test/java/tech/mcprison/prison/discord/PrisonSupportFilesTest.java @@ -44,6 +44,14 @@ public void test() { assertEquals(r5, convertColorCodes(t5) ); + +// String t6 = "&3This is &-a &1test & a&r &c&+fun &1sample"; +// String r6 = "This is a " +// + "test & a" +// + " fun sample\n"; +// +// assertEquals(r6, convertColorCodes(t6) ); + } } diff --git a/prison-core/src/test/java/tech/mcprison/prison/selection/SelectionTest.java b/prison-core/src/test/java/tech/mcprison/prison/selection/SelectionTest.java index ecf00ca7d..188c13c4a 100644 --- a/prison-core/src/test/java/tech/mcprison/prison/selection/SelectionTest.java +++ b/prison-core/src/test/java/tech/mcprison/prison/selection/SelectionTest.java @@ -48,8 +48,9 @@ public class SelectionTest { @Before public void setUp() throws Exception { TestPlatform testPlatform = new TestPlatform(temporaryFolder.newFolder("test"), false); - Prison.get() - .init(testPlatform, "1.12.X-test.1", new File("plugins/Prison")); + Prison.get().init(testPlatform, "1.13.X-test.1"); + + Prison.get().init(new File("plugins/Prison")); } @Test public void testSelection() throws Exception { diff --git a/prison-mines/src/main/java/tech/mcprison/prison/mines/PrisonMines.java b/prison-mines/src/main/java/tech/mcprison/prison/mines/PrisonMines.java index d827c336d..d4d0739f6 100644 --- a/prison-mines/src/main/java/tech/mcprison/prison/mines/PrisonMines.java +++ b/prison-mines/src/main/java/tech/mcprison/prison/mines/PrisonMines.java @@ -89,6 +89,11 @@ public PrisonMines(String version) { } public static PrisonMines getInstance() { + if ( i == null ) { + PrisonMines temp = new PrisonMines("(not loaded yet)"); + temp.setEnabled(false); + return temp; + } return i; } 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 61b967958..304a5a21e 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 @@ -15,6 +15,7 @@ import tech.mcprison.prison.output.BulletedListComponent; import tech.mcprison.prison.output.ChatDisplay; import tech.mcprison.prison.output.LogLevel; +import tech.mcprison.prison.output.Output; import tech.mcprison.prison.output.RowComponent; import tech.mcprison.prison.placeholders.PlaceholdersUtil; @@ -202,6 +203,8 @@ protected BulletedListComponent getBlocksList( Mine m, CommandPagedData cmdPageD if ( includeTotals ) { + totals.setChance( totalChance ); + addBlockStats( m, totals, maxBlockNameLength, iFmt, dFmt, builder ); } @@ -230,7 +233,9 @@ private void addBlockStats( Mine mine, PrisonBlockStatusData block, if ( totals ) { - String text = String.format( "&d%" + maxBlockNameLength + "s Totals: ", " " ); + String percent = dFmt.format( block.getChance() ) + "%"; + int length = maxBlockNameLength - ( percent.length() == 7 ? -1 : 0); + String text = String.format( "&d%-" + length + "s Totals: ", percent ); row.addTextComponent( text ); } else @@ -849,5 +854,23 @@ public void constraintsBlockCommand(CommandSender sender, } + public void listBlockLayerStatsCommand( CommandSender sender, String mineName ) { + + setLastMineReferenced(mineName); + + PrisonMines pMines = PrisonMines.getInstance(); + Mine m = pMines.getMine(mineName); + + if ( m != null ) { + + Output.get().logInfo( "Mine %s Block Layer Stats:", m.getName() ); + + List layers = m.getTargetBlockStatsPerLevel(); + for ( String layer : layers ) { + Output.get().logInfo( " " + layer ); + } + + } + } } 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 35512e819..8e7ced08c 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 @@ -75,7 +75,7 @@ * @author Dylan M. Perks */ public class MinesCommands - extends MinesBlockCommands { + extends MinesImportCommands { public MinesCommands() { super( "MinesCommands" ); @@ -94,6 +94,47 @@ public void minesSetSubcommands(CommandSender sender) { } + /* + * NOTE: The mines import commands are from the class MinesImportCommands. + * The command handler setups is here, but the code is within that class. + */ + + + @Command(identifier = "mines import", + onlyPlayers = false, permissions = "prison.commands") + public void mineImport(CommandSender sender) { + sender.dispatchCommand( "mines import help" ); + } + + @Command(identifier = "mines import jetsPrisonMines", + description = "Imports mines that were created within the plugin JetsPrisonMines. " + + "Most settings will be brought over to prison. If the mine already " + + "exits within prison, it will be skipped. First run this command " + + "without the option 'save' to confirm what can be imported." + + " Prison will use the path " + + "'JetsPrisonMines/mines/' to search for all yaml files that are " + + "used to store the mine configs, but his can be overridden with the " + + "'path=' option. Use the option 'world=' to save to a different world " + + "which can be useful if the world does not exist on your server. " + + "", + onlyPlayers = true, permissions = "mines.set") + public void minesImportJetsPrisonMines( CommandSender sender, + @Wildcard(join=true) + @Arg(name = "options", + description = "Options. The following options can customize how prison will perform " + + "the imports. [addLiner path= world= save] " + + "'addLiner' will randomly generate a liner for each mine. " + + "'path=' the default path is 'JetsPrisonMines/mines/' and " + + "this option will override this path. " + + "'world=' is the world name to use for mine and spawn placemments, " + + "which will override the yaml file's world even if it exists on the server. " + + "'save' must be specified or the imported mines will not be saved.") + String options ) { + + super.importJetsPrisonMines(sender, options); + } + + /* * NOTE: Block commands from the class MinesBlockCommands need to have the "command" references here * so the prison command handler can pick them up properly. @@ -184,6 +225,17 @@ public void searchBlockAllCommand(CommandSender sender, "mine" ); } + @Override + @Command(identifier = "mines block layerStats", permissions = "mines.block", onlyPlayers = false, + description = "A Mine's list layer stats") + public void listBlockLayerStatsCommand( CommandSender sender, + @Arg(name = "mineName", description = "The name of the mine to generate block layer stats for.") + String mineName ) { + + super.listBlockLayerStatsCommand( sender, mineName ); + } + + @Override @Command(identifier = "mines block list", permissions = "mines.block", description = "Lists all of the blocks assigned to a mine.") @@ -194,9 +246,13 @@ public void listBlockCommand(CommandSender sender, } @Override - @Command(identifier = "mines block constraint", permissions = "mines.block", - description = "Optionally enable constraints on a mine's block generation.") + description = "Optionally enable constraints on a mine's block generation. " + + "Please note that 'excludeTop' and 'excludeBottom' uses the layer " + + "count from the top, where the top layer is 1. If " + + "a mine has 20 layers and you want to exclude a block from the " + + "bottomm 5 layers, then you need to use a value of 15, so it will " + + "read as 'excludeBottom from layers 15 and lower'.") public void constraintsBlockCommand(CommandSender sender, @Arg(name = "mineName", description = "The name of the mine to view.") String mineName, @Arg(name = "blockNme", description = "The block's name") String blockName, @@ -251,7 +307,7 @@ public void createCommand(CommandSender sender, } mineName = mineName.trim(); - Player player = getPlayer( sender ); + Player player = sender.getPlatformPlayer(); if ( !virtual && (player == null || !player.isOnline())) { sendMessage( sender, "&3You must be a player in the game to run this command. " + @@ -545,7 +601,7 @@ public void spawnpointCommand(CommandSender sender, @Arg(name = "options", def = "set", description = "Options: Option to set or remove a spawn. [set *remove*]") String options ) { - Player player = getPlayer( sender ); + Player player = sender.getPlatformPlayer(); if (player == null || !player.isOnline()) { sender.sendMessage( "&3You must be a player in the game to run this command." ); @@ -981,7 +1037,7 @@ else if ( !mineAccessByRank && tpAccessByRank ) { if ( !m.isVirtual() ) { String worldName = m.getWorld().isPresent() ? m.getWorld().get().getName() : "&cmissing"; - Player player = sender == null ? null : getPlayer( sender ); + Player player = sender == null ? null : sender.getPlatformPlayer(); chatDisplay.addText("&3World: &7%-10s &3Center: &7%s &3%s &7%s", worldName, m.getBounds().getCenter().toBlockCoordinates(), @@ -1328,7 +1384,7 @@ public void resetCommand(CommandSender sender, "or '*all*' to reset all the mines, " + "or '*cancel*' to cancel the resetting of all mines.") String mineName, @Wildcard(join=true) - @Arg(name = "options", description = "Optional settings [noCommands details] " + + @Arg(name = "options", description = "Optional settings [noCommands details force] " + "'noCommands' prevents the running of mine commands. " + "'details' shows progress on reset *all*.", def = "") String options ) { @@ -1339,18 +1395,23 @@ public void resetCommand(CommandSender sender, MineResetScheduleType resetType = MineResetScheduleType.FORCED; List resetActions = new ArrayList<>(); + boolean force = false; if ( options.contains( "nocommands" )) { options = options.replace( "nocommands", "" ).trim(); resetActions.add( MineResetActions.NO_COMMANDS ); } - // The value of chained is an internal value and should not be shown to users: if ( options.contains( "details" ) ) { options = options.replace( "details", "" ).trim(); resetActions.add( MineResetActions.DETAILS ); } + if ( options.contains( "force" ) ) { + options = options.replace( "force", "" ).trim(); + force = true; + } + // The value of chained is an internal value and should not be shown to users: if ( options.contains( "chained" ) ) { options = options.replace( "chained", "" ).trim(); @@ -1397,6 +1458,33 @@ public void resetCommand(CommandSender sender, sender.sendMessage( "&cMine is disabled&7. Use &a/mines info &7for possible cause." ); return; } + + if ( !m.getMineStateMutex().isMinable() && force ) { + + sender.sendMessage( + String.format( + "&cMine is currently being reset. &7An unlock is being forced to allow " + + "a new reset." ) + ); + + // Force the reset by setting the mineResetStartTimestamp to 10 mins ago: + m.setMineResetStartTimestamp( System.currentTimeMillis() - 10 * 60000 ); + } + + else if ( !m.getMineStateMutex().isMinable() ) { + long resetDuration = m.getMineResetStartTimestamp() == -1 ? 0 : + System.currentTimeMillis() - m.getMineResetStartTimestamp(); + + DecimalFormat dFmt = Prison.get().getDecimalFormatDouble(); + + sender.sendMessage( + String.format( + "&cMine is currently being reset. &7Will try to force an unlock to allow " + + "a new reset. May have to wait 3 minutes before the Mutex is releasable. " + + "The mine was reset %s seconds ago.", + dFmt.format( resetDuration / 1000.0d ) ) + ); + } try { @@ -1424,7 +1512,7 @@ public void listCommand(CommandSender sender, @Arg(name = "page", def = "1", description = "Page of search results (optional) [1-n, ALL]") String page ) { - Player player = getPlayer( sender ); + Player player = sender.getPlatformPlayer(); MineSortOrder sortOrder = MineSortOrder.fromString( sort ); @@ -1865,7 +1953,7 @@ public void skipResetCommand(CommandSender sender, Output.get().sendInfo( sender, message ); // Server Log message: - Player player = getPlayer( sender ); + Player player = sender.getPlatformPlayer(); Output.get().logInfo( "%s :: Changed by: %s", message, (player == null ? "console" : player.getDisplayName()) ); } @@ -1885,7 +1973,7 @@ public void skipResetCommand(CommandSender sender, @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, or '*all' to apply to all mines.") String mineName, + @Arg(name = "mineName", description = "The name of the mine to edit, or '*all*' to apply to all mines.") 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. Use of " @@ -1944,7 +2032,7 @@ else if ( "*default*".equalsIgnoreCase( time ) ) { mine.getTag(), resetTime ); // Server Log message: - Player player = getPlayer( sender ); + Player player = sender.getPlatformPlayer(); Output.get().logInfo( "&bmines set resettime&7: &b%s &7set &b%s &7resetTime to &b%d", (player == null ? "console" : player.getDisplayName()), mine.getTag(), resetTime ); } @@ -1990,7 +2078,7 @@ else if ( "*default*".equalsIgnoreCase( time ) ) { Output.get().sendInfo( sender, "&7mines set resettime: &b%s &7resetTime set to &b%d", m.getTag(), resetTime ); // Server Log message: - Player player = getPlayer( sender ); + Player player = sender.getPlatformPlayer(); Output.get().logInfo( "&bmines set resettime&7: &b%s &7set &b%s &7resetTime to &b%d", (player == null ? "console" : player.getDisplayName()), m.getTag(), resetTime ); } @@ -2019,19 +2107,21 @@ else if ( "*default*".equalsIgnoreCase( time ) ) { @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, + @Arg(name = "mineName", + description = "The name of the mine to edit. Use '*all' for all mines.") String mineName, @Arg(name = "time/DISABLE", description = "Delay in seconds before resetting when the mine reaches " + "zero blocks, or DISABLE." ) String time ) { - if (performCheckMineExists(sender, mineName)) { - setLastMineReferenced(mineName); + if ( "*all*".equalsIgnoreCase( mineName ) || + performCheckMineExists(sender, mineName)) { + + double resetTime = + time != null && "disable".equalsIgnoreCase( time ) ? -1.0d : + 0.0d; try { - double resetTime = - time != null && "disable".equalsIgnoreCase( time ) ? -1.0d : - 0.0d; if ( resetTime != -1.0d && time != null && time.trim().length() > 0 ) { resetTime = Double.parseDouble( time ); @@ -2044,45 +2134,64 @@ public void zeroBlockResetDelayCommand(CommandSender sender, resetTime = 0.0d; } } - - 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; -// } - - m.setZeroBlockResetDelaySec( resetTime ); - - pMines.getMineManager().saveMine( m ); - - 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", - m.getTag(), dFmt.format( resetTime ) ); - - } else { - Output.get().sendInfo( sender, "&7Mine &b%s Zero Block Reset Delay: &b%s &7sec", - m.getTag(), dFmt.format( resetTime ) ); - - } - - // Server Log message: - Player player = getPlayer( sender ); - Output.get().logInfo( "&7Mine &b%s Zero Block Reset Delay: &b%s &7set it to &b%s &7sec", - (player == null ? "console" : player.getDisplayName()), - m, dFmt.format( resetTime ) ); } catch ( NumberFormatException e ) { Output.get().sendWarn( sender, "&7Invalid zeroBlockResetDelay value for &b%s&7. Must be an double value of &b0.00 &7or " + "greater. [&b%s&7]", mineName, time ); + return; + } + + PrisonMines pMines = PrisonMines.getInstance(); + + if ( !"*all*".equalsIgnoreCase( mineName ) ) { + setLastMineReferenced(mineName); + + Mine m = pMines.getMine(mineName); + + minesSetResetDelay(sender, resetTime, pMines, m); + } + else { + + for ( Mine m : pMines.getMines() ) { + minesSetResetDelay(sender, resetTime, pMines, m); + } } + + +// if ( !m.isEnabled() ) { +// sender.sendMessage( "&cMine is disabled&7. Use &a/mines info &7for possible cause." ); +// return; +// } + + } } + + private void minesSetResetDelay(CommandSender sender, double resetTime, PrisonMines pMines, Mine m) { + m.setZeroBlockResetDelaySec( resetTime ); + + pMines.getMineManager().saveMine( m ); + + 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", + m.getTag(), dFmt.format( resetTime ) ); + + } else { + Output.get().sendInfo( sender, "&7Mine &b%s Zero Block Reset Delay: &b%s &7sec", + m.getTag(), dFmt.format( resetTime ) ); + + } + + // Server Log message: + Player player = sender.getPlatformPlayer(); + Output.get().logInfo( "&7Mine &b%s Zero Block Reset Delay: &b%s &7set it to &b%s &7sec", + (player == null ? "console" : player.getDisplayName()), + m, dFmt.format( resetTime ) ); + } @@ -2099,71 +2208,89 @@ public void zeroBlockResetDelayCommand(CommandSender sender, 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, - @Arg(name = "mineName", description = "The name of the mine to edit.") String mineName, + @Arg(name = "mineName", + description = "The name of the mine to edit. Use '*all*' to apply to all mmines.") + String mineName, @Arg(name = "percent", description = "Threshold percent to trigger a reset.(0 is disabled)", def = "0" ) String percent ) { - if (performCheckMineExists(sender, mineName)) { - setLastMineReferenced(mineName); + if ( "*all*".equalsIgnoreCase( mineName ) || + performCheckMineExists(sender, mineName)) { PrisonMines pMines = PrisonMines.getInstance(); - Mine m = pMines.getMine(mineName); + + if ( !"*all*".equalsIgnoreCase( mineName ) ) { + setLastMineReferenced(mineName); + + Mine m = pMines.getMine(mineName); + + changeMinePercentThreshold(sender, percent, pMines, m); + } + else { + for ( Mine m : pMines.getMines() ) { + + changeMinePercentThreshold(sender, percent, pMines, m); + } + } // if ( !m.isEnabled() ) { // sender.sendMessage( "&cMine is disabled&7. Use &a/mines info &7for possible cause." ); // return; // } - double thresholdPercent = 0.0d; - - try { - thresholdPercent = Double.parseDouble( percent ); - if ( thresholdPercent < 0.0d ) { - thresholdPercent = 0.0d; - } else if ( thresholdPercent > 100.0d ) { - thresholdPercent = 100.0d; - } - } - catch ( NumberFormatException e1 ) { - Output.get().sendWarn( sender,"&7Invalid percentage. Not a number. " + - "Was &b%s&7.", (percent == null ? "&c-blank-" : percent) ); - return; - } - - - if ( thresholdPercent == m.getResetThresholdPercent() ) { - String msg = "The Reset Threshold Percent was not changed."; - Output.get().sendInfo( sender, msg ); - return; - } - - m.setResetThresholdPercent( thresholdPercent ); - - pMines.getMineManager().saveMine( m ); - - double blocks = m.isVirtual() ? 0 : - m.getBounds().getTotalBlockCount() * - m.getResetThresholdPercent() / 100.0d; - - 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, " + - "which is about &b%s &7blocks.", - m.getTag(), - fFmt.format( m.getResetThresholdPercent() ), - dFmt.format( blocks ) ); - Output.get().sendInfo( sender, message ); - - // Server Log message: - Player player = getPlayer( sender ); - Output.get().logInfo( "%s :: Changed by: %s", message, - (player == null ? "console" : player.getDisplayName()) ); } } + private void changeMinePercentThreshold(CommandSender sender, String percent, PrisonMines pMines, Mine m) { + double thresholdPercent = 0.0d; + + try { + thresholdPercent = Double.parseDouble( percent ); + if ( thresholdPercent < 0.0d ) { + thresholdPercent = 0.0d; + } else if ( thresholdPercent > 100.0d ) { + thresholdPercent = 100.0d; + } + } + catch ( NumberFormatException e1 ) { + Output.get().sendWarn( sender,"&7Invalid percentage. Not a number. " + + "Was &b%s&7.", (percent == null ? "&c-blank-" : percent) ); + return; + } + + + if ( thresholdPercent == m.getResetThresholdPercent() ) { + String msg = "The Reset Threshold Percent was not changed."; + Output.get().sendInfo( sender, msg ); + return; + } + + m.setResetThresholdPercent( thresholdPercent ); + + pMines.getMineManager().saveMine( m ); + + double blocks = m.isVirtual() ? 0 : + m.getBounds().getTotalBlockCount() * + m.getResetThresholdPercent() / 100.0d; + + 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, " + + "which is about &b%s &7blocks.", + m.getTag(), + fFmt.format( m.getResetThresholdPercent() ), + dFmt.format( blocks ) ); + Output.get().sendInfo( sender, message ); + + // Server Log message: + Player player = sender.getPlatformPlayer(); + Output.get().logInfo( "%s :: Changed by: %s", message, + (player == null ? "console" : player.getDisplayName()) ); + } + @Command(identifier = "mines set notification", permissions = "mines.set", @@ -2282,49 +2409,67 @@ private boolean changeMineNotification( CommandSender sender, String mineName, "can be combined with the other notification settings.", altPermissions = "mines.notification.[mineName]") public void setNotificationPermissionCommand(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. Use '*all*' for all mines.") String mineName, @Arg(name = "action", def="enable", description = "Enable or disable the permission filtering: [enable, disable]") String action ) { - if (performCheckMineExists(sender, mineName)) { - setLastMineReferenced(mineName); + + if ( !action.equalsIgnoreCase( "enable" ) && !action.equalsIgnoreCase( "disable" )) { + sender.sendMessage( "&7Invalid value for action: [enable, disable]" ); + return; + } + + if ( "*all*".equalsIgnoreCase( mineName ) || + performCheckMineExists(sender, mineName)) { PrisonMines pMines = PrisonMines.getInstance(); - Mine m = pMines.getMine(mineName); - + + if ( "*all*".equalsIgnoreCase( mineName ) ) { + setLastMineReferenced(mineName); + + Mine m = pMines.getMine(mineName); + + minesSetNotificationPerm(sender, action, pMines, m); + } + else { + + for ( Mine m : pMines.getMines() ) { + minesSetNotificationPerm(sender, action, pMines, m); + } + } + // if ( !m.isEnabled() ) { // sender.sendMessage( "&cMine is disabled&7. Use &a/mines info &7for possible cause." ); // return; // } - if ( !action.equalsIgnoreCase( "enable" ) && !action.equalsIgnoreCase( "disable" )) { - sender.sendMessage( "&7Invalid value for action: [enable, disable]" ); - return; - } - - if ( action.equalsIgnoreCase( "enable" ) && !m.isUseNotificationPermission() ) { - sender.sendMessage( - String.format( "&7Notification Permission filter has been enabled. Using permission %s", - m.getMineNotificationPermissionName() ) ); - m.setUseNotificationPermission( true ); - pMines.getMineManager().saveMine( m ); - } - else if ( action.equalsIgnoreCase( "disable" ) && m.isUseNotificationPermission() ) { - sender.sendMessage( "&7Notification Permission filter has been disabled." ); - m.setUseNotificationPermission( false ); - pMines.getMineManager().saveMine( m ); - } - else { - - sender.sendMessage( "&7Notification Permission filter was not changed. Canceling." ); - } } } + private void minesSetNotificationPerm(CommandSender sender, String action, PrisonMines pMines, Mine m) { + if ( action.equalsIgnoreCase( "enable" ) && !m.isUseNotificationPermission() ) { + sender.sendMessage( + String.format( "&7Notification Permission filter has been enabled. Using permission %s", + m.getMineNotificationPermissionName() ) ); + m.setUseNotificationPermission( true ); + pMines.getMineManager().saveMine( m ); + } + else if ( action.equalsIgnoreCase( "disable" ) && m.isUseNotificationPermission() ) { + sender.sendMessage( "&7Notification Permission filter has been disabled." ); + m.setUseNotificationPermission( false ); + pMines.getMineManager().saveMine( m ); + } + else { + + sender.sendMessage( "&7Notification Permission filter was not changed. Canceling." ); + } + } + @@ -2340,48 +2485,78 @@ else if ( action.equalsIgnoreCase( "disable" ) && m.isUseNotificationPermission( "This command can only use permissions. Permission groups will not work. ", altPermissions = "mines.notification.[mineName]") public void setMinePermissionCommand(CommandSender sender, - @Arg(name = "mineName", description = "The name of the mine to add a permission to.") String mineName, - @Arg(name = "permission", def="enable", description = "Permission. Suggested: `mines.`: [none]") + @Arg(name = "mineName", + description = "The name of the mine to add a permission to. Use '*all*' for all mines.") + String mineName, + @Arg(name = "permission", def="enable", + description = "Permission. Can use a placeholder '{mmine}' to dynamically apply " + + "the mine name when using '*all*'. Example using placeholder: 'mines.{mine}' " + + "Suggested: 'mines.': [none]") String permission ) { - if (performCheckMineExists(sender, mineName)) { - setLastMineReferenced(mineName); - + if ( "*all*".equalsIgnoreCase( mineName ) || + performCheckMineExists(sender, mineName)) { + PrisonMines pMines = PrisonMines.getInstance(); - Mine m = pMines.getMine(mineName); - - if ( m.isMineAccessByRank() ) { - sender.sendMessage( "&3The use of Mine Access Permissions is not needed and is disabled " + - "because Mine Access is controlled by Ranks." ); + if ( "*all*".equalsIgnoreCase( mineName ) ) { - return; + for ( Mine m : pMines.getMines() ) { + + minesSetAccessPermission(sender, permission, pMines, m); + } + } + else { + setLastMineReferenced(mineName); + Mine m = pMines.getMine(mineName); + + minesSetAccessPermission(sender, permission, pMines, m); } - - - if ( permission == null || permission.equalsIgnoreCase( "none" ) ) { - m.setAccessPermission( null ); - pMines.getMineManager().saveMine( m ); - sender.sendMessage( - String.format( "&7The Mine Access Permission has been disabled for %s.", - m.getName() )); - } - else { - m.setAccessPermission( permission ); - pMines.getMineManager().saveMine( m ); - - sender.sendMessage( - String.format( "&7The Mine Access Permission has been enable for %s and " + - "has a value of [%s].", m.getName(), permission )); - } - } } + private void minesSetAccessPermission(CommandSender sender, + String permission, PrisonMines pMines, Mine m) { + + permission = permission + .replace( "{mine}", m.getName() ) + .replace( "{mineName}", m.getName() ) + .replace( "{minename}", m.getName() ) + .replace( "", m.getName() ) + .replace( "", m.getName() ) + .replace( "", m.getName() ); + + if ( m.isMineAccessByRank() ) { + + sender.sendMessage( "&3The use of Mine Access Permissions is not needed and is disabled " + + "because Mine Access is controlled by Ranks." ); + + return; + } + + + if ( permission == null || permission.equalsIgnoreCase( "none" ) ) { + m.setAccessPermission( null ); + pMines.getMineManager().saveMine( m ); + + sender.sendMessage( + String.format( "&7The Mine Access Permission has been disabled for %s.", + m.getName() )); + } + else { + m.setAccessPermission( permission ); + pMines.getMineManager().saveMine( m ); + + sender.sendMessage( + String.format( "&7The Mine Access Permission has been enable for %s and " + + "has a value of [%s].", m.getName(), permission )); + } + } + @Command(identifier = "mines set rank", permissions = "mines.set", description = "Links a mine to a rank or removes the rank.") @@ -2539,7 +2714,7 @@ public void redefineCommand(CommandSender sender, PrisonMines pMines = PrisonMines.getInstance(); Mine m = pMines.getMine(mineName); - Player player = getPlayer( sender ); + Player player = sender.getPlatformPlayer(); // if ( !m.isEnabled() ) { // sender.sendMessage( "&cMine is disabled&7. Use &a/mines info &7for possible cause." ); @@ -3238,7 +3413,7 @@ public void mineTp(CommandSender sender, } - Player player = getPlayer( sender ); + Player player = sender.getPlatformPlayer(); Player playerAlt = getOnlinePlayer( playerName ); @@ -3342,7 +3517,7 @@ else if ( playerAlt != null && !player.getName().equalsIgnoreCase( playerAlt.get public void mineTpTop(CommandSender sender ) { - Player player = getPlayer( sender ); + Player player = sender.getPlatformPlayer(); //oboolean isOp = sender.isOp(); @@ -3435,7 +3610,7 @@ public void mineStats(CommandSender sender) { description = "Identifies what mines you are in, or are the closest to." ) public void mineWhereAmI(CommandSender sender) { - Player player = getPlayer( sender ); + Player player = sender.getPlatformPlayer(); if (player == null || !player.isOnline()) { sender.sendMessage( "&3You must be a player in the game to run this command." ); @@ -3548,7 +3723,7 @@ private Player getOnlinePlayer( String playerName ) { onlyPlayers = false ) public void wandCommand(CommandSender sender) { - Player player = getPlayer( sender ); + Player player = sender.getPlatformPlayer(); if (player == null || !player.isOnline()) { sender.sendMessage( "&3You must be a player in the game to run this command." ); @@ -3649,8 +3824,8 @@ private void generateBlockEventListing( Mine m, ChatDisplay display, boolean inc FancyMessage msgCommand = new FancyMessage( String.format( " &a'&7%s&a'", blockEvent.getCommand() ) ) //.command("/mines blockEvent remove " + mineName + " " + blockEvent.getCommand() ) - .tooltip("Event Commands - You cannot change a command directly, " + - "delete it and then re-add it."); + .suggest( "/mines blockEvent update " + m.getName() + " " + rowNumber + " " + blockEvent.getCommand() ) + .tooltip("BlockEvent Command - Click to Edit"); row.addFancy( msgCommand ); @@ -3775,6 +3950,102 @@ public void blockEventRemove(CommandSender sender, } + @Command(identifier = "mines blockEvent update", + description = "Updates a mine BlockEvent; must be ran in console, or click on blockevent " + + "number in game when listing each block list. Due to limitations on auto editing " + + "you need to follow the special instructions as presented. First run this command " + + "to get a list of block events and their corresponding numbers. ", + onlyPlayers = false, permissions = "mines.set") + public void blockEventUpdate(CommandSender sender, + @Arg(name = "mineName" ) String mineName, + @Arg(name = "row", def = "0") Integer row, + @Arg(name = "command", def = "") @Wildcard String command ) { + + if (!performCheckMineExists(sender, mineName)) { + return; + } + + setLastMineReferenced(mineName); + + PrisonMines pMines = PrisonMines.getInstance(); + Mine m = pMines.getMine(mineName); + + if ( row == null || row <= 0 ) { + + ChatDisplay display = new ChatDisplay("BlockEvent Commands for " + m.getTag()); + display.addText("&8Hover over values for more information and clickable actions."); + generateBlockEventListing( m, display, true ); + + display.addText( + "&7Please provide a valid row number greater than zero. " + + "Was row=[&b%d&7]", + (row == null ? "null" : row) ); + + display.send(sender); + + return; + } + + + if (m.getBlockEvents() == null || m.getBlockEvents().size() == 0) { + Output.get().sendInfo(sender, "The mine '%s' contains no BlockEvent commands.", m.getTag()); + return; + } + + if ( row > m.getBlockEvents().size() ) { + sender.sendMessage( + String.format("&7Please provide a valid row number no greater than &b%d&7. " + + "Was row=[&b%d&7]", + m.getBlockEvents().size(), (row == null ? "null" : row) )); + return; + } + + MineBlockEvent blockEvent = m.getBlockEvents().get( row - 1 ); + + + + if ( blockEvent != null ) { + + String msg1 = String.format( "Original: '%s'", + blockEvent.getCommand() ); + sender.sendMessage(msg1); + + + if ( command == null || command.trim().length() == 0 ) { + sender.sendMessage( + String.format("&7Please resubmit this command and copy and paste the above original blockevent " + + "to the end. Edit the command prior to submitting. If you want to remove the " + + "blockevent, then use `/mines blockevent remove help`." )); + return; + } + else if (command.startsWith("/")) { + command = command.replaceFirst("/", ""); + } + + if ( blockEvent.getCommand().equals( command ) ) { + + sender.sendMessage( "&7No change detected. Will not update an existing command with the same commmand. " + + "Please review submitted updates and make changes if still needed."); + return; + } + + blockEvent.setCommand(command ); + + pMines.getMineManager().saveMine( m ); + + Output.get().sendInfo(sender, "Updated BlockEvent command '%s' in mine '%s'.", + blockEvent.getCommand(), m.getTag()); + } else { + Output.get().sendWarn(sender, + String.format("The mine %s doesn't contain that BlockEvent command. Nothing was changed.", + m.getTag())); + } + + // Redisplay the event list: + blockEventList( sender, mineName ); + } + + @Command(identifier = "mines blockEvent add", description = "Adds a BlockBreak command to a mine. " + "For each block that is broke there will be a chance to run one of these commands. \n" + diff --git a/prison-mines/src/main/java/tech/mcprison/prison/mines/commands/MinesCoreCommands.java b/prison-mines/src/main/java/tech/mcprison/prison/mines/commands/MinesCoreCommands.java index 7e82c09a5..238d71e59 100644 --- a/prison-mines/src/main/java/tech/mcprison/prison/mines/commands/MinesCoreCommands.java +++ b/prison-mines/src/main/java/tech/mcprison/prison/mines/commands/MinesCoreCommands.java @@ -78,4 +78,25 @@ public String formatStringPadRight( String text, int totalLength, Object... args return sb.toString(); } + + protected String extractParameter( String key, String options ) { + return extractParameter( key, options, true ); + } + + protected String extractParameter( String key, String options, boolean tryLowerCase ) { + String results = null; + int idx = options.indexOf( key ); + if ( idx != -1 ) { + int idxEnd = options.indexOf( " ", idx ); + if ( idxEnd == -1 ) { + idxEnd = options.length(); + } + results = options.substring( idx, idxEnd ); + } + else if ( tryLowerCase ) { + // try again, but lowercase the key + results = extractParameter( key.toLowerCase(), options, false ); + } + return results; + } } diff --git a/prison-mines/src/main/java/tech/mcprison/prison/mines/commands/MinesImportCommands.java b/prison-mines/src/main/java/tech/mcprison/prison/mines/commands/MinesImportCommands.java new file mode 100644 index 000000000..1ca912e33 --- /dev/null +++ b/prison-mines/src/main/java/tech/mcprison/prison/mines/commands/MinesImportCommands.java @@ -0,0 +1,394 @@ +package tech.mcprison.prison.mines.commands; + +import java.io.File; +import java.text.DecimalFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +import tech.mcprison.prison.Prison; +import tech.mcprison.prison.internal.CommandSender; +import tech.mcprison.prison.internal.World; +import tech.mcprison.prison.internal.block.PrisonBlock; +import tech.mcprison.prison.internal.block.PrisonBlockTypes; +import tech.mcprison.prison.mines.PrisonMines; +import tech.mcprison.prison.mines.data.Mine; +import tech.mcprison.prison.mines.data.Mine.MineType; +import tech.mcprison.prison.mines.data.MineData.MineNotificationMode; +import tech.mcprison.prison.mines.features.MineLinerBuilder; +import tech.mcprison.prison.mines.features.MineLinerBuilder.LinerPatterns; +import tech.mcprison.prison.output.Output; +import tech.mcprison.prison.selection.Selection; +import tech.mcprison.prison.util.Location; +import tech.mcprison.prison.util.Bounds.Edges; + +public class MinesImportCommands + extends MinesBlockCommands { + + + public MinesImportCommands( String cmdGroup ) { + super( cmdGroup ); + } + + + + + public void importJetsPrisonMines( CommandSender sender, + String options ) { + + boolean save = false; + boolean addLiner = false; + + String path = "JetsPrisonMines//mines//"; + + String worldForced = ""; + +// if ( options.contains( "testImport" ) ) { +// testImport = true; +// list = true; +// options = options.replace( "testImport", "" ).trim(); +// } +// +// if ( options.contains( "list" ) ) { +// testImport = false; +// list = true; +// options = options.replace( "list", "" ).trim(); +// } + + if ( options.contains( "save" ) ) { + save = true; + options = options.replace( "save", "" ).trim(); + } + + if ( options.contains( "addLiner" ) ) { + addLiner = true; + options = options.replace( "addLiner", "" ).trim(); + } + + String pathStr = extractParameter("path=", options); + if ( pathStr != null ) { + options = options.replace( pathStr, "" ); + pathStr = pathStr.replace( "path=", "" ).trim(); + + path = pathStr; + } + + String worldStr = extractParameter("world=", options); + if ( worldStr != null ) { + options = options.replace( worldStr, "" ); + worldStr = worldStr.replace( "world=", "" ).trim(); + + worldForced = worldStr; + } + + File dirPlugins = Prison.get().getPlatform().getPluginDirectory().getParentFile(); + File dirMines = new File( dirPlugins, path ); + + if ( !dirMines.exists() || !dirMines.isDirectory() ) { + sender.sendMessage( + String.format( + "Error: The path for JetsPrisonMines' mines does not exist: '%s'", + dirMines.getAbsolutePath() ) ); + + return; + } + + DecimalFormat iFmt = Prison.get().getDecimalFormatInt(); + List files = Arrays.asList( dirMines.listFiles() ); + + PrisonMines pMines = PrisonMines.getInstance(); + + sender.sendMessage( + String.format( + "Prison import from JetsPrisonMines' mines: '%s'", + dirMines.getAbsolutePath() ) ); + sender.sendMessage( + String.format( + "Mines to import: '%d'", + files.size() ) ); + + int alreadyExists = 0; + int failed = 0; + int saved = 0; + int savable = 0; + + for ( File f : files ) { + + if ( f.exists() && f.isFile() ) { + + Mine mine = convertJetsPrisonMines( f, worldForced ); + + String status = ""; + if ( mine == null ) { + failed++; + status = "(failed)"; + } + else if ( pMines.getMine( mine.getName() ) != null ) { + alreadyExists++; + status = "(alreadyExists)"; + } + else if ( save ) { + pMines.getMineManager().add(mine); + pMines.getMineManager().saveMine( mine ); + + if ( addLiner ) { + Prison.get().getPlatform().autoCreateMineLinerAssignment( + mine, true, true ); + } + + saved++; + status = "(saved)"; + } + else { + savable++; + status = "(savable)"; + } + + sender.sendMessage( + String.format( + " %-18s %7s bytes %s", + f.getName(), iFmt.format(f.length()), + status ) ); + } + } + + if ( addLiner ) { + List mines = new ArrayList<>(); + + mines.addAll( pMines.getMines() ); + + for ( Mine mine : mines ) + { + if ( !mine.isVirtual() ) { + + for (Edges edge : Edges.values() ) { + + LinerPatterns linerPattern = LinerPatterns.fromString( + mine.getLinerData().getEdge(edge) ); + + boolean force = mine.getLinerData().getForce(edge); + boolean useTracer = false; + + new MineLinerBuilder( mine, edge, linerPattern, force, useTracer ); + } + + } + } + } + + sender.sendMessage( + String.format( + "Impored Mines: Saved: %d AlreadyExists: %d Saveable: %d Failed: %d", + saved, alreadyExists, savable, failed )); + } + + + + + private Mine convertJetsPrisonMines(File f, String worldForced ) { + Mine mine = null; + + + if ( !f.isFile() || !f.canRead() || f.length() == 0 ) { + return mine; + } + + + Map yaml = null; + + try { + yaml = Prison.get().getPlatform().loadYaml( f ); + + String mineName = (String) yaml.get( "mine_name" ); + + + List blocks = getYamlListString( yaml, "blocks" ); + + String spawnWorld = worldForced != null && worldForced.length() > 0 ? + worldForced : + getYamlString( yaml, "teleport_location.world" ); + double spawnX = getYamlDouble( yaml, "teleport_location.x" ); + double spawnY = getYamlDouble( yaml, "teleport_location.y" ); + double spawnZ = getYamlDouble( yaml, "teleport_location.z" ); + double spawnPitch = getYamlDouble( yaml, "teleport_location.pitch" ); + double spawnYaw = getYamlDouble( yaml, "teleport_location.yaw" ); + + String locWorld = worldForced != null && worldForced.length() > 0 ? + worldForced : + getYamlString( yaml, "region.world" ); + double xMin = getYamlInteger( yaml, "region.xmin" ); + double yMin = getYamlInteger( yaml, "region.ymin" ); + double zMin = getYamlInteger( yaml, "region.zmin" ); + double xMax = getYamlInteger( yaml, "region.xmax" ); + double yMax = getYamlInteger( yaml, "region.ymax" ); + double zMax = getYamlInteger( yaml, "region.zmax" ); + + + boolean rUseTimer = getYamlBoolean( yaml, "reset.use_timer" ); + int rTimer = getYamlInteger( yaml, "reset.timer" ); + boolean rUsePercentage = getYamlBoolean( yaml, "reset.use_percentage" ); + double rPercentage = getYamlDouble( yaml, "reset.percentage" ); + + boolean rUseMessages = getYamlBoolean( yaml, "reset.use_messages" ); + int rBlocksMined = getYamlInteger( yaml, "reset.blocks_mined" ); + + + if ( mineName == null || mineName.trim().length() == 0 || + spawnWorld == null || spawnWorld.trim().length() == 0 || + locWorld == null || locWorld.trim().length() == 0 ) { + return mine; + } + + + World sWorld = Prison.get().getPlatform().getWorld( spawnWorld ).orElse(null); + Location spawn = new Location( sWorld, spawnX, spawnY, spawnZ, + (float) spawnPitch, (float) spawnYaw ); + + + World lWorld = Prison.get().getPlatform().getWorld( locWorld ).orElse(null); + Location locMin = new Location( lWorld, xMin, yMin, zMin ); + Location locMax = new Location( lWorld, xMax, yMax, zMax ); + Selection mSel = new Selection( locMin, locMax); + + + boolean logInfo = false; + mine = new Mine( mineName, mSel, MineType.primary, logInfo ); + + String tag = "&5[&d+" + mineName + "&5]"; + mine.setTag( tag ); + + mine.setHasSpawn( false ); + + if ( spawn != null ) { + mine.setSpawn( spawn ); + mine.setHasSpawn( true ); + } + + if ( rUseTimer ) { + // reset time in seconds: + int time = rTimer * 60; + mine.setResetTime(time); + } + else { + // value of -1 disables resets by time: + mine.setResetTime( -1 ); + } + + if ( rUsePercentage ) { + mine.setResetThresholdPercent( rPercentage ); + } + + if ( rUseMessages ) { + mine.setNotificationMode( MineNotificationMode.within ); + } + else { + mine.setNotificationMode( MineNotificationMode.disabled ); + } + + mine.setBlockBreakCount(rBlocksMined); + + PrisonBlockTypes prisonBlockTypes = Prison.get().getPlatform().getPrisonBlockTypes(); + + for (String blockDetails : blocks) { + + String[] bd = blockDetails.split( ":" ); + + String blockName = bd.length > 0 ? bd[0] : null; + String chanceStr = bd.length > 1 ? bd[1] : "1.0"; + + PrisonBlock prisonBlock = prisonBlockTypes.getBlockTypesByName( blockName ); + + if ( prisonBlock != null ) { + + double chance = 1.0; + + try { + chance = Double.parseDouble(chanceStr); + } + catch (NumberFormatException e) { + } + + prisonBlock.setChance( chance ); + + mine.addPrisonBlock( prisonBlock ); + } + } + + + // Check if one of the blocks is effected by gravity, and if so, set that indicator. + mine.checkGravityAffectedBlocks(); + } + catch (Exception e) { + + String message = String.format( "Could not %s: %s [%s]", + (yaml == null ? "parse mine file" : + mine == null ? "generate mine" : + "fully configure mine"), + f.getName(), + e.getMessage()); + Output.get().logInfo( message ); + } + + return mine; + } + + private String getYamlString( Map yaml, String key ) { + String results = null; + + try { + results = (String) yaml.get( key ); + } + catch (Exception e) { + } + + return results; + } + private double getYamlDouble( Map yaml, String key ) { + double results = 0; + + try { + results = (Double) yaml.get( key ); + } + catch (Exception e) { + } + + return results; + } + private int getYamlInteger( Map yaml, String key ) { + int results = 0; + + try { + results = (Integer) yaml.get( key ); + } + catch (Exception e) { + } + + return results; + } + private boolean getYamlBoolean( Map yaml, String key ) { + boolean results = false; + + try { + results = (Boolean) yaml.get( key ); + } + catch (Exception e) { + } + + return results; + } + @SuppressWarnings("unchecked") + private List getYamlListString( Map yaml, String key ) { + List results = new ArrayList<>(); + + try { + results = new ArrayList<>( (List) yaml.get(key) ); + } + catch (Exception e) { + } + + return results; + } + +} + \ No newline at end of file diff --git a/prison-mines/src/main/java/tech/mcprison/prison/mines/data/Mine.java b/prison-mines/src/main/java/tech/mcprison/prison/mines/data/Mine.java index 316f3639f..a98462376 100644 --- a/prison-mines/src/main/java/tech/mcprison/prison/mines/data/Mine.java +++ b/prison-mines/src/main/java/tech/mcprison/prison/mines/data/Mine.java @@ -34,6 +34,7 @@ import tech.mcprison.prison.mines.features.MineLinerData; import tech.mcprison.prison.mines.managers.MineManager; import tech.mcprison.prison.output.Output; +import tech.mcprison.prison.placeholders.PlaceholderStringCoverter; import tech.mcprison.prison.selection.Selection; import tech.mcprison.prison.sorting.PrisonSortable; import tech.mcprison.prison.store.Document; @@ -47,7 +48,7 @@ @SuppressWarnings( "deprecation" ) public class Mine extends MineScheduler - implements PrisonSortable, Comparable { + implements PrisonSortable, Comparable, PlaceholderStringCoverter { public enum MineType { @@ -69,6 +70,10 @@ public static MineType fromString( String mineType ) { return results; } } + + public enum MineUnitTestUsage { + TRUE; + } /** * Creates a new, empty mine instance @@ -80,6 +85,23 @@ public Mine() { initialize(); } + /** + *

This constructor should ONLY be used in unit test since it will NOT run + * any of the initialization code so the automated services will not be started, + * which are not needed for unit tests. + *

+ * + * @param unitTestUsage + */ + public Mine( MineUnitTestUsage unitTestUsage, String mineName ) { + super(); + + setName( mineName ); + + // Kick off the initialize: + //initialize(); + } + /** *

This is called when a mine is first created. @@ -92,7 +114,7 @@ public Mine(String name, Selection selection) { this( name, selection, MineType.primary ); } - public Mine(String name, Selection selection, MineType mineType) { + public Mine(String name, Selection selection, MineType mineType, boolean logInfo ) { super(); setName(name); @@ -104,7 +126,7 @@ public Mine(String name, Selection selection, MineType mineType) { } else { - setBounds(selection.asBounds()); + setBounds(selection.asBounds(), logInfo ); setWorldName( getBounds().getMin().getWorld().getName()); @@ -115,6 +137,11 @@ public Mine(String name, Selection selection, MineType mineType) { initialize(); } + public Mine(String name, Selection selection, MineType mineType) { + this( name, selection, mineType, true ); + + } + /** *

Loads a mine from a document. *

@@ -438,6 +465,19 @@ else if (validateBlockNames.contains( blockTypeName ) ) { dirty = true; } + if ( prisonBlock == null && "grass".equalsIgnoreCase(docBlock) ) { + // For spigot v20.0.4 GRASS was changed to SHORT_GRASS + + String fixedName = "SHORT_GRASS".toLowerCase(); + + prisonBlock = PrisonBlockStatusData.parseFromSaveFileFormat( fixedName ); + dirty = true; + + Output.get().logInfo( "NOTE: Block named GRASS has ben changed to SHORT_GRASS " + + "due to XMaterial's support for spigot v20.0.4. Please verify that " + + "it's spawning correctly on mine resets." ); + } + if ( prisonBlock != null ) { totalBlockCount += prisonBlock.getBlockCountTotal(); @@ -828,5 +868,160 @@ public String getBlockListString() public int compareTo( Mine o ) { return getName().toLowerCase().compareTo( o.getName().toLowerCase() ); } + + + + @Override + public String getStringPlaceholders() { + return "{mine} {mine_tag} {mine_world} {mine_type} {mine_group} " + + "{mine_rank} {mine_air_count} {mine_player_count} " + + "{mine_block_break_count} {mine_block_remaining_count} {mine_block_remaining_percent} " + + "{mine_blocks_mined_total} {mine_reset_time_sec} {mine_reset_time_remaining_sec} " + + "{mine_block_[block]_name} {mine_block_[block]_type} {mine_block_[block]_placed} " + + "{mine_block_[block]_remaining} {mine_block_[block]_total} {mine_block_[block]_chance}"; + } + + + /** + *

This function will provide support for secondary placeholders for all mine related placeholders. + * These secondary placeholders are in addition to the preexisting positional placeholders + * that are hard coded for the specific parameters. + *

+ * + *

These secondary placeholders can be inserted anywhere in the message. + *

+ * + *
    + *
  • {mine}
  • + *
  • {mine_tag}
  • + *
  • {mine_world}
  • + *
  • {mine_type}
  • + *
  • {mine_group}
  • + * + *
  • {mine_rank}
  • + *
  • {mine_air_count}
  • + *
  • {mine_player_count}
  • + * + *
  • {mine_block_break_count}
  • + *
  • {mine_block_remaining_count}
  • + *
  • {mine_block_remaining_percent}
  • + *
  • {mine_blocks_mined_total}
  • + *
  • {mine_reset_time_sec}
  • + *
  • {mine_reset_time_remaining_sec}
  • + * + *
  • {mine_block__name}
  • + *
  • {mine_block__type}
  • + *
  • {mine_block__placed}
  • + *
  • {mine_block__remaining}
  • + *
  • {mine_block__total}
  • + *
  • {mine_block__chance}
  • + + * + *
  • {mine} {mine_tag} {mine_world} {mine_type} {mine_group} + * {mine_rank} {mine_air_count} {mine_player_count} + * {mine_block_break_count} {mine_block_remaining_count} {mine_block_remaining_percent} + * {mine_blocks_mined_total} {mine_reset_time_sec} {mine_reset_time_remaining_sec} + * {mine_block_[block]_name} {mine_block_[block]_type} {mine_block_[block]_placed} + * {mine_block_[block]_remaining} {mine_block_[block]_total} {mine_block_[block]_chance} + *
  • + * + *
+ * + * @param rankPlayer + * @param results + * @return + */ + @Override + public String convertStringPlaceholders(String results) { + + Mine mine = this; + + if ( mine != null ) { + + results = applySecondaryPlaceholdersCheck( "{mine}", mine.getName(), results ); + results = applySecondaryPlaceholdersCheck( "{mine_tag}", mine.getTag(), results ); + results = applySecondaryPlaceholdersCheck( "{mine_world}", mine.getWorldName(), results ); + results = applySecondaryPlaceholdersCheck( "{mine_type}", mine.getMineType().name(), results ); + results = applySecondaryPlaceholdersCheck( "{mine_group}", mine.getMineGroup().getName(), results ); + + results = applySecondaryPlaceholdersCheck( "{mine_rank}", mine.getRankString(), results ); + + results = applySecondaryPlaceholdersCheck( "{mine_air_count}", + Integer.toString( mine.getAirCount()), results ); + results = applySecondaryPlaceholdersCheck( "{mine_player_count}", + Integer.toString( mine.getPlayerCount()), results ); + + results = applySecondaryPlaceholdersCheck( "{mine_block_break_count}", + Integer.toString( mine.getBlockBreakCount()), results ); + results = applySecondaryPlaceholdersCheck( "{mine_block_remaining_count}", + Integer.toString( mine.getRemainingBlockCount()), results ); + results = applySecondaryPlaceholdersCheck( "{mine_block_remaining_percent}", + Double.toString( (mine.getPercentRemainingBlockCount() * 100.0d )), results ); + results = applySecondaryPlaceholdersCheck( "{mine_blocks_mined_total}", + Long.toString( mine.getTotalBlocksMined()), results ); + + results = applySecondaryPlaceholdersCheck( "{mine_reset_time_sec}", + Integer.toString( mine.getResetTime()), results ); + results = applySecondaryPlaceholdersCheck( "{mine_reset_time_remaining_sec}", + Double.toString( mine.getRemainingTimeSec()), results ); + + + Set keys = mine.getBlockStats().keySet(); + for (String key : keys) { + PrisonBlockStatusData blockStat = mine.getBlockStats().get( key ); + + String bName = blockStat.getBlockName().toLowerCase(); + String type = blockStat.getBlockType().name(); + + long placed = blockStat.getBlockPlacedCount(); + long remaining = blockStat.getBlockPlacedCount() - blockStat.getBlockCountUnsaved(); + long total = blockStat.getBlockCountTotal(); + + Double chance = blockStat.getChance() * 100.0d; + + results = applySecondaryPlaceholdersCheck( "{mine_block_" + bName + "_name}", + bName, results ); + results = applySecondaryPlaceholdersCheck( "{mine_block_" + bName + "_type}", + type, results ); + + results = applySecondaryPlaceholdersCheck( "{mine_block_" + bName + "_placed}", + Long.toString( placed ), results ); + results = applySecondaryPlaceholdersCheck( "{mine_block_" + bName + "_remaining}", + Long.toString( remaining ), results ); + results = applySecondaryPlaceholdersCheck( "{mine_block_" + bName + "_total}", + Long.toString( total ), results ); + results = applySecondaryPlaceholdersCheck( "{mine_block_" + bName + "_chance}", + Double.toString( chance ), results ); + + } + + + + } + + return results; + } + + + /** + *

Ths function will perform individual replacements of the given placeholders, but + * if the placeholder does not exist, then it will not change anything with the results + * and it will be just passed through. + *

+ * + * @param placeholder + * @param value + * @param results + * @return + */ + private String applySecondaryPlaceholdersCheck( String placeholder, String value, String results) { + + if ( results.contains( placeholder ) && value != null ) { + results = results.replace( placeholder, value ); + } + + return results; + } + } 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 9fddfe96a..e8f3f9f2f 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 @@ -406,6 +406,10 @@ public Bounds getBounds() { return bounds; } + public void setBounds(Bounds bounds ) { + setBounds( bounds, true ); + } + /** *

(Re)defines the boundaries for this mine. *

@@ -427,7 +431,7 @@ public Bounds getBounds() { * * @param bounds the new boundaries */ - public void setBounds(Bounds bounds) { + public void setBounds(Bounds bounds, boolean logInfo ) { this.bounds = bounds; // if Bounds is null, then clear out the world fields and set mine to virtual and disable the mine: @@ -454,7 +458,10 @@ else if ( isVirtual() || !getWorld().isPresent() || setVirtual( false ); setEnabled( true ); - Output.get().logInfo( "&7Mine " + getTag() + "&7: world has been set and is now enabled." ); + if ( logInfo ) { + Output.get().logInfo( "&7Mine " + getTag() + "&7: world has been set and is now enabled." ); + } + } else { setEnabled( false ); @@ -784,6 +791,7 @@ public void resetResetBlockCounts() { block.setRangeBlockCountHigh( -1 ); block.setRangeBlockCountLowLimit( -1 ); block.setRangeBlockCountHighLimit( -1 ); +// block.setIncludeInLayerCalculations( true ); } for ( PrisonBlockStatusData block : getPrisonBlocks() ) { @@ -794,6 +802,7 @@ public void resetResetBlockCounts() { block.setRangeBlockCountHigh( -1 ); block.setRangeBlockCountLowLimit( -1 ); block.setRangeBlockCountHighLimit( -1 ); +// block.setIncludeInLayerCalculations( true ); } // for ( PrisonBlockStatusData blockStats : getBlockStats().values() ) { @@ -811,10 +820,15 @@ public void resetResetBlockCounts() { */ public PrisonBlockStatusData incrementResetBlockCount( PrisonBlockStatusData statsBlock ) { - PrisonBlockStatusData sBlock = getBlockStats( statsBlock ); - if ( sBlock != null ) { + PrisonBlockStatusData sBlock = null; + + if ( statsBlock != null ) { + sBlock = getBlockStats( statsBlock ); - sBlock.incrementResetBlockCount(); + if ( sBlock != null ) { + + sBlock.incrementResetBlockCount(); + } } return sBlock; @@ -1077,14 +1091,20 @@ public void setHasSpawn( boolean hasSpawn ) { this.hasSpawn = hasSpawn; } - /* + /** *

This is the reset time for the mine, in seconds. * A value of -1 means no timed resets. They will have to be done manually. *

- */ + **/ public int getResetTime() { return resetTime; } + /** + *

This is the reset time for the mine, in seconds. + * A value of -1 means no timed resets. They will have to be done manually. + *

+ * @param resetTime + */ public void setResetTime( int resetTime ) { this.resetTime = resetTime; } diff --git a/prison-mines/src/main/java/tech/mcprison/prison/mines/data/MineLevelBlockListData.java b/prison-mines/src/main/java/tech/mcprison/prison/mines/data/MineLevelBlockListData.java index ac7b6479c..6ffe17b7b 100644 --- a/prison-mines/src/main/java/tech/mcprison/prison/mines/data/MineLevelBlockListData.java +++ b/prison-mines/src/main/java/tech/mcprison/prison/mines/data/MineLevelBlockListData.java @@ -5,28 +5,38 @@ import java.util.Random; import tech.mcprison.prison.internal.block.PrisonBlock; +import tech.mcprison.prison.output.Output; public class MineLevelBlockListData { private int currentMineLevel; + private int maxMineLevel; + private Mine mine; private Random random; private List selectedBlocks; + private PrisonBlock fillerBlock; + private double totalChance = 0d; private double selectedChance = 0d; private double airChance = 0d; + + private boolean errorMessageSent = false; + - public MineLevelBlockListData( int currentMineLevel, Mine mine, Random random ) { + public MineLevelBlockListData( int currentMineLevel, int maxMineLevel, Mine mine, Random random ) { super(); this.currentMineLevel = currentMineLevel; + this.maxMineLevel = maxMineLevel; + this.mine = mine; this.random = random; @@ -38,6 +48,11 @@ public MineLevelBlockListData( int currentMineLevel, Mine mine, Random random ) private void initialize() { + totalChance = 0d; + selectedChance = 0d; + airChance = 0d; + + fillerBlock = null; // PrisonBlocks contains the percent chance of spawning: @@ -46,49 +61,68 @@ private void initialize() { // First calculate the total percent chance: totalChance += pBlock.getChance(); - // If the block has no constraints, or if the block is within the - // mine constraints, add it to our list: - if ( pBlock.getConstraintExcludeTopLayers() == 0 && - pBlock.getConstraintExcludeBottomLayers() == 0 || + int cExcludeTop = pBlock.getConstraintExcludeTopLayers(); + int cExcludeBottom = pBlock.getConstraintExcludeBottomLayers(); + + int cMin = pBlock.getConstraintMin(); + int cMax = pBlock.getConstraintMax(); + + boolean hasConstraints = cExcludeTop != 0 || cExcludeBottom != 0 || + cMin != 0 || cMax != 0; + + boolean includeOnThisLevel = + cExcludeTop == 0 && cExcludeBottom == 0 || - pBlock.getConstraintExcludeTopLayers() <= currentMineLevel && - (pBlock.getConstraintExcludeBottomLayers() == 0 || - pBlock.getConstraintExcludeBottomLayers() > currentMineLevel) ) { + (cExcludeTop == 0 || cExcludeTop != 0 && currentMineLevel > cExcludeTop) && + (cExcludeBottom == 0 || cExcludeBottom != 0 && currentMineLevel < cExcludeBottom ); + + + + // If the block has no constraints, or if the block is within the + // mine constraints of top and bottom, then add it to our list. + // If block has exceed max constraint, let it pass through this + // code so it can get the update on the rangeBlockCountHigh. + // Check to ensure that the max placement has not been exceeded and if + // it has, exclude from this level. Note that past levels may have + // placed more than max. + if ( includeOnThisLevel ) { - // Sum the selected blocks: - selectedChance += pBlock.getChance(); - // Add the selected blocks to our list: - selectedBlocks.add( pBlock ); + // If block has reached it's max, then do not add it's chance or add + // add it as a selected block: + if ( cMax == 0 || + cMax != 0 && pBlock.getBlockPlacedCount() < cMax) { + + // Sum the selected blocks: + selectedChance += pBlock.getChance(); + + // Add the selected blocks to our list: + selectedBlocks.add( pBlock ); + + // Need to find a filler block that has no constraints used: + if ( !hasConstraints && + (fillerBlock == null || + fillerBlock != null && pBlock.getChance() > fillerBlock.getChance() ) ) { + fillerBlock = pBlock; + } + + } - // If exclude top layers is enabled, then only try to set the - // rangeBlockCountLowLimit once since we need the lowest possible - // value. The initial value for getRangeBlockCountLowLimit is -1. - if ( pBlock.getRangeBlockCountLowLimit() <= 0 && - currentMineLevel > pBlock.getConstraintExcludeTopLayers() ) { + // Only set the rangeBlockCountLowLimit on the first pass through here. + // The initial value for getRangeBlockCountLowLimit is -1. + if ( pBlock.getRangeBlockCountLowLimit() == -1 ) { int targetBlockPosition = mine.getMineTargetPrisonBlocks().size(); pBlock.setRangeBlockCountLowLimit( targetBlockPosition ); } - // If exclude bottom layer is enabled, then we need to track every number - // until the currentLevel exceeds the getConstraintExcludeBottomLayers value. + // Always set getConstraintExcludeBottomLayers value: // If exclude top layers, then do not record for the bottom layers until // the top layers is cleared. - if ( (pBlock.getConstraintExcludeTopLayers() > 0 && - currentMineLevel > pBlock.getConstraintExcludeTopLayers() || - pBlock.getConstraintExcludeTopLayers() == 0) && - - pBlock.getConstraintExcludeBottomLayers() > 0 && - pBlock.getConstraintExcludeBottomLayers() < currentMineLevel - ) { - - int targetBlockPosition = mine.getMineTargetPrisonBlocks().size(); - pBlock.setRangeBlockCountHighLimit( targetBlockPosition ); - - } + int targetBlockPosition = mine.getMineTargetPrisonBlocks().size(); + pBlock.setRangeBlockCountHighLimit( targetBlockPosition ); } @@ -112,31 +146,64 @@ private void initialize() { /** - *

For each block, run this to ensure all selected blocks that have a specified - * exclusion from the lower levels of the mine, that the rangeBlockCountHighLimit is - * properly set. + *

For each block, need to update the rangeBlockCountHighLimit, even if the + * block has reached it's max constraint. This is not tracking what was the + * last block that was placed, but it's tracking what is the max range of + * the targetBlocks collection (`mine.getMineTargetPrisonBlocks()`) in which + * this block can be placed while honoring the constraints exclude from + * top and exclude from bottom. *

*/ public void checkSelectedBlockExcludeFromBottomLayers() { for ( PrisonBlock pBlock : selectedBlocks ) { - // If exclude bottom layer is enabled, then we need to track every number - // until the currentLevel exceeds the getConstraintExcludeBottomLayers value. - // If exclude top layers, then do not record for the bottom layers until - // the top layers is cleared. - if ( (pBlock.getConstraintExcludeTopLayers() > 0 && - currentMineLevel > pBlock.getConstraintExcludeTopLayers() || - pBlock.getConstraintExcludeTopLayers() == 0) && + int cExcludeTop = pBlock.getConstraintExcludeTopLayers(); + int cExcludeBottom = pBlock.getConstraintExcludeBottomLayers(); + +// int cMin = pBlock.getConstraintMin(); +// int cMax = pBlock.getConstraintMax(); + +// boolean hasConstraints = cExcludeTop != 0 || cExcludeBottom != 0 || +// cMin != 0 || cMax != 0; + + boolean includeOnThisLevel = + cExcludeTop == 0 && cExcludeBottom == 0 || - pBlock.getConstraintExcludeBottomLayers() > 0 && - pBlock.getConstraintExcludeBottomLayers() < currentMineLevel - ) { + (cExcludeTop == 0 || cExcludeTop != 0 && currentMineLevel > cExcludeTop) && + (cExcludeBottom == 0 || cExcludeBottom != 0 && currentMineLevel < cExcludeBottom ); + + + + // If the block has no constraints, or if the block is within the + // mine constraints of top and bottom, then add it to our list. + // If block has exceed max constraint, let it pass through this + // code so it can get the update on the rangeBlockCountHigh. + // Check to ensure that the max placement has not been exceeded and if + // it has, exclude from this level. Note that past levels may have + // placed more than max. + if ( includeOnThisLevel ) { int targetBlockPosition = mine.getMineTargetPrisonBlocks().size(); pBlock.setRangeBlockCountHighLimit( targetBlockPosition ); - + } + +// // If exclude bottom layer is enabled, then we need to track every number +// // until the currentLevel exceeds the getConstraintExcludeBottomLayers value. +// // If exclude top layers, then do not record for the bottom layers until +// // the top layers is cleared. +// if ( (pBlock.getConstraintExcludeTopLayers() > 0 && +// currentMineLevel > pBlock.getConstraintExcludeTopLayers() || +// pBlock.getConstraintExcludeTopLayers() == 0) && +// +// (pBlock.getConstraintExcludeBottomLayers() == 0 || +// pBlock.getConstraintExcludeBottomLayers() > 0 && +// pBlock.getConstraintExcludeBottomLayers() < currentMineLevel) +// ) { +// +// +// } } } @@ -152,6 +219,13 @@ public PrisonBlock randomlySelectPrisonBlock() for ( PrisonBlock block : selectedBlocks ) { + // NOTE: do not have use this field anymore: +// block.isIncludeInLayerCalculations(); + + // If chance falls on this block, then select it as long as it has not + // exceed the max count for this block if the max constraint is enabled. + // If the block's constraint max is reached, then isIncludedInLayerCalculation will + // prevent more of them from being added to the mine. if ( chance <= block.getChance() ) { // If this block is chosen and it was not skipped, then use this block and exit. @@ -160,13 +234,124 @@ public PrisonBlock randomlySelectPrisonBlock() selected = block; break; - } else { + } + else { chance -= block.getChance(); } } + // If block reaches it's max amount, remove it from the block list so it will not + // be selected again. If max is reached, then this block is the max number allowed. + // Note that the block has not been incremented yet, so add one to the placement count + if ( selected != null && + selected.getConstraintMax() > 0 && + (selected.getBlockPlacedCount() + 1) >= selected.getConstraintMax() ) { + +// selected.setIncludeInLayerCalculations( false ); + + selectedBlocks.remove(selected); + + selectedChance -= selected.getChance(); + } + + // if selected == null, then the block feel through the cracks because + // if the mine did not have a full 100% chance of all blocks combined, + // then an AIR block was added to the selectedBlocks collection when + // starting to process this level. So if selected is null, then something + // went wrong... assign it the filler block. + // If all blocks have constraints, the the filler block will be null so + // then assign it an AIR block. + if ( chance == 0d && selected == null ) { + if ( fillerBlock != null ) { + selected = fillerBlock; + } + else { + selected = PrisonBlock.AIR.clone(); + + if ( !errorMessageSent ) { + + String msg = String.format( + "Error: generateBlockListAsync() selectBlock: " + + "Mine: %s Layer: %d : All blocks " + + "have constraints so could not backfill a void with a block " + + "so using AIR. Add a non-constrained block to the mine to " + + "prevent air blocks from spawning in this mine when a valid " + + "block cannot be choosen. This is not a bug, but it's an " + + "issue with base-2 being coverted to base-10 and the " + + "resulting random " + + "generated number not falling on any valid blocks. ", + getMine().getName(), getCurrentMineLevel() + ); + Output.get().logError( msg ); + errorMessageSent = true; + } + } + } + return selected; } - + + public int getCurrentMineLevel() { + return currentMineLevel; + } + public void setCurrentMineLevel(int currentMineLevel) { + this.currentMineLevel = currentMineLevel; + } + + public int getMaxMineLevel() { + return maxMineLevel; + } + public void setMaxMineLevel(int maxMineLevel) { + this.maxMineLevel = maxMineLevel; + } + + public Mine getMine() { + return mine; + } + public void setMine(Mine mine) { + this.mine = mine; + } + + public Random getRandom() { + return random; + } + public void setRandom(Random random) { + this.random = random; + } + + public List getSelectedBlocks() { + return selectedBlocks; + } + public void setSelectedBlocks(List selectedBlocks) { + this.selectedBlocks = selectedBlocks; + } + + public PrisonBlock getFillerBlock() { + return fillerBlock; + } + public void setFillerBlock(PrisonBlock fillerBlock) { + this.fillerBlock = fillerBlock; + } + + public double getTotalChance() { + return totalChance; + } + public void setTotalChance(double totalChance) { + this.totalChance = totalChance; + } + + public double getSelectedChance() { + return selectedChance; + } + public void setSelectedChance(double selectedChance) { + this.selectedChance = selectedChance; + } + + public double getAirChance() { + return airChance; + } + public void setAirChance(double airChance) { + this.airChance = airChance; + } } 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 d397bfdc6..e7dda5f87 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 @@ -6,6 +6,7 @@ import java.util.Optional; import java.util.Random; import java.util.TreeMap; +import java.util.TreeSet; import tech.mcprison.prison.Prison; import tech.mcprison.prison.internal.Player; @@ -28,6 +29,7 @@ import tech.mcprison.prison.mines.tasks.MinePagedResetAsyncTask; import tech.mcprison.prison.mines.tasks.MineTeleportTask; import tech.mcprison.prison.output.Output; +import tech.mcprison.prison.output.Output.DebugTarget; import tech.mcprison.prison.tasks.PrisonCommandTaskData; import tech.mcprison.prison.tasks.PrisonCommandTasks; import tech.mcprison.prison.tasks.PrisonRunnable; @@ -475,7 +477,9 @@ public void saveIfUnsavedBlockCounts() { protected abstract void broadcastPendingResetMessageToAllPlayersWithRadius(MineJob mineJob); - + protected abstract void broadcastSkipResetMessageToAllPlayersWithRadius(); + + public int getPlayerCount() { int count = 0; @@ -560,7 +564,6 @@ public void generateBlockListAsync() { World world = worldOptional.get(); int airCount = 0; - int currentLevel = 0; int yMin = getBounds().getyBlockMin(); @@ -571,6 +574,10 @@ public void generateBlockListAsync() { int zMin = getBounds().getzBlockMin(); int zMax = getBounds().getzBlockMax(); + + + int currentLevel = 0; + int maxLevels = yMax - yMin + 1; // The reset takes place first with the top-most layer since most mines may have @@ -580,7 +587,8 @@ public void generateBlockListAsync() { // This is used to select the correct block list for the given mine level: - MineLevelBlockListData mineLevelBlockList = new MineLevelBlockListData( currentLevel, (Mine) this, random ); + MineLevelBlockListData mineLevelBlockList = + new MineLevelBlockListData( currentLevel, maxLevels, (Mine) this, random ); for (int x = xMin; x <= xMax; x++) { @@ -598,9 +606,9 @@ public void generateBlockListAsync() { boolean isCorner = xEdge && yEdge && zEdge; - Location targetBlock = new Location(world, x, y, z); - targetBlock.setEdge( isEdge ); - targetBlock.setCorner( isCorner ); + Location targetLocation = new Location(world, x, y, z); + targetLocation.setEdge( isEdge ); + targetLocation.setCorner( isCorner ); // MineTargetBlock mtb = null; @@ -609,12 +617,17 @@ public void generateBlockListAsync() { PrisonBlock prisonBlock = mineLevelBlockList.randomlySelectPrisonBlock(); + if ( prisonBlock == null ) { + prisonBlock = PrisonBlock.AIR.clone(); + } + // PrisonBlock prisonBlock = randomlySelectPrisonBlock( random, currentLevel ); // Increment the mine's block count. This block is one of the control blocks: incrementResetBlockCount( prisonBlock ); - addMineTargetPrisonBlock( prisonBlock, targetBlock ); + // TODO AIR block fix - allow AIR to be part of the regular block list? + addMineTargetPrisonBlock( prisonBlock, targetLocation ); // mtb = new MineTargetPrisonBlock( prisonBlock, x, y, z); if ( prisonBlock.equals( PrisonBlock.AIR ) ) { @@ -636,6 +649,37 @@ public void generateBlockListAsync() { constraintsApplyMin(); + if ( Output.get().isDebug() && Output.get().isSelectiveTarget( DebugTarget.blockConstraints ) ) { + + DecimalFormat dFmt = Prison.get().getDecimalFormatDouble(); + //DecimalFormat iFmt = Prison.get().getDecimalFormatInt(); + + for ( PrisonBlockStatusData b : getPrisonBlocks() ) { + + int rangeLow = b.getRangeBlockCountLowLimit(); + int rangeHigh = b.getRangeBlockCountHighLimit(); + int rangeCount = b.getRangeBlockCountHighLimit() - b.getRangeBlockCountLowLimit() + 1; + double rangePercent = rangeCount / (double) getBounds().getTotalBlockCount(); + + String msg = String.format( + " Block: %-14s : placed: %-5d PlacementRange: (%d - %d) " + + "%d out of %d %s " + + "min: %d max: %d ExcldTop: %d ExcldBottom: %d ", + b.getBlockName(), b.getBlockPlacedCount(), + rangeLow, rangeHigh, + rangeCount, + getBounds().getTotalBlockCount(), + dFmt.format( rangePercent ), + + b.getConstraintMin(), b.getConstraintMax(), + b.getConstraintExcludeTopLayers(), + b.getConstraintExcludeBottomLayers() + ); + + Output.get().logInfo( msg ); + } + } + // The reset position is critical in ensuring that all blocks within the mine are reset // and that when a reset process pages (allows another process to run) then it will be // used to pick up where it left off. @@ -853,6 +897,313 @@ public void generateBlockListAsync() { // // } + + + public List getTargetBlockStatsPerLevel() { + List layers = new ArrayList<>(); + + + // Scan all blocks to see if they are the same or now air + // Use isCheckAir() and isCheckSamme(); + scanAllBlocksForUpdates(); + + +// int blocksPerLayer = getBounds().getBlockCountPerLayer(); + //int totalLayers = getBounds().getTotalLayers(); + + // BlockName = BlockLetter +// TreeMap translator = new TreeMap<>(); +// TreeMap map = new TreeMap<>(); +// TreeMap mapMine = new TreeMap<>(); + + // Add AIR to make sure it is there: + PrisonBlock air = PrisonBlock.AIR.clone(); + boolean hasAir = getPrisonBlock( air.getBlockName() ) != null; + + if ( !hasAir ) { + getPrisonBlocks().add( air ); + getBlockStats( air ); + } + + int j = 0; + TreeSet keys = new TreeSet<>( getBlockStats().keySet() ); + for (String key : keys) { + PrisonBlockStatusData blk = getBlockStats().get( key ); + + blk.setAltValues( j++ ); + } + + + +// String codesStr = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789@#&*"; +// List codes = Arrays.asList( codesStr.split("|")); +// String colors = "12345789abcde"; + + + // Always add the air block: +// translator.put( PrisonBlock.AIR.getBlockName(), "" ); + + + +// // Build translations: +// char blk = 'A'; +//// double chance = 0; +//// boolean hasAir = false; +// +// // First add all the blocks with an empty String as the value: +// for (PrisonBlock b : getPrisonBlocks() ) { +//// chance += b.getChance(); +// translator.put( b.getBlockName(), "" ); +//// if ( b.isAir() ) { +//// hasAir = true; +//// } +// } +//// if ( !hasAir && chance < 100.0d ) { +//// translator.put( PrisonBlock.AIR.getBlockName(), "" ); +//// } +// +// // Now that they are in order, assign the alphabetical names: +// Set tkeys = translator.keySet(); +// for (String tKey : tkeys) { +// translator.put( tKey, Character.toString( blk ) ); +// +// if ( blk == 'Z' ) { +// blk = 'a'; +// } +// else if ( blk == 'z' ) { +// blk = '1'; +// } +// else { +// blk++; +// } +// } + +// String airName = PrisonBlock.AIR.getBlockName(); +// String keyAir = translator.get(airName); +// +// map.put( keyAir, 0 ); +// mapMine.put( keyAir, 0 ); + + int layer = 0; + int blockCount = 0; + + for ( int i = 0; i < getMineTargetPrisonBlocks().size(); i++ ) { + + MineTargetPrisonBlock tBlock = getMineTargetPrisonBlocks().get(i); + int y = getMineTargetPrisonBlocks().get(i).getLocation().getBlockY(); + blockCount++; + + + { + PrisonBlockStatusData statsBlock = null; + + // the getPrisonblock() should not return a null value: + PrisonBlockStatusData sBlock = tBlock.getPrisonBlock(); + + if ( sBlock == null ) { + sBlock = PrisonBlock.AIR.clone(); + } + + String blockName = sBlock.getBlockName(); + statsBlock = getBlockStats().get( blockName ); + + if ( statsBlock == null ) { + statsBlock = getBlockStats().get( air ); + } + + + statsBlock.setAltCountVirtual( statsBlock.getAltCountVirtual() + 1); + if ( tBlock.isCheckSame() ) { + statsBlock.setAltCountPhysical( statsBlock.getAltCountPhysical() + 1); + } + else if ( tBlock.isCheckAir() ) { + + PrisonBlockStatusData airStats = getBlockStats( air ); + airStats.setAltCountPhysical( airStats.getAltCountPhysical() + 1); + + } + + } + + +// int level = (int) ((i / (double) blocksPerLayer) + 1); + +// getBlockStats(keyAir); +// tBlock.getPrisonBlock(); +// +// String keyPrime = tBlock == null || tBlock.getPrisonBlock() == null ? +// airName : +// tBlock.getPrisonBlock().getBlockName(); +// +// String key = translator.get(keyPrime); +// +// if ( !map.containsKey(key) ) { +// map.put( key, 1 ); +// } +// else { +// map.put( key, 1 + map.get(key) ); +// } +// +// if ( !mapMine.containsKey(key) ) { +// mapMine.put( key, 0 ); +// } +//// if ( !mapMine.containsKey(keyAir) ) { +//// mapMine.put( keyAir, 0 ); +//// } +// +// if ( tBlock.isCheckSame() ) { +// mapMine.put( key, 1 + mapMine.get(key) ); +// } +// else if ( tBlock.isCheckAir() ) { +// mapMine.put( keyAir, 1 + mapMine.get(keyAir) ); +// +// } + + + if ( (i + 1) >= getMineTargetPrisonBlocks().size() || + getMineTargetPrisonBlocks().get(i + 1).getLocation().getBlockY() != y ) { + + StringBuilder sb = new StringBuilder(); + + sb.append( "Layer " ).append( layer++ ) + .append( " (" ).append( blockCount ).append(")") + .append( " : " ); + +// TreeSet keys = new TreeSet<>( map.keySet() ); + for ( String k : keys ) { + + PrisonBlockStatusData statsBlock = getBlockStats( k ); + + sb.append( statsBlock.getAltColorCode() ) + .append( statsBlock.getAltAlias() ) + .append( Output.get().getColorCodeInfo() ) + .append( ":" ) + .append( statsBlock.getAltCountVirtual() ); + + if ( statsBlock.getAltCountVirtual() != statsBlock.getAltCountPhysical() ) { + sb.append( ":" ) + .append( statsBlock.getAltCountPhysical() ); + } + + sb.append( " " ); + + statsBlock.resetAltValues(); + +// for ( Entry eSet : translator.entrySet()) { +// if ( eSet.getValue().equalsIgnoreCase(k) ) { +// +// String blockName = eSet.getKey(); +// sb.append( blockName ).append( ":" ).append( map.get(k) ).append( " " ); +// +// break; +// } +// } + +// int c = k.charAt(0) % colors.length(); +// +// String color = "&" + String.valueOf(colors.charAt(c)); +// +// int count = map.get(k); +// int countMine = mapMine.get(k); +// +// sb +// .append( color ).append( k ).append( Output.get().getColorCodeDebug() ) +// .append( ":" ).append( count ); +// +// if ( count != countMine ) { +// sb +// .append( ":" ).append( countMine ); +// } +// +// sb.append( " " ); + } + + layers.add( sb.toString() ); + + blockCount = 0; + + +// map.clear(); +// mapMine.clear(); +// +// map.put( keyAir, 0 ); +// mapMine.put( keyAir, 0 ); + } + +// // if last block of the layer: +// if ( (int) (((i + 1) / (double) blocksPerLayer) + 1) > level ) { +// StringBuilder sb = new StringBuilder(); +// +// sb.append( "Layer " ).append( layer++ ).append( " : " ); +// +// TreeSet keys = new TreeSet<>( map.keySet() ); +// for ( String k : keys ) { +//// for ( Entry eSet : translator.entrySet()) { +//// if ( eSet.getValue().equalsIgnoreCase(k) ) { +//// +//// String blockName = eSet.getKey(); +//// sb.append( blockName ).append( ":" ).append( map.get(k) ).append( " " ); +//// +//// break; +//// } +//// } +// sb.append( k ).append( ":" ).append( map.get(k) ).append( " " ); +// } +// +// layers.add( sb.toString() ); +// +// map.clear(); +// } + } + + + { + // print the legend: + StringBuilder sb = new StringBuilder(); + + sb.append( "Legend: " ); + + for ( String k : keys ) { + + PrisonBlockStatusData statsBlock = getBlockStats( k ); + + sb.append( statsBlock.getAltColorCode() ) + .append( statsBlock.getAltAlias() ) + .append( Output.get().getColorCodeInfo() ) + .append( "=" ) + .append( statsBlock.getBlockName() ) + .append( " " ); + + + } + +// for ( Entry eSet : translator.entrySet()) { +// String blockName = eSet.getKey(); +// +// String value = eSet.getValue(); +// +// int c = value.charAt(0) % colors.length(); +// String color = "&" + String.valueOf(colors.charAt(c)); +// +// sb +// .append( color ).append( eSet.getValue() ).append( Output.get().getColorCodeDebug() ) +// .append( ":" ).append( blockName ).append( " " ); +// } + + layers.add( sb.toString() ); + + } + + if ( !hasAir ) { + removePrisonBlock( air ); + getBlockStats().remove( air.getBlockName() ); + } + + + return layers; + } + + public void asynchronouslyResetSetup() { // Reset the block break count before resetting the blocks: @@ -912,6 +1263,12 @@ public void asynchronouslyResetFinalize( List jobResetActions incrementResetCount(); + try { + ((MineScheduler) this).setMineResetStartTimestamp( -1 ); + } catch (Exception e) { + // ignore... + } + if ( !getCurrentJob().getResetActions().contains( MineResetActions.NO_COMMANDS )) { // After reset commands: @@ -1274,11 +1631,11 @@ public List refreshAirCountSyncTaskBuildLocations() { boolean isCorner = xEdge && yEdge && zEdge; - Location targetBlock = new Location(world, x, y, z); - targetBlock.setEdge( isEdge ); - targetBlock.setCorner( isCorner ); + Location targetLocation = new Location(world, x, y, z); + targetLocation.setEdge( isEdge ); + targetLocation.setCorner( isCorner ); - locations.add( targetBlock ); + locations.add( targetLocation ); @@ -1351,7 +1708,7 @@ public List refreshAirCountSyncTaskBuildLocations() { } - public void refreshAirCountSyncTaskSetLocation( Location targetBlock, + public void refreshAirCountSyncTaskSetLocation( Location targetLocation, OnStartupRefreshBlockBreakCountSyncTask stats ) { try { @@ -1361,20 +1718,23 @@ public void refreshAirCountSyncTaskSetLocation( Location targetBlock, getPrisonBlockTypes().contains( PrisonBlockType.CustomItems ) || getPrisonBlockTypes().contains( PrisonBlockType.ItemsAdder ); - Block tBlock = targetBlock.getBlockAt( containsCustomBlocks ); + Block tBlock = targetLocation.getBlockAt( containsCustomBlocks ); PrisonBlock pBlock = tBlock.getPrisonBlock(); - if ( pBlock != null ) { - - // Increment the mine's block count. This block is one of the control blocks: - addMineTargetPrisonBlock( incrementResetBlockCount( pBlock ), targetBlock ); - + if ( pBlock == null ) { + // TODO AIR block fix - allow AIR to be part of the regular block list? + pBlock = PrisonBlock.AIR.clone(); } - if ( pBlock == null || pBlock.isAir() ) { + + // Increment the mine's block count. This block is one of the control blocks: + addMineTargetPrisonBlock( incrementResetBlockCount( pBlock ), targetLocation ); + + + if ( pBlock.isAir() ) { stats.incrementAirCount(); } } @@ -1388,7 +1748,7 @@ public void refreshAirCountSyncTaskSetLocation( Location targetBlock, // If there are no entities, it will be fine, but they could cause issues with async // access of unloaded chunks. String coords = String.format( "%d.%d.%d ", - targetBlock.getBlockX(), targetBlock.getBlockY(), targetBlock.getBlockZ() ); + targetLocation.getBlockX(), targetLocation.getBlockY(), targetLocation.getBlockZ() ); if ( stats.getErrorCount() == 0 ) { String message = String.format( @@ -1409,6 +1769,93 @@ else if ( stats.getErrorCount() <= 10 ) { } + + private void scanAllBlocksForUpdates() { + + World world = getBounds().getCenter().getWorld(); + if ( world != null ) { + + long start = System.currentTimeMillis(); + + int i = 0; + for ( MineTargetPrisonBlock targetBlock : getMineTargetPrisonBlocks() ) { + + if ( targetBlock != null ) { + + i++; + +; targetBlock.setCheckAir( false ); + targetBlock.setCheckSame( false ); + + try { +// Location targetBlock = new Location(world, x, y, z); + + boolean containsCustomBlocks = + getPrisonBlockTypes().contains( PrisonBlockType.CustomItems ) || + getPrisonBlockTypes().contains( PrisonBlockType.ItemsAdder ); + + Block tBlock = targetBlock.getLocation().getBlockAt( containsCustomBlocks ); + PrisonBlock pBlock = tBlock == null ? null : tBlock.getPrisonBlock(); + + PrisonBlockStatusData tpBlock = targetBlock.getPrisonBlock(); + + if ( tBlock == null || pBlock == null || tpBlock == null ) { + targetBlock.setCheckAir( true ); + } + else { + + + String targetBlockName = tpBlock.getBlockName(); + + + if ( pBlock.getBlockName().equalsIgnoreCase( targetBlockName) ) { + targetBlock.setCheckSame( true ); + } + else if ( pBlock.isAir() ) { + targetBlock.setCheckAir( true ); + } + else if ( pBlock.getBlockName().equalsIgnoreCase( targetBlockName) ) { + targetBlock.setCheckSame( true ); + } + else { + targetBlock.setCheckSame( false ); + + } + + } + + + + } + catch ( Exception e ) { + + Output.get().logInfo( "MineReset.scanAllBlocksForUpdates: error:" + + " count=%d %s", (i - 1), e.getMessage()); + + } + } + + } + + if ( Output.get().isDebug() ) { + + long stop = System.currentTimeMillis(); + long elapsed = stop - start; + + double ms = elapsed / 1_000_000_000d; + String msStr = Prison.getDecimalFormatStaticDouble().format(ms); + + Output.get().logInfo( + String.format( + "MineReset.scanAllBlocksForUpdates runtime%s=", + msStr + ) + ); + + } + } + } + /** *

This function should ONLY be used if an enchantment plugin is being used that cannot * provide a working explosion event to monitor, and the plugin is breaking more blocks than what @@ -1566,6 +2013,9 @@ else if ( getPercentRemainingBlockCount() > getSkipResetPercent() ) { if ( getSkipResetBypassCount() < getSkipResetBypassLimit() ) { // Skip Reset!! + + broadcastSkipResetMessageToAllPlayersWithRadius(); + return; } @@ -1736,26 +2186,31 @@ private void constraintsApplyMin() { */ private void constraintsApplyMin( PrisonBlockStatusData block ) { - if ( block.getConstraintMin() > 0 ) { + + if ( block.getConstraintMin() > 0 && block.getBlockPlacedCount() < block.getConstraintMin() ) { + + int maxAttempts = (block.getConstraintMin() - block.getBlockPlacedCount()) + 3; - int maxAttempts = (block.getConstraintMin() - block.getBlockPlacedCount()) * 3; for ( int i = 0; i < maxAttempts && block.getBlockPlacedCount() < block.getConstraintMin(); i++ ) { // int maxSize = getMineTargetPrisonBlocks().size(); - int rangeLow = block.getRangeBlockCountLowLimit(); - int rangeHigh = block.getRangeBlockCountHighLimit(); -// int rangeLow = block.getRangeBlockCountLow(); -// int rangeHigh = block.getRangeBlockCountHigh(); + // Get an unmatched block in the block's range (not the same block): + int blockPos = block.getRandomBlockPositionInRangeUnmatched( getMineTargetPrisonBlocks() ); + + +// int rangeLow = block.getRangeBlockCountLowLimit(); +// int rangeHigh = block.getRangeBlockCountHighLimit(); + // Each block has a valid range in which it can spawn in the mine. This range // is honored by using the rangeHigh and rangeLow values. - int rndPos = ((int) Math.round( Math.random() * (rangeHigh - rangeLow) )) + rangeLow; +// int rndPos = ((int) Math.round( Math.random() * (rangeHigh - rangeLow) )) + rangeLow; - if ( rndPos < getMineTargetPrisonBlocks().size() ) { + if ( blockPos > -1 && blockPos < getMineTargetPrisonBlocks().size() ) { - MineTargetPrisonBlock targetBlock = getMineTargetPrisonBlocks().get( rndPos ); + MineTargetPrisonBlock targetBlock = getMineTargetPrisonBlocks().get( blockPos ); if ( targetBlock != null && targetBlock.getPrisonBlock().getConstraintMin() == 0 && @@ -1888,11 +2343,9 @@ public void setCurrentJob( MineJob currentJob ) - private void addMineTargetPrisonBlock( PrisonBlockStatusData block, Location targetBlock ) { + private void addMineTargetPrisonBlock( PrisonBlockStatusData block, Location targetLocation ) { - MineTargetPrisonBlock mtpb = new MineTargetPrisonBlock( block, getWorld().get(), - targetBlock.getBlockX(), targetBlock.getBlockY(), targetBlock.getBlockZ(), - targetBlock.isEdge(), targetBlock.isCorner() ); + MineTargetPrisonBlock mtpb = new MineTargetPrisonBlock( block, targetLocation ); synchronized ( getMineStateMutex() ) { 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 cf68899db..82bbc534e 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 @@ -49,12 +49,16 @@ public abstract class MineScheduler // private MineJob currentJob; private Integer taskId = null; + private transient long mineResetStartTimestamp; + + public MineScheduler() { super(); this.jobWorkflow = new ArrayList<>(); this.jobStack = new Stack<>(); + this.mineResetStartTimestamp = -1; } /** @@ -394,8 +398,10 @@ public void run() resetTask.submitTaskAsync(); // resetAsynchonously(); - } else { + } + else { incrementSkipResetBypassCount(); + broadcastSkipResetMessageToAllPlayersWithRadius(); } break; @@ -490,7 +496,8 @@ private void submitTask() { // Submit currentJob using delay in the job. Must be a one time run, no repeats. int taskId = PrisonTaskSubmitter.runTaskLater(this, ticksToWait); setTaskId( taskId ); - } else { + } + else { Output.get().logError("Mine " + getName() + " failed to resubmit itself so it will not auto reset. Manually reset " + "this mine to re-enable the auto reset."); @@ -746,11 +753,14 @@ public boolean checkZeroBlockReset() { if ( !isVirtual() && getMineStateMutex().isMinable() ) { + int totalBlocks = getBounds().getTotalBlockCount(); + int remaining = getRemainingBlockCount(); + double threshold = getResetThresholdPercent() == 0 ? 0 : + totalBlocks * getResetThresholdPercent() / 100.0d; + if ( - getRemainingBlockCount() <= 0 && !isZeroBlockResetDisabled() || - getResetThresholdPercent() > 0 && - getRemainingBlockCount() < (getBounds().getTotalBlockCount() * - getResetThresholdPercent() / 100.0d) + remaining <= 0 && !isZeroBlockResetDisabled() || + remaining <= threshold ) { // submit a manual reset since the mine is empty: @@ -803,11 +813,26 @@ public void manualReset( MineResetScheduleType resetType, List private void manualReset( MineResetScheduleType resetType, double delayActionSec, List resetActions ) { - if ( isVirtual() || !getMineStateMutex().isMinable() ) { - // Nope... nothing to reset... or it's locked out already with a reset + if ( isVirtual() ) { + // Nope... nothing to reset... return; } + if ( !getMineStateMutex().isMinable() && + getMineResetStartTimestamp() != -1 && + System.currentTimeMillis() - getMineResetStartTimestamp() > 3 * 60000 ) { + + // Mine reset was trying to run for more than 3 minutes... so it's locked out and failed? + + // reset mutex and allow the rest to be forced: + getMineStateMutex().setMineStateResetFinishedForced(); + + setMineResetStartTimestamp( -1 ); + + } + + + synchronized ( getMineStateMutex() ) { // The synchronized block will halt threads and will wait. @@ -823,6 +848,8 @@ private void manualReset( MineResetScheduleType resetType, double delayActionSec getMineStateMutex().setMineStateResetStart(); + + setMineResetStartTimestamp( System.currentTimeMillis() ); // // Lock the mine's mutex if it's still minable. Otherwise skip it since the @@ -849,29 +876,31 @@ private void manualReset( MineResetScheduleType resetType, double delayActionSec // } // // } + + + + // cancel existing job: + if ( getTaskId() != null ) { + PrisonTaskSubmitter.cancelTask( getTaskId() ); + } + + // Clear jobStack and set currentJob to run the RESET with zero delay: + getJobStack().clear(); + + MineJobAction action = MineJobAction.RESET_ASYNC; // : MineJobAction.RESET_SYNC; + + MineJob mineJob = new MineJob( action, delayActionSec, 0, resetType ); + mineJob.setResetType( resetType ); + mineJob.setResetActions( resetActions ); + + setCurrentJob( mineJob ); + + // Force reset even if skip is enabled: + + // Submit to run: + submitTask(); } - - // cancel existing job: - if ( getTaskId() != null ) { - PrisonTaskSubmitter.cancelTask( getTaskId() ); - } - - // Clear jobStack and set currentJob to run the RESET with zero delay: - getJobStack().clear(); - - MineJobAction action = MineJobAction.RESET_ASYNC; // : MineJobAction.RESET_SYNC; - - MineJob mineJob = new MineJob( action, delayActionSec, 0, resetType ); - mineJob.setResetType( resetType ); - mineJob.setResetActions( resetActions ); - - setCurrentJob( mineJob ); - - // Force reset even if skip is enabled: - - // Submit to run: - submitTask(); } public List getJobWorkflow() @@ -901,4 +930,11 @@ public void setTaskId( Integer taskId ) this.taskId = taskId; } + public long getMineResetStartTimestamp() { + return mineResetStartTimestamp; + } + public void setMineResetStartTimestamp(long mineResetStartTimestamp) { + this.mineResetStartTimestamp = mineResetStartTimestamp; + } + } diff --git a/prison-mines/src/main/java/tech/mcprison/prison/mines/data/MineTasks.java b/prison-mines/src/main/java/tech/mcprison/prison/mines/data/MineTasks.java index ce8b92aca..7e64551c7 100644 --- a/prison-mines/src/main/java/tech/mcprison/prison/mines/data/MineTasks.java +++ b/prison-mines/src/main/java/tech/mcprison/prison/mines/data/MineTasks.java @@ -299,6 +299,57 @@ protected void broadcastResetMessageToAllPlayersWithRadius() { // setStatsMessageBroadcastTimeMS( stop - start ); } + + @Override + protected void broadcastSkipResetMessageToAllPlayersWithRadius() { +// long start = System.currentTimeMillis(); + + if ( isVirtual() || getResetTime() <= 0 ) { + // ignore: + } + else if ( PrisonMines.getInstance().getMinesMessages() + .getLocalizable("skip_reset_message").localize().trim().length() == 0 ) { + + // NOTE: The mine_skip_reset_message is blank, so do not broadcast it... + } + else + if ( getNotificationMode() != MineNotificationMode.disabled ) { + World world = getBounds().getCenter().getWorld(); + + if ( world != null ) { + List players = (world.getPlayers() != null ? world.getPlayers() : + Prison.get().getPlatform().getOnlinePlayers()); + for (Player player : players) { + + // Check for either mode: Within the mine, or by radius from mines center: + if ( getNotificationMode() == MineNotificationMode.within && + getBounds().withinIncludeTopBottomOfMine(player.getLocation() ) || + getNotificationMode() == MineNotificationMode.radius && + getBounds().within(player.getLocation(), getNotificationRadius()) ) { + + if ( !isUseNotificationPermission() || + isUseNotificationPermission() && + player.hasPermission( getMineNotificationPermissionName() ) ) { + + + PrisonMines.getInstance().getMinesMessages() + .getLocalizable("skip_reset_message").withReplacements( getTag() ) + .sendTo(player); + +// player.sendMessage( "The mine " + getName() + " has just reset." ); + } + } + } + + } + + } + +// long stop = System.currentTimeMillis(); + +// setStatsMessageBroadcastTimeMS( stop - start ); + } + @Override protected void broadcastPendingResetMessageToAllPlayersWithRadius(MineJob mineJob) { 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 7c866ab23..d2a7f2964 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 @@ -69,9 +69,9 @@ public void run() { int start = position; for (int i = start; i < locations.size(); i++ ) { - Location targetBlock = locations.get( i ); + Location targetLocation = locations.get( i ); - mine.refreshAirCountSyncTaskSetLocation( targetBlock, this ); + mine.refreshAirCountSyncTaskSetLocation( targetLocation, this ); position++; if ( (i - start) % 500 == 0 ) { diff --git a/prison-mines/src/main/java/tech/mcprison/prison/mines/features/MineLinerBuilder.java b/prison-mines/src/main/java/tech/mcprison/prison/mines/features/MineLinerBuilder.java index 250e24613..2e6430a58 100644 --- a/prison-mines/src/main/java/tech/mcprison/prison/mines/features/MineLinerBuilder.java +++ b/prison-mines/src/main/java/tech/mcprison/prison/mines/features/MineLinerBuilder.java @@ -175,7 +175,8 @@ protected MineLinerBuilder() { } - public MineLinerBuilder( Mine mine, Edges edge, LinerPatterns pattern, boolean isForced ) { + public MineLinerBuilder( Mine mine, Edges edge, LinerPatterns pattern, + boolean isForced, boolean useTracer ) { super(); this.pattern3d = new ArrayList<>(); @@ -193,12 +194,20 @@ public MineLinerBuilder( Mine mine, Edges edge, LinerPatterns pattern, boolean i this.isForced = isForced; if ( pattern != null ) { - mine.enableTracer( MineResetType.clear ); + if ( useTracer ) { + + mine.enableTracer( MineResetType.clear ); + } generatePattern( edge ); } } + public MineLinerBuilder( Mine mine, Edges edge, LinerPatterns pattern, boolean isForced ) { + this( mine, edge, pattern, isForced, true ); + + } + private void generatePattern( Edges edge ) { World world = getLiner().getMin().getWorld(); 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 f53f77ae6..2a1513338 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 @@ -303,7 +303,12 @@ public boolean add(Mine mine) { */ private boolean add(Mine mine, boolean save, int offsetTimingMs ) { boolean results = false; - if (!getMines().contains(mine)){ + + // not add if it already exists, or if the mine is null or does not have a valid name: + if ( mine != null && mine.getName() != null && + mine.getName().trim().length() > 0 && + !getMines().contains(mine)) { + if ( save ) { saveMine( mine ); } diff --git a/prison-mines/src/main/java/tech/mcprison/prison/mines/tasks/MinePagedResetAsyncTask.java b/prison-mines/src/main/java/tech/mcprison/prison/mines/tasks/MinePagedResetAsyncTask.java index 25e7ed617..66a3f2263 100644 --- a/prison-mines/src/main/java/tech/mcprison/prison/mines/tasks/MinePagedResetAsyncTask.java +++ b/prison-mines/src/main/java/tech/mcprison/prison/mines/tasks/MinePagedResetAsyncTask.java @@ -194,8 +194,15 @@ public void run() { } // Isolate the sub-list from the main targetBlocks list: + List subList = new ArrayList<>(); + + for ( int i = position; i < endIndex; i++ ) { + subList.add( targetBlocks.get( i ) ); + } +// targetBlocks.subList( position, endIndex ) ); + List tBlocks = new ArrayList<>(); - for (MineTargetPrisonBlock mtpb : targetBlocks.subList( position, endIndex )) { + for (MineTargetPrisonBlock mtpb : subList ) { tBlocks.add(mtpb); } diff --git a/prison-mines/src/test/java/tech/mcprison/prison/mines/data/PrisonSortableMinesTest.java b/prison-mines/src/test/java/tech/mcprison/prison/mines/data/PrisonSortableMinesTest.java index c93683e37..6b9d26292 100644 --- a/prison-mines/src/test/java/tech/mcprison/prison/mines/data/PrisonSortableMinesTest.java +++ b/prison-mines/src/test/java/tech/mcprison/prison/mines/data/PrisonSortableMinesTest.java @@ -8,6 +8,8 @@ import org.junit.Test; +import tech.mcprison.prison.mines.data.Mine.MineUnitTestUsage; + @SuppressWarnings("deprecation") public class PrisonSortableMinesTest extends PrisonSortableMines @@ -19,12 +21,20 @@ public class PrisonSortableMinesTest @Test public void testGetSortedSet() { - Mine a = new Mine(); - a.setName( "A" ); - Mine b = new Mine(); - b.setName( "b" ); - Mine c = new Mine(); - c.setName( "C" ); + /** + * The following mine constructor will not initialize the mines since that + * is not needed in unit tests. + */ + Mine a = new Mine( MineUnitTestUsage.TRUE, "A" ); + Mine b = new Mine( MineUnitTestUsage.TRUE, "b" ); // note lower case 'b' + Mine c = new Mine( MineUnitTestUsage.TRUE, "C" ); + +// Mine a = new Mine(); +// a.setName( "A" ); +// Mine b = new Mine(); +// b.setName( "b" ); +// Mine c = new Mine(); +// c.setName( "C" ); List unsortedList = new ArrayList<>(); unsortedList.add( b ); diff --git a/prison-mines/src/test/java/tech/mcprison/prison/mines/managers/MineManagerTest.java b/prison-mines/src/test/java/tech/mcprison/prison/mines/managers/MineManagerTest.java index 7851dd110..58ea9cc4f 100644 --- a/prison-mines/src/test/java/tech/mcprison/prison/mines/managers/MineManagerTest.java +++ b/prison-mines/src/test/java/tech/mcprison/prison/mines/managers/MineManagerTest.java @@ -9,6 +9,7 @@ import tech.mcprison.prison.mines.data.Mine; import tech.mcprison.prison.mines.data.PrisonSortableResults; +import tech.mcprison.prison.mines.data.Mine.MineUnitTestUsage; public class MineManagerTest extends @@ -17,14 +18,19 @@ public class MineManagerTest private List getTestMines() { List mines = new ArrayList<>(); - Mine a = new Mine(); - a.setName( "A" ); - Mine b = new Mine(); - b.setName( "b" ); - Mine c = new Mine(); - c.setName( "C" ); - Mine d = new Mine(); - d.setName( "D" ); + Mine a = new Mine( MineUnitTestUsage.TRUE, "A" ); + Mine b = new Mine( MineUnitTestUsage.TRUE, "b" ); + Mine c = new Mine( MineUnitTestUsage.TRUE, "C" ); + Mine d = new Mine( MineUnitTestUsage.TRUE, "D" ); + +// Mine a = new Mine(); +// a.setName( "A" ); +// Mine b = new Mine(); +// b.setName( "b" ); +// Mine c = new Mine(); +// c.setName( "C" ); +// Mine d = new Mine(); +// d.setName( "D" ); mines.add( d ); mines.add( b ); 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 abd6901ac..a5e73fa1f 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 @@ -474,7 +474,8 @@ public void ladderApplyRankCostMultiplier( CommandSender sender, @Arg( name = "ladderName" ) String ladderName, @Arg( name = "applyRankCostMultiplier", def = "apply", description = "Applies or disables the ranks on this ladder " - + "from applying the rank multiplier to the rank cost for players." + + "from applying the rank multiplier to the rank cost for players. " + + "Use a value of 'apply' or 'true'; anything else is treated as 'false'." ) String applyRankCostMultiplier ) { @@ -487,7 +488,8 @@ public void ladderApplyRankCostMultiplier( CommandSender sender, } boolean applyRCM = applyRankCostMultiplier != null && - applyRankCostMultiplier.equalsIgnoreCase( "apply" ); + (applyRankCostMultiplier.equalsIgnoreCase( "apply" ) || + applyRankCostMultiplier.equalsIgnoreCase( "true" ) ); boolean applyRCMOld = ladder.isApplyRankCostMultiplierToLadder(); 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 6ca277370..2a53095dd 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 @@ -119,17 +119,17 @@ public void rankUpMax(CommandSender sender, } + Player player = getPlayer( sender, null ); // submit cmdTasks if ( cmdTasks.size() > 0 ) { - Player player = getPlayer( sender, null ); submitCmdTasks( player, cmdTasks ); } if ( sbRanks.length() > 0 ) { - ranksRankupMaxSuccessMsg( sender, sbRanks ); + ranksRankupMaxSuccessMsg( sender, sbRanks, player.getRankPlayer() ); } // If the ran rankupmax for prestiges, and the last prestige was successful, then @@ -139,10 +139,11 @@ public void rankUpMax(CommandSender sender, } } else { + Player player = getPlayer( sender, null ); Output.get().logDebug( DebugTarget.rankup, "Rankup: Failed: cmd '/rankupmax %s' Does not have the permission ranks.rankupmax.%s", ladder, ladder ); - rankupMaxNoPermissionMsg( sender, "ranks.rankupmax." + ladder ); + rankupMaxNoPermissionMsg( sender, "ranks.rankupmax." + ladder, player.getRankPlayer() ); } } @@ -162,17 +163,65 @@ public void rankUp(CommandSender sender, @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 +// , +// @Arg(name = "confirm", def = "", +// description = "If confirmations are enabled, then the rankup command " + +// "must be repeated with the addition of 'confirm'. If the rankup 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 'prison-ranks.confirmation-enabled: true' is enabled, then confirmations will " +// + "be skipped (acts like a bypass)." ) +// String confirm ) { - if ( sender.isPlayer() ) { + boolean isPlayer = sender.isPlayer(); + + if ( isPlayer ) { playerName = ""; } - if ( !sender.isPlayer() && playerName.length() == 0 ) { + if ( !isPlayer && playerName.length() == 0 ) { Output.get().logInfo( rankupCannotRunFromConsoleMsg() ); return; } + +// RankPlayer rPlayer = getRankPlayer(sender, null, playerName); + +// boolean isConfirmed = ( confirm != null && confirm.toLowerCase().contains("confirm") ); +// if ( !isConfirmed && playerName != null && playerName.toLowerCase().equals( "confirm" ) ) { +// isConfirmed = true; +// playerName = ""; +// } +// else if ( !isConfirmed && ladder != null && ladder.toLowerCase().equals( "confirm" ) ) { +// isConfirmed = true; +// ladder = ""; +// } + + + +// boolean isConfirmationEnabled = Prison.get().getPlatform().getConfigBooleanFalse( "ranks.confirmation-enabled" ); +// 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; +// } + String perms = "ranks.rankup."; String permsLadder = perms + ladder; @@ -211,10 +260,11 @@ public void rankUp(CommandSender sender, submitCmdTasks( player, cmdTasks ); } else { + Player player = getPlayer( sender, playerName ); Output.get().logDebug( DebugTarget.rankup, "Rankup: Failed: cmd '/rankup %s' Does not have the permission %s", ladder, permsLadder ); - rankupMaxNoPermissionMsg( sender, permsLadder ); + rankupMaxNoPermissionMsg( sender, permsLadder, player.getRankPlayer() ); } } @@ -296,16 +346,16 @@ public void prestigeCmd(CommandSender sender, if ( nRank == null ) { // You're at the last possible rank. - rankupNotAbleToPrestigeMsg( sender ); - rankupAtLastRankMsg( sender ); + rankupNotAbleToPrestigeMsg( sender, rPlayer ); + rankupAtLastRankMsg( sender, rPlayer ); return; } if ( !nRank.getLadder().getName().equals( LadderManager.LADDER_PRESTIGES ) ) { // your next rank is not a Prestiges rank - rankupNotAbleToPrestigeMsg( sender ); - rankupNotAtLastRankMsg( sender ); + rankupNotAbleToPrestigeMsg( sender, rPlayer ); + rankupNotAtLastRankMsg( sender, rPlayer ); return; } @@ -315,8 +365,8 @@ public void prestigeCmd(CommandSender sender, if ( rPlayer.getBalance( currency ) < nextRank.getRankCost() ) { // You do not have enough to prestige yet - ranksRankupCannotAffordMsg( sender, nextRank ); - ranksRankupPlayerBalanceMsg( sender, rPlayer.getBalance( currency ), currency ); + ranksRankupCannotAffordMsg( sender, nextRank, rPlayer ); + ranksRankupPlayerBalanceMsg( sender, rPlayer.getBalance( currency ), currency, rPlayer); return; } @@ -432,8 +482,9 @@ private boolean rankUpPrivate(CommandSender sender, String playerName, String la //UUID playerUuid = player.getUUID(); + RankPlayer rankPlayer = getRankPlayer( sender, player.getUUID(), player.getName() ); - ladder = confirmLadder( sender, ladder ); + ladder = confirmLadder( sender, ladder, rankPlayer ); if ( ladder == null ) { // ladder cannot be null, return false; @@ -454,7 +505,6 @@ private boolean rankUpPrivate(CommandSender sender, String playerName, String la - RankPlayer rankPlayer = getRankPlayer( sender, player.getUUID(), player.getName() ); PlayerRank rankCurrent = rankPlayer.getPlayerRank(ladder); @@ -462,7 +512,7 @@ private boolean rankUpPrivate(CommandSender sender, String playerName, String la // If the player has a rank on the target ladder, mmake sure the next rank is not null if ( rankCurrent != null && rankCurrent.getRank().getRankNext() == null ) { - rankupAtLastRankMsg(sender); + rankupAtLastRankMsg(sender, rankPlayer ); return false; } @@ -558,7 +608,7 @@ private boolean rankUpPrivate(CommandSender sender, String playerName, String la // On the default ladder, the player must be at the last rank: // The last rank will never have a rankNext (it will be null): if ( playersRankOnDefaultLadder.getRankNext() != null ) { - rankupNotAtLastRankMsg( sender ); + rankupNotAtLastRankMsg( sender, rankPlayer ); return false; } @@ -618,7 +668,7 @@ private boolean rankUpPrivate(CommandSender sender, String playerName, String la } else if ( canPrestige ) { - rankupNotAbleToPrestigeMsg( sender ); + rankupNotAbleToPrestigeMsg( sender, rankPlayer ); } } @@ -695,13 +745,13 @@ private void prestigePlayer(CommandSender sender, RankPlayer rankPlayer, if ( !pRankSecond.equals( lm.getLadder(LadderManager.LADDER_DEFAULT).getLowestRank().get()) ) { - rankupNotAbleToResetRankMsg( sender ); + rankupNotAbleToResetRankMsg( sender, rankPlayer ); success = false; } } else { - rankupNotAbleToResetRankMsg( sender ); + rankupNotAbleToResetRankMsg( sender, rankPlayer ); success = false; } // } @@ -711,7 +761,7 @@ private void prestigePlayer(CommandSender sender, RankPlayer rankPlayer, // set the player's balance to zero: rankPlayer.setBalance( 0 ); - prestigePlayerBalanceSetToZeroMsg( sender ); + prestigePlayerBalanceSetToZeroMsg( sender, rankPlayer ); } @@ -727,11 +777,11 @@ private void prestigePlayer(CommandSender sender, RankPlayer rankPlayer, if ( success ) { // Send a message to the player because he did prestige! - prestigePlayerSucessfulMsg( sender, title ); + prestigePlayerSucessfulMsg( sender, title, rankPlayer ); } else { - prestigePlayerFailureMsg( sender, title ); + prestigePlayerFailureMsg( sender, title, rankPlayer ); } } @@ -752,50 +802,60 @@ public void promotePlayer(CommandSender sender, ) { Player player = getPlayer( sender, playerName ); + UUID playerUuid = player.getUUID(); if (player == null) { ranksPromotePlayerMustBeOnlineMsg( sender ); return; } + RankPlayerFactory rankPlayerFactory = new RankPlayerFactory(); + RankPlayer rankPlayer = getRankPlayer( sender, playerUuid, player.getName() ); + PromoteForceCharge pForceCharge = PromoteForceCharge.fromString( chargePlayer ); if ( pForceCharge == null|| pForceCharge == PromoteForceCharge.refund_player ) { - ranksPromotePlayerInvalidChargeValueMsg( sender ); + ranksPromotePlayerInvalidChargeValueMsg( sender, rankPlayer ); return; } - UUID playerUuid = player.getUUID(); - ladder = confirmLadder( sender, ladder ); + ladder = confirmLadder( sender, ladder, rankPlayer ); + if ( ladder == null ) { + return; + } - RankPlayerFactory rankPlayerFactory = new RankPlayerFactory(); - RankPlayer rankPlayer = getRankPlayer( sender, playerUuid, player.getName() ); PlayerRank playerRank = rankPlayerFactory.getRank( rankPlayer, ladder ); - if ( playerRank != null ) { + if ( rankPlayer != null && playerRank != null ) { Rank pRank = playerRank.getRank(); + if ( pRank == null ) { + sender.sendMessage( "Promote: There was an error trying to access the " + + "current rank of the player. Try viewing the player's " + + "details: '/ranks player help'."); + return; + } // 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(); + String currency = pRank.getCurrency(); + + List cmdTasks = new ArrayList<>(); + + RankupResults results = new RankUtil().promotePlayer(player, rankPlayer, ladder, + player.getName(), sender.getName(), pForceCharge, cmdTasks ); + + // submit cmdTasks... + submitCmdTasks( player, cmdTasks ); + + processResults( sender, player.getName(), results, null, ladder, currency, null ); - if ( ladder != null && rankPlayer != null ) { - - List cmdTasks = new ArrayList<>(); - - RankupResults results = new RankUtil().promotePlayer(player, rankPlayer, ladder, - player.getName(), sender.getName(), pForceCharge, cmdTasks ); - - // submit cmdTasks... - submitCmdTasks( player, cmdTasks ); - - processResults( sender, player.getName(), results, null, ladder, currency, null ); - } } else { // Message: Player is not on the ladder + sender.sendMessage( "Promote: Player is not on the specified ladder. " + + "Try using '/ranks set rank' to add them."); } } @@ -823,15 +883,16 @@ public void demotePlayer(CommandSender sender, return; } + UUID playerUuid = player.getUUID(); + RankPlayer rankPlayer = getRankPlayer( sender, playerUuid, player.getName() ); + PromoteForceCharge pForceCharge = PromoteForceCharge.fromString( refundPlayer ); if ( pForceCharge == null || pForceCharge == PromoteForceCharge.charge_player ) { - ranksDemotePlayerInvalidRefundValueMsg( sender ); + ranksDemotePlayerInvalidRefundValueMsg( sender, rankPlayer ); return; } - UUID playerUuid = player.getUUID(); - - ladder = confirmLadder( sender, ladder ); + ladder = confirmLadder( sender, ladder, rankPlayer ); if ( ladder == null ) { // Already displayed error message about ladder not existing: return; @@ -839,31 +900,36 @@ public void demotePlayer(CommandSender sender, RankPlayerFactory rankPlayerFactory = new RankPlayerFactory(); - RankPlayer rankPlayer = getRankPlayer( sender, playerUuid, player.getName() ); PlayerRank playerRank = rankPlayerFactory.getRank( rankPlayer, ladder ); - if ( playerRank != null ) { + if ( rankPlayer != null && playerRank != null ) { Rank pRank = playerRank.getRank(); + if ( pRank == null ) { + sender.sendMessage( "Demote: There was an error trying to access the " + + "current rank of the player. Try viewing the player's " + + "details: '/ranks player help'."); + return; + } // 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(); + String currency = pRank.getCurrency(); + + List cmdTasks = new ArrayList<>(); + + RankupResults results = new RankUtil().demotePlayer(player, rankPlayer, ladder, + player.getName(), sender.getName(), pForceCharge, cmdTasks ); + + // submit cmdTasks + submitCmdTasks( player, cmdTasks ); + + processResults( sender, player.getName(), results, null, ladder, currency, null ); - if ( ladder != null && rankPlayer != null ) { - - List cmdTasks = new ArrayList<>(); - - RankupResults results = new RankUtil().demotePlayer(player, rankPlayer, ladder, - player.getName(), sender.getName(), pForceCharge, cmdTasks ); - - // submit cmdTasks - submitCmdTasks( player, cmdTasks ); - - processResults( sender, player.getName(), results, null, ladder, currency, null ); - } } else { // Message: Player is not on the ladder + sender.sendMessage( "Demote: Player is not on the specified ladder. " + + "Try using '/ranks set rank' to add them."); } } @@ -1007,9 +1073,9 @@ private void setPlayerRank( Player player, String rank, String ladderName, Comma Output.get().logDebug( DebugTarget.rankup, "Rankup: setPlayerRank: "); - ladderName = confirmLadder( sender, ladderName ); + RankPlayer rankPlayer = getRankPlayer( sender, playerUuid, player.getName() ); - RankPlayer rankPlayer = getRankPlayer( sender, playerUuid, player.getName() ); + ladderName = confirmLadder( sender, ladderName, rankPlayer ); if ( ladderName != null && rankPlayer != null ) { @@ -1034,13 +1100,14 @@ private void setPlayerRank( Player player, String rank, String ladderName, Comma - public String confirmLadder( CommandSender sender, String ladderName ) { + private String confirmLadder( CommandSender sender, String ladderName, RankPlayer rPlayer ) { String results = null; RankLadder ladder = PrisonRanks.getInstance().getLadderManager().getLadder(ladderName); // The ladder doesn't exist if ( ladder == null ) { - ranksConfirmLadderMsg( sender, ladderName ); + + ranksConfirmLadderMsg( sender, ladderName, rPlayer ); } else { results = ladder.getName(); @@ -1092,62 +1159,64 @@ public void processResults( CommandSender sender, String playerName, break; case RANKUP_FAILURE: - ranksRankupFailureMsg( sender ); + ranksRankupFailureMsg( sender, results.getRankPlayer() ); break; case RANKUP_FAILURE_COULD_NOT_LOAD_PLAYER: - ranksRankupFailureCouldNotLoadPlayerMsg( sender ); + ranksRankupFailureCouldNotLoadPlayerMsg( sender, results.getRankPlayer() ); break; case RANKUP_FAILURE_COULD_NOT_LOAD_LADDER: - ranksRankupFailureCouldNotLoadLadderMsg( sender ); + ranksRankupFailureCouldNotLoadLadderMsg( sender, results.getRankPlayer() ); break; case RANKUP_FAILURE_UNABLE_TO_ASSIGN_RANK: - ranksRankupFailureUnableToAssignRankMsg( sender ); + ranksRankupFailureUnableToAssignRankMsg( sender, results.getRankPlayer() ); break; case RANKUP_FAILURE_COULD_NOT_SAVE_PLAYER_FILE: - ranksRankupFailureCouldNotSavePlayerFileMsg( sender ); + ranksRankupFailureCouldNotSavePlayerFileMsg( sender, results.getRankPlayer() ); break; case RANKUP_NO_RANKS: - ranksRankupFailureNoRanksMsg( sender ); + ranksRankupFailureNoRanksMsg( sender, results.getRankPlayer() ); break; case RANKUP_FAILURE_RANK_DOES_NOT_EXIST: - ranksRankupFailureRankDoesNotExistMsg( sender, rank ); + ranksRankupFailureRankDoesNotExistMsg( sender, rank, results.getRankPlayer() ); break; case RANKUP_FAILURE_RANK_IS_NOT_IN_LADDER: - ranksRankupFailureRankIsNotInLadderMsg( sender, rank, ladder ); + ranksRankupFailureRankIsNotInLadderMsg( sender, rank, ladder, results.getRankPlayer() ); break; case RANKUP_FAILURE_CURRENCY_IS_NOT_SUPPORTED: - ranksRankupFailureCurrencyIsNotSupportedMsg( sender, results.getTargetRank().getCurrency() ); + ranksRankupFailureCurrencyIsNotSupportedMsg( sender, results.getTargetRank().getCurrency(), + results.getRankPlayer() ); break; case RANKUP_FAILURE_ECONOMY_FAILED: // TODO externalize message - sender.sendMessage( "Failed to adjust player's balance. Could be an issue with vault or " + - "a cache timing issue. Try again." ); + String msg = "Failed to adjust player's balance. Could be an issue with vault or " + + "a cache timing issue. Try again."; + sender.sendMessage( results.getRankPlayer().convertStringPlaceholders( msg ) ); break; case RANKUP_LADDER_REMOVED: - ranksRankupFailureLadderRemovedMsg( sender, ladder ); + ranksRankupFailureLadderRemovedMsg( sender, ladder, results.getRankPlayer() ); break; case RANKUP_FAILURE_REMOVING_LADDER: - ranksRankupFailureRemovingLadderMsg( sender, ladder ); + ranksRankupFailureRemovingLadderMsg( sender, ladder, results.getRankPlayer() ); break; case IN_PROGRESS: - ranksRankupFailureInProgressMsg( sender ); + ranksRankupFailureInProgressMsg( sender, results.getRankPlayer() ); break; default: 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 c0782abae..6c1a1c9aa 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 @@ -25,11 +25,12 @@ public RankUpCommandMessages( String cmdGroup ) } - protected void rankupMaxNoPermissionMsg( CommandSender sender, String permission ) { + protected void rankupMaxNoPermissionMsg( CommandSender sender, String permission, + RankPlayer rPlayer ) { PrisonRanks.getInstance().getRanksMessages() .getLocalizable( "ranks_rankup__no_permission" ) .withReplacements( permission.toLowerCase() ) - .sendTo( sender ); + .sendTo( sender, rPlayer ); } protected String rankupCannotRunFromConsoleMsg() { @@ -85,50 +86,65 @@ protected void rankupErrorPlayerNotOnDefaultLadder( CommandSender sender, .sendTo( sender ); } - protected void rankupNotAtLastRankMsg( CommandSender sender ) { + protected void rankupNotAtLastRankMsg( CommandSender sender, + RankPlayer rPlayer ) { PrisonRanks.getInstance().getRanksMessages() .getLocalizable( "ranks_rankup__not_at_last_rank" ) - .sendTo( sender ); + .sendTo( sender, rPlayer ); } - protected void rankupAtLastRankMsg( CommandSender sender ) { + protected void rankupAtLastRankMsg( CommandSender sender, + RankPlayer rPlayer ) { PrisonRanks.getInstance().getRanksMessages() .getLocalizable( "ranks_rankup__at_last_rank" ) - .sendTo( sender ); + .sendTo( sender, rPlayer ); } - protected void rankupNotAbleToPrestigeMsg( CommandSender sender ) { + protected void rankupNotAbleToPrestigeMsg( CommandSender sender, + RankPlayer rPlayer ) { PrisonRanks.getInstance().getRanksMessages() .getLocalizable( "ranks_rankup__not_able_to_prestige" ) - .sendTo( sender ); + .sendTo( sender, rPlayer ); } - protected void rankupNotAbleToResetRankMsg( CommandSender sender ) { + protected void rankupNotAbleToResetRankMsg( CommandSender sender, + RankPlayer rPlayer ) { PrisonRanks.getInstance().getRanksMessages() .getLocalizable( "ranks_rankup__not_able_to_reset_rank" ) - .sendTo( sender ); + .sendTo( sender, rPlayer ); } - protected void prestigePlayerBalanceSetToZeroMsg( CommandSender sender ) { + protected void prestigePlayerBalanceSetToZeroMsg( CommandSender sender, + RankPlayer rPlayer ) { PrisonRanks.getInstance().getRanksMessages() .getLocalizable( "ranks_rankup__balance_set_to_zero" ) - .sendTo( sender ); + .sendTo( sender, rPlayer ); } - protected void prestigePlayerSucessfulMsg( CommandSender sender, String tag ) { + protected void prestigePlayerSucessfulMsg( CommandSender sender, String tag, + RankPlayer rPlayer ) { PrisonRanks.getInstance().getRanksMessages() .getLocalizable( "ranks_rankup__prestige_successful" ) .withReplacements( tag ) - .sendTo( sender ); + .sendTo( sender, rPlayer ); } - protected void prestigePlayerFailureMsg( CommandSender sender, String tag ) { + protected void prestigePlayerSucessfulBroadcastMsg( CommandSender sender, String tag, + RankPlayer rPlayer ) { + PrisonRanks.getInstance().getRanksMessages() + .getLocalizable( "ranks_rankup__prestige_successful_broadcast" ) + .withReplacements( tag ) + .sendTo( sender, rPlayer ); + } + + protected void prestigePlayerFailureMsg( CommandSender sender, String tag, + RankPlayer rPlayer ) { PrisonRanks.getInstance().getRanksMessages() .getLocalizable( "ranks_rankup__prestige_failure" ) .withReplacements( tag ) - .sendTo( sender ); + .sendTo( sender, rPlayer ); } protected String prestigeConfirmationGUIMsg( CommandSender sender, @@ -146,34 +162,46 @@ protected String prestigeConfirmationGUIMsg( CommandSender sender, 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( " " ); + sb.append( + rPlayer.convertStringPlaceholders( + rMsg.getLocalizable( "ranks_rankup__confirm_prestige_line_1" ) + .withReplacements( tag ) + .localize().replace(" ", "_") )).append( " " ); + + sb.append( + rPlayer.convertStringPlaceholders( + rMsg.getLocalizable( "ranks_rankup__confirm_prestige_line_2" ) + .withReplacements( + dFmt.format( targetRank.getRankCost()) ) + .localize().replace(" ", "_") )).append( " " ); + + sb.append( + rPlayer.convertStringPlaceholders( + 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( " " ); + sb.append( + rPlayer.convertStringPlaceholders( + 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( + rPlayer.convertStringPlaceholders( + rMsg.getLocalizable( "ranks_rankup__confirm_prestige_line_5" ) + .localize().replace(" ", "_") )).append( " " ); } - sb.append( rMsg.getLocalizable( "ranks_rankup__confirm_prestige_line_7" ) - .localize().replace(" ", "_") ); + sb.append( + rPlayer.convertStringPlaceholders( + rMsg.getLocalizable( "ranks_rankup__confirm_prestige_line_7" ) + .localize().replace(" ", "_") )); return sb.toString(); } @@ -196,38 +224,38 @@ protected void prestigeConfirmationMsg( CommandSender sender, } rMsg.getLocalizable( "ranks_rankup__confirm_prestige_line_1" ) .withReplacements( tag ) - .sendTo( sender ); + .sendTo( sender, rPlayer ); rMsg.getLocalizable( "ranks_rankup__confirm_prestige_line_2" ) .withReplacements( dFmt.format( targetRank.getRankCost()) ) - .sendTo( sender ); + .sendTo( sender, rPlayer ); rMsg.getLocalizable( "ranks_rankup__confirm_prestige_line_3" ) .withReplacements( dFmt.format( balance), currency == null || currency.trim().length() == 0 ? "" : " " + currency ) - .sendTo( sender ); + .sendTo( sender, rPlayer ); if ( isResetDefaultLadder ) { rMsg.getLocalizable( "ranks_rankup__confirm_prestige_line_4" ) - .sendTo( sender ); + .sendTo( sender, rPlayer ); } if ( isResetMoney ) { rMsg.getLocalizable( "ranks_rankup__confirm_prestige_line_4" ) - .sendTo( sender ); + .sendTo( sender, rPlayer ); } rMsg.getLocalizable( "ranks_rankup__confirm_prestige_line_5" ) - .sendTo( sender ); + .sendTo( sender, rPlayer ); String playerName = !isPlayer ? rPlayer.getName() + " " : ""; rMsg.getLocalizable( "ranks_rankup__confirm_prestige_line_6" ) .withReplacements( playerName ) - .sendTo( sender ); + .sendTo( sender, rPlayer ); // ranks_rankup__confirm_prestige_line_1=&3Confirm Prestige: %s @@ -240,7 +268,8 @@ protected void prestigeConfirmationMsg( CommandSender sender, } protected void ranksRankupPlayerBalanceMsg( CommandSender sender, - double balance, String currency ) { + double balance, String currency, + RankPlayer rPlayer ) { DecimalFormat dFmt = Prison.get().getDecimalFormat("#,##0.00"); LocaleManager rMsg = PrisonRanks.getInstance().getRanksMessages(); @@ -250,7 +279,7 @@ protected void ranksRankupPlayerBalanceMsg( CommandSender sender, dFmt.format( balance), currency == null || currency.trim().length() == 0 ? "" : " " + currency ) - .sendTo( sender ); + .sendTo( sender, rPlayer ); } protected void ranksPromotePlayerMustBeOnlineMsg( CommandSender sender ) { @@ -259,31 +288,34 @@ protected void ranksPromotePlayerMustBeOnlineMsg( CommandSender sender ) { .sendTo( sender ); } - protected void ranksPromotePlayerInvalidChargeValueMsg( CommandSender sender ) { + protected void ranksPromotePlayerInvalidChargeValueMsg( CommandSender sender, + RankPlayer rPlayer ) { PrisonRanks.getInstance().getRanksMessages() .getLocalizable( "ranks_rankup__invalid_charge_value" ) .withReplacements( PromoteForceCharge.no_charge.name(), PromoteForceCharge.charge_player.name() ) - .sendTo( sender ); + .sendTo( sender, rPlayer ); } - protected void ranksDemotePlayerInvalidRefundValueMsg( CommandSender sender ) { + protected void ranksDemotePlayerInvalidRefundValueMsg( CommandSender sender, + RankPlayer rPlayer ) { PrisonRanks.getInstance().getRanksMessages() .getLocalizable( "ranks_rankup__invalid_refund_value" ) .withReplacements( PromoteForceCharge.no_charge.name(), PromoteForceCharge.refund_player.name() ) - .sendTo( sender ); + .sendTo( sender, rPlayer ); } - protected void ranksConfirmLadderMsg( CommandSender sender, String ladderName ) { + protected void ranksConfirmLadderMsg( CommandSender sender, String ladderName, + RankPlayer rPlayer ) { PrisonRanks.getInstance().getRanksMessages() .getLocalizable( "ranks_rankup__rankup_failure_invalid_ladder" ) .withReplacements( ladderName ) - .sendTo( sender ); + .sendTo( sender, rPlayer ); } @@ -297,7 +329,10 @@ protected void ranksRankupFailureToGetRankPlayerMsg( CommandSender sender ) { protected void ranksRankupSuccessMsg( CommandSender sender, String playerName, RankupResults results, - StringBuilder sbRanks ) { + StringBuilder sbRanks + ) { + + RankPlayer rPlayer = results.getRankPlayer(); // PlayerRank tpRank = results.getPlayerRankTarget(); Rank tRank = results.getTargetRank(); @@ -333,7 +368,9 @@ protected void ranksRankupSuccessMsg( CommandSender sender, String playerName, sender.getName(), localManager.localize() ); - Output.get().logInfo( localManagerLog.localize() ); + Output.get().logInfo( + rPlayer.convertStringPlaceholders( + localManagerLog.localize() )); if ( Prison.get().getPlatform().getConfigBooleanFalse( "broadcast-rankups" ) ) { @@ -348,14 +385,15 @@ protected void ranksRankupSuccessMsg( CommandSender sender, String playerName, (tRank == null ? "" : tRank.getTag() ), (results.getMessage() != null ? results.getMessage() : "") ) - .broadcast(); + .broadcast( rPlayer ); } else { - localManager.sendTo( sender ); + localManager.sendTo( sender, rPlayer ); } } - protected void ranksRankupMaxSuccessMsg( CommandSender sender, StringBuilder ranks ) { + protected void ranksRankupMaxSuccessMsg( CommandSender sender, StringBuilder ranks, + RankPlayer rPlayer ) { Localizable localManagerLog = PrisonRanks.getInstance().getRanksMessages() .getLocalizable( "ranks_rankup__log_rank_change" ) @@ -370,12 +408,12 @@ protected void ranksRankupMaxSuccessMsg( CommandSender sender, StringBuilder ran if ( Prison.get().getPlatform().getConfigBooleanFalse( "broadcast-rankups" ) ) { - localManagerLog.broadcast(); + localManagerLog.broadcast( rPlayer ); } else { - localManagerLog.sendTo( sender ); + localManagerLog.sendTo( sender, rPlayer ); } } @@ -384,11 +422,12 @@ protected void ranksRankupCannotAffordMsg( CommandSender sender, PlayerRank tpRank = results.getPlayerRankTarget(); - ranksRankupCannotAffordMsg( sender, tpRank ); + ranksRankupCannotAffordMsg( sender, tpRank, results.getRankPlayer() ); } protected void ranksRankupCannotAffordMsg( CommandSender sender, - PlayerRank tpRank ) { + PlayerRank tpRank, + RankPlayer rPlayer ) { DecimalFormat dFmt = Prison.get().getDecimalFormat("#,##0.00"); @@ -402,7 +441,7 @@ protected void ranksRankupCannotAffordMsg( CommandSender sender, tRank == null || tRank.getCurrency() == null ? "" : " " +tRank.getCurrency() ) - .sendTo( sender ); + .sendTo( sender, rPlayer ); } protected void ranksRankupLowestRankMsg( CommandSender sender, String playerName, @@ -416,7 +455,7 @@ protected void ranksRankupLowestRankMsg( CommandSender sender, String playerName .withReplacements( (playerName == null ? messagYouAre : playerName) ) - .sendTo( sender ); + .sendTo( sender, results.getRankPlayer() ); } protected void ranksRankupHighestRankMsg( CommandSender sender, String playerName, @@ -430,107 +469,120 @@ protected void ranksRankupHighestRankMsg( CommandSender sender, String playerNam .withReplacements( (playerName == null ? messagYouAre : playerName) ) - .sendTo( sender ); + .sendTo( sender, results.getRankPlayer() ); } - protected void ranksRankupFailureMsg( CommandSender sender ) { + protected void ranksRankupFailureMsg( CommandSender sender, + RankPlayer rPlayer ) { PrisonRanks.getInstance().getRanksMessages() .getLocalizable( "ranks_rankup__rankup_failure" ) - .sendTo( sender ); + .sendTo( sender, rPlayer ); } - protected void ranksRankupFailureCouldNotLoadPlayerMsg( CommandSender sender ) { + protected void ranksRankupFailureCouldNotLoadPlayerMsg( CommandSender sender, + RankPlayer rPlayer ) { PrisonRanks.getInstance().getRanksMessages() .getLocalizable( "ranks_rankup__rankup_failed_to_load_player" ) - .sendTo( sender ); + .sendTo( sender, rPlayer ); } - protected void ranksRankupFailureCouldNotLoadLadderMsg( CommandSender sender ) { + protected void ranksRankupFailureCouldNotLoadLadderMsg( CommandSender sender, + RankPlayer rPlayer ) { PrisonRanks.getInstance().getRanksMessages() .getLocalizable( "ranks_rankup__rankup_failed_to_load_ladder" ) - .sendTo( sender ); + .sendTo( sender, rPlayer ); } - protected void ranksRankupFailureUnableToAssignRankMsg( CommandSender sender ) { + protected void ranksRankupFailureUnableToAssignRankMsg( CommandSender sender, + RankPlayer rPlayer ) { PrisonRanks.getInstance().getRanksMessages() .getLocalizable( "ranks_rankup__rankup_failed_to_assign_rank" ) - .sendTo( sender ); + .sendTo( sender, rPlayer ); } - protected void ranksRankupFailureUnableToAssignRankWithRefundMsg( CommandSender sender ) { + protected void ranksRankupFailureUnableToAssignRankWithRefundMsg( CommandSender sender, + RankPlayer rPlayer ) { PrisonRanks.getInstance().getRanksMessages() .getLocalizable( "ranks_rankup__rankup_failed_to_assign_rank_with_refund" ) - .sendTo( sender ); + .sendTo( sender, rPlayer ); } - protected void ranksRankupFailureCouldNotSavePlayerFileMsg( CommandSender sender ) { + protected void ranksRankupFailureCouldNotSavePlayerFileMsg( CommandSender sender, + RankPlayer rPlayer ) { PrisonRanks.getInstance().getRanksMessages() .getLocalizable( "ranks_rankup__rankup_failed_to_save_player_file" ) - .sendTo( sender ); + .sendTo( sender, rPlayer ); } - protected void ranksRankupFailureNoRanksMsg( CommandSender sender ) { + protected void ranksRankupFailureNoRanksMsg( CommandSender sender, + RankPlayer rPlayer ) { PrisonRanks.getInstance().getRanksMessages() .getLocalizable( "ranks_rankup__rankup_no_ranks" ) - .sendTo( sender ); + .sendTo( sender, rPlayer ); } - protected void ranksRankupFailureRankDoesNotExistMsg( CommandSender sender, String rank ) { + protected void ranksRankupFailureRankDoesNotExistMsg( CommandSender sender, String rank, + RankPlayer rPlayer ) { PrisonRanks.getInstance().getRanksMessages() .getLocalizable( "ranks_rankup__rankup_rank_does_not_exist" ) .withReplacements( rank ) - .sendTo( sender ); + .sendTo( sender, rPlayer ); } protected void ranksRankupFailureRankIsNotInLadderMsg( CommandSender sender, - String rank, String ladder ) { + String rank, String ladder, + RankPlayer rPlayer ) { PrisonRanks.getInstance().getRanksMessages() .getLocalizable( "ranks_rankup__rankup_rank_is_not_in_ladder" ) .withReplacements( rank, ladder ) - .sendTo( sender ); + .sendTo( sender, rPlayer ); } protected void ranksRankupFailureCurrencyIsNotSupportedMsg( CommandSender sender, - String currency ) { + String currency, + RankPlayer rPlayer ) { PrisonRanks.getInstance().getRanksMessages() .getLocalizable( "ranks_rankup__rankup_currency_is_not_supported" ) .withReplacements( currency ) - .sendTo( sender ); + .sendTo( sender, rPlayer ); } protected void ranksRankupFailureLadderRemovedMsg( CommandSender sender, - String ladder ) { + String ladder, + RankPlayer rPlayer ) { PrisonRanks.getInstance().getRanksMessages() .getLocalizable( "ranks_rankup__rankup_ladder_removed" ) .withReplacements( ladder ) - .sendTo( sender ); + .sendTo( sender, rPlayer ); } protected void ranksRankupFailureRemovingLadderMsg( CommandSender sender, - String ladder ) { + String ladder, + RankPlayer rPlayer ) { PrisonRanks.getInstance().getRanksMessages() .getLocalizable( "ranks_rankup__rankup_failure_removing_ladder" ) .withReplacements( ladder ) - .sendTo( sender ); + .sendTo( sender, rPlayer ); } - protected void ranksRankupFailureInProgressMsg( CommandSender sender ) { + protected void ranksRankupFailureInProgressMsg( CommandSender sender, + RankPlayer rPlayer ) { PrisonRanks.getInstance().getRanksMessages() .getLocalizable( "ranks_rankup__rankup_in_progress_failure" ) - .sendTo( sender ); + .sendTo( sender, rPlayer ); } 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 3dcb370cd..7503bccc8 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 @@ -768,7 +768,7 @@ public void listRanks(CommandSender sender, // } RankPlayer rPlayer = - PrisonRanks.getInstance().getPlayerManager().getPlayer( getPlayer(sender) ); + PrisonRanks.getInstance().getPlayerManager().getPlayer( sender.getPlatformPlayer() ); ChatDisplay display = null; @@ -1228,9 +1228,9 @@ private ChatDisplay listRanksOnLadder( RankLadder ladder, boolean hasPerm, RankP return display; } - private String padRankName( Rank rank, int maxRankNameSize, int maxRankTagNoColorSize, boolean hasPerm ) { - return padRankName( rank.getName(), rank.getTag(), maxRankNameSize, maxRankTagNoColorSize, hasPerm ); - } +// private String padRankName( Rank rank, int maxRankNameSize, int maxRankTagNoColorSize, boolean hasPerm ) { +// return padRankName( rank.getName(), rank.getTag(), maxRankNameSize, maxRankTagNoColorSize, hasPerm ); +// } protected String padRankName( String rankName, String rankTag, int maxRankNameSize, int maxRankTagNoColorSize, boolean hasPerm ) { StringBuilder sb = new StringBuilder(); @@ -1763,6 +1763,11 @@ public void rankPlayer(CommandSender sender, msgs.add( messageSellallMultiplier ); // sendToPlayerAndConsole( sender, messageSellallMultiplier ); + List sellallDetails = player.getSellAllMultiplierListings(); + for (String sellallDetail : sellallDetails) { + msgs.add( " " + sellallDetail ); + } + msgs.add( "" ); @@ -2263,6 +2268,7 @@ public void rankTopN(CommandSender sender, // boolean sort = contains( "sort", pageNumber, pageSizeNumber, options ); int topNSize = TopNPlayers.getInstance().getTopNSize(); + boolean loading = TopNPlayers.getInstance().isLoading(); int archivedSize = TopNPlayers.getInstance().getArchivedSize(); @@ -2335,6 +2341,11 @@ public void rankTopN(CommandSender sender, RankPlayer.printRankScoreLine1Header(); sender.sendMessage( header ); + if ( loading ) { + sender.sendMessage( "&3(Loading TopN List - Please Wait)" ); + } + + for ( int i = posStart; i < posEnd; i++ ) { RankPlayer rPlayer = 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 de0a28878..4c79e3cf6 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 @@ -64,6 +64,9 @@ public class TopNPlayers private long statsSaveDataNanoSec = 0L; private long statsLoadDataNanoSec = 0L; + private boolean loading = true; + + private TopNPlayers() { super(); @@ -798,5 +801,12 @@ public long getStatsLoadDataNanoSec() { public void setStatsLoadDataNanoSec(long statsLoadDataNanoSec) { this.statsLoadDataNanoSec = statsLoadDataNanoSec; } + + public boolean isLoading() { + return loading; + } + public void setLoading(boolean loading) { + this.loading = loading; + } } 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 c068b8955..01fc9253e 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 @@ -196,26 +196,26 @@ public void savePlayer(RankPlayer player) { * @throws IOException If one of the players could not be saved. * @see #savePlayer(RankPlayer, String) */ - public void savePlayers() throws IOException { - for (RankPlayer player : players) { - - // Catch exceptions if a failed save so other players can be saved: - try { - savePlayer(player); - } - catch ( Exception e ) { - - String errorMessage = cannotSavePlayerFile( player.filename() ); - - if ( !getPlayerErrors().contains( errorMessage ) ) { - getPlayerErrors().add( errorMessage ); - Output.get().logError( errorMessage ); - } - -// Output.get().logError(errorMessage, e); - } - } - } +// public void savePlayers() throws IOException { +// for (RankPlayer player : players) { +// +// // Catch exceptions if a failed save so other players can be saved: +// try { +// savePlayer(player); +// } +// catch ( Exception e ) { +// +// String errorMessage = cannotSavePlayerFile( player.filename() ); +// +// if ( !getPlayerErrors().contains( errorMessage ) ) { +// getPlayerErrors().add( errorMessage ); +// Output.get().logError( errorMessage ); +// } +// +//// Output.get().logError(errorMessage, e); +// } +// } +// } /** *

If the player does not have a default rank, then assign it to them and @@ -330,8 +330,8 @@ public RankPlayer getPlayer(UUID uid, String playerName) { // dirty = results != null; } - // Save if dirty (change or new): - if ( results != null ) { + // Save if dirty (changed or new): + if ( results != null && results.isDirty() ) { savePlayer( results ); } @@ -729,7 +729,7 @@ public String getPlayerNextRankCostPercent( RankPlayer rankPlayer, String ladder if ( attributeNFormat != null ) { - sb.append( attributeNFormat.format( cost ) ); + sb.append( attributeNFormat.format( percent ) ); } else { @@ -1961,6 +1961,11 @@ public String getTranslatePlayerPlaceHolder( PlaceholderIdentifier identifier ) break; } + +// results = applySecondaryPlaceholders( rankPlayer, results ); + + + if ( attributeText != null && results != null ) { results = attributeText.format( results ); @@ -1974,6 +1979,93 @@ public String getTranslatePlayerPlaceHolder( PlaceholderIdentifier identifier ) } + /** + *

This function will provide support for secondary placeholders for all player related placeholders. + * These secondary placeholders are in addition to the preexisting positional placeholders + * that are hard coded for the specific parameters. + *

+ * + *

These secondary placeholders can be inserted anywhere in the message. + *

+ * + *
    + *
  • {player}
  • + *
  • {rank_default}
  • + *
  • {rank_tag_default}
  • + *
  • {rank_next_default}
  • + *
  • {rank_next_tag_default}
  • + *
  • {rank_prestiges}
  • + *
  • {rank_tag_prestiges}
  • + *
  • {rank_next_prestiges}
  • + *
  • {rank_next_tag_prestiges}
  • + * + *
  • {player} {rank_default} {rank_tag_default} {rank_next_default} {rank_next_tag_default}
  • + *
  • {rank_prestiges} {rank_tag_prestiges} {rank_next_prestiges} {rank_next_tag_prestiges}
  • + *
+ * + * @param rankPlayer + * @param results + * @return + */ + private String applySecondaryPlaceholders(RankPlayer rankPlayer, String results) { + + results = applySecondaryPlaceholdersCheck( "{player}", rankPlayer.getName(), results ); + + if ( rankPlayer.getPlayerRankDefault() != null ) { + PlayerRank rankP = rankPlayer.getPlayerRankDefault(); + Rank rank = rankP == null ? null : rankP.getRank(); + Rank rankNext = rank == null ? null : rank.getRankNext(); + + results = applySecondaryPlaceholdersCheck( "{rank_default}", + rank == null ? "" : rank.getName(), results ); + results = applySecondaryPlaceholdersCheck( "{rank_tag_default}", + rank == null ? "" : rank.getTag(), results ); + + results = applySecondaryPlaceholdersCheck( "{rank_next_default}", + rankNext == null ? "" : rankNext.getName(), results ); + results = applySecondaryPlaceholdersCheck( "{rank_next_tag_default}", + rankNext == null ? "" : rankNext.getTag(), results ); + } + + if ( rankPlayer.getPlayerRankPrestiges() != null ) { + + PlayerRank rankP = rankPlayer.getPlayerRankPrestiges(); + Rank rank = rankP == null ? null : rankP.getRank(); + Rank rankNext = rank == null ? null : rank.getRankNext(); + + results = applySecondaryPlaceholdersCheck( "{rank_prestiges}", + rank == null ? "" : rank.getName(), results ); + results = applySecondaryPlaceholdersCheck( "{rank_tag_prestiges}", + rank == null ? "" : rank.getTag(), results ); + + results = applySecondaryPlaceholdersCheck( "{rank_next_prestiges}", + rankNext == null ? "" : rankNext.getName(), results ); + results = applySecondaryPlaceholdersCheck( "{rank_next_tag_prestiges}", + rankNext == null ? "" : rankNext.getTag(), results ); + } + + return results; + } + + /** + *

Ths function will perform individual replacements of the given placeholders, but + * if the placeholder does not exist, then it will not change anything with the results + * and it will be just passed through. + *

+ * + * @param placeholder + * @param value + * @param results + * @return + */ + private String applySecondaryPlaceholdersCheck( String placeholder, String value, String results) { + + if ( results.contains( placeholder ) && value != null ) { + results = results.replace( placeholder, value ); + } + + return results; + } @Override public List getTranslatedPlaceHolderKeys() { 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 c4d6d20d8..561bb8c87 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 @@ -947,7 +947,7 @@ public String getTranslateRanksPlaceHolder( PlaceholderIdentifier identifier ) { { RankPlayer topRankPlayer = getTopNRankPlayer( sequence ); - if ( topRankPlayer != null ) { + if ( topRankPlayer != null && topRankPlayer.getPlayerRankPrestiges() != null) { results = topRankPlayer.getPlayerRankPrestiges().getRank().getTag(); } @@ -962,7 +962,7 @@ public String getTranslateRanksPlaceHolder( PlaceholderIdentifier identifier ) { { RankPlayer topRankPlayer = getTopNRankPlayer( sequence ); - if ( topRankPlayer != null ) { + if ( topRankPlayer != null && topRankPlayer.getPlayerRankDefault() != null ) { results = topRankPlayer.getPlayerRankDefault().getRank().getTag(); } diff --git a/prison-ranks/src/main/java/tech/mcprison/prison/ranks/tasks/TopNPlayerUpdateAsyncTask.java b/prison-ranks/src/main/java/tech/mcprison/prison/ranks/tasks/TopNPlayerUpdateAsyncTask.java index ffdde60fd..98c2e3705 100644 --- a/prison-ranks/src/main/java/tech/mcprison/prison/ranks/tasks/TopNPlayerUpdateAsyncTask.java +++ b/prison-ranks/src/main/java/tech/mcprison/prison/ranks/tasks/TopNPlayerUpdateAsyncTask.java @@ -40,13 +40,20 @@ public void run() { // } if ( forceReload ) { + topNPlayers.setLoading( true ); + topNPlayers.forceReloadAllPlayers(); + topNPlayers.setLoading( false ); forceReload = false; } else { + topNPlayers.setLoading( true ); + topNPlayers.refreshAndSort(); + + topNPlayers.setLoading( false ); } } diff --git a/prison-spigot/build.gradle b/prison-spigot/build.gradle index 1e33b8b42..b94f6db3a 100644 --- a/prison-spigot/build.gradle +++ b/prison-spigot/build.gradle @@ -136,7 +136,8 @@ dependencies { - compileOnly 'me.clip:placeholderapi:2.11.2' + compileOnly 'me.clip:placeholderapi:2.11.5' + //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/ @@ -146,11 +147,12 @@ dependencies { // https://mvnrepository.com/artifact/me.lucko.luckperms/luckperms-api compileOnly 'me.lucko.luckperms:luckperms-api:4.4' - // jitpack.io: -// implementation 'com.github.cryptomorin:xseries:b95d195482' + // https://mvnrepository.com/artifact/com.github.cryptomorin/XSeries - implementation 'com.github.cryptomorin:XSeries:9.4.0' + implementation 'com.github.cryptomorin:XSeries:9.9.0' +// implementation 'com.github.cryptomorin:XSeries:9.8.0' + //implementation 'com.github.cryptomorin:XSeries:9.4.0' //implementation 'com.github.cryptomorin:XSeries:9.2.0' @@ -185,14 +187,15 @@ dependencies { // NOTE: mavenrepository.com is not the offical repo. - // NOTE: This item-nbt MUST use the API and not the plugini version! + // NOTE: This item-nbt MUST use the API and not the plugin version! // Good: https://repo.codemc.io/service/rest/repository/browse/maven-public/de/tr7zw/item-nbt-api/ // Bad?: https://repo.codemc.io/service/rest/repository/browse/maven-public/de/tr7zw/item-nbt-api-plugin/2.11.3/ // NOTE: This maven repo was failing to be accessable during online builds. So added to the /lib. // https://github.com/tr7zw/Item-NBT-API/wiki/Using-Gradle // https://www.spigotmc.org/resources/nbt-api.7939/ // https://mvnrepository.com/artifact/de.tr7zw/item-nbt-api-plugin - implementation 'de.tr7zw:item-nbt-api:2.12.0' + implementation 'de.tr7zw:item-nbt-api:2.12.2' +// implementation 'de.tr7zw:item-nbt-api:2.12.0' // implementation 'de.tr7zw:item-nbt-api-plugin:2.11.2' // implementation 'de.tr7zw:item-nbt-api-plugin:2.10.0' // implementation 'de.tr7zw:item-nbt-api-plugin:2.9.2' @@ -265,10 +268,7 @@ shadowJar { //include(dependency('me.clip:placeholderapi:2.10.9')) // https://mvnrepository.com/artifact/com.github.cryptomorin/XSeries - include(dependency('com.github.cryptomorin:XSeries:9.4.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('com.github.cryptomorin:XSeries:')) // https://mvnrepository.com/artifact/de.tr7zw/item-nbt-api-plugin 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 3bfc67237..2d0be5df4 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,9 @@ package tech.mcprison.prison.spigot; import java.io.File; +import java.io.IOException; +import java.io.StringReader; +import java.nio.file.Files; import java.text.DecimalFormat; import java.util.ArrayList; import java.util.Collections; @@ -45,9 +48,12 @@ import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.event.EventPriority; +import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.event.player.AsyncPlayerChatEvent; import org.bukkit.event.player.PlayerChatEvent; +import org.bukkit.event.player.PlayerDropItemEvent; import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.player.PlayerPickupItemEvent; import org.bukkit.plugin.Plugin; import org.bukkit.plugin.RegisteredListener; @@ -187,24 +193,30 @@ public SpigotPlatform(SpigotPrison plugin) { this.plugin = plugin; this.scoreboardManager = new SpigotScoreboardManager(); - this.storage = initStorage(); + + + this.storage = null; +// this.storage = initStorage(); this.placeholders = new SpigotPlaceholders(); ActionBarUtil.init(plugin); } - private Storage initStorage() { - String confStorage = plugin.getConfig().getString("storage", "file"); + public Storage initStorage() { + + @SuppressWarnings("unused") + String confStorage = plugin.getConfig().getString("storage", "file"); Storage storage = new FileStorage(plugin.getDataDirectory()); - if (!confStorage.equalsIgnoreCase("file")) { - Output.get().logError("Unknown file storage type in configuration \"" + confStorage - + "\". Using file storage."); - Output.get().logWarn( - "Note: In this version of Prison 3, 'file' is the only supported type of storage. We're working to bring other storage types soon."); - } +// if (!confStorage.equalsIgnoreCase("file")) { +// Output.get().logError("Unknown file storage type in configuration \"" + confStorage +// + "\". Using file storage."); +// Output.get().logWarn( +// "Note: In this version of Prison 3, 'file' is the only supported type of storage. We're working to bring other storage types soon."); +// } + this.storage = storage; return storage; } @@ -1459,9 +1471,9 @@ public ModuleElement getPlayerDefaultMine( tech.mcprison.prison.internal.Command PrisonRanks.getInstance() != null && PrisonRanks.getInstance().isEnabled() ) { - PlayerManager pm = PrisonRanks.getInstance().getPlayerManager(); - Player player = pm.getPlayer( sender ); - RankPlayer rankPlayer = pm.getPlayer( player ); +// PlayerManager pm = PrisonRanks.getInstance().getPlayerManager(); +// Player player = sender.getPlatformPlayer(); + RankPlayer rankPlayer = sender.getRankPlayer(); RankPlayerFactory rankPlayerFactory = new RankPlayerFactory(); @@ -1763,25 +1775,48 @@ public void autoCreateMineLinerAssignment( List rankMineNames, for ( String mineName : rankMineNames ) { Mine mine = mm.getMine( mineName ); + + String msg = + autoCreateMineLinerAssignment( mine, forceLinersBottom, forceLinersWalls ); + if ( msg != null ) { + + Output.get().logInfo( msg ); + } + } + } + + @Override + public String autoCreateMineLinerAssignment( ModuleElement eMine, + boolean forceLinersBottom, boolean forceLinersWalls ) { + String message = null; + + if ( eMine instanceof Mine ) { + + MineManager mm = PrisonMines.getInstance().getMineManager(); +// List mines = mm.getMines(); + + Mine mine = (Mine) eMine; + String mineLinerData = mine.getLinerData().toSaveString(); boolean createLiner = mineLinerData.trim().isEmpty(); if ( createLiner ) { mine.getLinerData().setLiner( Edges.walls, getRandomLinerType(), forceLinersWalls ); mine.getLinerData().setLiner( Edges.bottom, getRandomLinerType(), forceLinersBottom ); - + mineLinerData = mine.getLinerData().toSaveString(); mm.saveMine( mine ); } - - String message = String.format( "Mine Liner status: %s %s : %s", + + message = String.format( "Mine Liner status: %s %s : %s", mine.getName(), (createLiner ? "(Created)" : "(AlreadyExists)"), mineLinerData ); - Output.get().logInfo( message ); - } + } + + return message; } private LinerPatterns getRandomLinerType() { @@ -2729,17 +2764,19 @@ public String dumpEventListenersBlockBreakEvents() { blockEvents.dumpEventListeners( sb ); + // NOTE: the use of '..==..' prevents these packages from being shortened. See end of this function. + sb.append( "\n" ); sb.append( "&2NOTE: Prison Block Event Listeners:\n" ); sb.append( "&2. . Prison Internal BlockBreakEvents: " + - "tech.mcprison.prison.spigot.SpigotListener\n" ); + "tmps.SpigotListener\n" ); sb.append( "&2. . Auto Features: " + - "tmpsae.AutoManagerBlockBreakEvents$AutoManagerBlockBreakEventListener\n" ); + "tmps.ae.AutoManagerBlockBreakEvents$AutoManagerBlockBreakEventListener\n" ); sb.append( "&2. . Prison's multi-block explosions (bombs): " + "tmpsae.AutoManagerPrisonsExplosiveBlockBreakEvents$AutoManagerExplosiveBlockBreakEventListener\n" ); sb.append( "&2. . Prison Abbrv: '&3tmps.&2' = '&3tech..==..mcprison.prison.spigot.&2' & " + - "'&3tmpsae.&2' = '&3tmps..==..autofeatures.events.&2'\n" ); + "'&3tmps.ae.&2' = '&3tmps..==..autofeatures.events.&2'\n" ); // sb.append( "&2. . Auto Feature Core: Non-AutoManager: " + @@ -2794,7 +2831,7 @@ public String dumpEventListenersBlockBreakEvents() { // 'tmpsae.' = 'tmps.autofeatures.events.' String results = sb.toString() .replace( "tech.mcprison.prison.spigot.", "tmps." ) - .replace( "tmps.autofeatures.events.", "tmpsae." ) + .replace( "tmps.autofeatures.events.", "tmps.ae." ) .replace( "..==..", "." ); return results; @@ -2838,6 +2875,52 @@ public String dumpEventListenersPlayerInteractEvents() { return sb.toString(); } + @Override + public String dumpEventListenersBlockPlaceEvents() { + StringBuilder sb = new StringBuilder(); + + ChatDisplay eventDisplay = dumpEventListenersChatDisplay( + "BlockPlaceEvent", + new SpigotHandlerList( BlockPlaceEvent.getHandlerList()) ); + if ( eventDisplay != null ) { + sb.append( eventDisplay.toStringBuilder() ); + } + + return sb.toString(); + } + + @Override + public String dumpEventListenersPlayerDropItemEvents() { + StringBuilder sb = new StringBuilder(); + + ChatDisplay eventDisplay = dumpEventListenersChatDisplay( + "PlayerDropItemEvent", + new SpigotHandlerList( PlayerDropItemEvent.getHandlerList()) ); + if ( eventDisplay != null ) { + sb.append( eventDisplay.toStringBuilder() ); + } + + return sb.toString(); + } + + @Override + public String dumpEventListenersPlayerPickupItemEvents() { + StringBuilder sb = new StringBuilder(); + + try { + ChatDisplay eventDisplay = dumpEventListenersChatDisplay( + "PlayerPickupItemEvent", + new SpigotHandlerList( PlayerPickupItemEvent.getHandlerList()) ); + if ( eventDisplay != null ) { + sb.append( eventDisplay.toStringBuilder() ); + } + } catch (Exception e) { + sb.append( "The PlayerPickupItemEvent is not valid on this version of spigot." ); + } + + return sb.toString(); + } + /** *

Some information on events... *

@@ -2998,7 +3081,15 @@ public void testPlayerUtil( UUID uuid ) @Override public void saveResource( String fileName, boolean replace ) { - SpigotPrison.getInstance().saveResource( fileName, replace ); + + try { + SpigotPrison.getInstance().saveResource( fileName, replace ); + } catch (Exception e) { + Output.get().logInfo( + "SpigotPlatformm.saveResource(): Error trying to save a resource '%s' replace=%s : %s", + fileName, Boolean.toString(replace), e.getMessage() + ); + } } @Override @@ -3348,4 +3439,78 @@ public String getRankByFileName(String name) { return results; } + + /** + * This loadYaml function will load only text based yaml files, but if the + * file contains a class serialization (prefixed with '==:') then it will + * purge all references to such classes so the data is loaded as plain text. + */ + @Override + public Map loadYaml( File file ) { + Map values = null; + + try { + List lines = Files.readAllLines( file.toPath() ); + + StringBuilder sb = new StringBuilder(); + for (String line : lines ) { + // remove object mapping from yaml files: + if ( !line.startsWith(" ==: " ) ) { + sb.append( line ).append( "\n" ); + } + } + + try ( + StringReader sr = new StringReader( sb.toString() ); + ) + { + YamlConfiguration yaml = SpigotPrison.getInstance().loadExternalConfig( sr ); + + if ( yaml != null ) { + values = yaml.getValues( true ); + } + + } + + } + catch (IOException e1) { + e1.printStackTrace(); + } + +// try { +// Class worldClass = Class.forName( "org.bukkit.World" ); +// YamlConfiguration yaml = SpigotPrison.getInstance().loadExternalConfig( file ); +// +// if ( yaml != null ) { +// values = yaml.getValues( true ); +// +// +// if ( yaml.contains( "teleport_location" ) ) { +// +// org.bukkit.Location loc = +// (org.bukkit.Location) yaml.getObject( +// "teleport_location", org.bukkit.Location.class ); +// +// org.bukkit.World world = loc.getWorld(); +// +// if ( loc != null ) { +// values.put( "teleport_location.world", world.getName() ); +// values.put( "teleport_location.x", Double.valueOf( loc.getX()) ); +// values.put( "teleport_location.y", Double.valueOf( loc.getY()) ); +// values.put( "teleport_location.z", Double.valueOf( loc.getZ()) ); +// values.put( "teleport_location.pitch", Double.valueOf( loc.getPitch()) ); +// values.put( "teleport_location.yaw", Double.valueOf( loc.getYaw()) ); +// +// } +// } +// } +// +// } catch (ClassNotFoundException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } + + + return values; + } } 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 1945db12c..8d5b1d05b 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 @@ -20,6 +20,7 @@ import java.io.File; import java.io.IOException; +import java.io.Reader; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.List; @@ -218,13 +219,20 @@ public void onEnable() { // prior to starting up: initCommandMap(); this.scheduler = new SpigotScheduler(this); + + + Prison.get(); SpigotPlatform platform = new SpigotPlatform(this); + + Prison.get().init( platform, Bukkit.getVersion() ); + // Initialize storage after setting the platformm in the Prison.get(): + platform.initStorage(); + // Show Prison's splash screen and setup the core components: - Prison.get() - .init( platform, Bukkit.getVersion(), getDataFolder() ); + Prison.get().init( getDataFolder() ); @@ -1330,6 +1338,14 @@ public YamlConfiguration loadConfig(String file) { return YamlConfiguration.loadConfiguration(getBundledFile(file)); } + public YamlConfiguration loadExternalConfig(File file) { + return YamlConfiguration.loadConfiguration( file ); + } + + public YamlConfiguration loadExternalConfig( Reader reader ) { + return YamlConfiguration.loadConfiguration( reader ); + } + public void saveConfig(String fileName, YamlConfiguration config ) { if ( config != null ) { File file = getBundledFile(fileName); 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 c37f9f0c3..e9bb0fcd6 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 @@ -736,8 +736,11 @@ public static List getAllCustomBlockTypes() { * @return */ public static PrisonBlock getPrisonBlock( String blockName ) { + return getPrisonBlock( blockName, null ); + } + public static PrisonBlock getPrisonBlock( String blockName, String displayName ) { - PrisonBlock results = new PrisonBlock( blockName ); + PrisonBlock results = new PrisonBlock( blockName, displayName ); results.setValid( false ); // BlockType bTypeObsolete = null; @@ -766,16 +769,19 @@ public static PrisonBlock getPrisonBlock( String blockName ) { } public static PrisonBlock getPrisonBlock( XMaterial xMat ) { + return getPrisonBlock( xMat, null ); + } + public static PrisonBlock getPrisonBlock( XMaterial xMat, String displayName ) { PrisonBlock results = null; if ( xMat != null ) { - results = new PrisonBlock( xMat.name() ); + results = new PrisonBlock( xMat.name(), displayName ); } if ( results == null ) { - results = getPrisonBlock( xMat.name() ); + results = getPrisonBlock( xMat.name(), displayName ); } return results; 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 d20bf0304..415085e15 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 @@ -140,6 +140,9 @@ public class PrisonMinesBlockBreakEvent private List unprocessedRawBlocks; + private boolean applyToPlayersBlockCount; + + private StringBuilder debugInfo; private boolean forceDebugLogging; @@ -194,6 +197,8 @@ public PrisonMinesBlockBreakEvent( this.forceDebugLogging = false; + this.applyToPlayersBlockCount = true; + } public PrisonMinesBlockBreakEvent( Block theBlock, Player player, @@ -224,6 +229,8 @@ public PrisonMinesBlockBreakEvent( Block theBlock, Player player, this.debugInfo = debugInfo; + this.applyToPlayersBlockCount = true; + } /** @@ -507,6 +514,13 @@ public void setForceIfAirBlock( boolean forceIfAirBlock ) { this.forceIfAirBlock = forceIfAirBlock; } + public boolean isApplyToPlayersBlockCount() { + return applyToPlayersBlockCount; + } + public void setApplyToPlayersBlockCount(boolean applyToPlayersBlockCount) { + this.applyToPlayersBlockCount = applyToPlayersBlockCount; + } + @Override public HandlerList getHandlers() { return handlers; 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 3cb826a75..58d8d426a 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 @@ -51,14 +51,80 @@ *

If you need something special, then please ask on our discord server and we * can probably provide it for you. *

+ * @param * */ -public class PrisonSpigotAPI { +public class PrisonSpigotAPI { private PrisonMines prisonMineManager; private boolean mineModuleDisabled = false; private SellAllUtil sellAll; + + private void junk() { + +// SpigotPrison.getInstance().isSellAllEnabled(); +// +// SpigotPlayer sPlayer = new SpigotPlayer( Player player ); +// +// sPlayer.getSellAllMulitiplier() +// sPlayer.getSellAllMultiplierListings() +// sPlayer.checkAutoSellPermsAutoFeatures() +// sPlayer.checkAutoSellTogglePerms( sbDebug ) +// sPlayer.isAutoSellEnabled( sbDebug ) +// + + // PrisonSpigotAPI.sellPlayerItems(Player player ); + } + +// private void handleAffectedBlocks(Player p, IWrappedRegion region, List blocksAffected) { +// double totalDeposit = 0.0; +// int fortuneLevel = EnchantUtils.getItemFortuneLevel(p.getItemInHand()); +// boolean autoSellPlayerEnabled = this.plugin.isAutoSellModuleEnabled() && plugin.getCore().getAutoSell().getManager().hasAutoSellEnabled(p); +// +// TreeMap itemValues = new TreeMap<>(); +// PrisonSpigotAPI pApi = new PrisonSpigotAPI(); +// +// getItemStackValueTransactions(p, null); +// +// for (Block block : blocksAffected) { +// +// int amplifier = fortuneLevel; +// if (FortuneEnchant.isBlockBlacklisted(block)) { +// amplifier = 1; +// } +// +// String blockNamme = block.getType().name(); +// double value = 0dg; +// +// if ( itemValues.containsKey(blockNamme) ) { +// value = itemValues.get(blockNamme); +// } +// else { +// ItemStack iStk = new ItemStack( block.getType() ); +// if ( iStk != null ) { +// +// value = getItemStackValue(p, iStk); +// if ( value > 0 ) {{ +// itemValues.put(blockNamme, value); +// } +// } +// } +// +// if (autoSellPlayerEnabled && value > 0) { +// totalDeposit += value * amplifier; +// } else { +// ItemStack itemToGive = CompMaterial.fromBlock(block).toItem(amplifier); +// p.getInventory().addItem(itemToGive); +// } +// +// if (this.removeBlocks ) { +// this.plugin.getCore().getNmsProvider().setBlockInNativeDataPalette(block.getWorld(), block.getX(), block.getY(), block.getZ(), 0, (byte) 0, true); +// } +// +// } +// this.giveEconomyRewardsToPlayer(p, totalDeposit); +// } /** *

This returns all mines that are within prison. @@ -480,6 +546,94 @@ public SellAllUtil getPrisonSellAll(){ return sellAll; } + + + /** + *

This will convert a List to Prison's + * List so it can be used with the various SellAll + * functions. + *

+ * + * @param blocks + * @return + */ + public List getPrisonItemmStacks( List blocks ) { + List results = new ArrayList<>(); + TreeMap map = new TreeMap<>(); + + if ( blocks != null ) { + for ( Block b : blocks ) { + if ( b != null ) { + SpigotBlock sBlock = SpigotBlock.getSpigotBlock( b ); + + if ( sBlock != null ) { + + String bName = sBlock.getBlockName(); + + if ( !map.containsKey( bName ) ) { + String[] lore = null; + SpigotItemStack sis = new SpigotItemStack( 1, sBlock, lore ); + + map.put(bName, sis ); + } + else { + map.get(bName).addToAmount( 1 ); + } + } + + } + } + + } + + if ( map.size() > 0 ) { + for ( SpigotItemStack sItemStack : map.values() ) { + results.add( sItemStack ); + } + } + + return results; + } + + public List getItemStacks( List blocks ) { + List results = new ArrayList<>(); + TreeMap map = new TreeMap<>(); + + if ( blocks != null ) { + for ( Block b : blocks ) { + if ( b != null ) { + + String bName = b.getType().name(); + + if ( bName != null ) { + + if ( !map.containsKey( bName ) ) { + + ItemStack iStk = new ItemStack( b.getType() ); + map.put(bName, iStk ); + } + else { + ItemStack iStk = map.get(bName); + + iStk.setAmount( iStk.getAmount() ); + + map.put(bName, iStk); + } + } + + } + } + + } + + if ( map.size() > 0 ) { + for ( ItemStack sItemStack : map.values() ) { + results.add( sItemStack ); + } + } + + return results; + } /** *

Get the money to give to the Player depending on the SellAll multiplier. 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 79da13c74..587cf4839 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 @@ -39,8 +39,6 @@ import tech.mcprison.prison.output.ChatDisplay; import tech.mcprison.prison.output.Output; import tech.mcprison.prison.output.Output.DebugTarget; -import tech.mcprison.prison.ranks.PrisonRanks; -import tech.mcprison.prison.ranks.data.RankPlayer; import tech.mcprison.prison.spigot.SpigotPrison; import tech.mcprison.prison.spigot.SpigotUtil; import tech.mcprison.prison.spigot.api.PrisonMinesBlockBreakEvent; @@ -516,9 +514,19 @@ private int applyAutoEventsDetails( PrisonMinesBlockBreakEvent pmEvent ) { boolean isAutoFeaturesEnabled = isBoolean( AutoFeatures.isAutoFeaturesEnabled ); - boolean permPickup = isAutoFeaturesEnabled && player.isPermissionSet( getMessage( AutoFeatures.permissionAutoPickup )); - boolean permSmelt = isAutoFeaturesEnabled && player.isPermissionSet( getMessage( AutoFeatures.permissionAutoSmelt )); - boolean permBlock = isAutoFeaturesEnabled && player.isPermissionSet( getMessage( AutoFeatures.permissionAutoBlock )); + String permAutoPickup = getMessage( AutoFeatures.permissionAutoPickup ); + String permAutoSmelt = getMessage( AutoFeatures.permissionAutoSmelt ); + String permAutoBlock = getMessage( AutoFeatures.permissionAutoBlock ); + + boolean permPickup = isAutoFeaturesEnabled && + !"disable".equalsIgnoreCase( permAutoPickup ) && + player.isPermissionSet( permAutoPickup ); + boolean permSmelt = isAutoFeaturesEnabled && + !"disable".equalsIgnoreCase( permAutoSmelt ) && + player.isPermissionSet( permAutoSmelt ); + boolean permBlock = isAutoFeaturesEnabled && + !"disable".equalsIgnoreCase( permAutoBlock ) && + player.isPermissionSet( permAutoBlock ); boolean configPickup = isAutoFeaturesEnabled && isBoolean( AutoFeatures.autoPickupEnabled ); @@ -909,6 +917,9 @@ protected int autoPickup( PrisonMinesBlockBreakEvent pmEvent, // SellAllUtil.get().isSellallPlayerUserToggleEnabled( // pmEvent.getSpigotPlayer().getWrapper() )); + + // isAutoSellEnabled should include perms check too: + boolean isPlayerAutosellEnabled = pmEvent.getSpigotPlayer().isAutoSellEnabled( pmEvent.getDebugInfo() ); @@ -931,11 +942,12 @@ protected int autoPickup( PrisonMinesBlockBreakEvent pmEvent, // !"false".equalsIgnoreCase( getMessage( AutoFeatures.permissionAutoSellPerBlockBreakEnabled ) ) && // player.hasPermission( getMessage( AutoFeatures.permissionAutoSellPerBlockBreakEnabled ) ); - boolean autoSellByPerm = pmEvent.getSpigotPlayer().isAutoSellByPermEnabled( isPlayerAutosellEnabled ); +// boolean autoSellByPerm = pmEvent.getSpigotPlayer().isAutoSellByPermEnabled( isPlayerAutosellEnabled, pmEvent.getDebugInfo() ); // Try to autosell if enabled in any of the following ways: - boolean autoSell = ( forceAutoSell || autoSellBySettings || autoSellByPerm ); + boolean autoSell = ( forceAutoSell || autoSellBySettings ); +// boolean autoSell = ( forceAutoSell || autoSellBySettings || autoSellByPerm ); for ( SpigotItemStack itemStack : drops ) { @@ -991,7 +1003,8 @@ protected int autoPickup( PrisonMinesBlockBreakEvent pmEvent, // AutoSell failure... some items may be unsellable due to not being setup in the sellall shop: - if ( forceAutoSell || autoSellBySettings || autoSellByPerm ) { + if ( forceAutoSell || autoSellBySettings ) { +// if ( forceAutoSell || autoSellBySettings || autoSellByPerm ) { // Force debug printing for this entry even if debug mode is turned off: pmEvent.setForceDebugLogging( true ); @@ -1460,9 +1473,10 @@ protected void dropExtra( HashMap extra, boolean isPlayerAutosellEnabled = sPlayer.isAutoSellEnabled( debugInfo ); - boolean isPlayerAutoSellByPerm = sPlayer.isAutoSellByPermEnabled( isPlayerAutosellEnabled ); +// boolean isPlayerAutoSellByPerm = sPlayer.isAutoSellByPermEnabled( isPlayerAutosellEnabled, debugInfo ); - if ( isPlayerAutosellEnabled || isPlayerAutoSellByPerm ) { + if ( isPlayerAutosellEnabled ) { +// if ( isPlayerAutosellEnabled || isPlayerAutoSellByPerm ) { SellAllUtil sellAllUtil = SellAllUtil.get(); @@ -2617,7 +2631,7 @@ else if ( isBoolean( AutoFeatures.isCalculateAltFortuneEnabled ) ) { xMat == XMaterial.MELON_SEEDS || xMat == XMaterial.NETHER_WART || xMat == XMaterial.POTATO || - xMat == XMaterial.GRASS || + xMat == XMaterial.SHORT_GRASS || xMat == XMaterial.WHEAT ) { 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 c5726ea9f..79de1dcb8 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 @@ -516,13 +516,16 @@ else if ( cancelBy == EventListenerCancelBy.drops ) { // isBoolean(AutoFeatures.isAutoSellPerBlockBreakEnabled); - boolean isPlayerAutoSellByPerm = pmEvent.getSpigotPlayer().isAutoSellByPermEnabled( isPlayerAutosellEnabled ); +// boolean isPlayerAutoSellByPerm = pmEvent.getSpigotPlayer().isAutoSellByPermEnabled( +// isPlayerAutosellEnabled, pmEvent.getDebugInfo() ); if ( isBoolean( AutoFeatures.isForceSellAllOnInventoryWhenBukkitBlockBreakEventFires ) && - ( isPlayerAutosellEnabled || isPlayerAutoSellByPerm )) { + isPlayerAutosellEnabled ) { + +// ( isPlayerAutosellEnabled || isPlayerAutoSellByPerm )) { pmEvent.getDebugInfo().append( Output.get().getColorCodeWarning()); pmEvent.performSellAllOnPlayerInventoryLogged( "FORCED BlockBreakEvent sellall"); @@ -530,7 +533,9 @@ else if ( cancelBy == EventListenerCancelBy.drops ) { } if ( isBoolean( AutoFeatures.isEnabledDelayedSellAllOnInventoryWhenBukkitBlockBreakEventFires ) && - ( isPlayerAutosellEnabled || isPlayerAutoSellByPerm ) ) { + isPlayerAutosellEnabled ) { + +// ( isPlayerAutosellEnabled || isPlayerAutoSellByPerm ) ) { if ( !getDelayedSellallPlayers().contains( pmEvent.getSpigotPlayer() ) ) { 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 20680ca16..c429dc195 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 @@ -334,6 +334,10 @@ protected void handleExplosiveBlockBreakEvent( ExplosiveBlockBreakEvent e, // removed, then it's removed within this funciton. removeEventTriggerBlocksFromExplosions( pmEvent ); + + + pmEvent.setApplyToPlayersBlockCount( + e.getMineBomb().isApplyToPlayersBlockCount() ); if ( !validateEvent( pmEvent ) ) { 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 3017e4ec4..30d12655c 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 @@ -33,7 +33,6 @@ import tech.mcprison.prison.spigot.compat.Compatibility; import tech.mcprison.prison.spigot.compat.SpigotCompatibility; 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.util.Text; @@ -420,6 +419,13 @@ protected boolean validateEvent( PrisonMinesBlockBreakEvent pmEvent ) pmEvent.setTargetBlock( targetBlock ); // NOTE: I have no idea why 25 blocks and less should be bypassed for validation: + // Perhaps its because small mines, with 25 or less blocks, just need to be + // processed as quickly as possible? Which could allow breakage even if it + // does not match? + // Later on, bypassMatchedBlocks is used for monitor events when the + // target block is AIR which may mean the block was already removed, so + // ignore the block in the event, and just process it if it was not + // already mined? boolean bypassMatchedBlocks = pmEvent.getMine().getBounds().getTotalBlockCount() <= 25; if ( bypassMatchedBlocks ) { pmEvent.setDebugColorCodeWarning(); @@ -917,15 +923,22 @@ else if ( results && pmEvent.getBbPriority().isMonitor() && mine != null ) { if ( SpigotPrison.getInstance().isSellAllEnabled() ) { - SellAllUtil sellAllUtil = SellAllUtil.get(); +// SellAllUtil sellAllUtil = SellAllUtil.get(); // This will return true (allow autosell) unless players can toggle autosell and they turned it off: // This is to be used with other auto sell setting, but never on it's own: boolean isPlayerAutosellEnabled = - (!sellAllUtil.isAutoSellPerUserToggleable || - sellAllUtil.isSellallPlayerUserToggleEnabled( - pmEvent.getPlayer() )); + pmEvent.getSpigotPlayer().isAutoSellEnabled( pmEvent.getDebugInfo() ); +// (!sellAllUtil.isAutoSellPerUserToggleable || +// sellAllUtil.isSellallPlayerUserToggleEnabled( +// pmEvent.getPlayer() )); + + +// boolean isPlayerAutoSellByPerm = pmEvent.getSpigotPlayer() +// .isAutoSellByPermEnabled( isPlayerAutosellEnabled, pmEvent.getDebugInfo() ); + + // AutoSell on full inventory when using BLOCKEVENTS: @@ -1154,9 +1167,13 @@ private boolean countBlocksMined( PrisonMinesBlockBreakEvent pmEvent, if ( mine.incrementBlockMiningCount( targetBlock ) ) { results = true; - // Now in AutoManagerFeatures.autoPickup and calculateNormalDrop: - PlayerCache.getInstance().addPlayerBlocks( pmEvent.getSpigotPlayer(), - mine.getName(), targetBlock.getPrisonBlock(), 1 ); + + if ( pmEvent.isApplyToPlayersBlockCount() ) { + + // Now in AutoManagerFeatures.autoPickup and calculateNormalDrop: + PlayerCache.getInstance().addPlayerBlocks( pmEvent.getSpigotPlayer(), + mine.getName(), targetBlock.getPrisonBlock(), 1 ); + } } } 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 fa3c32710..a35990cd1 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 @@ -82,7 +82,6 @@ private void setupBukkitStack( org.bukkit.inventory.ItemStack bukkitStack ) { - PrisonBlock type = SpigotUtil.getPrisonBlock( xMat ); // BlockType type = SpigotCompatibility.getInstance() // .getBlockType( bukkitStack ); @@ -98,6 +97,10 @@ private void setupBukkitStack( org.bukkit.inventory.ItemStack bukkitStack ) { // displayName = type.getBlockName().toLowerCase(); // } + + PrisonBlock type = SpigotUtil.getPrisonBlock( xMat, displayName ); + + List lores = new ArrayList<>(); if ( meta.hasLore() ) { @@ -148,6 +151,10 @@ public void setPrisonBlock( PrisonBlock pBlock ) { String displayName = pBlock.getBlockName(); + if ( pBlock.getDisplayName() != null ) { + displayName = pBlock.getDisplayName(); + } + setDisplayName( displayName ); setMaterial( pBlock ); @@ -258,6 +265,15 @@ public void setNBTString( String key, String value ) { // } } + + + public String getNBTItemStackInfo() { + + String results = PrisonNBTUtil.nbtDebugString(getBukkitStack()) ; + + return results; + } + // public int getNBTInt( String key ) { // int results = -1; // @@ -342,6 +358,18 @@ public void setAmount( int amount ) { } } + /** + *

This function will add the given amount to the item stack's total amount. + *

+ * + * @param i amount to add to this itemStack + */ + public void addToAmount( int i ) { + int amt = getAmount() + i; + setAmount( amt ); + } + + private ItemMeta getMeta() { ItemMeta meta; if (!bukkitStack.hasItemMeta()) { @@ -461,6 +489,19 @@ public static SpigotItemStack deserialize( Map map ) return sItemStack; } + + public Map getEnchantments() { + Map results = null; + + ItemMeta meta = getMeta(); + if ( meta != null && + meta.getEnchants() != null && + meta.getEnchants().size() > 0 ) { + + results = meta.getEnchants(); + } + return results; + } /** *

This function will return information on the item in the item stack, which is for diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/commands/PrisonSpigotGUIBackPackCommands.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/commands/PrisonSpigotGUIBackPackCommands.java index b301ba73e..8c8f3a7d8 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/commands/PrisonSpigotGUIBackPackCommands.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/commands/PrisonSpigotGUIBackPackCommands.java @@ -40,7 +40,10 @@ private void backpackGUIOpenCommand(CommandSender sender, } if (getBoolean(BackpacksUtil.get().getBackpacksConfig().getString("Options.BackPack_Use_Permission_Enabled")) && !p.hasPermission(BackpacksUtil.get().getBackpacksConfig().getString("Options.BackPack_Use_Permission"))){ - Output.get().sendWarn(sender, SpigotPrison.format(messages.getString(MessagesConfig.StringID.spigot_message_missing_permission) + " [" + BackpacksUtil.get().getBackpacksConfig().getString("Options.BackPack_Use_Permission") + "]")); + Output.get().sendWarn(sender, SpigotPrison.format( + messages.getString(MessagesConfig.StringID.spigot_message_missing_permission) +// + " [" + BackpacksUtil.get().getBackpacksConfig().getString("Options.BackPack_Use_Permission") + "]" + )); return; } @@ -71,7 +74,10 @@ private void backpackListGUICommand(CommandSender sender){ // New method. if (getBoolean(BackpacksUtil.get().getBackpacksConfig().getString("Options.Multiple-BackPacks-For-Player-Enabled"))){ if (getBoolean(BackpacksUtil.get().getBackpacksConfig().getString("Options.BackPack_Use_Permission_Enabled")) && !p.hasPermission(BackpacksUtil.get().getBackpacksConfig().getString("Options.BackPack_Use_Permission"))){ - Output.get().sendWarn(sender, SpigotPrison.format(messages.getString(MessagesConfig.StringID.spigot_message_missing_permission) + " [" + BackpacksUtil.get().getBackpacksConfig().getString("Options.BackPack_Use_Permission") + "]")); + Output.get().sendWarn(sender, SpigotPrison.format( + messages.getString(MessagesConfig.StringID.spigot_message_missing_permission) +// + " [" + BackpacksUtil.get().getBackpacksConfig().getString("Options.BackPack_Use_Permission") + "]" + )); return; } BackpacksListPlayerGUI gui = new BackpacksListPlayerGUI(p); 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 2481f67dc..c93825121 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 @@ -86,8 +86,10 @@ protected void cmdPrisonManagerPrestiges( CommandSender sender, int page, String String perm = getConfig( "Options.Prestiges.Permission_GUI"); if ( !sender.hasPermission( perm ) ){ - Output.get().sendInfo(sender, SpigotPrison.format(messages.getString(MessagesConfig.StringID.spigot_message_missing_permission) + " [" + - perm + "]")); + Output.get().sendInfo(sender, SpigotPrison.format( + messages.getString(MessagesConfig.StringID.spigot_message_missing_permission) +// + " [" + perm + "]" + )); return; } } @@ -142,8 +144,10 @@ protected void cmdPrisonManagerMines( CommandSender sender, int page, String cmd String perm = getConfig( "Options.Mines.Permission_GUI"); if ( !sender.hasPermission( perm ) ){ - Output.get().sendInfo(sender, SpigotPrison.format( getMessages().getString(MessagesConfig.StringID.spigot_message_missing_permission) + " [" + - perm + "]")); + Output.get().sendInfo(sender, SpigotPrison.format( + getMessages().getString(MessagesConfig.StringID.spigot_message_missing_permission) +// + " [" + perm + "]" + )); return; } } @@ -225,8 +229,10 @@ protected void cmdPrisonManagerRanks(CommandSender sender, int page, String cmdP String perm = getConfig( "Options.Ranks.Permission_GUI"); if (!sender.hasPermission(perm)) { - Output.get().sendInfo(sender, SpigotPrison.format( getMessages().getString(MessagesConfig.StringID.spigot_message_missing_permission) + " [" + - perm + "]")); + Output.get().sendInfo(sender, SpigotPrison.format( + getMessages().getString(MessagesConfig.StringID.spigot_message_missing_permission) +// + " [" + perm + "]" + )); return; } } @@ -345,8 +351,10 @@ protected void cmdPrisonManagerLadders(CommandSender sender, int page, String cm String perm = getConfig( "Options.Ranks.Permission_GUI"); if (!sender.hasPermission(perm)) { - Output.get().sendInfo(sender, SpigotPrison.format( getMessages().getString(MessagesConfig.StringID.spigot_message_missing_permission) + " [" + - perm + "]")); + Output.get().sendInfo(sender, SpigotPrison.format( + getMessages().getString(MessagesConfig.StringID.spigot_message_missing_permission) +// + " [" + perm + "]" + )); return; } } 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 cb5c734cc..1ae5e8dbb 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 @@ -1,11 +1,14 @@ package tech.mcprison.prison.spigot.commands; +import java.lang.reflect.Method; import java.text.DecimalFormat; import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.TreeMap; +import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; @@ -30,6 +33,7 @@ import tech.mcprison.prison.spigot.compat.Compatibility; import tech.mcprison.prison.spigot.configs.MessagesConfig; import tech.mcprison.prison.spigot.game.SpigotPlayer; +import tech.mcprison.prison.spigot.game.SpigotPlayerUtil; import tech.mcprison.prison.spigot.sellall.SellAllBlockData; import tech.mcprison.prison.spigot.sellall.SellAllUtil; import tech.mcprison.prison.spigot.utils.tasks.PlayerAutoRankupTask; @@ -47,7 +51,7 @@ public class PrisonSpigotSellAllCommands extends PrisonSpigotBaseCommands { /** * Check if SellAll's enabled. * */ - public static boolean isEnabled(){ + public static boolean isEnabled() { return SpigotPrison.getInstance().isSellAllEnabled(); } @@ -59,9 +63,6 @@ public static PrisonSpigotSellAllCommands get() { if (instance == null && isEnabled()) { instance = new PrisonSpigotSellAllCommands(); } - if (instance == null){ - return null; - } return instance; } @@ -92,7 +93,9 @@ private void sellAllCurrency(CommandSender sender, onlyPlayers = false) private void sellAllCommands(CommandSender sender) { - if (!isEnabled()) return; + if ( !isEnabled() ) { + return; + } if (sender.hasPermission("prison.admin")) { sender.dispatchCommand("sellall help"); @@ -115,7 +118,7 @@ private void sellAllDelay(CommandSender sender, description = "True to enable or false to disable.", def = "false") String enable){ - if (!isEnabled() || !SpigotPrison.getInstance().isSellAllEnabled() ){ + if ( !isEnabled() ){ return; } SellAllUtil sellAllUtil = SellAllUtil.get(); @@ -153,7 +156,7 @@ private void sellAllDelaySet(CommandSender sender, @Arg(name = "delay", description = "Set delay value in seconds. Defaults to a value of 15 seconds.", def = "15") String delay){ - if ( !isEnabled() || !SpigotPrison.getInstance().isSellAllEnabled() ){ + if ( !isEnabled() ) { return; } SellAllUtil sellAllUtil = SellAllUtil.get(); @@ -182,7 +185,7 @@ private void sellAllAutoSell(CommandSender sender, + "[true false perUserToggleable]", def = "true") String enable){ - if ( !isEnabled() || !SpigotPrison.getInstance().isSellAllEnabled() ){ + if ( !isEnabled() ){ return; } SellAllUtil sellAllUtil = SellAllUtil.get(); @@ -229,7 +232,7 @@ private void sellAllAutoSellPerUserToggleable(CommandSender sender, description = "'True' to enable or 'false' to disable. [true false]", def = "") String enable){ - if (!isEnabled() || !SpigotPrison.getInstance().isSellAllEnabled() ){ + if (!isEnabled() ){ return; } SellAllUtil sellAllUtil = SellAllUtil.get(); @@ -266,7 +269,9 @@ public void sellAllSellCommand(CommandSender sender, description = "Notification behavior for the sellall transaction. Defaults to normal. " + "'silent' suppresses all notifications. [silent]") String notification ){ - if (!isEnabled()) return; + if ( !isEnabled() ) { + return; + } Player p = getSpigotPlayer(sender); @@ -320,7 +325,10 @@ else if (p == null){ if (sellAllUtil.isSellAllSellPermissionEnabled){ String permission = sellAllUtil.permissionSellAllSell; if (permission == null || !p.hasPermission(permission)){ - Output.get().sendWarn(new SpigotPlayer(p), messages.getString(MessagesConfig.StringID.spigot_message_missing_permission) + " [" + permission + "]"); + Output.get().sendWarn(new SpigotPlayer(p), + messages.getString(MessagesConfig.StringID.spigot_message_missing_permission) +// + " [" + permission + "]" + ); return; } } @@ -338,7 +346,7 @@ else if (p == null){ onlyPlayers = true) public void sellAllSellHandCommand(CommandSender sender){ - if (!isEnabled() || !SpigotPrison.getInstance().isSellAllEnabled() ){ + if ( !isEnabled() ){ return; } SellAllUtil sellAllUtil = SellAllUtil.get(); @@ -360,7 +368,10 @@ public void sellAllSellHandCommand(CommandSender sender){ if (sellAllUtil.isSellAllSellPermissionEnabled){ String permission = sellAllUtil.permissionSellAllSell; if (permission == null || !p.hasPermission(permission)){ - Output.get().sendWarn(new SpigotPlayer(p), messages.getString(MessagesConfig.StringID.spigot_message_missing_permission) + " [" + permission + "]"); + Output.get().sendWarn(new SpigotPlayer(p), + messages.getString(MessagesConfig.StringID.spigot_message_missing_permission) +// + " [" + permission + "]" + ); return; } } @@ -377,7 +388,7 @@ public void sellAllSellHandCommand(CommandSender sender){ } public void sellAllSell(Player p){ - if ( !isEnabled() || !SpigotPrison.getInstance().isSellAllEnabled() ){ + if ( !isEnabled() ){ return; } SellAllUtil sellAllUtil = SellAllUtil.get(); @@ -393,7 +404,10 @@ public void sellAllSell(Player p){ if (sellAllUtil.isSellAllSellPermissionEnabled){ String permission = sellAllUtil.permissionSellAllSell; if (permission == null || !p.hasPermission(permission)){ - Output.get().sendWarn(new SpigotPlayer(p), messages.getString(MessagesConfig.StringID.spigot_message_missing_permission) + " [" + permission + "]"); + Output.get().sendWarn(new SpigotPlayer(p), + messages.getString(MessagesConfig.StringID.spigot_message_missing_permission) +// + " [" + permission + "]" + ); return; } } @@ -416,7 +430,7 @@ public void sellAllValueOfCommand(CommandSender sender, "Only console or prison commands can include this parameter") String playerName ){ - if (!isEnabled() || !SpigotPrison.getInstance().isSellAllEnabled() ){ + if ( !isEnabled() ) { return; } SellAllUtil sellAllUtil = SellAllUtil.get(); @@ -468,7 +482,10 @@ else if (p == null){ if (sellAllUtil.isSellAllSellPermissionEnabled){ String permission = sellAllUtil.permissionSellAllSell; if (permission == null || !p.hasPermission(permission)){ - Output.get().sendWarn(new SpigotPlayer(p), messages.getString(MessagesConfig.StringID.spigot_message_missing_permission) + " [" + permission + "]"); + Output.get().sendWarn(new SpigotPlayer(p), + messages.getString(MessagesConfig.StringID.spigot_message_missing_permission) +// + " [" + permission + "]" + ); return; } } @@ -488,7 +505,7 @@ else if (p == null){ onlyPlayers = true) public void sellAllValueOfHandCommand(CommandSender sender){ - if (!isEnabled() || !SpigotPrison.getInstance().isSellAllEnabled() ){ + if ( !isEnabled() ){ return; } SellAllUtil sellAllUtil = SellAllUtil.get(); @@ -510,7 +527,10 @@ public void sellAllValueOfHandCommand(CommandSender sender){ if (sellAllUtil.isSellAllSellPermissionEnabled){ String permission = sellAllUtil.permissionSellAllSell; if (permission == null || !p.hasPermission(permission)){ - Output.get().sendWarn(new SpigotPlayer(p), messages.getString(MessagesConfig.StringID.spigot_message_missing_permission) + " [" + permission + "]"); + Output.get().sendWarn(new SpigotPlayer(p), + messages.getString(MessagesConfig.StringID.spigot_message_missing_permission) +// + " [" + permission + "]" + ); return; } } @@ -532,7 +552,7 @@ public void sellAllValueOfHandCommand(CommandSender sender){ onlyPlayers = true) public void sellAllSellWithDelayCommand(CommandSender sender){ - if ( !isEnabled() || !SpigotPrison.getInstance().isSellAllEnabled() ){ + if ( !isEnabled() ) { return; } SellAllUtil sellAllUtil = SellAllUtil.get(); @@ -550,7 +570,10 @@ public void sellAllSellWithDelayCommand(CommandSender sender){ if (sellAllUtil.isSellAllSellPermissionEnabled){ String permission = sellAllUtil.permissionSellAllSell; if (permission == null || !p.hasPermission(permission)){ - Output.get().sendWarn(new SpigotPlayer(p), messages.getString(MessagesConfig.StringID.spigot_message_missing_permission) + " [" + permission + "]"); + Output.get().sendWarn(new SpigotPlayer(p), + messages.getString(MessagesConfig.StringID.spigot_message_missing_permission) +// + " [" + permission + "]" + ); return; } } @@ -576,12 +599,16 @@ public void sellAllSellWithDelayCommand(CommandSender sender){ altPermissions = "prison.sellall.toggle", onlyPlayers = true) private void sellAllAutoEnableUser(CommandSender sender){ - if (!isEnabled() || !SpigotPrison.getInstance().isSellAllEnabled() ){ + if ( !isEnabled() ) { return; } + StringBuilder debugInfo = new StringBuilder(); + debugInfo.append( "[sellall autoSellToggle] " ); + SellAllUtil sellAllUtil = SellAllUtil.get(); Player p = getSpigotPlayer(sender); + SpigotPlayer sPlayer = new SpigotPlayer(p); // Sender must be a Player, not something else like the Console. if (p == null) { @@ -596,20 +623,35 @@ private void sellAllAutoEnableUser(CommandSender sender){ return; } - String permission = sellAllUtil.permissionAutoSellPerUserToggleable; - if (sellAllUtil.isAutoSellPerUserToggleablePermEnabled && (permission != null && !p.hasPermission(permission))){ - Output.get().sendWarn(sender, messages.getString(MessagesConfig.StringID.spigot_message_missing_permission) + " [" + permission + "]"); + boolean hasAutosellPerms = sPlayer.checkAutoSellTogglePerms( debugInfo ); + +// String permission = sellAllUtil.permissionAutoSellPerUserToggleable; + if ( sellAllUtil.isAutoSellPerUserToggleablePermEnabled && !hasAutosellPerms ) { +// if (sellAllUtil.isAutoSellPerUserToggleablePermEnabled && (permission != null && !p.hasPermission(permission))){ + Output.get().sendWarn(sender, + messages.getString(MessagesConfig.StringID.spigot_message_missing_permission) +// + " [" + permission + "]" + ); return; } - boolean isplayerAutosellEnabled = sellAllUtil.isPlayerAutoSellEnabled(p); - if (sellAllUtil.setAutoSellPlayer(p, !isplayerAutosellEnabled)){ - if ( !isplayerAutosellEnabled ){ // Note this variable was negated then saved, so we need to check the negative: - Output.get().sendInfo(new SpigotPlayer(p), messages.getString(MessagesConfig.StringID.spigot_message_sellall_auto_disabled)); - } else { - Output.get().sendInfo(new SpigotPlayer(p), messages.getString(MessagesConfig.StringID.spigot_message_sellall_auto_enabled)); + boolean isplayerAutosellEnabled = sellAllUtil.isSellallPlayerUserToggleEnabled(p); + if (sellAllUtil.setAutoSellPlayer(p, !isplayerAutosellEnabled)) { + if ( isplayerAutosellEnabled ){ + String msg = messages.getString(MessagesConfig.StringID.spigot_message_sellall_auto_disabled); + + Output.get().sendInfo( sPlayer, msg ); + } + else { + String msg = messages.getString(MessagesConfig.StringID.spigot_message_sellall_auto_enabled); + + Output.get().sendInfo( sPlayer, msg ); } } + + if ( Output.get().isDebug() ) { + Output.get().logInfo( debugInfo.toString() ); + } } // // @Command(identifier = "sellall gui", @@ -682,7 +724,7 @@ private void sellAllAddCommand(CommandSender sender, description = "The Item_ID or block to add to the sellAll Shop.") String itemID, @Arg(name = "Value", description = "The value of the item.") Double value){ - if (!isEnabled() || !SpigotPrison.getInstance().isSellAllEnabled() ){ + if ( !isEnabled() ){ return; } SellAllUtil sellAllUtil = SellAllUtil.get(); @@ -756,7 +798,7 @@ public void sellAllAddCommand(XMaterial blockAdd, Double value){ private void sellAllDeleteCommand(CommandSender sender, @Arg(name = "Item_ID", description = "The Item_ID you want to remove.") String itemID){ - if ( !isEnabled() || !SpigotPrison.getInstance().isSellAllEnabled() ){ + if ( !isEnabled() ) { return; } SellAllUtil sellAllUtil = SellAllUtil.get(); @@ -787,7 +829,7 @@ private void sellAllEditCommand(CommandSender sender, @Arg(name = "Item_ID", description = "The Item_ID or block to add to the sellAll Shop.") String itemID, @Arg(name = "Value", description = "The value of the item.") Double value){ - if ( !isEnabled() || !SpigotPrison.getInstance().isSellAllEnabled() ){ + if ( !isEnabled() ) { return; } SellAllUtil sellAllUtil = SellAllUtil.get(); @@ -828,6 +870,208 @@ private void sellAllEditCommand(CommandSender sender, } + @Command(identifier = "sellall items allowLore", + description = "Edits an existing SellAll shop item to either allow the sellable items " + + "to have lore or not. If an item is not allowed to have lore, but the itemm " + + "that is intended to be sold has lore, then the item will not be sellable..", + permissions = "prison.admin", onlyPlayers = false) + private void sellAllAllowLoreCommand(CommandSender sender, + @Arg(name = "Item_ID", description = "The Item_ID or block to add to the sellAll Shop.") String itemID, + @Arg(name = "allowLore", description = "Allow lore to be used. " + + "Default: 'false'. [true, allow, false] Invalid values are treated as 'false'.", + def = "false") + String isLoreAllowed ){ + + if ( !isEnabled() ) { + return; + } + SellAllUtil sellAllUtil = SellAllUtil.get(); + + if (itemID == null){ + Output.get().sendWarn(sender, messages.getString(MessagesConfig.StringID.spigot_message_sellall_item_missing_name)); + return; + } + itemID = itemID.toUpperCase(); + + + if (sellAllUtil.sellAllConfig.getConfigurationSection("Items." + itemID) == null){ + Output.get().sendWarn(sender, itemID + " " + messages.getString(MessagesConfig.StringID.spigot_message_sellall_item_not_found)); + return; + } + + boolean allowLore = false; + + if ( isLoreAllowed != null && + ("true".equalsIgnoreCase(isLoreAllowed) || "allow".equalsIgnoreCase(isLoreAllowed)) ) { + allowLore = true; + } + + +// sender.sendMessage("not yet enabled"); +// return; + + try { + XMaterial blockAdd; + try { + blockAdd = XMaterial.valueOf(itemID); + } catch (IllegalArgumentException ex){ + Output.get().sendError(sender, messages.getString(MessagesConfig.StringID.spigot_message_sellall_item_id_not_found) + " [" + itemID + "]"); + return; + } + + if (sellAllUtil.editAllowLore(blockAdd, allowLore )) { + + Output.get().sendInfo(sender, "&3ITEM [" + itemID + ", allowLore= " + allowLore + "] " + messages.getString(MessagesConfig.StringID.spigot_message_sellall_item_edit_success)); + } + + } catch (IllegalArgumentException ex){ + Output.get().sendError(sender, messages.getString(MessagesConfig.StringID.spigot_message_sellall_item_id_not_found) + " [" + itemID + "]"); + } + } + + + + @Command(identifier = "sellall items inspect", + description = "Inspects what the player is holding and provides a dump of all related " + + "information.", + permissions = "prison.admin", onlyPlayers = false) + private void sellAllItemInspectCommand(CommandSender sender) { + + if ( !isEnabled() ) { + return; + } + SellAllUtil sellAllUtil = SellAllUtil.get(); + + + SpigotPlayer sPlayer = (SpigotPlayer) sender.getPlatformPlayer(); + + if ( sPlayer == null ) { + String msg = String.format( + "Only online players can see what they're holding." + ); + sender.sendMessage(msg); + } + else { + + SpigotPlayerUtil sUtil = new SpigotPlayerUtil( sPlayer ); + + SpigotItemStack iStack = sUtil.getItemInHand(); + + if ( iStack == null || iStack.isAir() ) { + + String msg = String.format( + "Nothing to report. You're not holding anything other than air." + ); + sender.sendMessage(msg); + } + else { + + + ChatDisplay chatDisplay = new ChatDisplay("&bSellall Items inspect: " ); + + List msg = new ArrayList<>(); + + String name = iStack.getName(); + String nameFull = iStack.getDisplayName() == null ? "" : iStack.getDisplayName(); + + PrisonBlock pBlock = iStack.getMaterial(); + + int amount = iStack.getAmount(); + + List lore = iStack.getLore(); + Map enchants = iStack.getEnchantments(); + + String nbtInfo = iStack.getNBTItemStackInfo(); + + + chatDisplay.addText( "Item: %-14s (%s)", name, nameFull ); + chatDisplay.addText( "Qty: %5s PrisonItem: %s", + Integer.toString(amount), pBlock.getBlockNameFormal() ); + + if ( lore.size() == 0 ) { + + chatDisplay.addText( "No Lore." ); + } + else { + chatDisplay.addText( "Lore:" ); + + for (String l : lore) { + chatDisplay.addText( " %s", l ); + } + } + + if ( enchants == null || enchants.size() == 0 ) { + + chatDisplay.addText( "No Enchantments." ); + } + else { + chatDisplay.addText( "Enchantments:" ); + + Set keys = enchants.keySet(); + for (Enchantment ench : keys ) { + + Integer value = enchants.get( ench ); + + String namespace = ""; + String targetName = ""; + + try { + + // NOTE: This is for spigot 1.13.x and higher: + if ( ench.getClass().getMethod( "getKey" ) != null ) { + namespace = ench.getKey() == null ? + "---" : + ench.getKey().toString(); + } + else if ( ench.getClass().getMethod( "getName" ) != null ) { + // Versions of spigot prior to 1.13.x: + namespace = ench.getName(); + + } + + + if ( ench.getClass().getMethod( "getItemTarget" ) != null && + ench.getItemTarget() != null ) { + targetName = ench.getItemTarget().name(); + } + + } catch (Exception e) { + } + + if ( namespace == null || namespace.trim().length() == 0 ) { + namespace = ench.toString(); + } + + chatDisplay.addText( " %-10s %s %s (%s - %s)", + //ench.toString(), + namespace, + targetName, + + value.toString(), + Integer.toString( ench.getStartLevel()), + Integer.toString( ench.getMaxLevel()) + ); + } + + + } + + if ( nbtInfo == null || nbtInfo.trim().length() == 0 ) { + + chatDisplay.addText( " No NBT." ); + } + else { + + chatDisplay.addText( " %s", nbtInfo ); + } +// chatDisplay.addText( " ", ); + + chatDisplay.send( sender );; + } + + } + } + @Command(identifier = "sellall multiplier list", description = "Lists all of the SellAll Rank multipliers", permissions = "prison.admin", onlyPlayers = false) @@ -839,7 +1083,7 @@ private void sellAllMultiplierCommand(CommandSender sender, + "columns in the output by using 'cols=16', where the default is 10 columns. ") String options ) { - if ( !isEnabled() || !SpigotPrison.getInstance().isSellAllEnabled() ){ + if ( !isEnabled() ) { return; } SellAllUtil sellAllUtil = SellAllUtil.get(); @@ -1047,7 +1291,7 @@ private void sellAllAddMultiplierCommand(CommandSender sender, @Arg(name = "rank", description = "The rank name for the multiplier.") String rank, @Arg(name = "multiplier", description = "Multiplier value.") Double multiplier) { - if (!isEnabled() || !SpigotPrison.getInstance().isSellAllEnabled() ){ + if (!isEnabled() ) { return; } SellAllUtil sellAllUtil = SellAllUtil.get(); @@ -1071,7 +1315,7 @@ private void sellAllAddMultiplierCommand(CommandSender sender, private void sellAllDeleteMultiplierCommand(CommandSender sender, @Arg(name = "Rank", description = "The rank name of the multiplier.") String rank){ - if ( !isEnabled() || !SpigotPrison.getInstance().isSellAllEnabled() ){ + if ( !isEnabled() ) { return; } SellAllUtil sellAllUtil = SellAllUtil.get(); @@ -1109,7 +1353,7 @@ private void sellAllMultiplierDeleteLadderCommand( ) { - if ( !isEnabled() || !SpigotPrison.getInstance().isSellAllEnabled() ){ + if ( !isEnabled() ) { return; } SellAllUtil sellAllUtil = SellAllUtil.get(); @@ -1181,7 +1425,7 @@ private void sellAllMultiplierAddLadderCommand( ) { - if ( !isEnabled() || !SpigotPrison.getInstance().isSellAllEnabled() ){ + if ( !isEnabled() ) { return; } SellAllUtil sellAllUtil = SellAllUtil.get(); @@ -1249,7 +1493,7 @@ private void sellAllMultiplierAddLadderCommand( private void sellAllToolsTriggerToggle(CommandSender sender, @Arg(name = "Boolean", description = "Enable or disable", def = "true") String enable){ - if (!isEnabled() || !SpigotPrison.getInstance().isSellAllEnabled() ){ + if (!isEnabled() ) { return; } SellAllUtil sellAllUtil = SellAllUtil.get(); @@ -1292,7 +1536,7 @@ private void sellAllToolsTriggerToggle(CommandSender sender, private void sellAllTriggerAdd(CommandSender sender, @Arg(name = "Item", description = "Item name") String itemID){ - if (!isEnabled() || !SpigotPrison.getInstance().isSellAllEnabled() ){ + if (!isEnabled() ) { return; } SellAllUtil sellAllUtil = SellAllUtil.get(); @@ -1331,7 +1575,7 @@ private void sellAllTriggerAdd(CommandSender sender, private void sellAllTriggerDelete(CommandSender sender, @Arg(name = "Item", description = "Item name") String itemID){ - if (!isEnabled() || !SpigotPrison.getInstance().isSellAllEnabled() ){ + if ( !isEnabled() ) { return; } SellAllUtil sellAllUtil = SellAllUtil.get(); @@ -1369,7 +1613,9 @@ private void sellAllTriggerDelete(CommandSender sender, permissions = "prison.admin", onlyPlayers = false) private void sellAllSetDefaultCommand(CommandSender sender){ - if (!isEnabled()) return; + if ( !isEnabled() ) { + return; + } // Setup all the prices in sellall: SpigotPlatform platform = (SpigotPlatform) Prison.get().getPlatform(); @@ -1387,7 +1633,7 @@ private void sellAllSetDefaultCommand(CommandSender sender){ permissions = "prison.admin", onlyPlayers = false) private void sellAllListItems( CommandSender sender ) { - if ( !isEnabled() || !SpigotPrison.getInstance().isSellAllEnabled() ){ + if ( !isEnabled() ) { return; } SellAllUtil sellAllUtil = SellAllUtil.get(); diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/compat/Compatibility.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/compat/Compatibility.java index 2740820fd..ce342617a 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/compat/Compatibility.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/compat/Compatibility.java @@ -21,6 +21,7 @@ import org.bukkit.Location; import org.bukkit.Sound; import org.bukkit.entity.Player; +import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.PlayerInventory; @@ -39,6 +40,8 @@ public interface Compatibility public EquipmentSlot getHand(PlayerInteractEvent e); + + public EquipmentSlot getHand(BlockPlaceEvent e); public ItemStack getItemInMainHand(PlayerInteractEvent e); diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/compat/Spigot_1_13.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/compat/Spigot_1_13.java index 86c3642a8..c14d3a370 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/compat/Spigot_1_13.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/compat/Spigot_1_13.java @@ -4,6 +4,7 @@ import org.bukkit.Location; import org.bukkit.Sound; import org.bukkit.entity.Player; +import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.PlayerInventory; @@ -25,6 +26,15 @@ public EquipmentSlot getHand(PlayerInteractEvent e) { } } + @Override + public EquipmentSlot getHand(BlockPlaceEvent e) { + if (e.getHand() == null) { + return null; + } else { + return EquipmentSlot.valueOf(e.getHand().name()); + } + } + @Override public ItemStack getItemInMainHand(PlayerInteractEvent e) { return getItemInMainHand( e.getPlayer() ); diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/compat/Spigot_1_8.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/compat/Spigot_1_8.java index ec7cffb74..67fb01c47 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/compat/Spigot_1_8.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/compat/Spigot_1_8.java @@ -22,6 +22,7 @@ import org.bukkit.Location; import org.bukkit.Sound; import org.bukkit.entity.Player; +import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.PlayerInventory; @@ -43,6 +44,11 @@ public class Spigot_1_8 public EquipmentSlot getHand(PlayerInteractEvent e) { return EquipmentSlot.HAND; // Spigot 1.8 only has one hand } + + @Override + public EquipmentSlot getHand(BlockPlaceEvent e) { + return EquipmentSlot.HAND; // Spigot 1.8 only has one hand + } @Override public ItemStack getItemInMainHand(PlayerInteractEvent e) { diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/compat/Spigot_1_9.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/compat/Spigot_1_9.java index b6fb32c73..7f005893f 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/compat/Spigot_1_9.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/compat/Spigot_1_9.java @@ -22,6 +22,7 @@ import org.bukkit.Location; import org.bukkit.Sound; import org.bukkit.entity.Player; +import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.PlayerInventory; @@ -48,6 +49,15 @@ public EquipmentSlot getHand(PlayerInteractEvent e) { } } + @Override + public EquipmentSlot getHand(BlockPlaceEvent e) { + if (e.getHand() == null) { + return null; + } else { + return EquipmentSlot.valueOf(e.getHand().name()); + } + } + @Override public ItemStack getItemInMainHand(PlayerInteractEvent e) { return getItemInMainHand( e.getPlayer() ); 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 bdf924b1b..9e95e5d6f 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 @@ -204,9 +204,15 @@ public void initialize() { map.put("NoMineAccess", XMaterial.REDSTONE_BLOCK.name() ); - for ( Mine mine : PrisonMines.getInstance().getMineManager().getMines() ) { - if ( mine.getPrisonBlocks().size() > 0 ) { - map.put( mine.getName(), mine.getPrisonBlocks().get(0).getBlockName() ); + + if ( PrisonMines.getInstance().getMineManager() != null && + PrisonMines.getInstance().getMineManager().getMines() != null && + PrisonMines.getInstance().getMineManager().getMines().size() > 0 ) { + + for ( Mine mine : PrisonMines.getInstance().getMineManager().getMines() ) { + if ( mine.getPrisonBlocks().size() > 0 ) { + map.put( mine.getName(), mine.getPrisonBlocks().get(0).getBlockName() ); + } } } @@ -232,12 +238,17 @@ else if ( conf.get( "Options.Mines.MaterialType.NoMineAccess" ) == null ) { map.put("NoRankAccess", XMaterial.REDSTONE_BLOCK.name() ); - // Example to preset all ranks: Only do the first 10: - int count = 0; - for ( Rank rank : PrisonRanks.getInstance().getRankManager().getRanks() ) { - map.put( rank.getName(), XMaterial.TRIPWIRE_HOOK.name() ); - if ( ++count >= 10 ) { - break; + if ( PrisonRanks.getInstance().getRankManager() != null && + PrisonRanks.getInstance().getRankManager().getRanks() != null && + PrisonRanks.getInstance().getRankManager().getRanks().size() > 0 ) { + + // Example to preset all ranks: Only do the first 10: + int count = 0; + for ( Rank rank : PrisonRanks.getInstance().getRankManager().getRanks() ) { + map.put( rank.getName(), XMaterial.TRIPWIRE_HOOK.name() ); + if ( ++count >= 10 ) { + break; + } } } @@ -265,8 +276,11 @@ else if ( conf.get( "Options.Ranks.MaterialType.NoMineAccess" ) == null ) { if ( conf.get( "Options.Mines.GuiItemNames" ) == null ) { - if ( PrisonMines.getInstance() != null ) { - + if ( PrisonMines.getInstance() != null && + PrisonMines.getInstance().getMineManager() != null && + PrisonMines.getInstance().getMineManager().getMines() != null && + PrisonMines.getInstance().getMineManager().getMines().size() > 0 ) { + LinkedHashMap map = new LinkedHashMap<>(); // Example to preset all mines: Only do the first 10: @@ -293,7 +307,10 @@ else if ( conf.get( "Options.Ranks.MaterialType.NoMineAccess" ) == null ) { } if ( conf.get( "Options.Ranks.GuiItemNames" ) == null ) { - if ( PrisonRanks.getInstance() != null ) { + if ( PrisonRanks.getInstance() != null && + PrisonRanks.getInstance().getRankManager() != null && + PrisonRanks.getInstance().getRankManager().getRanks() != null && + PrisonRanks.getInstance().getRankManager().getRanks().size() > 0 ) { LinkedHashMap map = new LinkedHashMap<>(); 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 b1cf349d8..f3392f4f4 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 @@ -39,7 +39,13 @@ class EssEconomyWrapper { double getBalance(Player player) { try { - return Economy.getMoneyExact(player.getName()).doubleValue(); + if ( Economy.playerExists( player.getName() ) ) { + return Economy.getMoneyExact(player.getName()).doubleValue(); + } + + player.sendMessage( "You don't exist in the economy plugin." ); + return 0; + } catch (UserDoesNotExistException e) { player.sendMessage("You don't exist in the economy plugin."); return 0.0; @@ -48,7 +54,14 @@ class EssEconomyWrapper { void setBalance(Player player, double amount) { try { - Economy.setMoney(player.getName(), new BigDecimal(amount)); + if ( Economy.playerExists( player.getName() ) ) { + Economy.setMoney(player.getName(), new BigDecimal(amount)); + } + else { + + player.sendMessage( "You don't exist in the economy plugin." ); + } + } catch (UserDoesNotExistException | NoLoanPermittedException e) { player.sendMessage("You don't exist in the economy plugin."); } diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/economies/SaneEconomyWrapper.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/economies/SaneEconomyWrapper.java index cee34711a..c4dd89504 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/economies/SaneEconomyWrapper.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/economies/SaneEconomyWrapper.java @@ -27,7 +27,15 @@ public double getBalance(Player player) { double result = 0; try { - result = economyManager.getBalance(toEconomablePlayer(player)); + EconomablePlayer p = toEconomablePlayer(player); + + if ( !economyManager.accountExists( p ) ) { + player.sendMessage( "Economy Error: You don't have an account."); + } + else { + + result = economyManager.getBalance( p ); + } } catch ( Exception e ) { Output.get().logError( "Failed to get SaneEconomy balance. " + @@ -39,7 +47,16 @@ public double getBalance(Player player) { public void setBalance(Player player, double amount) { try { - economyManager.setBalance(toEconomablePlayer(player), amount); + EconomablePlayer p = toEconomablePlayer(player); + + if ( !economyManager.accountExists( p ) ) { + player.sendMessage( "Economy Error: You don't have an account."); + } + else { + + economyManager.setBalance(toEconomablePlayer(player), amount); + } + } catch ( Exception e ) { Output.get().logError( "Failed to set SaneEconomy balance. " + 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 b34c0f9a8..aa3960a8c 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 @@ -110,7 +110,13 @@ private OfflinePlayer getOfflinePlayer(Player player) { @SuppressWarnings( "deprecation" ) public double getBalance(Player player) { double results = 0; + + if ( economy != null && !economy.hasAccount( getOfflinePlayer( player ) ) ) { + player.sendMessage( "Economy Error: You don't have an account."); + } + else if (economy != null) { + if ( isPreV1_4() ) { results = economy.getBalance(player.getName()); } @@ -152,6 +158,11 @@ public double getBalance(Player player) { @SuppressWarnings( "deprecation" ) public boolean setBalance(Player player, double amount) { boolean results = false; + + if ( economy != null && !economy.hasAccount( getOfflinePlayer( player ) ) ) { + player.sendMessage( "Economy Error: You don't have an account."); + } + else if (economy != null) { if ( isPreV1_4() ) { @@ -191,6 +202,10 @@ public boolean addBalance(Player player, double amount) { if ( amount < 0 ) { results = removeBalance( player, amount ); } + + else if ( economy != null && !economy.hasAccount( getOfflinePlayer( player ) ) ) { + player.sendMessage( "Economy Error: You don't have an account."); + } else if (economy != null) { if ( isPreV1_4() ) { economy.depositPlayer( player.getName(), amount ); @@ -239,6 +254,10 @@ public boolean removeBalance(Player player, double amount) { amount *= -1; } + if ( economy != null && !economy.hasAccount( getOfflinePlayer( player ) ) ) { + player.sendMessage( "Economy Error: You don't have an account."); + } + else if (economy != null) { if ( isPreV1_4() ) { economy.withdrawPlayer( player.getName(), amount ); @@ -284,6 +303,11 @@ public boolean removeBalance(Player player, double amount) { @SuppressWarnings( "deprecation" ) public boolean canAfford(Player player, double amount) { boolean results = false; + + if ( economy != null && !economy.hasAccount( getOfflinePlayer( player ) ) ) { + player.sendMessage( "Economy Error: You don't have an account."); + } + else if (economy != null) { if ( isPreV1_4() ) { results = economy.has(player.getName(), amount); diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/game/SpigotCommandSender.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/game/SpigotCommandSender.java index 8e4b0d890..9d5d4c9f4 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/game/SpigotCommandSender.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/game/SpigotCommandSender.java @@ -29,9 +29,12 @@ import tech.mcprison.prison.Prison; import tech.mcprison.prison.PrisonAPI; +import tech.mcprison.prison.commands.CommandHandler; import tech.mcprison.prison.integration.PermissionIntegration; import tech.mcprison.prison.internal.CommandSender; import tech.mcprison.prison.internal.Player; +import tech.mcprison.prison.ranks.PrisonRanks; +import tech.mcprison.prison.ranks.data.RankPlayer; import tech.mcprison.prison.spigot.SpigotPrison; import tech.mcprison.prison.spigot.sellall.SellAllUtil; import tech.mcprison.prison.util.Text; @@ -39,7 +42,8 @@ /** * @author Faizaan A. Datoo */ -public class SpigotCommandSender implements CommandSender { +public class SpigotCommandSender + implements CommandSender { private org.bukkit.command.CommandSender bukkitSender; @@ -68,12 +72,19 @@ public String getName() { * it then uses the mapped command. *

*/ - @Override public void dispatchCommand(String command) { - String registeredCmd = Prison.get().getCommandHandler().findRegisteredCommand( command ); + @Override + public void dispatchCommand(String command) { + + command = CommandHandler.remapRootCmdIdentifiers( command ); + + String registeredCmd = Prison.get().getCommandHandler() + .findRegisteredCommand( command ); + Bukkit.getServer().dispatchCommand(bukkitSender, registeredCmd); } - @Override public boolean doesSupportColors() { + @Override + public boolean doesSupportColors() { return (this instanceof ConsoleCommandSender) && Bukkit.getConsoleSender() != null; } @@ -98,6 +109,18 @@ public void sendMessage(String[] messages) { } } } + + @Override + public void sendMessage(List messages) { + for (String message : messages) { + + String[] msgs = Text.translateAmpColorCodes(message).split( "\\{br\\}" ); + for ( String msg : msgs ) { + + sendMessage(msg); + } + } + } @Override public void sendRaw(String json) { @@ -176,6 +199,23 @@ public double getSellAllMultiplier() { // return results; } + @Override + public List getSellAllMultiplierListings() { + List results = new ArrayList<>(); + + if ( isPlayer() ) { + + SellAllUtil sellall = SpigotPrison.getInstance().getSellAllUtil(); + + if ( sellall != null && getWrapper() != null ) { + results.addAll( sellall.getPlayerMultiplierList((org.bukkit.entity.Player) getWrapper()) ); + } + } + + + return results; + } + public List getPermissionsIntegrations( boolean detailed ) { List results = new ArrayList<>(); @@ -214,4 +254,28 @@ public org.bukkit.command.CommandSender getWrapper() { return bukkitSender; } + @Override + public Player getPlatformPlayer() { + Player player = null; + + Optional oPlayer = Prison.get().getPlatform().getPlayer( getName() ); + + if ( oPlayer.isPresent() ) { + player = oPlayer.get(); + } + + return player; + } + + @Override + public RankPlayer getRankPlayer() { + RankPlayer rankPlayer = null; + + if ( PrisonRanks.getInstance().isEnabled() ) { + + rankPlayer = PrisonRanks.getInstance().getPlayerManager().getPlayer( (Player) this ); + } + return rankPlayer; + } + } 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 044dc3dab..77bbd4638 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 @@ -10,6 +10,7 @@ import org.bukkit.entity.Player; import org.bukkit.permissions.PermissionAttachmentInfo; +import tech.mcprison.prison.Prison; import tech.mcprison.prison.cache.PlayerCache; import tech.mcprison.prison.cache.PlayerCachePlayerData; import tech.mcprison.prison.file.JsonFileIO; @@ -20,6 +21,8 @@ import tech.mcprison.prison.output.Output; import tech.mcprison.prison.ranks.PrisonRanks; import tech.mcprison.prison.ranks.data.RankPlayer; +import tech.mcprison.prison.spigot.SpigotPrison; +import tech.mcprison.prison.spigot.sellall.SellAllUtil; import tech.mcprison.prison.util.Gamemode; import tech.mcprison.prison.util.Location; @@ -320,6 +323,23 @@ public double getSellAllMultiplier() { return results; } + + public List getSellAllMultiplierListings() { + List results = new ArrayList<>(); + + if ( isPlayer() ) { + + SellAllUtil sellall = SpigotPrison.getInstance().getSellAllUtil(); + + if ( sellall != null && getWrapper() != null ) { + results.addAll( sellall.getPlayerMultiplierList((org.bukkit.entity.Player) getWrapper()) ); + } + } + + + return results; + } + @Override public void setTitle( String title, String subtitle, int fadeIn, int stay, int fadeOut ) { } @@ -369,4 +389,23 @@ public void incrementMinecraftStatsDropCount( tech.mcprison.prison.internal.Play } + @Override + public void sendMessage(List messages) { + // TODO Auto-generated method stub + + } + + @Override + public tech.mcprison.prison.internal.Player getPlatformPlayer() { + tech.mcprison.prison.internal.Player player = null; + + Optional oPlayer = Prison.get().getPlatform().getPlayer( getName() ); + + if ( oPlayer.isPresent() ) { + player = oPlayer.get(); + } + + return player; + } + } diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/game/SpigotPlayer.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/game/SpigotPlayer.java index 453d6bcc6..7b2e70f85 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/game/SpigotPlayer.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/game/SpigotPlayer.java @@ -668,8 +668,11 @@ public void setActionBar( String actionBar ) { } } + @Override public RankPlayer getRankPlayer() { - if ( rankPlayer == null ) { + if ( rankPlayer == null && + PrisonRanks.getInstance().isEnabled() ) { + rankPlayer = PrisonRanks.getInstance().getPlayerManager().getPlayer( this ); } return rankPlayer; @@ -854,53 +857,98 @@ public boolean isInventoryFull() { * autosell capabilities ('/sellall autoSellToggle`). *

* + *

Please note that for sellall, autosell happens upon a + * full inventory event, and only when sellall detects it, which + * it may not alway detect it as soon as it happens. + *

y + * + *

Autosell in auto features behaves differently, it sells all + * blocks that are mined, before they even enter the player's + * inventory. This is also a performance boost since the player's + * inventory does not have to be accessed or manipulated. + * As such, auto feature's autsell only is applied within the + * block handling of auto feature's code, it should never be applied + * outside of auto features, and as such, should not be included in + * the processing of this function. + *

+ * * @return */ - public boolean isAutoSellEnabled() { - return isAutoSellEnabled( null ); - } +// public boolean isAutoSellEnabled() { +// return isAutoSellEnabled( null ); +// } + public boolean isAutoSellEnabled( StringBuilder debugInfo ) { boolean results = false; - if ( SpigotPrison.getInstance().isSellAllEnabled() ) { - - boolean isAutoSellPerUserToggleable = SellAllUtil.get().isAutoSellPerUserToggleable; - - boolean isPlayerAutoSellTurnedOff = isAutoSellPerUserToggleable && - !SellAllUtil.get().isSellallPlayerUserToggleEnabled( - getWrapper() ); + if ( SpigotPrison.getInstance().isSellAllEnabled() && + SellAllUtil.get().isAutoSellEnabled ) { - if ( debugInfo != null && isPlayerAutoSellTurnedOff ) { - debugInfo.append( Output.get().getColorCodeWarning() ); - debugInfo.append( "(Player toggled off autosell) " ); - debugInfo.append( Output.get().getColorCodeDebug() ); + if ( SellAllUtil.get().isAutoSellPerUserToggleable ) { + debugInfo.append( "(sellallEnabled:userToggleable)" ); + +// boolean isAutoSellPerUserToggleable = SellAllUtil.get().isAutoSellPerUserToggleable; + + boolean isPlayerAutoSellTurnedOn = + SellAllUtil.get().isSellallPlayerUserToggleEnabled( getWrapper() ); + + if ( debugInfo != null ) { + debugInfo.append( "(autosellPlayerToggled: " ) + .append( Output.get().getColorCodeWarning() ) + .append( isPlayerAutoSellTurnedOn ? "enabled" : "disabled" ) + .append( Output.get().getColorCodeDebug() ) + .append( ")"); + } + + // This will return true (allow autosell) unless players can toggle autosell and they turned it off: + // This is to be used with other auto sell setting, but never on it's own: + results = isPlayerAutoSellTurnedOn; + + + // if autosell is enabled, then need to check to see if perms permit + // it to remain enabled... if not, then set results to false: + if ( results ) { + results = checkAutoSellTogglePerms( debugInfo ); + } + + } + else { + debugInfo.append( "(autosell" ) + .append( Output.get().getColorCodeWarning() ) + .append( "Enabled" ) + .append( Output.get().getColorCodeDebug() ) + .append( ")" ); + results = true; } - // This will return true (allow autosell) unless players can toggle autosell and they turned it off: - // This is to be used with other auto sell setting, but never on it's own: - results = !isAutoSellPerUserToggleable || - isPlayerAutoSellTurnedOff; + } + else { + debugInfo.append( "(autosell" ) + .append( Output.get().getColorCodeWarning() ) + .append( "Disabled" ) + .append( Output.get().getColorCodeDebug() ) + .append( ")" ); } return results; } - /** - *

This will check to see if the player has the perms enabled - * for autosell. - *

- * - *

If the function 'isAutoSellEnabled()' has already - * been called, you can also pass that in as a parameter so it does - * not have to be recalculated. - *

- * - * @return - */ - public boolean isAutoSellByPermEnabled() { - return isAutoSellByPermEnabled( isAutoSellEnabled() ); - } +// /** +// *

This will check to see if the player has the perms enabled +// * for autosell. +// *

If the function 'isAutoSellEnabled()' has already +// * been called, you can also pass that in as a parameter so it does +// * not have to be recalculated. +// *

+// * +// * @return +// */ +// public boolean isAutoSellByPermEnabled( StringBuilder debugInfo ) { +// return isAutoSellByPermEnabled( isAutoSellEnabled( debugInfo ), debugInfo ); +// } /** *

This will check to see if the player has the perms enabled @@ -915,28 +963,105 @@ public boolean isAutoSellByPermEnabled() { * @param isPlayerAutosellEnabled * @return */ - public boolean isAutoSellByPermEnabled( boolean isPlayerAutosellEnabled ) { + private boolean isAutoSellByPermEnabledAutoFeatures( StringBuilder debugInfo ) { - boolean autoSellByPerm = false; + boolean autoSellByPerm = true; AutoFeaturesWrapper afw = AutoFeaturesWrapper.getInstance(); - boolean isSellallEnabled = SpigotPrison.getInstance().isSellAllEnabled(); + if ( afw.isBoolean(AutoFeatures.isAutoSellPerBlockBreakEnabled) ) { + + String perm = afw.getMessage( AutoFeatures.permissionAutoSellPerBlockBreakEnabled ); + + if ( !"disable".equalsIgnoreCase( perm ) && + !"false".equalsIgnoreCase( perm ) ) { + + debugInfo.append( "(autosellAutoFeaturesByPerm: " ) + .append( Output.get().getColorCodeWarning() ) + ; + + if ( isOp() ) { + debugInfo.append( "Op-Disabled" ); + autoSellByPerm = false; + } + else { + + autoSellByPerm = hasPermission( perm ); + + debugInfo.append( autoSellByPerm ? "hasPerm" : "noPerm" ); + } + + debugInfo.append( Output.get().getColorCodeDebug() ) + .append( ")" ); + } + } + + return autoSellByPerm; + } + + public boolean checkAutoSellPermsAutoFeatures() { + boolean results = false; - if ( isSellallEnabled && isPlayerAutosellEnabled && !isOp() ) { + AutoFeaturesWrapper afw = AutoFeaturesWrapper.getInstance(); + if ( afw.isBoolean(AutoFeatures.isAutoSellPerBlockBreakEnabled) ) { String perm = afw.getMessage( AutoFeatures.permissionAutoSellPerBlockBreakEnabled ); + + if ( !"disable".equalsIgnoreCase( perm ) && + !"false".equalsIgnoreCase( perm ) ) { + if ( isOp() ) { + results = false; + } + else { + + results = hasPermission( perm ); + + } + } + } + + return results; + } + + /** + *

This is using the sellall perms check to see if the player has + * the perms to use the player toggle. + *

+ * + * @return + */ + public boolean checkAutoSellTogglePerms( StringBuilder debugInfo ) { + boolean results = true; + + if ( SellAllUtil.get().isAutoSellPerUserToggleablePermEnabled ) { + + debugInfo.append( "(autosellToggleByPerm: " ) + .append( Output.get().getColorCodeWarning() ) + ; - autoSellByPerm = + String perm = SellAllUtil.get().permissionAutoSellPerUserToggleable; + + if ( !"disable".equalsIgnoreCase( perm ) && + !"false".equalsIgnoreCase( perm ) ) { + if ( isOp() ) { + + debugInfo.append( "Op-Disabled" ); + + results = false; + } + else { - afw.isBoolean(AutoFeatures.isAutoSellPerBlockBreakEnabled) && - !"disable".equalsIgnoreCase( perm ) && - !"false".equalsIgnoreCase( perm ) && - hasPermission( perm ); + results = hasPermission( perm ); + + debugInfo.append( results ? "hasPerm" : "noPerm" ); + } + } + + debugInfo.append( Output.get().getColorCodeDebug() ) + .append( ")" ); } - - return autoSellByPerm; + return results; } } 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 cfe91068e..5497f41af 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 @@ -263,7 +263,10 @@ public void onPlayerInteractEvent(PlayerInteractEvent e){ if (sign.getLine(0).equalsIgnoreCase(SpigotPrison.format(signTag))) { String permissionUseSign = sellAllUtil.permissionUseSign; if (sellAllUtil.isSellAllSignPermissionToUseEnabled && !p.hasPermission(permissionUseSign)) { - Output.get().sendWarn(new SpigotPlayer(p), messages.getString(MessagesConfig.StringID.spigot_message_missing_permission) + " [&3" + permissionUseSign + "&7]"); + Output.get().sendWarn(new SpigotPlayer(p), + messages.getString(MessagesConfig.StringID.spigot_message_missing_permission) +// + " [&3" + permissionUseSign + "&7]" + ); return; } 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 951149bb1..b3e48b3b2 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 @@ -101,7 +101,7 @@ public void open() { PrisonGUI gui = new PrisonGUI(p, guiPageData.getDimension(), guiConfig.getString("Options.Titles.PlayerMinesGUI")); - String guiItemNameDefault = guiConfig.getString( "Options.Mines.GuiItemNameDefault" ); + String guiItemNameDefaultSetting = guiConfig.getString( "Options.Mines.GuiItemNameDefault" ); // Load the generic mine LORE that would be displayed first: @@ -144,7 +144,13 @@ public void open() { // Bug: Cannot safely use Material due to variants prior to bukkit v1.13: // Material material; - + + String guiItemNameDefault = + (guiItemNameDefaultSetting == null || guiItemNameDefaultSetting.trim().length() == 0) ? + m.getName() : + guiItemNameDefaultSetting + .replace( "{mineName}", m.getName() ) + .replace( "{mineTag}", m.getTag() ); // Get Mine Name. First use 'guiItemName' if not null, then try to use 'guiItemNameDefault' // if not null, and then use the mine's tag, or if that's null, then use the name: 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 0ea8b0a8e..ddce1a2f1 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 @@ -146,6 +146,11 @@ public void open() { PrisonGUI gui = new PrisonGUI(getPlayer(), guiPageData.getDimension(), guiConfig.getString("Options.Titles.PlayerPrestigesGUI")); + + String guiItemNameDefaultSetting = guiConfig.getString( "Options.Ranks.GuiItemNameDefault" ); + + + // dead code: // if ( ladder == null ){ // Output.get().sendWarn(new SpigotPlayer(player), messages.getString("Message.LadderPrestigesNotFound")); @@ -189,6 +194,26 @@ public void open() { for ( Rank rank : ranksDisplay ) { + + String guiItemNameDefault = + (guiItemNameDefaultSetting == null || guiItemNameDefaultSetting.trim().length() == 0) ? + rank.getName() : + guiItemNameDefaultSetting + .replace( "{rankName}", rank.getName() ); + + + String guiItemName = guiConfig.getString( "Options.Ranks.GuiItemNames." + rank.getName() ); + + + // Get Rank Name. First use 'guiItemName' if not null, then try to use 'guiItemNameDefault' + // if not null, and then use the rank's tag, or if that's null, then use the name: + String rankName = + guiItemName != null ? guiItemName : + guiItemNameDefault != null ? guiItemNameDefault : + rank.getTag() != null ? rank.getTag() : + rank.getName(); + + // hasAccess uses access by rank, and access by perm: boolean playerHasThisRank = getRankPlayer() != null && getRankPlayer().hasAccessToRank( rank ); @@ -218,7 +243,10 @@ public void open() { // playerHasThisRank = false; // } - Button itemrank = new Button(null, playerHasThisRank ? materialHas : materialHasNot, 1, ranksLore, rank.getTag()); + XMaterial hasRankMsg = playerHasThisRank ? materialHas : materialHasNot; + + Button itemrank = new Button( null, hasRankMsg, 1, ranksLore, rankName ); + if (!(playerHasThisRank)){ if (hackyCounterEnchant <= 0) { hackyCounterEnchant++; 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 7e489f599..a0c9b22e0 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 @@ -159,7 +159,7 @@ public void open() { - String guiItemNameDefault = guiConfig.getString( "Options.Ranks.GuiItemNameDefault" ); + String guiItemNameDefaultSetting = guiConfig.getString( "Options.Ranks.GuiItemNameDefault" ); // Not sure how you want to represent this: @@ -190,6 +190,14 @@ public void open() { for ( Rank rank : ranksDisplay ) { + + String guiItemNameDefault = + (guiItemNameDefaultSetting == null || guiItemNameDefaultSetting.trim().length() == 0) ? + rank.getName() : + guiItemNameDefaultSetting + .replace( "{rankName}", rank.getName() ) + .replace( "{rankTag}", rank.getTag() ); + String guiItemName = guiConfig.getString( "Options.Ranks.GuiItemNames." + rank.getName() ); // Get Rank Name. First use 'guiItemName' if not null, then try to use 'guiItemNameDefault' 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 415409308..ed4edbff0 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 @@ -2,11 +2,14 @@ import java.util.function.Function; +import org.bukkit.block.Block; +import org.bukkit.block.BlockState; import org.bukkit.inventory.ItemStack; import de.tr7zw.changeme.nbtapi.NBT; import de.tr7zw.changeme.nbtapi.iface.ReadWriteNBT; import de.tr7zw.changeme.nbtapi.iface.ReadableItemNBT; +import de.tr7zw.changeme.nbtapi.iface.ReadableNBT; import tech.mcprison.prison.output.Output; /** @@ -50,6 +53,18 @@ public static String getNBTString( ItemStack bukkitStack, String key ) { return results; } + + public static String getNBTString( Block bukkitBlock, String key ) { + String results = null; + + Function gsFnc = nbt -> nbt.getString(key); + + BlockState blockState = bukkitBlock.getState(); + + results = NBT.get(blockState, gsFnc ); + + return results; + } public static void setNBTString( ItemStack bukkitStack, String key, String value ) { @@ -108,12 +123,21 @@ public static void nbtDebugLog( ItemStack bukkitStack, String desc ) { } } + public static String nbtDebugString( ItemStack bukkitStack ) { ReadWriteNBT nbtItem = NBT.itemStackToNBT(bukkitStack); return nbtItem.toString(); } + public static String nbtDebugString() { + + ReadWriteNBT nbtItem = NBT.createNBTObject(); + +// ReadWriteNBT nbtItem = NBT.itemStackToNBT(bukkitStack); + return nbtItem.toString(); + } + // public NBTItem getNBT( ItemStack bukkitStack ) { // NBTItem nbtItemStack = null; // 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 1acf5a8eb..145bc08a3 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 @@ -7,6 +7,7 @@ import java.util.HashMap; import java.util.List; import java.util.Optional; +import java.util.Set; import org.bukkit.Bukkit; import org.bukkit.Sound; @@ -29,6 +30,7 @@ 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.RankLadder; import tech.mcprison.prison.ranks.data.RankPlayer; import tech.mcprison.prison.sellall.messages.SpigotVariousGuiMessages; import tech.mcprison.prison.spigot.SpigotPrison; @@ -401,34 +403,37 @@ public HashMap getPrestigeMultipliers() { public double getPlayerMultiplier(Player p){ if (!isSellAllMultiplierEnabled){ - return 1; + return 1d; } // long tPoint1 = System.nanoTime(); -// // Get Ranks module. -// ModuleManager modMan = Prison.get().getModuleManager(); -// Module module = modMan == null ? null : modMan.getModule(PrisonRanks.MODULE_NAME).orElse(null); SpigotPlayer sPlayer = new SpigotPlayer(p); - double multiplier = defaultMultiplier; + double multiplier = 0d; + if ( PrisonRanks.getInstance() != null && PrisonRanks.getInstance().isEnabled() ) { RankPlayer rPlayer = sPlayer.getRankPlayer(); -// rPlayer.getSellAllMultiplier(); // NOTE: This actually calls this function - PlayerRank pRank = rPlayer.getPlayerRankPrestiges(); - Rank rank = pRank == null ? null : pRank.getRank(); - if ( pRank != null ) { - String rankName = rank.getName(); + Set keys = rPlayer.getLadderRanks().keySet(); + for (RankLadder ladderKey : keys) { + PlayerRank pRank = rPlayer.getLadderRanks().get(ladderKey); + String rankName = pRank.getRank().getName(); + String multiplierRankString = sellAllConfig.getString("Multiplier." + rankName + ".MULTIPLIER"); if (multiplierRankString != null && sellAllPrestigeMultipliers.containsKey( rankName )){ - multiplier = sellAllPrestigeMultipliers.get( rankName ); + multiplier += sellAllPrestigeMultipliers.get( rankName ); } - } - + } + } + + if ( multiplier == 0 ) { + multiplier = defaultMultiplier; } + + // long tPoint2 = System.nanoTime(); @@ -463,10 +468,13 @@ public double getPlayerMultiplier(Player p){ List perms = sPlayer.getPermissions("prison.sellall.multiplier."); double multiplierExtraByPerms = 0; for (String multByPerm : perms) { + double multByPermDouble = Double.parseDouble(multByPerm.substring(26)); - if (!isSellAllPermissionMultiplierOnlyHigherEnabled) { + + if ( !isSellAllPermissionMultiplierOnlyHigherEnabled ) { multiplierExtraByPerms += multByPermDouble; - } else if (multByPermDouble > multiplierExtraByPerms) { + } + else if (multByPermDouble > multiplierExtraByPerms) { multiplierExtraByPerms = multByPermDouble; } } @@ -483,6 +491,89 @@ public double getPlayerMultiplier(Player p){ return multiplier; } + + public List getPlayerMultiplierList( Player p ) { + List results = new ArrayList<>(); + + + if (!isSellAllMultiplierEnabled) { + results.add( "1.0 - Sellall multipler is disabled. Default value." ); + + return results; + } + + DecimalFormat dFmt = Prison.getDecimalFormatStaticDouble(); + + SpigotPlayer sPlayer = new SpigotPlayer(p); + + if ( PrisonRanks.getInstance() != null && PrisonRanks.getInstance().isEnabled() ) { + + RankPlayer rPlayer = sPlayer.getRankPlayer(); + + Set keys = rPlayer.getLadderRanks().keySet(); + for (RankLadder ladderKey : keys) { + PlayerRank pRank = rPlayer.getLadderRanks().get(ladderKey); + String rankName = pRank.getRank().getName(); + + String multiplierRankString = sellAllConfig.getString("Multiplier." + rankName + ".MULTIPLIER"); + if (multiplierRankString != null && sellAllPrestigeMultipliers.containsKey( rankName )){ + double mult = sellAllPrestigeMultipliers.get( rankName ); + String msg = String.format( + "%s - %s rank Sellall multiplier", + dFmt.format(mult), rankName + ); + results.add( msg ); + } + } + } + + if ( results.size() == 0 ) { + String msg = String.format( + "%s - default Sellall multiplier - no rank mulitiplers", + dFmt.format(defaultMultiplier) + ); + results.add(msg); + } + + + // Get Multiplier from multipliers permission's if there's any. + List perms = sPlayer.getPermissions("prison.sellall.multiplier."); + double multiplierExtraByPerms = 0; + int count = 0; + String greatestPerm = ""; + for (String multByPerm : perms) { + + double multByPermDouble = Double.parseDouble(multByPerm.substring(26)); + + if ( !isSellAllPermissionMultiplierOnlyHigherEnabled ) { + multiplierExtraByPerms += multByPermDouble; + + String msg = String.format( + "%s - Sellall permission multiplier - %s", + dFmt.format(multByPermDouble), multByPerm + ); + results.add(msg); + } + else if (multByPermDouble > multiplierExtraByPerms) { + multiplierExtraByPerms = multByPermDouble; + count++; + greatestPerm = multByPerm; + } + } + + if ( isSellAllPermissionMultiplierOnlyHigherEnabled ) { + + String msg = String.format( + "%s - Sellall permission multiplier - greatest out of %d - %s", + dFmt.format(multiplierExtraByPerms), count, greatestPerm + ); + results.add(msg); + } + + return results; + } + + // /** // * Get SellAll Money to give, it requires Player because of SellAll perBlockPermission as an option. // * NOTE: This WON'T remove blocks from the HashMap when sold, and won't edit Inventories of Players, @@ -737,7 +828,8 @@ public List sellPlayerItemStacks(Player p, } - private List sellInventoryItems( tech.mcprison.prison.internal.inventory.Inventory inventory, double multiplier ) { + private List sellInventoryItems( tech.mcprison.prison.internal.inventory.Inventory inventory, + double multiplier ) { List soldItems = new ArrayList<>(); if ( inventory != null ) { @@ -808,13 +900,30 @@ private SellAllData sellItemStack( SpigotItemStack iStack, double multiplier ) { if ( iStack != null ) { + // This converts a bukkit ItemStackk to a PrisonBlock, and it also sets up the + // displayName if that is set on the itemStack. PrisonBlock pBlockInv = iStack.getMaterial(); - PrisonBlock pBlockSellAll = sellAllItems.get( pBlockInv.getBlockName().toLowerCase() ); + + PrisonBlock pBlockSellAll = sellAllItems.get( pBlockInv.getBlockNameSearch() ); if ( pBlockSellAll != null ) { - double amount = iStack.getAmount() * pBlockSellAll.getSalePrice() * multiplier; - soldItem = new SellAllData( pBlockSellAll, iStack.getAmount(), amount ); + if ( !pBlockSellAll.isLoreAllowed() && iStack.getLore().size() > 0 ) { + String msg = String.format( + "Sellall: Cannot sell item '%s' (qty %s) because it has lore which is not allowed. ", + iStack.getDisplayName(), + Integer.toString( iStack.getAmount() ) + ); + if ( Output.get().isDebug() ) { + Output.get().logInfo( msg ); + } + + } + else { + + double amount = iStack.getAmount() * pBlockSellAll.getSalePrice() * multiplier; + soldItem = new SellAllData( pBlockSellAll, iStack.getAmount(), amount ); + } } } @@ -981,49 +1090,49 @@ private SellAllData sellItemStack( SpigotItemStack iStack, double multiplier ) { // return xMaterialIntegerHashMap; // } - /** - * If autosell is enabled, and if user toggleable is enabled, then - * it will check to see if the player has the perm or - * - * Get AutoSell Player toggle if available. - * If he enabled it, AutoSell will work, otherwise it won't. - * If he never used the toggle command, this will return true, just like if he enabled it in the first place. - * - * @param p - Player. - * - * @return boolean. - * */ - public boolean isPlayerAutoSellEnabled(Player p){ - boolean results = false; - - // If autosell isn't enabled, then return false - if ( isAutoSellEnabled ) { - - results = isSellallPlayerUserToggleEnabled( p ); -// if ( !isAutoSellPerUserToggleablePermEnabled || -// isAutoSellPerUserToggleablePermEnabled && -// p.hasPermission(permissionAutoSellPerUserToggleable)){ -// -// String settingName = "Users." + p.getUniqueId() + ".isEnabled"; -// -// results = sellAllConfig.getString(settingName) == null || -// getBooleanValue( settingName ); -// } - } - - -// if (isAutoSellPerUserToggleablePermEnabled && -// !p.hasPermission(permissionAutoSellPerUserToggleable)){ -// return false; -// } +// /** +// * If autosell is enabled, and if user toggleable is enabled, then +// * it will check to see if the player has the perm or +// * +// * Get AutoSell Player toggle if available. +// * If he enabled it, AutoSell will work, otherwise it won't. +// * If he never used the toggle command, this will return true, just like if he enabled it in the first place. +// * +// * @param p - Player. +// * +// * @return boolean. +// * */ +// public boolean isPlayerAutoSellEnabled(Player p){ +// boolean results = false; +// +// // If autosell isn't enabled, then return false +// if ( isAutoSellEnabled ) { +// +// results = isSellallPlayerUserToggleEnabled( p ); +//// if ( !isAutoSellPerUserToggleablePermEnabled || +//// isAutoSellPerUserToggleablePermEnabled && +//// p.hasPermission(permissionAutoSellPerUserToggleable)){ +//// +//// String settingName = "Users." + p.getUniqueId() + ".isEnabled"; +//// +//// results = sellAllConfig.getString(settingName) == null || +//// getBooleanValue( settingName ); +//// } +// } +// +// +//// if (isAutoSellPerUserToggleablePermEnabled && +//// !p.hasPermission(permissionAutoSellPerUserToggleable)){ +//// return false; +//// } +//// +//// if (sellAllConfig.getString("Users." + p.getUniqueId() + ".isEnabled") == null){ +//// return true; +//// } // -// if (sellAllConfig.getString("Users." + p.getUniqueId() + ".isEnabled") == null){ -// return true; -// } - -// return getBooleanValue("Users." + p.getUniqueId() + ".isEnabled"); - return results; - } +//// return getBooleanValue("Users." + p.getUniqueId() + ".isEnabled"); +// return results; +// } /** *

This function only checks to see if the user can toggle autosell @@ -1040,17 +1149,21 @@ public boolean isPlayerAutoSellEnabled(Player p){ public boolean isSellallPlayerUserToggleEnabled( Player p ) { boolean results = false; - if ( isAutoSellPerUserToggleable ) { + // If autosell isn't enabled, then return false + if ( isAutoSellEnabled ) { - if ( !isAutoSellPerUserToggleablePermEnabled || - isAutoSellPerUserToggleablePermEnabled && - p.hasPermission(permissionAutoSellPerUserToggleable)){ - - String settingName = "Users." + p.getUniqueId() + ".isEnabled"; - - results = sellAllConfig.getString( settingName ) == null || - getBooleanValue( settingName ); - } + if ( isAutoSellPerUserToggleable ) { + + if ( !isAutoSellPerUserToggleablePermEnabled || + isAutoSellPerUserToggleablePermEnabled && + p.hasPermission(permissionAutoSellPerUserToggleable)){ + + String settingName = "Users." + p.getUniqueId() + ".isEnabled"; + + results = sellAllConfig.getString( settingName ) == null || + getBooleanValue( settingName ); + } + } } return results; @@ -1149,13 +1262,20 @@ public HashMap initSellAllItems(){ for (String key : sellAllConfig.getConfigurationSection("Items").getKeys(false)) { String itemName = key.trim().toUpperCase(); + String itemPrefix = "Items." + itemName; - String itemID = sellAllConfig.getString("Items." + itemName + ".ITEM_ID"); + String itemID = sellAllConfig.getString( itemPrefix + ".ITEM_ID"); PrisonBlock pBlock = Prison.get().getPlatform().getPrisonBlock(itemID); if ( pBlock != null ) { - String saleValueString = sellAllConfig.getString("Items." + itemName + ".ITEM_VALUE"); + + String itemDisplayName = sellAllConfig.getString( itemPrefix + ".ITEM_DISPLAY_NAME"); + if ( itemDisplayName != null ) { + pBlock.setDisplayName( itemDisplayName ); + } + + String saleValueString = sellAllConfig.getString( itemPrefix + ".ITEM_VALUE"); if ( saleValueString != null ) { try { @@ -1165,7 +1285,7 @@ public HashMap initSellAllItems(){ } } - String purchaseValueString = sellAllConfig.getString("Items." + itemName + ".PURCHASE_PRICE"); + String purchaseValueString = sellAllConfig.getString( itemPrefix + ".PURCHASE_PRICE"); if ( purchaseValueString != null ) { try { @@ -1174,7 +1294,21 @@ public HashMap initSellAllItems(){ } catch (NumberFormatException ignored) { } } - sellAllItems.put( pBlock.getBlockName().toLowerCase(), pBlock ); + + String isLoreAllowedString = sellAllConfig.getString( itemPrefix + ".IS_LORE_ALLOWED"); + boolean isLoreAllowed = false; + if ( isLoreAllowedString != null ) { + + try { + isLoreAllowed = Boolean.parseBoolean(isLoreAllowedString); + } + catch (NumberFormatException ignored) { + } + } + pBlock.setLoreAllowed( isLoreAllowed ); + + + sellAllItems.put( pBlock.getBlockNameSearch(), pBlock ); } // Optional iMatOptional = XMaterial.matchXMaterial(itemID); @@ -1259,14 +1393,19 @@ public ArrayList initSellAllItemTrigger(){ * * @return boolean. * */ - public boolean addSellAllBlock(XMaterial xMaterial, double value){ + public boolean addSellAllBlock(XMaterial xMaterial, double value) { + return addSellAllBlock( xMaterial, null, value ); + } + + public boolean addSellAllBlock(XMaterial xMaterial, String displayName, double value) { PrisonBlock pBlockKey = Prison.get().getPlatform().getPrisonBlock( xMaterial.name() ); if ( pBlockKey == null ) { Output.get().logDebug( "sellall add: invalid block name (%s)", xMaterial.name()); return false; } - String key = pBlockKey.getBlockName().toLowerCase(); + String key = pBlockKey.getBlockNameSearch(); +// String key = pBlockKey.getBlockName().toLowerCase(); PrisonBlock pBlock = sellAllItems.get( key ); @@ -1276,6 +1415,10 @@ public boolean addSellAllBlock(XMaterial xMaterial, double value){ return false; } + + // pBlock is null, but it's being used below. So clone the key: + pBlock = pBlockKey.clone(); + try { String itemName = pBlockKey.getBlockName().toUpperCase(); @@ -1284,6 +1427,12 @@ public boolean addSellAllBlock(XMaterial xMaterial, double value){ FileConfiguration conf = YamlConfiguration.loadConfiguration(sellAllFile); conf.set("Items." + itemName + ".ITEM_ID", xMaterial.name()); conf.set("Items." + itemName + ".ITEM_VALUE", value); + conf.set("Items." + itemName + ".IS_LORE_ALLOWED", pBlock.isLoreAllowed() ); + + if ( displayName != null ) { + conf.set("Items." + itemName + ".ITEM_DISPLAY_NAME", displayName ); + } + if (getBooleanValue("Options.Sell_Per_Block_Permission_Enabled")) { String itemPerm = "Items." + itemName + ".ITEM_PERMISSION"; conf.set( itemPerm, sellAllConfig.getString("Options.Sell_Per_Block_Permission") + xMaterial.name()); @@ -1292,7 +1441,7 @@ public boolean addSellAllBlock(XMaterial xMaterial, double value){ updateConfig(); pBlockKey.setSalePrice( value ); - sellAllItems.put( pBlockKey.getBlockName().toLowerCase(), pBlockKey ); + sellAllItems.put( pBlockKey.getBlockNameSearch(), pBlockKey ); } catch (IOException e) { e.printStackTrace(); @@ -1584,10 +1733,13 @@ public boolean canPlayerSell(Player p, boolean isUsingSign){ * * @return boolean. * */ - public boolean editPrice(XMaterial xMaterial, double value){ + public boolean editPrice(XMaterial xMaterial, double value) { + return editPrice( xMaterial, null, value ); + } + public boolean editPrice(XMaterial xMaterial, String displayName, double value) { PrisonBlock pBlockKey = Prison.get().getPlatform().getPrisonBlock( xMaterial.name() ); - String key = pBlockKey.getBlockName().toLowerCase(); + String key = pBlockKey.getBlockNameSearch(); PrisonBlock pBlock = sellAllItems.get( key ); @@ -1613,6 +1765,15 @@ public boolean editPrice(XMaterial xMaterial, double value){ String itemName = key.toUpperCase(); conf.set("Items." + itemName + ".ITEM_ID", key ); conf.set("Items." + itemName + ".ITEM_VALUE", value); + conf.set("Items." + itemName + ".IS_LORE_ALLOWED", pBlock.isLoreAllowed() ); + + if ( displayName != null ) { + conf.set("Items." + itemName + ".ITEM_DISPLAY_NAME", value); + } + else { + //conf.set("Items." + itemName + ".ITEM_DISPLAY_NAME", null); + } + if ( pBlock.getPurchasePrice() != null ) { @@ -1636,6 +1797,51 @@ public boolean editPrice(XMaterial xMaterial, double value){ return true; } + + + public boolean editAllowLore(XMaterial xMaterial, boolean value) { + + PrisonBlock pBlockKey = Prison.get().getPlatform().getPrisonBlock( xMaterial.name() ); + String key = pBlockKey.getBlockNameSearch(); + + PrisonBlock pBlock = sellAllItems.get( key ); + + // Do not allow an edit price if the material does not exist, or if the value has not changed: + if ( pBlock == null ){ + + Output.get().logDebug( "sellall edit: item does not exist in shop so it cannot be edited (%s)", pBlockKey.getBlockName()); + return false; + } + if ( pBlock.isLoreAllowed() == value ){ + Output.get().logDebug( "sellall edit: No change in 'allow lore' (%s %s)", + pBlockKey.getBlockName(), Boolean.toString( pBlock.isLoreAllowed() ) ); + return false; + } + + pBlock.setLoreAllowed( value ); + + try { + File sellAllFile = new File(SpigotPrison.getInstance().getDataFolder() + "/SellAllConfig.yml"); + FileConfiguration conf = YamlConfiguration.loadConfiguration(sellAllFile); + + String itemName = key.toUpperCase(); +// conf.set("Items." + itemName + ".ITEM_ID", key ); + conf.set("Items." + itemName + ".IS_LORE_ALLOWED", pBlock.isLoreAllowed() ); + + conf.save(sellAllFile); + + // Update only if successful + updateConfig(); + } catch (IOException e) { + e.printStackTrace(); + return false; + } + + // pBlock is still in the sellAllItems collection so no need to readd it +// sellAllBlocks.put(xMaterial, value); + + return true; + } // /** // * BUG: With Spigot versions less than 1.13 bukkit's Material will not work on all Materials since @@ -1683,7 +1889,7 @@ public boolean editPrestigeMultiplier(String prestigeName, double multiplier) { public boolean removeSellAllBlock(XMaterial xMaterial){ PrisonBlock pBlockKey = Prison.get().getPlatform().getPrisonBlock( xMaterial.name() ); - String key = pBlockKey.getBlockName().toLowerCase(); + String key = pBlockKey.getBlockNameSearch(); PrisonBlock pBlock = sellAllItems.get( key ); 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 966b638fc..83ac8ca39 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 @@ -4,13 +4,17 @@ import java.util.List; import org.bukkit.Material; +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.Listener; import org.bukkit.event.block.Action; +import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.event.player.PlayerDropItemEvent; import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.inventory.ItemStack; import tech.mcprison.prison.Prison; import tech.mcprison.prison.bombs.MineBombData; @@ -51,6 +55,36 @@ public PrisonBombListener( PrisonUtilsMineBombs utilsMineBombs ) { this.blockBreakMines = new OnBlockBreakMines(); } + + @EventHandler( priority = EventPriority.LOW ) + public void onInteract( BlockPlaceEvent event ) { + + ItemStack iStack = event.getItemInHand(); + + if ( iStack.getType() != Material.AIR ) { + + + String bombName = checkMineBombItemStack( iStack ); + + if ( bombName != null ) { + + Player player = event.getPlayer(); + + Block targetBlock = event.getBlockAgainst(); + + EquipmentSlot hand = SpigotCompatibility.getInstance().getHand(event); + + boolean canceled = processBombTriggerEvent(event, player, bombName, + targetBlock, hand ); + + if ( canceled ) { + event.setCancelled( canceled ); + } + } + + } + + } @EventHandler( priority = EventPriority.LOW ) public void onInteract( PlayerInteractEvent event ) { @@ -68,31 +102,65 @@ public void onInteract( PlayerInteractEvent event ) { // If the player is holding a mine bomb, then get the bomb and decrease the // ItemStack in the player's hand by 1: + ItemStack iStack = event.getItem(); - // Check to see if this is an mine bomb by checking the NBT key-value pair, - // which will also identify which mine bomb it is too. - // NOTE: Because we're just checking, do not auto update the itemstack. -// NBTItem nbtItem = new NBTItem( event.getItem() ); - - String bombName = PrisonNBTUtil.getNBTString( event.getItem(), MineBombs.MINE_BOMBS_NBT_BOMB_KEY ); + String bombName = checkMineBombItemStack( iStack ); - if ( bombName == null || bombName.trim().length() == 0 ) { -// if ( !nbtItem.hasKey( MineBombs.MINE_BOMBS_NBT_BOMB_KEY ) ) { - return; + if ( bombName != null ) { + + Player player = event.getPlayer(); + + Block targetBlock = event.getClickedBlock(); + + EquipmentSlot hand = SpigotCompatibility.getInstance().getHand(event); + + boolean canceled = processBombTriggerEvent(event, player, bombName, + targetBlock, hand ); + + if ( canceled ) { + event.setCancelled( canceled ); + } + + } -// String bombName = nbtItem.getString( MineBombs.MINE_BOMBS_NBT_BOMB_KEY ); - - if ( Output.get().isDebug() ) { - Output.get().logInfo( "PrisonBombListener.onInteract bombName: &7%s&r &3:: nbt: &r%s", - bombName, - PrisonNBTUtil.nbtDebugString( event.getItem() ) + } + } + + private String checkMineBombItemStack( ItemStack iStack ) { + // Check to see if this is an mine bomb by checking the NBT key-value pair, + // which will also identify which mine bomb it is too. + // NOTE: Because we're just checking, do not auto update the itemstack. +// NBTItem nbtItem = new NBTItem( event.getItem() ); + + String bombName = PrisonNBTUtil.getNBTString( iStack, MineBombs.MINE_BOMBS_NBT_BOMB_KEY ); + + if ( bombName != null && bombName.trim().length() == 0 ) { + bombName = null; + } + else if ( bombName != null ){ + + if ( Output.get().isDebug() ) { + Output.get().logInfo( "PrisonBombListener.onInteract (item) " + + "bombName: &7%s&r &3:: nbt: &r%s", + bombName, + PrisonNBTUtil.nbtDebugString( iStack ) // (nbtItem == null ? "&a-no-nbt-" : nbtItem.toString()) - ); - } - - Player player = event.getPlayer(); - + ); + } + } + + + return bombName; + } + + private boolean processBombTriggerEvent( Event event, Player player, + String bombName, Block targetBlock, + EquipmentSlot hand ) { + + boolean canceled = false; + + // // Temp test stuff... remove when NBTs are working: // { // @@ -110,95 +178,97 @@ public void onInteract( PlayerInteractEvent event ) { // SpigotItemStack sItemStack = new SpigotItemStack( event.getItem() ); // Output.get().logInfo( sItemStack.getNBT().toString() ); // } - - MineBombData bomb = getPrisonUtilsMineBombs().getBombItem( bombName ); - - - if ( bomb == null ) { - if ( Output.get().isDebug() ) { - Output.get().logInfo( "MineBombs: The bomb named '%s' cannot be mapped to a mine bomb.", - bombName ); - } - return; - } - - SpigotBlock sBlock = null; - - SpigotPlayer sPlayer = new SpigotPlayer( player ); - - // If clicking AIR, then event.getClickedBlock() will be null... - // so if null, then use the player's location for placing the bomb. - if ( event.getClickedBlock() == null ) { - Location loc = sPlayer.getLocation(); - - // Get the block 3 away from the player, in the direction (vector) in which - // the player is looking. - sBlock = (SpigotBlock) loc.add( loc.getDirection().multiply( 3 ) ) .getBlockAt(); - } - else { - sBlock = SpigotBlock.getSpigotBlock( event.getClickedBlock() ); - } - - - Mine mine = blockBreakMines.findMine(player, sBlock, null, null); - 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; - } - - HashSet allowedMines = new HashSet<>( bomb.getAllowedMines() ); - HashSet preventedMines = new HashSet<>( bomb.getPreventedMines() ); - List globalPreventedMines = (List) Prison.get().getPlatform() - .getConfigStringArray("prison-mines.mine-bombs.prevent-usage-in-mines"); - preventedMines.addAll( globalPreventedMines ); - - // Skip prevent-in-mines check if mine is within the allowedMines list: - if ( !allowedMines.contains( mine.getName().toLowerCase() ) ) { - - if ( preventedMines.contains( mine.getName().toLowerCase() ) ) { - - // Mine bombs are not allowed to be used in this mine so cancel: - event.setCancelled( true ); - return; - } - } + + MineBombData bomb = getPrisonUtilsMineBombs().getBombItem( bombName ); + + + if ( bomb == null ) { + if ( Output.get().isDebug() ) { + Output.get().logInfo( "MineBombs: The bomb named '%s' cannot be mapped to a mine bomb.", + bombName ); + } + return canceled; + } + + SpigotBlock sBlock = null; + + SpigotPlayer sPlayer = new SpigotPlayer( player ); + + // If clicking AIR, then event.getClickedBlock() will be null... + // so if null, then use the player's location for placing the bomb. + if ( targetBlock == null ) { + Location loc = sPlayer.getLocation(); + + // Get the block 3 away from the player, in the direction (vector) in which + // the player is looking. + sBlock = (SpigotBlock) loc.add( loc.getDirection().multiply( 3 ) ) .getBlockAt(); + } + else { + sBlock = SpigotBlock.getSpigotBlock( targetBlock ); + } + + + Mine mine = blockBreakMines.findMine(player, sBlock, null, null); + 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." ); + } + + canceled = true; +// event.setCancelled( true ); + return canceled; + } + 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()); + } + + canceled = true; +// event.setCancelled( true ); + return canceled; + } + + HashSet allowedMines = new HashSet<>( bomb.getAllowedMines() ); + HashSet preventedMines = new HashSet<>( bomb.getPreventedMines() ); + List globalPreventedMines = (List) Prison.get().getPlatform() + .getConfigStringArray("prison-mines.mine-bombs.prevent-usage-in-mines"); + preventedMines.addAll( globalPreventedMines ); + + // Skip prevent-in-mines check if mine is within the allowedMines list: + if ( !allowedMines.contains( mine.getName().toLowerCase() ) ) { + + if ( preventedMines.contains( mine.getName().toLowerCase() ) ) { + + // Mine bombs are not allowed to be used in this mine so cancel: + canceled = true; +// event.setCancelled( true ); + return canceled; + } + } - - // getHand() is not available with bukkit 1.8.8 so use the compatibility functions: - EquipmentSlot hand = SpigotCompatibility.getInstance().getHand(event); + + // 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 ) ) { - - // The item was a bomb and it was activated. - // Cancel the event so the item will not be placed or processed farther. - + if ( getPrisonUtilsMineBombs().setBombInHand( player, bomb, sBlock, hand ) ) { + + // The item was a bomb and it was activated. + // Cancel the event so the item will not be placed or processed farther. + // Output.get().logInfo( "### PrisonBombListener: PlayerInteractEvent 03 Bomb detected - May not have been set. " ); - event.setCancelled( true ); - } - - - - } - } + canceled = true; +// event.setCancelled( true ); + } + + return canceled; + } // @EventHandler( priority = EventPriority.HIGHEST, ignoreCancelled = false ) diff --git a/prison-spigot/src/main/resources/config.yml b/prison-spigot/src/main/resources/config.yml index 4730ba395..db8394e8d 100644 --- a/prison-spigot/src/main/resources/config.yml +++ b/prison-spigot/src/main/resources/config.yml @@ -274,10 +274,18 @@ number-format-location: en_US # The storage engine that Prison should use to store data. -# The only valid storageType is json. -storageType: "json" +# The only valid storageType is file. +storageType: "file" +# The following is experimental and should only be used if advised by a +# Prison support team member. +# +storage: + file: + disable-advanced-saves: + enabled: false + debug-keep-temp-files: false # Prison mines reset gap is the number of milliseconds that are used to @@ -309,8 +317,8 @@ storageType: "json" prison-mines: reset-gap-ms: 5000 reset-paging: - max-page-elapsed-time-ms: 75 - page-submit-delay-ticks: 1 + max-page-elapsed-time-ms: 40 + page-submit-delay-ticks: 0 page-timeout-check-block-count: 250 reset-async-paging: async-page-size: 4000 @@ -328,6 +336,7 @@ prison-mines: - GoldMine - SampleMineName world-guard: + WARNING: WorldGuard support is not yet available. Coming soon. region-mine: enable: true name-prefix: prison_mine_ @@ -470,20 +479,28 @@ prisonCommandHandler: exclude-worlds: - miniGameWorld - playerPlotWorld + command-roots: + prison: prison + mines: mines + ranks: ranks + gui: gui + sellall: sellall disable-player-placeholders-in-excluded-worlds: false exclude-non-ops: exclude-related-aliases: true commands: - mines: - tp: - includeCmdPerms: true - includeCmdAltPerms: true - perms: - - prison.exclude.test + prison: + support: + colorTest: + includeCmdPerms: false + includeCmdAltPerms: false + perms: + - prison.exclude.test aliases: - mines: - tp: - - mines teleport + prison: + support: + colorTest: + - pColorTest