diff --git a/docs/changelog_v3.2.x.md b/docs/changelog_v3.2.x.md index f2ec3d3a3..c55bc2e1e 100644 --- a/docs/changelog_v3.2.x.md +++ b/docs/changelog_v3.2.x.md @@ -30,10 +30,8 @@ that you need. # v3.2.6 2021-04-11 - * **v3.2.6 2021-04-11** - * **Start to add in a PrisonMinesBlockEventEvent class.** It has been disabled because it cannot be used yet; the BlockEvents need to under go some major changes to support its use. Currently the BlockEvents receive only references to the sources (block names and not the actual blocks), but in order to hook this up properly, all blocks and details need to be passed. The current system for controlling the BlockEvents is unable to support that kind of an environment right now. It will be changed in the very near future to get this working. diff --git a/docs/changelog_v3.3.x.md b/docs/changelog_v3.3.x.md index a76b3b826..aae7a5a96 100644 --- a/docs/changelog_v3.3.x.md +++ b/docs/changelog_v3.3.x.md @@ -13,952 +13,1008 @@ These build logs represent the work that has been going on within prison. *Will continue as v3.3.0-alpha.7 2021-06-?? in the near future.* +# 3.2.11 2022-01-22 -# v3.2.10 2021-08-22 +**3.2.11 2022-01-22** + + +* **Added to SpigotPlayer the ability to enable flying and to check to see if the player is flying. This is to prepare for mine effects.** + + +* **Considering adding heads support to prison. Added a few parts, but they are not functional.** + + +* **3.2.11-alpha.17 2022-01-18** + + +* **More updates to the player's rank menu with the ability to add rank specific lore to the configs.** +When referring to ranks, the names much match exactly since they are case sensitive. + + +* **Bug fix with the rank cost calculations since they were not pulling in the last rank in the rang of ranks.** -* **Prison Release v3.2.10** +* **Fixed an issue with CI's function that was not returning any ids.** -* **Updated to the support of the Prison's ExplosiveBlockBreakEvent. There were a few adjustments that were needed.** +* **Mine auto resets can now be disabled.** +When disabled, they will never reset based upon time. The resets can still be triggered by blocks remaining thresholds. -* **Some blocks within the liners are not compatible with all versions of bukkit/spigot/minecraft.** -Added minimal versions to the patterns so as to help prevent the use of the wrong patterns for the server version. +* **3.2.11-alpha.16 2022-01-16** -* **Found an error with two Mine Liners that had pillar_quartz_block instead of quartz_pillar.** +* **Lot of updates to the GUI menus.** +Major improvements to the player's /gui ranks to work better with placeholders. Added comments to the GuiConfig.yml file on how to use it and the placeholders. +Delete the GuiConfig.yml file to regenerate with the updated information on lore settings. -* **Added support for Prison's own ExplosiveBlockBreakEvent.** -This will be used for Prison's up coming Prison Bombs. Also this can be used by other plugins too. +* **Update a few of the player's GUIs to support the SpigotGUIMenutools.** +Added capability to control the return command and the paging command so it now works more intuitivily. -* **Update the PrisonEnchants code for handing their PEExplosionEvent object.** +* **Fix issue with the placeholders related to prison_rankup_cost.** +This now works correctly to include the next prestig rank's cost when at the last rank in the default ladder. -* **Fix a problem with NPE when getting the player's Locale when it wasn't set.** +* **Bug fix: Get the 32 placeholders related to prison_rankup_cost working correctly when dealing with various prestige conditions.** -* **More adjustments to the /ranks list to add information about the player's current multipliers on all the ladders.** -This makes it easier to understand why the rank multiplier is a specific value. -* **Some adjustments to `/ranks list` to remove "admin stuff" from the list for non-admins.** +* **Bug fix: The player based playSound was not working, but the world's playSound works perfectly. Not sue why bukkit player would be messed up that ** -* **v3.2.10-alpha.14b 2021-08-22** +* **Bug fix: Hooking up the rollover to the next prestige rank cost, when at th end of the ladder, had a typo where it would not evaluate any rank.** -* **Removed the option to delete a rank from the ranks info command since it should not be that easy to remove a rank, which could easily be clicked on in game.** -Also commented out dead code. +**3.2.11-alpha.15 2022-01-13** -* **Hook up the process to have all unjoined players added to prison by giving them the default rank.** -This is also ran now at the end of the /ranks autoConfigure to ensure all players are hooked up as soon as the default ladder and it's ranks exists. +* **Bug Fix: If the wrong sound file was being used it used to throw a NPE.** +Now this is a safer way to find the correct file, and it will fall back upon a plink sound for any version of spigot. -* **Player join bug: Fixed a bug... if a player is not on the default ladder, then this was preventing them from being added.** +* **If upon loading a mine, there is a reson or need to resave the data, since this is an auto update, then this will make a backup copy of the mine's save file before saving it.** -* **Added virtual checks to prevent placeholders from trying to access mine features that do not exist.** +* **Bug fix: If spigot version is less than 1.13.0, and trying to use a _WOOD block, XMaterials cannot map that correctly to a Material and then back to the same XMaterial.** +This is causing a problem when using in a mine since it cannot be tied back to the block that was placed. So for these versions, all _WOOD blocks are removed from the server. If a _WOOD block is saved in a mine, it will be remapped to the same _PLANKS block, which will work just fine. -* **v3.2.10-alpha.14 2021-08-21** +* **Bug fix: Prevent stack traces when a broken block cannot be mapped to a PrisonBlockStatusData object.** +This is happening with spigot versions 1.8 through 1.12.2 when using "WOOD" blocks since XSeries translates these blocks to LOGs, so they will never map back to the XMaterial WOOD entries. This was producing a stacktrace and would prevent the proper handling of the auto features. -* **reduce what is shown on /rank if for non-op players.** +* **3.2.11-alpha.14 2022-01-11** -* **Decrease the autoConfigure's prestige costs from 2 B to just 1 B.** +* **Update the failed rank message so it is clearer.** -* **Reload auto features after running ranks autoconfigure to enable the auto pickup.** -It wasn't working right after generating the mines. +* **When a player is on the default ladder at the last possible rank, instead of showing nothing for rankup costs, percent, bar, etc, it will now use the next prestige rank if prestiges are enabled.** -* **Fixed an issue with virtual mines not being included in /mines list all command.** + These changes apply to the following placeholders: + prison_rc prison_rankup_cost prison_rc_laddername prison_rankup_cost_laddername + prison_rcf prison_rankup_cost_formatted prison_rcf_laddername prison_rankup_cost_formatted_laddername + prison_rcp prison_rankup_cost_percent prison_rcp_laddername prison_rankup_cost_percent_laddername + prison_rcb prison_rankup_cost_bar prison_rcb_laddername prison_rankup_cost_bar_laddername + prison_rcr prison_rankup_cost_remaining prison_rcr_laddername prison_rankup_cost_remaining_laddername + prison_rcrf prison_rankup_cost_remaining_formatted prison_rcrf_laddername prison_rankup_cost_remaining_formatted_laddername + prison_rcrp prison_rankup_cost_remaining_percent prison_rcrp_laddername prison_rankup_cost_remaining_percent_laddername + prison_rcrb prison_rankup_cost_remaining_bar prison_rcrb_laddername prison_rankup_cost_remaining_bar_laddername -* **Now `/ranks autoConfigure` creates 10 prestiges ranks. ** -* **Have placeholders reload after mines or ranks are created, removed, or renamed.** -Create mine and create rank now has an option to suppress updating placeholders since commands like autoConfigure will cause tons of messages to be generated. The placeholders are regenerated after all mines and ranks are created. +* **On delayed startup, allow a combination of selectors to target essentials, since the class name has changed in v2.19.x** -* **Command '/mines set area' fixed confirmation to use yes or confirm.** -Added the ability to set size when using feet. The size is what is used with the '/mines set size' command. So 20 width is really 41 since it's adding 40 blocks in all directions. +* **Setup the block inspector to auto select a diamond shovel, a diamond axe, or a diamond pickaxe.** +* **On the blockbreak debug information, show the information on either the block that was hit, or if that is null, just dashes to show such a block was not provided.** -* **Redesign the /mines info command to reduce and compact the listing.** -`/mines info ` is the reduced listing where disabled features are not shown. `/mines info all` is the expanded listing that includes more details. -Reworked the block list to use the String.format for spacing instead of manual adjustments. +* **For EssentialsX v2.19.x, the class being used to identify if the economy has been loaded has changed.** +This commit has the references to the proper class to use depeending upon the version of EssentialsX. It should be noted that this only applies if delayed startup is enabled for the EssentialsX economy, which generally does not require it. -* **v3.2.10-alpha.13 2021-08-20** +* **Change in how prison deals with ranks when there isn't an economy plugin loaded.** +Now, instead of printing a simple little message in the console, which everyone appear to miss, it also enables a generic `/ranks` command that only displays a message indicating that no economy was found, with links to documentation. This should make it more obvious. -* **Fixed an issue with null for the playerUuid..** -it's rare, but it could be null. This prevents the failures. +* **Change to auto features for the event listeners: now MONITOR is not enabled unless set to priority of MONITOR.** -* **Fixed a few issues with ranks, a NPEs.** +* **If a language file has a message that is set to an empty string or a space, it will now no longer generate an empty message.** +Instead it will supress the sending of any message that is blank. -* **The text for ladder info was changed to remove player's name, which does not make sense to include, especially if ran from console.** +* **Move the placeholder `prison_player_blocks_total` from being a player mine placeholder, to a player placeholder since it is not tied to a specific mine.** +Added a formatted version (with commas) and this one became unformatted so it can be used within scripts if needed. -* **Yet another situation where CMI needed prison to start with a delay; confirmed setting is correct.** -It was confirmed for the second time that 'Economy_CMI' works so I moved that to the 'vault-economy-name:' setting. +* **The use of the `/ranks command remove` within the `/ranks info`, or `/ranks command list` was not correctly including the correct row number**; it was using one higher than what it should have due to prior incrementing. -* **Fixes a bug when checking offline players which was returning a null with rPlayer.getRank(). Was fixed.** +* **Issues with SellAll when dealing with varient block types when bukkit version is less than 1.13.** +Eliminate usage of org.bukkit.Material where possible. XMaterial must generate the ItemStack directly, instead of creating a Material object. -* **Ranks autoConfigure: Add to the prestiges ladder the base rank cost multiplier of 10 percent.** -Provide a few messages to document it when the /ranks autoConfigure command is ran. +* **Fix some issues with canceling drops:** +Will not work on 1.8.x and maybe a few other versions of spigot with no work arounds. Works on newer versions. -* **For the /ranks autoConfigure command, setup an alias to /prison autoConfigure.** +**New Feature: Dump the BlockBreakEvent and monitor changes per listener.** +This provides a great deal of information on what is modifying the blocks. +To use, enter prison debug mode with `/prison debug` and then shift-click on a block using the prison wand (`/mines wand`). -* **Setup a task that is to be ran whenever there is a rank change within a ladder, or if the ladder has the base rank cost multiplier changed.** -This helps to ensure that the rank costs are correct for all players. -* **Renamed the command `/ranks remove rank` to `/ranks removeRank` since the prior command was a single command within it's own sub-group.** -This change will now list the command with the others when using `/ranks`. It was "lost" and "hidden" and admins were not able to find it that easily. +* **Bug Fix: When loading the mines, and if using the old block model, some blocks were not mapping to the new PrisonBlocks.** +When this now happens, the loader now tries to use the old block model's getXMaterialName() function, which returns one or more names that can map to XMaterial objects. It tries all of them until it is able to get a non-null PrisonBlock result. -* **Changed the /ranks ladder delete command to prevent a ladder from being deleted if it has any ranks associated with it.** -To delete a ladder with ranks would corrupt the ranks. The ranks would have to be removed first to ensure no players are on the ranks. +* **Added a safty backup of the player's cache file... if it is detected that the new size is smaller than the prior size, then make a backup copy saving the original version instead of deleting it.** +This implies that stats will always be added to the player's cache and that the file should alwaysbe getting larger. This only makes sense when recording stats. The file could become smaller when balances are reset, such as spending a lot of tokens. +This also implies that some times, such as player inventories, should not be stored in this object... player's backpacks will be removed in the near future. +It should be mentioned that on a test server I saw my player stats for my test player being wipped out. I have no idea if it was because of file system commands that I ran, or if it was a bug in prison that reset it. But because there was a potential loss, I'm making sure certain things cannot happen anymore, or trying to reduce the risk of losses. -* **After a change in a player's rank, have the player's Rank Cost Multipliers recalculated.** +* **Fix the sellall block list gui for when there is an invalid XMaterial name**, that it will print out the error to the console, and continue with using COBBLESTONE instead of producing a NPE. -* **The command /ranks player perms was generating an error with offline players so this fixes that issue.** -* **Changed config.yml to enable and disable prestige confirmations.** -Updated the GUI to support this. Settings where changed and config.yml may need to be reset when updating prison to use these new features. +* **For the list of displaying the ranks on a ladder, split them up to show 15 per line which will help when there are a lot of ranks on a given ladder.** -* **Fixed bug with `/ranks ladder moveRank`.** -It was not removing the rank from the source ladder, but was also adding it to the destination ladder. This was fixed and is now working correctly. +* **Increased the confirmation on mine size from 25,000 to 50,000 blocks so as to minimize the number of times this will occur.** -* **Removed the remainder of the ladder/rank permissions that were never used.** +* **Add support for specifying the sound to use for inventory full event.** +Valid sounds can be listed with the command /prison utils sounds list. -* **Start to setup MineBombs basics.** +* **Added support for doubles in the AutoFeatures settings.** +The basics were there, but the actual AutoFeatures enum did not have them hooked up. -* **Add to the World object, a function to set the block.** -The SpigotWorld class uses prison's compatibility functions to perform this action. +* **Remove an unused function on the PlayerCache.** -* **v3.2.10-alpha.12 2021-08-16** -Released alpha.12 +* **Bug fix for mohist, or other platforms that are trying to use SuperPerms, or other perm plugins that do not support groups.** -* **Updates to fix the prestige issues.** -Moved more of the processing in to the PlayerRank object to reduce issues. Shutdown one of the constructors since it could lead to the wrong amounts. -Prestige was fixed by rewriting the way the rankup handled the ranks and playerRanks. +* **Add *all* to the command /mines set tpAccessByRank.** -* **Fixed an issue with logging when using a debug target mode.** -It was not logging when the global debug was off. +* **Add '*all*' as an option for applying Access by Rank for mines command: /mines set mineAccessByRank.** -* **Added some rankup debug logging details.** -Enable with `/prison debug rankup`. +* **3.2.11-alpha.13** 2021-12-24 -* **v3.2.10-alpha.11 2021-08-15** -Bump the version +* **Prison command handler: adds the ability to add new aliases from the config file.** -* **Changed the /ranks info to show the ranks multiplier information.** +* **For ranks that are null, made some changes so either empty strings are used instad, or most of the time the rank name is used.** -* **Work on /ranks list to improve the content to better present the rank cost multiplier.** +* **Fixed a potential issue with nulls in the language file parameters. All nulls are replaced with empty strings.** -* **General changes to code that uses getRank() that returns a PlayerData object... ** -Since that is a player's instance of a rank, this may be null for a lot of players. A lot of the old code would not take in to consideration that there may be no value, so hence the NPEs that we've been seeing. This should address a lot of the potential issues. +* **Added the ability for admins to add aliases to commands so they can better customize their environment.** -* **Found situations where players are not on a ladder and its causing issues.** -Need to expand to other code... +* **Disable block break events in the worlds where prison commands are disabled.** -* **Bump to v3.2.10-alpha.10f.** -Will be trying to release a more formal alpha later today. +* **Added the ability to disable prison command hander is specific worlds.** +The settings are within config.yml. The disabling of prison is only done on the command handler, and will soon be hooked up to the block break events too. +The command /prison now lists worlds in which prison has been disabled -* **Fixed a typo in the name of a function. Prevent a possible NPE. Revised how one of the PlayerRank constructors works so it will actually calculate the correct multiplier.** +**3.2.11-alpha.12** 2021-12-21 +Alpha 12 released. -* **v3.2.10-alpha.10e 2021-08-13** +* **Fixed issue with XMaterial when trying to parse a custom blcok that is not compatible with prison.** +The function will now return a null value and everything that uses it, must ensure it's not null before trying to use it. -* **More adjustments to rankups and PlayerRanks.** I think I've addressed all issues with ranks. +* **Make sure the targetBlock is not null before trying to process it.** -* **Remove three redundant ladder commands dealing with ranks: listranks, addrank, and delrank.** +* **Docs: Updated the LuckPerms Tracks and Groups document to provide more details on how to set them up.** -* **There was a report that the mine would continue to reset after it was deleted.** -Cleaned up a few things and added a boolean field to indicate it's delete. If its set to deleted, then it will prevent the resets from happening. Just as a safety check. Not 100% sure that this was actually an issue. +* **Bug fix: Ran in to a rare situation where the use of essentialsX economy failed to allow prison to load the players during startup.** +Prison was trying to "rank" the players within each rank that they were in, and that required prison to get their balance.... but bukkit was not able to return an OfflinePlayer instance for any of the plyers. Therefore prison could not access the player through vault. No idea why bukkit is not able to provide the players. The server in question had about 2500 players. +So to prevent this from happening, the initial ranking bypasses the loading of any monetary amounts; they will be updated later. -* **Setup the AsyncPlayerChatEvent listener within Prison to be able to dynamically set the priority based upon a new setting in the config.yml file.** +* **Update and create some new LuckPerms docs.** -* **Bug fixes: Fixed some issues with the use of the new PlayerRank object.** -They were not always not-null, and there were some instances of the wrong variable being used. +* **Move gui tools menu changes to improve them and hook them up to menus that did not have any paging.** -* **Fixed an issue with the regular expression block quote... didn't need the second backslash.** +* **Adjustments to improve the way the new gui tools work to reduce the amount of use of lore, or at least the visible lore.** +This visually cleans it up a lot. -* **Bug fix: Fixed a few issues with PlayerRank object not being set correctly everywhere.** -Was also checking the wrong object for null. These fix about 3 different NPEs. +* **Hooked up some of the new features to the /gui ranks menu, plus added a /gui ladders and hooked that up. Simplified how the ladders page was setup.** -* **Removal of the obsolete ranks related permissions and permission groups.** -This was a failed attempt to automate the user of permissions with ranks. This did not work, since vault does not support the creation of permission groups, plus a few other issues and limitations with vault. +* **More work on the GUI menu tools to not only get them to work better (correctly) but also add new capabilities... now supports adding a menu option and the tool auto assigns it to the next available slot.** -* **Initial setup of ladder rank cost multipliers.** -All ladders a player has, will contribute to the total rank cost multiplier value, and all ranks for that player will have their cost adjusted. -Overall this will allow an increasing rank cost as players rankup on the prestige ladder, and/or it can help reduce rank costs if donor ranks provide a negative adjustment. -Currently there is no way to set the ladder's multiplier... that's next. But everything else is hooked up and should be functional. +* **GUI menu tools update...** -* **v3.2.10-alpha.10 2021-08-11** +* **Prison Tokens: Remove the alias so they will not cause conflict with other token plugins.** -* **Added a missing ranks message: when removing a player from a rank and it fails.** +* **Potential bug fix: There was a situation where with multiverse-core a delayed world loading resulted in the world not being found**, and therefore it was preventing the loading of all locations tied to the mine. This now allows the locations to be loaded without a valid world. Then when the world is finally loaded, it will refresh the references to the world objects. -* **LocalManager.getLocale: Fixed an issue with player being null when the player object originated from a task processing offline players.** +* **GUI Menu: a few minor changes before more radical changes to go with the final "idea".** -* **Added the event level MONITOR and changed the event listeners to only register the MONITOR event when the config is set to MONITOR.** +* **GUI Menu Tools - Added a first page and last page button.** -* **Updates to the JumboTextFont by adding most of the lowercase characters.** +* **GUI Bug fix: If there are more than 45 ranks on a ladder, the GUI will NOW be able to provide paging capabilities to view all ranks.** +By default it will start off with page one, but this can handle an unlimited number of pages. +This paging system can be expanded and easily used on other GUI lists with minimal changes to hook it up. -* **Alter the use of accessing the player to help eliminate the risk of concurrent modification events.** +* **Found a bug in XMaterial where it was converting "melon" to melon_slice instead of the melon block.** -* **Added a spigot module en_US.properties language file.** +* **Bug fix: Fixed an incorrect use of XMaterial which prevented it from working properly with spigot 1.8 through 1.12.** +It was using XMaterial to get the Material value, which is wrong, since it's the item stack that contains the variants of the materials. So the change is to extract the item stack directly from XMaterial which solves the problem. +Also there was another error where if amounts are greater than 64, setting them to 1 so the GUI will still work, but it will suppress the incorrect counts for the itemstack. -* **Added a new function to the PrisonEventManager to return the list of event listeners as a string so they can be logged to the console, or through helpch.at which is not yet hooked up.** +* **Update XSeries to v8.5.0.1 to better support spigot 1.18.** -* **Added JumboTextFonts to prison support submit ranks.** -Fixed a few issues and added more characters to the fonts. Added /ranks info all to the ranks output for more detailed information. +**Prison tokens: Add a few more prison tokens placeholders.** +Fixed the admin token commands to use longs and not integers. -* **Found and fixed an obscure bug with regular expression quotes.** -It was duplicating text and making the results much larger than what they should have been. +* **Ranks GUI Error.** ~~Fixed an error with Ranks GUI.~~ This did not fix anything. -* **Created a JumboTextFont to be included in the prison support submit documents.** -Hooked up to mines. This will make it easier to identify the various mines in the listings. +* **Some adjustments to admin token functions.** -* **Add the capture and display of all support submit URLs in each additional submission.** +* **Bug fix: Rankup on a ladder in which there is not already a rank was producing an error.** +Similar to prior problem... just did not fix it correctly for all situations. -* **Expand '/prison support submit mines' details by including the '/mines info all' command.** -Had to redesign some of the mine commands to be able to capture all of those details. Added a table of contents to the submission so it's clear all these details are included, since it could be a HUGE file. +* **Start building the structure for the Top N rankings.** -* **Added 6 new placeholders to provide the whole line for the prison_top_mine_block_ plus the heading and total line.** +* **Mine Bombs: Noticed the player inventory was not be "updated" through bukkit.** +This could help prevent wrong item amounts. -* **Placeholders with _nnn_ numeric ranges: Fixes a potential problem of where it was unable to match a placeholder if placeholder escape characters were not used.** -Now it will properly identify and match the series. +* **Mine Bombs: Set them up to auto refresh the data structure that is being saved, if it is detected that there has been a change.** +Added a version number to the mine bomb save data structure so as to use that to detect when the structure changes. That number will be updated in code when it has been modified. So when running the mine bomb loader, it will detect that the saved data is in an older format, and so it will rename the old file to preserve it as a backup, then write the new data to the file system. This will allow new fields to be added,and then they will appear in the save file upon the next restart. This will make it easier for admins to update and use the new features. -* **Fixed a problem with block constrains, the min number of blocks, when no blocks were initially added to the mine.** -When revisiting to ensure the min amount is set, it did not have the correct values set for the ranges. -This has been fixed by adding a low and high limit field that not does record the actual block positions of this block type, but of the limits as defined by the constraints. This allows adding more blocks to reach the min amount, when no block has been added before. +* **Bug fix: Was causing a null pointer exception when trying to add a player to a new ladder.** +This now correctly gives the player the requested rank, or if not specified, then the lowest rank on that ladder. -* **Prevent the use of % in the ranks and ladder commands.** -Could not use them before, but they would cause errors when messaging details about the commands. Now the command will be rejected and it will have to be submitted correctly. +* **3.2.11-alpha.11 2021-12-07** -* **ButtonLore Utility got a couple of new methods.** +* **Mine Bombs: A few other minor fixes and changes.** -* **Some GUIs were still using the old deprecated buttons. This got fixed.** +* **Mine Bombs: Some changes in how they are setup. Added a bombItemId which becomes line one of the lore and is used to identify that it's a mine bomb.** +Added a nameTag that is used to put a nameTag on the armor stand. Added a itemRemovalDelayTicks field to better control when the armor stand is removed (exact time). +Update a lot of Mine Bomb code for creating the time, placing the item (armor stand) etc... It's working better overall. -* **All GUIs got a new common lore Format.** +* **Update Tokens to fix an issue with the admin set.** +Added better tracking of adminAdded and adminRemoved stats. -* **All GUIs now use ButtonLore utility and lore format.** +* **Bug fix: Fixed a class not found except caused by google guava trying to load functions that it should not have been using for their event manager.** +Moved the PEE event out of this class all together, so now it's safe to use in other areas of prison, such as with guava's event handler. This was not an issue with spigot 1.8.8, but manifested itself with Spigot 1.16.5 since I believe that version of spigot is using a newer version of guava that has that behavior. -* **Fixed an issue with spigot 1.17.1 where they appear to be extending the BlockBreakEvent for FurnaceExtractEvent but not isolating the listeners.** -Forced to check to ensure the event is actually a BlockBreakEvent to ensure the correct event is really being fired correctly. +* **Upgrade XSeries to v8.5.0** -* **Added prison's version to the chat display's title.** -is will help support since it wil help show us what version someone is using. +* **3.2.11-alpha.10 2021-12-05** -* **Added the recording of earnings per mine.** -The add earnings must be called within the time limit as defined by the session timeout for mining, which is currently 15 seconds. -If something is sold outside of that session timeout, then it will not be attributed to the mine. +* **Bug fix: There was an issue that I found where blocks outside of the explosion events were being marked as mined without actually being broken.** +Therefore prison would not be able to break those blocks. This was caused by the initial explosion setting off a chained reaction explosion through a blockEvent. Now blocks that are part of an explosion cannot be part of a future explosion. -* **Minor design changes to the main GUI /gui**: to apply them you should reset (delete it) your en_US.yml at this path -> - Prison/module_conf/lang/en_US.yml. More changes will come in the future. +* **Added a new debug mode to inspect blocks by click on them with the mine wand tool when prison is in debug mode.** -* **ButtonLore is quite ready and already in use for the /gui main GUI, only the first page uses it.** +* **Renamed Prison's PlayerListener to PrisonPlayerListener to reduce a conflict and to make it more obvious which object is which.** -* **Started working on a new ButtonLore Utility that will be included in the SpigotGUI Utility.** +* **For the bukkit 1.8 through bukkit 1.12, if an object has a different data value than what it normally has**, +it would not be matched through XMaterials... Examples are leaves, chests, etc... if there is no match initially using the block then try to then match on just the name, which eliminates the problem of a failed match. -* **v3.2.10-alpha.9 2021-08-04** -Released... -Upgraded gradle to use v6.1.0 of Jengleman's ShadowJar... was v5.2.0. +* **Add a selective debug option where only the selected element is loged through the debugger.** -* **Modify the block break events to merge most of the preliminary processing from all of the different kind of block events.** -This enables a single function to be able to handle most of the initial setup processes for all of the different block break events. This will reduce the amount of code, eliminate possible errors, and make it a lot easier to enable more events to be processed. +* **Removed the DebugTarget value of "support" since it is not using anymore.** -* **Add the option for using '*all*' for mine name for adding block events, which will add the event to all mines.** +* **Bug fix: If a block has been placed in the mine that should not be there, prison was canceling the event which was preventing other plugins, or normal breakage, from breaking the block.** +The event is no longer being canceled. -* **All GUIs now use PrisonGUI Utility, finally it should be done now.** +* **Added 12 new placeholders: 4 new ones for player balances and 8 new ones for tokens.** -* **2 more autofeatures GUIs now use PrisonGUI Utility.** +* **Prison tokens: Added admin functions of balance, add, remove, and set.** -* **All SellAll GUIs now use PrisonGUI Utility.** +* **Added the title and actionBar to the Player object so it will work in all forms of Player, such as RankPlayer.** +Had to use the Platform to cross over to spigot from core. -* **All Mines GUIs now use PrisonGUI Utility.** +* **Added access to the player cache within the Player object so it's easier to use it.** -* **Disabled some old Block model code in use for GUIs.** +* **Updates some documents.** -* **Mines Blocks List GUI now uses PrisonGUI utility.** +* **Bug fix: One of the blockEvent placeholders was inserting the wrong value.** +{blocksMinedTotal} was inserted the blockName. -* **Fixed Mines Blocks List GUI (the one that shows the blocks currently in the mine).** The GUI wasn't translating -correctly blocks, and showing a "barrier" instead of the block, the GUI was working anyway, just - not good looking, now it's fixed for newer versions. +* **Slight adjustment to the mine backups's file name.** -* **Mines Reset Time GUI now uses PrisonGUI utility.** +* **Move the messages for /mines tp to the language files.** -* **Mines Set Notification Mode GUI now uses PrisonGUI utility.** +* **3.2.11-alpha.9 2021-12-02** +Version v3.2.11-alpha.9 -* **Mines Notification Radius GUI now uses PrisonGUI utility.** +* **Added a new feature to back up a mine and to provide a way to convert a mine to a virtual mine.** +When converting to a virtual, with the command '/mines set area virtual', a back up is made first. +The new backup command is '/mines back help'. -* **Mines Blocks Set Percentage GUI now uses PrisonGUI utility.** +* **added mine name to reset notifications** -* **Updated Buttons PrisonGUI Utility to support enchantments.** +* **Bug fix: If a MONITOR event listener, then it should not process the block break event.** +Monitors were processing the block break events when they shouldn't so monitors are not terminated after validation since their "processing" is handled there. -* **For the fortune calculations, converted the use of the old block model over to use XMaterial instead.** -Updated to include the newest 1.17 blocks too. +* **Bug fix: The command '/mines reset *all* details' was not working and was only running one mine reset instead of all mines.** -* **Updated smelting to use the newer 1.17 blocks, such as all of the deepslate variations, and the raw iron, raw copper, and raw gold.** -Updated all code that had these variations. +* **Rank data refactoring. A few changes to get this working. The ladderRanks collection was not being setup was the main issue.** -* **Updated the XP calculations to include the newer blocks from 1.17** +* **Rank data refactoring. A few changes to get this to work well.** -* **Upgrade XSeries from v8.2.0 to v8.3.0** +* **Major refactoring of Rank Player data objects.** +This is to transition to easier use of player objects in prison. Some of the key classes have been moved from Ranks module to Core module, with the removal of rank functions being moved back to the ranks module. +This is a work in progress and does not yet work. The player's ladders and ranks have not been linked together yet. -* **Remove the dump of block break events from the command /prison version all since it was appearing first.** -It will need to be rewritten to capture in a list of strings. +* **Fixed the auto sell command within the auto features to include the ability to use autosell based upon the auto features settings.** -* **Added mining time by Mine.** -This will also track in which mine, players are mining. +* **Fixed issue with a block break event happening outside of a mine, which will result in mine being null.** -* **Found a bug in the TokenEnchant event listener class.** -It was casting to the wrong class for the Monitor event. -* **Fixed an issue with PlayerCache and mining duration.** -Also added logging if unable to rename a temp file. +* **Fixed issue with getMine not striping color codes, but in the function before this one is called, it strips them to check to see if the mine name is valid.** -* **Added support for jumbo and full ladder types with the mine liners.** -* **Update the custom ladder type feature in mine liners.** -Now you can select none, normal, and wide. +**3.2.11-alpha.8 2021-11-28** +Release v3.2.11-alpha.8. -* **Provide break the list of placeholders down by placeholder types, along with sub total counts.** -Also added total count at the top of the list. Breaking down the large list in to sub-types will make it easier to read the list. +* **Update the last seen time.** +But will not set dirty. If player is not active, then it will not be recorded. -* **Provided a way to specify a last next rank message for the placeholder:** -prison_rankup_rank_tag_default -This will only apply on the default ladder and when the next rank tag is empty. +* **Expand the last seen information on the command /ranks player, which now includes how long ago instead of just a date and time.** -* **Started to look in to providing the ability to import player ranks** based upon perms, but ran in to an issue that if the player is not online, then it can be very difficult to get their actual perms. Would not be able to get a listing of all perms, as if they were online, so it would make this less flexible. -This has been canned because the person who was needing it, is no longer needing it. May revisit in the future. +* **Add a listSeenDate to the player's cache data.** +This will be used to track when the player was last on, and more importantly, determine if the player's cache data should be updated for stats reporting for top-n functions. -* **About 56 new placeholders!** SpigotPlayerUtil has been updated to provide support for all of the functionality that it needs. It's been hooked up to the placeholders so they should be functional. +* **Fix a rare condition where the wrapper of the PrisonBlock is null (the actual bukkit block).** +This may not fix everything related to this issue, but it will prevent a NPE at this location. -* **Setup the Platform to be able to provide a SpigotPlayerUtil object.** -This is needed for placeholder support and a few other things. +* **Minor changes to clean up auto features a bit:** move functions that are no longer used in the normal block break code to OnBlockBreakPlayerManualCore so it's not confused with the main-core functions and accidentally used. +Also clean up the messaging and sellall usage to eliminate duplication. -* **There was a concurrent modification exception on the line with** `playerData.setDirty( false );`. -These changes will not prevent that issue, but it will trap it so it does not register in the log files. If this happens, then the player's cache will be saved on the next attempt. This should be a rare event. -The changes needed are more complex that this simple "fix" and will be made in the near future. +* **Fixed an issue with the mine state mutex being null.** +Not sure what's causing it, but I suspect it mabe an issue with loading the mine from a saved state on server startup and that field never gets initialized. So fixed it by doing a lazy initialization on the field. -* **Prison Mines Blocks Set Percentage GUI now uses PrisonGUI Utility.** +* **Fixes a minor issue with the command '/mines set spawn' where it was requiring an option be specified.** +I fixed it by setting a default value of "set" which does nothing, but makes the optional options, optional now. -* **Prison Mine Blocks List GUI now uses PrisonGUI Utility.** +* **Removed from the GUI the hologram on inventory full, and replaced it with actionBar.** -* **Prison Blocks List GUI now uses PrisonGUI Utility.** +* **Some adjustments to the overflow of the drops and other inventory controls.** +On normal drops, disconnected autosell except if it is forced through the pmEvent. +Fix inventory full sounds. For 1.13 and up it had the wrong sound file. Using something less harsh than anvil and turned down the volume which was horribly excessive with the volume set to 10, when normal is 1. -* **Fixed some errors of the Prison Mines Blocks Set Percentage GUI:** There were some ArrayOutOfBonds exceptions. +* **Prison Tokens: Prison now is able to auto generate player tokens based upon blocks mined.** +It's enabled through AutoFeatures config file's setting 'tokensEnabled' and is able to set the blocks per token earnings rate with 'tokensBlocksPerToken'. +More features will be added soon, such admin functions and top-n token holders.... etc... -* **Auto Features: Added food exhaustion calculations.** -Now on each block break, Configurable to be disabled. For explosions events, only applies to the one block they actually mined. -* **For various add commands, the messages for the 'placeholders' was being sent to the console instead of the player issuing the command. This was an issue in game, but not the console.** +* **3.2.11-alpha.7 2021-11-26** +Released alpha.7. Major advancements to mine bombs. -* **Placeholders durability: add support for a percentage and bars.** +* **Mine Bombs: Added the use of a armor stand for holding the item, with an animation of swirling it around.** +The item's armor stand is managed in a task which removes itself when finished. This process is independent from the visual and sound effects. +Removed the static functions that were being used (which is much better). -* **3 new Backpacks GUIs for admins now use PrisonGUI Utility.** +* **Mine Bombs: Added more effects to the examples.** +Removed some that would not work. These are not perfectly selected and may not work for most versions of spigot. The visual effect do not appear to really do much. -* **Bug fixes with the setup of token enchant event listeners.** +* **Mine Bombs: Setup some changes in how classes are related to each other so as to prepare for significant changes.** -* **Added many more features to SpigotPlayerUtil and getting ready for the new placeholders.** +* **Mine Bombs: Got the sounds and visual effects hooked up to the explosions.** +Made many revisions on how all of this works, but pushed the tasks to a new class PrisonUtilsMinBombsTask. -* **Started to add a PlayerUtil and SpigotPlayerUtil to prison.** -This will allow an easier access to specific player values in other parts of prison with just a single call to a util function. This will be used with a number of new placeholders. +* **Mine Bombs: Updated the listings of the mine bombs, which now includes full detail including the visual and sound effects, the list of shapes, list of sounds, and list of visual effects that can be used.** -* **Removal of a function from the prison Player object that is no longer being used.** +* **Mine Bombs: Updated the junit test for validating that the EffectState is sorted in the proper order when using the MineBombEffectsData as a comparator.** -* **A couple of updates for CMI economy.** -Added a note on what value to try first for cmi with prison. +* **Mine Bombs: Setup a test unit test to confirm that the sorting of the EffectStates is as expected.** +Needs to be: placed, explode, finished. -* **Changed some logging information from debug to info so it will be registered when requested by the admin.** +* **Mine Bombs: Add the sound effects and visual effects to the default test bombs.** +NOTE: Some of these settings may not work on all versions of spigot, and some may not work on any version. -* **PrisonEnchants changed the class name of their event.** -This updates prison's code and changes the api jar file. +* **Bug fix: Auto features get drops not always working with explosions.** +The get drops was moved around to help ensure it does not try to get the block drops if the block is not what it is expected. This is now passing the needed object used for the check, instead of extracting it from the target blocks, which have not yet been set. -* **Created a new group within auto features for durability related items and created a new group autoManager just for the isAutoManagerEnabled to get it out of the options.general grouping since that is the main "switch" and it is getting lost in the configs.** -There was too many for the general group, and they were not being kept together, especially since we have a comment now. +* **Bug fix: Auto Features Auto Pickup is now ignored if sellall has not been setup on the server.** +If getting an instance of SellAll when it is disabled, will result in a null value. -* **Backpacks admin GUI now uses PrisonGUI Utility.** +* **Mine Bombs: Added a few new shapes.** +Disk and Ring. Available in each plane x, y, and z. -* **v3.2.10-alpha.8 2021-07-25** +* **Mine Bombs: Added the collections for sound effects and visual effects.** +Both share the same object, MineBombEffectsData. +An effect has a name, plus an EffectState, and an offset in ticks that will apply that effect based upon the EffectState. +The EffectState can be placed, explode, or finished. -* **Auto features: Removed unused classes and cleaned up a few things. Fixed a reference to one of the deleted classes.** +* **Ran in to another Java format exception.** +Not sure what caused this problem, but added it to the catch so it can be reported in details so it can be fixed. -* **Auto features events: Added an abstract class to manage the unregisterListeners in one place, to eliminate duplication of code.** +* **Add the ability to remove a mine's spawn point.** -* **For the command /prison reload autoFeatures hooked it up to include unregistering all of the event listeners that auto features setup, then it uses the configurations to reregister them all.** +* **Reworked how the drops were processed to prevent dropping the wrong contents.** +There was an issue where the drops were retrieved later in the process that allowed it to incorrectly pickup drops that were related to a decay function. This resolves the incorrect drops. -* **Fixes a major problem with how Zenchantments works because the plugin extends the BlockBreakEvent with their BlockShredEvent.** -It has issues.. but... this ensures that the correct event is being trapped. +* **Player cache timing improvements.** This fixes issues with tracking the timing when mining. +Not 100% sure it is perfect, but it's actually working much better. Will need to revisit later. -* **Change to player cache field that was not so clear with it's name.** -It's supposed to be the config field name, but the description did not reflect that. +* **Added a check to detect that a block has been altered and is not the block that was placed there by the mine reset.** +There have been drops of other materials making it in to an explosion event, and mostly due to block changes that happen due to other means. -* **Fixed GuiUtility button add lore method:** The method to add a line to an already existing button got now fixed. +* **Refactored some of the checks to determin if the event should be processed or not, so this can be used with a new feature that may help to auto manage access when WorldGuard is being used.** -* **Adjustments to get the new event listeners working fully. Still need to hook them up to the reloading.** +* **Setup a mutex for locking the mine resets, which prevents active block break attempts, including explosions, from trying to break blocks while a mine is actively being reset.** +This helps to reduce the chance of hitting a concurrent modification exception. -* **Next step in rewriting how the event listeners are setup...** +* **Shut down auto manager and all auto features if the setting 'autoManager.isAutoManagerEnabled' is set to 'false' in autoFeaturesConfig.yml.** +If anyone wants to use prison's block events, then they must use the auto manager. -* **Move the event listener managers in to a common package to prepare to extend them to the non-auto features event listeners.** +* **When using autosell through auto features, if a block cannot be sold, then the block is now placed in the player's inventory, or dropped if their inventory is full.** +If a block is unable to be sold, the amount returned for the item stack will be zero. -* **Rewriting how the event listeners are being registered.** -Added ability to unregister. This is working, but is only for the auto pickups. WIll need more work to hook up to the non-auto manager. +* **Bug Fix: There was originally a problem with applying block constraints that resulted in being unable to select a block when trying to randomly choose one.** +Initially as a first quick fix was to trying to reselect a block, but if the block chances were really low, then it could still fail to select a block. Then it was attempted to select a default block, but that too failed to work, especially if there were a sizable chance for AIR, and it would fail 100% of the time if the was only one block with a very low chance. The failure was the whole mine could be filled with that one block with the very small chance. +This fix completely redesigns the block selection, by first selecting only the blocks that are valid for that level of the mine. That way, when selecting blocks where blocks should be excluded from that level, those excluded blocks are never in the selected blocks to be considered. Also if AIR is a valid option, then this new process adds an AIR block to the temporary level block list with the percent chance assigned to the air. +Overall, this is working really well now, and it actually simplifies a lot of code and reduces the amount of processing involved. This new process always selects a block on the first pass too so it never haves to try to reselect a block. -* **Setup the ability to log more than just the BlockBreakEvent.** -It it mow able to log details to Lists so they can be included in other output, such as support submits. +* **Moved the multi-column formatting of data to the class Text so it can be used in other parts of the project.** +It was originally created for use in /ranks player but is now extended to be usd to list the plugins within the /prison version command. -* **Rewrote how the event listener is registered so the priority is dynamic.** -This appears to be working well. +* **Bug fix: If player is mining outside of a mine, then don't process anything.** +May want to allow prison to manage block breaks outside of mines in the future, but for now, prison is only managing mines. -* **clean up some of the /prison version all commands to better reflect the actual details with dependencies with the settings for auto features.** -This should help better convey what the settings are doing, especially when a setting disables another setting. This should help reduce support issues. +* **3.2.11-alpha.6 2021-11-21** -* **Prestige confirming fix:** Fixing Prestige confirm by chat or GUI when possible. +* **New feature which lists all of the Player Cache stats in the command `/ranks player`. This includes stats for block breaks, time spent in mines, and earnings per mine.** -* **v3.2.10-alpha.7 2021-07-23** +* **Capture an error within prison's Output class when trying to log content that has an UnknownFormatConversionException error.** +This happens when there is a problem with text formatting characters that conflict with Java's formating class. This tries to log the error with better details so it can be fixed and resolved where the error is happening. This does not "fix" the problem, but just better reports it so it can be identified and fixed. +* **Update on how prison manages the tracking of block breaks and earnings when auto features has autosell enabled.** -* **Fixed the way some of the autofeature block settings were named.** -They had "autoBlock" when auto has nothing to do with it anymore, since those setting will be applied for normal drops too. -Fixed an issue with auto smelt and auto block where it was not using the config settings, so now it's working correctly. -Added more debugInfo messages to better understand what's going on when something is not working correctly. +* **Changes to how the event listeners are setup: reduced by 1/3rd.** +Used to be that all three would be set if autopickup was enabled, but now only two will be set... monitor, and then either autopickup or manual drops. +This should improve performance since prison will be processing 1/3 less events. -* **Added a note on how fortune works... it's been confusing...** +* **3.2.11-alpha.5 2021-11-19** -* **Updates to the liner to allow the use of '*all*' for the mine name to apply the same pattern to all mines.** -For auto configure, ensure that the random liner applied to the mines is not remove, removeAll, or repair. +Post the alpha.5 release. -* **Prevent slime fun from registering if it is disabled.** +* **Remove the now obsolete auto features setting isAutoSellPerBlockBreaknliedEnabled.** +It is no longer needed since the auto features autosell per block break is now optimized and has no impact anymore. +Improve the autosell integration in to the auto features for both the auto pickup and also the normal drops. Improved the debug logging to include a list of all blocks being sold, or dropped, and their quantity and value. Also the total counts too. -* **Fixed a problem with the registration of the events failed due to the parameter of ExplosiveEvent.** -Had to set it to Object to allow it to be registered when the plugin and class does not exist on the server. +* **Bug fix with SellAll: bug in original logic where the delayed notification when initialized is losing the first amount.** +It now always adds the amount to the delayed queue. -* **Added more internal debug details.** +* **Autofeatures ignore certain events to improve performance and reduce logging entries when in debug mode.** +Since there are multiple listeners on block break events, which monitor the same event, these changes are able to mark a specific block within the MineTargetPrisonBlock objects that will be able to pass along an "ignore" event status to the other listeners to short-circuit their processing. This is highly beneficial when using large mine bombs and the mine has blockEvents setup to perform explosions... which will help reduce a ton of "dead" events. -* **Mine liners: Added glowstone and also added the ability to apply a liner change, or removal, from all mines with one command by using `*all*` for the mine name.** +* **Auto Features Forced Auto Sell Optimization Improvement: AutoSell within auto features now only uses sellall by item stack and not the player interface that accesses all of the player's inventories.** +Since the auto features items are not placed in the player's inventories at this time in the process of auto features, there is no reason to access the player's inventories. Selling directly reduces a lot of sellall overhead and as a result sellall is just calculating the prices. +The old autosell code within autofeatures has not be removed yet, but it cannot be called anymore. -* **Add the debugInfo to more functions and a few more messages.** +* **PrisonDispatchCommandTask: Removed the debug logging since it can be very numerous when used with a large mine bomb and it's pointless since most of the block events being submitted runs in less that one millisecond.** +So this is just cleaning up a messy logging item. -* **Changed the debugInfo variable to a StringBuilder instead of just a String.** -This will provide a little bit of a performance improvement, plus it can then be passed in to the functions to gather more information. +* **SellAll: Setup a sellall function that will allow the selling of one ItemStack, which is not tied to any of the player's inventories.** +This is used in prison's auto features when enabling the option to auto sell on a per block break event basis. This is highly optimized and a lot faster than using the normal sellall since it does not deal with any of the player's inventories or backpacks. +This forces a delayed sold amount message since an explosion could includ many ItemStacks. -* **A few minor adjustments to better identify the function that is running when logging the debug information on BlockBreaks.** -Tweaks to the PrisonEnchant's plugin code. Missed a few changes. +* **Mine bombs: Add cooldown and fuse delay to the mine bomb settings so each bomb can be customized. +Added gravity to the mine bombs too.** Gravity, like glow, was added in minecraft 1.9 so older versions won't work. -* **Changed some of the DebugTarget names to better reflect where in the project they are occurring.** +* **Bug fix: For TokenEnchant's explosive event processing,** need to set PrisonMinesBlockBreakEvent's setForceIfAirBlock( true ) so the explosion event can be processed, even if the initial block has already been processed. +This allows TE explosion events to work correctly now. -* **Bug Fix: If a message is removed, such that there is nothing left of the = character in the language properties files, it will now not throw an index out of bounds exception.** -Removal of the message was not expected and there was unable to handle that situation. +* **Bug fix: refined the use of a few internal registers that are being used to control block break behavior, and also block counts and block events.* +A few of the settings were being changed in the wrong places, which was out of synch with when they should have been applied. +A few of the side effects was failure of tracking block counts, block events, and handling some explosion events. -* **Added support for 4 new types of placeholders that uses the PlayerCache:** -Player's total block count. And player's count per mine. +* **Mine Bombs: More features and fixes.** +Added support for radiusInner (for hollow sphere explosion shapes), removalChance (chance for block inclusion), glowing, autoSell, tool material type, tool fortune level. + Added a new shape which is "cube" and hooked up sphereHollow. Hooked up cube, sphereHollow, removalChance, glowing, the specified tool in hand with the custom fortune level. Did not hook up the forced autosell yet. +Fixed some issues to get things to work a little better too. -* **Issue with using offline players with the playerCache.** -The playerCache should typically only contain active players, but in testing, like using /prison placeholders search, it may add an offline player to get placeholder data from them. -This prevents null issues with the locations, and eliminates the excessive error message when trying to use getLocation() on an offline player. +* **Prison Bombs: enabled the right clicking of AIR to set the bombs.** +If clicking air blocks, then the block tied to the event will be null (at least for spigot 1.13.x) in that case, will use the block location of the player, and then adding the player's vector to it times three. -* **PlayerCache changes: Start to take in to consideration that a player within the cache may be offline.** -If that's the case, then prevent some calculations, and remove them from the cache. Offline players would be added to look up some stats, but then they would be safe to purge. -When checking the timerTasks, add an earnings of zero to purge past earnings. This will prevent the average earnings from staying there forever when the player stops mining. +* **Fixed a bug with how the regex handles block quotes.** +Not only was it not working correctly for multiple block quotes, but it was incorrectly handling the tail end of the processed text and was basically doubling the text. It now works correctly, even with multiple block quotes. -* **Added a debug logging entry for XP Calculations.** -This will be able to provide detail infomation on if it's working and what the results are. +* **Fixed an unexpected "bug" with the JumboText font for the letter Q.** +One section was setup to use "\Q" which is an escape character for a regex block quote. This was causing problems since it was forcing large sections of text to be ignored when translating minecraft color codes. By changing it to "\q", a lower case Q, this eliminated the translation from making the mistake. -* **Add support for PrisonEnchants' ExplosiveEvent.** -While adding support for the ExplosiveEvent, found a few issues and fixed them. Some changes were just in names of functions, others were functional, such as improving the support of unbreakable and blocks that fall outside of a mine. +* **Bug fix: The command "/prison support submit ranks" was passing a null sender, which is valid when generated by this support tool.** +The fixes now works well, and treats the null basically the same as an OP'd player, or the command being ran from the console. -* **Simplified how the title, subtitle, and actionBar are setup with the /prison utils titles title command. ** +* **Bug fix. If a null message is sent to this function, it would cause a NPE.** +This now prevents a few failures from causing potential problems. -* **New Feature: Prison now tracks average earnings per minute.** -If you have auto sell enabled (sell upon each block break, see autoFeaturesConfig.yml) then prison will be able to report your average earnings over the last 5 minutes of mining activity. -`prison_player_balance_earnings_per_minute` prison_pb_epm -`prison_player_balance_earnings_per_minute_formatted` prison_pb_epmf +* **Fixes a concurrent modification exception when the PlayerCacheCheckTimersTask is running.** +This happens rarely when a player is logging off while "trying" to process their entries; they have been removed. +So when this happens, the process retries to start over a total of 2 more times and it skips processing players that have already been processed. Any update that was skipped would be covered in the next pass with no real loss. -* **Rewrite how the player uses title, subtitle, and actionBar for the /prison utils titles command.** -Spigot 1.8 does not support any of this. -Spigot 1.8.8 is when this was introduced. But 1.8.8 does not have actionBar, so instead it shows the message in the subtitle. -Spigot 1.9+ are able to display title, subtitle, and actionBar at the same time. +* **The use of a command placeholders for `{actionBar}` and `{title}` were added to the placeholder enumeration so they are included in the placeholders listings.** +The support for these two commands were added a while ago, but because they were not added to the enum, they were not being listed in the help. -* **Release of v3.2.10-alpha.6 - 2021-07-19** +**3.2.11-alpha.4 2021-11-01** + Released alpha.4. -* **Try to better handle situations where integrations fail when integrating.** -Now has the ability to disable the integration and remove it when it fails. +* **Changes to improve the way the upcoming mine bombs.** +They are currently non-functional. -* **New feature: prison utils titles.** -This enables sending messages to the player's console as either a title, a subtitle, and/or actionBar. Can also clear, reset, or set the timings on the titles. -All three can be sent through the title by using a double colon to indicate the various parts. -For example: 'Hello Title!::Subtitle is Here!::I'm on an actionBar!' +* **Adjustments to get block events, such as decays, to work correctly with the new auto feature block event handlers.** + Block events were moved to be processed after the block is broke. Also if a block has already been processed, it now will cancel the event to prevent normal block breakage when none should happen. +At this point, the new auto manager appears to be working really well. -* **Add feature to Auto Features to prevent tools from breaking or being used when durability is equal to or greater than maxDurability.** +* **Changed the location usage with block event placeholders, which now uses the location that is tied to the targetBlock instead of the mined block.** +The mined block may be null so it's not stable. -* **Added some documentation to the ExplosiveBlockBreakEvent so users can better understand how it should be used.** +* **Fixed an issue with /mines block list when an incorrect mine name is used.** +Now displays an error stating the name is invalid. -* **This is an example of an explosive block break event that should be used so prison can monitor for it, and consume it.** +* **Starting to add some video documents for prison.** -* **More adjustments to the Taiwanese language files.** +* **Fixed an issue with adding a non-block item to a mine.** +It now validates that the specified item is a block. Also if a specified block is not in a mine when trying to remove it, it will now display a message indicating that nothing was removed. -* **More tweaks to player cache file saving... ** +* **Major rewrites to how auto features work.** +Using the PrisonMinesBlockBreakEvent object to carry all of the various parameters that are used within the auto features code. This allowed the elimination of many functions since they have been combined together. It also allowed for more efficient handling of explosions by combining similar blocks together and processing them as a single unit, so massive explosions are handled far more efficiently. If the admin chooses to break the blocks in another thread, then handling of many blocks is optimized to reduce the overhead. The state of the blocks being broken are being tracked through the MineTargetPrisonBlock such that it's flagged as soon as it starts to process the impacted blocks so as to prevent the same block from being processed more than once, even when there are many explosions occurring at the same time. Changes to the block (block break) has been moved out of the depths of the code, to be closer to the event handlers so it's easier to monitor/track. +Due to the many changes and major alterations to the logic, this is a work in progress and needs more testing. -* **PlayerCache adjustments for timing tracking. A work in progress.** +* **Async Mine Reset performance Improvements.** Adjustments were made to improve the performance of the asynch mine resets by providing the ability to fine tune the page sizes, and also provide the ability to reset more than one block in the synchronous thread at a time. This is called a slice. Measuring the actual block reset time with nanos for better resolution. +MineTargetBlockKey class was relocated to allow for the use of sub listings on the synchronized block updates. -* **Updates to he Taiwanese language files.** +* **Cloning a bomb was not complete. Some details were omitted.** -* **Improvements to adding new players to prison upon startup.** -This process scans bukkit's offline players and finds everyone who is not already setup in prison and adds them. -It now uses the /ranks set rank command now. +* **Fix for Potion IllegalArgumentException:** Fixed an error with potions in Player inventories when +using sellall sell, potions aren't supported by now and won't be sold, but at least it won't break +sellall anymore. -* **Added support for zh_TW Taiwanese.** -This is just an initial setup for now. To enable it, set the language in the config.yml file to zh_TW. +* **Switched prison block debugging timing to use nanoTime instead of milliseconds since milliseconds is too large of a unit.** -* **Player Cache: Hooked up block tracking for players.** -Appears to be working as far as tracking blocks that are being broke. It loads and unloads when a player joins and leaves the server so only active players have their data online. Performs periodical updates on saving. -This tracks total blocks, block counts by mine, and block counts by block type. -Starting to setup time tracking. +* **Bug Fix: When using block constraints,** there was a common situation where an AIR block was being used in the top layers because all other blocks were being rejected due to chance. Order of blocks had an impact on this error, when it shouldn't. Now, if a block cannot be selected, the first block with no constraint issue will be used instead. Also found a bug in the applying of the chance to each block. Under some situations, the percent chance was not being reduced for a bypassed block, when it should have. This now will better select the blocks, and better preserve their intended percentage odds of being spawned. -* **More changes to setting up a player cache.** -The basics should be represented, with startup and shutdown of the cache, running a periodical task to refresh the data, running a periodical task to save the data. -No data is processed as of yet, but the cache should be reactive to players logging on and off the server. +**Prison v3.2.11-alpha.3 2021-10-18** -* **Initial work on setting up the Player Cache.** +* **Enable the ability to choose between setting the block to air inline, or through submitting a synch task to allow the blockBreak event handler to finish quicker, which may reduce lag.** -* **Minor SellAll utility changes.** +* **Simplified the configuration of the handling of the block break events.** +Instead of having a separate setting that is a boolean value that indicates it's either enabled or disabled, these are now using the priority value of DISABLED. -* **SellAll Player Blocks List GUI now supports pages.** +* **Add millisecond reporting for the time it takes to handle a block break event.** -* **Minor improvements for GUIs to improve performance.** -* **PrisonGUI Buttons utility minor changes.** +**3.2.11-alpha.2 2021-10-14** -* **Add the ability to play sounds through the /prison utils sound command.** +* **A few updates to mine bombs. They have been disabled so they cannot be used.** -* **Update docs... scale back what we support with WorldGuard regions since access by ranks solves so many problems.** +* **Add the ability to glow the prison bombs when they are dropped/set.** -* **SellAll Admin Blocks List GUI now supports pages.** Note: This was **not** part of the v3.2.10-alpha.5 release. +* **For a couple of rankup messages, using the rank tag now instead of the rank name.** -* **SpigotGUIComponents minor changes.** Note: This was **not** part of the v3.2.10-alpha.5 release. +* **Fixed a compatibility issue with older versions of spigot.** Should have possibly use the compatibility classes, but if a method does not exist, then this will fall back on a string matching pattern. -* **SellAll Blocks GUI now uses PrisonGUI Utility.** Note: This was **not** part of the v3.2.10-alpha.5 release. +* **Changed the message about worn out tool to use the SpigotPlayer's setActionBar() function to prevent overloading console messages.** +* **Bug fix: Logic was corrected to handle the double negative correctly.** +The was an issue with the /mines set area command when the mine's area was larger than 25,000 blocks. They have to enter either "confirm" or "yes". The bug would require them to enter both to create the mine. -* **v3.2.10-alpha.5 2021-07-14** +* **Added an example of possible backpack object to the PlayerCachePlayerData object.** -* **Made the RankLadder comparable and in the RankPlayer changed the map to a TreeMap.** -This should fix the inconsistencies that I was seeing earlier. +* **Adjustments to the new auto features for cancel block break events and block drops.** -* **If a player is detected to be lacking a rank on the default ladder, it will adde the default rank.** -Ran in a problem where getting the current rank for a ladder was failing when it was ran, but worked when stepped through a debugger. +* **Removal of some auto feature commented out old code.** -* **When checking for players not hooked up to prison, prison now ensures there is a default rank configured or it won't try to check the players.** -This change also checks players within prison to ensure they have a rank on the default ladder. +* **New auto features settings: Able to prevent event canceling and also control if the drops are cleared.** +This has not been tested too much, but it may help make prison more compatible with other plugins that are needing to handle the block break events. -* **MineInfo GUI now uses PrisonGUI Utility.** +* **Fortune on a tool was appearing as a negative value: -1000.** +Not sure how it became negative, but this will better deal with negative values. -* **Removed unused imports from some GUI classes.** +* **Added a listener for PlayerInteractEvent.** -* **MineInfo GUI TP Button now has an Arrow instead of a red_bed:** red_bed can't be translated to a legacy block in 1.8.8. +* **Add a new feature to the PrisonSpigotAPI to allow for the creation of a new mine through the API.** +This could be used to generate player mines in a plot world. -* **Fixed performance issues for MinesInfo GUI.** +* **Able to give players bombs, based upon the item type as defined for the bomb.** -* **Added information to the language files on how to use utf-8 text in these properties files.** +* **Significant progress on Prison's Mine Bombs:** +Moved the mine bombs primary classes to the prison core so it's accessible from all packages. +Setup 4 default mine bombs if the commands are used and there are none defined. +Setup a new /prison utils bomb commands to list all bombs and to give players bombs. These are not complete and fully tested yet. -* **Setup prison to ensure all compliers within gradle is using utf-8.** +* **Some initial work to setup the mine bombs configs.** -* **Enable loading utf-8 encoding from the properties files. Java 1.8 is unable load them as utf-8, so this provides a work around.** -At this point, this ensures that if a properties file contains utf-8 encoded text, that it can be packaged in the prison jar, extracted to the file system, then loaded and used and maintain full utf-8 encoding all the way until it hits bukkit. bukkit corrupts it and confirmed it was corrupted in spigot 1.8.8, 1.3.4, and 1.16.5 so its not an isolated issue for just one spigot version. +* **Add placeholders {actionBar} and {title} to the blockEvent listing of placeholders that can be used.** +They are shortcuts for the new prison utils commands. -* **Updated cryptomorin's XSeries to v8.2.0.** +* **For the actionBar and title, translate the color codes so they work properly.** -* **Convert the CommandHandler.getHelpMessage() to return a ChatDisplay object to allow the use of creating clickable URLs in the help messages.** -The help messages now has headers which shows the command that's being listed. -Updated the /mines blockEvent add command to include two docURLs to use as an example; improved the help message. +* **Hook up the auto features notification to use the new actionBar interface.** +This "should" prevent duplicate messages from being sent to the player while the same message is displayed in the actionbar. -* **If a Ladder has a bad rank that is already in another ladder, that rank will not be added to the new ladder that is being loaded.** -An error message is already being logged, but this change will update the ladder to resave it without the duplicate rank. +* **Fixed an error about backpacks and lore transition:** A single lore was being used for the backpacks utility, if a server +was new and fresh, this would've been missing and an error could occur, this now got fixed with the full transition. -* **Clean up Ranks a little more by removing more of the rank position and report failures if a rank is already loaded in another rank to prevent internal failures if a ladder save file is corrupted by manual editing.** +* **Full transition of all messages to the .properties lang:** All messages are now on the .properties file and the old +.yml one is unused from now on, you can delete it and start translating the new one. Please note that some messages may +be wrong, as it's still in a young stage and a lot of messages got transitioned. -* **Removed the use of rank.getPosition() from all saved information within ranks and ladders.** -Position is no longer used to access any rank. It is only used to compare if one rank is higher or lower than another. It's lazy loaded only when it is needed the first time. If a rank is removed from a ladder, or inserted in to a ladder other than at the end, then all ranks in the ladder are set to -1 for the position so they recalculate when they are used the next time. +* **The player cache, when being shut down ran in to a problem if the players were removed when they logged off.** +This function was making a new collection based upon the original player cache copy of players, of which, when a few of the players are removed, then they were resulting in nulls. -* **This fixes a user error situation, which is not a bug, in the listing of ranks.** -The user copied the contents of one ladder to another ladder, without deleting the source ladder. Thus there were two instances of a series of ranks, when there should ever be only one instance of a rank. A rank can be in at most one ladder, or no ladder. -The result of this issue is that when the second ladder was hookedup at prison's startup, it corrupted the ranks in the first ladder. -This works around such problems by changing /ranks list by using the list of ranks within the ladder, instead of using the rank's prior and next associations. -These changes also add the rankId to both the '/ranks list' and '/ranks ladder rankList' commands, and also '-' and '+' notations to indicate a rank is linked to a prior and next rank. +* **Prevented a problem when unloading players, and when a player is null.** +The condition that was causing a null player was that the player was unloaded when the player left the server at the same time when the server was shut down. Basically a race condition with two parallel async tasks trying to shut down the player cache object, each focusing on a different aspect (player vs. server). -* **Simplify the command /mines blockEvent add by removing the permissions and taskMode from the add.** -This was causing too muchh confusion for a lot of people. It should help to keep the add much more basic. There have been alternative commands to modify those settings so it really isn't important to set them on the add. Also odds are they will not anything but the default values for these two fields. The defaults are perms = none and taskMode = sync. TaskMode is not defaulting to inline due to increased risk of lag and prison being falsely blamed for it. If desired, the admin can always change the taskMode to what they need. +* **Hooked up XSeries' Titles to the compatibility class instead of using version specific code.** +XSeries says they support 1.8.8 through 1.17.1. +Deleted the support for the Spigot110 classes since it was only to support the use of the ActionBar and also the Title, which are no longer needed for 1.10+. -* **Bug fix: Fixed an issue where the "on click" events were using the wrong row number.** -The row number was getting incremented at the wrong time. +* **Adding a player messaging component to the PlayerCache.** +When used, this will prevent more than one of the same messages from being displayed at the same time. -* **v3.2.10-alpha.4 2021-07-10 ** +* **For the command /mines set area the confirmation of "yes" was setup incorrectly with being negated.** -* **Few minor tweaks to the mines info command with formatting.** +* **Switch over to using XSeries for the actionBar.** +XSeries claims it works for 1.8.8 through 1.17.1. -* **Added player counts to the rank list command.** +* **Moved all Lores to the new .properties Language file:** Changes to the old .yml language file about Lore messages +won't take effect, only if you edit the .properties file they will. -* **Hooked up the /ranks list all command to the /prison support submit ranks command.** +* **Added the trigger "minebombs" for the utils command bombs.** -* **Add option to /ranks list to include all ranks through the use of the "all" in place of the ladder name.** +* **Adjustments to the BlockEvents and how it handles some of the event types.** +Expanded and fixed some of the settings for prison's explosions, and PE's too. +Added the ability to exclude specfic triggers. -* **Fixed a bug where getting a player was returning a null.** -When that null was encountered, it was not processing the placeholders, especially for the bars. -Not really sure why it was failing, but replaced the use of getting the player balance with the most recent use of RankPlayer's getBalance() works perfectly. +* **Updates to the Prison's explosion event handling to correct a few problems. ** -* **More adjustments on the /ranks list to prepare for listing all ladders.** -Also added a couple of more messages. +* **Fixed SellAll Hand not removing item:** SellAll Hand didn't work properly and got now fixed. -* **Added an error message if there is a failure when using /prison support submit.** -I assumed that other error messages would exist, but having doubts if it always will have other errors displayed. +* **Initial setup of Prison's mine bombs.** +Initially it will be controllable as a utils command, so random chances can be assigned to explosions. -* **Improvements to the /ranks list command.** -Enhanced the header so it's clear which ladder is involved. Also cleaned up the formatting with the tag colors so it does not impact the column alignments. Also doing a little more with injecting the "default" tag so it does not shift the columns. +* **Cleaned up some of the unused variables in the Utils titles command.** +There were plans for more commands, but they were eliminated. This will soon be rewritten to utilize XSeries's classes for these display items. -* **Adds the listing of all mines to the /prison support submit mines command.** -This provides an overview of all mines and is included at the top of the listing. +* **Ran in to a situation where results was actually null. So this prevents a NPE.** -* **Improve the layout of all of the mines with the command /mines list all.** +* **Fixed issue with tool's durability being cutoff right before reaching the threshold.** +Had to change a > to a >=. -* **pasteChat update to keep the color codes.** It will only keep the color codes that start with &, and all others will be removed. +* **3.2.11-alpha.1 2021-08-31** +- Release the first alpha.1 -* **New feature: /prison reload locales. Its now possible to reload the language files that prison uses.** -Added a new debug item to test to see if utf-8 is working: /prison debug testLocale. No, it does not work with utf-8 text yet. -I did confirm that if the properties files are setup with UTF-8 and are a part of the prion jar, that the UTF-8 encoding will properly be saved to the local file system. -The area that I think is causing failures is with the Properties object itself since that is not utf-8 compatible, so it appears. +* **Replace the block with air through a task to get it out of the auto features thread.** -* **v3.2.10-alpha.3 2021-07-09** +* **If the settings isPreventToolBreage is enabled, then don't allow the tool to break.** -* **reformat the /mines list command to mak it easier to read** +* **Update some messages to be clearer as to what they are.** +Removed the MONITOR from auto features since they should not have the monitor setting enabled. The blockBreakEvent has the monitoring event. -* **Added support for prison support submit for ranks and ladders, and also for mines.** -These two new commands will submit the raw json files. +* **Trying to fix an error related to SpigotRankManager GUI:** I can't reproduce the issue but the NPE shouldn't +give a stacktrace in the console anymore. -* **New Feature!! Major support feature! Send all of prison's configs to paste.helpch.at so we can know exactly how servers are configured.** -This logs the following config files: config.yml plugin.yml autoFeaturesConfig.yml modules.yml module_conf/mines/config.json - SellAllConfig.yml GuiConfig.yml backpacks/backpacksconfig.yml +* **If the primary block was null, which it never should be, then this prevents a failure in this section of code in the OnBlockBreakEventCore.** -* **Added a success message when a player is added to prison's default rank.** -* **Fixed issue with a few placeholders that were not working.** -Was using the wrong translator so a number of mine related placeholders stopped working. -The mineplayers were not working too. The bug was introduced by hooking up STATSMINES. +* **For the initial startup air count task, which is used to "reset" the block counts on a mine.** +This does not change any blocks, but just finds out where the mine was when the server was last shut down. This is needed to ensure we have valid counts for the mines before the first time they are reset. The other way to update these values is to do a full mine reset which is more costly. +There was an inconclusive error that just listed "null" as the error messags, without identifying the actual line number. This error catching was changed to now generate a stack trace so it can be properly fixed if it occurs in the future. -* **Hooked up STATSRANKS placeholders and got rid of obsolete ones. Still more testing needed.** +* **Added a few more reporting entries on the block break handling.** +Reporting how many blocks are being processed and if it passes the validation phase. -* **Added a player check on prison startup that will add all offline players that are not hooked up to prison yet. Plus it will register name changes too.** +* **Some fixes for teleporting and the removal of the teleport glass block.** -* **Added top rank balance placeholders: 6 for now and more will be added soon once these are fully working.** -These are based upon the player's balance within the rank. -Also added a Hesitancy Delay Penalty to help encourage players to rankup instead of trying to dominate a single rank. -These have not yet been tested. +* **Updates to the PrisonEnchant's API.** +Minor adjustments to work with the new API from PrisonEnchants. -* **Added RankPlayers to Ranks.** -This will allow quicker access to all players at each rank, which will help for top ranking reporting. +* **Updates to async block updates.** +Included changes to hook up the CustomItems to work with the async updates. -* **Clean up some rank and ladder function to eliminate the use of magic numbers: both rank ids and ladder ids.** -These were bad, since the objects were already linked together, so using these functions were just adding unneeded overhead. +* **Clarify some of the messages related to listing of the block events.** -* **v3.2.10-alpha.2 2021-07-06** +* **Added the ability to identify if a block is able to be affected by gravity. Also the mine has a global setting to identify quickly if any block is gravity affected.** +This will be used to alter the mine reset strategy to improve performance so as to hopefully eliminate long resets due to extensive lag from falling blocks. The idea is to get all the other blocks in to place before placing the falling blocks to ensure they are less likely to fall. -* **Added the ability to fail silently for the Localizable object to prevent the message ID from flooding certain messages.** -This will be employed in the Output.get() functions so if it cannot load the prefixes and level colors, then the message IDs will not be injected in to the messages. -This new feature should never be used without careful consideration since it is important to identify when messages fail so they can be fixed properly. +* **If the Mine's saved file data is corrupted (manually edited with incorrect data), this will prevent the mine from being loaded and will now generate an error message indicating which mine has a problem loading. It will print out the invalid data, and it will default to a value of 0.00001. The function has been updated to "properly" use the localized format, so if it saves in a non US way, then it should now be able to read it back in and parse it correctly. -* **Adjustments to LocaleManager for updating the internal checks for if the external files need to be updated.** -Also finalize how Prison object works with the LocaleManager. +* **If the Mine's saved file data is corrupted (manually edited with incorrect data),** +this will prevent the mine from being loaded and will now generate an error message indicating which mine has a problem loading. It will print out the invalid data, and it will default to a value of 0.00001. -* **Removed obsolete placeholders that are not used anymore.** +* **Checking to ensure the locations are not null when loading.** +There was a failure with bad data on the files system that was resulting in trying to resolve nulls to a location, which obviously cannot happen. -* **Adjustments to when the LocalManager is started so it can be activated as soon as possible.** -This is because of the need for Output.get() to use externalized messages for it's prefixes and color codes. This does present some problems, but it actually works fine at runtime and also for junit tests too. +* **There was an odd situation where the player was null, when usually they never can be, so this helps prevent possible errors.** +The null was caused by an issue with a placeholder? Don't really remember. -* **Setup a getConfigString in the Platform with a default value.** +* **Adjustments to Prison's TPS calculations.** +They were only taking the average of just two readings which was resulting in very unstable TPS values. Now 10 are being used. +Enabled a new feature where the resolution can be changed from normal (a reading every tick) to high resolution (one reading every 2 ticks). When the resolution changes, the task will auto terminate and resubmit with the new settings. -* **New placeholders for mine block stats: Renamed percent to chance. Added prison_top_mine_block_remaining_bar_nnn_minename.** +* **For the command /ranks autoConfigure made some adjustments to the block lists being used so the top mines have more valuable ores and blocks. There was a shortage and the wrong blocks were being used. -* **Used the wrong numeric formatter... needed to be an integer.** +* **Fixed an auto features config setting for prison's ExplosiveBockBreakvents priority; it was missing the word priority.** +Reworked some of the details on autofeatures as displayed through /prison version to update them to better reflect the correct settings and dependencies. -* **Added 10 new placeholders to provide stats on mine blocks.** -These use a series value in the placeholder to specify the specific block. The series number is not limited and can range from 1 through a large reasonable value. The number can be one or more digits, with or without a left padding zeros. +* **Fixed a problem with placeholders when using the search feature, but not supplying a player's name.** -* **Renamed the field PrisonBlockStatusData.getResetBlockCount() to getBlockPlacedCount() to be more descriptive of what it actually is.** +* **some internal changes to improve the resets** -* **Add the ability of a PlaceholderFlag to self identify as having a sequence.** -This will allow for automatic processing of these kind of placeholders without having to hard code for them. +* **eliminate the block access in this class since it handles everything in the submitted task.** +This was causing an error when it was being ran in an async thread. When the task is submitted, it is ran synchoronously so it works correctly. -* **Placeholders test: Fixed issue with player name being incorrect and also added player information if it is provided in the output.** +* **Changed prison's TPS calculation to be able to enable a high-res setting when the `/mines stats` is enabled.** +The one problem with enabling high resolution mode is that it could show an unrealistic low TPS during a reset. The /lag command shows a much higher TPS value. -* **Fixed a typo that was made a long time ago. Placeholder has a capitol H in the name.** +* **Setup up the basics for async updates.** +In the code that does the update, it also now reads the block to ensure that the read and update is all done in the synch thread. Otherwise the old code would be risking chunk loading in an async thread. +Using the Location and World to perform the async updates outside of needing access to the spigot module. +At this time, only `/mines set tracer` is using the new async reset. -* **Increased the number of rows displayed when using the placeholder search. It was showing six placeholders and I increased it to 10.** +* **Tweaks to the event listener dumps for block breaks.** +Updated the notes about prison's listeners. +PEExplosionEvent was setup with the wrong forClass name. -* **Renamed the PlaceHolderFlags from PLAYERMINES to MINEPLAYERS which is more consistent in how it is being used.** +* **Setting up a new way to handle block updates in prison. Adding functions that are intended to be use while running in an async threads.** -* **v3.2.10-alpha.1 2021-07-05** +* **Transitioning over to the correct way to get the compatibility object.** +Just a few classes are using the old way, but they will be switched over when they are done with the edits. -* **Bug fix... when selling on each block break event, it needs to suppress the per-sale messages.** +* **Fixed the way some of the language files were being generated** +so it can include the spigot module, which makes it self-contained for actual Modules, since it's always based upon the module name. +Core and spigot are not technically modules, so they have special setups. +Changed the Module folder from dataFolder to moduleDataFolder so it would not conflict with the SpigotPrison object. -* **Fix a few other issues with the new placeholders.** +* **Fixed a problem with Prison's ExplosiveBlockBreakHandler** + in that it has a typo in the getHandlerList() and was not included with the registration processes. It also needed to be included with the generation of the listener dumps. -* **Enhance the /ranks autoConfigure to work much better with existing mines and ranks when doing a force.** +* **Added /sellall hand command.** -* **New 18 new placeholders added to prison. Hooked up the following placeholders, but have not yet ran through testing yet.** -prison_rank_ladder_position (prison_rlp), prison_rank_ladder_position_laddername (prison_rlp_laddername), -prison_rank__ladder_position_rankname (prison_r_lp_rankname), prison_rank__player_cost_rankname (prison_r_pcst_rankname), -prison_rank__player_cost_formatted_rankname (prison_r_pcf_rankname), prison_rank__player_cost_remaining_rankname (prison_r_pcf_rankname), -prison_rank__player_cost_remaining_formatted_rankname (prison_r_pcf_rankname), prison_rank__player_cost_percent_rankname (prison_r_pcp_rankname), -prison_rank__player_cost_bar_rankname (prison_r_pcb_rankname) +* **Minor changes to SellAll Util.** -* **Refactored ranks and RankLadders to eliminate old and inefficient ways to get the ranks and next ranks.** -These change will help improve the performance of processing the placeholders. -This also allows the elimination of a few functions that are now obsolete. +* **Much better performance for SellAll generally.** + + +* **SellAll Commands internal changes.** + + +* **Minor changes to GUIs:** Some fixes and visual changes. + + +* **SellAllUtil Rewrite:** New internals for SellAll and SellAll API. + + + + +# v3.2.10 2021-08-22 # v3.2.9 2021-07-03 diff --git a/docs/images/prison_docs_100_setting_up_auto_configure_03.png b/docs/images/prison_docs_100_setting_up_auto_configure_03.png index 058b90acc..4d5bf7bd4 100644 Binary files a/docs/images/prison_docs_100_setting_up_auto_configure_03.png and b/docs/images/prison_docs_100_setting_up_auto_configure_03.png differ diff --git a/docs/images/prison_docs_100_setting_up_auto_configure_04.png b/docs/images/prison_docs_100_setting_up_auto_configure_04.png index 5d20f112d..7e00e68ae 100644 Binary files a/docs/images/prison_docs_100_setting_up_auto_configure_04.png and b/docs/images/prison_docs_100_setting_up_auto_configure_04.png differ diff --git a/docs/images/prison_docs_100_setting_up_auto_configure_05.png b/docs/images/prison_docs_100_setting_up_auto_configure_05.png index a09761c73..0514bcbde 100644 Binary files a/docs/images/prison_docs_100_setting_up_auto_configure_05.png and b/docs/images/prison_docs_100_setting_up_auto_configure_05.png differ diff --git a/docs/images/prison_docs_100_setting_up_auto_configure_06.png b/docs/images/prison_docs_100_setting_up_auto_configure_06.png index 9ebd8c78d..eadfe8eb3 100644 Binary files a/docs/images/prison_docs_100_setting_up_auto_configure_06.png and b/docs/images/prison_docs_100_setting_up_auto_configure_06.png differ diff --git a/docs/images/prison_docs_115_blockevents_01.png b/docs/images/prison_docs_115_blockevents_01.png new file mode 100644 index 000000000..2adab6b28 Binary files /dev/null and b/docs/images/prison_docs_115_blockevents_01.png differ diff --git a/docs/images/prison_docs_115_blockevents_02.png b/docs/images/prison_docs_115_blockevents_02.png new file mode 100644 index 000000000..20c7c4d76 Binary files /dev/null and b/docs/images/prison_docs_115_blockevents_02.png differ diff --git a/docs/knownissues_v3.3.x.md b/docs/knownissues_v3.3.x.md index b0747c03e..082006343 100644 --- a/docs/knownissues_v3.3.x.md +++ b/docs/knownissues_v3.3.x.md @@ -3,43 +3,182 @@ # Prison Known Issues and To Do's for v3.3.x +# TODO Items for v3.2.11-alpha.13 -# TODOs for v3.2.10 release: -1. DONE: Final testing of ladder rank multipliers -2. DONE: /ranks ladder moveRank not working -3. DONE: Forced global refresh of rank multipliers when a ladder multiplier is changed. - - Should be simple - - Run as async task - - DONE: Force update when updating a ladder's multiplier - all players - - DONE: Force update when changing ranks - only targeted player -4. DONE: Add ladder base cost multiplier to /ranks autoConfigure. Start with a simple 10%. - - Include message that it's enabled and how to change it or disable it: - - /ranks ladder rankCostMultiplier prestiges 0 -5. Add to /ranks player the detail information on rank cost multipliers -6. DONE: For '/ranks autoConfigure' add an alias to '/prison autoConfigure' -7. DONE: Change /ranks list so if non-op it does not show all the extra details. A simplified list for plain players. +**Tasks needed for the v3.2.11 release:** +* Review some documentation and udpate... especially with the luckperms. +* Finalize the event listeners to use only one event (was three, now two, but reduce down to one). +* Review placeholders +* Try to hook up a top-n command - may be too complex and may need to be pushed over to the next release +* Review Mine Bombs and see if there are some simple updates +* Backpacks - may need to push over to next version +* GUI menus - Add the new GUI Tools to more of the GUI menus to simplify some of the commands? -8. Liners: Some are only for later releases and do not work with 1.8.8. So need to setup something to restrict the liners that are not functional for the older releases of spigot. -9. Hook up Prison's Explosion event. +* test Mine placements and resizing. Something does not look correct with tracer and liners. -### Others -* DONE: Add a rank cost multiplier to ladders. Sum all active ranks a player has to get the total multiplier to use for rank costs. -* DONE: Fix the "next rank" value with PlayerRanks.... needs to recalc with the new rank. -* DONE: When a ladder's rate cost multiplier is changed, need to recalculate all player's multipliers. Setup a task? + +* create a command placeholder that will be able to add a delay between submitting commands. Have it based upon ms.. and have it setup to be used when more than one command is combined with others. + + +* Command cooldowns - ranks - use config file to customize on a per command basis. Modify the prison command handler to manage cooldows as a new attribte to the commands. + + +* Mine Bombs: identify bombs... new way. +See SelectionManager... Prison wand uses the whole items stack to identify a wand, instead of just one small part, such as name or lore. Well, actually, its only the display name and material... no lore. + + +* Add Mine Regions - Similar to mines in a way, where they will allow players to have access to the region, have mine effects (outside of a mine)... and mine effects would also be tied to these too. + + +* DONE: command handler - Ignore commands in certain worlds + + +* Placing mines could triggers many resets... also placing mines may not clear all blocks. + + +* DONE: Player Cache - Make sure the cache is loadable otherwise a new instance may be created that could wipe out the existing data. + - All player loads block... they do not submit a task anymore. + - ~block for all loads - currently it may return a null and load via async~ + - (no) Track file last saved date and if they don't match, then create a backup of the file version and don't delete it. + + +* GUI Menu Tools + - Page prior and page next + - Current page + - Go Back button + - Background colored panes when no options + - Current version is not tied to configs... future options... + -- Hook up to more gui menus + + +* DONE: Add a base class for the mine bomb configs... + - DONE: Add a version so as to be able to auto refresh the formats + + +* New documentation - Madog's knowledge + - look for pins + + +* Add mine effects. See conversation with Madog. + - Use PlayerCache and existing utils. + - Simple to implement some features, including flying in a mine. + + +**List for v3.2.11 release:** + + +* DONE: Players need to be restructured. Move rank player object, or at least most of the core, to the core project so as to reduce the number of player types. + +* Cache player + - cache player's balance - Hmm... may need to put it in RankPlayer + - cache player's ranks... only prestiges, default + +* Top-n ranks + - total blocks mined + - total tokens earned (or currently has) + - balance + - highest rank: prestiges, default, balance + - most online time, or most mining time (which will probably be better) + + +* DONE: FIXED: Issue with blocks. Explosions are creating "untouchable" blocks that cannot be included in other explosions. + - My observations were with multiple explosions leaving rings that are within the the radius of an explosion + - I could break the blocks. + - jamo said that the pillars that were created on his server could not be broke + + + +* Review placeholders - add and test placeholders that are tied to playerCache stats + +* Mine Bombs - Finish + - Add sound and particle effects + - Other features? + - Make sure the bomb is set within a mine. Do not allow it to be placed outside of a mine. + - DONE: When exploding large bombs with block decay, there is a chance that you can get the first block in the decay as part of the drops. + - DONE: Check to make sure the block broke is the one in the target block. If not, then ignore. + - make sure the block is not "locked" + + +* Add a top 10 listing commands + - Top player on server (rank / ladder) + - Top player per mine? + - Top Player per Blocks + - Top Player per time + +* Add Block & Time requirements for rankups + - Upon rankup, player will get a new "object" that would track rankup progress + - Would record current blocks and time for that rank, which is needed for when they + prestige. The rankup Progress won't change until they rankup and it will be reset. + It's used to subtract from current stats to get "progress". + +* BackPacks & Vaults & Warehouses - rewrite + - Add PlayerCache support with integrated backpack data object to track details + - Create new gradle module for backpacks and other items. Call it something like Accessories. + - Remove hooks in the spigot module except for the code to read existing old backpacks to migrate contents. + - Backpacks are able to have pickup and sell used against them. + - Vaults are protected from pickup and sell - Have to manually move items in and out to main inventory in order to sell them. Max size limit is a double chest. + - Backpacks can be protected from pickup and sell via command, which can be used to charge players. + - Warehouses are not normal player inventory/chests. They are virtual containers for items and blocks. + - Warehouses have slots, where each slot is one item. A slot can have a dynamic amount of items it can store. The player can buy more slots in their warehouse and increase the capacity of each slot. + - Warehouses - have formula to calculate costs of slots and capacity, where prices increase on both depending upon number of slots, and total capacity size of warehouse. + - Warehouses - Initial capacity of 5 slots, each at 100 to 200 capacity. + - Should vaults be tied to a physical location, such a server-wide "bank"? If so, then players has to physically go there to access their vaults. Same with warehouses. A defined bank or warehouse would be similar to a mine in such it would be 3d and access would work anywhere in there. Or a given mine could be designated as a bank or mine. So like for example, mine c could be the bank so a player would have to rank up to C to access it. Then a vault could be tied to a third tier prestige or something (but those don't have physical locations, but could make it mine a) or create a new mine that is empty, then link that new mine to that prestige rank so players have access to it. + + + + + + +* Mine reset messages: Have setting to control by percent remaining in the mine. + + +* Save files do not include the block type prefix. Such as used with CustomItems. +Not sure if it needs to? Need to test and confirm if working correctly. World coordinates would be wrong if missing. + + + + +- Not sure why the following would be needed: +* Auto Features Settings : Create an API object that has the auto features settings listed. Basically this would serve as a simple cache with a life span of about 10 seconds. So if a player is mining hundreds of blocks within 10 seconds, odds are these settings will not be changing... both server config settings, and the player's permissions. Can provide helper classes that will a simple check of all these details, such as passing tool in hand to check perms for auto pickup settings for the server, the player's perms and lore on the tool. ... as an example. +- Store in the player cache object, but make transient. Refresh every 10 to 15 seconds.. maybe even 30? +- Add to the auto features event so its available there +- Change function parameters to use the event and this new object as parameters... reduces number of parms... + + + + + +* Multi-language - Unable to create a custom language file that is not within the prison jar. It's been reported by Ingrosso that cannot create a new language file that does not match a file within the jar? + + +* BlockEvent processing queue - submit blockEvents to a job queue to run in another async thread... the individual commands would have to run in a sync thread. + - This will release the block break thread faster and won't contribute to lag. + + + + +* DONE: https://github.com/PrisonTeam/Prison/issues/222 + DecimalFormat not being used correctly in saving mine data so if different Locale is used, other than EN US, then parsing the saved file can result in a failure. + - MineBlockEvent is an example of where this was a problem + - The offending sections were corrected and should now work + + +* Add option to /ranks to rename a rank. Tag too? + # Start on mine bombs 1. Select size of bomb. Configuration. - 1a. Identify items to use as bombs - 1b. Bomb size - 1c. Bomb explosion pattern. Currently only sphere, but could include other shapes. + 1a. DONE: Identify items to use as bombs + 1b. DONE: Bomb size + 1c. DONE: Bomb explosion pattern. Currently only sphere, but could include other shapes. 2. DONE: Select list of blocks that will be effected by bomb explosion 3. Throw bomb, or place bomb... start processing count down. 4. Pre-fire effects: sound & particles (low priority) @@ -48,6 +187,8 @@ 7. Hook up prison's event handler for prison's explosion event + + * DONE: Modified /ranks list to provide this feature - Maybe provide a /rankcost command? Show current player rank costs with rank cost multipliers applied - /rankcost @@ -86,10 +227,6 @@ # **Possible bugs/issues:** -* DONE: /ranks ladder moveRank did not work to move from one ladder to another - -* DONE: When adding a new rank or mine, auto reload all placeholders so they pick up the new entry. - * Test BlockEvent perms... they appear like they don't work. * If ranks module fails due to no economy, try to make that a little more obvious. @@ -498,6 +635,97 @@ Offers for translation:
+# Features recently added for v3.2.11 + + + + + + + + + + +* DONE: New update to combine block processing results in many block.getDrops() being combined. Since they are combined, the extended fortune calculations may not work properly since it does not know how many original blocks were included. +- May need to have an intermediate object to better collect original blocks, drops, and targetBlocks. It can include some of the more basics that are not tracked, such as original block count to better calculate the fortunes. + + + +* DONE: Rewrite the `/prison utils titles` to use XSeries' title commands. XSeries only supports 1.9+ so I still need to support 1.8.8 directly within prison. + + + +* DONE: Common messaging framework so if hundreds of messages are sent, only one is displayed. Eliminate the duplicates. + + + + +* DONE: Revert a mine to a virtual mine. Maybe with the command: `/mines set area *virtual*`. Backup the mine's data file before updating and saving. + + +* DONE: the command /mines reset *all* is not working correctly. Could be an issue with the chaining not submitting the next reset since this is all done through async processes right now. + + +* DONE: Add a few more options to auto features for auto sell, such on full inventory. This was removed recently to stabilize some of the new code. + - Just refined what was already there. + + + + +* DONE: Concurrent modification error on the MineTargetPrisonBlock when resetting the mine. + tech.mcprison.prison.spigot.game.SpigotWorld.setBlocksSynchronously() (146). + Serialize Id the mine resets and provide a locking mechanism that will prevent auto features from being processed when it goes in to a reset mode. Also when in a reset mode, prevent another reset from being submitted so they cannot run concurrently or back to back. Maybe attach a cooldown to the resets too, such as 10 seconds would be long enough to prevent a runaway chained reaction. + - DONE: Create an object such as a MineStateToken that will hold the state of the mine reset (in progress, mineable, stable, usable, locked, etc... not sure proper terminology right now... or how many states), with a serial number that will be incremented on each reset. + - (on hold) Do not perform a clear on the collection of MineTargetPrisonBlocks within the mine. Just replace the collection with a new collection and let the garbage collection handle reclaiming all resources. Carefully review for possible memory leaks. May be a good idea to hold on to that collection and submit a task that runs in about 30 seconds to perform a clear on the collection to release the resources. This may be important since the target blocks contains references to the stats blocks and may not be GC'd automatically. May want to null those refs first too. + MineReset.clearMineTargetPrisonBlocks() (1799) + +* DONE: PlayerCache Time per Mine stats - not recording correctly. + +* DONE: new auto features autosell should place items in inventory that have no sell value. Items that cannot be auto sold. + + + + + +# Features recently added for v3.2.10 + + +# TODOs for v3.2.10 release: + +1. DONE: Final testing of ladder rank multipliers +2. DONE: /ranks ladder moveRank not working +3. DONE: Forced global refresh of rank multipliers when a ladder multiplier is changed. + - Should be simple + - Run as async task + - DONE: Force update when updating a ladder's multiplier - all players + - DONE: Force update when changing ranks - only targeted player +4. DONE: Add ladder base cost multiplier to /ranks autoConfigure. Start with a simple 10%. + - Include message that it's enabled and how to change it or disable it: + - /ranks ladder rankCostMultiplier prestiges 0 +5. Add to /ranks player the detail information on rank cost multipliers +6. DONE: For '/ranks autoConfigure' add an alias to '/prison autoConfigure' + +7. DONE: Change /ranks list so if non-op it does not show all the extra details. A simplified list for plain players. + +8. DONE: Liners: Some are only for later releases and do not work with 1.8.8. So need to setup something to restrict the liners that are not functional for the older releases of spigot. + +9. DONE: Hook up Prison's Explosion event. + + +### Others + +* DONE: Add a rank cost multiplier to ladders. Sum all active ranks a player has to get the total multiplier to use for rank costs. +* DONE: Fix the "next rank" value with PlayerRanks.... needs to recalc with the new rank. +* DONE: When a ladder's rate cost multiplier is changed, need to recalculate all player's multipliers. Setup a task? + + + +* DONE: /ranks ladder moveRank did not work to move from one ladder to another + +* DONE: When adding a new rank or mine, auto reload all placeholders so they pick up the new entry. + + + # Features recently added since v3.2.9 diff --git a/docs/prison_changelog_v3.2.10.md b/docs/prison_changelog_v3.2.10.md index 78c3d6290..699fa0041 100644 --- a/docs/prison_changelog_v3.2.10.md +++ b/docs/prison_changelog_v3.2.10.md @@ -32,7 +32,9 @@ These build logs represent the work that has been going on within prison. * Provide a more robust support system in prison, in addition to the support submit features. Can now enable more debug mode targets to better trackdown potential issues. -* Prison now supports reloadable locales and auto features. For the auto features, it also reregisters the block break events listeners that auto features use. +* Prison now supports reloadable locales and auto features. For the auto features, it now unregisters all previously registered block event listeners, and the re-registers them based upon the updates to the settings in the reloaded auto features. The server no longer needs to be restarted if the configuration settings for event listeners have changed in any way. + +* Auto features has undergone more refactoring to prepare for future enhancements, and to streamline the existing processes. A few undiscovered bugs were found and fixed during these enhancements. As a result, auto features works better with other enchantment plugins. * Rewrote some of the auto features to resolve some obscure issues, and to provide performance improvements and greater flexibility. @@ -43,7 +45,7 @@ These build logs represent the work that has been going on within prison. * Update many of the internal libraries. -* Rewrites of the GUIs and Sellall features. +* Performance improvements with GUIs, backpack, and Sellall features. Includes fixs and some layout functional improvements too. * Expand Prison's utils features. Added a few more utilities. diff --git a/docs/prison_changelog_v3.2.11.md b/docs/prison_changelog_v3.2.11.md new file mode 100644 index 000000000..ee3fa9319 --- /dev/null +++ b/docs/prison_changelog_v3.2.11.md @@ -0,0 +1,1059 @@ +[Prison Documents - Table of Contents](prison_docs_000_toc.md) + +## Prison Build Logs for v3.2.11 + +## Build logs + - **[v3.3.0-alpha - Current](changelog_v3.3.x.md)** + - [v3.2.0 through v3.2.10](prison_changelogs.md) + + +These build logs represent the work that has been going on within prison. + + + +# 3.2.11 2022-01-22 + +* Prison now supports 258 Placeholders, including aliases. + +- - - - + +Prison supports: + - Java 1.8 through Java 17. + - Spigot 1.8 through 1.18, and other platforms based upon Spigot. + +* Many updates and bug fixes. Please see the change log for all of them. Below is just a limited sumary of some of the more important updates. + + +* Asynchronous mine reset enablement + + +* Prison can now be disabled completely on a per world basis. See setting in config.yml. + + +* If the server is missing an economy plugin, prison now does a better job at communicting what the problem is so it can be fixed quickly. An economy plugin is required for the ranks module to function. + + +* Added a debug mode for inspecting a block. To enable, enabl prison debug with `/prison debug` then while holding a prison wand `/mines wand` click a block and it will show a couple of lines tied to the information that prison has recorded for that block. If you shift-right click a block, then prison will check each event listener to see what it does with the block. It will report when a block event is canceled and other details, on a per listener basis. + + +* Start to add tokens to prison. Players can now earn tokens while mining. Its a work in progress, but they cannot spend them yet. + + +* Updated block constraints so blocks can be spawned in spedific layers within a mine, and with a minimum or maximum amouts. + + +* Placeholders - Prison now has 258 placeholders, including aliases. Added many placeholders and improve a few that were having some issues. There are still more that are planned to be added. + + +* Added new Prison Mine Bombs - Work in progress - Basics exist and have a lot of functionality, but more work will be done to add new features and address issues when found and reported. If you have ideas, or need something specific, please visit our discord server and talk to Blue. + + +* Coming Soon: Mine Region. Mine effects that are applied to Mine Regions. Mine Effects will include potion effects like night vision, and other effects such as no hunger, no fall damage, and fly. Also may be adding enhantments soon too. + + +* Significant improvements for handling multi-block explosions with a major rewrite to improve the overall performance within the handling of block break events within the auto features. Many changes to improve performance on a per-block basis, and to prevent a block from being counted more than once when many different players are trying to break, or explode the same blocks. + + +* Signficant updates to most Prison GUIs and sellall + +**NOTE:** It is currently recommended that the old Prison Backpacks should not be used at this time. They will be rewritten shortly to address the current issues. + + + +# 3.2.11-alpha.17 2022-01-18 + + +* **Added to SpigotPlayer the ability to enable flying and to check to see if the player is flying. This is to prepare for mine effects.** + + +* **Considering adding heads support to prison. Added a few parts, but they are not functional.** + + +* **3.2.11-alpha.17 2022-01-18** + + +* **More updates to the player's rank menu with the ability to add rank specific lore to the configs.** +When referring to ranks, the names much match exactly since they are case sensitive. + + +* **Bug fix with the rank cost calculations since they were not pulling in the last rank in the rang of ranks.** + + +* **Fixed an issue with CI's function that was not returning any ids.** + + +* **Mine auto resets can now be disabled.** +When disabled, they will never reset based upon time. The resets can still be triggered by blocks remaining thresholds. + + +* **3.2.11-alpha.16 2022-01-16** + + +* **Lot of updates to the GUI menus.** +Major improvements to the player's /gui ranks to work better with placeholders. Added comments to the GuiConfig.yml file on how to use it and the placeholders. +Delete the GuiConfig.yml file to regenerate with the updated information on lore settings. + + +* **Update a few of the player's GUIs to support the SpigotGUIMenutools.** +Added capability to control the return command and the paging command so it now works more intuitivily. + + +* **Fix issue with the placeholders related to prison_rankup_cost.** +This now works correctly to include the next prestig rank's cost when at the last rank in the default ladder. + + +* **Bug fix: Get the 32 placeholders related to prison_rankup_cost working correctly when dealing with various prestige conditions.** + + + +* **Bug fix: The player based playSound was not working, but the world's playSound works perfectly. Not sue why bukkit player would be messed up that ** + + +* **Bug fix: Hooking up the rollover to the next prestige rank cost, when at th end of the ladder, had a typo where it would not evaluate any rank.** + + +**3.2.11-alpha.15 2022-01-13** + + +* **Bug Fix: If the wrong sound file was being used it used to throw a NPE.** +Now this is a safer way to find the correct file, and it will fall back upon a plink sound for any version of spigot. + + +* **If upon loading a mine, there is a reson or need to resave the data, since this is an auto update, then this will make a backup copy of the mine's save file before saving it.** + + +* **Bug fix: If spigot version is less than 1.13.0, and trying to use a _WOOD block, XMaterials cannot map that correctly to a Material and then back to the same XMaterial.** +This is causing a problem when using in a mine since it cannot be tied back to the block that was placed. So for these versions, all _WOOD blocks are removed from the server. If a _WOOD block is saved in a mine, it will be remapped to the same _PLANKS block, which will work just fine. + + +* **Bug fix: Prevent stack traces when a broken block cannot be mapped to a PrisonBlockStatusData object.** +This is happening with spigot versions 1.8 through 1.12.2 when using "WOOD" blocks since XSeries translates these blocks to LOGs, so they will never map back to the XMaterial WOOD entries. This was producing a stacktrace and would prevent the proper handling of the auto features. + + +* **3.2.11-alpha.14 2022-01-11** + + +* **Update the failed rank message so it is clearer.** + + + +* **When a player is on the default ladder at the last possible rank, instead of showing nothing for rankup costs, percent, bar, etc, it will now use the next prestige rank if prestiges are enabled.** + + These changes apply to the following placeholders: + + prison_rc prison_rankup_cost prison_rc_laddername prison_rankup_cost_laddername + prison_rcf prison_rankup_cost_formatted prison_rcf_laddername prison_rankup_cost_formatted_laddername + prison_rcp prison_rankup_cost_percent prison_rcp_laddername prison_rankup_cost_percent_laddername + prison_rcb prison_rankup_cost_bar prison_rcb_laddername prison_rankup_cost_bar_laddername + prison_rcr prison_rankup_cost_remaining prison_rcr_laddername prison_rankup_cost_remaining_laddername + prison_rcrf prison_rankup_cost_remaining_formatted prison_rcrf_laddername prison_rankup_cost_remaining_formatted_laddername + prison_rcrp prison_rankup_cost_remaining_percent prison_rcrp_laddername prison_rankup_cost_remaining_percent_laddername + prison_rcrb prison_rankup_cost_remaining_bar prison_rcrb_laddername prison_rankup_cost_remaining_bar_laddername + + + +* **On delayed startup, allow a combination of selectors to target essentials, since the class name has changed in v2.19.x** + + +* **Setup the block inspector to auto select a diamond shovel, a diamond axe, or a diamond pickaxe.** + + +* **On the blockbreak debug information, show the information on either the block that was hit, or if that is null, just dashes to show such a block was not provided.** + + +* **For EssentialsX v2.19.x, the class being used to identify if the economy has been loaded has changed.** +This commit has the references to the proper class to use depeending upon the version of EssentialsX. It should be noted that this only applies if delayed startup is enabled for the EssentialsX economy, which generally does not require it. + + +* **Change in how prison deals with ranks when there isn't an economy plugin loaded.** +Now, instead of printing a simple little message in the console, which everyone appear to miss, it also enables a generic `/ranks` command that only displays a message indicating that no economy was found, with links to documentation. This should make it more obvious. + + +* **Change to auto features for the event listeners: now MONITOR is not enabled unless set to priority of MONITOR.** + + +* **If a language file has a message that is set to an empty string or a space, it will now no longer generate an empty message.** +Instead it will supress the sending of any message that is blank. + + +* **Move the placeholder `prison_player_blocks_total` from being a player mine placeholder, to a player placeholder since it is not tied to a specific mine.** +Added a formatted version (with commas) and this one became unformatted so it can be used within scripts if needed. + + +* **The use of the `/ranks command remove` within the `/ranks info`, or `/ranks command list` was not correctly including the correct row number**; it was using one higher than what it should have due to prior incrementing. + + +* **Issues with SellAll when dealing with varient block types when bukkit version is less than 1.13.** +Eliminate usage of org.bukkit.Material where possible. XMaterial must generate the ItemStack directly, instead of creating a Material object. + + +* **Fix some issues with canceling drops:** +Will not work on 1.8.x and maybe a few other versions of spigot with no work arounds. Works on newer versions. + + +**New Feature: Dump the BlockBreakEvent and monitor changes per listener.** +This provides a great deal of information on what is modifying the blocks. +To use, enter prison debug mode with `/prison debug` and then shift-click on a block using the prison wand (`/mines wand`). + + + +* **Bug Fix: When loading the mines, and if using the old block model, some blocks were not mapping to the new PrisonBlocks.** +When this now happens, the loader now tries to use the old block model's getXMaterialName() function, which returns one or more names that can map to XMaterial objects. It tries all of them until it is able to get a non-null PrisonBlock result. + + +* **Added a safty backup of the player's cache file... if it is detected that the new size is smaller than the prior size, then make a backup copy saving the original version instead of deleting it.** +This implies that stats will always be added to the player's cache and that the file should alwaysbe getting larger. This only makes sense when recording stats. The file could become smaller when balances are reset, such as spending a lot of tokens. +This also implies that some times, such as player inventories, should not be stored in this object... player's backpacks will be removed in the near future. +It should be mentioned that on a test server I saw my player stats for my test player being wipped out. I have no idea if it was because of file system commands that I ran, or if it was a bug in prison that reset it. But because there was a potential loss, I'm making sure certain things cannot happen anymore, or trying to reduce the risk of losses. + + + +* **Fix the sellall block list gui for when there is an invalid XMaterial name**, that it will print out the error to the console, and continue with using COBBLESTONE instead of producing a NPE. + + + +* **For the list of displaying the ranks on a ladder, split them up to show 15 per line which will help when there are a lot of ranks on a given ladder.** + + +* **Increased the confirmation on mine size from 25,000 to 50,000 blocks so as to minimize the number of times this will occur.** + + +* **Add support for specifying the sound to use for inventory full event.** +Valid sounds can be listed with the command /prison utils sounds list. + + +* **Added support for doubles in the AutoFeatures settings.** +The basics were there, but the actual AutoFeatures enum did not have them hooked up. + + +* **Remove an unused function on the PlayerCache.** + + +* **Bug fix for mohist, or other platforms that are trying to use SuperPerms, or other perm plugins that do not support groups.** + + +* **Add *all* to the command /mines set tpAccessByRank.** + + +* **Add '*all*' as an option for applying Access by Rank for mines command: /mines set mineAccessByRank.** + + +* **3.2.11-alpha.13** 2021-12-24 + + +* **Prison command handler: adds the ability to add new aliases from the config file.** + + +* **For ranks that are null, made some changes so either empty strings are used instad, or most of the time the rank name is used.** + + +* **Fixed a potential issue with nulls in the language file parameters. All nulls are replaced with empty strings.** + + +* **Added the ability for admins to add aliases to commands so they can better customize their environment.** + + +* **Disable block break events in the worlds where prison commands are disabled.** + + +* **Added the ability to disable prison command hander is specific worlds.** +The settings are within config.yml. The disabling of prison is only done on the command handler, and will soon be hooked up to the block break events too. +The command /prison now lists worlds in which prison has been disabled + + + +**3.2.11-alpha.12** 2021-12-21 +Alpha 12 released. + + +* **Fixed issue with XMaterial when trying to parse a custom blcok that is not compatible with prison.** +The function will now return a null value and everything that uses it, must ensure it's not null before trying to use it. + + +* **Make sure the targetBlock is not null before trying to process it.** + + +* **Docs: Updated the LuckPerms Tracks and Groups document to provide more details on how to set them up.** + + +* **Bug fix: Ran in to a rare situation where the use of essentialsX economy failed to allow prison to load the players during startup.** +Prison was trying to "rank" the players within each rank that they were in, and that required prison to get their balance.... but bukkit was not able to return an OfflinePlayer instance for any of the plyers. Therefore prison could not access the player through vault. No idea why bukkit is not able to provide the players. The server in question had about 2500 players. +So to prevent this from happening, the initial ranking bypasses the loading of any monetary amounts; they will be updated later. + + +* **Update and create some new LuckPerms docs.** + + +* **Move gui tools menu changes to improve them and hook them up to menus that did not have any paging.** + + +* **Adjustments to improve the way the new gui tools work to reduce the amount of use of lore, or at least the visible lore.** +This visually cleans it up a lot. + + +* **Hooked up some of the new features to the /gui ranks menu, plus added a /gui ladders and hooked that up. Simplified how the ladders page was setup.** + + +* **More work on the GUI menu tools to not only get them to work better (correctly) but also add new capabilities... now supports adding a menu option and the tool auto assigns it to the next available slot.** + + +* **GUI menu tools update...** + + +* **Prison Tokens: Remove the alias so they will not cause conflict with other token plugins.** + + +* **Potential bug fix: There was a situation where with multiverse-core a delayed world loading resulted in the world not being found**, and therefore it was preventing the loading of all locations tied to the mine. This now allows the locations to be loaded without a valid world. Then when the world is finally loaded, it will refresh the references to the world objects. + + +* **GUI Menu: a few minor changes before more radical changes to go with the final "idea".** + + +* **GUI Menu Tools - Added a first page and last page button.** + + +* **GUI Bug fix: If there are more than 45 ranks on a ladder, the GUI will NOW be able to provide paging capabilities to view all ranks.** +By default it will start off with page one, but this can handle an unlimited number of pages. +This paging system can be expanded and easily used on other GUI lists with minimal changes to hook it up. + + +* **Found a bug in XMaterial where it was converting "melon" to melon_slice instead of the melon block.** + + +* **Bug fix: Fixed an incorrect use of XMaterial which prevented it from working properly with spigot 1.8 through 1.12.** +It was using XMaterial to get the Material value, which is wrong, since it's the item stack that contains the variants of the materials. So the change is to extract the item stack directly from XMaterial which solves the problem. +Also there was another error where if amounts are greater than 64, setting them to 1 so the GUI will still work, but it will suppress the incorrect counts for the itemstack. + + +* **Update XSeries to v8.5.0.1 to better support spigot 1.18.** + + +**Prison tokens: Add a few more prison tokens placeholders.** +Fixed the admin token commands to use longs and not integers. + + +* **Ranks GUI Error.** ~~Fixed an error with Ranks GUI.~~ This did not fix anything. + + +* **Some adjustments to admin token functions.** + + +* **Bug fix: Rankup on a ladder in which there is not already a rank was producing an error.** +Similar to prior problem... just did not fix it correctly for all situations. + + +* **Start building the structure for the Top N rankings.** + + +* **Mine Bombs: Noticed the player inventory was not be "updated" through bukkit.** +This could help prevent wrong item amounts. + + +* **Mine Bombs: Set them up to auto refresh the data structure that is being saved, if it is detected that there has been a change.** +Added a version number to the mine bomb save data structure so as to use that to detect when the structure changes. That number will be updated in code when it has been modified. So when running the mine bomb loader, it will detect that the saved data is in an older format, and so it will rename the old file to preserve it as a backup, then write the new data to the file system. This will allow new fields to be added,and then they will appear in the save file upon the next restart. This will make it easier for admins to update and use the new features. + + +* **Bug fix: Was causing a null pointer exception when trying to add a player to a new ladder.** +This now correctly gives the player the requested rank, or if not specified, then the lowest rank on that ladder. + + +* **3.2.11-alpha.11 2021-12-07** + + +* **Mine Bombs: A few other minor fixes and changes.** + + +* **Mine Bombs: Some changes in how they are setup. Added a bombItemId which becomes line one of the lore and is used to identify that it's a mine bomb.** +Added a nameTag that is used to put a nameTag on the armor stand. Added a itemRemovalDelayTicks field to better control when the armor stand is removed (exact time). +Update a lot of Mine Bomb code for creating the time, placing the item (armor stand) etc... It's working better overall. + + +* **Update Tokens to fix an issue with the admin set.** +Added better tracking of adminAdded and adminRemoved stats. + + +* **Bug fix: Fixed a class not found except caused by google guava trying to load functions that it should not have been using for their event manager.** +Moved the PEE event out of this class all together, so now it's safe to use in other areas of prison, such as with guava's event handler. This was not an issue with spigot 1.8.8, but manifested itself with Spigot 1.16.5 since I believe that version of spigot is using a newer version of guava that has that behavior. + + +* **Upgrade XSeries to v8.5.0** + + +* **3.2.11-alpha.10 2021-12-05** + + +* **Bug fix: There was an issue that I found where blocks outside of the explosion events were being marked as mined without actually being broken.** +Therefore prison would not be able to break those blocks. This was caused by the initial explosion setting off a chained reaction explosion through a blockEvent. Now blocks that are part of an explosion cannot be part of a future explosion. + + +* **Added a new debug mode to inspect blocks by click on them with the mine wand tool when prison is in debug mode.** + + +* **Renamed Prison's PlayerListener to PrisonPlayerListener to reduce a conflict and to make it more obvious which object is which.** + + +* **For the bukkit 1.8 through bukkit 1.12, if an object has a different data value than what it normally has**, +it would not be matched through XMaterials... Examples are leaves, chests, etc... if there is no match initially using the block then try to then match on just the name, which eliminates the problem of a failed match. + + +* **Add a selective debug option where only the selected element is loged through the debugger.** + + +* **Removed the DebugTarget value of "support" since it is not using anymore.** + + +* **Bug fix: If a block has been placed in the mine that should not be there, prison was canceling the event which was preventing other plugins, or normal breakage, from breaking the block.** +The event is no longer being canceled. + + +* **Added 12 new placeholders: 4 new ones for player balances and 8 new ones for tokens.** + + +* **Prison tokens: Added admin functions of balance, add, remove, and set.** + + +* **Added the title and actionBar to the Player object so it will work in all forms of Player, such as RankPlayer.** +Had to use the Platform to cross over to spigot from core. + + +* **Added access to the player cache within the Player object so it's easier to use it.** + + +* **Updates some documents.** + + +* **Bug fix: One of the blockEvent placeholders was inserting the wrong value.** +{blocksMinedTotal} was inserted the blockName. + + +* **Slight adjustment to the mine backups's file name.** + + +* **Move the messages for /mines tp to the language files.** + + +* **3.2.11-alpha.9 2021-12-02** +Version v3.2.11-alpha.9 + + +* **Added a new feature to back up a mine and to provide a way to convert a mine to a virtual mine.** +When converting to a virtual, with the command '/mines set area virtual', a back up is made first. +The new backup command is '/mines back help'. + + +* **added mine name to reset notifications** + + +* **Bug fix: If a MONITOR event listener, then it should not process the block break event.** +Monitors were processing the block break events when they shouldn't so monitors are not terminated after validation since their "processing" is handled there. + + +* **Bug fix: The command '/mines reset *all* details' was not working and was only running one mine reset instead of all mines.** + + +* **Rank data refactoring. A few changes to get this working. The ladderRanks collection was not being setup was the main issue.** + + +* **Rank data refactoring. A few changes to get this to work well.** + + +* **Major refactoring of Rank Player data objects.** +This is to transition to easier use of player objects in prison. Some of the key classes have been moved from Ranks module to Core module, with the removal of rank functions being moved back to the ranks module. +This is a work in progress and does not yet work. The player's ladders and ranks have not been linked together yet. + + +* **Fixed the auto sell command within the auto features to include the ability to use autosell based upon the auto features settings.** + + +* **Fixed issue with a block break event happening outside of a mine, which will result in mine being null.** + + + +* **Fixed issue with getMine not striping color codes, but in the function before this one is called, it strips them to check to see if the mine name is valid.** + + + + +**3.2.11-alpha.8 2021-11-28** +Release v3.2.11-alpha.8. + + + +* **Update the last seen time.** +But will not set dirty. If player is not active, then it will not be recorded. + + +* **Expand the last seen information on the command /ranks player, which now includes how long ago instead of just a date and time.** + + +* **Add a listSeenDate to the player's cache data.** +This will be used to track when the player was last on, and more importantly, determine if the player's cache data should be updated for stats reporting for top-n functions. + + +* **Fix a rare condition where the wrapper of the PrisonBlock is null (the actual bukkit block).** +This may not fix everything related to this issue, but it will prevent a NPE at this location. + + +* **Minor changes to clean up auto features a bit:** move functions that are no longer used in the normal block break code to OnBlockBreakPlayerManualCore so it's not confused with the main-core functions and accidentally used. +Also clean up the messaging and sellall usage to eliminate duplication. + + +* **Fixed an issue with the mine state mutex being null.** +Not sure what's causing it, but I suspect it mabe an issue with loading the mine from a saved state on server startup and that field never gets initialized. So fixed it by doing a lazy initialization on the field. + + +* **Fixes a minor issue with the command '/mines set spawn' where it was requiring an option be specified.** +I fixed it by setting a default value of "set" which does nothing, but makes the optional options, optional now. + + +* **Removed from the GUI the hologram on inventory full, and replaced it with actionBar.** + + +* **Some adjustments to the overflow of the drops and other inventory controls.** +On normal drops, disconnected autosell except if it is forced through the pmEvent. +Fix inventory full sounds. For 1.13 and up it had the wrong sound file. Using something less harsh than anvil and turned down the volume which was horribly excessive with the volume set to 10, when normal is 1. + + +* **Prison Tokens: Prison now is able to auto generate player tokens based upon blocks mined.** +It's enabled through AutoFeatures config file's setting 'tokensEnabled' and is able to set the blocks per token earnings rate with 'tokensBlocksPerToken'. +More features will be added soon, such admin functions and top-n token holders.... etc... + + + +* **3.2.11-alpha.7 2021-11-26** +Released alpha.7. Major advancements to mine bombs. + + +* **Mine Bombs: Added the use of a armor stand for holding the item, with an animation of swirling it around.** +The item's armor stand is managed in a task which removes itself when finished. This process is independent from the visual and sound effects. +Removed the static functions that were being used (which is much better). + + +* **Mine Bombs: Added more effects to the examples.** +Removed some that would not work. These are not perfectly selected and may not work for most versions of spigot. The visual effect do not appear to really do much. + + +* **Mine Bombs: Setup some changes in how classes are related to each other so as to prepare for significant changes.** + + +* **Mine Bombs: Got the sounds and visual effects hooked up to the explosions.** +Made many revisions on how all of this works, but pushed the tasks to a new class PrisonUtilsMinBombsTask. + + +* **Mine Bombs: Updated the listings of the mine bombs, which now includes full detail including the visual and sound effects, the list of shapes, list of sounds, and list of visual effects that can be used.** + + +* **Mine Bombs: Updated the junit test for validating that the EffectState is sorted in the proper order when using the MineBombEffectsData as a comparator.** + + +* **Mine Bombs: Setup a test unit test to confirm that the sorting of the EffectStates is as expected.** +Needs to be: placed, explode, finished. + + +* **Mine Bombs: Add the sound effects and visual effects to the default test bombs.** +NOTE: Some of these settings may not work on all versions of spigot, and some may not work on any version. + + +* **Bug fix: Auto features get drops not always working with explosions.** +The get drops was moved around to help ensure it does not try to get the block drops if the block is not what it is expected. This is now passing the needed object used for the check, instead of extracting it from the target blocks, which have not yet been set. + + +* **Bug fix: Auto Features Auto Pickup is now ignored if sellall has not been setup on the server.** +If getting an instance of SellAll when it is disabled, will result in a null value. + + +* **Mine Bombs: Added a few new shapes.** +Disk and Ring. Available in each plane x, y, and z. + + +* **Mine Bombs: Added the collections for sound effects and visual effects.** +Both share the same object, MineBombEffectsData. +An effect has a name, plus an EffectState, and an offset in ticks that will apply that effect based upon the EffectState. +The EffectState can be placed, explode, or finished. + + +* **Ran in to another Java format exception.** +Not sure what caused this problem, but added it to the catch so it can be reported in details so it can be fixed. + + +* **Add the ability to remove a mine's spawn point.** + + +* **Reworked how the drops were processed to prevent dropping the wrong contents.** +There was an issue where the drops were retrieved later in the process that allowed it to incorrectly pickup drops that were related to a decay function. This resolves the incorrect drops. + + +* **Player cache timing improvements.** This fixes issues with tracking the timing when mining. +Not 100% sure it is perfect, but it's actually working much better. Will need to revisit later. + + +* **Added a check to detect that a block has been altered and is not the block that was placed there by the mine reset.** +There have been drops of other materials making it in to an explosion event, and mostly due to block changes that happen due to other means. + + +* **Refactored some of the checks to determin if the event should be processed or not, so this can be used with a new feature that may help to auto manage access when WorldGuard is being used.** + + +* **Setup a mutex for locking the mine resets, which prevents active block break attempts, including explosions, from trying to break blocks while a mine is actively being reset.** +This helps to reduce the chance of hitting a concurrent modification exception. + + +* **Shut down auto manager and all auto features if the setting 'autoManager.isAutoManagerEnabled' is set to 'false' in autoFeaturesConfig.yml.** +If anyone wants to use prison's block events, then they must use the auto manager. + + +* **When using autosell through auto features, if a block cannot be sold, then the block is now placed in the player's inventory, or dropped if their inventory is full.** +If a block is unable to be sold, the amount returned for the item stack will be zero. + + +* **Bug Fix: There was originally a problem with applying block constraints that resulted in being unable to select a block when trying to randomly choose one.** +Initially as a first quick fix was to trying to reselect a block, but if the block chances were really low, then it could still fail to select a block. Then it was attempted to select a default block, but that too failed to work, especially if there were a sizable chance for AIR, and it would fail 100% of the time if the was only one block with a very low chance. The failure was the whole mine could be filled with that one block with the very small chance. +This fix completely redesigns the block selection, by first selecting only the blocks that are valid for that level of the mine. That way, when selecting blocks where blocks should be excluded from that level, those excluded blocks are never in the selected blocks to be considered. Also if AIR is a valid option, then this new process adds an AIR block to the temporary level block list with the percent chance assigned to the air. +Overall, this is working really well now, and it actually simplifies a lot of code and reduces the amount of processing involved. This new process always selects a block on the first pass too so it never haves to try to reselect a block. + + +* **Moved the multi-column formatting of data to the class Text so it can be used in other parts of the project.** +It was originally created for use in /ranks player but is now extended to be usd to list the plugins within the /prison version command. + + +* **Bug fix: If player is mining outside of a mine, then don't process anything.** +May want to allow prison to manage block breaks outside of mines in the future, but for now, prison is only managing mines. + + +* **3.2.11-alpha.6 2021-11-21** + + +* **New feature which lists all of the Player Cache stats in the command `/ranks player`. This includes stats for block breaks, time spent in mines, and earnings per mine.** + + +* **Capture an error within prison's Output class when trying to log content that has an UnknownFormatConversionException error.** +This happens when there is a problem with text formatting characters that conflict with Java's formating class. This tries to log the error with better details so it can be fixed and resolved where the error is happening. This does not "fix" the problem, but just better reports it so it can be identified and fixed. + + +* **Update on how prison manages the tracking of block breaks and earnings when auto features has autosell enabled.** + + +* **Changes to how the event listeners are setup: reduced by 1/3rd.** +Used to be that all three would be set if autopickup was enabled, but now only two will be set... monitor, and then either autopickup or manual drops. +This should improve performance since prison will be processing 1/3 less events. + + +* **3.2.11-alpha.5 2021-11-19** + +Post the alpha.5 release. + + +* **Remove the now obsolete auto features setting isAutoSellPerBlockBreaknliedEnabled.** +It is no longer needed since the auto features autosell per block break is now optimized and has no impact anymore. +Improve the autosell integration in to the auto features for both the auto pickup and also the normal drops. Improved the debug logging to include a list of all blocks being sold, or dropped, and their quantity and value. Also the total counts too. + + +* **Bug fix with SellAll: bug in original logic where the delayed notification when initialized is losing the first amount.** +It now always adds the amount to the delayed queue. + + +* **Autofeatures ignore certain events to improve performance and reduce logging entries when in debug mode.** +Since there are multiple listeners on block break events, which monitor the same event, these changes are able to mark a specific block within the MineTargetPrisonBlock objects that will be able to pass along an "ignore" event status to the other listeners to short-circuit their processing. This is highly beneficial when using large mine bombs and the mine has blockEvents setup to perform explosions... which will help reduce a ton of "dead" events. + + +* **Auto Features Forced Auto Sell Optimization Improvement: AutoSell within auto features now only uses sellall by item stack and not the player interface that accesses all of the player's inventories.** +Since the auto features items are not placed in the player's inventories at this time in the process of auto features, there is no reason to access the player's inventories. Selling directly reduces a lot of sellall overhead and as a result sellall is just calculating the prices. +The old autosell code within autofeatures has not be removed yet, but it cannot be called anymore. + + +* **PrisonDispatchCommandTask: Removed the debug logging since it can be very numerous when used with a large mine bomb and it's pointless since most of the block events being submitted runs in less that one millisecond.** +So this is just cleaning up a messy logging item. + + +* **SellAll: Setup a sellall function that will allow the selling of one ItemStack, which is not tied to any of the player's inventories.** +This is used in prison's auto features when enabling the option to auto sell on a per block break event basis. This is highly optimized and a lot faster than using the normal sellall since it does not deal with any of the player's inventories or backpacks. +This forces a delayed sold amount message since an explosion could includ many ItemStacks. + + +* **Mine bombs: Add cooldown and fuse delay to the mine bomb settings so each bomb can be customized. +Added gravity to the mine bombs too.** Gravity, like glow, was added in minecraft 1.9 so older versions won't work. + + +* **Bug fix: For TokenEnchant's explosive event processing,** need to set PrisonMinesBlockBreakEvent's setForceIfAirBlock( true ) so the explosion event can be processed, even if the initial block has already been processed. +This allows TE explosion events to work correctly now. + + +* **Bug fix: refined the use of a few internal registers that are being used to control block break behavior, and also block counts and block events.* +A few of the settings were being changed in the wrong places, which was out of synch with when they should have been applied. +A few of the side effects was failure of tracking block counts, block events, and handling some explosion events. + + +* **Mine Bombs: More features and fixes.** +Added support for radiusInner (for hollow sphere explosion shapes), removalChance (chance for block inclusion), glowing, autoSell, tool material type, tool fortune level. + Added a new shape which is "cube" and hooked up sphereHollow. Hooked up cube, sphereHollow, removalChance, glowing, the specified tool in hand with the custom fortune level. Did not hook up the forced autosell yet. +Fixed some issues to get things to work a little better too. + + +* **Prison Bombs: enabled the right clicking of AIR to set the bombs.** +If clicking air blocks, then the block tied to the event will be null (at least for spigot 1.13.x) in that case, will use the block location of the player, and then adding the player's vector to it times three. + + + +* **Fixed a bug with how the regex handles block quotes.** +Not only was it not working correctly for multiple block quotes, but it was incorrectly handling the tail end of the processed text and was basically doubling the text. It now works correctly, even with multiple block quotes. + + +* **Fixed an unexpected "bug" with the JumboText font for the letter Q.** +One section was setup to use "\Q" which is an escape character for a regex block quote. This was causing problems since it was forcing large sections of text to be ignored when translating minecraft color codes. By changing it to "\q", a lower case Q, this eliminated the translation from making the mistake. + + +* **Bug fix: The command "/prison support submit ranks" was passing a null sender, which is valid when generated by this support tool.** +The fixes now works well, and treats the null basically the same as an OP'd player, or the command being ran from the console. + + +* **Bug fix. If a null message is sent to this function, it would cause a NPE.** +This now prevents a few failures from causing potential problems. + + +* **Fixes a concurrent modification exception when the PlayerCacheCheckTimersTask is running.** +This happens rarely when a player is logging off while "trying" to process their entries; they have been removed. +So when this happens, the process retries to start over a total of 2 more times and it skips processing players that have already been processed. Any update that was skipped would be covered in the next pass with no real loss. + + +* **The use of a command placeholders for `{actionBar}` and `{title}` were added to the placeholder enumeration so they are included in the placeholders listings.** +The support for these two commands were added a while ago, but because they were not added to the enum, they were not being listed in the help. + + +**3.2.11-alpha.4 2021-11-01** + Released alpha.4. + + +* **Changes to improve the way the upcoming mine bombs.** +They are currently non-functional. + + +* **Adjustments to get block events, such as decays, to work correctly with the new auto feature block event handlers.** + Block events were moved to be processed after the block is broke. Also if a block has already been processed, it now will cancel the event to prevent normal block breakage when none should happen. +At this point, the new auto manager appears to be working really well. + + +* **Changed the location usage with block event placeholders, which now uses the location that is tied to the targetBlock instead of the mined block.** +The mined block may be null so it's not stable. + + +* **Fixed an issue with /mines block list when an incorrect mine name is used.** +Now displays an error stating the name is invalid. + + +* **Starting to add some video documents for prison.** + + +* **Fixed an issue with adding a non-block item to a mine.** +It now validates that the specified item is a block. Also if a specified block is not in a mine when trying to remove it, it will now display a message indicating that nothing was removed. + + +* **Major rewrites to how auto features work.** +Using the PrisonMinesBlockBreakEvent object to carry all of the various parameters that are used within the auto features code. This allowed the elimination of many functions since they have been combined together. It also allowed for more efficient handling of explosions by combining similar blocks together and processing them as a single unit, so massive explosions are handled far more efficiently. If the admin chooses to break the blocks in another thread, then handling of many blocks is optimized to reduce the overhead. The state of the blocks being broken are being tracked through the MineTargetPrisonBlock such that it's flagged as soon as it starts to process the impacted blocks so as to prevent the same block from being processed more than once, even when there are many explosions occurring at the same time. Changes to the block (block break) has been moved out of the depths of the code, to be closer to the event handlers so it's easier to monitor/track. +Due to the many changes and major alterations to the logic, this is a work in progress and needs more testing. + + +* **Async Mine Reset performance Improvements.** Adjustments were made to improve the performance of the asynch mine resets by providing the ability to fine tune the page sizes, and also provide the ability to reset more than one block in the synchronous thread at a time. This is called a slice. Measuring the actual block reset time with nanos for better resolution. +MineTargetBlockKey class was relocated to allow for the use of sub listings on the synchronized block updates. + + +* **Cloning a bomb was not complete. Some details were omitted.** + + +* **Fix for Potion IllegalArgumentException:** Fixed an error with potions in Player inventories when +using sellall sell, potions aren't supported by now and won't be sold, but at least it won't break +sellall anymore. + + + +* **Switched prison block debugging timing to use nanoTime instead of milliseconds since milliseconds is too large of a unit.** + + +* **Bug Fix: When using block constraints,** there was a common situation where an AIR block was being used in the top layers because all other blocks were being rejected due to chance. Order of blocks had an impact on this error, when it shouldn't. Now, if a block cannot be selected, the first block with no constraint issue will be used instead. Also found a bug in the applying of the chance to each block. Under some situations, the percent chance was not being reduced for a bypassed block, when it should have. This now will better select the blocks, and better preserve their intended percentage odds of being spawned. + + +**Prison v3.2.11-alpha.3 2021-10-18** + + +* **Enable the ability to choose between setting the block to air inline, or through submitting a synch task to allow the blockBreak event handler to finish quicker, which may reduce lag.** + + +* **Simplified the configuration of the handling of the block break events.** +Instead of having a separate setting that is a boolean value that indicates it's either enabled or disabled, these are now using the priority value of DISABLED. + + +* **Add millisecond reporting for the time it takes to handle a block break event.** + + + +**3.2.11-alpha.2 2021-10-14** + + +* **A few updates to mine bombs. They have been disabled so they cannot be used.** + + +* **Add the ability to glow the prison bombs when they are dropped/set.** + + +* **For a couple of rankup messages, using the rank tag now instead of the rank name.** + + +* **Fixed a compatibility issue with older versions of spigot.** Should have possibly use the compatibility classes, but if a method does not exist, then this will fall back on a string matching pattern. + + +* **Changed the message about worn out tool to use the SpigotPlayer's setActionBar() function to prevent overloading console messages.** + + +* **Bug fix: Logic was corrected to handle the double negative correctly.** +The was an issue with the /mines set area command when the mine's area was larger than 25,000 blocks. They have to enter either "confirm" or "yes". The bug would require them to enter both to create the mine. + + +* **Added an example of possible backpack object to the PlayerCachePlayerData object.** + + +* **Adjustments to the new auto features for cancel block break events and block drops.** + + +* **Removal of some auto feature commented out old code.** + + +* **New auto features settings: Able to prevent event canceling and also control if the drops are cleared.** +This has not been tested too much, but it may help make prison more compatible with other plugins that are needing to handle the block break events. + + +* **Fortune on a tool was appearing as a negative value: -1000.** +Not sure how it became negative, but this will better deal with negative values. + + +* **Added a listener for PlayerInteractEvent.** + + +* **Add a new feature to the PrisonSpigotAPI to allow for the creation of a new mine through the API.** +This could be used to generate player mines in a plot world. + + + +* **Able to give players bombs, based upon the item type as defined for the bomb.** + + +* **Significant progress on Prison's Mine Bombs:** +Moved the mine bombs primary classes to the prison core so it's accessible from all packages. +Setup 4 default mine bombs if the commands are used and there are none defined. +Setup a new /prison utils bomb commands to list all bombs and to give players bombs. These are not complete and fully tested yet. + + +* **Some initial work to setup the mine bombs configs.** + + +* **Add placeholders {actionBar} and {title} to the blockEvent listing of placeholders that can be used.** +They are shortcuts for the new prison utils commands. + + +* **For the actionBar and title, translate the color codes so they work properly.** + + +* **Hook up the auto features notification to use the new actionBar interface.** +This "should" prevent duplicate messages from being sent to the player while the same message is displayed in the actionbar. + + +* **Fixed an error about backpacks and lore transition:** A single lore was being used for the backpacks utility, if a server +was new and fresh, this would've been missing and an error could occur, this now got fixed with the full transition. + + +* **Full transition of all messages to the .properties lang:** All messages are now on the .properties file and the old +.yml one is unused from now on, you can delete it and start translating the new one. Please note that some messages may +be wrong, as it's still in a young stage and a lot of messages got transitioned. + + +* **The player cache, when being shut down ran in to a problem if the players were removed when they logged off.** +This function was making a new collection based upon the original player cache copy of players, of which, when a few of the players are removed, then they were resulting in nulls. + + +* **Prevented a problem when unloading players, and when a player is null.** +The condition that was causing a null player was that the player was unloaded when the player left the server at the same time when the server was shut down. Basically a race condition with two parallel async tasks trying to shut down the player cache object, each focusing on a different aspect (player vs. server). + + +* **Hooked up XSeries' Titles to the compatibility class instead of using version specific code.** +XSeries says they support 1.8.8 through 1.17.1. +Deleted the support for the Spigot110 classes since it was only to support the use of the ActionBar and also the Title, which are no longer needed for 1.10+. + + +* **Adding a player messaging component to the PlayerCache.** +When used, this will prevent more than one of the same messages from being displayed at the same time. + + +* **For the command /mines set area the confirmation of "yes" was setup incorrectly with being negated.** + + +* **Switch over to using XSeries for the actionBar.** +XSeries claims it works for 1.8.8 through 1.17.1. + + +* **Moved all Lores to the new .properties Language file:** Changes to the old .yml language file about Lore messages +won't take effect, only if you edit the .properties file they will. + + +* **Added the trigger "minebombs" for the utils command bombs.** + + +* **Adjustments to the BlockEvents and how it handles some of the event types.** +Expanded and fixed some of the settings for prison's explosions, and PE's too. +Added the ability to exclude specfic triggers. + + +* **Updates to the Prison's explosion event handling to correct a few problems. ** + + +* **Fixed SellAll Hand not removing item:** SellAll Hand didn't work properly and got now fixed. + + +* **Initial setup of Prison's mine bombs.** +Initially it will be controllable as a utils command, so random chances can be assigned to explosions. + + +* **Cleaned up some of the unused variables in the Utils titles command.** +There were plans for more commands, but they were eliminated. This will soon be rewritten to utilize XSeries's classes for these display items. + + +* **Ran in to a situation where results was actually null. So this prevents a NPE.** + + +* **Fixed issue with tool's durability being cutoff right before reaching the threshold.** +Had to change a > to a >=. + + +* **3.2.11-alpha.1 2021-08-31** +- Release the first alpha.1 + + +* **Replace the block with air through a task to get it out of the auto features thread.** + + +* **If the settings isPreventToolBreage is enabled, then don't allow the tool to break.** + + +* **Update some messages to be clearer as to what they are.** +Removed the MONITOR from auto features since they should not have the monitor setting enabled. The blockBreakEvent has the monitoring event. + + +* **Trying to fix an error related to SpigotRankManager GUI:** I can't reproduce the issue but the NPE shouldn't +give a stacktrace in the console anymore. + + +* **If the primary block was null, which it never should be, then this prevents a failure in this section of code in the OnBlockBreakEventCore.** + + + +* **For the initial startup air count task, which is used to "reset" the block counts on a mine.** +This does not change any blocks, but just finds out where the mine was when the server was last shut down. This is needed to ensure we have valid counts for the mines before the first time they are reset. The other way to update these values is to do a full mine reset which is more costly. +There was an inconclusive error that just listed "null" as the error messags, without identifying the actual line number. This error catching was changed to now generate a stack trace so it can be properly fixed if it occurs in the future. + + +* **Added a few more reporting entries on the block break handling.** +Reporting how many blocks are being processed and if it passes the validation phase. + + +* **Some fixes for teleporting and the removal of the teleport glass block.** + + +* **Updates to the PrisonEnchant's API.** +Minor adjustments to work with the new API from PrisonEnchants. + + +* **Updates to async block updates.** +Included changes to hook up the CustomItems to work with the async updates. + + +* **Clarify some of the messages related to listing of the block events.** + + +* **Added the ability to identify if a block is able to be affected by gravity. Also the mine has a global setting to identify quickly if any block is gravity affected.** +This will be used to alter the mine reset strategy to improve performance so as to hopefully eliminate long resets due to extensive lag from falling blocks. The idea is to get all the other blocks in to place before placing the falling blocks to ensure they are less likely to fall. + + +* **If the Mine's saved file data is corrupted (manually edited with incorrect data), this will prevent the mine from being loaded and will now generate an error message indicating which mine has a problem loading. It will print out the invalid data, and it will default to a value of 0.00001. The function has been updated to "properly" use the localized format, so if it saves in a non US way, then it should now be able to read it back in and parse it correctly. + + +* **If the Mine's saved file data is corrupted (manually edited with incorrect data),** +this will prevent the mine from being loaded and will now generate an error message indicating which mine has a problem loading. It will print out the invalid data, and it will default to a value of 0.00001. + + +* **Checking to ensure the locations are not null when loading.** +There was a failure with bad data on the files system that was resulting in trying to resolve nulls to a location, which obviously cannot happen. + + +* **There was an odd situation where the player was null, when usually they never can be, so this helps prevent possible errors.** +The null was caused by an issue with a placeholder? Don't really remember. + + +* **Adjustments to Prison's TPS calculations.** +They were only taking the average of just two readings which was resulting in very unstable TPS values. Now 10 are being used. +Enabled a new feature where the resolution can be changed from normal (a reading every tick) to high resolution (one reading every 2 ticks). When the resolution changes, the task will auto terminate and resubmit with the new settings. + + +* **For the command /ranks autoConfigure made some adjustments to the block lists being used so the top mines have more valuable ores and blocks. There was a shortage and the wrong blocks were being used. + + +* **Fixed an auto features config setting for prison's ExplosiveBockBreakvents priority; it was missing the word priority.** +Reworked some of the details on autofeatures as displayed through /prison version to update them to better reflect the correct settings and dependencies. + + +* **Fixed a problem with placeholders when using the search feature, but not supplying a player's name.** + + +* **some internal changes to improve the resets** + + +* **eliminate the block access in this class since it handles everything in the submitted task.** +This was causing an error when it was being ran in an async thread. When the task is submitted, it is ran synchoronously so it works correctly. + + +* **Changed prison's TPS calculation to be able to enable a high-res setting when the `/mines stats` is enabled.** +The one problem with enabling high resolution mode is that it could show an unrealistic low TPS during a reset. The /lag command shows a much higher TPS value. + + +* **Setup up the basics for async updates.** +In the code that does the update, it also now reads the block to ensure that the read and update is all done in the synch thread. Otherwise the old code would be risking chunk loading in an async thread. +Using the Location and World to perform the async updates outside of needing access to the spigot module. +At this time, only `/mines set tracer` is using the new async reset. + + +* **Tweaks to the event listener dumps for block breaks.** +Updated the notes about prison's listeners. +PEExplosionEvent was setup with the wrong forClass name. + + +* **Setting up a new way to handle block updates in prison. Adding functions that are intended to be use while running in an async threads.** + + +* **Transitioning over to the correct way to get the compatibility object.** +Just a few classes are using the old way, but they will be switched over when they are done with the edits. + + +* **Fixed the way some of the language files were being generated** +so it can include the spigot module, which makes it self-contained for actual Modules, since it's always based upon the module name. +Core and spigot are not technically modules, so they have special setups. +Changed the Module folder from dataFolder to moduleDataFolder so it would not conflict with the SpigotPrison object. + + +* **Fixed a problem with Prison's ExplosiveBlockBreakHandler** + in that it has a typo in the getHandlerList() and was not included with the registration processes. It also needed to be included with the generation of the listener dumps. + + +* **Added /sellall hand command.** + + +* **Minor changes to SellAll Util.** + + +* **Much better performance for SellAll generally.** + + +* **SellAll Commands internal changes.** + + +* **Minor changes to GUIs:** Some fixes and visual changes. + + +* **SellAllUtil Rewrite:** New internals for SellAll and SellAll API. + + diff --git a/docs/prison_changelogs.md b/docs/prison_changelogs.md index 90e81a861..73aa35c18 100644 --- a/docs/prison_changelogs.md +++ b/docs/prison_changelogs.md @@ -3,20 +3,31 @@ ## Prison Build Logs for v3.3.x ## Build logs + +These build logs represent the work that has been going on within prison. + - **[v3.3.0-alpha - Current](changelog_v3.3.x.md)** + - Future updates will be under the v3.3.x release + + + - [v3.2.11 - 2022-01-22](prison_changelog_v3.2.11.md)   + - [v3.2.10 - 2021-08-23](prison_changelog_v3.2.10.md)   + - [v3.2.9 - 2021-07-03](prison_changelog_v3.2.9.md)   + - [v3.2.8 - 2021-06-17](prison_changelog_v3.2.8.md)   + + + - [v3.2.7 - 2021-05-02](prison_changelog_v3.2.7.md)   + - [v3.2.6 - 2021-04-11](prison_changelog_v3.2.6.md)   + - [v3.2.5 - 2021-04-01](prison_changelog_v3.2.5.md)   + - [v3.2.4 - 2021-03-01](prison_changelog_v3.2.4.md)   + + + - [v3.2.3 - 2020-12-25](prison_changelog_v3.2.3.md)   + - [v3.2.2 - 2020-11-21](prison_changelog_v3.2.2.md)   + - [v3.2.1 - 2020-09-27](prison_changelog_v3.2.1.md)   - [v3.2.0 - 2019-12-03](prison_changelog_v3.2.0.md)   -[v3.2.1 - 2020-09-27](prison_changelog_v3.2.1.md)   -[v3.2.2 - 2020-11-21](prison_changelog_v3.2.2.md)   -[v3.2.3 - 2020-12-25](prison_changelog_v3.2.3.md)   -[v3.2.4 - 2021-03-01](prison_changelog_v3.2.4.md)   -[v3.2.5 - 2021-04-01](prison_changelog_v3.2.5.md)   -[v3.2.6 - 2021-04-11](prison_changelog_v3.2.6.md)   -[v3.2.7 - 2021-05-02](prison_changelog_v3.2.7.md)   -[v3.2.8 - 2021-06-17](prison_changelog_v3.2.8.md)   -[v3.2.9 - 2021-07-03](prison_changelog_v3.2.9.md)   -[v3.2.10 - 2021-08-23](prison_changelog_v3.2.10.md) + -These build logs represent the work that has been going on within prison. diff --git a/docs/prison_docs_000_toc.md b/docs/prison_docs_000_toc.md index 7f2aac8bc..1e48226ee 100644 --- a/docs/prison_docs_000_toc.md +++ b/docs/prison_docs_000_toc.md @@ -17,7 +17,8 @@ ## Build logs - **[v3.3.0-alpha - Current](changelog_v3.3.x.md)** - - [v3.2.0 through v3.2.10](prison_changelogs.md) + + - [v3.2.0 through v3.2.11](prison_changelogs.md) @@ -25,25 +26,70 @@
-# Prison Now Fully Supports Spigot 1.17.1 and Java 16 !! +# Prison Supports Spigot 1.8 through Spigot 1.18.x +# Prison Supports Java 1.8 though Java 17 +# Prison is created for the Spigot Platform, and works on other platforms based upon Spigot -## Prison now has Access By Rank to Reduce the number of Permissions needed! - +With the release of Spigot 1.17.x, there were a few minor changes that were needed to be made to prison to support Java 16. These were mostly related to a couple of NMS routines that were trying to figure out the player's default language they have selected. Due to new restrictions moving forward with Spigot, the ability to correctly identify the player's default language may not be possible, but prison will still use the selected language setting in the config files. + + +Prison supports both Spigot 1.17.1 and Spigot 1.18.x, along with Java 17. At this time there hasn't been any reports of incompatibilities. Since prison is using a library to support the correct blocks for the version of the server that you are running, we are limited to when updates are released for that library. Luckily they have had a couple of releases and we have applied them to the latest alpha releases. So if you are wanting to maximize the new Spigot 1.18.x experience, please upgrade to the latest alpha release as found on our discord server in the #alpha channel. + + +### Newer features and updates in Prison: + + +* Auto Configure: Even if you really don't want to use auto configure when setting up your server, it may be worth trying it out just to see what it does. If you're not happy with it, then deleting the `plugins/Prison/` directory will remove "everything" and on the next restart of your server, prison will load for the first time. So if you are just getting started with prison, it's worth a try. + + +* Prison now has Access By Rank to reduce the number of Permissions needed! This simplifies a lot of settings and on a simple Prison server, can get you up and running much faster. + +* Backpacks: It is advised not to use Prison's backpacks at this time. They will be going through a rewrite and may result in content losses when upgrading when the newer version is available. It is suggested you give MinePacks at try. + +* Prison Mine Bombs! Prison is starting to add mine bombs to the list of available features. This is a work in progress and more enhancements and features will be added in the future. The idea with these, is that you can configure almost every aspect of the mine bombs, and you can have as many different varieties as you want. + +* Prison Tokens! Prison is starting to implement the earning of tokens within the mines as the players mine. This is a work in progress. Currently the hooks are added to earn tokens, and for admins to manage them. But more features need to be added to help enable using them. + +* Prison Stats! More stats are being tracked for each player. This is a work in progress. Prison is tracking blocks mined and even per mine. Prison is tracking time spent mining in each mine, along with how much a player is earning per mine with both regular currency, and with tokens. Top-n reports will be available shortly. Rankup requirements will soon include the ability to specify blocks mined, time spent mining, and even tokens. This will help you customize how you want your players to ranup. + + +### Features planned for the near future + +These new features are in the planning stages... + +* New backpacks: A rewrite of the backpacks that will give a little more flexibility. You will be ble to use them as backpacks, or as vaults. Could even sell, or trade backpacks/vaults with their contents. ETA is unknown since a new storage management system needs to be created. + +* Mine Effects: The ability to set mine effects for a given mine, or to allow players to buy effects using their earned tokens. Effects could be simple potion effects (haste, night vision), or even effects such as no fall damage, and even flight. Other options could be no-pvp, enable pvp, no block break, no fire, etc... The options are numerous, but will be added a little at a time, and upon request. -
+ * Mine Regions: Mine regions may be added to prison soon. They would be "area" that will control the Mine Effects and a region would/should enclose a given mine. But mine regions could be used on their own, were no mine is involved, such as at spawn to enble flight and no fall damage for your higher ranking players, or even allow players to "buy" regions to put around their bases so they can enable nigh vision and flight. + +* Custom Menus: Simple custom menus could be added so admins can setup simple commands and features. For example, custom token shop for enchantments or other in game items, or run any commands in general. This will start off simple, but will expand upon requests. + +* Unlimited Prestiges: This has been a long standing requested feature. It's close to being added. Although the levels may be unlimited, special configurations could be added for different levels, such as adding ladder commands at specific levels (ladder commands allows you to peform any action upon rankup, even from other plugins). + +* Custom Shops: Custom shops will allow for an unlimited number of new shops to be created. These shops can be tied to perms or player Ranks, or even specific mines. Each shop could be either stand alone, or it could be based upon another shop with price modifies and new items to prevent the need to redefine all entries for each shop. A mine shop would only be able to sell items that are retrived from mining in that mine. + +* Cells: They have been requested many times in the past. At this time, we cannot add them yet, but we would like to sometime in the distant future. + +* Enchantments: In the past we have stated that Prison will never support enchantments for pickaxes, or other tools, or weapons and amour. But as Prison is evolving and more features such as mine bombs and mine effects are added, along with natively supporting tokens within prison, the idea of adding enchantments is almost a no-brainer since most of the complicated details will already be supported through other features. So in the distant future, some time after mine bombs and mine effects have matured, we may add our own Enchantments. + + + +
# New! Prison Fast Start +See the Auto Configure documentation for more information: [Prison Auto Configure / Prison Quick Start!](prison_docs_100_setting_up_auto_configure.md) Prison now has a new set of features that can help you get up and running faster than ever! With the latest version of Prison, you can even have a functional Prison server running with just two Prison commands. See below for more information. -**It is strongly recommended that the '/ranks autoConfigure' should always be ran first.** Prison's Auto Configure sets up so many features, that it can help resolve many initial issues. +**It is strongly recommended that the '/ranks autoConfigure' should always be ran first.** Prison's Auto Configure sets up so many features, that it can help resolve many initial issues. It's worth trying the first time you run prison since it's easy to undo: just delete the `plugins/Prison' directory and the next time you restart your server Prison will startup as if it was just installed with no settings. -Before you try to setup Prison, you really need to install an Economy or the Ranks module will not be enabled. It is strongly suggested you install the following plugins: Vault, EssentialsX, EssentialsX-Chat, PlaceholderAPI, LuckPerms, WorldEdit, WorldGuard (or Fast Async World Edit, FAWE, on newer versions of Spigot). +Before you try to setup Prison, you really need to install an Economy or the Ranks module will not be enabled. It is strongly suggested you install the following plugins: Vault, EssentialsX, EssentialsX-Chat, PlaceholderAPI, LuckPerms, WorldEdit (or Fast Async World Edit, FAWE, on newer versions of Spigot), WorldGuard. `/ranks autoConfigure`. It can auto create your ranks and virtual mines, A through Z, it will link the mines to the ranks, setup the Mine Access By Rank and TP Access By Rank. It will also setup the Mine as a Virtual Mine will and assign blocks of increasing values to all mines. Each mine will also be assigned a random liner. The Ranks autoConfigure will also enable sellall and load over 90 default blocks for your shop. Auto features will be enabled (auto pickup, auto smelt, and auto blocking). @@ -205,7 +251,9 @@ Auto configure can get you up and running with as little as two commands. The f * [Setting up LuckPerms](prison_docs_020_setting_up_luckperms.md) - Setting up LuckPerms. Warning about LuckPerms Versions. + Setting up LuckPerms. +* [Setting up LuckPerms Groups & Tracks](prison_docs_030_LuckPerms_Groups_Tracks.md) + Using LuckPerms's groups and tracks with Prison. * [Setting up PermissionsEX](prison_docs_022_setting_up_PermissionsEX.md) diff --git a/docs/prison_docs_010_setting_up_a_spigot_server.md b/docs/prison_docs_010_setting_up_a_spigot_server.md index 12b635bf6..814fbc645 100644 --- a/docs/prison_docs_010_setting_up_a_spigot_server.md +++ b/docs/prison_docs_010_setting_up_a_spigot_server.md @@ -13,6 +13,7 @@ Buildtools also allows easy setup of many test environments since all you would need to do is to just change the version. +*Documented updated: 2021-12-03*
@@ -22,8 +23,9 @@ This is intended strictly as a high-level overview on how to setup Java. If you need more assistance, please search for online documentation since there are many good resources out there. -* First install a copy of Java that is accessible from the command line. - - It’s strongly suggested to use only the latest version 1.8.0_x since that is the version spigot and most other plugins are developed under. +* First install a copy of Java that is accessible from the command line. + - The current version of Java is version 17. Even if you are using jars and other plugins that were compiled with Java 1.8.x, it is recommended to use Java 17. + - If you feel like you must use Java 1.8, it’s strongly suggested to use only the latest version 1.8.0_x. * You can download it from [Sun SE Development Kit 8]https://www.oracle.com/java/technologies/javase/javase-jdk8-downloads.html) for product that you need. @@ -48,18 +50,25 @@ there are many good resources out there. ``` java -jar BuildTools.jar --rev 1.8.8 + java -jar BuildTools.jar --rev 1.9.4 + java -jar BuildTools.jar --rev 1.10.2 + java -jar BuildTools.jar --rev 1.11 java -jar BuildTools.jar --rev 1.12.2 java -jar BuildTools.jar --rev 1.13.2 java -jar BuildTools.jar --rev 1.14.4 - java -jar BuildTools.jar --rev 1.15.1 + java -jar BuildTools.jar --rev 1.15.2 + java -jar BuildTools.jar --rev 1.16.5 + java -jar BuildTools.jar --rev 1.17.1 + java -jar BuildTools.jar --rev 1.18 ``` -* For example, with BuildTools.jar being in a root directory, create a subdirectory and then start a build within that directory. The benefit is that you can use the same BuildTools.jar to build multiple different versions of spigot. This example starts off with building a v1.14.4 instance and then builds a 1.8.8 instance. +* For example, with BuildTools.jar being in a root directory, create a subdirectory and then start a build within that directory. The benefit is that you can use the same BuildTools.jar to build multiple different versions of spigot. This example starts off with building a v1.17.1 instance and then builds a 1.8.8 instance. Normally you wouldn't build multiple versions of spigot, but this shows how easy and flexible it is to build any version of spigot that has been released. ``` - mkdir spigot-1.14.4 - cd spigot-1.14.4 - java -jar ../BuildTools.jar –rev 1.14.4 + mkdir spigot-1.17.1 + cd spigot-1.17.1 + java -jar ../BuildTools.jar –rev 1.17.1 + cd .. mkdir spigot-1.8.8 cd spigot-1.8.8 @@ -78,33 +87,35 @@ there are many good resources out there. # Creating a Runnable Spigot Server -* Create a runnable server directory by creating a new directory outside of the build directory. Then copy the newly generated jar file, such as spigot-1.14.4.jar, to the new server run time directory. +* Create a runnable server directory by creating a new directory outside of the build directory. Then copy the newly generated jar file, such as spigot-1.17.1.jar, to the new server run time directory. + +* NOTE: At the time when this document was updated, Spigot 1.18 was just released. Because 1.18 requires Java 17, it is advisable to use that version of Java. Prison, because it is still being ran on older servers and under older environments, it must try to support the widest array of Spigot versions; therefore it is built with the latest version of Java 1.8.x, and built using Spigot 1.13.2. The environments in which Prison is built, should not impact how you build and run your server, of which it could easily be with Java 17 and Spigot 18. * Windows example, if you’re still in the build directory: ``` cd ../.. - mkdir spigot-1.14.4_server - copy /B builds\spigot-1.14.4\spigot-1.14.4.jar spigot-1.14.4_server + mkdir spigot-1.17.1_server + copy /B builds\spigot-1.17.1\spigot-1.17.1.jar spigot-1.17.1_server ``` * Linux example, if you’re still in the build directory: ``` cd ../.. - mkdir spigot-1.14.4_server - cp builds/spigot-1.14.4/spigot-1.14.4.jar spigot-1.14.4_server + mkdir spigot-1.17.1_server + cp builds/spigot-1.17.1/spigot-1.17.1.jar spigot-1.17.1_server ``` -* Run the server for the first time (see the next step). It will start to auto-generate the server environment and then will stop. You will need to manually modify eula.txt and set eula=true. Save. Close. Restart the server. It will startup successfully now. +* Run the server for the first time (see the next step). It will start to auto-generate the server environment and then will stop. You will need to manually modify the `eula.txt` file and set `eula=true`. Save. Close. Restart the server. It will startup successfully now. * This is a simple example of what is needed for a windows cmd file. It sets the minimum memory to 2 GB and the max to 8 GB. A linux script would be similar, but without the pause. ``` - java -Xms2g -Xmx8g -jar spigot-1.14.4.jar + java -Xms2g -Xmx8g -jar spigot-1.17.1.jar pause ``` diff --git a/docs/prison_docs_012_setting_up_prison_basics.md b/docs/prison_docs_012_setting_up_prison_basics.md index 35b801f3b..1dcf09962 100644 --- a/docs/prison_docs_012_setting_up_prison_basics.md +++ b/docs/prison_docs_012_setting_up_prison_basics.md @@ -6,6 +6,9 @@ This document provides a quick overview on how to install Prison and get it running. + +*Documented updated: 2021-12-03* +
@@ -40,7 +43,7 @@ Setting up Prison is simple: * Prison's startup information contains a lot of information. If you ever have issues, check that information first since it probably will identify what the issues are. -* It is strongly suggested that `/ranks autoConfigure` is ran to initially setup your Prison environment. +* It is strongly suggested that `/ranks autoConfigure` is ran to initially setup your Prison environment. A great deal of configurations are setup that can save a lot of effort. Even if you are wanting to start from scratch, it may be worth giving it a try to see how some of the more complex settings are configured. You can always start over by deleting the `plugins/Prison/` directory. * Follow Prison's documentation on customization; at this point it's ready for use. @@ -54,13 +57,15 @@ Setting up Prison is simple: * **None - No hard dependencies** - There are no hard dependencies for Prison. -There may be no hard dependencies that will prevent Prison from running, but there are some core plugins that will make it easier to use. This short list is just a suggestion, but alternatives do exist and may be outside of our ability to comment or assist in their usage. +There may be no hard dependencies that will prevent Prison from running, but there are some core plugins that will make it easier to use, and are even required for activation of some features within Prison. This short list is just a suggestion, but alternatives do exist and may be outside of our ability to comment or assist in their usage. * **Vault** - Optional, but STRONGLY Suggested - This is perhaps the most important plugin. This plugin provides a common way to access other plugins running on your server, but without having to write any code within Prison to support them. Vault provides the mapping of a plugin's unique APIs to a common Vault API. Vault helps support Economy, Permissions, and Placeholders. Because of Vault, Prison can work flawlessly with dozens of other plugins. Please refer to Vault's documentation for what it supports. -* **EssentialsX** - **STRONGLY SUGGESTED**, but still Optional - Provides many of the basic commands and behaviors that you would expect from a Spigot server such as chat, warps, and even some moderation commands and commands that can be given to premium players. EssentialsX is not Essentials, since Essentials is an older abandoned project, and EssentialsX is a forked project that is still maintained. Unfortunately, internally it is identified as simply Essentials, but you can tell it's EssentialsX if the version is greater than 2.15.x. EssentialsX is released as a zip file and you must extract the jars that you are interested in. It should also be pointed out that all EssentialsX jars should come from the same zip file so they will be of the same version and the same release. +* **EssentialsX** - **STRONGLY SUGGESTED**, but still Optional - Provides many of the basic commands and behaviors that you would expect from a Spigot server such as chat, warps, and even some moderation commands and commands that can be given to premium players. EssentialsX is not Essentials, since Essentials is an older abandoned project, and EssentialsX is a forked project that is still maintained. Unfortunately, internally it is identified as simply Essentials, but you can tell it's EssentialsX if the version is greater than 2.15.x. + + EssentialsX is released as a zip file and you must extract the jars that you are interested in. It should also be pointed out that all EssentialsX jars should come from the same zip file so they will be of the same version and the same release. UPDATE: The last I checked EssentialsX may not be released in a single zip file anymore. It looks like you have to download the parts you are interested in using. ### Economy Plugins - Required @@ -68,15 +73,36 @@ There may be no hard dependencies that will prevent Prison from running, but the Prison requires an active economy in order to active the Ranks plugin. When Prison starts up, it performs many validations on the mines and ranks as they are being loaded. With Ranks, if Prison cannot find an active economy, then it will refuse to load the Ranks module due to possible server corruption (ie... what failed that there is no economy). -* **EssentialsX Economy** - SUGGESTED - Optional - This is a simple economy plugin that just works well. If you don't have a specific need to use another economy plugin, then it may be best to use this one since it works so well. +* **EssentialsX Economy** - SUGGESTED - Optional - This is a simple economy plugin that just works well. If you don't have a specific need to use another economy plugin, then it may be best to use this one since it works so well. The reason why we recommend this economy is because it always works. That said, we acknowledge the reason it works well, is because it is so simple, so if there are features in other economy plugins that you want to use on your sever, then please explore using them. But overall, if you just want an economy that is rock solid, then EssentialsX's Economy is a great choice. + + +* **CMI Economy** - Optional - Formerly we could not recommend its use, but Prison now has a couple of advanced tools that is able to allow CMI to fully load before Prison needs to use CMI's functions. Therefore if you want to use many of CMI's features, you now can! + + CMI "tries" to load last, thus it can ensure all of it's dependencies and hooks are in place before it starts up. That's understandable, and Prison also has similar requirements and expectations. Unfortunately, this also causes a conflict with Prison, since Prison must perform validation on startup, and if there is no economy, then Prison could fail to start. + + To get CMIE to work correctly with prison, there are a couple of things that you must do. + + 1) You must use the normal version of Vault and then use the CMI Vault Injector. We've never seen the CMI provided version of Vault work with prison, so therefore recommend not using it. Symptom is that prison reports a 0.00 amount for the online player when using `/ranks player `. The Vault inject has always worked well. + 2) The CMI Economy **has** to be fully loaded and active *before* prison loads the Ranks. Otherwise prison will refuse to load the ranks and prison will not work. You must make a configuration change within Prison's `plugins/Prison/config.yml` file. Near the bottom of that config, are a few settings that need to be enabled. The following is an example of what is needed, along with a configuration that will work in most situations. + +``` +delayedPrisonStartup: + enabled: true + cooldown-secs: 5 + max-attempts: 6 + inspect-vault: true + triggers: + vault: true + vault-economy-name: Economy_Essentials +``` + If enabled, and you are still having problems, please contact Blue on Prison's discord server. To get CMIE to work may be as simple as increasing the `cooldown-secs` or the `max-attempts` settings, but there could be another conflict going on. Blue can review your server's startup log to identify the problem and help you fix it. + -* **CMI Economy** - Not Suggested - CMI has a lot of really neat features, so it's totally understandable that you may want to use their economy too. But the reason why we do not suggest it's use is because it is difficult to get to work with prison for a few reasons. We will try to support your use of CMIE, but you will have to try to be proactive in trying to get it to work; if you just want "simple", then try EssentialsX Economy first. -1) You must use the normal Vault and then use the CMI Vault Injector. We've never seen the CMI provided version of Vault work with prison. Symptom is that prison reports a 0.00 amount for the player when using `/ranks player `. The Vault inject has always worked well. -2) The CMI Economy **has** to be fully loaded and active *before* prison loads the Ranks. Otherwise prison will refuse to load the ranks and prison will not work. It appears as if CMIE is purposefully delaying it's activation until all other plugins are finished loading; I'm sure there is a good reason for that, but it causes prison to fail. Setting up proper soft dependencies within Prison does not work. To address this serious issue, because we really want CMIE to work with Prison, there is a new setting that will actually delay prison's startup to give CMIE a chance to active. This new feature should not be used without a good reason since it alters Prison's startup processes, but it has shown to work very well. The configs are within the config.yml file, but talk to Blue *before* trying to enable it. +### Chat Prefix Plugins - Optional +These plugins are used to add rank tags to the player's chat messages that they send. -### Chat Plugins - Optional * **EssentialsX Chat** - Optional - Enhanced Chat experience. Provides customizations to the chat prefixes. @@ -95,36 +121,55 @@ Permission plugins are not *strictly* required for Prison to work, but within a Prison actually uses bukkit's permission interfaces. This makes it simple for Prison, but it also limits what prison can do. For example, one limitation is with permission groups; Prison is unable to resolve permission groups since that "concept" does not exist in bukkit, but is a concept that is implemented through plugins like PEX and LuckPerms. -* **LuckPerms** - Required - LuckPerms is a great permission plugin that is actively supported and has many new features to make managing your server easier. +* **LuckPerms** - Required - Strongly Suggested - LuckPerms is a great permission plugin that is actively supported and has many new features to make managing your server easier. -* **LuckPerms v5.x.x** - Use the latest version of LuckPerms whenever you can. Keep in mind that releases to spigotmc.org is somewhat infrequent; giving them the "counts" for downloads is nice, but you may have to go to their main download page to get the most recent releases: [https://luckperms.net/download](https://luckperms.net/download). Please note that is normal for issues to surface once in a while, and there were a few that needs to be avoided: The releases v5.3.0 through about v5.3.3 had some issues that caused significant logging and failures. +* **LuckPerms v5.x.x** - Use the latest version of LuckPerms whenever you can. Keep in mind that releases to spigotmc.org is somewhat infrequent; giving them the "counts" for downloads is nice, but you may have to go to their main download page to get the most recent releases: [https://luckperms.net/download](https://luckperms.net/download). Please note that it is normal for issues to surface once in a while, and there were a few that needs to be avoided: The releases v5.3.0 through about v5.3.3 had some issues that caused significant logging and failures. * **LuckPerms v4.x.x** This older version of LuckPerms is still supported, but it is highly recommended to upgrade to the latest v5.x.x release. LuckPerms v4.x.x is required for prison v3.2.0 and older (Prison v3.2.1 and newer supports all versions of LuckPerms). Please consider upgrading both Prison and LuckPerms to the latest releases for the best experience. -* **NOTE: A permissions plugin of your choice** - Required - Prison works with many different permission plugins through Vault. I strongly suggest LuckPerms since it is free and is under active development so bugs and performance issues will be addressed. If you choose to use another permission plugin, then please consider ones that work with Vault; Prison uses Vault provide the flexibility of choosing from many different plugins. +* **Gems Economy** - Gems Economy supports multiple currencies. Support for Gems Economy was added a few years ago and worked well at the time. If you try to use this plugin and have issues, please contact Blue on Prison's discord server so the issues can be addressed. + + +* **NOTE: A permissions plugin of your choice** - Required - Prison works with many different permission plugins through Vault. I strongly suggest LuckPerms since it is free and is under active development so bugs and performance issues will be addressed if they ever become an issue. If you choose to use another permission plugin, then please consider ones that work with Vault; Prison uses Vault to provide the flexibility of choosing from many different plugins. * **Other Permission Plugins** There are many out there, and as developer of Prison, and through providing support, we don't hear of any issues with other permission plugins. The reason for this is because they probably just work well to begin with, and that Prison uses bukkit's permission interfaces. So it keeps things simple for setting up Prison. If you are just getting started with building a server, then we suggested keeping it simple with something like LuckPerms, but there are other permission plugins out there that can provide a whole new experience with your server, such as jobs and careers for your players. + ### Placeholder Plugins -Chat related plugins provides access to Prison placeholders, but these placeholder plugins takes it to the next level and allows other plugins to access prison data. There are not many out there, mostly because papi is so simple and does it so well so there is no real need for other plugins. +Chat related plugins are able to provides access to Prison placeholders, which can allow Prison data to be included in their content. PAPI is simple and works so well, that it usually is the default choice. + + +The way a placeholder works, is that it is a text based **key** that is used to request data. Generally the key is included with other text, such as a chat message, holographic display, or a scoreboard content, and the key is replaced with the requested data. Usually the plugins using placeholders have no idea what other plugins are supplying the requested data; they basically make a general request for information to all plugins, and the plugins that recognize that **key** will respond. + + +It should be noted that Prison's placeholders are just text based keys. They are usually all lower case alpha numeric characters, with underscores, and maybe some colons too. The important thing to understand is that they do not include the escape characters, and that the escape characters may differ from what is required in other plugins. Placeholder escape characters are usually `{ }` or `% %`, and sometimes you may have to mix the two. The plugin's documentation should help you identify what's the correct usage. + +All prison placeholders start with `prison_` and are usually all lower case. Upper case may work too, but lower case is recommended. Prison tries to ignore the case of its placeholder keys, but its the other plugins that can have issues. For example, if Prison registers all of the plugins as lower case, then the other plugins may not recognize all upper case, or mixed case, as being related to Prison, so therefore they may not send the request to Prison. -It should be noted that Prison's placeholders do not include the escape characters, and they may vary in the other plugins that you use placeholders. Sometimes they may be { } or % %, and sometimes you may have to mix the two. The plugin's documentation should help you identify what's the correct usage. +An example of a prison placeholder is `prison_rank`. But used in another plugin, you will need to add escape characters such that it may be either `{prison_rank}` or `%prison_rank%`. Prison only controls what the text key is; prison cannot control which escape characters are used in another plugin. -* **PlaceholderAPI** - Strongly Suggested - Also known as papi. Used through Vault, it is free and provides the core interfaces in to the usage of placeholders. Prison also has a special integration setup for PlaceholderAPI to register all of the Prison placeholders dynamically upon startup. You do not need to download anything from the cloud for prison to work with this plugin. Also if you reload papi, you do not have to reload Prison's placeholders. Prison registers placeholders that are all lower case and more recently, all upper case too so it's easier to use placholders through papi. + +All of Prison's placeholders have an alias. An alias is a shortened name for a placeholder. Some placeholder names can become large based upon trying to keep their names informative as to what they represent. As an example, `prison_rank` has an alias of `prison_r`. And `prison_player_balance_earnings_per_minute_formatted` has an alias of `prison_pb_epmf` which can be useful if there is limited space in the configurations. The command `/prison placeholders list` shows all available placeholders, along with their aliases. + + +* **PlaceholderAPI** - Strongly Suggested - Also known as **papi**. Used through Vault, it is free and provides the core interfaces in to the usage of placeholders. Prison also has a special integration setup for PlaceholderAPI to register all of the Prison placeholders dynamically upon startup. You do not need to download anything from the cloud for prison to work with this plugin. Also if you reload papi, you do not have to reload Prison's placeholders. Prison registers placeholders that are all lower case and more recently, all upper case too so it's easier to use placeholders through papi. + + NOTE: You may also need to install the follow plugin for full support: ProtocolLib. * **MVdWPlaceholder** - Suggested to Avoid - Prison does support this plugin, but since it is used mostly with premium plugins, we have no way to fully test this plugin to ensure it actually works correctly. We've heard very few people have used this plugin, but we've heard it does work well. Use at your own risk. -With this plugin, all placeholders are registered with it automatically when prison starts up, and all placeholders should be used as all lower case. Because prison has so many plugins, with many that are expanded based upon ladders, ranks, and mine names, a modest prison server could generate and register well over 1000 placeholders. MVdWPlaceholder appears to be very verbose so you will see a lot of logging. -It should also be noted that because of some of the limitations of MVdW, not all features of Prison's placeholder support will be supported. For example, you may not be able to reload placeholders, or use placeholder attributes to customize how placeholders are used. +With this plugin, all placeholders are registered with it automatically when prison starts up, and all placeholders should be used as all lower case. Because prison has so many placeholders, with many that are expanded based upon ladders, ranks, and mine names, a modest prison server could generate and register well over 1000 placeholders. MVdWPlaceholder appears to be very verbose so you will see a lot of logging in the console when it starts up. + + It should also be noted that because of some of the limitations of MVdW, not all features of Prison's placeholder support will be supported. For example, you may not be able to reload placeholders, or use placeholder attributes to customize how placeholders are used. @@ -216,7 +261,7 @@ Some of the important details that are listed: * Which modules were successfully loaded * The root commands that are available * The integration status of all related plugins that are supported -* The list of active placeholders +* The list of active placeholders (removed due to size. see `/prison placeholders list`) * Startup error messages, if any. Examples would be if a rank is configured to use a custom currency and that currency cannot be found in any economy. @@ -230,7 +275,7 @@ custom currency and that currency cannot be found in any economy. If you are leasing a server from a hosting service you may not be able to customize the startup script. But if you have control over it, then the following information may help. -`java -Xdebug -Xms2g -Xmx4g -jar spigot-1.16.5.jar -nogui` +`java -Xms2g -Xmx4g -jar spigot-1.16.5.jar -nogui` Example of enabling debug hooks for the server. This is used with Eclipse, and may work with other IDEs since it's a java directive. @@ -274,6 +319,35 @@ through: ``` +# Prison Support Submit Information + +Prison now has a built in way to share your configurations and settings with support personnel. + +More information will be documented in the future, but for now, here are the basics on how to use it. + +When requested by the Prison support team, you would first enter the following command to set your name that will be included on all reports to help identify who the are related to. It doesn't have to be your full discord name, but enough characters to allow us to identify who you are. + + +These commands will collect all of the related information from your Prison setup, and send it to the website `https://paste.helpch.at`. It will provide you with an URL. All you need to do is to copy and paste that URL in to the discord chat so the Prison support team can help with your issue. + + +`/prison support setSupportName ` + +Once entered, it will enable the following submit tools: + +`/prison support submit` - Show the available tools. + +``` +/prison support submit configs +/prison support submit latestLogs +/prison support submit mines +/prison support submit ranks +/prison support submit version +``` + +Here is an example that I generated from one of my test servers on 2021-12-03. I have no idea how long the content remains available, but for support purposes, we only need this information for a few hours. + [https://paste.helpch.at/itejovejeh](https://paste.helpch.at/itejovejeh) + # Prison Commands diff --git a/docs/prison_docs_013_Prison_Help.md b/docs/prison_docs_013_Prison_Help.md index 4bddd8f26..f6d6bd04e 100644 --- a/docs/prison_docs_013_Prison_Help.md +++ b/docs/prison_docs_013_Prison_Help.md @@ -6,6 +6,9 @@ This document provides some important information on how to find help in setting up your prison server, and ultimately, how and where to ask for help. + +*Documented updated: 2021-12-03* +
# Overview @@ -20,19 +23,50 @@ If you are having problem, please take a quick look at the following documents a
+ +# Asking for Help + +Before you actually ask for help, take a look at some of the documents presented here. You may find your answer, or at least become a little more familiar with Prison. There is a good chance that if your question is a common one, then you will just be referred to this documentation anyway. + +When you do ask for help, please realize if you can provide a clear description of the problems you are experiencing, plus the versions of Prison, Spigot, etc, then we can help you faster and more accurately. To help provide you with answers to these questions, see the next section of this document for information on what you can copy and paste to provide all those much needed details. + + + +
+ + + +# Prison Command 'help' keyword + + +Prison has a very advanced command handler that provides a lot of advance features. But one simple feature to know about and to use is the use of the 'help' keyword. + + +If you add '**help**' to any command within prison, prison's command handler will show you information on what the command is, how to use it, parameters, how to get more help and details, and also what permissions are needed to use the command. + + +Prison automatically inserts the **help** keyword if you enter the base commands. So the command **/mines** is really the command handler recognizing there are many commands tied to the path '/mines' that it automatically injects the **help** keyword for you so it will generate the list. It's exactly the same as if you've entered **/mines help**. + + # General Information on Prison Commands + All of the commands for Prison can be ran in-game, and most can be ran from the console. When running commands from the console, you do not have to prefix the commands with a **/**. But within these documents, all commands will be referenced with a prefixed **/** so it is clear that it's a command. Just don't include it when running within the console. -Personal preference is to run the commands from the console since there are less restrictions on width or number of lines shown, and they are easier to see without the busy background of the game. -Within most of these documents, the console will be used to screen print from for those reasons. +My (Blue) personal preference is to run the commands from the console since there are less restrictions on width or number of lines shown, and they are easier to see without the busy background of the game. + + +Within most of these documents, the console will be used for screen prints for those reasons. + The only commands that cannot be ran from the console are the commands that expect you to be an in-game player. Examples are **/mines whereami** and **/mines tp **. But note, you can now run the TP command from the console if you supply the name of an online player: **/mines tp **. + If you need to do some maintenance, or configurating of your Prison, the console could be an easier environment to use. -But in-game, some commands have clickable actions. Such as page next or page prior. Or even command completion, such as with **/mines block search** and clicking on a search result provides you with a filled in copy of **/mines block add** where all you need to do is just fill in the percentage since it uses the last mine name that has been used. + +But in-game, some commands have clickable actions such as **page next** or **page prior**. Or even command completion, such as with **/mines block search** and clicking on a search result provides you with a filled in copy of **/mines block add** where all you need to do is just fill in the percentage since it uses the last mine name that has been used.
@@ -43,14 +77,16 @@ But in-game, some commands have clickable actions. Such as page next or page pr It may be helpful to know what commands are available, and what options exist for those commands. +Prison's command handler not only understands what commands have been registered within Prison, but it has awareness of what parameters are needed, and what permissions some commands are required. The command handler is able to provide a lot of information if you know a few basic things. -**Note: the details below still apply, but are slightly out of date.** The best way to start exploring all commands within prison is to start with `/prison` which will list all subcommands related to `/prison`, but also will show all other root commands and aliases. +Prison's commands are based upon a hierarchy of commands, which groups them by context. If you enter a lower command in the hierarchy that includes sub commands, then Prison will list them. This is a great way to explore what commands are available within Prison. -Upon startup, prison lists many details about the environment, and one set of those details, are the base commands that are available within Prison. See the area pertaining to the modules, since the commands generally are tied to modules. +The best starting point is with the root command `/prison`. Not only is that the root command for everything that starts with `/prison`, but it has special behavior in that it also includes all other command roots. So if a command exists in prison, you can find it through starting with `/prison` and exploring their children. -Prison Commands + +Some of the root commands that are important to know: `/prison`, `/mines`, `/ranks`, `/rankup`, `/gui`, `/sellall`. Many commands within prison are compound commands, such that they start with a base command, followed by one or more other commands. When Prison lists the available commands, if there are sub commands, that information is included in the command listing, including the sub command count. For example: @@ -73,8 +109,6 @@ Let's take a closer look at **/mines set notification** and how the **help** key But notice within the above screen print, the same command has been entered, but this time with the keyword **help** added as if it were the first parameter. For example, **/mines set notification help**. Prison recognizes that you are requesting help for that command, and then it displays all of the information it has for each parameter. -Prison automatically inserts the **help** keyword if you enter the base commands. So **/mines** is really injecting the **help** keyword for you so it will generate the list. It's like you've entered **/mines help**. -
@@ -95,40 +129,42 @@ You can also submit a help ticket on the Prison github Issues tab, but the respo -# Asking for Help - -Before you actually ask for help, take a look at some of the documents presented here. You may find your answer, or at least become a little more familiar with Prison. There is a good chance that if your question is a common one, then you will just be referred to this documentation anyway. - -When you do ask for help, please realize if you can provide a clear description of the problems you are experiencing, plus the versions of Prison, Spigot, etc, then we can help you faster and more accurately. To help provide you with answers to these questions, see the next section of this document for information on what you can copy and paste to provide all those much needed details. - - - -
- - # Prison Debugger Prison has been evolving to provide many new features, but as a result, it's also becoming very complex in some areas. To help address these greater complexities, Prison has some debugging details that can be dynamically enabled. These can help identify what's happening and provide hints as to what may be the trouble. -New targets will be added to Prison overtime. So check with the command for the latests updates for the version that you are using. +New targets will be added to Prison overtime. So check with the command for the latest updates for the version that you are using. To enable the debugger, you can toggle them all on with `/prison debug` once to turn it on, and again to turn them all off. + To review the options available, use the command `/prison debug help`. There are also debug targets that only enable specific debug statements and the list of the available targets can be displayed with `/prison debug targets`. + ``` >prison debug help -[21:07:00 INFO]: For internal use only. Do not use unless instructed. -[21:07:00 INFO]: /prison debug [targets] -[21:07:00 INFO]: [targets] Enable or disable a debugging target. 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. -[21:07:00 INFO]: Permissions: -[21:07:00 INFO]: prison.debug +[12:16:39 INFO]: ---------- < Cmd: /prison debug > ------------- (3.2.11-alpha.9) +[12:16:39 INFO]: Enables debugging and trouble shooting information. For internal use only. Do not use unless instructed. +[12:16:39 INFO]: /prison debug [targets] +[12:16:39 INFO]: [targets] Optional. Enable or disable a debugging target. [on, off, targets, jarScan, testPlayerUtil, testLocale, rankup] 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. jarScan will identify what Java version compiled the class files within the listed jars +[12:16:39 INFO]: Permissions: +[12:16:39 INFO]: prison.debug + + >prison debug targets -[21:08:21 INFO]: Global Debug Logging is enabled -[21:08:21 INFO]: . Valid Targets: all, on, off, blockBreak, blockBreakFortune, durability +[12:17:19 INFO]: Global Debug Logging is enabled +[12:17:19 INFO]: . Valid Targets: all, on, off, blockBreak, blockBreakFortune, rankup, support + +>prison debug +[12:18:18 INFO]: Global Debug Logging is enabled +[12:18:18 INFO]: . Valid Targets: all, on, off, blockBreak, blockBreakFortune, rankup, support + +>prison debug +[12:18:20 INFO]: Global Debug Logging is disabled +[12:18:20 INFO]: . Valid Targets: all, on, off, blockBreak, blockBreakFortune, rankup, support ``` It should be noted that every time you use the command, other than with the help keyword, it will always show the current status of the debugging information. It will show if the global logging is enabled or not, and if any targets are enabled, it will list all of the active ones. Plus it will show all of the available targets too. @@ -359,4 +395,9 @@ Once you are running Prison v3.x.x then you can safely upgrade to Prison v3.2.0,
+**Obsolete Screen Prints:** +Prison Commands + + +
diff --git a/docs/prison_docs_020_setting_up_luckperms.md b/docs/prison_docs_020_setting_up_luckperms.md index e00ce9331..f00d9628f 100644 --- a/docs/prison_docs_020_setting_up_luckperms.md +++ b/docs/prison_docs_020_setting_up_luckperms.md @@ -6,14 +6,20 @@ This document provides a quick overview on how to install LuckPerms. +*Documented updated: 2021-12-19* +
-# Dependencies +# Dependencies & Other Information * **Vault** - **Required** - Provides the permission integration with Prison + +* [Setting up LuckPerms Groups & Tracks](prison_docs_030_LuckPerms_Groups_Tracks.md) + Using LuckPerms's groups and tracks with Prison. +
@@ -25,14 +31,23 @@ Setting up LuckPerms is simple: * Download LuckPerms - Go to the SpigotMC.org LuckPerm's resource page: - [LuckPerms Downloads](https://www.spigotmc.org/resources/luckperms-an-advanced-permissions-plugin.28140/history "LuckPerms download can be found under the Version History tab") + - A benefit of downloading from spigotmc.org is that downloads are tracked and LuckPerms will get a higher rating - Click on the Version History tab - Choose the version to download + +* LuckPerms Website + - You can also directly download LuckPerms from their own website + - [LuckPerms Website](https://luckperms.net/) + - Updates are released on their own website more frequently than to spigotmc.org + - If you are having issues, check this website for most recent release + + * Copy to your server's plugin directory * Restart the server -* Follow LuckPerm's documentation on customization, but at this point it's ready for use with the Prison plugin. +* Follow LuckPerm's documentation on customization, but at this point it's ready for use with the Prison plugin.
@@ -40,14 +55,17 @@ Setting up LuckPerms is simple: -# Warning about LuckPerms Versions +# Older Versions of LuckPerms and Prison + +Older versions of Prison only worked with older versions of LuckPerms. Prison v3.2.0 and older required luckperms v4.4.1 and older. + +Newer versions of Prison supports both the older version of LuckPerms, and all current releases. It is strongly suggested that you use the latest version of both Prison and LuckPerms. -Due to how LuckPerms registers with the Spigot Plugin Manager, it will cause plugins to fail if they were designed for the older LuckPerms version. Therefore, plugins can only be used with the version of LuckPerms that they were designed for and it's up to the server owner to be able to figure that out on their own. **Prison plugin v3.2.0** *only* works with LuckPerms v4.4.1 and older. Luckperms v4.4.1 is the suggested version and can be downloaded here: -[LuckPerms v4.4.1](https://www.spigotmc.org/resources/luckperms-an-advanced-permissions-plugin.28140/history "LuckPerms v4.4.1 can be found under the Version History tab") +[LuckPerms v4.4.1](https://www.spigotmc.org/resources/luckperms.28140/history "LuckPerms v4.4.1 can be found under the Version History tab") -**Prison plugin v3.2.1** and newer works with *any* version of LuckPerms. It is suggested that LuckPerms v5.0.x is used, but you may also use LuckPerms v4.4.1. +**Prison plugin v3.2.1** and newer works with *any* version of LuckPerms. It is suggested that LuckPerms v5.x.x is used, but you may also use LuckPerms v4.4.1. diff --git a/docs/prison_docs_030_LuckPerms_Groups_Tracks.md b/docs/prison_docs_030_LuckPerms_Groups_Tracks.md new file mode 100644 index 000000000..57f445b3e --- /dev/null +++ b/docs/prison_docs_030_LuckPerms_Groups_Tracks.md @@ -0,0 +1,218 @@ + +### Prison Documentation +[Prison Documents - Table of Contents](prison_docs_000_toc.md) + +## Setting up LuckPerms' Groups and Tracks + +This document provides an overview to help setup LuckPerms groups and tracks. + + +*Documented updated: 2021-12-19* + +
+ + + +# Setting Up LuckPerms + + +Setup LuckPerms as needed. Information on where to download it can be found here: + +[Setting Up LuckPerms](prison_docs_020_setting_up_luckperms.md) + + +Other plugin... + +
+ + +# LuckPerms Groups + +To help simplify the management of permissions for players, LuckPerms uses permission Groups to form a collection of permissions. This helps to simplify assigning permission to players since one group can contain many permissions. For example, if there are 20 permissions in a group, then you would only have to issue one group command instead of 20 permission commands. + + +# LuckPerms Tracks + +A brief overview of Tracks: Tracks are to LuckPerms, as ranks and ladders are to Prison. They provide an easy way to manage player's perms by associating them with these ranks. Tracks are also linked together, just like Prison ladders. A player is then moved along these Tracks to provide a way to change their permissions to match the evolving access and roles. + + +To advance a player within LuckPerms Tracks, you just promote the player to the next higher Track. This is very similar to how Prison ranks and ladders are used. + + +Since Prison needs to use their own ranks, and is not directly tied to LuckPerms Tracks, Prison Ranks can help manage a player's LuckPerms Track. + +
+ + +# Using Prison Rank Commands with Groups and Tracks + +Since LuckPerm Groups and Tracks must be synchronized with Prison Ranks, the Prison Rank Commands are used to provide this linkage through Prison Rank Commands. This allows the player to control when they rankup within Prison, which then synchronizes the LuckPerms' Track. + + +If you are not using LuckPerms Tracks, the following is the command you would use to setup the prison rank command. + + +``` +/ranks command add B lp user {player} parent set [group] +``` + + +As a quick review, to get more help about the prison rank commands. The `help` key word displays detailed help about the selected Prison command. And the `placeholders` keyword is important for prison commands since it lists all of the available placeholders that can be used to provide prison related data and values to be used within the commands. + +``` +/ranks command add help +/ranks command add placeholders +``` + + +The following is how you would setup a Prison rank command to use tracks. + +``` +/ranks command add B lp user {player} parent settrack [track] [group] +``` + +Setting up these rank commands, will cause Prison to run these commands when the player ranks up. + + +So in review, this are two examples of rankup commands for a player who joins the server for the first time, are demoted back to A, or the prestiged and are reset to rank A. The Prison rank is named `A` and so is the LuckPerms group. The first command is for setups with no tracks, and the second is for tracks; insert the track's name for `[track]`. If you name your track `PrisonRanks`, with the Track's Groups named the same as the Prison Ranks. + + +``` +/ranks command add B lp user {player} parent set A + +/ranks command add B lp user {player} parent settrack PrisonRanks A +``` + + +
+ + +# More Examples of Usage + + +If you change a player's rank from E to A, the Prison rank commands for A will run, and set the player to group A, or default. + +When you prestige, your rank goes from Z to A, so rank's A commands will be ran. +Plus the rank on your first Prestige rank (typically P1) will **ALSO** be ran. This is highly useful since if you want certain prestige levels to have their own certain benefits/perms, you can setup a separate track and groups for Prestige ranks. + +For example, where `P1` is the Prestige 1 rank: + +``` +/ranks command add P1 lp user {player} parent settrack [track] P1 +``` + + + + +
+ + +# The Suggested Way to Setup LuckPerms Groups and Tracks + +Although there are many ways to configure any plugin, these suggestions tries to keep things simple through using the same names as the counter parts between Prison and LuckPerms. It may be slightly confusion which is which, as far as Prison or LuckPerms, but it makes it easier by being consistent with the same names for the similar parts. + + +The best way to setup LuckPerms Groups is to make 1 group for every Prison Rank. Then use the Rank Commands to assign users to that group automatically when they rankup. Then to tie things together within LuckPerms, place these created LuckPerms Groups on a LuckPerms Track. + + +If you have not done so already, the best option to get started with Prison, is to run `/ranks autoConfigure`. That provides so much of the basic configurations and can save you hours just trying to get the basics setup. You can always change the default settings later to fine tune your setup. + + +The command `/ranks autoConfigure` will create Ranks and Mines with names from A through Z. It will also create the first 10 Prestige ranks with the names P01 through P10. + + +So to get started with how you would setup a Prison Rank command for Rank B: +`/ranks command add B lp user {player} parent settrack [track] b` + + +When they become rank B, the command `/lp user {player} parent settrack [track] b` will be ran as console/admin. The Prison placeholder `{player}` is the player's name, and `[track]` is the name you're calling your track. + + +To setup all the LuckPerms groups, you can use `/lp editor` to make it easier. And setup the ranks from A through Z. + + + +Next you should setup the LuckPerms Tracks, which will take a little more effort up front. You don't have to use Tracks, but it will simplify some things later on by simplifying the synchronization between Prison Ranks and the LuckPerms Groups. + + +For our examples, we will name our track **PrisonRank**. + +``` +/luckperms createtrack [track] + +/luckperms createtrack PrisonRanks + +``` + + +Now we need to add all of our created groups to this track. It's important to add them **IN ORDER**. Yes, the order is critical. Remember our Prison Ranks are named A through Z, and so are our LuckPerms Groups, so we have to add them all. + + +``` +/luckperms track [track] append + +/luckperms track PrisonRank append A +/luckperms track PrisonRank append B +/luckperms track PrisonRank append C +/luckperms track PrisonRank append D + +... + +/luckperms track PrisonRank append Z + +``` + + +The next step that you need to do, is to setup all the perms for each of your groups. The perms that you need, are based upon the plugins that you have setup on your server, and the perms that they will require. + + +For brevity, we will only show you the commands to use manually. You can use the command `/lp editor` too. Remember that the **group** listed in this command are the LuckPerms groups that you created earlier, that are named A trough Z. The **permission**s that you use in these commands should be entered exactly as they are needed. + +``` +/lp group permission set + +``` + +It may take a while to setup all the permissions, and you will have to revisit these as you're adding more plugins. + + +Next, we need to setup Prison's Rank Commands to allow the rankup process to keep the LuckPerms Track's Groups in synchronization. Luckily, this is pretty simple and is accomplished with just one Rank Command per rank. Please not that for Prison's Rank names they are not case sensitive, but the LuckPerms track names may be, so they are listed here in upper case. + + +These are based upon the two individual commands; the Prison Ranks Command and the LP command. The **command** reference in the Prison Rank Command is the whole LP command, as you will see following the templates. + +``` +/ranks command add +/lp user {player} parent settrack [track] + +/ranks command add a lp user {player} parent settrack PrisonRank A +/ranks command add b lp user {player} parent settrack PrisonRank B +/ranks command add c lp user {player} parent settrack PrisonRank C +/ranks command add d lp user {player} parent settrack PrisonRank D + +... + +/ranks command add z lp user {player} parent settrack PrisonRank Z +``` + + +The following is optional, but what it does is to apply all rank commands to all players at their current ranks. So this will apply everything we just entered above to anyone who is already setup in Prison. + +`/ranks set rank *all* *same* default` + + +And that should be it. + + + + +
+ + + +# Setting up LuckPerms Chat Prefixes + +*coming soon...* + + +
\ No newline at end of file diff --git a/docs/prison_docs_100_setting_up_auto_configure.md b/docs/prison_docs_100_setting_up_auto_configure.md index af084e7db..e267ba0ed 100644 --- a/docs/prison_docs_100_setting_up_auto_configure.md +++ b/docs/prison_docs_100_setting_up_auto_configure.md @@ -7,6 +7,11 @@ This document provides information on how to get started quickly using Prison's `/ranks autoConfigure`. +[Prison Log File Examples - Starting Prison & auto configure](prison_docs_101_auto_configure_log_examples.md) + + +*Documented updated: 2021-12-11* +
# Overview @@ -77,33 +82,30 @@ Some of the steps involved and which are covered by this document: * **Turning Virtual Mines in to Actual Mines** - How to set the mine's locations so they become real. -* **Setting a Mine's Spawn Location** -* **Resizing A Mine** +Other topics that may be helpful but not fully covered in this document: +* **Setting a Mine's Spawn Location** -* **Moving A Mine** +* **Resizing A Mine** +* **Moving A Mine** * **Changing A Mine's Liner** - * **Submitting a New Liner Request** - * **Working with Mines within a Void World** - Special considerations for resizing, moving, and liners when in a Void World. - * **Working with Mine's Permissions** - * **Using Mine Reset Commands** - * **Working with Rank Commands** +
@@ -119,9 +121,9 @@ These listings are to help guide you in planning on what you need. A minecraft * **Minecraft Server Version** - - Prison support a native minecraft server version of v1.8 through v1.16.5. - - Prison is developed and compiled with the Spigot v1.13.2 build. This ensures that Prison is able to natively support all functional behaviors from v1.8 through v1.16.5 since v.1.13 is the only version of Spigot that has both the old internal functions and new internal functions coexisting at the same time. - - Prison will try to support v1.17 when it is released, but not sure what special requirements it will place upon the development environment. + - Prison support a native minecraft server version of v1.8 through v1.18.x. + - Prison is developed and compiled with the Spigot v1.13.2 build. This ensures that Prison is able to natively support all functional behaviors from v1.8 through v1.18.x since v.1.13 is the only version of Spigot that has both the old internal functions and new internal functions coexisting at the same time. + - Prison supports the early releases of v1.18. There has been no issues found. Prison will try to support all of the new blocks within 1.18, we use a library called XSeries to provide the new blocks. So as they release their updates, prison will pickup support for more blocks. * **Memory Requirements** @@ -206,7 +208,7 @@ The current version of Prison's `/ranks autoConfigure` uses Access by Ranks to a The use of Access by Ranks prevents the need for `/ranks autoConfigure` to generate any rank commands dealing with permissions. You may need to add them for your own needs. -**Critical:** It should be noted that the ideal conditions to running this command is without having any mines or ranks previously defined. If any are detected, this command will terminate and will not attempt to perform any actions. You can use the Option **force** to force the auto configure to run if there are ranks and mines already defined. If you do force it, keep in mind that it will skip over any rank or mine that it would otherwise try to generate. It will not add rank commands to existing ranks. It will not add blocks to existing mines. It will not hook up ranks to mines. Nor will it configure such features as Mine Access Permissions. If you decide to use **force** you do so at your own risks. That said, it's easy to delete the `plugins/Prison/` directory and start over (or just rename it). +**Critical:** It should be noted that the ideal conditions to running this command is without having any mines or ranks previously defined. If any are detected, this command will terminate and will not attempt to perform any actions. You can use the Option **force** to force the auto configure to run if there are ranks and mines already defined. If you do force it, keep in mind that it will skip over any rank or mine that it would otherwise try to generate. It will not add blocks to existing mines. It will not hook up ranks to mines. Nor will it configure such features as Mine Access Permissions. If you decide to use **force** you do so at your own risks. That said, it's easy to delete the `plugins/Prison/` directory and start over (or just rename it). Almost every command within prison has detailed help, and it can be activated by adding the `help` keyword to the end of the command. For example: @@ -239,339 +241,37 @@ The server that was created to run this example was using 9 core plugins: 9 core plugins -

Note: The following is from an older release of prison that generated rank commands that controlled the way prison worked.

+The generated log files can now be found in this document: -Sample of prison starting up for the first time and it's console messages: +[Prison Log File Examples - Starting Prison & auto configure](prison_docs_101_auto_configure_log_examples.md) -``` -[03:02:59 INFO]: [Prison] Enabling Prison v3.2.5-alpha.14 -[03:02:59 INFO]: [Prison] Using version adapter tech.mcprison.prison.spigot.compat.Spigot18 -[03:02:59 INFO]: | Prison | -[03:02:59 INFO]: | Prison | _____ _ -[03:02:59 INFO]: | Prison | | __ \ (_) -[03:02:59 INFO]: | Prison | | |__) | __ _ ___ ___ _ __ -[03:02:59 INFO]: | Prison | | ___/ '__| / __|/ _ \| '_ \ -[03:02:59 INFO]: | Prison | | | | | | \__ \ (_) | | | | -[03:02:59 INFO]: | Prison | |_| |_| |_|___/\___/|_| |_| -[03:02:59 INFO]: | Prison | -[03:02:59 INFO]: | Prison | Loading Prison version: 3.2.5-alpha.14 -[03:02:59 INFO]: | Prison | Running on platform: SpigotPlatform -[03:02:59 INFO]: | Prison | Minecraft version: git-Spigot-21fe707-e1ebe52 (MC: 1.8.8) -[03:02:59 INFO]: | Prison | -[03:02:59 INFO]: | Prison | Enabling and starting... -[03:02:59 INFO]: | Prison | Enabled Prison v3.2.5-alpha.14 in 223 milliseconds. -[03:02:59 INFO]: | Prison | There were 19 new values added to the GuiConfig.yml file located at C:\mc_servers\spigot-1.8.8-autoConfig_server\plugins\Prison\GuiConfig.yml -[03:02:59 INFO]: | Prison | There were 37 new values added for the language files used by the SellAllConfig.yml file located at C:\mc_servers\spigot-1.8.8-autoConfig_server\plugins\Prison\SellAllConfig.yml -[03:02:59 INFO]: | Prison | There were 37 new values added for the language files used by the SellAllConfig.yml file located at C:\mc_servers\spigot-1.8.8-autoConfig_server\plugins\Prison\SellAllConfig.yml -[03:02:59 INFO]: | Prison | There were 272 new values added for the language files used by the GuiConfig.yml file located at C:\mc_servers\spigot-1.8.8-autoConfig_server\plugins\Prison\module_conf\lang\en_US.yml -[03:02:59 INFO]: | Prison | Notice: AutoManager config file was just updated with 89 new entries. May need to be configured. File: autoFeaturesConfig.yml -[03:02:59 INFO]: | Prison | Notice: AutoManager config file was just created. You must configure it to use it. File: autoFeaturesConfig.yml -[03:02:59 INFO]: | Prison | ###--### AutoFeaturesFileConfig: test autoPickupBlockNameList: length = 2 value = [coal_block, iron_ore] -[03:02:59 INFO]: | Prison | ### VaultEconomyWrapper : vaultVersion = 1.5.6-b49 is pre1_4= false -[03:02:59 INFO]: | Prison | EssentialsEconomy is not directly enabled - Available as backup. -[03:02:59 INFO]: [PlaceholderAPI] Successfully registered expansion: prison -[03:02:59 INFO]: | Prison | Mines Module enablement starting... -[03:02:59 INFO]: | Prison | Mines Module enabled successfully in 152 milliseconds. -[03:02:59 INFO]: | Prison | Ranks Module enablement starting... -[03:03:00 INFO]: | Prison | Loaded 0 ranks. -[03:03:00 INFO]: | Prison | Loaded 2 ladders. -[03:03:00 INFO]: | Prison | Loaded 0 players. -[03:03:00 INFO]: | Prison | Ranks by ladders: -[03:03:00 INFO]: | Prison | default: -[03:03:00 INFO]: | Prison | prestiges: -[03:03:00 INFO]: | Prison | none: -[03:03:00 INFO]: | Prison | Ranks Module enabled successfully in 580 milliseconds. -[03:03:00 INFO]: | Prison | Utils Module enablement starting... -[03:03:00 INFO]: | Prison | Utils Module enabled successfully in 7 milliseconds. -[03:03:00 INFO]: | Prison | Loaded 0 mines and submitted with a 5000 millisecond offset timing for auto resets. -[03:03:00 INFO]: [PlaceholderAPI] Successfully registered expansion: prison -[03:03:00 INFO]: | Prison | Total placeholders generated: 122 -[03:03:00 INFO]: | Prison | PLAYER: 26 -[03:03:00 INFO]: | Prison | LADDERS: 48 -[03:03:00 INFO]: | Prison | PLAYERMINES: 48 -[03:03:00 INFO]: | Prison | ALIAS: 61 -[03:03:00 INFO]: | Prison | Total placeholders available to be Registered: 122 -[03:03:00 INFO]: | Prison | A total of 0 Mines and Ranks have been linked together. -[03:03:00 INFO]: | Prison | ------------- < /prison version > --------------- -[03:03:00 INFO]: | Prison | Prison Version: 3.2.5-alpha.14 -[03:03:00 INFO]: | Prison | Running on Platform: tech.mcprison.prison.spigot.SpigotPlatform -[03:03:00 INFO]: | Prison | Minecraft Version: git-Spigot-21fe707-e1ebe52 (MC: 1.8.8) -[03:03:00 INFO]: | Prison | -[03:03:00 INFO]: | Prison | Commands: /prison -[03:03:00 INFO]: | Prison | Module: Mines : Enabled -[03:03:00 INFO]: | Prison | . Base Commands: /mines -[03:03:00 INFO]: | Prison | Module: Ranks : Enabled -[03:03:00 INFO]: | Prison | . Base Commands: /ranks /rankup /rankupMax /prestige /prestiges -[03:03:00 INFO]: | Prison | Module: Utils : Enabled -[03:03:00 INFO]: | Prison | . Base Commands: /prison utils -[03:03:00 INFO]: | Prison | -[03:03:00 INFO]: | Prison | Integrations: -[03:03:00 INFO]: | Prison | Permissions: LuckPerms (Vault) -[03:03:00 INFO]: | Prison | Economy: Essentials Economy (Vault) -[03:03:00 INFO]: | Prison | Integration Type: ECONOMY -[03:03:00 INFO]: | Prison | Essentials Economy (Vault) [URL] -[03:03:00 INFO]: | Prison | Essentials (EssentialsX) (disabled) [URL] -[03:03:00 INFO]: | Prison | SaneEconomy (API v0.15.0) [URL] -[03:03:00 INFO]: | Prison | GemsEconomy [URL] -[03:03:00 INFO]: | Prison | Integration Type: PERMISSION -[03:03:00 INFO]: | Prison | LuckPerms (Vault) -[03:03:00 INFO]: | Prison | LuckPerms (LuckPermsV5) [URL] -[03:03:00 INFO]: | Prison | LuckPerms (LuckPerms-Legacy) [URL] -[03:03:00 INFO]: | Prison | Integration Type: PLACEHOLDER -[03:03:00 INFO]: | Prison | To list all or search for placeholders see: /prison placeholders -[03:03:00 INFO]: | Prison | MVdWPlaceholderAPI [URL] -[03:03:00 INFO]: | Prison | PlaceholderAPI [URL] -[03:03:00 INFO]: | Prison | MVdWPlaceholderAPI [URL] -[03:03:00 INFO]: | Prison | PlaceholderAPI [URL] -[03:03:00 INFO]: | Prison | Registered Plugins: -[03:03:00 INFO]: | Prison | LuckPerms (5.1.26), WorldEdit (6.1;no_git_id) -[03:03:00 INFO]: | Prison | Vault (1.5.6-b49), PlaceholderAPI (2.10.9) -[03:03:00 INFO]: | Prison | ProtocolLib (4.5.0), WorldGuard (6.1) -[03:03:00 INFO]: | Prison | Essentials (2.18.1.0), EssentialsChat (2.18.1.0) -[03:03:00 INFO]: | Prison | Prison (3.2.5-alpha.14) -[03:03:00 INFO]: | Prison | Prison - Finished loading. -``` -Running the command: -``` ->ranks autoConfigure help -[04:19:55 INFO]: Auto configures Ranks and Mines using single letters A through Z for both the rank and mine names. If both ranks and mines are generated, they will also be linked together automatically. To set the starting price use price=x. To set multiplier mult=x. Cannot autoConfigure if any ranks or mines are defined, but 'force' will attempt it but at your risk. Default values [full price=50000 mult=1.5] -[04:19:55 INFO]: /ranks autoConfigure [options] -[04:19:55 INFO]: [options | full] Options: [full ranks mines price=x mult=x force] -[04:19:55 INFO]: Permissions: -[04:19:55 INFO]: ranks.set ->ranks autoConfigure -[04:20:03 INFO]: | Info | Your new rank, 'A', was created in the ladder 'default', using the tag value of '[A]' -[04:20:03 INFO]: Virtual mine created: use command /mines set area to enable as a normal mine. -[04:20:04 INFO]: | Info | Your new rank, 'B', was created in the ladder 'default', using the tag value of '[B]' -[04:20:04 INFO]: Virtual mine created: use command /mines set area to enable as a normal mine. -[04:20:04 INFO]: | Info | Your new rank, 'C', was created in the ladder 'default', using the tag value of '[C]' -[04:20:04 INFO]: Virtual mine created: use command /mines set area to enable as a normal mine. -[04:20:04 INFO]: | Info | Your new rank, 'D', was created in the ladder 'default', using the tag value of '[D]' -[04:20:04 INFO]: Virtual mine created: use command /mines set area to enable as a normal mine. -[04:20:04 INFO]: | Info | Your new rank, 'E', was created in the ladder 'default', using the tag value of '[E]' -[04:20:04 INFO]: Virtual mine created: use command /mines set area to enable as a normal mine. -[04:20:04 INFO]: | Info | Your new rank, 'F', was created in the ladder 'default', using the tag value of '[F]' -[04:20:04 INFO]: Virtual mine created: use command /mines set area to enable as a normal mine. -[04:20:04 INFO]: | Info | Your new rank, 'G', was created in the ladder 'default', using the tag value of '[G]' -[04:20:04 INFO]: Virtual mine created: use command /mines set area to enable as a normal mine. -[04:20:04 INFO]: | Info | Your new rank, 'H', was created in the ladder 'default', using the tag value of '[H]' -[04:20:04 INFO]: Virtual mine created: use command /mines set area to enable as a normal mine. -[04:20:04 INFO]: | Info | Your new rank, 'I', was created in the ladder 'default', using the tag value of '[I]' -[04:20:04 INFO]: Virtual mine created: use command /mines set area to enable as a normal mine. -[04:20:04 INFO]: | Info | Your new rank, 'J', was created in the ladder 'default', using the tag value of '[J]' -[04:20:05 INFO]: Virtual mine created: use command /mines set area to enable as a normal mine. -[04:20:05 INFO]: | Info | Your new rank, 'K', was created in the ladder 'default', using the tag value of '[K]' -[04:20:05 INFO]: Virtual mine created: use command /mines set area to enable as a normal mine. -[04:20:05 INFO]: | Info | Your new rank, 'L', was created in the ladder 'default', using the tag value of '[L]' -[04:20:05 INFO]: Virtual mine created: use command /mines set area to enable as a normal mine. -[04:20:05 INFO]: | Info | Your new rank, 'M', was created in the ladder 'default', using the tag value of '[M]' -[04:20:05 INFO]: Virtual mine created: use command /mines set area to enable as a normal mine. -[04:20:05 INFO]: | Info | Your new rank, 'N', was created in the ladder 'default', using the tag value of '[N]' -[04:20:05 INFO]: Virtual mine created: use command /mines set area to enable as a normal mine. -[04:20:05 INFO]: | Info | Your new rank, 'O', was created in the ladder 'default', using the tag value of '[O]' -[04:20:05 INFO]: Virtual mine created: use command /mines set area to enable as a normal mine. -[04:20:05 INFO]: | Info | Your new rank, 'P', was created in the ladder 'default', using the tag value of '[P]' -[04:20:05 INFO]: Virtual mine created: use command /mines set area to enable as a normal mine. -[04:20:05 INFO]: | Info | Your new rank, 'Q', was created in the ladder 'default', using the tag value of '[Q]' -[04:20:05 INFO]: Virtual mine created: use command /mines set area to enable as a normal mine. -[04:20:05 INFO]: | Info | Your new rank, 'R', was created in the ladder 'default', using the tag value of '[R]' -[04:20:05 INFO]: Virtual mine created: use command /mines set area to enable as a normal mine. -[04:20:05 INFO]: | Info | Your new rank, 'S', was created in the ladder 'default', using the tag value of '[S]' -[04:20:05 INFO]: Virtual mine created: use command /mines set area to enable as a normal mine. -[04:20:05 INFO]: | Info | Your new rank, 'T', was created in the ladder 'default', using the tag value of '[T]' -[04:20:05 INFO]: Virtual mine created: use command /mines set area to enable as a normal mine. -[04:20:05 INFO]: | Info | Your new rank, 'U', was created in the ladder 'default', using the tag value of '[U]' -[04:20:05 INFO]: Virtual mine created: use command /mines set area to enable as a normal mine. -[04:20:05 INFO]: | Info | Your new rank, 'V', was created in the ladder 'default', using the tag value of '[V]' -[04:20:05 INFO]: Virtual mine created: use command /mines set area to enable as a normal mine. -[04:20:05 INFO]: | Info | Your new rank, 'W', was created in the ladder 'default', using the tag value of '[W]' -[04:20:05 INFO]: Virtual mine created: use command /mines set area to enable as a normal mine. -[04:20:05 INFO]: | Info | Your new rank, 'X', was created in the ladder 'default', using the tag value of '[X]' -[04:20:05 INFO]: Virtual mine created: use command /mines set area to enable as a normal mine. -[04:20:05 INFO]: | Info | Your new rank, 'Y', was created in the ladder 'default', using the tag value of '[Y]' -[04:20:05 INFO]: Virtual mine created: use command /mines set area to enable as a normal mine. -[04:20:05 INFO]: | Info | Your new rank, 'Z', was created in the ladder 'default', using the tag value of '[Z]' -[04:20:05 INFO]: Virtual mine created: use command /mines set area to enable as a normal mine. -``` -Note: The following are the messages generated while building the **sellall** shop with the default items: +Listing the generated ranks on all ladders using the `all` keyword: +`/ranks list all` -``` -[04:20:05 INFO]: Virtual mine created: use command /mines set area to enable as a normal mine. -[04:20:05 INFO]: | Prison | ITEM [COBBLESTONE, 4.0] added with success! -[04:20:05 INFO]: | Prison | ITEM [ANDESITE, 5.0] added with success! -[04:20:05 INFO]: | Prison | ITEM [DIORITE, 6.0] added with success! -[04:20:05 INFO]: | Prison | ITEM [COAL_ORE, 13.0] added with success! -[04:20:05 INFO]: | Prison | ITEM [GRANITE, 8.0] added with success! -[04:20:05 INFO]: | Prison | ITEM [STONE, 9.0] added with success! -[04:20:05 INFO]: | Prison | ITEM [IRON_ORE, 18.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [POLISHED_ANDESITE, 7.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [GOLD_ORE, 45.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [MOSSY_COBBLESTONE, 29.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [COAL_BLOCK, 135.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [IRON_BLOCK, 190.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [LAPIS_ORE, 100.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [REDSTONE_ORE, 45.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [DIAMOND_ORE, 200.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [EMERALD_ORE, 250.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [GOLD_BLOCK, 450.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [LAPIS_BLOCK, 950.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [REDSTONE_BLOCK, 405.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [DIAMOND_BLOCK, 2000.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [EMERALD_BLOCK, 2250.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [OBSIDIAN, 450.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [CLAY, 12.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [GRAVEL, 3.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [SAND, 6.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [DIRT, 4.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [COARSE_DIRT, 7.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [PODZOL, 6.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [RED_SAND, 9.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [BEDROCK, 500.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [SANDSTONE, 3.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [POLISHED_DIORITE, 8.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [POLISHED_GRANITE, 9.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [CHISELED_NETHER_BRICKS, 39.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [CHISELED_RED_SANDSTONE, 11.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [CHISELED_STONE_BRICKS, 11.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [CUT_RED_SANDSTONE, 13.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [CUT_SANDSTONE, 10.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [NETHER_QUARTZ_ORE, 34.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [QUARTZ, 34.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [QUARTZ_BLOCK, 136.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [QUARTZ_SLAB, 68.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [CHISELED_QUARTZ_BLOCK, 136.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [QUARTZ_BRICKS, 136.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [QUARTZ_PILLAR, 136.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [SMOOTH_QUARTZ, 136.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [SMOOTH_RED_SANDSTONE, 14.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [SMOOTH_SANDSTONE, 14.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [SMOOTH_STONE, 14.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [CHARCOAL, 16.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [CRACKED_NETHER_BRICKS, 16.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [CRACKED_STONE_BRICKS, 14.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [EMERALD, 14.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [END_STONE, 14.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [END_STONE_BRICKS, 14.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [FLINT, 9.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [LAPIS_LAZULI, 14.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [MOSSY_STONE_BRICKS, 14.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [PRISMARINE_SHARD, 13.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [PRISMARINE, 52.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [PRISMARINE_BRICKS, 52.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [PRISMARINE_BRICK_SLAB, 52.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [PRISMARINE_CRYSTALS, 37.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [DARK_PRISMARINE, 52.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [DARK_PRISMARINE_SLAB, 52.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [PURPUR_BLOCK, 14.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [PURPUR_PILLAR, 14.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [TERRACOTTA, 10.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [ACACIA_LOG, 7.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [BIRCH_LOG, 7.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [DARK_OAK_LOG, 7.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [JUNGLE_LOG, 7.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [OAK_LOG, 7.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [SPRUCE_LOG, 7.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [ACACIA_PLANKS, 28.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [BIRCH_PLANKS, 28.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [DARK_OAK_PLANKS, 28.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [JUNGLE_PLANKS, 28.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [OAK_PLANKS, 28.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [SPRUCE_PLANKS, 28.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [ACACIA_WOOD, 7.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [BIRCH_WOOD, 7.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [DARK_OAK_WOOD, 7.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [JUNGLE_WOOD, 7.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [OAK_WOOD, 7.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [SPRUCE_WOOD, 7.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [IRON_NUGGET, 3.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [IRON_INGOT, 27.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [GOLD_NUGGET, 12.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [GOLD_INGOT, 108.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [REDSTONE, 45.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [GLOWSTONE, 52.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [GLOWSTONE_DUST, 14.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [COAL, 15.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [DIAMOND, 200.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [SUGAR_CANE, 13.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [SUGAR, 13.0] added with success! -[04:20:06 INFO]: | Prison | ITEM [PAPER, 13.0] added with success! -``` - -The following are log entries from the generation and assignment of the blocks to all of the generated mines. - -``` -[04:20:06 INFO]: | Prison | Mine A: [ANDESITE 5.0, COBBLESTONE 95.0] -[04:20:06 INFO]: | Prison | Mine B: [DIORITE 5.0, ANDESITE 10.0, COBBLESTONE 85.0] -[04:20:06 INFO]: | Prison | Mine C: [COAL_ORE 5.0, DIORITE 10.0, ANDESITE 20.0, COBBLESTONE 65.0] -[04:20:06 INFO]: | Prison | Mine D: [GRANITE 5.0, COAL_ORE 10.0, DIORITE 20.0, ANDESITE 20.0, COBBLESTONE 45.0] -[04:20:06 INFO]: | Prison | Mine E: [STONE 5.0, GRANITE 10.0, COAL_ORE 20.0, DIORITE 20.0, ANDESITE 20.0, COBBLESTONE 25.0] -[04:20:06 INFO]: | Prison | Mine F: [IRON_ORE 5.0, STONE 10.0, GRANITE 20.0, COAL_ORE 20.0, DIORITE 20.0, ANDESITE 25.0] -[04:20:06 INFO]: | Prison | Mine G: [POLISHED_ANDESITE 5.0, IRON_ORE 10.0, STONE 20.0, GRANITE 20.0, COAL_ORE 20.0, DIORITE 25.0] -[04:20:06 INFO]: | Prison | Mine H: [GOLD_ORE 5.0, POLISHED_ANDESITE 10.0, IRON_ORE 20.0, STONE 20.0, GRANITE 20.0, COAL_ORE 25.0] -[04:20:06 INFO]: | Prison | Mine I: [MOSSY_COBBLESTONE 5.0, GOLD_ORE 10.0, POLISHED_ANDESITE 20.0, IRON_ORE 20.0, STONE 20.0, GRANITE 25.0] -[04:20:06 INFO]: | Prison | Mine J: [COAL_BLOCK 5.0, MOSSY_COBBLESTONE 10.0, GOLD_ORE 20.0, POLISHED_ANDESITE 20.0, IRON_ORE 20.0, STONE 25.0] -[04:20:06 INFO]: | Prison | Mine K: [NETHER_QUARTZ_ORE 5.0, COAL_BLOCK 10.0, MOSSY_COBBLESTONE 20.0, GOLD_ORE 20.0, POLISHED_ANDESITE 20.0, IRON_ORE 25.0] -[04:20:06 INFO]: | Prison | Mine L: [IRON_BLOCK 5.0, NETHER_QUARTZ_ORE 10.0, COAL_BLOCK 20.0, MOSSY_COBBLESTONE 20.0, GOLD_ORE 20.0, POLISHED_ANDESITE 25.0] -[04:20:06 INFO]: | Prison | Mine M: [LAPIS_ORE 5.0, IRON_BLOCK 10.0, NETHER_QUARTZ_ORE 20.0, COAL_BLOCK 20.0, MOSSY_COBBLESTONE 20.0, GOLD_ORE 25.0] -[04:20:06 INFO]: | Prison | Mine N: [REDSTONE_ORE 5.0, LAPIS_ORE 10.0, IRON_BLOCK 20.0, NETHER_QUARTZ_ORE 20.0, COAL_BLOCK 20.0, MOSSY_COBBLESTONE 25.0] -[04:20:06 INFO]: | Prison | Mine O: [DIAMOND_ORE 5.0, REDSTONE_ORE 10.0, LAPIS_ORE 20.0, IRON_BLOCK 20.0, NETHER_QUARTZ_ORE 20.0, COAL_BLOCK 25.0] -[04:20:06 INFO]: | Prison | Mine P: [QUARTZ_BLOCK 5.0, DIAMOND_ORE 10.0, REDSTONE_ORE 20.0, LAPIS_ORE 20.0, IRON_BLOCK 20.0, NETHER_QUARTZ_ORE 25.0] -[04:20:06 INFO]: | Prison | Mine Q: [EMERALD_ORE 5.0, QUARTZ_BLOCK 10.0, DIAMOND_ORE 20.0, REDSTONE_ORE 20.0, LAPIS_ORE 20.0, IRON_BLOCK 25.0] -[04:20:06 INFO]: | Prison | Mine R: [GOLD_BLOCK 5.0, EMERALD_ORE 10.0, QUARTZ_BLOCK 20.0, DIAMOND_ORE 20.0, REDSTONE_ORE 20.0, LAPIS_ORE 25.0] -[04:20:06 INFO]: | Prison | Mine S: [LAPIS_BLOCK 5.0, GOLD_BLOCK 10.0, EMERALD_ORE 20.0, QUARTZ_BLOCK 20.0, DIAMOND_ORE 20.0, REDSTONE_ORE 25.0] -[04:20:06 INFO]: | Prison | Mine T: [REDSTONE_BLOCK 5.0, LAPIS_BLOCK 10.0, GOLD_BLOCK 20.0, EMERALD_ORE 20.0, QUARTZ_BLOCK 20.0, DIAMOND_ORE 25.0] -[04:20:06 INFO]: | Prison | Mine U: [DIAMOND_BLOCK 5.0, REDSTONE_BLOCK 10.0, LAPIS_BLOCK 20.0, GOLD_BLOCK 20.0, EMERALD_ORE 20.0, QUARTZ_BLOCK 25.0] -[04:20:06 INFO]: | Prison | Mine V: [EMERALD_BLOCK 5.0, DIAMOND_BLOCK 10.0, REDSTONE_BLOCK 20.0, LAPIS_BLOCK 20.0, GOLD_BLOCK 20.0, EMERALD_ORE 25.0] -[04:20:07 INFO]: | Prison | Mine W: [EMERALD_BLOCK 10.0, DIAMOND_BLOCK 20.0, REDSTONE_BLOCK 20.0, LAPIS_BLOCK 20.0, GOLD_BLOCK 30.0] -[04:20:07 INFO]: | Prison | Mine X: [EMERALD_BLOCK 20.0, DIAMOND_BLOCK 20.0, REDSTONE_BLOCK 20.0, LAPIS_BLOCK 40.0] -[04:20:07 INFO]: | Prison | Mine Y: [EMERALD_BLOCK 20.0, DIAMOND_BLOCK 20.0, REDSTONE_BLOCK 60.0] -[04:20:07 INFO]: | Prison | Mine Z: [EMERALD_BLOCK 20.0, DIAMOND_BLOCK 80.0] -[04:20:07 INFO]: | Prison | Ranks autoConfigure: 26 ranks were created. -[04:20:07 INFO]: | Prison | Ranks autoConfigure: 26 rank commands were created. -[04:20:07 INFO]: | Prison | Ranks autoConfigure: The permission mines. and mines.tp. was created for each rank. Make sure you add every permission to your permission plugin or they may not work. -[04:20:07 INFO]: | Prison | Ranks autoConfigure: 26 mines were created. -[04:20:07 INFO]: | Prison | Ranks autoConfigure: 26 ranks and mines were linked. -[04:20:07 INFO]: | Prison | -``` - - - -Listing the generated ranks: - -`/ranks list` Listing all ranks -Listing the information on Rank A: +Listing the information on Rank A, including the ladder and rank commands.: -`/ranks info a` +`/ranks info a all` -`/ranks command list a` ranks info and command list for Rank A -Note: This list of commands for Rank A is how all the other ranks will look, but Rank A actually contains all the removals of all ranks now. This will allow Prestige to use the command `/ranks set rank` on a player, and then let these commands remove the permissions they should not have while at rank A. +Using the keyword `all` is the same as also running the command: `/ranks command list a` + -``` ->ranks command list a -[04:21:51 INFO]: ------- < RankUpCommand for [A] > --------- -[04:21:51 INFO]: Click a command to remove it. -[04:21:51 INFO]: * /lp user {player} permission set mines.a -[04:21:51 INFO]: * /lp user {player} permission set mines.tp.a -[04:21:51 INFO]: [+] Add -> -``` @@ -679,6 +379,23 @@ The other method is a little more controlled, and that's using prison wand to se +
+ +# A Quick Overview of the 'help' Keyword + +Prison has an advanced command handler that is able to do a lot of things. One of it's features is to provide more information on each command that it has registered. To activate this feature, just add the keyword `help` to the end of any command. Here are a few examples. + +``` +/mines info help +/ranks promote help +/ranks command add help +/prison support submit +/prison utils potionEffect help +``` + +The `help` keyword can be used on sub-command listings, which will display the list of commands at that level. The `help` keyword is applied automatically for sub-commands and is what actually triggers the command listings. + +
diff --git a/docs/prison_docs_101_auto_configure_log_example.md b/docs/prison_docs_101_auto_configure_log_example.md new file mode 100644 index 000000000..cecc7c657 --- /dev/null +++ b/docs/prison_docs_101_auto_configure_log_example.md @@ -0,0 +1,348 @@ + +### Prison Documentation +[Prison Documents - Table of Contents](prison_docs_000_toc.md) + +## Prison - Examples of Prison's Log Entries + +This document provides information on what log entries are generated when prison starts up for the first time, and while running the command `/ranks autoConfigure`. + +NOTE: Prison has been designed to behave the same under any version of bukkit/Spigot from 1.8 through 1.18. Therefore the spigot version in these logs are not important, and apply to all versions. The same applies for Java versions 1.8.x through Java 17. + +*Documented updated: 2021-12-11* + +
+ +# Prison logs when starting for the first time + +When the prison jar file has been added for the first time to a server, you will see something similar to these startup logs. + + +``` +[13:14:48 INFO]: [Prison] Enabling Prison v3.2.11-alpha.11 +[13:14:49 INFO]: | Prison | -------------------- < > ----------------------- (3.2.11-alpha.11) +[13:14:49 INFO]: | Prison | +[13:14:49 INFO]: | Prison | _____ _ +[13:14:49 INFO]: | Prison | | __ \ (_) +[13:14:49 INFO]: | Prison | | |__) | __ _ ___ ___ _ __ +[13:14:49 INFO]: | Prison | | ___/ '__| / __|/ _ \| '_ \ +[13:14:49 INFO]: | Prison | | | | | | \__ \ (_) | | | | +[13:14:49 INFO]: | Prison | |_| |_| |_|___/\___/|_| |_| +[13:14:49 INFO]: | Prison | +[13:14:49 INFO]: | Prison | Loading Prison version: 3.2.11-alpha.11 +[13:14:49 INFO]: | Prison | Running on platform: SpigotPlatform +[13:14:49 INFO]: | Prison | Minecraft version: git-Spigot-21fe707-e1ebe52 (MC: 1.8.8) +[13:14:49 INFO]: | Prison | +[13:14:49 INFO]: | Prison | Server runtime: 0s +[13:14:49 INFO]: | Prison | Java Version: 1.8.0_291 Processor cores: 8 +[13:14:49 INFO]: | Prison | Memory Max: 3.556 GB Total: 1.054 GB Free: 674.204 MB Used: 405.296 MB +[13:14:49 INFO]: | Prison | Total Server Disk Space: 943.719 GB Usable: 689.799 GB Free: 689.799 GB Used: 253.919 GB +[13:14:49 INFO]: | Prison | Prison's File Count: 10 Folder Count: 5 Disk Space: 60.154 KB Other Objects: 0 +[13:14:49 INFO]: | Prison | Prison TPS Average: 0.00 Min: 20.00 Max: 20.00 Interval: 10 ticks Samples: 0 +[13:14:49 INFO]: | Prison | +[13:14:49 INFO]: | Prison | Enabling and starting... +[13:14:49 INFO]: | Prison | Enabled Prison v3.2.11-alpha.11 in 376 milliseconds. +[13:14:49 INFO]: | Prison | Using version adapter tech.mcprison.prison.spigot.compat.Spigot18 +[13:14:49 INFO]: | Prison | There were 21 new values added to the GuiConfig.yml file located at C:\mc_servers\spigot-1.8.8-basic_server\plugins\Prison\GuiConfig.yml +[13:14:49 INFO]: | Prison | SpigotListener: Trying to register events +[13:14:49 INFO]: | Prison | There were 41 new values added for the language files used by the SellAllConfig.yml file located at C:\mc_servers\spigot-1.8.8-basic_server\plugins\Prison\SellAllConfig.yml +[13:14:49 INFO]: | Prison | There were 41 new values added for the language files used by the SellAllConfig.yml file located at C:\mc_servers\spigot-1.8.8-basic_server\plugins\Prison\SellAllConfig.yml +[13:14:49 INFO]: | Prison | EssentialsEconomy is not directly enabled - Available as backup. +[13:14:49 INFO]: [PlaceholderAPI] Successfully registered expansion: prison +[13:14:49 INFO]: [PlaceholderAPI] Successfully registered expansion: PRISON +[13:14:49 INFO]: | Prison | Mines Module enablement starting... +[13:14:49 INFO]: | Prison | Mines Module enabled successfully in 271 milliseconds. +[13:14:49 INFO]: | Prison | Ranks Module enablement starting... +[13:14:50 INFO]: | Prison | Loaded 0 ranks. +[13:14:50 INFO]: | Prison | Loaded 2 ladders. +[13:14:50 INFO]: | Prison | Loaded 0 players. +[13:14:50 INFO]: | Prison | Ranks by ladders: +[13:14:50 INFO]: | Prison | default: +[13:14:50 INFO]: | Prison | prestiges: +[13:14:50 INFO]: | Prison | none: +[13:14:50 INFO]: | Prison | Ranks Module enabled successfully in 241 milliseconds. +[13:14:50 INFO]: | Prison | Utils Module enablement starting... +[13:14:50 INFO]: | Prison | Utils Module enabled successfully in 15 milliseconds. +[13:14:50 INFO]: | Prison | Loaded 0 mines and submitted with a 5000 millisecond offset timing for auto resets. +[13:14:50 INFO]: | Prison | Total placeholders generated: 197 +[13:14:50 INFO]: | Prison | PLAYER: 102 +[13:14:50 INFO]: | Prison | LADDERS: 64 +[13:14:50 INFO]: | Prison | MINEPLAYERS: 31 +[13:14:50 INFO]: | Prison | ALIAS: 99 +[13:14:50 INFO]: | Prison | Total placeholders available to be Registered: 197 +[13:14:50 INFO]: | Prison | A total of 0 Mines and Ranks have been linked together. +[13:14:50 INFO]: | Prison | Notice: AutoManager config file was just updated with 120 new entries. May need to be configured. File: autoFeaturesConfig.yml +[13:14:50 INFO]: | Prison | Notice: AutoManager config file was just created. You must configure it to use it. File: autoFeaturesConfig.yml +[13:14:50 INFO]: | Prison | AutoManager: AutoFeatures and the Mine module are enabled. Prison will register the selected block break listeners. +[13:14:50 INFO]: | Prison | AutoManager: Trying to register BlockBreakEvent +[13:14:50 INFO]: | Prison | ------------- < /prison version > --------------- (3.2.11-alpha.11) +[13:14:50 INFO]: | Prison | Prison Version: 3.2.11-alpha.11 +[13:14:50 INFO]: | Prison | Running on Platform: tech.mcprison.prison.spigot.SpigotPlatform +[13:14:50 INFO]: | Prison | Minecraft Version: git-Spigot-21fe707-e1ebe52 (MC: 1.8.8) +[13:14:50 INFO]: | Prison | +[13:14:50 INFO]: | Prison | Server runtime: 1s +[13:14:50 INFO]: | Prison | Java Version: 1.8.0_291 Processor cores: 8 +[13:14:50 INFO]: | Prison | Memory Max: 3.556 GB Total: 1.054 GB Free: 644.558 MB Used: 434.942 MB +[13:14:50 INFO]: | Prison | Total Server Disk Space: 943.719 GB Usable: 689.799 GB Free: 689.799 GB Used: 253.919 GB +[13:14:50 INFO]: | Prison | Prison's File Count: 28 Folder Count: 23 Disk Space: 174.540 KB Other Objects: 0 +[13:14:50 INFO]: | Prison | Prison TPS Average: 0.00 Min: 20.00 Max: 20.00 Interval: 10 ticks Samples: 0 +[13:14:50 INFO]: | Prison | +[13:14:50 INFO]: | Prison | Prison's root Command: /prison +[13:14:50 INFO]: | Prison | Module: Mines : Enabled +[13:14:50 INFO]: | Prison | Module: Ranks : Enabled +[13:14:50 INFO]: | Prison | Module: Utils : Enabled +[13:14:50 INFO]: | Prison | +[13:14:50 INFO]: | Prison | AutoManager Enabled: true +[13:14:50 INFO]: | Prison | . Apply Block Breaks through Sync Tasks: true +[13:14:50 INFO]: | Prison | . Cancel all Block Break Events: true +[13:14:50 INFO]: | Prison | . Cancel All Block Break Events Block Drops: false +[13:14:50 INFO]: | Prison | . 'org.bukkit.BlockBreakEvent' Priority: LOW +[13:14:50 INFO]: | Prison | . Auto Pickup: true +[13:14:50 INFO]: | Prison | . Auto Smelt: true +[13:14:50 INFO]: | Prison | . Auto Block: true +[13:14:50 INFO]: | Prison | +[13:14:50 INFO]: | Prison | . Calculate Fortune: true +[13:14:50 INFO]: | Prison | . . Extended Bukkit Fortune Enabled: true +[13:14:50 INFO]: | Prison | +[13:14:50 INFO]: | Prison | . Calculate XP: true +[13:14:50 INFO]: | Prison | . Drop XP as Orbs: false +[13:14:50 INFO]: | Prison | . Calculate Food Exhustion: true +[13:14:50 INFO]: | Prison | . Calculate Additional Items in Drop: true (like flint in gravel) +[13:14:50 INFO]: | Prison | Prestiges Enabled: true +[13:14:50 INFO]: | Prison | . Reset Money: true +[13:14:50 INFO]: | Prison | . Reset Default Ladder: true +[13:14:50 INFO]: | Prison | +[13:14:50 INFO]: | Prison | GUI Enabled: true +[13:14:50 INFO]: | Prison | Sellall Enabled: true +[13:14:50 INFO]: | Prison | Backpacks Enabled: false +[13:14:50 INFO]: | Prison | +[13:14:50 INFO]: | Prison | Integrations: +[13:14:50 INFO]: | Prison | . . Permissions: LuckPerms (Vault) +[13:14:50 INFO]: | Prison | . . Economy: Essentials Economy (Vault) +[13:14:50 INFO]: | Prison | Integration Type: ECONOMY +[13:14:50 INFO]: | Prison | . . Essentials Economy (Vault) [URL] +[13:14:50 INFO]: | Prison | Integration Type: PERMISSION +[13:14:50 INFO]: | Prison | . . LuckPerms (Vault) +[13:14:50 INFO]: | Prison | . . LuckPerms (LuckPermsV5) [URL] +[13:14:50 INFO]: | Prison | Integration Type: PLACEHOLDER +[13:14:50 INFO]: | Prison | . . To list all or search for placeholders see: /prison placeholders +[13:14:50 INFO]: | Prison | . . PlaceholderAPI [URL] +[13:14:50 INFO]: | Prison | +[13:14:50 INFO]: | Prison | Registered Plugins: +[13:14:50 INFO]: | Prison | CS-CoreLib (1.5.4 JavaSE_6) Essentials (2.18.2.0 JavaSE_8) +[13:14:50 INFO]: | Prison | EssentialsChat (2.18.2.0 JavaSE_8) HolographicDisplays (2.4.1 JavaSE_8) +[13:14:50 INFO]: | Prison | HolographicExtension (1.10.8 JavaSE_8) LuckPerms (5.1.26 JavaSE_8) +[13:14:50 INFO]: | Prison | PlaceholderAPI (2.10.10 JavaSE_8) Prison (3.2.11-alpha.11 JavaSE_8) +[13:14:50 INFO]: | Prison | ProtocolLib (4.5.0 JavaSE_8) Vault (1.5.6-b49 JavaSE_6) +[13:14:50 INFO]: | Prison | WorldEdit (6.1;no_git_id JavaSE_6) WorldGuard (6.1 JavaSE_6) +[13:14:50 INFO]: | Prison | Prison - Finished loading. +``` + + +
+ + +# Prison Information - Setting up a new Prison Server + + +When Prison detects that it has not ran on the server before, it will display the following message in the console, after waiting about 10 seconds for the other plugins to finish logging their startup information. + + +``` +[13:14:55 INFO]: | Prison | ----- < Setting up a new Prison Server > -------- (3.2.11-alpha.11) +[13:14:55 INFO]: | Prison | Welcome to Prison! +[13:14:55 INFO]: | Prison | +[13:14:55 INFO]: | Prison | To quickly get started, it is suggested to use the following command which will setup Ranks, Mines, link the Mines to the Ranks, setup automatic Access by Ranks, auto assign blocks to the generated Mines in increasing value,Enable the auto features (auto pickup, smelt, and block), setup the sellall's default shop pricing on about 95 items, etc... +[13:14:55 INFO]: | Prison | . /ranks autoConfigure +[13:14:55 INFO]: | Prison | +[13:14:55 INFO]: | Prison | For more information on what to do next, after running autoConfigure, check out this document: +[13:14:55 INFO]: | Prison | . https://prisonteam.github.io/Prison/prison_docs_100_setting_up_auto_configure.html +[13:14:55 INFO]: | Prison | +[13:14:55 INFO]: | Prison | +[13:14:55 INFO]: | Prison | For more information on how to setup Prison, see our extensive documentation that is online: +[13:14:55 INFO]: | Prison | . https://prisonteam.github.io/Prison/prison_docs_000_toc.html +[13:14:55 INFO]: | Prison | +[13:14:55 INFO]: | Prison | Information on suggested plugins can be found here: +[13:14:55 INFO]: | Prison | . https://prisonteam.github.io/Prison/prison_docs_012_setting_up_prison_basics.html +[13:14:55 INFO]: | Prison | +[13:14:55 INFO]: | Prison | If you need help with setting up prison, please see our documentation. +[13:14:55 INFO]: | Prison | If you find an issue with Prison, or need help for things not in the documentation, then please visit our discord server: +[13:14:55 INFO]: | Prison | +[13:14:55 INFO]: | Prison | +> + +``` + +
+ + +# Running command: /ranks autoConfigure help + + +``` +>ranks autoConfigure help +[13:31:26 INFO]: ------- < Cmd: /ranks autoConfigure > --------- (3.2.11-alpha.11) +[13:31:26 INFO]: Auto configures Ranks and Mines using single letters A through Z for both the rank and mine names. Both ranks and mines are generated, they will also be linked together automatically. To set the starting price use price=x. To set multiplier mult=x. AutoConfigure will try to merge any preexsiting ranks and mines, but you must use the 'force' keyword in 'options'. Force will replace all blocks in preexisting mines. To keep preexisting blocks, use 'forceKeepBlocks' with the 'force' option. Default values [full price=50000 mult=1.5] +[13:31:26 INFO]: /ranks autoConfigure [options] +[13:31:26 INFO]: [options | full] Options: [full ranks mines price=x mult=x force forceKeepBlocks dontForceLinerWalls dontForceLinerBottoms] +[13:31:26 INFO]: Permissions: +[13:31:26 INFO]: ranks.set +[13:31:26 INFO]: Aliases: +[13:31:26 INFO]: [prison autoConfigure] +> +``` + + +
+ + +# Running command: /ranks autoConfigure + + +``` +>ranks autoConfigure +[13:33:38 INFO]: Your new rank, 'A', was created in the ladder 'default', using the tag value of '[A]' +[13:33:38 INFO]: Virtual mine created: use command '/mines set area help' set an area within a world to enable as a normal mine. +[13:33:38 INFO]: Your new rank, 'B', was created in the ladder 'default', using the tag value of '[B]' +[13:33:38 INFO]: Virtual mine created: use command '/mines set area help' set an area within a world to enable as a normal mine. +[13:33:38 INFO]: Your new rank, 'C', was created in the ladder 'default', using the tag value of '[C]' +[13:33:38 INFO]: Virtual mine created: use command '/mines set area help' set an area within a world to enable as a normal mine. +[13:33:38 INFO]: Your new rank, 'D', was created in the ladder 'default', using the tag value of '[D]' +[13:33:38 INFO]: Virtual mine created: use command '/mines set area help' set an area within a world to enable as a normal mine. +[13:33:38 INFO]: Your new rank, 'E', was created in the ladder 'default', using the tag value of '[E]' +[13:33:38 INFO]: Virtual mine created: use command '/mines set area help' set an area within a world to enable as a normal mine. +[13:33:38 INFO]: Your new rank, 'F', was created in the ladder 'default', using the tag value of '[F]' +[13:33:38 INFO]: Virtual mine created: use command '/mines set area help' set an area within a world to enable as a normal mine. +[13:33:38 INFO]: Your new rank, 'G', was created in the ladder 'default', using the tag value of '[G]' +[13:33:38 INFO]: Virtual mine created: use command '/mines set area help' set an area within a world to enable as a normal mine. +[13:33:38 INFO]: Your new rank, 'H', was created in the ladder 'default', using the tag value of '[H]' +[13:33:38 INFO]: Virtual mine created: use command '/mines set area help' set an area within a world to enable as a normal mine. +[13:33:38 INFO]: Your new rank, 'I', was created in the ladder 'default', using the tag value of '[I]' +[13:33:38 INFO]: Virtual mine created: use command '/mines set area help' set an area within a world to enable as a normal mine. +[13:33:38 INFO]: Your new rank, 'J', was created in the ladder 'default', using the tag value of '[J]' +[13:33:38 INFO]: Virtual mine created: use command '/mines set area help' set an area within a world to enable as a normal mine. +[13:33:38 INFO]: Your new rank, 'K', was created in the ladder 'default', using the tag value of '[K]' +[13:33:38 INFO]: Virtual mine created: use command '/mines set area help' set an area within a world to enable as a normal mine. +[13:33:38 INFO]: Your new rank, 'L', was created in the ladder 'default', using the tag value of '[L]' +[13:33:38 INFO]: Virtual mine created: use command '/mines set area help' set an area within a world to enable as a normal mine. +[13:33:38 INFO]: Your new rank, 'M', was created in the ladder 'default', using the tag value of '[M]' +[13:33:39 INFO]: Virtual mine created: use command '/mines set area help' set an area within a world to enable as a normal mine. +[13:33:39 INFO]: Your new rank, 'N', was created in the ladder 'default', using the tag value of '[N]' +[13:33:39 INFO]: Virtual mine created: use command '/mines set area help' set an area within a world to enable as a normal mine. +[13:33:39 INFO]: Your new rank, 'O', was created in the ladder 'default', using the tag value of '[O]' +[13:33:39 INFO]: Virtual mine created: use command '/mines set area help' set an area within a world to enable as a normal mine. +[13:33:39 INFO]: Your new rank, 'P', was created in the ladder 'default', using the tag value of '[P]' +[13:33:39 INFO]: Virtual mine created: use command '/mines set area help' set an area within a world to enable as a normal mine. +[13:33:39 INFO]: Your new rank, 'Q', was created in the ladder 'default', using the tag value of '[Q]' +[13:33:39 INFO]: Virtual mine created: use command '/mines set area help' set an area within a world to enable as a normal mine. +[13:33:39 INFO]: Your new rank, 'R', was created in the ladder 'default', using the tag value of '[R]' +[13:33:39 INFO]: Virtual mine created: use command '/mines set area help' set an area within a world to enable as a normal mine. +[13:33:39 INFO]: Your new rank, 'S', was created in the ladder 'default', using the tag value of '[S]' +[13:33:39 INFO]: Virtual mine created: use command '/mines set area help' set an area within a world to enable as a normal mine. +[13:33:39 INFO]: Your new rank, 'T', was created in the ladder 'default', using the tag value of '[T]' +[13:33:39 INFO]: Virtual mine created: use command '/mines set area help' set an area within a world to enable as a normal mine. +[13:33:39 INFO]: Your new rank, 'U', was created in the ladder 'default', using the tag value of '[U]' +[13:33:39 INFO]: Virtual mine created: use command '/mines set area help' set an area within a world to enable as a normal mine. +[13:33:39 INFO]: Your new rank, 'V', was created in the ladder 'default', using the tag value of '[V]' +[13:33:39 INFO]: Virtual mine created: use command '/mines set area help' set an area within a world to enable as a normal mine. +[13:33:39 INFO]: Your new rank, 'W', was created in the ladder 'default', using the tag value of '[W]' +[13:33:39 INFO]: Virtual mine created: use command '/mines set area help' set an area within a world to enable as a normal mine. +[13:33:39 INFO]: Your new rank, 'X', was created in the ladder 'default', using the tag value of '[X]' +[13:33:39 INFO]: Virtual mine created: use command '/mines set area help' set an area within a world to enable as a normal mine. +[13:33:39 INFO]: Your new rank, 'Y', was created in the ladder 'default', using the tag value of '[Y]' +[13:33:39 INFO]: Virtual mine created: use command '/mines set area help' set an area within a world to enable as a normal mine. +[13:33:39 INFO]: Your new rank, 'Z', was created in the ladder 'default', using the tag value of '[Z]' +[13:33:39 INFO]: Virtual mine created: use command '/mines set area help' set an area within a world to enable as a normal mine. +[13:33:39 INFO]: Your new rank, 'P1', was created in the ladder 'prestiges', using the tag value of '[+]' +[13:33:39 INFO]: Your new rank, 'P2', was created in the ladder 'prestiges', using the tag value of '[+2]' +[13:33:39 INFO]: Your new rank, 'P3', was created in the ladder 'prestiges', using the tag value of '[+3]' +[13:33:39 INFO]: Your new rank, 'P4', was created in the ladder 'prestiges', using the tag value of '[+4]' +[13:33:39 INFO]: Your new rank, 'P5', was created in the ladder 'prestiges', using the tag value of '[+5]' +[13:33:39 INFO]: Your new rank, 'P6', was created in the ladder 'prestiges', using the tag value of '[+6]' +[13:33:39 INFO]: Your new rank, 'P7', was created in the ladder 'prestiges', using the tag value of '[+7]' +[13:33:39 INFO]: Your new rank, 'P8', was created in the ladder 'prestiges', using the tag value of '[+8]' +[13:33:39 INFO]: Your new rank, 'P9', was created in the ladder 'prestiges', using the tag value of '[+9]' +[13:33:39 INFO]: Your new rank, 'P10', was created in the ladder 'prestiges', using the tag value of '[+10]' +[13:33:40 INFO]: | Prison | Mine A: [minecraft: andesite 5.0, minecraft: cobblestone 95.0] +[13:33:40 INFO]: | Prison | Mine B: [minecraft: diorite 5.0, minecraft: andesite 10.0, minecraft: cobblestone 85.0] +[13:33:40 INFO]: | Prison | Mine C: [minecraft: coal_ore 5.0, minecraft: diorite 10.0, minecraft: andesite 20.0, minecraft: cobblestone 65.0] +[13:33:40 INFO]: | Prison | Mine D: [minecraft: granite 5.0, minecraft: coal_ore 10.0, minecraft: diorite 20.0, minecraft: andesite 20.0, minecraft: cobblestone 45.0] +[13:33:40 INFO]: | Prison | Mine E: [minecraft: stone 5.0, minecraft: granite 10.0, minecraft: coal_ore 20.0, minecraft: diorite 20.0, minecraft: andesite 20.0, minecraft: cobblestone 25.0] +[13:33:40 INFO]: | Prison | Mine F: [minecraft: iron_ore 5.0, minecraft: stone 10.0, minecraft: granite 20.0, minecraft: coal_ore 20.0, minecraft: diorite 20.0, minecraft: andesite 25.0] +[13:33:40 INFO]: | Prison | Mine G: [minecraft: polished_andesite 5.0, minecraft: iron_ore 10.0, minecraft: stone 20.0, minecraft: granite 20.0, minecraft: coal_ore 20.0, minecraft: diorite 25.0] +[13:33:40 INFO]: | Prison | Mine H: [minecraft: gold_ore 5.0, minecraft: polished_andesite 10.0, minecraft: iron_ore 20.0, minecraft: stone 20.0, minecraft: granite 20.0, minecraft: coal_ore 25.0] +[13:33:40 INFO]: | Prison | Mine I: [minecraft: mossy_cobblestone 5.0, minecraft: gold_ore 10.0, minecraft: polished_andesite 20.0, minecraft: iron_ore 20.0, minecraft: stone 20.0, minecraft: granite 25.0] +[13:33:40 INFO]: | Prison | Mine J: [minecraft: coal_block 5.0, minecraft: mossy_cobblestone 10.0, minecraft: gold_ore 20.0, minecraft: polished_andesite 20.0, minecraft: iron_ore 20.0, minecraft: stone 25.0] +[13:33:40 INFO]: | Prison | Mine K: [minecraft: nether_quartz_ore 5.0, minecraft: coal_block 10.0, minecraft: mossy_cobblestone 20.0, minecraft: gold_ore 20.0, minecraft: polished_andesite 20.0, minecraft: iron_ore 25.0] +[13:33:40 INFO]: | Prison | Mine L: [minecraft: lapis_ore 5.0, minecraft: nether_quartz_ore 10.0, minecraft: coal_block 20.0, minecraft: mossy_cobblestone 20.0, minecraft: gold_ore 20.0, minecraft: polished_andesite 25.0] +[13:33:40 INFO]: | Prison | Mine M: [minecraft: end_stone 5.0, minecraft: lapis_ore 10.0, minecraft: nether_quartz_ore 20.0, minecraft: coal_block 20.0, minecraft: mossy_cobblestone 20.0, minecraft: gold_ore 25.0] +[13:33:40 INFO]: | Prison | Mine N: [minecraft: iron_block 5.0, minecraft: end_stone 10.0, minecraft: lapis_ore 20.0, minecraft: nether_quartz_ore 20.0, minecraft: coal_block 20.0, minecraft: mossy_cobblestone 25.0] +[13:33:40 INFO]: | Prison | Mine O: [minecraft: redstone_ore 5.0, minecraft: iron_block 10.0, minecraft: end_stone 20.0, minecraft: lapis_ore 20.0, minecraft: nether_quartz_ore 20.0, minecraft: coal_block 25.0] +[13:33:40 INFO]: | Prison | Mine P: [minecraft: diamond_ore 5.0, minecraft: redstone_ore 10.0, minecraft: iron_block 20.0, minecraft: end_stone 20.0, minecraft: lapis_ore 20.0, minecraft: nether_quartz_ore 25.0] +[13:33:40 INFO]: | Prison | Mine Q: [minecraft: quartz_block 5.0, minecraft: diamond_ore 10.0, minecraft: redstone_ore 20.0, minecraft: iron_block 20.0, minecraft: end_stone 20.0, minecraft: lapis_ore 25.0] +[13:33:40 INFO]: | Prison | Mine R: [minecraft: emerald_ore 5.0, minecraft: quartz_block 10.0, minecraft: diamond_ore 20.0, minecraft: redstone_ore 20.0, minecraft: iron_block 20.0, minecraft: end_stone 25.0] +[13:33:40 INFO]: | Prison | Mine S: [minecraft: gold_block 5.0, minecraft: emerald_ore 10.0, minecraft: quartz_block 20.0, minecraft: diamond_ore 20.0, minecraft: redstone_ore 20.0, minecraft: iron_block 25.0] +[13:33:40 INFO]: | Prison | Mine T: [minecraft: prismarine 5.0, minecraft: gold_block 10.0, minecraft: emerald_ore 20.0, minecraft: quartz_block 20.0, minecraft: diamond_ore 20.0, minecraft: redstone_ore 25.0] +[13:33:40 INFO]: | Prison | Mine U: [minecraft: lapis_block 5.0, minecraft: prismarine 10.0, minecraft: gold_block 20.0, minecraft: emerald_ore 20.0, minecraft: quartz_block 20.0, minecraft: diamond_ore 25.0] +[13:33:40 INFO]: | Prison | Mine V: [minecraft: redstone_block 5.0, minecraft: lapis_block 10.0, minecraft: prismarine 20.0, minecraft: gold_block 20.0, minecraft: emerald_ore 20.0, minecraft: quartz_block 25.0] +[13:33:40 INFO]: | Prison | Mine W: [minecraft: obsidian 5.0, minecraft: redstone_block 10.0, minecraft: lapis_block 20.0, minecraft: prismarine 20.0, minecraft: gold_block 20.0, minecraft: emerald_ore 25.0] +[13:33:40 INFO]: | Prison | Mine X: [minecraft: diamond_block 5.0, minecraft: obsidian 10.0, minecraft: redstone_block 20.0, minecraft: lapis_block 20.0, minecraft: prismarine 20.0, minecraft: gold_block 25.0] +[13:33:40 INFO]: | Prison | Mine Y: [minecraft: dark_prismarine 5.0, minecraft: diamond_block 10.0, minecraft: obsidian 20.0, minecraft: redstone_block 20.0, minecraft: lapis_block 20.0, minecraft: prismarine 25.0] +[13:33:40 INFO]: | Prison | Mine Z: [minecraft: emerald_block 5.0, minecraft: dark_prismarine 10.0, minecraft: diamond_block 20.0, minecraft: obsidian 20.0, minecraft: redstone_block 20.0, minecraft: lapis_block 25.0] +[13:33:40 INFO]: | Prison | Mine Liner status: A (Created) : walls:bricked:forced,bottom:bedrock:forced,ladderType:normal +[13:33:41 INFO]: | Prison | Mine Liner status: B (Created) : walls:darkForest:forced,bottom:glowstone:forced,ladderType:normal +[13:33:41 INFO]: | Prison | Mine Liner status: C (Created) : walls:blackAndWhite:forced,bottom:glowingPlanks:forced,ladderType:normal +[13:33:41 INFO]: | Prison | Mine Liner status: D (Created) : walls:glowstone:forced,bottom:bedrock:forced,ladderType:normal +[13:33:41 INFO]: | Prison | Mine Liner status: E (Created) : walls:obby:forced,bottom:glowstone:forced,ladderType:normal +[13:33:41 INFO]: | Prison | Mine Liner status: F (Created) : walls:bricked:forced,bottom:bright:forced,ladderType:normal +[13:33:41 INFO]: | Prison | Mine Liner status: G (Created) : walls:darkForest:forced,bottom:glowingPlanks:forced,ladderType:normal +[13:33:41 INFO]: | Prison | Mine Liner status: H (Created) : walls:bedrock:forced,bottom:beacon:forced,ladderType:normal +[13:33:41 INFO]: | Prison | Mine Liner status: I (Created) : walls:beacon:forced,bottom:glowstone:forced,ladderType:normal +[13:33:41 INFO]: | Prison | Mine Liner status: J (Created) : walls:seaEchos:forced,bottom:bricked:forced,ladderType:normal +[13:33:41 INFO]: | Prison | Mine Liner status: K (Created) : walls:blackAndWhite:forced,bottom:glowingPlanks:forced,ladderType:normal +[13:33:41 INFO]: | Prison | Mine Liner status: L (Created) : walls:bricked:forced,bottom:bricked:forced,ladderType:normal +[13:33:41 INFO]: | Prison | Mine Liner status: M (Created) : walls:glowingPlanks:forced,bottom:glowingPlanks:forced,ladderType:normal +[13:33:41 INFO]: | Prison | Mine Liner status: N (Created) : walls:beacon:forced,bottom:blackAndWhite:forced,ladderType:normal +[13:33:41 INFO]: | Prison | Mine Liner status: O (Created) : walls:darkOakPrismarine:forced,bottom:glowstone:forced,ladderType:normal +[13:33:41 INFO]: | Prison | Mine Liner status: P (Created) : walls:bricked:forced,bottom:glowingPlanks:forced,ladderType:normal +[13:33:41 INFO]: | Prison | Mine Liner status: Q (Created) : walls:bright:forced,bottom:beacon:forced,ladderType:normal +[13:33:41 INFO]: | Prison | Mine Liner status: R (Created) : walls:glowstone:forced,bottom:obby:forced,ladderType:normal +[13:33:41 INFO]: | Prison | Mine Liner status: S (Created) : walls:darkForest:forced,bottom:darkOakPrismarine:forced,ladderType:normal +[13:33:41 INFO]: | Prison | Mine Liner status: T (Created) : walls:obby:forced,bottom:glowingPlanks:forced,ladderType:normal +[13:33:41 INFO]: | Prison | Mine Liner status: U (Created) : walls:bricked:forced,bottom:obby:forced,ladderType:normal +[13:33:41 INFO]: | Prison | Mine Liner status: V (Created) : walls:beacon:forced,bottom:darkForest:forced,ladderType:normal +[13:33:41 INFO]: | Prison | Mine Liner status: W (Created) : walls:bricked:forced,bottom:obby:forced,ladderType:normal +[13:33:41 INFO]: | Prison | Mine Liner status: X (Created) : walls:darkOakPrismarine:forced,bottom:beacon:forced,ladderType:normal +[13:33:41 INFO]: | Prison | Mine Liner status: Y (Created) : walls:darkOakPrismarine:forced,bottom:seaEchos:forced,ladderType:normal +[13:33:41 INFO]: | Prison | Mine Liner status: Z (Created) : walls:white:forced,bottom:darkForest:forced,ladderType:normal +[13:33:41 INFO]: The 'prestiges' ladder has been enabled to apply a Base Rank Cost Multiplier of 0.1000 that will be applied to 'all' rank costs. This multiplier will be increased with each rank on the ladder. +[13:33:41 INFO]: The Base Rank Cost Multiplier can be adjusted, or disabled, with the command: '/ranks ladder rankCostMultiplier +[13:33:41 INFO]: Ranks autoConfigure: 26 ranks were created. +[13:33:41 INFO]: Ranks autoConfigure: No rank commands were created. +[13:33:41 INFO]: | Prison | Total placeholders generated: 1419 +[13:33:41 INFO]: | Prison | PLAYER: 102 +[13:33:41 INFO]: | Prison | LADDERS: 64 +[13:33:41 INFO]: | Prison | MINES: 832 +[13:33:41 INFO]: | Prison | MINEPLAYERS: 57 +[13:33:41 INFO]: | Prison | STATSMINES: 364 +[13:33:41 INFO]: | Prison | ALIAS: 697 +[13:33:41 INFO]: | Prison | Total placeholders available to be Registered: 1419 +[13:33:41 INFO]: | Prison | AutoManagerEventsManager: unregistered a total of 2 event listeners. +[13:33:41 INFO]: | Prison | AutoManager: Trying to register BlockBreakEvent +[13:33:41 INFO]: | Prison | Welcome! RoyalBlueRanger just joined the server and was assigned the default ranks. +[13:33:41 INFO]: | Prison | Welcome! Myrqua just joined the server and was assigned the default ranks. +[13:33:41 INFO]: | Prison | Welcome! RoyalCoffeeBeans just joined the server and was assigned the default ranks. +[13:33:41 INFO]: Ranks autoConfigure: 26 mines were created. +[13:33:41 INFO]: Ranks autoConfigure: 26 ranks and mines were linked. +[13:33:41 INFO]: Created 10 prestige ranks (temp message). +[13:33:41 INFO]: | Prison | +> + + +``` + +
+ + + + + diff --git a/docs/prison_docs_115_using_BlockEvents.md b/docs/prison_docs_115_using_BlockEvents.md index 65e55fcf5..c0f374bf2 100644 --- a/docs/prison_docs_115_using_BlockEvents.md +++ b/docs/prison_docs_115_using_BlockEvents.md @@ -13,11 +13,52 @@ A single BlockEvent can also have more than one command that is ran together wit BlockEvents have a taskMode that defines how the specified commands are to be ran. +*Documented updated: 2021-12-03* +
+# BlockEvent Commands + +BlockEvents can be access through the command prefixes of: + +`/mines blockEvent` + +There are 9 sub-commands, which includes add and list, which are probably the most important of the commands. + + +BlockEvent Sub-Commands + + +In the above screen print, the sub-commands have as a parameter named **row**. See the next section in this document for more information. + + +The BlockEvent listings can also be included in the following command by including the keyword **all**: +`/mines info all` + + +## Use of Row Numbers In The BlockEvent Commands: + + Due to the complexity of the blockEvent commands being deeply nested, and there could be so many of them, many of the blockEvent commands uses a **Row** identifier. This row identifier is based upon the order of the commands as listed under the `/mines blockEvent list` command. + +A number of examples of a few different blockEvets is as follows. Emphasis is on the row numbers. + +BlockEvent Sub-Commands + + + + + # BlockEvents Placeholders -Within the BlockEvents commands you can use placeholders and Prison will substitute the correct values for you. +Within the BlockEvents commands you can use placeholders and Prison will substitute the correct values within the commands. + + +For a current list of all blockEvent commands use **placeholders** keyword with the **add** command: + +`/mines blockEvent add placeholders` + + +`{player} {player_uid} {msg} {broadcast} {title} {actionBar} {inline} {inlinePlayer} {sync} {syncPlayer} {blockName} {mineName} {locationWorld} {locationX} {locationY} {locationZ} {coordinates} {worldCoordinates} {blockCoordinates} {blockChance} {blockIsAir} {blocksPlaced} {blockRemaining} {blocksMinedTotal} {mineBlocksRemaining} {mineBlocksRemainingPercent} {mineBlocksTotalMined} {mineBlocksSize} {blockMinedName} {blockMinedNameFormal} {blockMinedBlockType} {eventType} {eventTriggered} {utilsDecay}` - **{player}** Provides the player's name. @@ -32,22 +73,124 @@ Prison's BlockEvents also supports more advanced placeholders that can help simp - **{msg}** Send a message to the player. This is a shortcut for the prison command: `/prison utils msg`. Example: `{msg} Congrats! You found a token!`. -- **{broadcast}** Sends a broadcast message to all players on the server. this is a shortcut for the prison command: `/prison utils broadcast`. Example: `{broadcast} {player} found a treasure trove of 100 voter keys!`. +- **{broadcast}** Sends a broadcast message to all players on the server. Just use this placeholder followed by the message. This is a shortcut for the prison command: `/prison utils broadcast`. Example: `{broadcast} {player} found a treasure trove of 100 voter keys!`. + + +- **{actionBar}** Sends a message to the "actionBar" on the player's screen. Just use this placeholder followed by the message. This is a shortcut for the prison command: `\prison utils titles actionBar `. Example: `{actionBar}You Found Tokens!` + + +- **{title}** Sends a message to the "title" on the player's screen. Just use this placeholder followed by the message. This is a shortcut for the prison command: `\prison utils titles title `. Example: `{title}You Found Tokens!` + + + +**How the command runs:** + +There are four **taskModes** on how BlockEvent commands run. The taskModes can be setup through the command `/mines blockEvent taskMode help`, or they can be specified as placeholders. There are 4 taskModes, and the placeholder versions are listed here: + +- **{inline}** This is the default taskMode if not specified. **{inline}** runs the commands in the same thread that in which Prison is handling the Block Break Events within Auto Features, and runs them as console (OP). If the command you use with BlockEvents is "slow" to run, then it could cause significant lag on the server. + +- **{inlinePlayer}** This placeholder is similar to the **{inline}** placeholder, but it is ran as the player who is mining. This too can cause significant lag if the command is not fast. +- **{sync}** This placeholder uses the taskMode of synchronous task submission. The command specified will be submitted to run in the bukkit's synchronous thread, and is ran as console (OP). Since all block break events are ran in the same bukkit synchronous thread, the specified command will run after prison is finished processing the broken block. Long running commands will not cause lag through the handling of the block break events, but they could still cause lag. +- **{syncPlayer}** This placeholder is similar to the **{sync}** placeholder, with the exception the commands are ran as the player, so the player must have access to those commands. -Some examples showing how to use these in BlockEvent: +NOTE: It is impossible to run a command asynchronously, since the execution of a command must always be in a synchronous thread. Hence you can submit an async task, but then when you run the command, it does so in a sync thread. + + +`/mines blockEvent add help` +`/mines blockEvent add placeholders` + + +Some examples showing how to use placeholders in the blockEvents. ``` -/mines blockevent add A 0.075 none inline prison utils repairAll {player};{msg} Congrats! Everything in your inventory has been repaired! -/mines blockevent add A 1 none inline prison utils smelt {player};prison utils block {player} +/mines blockEvent add a 100 {utilsDecay} rainbow {blockCoordinates} AIR 40 {mineName} + +/mines blockevent add A 0.075 prison utils repairAll {player};{actionBar}Your items have been repaired! + +/mines blockevent add A 1 prison utils smelt {player} -/mines blockEvent add A 5.0 none inline prison utils potionEffect speed 90 2;prison utils potionEffect night_vision 300 1 +/mines blockEvent add A 5.0 prison utils potionEffect speed 90 2;prison utils potionEffect night_vision 300 1 ``` + +- **{blockName}** The name of the block that was placed in the mine during the last mine reset. The same name as used and provided within the command `/mines block search`. + + +- **{mineName}** The name of the mine. If outside of a mine it will be blank. + + +- **{locationWorld}** Provides the world name in which the block was mined. + + +-**{locationX}** The **X** coordinates for the broken block. This is an integer value. + + +- **{locationY}** The **Y** coordinates for the broken block. This is an integer value. + + +- **{locationZ}** The **Z** coordinates for the broken block. This is an integer value. + + +- **{coordinates}** This provides the X, Y, and Z coordinates for the broken block. These are double values, surrounded by parenthesis and separated by commas. Format: **(X,Y,Z)** Example: `(183.2,88.3792,-3828.248)` + + +- **{blockCoordinates}** This is similar to the **{coordinates}** placeholder, except for the use of integer values. Format: **(blockName,world,X,Y,Z)** Example: `(,prisonWorld,183,88,-3828)` + + +- **{worldCoordinates}** This combines both the **{locationWorld}** and **{blockCoordinates}** placeholder in to one placeholder. The coordinates are integer values. Format: **(world,X,Y,Z)** Example: `(prisonWorld,183,88,-3828)` + + +- **{blockChance}** The blockEvent's percent chance as defined when setting up the command. + + +- **{blockIsAir}** A boolean value of either TRUE or FALSE as to if the block was originally set to AIR during the last mine reset. Technically, if the block is set to AIR, then it is ignored in all block events that prison processes through the auto features. Therefore this should always return FALSE. + + +- **{blocksPlaced}** This is the number of blocks placed in the mine during the last Mine reset. This value should be equal to the mine's total block size, minus the number of AIR blocks that were placed during the reset. + + +- **{blockRemaining}** The current number of blocks remaining in the mine, until there would be zero blocks left to mine. Note that this is a dynamic and changing value, especially if many other players are mining at the same time. There is even a chance that this value may be non-zero with another player's block break handling triggering a mine reset event, or zero blocks remaining. + + +- **{blocksMinedTotal}** The total number of blocks mined of the same type that was just broke since the last mine reset. + + +- **{mineBlocksRemaining}** The total number of block remaining of the same type that was just broke. See **{blockName}** for the block name. + +- **{mineBlocksRemainingPercent}** The percent number of blocks remaining in the mine. + + +- **{mineBlocksTotalMined}** This is the total number of all blocks mined since the stats were first enabled. + + +- **{mineBlocksSize}** This is the total block count of all blocks mined. + + +- **{blockMinedName}** This is the name of the block that was mined. It may not be identical to the **{blockName}** placeholder, especially if another process replaced it with another block. + + +- **{blockMinedNameFormal}** This is the formal name of the block that was mined. The formal nature is the namespace prefixed to the block name, with a colon between the two. For example a block name may be "cobblestone" and then the formal name being "minecraft:cobblestone". This is more useful for custom blocks, such that their namespace is not "minecraft", which an example being "customitems:compressed_cobblestone". + + +- **{blockMinedBlockType}** This is the bukkit Material name for the block. It may not match the block name, especially on older versions of spigot. + + +- **{eventType}** This is the event type that Prison listened to that initiated the block break handling. + + +- **{eventTriggered}** A few enchantment plugins identify the enchantment that triggered the event. If it is available, then that value will be provided by this placeholder. One plugin that provides this value is TokenEnchant. + + +- **{utilsDecay}** This is a shortcut for `/prison utils decay`. + + + +
diff --git a/docs/prison_docs_117_setting_up_backpacks.md b/docs/prison_docs_117_setting_up_backpacks.md index cf47f4124..b39dc6646 100644 --- a/docs/prison_docs_117_setting_up_backpacks.md +++ b/docs/prison_docs_117_setting_up_backpacks.md @@ -5,10 +5,15 @@ # Backpacks +*NOTE: At this time it is not advisable to use Prison's backpacks. It is scheduled to undergo a rewrite soon. An alternative backbacks plugin that should work with Prison is MinePacks.* + + Prison provides backpacks. +*Documented updated: 2021-12-03* +
diff --git a/docs/prison_docs_310_guide_placeholders.md b/docs/prison_docs_310_guide_placeholders.md index 0c5e3cc34..0b4a04f28 100644 --- a/docs/prison_docs_310_guide_placeholders.md +++ b/docs/prison_docs_310_guide_placeholders.md @@ -6,6 +6,10 @@ This document covers different aspects of placeholders within Prison. It explains how they work, how to use them, and different ways to use them. + +*Documented updated: 2021-12-03* + +
@@ -13,34 +17,100 @@ This document covers different aspects of placeholders within Prison. It explai Placeholders allow the sharing of data from one plugin with another plugin, and without either plugin knowing anything about each other. -On the surface they appear to be simple, but there are a lot of moving parts below the surface, and with Prison Mines, there are even more things going on. +On the surface they appear to be simple, but there are a lot of moving parts below the surface, and with Prison Mines, there are even more complicated things going on. Add in to the mix, that different plugins deal with placeholders in slightly different ways, and you can wind up with a challenge to get them to work under different circumstances.
+ + + +# Placeholder Commands + + +*Since Prison v3.2.1-alpha.13* + + +There are a few useful commands within prison that will allow you list placeholders, search for placeholders, and to test random text that includes placeholders. + + +Sub-command listing of all placeholders commands: + +* **/prison placeholders** + + +* **/prison placeholders list** +* **/prison placeholders search** +* **/prison placeholders test** + +* **/prison placeholders reload** + +NOTE: the `/prison placeholders reload` command only reloads and registers the placeholders with the placeholder integrations. This would be required to enable placeholders when adding a new mine, a new rank, or a new ladder. If you reload another plugin, such as papi, you may need to reload the placeholders which will re-register them. Prison has been setup to survive a papi restart, but there could still be issues. + + +NOTE: Information on these command are provided in detail below. + + +
+ + # Placeholder Types and Counts -* **Rank Related:** 4 including aliases -* **Rankup Related:** 18 including aliases +Prison has numerous placeholders, with number of different types. Each of these types have different internal requirements and conditions of usage. This is a high overview of the various types and their counts. + +* **Player Related:** 92 including aliases + * **Rank Related:** 8 including aliases + * **Rankup Related:** 20 including aliases + * **Player Balance Related:** 8 including aliases + * **Player Tool Related:** 34 including aliases + * **Player Health Related:** 14 including aliases + * **Player XP and Levels Related:** 6 including aliases + * **Player Walk Speed:** 2 including aliases + + +* **Ladders Related:** 30 including aliases **times** each ladder + A LADDERS placeholder must include the ladder's name in the placeholder and therefore is static. + + +* **Ranks Related:** 22 including aliases **times** each rank + A RANKS placeholder needs to specify the Rank name as part of the placeholder. Each placeholder must specify a Rank and is static. -* **Rank Ladder Related:** 4 including aliases **times** each ladder -* **Rankup Ladder Related:** 18 including aliases **times** each ladder +* **RankPlayers Related:** 12 including aliases **times** each rank -* **Player Balance Related:** 2 including aliases -* **Player Ladder Balance Related:** 2 including aliases **times** each ladder + A RANKPLAYERS placeholder is one that will change based upon the player's own Rank. Each player could have a different rank. Because of this relationship, these can only be used with instances of players such as scoreboards and chat prefixes; they will not work in holographic displays or with signs. -* **Mine Related:** 28 including aliases **times** each mine -* **Mine Player Related:** 14 including aliases +* **Mines Related:** 18 including aliases **times** each ladder -**Total base Placeholders:** 90 including aliases +* **Player Ladder Balance Related:** 32 including aliases **times** each Mine + + A MINES placeholder must specify the Mine mine as part of the placeholder. Each placeholder must specify a mine and is static. + + +* **MinePlayers Related:** 34 including aliases + + A MINEPLAYERS placholder is similar to a RankPlayers placeholder in that it is dynamic and you cannot specify a mine's name with it. How it works, is that it provides the related stats for the mine in which the player is standing in. When the player leaves the mine, then these placeholders returns an empty string value (a blank). + + +* *STATSMINES Related:** 14 including aliases + + These are a work in progress, but will provide access to some mine stats such as total blocks mined. + + +* *STATSRANKS Related:** 6 including aliases + + These are a work in progress, but will provide access to some rank stats such as top ranked player in that rank. + + + +**Total base Placeholders:** 240 including aliases + -**Total if 26 Mines and 3 Ladders:** 844 placeholder including aliases (22 + 26*3 ladder + 2 + 28*26 mines + 14)
@@ -57,7 +127,7 @@ There is always more than one way to do things, and the same goes for having mor # Placeholder Theory for Prison -There are two major types of placeholders in prison: Player based and Mine based. With the most recent releases of prison, there have been hybrids added that are a combination of the two. For example there are now ladder based placeholder that allow targeting ranks on a specific ladder, instead of all ladders. Also there are player mine placeholders that report on the mine stats for the mine in which the player is physically located in. The player mine placeholders have no value when the player is not in a mine, and they will change as the player goes from mine to mine. +There are few major types of placeholders in prison: Player, Ranks, Ladders, Mines, and Stats based. With the most recent releases of prison, there have been hybrids added that are a combination of the player placeholders and with mines and ranks. For example there are now ladder based placeholder that allow targeting ranks on a specific ladder, instead of all ladders. Also there are player mine placeholders that report on the mine stats for the mine in which the player is physically located in. The player mine placeholders have no value when the player is not in a mine, and they will change as the player goes from mine to mine. There are also different types of data that are returned in placeholders. Text, numbers, formatted numbers, and bar graphs. @@ -348,31 +418,6 @@ This is mentioned here since these rank command placeholders are not part of all -# Placeholder Commands - - -*Since Prison v3.2.1-alpha.13* - - -There are a few commands within prison that will allow you list placeholders, search for placeholders, and to test random text that includes placeholders. - - -* **/prison placeholders** - - -* **/prison placeholders list** -* **/prison placeholders search** -* **/prison placeholders test** - -* **/prison placeholders reload** - -NOTE: the `/prison placeholders reload` command only reloads and registers the placeholders with the placeholder integrations. This would be required to enable placeholders on a new mine or new ranks or a new ladder that were added since the last server restart. Also if you reload another plugin, such as papi, you will need to reload the plugins, which just re-registers them. - - - -* **/prison version** No longer provides a list of placeholders since it's become too large. - -

Prison Placeholder Command Listing

diff --git a/docs/prison_video_000_video_list.md b/docs/prison_video_000_video_list.md new file mode 100644 index 000000000..013f4784d --- /dev/null +++ b/docs/prison_video_000_video_list.md @@ -0,0 +1,32 @@ +# Prison Video Listings + +
+ +[Prison Documents - Table of Contents](prison_docs_000_toc.md) + + +## Prison Videos - Basic Setup + + +* **[Prison Video - Auto Configure](prison_video_001_auto_configure.md)** + +This video covers the very basics on what you need to do to get your Prison server up and running. Prison has an Auto Configure feature that will setup almost everything you need to run the most basic Prison Server. + + +* **[Prison Video - After Running Auto Configure - Setting Up The Physical Mines](prison_video_002_after_auto_config.md)** + +Prison's Auto Configure configures almost everything needed to run a basic Prison Server, including creating all of the virtual mines with assigned blocks, a mine liner, and links the mines to the proper ranks. This video covers how to place a mine, which takes a virtual mine and turns it in to a physical mine. This video covers the different ways you can place a mine. + + + +## Future Videos Coming Soon + + +* **Prison Video - Mine Liners** + + +* **Prison Video - Adjusting the Size of Your Mines** + + + +
\ No newline at end of file diff --git a/docs/prison_video_001_auto_configure.md b/docs/prison_video_001_auto_configure.md new file mode 100644 index 000000000..5d00bcf9e --- /dev/null +++ b/docs/prison_video_001_auto_configure.md @@ -0,0 +1,108 @@ +# Prison Videos + +
+ +[Prison Documents - Table of Contents](prison_docs_000_toc.md) + +[Prison Video Listings](prison_video_000_video_list.md) + + +# Prison Videos - Basic Setup - Auto Configure + +This video covers the very basics on what you need to do to get your Prison server up and running. Prison has an Auto Configure feature that will setup almost everything you need to run the most basic Prison Server. + + +[video url goes here](url.to.video.com) + + +This document is the transcript for this video. It includes a few screen prints, URLs to resources, and copy and pastable commands. This document will also contain some updates, more information, and clarifications if they are needed. + + +
+ + +#Video Transcript + +> "Hello, this is RoyalBlueRanger and I'm the lead developer of the Prison Plugin. Thank you for your interest in Prison, and for taking the time to view this video. This video will cover the basic setup of a Prison server, which can serve as the foundation of building a uniquely customized server of your own." +> +> +> "If you ever need help with Prison, Please visit our Discord server. You will also find on our Discord server the latest alpha releases, which not only fixes any bugs or issues found, but also contains the new updates that will be included in Prison's next release." +> + +Prison's Discord server: +[![Discord](https://discordapp.com/api/guilds/332602419483770890/widget.png)](https://discord.gg/DCJ3j6r) + +> +> "Prison works great on Spigot 1.8.8 through Spigot 1.17.1. Since it's built on Spigot, it will also work great on other platforms based upon Bukkit and Spigot, such as paper. For the purpose of this demonstration video, I'm using Spigot 1.8.8." +> +> +> "I should point out that this video will not cover the details on how to build a Spigot server; that would be the subject of a future video. For this video it is assumed you have your sever built and it's ready to be started. But before you start your server, let's first go over some of the basic plugins you will need." +> +> +> "All plugins will need to be placed in the **plugins** directory within your Spigot server's directory. If you do not see that directory, go ahead and create it manually, or just start the server for the first time and spigot will create it for you." +> +> +> "Download the following plugins, which will be in **jar** files. You can find the URLs for these resources within this video's description below, and also within Prison's documentation for this video. You will need this plugin, which is of course **Prison**. Plus **EssentialsX**, **Vault**, **LuckPerms**, **WorldEdit**, and **WorldGuard**. Please note for all of these listed plugins, download the latest version that is available, except for Vault, WorldEdit and WorldGuard, of which you must use the version that is designed for your version of Spigot." +> + +(URLs to all mentioned plugins) + * Prison + - Download - https://www.spigotmc.org/resources/prison.1223/ + * EssentialsX + - https://www.spigotmc.org/resources/essentialsx.9089/ + - Download - https://essentialsx.net/downloads.html?branch=stable - Download only the stable release of the "core" component. + * Vault + - Download - 1.13 to 1.17 - https://www.spigotmc.org/resources/vault.34315/ + - Download - 1.8 to 1.11 use v1.5.6 - https://dev.bukkit.org/projects/vault/files + * LuckPerms + - Download - https://www.spigotmc.org/resources/luckperms.28140/ + - Download - https://luckperms.net/ + * WorldEdit + - Download - https://dev.bukkit.org/projects/worldedit/files + * WorldGuard + - Download - https://dev.bukkit.org/projects/worldguard/files + +(Screen prints of basic directories prior to starting the server the first time) + +> +> "Let me show you the directories of this test server. As you can see, in the server's directory is the plugins folder, the eula.txt file that has been set to `true` so the server starts up fully for the first time, and the spigot jar file along with the startup script to start the server. As you can also see in the plugins directory, are the previously listed plugins." +> +> +> +> "Once you have placed all of these plugins in the server's **plugin** directory, you can can then start your server. Let it fully startup. It may be a good idea to review the startup messages to ensure everything loaded successfully. Every time you add a new plugin, or make significant changes, you should review the startup messages in the console if something appears to be misbehaving. With these few plugins, the server should startup with no issues, especially if you are using the correct version of Vault, WorldEdit and WorldGuard." +> +> +> "Before we configure Prison, let me first introduce you to some very basic details about Prison. For the purpose of this video, and when using most Prison commands that generate a lot of text and information, it's best to run them within the server's console, instead of in-game." +> +> +> "First off, it is important to know that all commands within Prison can be reviewed with the command `/prison`. This command lists all of Prison's root commands that are available, including any commands that had a conflict with another plugin's commands when prison was registering it's commands. If a listed command has subcommands, it will be indicated in that list. You can then enter that command to drill down to see the list of subcommands." +> + +(Screen print of `/prison`) + +> +> "Another important feature with Prison, is that Prison's command handler is able to provide detailed information about the command, including all parameters, permissions, and even links to some online documentation. To view the **help**, all you need to do is to add the `help` keyword to any command. For example: `/ranks autoConfigure help` provides detailed information on the autoConfigure command. +> + +(Screen print of `/prison autoConfigure help`) + +> +> "Finally let's get to the purpose of this video, running Prison's autoConfigure command." +> +> "From the server's console, enter the command:" +> `/ranks autoConfigure` +> +> "The command will run for a few seconds, generate a lot of text, which documents all of the configurations that it sets up. Review the generated text in the console if you like." +> +> +> "And that's it. This is the end of the video, which just covered the basics of running the command `/prison autoConfigure`. The Prison server is now using the most common features and settings enabled that will allow your server to work properly." +> +> +> "In the next video we will cover what you need to do in-game to finalize your server setup, which is also very simple. The details that will be covered is configuring WorldGuard to protect your Prison world so players cannot break blocks outside of the mines. It will also explain the various ways you can **set the mines** which will turn the virtual mines in to fully functional physical mines. At the end of that video, we will have a fully functional Prison server." + + +(end of video) + +
+ + diff --git a/docs/prison_video_002_after_auto_config.md b/docs/prison_video_002_after_auto_config.md new file mode 100644 index 000000000..881d37975 --- /dev/null +++ b/docs/prison_video_002_after_auto_config.md @@ -0,0 +1,36 @@ +# Prison Videos + +
+ +[Prison Documents - Table of Contents](prison_docs_000_toc.md) + +[Prison Video Listings](prison_video_000_video_list.md) + + +# Prison Videos - Basic Setup +# After Running Auto Configure - Setting Up The Physical Mines + +This video covers the very basics on what you need to do to get your Prison server up and running. Prison has an Auto Configure feature that will setup almost everything you need to run the most basic Prison Server. + + +[video url goes here](url.to.video.com) + + +This document is the transcript for this video. It includes a few screen prints, URLs to resources, and copy and pastable commands. This document will also contain some updates, more information, and clarifications if they are needed. + + +
+ + +#Video Transcript + +> "Hello, this is RoyalBlueRanger and I'm the lead developer of the Prison Plugin. Thank you for your interest in Prison, and for taking the time to view this video. This video will cover the basic setup of a Prison server, which can serve as the foundation of building a uniquely customized server of your own." +> +> +> "If you ever need help with Prison, Please visit our Discord server. You will also find on our Discord server the latest alpha releases, which not only fixes any bugs or issues found, but also contains the new updates that will be included in Prison's next release." +> +> + (to be determined...) + + +
\ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 7706c53f6..a51d4fbdb 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.2.10 +version=3.2.11 #version=3.2.8.2 #version=3.3.0-alpha.6 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 bbf1b9ae8..2c47766ff 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/Prison.java +++ b/prison-core/src/main/java/tech/mcprison/prison/Prison.java @@ -88,7 +88,10 @@ public class Prison private CommandHandler commandHandler; private SelectionManager selectionManager; private EventBus eventBus; + private LocaleManager localeManager; + private File moduleDataFolder; + // private ItemManager itemManager; private ErrorManager errorManager; private TroubleshootManager troubleshootManager; @@ -135,11 +138,27 @@ public static Prison get() { public LocaleManager getLocaleManager() { if ( this.localeManager == null ) { + this.localeManager = new LocaleManager(this, "lang/core"); } return localeManager; } + /** + * Returns this module's data folder, where all data can be stored. + * It is located in the Prison data folder, and has the name of the module. + * It is automatically generated. + * + * @return The {@link File} representing the data folder. + */ + public File getModuleDataFolder() { + + if ( moduleDataFolder == null ) { + this.moduleDataFolder = Module.setupModuleDataFolder( "core" ); + } + return moduleDataFolder; + } + /** * 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. @@ -503,7 +522,7 @@ public void setStorageSize( long storageSize ) { private boolean initDataFolder() { // Creates the /Prison directory, for core configuration. this.dataFolder = getPlatform().getPluginDirectory(); - return this.dataFolder.exists() || this.dataFolder.mkdir(); + return this.dataFolder.exists() || this.dataFolder.mkdirs(); } private boolean initMetaDatabase() { @@ -634,6 +653,8 @@ public File getDataFolder() { return 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 e28d7cf16..ea12bb5aa 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/PrisonCommand.java +++ b/prison-core/src/main/java/tech/mcprison/prison/PrisonCommand.java @@ -25,6 +25,7 @@ import java.text.DecimalFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.Collections; import java.util.Date; import java.util.List; import java.util.Optional; @@ -55,6 +56,7 @@ import tech.mcprison.prison.troubleshoot.Troubleshooter; import tech.mcprison.prison.util.JumboTextFont; import tech.mcprison.prison.util.PrisonJarReporter; +import tech.mcprison.prison.util.Text; /** * Root commands for managing the platform as a whole, in-game. @@ -345,21 +347,31 @@ else if ( !isBasic ) { if ( getRegisteredPlugins().size() > 0 ) { display.addText(""); display.addText( "&7Registered Plugins: " ); - StringBuilder sb = new StringBuilder(); - for ( String plugin : getRegisteredPlugins() ) { - if ( sb.length() == 0) { - sb.append( ". " ); - sb.append( plugin ); - } else { - sb.append( ", " ); - sb.append( plugin ); - display.addText( sb.toString() ); - sb.setLength( 0 ); - } - } - if ( sb.length() > 0 ) { - display.addText( sb.toString()); - } + + List plugins = getRegisteredPlugins(); + Collections.sort( plugins ); + List plugins2Cols = Text.formatColumnsFromList( plugins, 2 ); + + for ( String rp : plugins2Cols ) { + + display.addText( rp ); + } + +// StringBuilder sb = new StringBuilder(); +// for ( String plugin : getRegisteredPlugins() ) { +// if ( sb.length() == 0) { +// sb.append( ". " ); +// sb.append( plugin ); +// } else { +// sb.append( ", " ); +// sb.append( plugin ); +// display.addText( sb.toString() ); +// sb.setLength( 0 ); +// } +// } +// if ( sb.length() > 0 ) { +// display.addText( sb.toString()); +// } } // This version of plugins does not have all the registered commands: @@ -882,92 +894,96 @@ public void autoFeaturesInformation(CommandSender sender) { afw.isBoolean( AutoFeatures.isAutoManagerEnabled )); - - - display.addText( "&b " ); - display.addText( "&b options.blockBreakEvents.isProcessTokensEnchantExplosiveEvents: %s", - afw.isBoolean( AutoFeatures.isProcessTokensEnchantExplosiveEvents ) ); - display.addText( "&b options.blockBreakEvents.TokenEnchantBlockExplodeEventPriority: %s", - afw.getMessage( AutoFeatures.isProcessTokensEnchantExplosiveEvents ) ); - - display.addText( "&b options.blockBreakEvents.isProcessCrazyEnchantsBlockExplodeEvents: %s", - afw.isBoolean( AutoFeatures.isProcessCrazyEnchantsBlockExplodeEvents ) ); - display.addText( "&b options.blockBreakEvents.CrazyEnchantsBlastUseEventPriority: %s", - afw.getMessage( AutoFeatures.CrazyEnchantsBlastUseEventPriority ) ); - - display.addText( "&b options.blockBreakEvents.isProcessZenchantsBlockExplodeEvents: %s", - afw.isBoolean( AutoFeatures.isProcessZenchantsBlockExplodeEvents ) ); - display.addText( "&b options.blockBreakEvents.ZenchantmentsBlockShredEventPriority: %s", - afw.getMessage( AutoFeatures.ZenchantmentsBlockShredEventPriority ) ); - - display.addText( "&b options.blockBreakEvents.isProcessPrisonEnchantsExplosiveEvents: %s", - afw.isBoolean( AutoFeatures.isProcessPrisonEnchantsExplosiveEvents ) ); - display.addText( "&b options.blockBreakEvents.PrisonEnchantsExplosiveEventPriority: %s", - afw.getMessage( AutoFeatures.PrisonEnchantsExplosiveEventPriority ) ); - - - display.addText( "&b " ); - display.addText( "&b Normal Drops (if auto pickup is off):" ); - display.addText( "&b options.normalDrop.isProcessNormalDropsEvents: %s", - afw.isBoolean( AutoFeatures.handleNormalDropsEvents ) ); - - display.addText( "&b " ); - display.addText( "&7 NOTE: If this is enabled, then lore and perms will override the settings for " ); - display.addText( "&7 pickup, smelt, and block when they are turned off." ); - - - display.addText( "&b " ); - - - display.addText( "&b options.autoPickup.autoPickupEnabled %s", - afw.isBoolean( AutoFeatures.autoPickupEnabled )); - - display.addText( "&b options.autoSmelt.autoSmeltEnabled %s", - afw.isBoolean( AutoFeatures.autoSmeltEnabled )); - display.addText( "&b options.autoBlock.autoBlockEnabled %s", - afw.isBoolean( AutoFeatures.autoBlockEnabled )); - - - - display.addText( "&b " ); - display.addText( "&b options.general.isCalculateDurabilityEnabled %s", - afw.isBoolean( AutoFeatures.isCalculateDurabilityEnabled )); - display.addText( "&b options.general.isCalculateFortuneEnabled %s", - afw.isBoolean( AutoFeatures.isCalculateFortuneEnabled )); - display.addText( "&b options.general.isCalculateAltFortuneOnAllBlocksEnabled %s", - afw.isBoolean( AutoFeatures.isCalculateAltFortuneOnAllBlocksEnabled )); - display.addText( "&b options.general.isCalculateXPEnabled %s", - afw.isBoolean( AutoFeatures.isCalculateXPEnabled )); - display.addText( "&b options.general.givePlayerXPAsOrbDrops %s", - afw.isBoolean( AutoFeatures.givePlayerXPAsOrbDrops )); - display.addText( "&b options.general.fortuneMultiplierMax %s", - afw.getMessage( AutoFeatures.fortuneMultiplierMax )); - - display.addText( "&b " ); - display.addText( "&b options.isProcessTokensEnchantExplosiveEvents %s", - afw.isBoolean( AutoFeatures.isProcessTokensEnchantExplosiveEvents )); - display.addText( "&b options.isProcessCrazyEnchantsBlockExplodeEvents %s", - afw.isBoolean( AutoFeatures.isProcessCrazyEnchantsBlockExplodeEvents )); - display.addText( "&b options.isProcessMcMMOBlockBreakEvents %s", - afw.isBoolean( AutoFeatures.isProcessMcMMOBlockBreakEvents )); - display.addText( "&b " ); - - - display.addText( "&b " ); - display.addText( "&b options.lore.isLoreEnabled %s", - afw.isBoolean( AutoFeatures.isLoreEnabled )); - display.addText( "&b options.lore.loreTrackBlockBreakCount %s", - afw.isBoolean( AutoFeatures.loreTrackBlockBreakCount )); - display.addText( "&b options.lore.loreBlockBreakCountName %s", - afw.getMessage( AutoFeatures.loreBlockBreakCountName )); - - display.addText( "&b options.lore.loreBlockExplosionCountName %s", - afw.getMessage( AutoFeatures.loreBlockExplosionCountName )); - display.addText( "&b options.lore.loreDurabiltyResistance %s", - afw.isBoolean( AutoFeatures.loreDurabiltyResistance )); - display.addText( "&b options.lore.loreDurabiltyResistanceName %s", - afw.getMessage( AutoFeatures.loreDurabiltyResistanceName )); - display.addText( "&b " ); + if ( afw.isBoolean( AutoFeatures.isAutoManagerEnabled ) ) { + + + display.addText( "&b " ); + display.addText( "&b options.blockBreakEvents.applyBlockBreaksThroughSyncTask: %s", + afw.getMessage( AutoFeatures.applyBlockBreaksThroughSyncTask ) ); + + display.addText( "&b options.blockBreakEvents.cancelAllBlockBreakEvents: %s", + afw.getMessage( AutoFeatures.cancelAllBlockBreakEvents ) ); + + display.addText( "&b options.blockBreakEvents.cancelAllBlockEventBlockDrops: %s", + afw.getMessage( AutoFeatures.cancelAllBlockEventBlockDrops ) ); + + + display.addText( "&b options.blockBreakEvents.TokenEnchantBlockExplodeEventPriority: %s", + afw.getMessage( AutoFeatures.TokenEnchantBlockExplodeEventPriority ) ); + + display.addText( "&b options.blockBreakEvents.CrazyEnchantsBlastUseEventPriority: %s", + afw.getMessage( AutoFeatures.CrazyEnchantsBlastUseEventPriority ) ); + + display.addText( "&b options.blockBreakEvents.ZenchantmentsBlockShredEventPriority: %s", + afw.getMessage( AutoFeatures.ZenchantmentsBlockShredEventPriority ) ); + + display.addText( "&b options.blockBreakEvents.PrisonEnchantsExplosiveEventPriority: %s", + afw.getMessage( AutoFeatures.PrisonEnchantsExplosiveEventPriority ) ); + + display.addText( "&b options.blockBreakEvents.ProcessPrisons_ExplosiveBlockBreakEventsPriority: %s", + afw.getMessage( AutoFeatures.ProcessPrisons_ExplosiveBlockBreakEventsPriority ) ); + + + + display.addText( "&b " ); + display.addText( "&b Normal Drops (if auto pickup is off):" ); + display.addText( "&b options.normalDrop.isProcessNormalDropsEvents: %s", + afw.isBoolean( AutoFeatures.handleNormalDropsEvents ) ); + + display.addText( "&b " ); + display.addText( "&7 NOTE: If this is enabled, then lore and perms will override the settings for " ); + display.addText( "&7 pickup, smelt, and block when they are turned off." ); + + + display.addText( "&b " ); + + + display.addText( "&b options.autoPickup.autoPickupEnabled %s", + afw.isBoolean( AutoFeatures.autoPickupEnabled )); + + display.addText( "&b options.autoSmelt.autoSmeltEnabled %s", + afw.isBoolean( AutoFeatures.autoSmeltEnabled )); + display.addText( "&b options.autoBlock.autoBlockEnabled %s", + afw.isBoolean( AutoFeatures.autoBlockEnabled )); + + + + display.addText( "&b " ); + display.addText( "&b options.general.isCalculateDurabilityEnabled %s", + afw.isBoolean( AutoFeatures.isCalculateDurabilityEnabled )); + display.addText( "&b options.general.isCalculateFortuneEnabled %s", + afw.isBoolean( AutoFeatures.isCalculateFortuneEnabled )); + display.addText( "&b options.general.isCalculateAltFortuneOnAllBlocksEnabled %s", + afw.isBoolean( AutoFeatures.isCalculateAltFortuneOnAllBlocksEnabled )); + display.addText( "&b options.general.isCalculateXPEnabled %s", + afw.isBoolean( AutoFeatures.isCalculateXPEnabled )); + display.addText( "&b options.general.givePlayerXPAsOrbDrops %s", + afw.isBoolean( AutoFeatures.givePlayerXPAsOrbDrops )); + display.addText( "&b options.general.fortuneMultiplierMax %s", + afw.getMessage( AutoFeatures.fortuneMultiplierMax )); + + display.addText( "&b " ); + display.addText( "&b options.isProcessMcMMOBlockBreakEvents %s", + afw.isBoolean( AutoFeatures.isProcessMcMMOBlockBreakEvents )); + display.addText( "&b " ); + + + display.addText( "&b " ); + display.addText( "&b options.lore.isLoreEnabled %s", + afw.isBoolean( AutoFeatures.isLoreEnabled )); + display.addText( "&b options.lore.loreTrackBlockBreakCount %s", + afw.isBoolean( AutoFeatures.loreTrackBlockBreakCount )); + display.addText( "&b options.lore.loreBlockBreakCountName %s", + afw.getMessage( AutoFeatures.loreBlockBreakCountName )); + + display.addText( "&b options.lore.loreBlockExplosionCountName %s", + afw.getMessage( AutoFeatures.loreBlockExplosionCountName )); + display.addText( "&b options.lore.loreDurabiltyResistance %s", + afw.isBoolean( AutoFeatures.loreDurabiltyResistance )); + display.addText( "&b options.lore.loreDurabiltyResistanceName %s", + afw.getMessage( AutoFeatures.loreDurabiltyResistanceName )); + display.addText( "&b " ); + } @@ -990,10 +1006,12 @@ public void toggleDebug(CommandSender sender, @Wildcard(join=true) @Arg(name = "targets", def = " ", description = "Optional. Enable or disable a debugging target. " + - "[on, off, targets, jarScan, " + - "testPlayerUtil, testLocale, rankup] " + + "[on, off, targets, selective, jarScan, " + + "testPlayerUtil, testLocale, rankup ] " + "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. " + + "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 " + + "activate debug with the specified targets. " + "jarScan will identify what Java version compiled the class files within the listed jars" ) String targets ) { @@ -1022,7 +1040,7 @@ public void toggleDebug(CommandSender sender, return; } - + // Applies normal and selective targets: Output.get().applyDebugTargets( targets ); String message = "Global Debug Logging is " + (Output.get().isDebug() ? "enabled" : "disabled"); @@ -1041,6 +1059,19 @@ public void toggleDebug(CommandSender sender, } } + Set selectiveDebugTargets = Output.get().getSelectiveDebugTargets(); + + if ( selectiveDebugTargets.size() > 0 ) { + message = ". Selective Debug Targets:"; + sender.sendMessage( message ); + + for ( DebugTarget target : selectiveDebugTargets ) + { + message = String.format( ". . Target: %s", target.name() ); + sender.sendMessage( message ); + } + } + String validTargets = Output.get().getDebugTargetsString(); message = String.format( ". Valid Targets: %s", validTargets ); sender.sendMessage( message ); @@ -1260,7 +1291,7 @@ public void supportSubmitMines(CommandSender sender List files = listFiles( "data_storage/mines/mines/", ".json" ); - + Collections.sort( files ); StringBuilder text = new StringBuilder(); @@ -1473,7 +1504,7 @@ 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. " + - "[blockBreak, traceBlockBreak, chat]" + "[blockBreak, traceBlockBreak, chat, playerInteract]" ) String listener ) { @@ -1502,6 +1533,11 @@ public void supportListenersDump(CommandSender sender, return; } + if ( "playerInteract".equalsIgnoreCase( listener ) ) { + + results = Prison.get().getPlatform().dumpEventListenersPlayerInteractEvents(); + } + if ( results != null ) { for ( String line : results.split( "\n" ) ) { @@ -1512,6 +1548,240 @@ public void supportListenersDump(CommandSender sender, } + + @Command(identifier = "prison tokens balance", + description = "Prison tokens: a player's current balance.", + // aliases = "tokens bal", + permissions = "tokens.bal", + altPermissions = "tokens.bal.others" ) + public void tokensBalance(CommandSender sender, + @Arg(name = "player", def = "", description = "Player to get token balance for. " + + "If player is online this is not required for their own balance. " + + "This is needed if used from console or to get the balance of " + + "another player.") String playerName + ) { + + Player player = getPlayer( sender ); + + // If player is null, then need to use the playerName, so if it's empty, we have a problem: + if ( ( player == null || !player.isOnline() ) && + ( playerName == null || playerName.isEmpty() ) ) { + + String message = "Prison Tokens: A player's name is required when used from console."; + + Output.get().logWarn( message ); + return; + } + else + if ( playerName != null && !playerName.isEmpty() ){ + + if ( !sender.isOp() && + !sender.hasPermission( "tokens.bal.others" ) ) { + String message = "Prison Tokens: You do not have permission to view other " + + "player's balances."; + Output.get().logWarn( message ); + return; + } + + Player tempPlayer = getPlayer( playerName ); + + if ( tempPlayer != null ) { + player = tempPlayer; + } + } + + +// player.getPlayerCache() + + DecimalFormat dFmt = new DecimalFormat("#,##0"); + + long tokens = player.getPlayerCachePlayerData().getTokens(); + + String tokensMsg = dFmt.format( tokens ); + + String message = String.format( "&3%s has %s tokens.", player.getName(), tokensMsg ); + + sender.sendMessage( message ); + } + + @Command(identifier = "prison tokens add", + description = "Prison tokens Admin: an admins tool to give more tokens to a player", + permissions = "tokens.admin.add" ) + public void tokensAdd( CommandSender sender, + @Arg(name = "player", + description = "Player to add the tokens to.") String playerName, + + @Arg(name = "amount", verifiers = "min[1]", + description = "The number of tokens to add to the player's account.") long amount + ) { + + if ( playerName == null || playerName.isEmpty() ) { + + String message = "Prison Tokens: A player's name is required."; + Output.get().logWarn( message ); + return; + } + + DecimalFormat dFmt = new DecimalFormat("#,##0"); + + if ( amount <= 0 ) { + + String message = + String.format( + "Prison Tokens: Invalid amount: '%s'. Must be greater than zero.", + dFmt.format( amount ) ); + Output.get().logWarn( message ); + return; + } + + Player player = getPlayer( playerName ); + + player.getPlayerCachePlayerData().addTokensAdmin( amount ); + + + + String tokens = dFmt.format( player.getPlayerCachePlayerData().getTokens() ); + + String message = String.format( "&3%s now has &7%s &3tokens after adding &7%s&3.", + player.getName(), tokens, dFmt.format( amount ) ); + + // The person adding the tokens, or console: + sender.sendMessage( message ); + + // The player getting the tokens, if they are online: + if ( player.isOnline() && !player.getName().equalsIgnoreCase( sender.getName() ) ) { + + player.sendMessage( message ); + } + } + + @Command(identifier = "prison tokens remove", + description = "Prison tokens Admin: an admins tool to remove tokens from a player. " + + "It is possible to remove more tokens than what the player has, which can " + + "be treated like a debt.", + permissions = "tokens.admin.add" ) + public void tokensRemove( CommandSender sender, + @Arg(name = "player", + description = "Player to remove the tokens from.") String playerName, + + @Arg(name = "amount", verifiers = "min[1]", + description = "The number of tokens to remove from the player's account. " + + "This amount must be positive. ") long amount + ) { + + if ( playerName == null || playerName.isEmpty() ) { + + String message = "Prison Tokens: A player's name is required."; + Output.get().logWarn( message ); + return; + } + + DecimalFormat dFmt = new DecimalFormat("#,##0"); + + if ( amount <= 0 ) { + + String message = + String.format( + "Prison Tokens: Invalid amount: '%s'. Must be greater than zero.", + dFmt.format( amount ) ); + Output.get().logWarn( message ); + return; + } + + Player player = getPlayer( playerName ); + + player.getPlayerCachePlayerData().removeTokensAdmin( amount ); + + + + String tokens = dFmt.format( player.getPlayerCachePlayerData().getTokens() ); + + String message = String.format( "&3%s now has &7%s &3tokens after removing &7%s&3.", + player.getName(), tokens, dFmt.format( amount ) ); + + // The person adding the tokens, or console: + sender.sendMessage( message ); + + // The player getting the tokens, if they are online: + if ( player.isOnline() && !player.getName().equalsIgnoreCase( sender.getName() ) ) { + + player.sendMessage( message ); + } + } + + @Command(identifier = "prison tokens set", + description = "Prison tokens Admin: an admins tool to set number of tokens " + + "for a player to a specific amount. " + + "It is possible to set the tokens to a negavtie amount, which can " + + "be treated like a debt.", + permissions = "tokens.admin.add" ) + public void tokensSet( CommandSender sender, + @Arg(name = "player", + description = "Player to remove the tokens from.") String playerName, + + @Arg(name = "amount", + description = "The number of tokens to set the player's account to. " + + "This amount must amount can be negative. ") long amount + ) { + + if ( playerName == null || playerName.isEmpty() ) { + + String message = "Prison Tokens: A player's name is required."; + Output.get().logWarn( message ); + return; + } + + DecimalFormat dFmt = new DecimalFormat("#,##0"); + + Player player = getPlayer( playerName ); + +// // Set to zero: +// long totalTokens = player.getPlayerCachePlayerData().getTokens(); +// player.getPlayerCachePlayerData().removeTokensAdmin( totalTokens ); + + + player.getPlayerCachePlayerData().setTokensAdmin( amount ); + + + String tokens = dFmt.format( player.getPlayerCachePlayerData().getTokens() ); + + String message = String.format( "&3%s now has &7%s &3tokens.", + player.getName(), tokens ); + + // The person adding the tokens, or console: + sender.sendMessage( message ); + + // The player getting the tokens, if they are online: + if ( player.isOnline() && !player.getName().equalsIgnoreCase( sender.getName() ) ) { + + player.sendMessage( message ); + } + } + + + + /** + *

This function tries to first get the online player, otherwise it + * gets an offline player. Hopefully it always returns a player if the + * have been on the server before. + *

+ * + * @param playerName + * @return + */ + private Player getPlayer( String playerName ) { + Player player = null; + if ( playerName != null && !playerName.trim().isEmpty() ) { + + player = Prison.get().getPlatform().getPlayer( playerName ).orElse( null ); + } + if ( player == null ) { + + player = Prison.get().getPlatform().getOfflinePlayer( playerName ).orElse( null ); + } + return player; + } + // This functionality should not be available in v3.2.1! If someone is still running Prison 2.x.x // then they must first upgrade to 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 d92b99567..64fe470c1 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 @@ -49,28 +49,36 @@ public enum AutoFeatures { blockBreakEvents(options), - blockBreakEventPriority(blockBreakEvents, "LOW"), + // Setting this to true will cancel the block break events (normal prison behavior): + cancelAllBlockBreakEvents(blockBreakEvents, true), + // Setting this to false will not zero out the block drops (normal prison behavior). + // When set to true, it will zero it out so if the block break event is not canceled, + // then it will prevent double drops: + cancelAllBlockEventBlockDrops(blockBreakEvents, false), + + + applyBlockBreaksThroughSyncTask(blockBreakEvents, true), + + + blockBreakEventPriority(blockBreakEvents, "LOW"), - isProcessTokensEnchantExplosiveEvents(blockBreakEvents, false), TokenEnchantBlockExplodeEventPriority(blockBreakEvents, "DISABLED"), - isProcessCrazyEnchantsBlockExplodeEvents(blockBreakEvents, false), CrazyEnchantsBlastUseEventPriority(blockBreakEvents, "DISABLED"), - isProcessZenchantsBlockExplodeEvents(blockBreakEvents, false), ZenchantmentsBlockShredEventPriority(blockBreakEvents, "DISABLED"), - isProcessPrisonEnchantsExplosiveEvents(blockBreakEvents, false), PrisonEnchantsExplosiveEventPriority(blockBreakEvents, "DISABLED"), - isProcessPrisons_ExplosiveBlockBreakEvents(blockBreakEvents, false), - ProcessPrisons_ExplosiveBlockBreakEvents(blockBreakEvents, "DISABLED"), + ProcessPrisons_ExplosiveBlockBreakEventsPriority(blockBreakEvents, "DISABLED"), blockBreakEvents__ReadMe(blockBreakEvents, "Use the following event priorities with the blockBreakEvents: " + "DISABLED, LOWEST, LOW, NORMAL, HIGH, HIGHEST, MONITOR" ), + + general(options), @@ -82,12 +90,40 @@ public enum AutoFeatures { isCalculateXPEnabled(general, true), givePlayerXPAsOrbDrops(general, false), - dropItemsIfInventoryIsFull(general, true), - playSoundIfInventoryIsFull(general, true), - hologramIfInventoryIsFull(general, false), + + + inventory(options), + + + isAutoSellPerBlockBreakEnabled(inventory, false), +// isAutoSellPerBlockBreakInlinedEnabled(general, false), + + isAutoSellIfInventoryIsFull(inventory, true), + + dropItemsIfInventoryIsFull(inventory, true), + + playSoundIfInventoryIsFull(inventory, true), + playSoundIfInventoryIsFullSound(inventory, "block_note_block_pling" ), + playSoundIfInventoryIsFullSoundVolume(inventory, 4.0d ), + playSoundIfInventoryIsFullSoundPitch(inventory, 1.0d ), + playSoundIfInventoryIsFullSound__readme(inventory, + "The name of the sound must be valid for the server platform and " + + "its version, and is case insensitive. To get a list of valid " + + "sounds use the command: " + + "'/prison utils sounds list '. Page is optional. Use page " + + "numbers to see all available sounds. An invalid sound will " + + "default to NOTE_PLING, BLOCK_NOTE_PLING, or BLOCK_NOTE_BLOCK_PLING, " + + "as valid for your server."), + + actionBarMessageIfInventoryIsFull(inventory, true), +// hologramIfInventoryIsFull(general, false), - isAutoSellPerBlockBreakEnabled(general, false), - isAutoSellPerBlockBreakInlinedEnabled(general, false), + + + tokens(options), + + tokensEnabled( tokens, false ), + tokensBlocksPerToken( tokens, 100 ), permissions(options), @@ -232,11 +268,12 @@ public enum AutoFeatures { - debug(options), - isDebugSupressOnBlockBreakEventCancels(debug, false), - isDebugSupressOnTEExplodeEventCancels(debug, false), - isDebugSupressOnCEBlastUseEventCancels(debug, false), - isDebugSupressOnPEExplosiveEventCancels(debug, false) +// debug(options), +// isDebugSupressOnBlockBreakEventCancels(debug, false), +// isDebugSupressOnTEExplodeEventCancels(debug, false), +// isDebugSupressOnCEBlastUseEventCancels(debug, false), +// isDebugSupressOnPEExplosiveEventCancels(debug, false), +// isDebugSupressOnPrisonMinesBlockBreakEventCancels(debug, false) ; @@ -348,6 +385,24 @@ private AutoFeatures(AutoFeatures section, int value) { this.doubleValue = null; this.listValue = new ArrayList<>(); } + private AutoFeatures(AutoFeatures section, double value) { + this.parent = section; + this.isSection = false; + this.isBoolean = false; + this.isMessage = false; + this.isInteger = false; + this.isLong = false; + this.isDouble = true; + this.isStringList = false; + + this.path = section.getKey(); + this.message = null; + this.value = null; + this.intValue = null; + this.longValue = null; + this.doubleValue = value; + this.listValue = new ArrayList<>(); + } private AutoFeatures(AutoFeatures section, NodeType nodeType, String... values ) { this.parent = section; this.isSection = false; @@ -505,13 +560,27 @@ public int getInteger( Map conf ) { IntegerNode intValue = (IntegerNode) conf.get( getKey() ); results = intValue.getValue(); } - else if ( getValue() != null ) { + else if ( getIntValue() != null ) { results = getIntValue(); } return results; } + public double getDouble( Map conf ) { + double results = 0d; + + if ( conf.containsKey(getKey()) && conf.get( getKey() ).isDoubleNode() ) { + DoubleNode doubleValue = (DoubleNode) conf.get( getKey() ); + results = doubleValue.getValue(); + } + else if ( getDoubleValue() != null ) { + results = getDoubleValue(); + } + + return results; + } + public List getStringList( Map conf ) { List results = null; @@ -519,10 +588,14 @@ public List getStringList( Map conf ) { StringListNode list = (StringListNode) conf.get( getKey() ); results = list.getValue(); } - else if ( getValue() != null ) { - results = new ArrayList<>(); + else if ( getListValue() != null && getListValue().size() > 0 ) { + results = getListValue(); } + if ( results == null ) { + results = new ArrayList<>(); + } + return results; } @@ -706,6 +779,10 @@ public int getInteger( AutoFeatures feature ) { return feature.getInteger( getConfig() ); } + public double getDouble( AutoFeatures feature ) { + return feature.getDouble( getConfig() ); + } + public List getFeatureStringList( AutoFeatures feature ) { return feature.getStringList( getConfig() ); @@ -724,7 +801,7 @@ public boolean saveConf() { * initial saving of the data since the original file will not be deleted first. *

* - * @param afConfig + * @param config * @return */ private boolean saveConf( Map config ) { diff --git a/prison-core/src/main/java/tech/mcprison/prison/autofeatures/AutoFeaturesWrapper.java b/prison-core/src/main/java/tech/mcprison/prison/autofeatures/AutoFeaturesWrapper.java index 91a9f0f2c..50f964a89 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/autofeatures/AutoFeaturesWrapper.java +++ b/prison-core/src/main/java/tech/mcprison/prison/autofeatures/AutoFeaturesWrapper.java @@ -48,6 +48,10 @@ public int getInteger( AutoFeatures feature ) { return autoFeaturesConfig.getInteger( feature ); } + public double getDouble( AutoFeatures feature ) { + return autoFeaturesConfig.getDouble( feature ); + } + public List getListString( AutoFeatures feature ) { List results = null; if ( feature.isStringList() ) { diff --git a/prison-core/src/main/java/tech/mcprison/prison/autofeatures/PlayerMessageData.java b/prison-core/src/main/java/tech/mcprison/prison/autofeatures/PlayerMessageData.java new file mode 100644 index 000000000..a839d4d86 --- /dev/null +++ b/prison-core/src/main/java/tech/mcprison/prison/autofeatures/PlayerMessageData.java @@ -0,0 +1,122 @@ +package tech.mcprison.prison.autofeatures; + +import tech.mcprison.prison.autofeatures.PlayerMessaging.MessageType; + +public class PlayerMessageData +{ + private final long startTime; + private long targetEndTime; + + private final MessageType messageType; + private final String message; + private long ticks = 20L; + + private int submitted = 0; + private int hits = -1; + + private int taskId; + + + public PlayerMessageData( MessageType messageType, String message, long ticks ) { + super(); + + this.startTime = System.currentTimeMillis(); + + this.targetEndTime = this.startTime + ( ticks * 50 ); + + this.messageType = messageType; + this.message = message; + this.ticks = ticks; + + this.hits++; + } + + + /** + *

When a new message has been submitted to be displayed to the + * player, this function will check to see if the same message is + * currently being displayed to the player by checking if the + * current system time is greater than targetEndTime. + *

+ * + *

If the current time is less than targetEndTime, then that + * indicates that the message is active and therefore can be + * ignored. + *

+ * + *

If the current time is greater than the targetEndTime then + * that indicates that the message should be displayed. The way + * it is indicated that the message needs to be displayed is + * by setting the jobId to -1, which indicates no job is currently + * running. + *

+ * + * @param ticks + */ + public void addRepeatMessage( long ticks ) { + this.hits++; + + long currentTime = System.currentTimeMillis(); + + // if currentType is greater than targetEndTime then + // needs to submit a new task, which will be indicated + // by setting the jobId to -1. + if ( currentTime > targetEndTime ) { + setTaskId( -1 ); + } + else { + // do nothing... the message is already being displayed + } + } + + public long getStartTime() { + return startTime; + } + + public long getTargetEndTime() { + return targetEndTime; + } + public void setTargetEndTime( long targetEndTime ) { + this.targetEndTime = targetEndTime; + } + + public MessageType getMessageType() { + return messageType; + } + + public String getMessage() + { + return message; + } + + public long getTicks() { + return ticks; + } + public void setTicks( long ticks ) { + this.ticks = ticks; + } + + public int getSubmitted() { + return submitted; + } + public void setSubmitted( int submitted ) { + this.submitted = submitted; + } + + public int getHits() { + return hits; + } + public void setHits( int hits ) { + this.hits = hits; + } + + public int getTaskId() { + return taskId; + } + public void setTaskId( int taskId ) { + this.taskId = taskId; + + this.submitted++; + } + +} diff --git a/prison-core/src/main/java/tech/mcprison/prison/autofeatures/PlayerMessaging.java b/prison-core/src/main/java/tech/mcprison/prison/autofeatures/PlayerMessaging.java new file mode 100644 index 000000000..d23fea22c --- /dev/null +++ b/prison-core/src/main/java/tech/mcprison/prison/autofeatures/PlayerMessaging.java @@ -0,0 +1,70 @@ +package tech.mcprison.prison.autofeatures; + +import java.util.TreeMap; + +public class PlayerMessaging +{ + + private final TreeMap> messages; + + + public enum MessageType { + title, + actionBar; + } + + public PlayerMessaging() { + + this.messages = new TreeMap<>(); + + // Preload all the message types and setup their TreeMaps + for ( MessageType mType : MessageType.values() ) { + + getMessages().put( mType, new TreeMap<>() ); + } + + } + + /** + *

This function adds a message to the player's PlayerCached object. It uses the + * default duration of 40 ticks (2 seconds). + *

+ * + *

If the same message is active, then the message will not be submitted. + *

+ * + * @param messageType + * @param message + * @return + */ + public PlayerMessageData addMessage( MessageType messageType, String message ) { + + return addMessage( messageType, message, 40L ); + } + + public PlayerMessageData addMessage( MessageType messageType, String message, long ticks ) { + PlayerMessageData pmData = null; + + TreeMap messagesOfType = getMessages().get( messageType ); + + if ( messagesOfType.containsKey( message ) ) { + pmData = messagesOfType.get( message ); + + // A message that was sent to the player before is requested to be sent again: + pmData.addRepeatMessage( ticks ); + } + else { + + // This message has not be sent to the player before: + pmData = new PlayerMessageData( messageType, message, ticks ); + messagesOfType.put( message, pmData ); + } + + return pmData; + } + + public TreeMap> getMessages() { + return messages; + } + +} 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 new file mode 100644 index 000000000..ba9a8aad6 --- /dev/null +++ b/prison-core/src/main/java/tech/mcprison/prison/bombs/MineBombData.java @@ -0,0 +1,427 @@ +package tech.mcprison.prison.bombs; + +import java.util.ArrayList; +import java.util.List; +import java.util.TreeSet; + +import tech.mcprison.prison.internal.block.Block; +import tech.mcprison.prison.internal.block.PrisonBlock; + +public class MineBombData { + + private String name; + + private String description; + + + /** + *

The 'bombItemId' is first line of the bomb's item lore, and + * it really needs to be unique and not match any other bomb's id. + *

+ */ + private String bombItemId; + private List lore; + + + /** + *

The String value that is shown over the placed item when the bomb is + * placed. Null or empty will show none. The placeholder '{name}' will show + * the bomb's name. + *

+ */ + private String nameTag; + + /** + *

The String name of an XMaterial item to use as the "bomb". + *

+ */ + private String itemType; + + /* + *

A transient reference to the actual XMaterial item that is used + * for the bomb. This is converted from the String itemType. + *

+ */ + private transient PrisonBlock item; + + /** + *

The radius identifies how large the blast should be as + * expressed in a radius. Generally this applies to a sphere or + * a circle or disk, but can also apply to other shapes such as + * cubes. + *

+ * + *

The radius is always based upon a center block, plus the radius. + * Therefore a radius of 1 will result in a sphere with a diameter of + * three (1 block for the center, and then 1 additional block on each + * side). The calculated diameter can never be even, and the actual + * blast size will appear to be larger than this specified radius due + * to the starting inner block. + *

+ * + */ + private int radius = 1; + + + /** + *

Some shapes may require an inner radius, such as a hollow sphere or + * a torus. This is ignored for all other shapes. + *

+ */ + private int radiusInner = 0; + + + /** + *

Some shapes may require a height, such as a cylinder or a cone. + * Even if the shape is laying on it's side, the height will still + * apply in other planes and not just up and down. + * This is ignored for all other shapes. + *

+ */ + private int height = 0; + + /** + *

The chance of complete removal. So if the explosion includes + * 100 blocks, but the chance is only 50%, each block will be given + * a 50% chance to be included from the explosion block list. + *

+ */ + private double removalChance = 100.0d; // 100.0 % chance + + + private String explosionShape; + + + private String toolInHandName; + + private int toolInHandFortuneLevel = 0; + + + private int fuseDelayTicks = 5 * 20; // 5 seconds + + private int cooldownTicks = 5 * 20; // 5 seconds + + + /** + *

This is the number of ticks after the explosion occurs to when + * the armor stand is removed. This is preferred since bukkit is + * managing the removal of the armor stand, which will help prevent it + * from not being removed, which will create a zombie. + *

+ * + *

This value will be added to fuseDelayTicks to setup the removal + * time that will be used when placing the armor stand. + *

+ */ + private int itemRemovalDelayTicks = 5; // 0.25 seconds + + + /** + *

On spigot versions that support it, the bomb, when placed, will glow. + * Was introduced with Minecraft 1.9. Applies only to Entities, of which + * dropped items may be considered an entity? + *

+ */ + private boolean glowing = false; + + + /** + *

Identifies if the item is effected by gravity. + * Gravity was introduced with Minecraft 1.9. + *

+ */ + private boolean gravity = true; + + + /** + *

This autosell will force the results of an explosion to autosell even when autosell + * is disabled on the server's auto features. This is almost a requirement for large + * explosions, especially if an unsafe fortune enchantment is being used. + *

+ */ + private boolean autosell = false; + + + /** + *

Internal just to indicated if a mine bomb is activated or not. + * This has not purpose if used in a save file. + *

+ */ + private transient boolean activated = false; + + + + private TreeSet soundEffects; + + private TreeSet visualEffects; + + private Block placedBombBlock; + + + public MineBombData() { + super(); + + + this.soundEffects = new TreeSet<>( new MineBombEffectsData() ); + this.visualEffects = new TreeSet<>( new MineBombEffectsData() ); + } + + + public MineBombData( String name, String itemType, String explosionShape, + int radius, String... lores ) { + this(); + + this.name = name; + this.itemType = itemType; + + this.nameTag = "{name}"; + + this.explosionShape = explosionShape; + this.radius = radius; + + this.bombItemId = "PrisonMineBomb: " + name; + + this.lore = new ArrayList<>(); + + if ( lores != null ) { + for ( String l : lores ) { + this.lore.add( l ); + } + } + + this.toolInHandName = null; + this.toolInHandFortuneLevel = 0; + + this.removalChance = 100.0d; + + this.fuseDelayTicks = 5 * 20; + + this.cooldownTicks = 30 * 20; + + this.itemRemovalDelayTicks = 5; + + this.glowing = false; + this.gravity = true; + + } + + + public MineBombData clone() { + MineBombData cloned = new MineBombData( getName(), getItemType(), getExplosionShape(), + getRadius() ); + + cloned.setBombItemId( getBombItemId() ); + + cloned.setDescription( getDescription() ); + + cloned.setNameTag( getNameTag() ); + + cloned.setToolInHandName( getToolInHandName() ); + cloned.setToolInHandFortuneLevel( getToolInHandFortuneLevel() ); + + cloned.setRadiusInner( getRadiusInner() ); + cloned.setHeight( getHeight() ); + + cloned.setRemovalChance( getRemovalChance() ); + cloned.setFuseDelayTicks( getFuseDelayTicks() ); + cloned.setCooldownTicks( getCooldownTicks() ); + + cloned.setGlowing( isGlowing() ); + cloned.setGravity( isGravity() ); + + cloned.setItemRemovalDelayTicks( getItemRemovalDelayTicks() ); + + cloned.setAutosell( isAutosell() ); + cloned.setActivated( isActivated() ); + + + for ( String l : getLore() ) { + cloned.getLore().add( l ); + } + + + for ( MineBombEffectsData soundEffect : getSoundEffects() ) + { + cloned.getSoundEffects().add( soundEffect.clone() ); + } + + + for ( MineBombEffectsData visualEffect : getVisualEffects() ) + { + cloned.getVisualEffects().add( visualEffect.clone() ); + } + + + return cloned; + } + + public String getName() { + return name; + } + public void setName( String name ) { + this.name = name; + } + + public String getNameTag() { + return nameTag; + } + public void setNameTag( String nameTag ) { + this.nameTag = nameTag; + } + + public String getDescription() { + return description; + } + public void setDescription( String description ) { + this.description = description; + } + + public String getBombItemId() { + return bombItemId; + } + public void setBombItemId( String bombItemId ) { + this.bombItemId = bombItemId; + } + + public List getLore() { + return lore; + } + public void setLore( List lore ) { + this.lore = lore; + } + + public String getItemType() { + return itemType; + } + public void setItemType( String itemType ) { + this.itemType = itemType; + } + + public PrisonBlock getItem() { + return item; + } + public void setItem( PrisonBlock item ) { + this.item = item; + } + + public int getRadius() { + return radius; + } + public void setRadius( int radius ) { + this.radius = radius; + } + + public int getRadiusInner() { + return radiusInner; + } + public void setRadiusInner( int radiusInner ) { + this.radiusInner = radiusInner; + } + + public int getHeight() { + return height; + } + public void setHeight( int height ) { + this.height = height; + } + + public double getRemovalChance() { + return removalChance; + } + public void setRemovalChance( double removalChance ) { + this.removalChance = removalChance; + } + + public String getExplosionShape() { + return explosionShape; + } + public void setExplosionShape( String explosionShape ) { + this.explosionShape = explosionShape; + } + + public String getToolInHandName() { + return toolInHandName; + } + public void setToolInHandName( String toolInHandName ) { + this.toolInHandName = toolInHandName; + } + + public int getToolInHandFortuneLevel() { + return toolInHandFortuneLevel; + } + public void setToolInHandFortuneLevel( int toolInHandFortuneLevel ) { + this.toolInHandFortuneLevel = toolInHandFortuneLevel; + } + + public int getFuseDelayTicks() { + return fuseDelayTicks; + } + public void setFuseDelayTicks( int fuseDelayTicks ) { + this.fuseDelayTicks = fuseDelayTicks; + } + + public int getCooldownTicks() { + return cooldownTicks; + } + public void setCooldownTicks( int cooldownTicks ) { + this.cooldownTicks = cooldownTicks; + } + + public boolean isGlowing() { + return glowing; + } + public void setGlowing( boolean glowing ) { + this.glowing = glowing; + } + + public boolean isGravity() { + return gravity; + } + public void setGravity( boolean gravity ) { + this.gravity = gravity; + } + + public int getItemRemovalDelayTicks() { + return itemRemovalDelayTicks; + } + public void setItemRemovalDelayTicks( int itemRemovalDelayTicks ) { + this.itemRemovalDelayTicks = itemRemovalDelayTicks; + } + + public boolean isAutosell() { + return autosell; + } + public void setAutosell( boolean autosell ) { + this.autosell = autosell; + } + + public boolean isActivated() { + return activated; + } + public void setActivated( boolean activated ) { + this.activated = activated; + } + + public TreeSet getSoundEffects() { + return soundEffects; + } + public void setSoundEffects( TreeSet soundEffects ) { + this.soundEffects = soundEffects; + } + + public TreeSet getVisualEffects() { + return visualEffects; + } + public void setVisualEffects( TreeSet visualEffects ) { + this.visualEffects = visualEffects; + } + + public Block getPlacedBombBlock() { + return placedBombBlock; + } + public void setPlacedBombBlock( Block placedBombBlock ) { + this.placedBombBlock = placedBombBlock; + } + + +} diff --git a/prison-core/src/main/java/tech/mcprison/prison/bombs/MineBombEffectsData.java b/prison-core/src/main/java/tech/mcprison/prison/bombs/MineBombEffectsData.java new file mode 100644 index 000000000..21e9a5b44 --- /dev/null +++ b/prison-core/src/main/java/tech/mcprison/prison/bombs/MineBombEffectsData.java @@ -0,0 +1,147 @@ +package tech.mcprison.prison.bombs; + +import java.util.Comparator; + +/** + *

The effectsName that is used should be one of the following, or it will not work. + * These effects depend upon the server's version too. If what you enter does not work, + * then try something else what would be compatible. It's important to test to make + * sure.

+ * + *

For Sound Effects: + *

+ * + * + * + *

For Visual Effects: + *

+ * https://hub.spigotmc.org/javadocs/spigot/org/bukkit/Particle.html + * + */ +public class MineBombEffectsData + implements Comparator, + Comparable +{ + + private String effectName; + + private EffectState effectState; + + private int offsetTicks; + + private float volumne; + private float pitch; + + public enum EffectState { + placed, + explode, + finished; + } + + protected MineBombEffectsData() { + super(); + } + + public MineBombEffectsData( String effectName, EffectState effectState, + int offsetTicks ) { + super(); + + this.effectName = effectName; + this.effectState = effectState; + this.offsetTicks = offsetTicks; + + this.volumne = 1.0f; + this.pitch = 1.0f; + } + + + public MineBombEffectsData( String effectName, EffectState effectState, + int offsetTicks, float volume, float pitch ) { + this( effectName, effectState, offsetTicks ); + + this.volumne = volume; + this.pitch = pitch; + } + + + public MineBombEffectsData clone() { + return new MineBombEffectsData( getEffectName(), getEffectState(), getOffsetTicks(), + getVolumne(), getPitch() ); + } + + @Override + public String toString() { + return getEffectName() + " (state: " + getEffectState().name() + " offset: " + getOffsetTicks() + + " ticks v: " + getVolumne() + " p: " + getPitch() + ")"; + } + public String toStringShort() { + return getEffectName() + " (state: " + getEffectState().name() + " offset: " + getOffsetTicks() + + " ticks)"; + } + + @Override + public int compare( MineBombEffectsData o1, MineBombEffectsData o2 ) + { + int results = o1.getEffectState().compareTo( o2.getEffectState() ); + + if ( results == 0 ) { + results = Integer.compare( o1.getOffsetTicks(), o2.getOffsetTicks() ); + + if ( results == 0 ) { + results = o1.getEffectName().compareTo( o2.getEffectName() ); + } + } + return results; + } + + @Override + public int compareTo( MineBombEffectsData o ) + { + return compare( this, o ); + } + + + public String getEffectName() { + return effectName; + } + public void setEffectName( String effectName ) { + this.effectName = effectName; + } + + public EffectState getEffectState() { + return effectState; + } + public MineBombEffectsData setEffectState( EffectState effectState ) { + this.effectState = effectState; + + return this; + } + + public int getOffsetTicks() { + return offsetTicks; + } + public MineBombEffectsData setOffsetTicks( int offsetTicks ) { + this.offsetTicks = offsetTicks; + + return this; + } + + public float getVolumne() { + return volumne; + } + public MineBombEffectsData setVolumne( float volumne ) { + this.volumne = volumne; + + return this; + } + + public float getPitch() { + return pitch; + } + public MineBombEffectsData setPitch( float pitch ) { + this.pitch = pitch; + + return this; + } + +} diff --git a/prison-core/src/main/java/tech/mcprison/prison/bombs/MineBombs.java b/prison-core/src/main/java/tech/mcprison/prison/bombs/MineBombs.java new file mode 100644 index 000000000..8cbf61ccb --- /dev/null +++ b/prison-core/src/main/java/tech/mcprison/prison/bombs/MineBombs.java @@ -0,0 +1,565 @@ +package tech.mcprison.prison.bombs; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import tech.mcprison.prison.bombs.MineBombEffectsData.EffectState; +import tech.mcprison.prison.file.JsonFileIO; +import tech.mcprison.prison.output.Output; +import tech.mcprison.prison.util.Location; +import tech.mcprison.prison.util.Text; + +public class MineBombs +{ + public static final String MINE_BOMBS_FILE_NAME = "mineBombsConfig.json"; + public static final String MINE_BOMBS_PATH_NAME = "module_conf/mines"; + + private static MineBombs instance; + + private MineBombsConfigData configData; + + + + public enum ExplosionShape { + + ring_x, + ring_y, + ring_z, + + disk_x, + disk_y, + disk_z, + + cube, + + sphere, + sphereHollow + ; + + public static ExplosionShape fromString( String shape ) { + ExplosionShape results = ExplosionShape.sphere; + + if ( shape != null ) { + for ( ExplosionShape xShape : values() ) + { + if ( xShape.name().equalsIgnoreCase( shape ) ) { + results = xShape; + break; + } + } + } + + return results; + } + + public static List asList() + { + List results = new ArrayList<>(); + + for ( ExplosionShape shape : values() ) + { + results.add( shape.name() ); + } + + return results; + } + } + + public enum ExplosionOrientation { + x_axis, + y_axis, + z_axis, + + full + } + + private MineBombs() { + super(); + + this.configData = new MineBombsConfigData(); + + loadConfigJson(); + } + + public static MineBombs getInstance() { + if ( instance == null ) { + synchronized ( MineBombs.class ) { + if ( instance == null ) { + + instance = new MineBombs(); + } + } + } + return instance; + } + + /** + *

This finds a bomb with the given name, and returns a clone. The clone is + * important since individual instances will set the isActivated() variable to + * true if the bomb is active. If it's activated, then that indicates the + * bomb will be used and the bomb was removed from the player's inventory. + *

+ * + * @param bombName + * @return + */ + public MineBombData findBomb( String bombName ) { + MineBombData bombOriginal = null; + + if ( bombName != null ) { + + bombOriginal = getConfigData().getBombs().get( bombName.toLowerCase() ); + } + + return bombOriginal.clone(); + } + + public void saveConfigJson() { + + JsonFileIO fio = new JsonFileIO( null, null ); + + File configFile = getConfigFile( fio ); + + fio.saveJsonFile( configFile, getConfigData() ); + + } + + public File getConfigFile( JsonFileIO jsonFileIO ) { + + File path = new File( jsonFileIO.getProjectRootDiretory(), MINE_BOMBS_PATH_NAME ); + path.mkdirs(); + File configFile = new File( path, MINE_BOMBS_FILE_NAME ); + + return configFile; + } + + public void loadConfigJson() { + JsonFileIO fio = new JsonFileIO( null, null ); + + File configFile = getConfigFile( fio ); + + if ( !configFile.exists() ) { + setupDefaultMineBombData(); + } + + else { + + MineBombsConfigData configs = + (MineBombsConfigData) fio.readJsonFile( configFile, getConfigData() ); + + if ( configs != null ) { + setConfigData( configs ); + + if ( configs.getDataFormatVersion() < + MineBombsConfigData.MINE_BOMB_DATA_FORMAT_VERSION ) { + + // Need to update the format version then save a new copy of the configs. + + // first backup the old file by renaming it: + + int oldVersion = configs.getDataFormatVersion(); + + String backupTag = "ver_" + oldVersion; + File backupFile = fio.getBackupFile( configFile, backupTag, "json" ); + + boolean renamed = configFile.renameTo( backupFile ); + + if ( renamed ) { + configs.setDataFormatVersion( MineBombsConfigData.MINE_BOMB_DATA_FORMAT_VERSION ); + + fio.saveJsonFile( configFile, configs ); + + Output.get().logInfo( String.format( + "MineBomb Data Format was updated and saved: Loaded v%d and updated to v%d. " + + "The old data is archived as: [%s]", + oldVersion, configs.getDataFormatVersion(), + backupFile.getName() +// backupFile.getAbsolutePath() + ) ); + } + + + } + } + + } + } + + + public List calculateCylinder( Location loc, int radius, boolean hollow ) { + List results = new ArrayList<>(); + + + + return results; + } + + public List calculateSphere( Location loc, int radius, boolean hollow ) { + + return calculateSphere( loc, radius, hollow, 0, ExplosionOrientation.full ); + } + + public List calculateSphere( Location loc, int radius, boolean hollow, + int radiusInner ) { + return calculateSphere( loc, radius, hollow, radiusInner, ExplosionOrientation.full ); + } + + + + public List calculateSphere( Location loc, int radius, boolean hollow, + int radiusInner, ExplosionOrientation explosionOrientation ) { + List results = new ArrayList<>(); + + if ( loc != null && radius > 0 ) { + int cenX = loc.getBlockX(); + int cenY = loc.getBlockY(); + int cenZ = loc.getBlockZ(); + + boolean xOri = explosionOrientation == ExplosionOrientation.x_axis; + boolean yOri = explosionOrientation == ExplosionOrientation.y_axis; + boolean zOri = explosionOrientation == ExplosionOrientation.z_axis; + + double radiusSqr = radius * radius; + + // If the radiusInner is not specified (== 0), then subtract one from radius. + double radiusHSqr = radiusInner == 0 ? + ((radius - 1) * (radius - 1)) : + (radiusInner * radiusInner); + + for ( int x = (xOri ? cenX : cenX - radius) ; x <= (xOri ? cenX : cenX + radius) ; x++ ) { + double xSqr = (cenX - x) * (cenX - x); + + for ( int y = (yOri ? cenY : cenY - radius) ; y <= (yOri ? cenY : cenY + radius) ; y++ ) { + double ySqr = (cenY - y) * (cenY - y); + + for ( int z = (zOri ? cenZ : cenZ - radius) ; z <= (zOri ? cenZ : cenZ + radius) ; z++ ) { + double zSqr = (cenZ - z) * (cenZ - z); + + double distSqr = xSqr + ySqr + zSqr; + + if ( distSqr <= radiusSqr && + (!hollow || + hollow && distSqr >= radiusHSqr )) { + + Location l = new Location( loc.getWorld(), x, y, z ); + results.add( l ); + } + } + } + } + } + return results; + } + + + public List calculateCube( Location loc, int radius ) { + List results = new ArrayList<>(); + + if ( loc != null && radius > 0 ) { + int cenX = loc.getBlockX(); + int cenY = loc.getBlockY(); + int cenZ = loc.getBlockZ(); + + for ( int x = cenX - radius ; x <= cenX + radius ; x++ ) { + for ( int y = cenY + 1; y >= 0 && y >= cenY + 1 - (radius * 2) ; y-- ) { + for ( int z = cenZ - radius ; z <= cenZ + radius ; z++ ) { + + Location l = new Location( loc.getWorld(), x, y, z ); + results.add( l ); + + } + } + } + } + return results; + } + + + @SuppressWarnings( "unused" ) + public void setupDefaultMineBombData() + { + if ( getConfigData().getBombs().size() == 0 ) { + +// XMaterial.WOODEN_PICKAXE; +// XMaterial.STONE_PICKAXE; +// XMaterial.IRON_PICKAXE; +// XMaterial.GOLDEN_PICKAXE; +// XMaterial.DIAMOND_PICKAXE; +// XMaterial.NETHERITE_PICKAXE; + + MineBombEffectsData mbeSound01 = new MineBombEffectsData( "ENTITY_CREEPER_PRIMED", EffectState.placed, 0 ); + MineBombEffectsData mbeSound02 = new MineBombEffectsData( "CAT_HISS", EffectState.placed, 0 ); + + MineBombEffectsData mbeSound03 = new MineBombEffectsData( "ENTITY_GENERIC_EXPLODE", EffectState.explode, 0 ); + MineBombEffectsData mbeSound04 = new MineBombEffectsData( "ENTITY_DRAGON_FIREBALL_EXPLODE", EffectState.explode, 0 ); + + // Does not work with spigot 1.8.x: + MineBombEffectsData mbeExplode01 = new MineBombEffectsData( "FIREWORKS_SPARK", EffectState.placed, 0 ); + // Does not work with spigot 1.8.x: + MineBombEffectsData mbeExplode02 = new MineBombEffectsData( "BUBBLE_COLUMN_UP", EffectState.placed, 0 ); + MineBombEffectsData mbeExplode03 = new MineBombEffectsData( "ENCHANTMENT_TABLE", EffectState.placed, 0 ); + +// MineBombEffectsData mbeExplode05 = new MineBombEffectsData( "END_ROD", EffectState.placed, 0 ); + MineBombEffectsData mbeExplode04 = new MineBombEffectsData( "FLAME", EffectState.placed, 0 ); + // Does not work with spigot 1.8.x: + MineBombEffectsData mbeExplode08 = new MineBombEffectsData( "DRAGON_BREATH", EffectState.placed, 0 ); + + MineBombEffectsData mbeExplode06a = new MineBombEffectsData( "SMOKE", EffectState.placed, 0 ); + // Does not work with spigot 1.8.x: + MineBombEffectsData mbeExplode06 = new MineBombEffectsData( "SMOKE_NORMAL", EffectState.placed, 0 ); + // Does not work with spigot 1.8.x: + MineBombEffectsData mbeExplode07 = new MineBombEffectsData( "SMOKE_LARGE", EffectState.placed, 0 ); + + MineBombEffectsData mbeExplode10 = new MineBombEffectsData( "EXPLOSION_NORMAL", EffectState.explode, 0 ); + MineBombEffectsData mbeExplode11 = new MineBombEffectsData( "EXPLOSION_LARGE", EffectState.explode, 0 ); + // Does not work with spigot 1.8.x: + MineBombEffectsData mbeExplode12 = new MineBombEffectsData( "EXPLOSION_HUGE", EffectState.explode, 0 ); + + + { + MineBombData mbd = new MineBombData( + "SmallBomb", "brewing_stand", ExplosionShape.sphere.name(), 2, "Small Mine Bomb" ); + mbd.setToolInHandName( "DIAMOND_PICKAXE" ); + mbd.setToolInHandFortuneLevel( 0 ); + mbd.setDescription("A small mine bomb made with some chemicals and a brewing stand."); + + mbd.getSoundEffects().add( mbeSound01.clone() ); + mbd.getSoundEffects().add( mbeSound02.clone().setOffsetTicks( 30 ) ); + mbd.getSoundEffects().add( mbeSound03.clone() ); + + mbd.getVisualEffects().add( mbeExplode04.clone() ); + mbd.getVisualEffects().add( mbeExplode03.clone().setOffsetTicks( 30 ) ); + + mbd.getVisualEffects().add( mbeExplode06a.clone() ); + mbd.getVisualEffects().add( mbeExplode10.clone() ); + mbd.getVisualEffects().add( mbeExplode06.clone() ); + + mbd.setCooldownTicks( 60 ); + + getConfigData().getBombs().put( mbd.getName().toLowerCase(), mbd ); + + } + + { + MineBombData mbd = new MineBombData( + "MediumBomb", "firework_rocket", ExplosionShape.sphere.name(), 5, "Medium Mine Bomb" ); + mbd.setDescription("A medium mine bomb made from leftover fireworks, " + + "but supercharged with a strange green glowing liquid."); + mbd.setToolInHandName( "DIAMOND_PICKAXE" ); + mbd.setToolInHandFortuneLevel( 3 ); + + mbd.getSoundEffects().add( mbeSound01.clone() ); + mbd.getSoundEffects().add( mbeSound02.clone().setOffsetTicks( 30 ) ); + mbd.getSoundEffects().add( mbeSound03.clone() ); + + mbd.getVisualEffects().add( mbeExplode04.clone() ); + mbd.getVisualEffects().add( mbeExplode03.clone().setOffsetTicks( 30 ) ); + + mbd.getVisualEffects().add( mbeExplode10.clone() ); + mbd.getVisualEffects().add( mbeExplode06.clone() ); + + mbd.setCooldownTicks( 60 ); + + getConfigData().getBombs().put( mbd.getName().toLowerCase(), mbd ); + + } + + { + MineBombData mbd = new MineBombData( + "LargeBomb", "tnt", ExplosionShape.sphereHollow.name(), 12, "Large Mine Bomb" ); + mbd.setRadiusInner( 3 ); + mbd.setDescription("A large mine bomb made from TNT with some strange parts " + + "that maybe be described as alien technology."); + mbd.setToolInHandName( "DIAMOND_PICKAXE" ); + mbd.setToolInHandFortuneLevel( 3 ); + + mbd.getSoundEffects().add( mbeSound01.clone() ); + mbd.getSoundEffects().add( mbeSound02.clone().setOffsetTicks( 30 ) ); + mbd.getSoundEffects().add( mbeSound03.clone().setVolumne( 2.0f ) ); + + mbd.getVisualEffects().add( mbeExplode04.clone() ); + mbd.getVisualEffects().add( mbeExplode03.clone().setOffsetTicks( 30 ) ); + + mbd.getVisualEffects().add( mbeExplode10.clone() ); + mbd.getVisualEffects().add( mbeExplode06.clone() ); + mbd.getVisualEffects().add( mbeExplode06a.clone() ); + + mbd.setCooldownTicks( 60 ); + + getConfigData().getBombs().put( mbd.getName().toLowerCase(), mbd ); + } + + { + MineBombData mbd = new MineBombData( + "OofBomb", "tnt_minecart", ExplosionShape.sphereHollow.name(), 19, "Oof Mine Bomb" ); + mbd.setRadiusInner( 3 ); + mbd.setDescription("An oof-ably large mine bomb made with a minecart heaping with TNT. " + + "Unlike the large mine bomb, this one obviously is built with alien technology."); + + mbd.setToolInHandName( "GOLDEN_PICKAXE" ); + mbd.setToolInHandFortuneLevel( 13 ); + + mbd.getSoundEffects().add( mbeSound01.clone() ); + mbd.getSoundEffects().add( mbeSound02.clone().setOffsetTicks( 10 ).setVolumne( 0.25f ).setPitch( 0.25f ) ); + mbd.getSoundEffects().add( mbeSound02.clone().setOffsetTicks( 20 ).setVolumne( 0.5f ).setPitch( 0.5f ) ); + mbd.getSoundEffects().add( mbeSound02.clone().setOffsetTicks( 30 ).setVolumne( 1.0f ).setPitch( 0.75f ) ); + mbd.getSoundEffects().add( mbeSound02.clone().setOffsetTicks( 40 ).setVolumne( 2.0f ).setPitch( 1.5f ) ); + mbd.getSoundEffects().add( mbeSound02.clone().setOffsetTicks( 50 ).setVolumne( 5.0f ).setPitch( 2.5f ) ); + + mbd.getSoundEffects().add( mbeSound03.clone().setOffsetTicks( 0 ).setVolumne( 3.0f ) ); + mbd.getSoundEffects().add( mbeSound04.clone().setOffsetTicks( 5 ).setVolumne( 1.5f ) ); + mbd.getSoundEffects().add( mbeSound03.clone().setOffsetTicks( 10 ).setVolumne( 2.5f ) ); + mbd.getSoundEffects().add( mbeSound04.clone().setOffsetTicks( 15 ).setVolumne( 1.0f ) ); + mbd.getSoundEffects().add( mbeSound03.clone().setOffsetTicks( 20 ).setVolumne( 2.0f ) ); + mbd.getSoundEffects().add( mbeSound04.clone().setOffsetTicks( 25 ).setVolumne( 0.75f ) ); + mbd.getSoundEffects().add( mbeSound03.clone().setOffsetTicks( 30 ).setVolumne( 1.5f ) ); + mbd.getSoundEffects().add( mbeSound04.clone().setOffsetTicks( 35 ).setVolumne( 0.55f ) ); + mbd.getSoundEffects().add( mbeSound03.clone().setOffsetTicks( 40 ).setVolumne( 1.0f ) ); + mbd.getSoundEffects().add( mbeSound04.clone().setOffsetTicks( 45 ).setVolumne( 0.25f ) ); + mbd.getSoundEffects().add( mbeSound03.clone().setOffsetTicks( 50 ).setVolumne( 0.5f ) ); + mbd.getSoundEffects().add( mbeSound04.clone().setOffsetTicks( 55 ).setVolumne( 0.15f ) ); + + + mbd.getVisualEffects().add( mbeExplode06.clone() ); + mbd.getVisualEffects().add( mbeExplode06a.clone() ); + mbd.getVisualEffects().add( mbeExplode03.clone() ); + mbd.getVisualEffects().add( mbeExplode12.clone() ); + mbd.getVisualEffects().add( mbeExplode12.clone().setOffsetTicks( 30 ) ); + mbd.getVisualEffects().add( mbeExplode12.clone().setOffsetTicks( 60 ) ); + mbd.getVisualEffects().add( mbeExplode07.clone().setOffsetTicks( 60 ) ); + mbd.getVisualEffects().add( mbeExplode08.clone().setOffsetTicks( 90 ) ); + + mbd.getVisualEffects().add( mbeExplode10.clone() ); + mbd.getVisualEffects().add( mbeExplode06.clone().setOffsetTicks( 20 ) ); + + mbd.setAutosell( true ); + mbd.setGlowing( true ); + mbd.setAutosell( true ); + + mbd.setCooldownTicks( 60 ); + mbd.setFuseDelayTicks( 3 * 20 ); // 3 seconds + + getConfigData().getBombs().put( mbd.getName().toLowerCase(), mbd ); + } + + { + MineBombData mbd = new MineBombData( + "WimpyBomb", "GUNPOWDER", ExplosionShape.sphere.name(), 5, + "A Wimpy Mine Bomb" ); + mbd.setBombItemId( "&7A &2Wimpy &cBomb &9...&02A3F" ); + + mbd.setNameTag( "&7A &2Wimpy &cBomb" ); + + mbd.setRadiusInner( 2 ); + mbd.setDescription("A whimpy bomb made with gunpowder and packs the punch of a " + + "dull wooden pickaxe. For some reason, it only has a 40% chance of removing " + + "a block."); + + mbd.getLore().add( "" ); + mbd.getLore().add( "A whimpy bomb made with gunpowder and packs the punch " ); + mbd.getLore().add( "of a dull wooden pickaxe. For some reason, it only " ); + mbd.getLore().add( "has a 40% chance of removing a block." ); + mbd.getLore().add( "" ); + mbd.getLore().add( "Not labeled for retail sale." ); + + mbd.setToolInHandName( "WOODEN_PICKAXE" ); + mbd.setToolInHandFortuneLevel( 0 ); + mbd.setRemovalChance( 40.0d ); + + mbd.getSoundEffects().add( mbeSound01.clone() ); + mbd.getSoundEffects().add( mbeSound02.clone().setOffsetTicks( 30 ) ); + mbd.getSoundEffects().add( mbeSound03.clone() ); + + mbd.getVisualEffects().add( mbeExplode01.clone() ); + mbd.getVisualEffects().add( mbeExplode02.clone().setOffsetTicks( 30 ) ); + mbd.getVisualEffects().add( mbeExplode03.clone().setOffsetTicks( 10 ) ); + mbd.getVisualEffects().add( mbeExplode04.clone() ); + + mbd.getVisualEffects().add( mbeExplode10.clone() ); + mbd.getVisualEffects().add( mbeExplode06.clone() ); + mbd.getVisualEffects().add( mbeExplode06a.clone() ); + mbd.getVisualEffects().add( mbeExplode11.clone().setOffsetTicks( 05 ) ); + + mbd.setCooldownTicks( 3 * 20 ); // 3 seconds + mbd.setFuseDelayTicks( 2 * 20 ); // 2 seconds + + mbd.setGlowing( true ); + mbd.setGravity( false ); + + mbd.setCooldownTicks( 5 ); + + getConfigData().getBombs().put( mbd.getName().toLowerCase(), mbd ); + } + + + { + MineBombData mbd = new MineBombData( + "CubeBomb", "SLIME_BLOCK", ExplosionShape.cube.name(), 2, + "A Cubic Bomb" ); + mbd.setDescription("The most anti-round bomb you will ever be able to find. " + + "It's totally cubic."); + + mbd.setToolInHandName( "DIAMOND_PICKAXE" ); + mbd.setToolInHandFortuneLevel( 7 ); + mbd.setRemovalChance( 100.0d ); + + mbd.getSoundEffects().add( mbeSound01.clone() ); + mbd.getSoundEffects().add( mbeSound02.clone().setOffsetTicks( 30 ) ); + mbd.getSoundEffects().add( mbeSound03.clone() ); + + mbd.getVisualEffects().add( mbeExplode04.clone() ); + mbd.getVisualEffects().add( mbeExplode02.clone().setOffsetTicks( 30 ) ); + + mbd.setGlowing( true ); + + mbd.setCooldownTicks( 60 ); + + getConfigData().getBombs().put( mbd.getName().toLowerCase(), mbd ); + } + + + saveConfigJson(); + + Output.get().logInfo( "Mine bombs: setup default values." ); + } + else { + Output.get().logInfo( "Could not generate a mine bombs save file since at least one " + + "mine bomb already exists." ); + } + + } + + + public MineBombsConfigData getConfigData() { + return configData; + } + public void setConfigData( MineBombsConfigData configData ) { + this.configData = configData; + } + + + public MineBombData findBombByItemId( String bombItemId ) + { + MineBombData results = null; + + String bombItemIdConvered = Text.convertToAmpColorCodes( bombItemId ); + + if ( bombItemIdConvered != null && !bombItemIdConvered.isEmpty() ) { + for ( String bombKey : getConfigData().getBombs().keySet() ) + { + MineBombData bomb = getConfigData().getBombs().get( bombKey ); + + if ( bomb != null && bomb.getBombItemId() != null && + bomb.getBombItemId().equalsIgnoreCase( bombItemIdConvered ) ) { + + results = bomb; + + } + } + } + + return results; + } + +} 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 new file mode 100644 index 000000000..573002a0f --- /dev/null +++ b/prison-core/src/main/java/tech/mcprison/prison/bombs/MineBombsConfigData.java @@ -0,0 +1,46 @@ +package tech.mcprison.prison.bombs; + +import java.util.Map; +import java.util.TreeMap; + +import tech.mcprison.prison.file.FileIOData; + +public class MineBombsConfigData + implements FileIOData +{ + /** + *

If the format of this class, or any other variables and their + * classes change that would effect the structure of the save file, + * then increment this variable by 1. This will force the saved + * files on the servers to be updated to the latest format of the + * data. + *

+ */ + public static final int MINE_BOMB_DATA_FORMAT_VERSION = 1; + + private int dataFormatVersion = 0; + + private Map bombs; + + public MineBombsConfigData() { + super(); + + this.dataFormatVersion = 0; + + this.bombs = new TreeMap<>(); + } + + public int getDataFormatVersion() { + return dataFormatVersion; + } + public void setDataFormatVersion( int dataFormatVersion ) { + this.dataFormatVersion = dataFormatVersion; + } + + public Map getBombs() { + return bombs; + } + public void setBombs( Map bombs ) { + this.bombs = bombs; + } +} diff --git a/prison-core/src/main/java/tech/mcprison/prison/cache/PlayerCache.java b/prison-core/src/main/java/tech/mcprison/prison/cache/PlayerCache.java index c4d5f554a..9646746a7 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/cache/PlayerCache.java +++ b/prison-core/src/main/java/tech/mcprison/prison/cache/PlayerCache.java @@ -9,7 +9,6 @@ import java.util.TreeSet; import tech.mcprison.prison.internal.Player; -import tech.mcprison.prison.internal.block.PrisonBlock; import tech.mcprison.prison.internal.block.PrisonBlockStatusData; import tech.mcprison.prison.output.Output; import tech.mcprison.prison.tasks.PrisonTaskSubmitter; @@ -206,11 +205,40 @@ public PlayerCachePlayerData removePlayerData( PlayerCachePlayerData playerData } + /** + *

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

+ * + *

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

+ * + *

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

+ * + * @param player + * @return + */ + public PlayerCachePlayerData getOnlinePlayer( Player player ) { + PlayerCachePlayerData playerData = getPlayer( player ); + + return playerData; + } /** *

This returns the cached player object. If they have not been loaded - * yet, then this will submit the loadPlayer task, which will then result - * in this function returning a null. + * yet, then this will load the player object while waiting for it. + *

+ * + *

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

* * @param player @@ -222,7 +250,8 @@ private PlayerCachePlayerData getPlayer( Player player ) { getStats().incrementGetPlayers(); - String playerUuid = player.getUUID().toString(); + String playerUuid = player == null || player.getUUID() == null ? null : + player.getUUID().toString(); if ( !getPlayers().containsKey( playerUuid ) ) { // Load the player's existing balance: @@ -244,10 +273,16 @@ private PlayerCachePlayerData getPlayer( Player player ) { playerData = getPlayers().get( playerUuid ); } - if ( playerData != null && - (playerData.getPlayer() == null || !playerData.getPlayer().equals( player ) ) ) { - playerData.setPlayer( player ); + if ( playerData != null ) { + + if ( playerData.getPlayer() == null || !playerData.getPlayer().equals( player ) ) { + + playerData.setPlayer( player ); + } + + playerData.updateLastSeen(); } + return playerData; } @@ -265,18 +300,29 @@ protected void submitAsyncLoadPlayer( Player player ) { } } - protected void runLoadPlayerNow( Player player ) { - - if ( player != null ) { - - PlayerCacheLoadPlayerTask task = new PlayerCacheLoadPlayerTask( player ); - - task.run(); -// // Submit task to run right away: -// int taskId = PrisonTaskSubmitter.runTaskLaterAsync( task, 0 ); -// task.setTaskId( taskId ); - } - } + +// /** +// *

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

+// * +// *

This is not used anywhere. +// *

+// * +// * @param player +// */ +// protected void runLoadPlayerNow( Player player ) { +// +// if ( player != null ) { +// +// PlayerCacheLoadPlayerTask task = new PlayerCacheLoadPlayerTask( player ); +// +// task.run(); +//// // Submit task to run right away: +//// int taskId = PrisonTaskSubmitter.runTaskLaterAsync( task, 0 ); +//// task.setTaskId( taskId ); +// } +// } protected void submitAsyncUnloadPlayer( Player player ) { @@ -325,20 +371,23 @@ public PlayerCacheRunnable submitCacheUpdatePlayerStats() { public void addPlayerBlocks( Player player, String mine, PrisonBlockStatusData block, int quantity ) { - addPlayerBlocks( player, mine, (PrisonBlock) block, quantity ); + addPlayerBlocks( player, mine, block.getBlockName(), quantity ); } - public void addPlayerBlocks( Player player, String mine, PrisonBlock block, int quantity ) { +// public void addPlayerBlocks( Player player, String mine, PrisonBlock block, int quantity ) { +// addPlayerBlocks( player, mine, block.getBlockName(), quantity ); +// } + public void addPlayerBlocks( Player player, String mine, String blockName, int quantity ) { PlayerCachePlayerData playerData = getPlayer( player ); // Output.get().logInfo( "### addPlayerBlock: mine= " + (mine == null ? "null" : mine) + // " block= " + (block == null ? "null" : block.getBlockName()) + " qty= " + quantity + " playerData= " + // (playerData == null ? "null" : playerData.toString() )); - + // if ( playerData != null && playerData.getBlocksTotal() % 20 == 0 ) { // Output.get().logInfo( "#### PlayerCache: " + playerData.toString() ); // } - playerData.addBlock( mine, block.getBlockName(), quantity ); + playerData.addBlock( mine, blockName, quantity ); } /** @@ -351,7 +400,13 @@ public void addPlayerBlocks( Player player, String mine, PrisonBlock block, int public void addPlayerEarnings( Player player, double earnings ) { PlayerCachePlayerData playerData = getPlayer( player ); - playerData.addEarnings( earnings ); + String mineName = null; + playerData.addEarnings( earnings, mineName ); + } + public void addPlayerEarnings( Player player, double earnings, String mineName ) { + PlayerCachePlayerData playerData = getPlayer( player ); + + playerData.addEarnings( earnings, mineName ); } public double getPlayerEarningsPerMinute( Player player ) { double earningsPerMinute = 0; diff --git a/prison-core/src/main/java/tech/mcprison/prison/cache/PlayerCacheCheckTimersTask.java b/prison-core/src/main/java/tech/mcprison/prison/cache/PlayerCacheCheckTimersTask.java index 84292dc31..7ace3b302 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/cache/PlayerCacheCheckTimersTask.java +++ b/prison-core/src/main/java/tech/mcprison/prison/cache/PlayerCacheCheckTimersTask.java @@ -1,6 +1,8 @@ package tech.mcprison.prison.cache; import java.util.ArrayList; +import java.util.ConcurrentModificationException; +import java.util.HashSet; import java.util.List; /** @@ -37,27 +39,68 @@ public class PlayerCacheCheckTimersTask extends PlayerCacheRunnable { + private HashSet processedKeys; + private int attempts = 0; + + public PlayerCacheCheckTimersTask() { + super(); + + this.processedKeys = new HashSet<>(); + } + @Override public void run() { - PlayerCache pCache = PlayerCache.getInstance(); + // Everytime this runs, clear the processed keys set: + processedKeys.clear(); + attempts = 0; - List keys = new ArrayList<>( pCache.getPlayers().keySet() ); + processCache(); - for ( String key : keys ) - { - PlayerCachePlayerData playerData = pCache.getPlayers().get( key ); + } + private void processCache() { + PlayerCache pCache = PlayerCache.getInstance(); + + if ( pCache.getPlayers() != null && pCache.getPlayers().keySet().size() > 0 ) { - if ( playerData != null ) { + try + { + List keys = new ArrayList<>( pCache.getPlayers().keySet() ); - playerData.checkTimers(); + for ( String key : keys ) + { + if ( processedKeys.contains( key ) ) { + // Already processed this key so skip it: + break; + } + processedKeys.add( key ); + + + PlayerCachePlayerData playerData = pCache.getPlayers().get( key ); + + if ( playerData != null ) { + + playerData.checkTimers(); + + // By adding a zero earnings, this will force the earnings "cache" to + // progress, even if the player stopped mining. + playerData.addEarnings( 0, null ); + } + + } + } + catch ( ConcurrentModificationException e ) + { + // We can ignore this overall. It is a very rare occurrence which happens when + // a player is added or removed from an external process. Since this is a maintenance + // thread, it takes on a secondary priority. - // By adding a zero earnings, this will force the earnings "cache" to - // progress, even if the player stopped mining. - playerData.addEarnings( 0 ); + // Try to process the list three times then give up: + if ( attempts++ < 3 ) { + processCache(); + } } - } } diff --git a/prison-core/src/main/java/tech/mcprison/prison/cache/PlayerCacheFiles.java b/prison-core/src/main/java/tech/mcprison/prison/cache/PlayerCacheFiles.java index 0241bfdef..8c5d4d15e 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/cache/PlayerCacheFiles.java +++ b/prison-core/src/main/java/tech/mcprison/prison/cache/PlayerCacheFiles.java @@ -90,39 +90,66 @@ public String toJson( PlayerCachePlayerData player ) { */ public void toJsonFile( PlayerCachePlayerData player) { - File playerFile = player.getPlayerFile(); - File outTemp = createTempFile( playerFile ); - boolean success = false; - - try ( - FileWriter fw = new FileWriter( outTemp ); - ){ - getGson().toJson( player, fw ); + if ( player != null ) { - success = true; - } - catch ( JsonIOException | IOException e ) { - e.printStackTrace(); - } - - if ( success && ( !playerFile.exists() || playerFile.delete()) ) { - outTemp.renameTo( playerFile ); - } - else { - - boolean removed = false; - if ( outTemp.exists() ) { - removed = outTemp.delete(); + File playerFile = player.getPlayerFile(); + File outTemp = createTempFile( playerFile ); + boolean success = false; + + try ( + FileWriter fw = new FileWriter( outTemp ); + ){ + getGson().toJson( player, fw ); + + success = true; + } + catch ( JsonIOException | IOException e ) { + e.printStackTrace(); } - - String message = String.format( - "Unable to rename PlayerCache temp file. It was %sremoved: %s", - (removed ? "" : "not "), outTemp.getAbsolutePath() ); - Output.get().logWarn( message ); + // If there is a significant change in file size, or the new file is smaller than the + // old, then rename it to a backup and keep it. If it is smaller, then something went wrong + // because player cache data should always increase, with the only exception being + // the player cache. + if ( playerFile.exists() ) { + long pfSize = playerFile.length(); + long tmpSize = outTemp.length(); + + if ( tmpSize < pfSize ) { + + renamePlayerFileToBU( playerFile ); + } + } + + if ( success && ( !playerFile.exists() || playerFile.delete()) ) { + outTemp.renameTo( playerFile ); + } + else { + + boolean removed = false; + if ( outTemp.exists() ) { + removed = outTemp.delete(); + } + + String message = String.format( + "Unable to rename PlayerCache temp file. It was %sremoved: %s", + (removed ? "" : "not "), outTemp.getAbsolutePath() ); + + Output.get().logWarn( message ); + } } } + private void renamePlayerFileToBU( File playerFile ) + { + String buFileName = ".backup_" + playerFile.getName().replace( ".temp", ".bu" ); + + File backupFile = new File( playerFile.getParent(), buFileName ); + + playerFile.renameTo( backupFile ); + + } + private File createTempFile( File file ) { SimpleDateFormat sdf = new SimpleDateFormat("_yyyy-MM-dd_HH-mm-ss"); String name = file.getName() + sdf.format( new Date() ) + ".temp"; diff --git a/prison-core/src/main/java/tech/mcprison/prison/cache/PlayerCachePlayerData.java b/prison-core/src/main/java/tech/mcprison/prison/cache/PlayerCachePlayerData.java index befae9dc1..1ae833cfc 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/cache/PlayerCachePlayerData.java +++ b/prison-core/src/main/java/tech/mcprison/prison/cache/PlayerCachePlayerData.java @@ -2,11 +2,17 @@ import java.io.File; import java.text.SimpleDateFormat; +import java.util.ArrayList; import java.util.Date; +import java.util.List; import java.util.TreeMap; +import tech.mcprison.prison.autofeatures.AutoFeaturesFileConfig.AutoFeatures; +import tech.mcprison.prison.autofeatures.AutoFeaturesWrapper; +import tech.mcprison.prison.autofeatures.PlayerMessaging; import tech.mcprison.prison.internal.Player; import tech.mcprison.prison.internal.block.PrisonBlock; +import tech.mcprison.prison.internal.inventory.Inventory; import tech.mcprison.prison.placeholders.PlaceholdersUtil; /** @@ -27,6 +33,7 @@ public class PlayerCachePlayerData { private transient Player player; + private String playerUuid; private String playerName; @@ -47,6 +54,11 @@ public class PlayerCachePlayerData { private transient PlayerCacheRunnable task = null; + // lastSeenDate tries to track when the player was last on the server. + // This is important to know for refreshing player stats. + private long lastSeenDate; + private double lastSeenBalance; + private long onlineTimeTotal = 0L; // "active" time is not needed. It's the total onlineTimeTotal minus @@ -66,22 +78,41 @@ public class PlayerCachePlayerData { private TreeMap timeByMine; private String lastMine = null; - private TreeMap earningsByMine; + private TreeMap earningsByMine; private transient TreeMap earningsPerMinute; + private long tokens; + private long tokensTotal; + private long tokensTotalAdminAdded; + private long tokensTotalAdminRemoved; + private long tokensLastBlocksTotals; + + private TreeMap tokensByMine; + private transient TreeMap tokensPerMinute; + + + + + // This is the time when the "session" was started: private transient SessionType sessionType; - private transient long sessionTimingStart = 0; +// private transient long sessionTimingStart = 0; private transient long sessionTimingLastCheck = 0; // sessionLastLocation is used for afk calculations: // private transient Location sessionLastLocation = null; + + private transient PlayerMessaging playerMessaging; + + + private List backpacks; + private transient boolean dirty = false; @@ -104,13 +135,22 @@ public PlayerCachePlayerData() { this.earningsPerMinute = new TreeMap<>(); + + this.tokensByMine = new TreeMap<>(); + this.tokensPerMinute = new TreeMap<>(); + + this.sessionType = SessionType.active; - this.sessionTimingStart = System.currentTimeMillis(); - this.sessionTimingLastCheck = sessionTimingStart; +// this.sessionTimingStart = System.currentTimeMillis(); + this.sessionTimingLastCheck = System.currentTimeMillis(); // this.sessionLastLocation = null; + this.playerMessaging = new PlayerMessaging(); + + this.backpacks = new ArrayList<>(); + } public PlayerCachePlayerData( Player player, File playerFile ) { @@ -118,6 +158,14 @@ public PlayerCachePlayerData( Player player, File playerFile ) { this.player = player; + if ( isOnline() ) { + + this.lastSeenDate = System.currentTimeMillis(); +// this.lastSeenBalance = player.get + + this.dirty = true; + } + this.playerUuid = player.getUUID().toString(); this.playerName = player.getName(); @@ -135,8 +183,9 @@ public void checkTimers() { if ( isOnline() ) { - // Do not change the session type, so pass it the current: - checkTimersMining( sessionType, getLastMine() ); + // Do not change the session type, but pass null for the mine to indicate + // that this is a checkTimers... + checkTimersMining( sessionType, null ); } } @@ -159,12 +208,16 @@ public void checkTimers() { *

If prior session type was mining, then do nothing if the last * @param mine */ - private void checkTimersMining( SessionType targetType, String mine ) { - final long currentTime = System.currentTimeMillis(); + private void checkTimersMining( SessionType currentSessionType, String mine ) { if ( !isOnline() ) { return; } + + final long currentTime = System.currentTimeMillis(); + final long duration = currentTime - sessionTimingLastCheck; + + // temp fix: if ( onlineTimeTotal < 0 ) { @@ -174,94 +227,129 @@ private void checkTimersMining( SessionType targetType, String mine ) { onlineMiningTimeTotal = 0; } - if ( sessionType == targetType && sessionType != SessionType.mining) { - // No change in status - - sessionTimingLastCheck = currentTime; - final long duration = currentTime - sessionTimingLastCheck; - // if duration is greater than 15 minutes, then move the session start - // point and save it. - if ( duration > 900000 ) { - - sessionTimingStart = currentTime; - dirty = true; - } - - } - else if ( sessionType != SessionType.mining ) { - - // Always Save as total time. Use sessionTimingStart. Ignore sessionTimingLastCheck. - final long duration = currentTime - sessionTimingStart; - onlineTimeTotal += duration; + if ( currentSessionType != SessionType.mining ) { //checkTimersAfk(); - sessionType = targetType; - sessionTimingStart = currentTime; + setLastMine( null ); + sessionType = currentSessionType; + sessionTimingLastCheck = currentTime; + dirty = true; } - else { - // The session type is still mining... + + else if ( currentSessionType == SessionType.mining ) { + // The current session type is still mining... and was before. // Must check sessionTimingLastCheck to see if we went over the // max mining idle time: - final long duration = currentTime - sessionTimingLastCheck; - - // If the duration is less than the session mining timeout, then player - // is still mining. Just set the sessionTimingLastCheck. - if ( duration < SESSION_TIMEOUT_MINING_MS ) { - - sessionTimingLastCheck = currentTime; + if ( sessionType != SessionType.mining || + getLastMine() == null ) { + + dirty = true; + } - // Mining can only be active for no more than SESSION_TIMEOUT_MINING_MS - // after the last block was broken. So check duration between now and - // sessionOnlineTimeLastCheck and if more than permitted, then shutdown - // mining session and log it for a duration since session start to - // last check plus the mining timeout value. Then set session start to - // that position. + else if ( mine == null && getLastMine() != null && + duration > SESSION_TIMEOUT_MINING_MS ) { + + addTimeToMine( getLastMine(), SESSION_TIMEOUT_MINING_MS ); + + onlineMiningTimeTotal += SESSION_TIMEOUT_MINING_MS; + + // Since this is being called from checkTimer(), need to + // set lastMine to null and sessionType to active: + + setLastMine( null ); + sessionType = SessionType.active; + + // Save as total online time. + onlineTimeTotal += duration; + + dirty = true; + return; + } - else if ( duration > SESSION_TIMEOUT_MINING_MS || getLastMine() == null || - mine.equalsIgnoreCase( getLastMine() )) { + else if ( mine == null ) { - // Calculate the end point of the mining session, which will be 30 seconds after - // the last time check: - final long tempTime = sessionTimingLastCheck + SESSION_TIMEOUT_MINING_MS; - final long miningDuration = tempTime - sessionTimingStart; -// final long miningDuration = sessionTimingStart - tempTime; - onlineTimeTotal += miningDuration; - onlineMiningTimeTotal += miningDuration; + // This is running in checkTimers() and not enough time has passed to + // exceed the SESSION_TIMEOUT_MINING_MS. So need to wait longer. + // return without setting anything. - addTimeToMine( mine, miningDuration ); + return; + } + + // Mine has changed since last check, so apply duration to last mine: + else if ( getLastMine() != null && + (mine == null || + !mine.equalsIgnoreCase( getLastMine() ) )) { - // Set new session to this boundary: - sessionTimingStart = tempTime; - sessionTimingLastCheck = tempTime; - // Since the last SessionType and current are mining, then the duration from - // the new sessionTimingStart to currentTime needs to go to active: - final long durationActive = currentTime - sessionTimingStart; - onlineTimeTotal += durationActive; + if ( duration > SESSION_TIMEOUT_MINING_MS ) { + addTimeToMine( getLastMine(), SESSION_TIMEOUT_MINING_MS ); + + onlineMiningTimeTotal += SESSION_TIMEOUT_MINING_MS; + + } + else { + + addTimeToMine( getLastMine(), duration ); + + onlineMiningTimeTotal += duration; + } + + } + + + else if ( duration > SESSION_TIMEOUT_MINING_MS ) { - //checkTimersAfk(); + // Same mine, but exceeded the duration: + addTimeToMine( mine, SESSION_TIMEOUT_MINING_MS ); - // Now reset the current session: - sessionType = targetType; - sessionTimingStart = currentTime; - sessionTimingLastCheck = currentTime; - dirty = true; + onlineMiningTimeTotal += SESSION_TIMEOUT_MINING_MS; + + } + else { + // same mine and less than session length, so add duration: + + addTimeToMine( mine, duration ); + onlineMiningTimeTotal += duration; + } + + + // Now change the active mine + setLastMine( mine ); + + // Should already be mining: +// sessionType = currentSessionType; + + // Set new session to this boundary and discard the extra time: + sessionTimingLastCheck = currentTime; + + dirty = true; } + + // Always Save as total online time. + onlineTimeTotal += duration; } + /** + *

Also generates tokens based upon blocks mined. + *

+ * + * @param mine + * @param blockName + * @param quantity + */ public void addBlock( String mine, String blockName, int quantity ) { if ( quantity > 0 && blockName != null && @@ -280,6 +368,8 @@ public void addBlock( String mine, String blockName, int quantity ) checkTimersMining( SessionType.mining, mine ); dirty = true; } + + addTokensByBlocks( mine, quantity ); } private void addBlockByType( String blockName, int quantity ) { @@ -313,6 +403,16 @@ private void addEarningsByMine( String mine, double amount ) { getEarningsByMine().put( mine, amt ); } + private void addTokensByMine( String mine, long tokens ) { + long toks = 0; + + if ( getTokensByMine().containsKey( mine ) ) { + toks = getTokensByMine().get( mine ); + } + + getTokensByMine().put( mine, (toks + tokens) ); + } + private void addTimeToMine( String mine, long miningDuration ) { if ( mine != null && !mine.trim().isEmpty() ) { @@ -334,28 +434,37 @@ private void addTimeToMine( String mine, long miningDuration ) * * @param earnings */ - public void addEarnings( double earnings ) { + public void addEarnings( double earnings, String mineName ) { SimpleDateFormat dateFmt = new SimpleDateFormat("yyyy-MM-dd_hh:mm"); String key = dateFmt.format( new Date() ); - if ( earningsPerMinute.containsKey( key ) ) { - earnings += earningsPerMinute.get( key ) + earnings; + + double earningsPM = earnings; + if ( getEarningsPerMinute().containsKey( key ) ) { + earningsPM += getEarningsPerMinute().get( key ); } + getEarningsPerMinute().put( key, earningsPM ); - earningsPerMinute.put( key, earnings ); - if ( earningsPerMinute.size() > 5 ) { - earningsPerMinute.remove( - earningsPerMinute.firstEntry().getKey() ); + if ( getEarningsPerMinute().size() > 5 ) { + getEarningsPerMinute().remove( + getEarningsPerMinute().firstEntry().getKey() ); } + if ( mineName != null && sessionType != SessionType.mining ) { + sessionType = SessionType.mining; + } + if ( mineName == null && getLastMine() != null ) { + mineName = getLastMine(); + } // If earnings are within the session timeout for mining, then add the // earnings to the moneyByMine: - if ( sessionType == SessionType.mining && getLastMine() != null ) { + if ( sessionType == SessionType.mining && mineName != null ) { long duration = System.currentTimeMillis() - sessionTimingLastCheck; if ( duration < SESSION_TIMEOUT_MINING_MS ) { - addEarningsByMine( getLastMine(), earnings ); + + addEarningsByMine( mineName, earnings ); } } @@ -379,6 +488,188 @@ public double getAverageEarningsPerMinute() { return ( size == 0 ? 0 : ( results / size )); } + private void addTokensByBlocks( String mineName, int blocks ) { + + if ( AutoFeaturesWrapper.getInstance().isBoolean( AutoFeatures.tokensEnabled ) ) { + int blocksPerToken = AutoFeaturesWrapper.getInstance().getInteger( AutoFeatures.tokensBlocksPerToken ); + + if ( blocksPerToken > 0 ) { + + // If blocksTotal > 10k and tokensLastBlocksTotals == 0, then this means + // the player was mining before tokens was enabled, so set the + // tokensLastBlocksTotals to the blocks total, minus current block count. + if ( tokensLastBlocksTotals == 0 && blocksTotal > 10000 ) { + tokensLastBlocksTotals = blocksTotal - blocks; + } + + // tokensLastBlocksTotals should never be greater than blocksTotal: + if ( tokensLastBlocksTotals > blocksTotal ) { + tokensLastBlocksTotals = blocksTotal; + } + + double delta = blocksTotal - tokensLastBlocksTotals; + + double tokens = delta / (double) blocksPerToken; + + if ( tokens >= 1.0 ) { + long tokensLong = (long) Math.floor( tokens ); + + long blocksForTokens = tokensLong * blocksPerToken; + tokensLastBlocksTotals += blocksForTokens; + + addTokens( tokensLong, mineName ); + + } + } + } + } + + /** + *

This stores the tokens from the player so they can + * be averaged to find their tokens per minute. Tokens are + * automatically generated based upon blocks mined so normally + * you wouldn't have to call this function. + *

+ * + *

If you just want to add tokens, you can pass a null for the + * mine name. + *

+ * + *

Note: Unlike adding blocks from mines, adding tokens with a mine name + * does not need to be concerned about session types. If a mine name is + * provided, then that's the mine it should be attributed to. + *

+ * + * @param newTokens + */ + public void addTokens( long newTokens, String mineName ) { + + addTokens( newTokens ); + + SimpleDateFormat dateFmt = new SimpleDateFormat("yyyy-MM-dd_hh:mm"); + String key = dateFmt.format( new Date() ); + + + long tokensPM = newTokens; + if ( getTokensPerMinute().containsKey( key ) ) { + tokensPM += getTokensPerMinute().get( key ); + } + getTokensPerMinute().put( key, tokensPM ); + + + if ( getTokensPerMinute().size() > 5 ) { + getTokensPerMinute().remove( + getTokensPerMinute().firstEntry().getKey() ); + } + + // If we are getting tokens from mining, then we have the mine name. + // No need to mess with sessions. +// if ( mineName != null && sessionType != SessionType.mining ) { +// sessionType = SessionType.mining; +// } +// if ( mineName == null && getLastMine() != null ) { +// mineName = getLastMine(); +// } + + // If earnings are within the session timeout for mining, then add the + // earnings to the tokensByMine: + if ( mineName != null ) { + + addTokensByMine( mineName, newTokens ); + } + + dirty = true; + } + + + /** + *

This adds tokens to the player, but it is from an admin-related purpose, or task, + * so it has no effects on the player's Tokens-Per-Minute calculations, or + * per mine stats. + *

+ * + * @param newTokens + */ + public void addTokensAdmin( long newTokens ) { + + this.tokens += newTokens; + this.tokensTotalAdminAdded += newTokens; + + dirty = true; + } + public void addTokens( long newTokens ) { + + this.tokens += newTokens; + this.tokensTotal += newTokens; + + dirty = true; + } + + /** + *

This removes tokens from the player, but it is from an admin-related purpose, or task, + * so it has no effects on the player's Tokens-Per-Minute calculations, or + * per mine stats. + *

+ * + *

Note: The player can have a negative balance with this function! This may be useful for + * small "token loans" when purchasing something. Such allowances would have to be + * handled in the task that calls this function. + *

+ * + * @param newTokens + */ + public void removeTokensAdmin( long removeTokens ) { + + this.tokens -= removeTokens; + this.tokensTotalAdminRemoved += removeTokens; + + dirty = true; + } + public void removeTokens( long removeTokens ) { + + this.tokens -= removeTokens; + + dirty = true; + } + + public void setTokensAdmin( long newBalance ) { + + if ( this.tokens > newBalance ) { + + long delta = this.tokens - newBalance; + + removeTokensAdmin( delta ); + } + else if ( this.tokens < newBalance ) { + + long delta = newBalance - this.tokens; + + addTokensAdmin( delta ); + } +// else { +// // do nothing if equals and no change is needed: +// } + + } + + /** + * This returns the average tokens earned per minute for the + * last 5 minutes. + * + * @return + */ + public double getAverageTokensPerMinute() { + double results = 0; + + int size = 0; + for ( double value : tokensPerMinute.values() ) { + results += value; + size++; + } + + return ( size == 0 ? 0 : ( results / size )); + } + @Override public String toString() { StringBuilder sb = new StringBuilder(); @@ -404,11 +695,27 @@ public String toString() { .append( " blocks: " ) .append( blocksByType ) + .append( " avg tokens/min: " ) + .append( getAverageTokensPerMinute() ) + .append( " tokens: " ) + .append( getTokens() ) + .append( " totalTokens earned: " ) + .append( getTokensTotal() ) + .append( " totalTokensAdminAdded: " ) + .append( getTokensTotalAdminAdded() ) + .append( " totalTokensAdminRemoved: " ) + .append( getTokensTotalAdminRemoved() ) ; return sb.toString(); } - + + public void updateLastSeen() { + + if ( getPlayer() != null && getPlayer().isOnline() ) { + lastSeenDate = System.currentTimeMillis(); + } + } protected Player getPlayer() { return player; @@ -417,6 +724,13 @@ protected void setPlayer( Player player ) { this.player = player; } + public long getLastSeenDate() { + return lastSeenDate; + } + public void setLastSeenDate( long lastSeenDate ) { + this.lastSeenDate = lastSeenDate; + } + public File getPlayerFile() { return playerFile; } @@ -510,6 +824,55 @@ public void setTimeByMine( TreeMap timeByMine ) { this.timeByMine = timeByMine; } + public long getTokens() { + return tokens; + } + public void setTokens( long tokens ) { + this.tokens = tokens; + } + + public long getTokensTotal() { + return tokensTotal; + } + public void setTokensTotal( long tokensTotal ) { + this.tokensTotal = tokensTotal; + } + + public long getTokensTotalAdminAdded() { + return tokensTotalAdminAdded; + } + public void setTokensTotalAdminAdded( long tokensTotalAdminAdded ) { + this.tokensTotalAdminAdded = tokensTotalAdminAdded; + } + + public long getTokensTotalAdminRemoved() { + return tokensTotalAdminRemoved; + } + public void setTokensTotalAdminRemoved( long tokensTotalAdminRemoved ) { + this.tokensTotalAdminRemoved = tokensTotalAdminRemoved; + } + + public long getTokensLastBlocksTotals() { + return tokensLastBlocksTotals; + } + public void setTokensLastBlocksTotals( long tokensLastBlocksTotals ) { + this.tokensLastBlocksTotals = tokensLastBlocksTotals; + } + + public TreeMap getTokensByMine() { + return tokensByMine; + } + public void setTokensByMine( TreeMap tokensByMine ) { + this.tokensByMine = tokensByMine; + } + + public TreeMap getTokensPerMinute() { + return tokensPerMinute; + } + public void setTokensPerMinute( TreeMap tokensPerMinute ) { + this.tokensPerMinute = tokensPerMinute; + } + public String getLastMine() { return lastMine; } @@ -524,6 +887,20 @@ public void setEarningsByMine( TreeMap earningsByMine ) { this.earningsByMine = earningsByMine; } + public PlayerMessaging getPlayerMessaging() { + return playerMessaging; + } + public void setPlayerMessaging( PlayerMessaging playerMessaging ) { + this.playerMessaging = playerMessaging; + } + + public List getBackpacks() { + return backpacks; + } + public void setBackpacks( List backpacks ) { + this.backpacks = backpacks; + } + public boolean isDirty() { return dirty; } diff --git a/prison-core/src/main/java/tech/mcprison/prison/cache/PlayerCacheSaveAllPlayersTask.java b/prison-core/src/main/java/tech/mcprison/prison/cache/PlayerCacheSaveAllPlayersTask.java index e4802a3d6..a3f0d3234 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/cache/PlayerCacheSaveAllPlayersTask.java +++ b/prison-core/src/main/java/tech/mcprison/prison/cache/PlayerCacheSaveAllPlayersTask.java @@ -44,6 +44,7 @@ public class PlayerCacheSaveAllPlayersTask extends PlayerCacheRunnable { + public static long LAST_SEEN_INTERVAL_30_MINUTES = 30 * 60 * 1000; @Override public void run() @@ -59,23 +60,40 @@ public void run() { PlayerCachePlayerData playerData = pCache.getPlayers().get( key ); - if ( playerData != null && playerData.isDirty() ) { + if ( playerData != null ) { - try - { - playerData.setDirty( false ); - pCache.getCacheFiles().toJsonFile( playerData ); + // If the player is online plus.. if dirty, or never last seen, or + // it's been more than 30 minutes since update of last seen field: + if ( playerData.isOnline() && + (playerData.isDirty() || + playerData.getLastSeenDate() == 0 || + (System.currentTimeMillis() - playerData.getLastSeenDate()) + > LAST_SEEN_INTERVAL_30_MINUTES ) ) { + // Update the player's last seen date only when dirty and they + // are online: + playerData.setLastSeenDate( System.currentTimeMillis() ); + playerData.setDirty( true ); } - catch ( Exception e ) - { - String message = String.format( - "PlayerCache: Error trying to save a player's " + - "cache data. Will try again later. " + - "%s", e.getMessage() ); - Output.get().logError( message, e ); + + if ( playerData.isDirty() ) { + + try + { + playerData.setDirty( false ); + pCache.getCacheFiles().toJsonFile( playerData ); + } + catch ( Exception e ) + { + String message = String.format( + "PlayerCache: Error trying to save a player's " + + "cache data. Will try again later. " + + "%s", e.getMessage() ); + Output.get().logError( message, e ); + } } } + // If a cached item is found with the player being offline, then // purge them from the cache. They were usually added only because // some process had to inspect their stats, so they are safe to remove. diff --git a/prison-core/src/main/java/tech/mcprison/prison/cache/TopNBalancesComparator.java b/prison-core/src/main/java/tech/mcprison/prison/cache/TopNBalancesComparator.java new file mode 100644 index 000000000..86a318877 --- /dev/null +++ b/prison-core/src/main/java/tech/mcprison/prison/cache/TopNBalancesComparator.java @@ -0,0 +1,13 @@ +package tech.mcprison.prison.cache; + +import java.util.Comparator; + +public class TopNBalancesComparator + implements Comparator +{ + + @Override + public int compare( TopNStatsData o1, TopNStatsData o2 ) { + return Double.compare( o1.getCurrentBalance(), o2.getCurrentBalance() ); + } +} diff --git a/prison-core/src/main/java/tech/mcprison/prison/cache/TopNBlocksComparator.java b/prison-core/src/main/java/tech/mcprison/prison/cache/TopNBlocksComparator.java new file mode 100644 index 000000000..63b6cb9e7 --- /dev/null +++ b/prison-core/src/main/java/tech/mcprison/prison/cache/TopNBlocksComparator.java @@ -0,0 +1,14 @@ +package tech.mcprison.prison.cache; + +import java.util.Comparator; + +public class TopNBlocksComparator + implements Comparator +{ + + @Override + public int compare( TopNStatsData o1, TopNStatsData o2 ) { + return Long.compare( o1.getTotalBlocks(), o2.getTotalBlocks() ); + } + +} diff --git a/prison-core/src/main/java/tech/mcprison/prison/cache/TopNRanksComparator.java b/prison-core/src/main/java/tech/mcprison/prison/cache/TopNRanksComparator.java new file mode 100644 index 000000000..b54b83967 --- /dev/null +++ b/prison-core/src/main/java/tech/mcprison/prison/cache/TopNRanksComparator.java @@ -0,0 +1,52 @@ +package tech.mcprison.prison.cache; + +import java.util.Comparator; + +public class TopNRanksComparator + implements Comparator +{ + @Override + public int compare( TopNStatsData o1, TopNStatsData o2 ) { + + int results = 0; + + if ( o1.getTopRankPrestiges() == null && o2.getTopRankPrestiges() == null ) { + results = 0; + } + if ( o1.getTopRankPrestiges() == null ) { + return 1; + } + if ( o2.getTopRankPrestiges() == null ) { + return -1; + } + + if ( o1.getTopRankDefault() == null && o2.getTopRankDefault() == null ) { + return Double.compare( o1.getCurrentBalance(), o2.getCurrentBalance() ); + } + if ( o1.getTopRankDefault() == null ) { + return 1; + } + if ( o2.getTopRankDefault() == null ) { + return -1; + } + + results = Integer.compare( + o1.getTopRankPrestiges().getPosition(), + o2.getTopRankPrestiges().getPosition() ); + + if ( results == 0 ) { + + results = Integer.compare( + o1.getTopRankDefault().getPosition(), + o2.getTopRankDefault().getPosition() ); + + if ( results == 0 ) { + + results = Double.compare( o1.getCurrentBalance(), o2.getCurrentBalance() ); + } + + } + + return 0; + } +} diff --git a/prison-core/src/main/java/tech/mcprison/prison/cache/TopNStats.java b/prison-core/src/main/java/tech/mcprison/prison/cache/TopNStats.java new file mode 100644 index 000000000..9b8f1ce92 --- /dev/null +++ b/prison-core/src/main/java/tech/mcprison/prison/cache/TopNStats.java @@ -0,0 +1,55 @@ +package tech.mcprison.prison.cache; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class TopNStats +{ + + private static TopNStats instance; + + List mainList; + + List topBlocksList; + List topTokensList; + List topBalancesList; + + List topRanksList; + + + + private TopNStats() { + super(); + + this.mainList = new ArrayList<>(); + } + + public static TopNStats getInstance() { + if ( instance == null ) { + synchronized ( TopNStats.class ) + { + if ( instance == null ) { + + instance = new TopNStats(); + } + } + } + return instance; + } + + + protected void sortAllLists() { + + Collections.sort( topBlocksList, new TopNBlocksComparator() ); + + Collections.sort( topTokensList, new TopNTokensComparator() ); + + Collections.sort( topBalancesList, new TopNBalancesComparator() ); + + Collections.sort( topRanksList, new TopNRanksComparator() ); + + } + + +} diff --git a/prison-core/src/main/java/tech/mcprison/prison/cache/TopNStatsData.java b/prison-core/src/main/java/tech/mcprison/prison/cache/TopNStatsData.java new file mode 100644 index 000000000..c4c08029a --- /dev/null +++ b/prison-core/src/main/java/tech/mcprison/prison/cache/TopNStatsData.java @@ -0,0 +1,112 @@ +package tech.mcprison.prison.cache; + +import tech.mcprison.prison.ranks.data.Rank; + +public class TopNStatsData +{ + + private String playerUuid; + private String playerName; + + + private long totalBlocks; + + private long currentTokens; + private double currentBalance; + + + private String topRankPrestigesName; + private String topRankDefaultName; + + private transient Rank topRankPrestiges; + private transient Rank topRankDefault; + + + private long lastSeenDate; + + private long lastUpdateDate; + + + public TopNStatsData() { + super(); + + } + + public String getPlayerUuid() { + return playerUuid; + } + public void setPlayerUuid( String playerUuid ) { + this.playerUuid = playerUuid; + } + + public String getPlayerName() { + return playerName; + } + public void setPlayerName( String playerName ) { + this.playerName = playerName; + } + + public long getTotalBlocks() { + return totalBlocks; + } + public void setTotalBlocks( long totalBlocks ) { + this.totalBlocks = totalBlocks; + } + + public long getCurrentTokens() { + return currentTokens; + } + public void setCurrentTokens( long currentTokens ) { + this.currentTokens = currentTokens; + } + + public double getCurrentBalance() { + return currentBalance; + } + public void setCurrentBalance( double currentBalance ) { + this.currentBalance = currentBalance; + } + + public String getTopRankPrestigesName() { + return topRankPrestigesName; + } + public void setTopRankPrestigesName( String topRankPrestigesName ) { + this.topRankPrestigesName = topRankPrestigesName; + } + + public String getTopRankDefaultName() { + return topRankDefaultName; + } + public void setTopRankDefaultName( String topRankDefaultName ) { + this.topRankDefaultName = topRankDefaultName; + } + + public Rank getTopRankPrestiges() { + return topRankPrestiges; + } + public void setTopRankPrestiges( Rank topRankPrestiges ) { + this.topRankPrestiges = topRankPrestiges; + } + + public Rank getTopRankDefault() { + return topRankDefault; + } + public void setTopRankDefault( Rank topRankDefault ) { + this.topRankDefault = topRankDefault; + } + + public long getLastSeenDate() { + return lastSeenDate; + } + public void setLastSeenDate( long lastSeenDate ) { + this.lastSeenDate = lastSeenDate; + } + + public long getLastUpdateDate() { + return lastUpdateDate; + } + public void setLastUpdateDate( long lastUpdateDate ) { + this.lastUpdateDate = lastUpdateDate; + } + +} diff --git a/prison-core/src/main/java/tech/mcprison/prison/cache/TopNTokensComparator.java b/prison-core/src/main/java/tech/mcprison/prison/cache/TopNTokensComparator.java new file mode 100644 index 000000000..172e9f198 --- /dev/null +++ b/prison-core/src/main/java/tech/mcprison/prison/cache/TopNTokensComparator.java @@ -0,0 +1,13 @@ +package tech.mcprison.prison.cache; + +import java.util.Comparator; + +public class TopNTokensComparator + implements Comparator +{ + + @Override + public int compare( TopNStatsData o1, TopNStatsData o2 ) { + return Long.compare( o1.getCurrentTokens(), o2.getCurrentTokens() ); + } +} 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 60595d1bc..19ac5379b 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 @@ -289,6 +289,17 @@ public ChatDisplay getHelpMessage(RegisteredCommand command) { } } + + ArrayList excludedWorlds = buildExcludedWorlds(); + if ( excludedWorlds.size() > 1 ) { + for ( String excludedWorld : excludedWorlds ) + { + chatDisplay.addText( excludedWorld ); + } + + } + + } @@ -296,6 +307,41 @@ public ChatDisplay getHelpMessage(RegisteredCommand command) { // return message.toArray(new String[0]); } + private ArrayList buildExcludedWorlds() { + + ArrayList message = new ArrayList<>(); + + message.add(ChatColor.DARK_AQUA + "Prison is disabled in the following Worlds:"); + + TreeSet excludedWorlds = Prison.get().getPlatform().getExcludedWorlds(); + + StringBuilder sb = new StringBuilder(); + int count = 0; + for ( String world : excludedWorlds ) + { + if ( sb.length() > 0 ) { + sb.append( ", " ); + } + + if ( count++ > 5 ) { + + message.add( " " + sb.toString() ); + sb.setLength( 0 ); + count = 0; + } + + sb.append( world ); + + } + + if ( sb.length() > 0 ) { + message.add( " " + sb.toString() ); + + } + + return message; + } + private ArrayList buildHelpRootCommands() { ArrayList message = new ArrayList<>(); @@ -526,6 +572,17 @@ public void registerArgumentHandler(Class clazz, argHandler.handler = this; argumentHandlers.put(clazz, argHandler); } + + public Object getRegisteredCommandClass( @SuppressWarnings( "rawtypes" ) Class commandClass ) { + Object results = null; + + String key = commandClass.getSimpleName(); + if ( key != null && getRegisteredCommands().containsKey( key ) ) { + results = getRegisteredCommands().get( key ); + } + + return results; + } public void registerCommands(Object methodInstance) { @@ -540,10 +597,16 @@ public void registerCommands(Object methodInstance) { } RegisteredCommand mainCommand = commandRegisterConfig( method, commandAnno, methodInstance ); + + + String[] aliases = addConfigAliases( commandAnno.identifier(), commandAnno.aliases() ); - if ( commandAnno.aliases() != null && commandAnno.aliases().length > 0 ) { + if ( aliases.length > 0 ) { +// if ( commandAnno.aliases() != null && commandAnno.aliases().length > 0 ) { + - for ( String alias : commandAnno.aliases() ) + for ( String alias : aliases ) +// for ( String alias : commandAnno.aliases() ) { RegisteredCommand aliasCommand = commandRegisterConfig( method, commandAnno, methodInstance, alias ); @@ -561,7 +624,8 @@ private RegisteredCommand commandRegisterConfig( Method method, Command commandA return commandRegisterConfig( method, commandAnno, methodInstance, null ); } - private RegisteredCommand commandRegisterConfig( Method method, Command commandAnno, Object methodInstance, String alias ) { + private RegisteredCommand commandRegisterConfig( Method method, Command commandAnno, + Object methodInstance, String alias ) { String[] identifiers = ( alias == null ? commandAnno.identifier() : alias).split(" "); if (identifiers.length == 0) { @@ -573,10 +637,16 @@ private RegisteredCommand commandRegisterConfig( Method method, Command commandA PluginCommand rootPluginCommand = plugin.getPlatform().getCommand(label).orElse( null ); if ( rootPluginCommand == null ) { + + String[] aliases = addConfigAliases( commandAnno.identifier(), commandAnno.aliases() ); rootPluginCommand = new PluginCommand(label, commandAnno.description(), "/" + label, - commandAnno.aliases() ); + aliases ); +// rootPluginCommand = new PluginCommand(label, +// commandAnno.description(), +// "/" + label, +// commandAnno.aliases() ); plugin.getPlatform().registerCommand(rootPluginCommand); } @@ -647,7 +717,34 @@ private RegisteredCommand commandRegisterConfig( Method method, Command commandA } - public boolean onCommand(CommandSender sender, PluginCommand command, String label, + public static String[] addConfigAliases( String label, String[] aliases ) + { + String[] results = aliases; + + String configKey = "prisonCommandHandler.aliases." + label.replace( " ", "." ); + + List ca = Prison.get().getPlatform().getConfigStringArray( configKey ); + if ( ca != null && ca.size() > 0 && ca.get( 0 ) instanceof String ) { + + List configAliases = new ArrayList<>(); + + for ( String alias : aliases ) { + configAliases.add( alias ); + } + + for ( Object aliasObj : ca ) { + if ( aliasObj instanceof String ) { + configAliases.add( aliasObj.toString() ); + } + } + + results = configAliases.toArray( new String[0] ); + + } + return results; + } + + public boolean onCommand(CommandSender sender, PluginCommand command, String label, String[] args) { RootCommand rootCommand = rootCommands.get(command); diff --git a/prison-core/src/main/java/tech/mcprison/prison/commands/RegisteredCommand.java b/prison-core/src/main/java/tech/mcprison/prison/commands/RegisteredCommand.java index ba3627088..d2eaf3cc7 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/commands/RegisteredCommand.java +++ b/prison-core/src/main/java/tech/mcprison/prison/commands/RegisteredCommand.java @@ -260,7 +260,10 @@ private void executeMethod(CommandSender sender, String[] args) { // to prevent this failure, escape all % with a double % such as %%. message = message.replace( "%", "%%" ); - Output.get().sendError( sender, message ); + Output.get().logError( message ); + + Output.get().sendError( sender, "An exception has occurred. Details have been " + + "logged to the server's console." ); // Generally these errors are major and require program fixes, so throw // the exception so the stacklist is logged. @@ -396,7 +399,12 @@ void set(Object methodInstance, Method method) { this.description = command.description(); this.permissions = command.permissions(); this.altPermissions = command.altPermissions(); - this.aliases = command.aliases(); + + String[] aliases = CommandHandler.addConfigAliases( command.identifier(), command.aliases() ); + //addConfigAliases( command.identifier(), command.aliases() ); + this.aliases = aliases; + +// this.aliases = command.aliases(); this.docURLs = command.docURLs(); this.onlyPlayers = command.onlyPlayers(); @@ -517,6 +525,34 @@ void set(Object methodInstance, Method method) { this.set = true; } + +// private String[] addConfigAliases( String label, String[] aliases ) +// { +// String[] results = aliases; +// +// String configKey = "prisonCommandHandler.aliases." + label.replace( " ", "." ); +// +// List ca = Prison.get().getPlatform().getConfigStringArray( configKey ); +// if ( ca != null && ca.size() > 0 && ca.get( 0 ) instanceof String ) { +// +// List configAliases = new ArrayList<>(); +// +// for ( String alias : aliases ) { +// configAliases.add( alias ); +// } +// +// for ( Object aliasObj : ca ) { +// if ( aliasObj instanceof String ) { +// configAliases.add( aliasObj.toString() ); +// } +// } +// +// results = configAliases.toArray( new String[0] ); +// +// } +// return results; +// } + public boolean testPermission(CommandSender sender) { if (!set) { return true; diff --git a/prison-core/src/main/java/tech/mcprison/prison/discord/DiscordWebhook.java b/prison-core/src/main/java/tech/mcprison/prison/discord/DiscordWebhook.java index 2490a5f95..09203dfb6 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/discord/DiscordWebhook.java +++ b/prison-core/src/main/java/tech/mcprison/prison/discord/DiscordWebhook.java @@ -205,12 +205,12 @@ public void execute() throws IOException { json.put("embeds", embedObjects.toArray()); } - if ( Output.get().isDebug( DebugTarget.support ) ) { - String jsonString = json.toString(); - Output.get().logDebug( DebugTarget.support, - "Prison Webhook debug: jsonSize: " + jsonString.length() + - " " + jsonString ); - } +// if ( Output.get().isDebug( DebugTarget.support ) ) { +// String jsonString = json.toString(); +// Output.get().logDebug( DebugTarget.support, +// "Prison Webhook debug: jsonSize: " + jsonString.length() + +// " " + jsonString ); +// } URL url = new URL(this.url); HttpsURLConnection connection = (HttpsURLConnection) url.openConnection(); diff --git a/prison-core/src/main/java/tech/mcprison/prison/discord/PrisonDiscordWebhook.java b/prison-core/src/main/java/tech/mcprison/prison/discord/PrisonDiscordWebhook.java index 085de2af6..66b4b40ec 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/discord/PrisonDiscordWebhook.java +++ b/prison-core/src/main/java/tech/mcprison/prison/discord/PrisonDiscordWebhook.java @@ -80,19 +80,19 @@ public void send( CommandSender sender, String title, String message, boolean ad } - if ( Output.get().isDebug( DebugTarget.support ) ) { - Output.get().logDebug( DebugTarget.support, - "Prison Webhook debug: total fields: %d total chars: %d ", - getFields().size(), totalSize ); - - if ( getFields().size() > 25 || totalSize > 6000 ) { - Output.get().logDebug( DebugTarget.support, - "Prison Webhook debug: total fields: Failure. Max number of " + - "fields is 25. Max number of characters is 6000. Please reduce " + - "these to bring in to complience and resubmit. " ); - } - - } +// if ( Output.get().isDebug( DebugTarget.support ) ) { +// Output.get().logDebug( DebugTarget.support, +// "Prison Webhook debug: total fields: %d total chars: %d ", +// getFields().size(), totalSize ); +// +// if ( getFields().size() > 25 || totalSize > 6000 ) { +// Output.get().logDebug( DebugTarget.support, +// "Prison Webhook debug: total fields: Failure. Max number of " + +// "fields is 25. Max number of characters is 6000. Please reduce " + +// "these to bring in to complience and resubmit. " ); +// } +// +// } String results = submitWebhook( webhook ); diff --git a/prison-core/src/main/java/tech/mcprison/prison/error/ErrorManager.java b/prison-core/src/main/java/tech/mcprison/prison/error/ErrorManager.java index f6185730c..cca993416 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/error/ErrorManager.java +++ b/prison-core/src/main/java/tech/mcprison/prison/error/ErrorManager.java @@ -31,7 +31,7 @@ public class ErrorManager { public ErrorManager(PluginEntity owner) { this.owner = owner; - this.errorDir = new File(owner.getDataFolder(), "errors"); + this.errorDir = new File(owner.getModuleDataFolder(), "errors"); if (!this.errorDir.exists()) { this.errorDir.mkdir(); } diff --git a/prison-core/src/main/java/tech/mcprison/prison/file/FileCollection.java b/prison-core/src/main/java/tech/mcprison/prison/file/FileCollection.java index d7785aad5..a94d97860 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/file/FileCollection.java +++ b/prison-core/src/main/java/tech/mcprison/prison/file/FileCollection.java @@ -101,5 +101,14 @@ public boolean delete(String name) File dbFile = new File(collDir, name + ".json"); return virtualDelete( dbFile ); } + + @Override + public File backup( String name ) + { + File dbFile = new File(collDir, name + ".json"); + File backupFile = virtualBackup( dbFile ); + + return backupFile; + } } 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 75071c04f..5c9f58bf0 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 @@ -9,6 +9,7 @@ import java.util.Date; import java.util.List; +import tech.mcprison.prison.Prison; import tech.mcprison.prison.error.Error; import tech.mcprison.prison.error.ErrorManager; import tech.mcprison.prison.modules.ModuleStatus; @@ -28,6 +29,11 @@ public FileIO() this(null, null); } + /** + * + * @param errorManager Optional; set to null if used outside of a module. + * @param status Optional; set to null if used outside of a module. + */ public FileIO(ErrorManager errorManager, ModuleStatus status) { super(); @@ -39,12 +45,45 @@ public FileIO(ErrorManager errorManager, ModuleStatus status) } + public File getProjectRootDiretory() { + return Prison.get().getDataFolder(); + } + + public File getTempFile( File file ) { + String tempFileName = file.getName() + "." + getTimestampFormat() + ".tmp"; + File tempFile = new File(file.getParentFile(), tempFileName); + + return tempFile; + } + + /** + *

This generates a new File with the filename of the backup file. + * This function only generates the File object and does not modify + * or save anything on the file system. + *

+ * + * @param file The original file name + * @param backupTag A no-spaced tag name to identify the type of backup. + * This is inserted after the original file name. + * @param suffix File suffix to use for the backup, not including the dot. + * @return File objct of the target backup file. + */ + public File getBackupFile( File file, String backupTag, String suffix ) { + + String tempFileName = file.getName() + "." + backupTag + "_" + + getTimestampFormat() + "." + suffix; + File tempFile = new File(file.getParentFile(), tempFileName); + + return tempFile; + } + protected void saveFile( File file, String data ) { if ( file != null && data != null ) { - String tempFileName = file.getName() + "." + getTimestampFormat() + ".tmp"; - File tempFile = new File(file.getParentFile(), tempFileName); + File tempFile = getTempFile( file ); +// String tempFileName = file.getName() + "." + getTimestampFormat() + ".tmp"; +// File tempFile = new File(file.getParentFile(), tempFileName); try { diff --git a/prison-core/src/main/java/tech/mcprison/prison/file/FileVirtualDelete.java b/prison-core/src/main/java/tech/mcprison/prison/file/FileVirtualDelete.java index 5fc29be28..5be2b65a6 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/file/FileVirtualDelete.java +++ b/prison-core/src/main/java/tech/mcprison/prison/file/FileVirtualDelete.java @@ -4,15 +4,21 @@ package tech.mcprison.prison.file; import java.io.File; +import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Date; +import com.google.common.io.Files; + +import tech.mcprison.prison.output.Output; + /** * */ public abstract class FileVirtualDelete { public static final String FILE_LOGICAL_DELETE_PREFIX = ".deleted_"; + public static final String FILE_LOGICAL_BACKUP_PREFIX = ".backup_"; public FileVirtualDelete() { @@ -38,6 +44,36 @@ protected boolean virtualDelete( File source ) return source.renameTo( newName ); } + /** + *

This function will make a backup of a file source. It's included in this virtual delete + * class since it's very similar and by changing the isDeleted() function, the backups can + * also be ignored. + *

+ * + * @param source + * @return File name of the backup file. + */ + protected File virtualBackup( File source ) + { + SimpleDateFormat sdf = new SimpleDateFormat("_yyyy-MM-dd_HH-mm-ss"); + String name = FILE_LOGICAL_BACKUP_PREFIX + source.getName() + sdf.format( new Date() ) + ".bu"; + File backupFile = new File( source.getParentFile(), name); + + try { + Files.copy( source, backupFile ); + } + catch ( IOException e ) + { + Output.get().logError( + String.format( + "Could not create a backup. SourceFile: %s BackupFile: %s Error: [%s]", + source.getAbsolutePath(), backupFile.getAbsolutePath(), e.getMessage() )); + e.printStackTrace(); + } + + return backupFile; + } + /** *

This function will return a boolean value to indicate if it has been logically * deleted. It will ONLY inspect the beginning of the file name which much have @@ -49,7 +85,9 @@ protected boolean virtualDelete( File source ) */ protected boolean isDeleted( File source ) { - return source.getName().toLowerCase().startsWith( FILE_LOGICAL_DELETE_PREFIX ); + return + source.getName().toLowerCase().startsWith( FILE_LOGICAL_DELETE_PREFIX ) || + source.getName().toLowerCase().startsWith( FILE_LOGICAL_BACKUP_PREFIX ); } } diff --git a/prison-core/src/main/java/tech/mcprison/prison/file/JsonFileIO.java b/prison-core/src/main/java/tech/mcprison/prison/file/JsonFileIO.java index 04482a331..bc872b0e8 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/file/JsonFileIO.java +++ b/prison-core/src/main/java/tech/mcprison/prison/file/JsonFileIO.java @@ -14,6 +14,11 @@ public class JsonFileIO { private final Gson gson; + /** + * + * @param errorManager Optional; set to null if used outside of a module. + * @param status Optional; set to null if used outside of a module. + */ public JsonFileIO(ErrorManager errorManager, ModuleStatus status) { super(errorManager, status); diff --git a/prison-core/src/main/java/tech/mcprison/prison/integration/CustomBlockIntegration.java b/prison-core/src/main/java/tech/mcprison/prison/integration/CustomBlockIntegration.java index 591c13599..e9b118296 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/integration/CustomBlockIntegration.java +++ b/prison-core/src/main/java/tech/mcprison/prison/integration/CustomBlockIntegration.java @@ -5,6 +5,7 @@ import tech.mcprison.prison.internal.block.Block; import tech.mcprison.prison.internal.block.PrisonBlock; import tech.mcprison.prison.internal.block.PrisonBlock.PrisonBlockType; +import tech.mcprison.prison.util.Location; public abstract class CustomBlockIntegration extends IntegrationCore { @@ -44,7 +45,9 @@ public CustomBlockIntegration( String keyName, String providerName, public abstract PrisonBlock getCustomBlock( Block block ); public abstract Block setCustomBlockId( Block block, String customId, boolean doBlockUpdate ); - + + public abstract void setCustomBlockIdAsync( PrisonBlock prisonBlock, Location location ); + public abstract List getCustomBlockList(); 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 f9386696d..c9029ef8f 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 @@ -22,6 +22,8 @@ import java.util.Optional; import java.util.UUID; +import tech.mcprison.prison.cache.PlayerCache; +import tech.mcprison.prison.cache.PlayerCachePlayerData; import tech.mcprison.prison.internal.block.Block; import tech.mcprison.prison.internal.inventory.InventoryHolder; import tech.mcprison.prison.internal.scoreboard.Scoreboard; @@ -144,6 +146,11 @@ public interface Player public void setActionBar( String actionBar ); + + public PlayerCache getPlayerCache(); + + public PlayerCachePlayerData getPlayerCachePlayerData(); + public boolean isSneaking(); } diff --git a/prison-core/src/main/java/tech/mcprison/prison/internal/PrisonStatsElapsedTimeNanos.java b/prison-core/src/main/java/tech/mcprison/prison/internal/PrisonStatsElapsedTimeNanos.java new file mode 100644 index 000000000..9892358ad --- /dev/null +++ b/prison-core/src/main/java/tech/mcprison/prison/internal/PrisonStatsElapsedTimeNanos.java @@ -0,0 +1,28 @@ +package tech.mcprison.prison.internal; + +public class PrisonStatsElapsedTimeNanos +{ + + private long elapsedTimeNanos; + + public PrisonStatsElapsedTimeNanos() { + super(); + + } + + public synchronized void addNanos( Long nanos ) { + + this.elapsedTimeNanos += nanos; + } + + public long getElapsedTimeNanos() + { + return elapsedTimeNanos; + } + + public void setElapsedTimeNanos( long elapsedTimeNanos ) + { + this.elapsedTimeNanos = elapsedTimeNanos; + } + +} diff --git a/prison-core/src/main/java/tech/mcprison/prison/internal/World.java b/prison-core/src/main/java/tech/mcprison/prison/internal/World.java index 8f1b87117..8541c896d 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/internal/World.java +++ b/prison-core/src/main/java/tech/mcprison/prison/internal/World.java @@ -21,6 +21,8 @@ import java.util.List; import tech.mcprison.prison.internal.block.Block; +import tech.mcprison.prison.internal.block.MineResetType; +import tech.mcprison.prison.internal.block.MineTargetPrisonBlock; import tech.mcprison.prison.internal.block.PrisonBlock; import tech.mcprison.prison.util.Location; @@ -37,7 +39,7 @@ public interface World { */ String getName(); - /**O + /** * Returns a list of all the players in this world. */ List getPlayers(); @@ -53,4 +55,20 @@ public interface World { public void setBlock( PrisonBlock block, int x, int y, int z ); + + /** + *

This function should be called from an async task, and it will + * drop down in to the synchronous thread to first get the block + * from the world, then it will change to the specified PrisonBlock type. + *

+ * + * @param prisonBlock + * @param location + */ + public void setBlockAsync( PrisonBlock prisonBlock, Location location ); + + public void setBlocksSynchronously( List tBlocks, + MineResetType resetType, + PrisonStatsElapsedTimeNanos nanos ); + } diff --git a/prison-core/src/main/java/tech/mcprison/prison/internal/block/MineResetType.java b/prison-core/src/main/java/tech/mcprison/prison/internal/block/MineResetType.java new file mode 100644 index 000000000..f300b2470 --- /dev/null +++ b/prison-core/src/main/java/tech/mcprison/prison/internal/block/MineResetType.java @@ -0,0 +1,9 @@ +package tech.mcprison.prison.internal.block; + +public enum MineResetType +{ + normal, + paged, + clear, + tracer; +} diff --git a/prison-mines/src/main/java/tech/mcprison/prison/mines/features/MineTargetBlockKey.java b/prison-core/src/main/java/tech/mcprison/prison/internal/block/MineTargetBlockKey.java similarity index 89% rename from prison-mines/src/main/java/tech/mcprison/prison/mines/features/MineTargetBlockKey.java rename to prison-core/src/main/java/tech/mcprison/prison/internal/block/MineTargetBlockKey.java index 9c8ce944c..0b51b0e2c 100644 --- a/prison-mines/src/main/java/tech/mcprison/prison/mines/features/MineTargetBlockKey.java +++ b/prison-core/src/main/java/tech/mcprison/prison/internal/block/MineTargetBlockKey.java @@ -1,4 +1,4 @@ -package tech.mcprison.prison.mines.features; +package tech.mcprison.prison.internal.block; import tech.mcprison.prison.internal.World; import tech.mcprison.prison.util.Location; @@ -23,6 +23,13 @@ public MineTargetBlockKey( Location location ) { this( location.getWorld(), location.getBlockX(), location.getBlockY(), location.getBlockZ() ); } + + public Location getLocation() { + Location location = new Location( world, x, y, z ); + return location; + } + + @Override public String toString() { StringBuilder sb = new StringBuilder(); 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 new file mode 100644 index 000000000..91cc4dd59 --- /dev/null +++ b/prison-core/src/main/java/tech/mcprison/prison/internal/block/MineTargetPrisonBlock.java @@ -0,0 +1,179 @@ +package tech.mcprison.prison.internal.block; + +import tech.mcprison.prison.internal.World; +import tech.mcprison.prison.util.Location; + +public class MineTargetPrisonBlock + implements Comparable +{ + private MineTargetBlockKey blockKey; + + private PrisonBlockStatusData prisonBlock; + + private boolean airBroke; + private boolean isEdge; + private boolean exploded; + + private boolean mined = false; + private Block minedBlock; + +// private boolean blockEvent = false; + private boolean counted = false; + + private boolean ignoreAllBlockEvents = false; + + + public MineTargetPrisonBlock( + PrisonBlockStatusData prisonBlock, + World world, + int x, int y, int z, boolean isEdge ) { + this.blockKey = new MineTargetBlockKey( world, x, y, z ); + + this.prisonBlock = prisonBlock; + + if ( prisonBlock == null || prisonBlock.isAir() ) { + this.airBroke = true; + } + + this.isEdge = isEdge; + } + + @Override + public String toString() { + return "MineTargetPrisonBlock: key= " + getBlockKey().toString() + + " block= " + getPrisonBlock().toString(); + } + + public PrisonBlock getPrisonBlock( MineResetType resetType ) { + + final PrisonBlock pBlock; + + if ( resetType == MineResetType.tracer && isEdge() ) + { + pBlock = PrisonBlock.PINK_STAINED_GLASS; + } + else if ( resetType == MineResetType.clear || + resetType == MineResetType.tracer ) + { + pBlock = PrisonBlock.AIR; + } + else if ( getPrisonBlock() != null && + getPrisonBlock() instanceof PrisonBlock ) + { + + // MineResetType.normal and MineResetType.paged + pBlock = (PrisonBlock) getPrisonBlock(); + } + else + { + pBlock = null; + } + + return pBlock; + + } + + public PrisonBlockStatusData getPrisonBlock() { + return prisonBlock; + } + public void setPrisonBlock( PrisonBlockStatusData prisonBlock ) { + this.prisonBlock = prisonBlock; + } + + + public MineTargetBlockKey getBlockKey() { + return blockKey; + } + + public String getBlockCoordinates() { + StringBuilder sb = new StringBuilder(); + + sb.append( getPrisonBlock().getBlockName() ); +// sb.append( getPrisonBlock().getBlockNameFormal() ); + + if ( getLocation() != null ) { + sb.append( "::" ); + + sb.append( getLocation().toWorldCoordinates() ); + } + + return sb.toString(); + } + + /** + *

This is a quick way to check to see if the block was originally set to air, or if + * the block was previously broke and "counted". This field, airBroke, needs to be + * set to 'true' when the block is counted as broken the first time so it won't be + * double counted in the future. Explosion events tends to cause blocks to be + * counted multiple times since it does not check to see if they are air prior to + * selecting them. + *

+ * + * @return + */ + public boolean isAirBroke() { + return airBroke; + } + public void setAirBroke( boolean airBroke ) { + this.airBroke = airBroke; + } + + public boolean isEdge() { + return isEdge; + } + public void setEdge( boolean isEdge ) { + this.isEdge = isEdge; + } + + public boolean isExploded() { + return exploded; + } + public void setExploded( boolean exploded ) { + this.exploded = exploded; + } + + public boolean isMined() { + return mined; + } + public void setMined( boolean mined ) { + this.mined = mined; + } + +// public boolean isBlockEvent() { +// return blockEvent; +// } +// public void setBlockEvent( boolean blockEvent ) { +// this.blockEvent = blockEvent; +// } + + public boolean isCounted() { + return counted; + } + public void setCounted( boolean counted ) { + this.counted = counted; + } + + public Block getMinedBlock() { + return minedBlock; + } + public void setMinedBlock( Block minedBlock ) { + this.minedBlock = minedBlock; + } + + public boolean isIgnoreAllBlockEvents() { + return ignoreAllBlockEvents; + } + public void setIgnoreAllBlockEvents( boolean ignoreAllBlockEvents ) { + this.ignoreAllBlockEvents = ignoreAllBlockEvents; + } + + @Override + public int compareTo( MineTargetPrisonBlock block ) { + return block.getBlockKey().compareTo( block.getBlockKey() ); + } + + public Location getLocation() + { + return getBlockKey().getLocation(); + } +} 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 28aac3252..d56a510a5 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 @@ -18,6 +18,7 @@ public class PrisonBlock public static PrisonBlock AIR; public static PrisonBlock GLASS; + public static PrisonBlock PINK_STAINED_GLASS; public static PrisonBlock IGNORE; public static PrisonBlock NULL_BLOCK; @@ -38,13 +39,15 @@ public class PrisonBlock static { AIR = new PrisonBlock( InternalBlockTypes.AIR.name(), false ); GLASS = new PrisonBlock( InternalBlockTypes.GLASS.name(), true ); + PINK_STAINED_GLASS = new PrisonBlock( InternalBlockTypes.PINK_STAINED_GLASS.name(), true ); IGNORE = new PrisonBlock( InternalBlockTypes.IGNORE.name(), false ); NULL_BLOCK = new PrisonBlock( InternalBlockTypes.NULL_BLOCK.name(), false ); } public enum PrisonBlockType { minecraft, - CustomItems + CustomItems, + heads } /** 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 31b10143d..c2ff50d8b 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 @@ -33,6 +33,9 @@ public abstract class PrisonBlockStatusData { private int rangeBlockCountHighLimit; + private boolean gravity = false; + + public PrisonBlockStatusData( String blockName, double chance, long blockCountTotal ) { super(); @@ -57,8 +60,28 @@ public PrisonBlockStatusData( String blockName, double chance, long blockCountTo this.rangeBlockCountLowLimit = -1; this.rangeBlockCountHighLimit = -1; + + this.gravity = checkGravityAffects( blockName ); } + + + @Override + public boolean equals( Object obj ) + { + boolean results = false; + + if ( obj instanceof PrisonBlockStatusData ) { + PrisonBlockStatusData pbsBlock = (PrisonBlockStatusData) obj; + + results = getBlockName().equalsIgnoreCase( pbsBlock.getBlockName() ); + } + + return results; + } + + + public void resetAfterSave() { blockCountUnsaved = 0; } @@ -91,7 +114,11 @@ public static PrisonBlock parseFromSaveFileFormat( String blockString ) { String[] split = blockString.split("-"); if ( split != null && split.length > 0 ) { + // The blockName is the first element. Use that to setup the PrisonBlock that + // will be used if the other stats that are available. String blockTypeName = split[0]; + + // The new way to get the PrisonBlocks: // The blocks return are cloned so they have their own instance: results = Prison.get().getPlatform().getPrisonBlock( blockTypeName ); @@ -115,6 +142,8 @@ public static PrisonBlock parseFromSaveFileFormat( String blockString ) { public void parseFromSaveFileFormatStats( String blockString ) { + + if ( blockString != null ) { String[] split = blockString.split("-"); @@ -289,6 +318,64 @@ public void addStats( PrisonBlockStatusData block ) { } + + /** + *

If a block is affected by gravity, which means the block can fall, then + * this function will return a value of true. + *

+ * + *

The items that are most likely to appear in the mine should + * be at the top to allow the minimization of what is required to be + * checked. + *

+ * + * https://minecraft.fandom.com/wiki/Falling_Block + * + * @param blockName + * @return + */ + private boolean checkGravityAffects( String blockName ) + { + boolean results = false; + + switch ( blockName ) + { + case "sand": + case "red_sand": + case "gravel": + + case "white_concrete_powder": + case "orange_concrete_powder": + case "magenta_concrete_powder": + case "light_blue_concrete_powder": + case "yellow_concrete_powder": + case "lime_concrete_powder": + case "pink_concrete_powder": + case "gray_concrete_powder": + case "light_gray_concrete_powder": + case "cyan_concrete_powder": + case "purple_concrete_powder": + case "blue_concrete_powder": + case "brown_concrete_powder": + case "green_concrete_powder": + case "red_concrete_powder": + case "black_concrete_powder": + + case "anvil": + case "chipped_anvil": + case "damaged_anvil": + + case "scaffolding": + case "pointed_dripstone": + case "dragon_egg": + { + results = true; + } + } + return results; + } + + @Override public String toString() { StringBuilder sb = new StringBuilder(); @@ -400,4 +487,11 @@ public void setRangeBlockCountHighLimit( int rangeBlockCountHighLimit ) { this.rangeBlockCountHighLimit = rangeBlockCountHighLimit; } + public boolean isGravity() { + return gravity; + } + public void setGravity( boolean gravity ) { + this.gravity = gravity; + } + } diff --git a/prison-core/src/main/java/tech/mcprison/prison/internal/block/PrisonBlockTypes.java b/prison-core/src/main/java/tech/mcprison/prison/internal/block/PrisonBlockTypes.java index b89393abb..5f593abf2 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/internal/block/PrisonBlockTypes.java +++ b/prison-core/src/main/java/tech/mcprison/prison/internal/block/PrisonBlockTypes.java @@ -20,6 +20,7 @@ public class PrisonBlockTypes { public enum InternalBlockTypes { AIR, GLASS, + PINK_STAINED_GLASS, IGNORE, NULL_BLOCK } diff --git a/prison-core/src/main/java/tech/mcprison/prison/internal/events/player/PlayerInteractEvent.java b/prison-core/src/main/java/tech/mcprison/prison/internal/events/player/PrisonPlayerInteractEvent.java similarity index 92% rename from prison-core/src/main/java/tech/mcprison/prison/internal/events/player/PlayerInteractEvent.java rename to prison-core/src/main/java/tech/mcprison/prison/internal/events/player/PrisonPlayerInteractEvent.java index 0f34ec64f..ab5a328f7 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/internal/events/player/PlayerInteractEvent.java +++ b/prison-core/src/main/java/tech/mcprison/prison/internal/events/player/PrisonPlayerInteractEvent.java @@ -29,7 +29,7 @@ * @author Faizaan A. Datoo * @since API 1.0 */ -public class PlayerInteractEvent implements Cancelable { +public class PrisonPlayerInteractEvent implements Cancelable { private Player player; private ItemStack itemInHand; @@ -37,7 +37,7 @@ public class PlayerInteractEvent implements Cancelable { private Location clicked; private boolean canceled = false; - public PlayerInteractEvent(Player player, ItemStack itemInHand, Action action, + public PrisonPlayerInteractEvent(Player player, ItemStack itemInHand, Action action, Location clicked) { this.player = player; this.itemInHand = itemInHand; 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 ba68215d0..acd287923 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 @@ -22,6 +22,7 @@ import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.TreeSet; import java.util.UUID; import tech.mcprison.prison.commands.PluginCommand; @@ -311,6 +312,9 @@ default Optional getCommand(String label) { public double getConfigDouble( String key, double defaultValue ); + + public boolean isWorldExcluded( String worldName ); + /** * Setup hooks in to the valid prison block types. This will be only the @@ -370,6 +374,8 @@ public void autoCreateMineLinerAssignment( List rankMineNames, public void traceEventListenersBlockBreakEvents( CommandSender sender ); + public String dumpEventListenersPlayerInteractEvents(); + public void testPlayerUtil( UUID uuid ); @@ -421,5 +427,18 @@ public void autoCreateMineLinerAssignment( List rankMineNames, public void reloadAutoFeaturesEventListeners(); + void setTitle( Player player, String title, String subtitle, int fadeIn, int stay, int fadeOut ); + + + void setActionBar( Player player, String actionBar ); + + + public TreeSet getExcludedWorlds(); + + + public List getConfigStringArray( String key ); + + + public int compareServerVerisonTo( String comparisonVersion ); } diff --git a/prison-core/src/main/java/tech/mcprison/prison/localization/LocaleManager.java b/prison-core/src/main/java/tech/mcprison/prison/localization/LocaleManager.java index 644889ef4..4ec090789 100755 --- a/prison-core/src/main/java/tech/mcprison/prison/localization/LocaleManager.java +++ b/prison-core/src/main/java/tech/mcprison/prison/localization/LocaleManager.java @@ -189,7 +189,7 @@ public String toString() { public File getLocalDataFolder() { // Setup the local folders: - File dataFolder = fixPrisonCoreLanguagePath( getOwningPlugin().getDataFolder() ); + File dataFolder = fixPrisonCoreLanguagePath( getOwningPlugin().getModuleDataFolder() ); File localeDirectory = new File(dataFolder, LOCALE_FOLDER); // if the folder does not exist, try to create it: @@ -497,7 +497,7 @@ private void loadCustomLocales() { private File fixPrisonCoreLanguagePath( File targetPath ) { if ( !targetPath.getAbsolutePath().startsWith( ModuleManager.getModuleRootDefault().getAbsolutePath() ) ) { - targetPath = Module.setupDataFolder( Prison.PSEDUO_MODLE_NAME ); + targetPath = Module.setupModuleDataFolder( Prison.PSEDUO_MODLE_NAME ); } return targetPath; } 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 3871fcf30..8878a9098 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 @@ -153,6 +153,17 @@ public Localizable setFailNormally() { * @since 1.0 */ public Localizable withReplacements(String... replacements) { + if ( replacements == null ) { + replacements = new String[1]; + replacements[0] = ""; + } + else { + for ( int i = 0; i < replacements.length; i++ ) { + if ( replacements[i] == null ) { + replacements[i] = ""; + } + } + } this.replacements = Arrays.copyOf(replacements, replacements.length); this.locReplacements = null; return this; @@ -344,7 +355,11 @@ public String localizeFor(CommandSender sender) { * @since 1.0 */ public void sendTo(CommandSender sender, LogLevel level) { - Output.get().sendMessage(sender, localizeFor(sender), level); + String message = localizeFor(sender); + if ( message != null && !message.isEmpty() ) { + + Output.get().sendMessage(sender, message, level); + } } /** @@ -370,10 +385,15 @@ public void sendTo(CommandSender sender) { * @since 1.0 */ public void broadcast() { - for (Player player : Prison.get().getPlatform().getOnlinePlayers()) { - sendTo(player); - } - Output.get().logInfo(localize()); + + String message = localize(); + if ( message != null && !message.isEmpty() ) { + + for (Player player : Prison.get().getPlatform().getOnlinePlayers()) { + sendTo(player); + } + Output.get().logInfo( message ); + } } /** @@ -384,12 +404,16 @@ public void broadcast() { * @since 1.0 */ public void broadcast(World... worlds) { - for (World w : worlds) { - for (Player player : w.getPlayers()) { - sendTo(player); - } - } - Output.get().logInfo(localize()); + String message = localize(); + if ( message != null && !message.isEmpty() ) { + + for (World w : worlds) { + for (Player player : w.getPlayers()) { + sendTo(player); + } + } + Output.get().logInfo( message ); + } } /** diff --git a/prison-core/src/main/java/tech/mcprison/prison/modules/Module.java b/prison-core/src/main/java/tech/mcprison/prison/modules/Module.java index 4c95f0cab..65a982a9e 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/modules/Module.java +++ b/prison-core/src/main/java/tech/mcprison/prison/modules/Module.java @@ -37,7 +37,8 @@ public abstract class Module implements PluginEntity { */ private String name, version; - private File dataFolder; + private File moduleDataFolder; + private int apiTarget; private ModuleStatus status; private ErrorManager errorManager; @@ -58,18 +59,18 @@ public Module(String name, String version, int target) { this.version = version; this.apiTarget = target; - this.dataFolder = setupDataFolder( name ); + this.moduleDataFolder = setupModuleDataFolder( name ); this.status = new ModuleStatus(); this.errorManager = new ErrorManager(this); } - public static File setupDataFolder( String name ) { + public static File setupModuleDataFolder( String name ) { File dataFolder = new File(ModuleManager.getModuleRootDefault(), name.toLowerCase().replace(" ", "_")); if (!dataFolder.exists()) { - dataFolder.mkdir(); + dataFolder.mkdirs(); } return dataFolder; } @@ -185,8 +186,8 @@ public ModuleStatus getStatus() { * * @return The {@link File} representing the data folder. */ - public File getDataFolder() { - return dataFolder; + public File getModuleDataFolder() { + return moduleDataFolder; } } diff --git a/prison-core/src/main/java/tech/mcprison/prison/modules/PluginEntity.java b/prison-core/src/main/java/tech/mcprison/prison/modules/PluginEntity.java index 03b3da3f6..6e64f95ff 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/modules/PluginEntity.java +++ b/prison-core/src/main/java/tech/mcprison/prison/modules/PluginEntity.java @@ -30,6 +30,6 @@ public interface PluginEntity { String getName(); - File getDataFolder(); + File getModuleDataFolder(); } 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 1b3f3ac1e..165f711f1 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 @@ -19,10 +19,12 @@ package tech.mcprison.prison.output; import java.util.Arrays; +import java.util.FormatFlagsConversionMismatchException; import java.util.HashSet; import java.util.MissingFormatArgumentException; import java.util.Set; import java.util.TreeSet; +import java.util.UnknownFormatConversionException; import tech.mcprison.prison.Prison; import tech.mcprison.prison.internal.CommandSender; @@ -55,6 +57,7 @@ public class Output private boolean debug = false; private Set activeDebugTargets; + private Set selectiveDebugTargets; public enum DebugTarget { all, @@ -62,12 +65,14 @@ public enum DebugTarget { off, blockBreak, // blockBreakListeners, - blockBreakDurability, +// blockBreakDurability, blockBreakFortune, - blockBreakXpCalcs, +// blockBreakXpCalcs, // Removed since it was inlined - rankup, - support + targetBlockMismatch, + + rankup +// support ; public static DebugTarget fromString( String target ) { @@ -105,6 +110,7 @@ private Output() { instance = this; this.activeDebugTargets = new HashSet<>(); + this.selectiveDebugTargets = new HashSet<>(); this.prefixTemplate = coreOutputPrefixTemplateMsg(); @@ -197,7 +203,10 @@ public String format(String message, LogLevel level, Object... args) { * Log a message with a specified {@link LogLevel} */ public void log(String message, LogLevel level, Object... args) { - if ( Prison.get() == null || Prison.get().getPlatform() == null ) { + if ( message == null || message.trim().isEmpty() ) { + // do not send an empty message... do nothing... + } + else if ( Prison.get() == null || Prison.get().getPlatform() == null ) { String errorMessage = coreOutputErrorStartupFailureMsg(); if ( errorMessage == null || errorMessage.trim().isEmpty() ) { // NOTE: The following must remain as is. This is a fallback for if there @@ -205,7 +214,14 @@ public void log(String message, LogLevel level, Object... args) { // can be identified along with the reasons. errorMessage = "Prison: (Sending to System.err due to Output.log Logger failure):"; } - System.err.println( errorMessage + " " + message ); + + StringBuilder sb = new StringBuilder(); + for ( Object arg : args ) { + sb.append( "[" ).append( arg ).append( "] " ); + } + + System.err.println( errorMessage + " message: [" + message + + "] params: " + sb.toString() ); } else { try { Prison.get().getPlatform().log( @@ -229,6 +245,27 @@ public void log(String message, LogLevel level, Object... args) { getLogColorCode(LogLevel.ERROR) + errorMessage ); } + catch ( UnknownFormatConversionException | + FormatFlagsConversionMismatchException e) + { + StringBuilder sb = new StringBuilder(); + + for ( Object arg : args ) { + sb.append( "[" ).append( arg ).append( "] " ); + } + + String errorMessage = "Error with Java format usage (eg %s): " + + " LogLevel: " + level.name() + + " message: [" + message + "] params: [" + sb.toString() + "]" + + " error: [" + e.getMessage() + "]"; + + Prison.get().getPlatform().logCore( + prefixTemplatePrison + " " + + getLogColorCode(LogLevel.ERROR) + + errorMessage ); + + e.printStackTrace(); + } } } @@ -306,10 +343,19 @@ public String getDebugTargetsString() { public void applyDebugTargets( String targets ) { + boolean isSelective = targets.contains( "selective" ); + TreeSet trgts = DebugTarget.fromMultiString( targets ); if ( trgts.size() > 0 ) { - applyDebugTargets( trgts ); + + if ( isSelective ) { + applySelectiveDebugTargets( trgts ); + } + else { + applyDebugTargets( trgts ); + } + } else { // No targets were set, so just toggle the debugger: @@ -355,9 +401,41 @@ else if ( offTarget ) { // Output.get().setDebug( !Output.get().isDebug() ); } + public void applySelectiveDebugTargets( TreeSet targets ) { + + for ( DebugTarget target : targets ) { + + if ( getSelectiveDebugTargets().contains( target ) ) { + + getSelectiveDebugTargets().remove( target ); + } + else { + + getSelectiveDebugTargets().add( target ); + } + + } + + + } + public boolean isDebug( DebugTarget debugTarget ) { - return isDebug() || getActiveDebugTargets().contains( debugTarget ); + return isDebug() || getActiveDebugTargets().contains( debugTarget ) || + getSelectiveDebugTargets().contains( debugTarget ); + } + + /** + *

This only return true if the specified debug target is enabled. + * The global debug mode, and other debugTargets, are ignored. + *

+ * + * @param debugTarget + * @return + */ + public boolean isSelectiveTarget( DebugTarget debugTarget ) { + return getSelectiveDebugTargets().contains( debugTarget ); } + public boolean isDebug() { return debug; } @@ -373,11 +451,25 @@ public void setActiveDebugTargets( Set activeDebugTargets ) { this.activeDebugTargets = activeDebugTargets; } + public Set getSelectiveDebugTargets() { + return selectiveDebugTargets; + } + public void setSelectiveDebugTargets( Set selectiveDebugTargets ) { + this.selectiveDebugTargets = selectiveDebugTargets; + } + + /** * Send a message to a {@link CommandSender} */ public void sendMessage(CommandSender sender, String message, LogLevel level, Object... args) { - sender.sendMessage(getLogPrefix(level) + String.format(message, args)); + + if ( sender != null && message != null && message.length() > 0 ) { + if ( level == null ) { + level = LogLevel.PLAIN; + } + sender.sendMessage(getLogPrefix(level) + String.format(message, args)); + } } public void send(CommandSender sender, String message, Object... args) { diff --git a/prison-core/src/main/java/tech/mcprison/prison/placeholders/PlaceholderManager.java b/prison-core/src/main/java/tech/mcprison/prison/placeholders/PlaceholderManager.java index 1159db5b7..01a9fc0cc 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/placeholders/PlaceholderManager.java +++ b/prison-core/src/main/java/tech/mcprison/prison/placeholders/PlaceholderManager.java @@ -240,7 +240,9 @@ public enum PrisonPlaceHolders { // player balances. Both with and without ladders. prison_pb(PlaceholderFlags.PLAYER, PlaceholderFlags.ALIAS), + prison_pbf(PlaceholderFlags.PLAYER, PlaceholderFlags.ALIAS), prison_player_balance(prison_pb, PlaceholderFlags.PLAYER), + prison_player_balance_formatted(prison_pbf, PlaceholderFlags.PLAYER), prison_pb_epm(PlaceholderFlags.PLAYER, PlaceholderFlags.ALIAS), @@ -250,20 +252,41 @@ public enum PrisonPlaceHolders { prison_pb_laddername(PlaceholderFlags.LADDERS, PlaceholderFlags.ALIAS), + prison_pbf_laddername(PlaceholderFlags.LADDERS, PlaceholderFlags.ALIAS), prison_player_balance_laddername(prison_pb_laddername, PlaceholderFlags.LADDERS), + prison_player_balance_formatted_laddername(prison_pbf_laddername, PlaceholderFlags.LADDERS), + prison_ptb(PlaceholderFlags.PLAYER, PlaceholderFlags.ALIAS), + prison_ptbf(PlaceholderFlags.PLAYER, PlaceholderFlags.ALIAS), + prison_ptbfm(PlaceholderFlags.PLAYER, PlaceholderFlags.ALIAS), + prison_ptbfk(PlaceholderFlags.PLAYER, PlaceholderFlags.ALIAS), + prison_player_token_balance(prison_ptb, PlaceholderFlags.PLAYER), + prison_player_token_balance_formatted(prison_ptbf, PlaceholderFlags.PLAYER), + prison_player_token_balance_formatted_metric(prison_ptbfm, PlaceholderFlags.PLAYER), + prison_player_token_balance_formatted_kmbt(prison_ptbfk, PlaceholderFlags.PLAYER), + + prison_ptb_epm(PlaceholderFlags.PLAYER, PlaceholderFlags.ALIAS), + prison_ptb_epmf(PlaceholderFlags.PLAYER, PlaceholderFlags.ALIAS), + prison_player_token_balance_earnings_per_minute(prison_ptb_epm, PlaceholderFlags.PLAYER), + prison_player_token_balance_earnings_per_minute_formatted(prison_ptb_epmf, PlaceholderFlags.PLAYER), + + + prison_psm(PlaceholderFlags.PLAYER, PlaceholderFlags.ALIAS), prison_player_sellall_multiplier(prison_psm, PlaceholderFlags.PLAYER), - prison_pbt(PlaceholderFlags.MINEPLAYERS, PlaceholderFlags.ALIAS), - prison_pbtm(PlaceholderFlags.MINEPLAYERS, PlaceholderFlags.ALIAS), + prison_pbt(PlaceholderFlags.PLAYER, PlaceholderFlags.ALIAS), + prison_pbtf(PlaceholderFlags.PLAYER, PlaceholderFlags.ALIAS), + prison_player_blocks_total(prison_pbt, PlaceholderFlags.PLAYER), + prison_player_blocks_total_formatted(prison_pbtf, PlaceholderFlags.PLAYER), + - prison_player_blocks_total(prison_pbt, PlaceholderFlags.MINEPLAYERS), + prison_pbtm(PlaceholderFlags.MINEPLAYERS, PlaceholderFlags.ALIAS), prison_player_blocks_total_minename(prison_pbtm, PlaceholderFlags.MINEPLAYERS), diff --git a/prison-core/src/main/java/tech/mcprison/prison/ranks/data/PlayerRank.java b/prison-core/src/main/java/tech/mcprison/prison/ranks/data/PlayerRank.java new file mode 100644 index 000000000..3e814ab36 --- /dev/null +++ b/prison-core/src/main/java/tech/mcprison/prison/ranks/data/PlayerRank.java @@ -0,0 +1,190 @@ +package tech.mcprison.prison.ranks.data; + +/** + *

PlayerRank is a container for holding a players rank, along with their + * rankMultiplier and the calculated rankCost. + *

+ * + */ +public class PlayerRank +{ + + private final Rank rank; + + private Double rankMultiplier = null; + private Double rankCost = null; + + protected PlayerRank( Rank rank ) { + super(); + + this.rank = rank; + +// double rankMultiplier = getLadderBasedRankMultiplier( rank ); +// +// setRankCost( rankMultiplier ); +//// this.rankCost = rank.getCost() * (1.0 + rankMultiplier); + } + + protected PlayerRank( Rank rank, double rankMultiplier ) { + this( rank ); + + this.rankMultiplier = rankMultiplier; + + setRankCost( rankMultiplier ); +// this.rankCost = rank.getCost() * (1.0 + rankMultiplier); + } + + @Override + public String toString() { + return "PlayerRank: " + rank.getName() + " (" + rank.getId() + + " mult: " + rankMultiplier + " cost: " + rankCost + ")"; + } + + public void applyMultiplier( double rankMultiplier ) { + + this.rankMultiplier = rankMultiplier; + + setRankCost( rankMultiplier ); +// this.rankCost = rank.getCost() * (1.0 + rankMultiplier); + } + + protected void setRankCost( double rankMultiplier ) { + + this.rankCost = rank.getCost() * (1.0 + rankMultiplier); + } + + public double getLadderBasedRankMultiplier() { + return getLadderBasedRankMultiplier( getRank() ); + } + + public double getLadderBasedRankMultiplier( Rank rank ) { + double rankMultiplier = 0; + + if ( rank != null && rank.getLadder() != null ) { + double ladderMultiplier = rank.getLadder().getRankCostMultiplierPerRank(); + + // Because it's zero based... so add a 1 + rankMultiplier = ladderMultiplier * (1 + rank.getPosition()); + } + + return rankMultiplier; + } + + +// public static double getRawRankCost( Rank rank ) { +// return rank.getCost(); +// } +// public static void setRawRankCost( Rank rank, double rawCost ) { +// rank.setCost( rawCost ); +// } + +// public static PlayerRank getTargetPlayerRankForPlayer( RankPlayer player, Rank targetRank ) { +// PlayerRank targetPlayerRank = null; +// +// if ( targetRank != null ) { +// +// double targetRankMultiplier = getLadderBaseRankdMultiplier( targetRank ); +// +// PlayerRank pRankForPLayer = player.getRank( targetRank.getLadder() ); +// double existingRankMultiplier = pRankForPLayer == null ? 0 : +// getLadderBaseRankdMultiplier( pRankForPLayer.getRank() ); +// +// // Get the player's total rankMultiplier from the default ladder +// // because they will always have a rank there: +// PlayerRank pRank = player.getRank( "default" ); +// double playerMultipler = pRank == null ? 0 : pRank.getRankMultiplier(); +// +// // So the actual rank multiplier that needs to be used, is based upon the +// // Player's current multiplier PLUS the multiplier for the target rank +// // AND MINUS the multiplier for the current rank the player has within the +// // target rank's ladder. +// double rankMultiplier = playerMultipler + targetRankMultiplier - existingRankMultiplier; +// +// targetPlayerRank = new PlayerRank( targetRank, rankMultiplier ); +// } +// +// return targetPlayerRank; +// } + + + public PlayerRank getTargetPlayerRankForPlayer( RankPlayer player, Rank targetRank ) { + return getTargetPlayerRankForPlayer( this, player, targetRank ); + } + + public PlayerRank getTargetPlayerRankForPlayer( PlayerRank playerRank, RankPlayer player, Rank targetRank ) + { + PlayerRank targetPlayerRank = null; + + if ( targetRank != null ) + { + + double targetRankMultiplier = playerRank.getLadderBasedRankMultiplier( targetRank ); + + + PlayerRank pRankForPLayer = player.getLadderRanks().get( targetRank.getLadder() ); + + // PlayerRank pRankForPLayer = getRank( player, targetRank.getLadder() ); + double existingRankMultiplier = pRankForPLayer == null ? 0 + : playerRank.getLadderBasedRankMultiplier( pRankForPLayer.getRank() ); + + // Get the player's total rankMultiplier from the default ladder + // because they will always have a rank there: + RankLadder defaultLadder = getDefaultLadder( player ); + + PlayerRank pRank = player.getLadderRanks().get( defaultLadder ); +// PlayerRank pRank = getRank( player, "default" ); + double playerMultipler = pRank == null ? 0 : pRank.getRankMultiplier(); + + // So the actual rank multiplier that needs to be used, is based upon + // the + // Player's current multiplier PLUS the multiplier for the target rank + // AND MINUS the multiplier for the current rank the player has within + // the + // target rank's ladder. + double rankMultiplier = playerMultipler + targetRankMultiplier - existingRankMultiplier; + + targetPlayerRank = createPlayerRank( targetRank, rankMultiplier ); + } + + return targetPlayerRank; + } + + private RankLadder getDefaultLadder( RankPlayer player ) + { + RankLadder defaultLadder = null; + + for ( RankLadder ladder : player.getLadderRanks().keySet() ) + { + if ( ladder.getName().equalsIgnoreCase( "default" ) ) { + defaultLadder = ladder; + } + } + + return defaultLadder; + } + + private PlayerRank createPlayerRank( Rank rank, double rankMultiplier ) { + PlayerRank results = new PlayerRank( rank, rankMultiplier ); + + return results; + } + + public Rank getRank() { + return rank; + } + + public Double getRankMultiplier() { + return rankMultiplier; + } +// public void setRankMultiplier( Double rankMultiplier ) { +// this.rankMultiplier = rankMultiplier; +// } + + public Double getRankCost() { + return rankCost; + } +// public void setRankCost( Double rankCost ) { +// this.rankCost = rankCost; +// } + +} diff --git a/prison-ranks/src/main/java/tech/mcprison/prison/ranks/data/Rank.java b/prison-core/src/main/java/tech/mcprison/prison/ranks/data/Rank.java similarity index 71% rename from prison-ranks/src/main/java/tech/mcprison/prison/ranks/data/Rank.java rename to prison-core/src/main/java/tech/mcprison/prison/ranks/data/Rank.java index a21e0d7c6..72f15671b 100644 --- a/prison-ranks/src/main/java/tech/mcprison/prison/ranks/data/Rank.java +++ b/prison-core/src/main/java/tech/mcprison/prison/ranks/data/Rank.java @@ -22,11 +22,7 @@ import tech.mcprison.prison.modules.ModuleElement; import tech.mcprison.prison.modules.ModuleElementType; -import tech.mcprison.prison.output.Output; -import tech.mcprison.prison.ranks.PrisonRanks; -import tech.mcprison.prison.ranks.RankUtil; import tech.mcprison.prison.sorting.PrisonSortable; -import tech.mcprison.prison.store.Document; /** * Represents a single rank. @@ -34,7 +30,7 @@ * @author Faizaan A. Datoo */ public class Rank - extends RankMessages + //extends RankMessages implements PrisonSortable, ModuleElement { @@ -131,112 +127,112 @@ protected Rank( String name ) { this.name = name; } - @SuppressWarnings( "unchecked" ) - public Rank(Document document) { - this(); - - try - { -// Object pos = document.get("position"); -// this.position = RankUtil.doubleToInt( pos == null ? 0.0d : pos ); - - this.id = RankUtil.doubleToInt(document.get("id")); - this.name = (String) document.get("name"); - this.tag = (String) document.get("tag"); - this.cost = (double) document.get("cost"); - - String currency = (String) document.get("currency"); - this.currency = (currency == null || - "null".equalsIgnoreCase( currency ) ? null : currency); - - getRankUpCommands().clear(); - Object cmds = document.get("commands"); - if ( cmds != null ) { - - List commands = (List) cmds; - for ( String cmd : commands ) { - if ( cmd != null ) { - getRankUpCommands().add( cmd ); - } - } - - // This was allowing nulls to be added to the live commands... -// this.rankUpCommands = (List) cmds; - } - - getMines().clear(); - getMineStrings().clear(); - Object minesObj = document.get("mines"); - if ( minesObj != null ) { - List mineStrings = (List) minesObj; - setMineStrings( mineStrings ); - } - - -// getPermissions().clear(); -// Object perms = document.get( "permissions" ); -// if ( perms != null ) { -// List permissions = (List) perms; -// for ( String permission : permissions ) { -// getPermissions().add( permission ); +// @SuppressWarnings( "unchecked" ) +// public Rank(Document document) { +// this(); +// +// try +// { +//// Object pos = document.get("position"); +//// this.position = RankUtil.doubleToInt( pos == null ? 0.0d : pos ); +// +// this.id = RankUtil.doubleToInt(document.get("id")); +// this.name = (String) document.get("name"); +// this.tag = (String) document.get("tag"); +// this.cost = (double) document.get("cost"); +// +// String currency = (String) document.get("currency"); +// this.currency = (currency == null || +// "null".equalsIgnoreCase( currency ) ? null : currency); +// +// getRankUpCommands().clear(); +// Object cmds = document.get("commands"); +// if ( cmds != null ) { +// +// List commands = (List) cmds; +// for ( String cmd : commands ) { +// if ( cmd != null ) { +// getRankUpCommands().add( cmd ); +// } // } +// +// // This was allowing nulls to be added to the live commands... +//// this.rankUpCommands = (List) cmds; // } -// // -// getPermissionGroups().clear(); -// Object permsGroups = document.get( "permissionGroups" ); -// if ( perms != null ) { -// List permissionGroups = (List) permsGroups; -// for ( String permissionGroup : permissionGroups ) { -// getPermissionGroups().add( permissionGroup ); -// } +// getMines().clear(); +// getMineStrings().clear(); +// Object minesObj = document.get("mines"); +// if ( minesObj != null ) { +// List mineStrings = (List) minesObj; +// setMineStrings( mineStrings ); // } - - } - catch ( Exception e ) - { - String message = rankFailureLoadingRanksMsg( Integer.toString( this.id ), - (this.name == null ? "null" : this.name ), - e.getMessage() ); - - Output.get().logError( message ); - } - } - - public Document toDocument() { - Document ret = new Document(); -// ret.put("position", this.position ); - ret.put("id", this.id); - ret.put("name", this.name); - ret.put("tag", this.tag); - ret.put("cost", this.cost); - ret.put("currency", this.currency); - - List cmds = new ArrayList<>(); - for ( String cmd : getRankUpCommands() ) { - // Filters out possible nulls: - if ( cmd != null ) { - cmds.add( cmd ); - } - } - ret.put("commands", cmds); - - List mineStrings = new ArrayList<>(); - if ( getMines() != null ) { - for ( ModuleElement mine : getMines() ) { - String mineString = mine.getModuleElementType() + "," + mine.getName() + "," + - mine.getId() + "," + mine.getTag(); - mineStrings.add( mineString ); - } - } - ret.put("mines", mineStrings); - -// ret.put( "permissions", getPermissions() ); -// ret.put( "permissionGroups", getPermissionGroups() ); - - return ret; - } - +// +// +//// getPermissions().clear(); +//// Object perms = document.get( "permissions" ); +//// if ( perms != null ) { +//// List permissions = (List) perms; +//// for ( String permission : permissions ) { +//// getPermissions().add( permission ); +//// } +//// } +//// +//// +//// getPermissionGroups().clear(); +//// Object permsGroups = document.get( "permissionGroups" ); +//// if ( perms != null ) { +//// List permissionGroups = (List) permsGroups; +//// for ( String permissionGroup : permissionGroups ) { +//// getPermissionGroups().add( permissionGroup ); +//// } +//// } +// +// } +// catch ( Exception e ) +// { +// String message = rankFailureLoadingRanksMsg( Integer.toString( this.id ), +// (this.name == null ? "null" : this.name ), +// e.getMessage() ); +// +// Output.get().logError( message ); +// } +// } + +// public Document toDocument() { +// Document ret = new Document(); +//// ret.put("position", this.position ); +// ret.put("id", this.id); +// ret.put("name", this.name); +// ret.put("tag", this.tag); +// ret.put("cost", this.cost); +// ret.put("currency", this.currency); +// +// List cmds = new ArrayList<>(); +// for ( String cmd : getRankUpCommands() ) { +// // Filters out possible nulls: +// if ( cmd != null ) { +// cmds.add( cmd ); +// } +// } +// ret.put("commands", cmds); +// +// List mineStrings = new ArrayList<>(); +// if ( getMines() != null ) { +// for ( ModuleElement mine : getMines() ) { +// String mineString = mine.getModuleElementType() + "," + mine.getName() + "," + +// mine.getId() + "," + mine.getTag(); +// mineStrings.add( mineString ); +// } +// } +// ret.put("mines", mineStrings); +// +//// ret.put( "permissions", getPermissions() ); +//// ret.put( "permissionGroups", getPermissionGroups() ); +// +// return ret; +// } +// // /** @@ -292,11 +288,14 @@ public StatsRankPlayerBalance getStatsPlayerBlance() { * @param player */ public void addPlayer( RankPlayer player ) { + addPlayer( player, true ); + } + public void addPlayer( RankPlayer player, boolean checkPlayerBalances ) { if ( !getPlayers().contains( player ) ) { getPlayers().add( player ); - getStatsPlayerBlance().addPlayer( player ); + getStatsPlayerBlance().addPlayer( player, checkPlayerBalances ); } } @@ -320,10 +319,10 @@ public String filename() { public RankLadder getLadder() { - if ( ladder == null ) { - - ladder = PrisonRanks.getInstance().getLadderManager().getLadder( this ); - } +// if ( ladder == null ) { +// +// ladder = PrisonRanks.getInstance().getLadderManager().getLadder( this ); +// } return ladder; } @@ -442,6 +441,21 @@ public void setTag( String tag ) { this.tag = tag; } + /** + *

This is publicly available as "raw" to underscore that it is not an + * adjusted cost value. + *

+ * + * @param rank + * @return + */ + public double getRawRankCost() { + return cost; + } + public void setRawRankCost( double cost ) { + this.cost = cost; + } + protected double getCost() { return cost; } diff --git a/prison-ranks/src/main/java/tech/mcprison/prison/ranks/data/RankLadder.java b/prison-core/src/main/java/tech/mcprison/prison/ranks/data/RankLadder.java similarity index 71% rename from prison-ranks/src/main/java/tech/mcprison/prison/ranks/data/RankLadder.java rename to prison-core/src/main/java/tech/mcprison/prison/ranks/data/RankLadder.java index 8864a5a0c..47c899f2a 100644 --- a/prison-ranks/src/main/java/tech/mcprison/prison/ranks/data/RankLadder.java +++ b/prison-core/src/main/java/tech/mcprison/prison/ranks/data/RankLadder.java @@ -23,9 +23,6 @@ import com.google.gson.internal.LinkedTreeMap; -import tech.mcprison.prison.ranks.PrisonRanks; -import tech.mcprison.prison.ranks.RankUtil; -import tech.mcprison.prison.ranks.managers.RankManager; import tech.mcprison.prison.sorting.PrisonSortable; import tech.mcprison.prison.store.Document; @@ -82,131 +79,131 @@ public RankLadder( int id, String name ) { this.name = name; } - @SuppressWarnings( "unchecked" ) - public RankLadder(Document document, PrisonRanks prisonRanks) { - this(); - - boolean isDirty = false; - - this.id = RankUtil.doubleToInt(document.get("id")); - this.name = (String) document.get("name"); - - RankManager rankManager = prisonRanks.getRankManager(); - - if ( rankManager == null ) { - - RankMessages rMessages = new RankMessages(); - rMessages.rankFailureLoadingRankManagerMsg( getName(), getId() ); - - return; - } - - List> ranksLocal = - (List>) document.get("ranks"); - - getRankUpCommands().clear(); - Object cmds = document.get("commands"); - if ( cmds != null ) { - - List commands = (List) cmds; - for ( String cmd : commands ) { - if ( cmd != null ) { - getRankUpCommands().add( cmd ); - } - } - - // This was allowing nulls to be added to the live commands... -// this.rankUpCommands = (List) cmds; - } - - - this.ranks = new ArrayList<>(); - for (LinkedTreeMap rank : ranksLocal) { - - - // The only real field that is important here is rankId to tie the - // rank back to this ladder. Name helps clarify the contents of the - // Ladder file. - int rRankId = RankUtil.doubleToInt((rank.get("rankId"))); - String rRankName = (String) rank.get( "rankName" ); - - Rank rankPrison = rankManager.getRank( rRankId ); - - if ( rankPrison != null && rankPrison.getLadder() != null ) { - - RankMessages rMessages = new RankMessages(); - rMessages.rankFailureLoadingDuplicateRankMsg( - rankPrison.getName(), rankPrison.getLadder().getName(), - getName() ); - - isDirty = true; - } - else if ( rankPrison != null) { - - addRank( rankPrison ); - -// Output.get().logInfo( "RankLadder load : " + getName() + -// " rank= " + rankPrison.getName() + " " + rankPrison.getId() + -// ); - -// // if null look it up from loaded ranks: -// if ( rRankName == null ) { -// rRankName = rankPrison.getName(); -// dirty = true; -// } - } - else { - // Rank not found. Try to create it? The name maybe wrong. - String rankName = rRankName != null && !rRankName.trim().isEmpty() ? - rRankName : "Rank " + rRankId; - - // NOTE: The following is valid use of getCost(): - double cost = getRanks().size() == 0 ? 0 : - getRanks().get( getRanks().size() - 1 ).getCost() * 3; - Rank newRank = new Rank( rRankId, rankName, null, cost ); - - addRank( newRank ); - -// String message = String.format( -// "Loading RankLadder Error: A rank for %s was not found so it was " + -// "fabricated: %s id=%d tag=%s cost=%d", getName(), newRank.getName(), newRank.getId(), -// newRank.getTag(), newRank.getCost() ); -// Output.get().logError( message ); - } - - } - -// this.maxPrestige = RankUtil.doubleToInt(document.get("maxPrestige")); - - - Double rankCostMultiplier = (Double) document.get( "rankCostMultiplierPerRank" ); - setRankCostMultiplierPerRank( rankCostMultiplier == null ? 0 : rankCostMultiplier ); - - -// getPermissions().clear(); -// Object perms = document.get( "permissions" ); -// if ( perms != null ) { -// List permissions = (List) perms; -// for ( String permission : permissions ) { -// getPermissions().add( permission ); +// @SuppressWarnings( "unchecked" ) +// public RankLadder(Document document, PrisonRanks prisonRanks) { +// this(); +// +// boolean isDirty = false; +// +// this.id = ConversionUtil.doubleToInt(document.get("id")); +// this.name = (String) document.get("name"); +// +// RankManager rankManager = prisonRanks.getRankManager(); +// +// if ( rankManager == null ) { +// +// RankMessages rMessages = new RankMessages(); +// rMessages.rankFailureLoadingRankManagerMsg( getName(), getId() ); +// +// return; +// } +// +// List> ranksLocal = +// (List>) document.get("ranks"); +// +// getRankUpCommands().clear(); +// Object cmds = document.get("commands"); +// if ( cmds != null ) { +// +// List commands = (List) cmds; +// for ( String cmd : commands ) { +// if ( cmd != null ) { +// getRankUpCommands().add( cmd ); +// } // } +// +// // This was allowing nulls to be added to the live commands... +//// this.rankUpCommands = (List) cmds; // } +// +// +// this.ranks = new ArrayList<>(); +// for (LinkedTreeMap rank : ranksLocal) { +// +// +// // The only real field that is important here is rankId to tie the +// // rank back to this ladder. Name helps clarify the contents of the +// // Ladder file. +// int rRankId = ConversionUtil.doubleToInt((rank.get("rankId"))); +// String rRankName = (String) rank.get( "rankName" ); +// +// Rank rankPrison = rankManager.getRank( rRankId ); +// +// if ( rankPrison != null && rankPrison.getLadder() != null ) { +// +// RankMessages rMessages = new RankMessages(); +// rMessages.rankFailureLoadingDuplicateRankMsg( +// rankPrison.getName(), rankPrison.getLadder().getName(), +// getName() ); +// +// isDirty = true; +// } +// else if ( rankPrison != null) { +// +// addRank( rankPrison ); +// +//// Output.get().logInfo( "RankLadder load : " + getName() + +//// " rank= " + rankPrison.getName() + " " + rankPrison.getId() + +//// ); +// +//// // if null look it up from loaded ranks: +//// if ( rRankName == null ) { +//// rRankName = rankPrison.getName(); +//// dirty = true; +//// } +// } +// else { +// // Rank not found. Try to create it? The name maybe wrong. +// String rankName = rRankName != null && !rRankName.trim().isEmpty() ? +// rRankName : "Rank " + rRankId; +// +// // NOTE: The following is valid use of getCost(): +// double cost = getRanks().size() == 0 ? 0 : +// getRanks().get( getRanks().size() - 1 ).getCost() * 3; +// Rank newRank = new Rank( rRankId, rankName, null, cost ); +// +// addRank( newRank ); +// +//// String message = String.format( +//// "Loading RankLadder Error: A rank for %s was not found so it was " + +//// "fabricated: %s id=%d tag=%s cost=%d", getName(), newRank.getName(), newRank.getId(), +//// newRank.getTag(), newRank.getCost() ); +//// Output.get().logError( message ); +// } +// +// } +// +//// this.maxPrestige = RankUtil.doubleToInt(document.get("maxPrestige")); +// +// +// Double rankCostMultiplier = (Double) document.get( "rankCostMultiplierPerRank" ); +// setRankCostMultiplierPerRank( rankCostMultiplier == null ? 0 : rankCostMultiplier ); // // -// getPermissionGroups().clear(); -// Object permsGroups = document.get( "permissionGroups" ); -// if ( perms != null ) { -// List permissionGroups = (List) permsGroups; -// for ( String permissionGroup : permissionGroups ) { -// getPermissionGroups().add( permissionGroup ); -// } +//// getPermissions().clear(); +//// Object perms = document.get( "permissions" ); +//// if ( perms != null ) { +//// List permissions = (List) perms; +//// for ( String permission : permissions ) { +//// getPermissions().add( permission ); +//// } +//// } +//// +//// +//// getPermissionGroups().clear(); +//// Object permsGroups = document.get( "permissionGroups" ); +//// if ( perms != null ) { +//// List permissionGroups = (List) permsGroups; +//// for ( String permissionGroup : permissionGroups ) { +//// getPermissionGroups().add( permissionGroup ); +//// } +//// } +// +// if ( isDirty ) { +// PrisonRanks.getInstance().getLadderManager().save( this ); // } - - if ( isDirty ) { - PrisonRanks.getInstance().getLadderManager().save( this ); - } - - } +// +// } public Document toDocument() { Document ret = new Document(); diff --git a/prison-ranks/src/main/java/tech/mcprison/prison/ranks/data/RankPlayer.java b/prison-core/src/main/java/tech/mcprison/prison/ranks/data/RankPlayer.java similarity index 71% rename from prison-ranks/src/main/java/tech/mcprison/prison/ranks/data/RankPlayer.java rename to prison-core/src/main/java/tech/mcprison/prison/ranks/data/RankPlayer.java index a4b44bfc8..c3557da95 100644 --- a/prison-ranks/src/main/java/tech/mcprison/prison/ranks/data/RankPlayer.java +++ b/prison-core/src/main/java/tech/mcprison/prison/ranks/data/RankPlayer.java @@ -20,16 +20,15 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.TreeMap; import java.util.UUID; -import com.google.gson.internal.LinkedTreeMap; - import tech.mcprison.prison.Prison; import tech.mcprison.prison.PrisonAPI; +import tech.mcprison.prison.cache.PlayerCache; +import tech.mcprison.prison.cache.PlayerCachePlayerData; import tech.mcprison.prison.integration.EconomyCurrencyIntegration; import tech.mcprison.prison.integration.EconomyIntegration; import tech.mcprison.prison.internal.ItemStack; @@ -38,12 +37,6 @@ import tech.mcprison.prison.internal.inventory.Inventory; import tech.mcprison.prison.internal.scoreboard.Scoreboard; import tech.mcprison.prison.output.Output; -import tech.mcprison.prison.ranks.FirstJoinHandlerMessages; -import tech.mcprison.prison.ranks.PrisonRanks; -import tech.mcprison.prison.ranks.RankUtil; -import tech.mcprison.prison.ranks.events.FirstJoinEvent; -import tech.mcprison.prison.ranks.top.RankPlayerBalance; -import tech.mcprison.prison.store.Document; import tech.mcprison.prison.util.Gamemode; import tech.mcprison.prison.util.Location; @@ -72,8 +65,8 @@ public class RankPlayer private List names; - // Block name, count - private HashMap blocksMined; +// // Block name, count +// private HashMap blocksMined; // For tops processing. Need current balance. @@ -93,6 +86,8 @@ public RankPlayer() { this.ranksRefs = new HashMap<>(); //this.prestige = new HashMap<>(); +// this.blocksMined = new HashMap<>(); + this.playerBalances = new TreeMap<>(); } @@ -108,68 +103,68 @@ public RankPlayer( UUID uid, String playerName ) { checkName( playerName ); } - @SuppressWarnings( "unchecked" ) - public RankPlayer(Document document) { - this(); - - this.uid = UUID.fromString((String) document.get("uid")); - LinkedTreeMap ranksLocal = - (LinkedTreeMap) document.get("ranks"); -// LinkedTreeMap prestigeLocal = -// (LinkedTreeMap) document.get("prestige"); - - LinkedTreeMap blocksMinedLocal = - (LinkedTreeMap) document.get("blocksMined"); - - Object namesListObject = document.get( "names" ); - - - for (String key : ranksLocal.keySet()) { - ranksRefs.put(key, RankUtil.doubleToInt(ranksLocal.get(key))); - } - -// for (String key : prestigeLocal.keySet()) { -// prestige.put(key, RankUtil.doubleToInt(prestigeLocal.get(key))); +// @SuppressWarnings( "unchecked" ) +// public RankPlayer(Document document) { +// this(); +// +// this.uid = UUID.fromString((String) document.get("uid")); +// LinkedTreeMap ranksLocal = +// (LinkedTreeMap) document.get("ranks"); +//// LinkedTreeMap prestigeLocal = +//// (LinkedTreeMap) document.get("prestige"); +// +// LinkedTreeMap blocksMinedLocal = +// (LinkedTreeMap) document.get("blocksMined"); +// +// Object namesListObject = document.get( "names" ); +// +// +// for (String key : ranksLocal.keySet()) { +// ranksRefs.put(key, ConversionUtil.doubleToInt(ranksLocal.get(key))); // } - - this.blocksMined = new HashMap<>(); - if ( blocksMinedLocal != null ) { - for (String key : blocksMinedLocal.keySet()) { - blocksMined.put(key, RankUtil.doubleToInt(blocksMinedLocal.get(key))); - } - } - - if ( namesListObject != null ) { - - for ( Object rankPlayerNameMap : (ArrayList) namesListObject ) { - LinkedTreeMap rpnMap = (LinkedTreeMap) rankPlayerNameMap; - - if ( rpnMap.size() > 0 ) { - String name = (String) rpnMap.get( "name" ); - long date = RankUtil.doubleToLong( rpnMap.get( "date" ) ); - - RankPlayerName rankPlayerName = new RankPlayerName( name, date ); - getNames().add( rankPlayerName ); -// Output.get().logInfo( "RankPlayer: uuid: " + uid + " RankPlayerName: " + rankPlayerName.toString() ); - } - - } - } - - } - - public Document toDocument() { - Document ret = new Document(); - ret.put("uid", this.uid); - ret.put("ranks", this.ranksRefs); -// ret.put("prestige", this.prestige); - - ret.put("names", this.names); - - ret.put("blocksMined", this.blocksMined); - return ret; - } - +// +//// for (String key : prestigeLocal.keySet()) { +//// prestige.put(key, RankUtil.doubleToInt(prestigeLocal.get(key))); +//// } +// +// this.blocksMined = new HashMap<>(); +// if ( blocksMinedLocal != null ) { +// for (String key : blocksMinedLocal.keySet()) { +// blocksMined.put(key, ConversionUtil.doubleToInt(blocksMinedLocal.get(key))); +// } +// } +// +// if ( namesListObject != null ) { +// +// for ( Object rankPlayerNameMap : (ArrayList) namesListObject ) { +// LinkedTreeMap rpnMap = (LinkedTreeMap) rankPlayerNameMap; +// +// if ( rpnMap.size() > 0 ) { +// String name = (String) rpnMap.get( "name" ); +// long date = ConversionUtil.doubleToLong( rpnMap.get( "date" ) ); +// +// RankPlayerName rankPlayerName = new RankPlayerName( name, date ); +// getNames().add( rankPlayerName ); +//// Output.get().logInfo( "RankPlayer: uuid: " + uid + " RankPlayerName: " + rankPlayerName.toString() ); +// } +// +// } +// } +// +// } +// +// public Document toDocument() { +// Document ret = new Document(); +// ret.put("uid", this.uid); +// ret.put("ranks", this.ranksRefs); +//// ret.put("prestige", this.prestige); +// +// ret.put("names", this.names); +// +// ret.put("blocksMined", this.blocksMined); +// return ret; +// } +// @Override public String toString() { @@ -261,12 +256,12 @@ public void setNames( List names ) { this.names = names; } - public HashMap getBlocksMined() { - return blocksMined; - } - public void setBlocksMined( HashMap blocksMined ) { - this.blocksMined = blocksMined; - } +// public HashMap getBlocksMined() { +// return blocksMined; +// } +// public void setBlocksMined( HashMap blocksMined ) { +// this.blocksMined = blocksMined; +// } /** *

This is a helper function to ensure that the given file name is @@ -281,44 +276,44 @@ public String filename() } - /** - *

This function will check to see if the player is on the default rank on - * the default ladder. If not, then it will add them. - *

- * - *

This is safe to run on anyone, even if they already are on the default ladder. - *

- * - *

Note, this will not save the player's new rank. The save function must be - * managed and called outside of this. - *

- */ - public void firstJoin() { - - RankLadder defaultLadder = PrisonRanks.getInstance().getDefaultLadder(); - - if ( !getLadderRanks().containsKey( defaultLadder ) ) { - - Optional firstRank = defaultLadder.getLowestRank(); - - if ( firstRank.isPresent() ) { - Rank rank = firstRank.get(); - - addRank( rank ); - - Prison.get().getEventBus().post(new FirstJoinEvent( this )); - - FirstJoinHandlerMessages messages = new FirstJoinHandlerMessages(); - Output.get().logWarn( messages.firstJoinSuccess( getName() ) ); - - } else { - - FirstJoinHandlerMessages messages = new FirstJoinHandlerMessages(); - Output.get().logWarn( messages.firstJoinWarningNoRanksOnServer() ); - } - } - - } +// /** +// *

This function will check to see if the player is on the default rank on +// * the default ladder. If not, then it will add them. +// *

+// * +// *

This is safe to run on anyone, even if they already are on the default ladder. +// *

+// * +// *

Note, this will not save the player's new rank. The save function must be +// * managed and called outside of this. +// *

+// */ +// public void firstJoin() { +// +// RankLadder defaultLadder = PrisonRanks.getInstance().getDefaultLadder(); +// +// if ( !getLadderRanks().containsKey( defaultLadder ) ) { +// +// Optional firstRank = defaultLadder.getLowestRank(); +// +// if ( firstRank.isPresent() ) { +// Rank rank = firstRank.get(); +// +// addRank( rank ); +// +// Prison.get().getEventBus().post(new FirstJoinEvent( this )); +// +// FirstJoinHandlerMessages messages = new FirstJoinHandlerMessages(); +// Output.get().logWarn( messages.firstJoinSuccess( getName() ) ); +// +// } else { +// +// FirstJoinHandlerMessages messages = new FirstJoinHandlerMessages(); +// Output.get().logWarn( messages.firstJoinWarningNoRanksOnServer() ); +// } +// } +// +// } /** * Add a rank to this player. @@ -411,78 +406,74 @@ public boolean hasLadder( String ladderName ) { return ranksRefs.containsKey( ladderName ); } - /** - * Removes a ladder from this player, including whichever rank this player had in it. - * Cannot remove the default ladder. - * - * @param ladderName The ladder's name. - */ - public boolean removeLadder(String ladderName) { - boolean results = false; - if ( !ladderName.equalsIgnoreCase("default") ) { - Integer id = ranksRefs.remove(ladderName); - results = (id != null); - - RankLadder ladder = PrisonRanks.getInstance().getLadderManager().getLadder( ladderName ); - if ( ladder != null && !ladder.getName().equalsIgnoreCase( "default" ) ) { - ladderRanks.remove( ladder ); - } - } - - return results; - } - - /* - * Getters & Setters - */ - - /** - * Retrieves the rank that this player has in a certain ladder, if any. - * - * @param ladder The ladder to check. - * @return An optional containing the {@link Rank} if found, or empty if there isn't a rank by that ladder for this player. - */ - public PlayerRank getRank(RankLadder ladder) { - PlayerRank results = null; - - if ( ladder != null ) { - - Set keys = ladderRanks.keySet(); - for ( RankLadder key : keys ) - { - if ( key != null && key.getName().equalsIgnoreCase( ladder.getName() ) ) { - results = ladderRanks.get( key ); - } - } - } - - return results; - -// if (!ranksRefs.containsKey(ladder.getName())) { -// return null; +// /** +// * Removes a ladder from this player, including whichever rank this player had in it. +// * Cannot remove the default ladder. +// * +// * @param ladderName The ladder's name. +// */ +// public boolean removeLadder(String ladderName) { +// boolean results = false; +// if ( !ladderName.equalsIgnoreCase("default") ) { +// Integer id = ranksRefs.remove(ladderName); +// results = (id != null); +// +// RankLadder ladder = PrisonRanks.getInstance().getLadderManager().getLadder( ladderName ); +// if ( ladder != null && !ladder.getName().equalsIgnoreCase( "default" ) ) { +// ladderRanks.remove( ladder ); +// } // } -// int id = ranksRefs.get(ladder.getName()); -// return PrisonRanks.getInstance().getRankManager().getRank(id); - } - - /** - * Retrieves the rank that this player has the specified ladder. - * - * @param ladder The ladder name to check. - * @return The {@link Rank} if found, otherwise null; - */ - public PlayerRank getRank( String ladderName ) { - - RankLadder ladder = PrisonRanks.getInstance().getLadderManager().getLadder( ladderName ); - return getRank( ladder ); - -// Rank results = null; -// if (ladder != null && ranksRefs.containsKey(ladder)) { -// int id = ranksRefs.get(ladder); -// results = PrisonRanks.getInstance().getRankManager().getRank(id); +// +// return results; +// } + +// /** +// * Retrieves the rank that this player has in a certain ladder, if any. +// * +// * @param ladder The ladder to check. +// * @return An optional containing the {@link Rank} if found, or empty if there isn't a rank by that ladder for this player. +// */ +// public PlayerRank getRank(RankLadder ladder) { +// PlayerRank results = null; +// +// if ( ladder != null ) { +// +// Set keys = ladderRanks.keySet(); +// for ( RankLadder key : keys ) +// { +// if ( key != null && key.getName().equalsIgnoreCase( ladder.getName() ) ) { +// results = ladderRanks.get( key ); +// } +// } // } +// // return results; - } +// +//// if (!ranksRefs.containsKey(ladder.getName())) { +//// return null; +//// } +//// int id = ranksRefs.get(ladder.getName()); +//// return PrisonRanks.getInstance().getRankManager().getRank(id); +// } +// +// /** +// * Retrieves the rank that this player has the specified ladder. +// * +// * @param ladder The ladder name to check. +// * @return The {@link Rank} if found, otherwise null; +// */ +// public PlayerRank getRank( String ladderName ) { +// +// RankLadder ladder = PrisonRanks.getInstance().getLadderManager().getLadder( ladderName ); +// return getRank( ladder ); +// +//// Rank results = null; +//// if (ladder != null && ranksRefs.containsKey(ladder)) { +//// int id = ranksRefs.get(ladder); +//// results = PrisonRanks.getInstance().getRankManager().getRank(id); +//// } +//// return results; +// } @@ -497,42 +488,56 @@ public void setRanks( HashMap ranks ) { this.ranksRefs = ranks; } - /** - * Returns all ladders this player is a part of, along with each rank the player has in that ladder. - * - * @return The map containing this data. - */ - public Map getLadderRanks() { - - if ( ladderRanks.isEmpty() && !ranksRefs.isEmpty() ) { - - //Map ret = new HashMap<>(); - for (Map.Entry entry : ranksRefs.entrySet()) { - RankLadder ladder = PrisonRanks.getInstance().getLadderManager().getLadder(entry.getKey()); - - if ( ladder == null ) { - continue; // Skip it - } - - Rank rank = PrisonRanks.getInstance().getRankManager().getRank(entry.getValue()); - if ( rank == null ) { - continue; // Skip it - } - - PlayerRank pRank = new PlayerRank( rank ); - - ladderRanks.put(ladder, pRank); - } - - // Need to recalculate all rank multipliers: - recalculateRankMultipliers(); - } - - return ladderRanks; - } +// /** +// * Returns all ladders this player is a part of, along with each rank the player has in that ladder. +// * +// * @return The map containing this data. +// */ +// public Map getLadderRanks( RankPlayer rankPlay) { +// +// if ( ladderRanks.isEmpty() && !ranksRefs.isEmpty() ) { +// +// //Map ret = new HashMap<>(); +// +// for (Map.Entry entry : rankPlay.getRanksRefs().entrySet()) { +// RankLadder ladder = PrisonRanks.getInstance().getLadderManager().getLadder(entry.getKey()); +// +// if ( ladder == null ) { +// continue; // Skip it +// } +// +// Rank rank = PrisonRanks.getInstance().getRankManager().getRank(entry.getValue()); +// if ( rank == null ) { +// continue; // Skip it +// } +// +// PlayerRank pRank = new PlayerRank( rank ); +// +// ladderRanks.put(ladder, pRank); +// } +// +// // Need to recalculate all rank multipliers: +// recalculateRankMultipliers(); +// } +// +// return ladderRanks; +// } + public TreeMap getLadderRanks() { + return ladderRanks; + } +// public void setLadderRanks( TreeMap ladderRanks ) { +// this.ladderRanks = ladderRanks; +// } - /** + public HashMap getRanksRefs(){ + return ranksRefs ; + } + public void setRanksRefs( HashMap ranksRefs ) { + this.ranksRefs = ranksRefs; + } + + /** *

This function will check to see if the player has the same rank as the * targetRank, or if the target rank is lower on the ladder than where their * current rank is located. This confirms that the two ranks are on the same @@ -548,7 +553,9 @@ public boolean hasAccessToRank( Rank targetRank ) { if ( targetRank != null && targetRank.getLadder() != null ) { - PlayerRank pRank = getRank( targetRank.getLadder() ); + PlayerRank pRank = getLadderRanks().get( targetRank.getLadder() ); + +// PlayerRank pRank = getRank( targetRank.getLadder() ); if ( pRank != null ) { Rank rank = pRank.getRank(); @@ -995,9 +1002,26 @@ public List getPermissionsIntegrations( boolean detailed ) { @Override public void setTitle( String title, String subtitle, int fadeIn, int stay, int fadeOut ) { + Prison.get().getPlatform().setTitle( this, title, subtitle, fadeIn, stay, fadeOut ); } @Override public void setActionBar( String actionBar ) { + Prison.get().getPlatform().setActionBar( this, actionBar ); + } + + @Override + public PlayerCache getPlayerCache() { + return PlayerCache.getInstance(); + } + + @Override + public PlayerCachePlayerData getPlayerCachePlayerData() { + return PlayerCache.getInstance().getOnlinePlayer( this ); + } + + @Override + public boolean isSneaking() { + return false; } } diff --git a/prison-ranks/src/main/java/tech/mcprison/prison/ranks/top/RankPlayerBalance.java b/prison-core/src/main/java/tech/mcprison/prison/ranks/data/RankPlayerBalance.java similarity index 98% rename from prison-ranks/src/main/java/tech/mcprison/prison/ranks/top/RankPlayerBalance.java rename to prison-core/src/main/java/tech/mcprison/prison/ranks/data/RankPlayerBalance.java index 0aa4440cf..bd139d3c4 100644 --- a/prison-ranks/src/main/java/tech/mcprison/prison/ranks/top/RankPlayerBalance.java +++ b/prison-core/src/main/java/tech/mcprison/prison/ranks/data/RankPlayerBalance.java @@ -1,4 +1,4 @@ -package tech.mcprison.prison.ranks.top; +package tech.mcprison.prison.ranks.data; public class RankPlayerBalance { diff --git a/prison-ranks/src/main/java/tech/mcprison/prison/ranks/data/RankPlayerName.java b/prison-core/src/main/java/tech/mcprison/prison/ranks/data/RankPlayerName.java similarity index 100% rename from prison-ranks/src/main/java/tech/mcprison/prison/ranks/data/RankPlayerName.java rename to prison-core/src/main/java/tech/mcprison/prison/ranks/data/RankPlayerName.java diff --git a/prison-ranks/src/main/java/tech/mcprison/prison/ranks/data/StatsRankPlayerBalance.java b/prison-core/src/main/java/tech/mcprison/prison/ranks/data/StatsRankPlayerBalance.java similarity index 84% rename from prison-ranks/src/main/java/tech/mcprison/prison/ranks/data/StatsRankPlayerBalance.java rename to prison-core/src/main/java/tech/mcprison/prison/ranks/data/StatsRankPlayerBalance.java index 802f71289..821658333 100644 --- a/prison-ranks/src/main/java/tech/mcprison/prison/ranks/data/StatsRankPlayerBalance.java +++ b/prison-core/src/main/java/tech/mcprison/prison/ranks/data/StatsRankPlayerBalance.java @@ -36,10 +36,12 @@ public void refresh() { } } - public void addPlayer( RankPlayer player ) { + public void addPlayer( RankPlayer player, boolean checkPlayerBalances ) { - StatsRankPlayerBalanceData pStats = new StatsRankPlayerBalanceData( rank, - player, isHesitancyDelayPenaltyEnabled() ); + StatsRankPlayerBalanceData pStats = + new StatsRankPlayerBalanceData( rank, + player, isHesitancyDelayPenaltyEnabled(), + checkPlayerBalances ); if ( !playerStats.contains( pStats ) ) { playerStats.add( pStats ); } @@ -48,7 +50,7 @@ public void addPlayer( RankPlayer player ) { public void removePlayer( RankPlayer player ) { StatsRankPlayerBalanceData pStats = new StatsRankPlayerBalanceData( rank, - player, isHesitancyDelayPenaltyEnabled() ); + player, isHesitancyDelayPenaltyEnabled(), true ); if ( playerStats.contains( pStats ) ) { playerStats.remove( pStats ); } diff --git a/prison-ranks/src/main/java/tech/mcprison/prison/ranks/data/StatsRankPlayerBalanceData.java b/prison-core/src/main/java/tech/mcprison/prison/ranks/data/StatsRankPlayerBalanceData.java similarity index 89% rename from prison-ranks/src/main/java/tech/mcprison/prison/ranks/data/StatsRankPlayerBalanceData.java rename to prison-core/src/main/java/tech/mcprison/prison/ranks/data/StatsRankPlayerBalanceData.java index fa09e0030..2267bb596 100644 --- a/prison-ranks/src/main/java/tech/mcprison/prison/ranks/data/StatsRankPlayerBalanceData.java +++ b/prison-core/src/main/java/tech/mcprison/prison/ranks/data/StatsRankPlayerBalanceData.java @@ -9,13 +9,17 @@ public class StatsRankPlayerBalanceData private double score = 0; private double penalty = 0; - public StatsRankPlayerBalanceData( Rank rank, RankPlayer player, boolean isPleanltyEnabled ) { + public StatsRankPlayerBalanceData( Rank rank, RankPlayer player, + boolean isPleanltyEnabled, boolean checkPlayerBalances ) { super(); this.rank = rank; this.player = player; - recalc( isPleanltyEnabled ); + if ( checkPlayerBalances ) { + + recalc( isPleanltyEnabled ); + } } public StatsRankPlayerBalanceData() { @@ -31,7 +35,8 @@ public void recalc( boolean isPenaltyEnabled ) { // The "cost" should be the cost of the next rank. If the next rank does not exist, // then it should be the current rank. - PlayerRank pRank = player.getRank( rank.getLadder() ); + PlayerRank pRank = player.getLadderRanks().get( rank.getLadder() ); + if ( pRank != null ) { double cost = pRank.getRankCost(); // This is the fallback value if nextRank doesn't exist. @@ -39,7 +44,7 @@ public void recalc( boolean isPenaltyEnabled ) { if ( rank.getRankNext() != null ) { // This calculates the target rank, and takes in to consideration the player's existing rank: - PlayerRank pRankNext = PlayerRank.getTargetPlayerRankForPlayer( player, rank.getRankNext() ); + PlayerRank pRankNext = pRank.getTargetPlayerRankForPlayer( player, rank.getRankNext() ); //PlayerRank pRankNext = new PlayerRank( rank.getRankNext(), pRank.getRankMultiplier() ); cost = pRankNext.getRankCost(); diff --git a/prison-core/src/main/java/tech/mcprison/prison/selection/SelectionListener.java b/prison-core/src/main/java/tech/mcprison/prison/selection/SelectionListener.java index 4c63844d7..7faf7efe7 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/selection/SelectionListener.java +++ b/prison-core/src/main/java/tech/mcprison/prison/selection/SelectionListener.java @@ -23,7 +23,7 @@ import tech.mcprison.prison.PrisonAPI; import tech.mcprison.prison.internal.ItemStack; import tech.mcprison.prison.internal.Player; -import tech.mcprison.prison.internal.events.player.PlayerInteractEvent; +import tech.mcprison.prison.internal.events.player.PrisonPlayerInteractEvent; /** * @author Faizaan A. Datoo @@ -34,7 +34,8 @@ public void init() { Prison.get().getEventBus().register(this); } - @Subscribe public void onPlayerInteract(PlayerInteractEvent e) { + @Subscribe + public void onPlayerInteract(PrisonPlayerInteractEvent e) { ItemStack ourItem = e.getItemInHand(); ItemStack toolItem = SelectionManager.SELECTION_TOOL; @@ -43,7 +44,7 @@ public void init() { } e.setCanceled(true); - if (e.getAction() == PlayerInteractEvent.Action.LEFT_CLICK_BLOCK) { + if (e.getAction() == PrisonPlayerInteractEvent.Action.LEFT_CLICK_BLOCK) { // Set first position Selection sel = Prison.get().getSelectionManager().getSelection(e.getPlayer()); sel.setMin(e.getClicked()); @@ -52,7 +53,7 @@ public void init() { .sendMessage("&7First position set to &8" + e.getClicked().toBlockCoordinates()); checkForEvent(e.getPlayer(), sel); - } else if (e.getAction() == PlayerInteractEvent.Action.RIGHT_CLICK_BLOCK) { + } else if (e.getAction() == PrisonPlayerInteractEvent.Action.RIGHT_CLICK_BLOCK) { // Set second position Selection sel = Prison.get().getSelectionManager().getSelection(e.getPlayer()); sel.setMax(e.getClicked()); diff --git a/prison-core/src/main/java/tech/mcprison/prison/store/Collection.java b/prison-core/src/main/java/tech/mcprison/prison/store/Collection.java index 274fefa25..49b8aee74 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/store/Collection.java +++ b/prison-core/src/main/java/tech/mcprison/prison/store/Collection.java @@ -1,5 +1,6 @@ package tech.mcprison.prison.store; +import java.io.File; import java.util.List; import java.util.Optional; @@ -36,5 +37,7 @@ public interface Collection { public boolean delete(String name); + + public File backup(String name); } diff --git a/prison-core/src/main/java/tech/mcprison/prison/tasks/PrisonCommandTask.java b/prison-core/src/main/java/tech/mcprison/prison/tasks/PrisonCommandTask.java index f0895ec1a..ab454d52c 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/tasks/PrisonCommandTask.java +++ b/prison-core/src/main/java/tech/mcprison/prison/tasks/PrisonCommandTask.java @@ -66,6 +66,8 @@ public enum CustomPlaceholders { msg(CommandEnvironment.all_commands), broadcast(CommandEnvironment.all_commands), + title(CommandEnvironment.all_commands ), + actionBar(CommandEnvironment.all_commands ), inline(CommandEnvironment.all_commands), inlinePlayer(CommandEnvironment.all_commands), @@ -258,6 +260,8 @@ private String translateCommand( Player player, String command ) { if ( player != null ) { formatted = formatted .replace( "{msg}", "prison utils msg {player} " ) + .replace( "{actionBar}", "prison utils titles actionBar {player} " ) + .replace( "{title}", "prison utils titles title {player} " ) .replace( "{player}", player.getName()) .replace( "{player_uid}", player.getUUID().toString()) .replace( "{utilsDecay}", "prison utils decay" ); diff --git a/prison-core/src/main/java/tech/mcprison/prison/tasks/PrisonDispatchCommandTask.java b/prison-core/src/main/java/tech/mcprison/prison/tasks/PrisonDispatchCommandTask.java index f9f63a2f9..16ad2ba65 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/tasks/PrisonDispatchCommandTask.java +++ b/prison-core/src/main/java/tech/mcprison/prison/tasks/PrisonDispatchCommandTask.java @@ -46,24 +46,24 @@ public void run() { try { if ( playerTask && player != null ) { - double start = System.currentTimeMillis(); +// double start = System.currentTimeMillis(); PrisonAPI.dispatchCommand( player, task ); - double stop = System.currentTimeMillis(); - Output.get().logDebug( "PrisonDispatchCommandTask.run: (player) " + - (stop - start) + " ms player= " + player.getName() + - " task: " + task ); +// double stop = System.currentTimeMillis(); +// Output.get().logDebug( "PrisonDispatchCommandTask.run: (player) " + +// (stop - start) + " ms player= " + player.getName() + +// " task: " + task ); } else { - double start = System.currentTimeMillis(); +// double start = System.currentTimeMillis(); PrisonAPI.dispatchCommand( task ); - double stop = System.currentTimeMillis(); - Output.get().logDebug( "PrisonDispatchCommandTask.run: (console) " + - (stop - start) + " ms" + - " task: " + task ); +// double stop = System.currentTimeMillis(); +// Output.get().logDebug( "PrisonDispatchCommandTask.run: (console) " + +// (stop - start) + " ms" + +// " task: " + task ); } } catch ( Exception e ) { diff --git a/prison-core/src/main/java/tech/mcprison/prison/util/ConversionUtil.java b/prison-core/src/main/java/tech/mcprison/prison/util/ConversionUtil.java new file mode 100644 index 000000000..b70e97444 --- /dev/null +++ b/prison-core/src/main/java/tech/mcprison/prison/util/ConversionUtil.java @@ -0,0 +1,14 @@ +package tech.mcprison.prison.util; + +public class ConversionUtil +{ + + public static int doubleToInt(Object d) { + return Math.toIntExact(Math.round((double) d)); + } + + public static long doubleToLong(Object d) { + return Math.round((double) d); + } + +} diff --git a/prison-core/src/main/java/tech/mcprison/prison/util/JumboTextFont.java b/prison-core/src/main/java/tech/mcprison/prison/util/JumboTextFont.java index de6346734..976b1a99b 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/util/JumboTextFont.java +++ b/prison-core/src/main/java/tech/mcprison/prison/util/JumboTextFont.java @@ -22,7 +22,10 @@ public enum JumboTextFont { N("N", 5, "N N", "NN N", "N N N", "N NN", "N N" ), O("O", 5, " OOO ", "O O", "O O", "O O", " OOO " ), P("P", 5, "PPPP ", "P P", "PPPP ", "P ", "P "), - Q("Q", 5, " QQQ ", "Q Q", "Q \\ Q", "Q \\Q", " QQ \\" ), + + // Warning: Note that \Q is an escape code for regex block quote. + // So use lowercase q so it does not match. + Q("Q", 5, " QQQ ", "Q Q", "Q \\ Q", "Q \\q", " QQ \\" ), R("R", 5, "RRRR ", "R R", "RRRR ", "R R ", "R R" ), S("S", 5, " SSS ", "S ", " SSS ", " S", " SSS " ), T("T", 5, "TTTTT", " T ", " T ", " T ", " T " ), diff --git a/prison-core/src/main/java/tech/mcprison/prison/util/Location.java b/prison-core/src/main/java/tech/mcprison/prison/util/Location.java index 0eecfb64f..0db64010d 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/util/Location.java +++ b/prison-core/src/main/java/tech/mcprison/prison/util/Location.java @@ -21,6 +21,7 @@ import tech.mcprison.prison.Prison; import tech.mcprison.prison.internal.World; import tech.mcprison.prison.internal.block.Block; +import tech.mcprison.prison.internal.block.PrisonBlock; /** * Represents a location in a Minecraft world. @@ -136,6 +137,10 @@ public int getBlockZ() { public Block getBlockAt() { return world.getBlockAt(this); } + + public void setBlockAsync( PrisonBlock prisonBlock ) { + world.setBlockAsync( prisonBlock, this ); + } @Override public boolean equals(Object o) { if (this == o) { @@ -218,5 +223,43 @@ public Location add( Vector direction ) return results; } + + /** + *

This function will clone the current location object and then add/subtract the amount of + * x, y, and/or z to that location. To keep the same value for one or more of these coordinates + * then use a value of zero. + *

+ * + * @param x + * @param y + * @param z + * @return + */ + public Location getLocationAtDelta( int x, int y, int z ) + { + Location results = new Location( this ); + + results.setX( results.getX() + x ); + results.setY( results.getY() + y ); + results.setZ( results.getZ() + z ); + + return results; + } + + /** + *

Returns the block that is at the location of this object, offset by x, y, and/or z deltas. + *

+ * + * @param x + * @param y + * @param z + * @return + */ + public Block getBlockAtDelta( int x, int y, int z ) + { + Location results = getLocationAtDelta( x, y, z ); + + return getWorld().getBlockAt( results ); + } } diff --git a/prison-core/src/main/java/tech/mcprison/prison/util/PrisonTPS.java b/prison-core/src/main/java/tech/mcprison/prison/util/PrisonTPS.java index dc358a843..84e4326e9 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/util/PrisonTPS.java +++ b/prison-core/src/main/java/tech/mcprison/prison/util/PrisonTPS.java @@ -166,8 +166,18 @@ public class PrisonTPS * processing overhead. */ public static final double SUBMIT_TICKS_INTERVAL = 10; + public static final double SUBMIT_TICKS_INTERVAL_HIGH_RESOLUTION = 2; - public static final double TARGET_TPS_AVERAGE_DURATION_IN_TICKS = 20; + // When enabled for highResolution the resolution will be set to submit_ticks_interval == 1, + // false will be the value of SUBMIT_TICKS_INTERVAL: + public boolean highResolution = false; + + + // TPS_AVERAGE_READINGS_TO_INCLUDE needs to include more than just a few TPS + // points to prevent wild fluxuations. With interval at 10 and a total + // duration of 120 ticks, then the readings will be 12 data points. Less will + // reflect variations faster, more will smooth out the bumps and dips. + public static final double TARGET_TPS_AVERAGE_DURATION_IN_TICKS = 120; public static final double TPS_AVERAGE_READINGS_TO_INCLUDE = TARGET_TPS_AVERAGE_DURATION_IN_TICKS / SUBMIT_TICKS_INTERVAL; @@ -195,10 +205,30 @@ public class PrisonTPS public static final Object tpsLock = new Object(); + // When submitted, taskId identifies the job. A value of -1 indicates the job + // failed to be submitted, or is not valid. + private int taskId = -1; + public void submitAsyncTPSTask() { lastPollNano = System.nanoTime(); - PrisonTaskSubmitter.runTaskTimerAsync( this, 0, (int) SUBMIT_TICKS_INTERVAL ); + if ( taskId > -1 ) { + PrisonTaskSubmitter.cancelTask( taskId ); + + // reset the key values: + tpsHistory.clear();; + tpsMin = 20.0d; + tpsMax = 20.0d; + tpsSamples = 0; + + lastPollNano = System.nanoTime(); + + } + + int submitInterval = isHighResolution() ? 1 : (int) SUBMIT_TICKS_INTERVAL; + int taskId = PrisonTaskSubmitter.runTaskTimerAsync( this, 0, submitInterval ); + + this.taskId = taskId; } @@ -248,6 +278,27 @@ else if ( tps > tpsMax ) { lastPollNano = timeStartNano; } + + + public boolean isHighResolution() { + return highResolution; + } + + /** + *

If changing the resolution, then resubmit this task so + * it will have the low resolution (10 ticks) or high resolution + * (1 tick). + *

+ * + * @param highResolution + */ + public void setHighResolution( boolean highResolution ) { + this.highResolution = highResolution; + + submitAsyncTPSTask(); + } + + /** *

Note that the individual TPS entries have already been * averaged based upon the value of SUBMIT_TICKS_INTERVAL, which diff --git a/prison-core/src/main/java/tech/mcprison/prison/util/Text.java b/prison-core/src/main/java/tech/mcprison/prison/util/Text.java index f0ec6f69c..b1df3cc29 100644 --- a/prison-core/src/main/java/tech/mcprison/prison/util/Text.java +++ b/prison-core/src/main/java/tech/mcprison/prison/util/Text.java @@ -18,16 +18,20 @@ package tech.mcprison.prison.util; +import java.text.DecimalFormat; import java.text.NumberFormat; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Set; +import java.util.TreeMap; import java.util.regex.Matcher; import java.util.regex.Pattern; import tech.mcprison.prison.Prison; +import tech.mcprison.prison.placeholders.PlaceholdersUtil; /** * Provides utilities for manipulating text. @@ -67,6 +71,11 @@ public class Text { //#([A-Fa-f0-9]){6} + private static DecimalFormat dFmt = new DecimalFormat("#,##0.00"); + private static DecimalFormat iFmt = new DecimalFormat("#,##0"); + + + protected Text() { super(); @@ -349,7 +358,8 @@ public static String translateHexColorCodes( String text, char targetColorCode ) } else { while ( idxStart >= 0 ) { - sb.append( translateHexColorCodesCore( text.substring( idxEnd + 1, idxStart ), targetColorCode) ); + sb.append( translateHexColorCodesCore( + text.substring( idxEnd + (idxEnd == -1 ? 1 : 0), idxStart ), targetColorCode) ); idxEnd = text.indexOf( "\\E", idxStart ); @@ -358,13 +368,13 @@ public static String translateHexColorCodes( String text, char targetColorCode ) idxStart = -1; } else { - sb.append( text.substring( idxStart, idxEnd + 1 ) ); + sb.append( text.substring( idxStart, idxEnd ) ); idxStart = text.indexOf( "\\Q", idxEnd ); } } - if ( idxEnd < text.length() ) { - sb.append( text.substring( idxEnd + 1 ) ); + if ( idxStart == -1 && idxEnd >= 0 && (idxEnd) < text.length() ) { + sb.append( text.substring( idxEnd ) ); } } } @@ -404,6 +414,17 @@ public static String translateHexColorCodesCore(String message, char targetColor return results; } + + public static String convertToAmpColorCodes( String textEncoded ) { + + String results = textEncoded; + + if ( textEncoded != null && textEncoded.contains( COLOR_ ) ) { + results = textEncoded.replaceAll( COLOR_, "&" ); + } + + return results; + } /** * Converts a double (3.45) into a US-localized currency string ($3.45). @@ -529,5 +550,222 @@ public static String pluralize(String baseNoun, int quantity) { } } + + public static String formatTimeDaysHhMmSs( long timeMs ) { + + DecimalFormat iFmt = new DecimalFormat("#,##0"); + DecimalFormat tFmt = new DecimalFormat("00"); +// SimpleDateFormat sdFmt = new SimpleDateFormat( "HH:mm:ss" ); + +// long _sec = 1000; +// long _min = _sec * 60; +// long _hour = _min * 60; +// long _day = _hour * 24; + + long ms = timeMs; + long days = millisPerDay < ms ? ms / millisPerDay : 0; + + ms -= (days * millisPerDay); + long hours = millisPerHour < ms ? ms / millisPerHour : 0; + + ms -= (hours * millisPerHour); + long mins = millisPerMinute < ms ? ms / millisPerMinute : 0; + + ms -= (mins * millisPerMinute); + long secs = millisPerSecond < ms ? ms / millisPerSecond : 0; + + + String results = + (days == 0 ? "" : iFmt.format( days ) + "d ") + + tFmt.format( hours ) + ":" + + tFmt.format( mins ) + ":" + + tFmt.format( secs ) + ; + + return results; + } + + + public static List formatTreeMapStats( TreeMap statMap, + int columns ) { + return formatTreeMapStats( statMap, columns, false ); + } + + public static List formatTreeMapStats( TreeMap statMap, + int columns, boolean timeFormat ) { + + List msgs = new ArrayList<>(); + + Set keys = statMap.keySet(); + + + List values = new ArrayList<>(); +// List valueMaxLen = new ArrayList<>(); + +// StringBuilder sb = new StringBuilder(); +// int count = 0; + + for ( String earningKey : keys ) + { + String value = null; + Object valueObj = statMap.get( earningKey ); + + if ( valueObj instanceof Double ) { + + value = PlaceholdersUtil.formattedKmbtSISize( (Double) valueObj, dFmt, " &9" ); + } + else if ( valueObj instanceof Integer ) { + int intVal = (Integer) valueObj; + value = PlaceholdersUtil.formattedKmbtSISize( intVal, + ( intVal < 1000 ? iFmt : dFmt ), " &9" ); + } + else if ( valueObj instanceof Long && timeFormat ) { + + value = Text.formatTimeDaysHhMmSs( (Long) valueObj ); + } + else if ( valueObj instanceof Long ) { + + long longVal = (Long) valueObj; + value = PlaceholdersUtil.formattedKmbtSISize( longVal, + ( longVal < 1000 ? iFmt : dFmt ), " &9" ); + } + + String msg = String.format( "&3%s&8: &b%s", earningKey, value ).trim(); + +// String msgNoColor = Text.stripColor( msg ); +// int lenMNC = msgNoColor.length(); +// +// +// int col = values.size() % columns; + values.add( msg ); + +// if ( col >= valueMaxLen.size() || lenMNC > valueMaxLen.get( col ) ) { +// +// if ( col > valueMaxLen.size() - 1 ) { +// valueMaxLen.add( lenMNC ); +// } +// else { +// +// valueMaxLen.set( col, lenMNC ); +// } +// } + } + + msgs = formatColumnsFromList( values, columns ); + +// for ( int j = 0; j < values.size(); j++ ) +// { +// String msg = values.get( j ); +// +// int col = j % columns; +// +// int maxColumnWidth = col > valueMaxLen.size() - 1 ? +// msg.length() : +// valueMaxLen.get( col ); +// +// sb.append( msg ); +// +// // Pad the right of all content with spaces to align columns, up to a +// // given maxLength: +// String msgNoColor = Text.stripColor( msg ); +// int lenMNC = msgNoColor.length(); +// for( int i = lenMNC; i < maxColumnWidth; i++ ) { +// sb.append( " " ); +// } +// +// // The spacer: +// sb.append( " " ); +// +// if ( ++count % columns == 0 ) { +// msgs.add( String.format( +// " " + sb.toString() ) ); +// sb.setLength( 0 ); +// +// } +// } +// +// if ( sb.length() > 0 ) { +// +// msgs.add( String.format( +// " " + sb.toString() ) ); +// } + + return msgs; + } + + + public static List formatColumnsFromList( List textItems, + int columns ) { + + List msgs = new ArrayList<>(); + + List valueMaxLen = new ArrayList<>(); + + StringBuilder sb = new StringBuilder(); + int count = 0; + + // Find the maxLenght value for each column that will be generated: + for ( int i = 0; i < textItems.size(); i++ ) + { + String msg = textItems.get( i ); + + String msgNoColor = Text.stripColor( msg ); + int lenMNC = msgNoColor.length(); + + + int col = i % columns; + + if ( col >= valueMaxLen.size() || lenMNC > valueMaxLen.get( col ) ) { + + if ( col > valueMaxLen.size() - 1 ) { + valueMaxLen.add( lenMNC ); + } + else { + + valueMaxLen.set( col, lenMNC ); + } + } + } + + + for ( int j = 0; j < textItems.size(); j++ ) + { + String msg = textItems.get( j ); + + int col = j % columns; + + int maxColumnWidth = col > valueMaxLen.size() - 1 ? + msg.length() : + valueMaxLen.get( col ); + + sb.append( msg ); + + // Pad the right of all content with spaces to align columns, up to a + // given maxLength: + String msgNoColor = Text.stripColor( msg ); + int lenMNC = msgNoColor.length(); + for( int i = lenMNC; i < maxColumnWidth; i++ ) { + sb.append( " " ); + } + + // The spacer: + sb.append( " " ); + + if ( ++count % columns == 0 ) { + msgs.add( String.format( + " " + sb.toString() ) ); + sb.setLength( 0 ); + + } + } + + if ( sb.length() > 0 ) { + + msgs.add( String.format( + " " + sb.toString() ) ); + } + + return msgs; + } } 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 03c93341b..1ead9ee64 100644 --- a/prison-core/src/main/resources/lang/mines/de_DE.properties +++ b/prison-core/src/main/resources/lang/mines/de_DE.properties @@ -51,7 +51,7 @@ -messages__version=1 +messages__version=3 messages__auto_refresh=true @@ -68,8 +68,8 @@ autoblock_disable=&bAutoblock &7wurde deaktiviert. autopickup_enable=&bAutoblock &7wurde aktiviert. autopickup_disable=&bAutoblock &7wurde deaktiviert. teleported=&7Teleportiert zur Mine&3%1&7. -mine_reset=&7Die Mine wurde zurückegetzt. -mine_reset_fail=&7Mine konnte nicht zurückgesetzt werden. &8Prüfe die Konsole nach Details. +mine_reset=&7Die Mine &3%1&7 wurde zurückegetzt. +mine_reset_fail=&7Mine &3%1&7 konnte nicht zurückgesetzt werden. &8Prüfe die Konsole nach Details. mine_created=&7Mine erfolgreich erstellt. mine_deleted=&7Mine erfolgreich gelöscht. select_bounds=&7Du musst zuerst die Minenbegrenzung auswählen. &8Type /mines wand to do so. @@ -77,6 +77,7 @@ world_diff=&7Du kannst keine Minen in zwei verschiedenen Welten erstellen. mine_exists=&7Eine Mine mit diesem Namen existiert bereits. mine_does_not_exist=&7Eine Mine mit diesem Namen existiert nicht. spawn_set=&7Der Minen-spawnpoint wurde festgelegt. +spawn_removed=&7The mine spawnpoint has been removed. spawnpoint_same_world=&7Der &cspawnpoint &7muss in derselben &cWelt &7 sein wie die Mine. not_a_block=&c%1 &7ist kein Block. block_already_added=&7Dieser Block wurde bereits zu der Mine hinzugefügt. @@ -87,3 +88,11 @@ block_not_removed=&7Dieser Block ist nicht in dieser Mine vorhanden. block_deleted=&7Block &3%1 &7von der Mine entfernt &3%2&7. mine_redefined=&7Erfolgreich die Mine &3neudefiniert &7. missing_world=&7Die Welt, in der die Mine erstellt wurde, kann nicht gefunden werden. + +mines_mtp__unable_to_teleport=Sorry. You're unable to teleport there. +mines_mtp__unable_to_teleport_others=&3You cannot teleport other players to a mine. Ignoring parameter. +mines_mtp__no_target_mine_found=No target mine found. &3Resubmit teleport request with a mine name. +mines_mtp__player_must_be_in_game=mines_mtp__player_must_be_in_game +mines_mtp__player_must_be_in_game=&3Specified player is not in the game so they cannot be teleported. +mines_mtp__cannot_use_virtual_mines=&cInvalid option. This mine is a virtual mine&7. Use &a/mines set area &7to enable the mine. +mines_mtp__teleport_failed=&3Telport failed. Are you sure you're a Player? diff --git a/prison-core/src/main/resources/lang/mines/en_US.properties b/prison-core/src/main/resources/lang/mines/en_US.properties index 9f298827b..3159ad152 100644 --- a/prison-core/src/main/resources/lang/mines/en_US.properties +++ b/prison-core/src/main/resources/lang/mines/en_US.properties @@ -51,7 +51,7 @@ -messages__version=1 +messages__version=3 messages__auto_refresh=true @@ -68,8 +68,8 @@ autoblock_disable=&bAutoblock &7has been &cdisabled&7. autopickup_enable=&bAutopickup &7has been &aenabled&7. autopickup_disable=&bAutopickup &7has been &cdisabled&7. teleported=&7Teleported to mine &3%1&7. -mine_reset=&7The mine has been reset. -mine_reset_fail=&7Could not reset the mine. &8Check the console for details. +mine_reset=&7The mine &3%1&7 has been reset. +mine_reset_fail=&7Could not reset mine &3%1&7. &8Check the console for details. mine_created=&7Successfully created the mine. mine_deleted=&7Successfully deleted the mine. select_bounds=&7You need to select the mine boundaries first. &8Type /mines wand to do so. @@ -77,6 +77,7 @@ world_diff=&7You may not create mines across two different worlds. mine_exists=&7A mine by that name already exists. mine_does_not_exist=&7A mine by that name does not exist. spawn_set=&7The mine spawnpoint has been set. +spawn_removed=&7The mine spawnpoint has been removed. spawnpoint_same_world=&7The &cspawnpoint &7must be in the same &cworld &7as the mine. not_a_block=&c%1 &7is not a block. block_already_added=&7That block has already been added to the mine. @@ -88,3 +89,11 @@ block_deleted=&7Removed block &3%1 &7from mine &3%2&7. mine_redefined=&7Successfully &3redefined &7the mine. missing_world=&7The world that the mine was created in can't be found. block_search_blank=&7Enter a value to search for a block.&7. + +mines_mtp__unable_to_teleport=Sorry. You're unable to teleport there. +mines_mtp__unable_to_teleport_others=&3You cannot teleport other players to a mine. Ignoring parameter. +mines_mtp__no_target_mine_found=No target mine found. &3Resubmit teleport request with a mine name. +mines_mtp__player_must_be_in_game=mines_mtp__player_must_be_in_game +mines_mtp__player_must_be_in_game=&3Specified player is not in the game so they cannot be teleported. +mines_mtp__cannot_use_virtual_mines=&cInvalid option. This mine is a virtual mine&7. Use &a/mines set area &7to enable the mine. +mines_mtp__teleport_failed=&3Telport failed. Are you sure you're a Player? diff --git a/prison-core/src/main/resources/lang/mines/es_ES.properties b/prison-core/src/main/resources/lang/mines/es_ES.properties index 015de3856..6cfa3b940 100644 --- a/prison-core/src/main/resources/lang/mines/es_ES.properties +++ b/prison-core/src/main/resources/lang/mines/es_ES.properties @@ -51,7 +51,7 @@ -messages__version=1 +messages__version=3 messages__auto_refresh=true @@ -68,8 +68,8 @@ autoblock_disable=&7El &bBloque Automático &7ha sido &cdesactivado&7. autopickup_enable=&7La &bRecolección Automática &7ha sido &aactivada&7. autopickup_disable=&7La &bRecolección Automática &7ha sido &cdesactivada&7. teleported=&7Transportado a la mina &3%1&7. -mine_reset=&7La mina ha sido reiniciada. -mine_reset_fail=&7No se ha podido reiniciar la mina. &8Diríjase la consola para más detalles. +mine_reset=&7La mina &3%1&7 ha sido reiniciada. +mine_reset_fail=&7No se ha podido reiniciar la mina &3%1&7. &8Diríjase la consola para más detalles. mine_created=&7Mina creada exitosamente. mine_deleted=&7Mina eliminada exitosamente. select_bounds=&7Necesitas seleccionar los límites de la mina previamente. &8Escribe /mines wand para realizarlo. @@ -77,6 +77,7 @@ world_diff=&7No debes crear minas a través de dos mundos distintos. mine_exists=&7Ya existe una mina con ese nombre. mine_does_not_exist=&7No existe una mina con ese nombre. spawn_set=&7El punto de aparición (spawnpoint) de la mina ha sido definid. +spawn_removed=&7The mine spawnpoint has been removed. spawnpoint_same_world=&7El &cpunto de aparición &7debe estar en el mismo &cmundo &7que la mina. not_a_block=&c%1 &7no es un bloque. block_already_added=&7Ese bloque ya ha sido añadido a la mina. @@ -87,3 +88,11 @@ block_not_removed=&7Ese bloque no se encuentra en esta mina. block_deleted=&7Se ha eliminado el bloque &3%1 &7de la mina &3%2&7. mine_redefined=&7Se ha &3redefinido &7la mina exitosamente. missing_world=&7El mundo en el que se ha creado la mina no se ha podido encontrar. + +mines_mtp__unable_to_teleport=Sorry. You're unable to teleport there. +mines_mtp__unable_to_teleport_others=&3You cannot teleport other players to a mine. Ignoring parameter. +mines_mtp__no_target_mine_found=No target mine found. &3Resubmit teleport request with a mine name. +mines_mtp__player_must_be_in_game=mines_mtp__player_must_be_in_game +mines_mtp__player_must_be_in_game=&3Specified player is not in the game so they cannot be teleported. +mines_mtp__cannot_use_virtual_mines=&cInvalid option. This mine is a virtual mine&7. Use &a/mines set area &7to enable the mine. +mines_mtp__teleport_failed=&3Telport failed. Are you sure you're a Player? diff --git a/prison-core/src/main/resources/lang/mines/hu_HU.properties b/prison-core/src/main/resources/lang/mines/hu_HU.properties index 45893d91d..53bdccfa7 100644 --- a/prison-core/src/main/resources/lang/mines/hu_HU.properties +++ b/prison-core/src/main/resources/lang/mines/hu_HU.properties @@ -51,7 +51,7 @@ -messages__version=1 +messages__version=3 messages__auto_refresh=true @@ -68,8 +68,8 @@ autoblock_disable=&bAz auto. blokk &7letiltva. autopickup_enable=&bAz auto. felvétel &7engedélyezve. autopickup_disable=&bAz auto. felvétel &7letiltva. teleported=&7Teleportálás a(z) &3%1&7 bányához. -mine_reset=&7A bánya újratöltve. -mine_reset_fail=&7Nem lehet újratölteni a bányát. &8A részletekért nézd meg a konzolt. +mine_reset=&7A bánya újratöltve. &3%1&7 +mine_reset_fail=&7Nem lehet újratölteni a bányát. &3%1&7. &8A részletekért nézd meg a konzolt. mine_created=&7A bánya sikeresen létrehozva. mine_deleted=&7A bánya sikeresen törölve. select_bounds=&7Először ki kell választani a bánya határait. &8Típus /mines wand. @@ -77,6 +77,7 @@ world_diff=&7Nem hozhatsz létre bányákat két különböző világon. mine_exists=&7A bánya ezzel a névvel már létezik. mine_does_not_exist=&7A bánya ezzel a névvel nem létezik. spawn_set=&7A bánya spawnpontja beállítva. +spawn_removed=&7The mine spawnpoint has been removed. spawnpoint_same_world=&7A &cspawnpont-nak&7 ugyanabban a &cvilágban&7 bányában kell lennie. not_a_block=&c%1 &7nem egy blokk. block_already_added=&7Ez a blokk már felkerült a bányába. @@ -87,3 +88,11 @@ block_not_removed=&7Ez a blokk nem ebben a bányában van. block_deleted=&7A blokk törölve &3%1 &7a(z) &3%2&7 bányából. mine_redefined=&7A bányát sikeresen &3újradefiniálta&7. missing_world=&7Nem található meg a világ, amelyet a bányát hoztak létre. + +mines_mtp__unable_to_teleport=Sorry. You're unable to teleport there. +mines_mtp__unable_to_teleport_others=&3You cannot teleport other players to a mine. Ignoring parameter. +mines_mtp__no_target_mine_found=No target mine found. &3Resubmit teleport request with a mine name. +mines_mtp__player_must_be_in_game=mines_mtp__player_must_be_in_game +mines_mtp__player_must_be_in_game=&3Specified player is not in the game so they cannot be teleported. +mines_mtp__cannot_use_virtual_mines=&cInvalid option. This mine is a virtual mine&7. Use &a/mines set area &7to enable the mine. +mines_mtp__teleport_failed=&3Telport failed. Are you sure you're a Player? diff --git a/prison-core/src/main/resources/lang/mines/it_IT.properties b/prison-core/src/main/resources/lang/mines/it_IT.properties index 9b4359aa1..293a87e32 100644 --- a/prison-core/src/main/resources/lang/mines/it_IT.properties +++ b/prison-core/src/main/resources/lang/mines/it_IT.properties @@ -51,7 +51,7 @@ -messages__version=1 +messages__version=3 messages__auto_refresh=true @@ -68,8 +68,8 @@ autoblock_disable=&bAutoBlocco &7è stato &cdisabilitato&7. autopickup_enable=&bAutoRaccoglitore &7è stato &aabilitato&7. autopickup_disable=&bAutoRaccoglitore &7è stato &cdisabilitato&7. teleported=&7Teletrasportato alla miniera &3%1&7. -mine_reset=&7La miniera è stata resettata. -mine_reset_fail=&7Non è possibile resettare la miniera. &8Controllare la console per dettagli. +mine_reset=&7La miniera &3%1&7 è stata resettata. +mine_reset_fail=&7Non è possibile resettare la miniera &3%1&7. &8Controllare la console per dettagli. mine_created=&7Miniera creata con successo. mine_deleted=&7Miniera cancellata con successo. select_bounds=&7Prima hai bisogno di selezionare gli estremi (angoli) della miniera. &8Il quale solo /mines wand può farlo. @@ -77,6 +77,7 @@ world_diff=&7Non puoi creare due miniere attraverso due mondi differenti. mine_exists=&7Una miniera con quel nome esiste già. mine_does_not_exist=&7Una miniera con quel nome non esiste. spawn_set=&7Il punto di spawn della miniera è stato settato. +spawn_removed=&7The mine spawnpoint has been removed. spawnpoint_same_world=&7Il &cPunto di spawn &7deve essere nello stesso &cmondo &7della miniera. not_a_block=&c%1 &7non è un blocco. block_already_added=&7Quel blocco è già stato aggiunto alla miniera. @@ -87,3 +88,11 @@ block_not_removed=&7Quel blocco non è in quella miniera. block_deleted=&7Rimosso il blocco &3%1 &7dalla miniera &3%2&7. mine_redefined=&7E' con successo stata &3ridefinita &7la miniera. missing_world=&7Il mondo nel quale è stata creata la miniera non è stato trovato. + +mines_mtp__unable_to_teleport=Sorry. You're unable to teleport there. +mines_mtp__unable_to_teleport_others=&3You cannot teleport other players to a mine. Ignoring parameter. +mines_mtp__no_target_mine_found=No target mine found. &3Resubmit teleport request with a mine name. +mines_mtp__player_must_be_in_game=mines_mtp__player_must_be_in_game +mines_mtp__player_must_be_in_game=&3Specified player is not in the game so they cannot be teleported. +mines_mtp__cannot_use_virtual_mines=&cInvalid option. This mine is a virtual mine&7. Use &a/mines set area &7to enable the mine. +mines_mtp__teleport_failed=&3Telport failed. Are you sure you're a Player? diff --git a/prison-core/src/main/resources/lang/mines/nl_BE.properties b/prison-core/src/main/resources/lang/mines/nl_BE.properties index ed01bbabf..64f5480bf 100644 --- a/prison-core/src/main/resources/lang/mines/nl_BE.properties +++ b/prison-core/src/main/resources/lang/mines/nl_BE.properties @@ -51,7 +51,7 @@ -messages__version=1 +messages__version=3 messages__auto_refresh=true @@ -66,8 +66,8 @@ autosmelt_disable=&bAutosmelt &7is afgezet. autoblock_enable=&bAutoblock &7is aangezet. autoblock_disable=&bAutoblock &7is afgezet. teleported=&7Geteleporteerd naar mijn &3%1&7. -mine_reset=&7De mijn is hersteld. -mine_reset_fail=&7Kon mijn niet herstellen. &8Kijk in de console voor meer info. +mine_reset=&7De mijn &3%1&7 is hersteld. +mine_reset_fail=&7Kon mijn &3%1&7 niet herstellen. &8Kijk in de console voor meer info. mine_created=&7Mijn succesvol gecreëerd. mine_deleted=&7Mijn succesvol verwijderd. select_bounds=&7Je moet de mijn dimensies eerst selecteren. &8Type /mines wand om dat te doen. @@ -75,6 +75,7 @@ world_diff=&7Je kan geen mijn creëren over twee werelden. mine_exists=&7Een mijn met die naam bestaat al. mine_does_not_exist=&7Een mijn met die naam bestaat niet. spawn_set=&7De mijn zijn startpunt is gezet. +spawn_removed=&7The mine spawnpoint has been removed. spawnpoint_same_world=&7Het startpunt moet in dezelfde wereld als de mijn zijn . not_a_block=&c%1 &7is geen blok. block_already_added=&7Deze blok is al in de mijn toegevoegd. @@ -85,3 +86,11 @@ block_not_removed=&7Die blok kon niet verwijderd worden. block_deleted=&7Blok &3%1 verwijderd &7van mijn &3%2&7. mine_redefined=&7Succesvol de mijn &3geherdefineerd. missing_world=&7De wereld van deze mijn kon niet worden gevonden. + +mines_mtp__unable_to_teleport=Sorry. You're unable to teleport there. +mines_mtp__unable_to_teleport_others=&3You cannot teleport other players to a mine. Ignoring parameter. +mines_mtp__no_target_mine_found=No target mine found. &3Resubmit teleport request with a mine name. +mines_mtp__player_must_be_in_game=mines_mtp__player_must_be_in_game +mines_mtp__player_must_be_in_game=&3Specified player is not in the game so they cannot be teleported. +mines_mtp__cannot_use_virtual_mines=&cInvalid option. This mine is a virtual mine&7. Use &a/mines set area &7to enable the mine. +mines_mtp__teleport_failed=&3Telport failed. Are you sure you're a Player? diff --git a/prison-core/src/main/resources/lang/mines/nl_NL.properties b/prison-core/src/main/resources/lang/mines/nl_NL.properties index ed01bbabf..64f5480bf 100644 --- a/prison-core/src/main/resources/lang/mines/nl_NL.properties +++ b/prison-core/src/main/resources/lang/mines/nl_NL.properties @@ -51,7 +51,7 @@ -messages__version=1 +messages__version=3 messages__auto_refresh=true @@ -66,8 +66,8 @@ autosmelt_disable=&bAutosmelt &7is afgezet. autoblock_enable=&bAutoblock &7is aangezet. autoblock_disable=&bAutoblock &7is afgezet. teleported=&7Geteleporteerd naar mijn &3%1&7. -mine_reset=&7De mijn is hersteld. -mine_reset_fail=&7Kon mijn niet herstellen. &8Kijk in de console voor meer info. +mine_reset=&7De mijn &3%1&7 is hersteld. +mine_reset_fail=&7Kon mijn &3%1&7 niet herstellen. &8Kijk in de console voor meer info. mine_created=&7Mijn succesvol gecreëerd. mine_deleted=&7Mijn succesvol verwijderd. select_bounds=&7Je moet de mijn dimensies eerst selecteren. &8Type /mines wand om dat te doen. @@ -75,6 +75,7 @@ world_diff=&7Je kan geen mijn creëren over twee werelden. mine_exists=&7Een mijn met die naam bestaat al. mine_does_not_exist=&7Een mijn met die naam bestaat niet. spawn_set=&7De mijn zijn startpunt is gezet. +spawn_removed=&7The mine spawnpoint has been removed. spawnpoint_same_world=&7Het startpunt moet in dezelfde wereld als de mijn zijn . not_a_block=&c%1 &7is geen blok. block_already_added=&7Deze blok is al in de mijn toegevoegd. @@ -85,3 +86,11 @@ block_not_removed=&7Die blok kon niet verwijderd worden. block_deleted=&7Blok &3%1 verwijderd &7van mijn &3%2&7. mine_redefined=&7Succesvol de mijn &3geherdefineerd. missing_world=&7De wereld van deze mijn kon niet worden gevonden. + +mines_mtp__unable_to_teleport=Sorry. You're unable to teleport there. +mines_mtp__unable_to_teleport_others=&3You cannot teleport other players to a mine. Ignoring parameter. +mines_mtp__no_target_mine_found=No target mine found. &3Resubmit teleport request with a mine name. +mines_mtp__player_must_be_in_game=mines_mtp__player_must_be_in_game +mines_mtp__player_must_be_in_game=&3Specified player is not in the game so they cannot be teleported. +mines_mtp__cannot_use_virtual_mines=&cInvalid option. This mine is a virtual mine&7. Use &a/mines set area &7to enable the mine. +mines_mtp__teleport_failed=&3Telport failed. Are you sure you're a Player? diff --git a/prison-core/src/main/resources/lang/mines/zh_TW.properties b/prison-core/src/main/resources/lang/mines/zh_TW.properties index 1a521c308..1d85f0401 100644 --- a/prison-core/src/main/resources/lang/mines/zh_TW.properties +++ b/prison-core/src/main/resources/lang/mines/zh_TW.properties @@ -51,7 +51,7 @@ -messages__version=2 +messages__version=4 messages__auto_refresh=true @@ -68,8 +68,8 @@ autoblock_disable=&b自動合成方塊 &7已被 &c停用&7 autopickup_enable=&b自動拾取 &7已被 &a啟用&7 autopickup_disable=&b自動拾取 &7已被 &c停用&7 teleported=&7正在傳送到 礦場 &3%1&7 -mine_reset=&7礦場已經被重置 -mine_reset_fail=&7礦場重置錯誤。 &8請打開 Console 查看細節 +mine_reset=&7礦場已經被重置。 &3%1&7 +mine_reset_fail=&7礦場重置錯誤。 &3%1&7。 &8請打開 Console 查看細節 mine_created=&7礦場 已成功 建立 mine_deleted=&7礦場 已成功 刪除 select_bounds=&7您必須要先選擇 礦場 的 界線。 &8如果想要 請輸入 /mines @@ -77,6 +77,7 @@ world_diff=&7您不能在多個世界中建立礦場 mine_exists=&7此礦場名稱已經存在 mine_does_not_exist=&7此礦場名稱並不存在 spawn_set=&7礦場出生點 已成功 設定 +spawn_removed=&7The mine spawnpoint has been removed. spawnpoint_same_world=&7這個 &c出生點 &7必須與其他 礦場 在同一個 &c世界 not_a_block=&c%1 &7不是一個方塊 block_already_added=&7此方塊已經被新增到礦場 @@ -88,3 +89,11 @@ block_deleted=&7將方塊 &3%1 &7從礦場 &3%2 &7中刪除 mine_redefined=&7成功 &3重新宣告 &7礦場 missing_world=&7無法找到已經建立礦場的世界 block_search_blank=&7請輸入值以搜索方塊。&7 + +mines_mtp__unable_to_teleport=Sorry. You're unable to teleport there. +mines_mtp__unable_to_teleport_others=&3You cannot teleport other players to a mine. Ignoring parameter. +mines_mtp__no_target_mine_found=No target mine found. &3Resubmit teleport request with a mine name. +mines_mtp__player_must_be_in_game=mines_mtp__player_must_be_in_game +mines_mtp__player_must_be_in_game=&3Specified player is not in the game so they cannot be teleported. +mines_mtp__cannot_use_virtual_mines=&cInvalid option. This mine is a virtual mine&7. Use &a/mines set area &7to enable the mine. +mines_mtp__teleport_failed=&3Telport failed. Are you sure you're a Player? diff --git a/prison-core/src/main/resources/lang/spigot/en_US.properties b/prison-core/src/main/resources/lang/spigot/en_US.properties index 444d11ae0..ee4df1d54 100644 --- a/prison-core/src/main/resources/lang/spigot/en_US.properties +++ b/prison-core/src/main/resources/lang/spigot/en_US.properties @@ -49,11 +49,256 @@ ## /prison support submit. ## - -messages__version=1 +messages__version=4 messages__auto_refresh=true +## Click to do something +spigot_gui_lore_click_to_add=Click to add. +spigot_gui_lore_click_to_add_backpack=Click to add a Backpack. +spigot_gui_lore_click_to_cancel=Click to cancel. +spigot_gui_lore_click_to_close=Click to close. +spigot_gui_lore_click_to_confirm=Click to confirm. +spigot_gui_lore_click_to_decrease=Click to decrease. +spigot_gui_lore_click_to_delete=Click to delete. +spigot_gui_lore_click_to_disable=Click to disable. +spigot_gui_lore_click_to_edit=Click to edit. +spigot_gui_lore_click_to_enable=Click to enable. +spigot_gui_lore_click_to_increase=Click to increase. +spigot_gui_lore_click_to_manage_rank=Click to manage Rank. +spigot_gui_lore_click_to_open=Click to open. +spigot_gui_lore_click_to_rankup=Click to Rankup. +spigot_gui_lore_click_to_rename=Click to rename. +spigot_gui_lore_click_to_select=Click to select. +spigot_gui_lore_click_to_start_block_setup=Click to add a block. +spigot_gui_lore_click_to_teleport=Click to teleport. +spigot_gui_lore_click_to_use=Click to use. + +## Left-Click to do something. +spigot_gui_lore_click_left_to_confirm=Left-Click to confirm. +spigot_gui_lore_click_left_to_reset=Left-Click to reset. +spigot_gui_lore_click_left_to_open=Left-Click to open. +spigot_gui_lore_click_left_to_edit=Left-Click to edit. + +## Right-Click to do something. +spigot_gui_lore_click_right_to_cancel=Right-Click to cancel. +spigot_gui_lore_click_right_to_delete=Right-Click to delete. +spigot_gui_lore_click_right_to_disable=Right-Click to disable. +spigot_gui_lore_click_right_to_enable=Right-Click to enable. +spigot_gui_lore_click_right_to_toggle=Right-Click to toggle. + +## Shift and Right-Click to do something +spigot_gui_lore_click_right_and_shift_to_delete=Shift and Right-Click to delete. +spigot_gui_lore_click_right_and_shift_to_disable=Shift and Right-Click to disable. +spigot_gui_lore_click_right_and_shift_to_toggle=Shift and Right-Click to toggle. + +## Titles or data naming. +spigot_gui_lore_backpack_id=Backpack ID: +spigot_gui_lore_blocks=Blocks: +spigot_gui_lore_blocktype=Blocktype: +spigot_gui_lore_chance=Chance: +spigot_gui_lore_command=Command: +spigot_gui_lore_currency=Currency: +spigot_gui_lore_delay=Delay: +spigot_gui_lore_id=ID: +spigot_gui_lore_info=Info: +spigot_gui_lore_minename=Minename: +spigot_gui_lore_multiplier=Multiplier: +spigot_gui_lore_name=Name: +spigot_gui_lore_owner=Owner: +spigot_gui_lore_percentage=Percentage: +spigot_gui_lore_permission=Permission: +spigot_gui_lore_players_at_rank=Players at rank: +spigot_gui_lore_prestige_name=Prestige name: +spigot_gui_lore_price=Price: +spigot_gui_lore_radius=Radius: +spigot_gui_lore_rank_tag=Rank Tag: +spigot_gui_lore_reset_time=Reset time(s): +spigot_gui_lore_size=Size: +spigot_gui_lore_show_item=Show Item: +spigot_gui_lore_spawnpoint=Spawnpoint: +spigot_gui_lore_volume=Volume: +spigot_gui_lore_value=Value: +spigot_gui_lore_world=World: + +## Simple actions or status. +spigot_gui_lore_disabled=Disabled. +spigot_gui_lore_enabled=Enabled. +spigot_gui_lore_locked=Locked! +spigot_gui_lore_next_page=Next page. +spigot_gui_lore_prior_page=Prior page. +spigot_gui_lore_rankup=Rankup. +spigot_gui_lore_selected=Selected. +spigot_gui_lore_unlocked=Unlocked! + +## Descriptions. +spigot_gui_lore_add_backpack_instruction_1=Please add at least one item +spigot_gui_lore_add_backpack_instruction_2=If you don't, the Backpack +spigot_gui_lore_add_backpack_instruction_3=Won't be saved. +spigot_gui_lore_prestige_warning_1=Prestige will reset: +spigot_gui_lore_prestige_warning_2=- Rank. +spigot_gui_lore_prestige_warning_3=- Balance. +spigot_gui_lore_ranks_setup_1=There aren't Ranks! +spigot_gui_lore_ranks_setup_2=If you want continue the setup. +spigot_gui_lore_ranks_setup_3=All Ranks and Mines from A to Z will be made +spigot_gui_lore_ranks_setup_4=With &adefault &3values! +spigot_gui_lore_ranks_setup_5=You can also use: +spigot_gui_lore_ranks_setup_6=/ranks autoConfigure full ! +spigot_gui_lore_ranks_setup_7=Please replace the X with the starting price and +spigot_gui_lore_ranks_setup_8=multiplier, default price = 50000, multiplier = 1.5. +spigot_gui_lore_sellall_delay_use_1=Short delay before using again +spigot_gui_lore_sellall_delay_use_2=the &3/sellall sell &8command. +spigot_gui_lore_set_mine_delay_instruction_1=Set a mine's delay +spigot_gui_lore_set_mine_delay_instruction_2=before reset when it +spigot_gui_lore_set_mine_delay_instruction_3=reaches zero blocks. +spigot_gui_lore_show_item_description_1=This's the item +spigot_gui_lore_show_item_description_2=shown in the Player's GUI +spigot_gui_lore_show_item_description_3=or /mines GUI. +spigot_gui_lore_skip_reset_instruction_1=Skip the reset if +spigot_gui_lore_skip_reset_instruction_2=not enough blocks +spigot_gui_lore_skip_reset_instruction_3=have been mined. + +## Button names or single line descriptions. +spigot_gui_lore_autofeatures_button_description=Manage AutoFeatures. +spigot_gui_lore_backpacks_button_description=Manage BackPacks. +spigot_gui_lore_disable_notifications=Disable notifications. +spigot_gui_lore_enable_radius_mode=Enable Radius mode. +spigot_gui_lore_enable_within_mode=Enable Within mode. +spigot_gui_lore_mines_button_description=Manage Mines. +spigot_gui_lore_no_multipliers=[!] There aren't multipliers! +spigot_gui_lore_ranks_button_description=Ranks GUI manager. +spigot_gui_lore_rankup_if_enough_money=If you have enough money. +spigot_gui_lore_sellall_button_description=Manage SellAll. +spigot_gui_lore_sellall_edit_info=Edit SellAll Currency. +spigot_gui_lore_tp_to_mine=Click to teleport to Mine. + +## Messages +spigot_message_missing_permission=Sorry, You don't have the permission to use that! +spigot_message_chat_event_time_end=You ran out of time, event cancelled! +spigot_message_event_cancelled=Event cancelled. +spigot_message_command_wrong_format=Sorry, wrong command format. +spigot_message_console_error=Sorry, you need to be a player to use that. + +## Ladder Messages +spigot_message_ladder_default_empty=Sorry, the Default Ladder's empty. + +## Mine Messages +spigot_message_mines_disabled=Sorry, Mines are disabled. +spigot_message_mines_name_chat_1=Please write the &6mineName &7you'd like to use and &6submit&7. +spigot_message_mines_name_chat_2=Input &cclose &7to cancel or wait &c30 seconds&7. +spigot_message_mines_name_chat_cancelled=Rename Mine &cclosed&7, nothing got changed! +spigot_message_mines_item_show_edit_success=Mine show item edited with success. +spigot_message_mines_or_gui_disabled=Sorry, Mines or GUIs are disabled. + +## Backpack Messages +spigot_message_backpack_cant_own=Sorry, you can't own Backpacks. +spigot_message_backpack_delete_error=Sorry, can't delete Backpack. +spigot_message_backpack_delete_success=Backpack deleted with success. +spigot_message_backpack_format_error=Sorry, the command format isn't right, maybe some arguments are missing. +spigot_message_backpack_limit_decrement_fail=The Backpack Limit can't be negative. +spigot_message_backpack_limit_edit_success=Backpack Limit edited with success. +spigot_message_backpack_limit_not_number=Sorry, the Backpack Limit isn't a number. +spigot_message_backpack_limit_reached=Sorry, you can't own more Backpacks. +spigot_message_backpack_missing_playername=Sorry, please add a valid Player name. +spigot_message_backpack_resize_success=If the Backpack exists, it got resized with success. +spigot_message_backpack_size_must_be_multiple_of_9=The Backpack size must be a multiple of 9 and not exceed 64! + + +## Prestige Messages +spigot_message_prestiges_disabled=Sorry, Prestiges are disabled. +spigot_message_prestiges_empty=Sorry, there aren't Prestiges. +spigot_message_prestiges_or_gui_disabled=Sorry, Prestiges or GUIs are disabled. +spigot_message_prestiges_confirm=Confirm&7: Type the word &aconfirm&7 to confirm. +spigot_message_prestiges_cancel=Cancel&7: Type the word &ccancel&7 to cancel, &cyou've 30 seconds. +spigot_message_prestiges_cancelled=Prestige cancelled. +spigot_message_prestiges_cancelled_wrong_keyword=Prestige &ccancelled&7, you didn't type the word: &aconfirm&7. -spigot___= +## Ranks Messages +spigot_message_ranks_disabled=Sorry, Ranks are disabled. +spigot_message_ranks_or_gui_disabled=Sorry, Ranks or GUIs are disabled. +spigot_message_ranks_tag_chat_rename_1=Please write the &6tag &7you'd like to use and &6submit&7. +spigot_message_ranks_tag_chat_rename_2=Input &cclose &7to cancel or wait &c30 seconds&7. +spigot_message_ranks_tag_chat_cancelled=Rename tag &cclosed&7, nothing got changed! +## SellAll Messages +spigot_message_sellall_auto_already_enabled=Sellall Auto already enabled. +spigot_message_sellall_auto_already_disabled=SellAll Auto already disabled. +spigot_message_sellall_auto_disabled=SellAll Auto disabled with success. +spigot_message_sellall_auto_disabled_cant_use=Sorry, you need to enable AutoSell to use this. +spigot_message_sellall_auto_enabled=SellAll Auto enabled with success. +spigot_message_sellall_auto_perusertoggleable_enabled=Sellall Auto perUserToggleable enabled with success. +spigot_message_sellall_auto_perusertoggleable_disabled=Sellall Auto perUserToggleable disabled with success. +spigot_message_sellall_auto_perusertoggleable_already_enabled=Sellall Auto perUserToggleable already enabled. +spigot_message_sellall_auto_perusertoggleable_already_disabled=Sellall Auto perUserToggleable already disabled. +spigot_message_sellall_boolean_input_invalid=The boolean value isn't valid (Valid values are True or False). +spigot_message_sellall_cant_find_item_config=Sorry, can't find your item in the config. +spigot_message_sellall_currency_chat_1=&3Started setup of new currency for SellAll! +spigot_message_sellall_currency_chat_2=Type &ccancel &7to cancel. +spigot_message_sellall_currency_chat_3=Type &3default &7to set to default currency. +spigot_message_sellall_currency_chat_4=Type the &aCurrency name &7to set the new currency. +spigot_message_sellall_currency_edit_success=SellAll Currency edited with success. +spigot_message_sellall_currency_not_found=Sorry, currency not found. +spigot_message_sellall_hand_disabled=SellAll Hand disabled with success. +spigot_message_sellall_hand_enabled=Sellall Hand enabled with success. +spigot_message_sellall_hand_is_disabled=SellAll Hand is disabled. +spigot_message_sellall_item_add_success=Item added with success. +spigot_message_sellall_item_already_added=You've already added this item, please use the edit command instead. +spigot_message_sellall_item_delete_success=Item deleted with success. +spigot_message_sellall_item_edit_success=SellAll Item edited with success. +spigot_message_sellall_item_id_not_found=Sorry, invalid Item Name/ID. +spigot_message_sellall_item_missing_name=Please add the Item Name/ID argument. +spigot_message_sellall_item_missing_price=Please add Item Value argument. +spigot_message_sellall_item_not_found=SellAll Item not found in the config. +spigot_message_sellall_default_values_success=SellAll Default values set with success. +spigot_message_sellall_delay_already_enabled=SellAll Delay already enabled. +spigot_message_sellall_delay_already_disabled=SellAll Delay already disabled. +spigot_message_sellall_delay_disabled=SellAll Delay disabled with success. +spigot_message_sellall_delay_disabled_cant_use=Sorry, please enable SellAll Delay to use this. +spigot_message_sellall_delay_edit_success=Sellall Delay edited with success. +spigot_message_sellall_delay_enabled=SellAll Delay enabled with success. +spigot_message_sellall_delay_not_number=SellAll Delay number isn't valid. +spigot_message_sellall_delay_wait=Please wait the end of the delay before using again the command. +spigot_message_sellall_gui_disabled=SellAll GUI is disabled. +spigot_message_sellall_money_earned=You got &a$ +spigot_message_sellall_multiplier_add_success=SellAll Multiplier added with success. +spigot_message_sellall_multiplier_are_disabled=Sorry, SellAll Multipliers are disabled. +spigot_message_sellall_multiplier_cant_find=Sorry, can't find SellAll Multiplier. +spigot_message_sellall_multiplier_delete_success=SellAll Multiplier deleted with success. +spigot_message_sellall_multiplier_disabled=SellAll Multipliers Disabled with success. +spigot_message_sellall_multiplier_edit_success=SellAll Multiplier edited with success. +spigot_message_sellall_multiplier_enabled=SellAll Multipliers Enabled with success. +spigot_message_sellall_sell_empty=Sorry, there aren't items in the SellAll shop. +spigot_message_sellall_sell_nothing_sellable=Sorry but you've nothing to sell. +spigot_message_sellall_sell_sign_only=You can use SellAll Sell only with Signs. +spigot_message_sellall_sell_sign_notify=You sold trough a sign with success. +spigot_message_sellall_trigger_already_disabled=SellAll Trigger already disabled. +spigot_message_sellall_trigger_already_enabled=SellAll Trigger already enabled. +spigot_message_sellall_trigger_disabled=SellAll Trigger disabled with success. +spigot_message_sellall_trigger_enabled=SellAll Trigger enabled with success. +spigot_message_sellall_trigger_is_disabled=Sorry, SellAll Trigger is disabled. +spigot_message_sellall_trigger_item_add_success=SellAll Item Trigger added with success. +spigot_message_sellall_trigger_item_cant_find=SellAll Item Trigger item not found in the config. +spigot_message_sellall_trigger_item_delete_success=SellAll Item Trigger deleted with success. +spigot_message_sellall_trigger_item_missing=Please add Item Name/ID to the command. +## GUI Messages +spigot_message_gui_backpack_disabled=Can't open GUI, Backpacks are disabled. +spigot_message_gui_backpack_empty=Sorry, there aren't Backpacks to show. +spigot_message_gui_backpack_too_many=Sorry, there are too many Backpacks and the GUI can't show them. +spigot_message_gui_close_success=GUI closed with success. +spigot_message_gui_error=Can't open GUI, disabled or error. +spigot_message_gui_error_empty=Can't open GUI, it's empty. +spigot_message_gui_ladder_empty=Sorry, there aren't Ladders to show. +spigot_message_gui_ladder_too_many=Sorry, there are too many Ladders and the GUI can't show them. +spigot_message_gui_mines_empty=Sorry, there aren't Mines to show. +spigot_message_gui_mines_too_many=Sorry, there are too many Mines for the GUI to show. +spigot_message_gui_prestiges_empty=Sorry, there aren't Prestiges to show. +spigot_message_gui_prestiges_too_many=Sorry, there are too many Prestiges and the GUI can't show them. +spigot_message_gui_ranks_empty=Sorry, there aren't Ranks in this Ladder to show. +spigot_message_gui_ranks_rankup_commands_empty=Sorry, there aren't Rankup Commands to show. +spigot_message_gui_ranks_rankup_commands_too_many=Sorry, there are too many Rankup Commands and the GUI can't show them. +spigot_message_gui_ranks_too_many=Sorry, there are too many Ranks and the GUI can't show them. +spigot_message_gui_reload_success=GUIs reloaded with success! +spigot_message_gui_sellall_disabled=Sorry, SellAll is disabled. +spigot_message_gui_sellall_empty=Sorry, there's nothing to show. +spigot_message_gui_too_high=Sorry, but the value is too high (above maximum possible). +spigot_message_gui_too_low_value=Sorry, but the value is too low (below minimum possible). \ No newline at end of file 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 a0b2b64fe..0299dad54 100644 --- a/prison-core/src/test/java/tech/mcprison/prison/TestPlatform.java +++ b/prison-core/src/test/java/tech/mcprison/prison/TestPlatform.java @@ -25,6 +25,7 @@ import java.util.Map; import java.util.Optional; import java.util.TreeMap; +import java.util.TreeSet; import java.util.UUID; import tech.mcprison.prison.PrisonCommand.RegisteredPluginsData; @@ -276,6 +277,22 @@ public long getConfigLong( String key, long defaultValue ) { public double getConfigDouble( String key, double defaultValue ) { return defaultValue; } + + @Override + public List getConfigStringArray( String key ) { + return new ArrayList(); + } + + @Override + public boolean isWorldExcluded( String worldName ) { + return false; + } + + @Override + public TreeSet getExcludedWorlds() + { + return new TreeSet<>(); + } @Override public PrisonBlockTypes getPrisonBlockTypes() { @@ -361,6 +378,11 @@ public void traceEventListenersBlockBreakEvents( CommandSender sender ) { } + @Override + public String dumpEventListenersPlayerInteractEvents() { + return ""; + } + @Override public void testPlayerUtil( UUID uuid ) { @@ -422,7 +444,25 @@ public ChatDisplay dumpEventListenersChatDisplay( String eventType, HandlerList * tech.mcprison.prison.autofeatures.AutoFeaturesFileConfig.reloadConfig() * */ + @Override public void reloadAutoFeaturesEventListeners() { } + + @Override + public void setTitle( Player player, String title, String subtitle, int fadeIn, int stay, int fadeOut ) + { + + } + + @Override + public void setActionBar( Player player, String actionBar ) + { + + } + + @Override + public int compareServerVerisonTo( String comparisonVersion ) { + return 0; + } } 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 52d75f24f..3e7e10a06 100644 --- a/prison-core/src/test/java/tech/mcprison/prison/TestPlayer.java +++ b/prison-core/src/test/java/tech/mcprison/prison/TestPlayer.java @@ -24,6 +24,8 @@ import java.util.Optional; import java.util.UUID; +import tech.mcprison.prison.cache.PlayerCache; +import tech.mcprison.prison.cache.PlayerCachePlayerData; import tech.mcprison.prison.internal.ItemStack; import tech.mcprison.prison.internal.Player; import tech.mcprison.prison.internal.block.Block; @@ -194,4 +196,22 @@ public void setTitle( String title, String subtitle, int fadeIn, int stay, int f @Override public void setActionBar( String actionBar ) { } + + @Override + public PlayerCache getPlayerCache() + { + return null; + } + + @Override + public PlayerCachePlayerData getPlayerCachePlayerData() + { + return null; + } + + @Override + public boolean isSneaking() { + return false; + } + } diff --git a/prison-core/src/test/java/tech/mcprison/prison/TestWorld.java b/prison-core/src/test/java/tech/mcprison/prison/TestWorld.java index a95546a19..72d67a289 100644 --- a/prison-core/src/test/java/tech/mcprison/prison/TestWorld.java +++ b/prison-core/src/test/java/tech/mcprison/prison/TestWorld.java @@ -21,8 +21,11 @@ import java.util.List; import tech.mcprison.prison.internal.Player; +import tech.mcprison.prison.internal.PrisonStatsElapsedTimeNanos; import tech.mcprison.prison.internal.World; import tech.mcprison.prison.internal.block.Block; +import tech.mcprison.prison.internal.block.MineResetType; +import tech.mcprison.prison.internal.block.MineTargetPrisonBlock; import tech.mcprison.prison.internal.block.PrisonBlock; import tech.mcprison.prison.util.Location; @@ -52,4 +55,16 @@ public TestWorld(String name) { @Override public void setBlock( PrisonBlock block, int x, int y, int z ) { } + + @Override + public void setBlockAsync( PrisonBlock prisonBlock, Location location ) { + } + + @Override + public void setBlocksSynchronously( List tBlocks, + MineResetType resetType, + PrisonStatsElapsedTimeNanos nanos ) { + + } + } diff --git a/prison-core/src/test/java/tech/mcprison/prison/bombs/MineBombEffectsDataTest.java b/prison-core/src/test/java/tech/mcprison/prison/bombs/MineBombEffectsDataTest.java new file mode 100644 index 000000000..e958991ff --- /dev/null +++ b/prison-core/src/test/java/tech/mcprison/prison/bombs/MineBombEffectsDataTest.java @@ -0,0 +1,57 @@ +package tech.mcprison.prison.bombs; + +import static org.junit.Assert.assertEquals; + +import java.util.ArrayList; +import java.util.List; +import java.util.TreeSet; + +import org.junit.Test; + +public class MineBombEffectsDataTest + extends MineBombEffectsData +{ + + @Test + public final void testCompare() + { + + MineBombEffectsData mbef01 = new MineBombEffectsData("ABC", EffectState.explode, 0 ); + MineBombEffectsData mbef02 = new MineBombEffectsData("XYZ", EffectState.placed, 3 ); + + MineBombEffectsData mbef03 = new MineBombEffectsData("BDF", EffectState.finished, 14 ); + MineBombEffectsData mbef04 = new MineBombEffectsData("DEF", EffectState.finished, 0 ); + + MineBombEffectsData mbef05 = new MineBombEffectsData("ABC", EffectState.placed, 0 ); + + + assertEquals( 1, compare( mbef01, mbef02 ) ); + + TreeSet xParticleEffects = new TreeSet<>( new MineBombEffectsData() ); + + xParticleEffects.add( mbef01 ); + xParticleEffects.add( mbef02 ); + xParticleEffects.add( mbef03 ); + xParticleEffects.add( mbef04 ); + xParticleEffects.add( mbef05 ); + + List testList = new ArrayList<>( xParticleEffects ); + + // mbef05 should be sorted "first": + assertEquals( mbef05, xParticleEffects.first() ); + + // mbef03 should be sorted "last": + assertEquals( mbef03, xParticleEffects.last() ); + + + assertEquals( 5, testList.size() ); + + assertEquals( mbef05, testList.get( 0 ) ); + assertEquals( mbef02, testList.get( 1 ) ); + assertEquals( mbef01, testList.get( 2 ) ); + assertEquals( mbef04, testList.get( 3 ) ); + assertEquals( mbef03, testList.get( 4 ) ); + + } + +} 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 b1d2a8bfa..8c01dfa75 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 @@ -28,7 +28,7 @@ import tech.mcprison.prison.TestWorld; import tech.mcprison.prison.internal.ItemStack; import tech.mcprison.prison.internal.World; -import tech.mcprison.prison.internal.events.player.PlayerInteractEvent; +import tech.mcprison.prison.internal.events.player.PrisonPlayerInteractEvent; import tech.mcprison.prison.util.BlockType; import tech.mcprison.prison.util.Location; import tech.mcprison.prison.util.Text; @@ -59,13 +59,13 @@ public class SelectionTest { coloredToolItemStack .setDisplayName(Text.translateAmpColorCodes(coloredToolItemStack.getDisplayName())); - Prison.get().getEventBus().post(new PlayerInteractEvent(ourPlayer, coloredToolItemStack, - PlayerInteractEvent.Action.LEFT_CLICK_BLOCK, new Location(ourWorld, 10, 20, 30))); + Prison.get().getEventBus().post(new PrisonPlayerInteractEvent(ourPlayer, coloredToolItemStack, + PrisonPlayerInteractEvent.Action.LEFT_CLICK_BLOCK, new Location(ourWorld, 10, 20, 30))); assertTrue(ourPlayer.getInput().contains("&7First position set to &8(10, 20, 30)")); - Prison.get().getEventBus().post(new PlayerInteractEvent(ourPlayer, coloredToolItemStack, - PlayerInteractEvent.Action.RIGHT_CLICK_BLOCK, new Location(ourWorld, 30, 20, 40))); + Prison.get().getEventBus().post(new PrisonPlayerInteractEvent(ourPlayer, coloredToolItemStack, + PrisonPlayerInteractEvent.Action.RIGHT_CLICK_BLOCK, new Location(ourWorld, 30, 20, 40))); assertTrue(ourPlayer.getInput().contains("&7Second position set to &8(30, 20, 40)")); } @@ -79,8 +79,8 @@ public class SelectionTest { int initialAmount = ourPlayer.getInput().size(); Prison.get().getEventBus().post( - new PlayerInteractEvent(ourPlayer, new ItemStack("test", 1, BlockType.ACACIA_SAPLING), - PlayerInteractEvent.Action.LEFT_CLICK_BLOCK, new Location(ourWorld, 10, 20, 30))); + new PrisonPlayerInteractEvent(ourPlayer, new ItemStack("test", 1, BlockType.ACACIA_SAPLING), + PrisonPlayerInteractEvent.Action.LEFT_CLICK_BLOCK, new Location(ourWorld, 10, 20, 30))); assertEquals(initialAmount, ourPlayer.getInput() .size()); // nothing should have happened because we have the wrong item in our hand diff --git a/prison-core/src/test/java/tech/mcprison/prison/util/TextTest.java b/prison-core/src/test/java/tech/mcprison/prison/util/TextTest.java index 8dcea75b5..9c038a37d 100644 --- a/prison-core/src/test/java/tech/mcprison/prison/util/TextTest.java +++ b/prison-core/src/test/java/tech/mcprison/prison/util/TextTest.java @@ -69,6 +69,11 @@ public void testTranslateColorCodesQuotedText() { assertEquals("This x7is xra &1t&2e&3s&4t", replaceColorCodeWithx( translateColorCodes("This &7is &Ra \\Q&1t&2e&3s&4t\\E", '&'))); + // Test with 2 quotes: + String results1 = replaceColorCodeWithx( + translateColorCodes("This &7is &Ra \\Q&1t&2e&3s&4t\\E &7and \\Q&1m&2o&3r&4e\\E", '&') ); + assertEquals("This x7is xra &1t&2e&3s&4t x7and &1m&2o&3r&4e", results1 ); + } /** @@ -131,4 +136,24 @@ public void testHexColors() { translateColorCodes("This &7is #a3b4c5 &Ra test \\Q#123456 test\\E test2 \\Q#778899 test\\E", '&'), '^' )); } + + + @Test + public void testBadRegexBlockQuote() { + + + // Test with quotes just to show it works: + String results1 = replaceColorCodeWithx( + translateColorCodes("This &7is \\Q&1t&2e\\E", '&')); + assertEquals("This x7is &1t&2e", results1 ); + assertEquals( 16, results1.length() ); + + // Test with no ending quotes: + String results2= replaceColorCodeWithx( + translateColorCodes("A&7b \\Q&1c&2d", '&')); + assertEquals("Ax7b &1c&2d", results2); + assertEquals( 11, results2.length() ); + + + } } 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 3111f2930..da33a9961 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 @@ -32,7 +32,7 @@ import tech.mcprison.prison.mines.commands.MinesCommands; import tech.mcprison.prison.mines.data.Mine; import tech.mcprison.prison.mines.data.MineScheduler.MineResetActions; -import tech.mcprison.prison.mines.data.MineScheduler.MineResetType; +import tech.mcprison.prison.mines.data.MineScheduler.MineResetScheduleType; import tech.mcprison.prison.mines.data.MinesConfig; import tech.mcprison.prison.mines.data.PrisonSortableResults; import tech.mcprison.prison.mines.managers.MineManager; @@ -41,6 +41,7 @@ import tech.mcprison.prison.output.Output; import tech.mcprison.prison.store.Database; import tech.mcprison.prison.util.Location; +import tech.mcprison.prison.util.Text; /** * The Prison 3 Mines Module @@ -178,7 +179,7 @@ private void initDb() { private void initConfig() { config = new MinesConfig(); - File configFile = new File(getDataFolder(), "config.json"); + File configFile = new File(getModuleDataFolder(), "config.json"); if (!configFile.exists()) { getJsonFileIO().saveJsonFile( configFile, config ); @@ -280,7 +281,7 @@ public Mine findMineLocation( Location blockLocation ) { * @param resetType * @param resetActions */ - public void resetAllMines( MineResetType resetType, List resetActions ) { + public void resetAllMines( MineResetScheduleType resetType, List resetActions ) { getMineManager().resetAllMines( resetType, resetActions ); } @@ -334,7 +335,7 @@ public PrisonSortableResults getMines( MineSortOrder sortOrder ) { } public Mine getMine(String mineName) { - return getMineManager().getMine(mineName); + return getMineManager().getMine( Text.stripColor( mineName ) ); } public LocaleManager getMinesMessages() { 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 2f978af11..44041d8e8 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 @@ -71,6 +71,12 @@ public void addBlockCommand(CommandSender sender, return; } + if ( !prisonBlock.isBlock() ) { + pMines.getMinesMessages().getLocalizable("not_a_block"). + withReplacements(block).sendTo(sender); + return; + } + // if (m.isInMine(prisonBlock)) { // pMines.getMinesMessages().getLocalizable("block_already_added"). @@ -129,6 +135,9 @@ else if ( chance <= 0 ) { percentTotal.getOldBlock().setChance( chance ); } + // Check if one of the blocks is effected by gravity, and if so, set that indicator. + m.checkGravityAffectedBlocks(); + pMines.getMineManager().saveMine( m ); pMines.getMinesMessages().getLocalizable("block_added") @@ -150,6 +159,11 @@ private void updateMinePrisonBlock( CommandSender sender, Mine m, PrisonBlock pr sender.sendMessage( "The percent chance must have a value greater than zero." ); } else { + + // Check if one of the blocks is effected by gravity, and if so, set that indicator. + m.checkGravityAffectedBlocks(); + + // Delete the block since it exists and the chance was set to zero: deleteBlock( sender, pMines, m, existingPrisonBlock ); } @@ -178,6 +192,9 @@ private void updateMinePrisonBlock( CommandSender sender, Mine m, PrisonBlock pr existingPrisonBlock.setChance( chance ); } + // Check if one of the blocks is effected by gravity, and if so, set that indicator. + m.checkGravityAffectedBlocks(); + pMines.getMineManager().saveMine( m ); pMines.getMinesMessages().getLocalizable("block_set") @@ -186,6 +203,9 @@ private void updateMinePrisonBlock( CommandSender sender, Mine m, PrisonBlock pr else { prisonBlock.setChance( chance ); m.addPrisonBlock( prisonBlock ); + + // Check if one of the blocks is effected by gravity, and if so, set that indicator. + m.checkGravityAffectedBlocks(); pMines.getMineManager().saveMine( m ); @@ -478,6 +498,10 @@ public void setBlockCommand(CommandSender sender, percentTotal.getOldBlock().setChance( chance ); + // Check if one of the blocks is effected by gravity, and if so, set that indicator. + m.checkGravityAffectedBlocks(); + + pMines.getMineManager().saveMine( m ); pMines.getMinesMessages().getLocalizable("block_set") @@ -604,6 +628,12 @@ public void delBlockCommand(CommandSender sender, deleteBlock( sender, pMines, m, preexistingPrisonBlock ); } + else { + + pMines.getMinesMessages().getLocalizable("block_not_removed") + .sendTo(sender); + return; + } } else { @@ -637,6 +667,10 @@ public void delBlockCommand(CommandSender sender, */ private void deleteBlock( CommandSender sender, PrisonMines pMines, Mine m, PrisonBlock prisonBlock ) { if ( m.removePrisonBlock( prisonBlock ) ) { + + // Check if one of the blocks is effected by gravity, and if so, set that indicator. + m.checkGravityAffectedBlocks(); + pMines.getMineManager().saveMine( m ); pMines.getMinesMessages().getLocalizable("block_deleted"). @@ -661,6 +695,10 @@ private void deleteBlock( CommandSender sender, PrisonMines pMines, Mine m, Bloc } } if ( m.getBlocks().remove( rBlock )) { + + // Check if one of the blocks is effected by gravity, and if so, set that indicator. + m.checkGravityAffectedBlocks(); + pMines.getMineManager().saveMine( m ); pMines.getMinesMessages().getLocalizable("block_deleted") @@ -871,6 +909,11 @@ public void listBlockCommand(CommandSender sender, PrisonMines pMines = PrisonMines.getInstance(); Mine m = pMines.getMine(mineName); + if ( m == null ) { + sender.sendMessage( "Invalid mine name." ); + return; + } + DecimalFormat dFmt = new DecimalFormat("#,##0"); DecimalFormat fFmt = new DecimalFormat("#,##0.00"); diff --git a/prison-mines/src/main/java/tech/mcprison/prison/mines/commands/MinesCommandMessages.java b/prison-mines/src/main/java/tech/mcprison/prison/mines/commands/MinesCommandMessages.java new file mode 100644 index 000000000..6281b61fd --- /dev/null +++ b/prison-mines/src/main/java/tech/mcprison/prison/mines/commands/MinesCommandMessages.java @@ -0,0 +1,73 @@ +package tech.mcprison.prison.mines.commands; + +import tech.mcprison.prison.commands.BaseCommands; +import tech.mcprison.prison.internal.CommandSender; +import tech.mcprison.prison.mines.PrisonMines; + +public class MinesCommandMessages + extends BaseCommands +{ + + public MinesCommandMessages( String cmdGroup ) + { + super( cmdGroup ); + } + + protected void exampleMsg( CommandSender sender, String mineName ) { + PrisonMines.getInstance().getMinesMessages() + .getLocalizable( "mines_mtp__" ) + .withReplacements( + mineName ) + .sendTo( sender ); + } + + protected void teleportUnableToTeleportMsg( CommandSender sender ) { + // Sorry. You're unable to teleport there. + PrisonMines.getInstance().getMinesMessages() + .getLocalizable( "mines_mtp__unable_to_teleport" ) + .sendTo( sender ); + } + + protected void teleportCannotTeleportOtherPlayersMsg( CommandSender sender ) { + // &3You cannot teleport other players to a mine. Ignoring parameter. + PrisonMines.getInstance().getMinesMessages() + .getLocalizable( "mines_mtp__unable_to_teleport_others" ) + .sendTo( sender ); + } + + protected void teleportNoTargetMineFoundMsg( CommandSender sender ) { + // No target mine found. &3Resubmit teleport request with a mine name. + PrisonMines.getInstance().getMinesMessages() + .getLocalizable( "mines_mtp__no_target_mine_found" ) + .sendTo( sender ); + } + + protected void teleportPlayerMustBeIngameMsg( CommandSender sender ) { + // &3The player must be in the game. + PrisonMines.getInstance().getMinesMessages() + .getLocalizable( "mines_mtp__player_must_be_in_game" ) + .sendTo( sender ); + } + + protected void teleportNamedPlayerMustBeIngameMsg( CommandSender sender ) { + // &3Specified player is not in the game so they cannot be teleported. + PrisonMines.getInstance().getMinesMessages() + .getLocalizable( "mines_mtp__player_must_be_in_game" ) + .sendTo( sender ); + } + + protected void teleportCannotUseVirtualMinesMsg( CommandSender sender ) { + // &cInvalid option. This mine is a virtual mine&7. Use &a/mines set area &7to enable the mine. + PrisonMines.getInstance().getMinesMessages() + .getLocalizable( "mines_mtp__cannot_use_virtual_mines" ) + .sendTo( sender ); + } + + protected void teleportFailedMsg( CommandSender sender ) { + // &3Telport failed. Are you sure you're a Player? + PrisonMines.getInstance().getMinesMessages() + .getLocalizable( "mines_mtp__teleport_failed" ) + .sendTo( sender ); + } + +} 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 286e2bc29..322edb930 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 @@ -18,8 +18,10 @@ package tech.mcprison.prison.mines.commands; +import java.io.File; import java.text.DecimalFormat; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.Optional; @@ -42,7 +44,7 @@ import tech.mcprison.prison.mines.data.MineData; import tech.mcprison.prison.mines.data.MineData.MineNotificationMode; import tech.mcprison.prison.mines.data.MineScheduler.MineResetActions; -import tech.mcprison.prison.mines.data.MineScheduler.MineResetType; +import tech.mcprison.prison.mines.data.MineScheduler.MineResetScheduleType; import tech.mcprison.prison.mines.data.PrisonSortableResults; import tech.mcprison.prison.mines.features.MineBlockEvent; import tech.mcprison.prison.mines.features.MineBlockEvent.BlockEventType; @@ -65,8 +67,8 @@ import tech.mcprison.prison.tasks.PrisonCommandTask.TaskMode; import tech.mcprison.prison.tasks.PrisonTaskSubmitter; import tech.mcprison.prison.util.Bounds; -import tech.mcprison.prison.util.JumboTextFont; import tech.mcprison.prison.util.Bounds.Edges; +import tech.mcprison.prison.util.JumboTextFont; import tech.mcprison.prison.util.Text; /** @@ -365,14 +367,56 @@ public void renameCommand(CommandSender sender, "event priorities are configured correctly.", onlyPlayers = true, permissions = "mines.set") public void mineAccessByRankCommand(CommandSender sender, - @Arg(name = "mineName", description = "The name of the mine") String mineName, + @Arg(name = "mineName", description = "The name of the mine, or *all* for all mines. [*all*]") String mineName, @Arg(name = "enable", description = "Enable the mineAccessByRank: [enable, disable]") String enable ) { + if ( enable == null || !"enable".equalsIgnoreCase( enable ) && !"disable".equalsIgnoreCase( enable ) ) { + + sender.sendMessage( "&cInvalid option. &7The parameter &3enable &7can only have the values of " + + "'enable' or 'disable'. Please try again." ); + return; + } + + boolean accessEnabled = "enable".equalsIgnoreCase( enable ); + + PrisonMines pMines = PrisonMines.getInstance(); + + if ( mineName != null && "*all*".equalsIgnoreCase( mineName ) ) { + int minesUpdated = 0; + int minesNoChange = 0; + int minesWithNoRanks = 0; + + for ( Mine m :pMines.getMines() ) { + if ( m.getRank() == null ) { + minesWithNoRanks++; + } + else if ( m.isMineAccessByRank() == accessEnabled ) { + minesNoChange++; + } + else { + minesUpdated++; + + m.setMineAccessByRank( accessEnabled ); + pMines.getMineManager().saveMine(m); + } + } + + String message = String.format( "&7%s Mine Access by Rank changes were applied to all Mines. " + + "%d were updated. %d had no changes. %d had no ranks so could not be set.", + + (accessEnabled ? "Enabling" : "Disabling"), + minesUpdated, minesNoChange, minesWithNoRanks + ); + + sender.sendMessage( message ); + + return; + } + if (!performCheckMineExists(sender, mineName)) { return; } - PrisonMines pMines = PrisonMines.getInstance(); Mine mine = pMines.getMine(mineName); if ( mine.getRank() == null ) { @@ -381,15 +425,6 @@ public void mineAccessByRankCommand(CommandSender sender, return; } - if ( enable == null || !"enable".equalsIgnoreCase( enable ) && !"disable".equalsIgnoreCase( enable ) ) { - - sender.sendMessage( "&cInvalid option. &7The parameter &3enable &7can only have the values of " + - "'enable' or 'disable'. Please try again." ); - return; - } - - boolean accessEnabled = "enable".equalsIgnoreCase( enable ); - if ( mine.isMineAccessByRank() == accessEnabled ) { sender.sendMessage( String.format( "&cInvalid setting. &7The mine's setting mineAccessByRank has not been " + @@ -416,14 +451,57 @@ public void mineAccessByRankCommand(CommandSender sender, "a Rank: See /mines set rank help.", onlyPlayers = true, permissions = "mines.set") public void tpAccessByRankCommand(CommandSender sender, - @Arg(name = "mineName", description = "The name of the mine") String mineName, + @Arg(name = "mineName", description = "The name of the mine, or *all* for all mines. [*all*]") String mineName, @Arg(name = "enable", description = "Enable the tpAccessByRank: [enable, disable]") String enable ) { + if ( enable == null || !"enable".equalsIgnoreCase( enable ) && !"disable".equalsIgnoreCase( enable ) ) { + + sender.sendMessage( "&cInvalid option. &7The parameter &3enable &7can only have the values of " + + "'enable' or 'disable'. Please try again." ); + return; + } + + boolean accessEnabled = "enable".equalsIgnoreCase( enable ); + + PrisonMines pMines = PrisonMines.getInstance(); + + + if ( mineName != null && "*all*".equalsIgnoreCase( mineName ) ) { + int minesUpdated = 0; + int minesNoChange = 0; + int minesWithNoRanks = 0; + + for ( Mine m :pMines.getMines() ) { + if ( m.getRank() == null ) { + minesWithNoRanks++; + } + else if ( m.isTpAccessByRank() == accessEnabled ) { + minesNoChange++; + } + else { + minesUpdated++; + + m.setTpAccessByRank( accessEnabled ); + pMines.getMineManager().saveMine(m); + } + } + + String message = String.format( "&7%s Mine TP Access by Rank changes were applied to all Mines. " + + "%d were updated. %d had no changes. %d had no ranks so could not be set.", + + (accessEnabled ? "Enabling" : "Disabling"), + minesUpdated, minesNoChange, minesWithNoRanks + ); + + sender.sendMessage( message ); + + return; + } + if (!performCheckMineExists(sender, mineName)) { return; } - PrisonMines pMines = PrisonMines.getInstance(); Mine mine = pMines.getMine(mineName); if ( mine.getRank() == null ) { @@ -432,15 +510,6 @@ public void tpAccessByRankCommand(CommandSender sender, return; } - if ( enable == null || !"enable".equalsIgnoreCase( enable ) && !"disable".equalsIgnoreCase( enable ) ) { - - sender.sendMessage( "&cInvalid option. &7The parameter &3enable &7can only have the values of " + - "'enable' or 'disable'. Please try again." ); - return; - } - - boolean accessEnabled = "enable".equalsIgnoreCase( enable ); - if ( mine.isTpAccessByRank() == accessEnabled ) { sender.sendMessage( String.format( "&cInvalid setting. &7The mine's setting tpAccessByRank has not been " + @@ -464,7 +533,9 @@ public void tpAccessByRankCommand(CommandSender sender, @Command(identifier = "mines set spawn", description = "Set the mine's spawn to where you're standing.", onlyPlayers = true, permissions = "mines.set") public void spawnpointCommand(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.") String mineName, + @Arg(name = "options", def = "set", + description = "Options: Option to set or remove a spawn. [set *remove*]") String options ) { Player player = getPlayer( sender ); @@ -507,9 +578,17 @@ public void spawnpointCommand(CommandSender sender, setLastMineReferenced(mineName); - mine.setSpawn(((Player) sender).getLocation()); + if ( options != null && options.toLowerCase().contains( "*remove*" ) ) { + mine.setSpawn( null ); + pMines.getMinesMessages().getLocalizable("spawn_removed").sendTo(sender); + } + else { + + mine.setSpawn(((Player) sender).getLocation()); + pMines.getMinesMessages().getLocalizable("spawn_set").sendTo(sender); + } + pMines.getMineManager().saveMine(mine); - pMines.getMinesMessages().getLocalizable("spawn_set").sendTo(sender); } @@ -794,7 +873,11 @@ public void allMinesInfoDetails( StringBuilder sb ) { PrisonMines pMines = PrisonMines.getInstance(); MineManager mMan = pMines.getMineManager(); - for ( Mine mine : mMan.getMines() ) { + List mines = new ArrayList<>(); + mines.addAll( mMan.getMines() ); + Collections.sort( mines ); + + for ( Mine mine : mines ) { PrisonCommand.printFooter( sb ); @@ -971,10 +1054,19 @@ else if ( !mineAccessByRank && tpAccessByRank ) { } + + + int resetTime = m.getResetTime(); - { + if ( resetTime <= 0 ) { + RowComponent row = new RowComponent(); + + row.addTextComponent( "&3Automatic Resets are &7Disabled" ); + chatDisplay.addComponent( row ); + } + else { RowComponent row = new RowComponent(); - double rtMinutes = m.getResetTime() / 60.0D; + double rtMinutes = resetTime / 60.0D; row.addTextComponent( "&3Reset time: &7%s &3Secs (&7%.2f &3Mins)", Integer.toString(m.getResetTime()), rtMinutes ); chatDisplay.addComponent( row ); @@ -1003,7 +1095,7 @@ else if ( cmdPageData.isShowAll() ) { } } - if ( !m.isVirtual() ) { + if ( !m.isVirtual() && resetTime > 0 ) { RowComponent row = new RowComponent(); long targetResetTime = m.getTargetResetTime(); @@ -1016,6 +1108,7 @@ else if ( cmdPageData.isShowAll() ) { chatDisplay.addComponent( row ); } + if ( resetTime > 0 ) { RowComponent row = new RowComponent(); row.addTextComponent( "&3Notification Mode: &7%s &7%s", @@ -1025,8 +1118,8 @@ else if ( cmdPageData.isShowAll() ) { chatDisplay.addComponent( row ); } - if ( m.isUseNotificationPermission() || - !m.isUseNotificationPermission() && cmdPageData.isShowAll() ) { + if ( resetTime > 0 && m.isUseNotificationPermission() || + resetTime > 0 && !m.isUseNotificationPermission() && cmdPageData.isShowAll() ) { RowComponent row = new RowComponent(); row.addTextComponent( "&3Notifications Filtered by Permissions: %s", ( m.isUseNotificationPermission() ? @@ -1081,7 +1174,7 @@ else if ( m.getResetThresholdPercent() > 0 ) { } - if ( m.isSkipResetEnabled() ) { + if ( resetTime > 0 && m.isSkipResetEnabled() ) { RowComponent row = new RowComponent(); row.addTextComponent( "&3Skip Reset: &2Enabled&3: &3Threshold: &7%s &3Skip Limit: &7%s", fFmt.format( m.getSkipResetPercent() ), dFmt.format( m.getSkipResetBypassLimit() )); @@ -1094,7 +1187,7 @@ else if ( m.getResetThresholdPercent() > 0 ) { chatDisplay.addComponent( row2 ); } } - else if ( cmdPageData.isShowAll() ) { + else if ( resetTime > 0 && cmdPageData.isShowAll() ) { RowComponent row = new RowComponent(); row.addTextComponent( "&3Skip Mine Reset if no Activity: &cnot set"); chatDisplay.addComponent( row ); @@ -1211,7 +1304,7 @@ public void resetCommand(CommandSender sender, // make sure not null and set to lower case: options = ( options == null ? "" : options.trim().toLowerCase()); - MineResetType resetType = MineResetType.FORCED; + MineResetScheduleType resetType = MineResetScheduleType.FORCED; List resetActions = new ArrayList<>(); @@ -1278,11 +1371,13 @@ public void resetCommand(CommandSender sender, m.manualReset( resetType, resetActions ); } catch (Exception e) { pMines.getMinesMessages().getLocalizable("mine_reset_fail") + .withReplacements( m.getName() ) .sendTo(sender); Output.get().logError("Couldn't reset mine " + mineName, e); } - pMines.getMinesMessages().getLocalizable("mine_reset").sendTo(sender); + pMines.getMinesMessages().getLocalizable("mine_reset") + .withReplacements( m.getName() ).sendTo(sender); } @@ -1444,7 +1539,7 @@ private BulletedListComponent getMinesLineItemList( PrisonSortableResults sorted row.addTextComponent( " &3(&2R: " ); - if ( !m.isVirtual() ) { + if ( !m.isVirtual() && m.getResetTime() > 0 ) { row.addFancy( new FancyMessage( String.format( "&7%s &3sec &3/ ", dFmt.format(m.getRemainingTimeSec()))) @@ -1453,10 +1548,21 @@ private BulletedListComponent getMinesLineItemList( PrisonSortableResults sorted // row.addTextComponent( " sec &3(&b" ); } - row.addFancy( - new FancyMessage( - String.format( "&7%s &3sec )&b", dFmt.format(m.getResetTime()) )) - .tooltip( "Reset time in seconds" ) ); + + if ( m.getResetTime() <= 0 ) { + + row.addFancy( + new FancyMessage( + String.format( "&7disabled )&b" )) + .tooltip( "Auto resets have been disabled." ) ); + } + else { + + row.addFancy( + new FancyMessage( + String.format( "&7%s &3sec )&b", dFmt.format(m.getResetTime()) )) + .tooltip( "Reset time in seconds" ) ); + } // row.addTextComponent( " sec&3)&b" ); if ( !m.isVirtual() && player != null && @@ -1696,15 +1802,31 @@ public void skipResetCommand(CommandSender sender, * @param time */ @Command(identifier = "mines set resetTime", permissions = "mines.resettime", - description = "Set a mine's time to reset.") + description = "Set a mine's auto reset time as expressed in seconds.") public void resetTimeCommand(CommandSender sender, @Arg(name = "mineName", description = "The name of the mine to edit.") String mineName, - @Arg(name = "time", description = "Time in seconds for the mine to auto reset." ) String time + @Arg(name = "time", description = "Time in seconds for the mine to auto reset. " + + "With a minimum value of "+ MineData.MINE_RESET__TIME_SEC__MINIMUM + " seconds. " + + "Using 'disable' will turn off the auto reset." ) String time ) { if (performCheckMineExists(sender, mineName)) { setLastMineReferenced(mineName); + + PrisonMines pMines = PrisonMines.getInstance(); + Mine m = pMines.getMine(mineName); + + if ( "disable".equalsIgnoreCase( time ) ) { + + m.setResetTime( -1 ); + + pMines.getMineManager().saveMine( m ); + + Output.get().logInfo( "&7Automatic resets have been disabled for mine %s.", m.getTag() ); + + return; + } try { int resetTime = MineData.MINE_RESET__TIME_SEC__DEFAULT; @@ -1718,9 +1840,6 @@ public void resetTimeCommand(CommandSender sender, "&7Invalid resetTime value for &b%s&7. Must be an integer value of &b%d&7 or greater. [&b%d&7]", mineName, MineData.MINE_RESET__TIME_SEC__MINIMUM, resetTime ); } else { - 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; @@ -2187,13 +2306,17 @@ public void setMineRankCommand(CommandSender sender, @Command(identifier = "mines set area", permissions = "mines.set", - description = "Set the area of a mine to your current selection or a 1x1 mine under your feet.") + description = "Set the area of a mine to your current selection or a 1x1 mine under your feet. " + + "If you are using 'feet' as the location of the mine, then you can also set the " + + "increases to the width, depth, and top. ") public void redefineCommand(CommandSender sender, @Arg(name = "mineName", description = "The name of the mine to edit.") String mineName, @Arg(name = "source", description = "&3The source to use for setting the area. The &7wand&3 " + "uses the area defined by the wand. &7Feet&3 defines a 1x1 mine under your feet" + "which is useful in void worlds or when flying and can be enlarged with " + - "&7/mines set size help&3 . &2[&7wand feet&2]", + "&7/mines set size help&3. " + + "The use of &7virtual&3 will remove the mine's location and spawn points, and " + + "will revert the mine to a virtual mine. &2[&7wand feet virtual&2]", def = "wand") String source, @Wildcard(join=true) @Arg(name = "options", description = " " + @@ -2228,8 +2351,60 @@ public void redefineCommand(CommandSender sender, else if ( source == null || "wand".equalsIgnoreCase( source ) ) { selection = Prison.get().getSelectionManager().getSelection( player ); } + else if ( source == null || "virtual".equalsIgnoreCase( source ) ) { + // do nothing... don't set selection: + } else { - sender.sendMessage( "&3Valid values for &2source &3are &7wand&3 and &7feet&3." ); + sender.sendMessage( "&3Valid values for &2source &3are &7wand&3, " + + "&7feet&3, and &7virtual&3." ); + return; + } + + if ( selection == null ) { + + // Revert the mine to a virtual mine: + + setLastMineReferenced(mineName); + + if ( m.isVirtual() ) { + // Already a virtual mine so exit: + String message = "Mine &7" + m.getName() + " &3is already virtual. No changes have been made."; + sender.sendMessage( message ); + + return; + } + + // Make a backup of the mine save file before making virtual: + File backupFile = pMines.getMineManager().backupMine( m ); + + String messageBu = "Mine &7" + m.getName() + " &3has " + + ( backupFile.exists() ? "been successfully" : "failed to be" ) + + " backed up: " + backupFile.getAbsolutePath(); + sender.sendMessage( messageBu ); + Output.get().logInfo( messageBu ); + + if ( !backupFile.exists() ) { + Output.get().logInfo( "Since the backup Failed, mine " + m.getName() + " cannot be " + + "virtualized." ); + + return; + } + + m.setBounds( null ); + m.setSpawn( null ); + + m.setVirtual( true ); + + m.getJobStack().clear(); + + // TODO Possibly may need to kill existing jobs and/or set a mutex state of VIRTUAL? + m.getMineStateMutex(); + + pMines.getMineManager().saveMine( m ); + + String message = "Mine &7" + m.getName() + " &3has been set to virtual. "; + sender.sendMessage( message ); + return; } @@ -2249,9 +2424,9 @@ else if ( source == null || "wand".equalsIgnoreCase( source ) ) { DecimalFormat dFmt = new DecimalFormat("#,##0"); Bounds selectedBounds = selection.asBounds(); - if ( selectedBounds.getTotalBlockCount() > 25000 && - (options == null || !options.toLowerCase().contains( "confirm" ) || - !options.toLowerCase().contains( "yes" ))) { + if ( selectedBounds.getTotalBlockCount() > 50000 && + (options == null || !options.toLowerCase().contains( "confirm" ) && + !options.toLowerCase().contains( "yes" )) ) { String message = String.format( "&7Warning: This mine has a size of %s. If this is " + "intentional, then please re-submit this command with adding the " + "keyword of either 'confirm' or 'yes' to the end of the command. ", @@ -2260,7 +2435,7 @@ else if ( source == null || "wand".equalsIgnoreCase( source ) ) { return; } else if ( options.toLowerCase().contains( "confirm" ) || - !options.toLowerCase().contains( "yes" ) ) { + options.toLowerCase().contains( "yes" ) ) { options = options.replace( "(?i)confirm|yes", "" ).trim(); } @@ -2338,6 +2513,39 @@ else if ( options.toLowerCase().contains( "confirm" ) || + @Command(identifier = "mines backup", permissions = "mines.set", + description = "Creates a backup of the specified mine. Backups are similar to virtually " + + "deleted mines in that a copy is made, but cannot be accessed. To recover from " + + "a backup, it must be done manually outside of the game or console. " + + "Once a backup is created, prison cannot do anything with it; it must be " + + "manually managed.") + public void backupMineCommand(CommandSender sender, + @Arg(name = "mineName", description = "The name of the mine to edit.") String mineName + ) { + + if (!performCheckMineExists(sender, mineName)) { + return; + } + + PrisonMines pMines = PrisonMines.getInstance(); + Mine m = pMines.getMine(mineName); + + + // Make a backup of the mine save file before making virtual: + File backupFile = pMines.getMineManager().backupMine( m ); + + String messageBu = "Mine &7" + m.getName() + " &3has " + + ( backupFile.exists() ? "been successfully" : "failed to be" ) + + " backed up: " + backupFile.getAbsolutePath(); + + if ( sender.isPlayer() ) { + sender.sendMessage( messageBu ); + } + Output.get().logInfo( messageBu ); + + } + + @Command(identifier = "mines set tracer", permissions = "mines.set", description = "Clear the mine and set a tracer around the outside") public void setTracerCommand(CommandSender sender, @@ -2715,8 +2923,7 @@ public void mineTp(CommandSender sender, if ( m == null ) { - sender.sendMessage( "&cNo target mine found. " + - "&3Resubmit teleport request with a mine name." ); + teleportNoTargetMineFoundMsg( sender ); return; } } @@ -2734,7 +2941,7 @@ public void mineTp(CommandSender sender, if ( m.isVirtual() ) { - sender.sendMessage( "&cInvalid option. This mine is a virtual mine&7. Use &a/mines set area &7to enable the mine." ); + teleportCannotUseVirtualMinesMsg( sender ); return; } @@ -2745,13 +2952,14 @@ public void mineTp(CommandSender sender, if ( playerName != null && playerName.trim().length() > 0 && playerAlt == null) { - sender.sendMessage( "&3Specified player is not in the game so they cannot be teleported." ); + teleportNamedPlayerMustBeIngameMsg( sender ); return; } if ( (player == null || !player.isOnline()) && playerAlt != null && !playerAlt.isOnline() ) { - sender.sendMessage( "&3The player must be in the game." ); + + teleportPlayerMustBeIngameMsg( sender ); return; } @@ -2777,7 +2985,7 @@ else if ( (player == null || !player.isOnline()) && playerAlt != null && playerA } else if ( playerAlt != null && !player.getName().equalsIgnoreCase( playerAlt.getName() ) ) { - sender.sendMessage( "&3You cannot teleport other players to a mine. Ignoring parameter." ); + teleportCannotTeleportOtherPlayersMsg( sender ); return; } @@ -2790,8 +2998,7 @@ else if ( playerAlt != null && !player.getName().equalsIgnoreCase( playerAlt.get if ( m == null ) { - sender.sendMessage( "&cNo target mine found. " + - "&3Resubmit teleport request with a mine name." ); + teleportNoTargetMineFoundMsg( sender ); return; } } @@ -2801,7 +3008,7 @@ else if ( playerAlt != null && !player.getName().equalsIgnoreCase( playerAlt.get // NOTE: Mine.hasTPAccess() checks for rank access and also if they have perms set. if ( !isOp && !m.hasTPAccess( player ) ) { - Output.get().sendError(sender, "Sorry. You're unable to teleport there." ); + teleportUnableToTeleportMsg( sender ); return; } @@ -2827,8 +3034,7 @@ else if ( playerAlt != null && !player.getName().equalsIgnoreCase( playerAlt.get teleportPlayer( (Player) sender, m, target ); // m.teleportPlayerOut( (Player) sender, target ); } else { - sender.sendMessage( - "&3Telport failed. Are you sure you're a Player?"); + teleportFailedMsg( sender ); } } @@ -2860,7 +3066,10 @@ private void teleportPlayer( Player player, Mine mine, String target ) { } - @Command(identifier = "mines stats", permissions = "mines.stats", description = "Toggle stats on all mines.") + @Command(identifier = "mines stats", permissions = "mines.stats", + description = "Toggle stats on and off for all mine resets. When enabled, " + + "Prison's mine TPS calculations will be set to high-resolution mode " + + "(1 tick vs. 10 ticks).") public void mineStats(CommandSender sender) { PrisonMines pMines = PrisonMines.getInstance(); @@ -2869,6 +3078,10 @@ public void mineStats(CommandSender sender) { // toggle the stats: mMan.setMineStats( !mMan.isMineStats() ); + // When mine stats are enabled, then it will also enable the high resolution + // tracking of the Prison TPS: + Prison.get().getPrisonTPS().setHighResolution( mMan.isMineStats() ); + if ( mMan.isMineStats() ) { sender.sendMessage( "&3Mine Stats are now enabled. Use &7/mines list&3 to view stats on last mine reset. "); @@ -3218,7 +3431,7 @@ public void blockEventRemove(CommandSender sender, @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" + - "To send messages use {msg} or {broadcast} followed by the formatted message. " + + "To send messages use {msg}, {broadcast}, {actionBar}, or {title} followed by the formatted message. " + "Can use placeholders {player} and {player_uid}. Use ; between multiple commands. \n" + "Example: &7\\Q'token give {player} 1;{msg} &7You got &31 &7token!;tpa a'\\E&3 \n" + "This command defaults to no permission and 'sync' task mode; " + @@ -3526,7 +3739,8 @@ public void blockEventEventType(CommandSender sender, @Arg(name = "row") Integer row, @Arg(name = "eventType", def = "all", description = "EventType to trigger BlockEvent: " + - "[all, blockBreak, TEXplosion, CEXplosion]" + "[all, blockBreak, PrisonExplosion, PEExplosive, " + + "TEXplosion, CEXplosion]" ) String eventType ) { @@ -3573,6 +3787,14 @@ public void blockEventEventType(CommandSender sender, BlockEventType eTypeOld = blockEvent.getEventType(); blockEvent.setEventType( eType ); + + // If the event type does not support triggered, then set triggered to null: + if ( eType != BlockEventType.PrisonExplosion && + eType != BlockEventType.TEXplosion && + eType != BlockEventType.PEExplosive ) { + + blockEvent.setTriggered( null ); + } pMines.getMineManager().saveMine( m ); @@ -3593,13 +3815,21 @@ public void blockEventEventType(CommandSender sender, } - @Command(identifier = "mines blockEvent triggered", description = "Edits a BlockBreak triggered value.", + @Command(identifier = "mines blockEvent triggered", + description = "Edits a BlockBreak triggered value. The event's triggered value will " + + "identify which enchantment fired the explosion event. For example, 'laser' " + + "or 'nuked'. Provide the enchantment name to filter on that event type, or " + + "prefix it with '!' to exclude that event type. " + + " The use of this field is only supported by TokenEnchant, " + + "Prison's own Explosion Evennt, and Pulsi_'s PrisonEnchants' explosion events. " + + "Requires TokenEnchant v18.11.0 or newer.", onlyPlayers = false, permissions = "mines.set") public void blockEventTriggered(CommandSender sender, @Arg(name = "mineName") String mineName, @Arg(name = "row") Integer row, @Arg(name = "triggered", def = "none", - description = "TE Explosion Triggered sources. Requires TokenEnchant v18.11.0 or newer. [none, ...]" + description = "The enchantment that Triggered the explosion event. Use 'none' to " + + "remove it. [none, ...]" ) String triggered ) { @@ -3636,11 +3866,17 @@ public void blockEventTriggered(CommandSender sender, MineBlockEvent blockEvent = m.getBlockEvents().get( row - 1 ); + BlockEventType eType = blockEvent.getEventType(); - if ( blockEvent.getEventType() != BlockEventType.TEXplosion && triggered != null && + if ( eType != BlockEventType.PrisonExplosion && + eType != BlockEventType.TEXplosion && + eType != BlockEventType.PEExplosive && + triggered != null && !"none".equalsIgnoreCase( triggered ) ) { - sender.sendMessage( "&7Notice: triggered is only valid exclusivly for eventTEXplosion. " + - "Defaulting to none." ); + + sender.sendMessage( "&7Notice: triggered is only valid with " + + "PrisonExplosion, TEXplosion, or PEExplosive. " + + "Defaulting to 'none'." ); triggered = null; } if ( triggered != null && "none".equalsIgnoreCase( triggered ) ) { @@ -3655,13 +3891,21 @@ public void blockEventTriggered(CommandSender sender, pMines.getMineManager().saveMine( m ); - Output.get().sendInfo(sender, "&7BlockEvent triggered &b%s&7 was changed for mine '&b%s&7'. " + - "Was &b%s&7. Command '&b%s&7'", - (triggered == null ? "none" : triggered), - m.getTag(), - (oldTriggered == null ? "none" : oldTriggered), - blockEvent.getCommand() ); + sender.sendMessage( + String.format( "&7BlockEvent triggered &b%s&7 was changed for mine '&b%s&7'. " + + "Was &b%s&7. Command '&b%s&7'", + (triggered == null ? "none" : triggered), + m.getTag(), + (oldTriggered == null ? "none" : oldTriggered), + blockEvent.getCommand()) ); + if ( triggered.startsWith( "!" ) ) { + sender.sendMessage( + String.format( "BlockEvent triggered is negated to exclude triggered " + + "events of '%s'.", + triggered.replace( "!", "" ))); + + } // Redisplay the event list: blockEventList( sender, mineName ); 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 7df0488da..7e82c09a5 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 @@ -1,12 +1,11 @@ package tech.mcprison.prison.mines.commands; -import tech.mcprison.prison.commands.BaseCommands; import tech.mcprison.prison.internal.CommandSender; import tech.mcprison.prison.mines.PrisonMines; import tech.mcprison.prison.util.Text; public class MinesCoreCommands - extends BaseCommands + extends MinesCommandMessages { private Long confirmTimestamp; 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 f47a39c58..cb4b00034 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 @@ -46,7 +46,7 @@ */ public class Mine extends MineScheduler - implements PrisonSortable { + implements PrisonSortable, Comparable { public enum MineType { @@ -417,23 +417,39 @@ else if (validateBlockNames.contains( blockTypeName ) ) { PrisonBlock prisonBlock = PrisonBlockStatusData.parseFromSaveFileFormat( docBlock ); + // If the server version is less than 1.13.0, and if the block is a "_wood" block, + // then it needs to be remapped to "_planks" so the resulting block will work properly. + // Versions prior to 1.13.0, _WOOD is identical to _PLANKS. + if ( prisonBlock != null && + prisonBlock.getBlockName().toLowerCase().contains( "_wood" ) && + Prison.get().getPlatform().compareServerVerisonTo( "1.13.0" ) < 0 ) { + String fixedName = docBlock.toLowerCase().replace( "_wood", "_planks" ); + + prisonBlock = PrisonBlockStatusData.parseFromSaveFileFormat( fixedName ); + dirty = true; + } - if ( prisonBlock != null && !validateBlockNames.contains( prisonBlock.getBlockName() )) { + if ( prisonBlock != null ) { - if ( prisonBlock.isLegacyBlock() ) { + if ( !validateBlockNames.contains( prisonBlock.getBlockName() )) { + + if ( prisonBlock.isLegacyBlock() ) { + dirty = true; + } + addPrisonBlock( prisonBlock ); + + validateBlockNames.add( prisonBlock.getBlockName() ); + } + else if ( validateBlockNames.contains( prisonBlock.getBlockName() ) ) { + // Detected and fixed a duplication so mark as dirty so fixed block list is saved: dirty = true; + inconsistancy = true; } - addPrisonBlock( prisonBlock ); - validateBlockNames.add( prisonBlock.getBlockName() ); - } - else if ( prisonBlock != null && validateBlockNames.contains( prisonBlock.getBlockName() ) ) { - // Detected and fixed a duplication so mark as dirty so fixed block list is saved: - dirty = true; - inconsistancy = true; } + // String[] split = docBlock.split("-"); // String blockTypeName = split[0]; // double chance = split.length > 1 ? Double.parseDouble(split[1]) : 0; @@ -476,6 +492,10 @@ else if ( prisonBlock != null && validateBlockNames.contains( prisonBlock.getBlo } } } + + + // Check if one of the blocks is effected by gravity, and if so, set that indicator. + checkGravityAffectedBlocks(); if ( isUseNewBlockModel() && @@ -484,7 +504,18 @@ else if ( prisonBlock != null && validateBlockNames.contains( prisonBlock.getBlo for ( BlockOld blockOld : getBlocks() ) { PrisonBlock prisonBlock = Prison.get().getPlatform().getPrisonBlock( blockOld.getType().name() ); - if ( prisonBlock != null ) { + + if ( prisonBlock == null ) { + for ( String altName : blockOld.getType().getXMaterialAltNames() ) { + + prisonBlock = Prison.get().getPlatform().getPrisonBlock( altName ); + if ( prisonBlock != null ) { + break; + } + } + } + + if ( prisonBlock != null ) { // This transfers all the stats over so none are lost. prisonBlock.transferStats( blockOld ); @@ -511,7 +542,7 @@ else if ( prisonBlock != null && validateBlockNames.contains( prisonBlock.getBlo List mineBlockEvents = (List) document.get("mineBlockEvents"); if ( mineBlockEvents != null ) { for ( String blockEvent : mineBlockEvents ) { - getBlockEvents().add( MineBlockEvent.fromSaveString( blockEvent ) ); + getBlockEvents().add( MineBlockEvent.fromSaveString( blockEvent, this.getName() ) ); } } @@ -530,6 +561,9 @@ else if ( prisonBlock != null && validateBlockNames.contains( prisonBlock.getBlo // every time the mine is loaded which may lead to other issues. // This is enabled since the original is not modified. + + // If dirty, then make a backup since these are automatic changes: + PrisonMines.getInstance().getMineManager().backupMine( this ); PrisonMines.getInstance().getMineManager().saveMine( this ); @@ -674,14 +708,53 @@ public String toString() { return getName() + " " + getTotalBlocksMined(); } + /** + *

Even if world is null, it will allow you to create a location, but + * the location will be invalid. In order to use this location, + * the world will have to be set to a valid world. + *

+ * + * @param doc + * @param world + * @param x + * @param y + * @param z + * @return + */ private Location getLocation(Document doc, World world, String x, String y, String z) { - return new Location(world, (double) doc.get(x), (double) doc.get(y), (double) doc.get(z)); + Location results = null; + +// if ( world != null ) { +// +// +// } + Object xD = doc.get(x); + Object yD = doc.get(y); + Object zD = doc.get(z); + + if ( xD != null && yD != null && zD != null ) { + + results = new Location(world, (double) xD, (double) yD, (double) zD ); + } + + return results; } private Location getLocation(Document doc, World world, String x, String y, String z, String pitch, String yaw) { Location loc = getLocation(doc, world, x, y, z); - loc.setPitch( ((Double) doc.get(pitch)).floatValue() ); - loc.setYaw( ((Double) doc.get(yaw)).floatValue() ); + + Object pitchD = doc.get(pitch); + Object yawD = doc.get(yaw); + + if ( pitchD != null ) { + + loc.setPitch( ((Double) pitchD ).floatValue() ); + } + + if ( yawD != null ) { + + loc.setYaw( ((Double) yawD ).floatValue() ); + } return loc; } @@ -726,4 +799,9 @@ public String getBlockListString() return sb.toString(); } + @Override + public int compareTo( Mine o ) { + return getName().toLowerCase().compareTo( o.getName().toLowerCase() ); + } + } 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 a45907205..e6dcf50cc 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 @@ -13,13 +13,13 @@ import tech.mcprison.prison.internal.Player; import tech.mcprison.prison.internal.World; import tech.mcprison.prison.internal.block.Block; +import tech.mcprison.prison.internal.block.MineTargetPrisonBlock; import tech.mcprison.prison.internal.block.PrisonBlock; import tech.mcprison.prison.internal.block.PrisonBlock.PrisonBlockType; import tech.mcprison.prison.internal.block.PrisonBlockStatusData; import tech.mcprison.prison.mines.data.Mine.MineType; import tech.mcprison.prison.mines.features.MineBlockEvent; import tech.mcprison.prison.mines.features.MineLinerData; -import tech.mcprison.prison.mines.features.MineTargetPrisonBlock; import tech.mcprison.prison.modules.ModuleElement; import tech.mcprison.prison.modules.ModuleElementType; import tech.mcprison.prison.output.Output; @@ -44,6 +44,11 @@ public abstract class MineData private boolean enabled = false; private boolean virtual = false; + + // Controls if a mine is able to be used during a mine reset: + private MineStateMutex mineStateMutex; + + private MineType mineType; private MineGroup mineGroup; @@ -105,6 +110,20 @@ public abstract class MineData private TreeMap blockStats; + /** + *

If any of the mine's blocks are effected by gravity, then this field + * will indicate that this mine has at least one. This field prevents the + * need to always check all the blocks. Special processing needs to be performed + * when resetting a mine with these blocks, since a non-gravity affected + * block must be placed first, prior to placing a gravity block. Or just leave + * it as is, even if it's air. Then on a second pass, place the gravity + * affected block. Technique may vary and could be controlled by settings. + *

+ */ + private transient boolean hasGravityAffectedBlocks = false; + + private transient PrisonBlock tempGravityBlock = null; + private int blockBreakCount = 0; private long totalBlocksMined = 0; @@ -171,6 +190,9 @@ public static MineNotificationMode fromString(String mode, MineNotificationMode } public MineData() { + + this.mineStateMutex = new MineStateMutex(); + this.elementType = ModuleElementType.MINE; this.tag = null; @@ -655,19 +677,42 @@ public boolean hasBlock( String blockName ) { * * @param targetPrisonBlock */ - public void incrementBlockMiningCount( MineTargetPrisonBlock targetPrisonBlock ) { + public boolean incrementBlockMiningCount( MineTargetPrisonBlock targetPrisonBlock ) { + boolean results = false; // Only count the block as being broke if it was not originally air and - // and it has not been broke before: - if ( targetPrisonBlock != null && !targetPrisonBlock.isAirBroke() ) { + // and it has not been broke before. + + // NOTE: setAirBroke() and setMined() will be set to true if the mine reset + // places an air block. That will prevent the air from being processed. + if ( targetPrisonBlock != null && !targetPrisonBlock.isCounted() ) { + + targetPrisonBlock.setAirBroke( true ); + targetPrisonBlock.setCounted( true ); + // The field isMined() is used to "reserve" a block to indicate that it is in + // the stages of being processed, since much later in the processing will the + // block be set to setAirBreak() or even setCounted(). This prevents + // high-speed or concurrent operations from multiple players from trying to + // process the same block. So set it to true here, if it has not already + // been set. + if ( !targetPrisonBlock.isMined() ) { + + targetPrisonBlock.setMined( true ); + } + incrementBlockBreakCount(); incrementTotalBlocksMined(); - targetPrisonBlock.getPrisonBlock().incrementMiningBlockCount(); + if ( targetPrisonBlock.getPrisonBlock() != null ) { + + targetPrisonBlock.getPrisonBlock().incrementMiningBlockCount(); + } - targetPrisonBlock.setAirBroke( true ); + results = true; } + + return results; } // public void incrementBlockMiningCount( Block block ) { @@ -850,10 +895,13 @@ public boolean isInMine(PrisonBlock blockType) { public PrisonBlock getPrisonBlock( PrisonBlock blockType ) { PrisonBlock results = null; - for (PrisonBlock block : getPrisonBlocks()) { - if (blockType.getBlockNameFormal().equalsIgnoreCase( block.getBlockNameFormal())) { - results = block; - break; + if ( blockType != null && blockType.getBlockNameFormal() != null ) { + + for (PrisonBlock block : getPrisonBlocks()) { + if ( block.getBlockNameFormal().equalsIgnoreCase( blockType.getBlockNameFormal() )) { + results = block; + break; + } } } @@ -1270,6 +1318,32 @@ public void setMineSweeperBlocksChanged( long mineSweeperBlocksChanged ) { this.mineSweeperBlocksChanged = mineSweeperBlocksChanged; } + public void checkGravityAffectedBlocks() { + setHasGravityAffectedBlocks( false ); + + for ( PrisonBlock pBlock : getPrisonBlocks() ) { + + if ( pBlock.isGravity() ) { + setHasGravityAffectedBlocks( true ); + break; + } + } + } + + public boolean isHasGravityAffectedBlocks() { + return hasGravityAffectedBlocks; + } + public void setHasGravityAffectedBlocks( boolean hasGravityAffectedBlocks ) { + this.hasGravityAffectedBlocks = hasGravityAffectedBlocks; + } + + public PrisonBlock getTempGravityBlock() { + return tempGravityBlock; + } + public void setTempGravityBlock( PrisonBlock tempGravityBlock ) { + this.tempGravityBlock = tempGravityBlock; + } + public boolean isDeleted() { return isDeleted; } @@ -1277,4 +1351,10 @@ public void setDeleted( boolean isDeleted ) { this.isDeleted = isDeleted; } + public MineStateMutex getMineStateMutex() { + if ( mineStateMutex == null ) { + this.mineStateMutex = new MineStateMutex(); + } + return mineStateMutex; + } } 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 new file mode 100644 index 000000000..ac7b6479c --- /dev/null +++ b/prison-mines/src/main/java/tech/mcprison/prison/mines/data/MineLevelBlockListData.java @@ -0,0 +1,172 @@ +package tech.mcprison.prison.mines.data; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import tech.mcprison.prison.internal.block.PrisonBlock; + +public class MineLevelBlockListData +{ + + private int currentMineLevel; + + private Mine mine; + + private Random random; + + private List selectedBlocks; + + private double totalChance = 0d; + + private double selectedChance = 0d; + + private double airChance = 0d; + + public MineLevelBlockListData( int currentMineLevel, Mine mine, Random random ) { + super(); + + this.currentMineLevel = currentMineLevel; + this.mine = mine; + + this.random = random; + + this.selectedBlocks = new ArrayList<>(); + + initialize(); + } + + private void initialize() { + + + + // PrisonBlocks contains the percent chance of spawning: + for ( PrisonBlock pBlock : mine.getPrisonBlocks() ) + { + // 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 || + + pBlock.getConstraintExcludeTopLayers() <= currentMineLevel && + (pBlock.getConstraintExcludeBottomLayers() == 0 || + pBlock.getConstraintExcludeBottomLayers() > currentMineLevel) ) { + + // Sum the selected blocks: + selectedChance += pBlock.getChance(); + + // Add the selected blocks to our list: + selectedBlocks.add( 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() ) { + + 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. + // 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 ); + + } + + } + + } + + + // Using the total chance, need to calculate the AIR percent: + airChance = 100d - totalChance; + + // If airChance is not zero, add an AIR block to the selectedBlocks list: + if ( airChance > 0d ) { + PrisonBlock airBlock = PrisonBlock.AIR.clone(); + + airBlock.setChance( airChance ); + + selectedBlocks.add( airBlock ); + } + + + } + + + /** + *

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. + *

+ */ + 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) && + + pBlock.getConstraintExcludeBottomLayers() > 0 && + pBlock.getConstraintExcludeBottomLayers() < currentMineLevel + ) { + + int targetBlockPosition = mine.getMineTargetPrisonBlocks().size(); + pBlock.setRangeBlockCountHighLimit( targetBlockPosition ); + + } + + } + } + + public PrisonBlock randomlySelectPrisonBlock() + { + PrisonBlock selected = null; + + // Will have a value of 100% if no blocks are excluded due to block constraints: + double totalSelectedChance = selectedChance + airChance; + + double chance = random.nextDouble() * totalSelectedChance; + + for ( PrisonBlock block : selectedBlocks ) { + + if ( chance <= block.getChance() ) { + + // If this block is chosen and it was not skipped, then use this block and exit. + // Otherwise the chance will be recalculated and tried again to find a valid block, + // since the odds have been thrown off... + selected = block; + + break; + } else { + chance -= block.getChance(); + } + } + + return selected; + } + + +} 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 541d3e6fb..174e0ed4a 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 @@ -11,6 +11,9 @@ import tech.mcprison.prison.internal.Player; import tech.mcprison.prison.internal.World; import tech.mcprison.prison.internal.block.Block; +import tech.mcprison.prison.internal.block.MineResetType; +import tech.mcprison.prison.internal.block.MineTargetBlockKey; +import tech.mcprison.prison.internal.block.MineTargetPrisonBlock; import tech.mcprison.prison.internal.block.PrisonBlock; import tech.mcprison.prison.internal.block.PrisonBlockStatusData; import tech.mcprison.prison.mines.PrisonMines; @@ -20,9 +23,9 @@ import tech.mcprison.prison.mines.features.MineLinerBuilder; import tech.mcprison.prison.mines.features.MineLinerBuilder.LinerPatterns; import tech.mcprison.prison.mines.features.MineMover; -import tech.mcprison.prison.mines.features.MineTargetBlockKey; -import tech.mcprison.prison.mines.features.MineTargetPrisonBlock; import tech.mcprison.prison.mines.features.MineTracerBuilder; +import tech.mcprison.prison.mines.tasks.MinePagedResetAsyncTask; +import tech.mcprison.prison.mines.tasks.MineTeleportTask; import tech.mcprison.prison.output.Output; import tech.mcprison.prison.tasks.PrisonCommandTask; import tech.mcprison.prison.tasks.PrisonRunnable; @@ -110,6 +113,7 @@ public abstract class MineReset private long statsResetTimeMS = 0; private long statsBlockGenTimeMS = 0; private long statsBlockUpdateTimeMS = 0; + private long statsBlockUpdateTimeNanos = 0; // Note: The time it takes to teleport players and broadcast is so trivial // that they are being disabled to reduce the clutter and memory load. @@ -257,7 +261,10 @@ private void resetSynchonouslyInternal() { } } - resetAsynchonouslyUpdate( false ); + + MinePagedResetAsyncTask resetTask = new MinePagedResetAsyncTask( (Mine) this, MineResetType.normal ); + resetTask.submitTaskAsync(); +// resetAsynchonouslyUpdate( false ); @@ -325,17 +332,11 @@ public String statsMessage() { sb.append( "&3 BlockGenTime: &7" ); sb.append( dFmt.format(getStatsBlockGenTimeMS() / 1000.0d )).append( " s " ); -// sb.append( "&3 TP1: &7" ); -// sb.append( dFmt.format(getStatsTeleport1TimeMS() / 1000.0d )); sb.append( "&3 BlockUpdateTime: &7" ); sb.append( dFmt.format(getStatsBlockUpdateTimeMS() / 1000.0d )).append( " s " ); + sb.append( dFmt.format(getStatsBlockUpdateTimeNanos() / 1000000.0d )).append( " ms(nanos) " ); -// sb.append( "&3 TP2: &7" ); -// sb.append( dFmt.format(getStatsTeleport2TimeMS() / 1000.0d )); - -// sb.append( "&3 Msg: &7" ); -// sb.append( dFmt.format(getStatsMessageBroadcastTimeMS() / 1000.0d )); sb.append( "&3 ResetPages: &7" ); sb.append( iFmt.format(getStatsResetPages() )); @@ -353,6 +354,9 @@ public String statsMessage() { sb.append( statsMessageMineSweeper() ); +// sb.append( " TPS: " ) +// .append( Prison.get().getPrisonTPS().getAverageTPSFormatted() ); + return sb.toString(); } @@ -391,6 +395,7 @@ private void resetStats() { setStatsResetTimeMS( 0 ); setStatsBlockGenTimeMS( 0 ); setStatsBlockUpdateTimeMS( 0 ); + setStatsBlockUpdateTimeNanos( 0 ); // setStatsTeleport1TimeMS( 0 ); // setStatsTeleport2TimeMS( 0 ); // setStatsMessageBroadcastTimeMS( 0 ); @@ -498,7 +503,7 @@ public int getPlayerCount() { *

* */ - protected void generateBlockListAsync() { + public void generateBlockListAsync() { if ( isVirtual() || isDeleted() ) { // ignore and generate no error messages: @@ -527,34 +532,64 @@ protected void generateBlockListAsync() { resetResetBlockCounts(); - // setup the monitoring of the blocks that have constraints: - List constrainedBlocks = null; +// // setup the monitoring of the blocks that have constraints: +// List constrainedBlocks = null; int airCount = 0; int currentLevel = 0; + + int yMin = getBounds().getyBlockMin(); + int yMax = getBounds().getyBlockMax(); + + int xMin = getBounds().getxBlockMin(); + int xMax = getBounds().getxBlockMax(); + + int zMin = getBounds().getzBlockMin(); + int zMax = getBounds().getzBlockMax(); + + // The reset takes place first with the top-most layer since most mines may have // the player enter from the top, and the reset will appear to be more "instant". - for (int y = getBounds().getyBlockMax(); y >= getBounds().getyBlockMin(); y--) { + for (int y = yMax; y >= yMin; y--) { currentLevel++; // One based: First layer is currentLevel == 1 - for (int x = getBounds().getxBlockMin(); x <= getBounds().getxBlockMax(); x++) { - for (int z = getBounds().getzBlockMin(); z <= getBounds().getzBlockMax(); z++) { + + + // This is used to select the correct block list for the given mine level: + MineLevelBlockListData mineLevelBlockList = new MineLevelBlockListData( currentLevel, (Mine) this, random ); + + + for (int x = xMin; x <= xMax; x++) { + for (int z = zMin; z <= zMax; z++) { + + // updates selected block's exclude from bottom layer max value settings: + mineLevelBlockList.checkSelectedBlockExcludeFromBottomLayers(); + + boolean xEdge = x == xMin || x == xMax; + boolean yEdge = y == yMin || y == yMax; + boolean zEdge = z == zMin || z == zMax; + boolean isEdge = xEdge && yEdge || xEdge && zEdge || + yEdge && zEdge; + + // MineTargetBlock mtb = null; if ( isUseNewBlockModel() ) { - // track the constraints: - trackConstraints( currentLevel, constrainedBlocks ); + // track the constraints: (obsolete) + //trackConstraints( currentLevel, constrainedBlocks ); - PrisonBlock prisonBlock = randomlySelectPrisonBlock( random, currentLevel ); + PrisonBlock prisonBlock = mineLevelBlockList.randomlySelectPrisonBlock(); + +// PrisonBlock prisonBlock = randomlySelectPrisonBlock( random, currentLevel ); // Increment the mine's block count. This block is one of the control blocks: incrementResetBlockCount( prisonBlock ); - addMineTargetPrisonBlock( prisonBlock, x, y, z ); + addMineTargetPrisonBlock( prisonBlock, x, y, z, isEdge ); // mtb = new MineTargetPrisonBlock( prisonBlock, x, y, z); if ( prisonBlock.equals( PrisonBlock.AIR ) ) { @@ -570,7 +605,7 @@ protected void generateBlockListAsync() { // Increment the mine's block count. This block is one of the control blocks: incrementResetBlockCount( tBlock ); - addMineTargetPrisonBlock( tBlock, x, y, z ); + addMineTargetPrisonBlock( tBlock, x, y, z, isEdge ); // mtb = new MineTargetBlock( tBlock.getType(), x, y, z); if ( tBlock.equals( BlockOld.AIR ) ) { @@ -603,60 +638,66 @@ protected void generateBlockListAsync() { } - private void trackConstraints( int currentLevel, List constrainedBlocks ) - { - - // If the constrainedBlocks list has not be configured, set it up with the - // blocks that have constraints: - if ( constrainedBlocks == null ) { - - constrainedBlocks = new ArrayList<>(); - - for (PrisonBlock block : getPrisonBlocks()) { - if ( block.getConstraintExcludeTopLayers() > 0 || - block.getConstraintExcludeBottomLayers() > 0 ) { - - constrainedBlocks.add( block ); - } - } - } - - - // If there are any constrained blocks, then need to record - for ( PrisonBlockStatusData block : constrainedBlocks ) { - - // If exclude top layers is enabled, then only try to set the - // rangeBlockCountLowLimit once since we need the lowest possible - // value. The inital value for getRangeBlockCountLowLimit is -1. - if ( block.getConstraintExcludeTopLayers() > 0 && - block.getRangeBlockCountLowLimit() <= 0 && - currentLevel > block.getConstraintExcludeTopLayers() ) { - - int targetBlockPosition = getMineTargetPrisonBlocks().size(); - block.setRangeBlockCountLowLimit( 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 ( (block.getConstraintExcludeTopLayers() > 0 && - currentLevel > block.getConstraintExcludeTopLayers() || - block.getConstraintExcludeTopLayers() == 0) && - - block.getConstraintExcludeBottomLayers() > 0 && - block.getConstraintExcludeBottomLayers() < currentLevel - ) { - - int targetBlockPosition = getMineTargetPrisonBlocks().size(); - block.setRangeBlockCountHighLimit( targetBlockPosition ); - - } - } - - } +// private void trackConstraints( int currentLevel, List constrainedBlocks ) +// { +// +// // If the constrainedBlocks list has not be configured, set it up with the +// // blocks that have constraints: +// if ( constrainedBlocks == null ) { +// +// constrainedBlocks = new ArrayList<>(); +// +// for (PrisonBlock block : getPrisonBlocks()) { +// if ( block.getConstraintExcludeTopLayers() > 0 || +// block.getConstraintExcludeBottomLayers() > 0 ) { +// +// constrainedBlocks.add( block ); +// } +// } +// } +// +// +// // If there are any constrained blocks, then need to record +// for ( PrisonBlockStatusData block : constrainedBlocks ) { +// +// // If exclude top layers is enabled, then only try to set the +// // rangeBlockCountLowLimit once since we need the lowest possible +// // value. The inital value for getRangeBlockCountLowLimit is -1. +// if ( block.getConstraintExcludeTopLayers() > 0 && +// block.getRangeBlockCountLowLimit() <= 0 && +// currentLevel > block.getConstraintExcludeTopLayers() ) { +// +// int targetBlockPosition = getMineTargetPrisonBlocks().size(); +// block.setRangeBlockCountLowLimit( 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 ( (block.getConstraintExcludeTopLayers() > 0 && +// currentLevel > block.getConstraintExcludeTopLayers() || +// block.getConstraintExcludeTopLayers() == 0) && +// +// block.getConstraintExcludeBottomLayers() > 0 && +// block.getConstraintExcludeBottomLayers() < currentLevel +// ) { +// +// int targetBlockPosition = getMineTargetPrisonBlocks().size(); +// block.setRangeBlockCountHighLimit( targetBlockPosition ); +// +// } +// } +// +// } /** + * + *

Update 2021-08-25 : This function should only be called once now. The main + * work on performing the actual resets is now performed within the task + * MinePagedResetAsyncTask. This is now to be ran asynchronously. + *

+ * *

Yeah I know, it has async in the name of the function, but it still can only * be ran synchronously. The async part implies this is the reset "part" for the * async workflow. @@ -684,116 +725,221 @@ protected void resetAsynchonously() { if ( !canceled ) { - // First time through... reset the block break count and run the before reset commands: - if ( getResetPosition() == 0 ) { - - // Reset the block break count before resetting the blocks: - // Set it to the original air count, if subtracted from total block count - // in the mine, then the result will be blocks remaining. - setBlockBreakCount( getAirCountOriginal() ); - - - if ( !getCurrentJob().getResetActions().contains( MineResetActions.NO_COMMANDS )) { - - // Before reset commands: - if ( getResetCommands() != null && getResetCommands().size() > 0 ) { - - for (String command : getResetCommands() ) { -// String formatted = cmd.replace("{player}", prisonPlayer.getName()) -// .replace("{player_uid}", player.uid.toString()); - if ( command.startsWith( "before: " )) { - String cmd = command.replace( "before: ", "" ); - - PrisonCommandTask cmdTask = new PrisonCommandTask( "MineReset: Before:" ); - cmdTask.submitCommandTask( cmd ); - - // PrisonAPI.dispatchCommand(cmd); - } - } - } - } - - } - - resetAsynchonouslyUpdate( true ); +// // First time through... reset the block break count and run the before reset commands: +// if ( getResetPosition() == 0 ) { +// +// // Reset the block break count before resetting the blocks: +// // Set it to the original air count, if subtracted from total block count +// // in the mine, then the result will be blocks remaining. +// setBlockBreakCount( getAirCountOriginal() ); +// +// +// if ( !getCurrentJob().getResetActions().contains( MineResetActions.NO_COMMANDS )) { +// +// // Before reset commands: +// if ( getResetCommands() != null && getResetCommands().size() > 0 ) { +// +// for (String command : getResetCommands() ) { +//// String formatted = cmd.replace("{player}", prisonPlayer.getName()) +//// .replace("{player_uid}", player.uid.toString()); +// if ( command.startsWith( "before: " )) { +// String cmd = command.replace( "before: ", "" ); +// +// PrisonCommandTask cmdTask = new PrisonCommandTask( "MineReset: Before:" ); +// cmdTask.submitCommandTask( cmd ); +// +// // PrisonAPI.dispatchCommand(cmd); +// } +// } +// } +// } +// +// } + + asynchronouslyResetSetup(); + + MinePagedResetAsyncTask resetTask = new MinePagedResetAsyncTask( (Mine) this, MineResetType.normal ); + resetTask.submitTaskAsync(); - if ( getResetPosition() == getMineTargetPrisonBlocks().size() ) { - // Done resetting the mine... wrap up: - - - // If a player falls back in to the mine before it is fully done being reset, - // such as could happen if there is lag or a lot going on within the server, - // this will TP anyone out who would otherwise suffocate. I hope! lol - teleportAllPlayersOut(); -// setStatsTeleport2TimeMS( -// teleportAllPlayersOut( getBounds().getyBlockMax() ) ); - - // Reset the paging for the next reset: - setResetPage( 0 ); - - incrementResetCount(); - - if ( !getCurrentJob().getResetActions().contains( MineResetActions.NO_COMMANDS )) { - - // After reset commands: - if ( getResetCommands() != null && getResetCommands().size() > 0 ) { - - for (String command : getResetCommands() ) { -// String formatted = cmd.replace("{player}", prisonPlayer.getName()) -// .replace("{player_uid}", player.uid.toString()); - if ( command.startsWith( "after: " )) { - String cmd = command.replace( "after: ", "" ); - - PrisonCommandTask cmdTask = new PrisonCommandTask( "MineReset: After:" ); - cmdTask.submitCommandTask( cmd ); - - // PrisonAPI.dispatchCommand(cmd); - } - } - } - } - - - // Broadcast message to all players within a certain radius of this mine: - broadcastResetMessageToAllPlayersWithRadius(); -// broadcastResetMessageToAllPlayersWithRadius( MINE_RESET__BROADCAST_RADIUS_BLOCKS ); - - - submitTeleportGlassBlockRemoval(); - - - // Tie to the command stats mode so it logs it if stats are enabled: - if ( PrisonMines.getInstance().getMineManager().isMineStats() || - getCurrentJob().getResetActions().contains( MineResetActions.DETAILS ) ) { - DecimalFormat dFmt = new DecimalFormat("#,##0"); - Output.get().logInfo("&cMine reset: &7" + getTag() + - "&c Blocks: &7" + dFmt.format( getBounds().getTotalBlockCount() ) + - statsMessage() ); - } - - // If part of a chained_resets, then kick off the next reset: - if ( getCurrentJob().getResetActions().contains( MineResetActions.CHAINED_RESETS )) { - - PrisonMines pMines = PrisonMines.getInstance(); - pMines.resetAllMinesNext(); - } - - - } else { - - // Need to continue to reset the mine. Resubmit it to run again. - MineResetAsyncResubmitTask mrAsyncRT = new MineResetAsyncResubmitTask( this, null, - getCurrentJob().getResetActions() ); - - // Must run synchronously!! - submitSyncTask( mrAsyncRT ); - } + asynchronouslyResetFinalize( null ); + + +// resetAsynchonouslyUpdate( true ); + +// if ( getResetPosition() == getMineTargetPrisonBlocks().size() ) { +// // Done resetting the mine... wrap up: +// +// +// // If a player falls back in to the mine before it is fully done being reset, +// // such as could happen if there is lag or a lot going on within the server, +// // this will TP anyone out who would otherwise suffocate. I hope! lol +// teleportAllPlayersOut(); +//// setStatsTeleport2TimeMS( +//// teleportAllPlayersOut( getBounds().getyBlockMax() ) ); +// +// // Reset the paging for the next reset: +// setResetPage( 0 ); +// +// incrementResetCount(); +// +// if ( !getCurrentJob().getResetActions().contains( MineResetActions.NO_COMMANDS )) { +// +// // After reset commands: +// if ( getResetCommands() != null && getResetCommands().size() > 0 ) { +// +// for (String command : getResetCommands() ) { +//// String formatted = cmd.replace("{player}", prisonPlayer.getName()) +//// .replace("{player_uid}", player.uid.toString()); +// if ( command.startsWith( "after: " )) { +// String cmd = command.replace( "after: ", "" ); +// +// PrisonCommandTask cmdTask = new PrisonCommandTask( "MineReset: After:" ); +// cmdTask.submitCommandTask( cmd ); +// +// // PrisonAPI.dispatchCommand(cmd); +// } +// } +// } +// } +// +// +// // Broadcast message to all players within a certain radius of this mine: +// broadcastResetMessageToAllPlayersWithRadius(); +//// broadcastResetMessageToAllPlayersWithRadius( MINE_RESET__BROADCAST_RADIUS_BLOCKS ); +// +// +// submitTeleportGlassBlockRemoval(); +// +// +// // Tie to the command stats mode so it logs it if stats are enabled: +// if ( PrisonMines.getInstance().getMineManager().isMineStats() || +// getCurrentJob().getResetActions().contains( MineResetActions.DETAILS ) ) { +// DecimalFormat dFmt = new DecimalFormat("#,##0"); +// Output.get().logInfo("&cMine reset: &7" + getTag() + +// "&c Blocks: &7" + dFmt.format( getBounds().getTotalBlockCount() ) + +// statsMessage() ); +// } +// +// // If part of a chained_resets, then kick off the next reset: +// if ( getCurrentJob().getResetActions().contains( MineResetActions.CHAINED_RESETS )) { +// +// PrisonMines pMines = PrisonMines.getInstance(); +// pMines.resetAllMinesNext(); +// } +// +// +// } + +// NOTE: Only run this ONCE now... MinePagedResetAsyncTask handles the paging now +// else { +// +// // Need to continue to reset the mine. Resubmit it to run again. +// MineResetAsyncResubmitTask mrAsyncRT = new MineResetAsyncResubmitTask( this, null, +// getCurrentJob().getResetActions() ); +// +// // Must run synchronously!! +// submitSyncTask( mrAsyncRT ); +// } } } + + public void asynchronouslyResetSetup() { + + // Reset the block break count before resetting the blocks: + // Set it to the original air count, if subtracted from total block count + // in the mine, then the result will be blocks remaining. + setBlockBreakCount( getAirCountOriginal() ); + + + if ( !getCurrentJob().getResetActions().contains( MineResetActions.NO_COMMANDS )) { + + // Before reset commands: + if ( getResetCommands() != null && getResetCommands().size() > 0 ) { + + for (String command : getResetCommands() ) { +// String formatted = cmd.replace("{player}", prisonPlayer.getName()) +// .replace("{player_uid}", player.uid.toString()); + if ( command.startsWith( "before: " )) { + String cmd = command.replace( "before: ", "" ); + + PrisonCommandTask cmdTask = new PrisonCommandTask( "MineReset: Before:" ); + cmdTask.submitCommandTask( cmd ); + + // PrisonAPI.dispatchCommand(cmd); + } + } + } + } + } - private boolean resetAsynchonouslyInitiate() { + public void asynchronouslyResetFinalize( List jobResetActions ) { + // If a player falls back in to the mine before it is fully done being reset, + // such as could happen if there is lag or a lot going on within the server, + // this will TP anyone out who would otherwise suffocate. I hope! lol + + MineTeleportTask teleportTask = new MineTeleportTask( (Mine) this ); + teleportTask.submitTaskSync(); + +// teleportAllPlayersOut(); +// setStatsTeleport2TimeMS( +// teleportAllPlayersOut( getBounds().getyBlockMax() ) ); + + // Reset the paging for the next reset: + setResetPage( 0 ); + + incrementResetCount(); + + if ( !getCurrentJob().getResetActions().contains( MineResetActions.NO_COMMANDS )) { + + // After reset commands: + if ( getResetCommands() != null && getResetCommands().size() > 0 ) { + + for (String command : getResetCommands() ) { +// String formatted = cmd.replace("{player}", prisonPlayer.getName()) +// .replace("{player_uid}", player.uid.toString()); + if ( command.startsWith( "after: " )) { + String cmd = command.replace( "after: ", "" ); + + PrisonCommandTask cmdTask = new PrisonCommandTask( "MineReset: After:" ); + cmdTask.submitCommandTask( cmd ); + + // PrisonAPI.dispatchCommand(cmd); + } + } + } + } + + + // Broadcast message to all players within a certain radius of this mine: + broadcastResetMessageToAllPlayersWithRadius(); +// broadcastResetMessageToAllPlayersWithRadius( MINE_RESET__BROADCAST_RADIUS_BLOCKS ); + + + submitTeleportGlassBlockRemoval(); + + + // Tie to the command stats mode so it logs it if stats are enabled: + if ( PrisonMines.getInstance().getMineManager().isMineStats() || + getCurrentJob().getResetActions().contains( MineResetActions.DETAILS ) ) { + DecimalFormat dFmt = new DecimalFormat("#,##0"); + Output.get().logInfo("&cMine reset: &7" + getTag() + + "&c Blocks: &7" + dFmt.format( getBounds().getTotalBlockCount() ) + + statsMessage() ); + } + + // If part of a chained_resets, then kick off the next reset: + if ( jobResetActions != null && jobResetActions.contains( MineResetActions.CHAINED_RESETS ) || + getCurrentJob().getResetActions().contains( MineResetActions.CHAINED_RESETS )) { + + PrisonMines pMines = PrisonMines.getInstance(); + pMines.resetAllMinesNext(); + } + + } + + public boolean resetAsynchonouslyInitiate() { boolean canceled = false; if ( isVirtual()) { @@ -808,7 +954,7 @@ private boolean resetAsynchonouslyInitiate() { canceled = true; } else { - long start = System.currentTimeMillis(); +// long start = System.currentTimeMillis(); // The all-important event MineResetEvent event = new MineResetEvent(this); @@ -817,132 +963,135 @@ private boolean resetAsynchonouslyInitiate() { canceled = event.isCanceled(); if (!canceled) { - try { - teleportAllPlayersOut(); -// setStatsTeleport1TimeMS( -// teleportAllPlayersOut( getBounds().getyBlockMax() ) ); - - } catch (Exception e) { - Output.get().logError("&cMineReset: Failed to TP players out of mine. mine= " + - getName(), e); - canceled = true; - } + MineTeleportTask teleportTask = new MineTeleportTask( (Mine) this ); + teleportTask.submitTaskSync(); +// try { +// teleportAllPlayersOut(); +//// setStatsTeleport1TimeMS( +//// teleportAllPlayersOut( getBounds().getyBlockMax() ) ); +// +// } catch (Exception e) { +// Output.get().logError("&cMineReset: Failed to TP players out of mine. mine= " + +// getName(), e); +// canceled = true; +// } } - long stop = System.currentTimeMillis(); - setStatsResetTimeMS( stop - start ); +// long stop = System.currentTimeMillis(); +// setStatsResetTimeMS( stop - start ); } return canceled; } - /** - *

This is the synchronous part of the job that actually updates the blocks. - * It will only replace what it can within the given allocated milliseconds, - * then it will terminate and allow this process to re-run, picking up where it - * left off. - *

- * - *

Paging is what this is doing. Running, and doing what it can within it's - * limited amount of time, then yielding to any other task, then resuming later. - * This is a way of running a massive synchronous task, without hogging all the - * resources and killing the TPS. - *

- * - *

NOTE: The values for MINE_RESET__PAGE_TIMEOUT_CHECK__BLOCK_COUNT and for - * MINE_RESET__MAX_PAGE_ELASPSED_TIME_MS are set to arbitrary values and may not - * be the correct values. They may be too large and may have to be adjusted to - * smaller values to better tune the process. - *

- * - */ - private void resetAsynchonouslyUpdate( boolean paged ) { - if ( isVirtual() ) { - // ignore: - } - else - if ( !isEnabled() ) { - Output.get().logError( - String.format( "MineReset: resetAsynchonouslyUpdate failure: Mine is not enabled. " + - "Ensure world exists. mine= %s ", - getName() )); - } - else { - World world = getBounds().getCenter().getWorld(); - - - long start = System.currentTimeMillis(); - -// boolean isFillMode = PrisonMines.getInstance().getConfig().fillMode; - - int blocksPlaced = 0; - long elapsed = 0; - - int i = getResetPosition(); - for ( ; i < getMineTargetPrisonBlocks().size(); i++ ) - { - MineTargetPrisonBlock target = getMineTargetPrisonBlocks().get(i); - - Location targetBlock = new Location(world, - target.getBlockKey().getX(), target.getBlockKey().getY(), - target.getBlockKey().getZ()); - -// if (!isFillMode || isFillMode && targetBlock.getBlockAt().isEmpty()) { -// } - if ( isUseNewBlockModel() ) { - - targetBlock.getBlockAt().setPrisonBlock( (PrisonBlock) target.getPrisonBlock() ); - } - else { - - targetBlock.getBlockAt().setType( ((BlockOld) target.getPrisonBlock()).getType() ); - } - - /** - * If paged is enabled... - * - * About every 250 blocks, or so, check to see if the current wall time - * spent is greater than - * the threshold. If it is greater, then end the update and let it resubmit. - * It does not matter how many blocks were actually updated during this "page", - * but what it is more important is the actual elapsed time. This is to allow other - * processes to get processing time and to eliminate possible lagging. - */ - if ( paged && i % getResetPageTimeoutCheckBlockCount() == 0 ) { - elapsed = System.currentTimeMillis() - start; - if ( elapsed > getResetPageMaxPageElapsedTimeMs() ) { - - break; - } - } - } - - blocksPlaced = i - getResetPosition(); - - if ( PrisonMines.getInstance().getMineManager().isMineStats() ) { - - // Only print these details if stats is enabled: - Output.get().logInfo( "MineReset.resetAsynchonouslyUpdate() :" + - " page " + getResetPage() + - " blocks = " + blocksPlaced + " elapsed = " + elapsed ); - } - - setResetPosition( i ); - - setResetPage( getResetPage() + 1 ); - - long time = System.currentTimeMillis() - start; - setStatsBlockUpdateTimeMS( time + getStatsBlockUpdateTimeMS() ); - setStatsResetTimeMS( time + getStatsResetTimeMS() ); - - - setStatsResetPages( getStatsResetPages() + 1 ); - setStatsResetPageBlocks( getStatsResetPageBlocks() + blocksPlaced ); - setStatsResetPageMs( getStatsResetPageMs() + time ); - } - - } +// /** +// *

This is the synchronous part of the job that actually updates the blocks. +// * It will only replace what it can within the given allocated milliseconds, +// * then it will terminate and allow this process to re-run, picking up where it +// * left off. +// *

+// * +// *

Paging is what this is doing. Running, and doing what it can within it's +// * limited amount of time, then yielding to any other task, then resuming later. +// * This is a way of running a massive synchronous task, without hogging all the +// * resources and killing the TPS. +// *

+// * +// *

NOTE: The values for MINE_RESET__PAGE_TIMEOUT_CHECK__BLOCK_COUNT and for +// * MINE_RESET__MAX_PAGE_ELASPSED_TIME_MS are set to arbitrary values and may not +// * be the correct values. They may be too large and may have to be adjusted to +// * smaller values to better tune the process. +// *

+// * +// */ +// private void resetAsynchonouslyUpdate( boolean paged ) { +// if ( isVirtual() ) { +// // ignore: +// } +// else +// if ( !isEnabled() ) { +// Output.get().logError( +// String.format( "MineReset: resetAsynchonouslyUpdate failure: Mine is not enabled. " + +// "Ensure world exists. mine= %s ", +// getName() )); +// } +// else { +// World world = getBounds().getCenter().getWorld(); +// +// +// long start = System.currentTimeMillis(); +// +//// boolean isFillMode = PrisonMines.getInstance().getConfig().fillMode; +// +// int blocksPlaced = 0; +// long elapsed = 0; +// +// int i = getResetPosition(); +// for ( ; i < getMineTargetPrisonBlocks().size(); i++ ) +// { +// MineTargetPrisonBlock target = getMineTargetPrisonBlocks().get(i); +// +// Location targetBlock = new Location(world, +// target.getBlockKey().getX(), target.getBlockKey().getY(), +// target.getBlockKey().getZ()); +// +//// if (!isFillMode || isFillMode && targetBlock.getBlockAt().isEmpty()) { +//// } +// if ( isUseNewBlockModel() ) { +// +// targetBlock.getBlockAt().setPrisonBlock( (PrisonBlock) target.getPrisonBlock() ); +// } +// else { +// +// targetBlock.getBlockAt().setType( ((BlockOld) target.getPrisonBlock()).getType() ); +// } +// +// /** +// * If paged is enabled... +// * +// * About every 250 blocks, or so, check to see if the current wall time +// * spent is greater than +// * the threshold. If it is greater, then end the update and let it resubmit. +// * It does not matter how many blocks were actually updated during this "page", +// * but what it is more important is the actual elapsed time. This is to allow other +// * processes to get processing time and to eliminate possible lagging. +// */ +// if ( paged && i % getResetPageTimeoutCheckBlockCount() == 0 ) { +// elapsed = System.currentTimeMillis() - start; +// if ( elapsed > getResetPageMaxPageElapsedTimeMs() ) { +// +// break; +// } +// } +// } +// +// blocksPlaced = i - getResetPosition(); +// +// if ( PrisonMines.getInstance().getMineManager().isMineStats() ) { +// +// // Only print these details if stats is enabled: +// Output.get().logInfo( "MineReset.resetAsynchonouslyUpdate() :" + +// " page " + getResetPage() + +// " blocks = " + blocksPlaced + " elapsed = " + elapsed + +// " ms TPS: " + Prison.get().getPrisonTPS().getAverageTPSFormatted() ); +// } +// +// setResetPosition( i ); +// +// setResetPage( getResetPage() + 1 ); +// +// long time = System.currentTimeMillis() - start; +// setStatsBlockUpdateTimeMS( time + getStatsBlockUpdateTimeMS() ); +// setStatsResetTimeMS( time + getStatsResetTimeMS() ); +// +// +// setStatsResetPages( getStatsResetPages() + 1 ); +// setStatsResetPageBlocks( getStatsResetPageBlocks() + blocksPlaced ); +// setStatsResetPageMs( getStatsResetPageMs() + time ); +// } +// +// } @@ -1024,6 +1173,16 @@ else if ( !isUseNewBlockModel() && World world = worldOptional.get(); + if ( world == null ) { + Output.get().logError( + String.format( "MineReset: refreshAirCountAsyncTask failure: The world is invalid and " + + "cannot be located. mine= %s worldName=%s ", + getName(), getWorldName() )); + + + return; + } + // Reset the target block lists: clearMineTargetPrisonBlocks(); @@ -1031,26 +1190,51 @@ else if ( !isUseNewBlockModel() && int airCount = 0; int errorCount = 0; + + + + int yMin = getBounds().getyBlockMin(); + int yMax = getBounds().getyBlockMax(); + + int xMin = getBounds().getxBlockMin(); + int xMax = getBounds().getxBlockMax(); + + int zMin = getBounds().getzBlockMin(); + int zMax = getBounds().getzBlockMax(); + + + StringBuilder sb = new StringBuilder(); - for (int y = getBounds().getyBlockMax(); y >= getBounds().getyBlockMin(); y--) { - for (int x = getBounds().getxBlockMin(); x <= getBounds().getxBlockMax(); x++) { - for (int z = getBounds().getzBlockMin(); z <= getBounds().getzBlockMax(); z++) { + for (int y = yMax; y >= yMin; y--) { + for (int x = xMin; x <= xMax; x++) { + for (int z = zMin; z <= zMax; z++) { try { Location targetBlock = new Location(world, x, y, z); Block tBlock = targetBlock.getBlockAt(); + + boolean xEdge = x == xMin || x == xMax; + boolean yEdge = y == yMin || y == yMax; + boolean zEdge = z == zMin || z == zMax; + + boolean isEdge = xEdge && yEdge || xEdge && zEdge || + yEdge && zEdge; + + if ( isUseNewBlockModel() ) { PrisonBlock pBlock = tBlock.getPrisonBlock(); - // Increment the mine's block count. This block is one of the control blocks: - addMineTargetPrisonBlock( incrementResetBlockCount( pBlock ), x, y, z ); - + if ( pBlock != null ) { + + // Increment the mine's block count. This block is one of the control blocks: + addMineTargetPrisonBlock( incrementResetBlockCount( pBlock ), x, y, z, isEdge ); + + } - if ( pBlock == null || - pBlock.equals( PrisonBlock.AIR ) ) { + if ( pBlock == null || pBlock.isAir() ) { airCount++; } } @@ -1058,9 +1242,12 @@ else if ( !isUseNewBlockModel() && BlockOld oBlock = new BlockOld( tBlock.getType() ); - // Increment the mine's block count. This block is one of the control blocks: - addMineTargetPrisonBlock( incrementResetBlockCount( oBlock ), x, y, z ); - + if ( oBlock != null ) { + + // Increment the mine's block count. This block is one of the control blocks: + addMineTargetPrisonBlock( incrementResetBlockCount( oBlock ), x, y, z, isEdge ); + + } if ( tBlock.getType() == BlockType.AIR ) { airCount++; @@ -1080,7 +1267,7 @@ else if ( !isUseNewBlockModel() && "MineReset.refreshAirCountAsyncTask: Error counting air blocks: " + "Mine=%s coords=%s Error: %s ", getName(), coords, e.getMessage() ); if ( e.getMessage() != null && e.getMessage().contains( "Asynchronous entity world add" )) { - Output.get().logWarn( message ); + Output.get().logWarn( message, e ); } else { Output.get().logWarn( message, e ); } @@ -1138,15 +1325,16 @@ protected void runMineSweeperTask() { for ( MineTargetPrisonBlock targetBlock : getMineTargetPrisonBlocks() ) { - if ( targetBlock != null && !targetBlock.isAirBroke() ) { + if ( targetBlock != null && !targetBlock.isAirBroke() && + !targetBlock.isCounted()) { + MineTargetBlockKey key = targetBlock.getBlockKey(); Location blockLocation = new Location( world, key.getX(), key.getY(), key.getZ() ); Block block = world.getBlockAt( blockLocation ); if ( block.isEmpty() ) { - targetBlock.getPrisonBlock().incrementMiningBlockCount(); - targetBlock.setAirBroke( true ); + incrementBlockMiningCount( targetBlock ); blocksChanged++; } @@ -1284,54 +1472,71 @@ else if ( getPercentRemainingBlockCount() > getSkipResetPercent() ) { // Mine reset here: // Async if possible... - resetAsynchonously(); - } - - public void refreshMineAsyncResubmitTask() { + MinePagedResetAsyncTask resetTask = new MinePagedResetAsyncTask( (Mine) this, MineResetType.normal ); + resetTask.submitTaskAsync(); - // Mine reset here: - resetAsynchonously(); +// resetAsynchonously(); } +// public void refreshMineAsyncResubmitTask() { +// +// // Mine reset here: +// resetAsynchonously(); +// } + - private PrisonBlock randomlySelectPrisonBlock( Random random, int currentLevel ) { - - int targetBlockPosition = getMineTargetPrisonBlocks().size(); - - PrisonBlock prisonBlock = Prison.get().getPlatform().getPrisonBlock( "AIR" ); - - // If a chosen block was skipped, try to find another block, but try no more than 10 times - // to prevent a possible endless loop. Side effects of failing to find a block in 10 attempts - // would be an air block. - boolean success = false; - int attempts = 0; - while ( !success && attempts++ < 10 ) { - double chance = random.nextDouble() * 100.0d; - - for (PrisonBlock block : getPrisonBlocks()) { - boolean isBlockEnabled = block.isBlockConstraintsEnbled( currentLevel, targetBlockPosition ); - - if ( chance <= block.getChance() ) { - - // If this block is chosen and it was not skipped, then use this block and exit. - // Otherwise the chance will be recalculated and tried again to find a valid block, - // since the odds have been thrown off... - if ( isBlockEnabled ) { - prisonBlock = block; - - // stop trying to locate a block so success will terminate the search: - success = true; - } - - break; - } else { - chance -= block.getChance(); - } - } - } - return prisonBlock; - } +// private PrisonBlock randomlySelectPrisonBlock( Random random, int currentLevel ) { +// +// int targetBlockPosition = getMineTargetPrisonBlocks().size(); +// +// PrisonBlock prisonBlock = Prison.get().getPlatform().getPrisonBlock( "AIR" ); +// +// +// // this fallbackBlock field will provide a valid block that can be used when all other +// // blocks have failed to be matched due to constraints not aligning with the random chance. +// // As a result of failing to find a block, would result in an AIR block being used instead. +// PrisonBlock fallbackBlock = null; +// +// +// // If a chosen block was skipped, try to find another block, but try no more than 10 times +// // to prevent a possible endless loop. Side effects of failing to find a block in 10 attempts +// // would be an air block. +// boolean success = false; +// int attempts = 0; +// while ( !success && attempts++ < 10 ) { +// double chance = random.nextDouble() * 100.0d; +// +// for (PrisonBlock block : getPrisonBlocks()) { +// boolean isBlockEnabled = block.isBlockConstraintsEnbled( currentLevel, targetBlockPosition ); +// +// if ( fallbackBlock == null && isBlockEnabled && !block.isAir() ) { +// fallbackBlock = block; +// } +// +// if ( chance <= block.getChance() && isBlockEnabled ) { +// +// // If this block is chosen and it was not skipped, then use this block and exit. +// // Otherwise the chance will be recalculated and tried again to find a valid block, +// // since the odds have been thrown off... +// prisonBlock = block; +// +// // stop trying to locate a block so success will terminate the search: +// success = true; +// +// break; +// } else { +// chance -= block.getChance(); +// } +// } +// +// if ( !success && fallbackBlock != null ) { +// prisonBlock = fallbackBlock; +// success = true; +// } +// } +// return prisonBlock; +// } private BlockOld randomlySelectBlock( Random random, int currentLevel ) { @@ -1339,6 +1544,14 @@ private BlockOld randomlySelectBlock( Random random, int currentLevel ) { BlockOld results = BlockOld.AIR; + + // this fallbackBlock field will provide a valid block that can be used when all other + // blocks have failed to be matched due to constraints not aligning with the random chance. + // As a result of failing to find a block, would result in an AIR block being used instead. + BlockOld fallbackBlock = null; + + + // If a chosen block was skipped, try to find another block, but try no more than 10 times // to prevent a possible endless loop. Side effects of failing to find a block in 10 attempts // would be an air block. @@ -1350,17 +1563,19 @@ private BlockOld randomlySelectBlock( Random random, int currentLevel ) { for (BlockOld block : getBlocks()) { boolean isBlockEnabled = block.isBlockConstraintsEnbled( currentLevel, targetBlockPosition ); - if ( chance <= block.getChance() ) { + if ( fallbackBlock == null && isBlockEnabled && !block.isAir() ) { + fallbackBlock = block; + } + + if ( chance <= block.getChance() && isBlockEnabled ) { // If this block is chosen and it was not skipped, then use this block and exit. // Otherwise the chance will be recalculated and tried again to find a valid block, // since the odds have been thrown off... - if ( isBlockEnabled ) { - results = block; - - // stop trying to locate a block so success will terminate the search: - success = true; - } + results = block; + + // stop trying to locate a block so success will terminate the search: + success = true; break; } else { @@ -1369,6 +1584,10 @@ private BlockOld randomlySelectBlock( Random random, int currentLevel ) { } } + if ( !success && fallbackBlock != null ) { + results = fallbackBlock; + success = true; + } // for (BlockOld block : getBlocks()) { // if (block.checkConstraints( currentLevel, targetBlockPosition ) && @@ -1460,6 +1679,15 @@ private void constraintsApplyMin( PrisonBlockStatusData block, boolean useNewBlo // Add the new block and increment it's count: targetBlock.setPrisonBlock( block ); + + // If the reset is placing an AiR block, then mark the block as + // setAirBroke() and setMined() to ensure they are not counted or + // processed during normal mining operations, or through + // MineSweeper checks. + if ( block.isAir() ) { + targetBlock.setAirBroke( true ); + targetBlock.setMined( true ); + } block.incrementResetBlockCount(); } } @@ -1560,9 +1788,9 @@ public void setCurrentJob( MineJob currentJob ) - private void addMineTargetPrisonBlock( PrisonBlockStatusData block, int x, int y, int z ) { + private void addMineTargetPrisonBlock( PrisonBlockStatusData block, int x, int y, int z, boolean isEdge ) { - MineTargetPrisonBlock mtpb = new MineTargetPrisonBlock( block, getWorld().get(), x, y, z ); + MineTargetPrisonBlock mtpb = new MineTargetPrisonBlock( block, getWorld().get(), x, y, z, isEdge ); getMineTargetPrisonBlocks().add( mtpb ); getMineTargetPrisonBlocksMap().put( mtpb.getBlockKey(), mtpb ); @@ -1735,32 +1963,12 @@ public void setStatsBlockUpdateTimeMS( long statsBlockUpdateTimeMS ) this.statsBlockUpdateTimeMS = statsBlockUpdateTimeMS; } -// public long getStatsTeleport1TimeMS() -// { -// return statsTeleport1TimeMS; -// } -// public void setStatsTeleport1TimeMS( long statsTeleport1TimeMS ) -// { -// this.statsTeleport1TimeMS = statsTeleport1TimeMS; -// } -// -// public long getStatsTeleport2TimeMS() -// { -// return statsTeleport2TimeMS; -// } -// public void setStatsTeleport2TimeMS( long statsTeleport2TimeMS ) -// { -// this.statsTeleport2TimeMS = statsTeleport2TimeMS; -// } -// -// public long getStatsMessageBroadcastTimeMS() -// { -// return statsMessageBroadcastTimeMS; -// } -// public void setStatsMessageBroadcastTimeMS( long statsMessageBroadcastTimeMS ) -// { -// this.statsMessageBroadcastTimeMS = statsMessageBroadcastTimeMS; -// } + public long getStatsBlockUpdateTimeNanos() { + return statsBlockUpdateTimeNanos; + } + public void setStatsBlockUpdateTimeNanos( long statsBlockUpdateTimeNanos ) { + this.statsBlockUpdateTimeNanos = statsBlockUpdateTimeNanos; + } public int getStatsResetPages() { return statsResetPages; diff --git a/prison-mines/src/main/java/tech/mcprison/prison/mines/data/MineResetAsyncResubmitTask.java b/prison-mines/src/main/java/tech/mcprison/prison/mines/data/MineResetAsyncResubmitTask.java deleted file mode 100644 index cff8db601..000000000 --- a/prison-mines/src/main/java/tech/mcprison/prison/mines/data/MineResetAsyncResubmitTask.java +++ /dev/null @@ -1,38 +0,0 @@ -package tech.mcprison.prison.mines.data; - -import java.util.List; - -import tech.mcprison.prison.mines.data.MineScheduler.MineResetActions; -import tech.mcprison.prison.tasks.PrisonRunnable; - -public class MineResetAsyncResubmitTask - implements PrisonRunnable -{ - - private MineReset mine; - private PrisonRunnable callbackAsync; - - private List resetActions; - - public MineResetAsyncResubmitTask(MineReset mine, PrisonRunnable callbackAsync, - List resetActions ) { - - this.mine = mine; - this.callbackAsync = callbackAsync; - - this.resetActions = resetActions; - } - - @Override - public void run() { - - this.mine.getCurrentJob().setResetActions( resetActions ); - - this.mine.refreshMineAsyncResubmitTask(); - - if ( this.callbackAsync != null ) { - this.mine.submitAsyncTask( callbackAsync ); - } - } - -} 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 1cea8ac3c..99809701a 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 @@ -11,17 +11,20 @@ import tech.mcprison.prison.Prison; import tech.mcprison.prison.internal.Player; import tech.mcprison.prison.internal.World; +import tech.mcprison.prison.internal.block.MineResetType; +import tech.mcprison.prison.internal.block.MineTargetPrisonBlock; import tech.mcprison.prison.internal.block.PrisonBlock; import tech.mcprison.prison.internal.block.PrisonBlockStatusData; import tech.mcprison.prison.mines.PrisonMines; import tech.mcprison.prison.mines.features.MineBlockEvent; import tech.mcprison.prison.mines.features.MineBlockEvent.BlockEventType; -import tech.mcprison.prison.mines.features.MineTargetPrisonBlock; +import tech.mcprison.prison.mines.tasks.MinePagedResetAsyncTask; import tech.mcprison.prison.output.Output; import tech.mcprison.prison.tasks.PrisonCommandTask; +import tech.mcprison.prison.tasks.PrisonCommandTask.CustomPlaceholders; import tech.mcprison.prison.tasks.PrisonRunnable; import tech.mcprison.prison.tasks.PrisonTaskSubmitter; -import tech.mcprison.prison.tasks.PrisonCommandTask.CustomPlaceholders; +import tech.mcprison.prison.util.Location; public abstract class MineScheduler extends MineTasks @@ -93,7 +96,7 @@ public JobType getJobType() } } - public enum MineResetType { + public enum MineResetScheduleType { NORMAL, FORCED; } @@ -123,7 +126,7 @@ public class MineJob private MineJobAction action; private double delayActionSec; private double resetInSec; - private MineResetType resetType; + private MineResetScheduleType resetType; private List resetActions; public MineJob( MineJobAction action, double delayActionSec, double resetInSec ) @@ -134,12 +137,12 @@ public MineJob( MineJobAction action, double delayActionSec, double resetInSec ) this.delayActionSec = delayActionSec; this.resetInSec = resetInSec; - this.resetType = MineResetType.NORMAL; + this.resetType = MineResetScheduleType.NORMAL; this.resetActions = new ArrayList<>(); } - public MineJob( MineJobAction action, double delayActionSec, double resetInSec, MineResetType resetType ) + public MineJob( MineJobAction action, double delayActionSec, double resetInSec, MineResetScheduleType resetType ) { this( action, delayActionSec, resetInSec ); @@ -186,10 +189,10 @@ public void setResetInSec( double resetInSec ) { this.resetInSec = resetInSec; } - public MineResetType getResetType() { + public MineResetScheduleType getResetType() { return resetType; } - public void setResetType( MineResetType resetType ) { + public void setResetType( MineResetScheduleType resetType ) { this.resetType = resetType; } @@ -237,6 +240,9 @@ private List initializeJobWorkflow() */ protected List initializeJobWorkflow( double resetTime, boolean includeMessages, ArrayList rwTimes ) { + double targetResetTime = resetTime; + + List workflow = new ArrayList<>(); ArrayList resetWarningTimes = new ArrayList<>(); @@ -258,8 +264,8 @@ protected List initializeJobWorkflow( double resetTime, boolean include // if the mine is virtual, set the resetTime to four hours. It won't reset, but it will stay active // in the workflow: - if ( isVirtual() ) { - resetTime = 60 * 60 * 4; // one hour * 4 + if ( isVirtual() || resetTime <= 0 ) { + targetResetTime = 60 * 60 * 4; // one hour * 4 } // Determine if the sync or async reset action should be used for this workflow. @@ -272,7 +278,7 @@ protected List initializeJobWorkflow( double resetTime, boolean include double total = 0; for ( Integer time : resetWarningTimes ) { - if ( time < resetTime ) { + if ( time < targetResetTime ) { // if reset time is less than warning time, then skip warning: double elapsed = time - total; workflow.add( @@ -283,11 +289,11 @@ protected List initializeJobWorkflow( double resetTime, boolean include } workflow.add( new MineJob( workflow.size() == 0 ? resetAction : MineJobAction.MESSAGE, - (resetTime - total), total) ); + (targetResetTime - total), total) ); } else { // Exclude all messages. Only reset mine: - workflow.add( new MineJob( resetAction, resetTime, 0) ); + workflow.add( new MineJob( resetAction, targetResetTime, 0) ); } return workflow; @@ -324,8 +330,14 @@ public void run() // appears like it will never load? //checkWorld(); + if ( getResetTime() <= 0 ) { + + submitNextAction(); + return; + } + boolean forced = getCurrentJob() != null && - getCurrentJob().getResetType() == MineResetType.FORCED; + getCurrentJob().getResetType() == MineResetScheduleType.FORCED; boolean skip = !forced && isSkipResetEnabled() && @@ -363,7 +375,14 @@ public void run() case RESET_ASYNC: if ( !skip ) { - resetAsynchonously(); + + List resetActions = getCurrentJob().getResetActions(); + + MinePagedResetAsyncTask resetTask = + new MinePagedResetAsyncTask( (Mine) this, MineResetType.paged, resetActions ); + resetTask.submitTaskAsync(); + +// resetAsynchonously(); } else { incrementSkipResetBypassCount(); } @@ -373,7 +392,15 @@ public void run() case RESET_SYNC: // synchronous reset. Will be phased out in the future? if ( !skip ) { - resetSynchonously(); + + List resetActions = getCurrentJob().getResetActions(); + + MinePagedResetAsyncTask resetTask = + new MinePagedResetAsyncTask( (Mine) this, MineResetType.normal, resetActions ); + + resetTask.submitTaskAsync(); + +// resetSynchonously(); } else { incrementSkipResetBypassCount(); } @@ -561,6 +588,7 @@ private void processBlockEventDetails( Player player, PrisonBlock prisonBlock, boolean fireEvent = blockEvent.isFireEvent( chance, eventType, targetBlock, triggered ); + if ( fireEvent ) { // If perms are set, check them, otherwise ignore perm check: @@ -579,17 +607,21 @@ private void processBlockEventDetails( Player player, PrisonBlock prisonBlock, cmdTask.addCustomPlaceholder( CustomPlaceholders.blockName, originalBlock.getBlockName() ); cmdTask.addCustomPlaceholder( CustomPlaceholders.mineName, getName() ); - if ( prisonBlock.getLocation() != null ) { - cmdTask.addCustomPlaceholder( CustomPlaceholders.locationWorld, prisonBlock.getLocation().getWorld().getName() ); - cmdTask.addCustomPlaceholder( CustomPlaceholders.locationX, Integer.toString( prisonBlock.getLocation().getBlockX() )); - cmdTask.addCustomPlaceholder( CustomPlaceholders.locationY, Integer.toString( prisonBlock.getLocation().getBlockY() )); - cmdTask.addCustomPlaceholder( CustomPlaceholders.locationZ, Integer.toString( prisonBlock.getLocation().getBlockZ() )); + if ( targetBlock.getLocation() != null ) { + Location location = targetBlock.getLocation(); - cmdTask.addCustomPlaceholder( CustomPlaceholders.coordinates, prisonBlock.getLocation().toCoordinates() ); - cmdTask.addCustomPlaceholder( CustomPlaceholders.worldCoordinates, prisonBlock.getLocation().toWorldCoordinates() ); + cmdTask.addCustomPlaceholder( CustomPlaceholders.locationWorld, location.getWorld().getName() ); + cmdTask.addCustomPlaceholder( CustomPlaceholders.locationX, Integer.toString( location.getBlockX() )); + cmdTask.addCustomPlaceholder( CustomPlaceholders.locationY, Integer.toString( location.getBlockY() )); + cmdTask.addCustomPlaceholder( CustomPlaceholders.locationZ, Integer.toString( location.getBlockZ() )); + + cmdTask.addCustomPlaceholder( CustomPlaceholders.coordinates, location.toCoordinates() ); + cmdTask.addCustomPlaceholder( CustomPlaceholders.worldCoordinates, location.toWorldCoordinates() ); + + cmdTask.addCustomPlaceholder( CustomPlaceholders.blockCoordinates, targetBlock.getBlockCoordinates() ); } - cmdTask.addCustomPlaceholder( CustomPlaceholders.blockCoordinates, prisonBlock.getBlockCoordinates() ); +// cmdTask.addCustomPlaceholder( CustomPlaceholders.blockCoordinates, prisonBlock.getBlockCoordinates() ); cmdTask.addCustomPlaceholder( CustomPlaceholders.blockChance, dFmt.format( originalBlock.getChance() ) ); @@ -597,7 +629,7 @@ private void processBlockEventDetails( Player player, PrisonBlock prisonBlock, cmdTask.addCustomPlaceholder( CustomPlaceholders.blocksPlaced, Integer.toString( originalBlock.getBlockPlacedCount() )); cmdTask.addCustomPlaceholder( CustomPlaceholders.blockRemaining, Long.toString( originalBlock.getBlockCountUnsaved() )); - cmdTask.addCustomPlaceholder( CustomPlaceholders.blocksMinedTotal, originalBlock.getBlockName() ); + cmdTask.addCustomPlaceholder( CustomPlaceholders.blocksMinedTotal, Long.toString( originalBlock.getBlockCountSession() ) ); cmdTask.addCustomPlaceholder( CustomPlaceholders.mineBlocksRemaining, Integer.toString( getRemainingBlockCount() )); cmdTask.addCustomPlaceholder( CustomPlaceholders.mineBlocksRemainingPercent, Double.toString( getPercentRemainingBlockCount() ) ); @@ -607,10 +639,12 @@ private void processBlockEventDetails( Player player, PrisonBlock prisonBlock, cmdTask.addCustomPlaceholder( CustomPlaceholders.blockIsAir, Boolean.toString( targetBlock.getPrisonBlock().isAir() )); - - cmdTask.addCustomPlaceholder( CustomPlaceholders.blockMinedName, prisonBlock.getBlockName() ); - cmdTask.addCustomPlaceholder( CustomPlaceholders.blockMinedNameFormal, prisonBlock.getBlockNameFormal() ); - cmdTask.addCustomPlaceholder( CustomPlaceholders.blockMinedBlockType, prisonBlock.getBlockType().name() ); + if ( prisonBlock != null ) { + + cmdTask.addCustomPlaceholder( CustomPlaceholders.blockMinedName, prisonBlock.getBlockName() ); + cmdTask.addCustomPlaceholder( CustomPlaceholders.blockMinedNameFormal, prisonBlock.getBlockNameFormal() ); + cmdTask.addCustomPlaceholder( CustomPlaceholders.blockMinedBlockType, prisonBlock.getBlockType().name() ); + } cmdTask.addCustomPlaceholder( CustomPlaceholders.eventType, eventType.name() ); cmdTask.addCustomPlaceholder( CustomPlaceholders.eventTriggered, triggered ); @@ -689,7 +723,7 @@ public boolean checkZeroBlockReset() { )) { // submit a manual reset since the mine is empty: - manualReset( MineResetType.NORMAL, getZeroBlockResetDelaySec() ); + manualReset( MineResetScheduleType.NORMAL, getZeroBlockResetDelaySec() ); reset = true; } return reset; @@ -701,21 +735,21 @@ public boolean checkZeroBlockReset() { * */ public void manualReset() { - manualReset( MineResetType.FORCED ); + manualReset( MineResetScheduleType.FORCED ); } - public void manualReset( MineResetType resetType ) { + public void manualReset( MineResetScheduleType resetType ) { if ( !isVirtual() ) { manualReset( resetType, 0 ); } } - private void manualReset( MineResetType resetType, double delayActionSec ) { + private void manualReset( MineResetScheduleType resetType, double delayActionSec ) { List resetActions = new ArrayList<>(); manualReset( resetType, delayActionSec, resetActions ); } - public void manualReset( MineResetType resetType, List resetActions ) { + public void manualReset( MineResetScheduleType resetType, List resetActions ) { manualReset( resetType, 0, resetActions ); } @@ -732,7 +766,7 @@ public void manualReset( MineResetType resetType, List resetAc * @param delayActionSec Delay in seconds before resetting mine. * */ - private void manualReset( MineResetType resetType, double delayActionSec, + private void manualReset( MineResetScheduleType resetType, double delayActionSec, List resetActions ) { if ( isVirtual() ) { diff --git a/prison-mines/src/main/java/tech/mcprison/prison/mines/data/MineStateMutex.java b/prison-mines/src/main/java/tech/mcprison/prison/mines/data/MineStateMutex.java new file mode 100644 index 000000000..7dbef5007 --- /dev/null +++ b/prison-mines/src/main/java/tech/mcprison/prison/mines/data/MineStateMutex.java @@ -0,0 +1,99 @@ +package tech.mcprison.prison.mines.data; + +public class MineStateMutex +{ + private MineState mineState; + private int mineStateSn = 0; + + private boolean cloned = false; + + public enum MineState { + LOCKED, + UNLOCKED; + } + + public MineStateMutex() { + + this.mineState = MineState.UNLOCKED; + + this.mineStateSn = 0; + + this.cloned = false; + } + + private MineStateMutex( MineStateMutex cloneSource ) { + + this.mineState = cloneSource.getMineState(); + + this.mineStateSn = cloneSource.getMineStateSn(); + + this.cloned = true; + } + + public void setMineStateResetStart() { + + synchronized ( this ) { + + this.mineState = MineState.LOCKED; + this.mineStateSn++; + } + + } + + public void setMineStateResetFinished() { + + synchronized ( this ) { + + this.mineState = MineState.UNLOCKED; + } + + } + + public boolean isMinable() { + boolean results = false; + + synchronized ( this ) { + + if ( getMineState() == MineState.UNLOCKED ) { + + results = true; + } + } + + return results; + } + + public boolean isValidState( MineStateMutex mutex ) { + boolean results = false; + + synchronized ( this ) { + + if ( getMineState() == MineState.UNLOCKED && + getMineStateSn() == mutex.getMineStateSn() ) { + + results = true; + } + } + + return results; + } + + public MineStateMutex clone() { + MineStateMutex results = new MineStateMutex( this ); + + return results; + } + + public MineState getMineState() { + return mineState; + } + + public int getMineStateSn() { + return mineStateSn; + } + + public boolean isCloned() { + return cloned; + } + +} 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 eada36bf0..5bdc66723 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 @@ -5,11 +5,11 @@ import tech.mcprison.prison.Prison; import tech.mcprison.prison.internal.Player; import tech.mcprison.prison.internal.World; -import tech.mcprison.prison.internal.block.Block; import tech.mcprison.prison.internal.block.PrisonBlock; import tech.mcprison.prison.mines.PrisonMines; import tech.mcprison.prison.mines.data.MineScheduler.MineJob; import tech.mcprison.prison.mines.tasks.MineChangeBlockTask; +import tech.mcprison.prison.output.Output; import tech.mcprison.prison.tasks.PrisonRunnable; import tech.mcprison.prison.tasks.PrisonTaskSubmitter; import tech.mcprison.prison.util.Location; @@ -81,7 +81,7 @@ public void submitSyncTask( PrisonRunnable callbackSync ) { * @param targetY */ @Override - protected long teleportAllPlayersOut() { + public long teleportAllPlayersOut() { long start = System.currentTimeMillis(); if ( isVirtual() ) { @@ -90,17 +90,23 @@ protected long teleportAllPlayersOut() { World world = getBounds().getCenter().getWorld(); - if ( isEnabled() && world != null ) { - List players = (world.getPlayers() != null ? world.getPlayers() : - Prison.get().getPlatform().getOnlinePlayers()); - for (Player player : players) { - if ( getBounds().withinIncludeTopBottomOfMine(player.getLocation()) ) { - - teleportPlayerOut(player); + try { + if ( isEnabled() && world != null ) { + List players = (world.getPlayers() != null ? world.getPlayers() : + Prison.get().getPlatform().getOnlinePlayers()); + for (Player player : players) { + if ( getBounds().withinIncludeTopBottomOfMine(player.getLocation()) ) { + + teleportPlayerOut(player); + } } } + } - + catch (Exception e) { + Output.get().logError("&cMineReset: Failed to TP players out of mine. mine= " + + getName(), e); + } return System.currentTimeMillis() - start; } @@ -177,27 +183,36 @@ public Location teleportPlayerOut(Player player, String targetLocation) { @Override public void submitTeleportGlassBlockRemoval() { - Location altTp = alternativeTpLocation(); - Location tpTargetLocation = isHasSpawn() ? getSpawn() : altTp; +// Location altTp = alternativeTpLocation(); + Location tpTargetLocation = isHasSpawn() ? getSpawn() : alternativeTpLocation(); Location glassBlockLocation = new Location( tpTargetLocation ); int newY = tpTargetLocation.getBlockY() - 1; glassBlockLocation.setY( newY ); - Block block = glassBlockLocation.getBlockAt(); - if ( block != null ) { - PrisonBlock prisonBlock = block.getPrisonBlock(); - - if ( prisonBlock != null && prisonBlock.equals( PrisonBlock.GLASS ) ) { - // The glass block is under the player's feet so submit to remove it: - - MineChangeBlockTask changeBlockTask = - new MineChangeBlockTask( glassBlockLocation, PrisonBlock.AIR ); - - int delayInTicks = 10; - PrisonTaskSubmitter.runTaskLater( changeBlockTask, delayInTicks ); - } - } + + MineChangeBlockTask changeBlockTask = + new MineChangeBlockTask( glassBlockLocation, + PrisonBlock.AIR, PrisonBlock.GLASS ); + + int delayInTicks = 10; + PrisonTaskSubmitter.runTaskLater( changeBlockTask, delayInTicks ); + + +// Block block = glassBlockLocation.getBlockAt(); +// if ( block != null ) { +// PrisonBlock prisonBlock = block.getPrisonBlock(); +// +// if ( prisonBlock != null && prisonBlock.equals( PrisonBlock.GLASS ) ) { +// // The glass block is under the player's feet so submit to remove it: +// +// MineChangeBlockTask changeBlockTask = +// new MineChangeBlockTask( glassBlockLocation, PrisonBlock.AIR ); +// +// int delayInTicks = 10; +// PrisonTaskSubmitter.runTaskLater( changeBlockTask, delayInTicks ); +// } +// } } @@ -231,7 +246,7 @@ public Location alternativeTpLocation() protected void broadcastResetMessageToAllPlayersWithRadius() { // long start = System.currentTimeMillis(); - if ( isVirtual() ) { + if ( isVirtual() || getResetTime() <= 0 ) { // ignore: } else @@ -275,7 +290,7 @@ protected void broadcastResetMessageToAllPlayersWithRadius() { @Override protected void broadcastPendingResetMessageToAllPlayersWithRadius(MineJob mineJob) { - if ( isVirtual() ) { + if ( isVirtual() || getResetTime() <= 0) { // ignore: } else diff --git a/prison-mines/src/main/java/tech/mcprison/prison/mines/data/MinesConfig.java b/prison-mines/src/main/java/tech/mcprison/prison/mines/data/MinesConfig.java index 1f10b04a5..008da7dda 100644 --- a/prison-mines/src/main/java/tech/mcprison/prison/mines/data/MinesConfig.java +++ b/prison-mines/src/main/java/tech/mcprison/prison/mines/data/MinesConfig.java @@ -47,10 +47,10 @@ public class MinesConfig implements FileIOData { // */ // public boolean multiworld = false; - /** - * True if only blocks that are air should be replaced. False otherwise - */ - public boolean fillMode = false; +// /** +// * True if only blocks that are air should be replaced. False otherwise +// */ +// public boolean fillMode = false; /** * The duration between mine resets in seconds. diff --git a/prison-mines/src/main/java/tech/mcprison/prison/mines/features/MineBlockEvent.java b/prison-mines/src/main/java/tech/mcprison/prison/mines/features/MineBlockEvent.java index ea8cc5778..b2664751b 100644 --- a/prison-mines/src/main/java/tech/mcprison/prison/mines/features/MineBlockEvent.java +++ b/prison-mines/src/main/java/tech/mcprison/prison/mines/features/MineBlockEvent.java @@ -1,12 +1,17 @@ package tech.mcprison.prison.mines.features; import java.text.DecimalFormat; +import java.text.NumberFormat; +import java.text.ParseException; +import java.util.Locale; import java.util.Set; import java.util.TreeSet; import tech.mcprison.prison.Prison; +import tech.mcprison.prison.internal.block.MineTargetPrisonBlock; import tech.mcprison.prison.internal.block.PrisonBlock; import tech.mcprison.prison.internal.block.PrisonBlockTypes; +import tech.mcprison.prison.output.Output; import tech.mcprison.prison.tasks.PrisonCommandTask.TaskMode; public class MineBlockEvent { @@ -29,6 +34,7 @@ public enum BlockEventType { TEXplosion, CEXplosion, PEExplosive, // PrisonEnchant: Pulsi_'s plugin + PrisonExplosion, eventTypeAll( all ), eventBlockBreak( blockBreak ), @@ -137,8 +143,17 @@ public MineBlockEvent( double chance, String permission, public String toSaveString() { - DecimalFormat dFmt = new DecimalFormat("0.00000"); - return dFmt.format( getChance() ) + "|" + + + NumberFormat nFmt = DecimalFormat.getInstance( Locale.US ); + if ( nFmt instanceof DecimalFormat ) { + DecimalFormat df = (DecimalFormat) nFmt; + df.applyLocalizedPattern( "0.00000" ); + } + nFmt.format( getChance() ); + +// DecimalFormat dFmt = new DecimalFormat("0.00000"); + + return nFmt.format( getChance() ) + "|" + (getPermission() == null || getPermission().trim().length() == 0 ? "none" : getPermission()) + "|" + getCommand() + "|" + getTaskMode().name() + "|" + getEventType().name() + "|" + @@ -147,12 +162,12 @@ public String toSaveString() { } - public static MineBlockEvent fromSaveString( String blockEventString ) { + public static MineBlockEvent fromSaveString( String blockEventString, String mineName ) { MineBlockEvent results = null; if ( blockEventString != null && !blockEventString.startsWith( "ver" ) ) { - results = fromStringV1( blockEventString ); + results = fromStringV1( blockEventString, mineName ); } // if ( chancePermCommand != null && chancePermCommand.trim().length() > 0 ) { @@ -191,13 +206,37 @@ public static MineBlockEvent fromSaveString( String blockEventString ) { } - private static MineBlockEvent fromStringV1( String chancePermCommand ) { + private static MineBlockEvent fromStringV1( String chancePermCommand, String mineName ) { MineBlockEvent results = null; if ( chancePermCommand != null && chancePermCommand.trim().length() > 0 ) { String[] cpc = chancePermCommand.split( "\\|" ); - double chance = cpc.length >= 1 ? Double.parseDouble( cpc[0] ) : 0d; + + double chance = 0.00001; + try { + String dbl = cpc.length >= 1 ? cpc[0] : "0"; + + NumberFormat nFmt = DecimalFormat.getInstance( Locale.US ); + if ( nFmt instanceof DecimalFormat ) { + DecimalFormat df = (DecimalFormat) nFmt; + df.applyLocalizedPattern( "0.00000" ); + } + Number nDbl = nFmt.parse( dbl ); + if ( nDbl != null ) { + chance = nDbl.doubleValue(); + } + +// chance = cpc.length >= 1 ? Double.parseDouble( cpc[0] ) : 0d; + } + catch ( ParseException | NumberFormatException e ) { + Output.get().logError( "Failure parsing a mine " + mineName + + "'s blockEven percent chance. " + + "It is not a double number. Please use the command " + + "'/mines blockEvent add help' when creating blockEvents instead of " + + "manually editing the files. The incorrect value was [" + cpc[0] + + "]. Using a value of [0.00001] instead."); + } String permission = cpc.length >= 2 ? cpc[1] : ""; if ( permission == null || "none".equalsIgnoreCase( permission) ) { @@ -298,28 +337,63 @@ public boolean removePrisonBlock( Integer rowBlockName ) { * @return */ public boolean isFireEvent( double chance, BlockEventType eventType, - MineTargetPrisonBlock targetBlock, String triggered ) { + MineTargetPrisonBlock targetBlock, String triggered ) { boolean results = false; - // First check chance, since that's perhaps the quickest check: + + // First check the chance and ensure the block is valid: if ( chance <= getChance() && + isValidBlock( targetBlock ) ) { + + // If the eventType is valid: + if ( getEventType() == BlockEventType.all || + getEventType() == eventType ) { - isValidBlock( targetBlock ) && - - // Make sure we have the correct eventTypes: - (eventType == BlockEventType.TEXplosion && - eventType == getEventType() && - ( getTriggered() == null || - getTriggered().equalsIgnoreCase( triggered )) || + // check if triggered and if valid eventTypes to support it: + if ( getTriggered() == null ) { + results = true; + } + else if ( getTriggered() != null && + (eventType == BlockEventType.PrisonExplosion || + eventType == BlockEventType.TEXplosion || + eventType == BlockEventType.PEExplosive) + ) { - getEventType() == BlockEventType.all || - getEventType() == eventType) ) { - - // The check for the player's perms will have to be done outside of this - // function. - - results = true; + // triggered can be negated to be used to exclude a triggered event + boolean notTriggered = getTriggered().startsWith( "!" ); + String trig = getTriggered().replace( "!", "" ); + + if ( !notTriggered && trig.equalsIgnoreCase( triggered ) || + notTriggered && !trig.equalsIgnoreCase( triggered ) ) { + + results = true; + } + + } + + } } + + +// // First check chance, since that's perhaps the quickest check: +// if ( chance <= getChance() && +// +// isValidBlock( targetBlock ) && +// +// // Make sure we have the correct eventTypes: +// (eventType == BlockEventType.TEXplosion && +// eventType == getEventType() && +// ( getTriggered() == null || +// getTriggered().equalsIgnoreCase( triggered )) || +// +// getEventType() == BlockEventType.all || +// getEventType() == eventType) ) { +// +// // The check for the player's perms will have to be done outside of this +// // function. +// +// results = true; +// } return results; diff --git a/prison-mines/src/main/java/tech/mcprison/prison/mines/features/MineTargetPrisonBlock.java b/prison-mines/src/main/java/tech/mcprison/prison/mines/features/MineTargetPrisonBlock.java deleted file mode 100644 index 190ca4ee6..000000000 --- a/prison-mines/src/main/java/tech/mcprison/prison/mines/features/MineTargetPrisonBlock.java +++ /dev/null @@ -1,72 +0,0 @@ -package tech.mcprison.prison.mines.features; - -import tech.mcprison.prison.internal.World; -import tech.mcprison.prison.internal.block.PrisonBlockStatusData; - -public class MineTargetPrisonBlock - implements Comparable -{ - private MineTargetBlockKey blockKey; - - private PrisonBlockStatusData prisonBlock; - - private boolean airBroke; - - - protected MineTargetPrisonBlock( World world, int x, int y, int z ) { - - this.blockKey = new MineTargetBlockKey( world, x, y, z ); - } - - public MineTargetPrisonBlock( PrisonBlockStatusData prisonBlock, World world, int x, int y, int z ) { - this( world, x, y, z ); - - this.prisonBlock = prisonBlock; - - if ( prisonBlock == null || prisonBlock.isAir() ) { - this.airBroke = true; - } - } - - @Override - public String toString() { - return "MineTargetPrisonBlock: key= " + getBlockKey().toString() + - " block= " + getPrisonBlock().toString(); - } - - public PrisonBlockStatusData getPrisonBlock() { - return prisonBlock; - } - public void setPrisonBlock( PrisonBlockStatusData prisonBlock ) { - this.prisonBlock = prisonBlock; - } - - - public MineTargetBlockKey getBlockKey() { - return blockKey; - } - - /** - *

This is a quick way to check to see if the block was originally set to air, or if - * the block was previously broke and "counted". This field, airBroke, needs to be - * set to 'true' when the block is counted as broken the first time so it won't be - * double counted in the future. Explosion events tends to cause blocks to be - * counted multiple times since it does not check to see if they are air prior to - * selecting them. - *

- * - * @return - */ - public boolean isAirBroke() { - return airBroke; - } - public void setAirBroke( boolean airBroke ) { - this.airBroke = airBroke; - } - - - @Override - public int compareTo( MineTargetPrisonBlock block ) { - return block.getBlockKey().compareTo( block.getBlockKey() ); - } -} diff --git a/prison-mines/src/main/java/tech/mcprison/prison/mines/features/MineTracerBuilder.java b/prison-mines/src/main/java/tech/mcprison/prison/mines/features/MineTracerBuilder.java index 2a8b766b4..d8814b9f8 100644 --- a/prison-mines/src/main/java/tech/mcprison/prison/mines/features/MineTracerBuilder.java +++ b/prison-mines/src/main/java/tech/mcprison/prison/mines/features/MineTracerBuilder.java @@ -1,13 +1,9 @@ package tech.mcprison.prison.mines.features; -import java.util.Optional; - -import tech.mcprison.prison.internal.World; -import tech.mcprison.prison.internal.block.PrisonBlock; +import tech.mcprison.prison.internal.block.MineResetType; import tech.mcprison.prison.mines.data.Mine; +import tech.mcprison.prison.mines.tasks.MinePagedResetAsyncTask; import tech.mcprison.prison.output.Output; -import tech.mcprison.prison.util.BlockType; -import tech.mcprison.prison.util.Location; public class MineTracerBuilder { @@ -48,84 +44,103 @@ public static TracerType fromString( String type ) { return results; } } - + public void clearMine( Mine mine, boolean tracer ) { if ( mine == null ) { - Output.get().logError(" #### NPE ###"); + Output.get().logError(" #### Null MINE? ###"); } - try { - - if ( mine.isVirtual() ) { - // Mine is virtual and cannot be reset. Just skip this with no error messages. - return; - } - - - // Output.get().logInfo( "MineRest.resetSynchonouslyInternal() " + getName() ); - Optional worldOptional = mine.getWorld(); - World world = worldOptional.get(); - - - PrisonBlock blockAirPB = new PrisonBlock( "AIR" ); - BlockType blockAirBT = BlockType.AIR; - - PrisonBlock blockRedPB = new PrisonBlock( "PINK_STAINED_GLASS" ); - BlockType blockRedBT = BlockType.PINK_STAINED_GLASS; - -// PrisonBlock blockRedstonePB = new PrisonBlock( "REDSTONE_BLOCK" ); -// BlockType blockRedstoneBT = BlockType.REDSTONE_BLOCK; - - - - // Reset the block break count before resetting the blocks: -// setBlockBreakCount( 0 ); -// Random random = new Random(); - - int yMin = mine.getBounds().getyBlockMin(); - int yMax = mine.getBounds().getyBlockMax(); - - int xMin = mine.getBounds().getxBlockMin(); - int xMax = mine.getBounds().getxBlockMax(); - - int zMin = mine.getBounds().getzBlockMin(); - int zMax = mine.getBounds().getzBlockMax(); - - for (int y = yMax; y >= yMin; y--) { -// for (int y = getBounds().getyBlockMin(); y <= getBounds().getyBlockMax(); y++) { - for (int x = xMin; x <= xMax; x++) { - for (int z = zMin; z <= zMax; z++) { - Location targetBlock = new Location(world, x, y, z); - - boolean xEdge = x == xMin || x == xMax; - boolean yEdge = y == yMin || y == yMax; - boolean zEdge = z == zMin || z == zMax; - - boolean isEdge = xEdge && yEdge || xEdge && zEdge || - yEdge && zEdge; - - if ( mine.isUseNewBlockModel() ) { - - targetBlock.getBlockAt().setPrisonBlock( - tracer && isEdge ? blockRedPB : blockAirPB ); - } - else { - - targetBlock.getBlockAt().setType( - tracer && isEdge ? blockRedBT : blockAirBT ); - } - } - } - } - - - } - catch (Exception e) { - Output.get().logError("&cFailed to clear mine " + mine.getName() + - " Error: [" + e.getMessage() + "]", e); - } + if ( mine.isVirtual() ) { + // Mine is virtual and cannot be reset. Just skip this with no error messages. + return; + } + + MineResetType resetType = tracer ? MineResetType.tracer : MineResetType.clear; + + MinePagedResetAsyncTask resetTask = new MinePagedResetAsyncTask( mine, resetType ); + resetTask.submitTaskAsync(); } +// public void clearMine( Mine mine, boolean tracer ) { +// +// if ( mine == null ) { +// Output.get().logError(" #### Null MINE? ###"); +// } +// try { +// +// if ( mine.isVirtual() ) { +// // Mine is virtual and cannot be reset. Just skip this with no error messages. +// return; +// } +// +// +// // Output.get().logInfo( "MineRest.resetSynchonouslyInternal() " + getName() ); +// +// Optional worldOptional = mine.getWorld(); +// World world = worldOptional.get(); +// +// +// PrisonBlock blockAirPB = new PrisonBlock( "AIR" ); +//// BlockType blockAirBT = BlockType.AIR; +// +// PrisonBlock blockRedPB = new PrisonBlock( "PINK_STAINED_GLASS" ); +//// BlockType blockRedBT = BlockType.PINK_STAINED_GLASS; +// +//// PrisonBlock blockRedstonePB = new PrisonBlock( "REDSTONE_BLOCK" ); +//// BlockType blockRedstoneBT = BlockType.REDSTONE_BLOCK; +// +// +// +// +// +// // Reset the block break count before resetting the blocks: +//// setBlockBreakCount( 0 ); +//// Random random = new Random(); +// +// int yMin = mine.getBounds().getyBlockMin(); +// int yMax = mine.getBounds().getyBlockMax(); +// +// int xMin = mine.getBounds().getxBlockMin(); +// int xMax = mine.getBounds().getxBlockMax(); +// +// int zMin = mine.getBounds().getzBlockMin(); +// int zMax = mine.getBounds().getzBlockMax(); +// +// for (int y = yMax; y >= yMin; y--) { +//// for (int y = getBounds().getyBlockMin(); y <= getBounds().getyBlockMax(); y++) { +// for (int x = xMin; x <= xMax; x++) { +// for (int z = zMin; z <= zMax; z++) { +// Location targetBlock = new Location(world, x, y, z); +// +// boolean xEdge = x == xMin || x == xMax; +// boolean yEdge = y == yMin || y == yMax; +// boolean zEdge = z == zMin || z == zMax; +// +// boolean isEdge = xEdge && yEdge || xEdge && zEdge || +// yEdge && zEdge; +// +// if ( mine.isUseNewBlockModel() ) { +// +// targetBlock.getBlockAt().setPrisonBlock( +// tracer && isEdge ? blockRedPB : blockAirPB ); +// } +//// else { +//// +//// targetBlock.getBlockAt().setType( +//// tracer && isEdge ? blockRedBT : blockAirBT ); +//// } +// } +// } +// } +// +// +// } +// catch (Exception e) { +// Output.get().logError("&cFailed to clear mine " + mine.getName() + +// " Error: [" + e.getMessage() + "]", e); +// } +// } + } 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 2db6049c3..b7234790f 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 @@ -17,6 +17,7 @@ package tech.mcprison.prison.mines.managers; +import java.io.File; import java.text.DecimalFormat; import java.util.ArrayList; import java.util.List; @@ -33,7 +34,7 @@ import tech.mcprison.prison.mines.PrisonMines; import tech.mcprison.prison.mines.data.Mine; import tech.mcprison.prison.mines.data.MineScheduler.MineResetActions; -import tech.mcprison.prison.mines.data.MineScheduler.MineResetType; +import tech.mcprison.prison.mines.data.MineScheduler.MineResetScheduleType; import tech.mcprison.prison.mines.data.PrisonSortableResults; import tech.mcprison.prison.output.Output; import tech.mcprison.prison.placeholders.ManagerPlaceholders; @@ -378,6 +379,22 @@ public void saveMinesIfUnsavedBlockCounts() { } + /** + *

Creates a backup of a mine's save file. Similar to a virtual delete + * but is a copy. If used, has to be manually renamed. + *

+ * + * @param mine + */ + public File backupMine( Mine mine ) + { + File backupFile = coll.backup( mine.getName() ); + + return backupFile; + } + + + public void rename( Mine mine, String newName ) { @@ -482,7 +499,7 @@ public void setMineStats( boolean mineStats ) * @param resetType * @param resetActions */ - public void resetAllMines( MineResetType resetType, List resetActions ) { + public void resetAllMines( MineResetScheduleType resetType, List resetActions ) { cancelResetAllMines(); @@ -626,6 +643,7 @@ public void assignAvailableWorld( String worldName ) { Optional worldOptional = Prison.get().getPlatform().getWorld(worldName); if ( worldOptional.isPresent() && getUnavailableWorlds().containsKey( worldName )) { + World world = worldOptional.get(); // Store this mine and the world in MineManager's unavailableWorld for later @@ -637,6 +655,20 @@ public void assignAvailableWorld( String worldName ) { for ( Mine mine : unenabledMines ) { if ( !mine.isEnabled() ) { mine.setWorld( world ); + + // Make sure world is hooked up properly to all locations. + // Since world is an object, it may already be auto hooked: + + + if ( mine.getBounds() != null ) { + mine.getBounds().setWorld( world ); + } + + + if ( mine.getSpawn() != null ) { + mine.getSpawn().setWorld( world ); + } + } // remove.add( mine ); } @@ -1203,28 +1235,28 @@ private String getTranslateMinesPlaceHolder( Player player, PlaceHolderKey place break; - case prison_pbt: - case prison_player_blocks_total: - if ( !mine.isVirtual() ) - { - long blocksTotal = PlayerCache.getInstance().getPlayerBlocksTotal( player ); - - if ( attribute != null && attribute instanceof PlaceholderAttributeNumberFormat ) { - PlaceholderAttributeNumberFormat attributeNF = - (PlaceholderAttributeNumberFormat) attribute; - results = attributeNF.format( blocksTotal ); - } - else { - - results = iFmt.format( blocksTotal ); - } - } - break; - +// case prison_pbt: +// case prison_player_blocks_total: +// if ( !mine.isVirtual() && player != null ) +// { +// long blocksTotal = PlayerCache.getInstance().getPlayerBlocksTotal( player ); +// +// if ( attribute != null && attribute instanceof PlaceholderAttributeNumberFormat ) { +// PlaceholderAttributeNumberFormat attributeNF = +// (PlaceholderAttributeNumberFormat) attribute; +// results = attributeNF.format( blocksTotal ); +// } +// else { +// +// results = iFmt.format( blocksTotal ); +// } +// } +// break; +// case prison_pbtm: case prison_player_blocks_total_minename: - if ( !mine.isVirtual() ) + if ( !mine.isVirtual() && player != null ) { long blocksTotalByMine = PlayerCache.getInstance() .getPlayerBlocksTotalByMine( player, mine.getName() ); @@ -1463,7 +1495,8 @@ else if ( p.getName().equalsIgnoreCase( playerName ) ) { if ( player == null ) { for ( Player p : Prison.get().getPlatform().getOfflinePlayers() ) { - if ( p.getUUID().compareTo( playerUuid ) == 0 ) { + if ( playerUuid != null && p.getUUID() != null && + p.getUUID().compareTo( playerUuid ) == 0 ) { player = p; break; } @@ -1612,5 +1645,4 @@ public void reloadPlaceholders() { } - } diff --git a/prison-mines/src/main/java/tech/mcprison/prison/mines/tasks/MineChangeBlockTask.java b/prison-mines/src/main/java/tech/mcprison/prison/mines/tasks/MineChangeBlockTask.java index c3899fcad..8d4067692 100644 --- a/prison-mines/src/main/java/tech/mcprison/prison/mines/tasks/MineChangeBlockTask.java +++ b/prison-mines/src/main/java/tech/mcprison/prison/mines/tasks/MineChangeBlockTask.java @@ -9,44 +9,49 @@ public class MineChangeBlockTask { private Location location; private PrisonBlock targetBlock; + private PrisonBlock checkBlock; - public MineChangeBlockTask( Location location, PrisonBlock targetBlock ) { + private Location topOfMineLocation; + + public MineChangeBlockTask( Location location, + PrisonBlock targetBlock, PrisonBlock checkBlock ) { super(); this.location = location; this.targetBlock = targetBlock; + + this.checkBlock = checkBlock; + + this.topOfMineLocation = new Location( getLocation() ); + this.topOfMineLocation.setY( topOfMineLocation.getBlockY() - 1 ); + } @Override public void run() { - Location topOfMineLocation = new Location( getLocation() ); - topOfMineLocation.setY( topOfMineLocation.getBlockY() - 1 ); - - if ( topOfMineLocation.getBlockAt().isEmpty() ) { - // When there is no block under the glass block, spawn in a - // glass block so the player won't fall to their death. - // This block will be within the mine, so it will be replaced - // when the mine resets, or the players can break it too. - - topOfMineLocation.getBlockAt().setPrisonBlock( PrisonBlock.GLASS ); - } - - getLocation().getBlockAt().setPrisonBlock( getTargetBlock() ); + // Replace the targetBlock if there is no checkBlock. If there is a checkBlock, + // then make sure the block that will be replaced is that type of a block. + if ( checkBlock == null || + !topOfMineLocation.getBlockAt().isEmpty() && + getLocation().getBlockAt().getPrisonBlock().equals( getCheckBlock() ) ) { + + getLocation().getBlockAt().setPrisonBlock( getTargetBlock() ); + } } public Location getLocation() { return location; } - public void setLocation( Location location ) { - this.location = location; - } public PrisonBlock getTargetBlock() { return targetBlock; } - public void setTargetBlock( PrisonBlock targetBlock ) { - this.targetBlock = targetBlock; + + public PrisonBlock getCheckBlock() + { + return checkBlock; } + } 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 new file mode 100644 index 000000000..466935390 --- /dev/null +++ b/prison-mines/src/main/java/tech/mcprison/prison/mines/tasks/MinePagedResetAsyncTask.java @@ -0,0 +1,260 @@ +package tech.mcprison.prison.mines.tasks; + +import java.util.List; + +import tech.mcprison.prison.Prison; +import tech.mcprison.prison.internal.PrisonStatsElapsedTimeNanos; +import tech.mcprison.prison.internal.block.MineResetType; +import tech.mcprison.prison.internal.block.MineTargetPrisonBlock; +import tech.mcprison.prison.mines.PrisonMines; +import tech.mcprison.prison.mines.data.Mine; +import tech.mcprison.prison.mines.data.MineScheduler.MineResetActions; +import tech.mcprison.prison.output.Output; +import tech.mcprison.prison.tasks.PrisonRunnable; +import tech.mcprison.prison.tasks.PrisonTaskSubmitter; + +public class MinePagedResetAsyncTask + implements PrisonRunnable +{ + private Mine mine; + private final MineResetType resetType; + + private int position = 0; + + private int page = 0; + + private int totalPages = 0; + private int pagesPerReport = 20; + private int pagePosition = 0; + + + private long timeStart = 0; + private long timePage = 0; + + private PrisonStatsElapsedTimeNanos nanos; + + + // Config Settings: + private int configAsyncResetPageSize = -1; + private int configSyncSubPageSlice = -1; + + + private List resetActions; + + + + public MinePagedResetAsyncTask( Mine mine, MineResetType resetType, List resetActions ) { + super(); + + this.mine = mine; + this.resetType = resetType; + + + this.timeStart = System.currentTimeMillis(); + this.timePage = timeStart; + + this.nanos = new PrisonStatsElapsedTimeNanos(); + + this.totalPages = (mine.getMineTargetPrisonBlocks().size() / + getConfigAsyncResetPageSize()) + 1; + + this.resetActions = resetActions; + } + + + public MinePagedResetAsyncTask( Mine mine, MineResetType resetType ) { + this( mine, resetType, null ); + } + + + public void submitTaskSync() { + submitTaskAsync(); + } + public void submitTaskAsync() { + + // Prevent the task from being submitted if it is a virtual mine: + if ( mine.isVirtual() ) { + return; + } + + + if ( position > 0 && page++ % pagesPerReport == 0 ) { + + if ( PrisonMines.getInstance().getMineManager().isMineStats() ) { + + logStats(); + } + } + + long delay = 0; + PrisonTaskSubmitter.runTaskLaterAsync( this, delay ); + } + + + private void logStats() + { + long timeCurrent = System.currentTimeMillis(); + long timeElapsedTotal = timeCurrent - timeStart; + long timeElapsedPage = timeCurrent - timePage; + timePage = timeCurrent; + + + int blocksPlaced = position - pagePosition; + pagePosition = position; + + + mine.setResetPosition( position ); + + mine.setResetPage( page ); + + mine.setStatsBlockUpdateTimeNanos( nanos.getElapsedTimeNanos() ); + + // long time = System.currentTimeMillis() - start; + mine.setStatsBlockUpdateTimeMS( timeElapsedPage + mine.getStatsBlockUpdateTimeMS() ); + mine.setStatsResetTimeMS( timeElapsedPage + mine.getStatsResetTimeMS() ); + + + mine.setStatsResetPages( page ); + mine.setStatsResetPageBlocks( mine.getStatsResetPageBlocks() + blocksPlaced ); + mine.setStatsResetPageMs( mine.getStatsResetPageMs() + timeElapsedPage ); + + + // Only print these details if stats are enabled: + if ( PrisonMines.getInstance().getMineManager().isMineStats() ) { + + Output.get().logInfo( "MinePagedResetAsyncTask : " + + mine.getName() + " " + + resetType.name() + + " : page " + page + " of " + totalPages + " : " + + " blocks = " + blocksPlaced + " elapsed = " + timeElapsedPage + + " ms TotalElapsed = " + timeElapsedTotal + " ms " + + "block update elapsed = " + + ( getNanos().getElapsedTimeNanos() / 1000000d ) + " ms(nanos)" +// " TPS " + +// Prison.get().getPrisonTPS().getAverageTPSFormatted() + ); + } + } + + @Override + public void run() { + + // The first time running this, need to setup the block list if a reset: + if ( position == 0 ) { + if ( runSetupCancelReset() ) { + // If the reset should be canceled then just return, and that will + // terminate the reset. There is nothing else that needs to be done. + return; + } + } + + List targetBlocks = mine.getMineTargetPrisonBlocks(); + + int pageEndPosition = position + getConfigAsyncResetPageSize(); + + + while ( position < pageEndPosition ) { + + int endIndex = position + getConfigSyncSubPageSlice(); + if ( endIndex > targetBlocks.size() ) { + endIndex = targetBlocks.size(); + pageEndPosition = endIndex; + } + + List tBlocks = targetBlocks.subList( position, endIndex ); + + mine.getWorld().get().setBlocksSynchronously( tBlocks, resetType, getNanos() ); + + position += tBlocks.size(); + } + + + // Keep resubmitting this task until it is completed: + if ( position < targetBlocks.size() ) { + submitTaskSync(); + } + else { + + // Finished running the task and let it end: + runShutdown(); + } + + } + + + /** + *

This is ran before the initial actual processing is performed. + * This calls the functions to + */ + private boolean runSetupCancelReset() { + + // Set the MineStateMutex to a state of starting a mine reset: + mine.getMineStateMutex().setMineStateResetStart(); + + + if ( resetType == MineResetType.normal || resetType == MineResetType.paged ) { + mine.generateBlockListAsync(); + + // resetAsynchonouslyInitiate() will confirm if the reset should happened + // and will raise Prison's mine reset event. + // A return value of true means cancel the reset: + return mine.resetAsynchonouslyInitiate(); + + } + + mine.asynchronouslyResetSetup(); + return false; + } + + private void runShutdown() { + + logStats(); + + + // Set the MineStateMutex to a state of Finishing a mine reset: + // It is now safe to allow mining in the mine. + mine.getMineStateMutex().setMineStateResetFinished(); + + + // Run items such as post-mine-reset commands: + mine.asynchronouslyResetFinalize( getResetActions() ); + + + } + + + public PrisonStatsElapsedTimeNanos getNanos() { + return nanos; + } + public void setNanos( PrisonStatsElapsedTimeNanos nanos ) { + this.nanos = nanos; + } + + public List getResetActions() { + return resetActions; + } + public void setResetActions( List resetActions ) { + this.resetActions = resetActions; + } + + + public int getConfigAsyncResetPageSize() { + if ( configAsyncResetPageSize == -1 ) { + this.configAsyncResetPageSize = + Long.valueOf( Prison.get().getPlatform() + .getConfigLong( "prison-mines.reset-async-paging.async-page-size", + 4000 )).intValue(); + } + return configAsyncResetPageSize; + } + + public int getConfigSyncSubPageSlice() { + if ( configSyncSubPageSlice == -1 ) { + this.configSyncSubPageSlice = + Long.valueOf( Prison.get().getPlatform() + .getConfigLong( "prison-mines.reset-async-paging.sync-sub-page-slice", + 200 )).intValue(); + } + return configSyncSubPageSlice; + } +} diff --git a/prison-mines/src/main/java/tech/mcprison/prison/mines/tasks/MineTeleportTask.java b/prison-mines/src/main/java/tech/mcprison/prison/mines/tasks/MineTeleportTask.java new file mode 100644 index 000000000..01cbeefc1 --- /dev/null +++ b/prison-mines/src/main/java/tech/mcprison/prison/mines/tasks/MineTeleportTask.java @@ -0,0 +1,35 @@ +package tech.mcprison.prison.mines.tasks; + +import tech.mcprison.prison.mines.data.Mine; +import tech.mcprison.prison.tasks.PrisonRunnable; +import tech.mcprison.prison.tasks.PrisonTaskSubmitter; + +public class MineTeleportTask + implements PrisonRunnable +{ + private Mine mine; + + public MineTeleportTask( Mine mine ) { + super(); + + this.mine = mine; + } + + public void submitTaskSync() { + + + // Prevent the task from being submitted if it is a virtual mine: + if ( mine.isVirtual() ) { + return; + } + + PrisonTaskSubmitter.runTaskLater( this, 0 ); + } + + @Override + public void run() { + + mine.teleportAllPlayersOut(); + + } +} diff --git a/prison-ranks/src/main/java/tech/mcprison/prison/ranks/FirstJoinHandler.java b/prison-ranks/src/main/java/tech/mcprison/prison/ranks/FirstJoinHandler.java index ca57dd184..7d546d044 100644 --- a/prison-ranks/src/main/java/tech/mcprison/prison/ranks/FirstJoinHandler.java +++ b/prison-ranks/src/main/java/tech/mcprison/prison/ranks/FirstJoinHandler.java @@ -21,6 +21,7 @@ import tech.mcprison.prison.Prison; import tech.mcprison.prison.ranks.data.RankPlayer; +import tech.mcprison.prison.ranks.data.RankPlayerFactory; import tech.mcprison.prison.ranks.events.FirstJoinEvent; /** @@ -47,7 +48,8 @@ public FirstJoinHandler() { RankPlayer player = event.getPlayer(); // Try to perform the first join processing to give them the default rank: - player.firstJoin(); + RankPlayerFactory rankPlayerFactory = new RankPlayerFactory(); + rankPlayerFactory.firstJoin( player ); PrisonRanks.getInstance().getPlayerManager().savePlayer(player); // try { diff --git a/prison-ranks/src/main/java/tech/mcprison/prison/ranks/PrisonRanks.java b/prison-ranks/src/main/java/tech/mcprison/prison/ranks/PrisonRanks.java index a1ee9fb89..ece133112 100644 --- a/prison-ranks/src/main/java/tech/mcprison/prison/ranks/PrisonRanks.java +++ b/prison-ranks/src/main/java/tech/mcprison/prison/ranks/PrisonRanks.java @@ -32,12 +32,14 @@ import tech.mcprison.prison.output.LogLevel; import tech.mcprison.prison.output.Output; import tech.mcprison.prison.ranks.commands.CommandCommands; +import tech.mcprison.prison.ranks.commands.FailedRankCommands; import tech.mcprison.prison.ranks.commands.LadderCommands; import tech.mcprison.prison.ranks.commands.RankUpCommand; import tech.mcprison.prison.ranks.commands.RanksCommands; 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.ranks.data.RankPlayerFactory; import tech.mcprison.prison.ranks.managers.LadderManager; import tech.mcprison.prison.ranks.managers.PlayerManager; import tech.mcprison.prison.ranks.managers.RankManager; @@ -107,6 +109,13 @@ public void enable() { .getIntegrationDetails(IntegrationType.ECONOMY); logStartupMessageError( prisonRanksFailureNoEconomyMsg( integrationDebug ) ); + + + // Register the failure /ranks command handler: + + FailedRankCommands failedRanksCommands = new FailedRankCommands(); + Prison.get().getCommandHandler().registerCommands( failedRanksCommands ); + return; } @@ -152,6 +161,19 @@ public void enable() { // rankManager.connectRanks(); + + // NOTE: The following is not needed since the ladders are already hooked up to the ranks. +// for ( Rank rank : rankManager.getRanks() ) { +// +// if ( rank.getLadder() == null ) { +// // Hook up the ladder if it has not been setup yet: +// RankLadder ladder = PrisonRanks.getInstance().getLadderManager().getLadder( rank ); +// +// rank.setLadder( ladder ); +// } +// } + + // Verify that all ranks that use currencies have valid currencies: rankManager.identifyAllRankCurrencies( getPrisonStartupDetails() ); @@ -178,8 +200,9 @@ public void enable() { // Hook up all players to the ranks: - playerManager.connectPlayersToRanks(); + playerManager.connectPlayersToRanks( false ); + Output.get().logInfo( "Ranks: Finished Connecting Players to Ranks." ); // Load up the commands @@ -199,11 +222,13 @@ public void enable() { Prison.get().getCommandHandler().registerCommands( rankupCommands ); Prison.get().getCommandHandler().registerCommands( ladderCommands ); + Output.get().logInfo( "Ranks: Finished registering Rank Commands." ); // Check all players to see if any need to join: checkAllPlayersForJoin(); + Output.get().logInfo( "Ranks: Finished First Join Checks." ); // Load up all else @@ -253,6 +278,8 @@ public void checkAllPlayersForJoin() } + RankPlayerFactory rankPlayerFactory = new RankPlayerFactory(); + // If any player does not have a rank on the default ladder, then add the default // ladder and rank: Rank defaultRank = defaultLadder.getLowestRank().get(); @@ -263,9 +290,9 @@ public void checkAllPlayersForJoin() Rank rankOnDefault = null; - if ( rPlayer.getRank( defaultLadder ) != null ) { + if ( rankPlayerFactory.getRank( rPlayer, defaultLadder ) != null ) { - rankOnDefault = rPlayer.getRank( defaultLadder ).getRank(); + rankOnDefault = rankPlayerFactory.getRank( rPlayer, defaultLadder ).getRank(); // Output.get().logInfo( "#### %s ladder = %s isRankNull= %s rank= %s %s [%s]" , // rPlayer.getName(), @@ -279,7 +306,7 @@ public void checkAllPlayersForJoin() rankupCommands.setPlayerRank( rPlayer, defaultRank ); - if ( rPlayer.getRank( defaultLadder ) != null ) { + if ( rankPlayerFactory.getRank( rPlayer, defaultLadder ) != null ) { String message = prisonRankAddedNewPlayer( rPlayer.getName() ); diff --git a/prison-ranks/src/main/java/tech/mcprison/prison/ranks/RankUtil.java b/prison-ranks/src/main/java/tech/mcprison/prison/ranks/RankUtil.java index c857d320b..e2bdaf188 100644 --- a/prison-ranks/src/main/java/tech/mcprison/prison/ranks/RankUtil.java +++ b/prison-ranks/src/main/java/tech/mcprison/prison/ranks/RankUtil.java @@ -32,6 +32,7 @@ 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.ranks.data.RankPlayerFactory; import tech.mcprison.prison.ranks.events.RankUpEvent; import tech.mcprison.prison.tasks.PrisonCommandTask; import tech.mcprison.prison.tasks.PrisonCommandTask.CustomPlaceholders; @@ -105,6 +106,7 @@ public enum RankupTransactions { failed_player, failed_ladder, + player_has_no_rank_on_ladder, orginal_rank, failed_rank_not_found, @@ -337,8 +339,19 @@ private void rankupPlayerInternal(RankupResults results, // This should never be null, since if a player is not on this ladder, then they // should never make it this far in to this code: // Um... not true when performing a prestige for the first time.... lol + // Also not true when being added to a ladder, since they will not have an existing rank. - PlayerRank originalRank = rankPlayer.getRank(ladder); + RankPlayerFactory rankPlayerFactory = new RankPlayerFactory(); + + + + // originalRank can be null... + PlayerRank originalRank = rankPlayerFactory.getRank( rankPlayer, ladder ); + + if ( originalRank == null ) { + + results.addTransaction( RankupTransactions.player_has_no_rank_on_ladder ); + } // if ( originalRank == null && ladder.getName().equals( "default" ) ) { // @@ -355,6 +368,8 @@ private void rankupPlayerInternal(RankupResults results, results.setPlayerRankOriginal( originalRank ); results.setOriginalRank( originalRank == null ? null : originalRank.getRank() ); + + /** * calculate the target rank. In this function the original rank is updated within the * results object, so from here on out, use the results object for original rank. @@ -376,7 +391,7 @@ private void rankupPlayerInternal(RankupResults results, results.addTransaction(RankupTransactions.cannot_delete_default_ladder); } else { - boolean success = rankPlayer.removeLadder( ladder.getName() ); + boolean success = rankPlayerFactory.removeLadder( rankPlayer, ladder.getName() ); if ( success ) { if ( savePlayerRank( results, rankPlayer ) ) { @@ -406,13 +421,18 @@ private void rankupPlayerInternal(RankupResults results, // This calculates the target rank, and takes in to consideration the player's existing rank: - PlayerRank pRankNext = PlayerRank.getTargetPlayerRankForPlayer( rankPlayer, targetRank ); + PlayerRank pRankNext = + originalRank == null ? null : + originalRank.getTargetPlayerRankForPlayer( rankPlayer, targetRank ); // new PlayerRank( targetRank, originalRank.getRankMultiplier() ); // If player does not have a rank on this ladder, then grab the first rank on the ladder since they need // to be added to the ladder. if ( pRankNext == null ) { - pRankNext = PlayerRank.getTargetPlayerRankForPlayer( rankPlayer, ladder.getLowestRank().get() ); + + pRankNext = rankPlayerFactory.createPlayerRank( targetRank ); + +// pRankNext = originalRank.getTargetPlayerRankForPlayer( rankPlayer, ladder.getLowestRank().get() ); } @@ -738,13 +758,13 @@ else if ("default".equalsIgnoreCase( results.getLadder().getName() ) && rankName } - public static int doubleToInt(Object d) { - return Math.toIntExact(Math.round((double) d)); - } - - public static long doubleToLong(Object d) { - return Math.round((double) d); - } +// public static int doubleToInt(Object d) { +// return Math.toIntExact(Math.round((double) d)); +// } +// +// public static long doubleToLong(Object d) { +// return Math.round((double) d); +// } diff --git a/prison-ranks/src/main/java/tech/mcprison/prison/ranks/RankupResults.java b/prison-ranks/src/main/java/tech/mcprison/prison/ranks/RankupResults.java index d703c213b..92cc3a811 100644 --- a/prison-ranks/src/main/java/tech/mcprison/prison/ranks/RankupResults.java +++ b/prison-ranks/src/main/java/tech/mcprison/prison/ranks/RankupResults.java @@ -10,6 +10,7 @@ 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.ranks.data.RankPlayerFactory; public class RankupResults { @@ -144,7 +145,10 @@ public void setStatus( RankupStatus status ) { public PlayerRank getPlayerRankOriginal() { if ( playerRankOriginal == null && originalRank != null && rankPlayer != null ) { - PlayerRank pRank = rankPlayer.getRank( originalRank.getLadder() ); + + RankPlayerFactory rankPlayerFactory = new RankPlayerFactory(); + + PlayerRank pRank = rankPlayerFactory.getRank( rankPlayer, originalRank.getLadder() ); playerRankOriginal = pRank; } return playerRankOriginal; @@ -158,8 +162,13 @@ public PlayerRank getPlayerRankTarget() { getOriginalRank() != null && getOriginalRank().getRankNext() != null && targetRank != null ) { + RankPlayerFactory rankPlayerFactory = new RankPlayerFactory(); + + PlayerRank pRank = rankPlayerFactory.createPlayerRank( getOriginalRank() ); + // This calculates the target rank, and takes in to consideration the player's existing rank: - playerRankTarget = PlayerRank.getTargetPlayerRankForPlayer( rankPlayer, targetRank ); + playerRankTarget = pRank.getTargetPlayerRankForPlayer( rankPlayer, targetRank ); +// playerRankTarget = PlayerRank.getTargetPlayerRankForPlayer( rankPlayer, targetRank ); // PlayerRank pRank = rankPlayer.getRank( originalRank.getLadder() ); // PlayerRank pRankNext = new PlayerRank( targetRank, pRank.getRankMultiplier() ); diff --git a/prison-ranks/src/main/java/tech/mcprison/prison/ranks/commands/CommandCommands.java b/prison-ranks/src/main/java/tech/mcprison/prison/ranks/commands/CommandCommands.java index cf26dcd73..5b3be3dc7 100644 --- a/prison-ranks/src/main/java/tech/mcprison/prison/ranks/commands/CommandCommands.java +++ b/prison-ranks/src/main/java/tech/mcprison/prison/ranks/commands/CommandCommands.java @@ -171,7 +171,9 @@ public void commandList(CommandSender sender, protected ChatDisplay commandListDetails( Rank rank, boolean noRemoves ) { - ChatDisplay display = new ChatDisplay( ranksCommandListCmdHeaderMsg( rank.getTag() )); + String title = rank.getTag() == null ? rank.getName() : rank.getTag(); + + ChatDisplay display = new ChatDisplay( ranksCommandListCmdHeaderMsg( title )); if ( !noRemoves ) { display.addText( ranksCommandListClickCmdToRemoveMsg() ); @@ -191,7 +193,7 @@ protected ChatDisplay commandListDetails( Rank rank, boolean noRemoves ) if ( !noRemoves ) { FancyMessage msgRemove = new FancyMessage( " &4Remove&3" ) - .suggest("/ranks command remove " + rank.getName() + " " + rowNumber ) + .suggest("/ranks command remove " + rank.getName() + " " + (rowNumber - 1) ) .tooltip( ranksCommandListClickToRemoveMsg() ); row.addFancy( msgRemove ); } diff --git a/prison-ranks/src/main/java/tech/mcprison/prison/ranks/commands/FailedRankCommands.java b/prison-ranks/src/main/java/tech/mcprison/prison/ranks/commands/FailedRankCommands.java new file mode 100644 index 000000000..d03775907 --- /dev/null +++ b/prison-ranks/src/main/java/tech/mcprison/prison/ranks/commands/FailedRankCommands.java @@ -0,0 +1,58 @@ +package tech.mcprison.prison.ranks.commands; + +import tech.mcprison.prison.commands.BaseCommands; +import tech.mcprison.prison.commands.Command; +import tech.mcprison.prison.internal.CommandSender; +import tech.mcprison.prison.output.ChatDisplay; + +public class FailedRankCommands + extends BaseCommands +{ + + + public FailedRankCommands() + { + super( "FailedRanksNoEconomy" ); + } + + @Command(identifier = "ranks", description = "Ranks are Disabled - No Economy plugin detected", + onlyPlayers = false ) + public void failedRanks( CommandSender sender ) { + + + ChatDisplay display = new ChatDisplay("Prison Ranks are Disbled"); + + display.addText("&aPrison Requires an Economy Plugin."); + + display.addText(""); + display.addText("Prison Ranks are disabled - No Economy plugin detected"); + display.addText(""); + display.addText("Add an Economy Plugin, such as EssentialsX, and then restart the server."); + display.addText(""); + display.addText("For more information on how to setup Prison, see our extensive " + + "documentation that is online:"); + display.addText(". &7 https://prisonteam.github.io/Prison/prison_docs_000_toc.html"); + display.addText(""); + display.addText("Information on suggested plugins can be found here:"); + display.addText(". &7 https://prisonteam.github.io/Prison/prison_docs_012_setting_up_prison_basics.html"); + display.addText(""); + display.addText("If you need help with setting up prison, please see our documentation."); + display.addText("If you find an issue with Prison, or need help for things not in the documenation, " + + "then please visit our discord server:"); + display.addText(""); + display.addText(""); + + + display.sendtoOutputLogInfo(); + + + if ( sender.isPlayer() ) { + display.send( sender ); + } + + + + } + + +} 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 eb9babf7c..4161dff44 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 @@ -37,6 +37,7 @@ 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.ranks.data.RankPlayerFactory; import tech.mcprison.prison.ranks.managers.LadderManager; import tech.mcprison.prison.ranks.managers.PlayerManager; @@ -158,13 +159,25 @@ private void rankUpPrivate(CommandSender sender, String ladder, RankupModes mode } + RankPlayerFactory rankPlayerFactory = new RankPlayerFactory(); + RankPlayer rankPlayer = getRankPlayer( sender, player.getUUID(), player.getName() ); - PlayerRank playerRankCurrent = rankPlayer.getRank( ladder ); - PlayerRank playerRankTarget = - PlayerRank.getTargetPlayerRankForPlayer( rankPlayer, - playerRankCurrent == null ? targetLadder.getLowestRank().get() : - playerRankCurrent.getRank() - ); + PlayerRank playerRankCurrent = rankPlayerFactory.getRank( rankPlayer, ladder ); + + PlayerRank playerRankTarget = null; + + // If the player does not have a rank on the current ladder, then assign the + // default rank for the ladder to be their next rank. + if ( playerRankCurrent == null ) { + + playerRankTarget = rankPlayerFactory.createPlayerRank( + targetLadder.getLowestRank().get() ); + } + else { + playerRankTarget = playerRankCurrent.getTargetPlayerRankForPlayer( rankPlayer, + playerRankCurrent.getRank() ); + } + Output.get().logDebug( DebugTarget.rankup, @@ -194,7 +207,7 @@ private void rankUpPrivate(CommandSender sender, String ladder, RankupModes mode } // gets the rank on the default ladder. Used if ladder is not default. - PlayerRank pRankDefaultLadder = rankPlayer.getRank("default"); + PlayerRank pRankDefaultLadder = rankPlayerFactory.getRank( rankPlayer, "default"); if ( pRankDefaultLadder == null ) { rankupErrorPlayerNotOnDefaultLadder( sender, rankPlayer ); } @@ -236,7 +249,7 @@ private void rankUpPrivate(CommandSender sender, String ladder, RankupModes mode // Get the player rank after - PlayerRank playerRankAfter = rankPlayer.getRank( ladder ); + PlayerRank playerRankAfter = rankPlayerFactory.getRank( rankPlayer, ladder ); if ( playerRankAfter != null ) { @@ -302,7 +315,9 @@ private void prestigePlayer(CommandSender sender, Player player, RankPlayer rank // lm.getLadder("default").getLowestRank().get().getName() + " default"); // Get that rank - PlayerRank playerRankSecond = rankPlayer.getRank("default"); + RankPlayerFactory rankPlayerFactory = new RankPlayerFactory(); + + PlayerRank playerRankSecond = rankPlayerFactory.getRank( rankPlayer, "default"); if ( playerRankSecond != null ) { Rank pRankSecond = playerRankSecond.getRank(); @@ -329,13 +344,15 @@ private void prestigePlayer(CommandSender sender, Player player, RankPlayer rank prestigePlayerBalanceSetToZeroMsg( sender ); } + String title = pRankAfter.getTag() == null ? pRankAfter.getName() : pRankAfter.getTag(); if ( success ) { // Send a message to the player because he did prestige! - prestigePlayerSucessfulMsg( sender, pRankAfter.getTag() ); + + prestigePlayerSucessfulMsg( sender, title ); } else { - prestigePlayerFailureMsg( sender, pRankAfter.getTag() ); + prestigePlayerFailureMsg( sender, title ); } } @@ -368,8 +385,10 @@ public void promotePlayer(CommandSender sender, ladder = confirmLadder( sender, ladder ); + RankPlayerFactory rankPlayerFactory = new RankPlayerFactory(); + RankPlayer rankPlayer = getRankPlayer( sender, playerUuid, player.getName() ); - PlayerRank playerRank = rankPlayer.getRank( ladder ); + PlayerRank playerRank = rankPlayerFactory.getRank( rankPlayer, ladder ); if ( playerRank != null ) { @@ -423,8 +442,10 @@ public void demotePlayer(CommandSender sender, return; } + RankPlayerFactory rankPlayerFactory = new RankPlayerFactory(); + RankPlayer rankPlayer = getRankPlayer( sender, playerUuid, player.getName() ); - PlayerRank playerRank = rankPlayer.getRank( ladder ); + PlayerRank playerRank = rankPlayerFactory.getRank( rankPlayer, ladder ); if ( playerRank != null ) { @@ -470,7 +491,9 @@ public void setRank(CommandSender sender, boolean isSameRank = rank.equalsIgnoreCase("*same*"); - PlayerRank pRank = player.getRank( ladder ); + RankPlayerFactory rankPlayerFactory = new RankPlayerFactory(); + + PlayerRank pRank = rankPlayerFactory.getRank( player, ladder ); String rankNameCurrent = isSameRank && pRank != null && pRank.getRank() != null ? 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 b756c595c..895a1f578 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 @@ -180,7 +180,7 @@ protected void ranksRankupSuccessMsg( CommandSender sender, String playerName, .withReplacements( (playerName == null ? messagNoPlayerName : playerName), - (tRank == null ? "" : tRank.getName()), + (tRank == null ? "" : tRank.getTag() ), (results.getMessage() != null ? results.getMessage() : "") ); @@ -202,7 +202,7 @@ protected void ranksRankupSuccessMsg( CommandSender sender, String playerName, .withReplacements( (playerName == null ? messagNoPlayerNameBroadcast : playerName), - (tRank == null ? "" : tRank.getName()), + (tRank == null ? "" : tRank.getTag() ), (results.getMessage() != null ? results.getMessage() : "") ) .broadcast(); 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 05cf02d20..729f6969d 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 @@ -1,8 +1,10 @@ package tech.mcprison.prison.ranks.commands; import java.text.DecimalFormat; +import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collections; +import java.util.Date; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; @@ -12,7 +14,10 @@ import tech.mcprison.prison.Prison; import tech.mcprison.prison.PrisonAPI; import tech.mcprison.prison.PrisonCommand; +import tech.mcprison.prison.autofeatures.AutoFeaturesFileConfig.AutoFeatures; import tech.mcprison.prison.autofeatures.AutoFeaturesWrapper; +import tech.mcprison.prison.cache.PlayerCache; +import tech.mcprison.prison.cache.PlayerCachePlayerData; import tech.mcprison.prison.chat.FancyMessage; import tech.mcprison.prison.commands.Arg; import tech.mcprison.prison.commands.Command; @@ -29,14 +34,17 @@ import tech.mcprison.prison.output.BulletedListComponent; import tech.mcprison.prison.output.ChatDisplay; import tech.mcprison.prison.output.FancyMessageComponent; +import tech.mcprison.prison.output.LogLevel; import tech.mcprison.prison.output.Output; import tech.mcprison.prison.output.RowComponent; +import tech.mcprison.prison.placeholders.PlaceholdersUtil; import tech.mcprison.prison.ranks.PrisonRanks; import tech.mcprison.prison.ranks.data.PlayerRank; import tech.mcprison.prison.ranks.data.PlayerRankRefreshTask; 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.ranks.data.RankPlayerFactory; import tech.mcprison.prison.ranks.data.RankPlayerName; import tech.mcprison.prison.ranks.managers.LadderManager; import tech.mcprison.prison.ranks.managers.PlayerManager; @@ -859,6 +867,8 @@ private ChatDisplay listRanksOnLadder( RankLadder ladder, boolean hasPerm, RankP } } + + RankPlayerFactory rankPlayerFactory = new RankPlayerFactory(); boolean first = true; for (Rank rank : ladder.getRanks()) { @@ -883,6 +893,7 @@ private ChatDisplay listRanksOnLadder( RankLadder ladder, boolean hasPerm, RankP // String tagNoColor = Text.stripColor( tag ); + // If rank list is being generated for a console or op'd player, then show the ladder's rank multiplier, // but if generating for a player, then show total multiplier accross all ladders. PlayerRank pRank = null; @@ -891,12 +902,17 @@ private ChatDisplay listRanksOnLadder( RankLadder ladder, boolean hasPerm, RankP if ( hasPerm || rPlayer == null ) { - rankCost = PlayerRank.getRawRankCost( rank ); - rMulti = PlayerRank.getLadderBaseRankdMultiplier( rank ); + rankCost = rank.getRawRankCost(); + + pRank = rankPlayerFactory.createPlayerRank( rank ); + + rMulti = pRank.getLadderBasedRankMultiplier(); } else { - pRank = PlayerRank.getTargetPlayerRankForPlayer( rPlayer, rank ); + pRank = rankPlayerFactory.createPlayerRank( rank ); + + pRank = pRank.getTargetPlayerRankForPlayer( pRank, rPlayer, rank ); rankCost = pRank.getRankCost(); rMulti = pRank.getRankMultiplier(); @@ -997,8 +1013,14 @@ private ChatDisplay listRanksOnLadder( RankLadder ladder, boolean hasPerm, RankP } if ( rPlayer != null && !"No Ladder".equals( ladder.getName() ) ) { + +// RankPlayerFactory rankPlayerFactory = new RankPlayerFactory(); + double ladderMultiplier = ladder.getRankCostMultiplierPerRank(); - double playerMultiplier = rPlayer.getRank( ladder ) != null ? rPlayer.getRank( ladder ).getRankMultiplier() : 0; + + PlayerRank pRank = rankPlayerFactory.getRank( rPlayer, ladder ); + double playerMultiplier = pRank != null ? + pRank.getRankMultiplier() : 0; if ( playerMultiplier == 0 ) { display.addText( "&3You have no Ladder Rank Multipliers enabled. The rank costs are not adjusted." ); @@ -1021,11 +1043,14 @@ private ChatDisplay listRanksOnLadder( RankLadder ladder, boolean hasPerm, RankP if ( rLadder.getRankCostMultiplierPerRank() != 0d ) { Rank r = rPlayer.getLadderRanks().get( rLadder ).getRank(); + + PlayerRank rpRank = rankPlayerFactory.createPlayerRank( r ); + display.addText( "&3 BaseMult: &7%7s &3CurrMult: &7%7s &7%s &7%s ", fFmt.format( rLadder.getRankCostMultiplierPerRank() ), - fFmt.format( PlayerRank.getLadderBaseRankdMultiplier( r )), + fFmt.format( rpRank.getLadderBasedRankMultiplier() ), rLadder.getName(), - r.getTag() + (r.getTag() == null ? r.getName() : r.getTag()) ); // display.addText( "&3 Ladder: &7%-9s &3Rank: &7%-8s &3Base Mult: %7s", @@ -1117,13 +1142,15 @@ public void allRanksInfoDetails( StringBuilder sb ) { private ChatDisplay rankInfoDetails( CommandSender sender, Rank rank, String options ) { - ChatDisplay display = new ChatDisplay( ranksInfoHeaderMsg( rank.getTag() )); + String title = rank.getTag() == null ? rank.getName() : rank.getTag(); - boolean isOp = sender.isOp(); - boolean isConsole = !sender.isPlayer(); + ChatDisplay display = new ChatDisplay( ranksInfoHeaderMsg( title )); + + boolean isOp = sender != null && sender.isOp(); + boolean isConsole = sender == null || !sender.isPlayer(); display.addText( ranksInfoNameMsg( rank.getName() )); - display.addText( ranksInfoTagMsg( rank.getTag() )); + display.addText( ranksInfoTagMsg( rank.getTag() == null ? "none" : rank.getTag() )); RowComponent row = new RowComponent(); @@ -1161,10 +1188,11 @@ private ChatDisplay rankInfoDetails( CommandSender sender, Rank rank, String opt + // NOTE: Since rank info is NOT tied to a PlayerRank we cannot figure out the // the actual cost, but we can calculate the ladder's multiplier. This // will not be the player's total multiplier. - display.addText( ranksInfoCostMsg( PlayerRank.getRawRankCost( rank ) )); + display.addText( ranksInfoCostMsg( rank.getRawRankCost() )); @@ -1172,7 +1200,11 @@ private ChatDisplay rankInfoDetails( CommandSender sender, Rank rank, String opt DecimalFormat fFmt = new DecimalFormat("#,##0.0000"); // The following is the rank adjusted rank multiplier - double rankCostMultiplier = PlayerRank.getLadderBaseRankdMultiplier( rank ); + + RankPlayerFactory rankPlayerFactory = new RankPlayerFactory(); + PlayerRank pRank = rankPlayerFactory.createPlayerRank( rank ); + + double rankCostMultiplier = pRank.getLadderBasedRankMultiplier(); double ladderBaseMultiplier = rank.getLadder() == null ? 0 : rank.getLadder().getRankCostMultiplierPerRank(); String cmdLadderRankCostMult = "/ranks ladder rankMultiplier " + rank.getName() + " " + ladderBaseMultiplier; @@ -1191,7 +1223,7 @@ private ChatDisplay rankInfoDetails( CommandSender sender, Rank rank, String opt int numberOfPlayersOnRank = rank.getPlayers().size(); display.addText( ranksInfoPlayersWithRankMsg( numberOfPlayersOnRank )); - if ( isOp || isConsole || sender == null || sender.hasPermission("ranks.admin")) { + if ( isOp || isConsole || sender.hasPermission("ranks.admin")) { // This is admin-exclusive content // display.addText("&8[Admin Only]"); @@ -1203,7 +1235,7 @@ private ChatDisplay rankInfoDetails( CommandSender sender, Rank rank, String opt // display.addComponent(new FancyMessageComponent(del)); } - if ( isOp && options != null && "all".equalsIgnoreCase( options )) { + if ( (isOp || isConsole) && options != null && "all".equalsIgnoreCase( options )) { if ( rank.getLadder() != null ) { @@ -1236,7 +1268,8 @@ public void setCost(CommandSender sender, } - PlayerRank.setRawRankCost( rank, rawCost ); + rank.setRawRankCost( rawCost ); +// PlayerRank.setRawRankCost( rank, rawCost ); PrisonRanks.getInstance().getRankManager().saveRank(rank); @@ -1417,21 +1450,57 @@ public void rankPlayer(CommandSender sender, return; } + List msgs = new ArrayList<>(); + + DecimalFormat iFmt = new DecimalFormat("#,##0"); + DecimalFormat dFmt = new DecimalFormat("#,##0.00"); + DecimalFormat fFmt = new DecimalFormat("0.0000"); + DecimalFormat pFmt = new DecimalFormat("#,##0.0000"); + SimpleDateFormat sdFmt = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss" ); + + PlayerManager pm = PrisonRanks.getInstance().getPlayerManager(); RankPlayer rankPlayer = pm.getPlayer(player.getUUID(), player.getName()); + + // Get the cachedPlayer: + PlayerCachePlayerData cPlayer = PlayerCache.getInstance().getOnlinePlayer( rankPlayer ); + + + + String msg1 = String.format( "&7Player Stats for&8: &c%s", + rankPlayer.getName() ); + msgs.add( msg1 ); + + + + String lastSeen = cPlayer == null || cPlayer.getLastSeenDate() == 0 ? + "-- never -- " : + sdFmt.format( new Date( cPlayer.getLastSeenDate() ) ); + long lastSeenElapsedMs = cPlayer == null || cPlayer.getLastSeenDate() == 0 ? + 0 : System.currentTimeMillis() - cPlayer.getLastSeenDate(); + String lastSeenElapsed = lastSeenElapsedMs == 0 ? + "" : + // less than 5 mins just show recently since its not too accurate + lastSeenElapsedMs < (5 * 60 * 1000) ? "-- recently --" : + Text.formatTimeDaysHhMmSs( System.currentTimeMillis() - cPlayer.getLastSeenDate() ) + " ago"; + + String msgLs = String.format( " &7Last Seen: &3%s %s", + lastSeen, lastSeenElapsed ); + msgs.add( msgLs ); + + - String msg1 = String.format( "&c%s:", rankPlayer.getName() ); - sendToPlayerAndConsole( sender, msg1 ); - DecimalFormat fFmt = new DecimalFormat("0.0000"); String msg2 = String.format( " &7Rank Cost Multiplier: &f", fFmt.format( rankPlayer.getSellAllMultiplier() )); - sendToPlayerAndConsole( sender, msg2 ); + msgs.add( msg2 ); if ( rankPlayer != null ) { - DecimalFormat dFmt = new DecimalFormat("#,##0.00"); +// DecimalFormat iFmt = new DecimalFormat("#,##0"); +// +// SimpleDateFormat sdFmt = new SimpleDateFormat( "HH:mm:ss" ); // Collect all currencies in the default ladder: Set currencies = new LinkedHashSet<>(); @@ -1444,6 +1513,9 @@ public void rankPlayer(CommandSender sender, } + RankPlayerFactory rankPlayerFactory = new RankPlayerFactory(); + + Map rankLadders = rankPlayer.getLadderRanks(); for ( RankLadder rankLadder : rankLadders.keySet() ) @@ -1453,7 +1525,8 @@ public void rankPlayer(CommandSender sender, Rank nextRank = rank.getRankNext(); // This calculates the target rank, and takes in to consideration the player's existing rank: - PlayerRank nextPRank = PlayerRank.getTargetPlayerRankForPlayer( rankPlayer, nextRank ); + PlayerRank nextPRank = pRank.getTargetPlayerRankForPlayer( rankPlayer, nextRank ); +// PlayerRank nextPRank = PlayerRank.getTargetPlayerRankForPlayer( rankPlayer, nextRank ); // PlayerRank nextPRank = nextRank == null ? null : // new PlayerRank( nextRank, pRank.getRankMultiplier() ); @@ -1475,7 +1548,8 @@ public void rankPlayer(CommandSender sender, } } - sendToPlayerAndConsole( sender, messageRank ); + msgs.add( messageRank ); +// sendToPlayerAndConsole( sender, messageRank ); } // Print out the player's balances: @@ -1483,13 +1557,16 @@ public void rankPlayer(CommandSender sender, // The default currency first: double balance = rankPlayer.getBalance(); String message = ranksPlayerBalanceDefaultMsg( player.getName(), dFmt.format( balance ) ); - sendToPlayerAndConsole( sender, message ); + msgs.add( message ); +// sendToPlayerAndConsole( sender, message ); + for ( String currency : currencies ) { double balanceCurrency = rankPlayer.getBalance( currency ); String messageCurrency = ranksPlayerBalanceOthersMsg( player.getName(), dFmt.format( balanceCurrency ), currency ); - sendToPlayerAndConsole( sender, messageCurrency ); + msgs.add( messageCurrency ); +// sendToPlayerAndConsole( sender, messageCurrency ); } @@ -1502,19 +1579,126 @@ public void rankPlayer(CommandSender sender, if ( !isOnline ) { String msgOffline = ranksPlayerPermsOfflineMsg(); - sendToPlayerAndConsole( sender, msgOffline ); + msgs.add( msgOffline ); +// sendToPlayerAndConsole( sender, msgOffline ); } double sellallMultiplier = player.getSellAllMultiplier(); - DecimalFormat pFmt = new DecimalFormat("#,##0.0000"); String messageNotAccurrate = ranksPlayerNotAccurateMsg(); String messageSellallMultiplier = ranksPlayerSellallMultiplierMsg( pFmt.format( sellallMultiplier ), (!isOnline ? " " + messageNotAccurrate : "") ); - sendToPlayerAndConsole( sender, messageSellallMultiplier ); + msgs.add( messageSellallMultiplier ); +// sendToPlayerAndConsole( sender, messageSellallMultiplier ); + msgs.add( "" ); + + + if ( cPlayer != null ) { + + msgs.add( "PlayerCache Information:" ); + + // Print all earnings for all mines: + msgs.add( String.format( + " Earnings By Mine: &2Avg Earnings per min: &3%s", + dFmt.format( cPlayer.getAverageEarningsPerMinute() )) ); + + msgs.addAll( + Text.formatTreeMapStats(cPlayer.getEarningsByMine(), 5 ) ); + + + if ( cPlayer.getTokens() > 0 || cPlayer.getTokensTotal() > 0 || + cPlayer.getTokensByMine().size() > 0 ) { + + msgs.add( String.format( + " Tokens By Mine: &2Tokens: &3%s &2Avg/min: &3%s &2Blocks/Token: &3%d", + iFmt.format( cPlayer.getTokens() ), + dFmt.format( cPlayer.getAverageTokensPerMinute() ), + AutoFeaturesWrapper.getInstance().getInteger( AutoFeatures.tokensBlocksPerToken ) + )); + + msgs.add( String.format( + " &2TotalEarned: &3%s &2AdminAdded: &3%s &2AdminRemvd: &3%s", + iFmt.format( cPlayer.getTokensTotal() ), + iFmt.format( cPlayer.getTokensTotalAdminAdded() ), + iFmt.format( cPlayer.getTokensTotalAdminRemoved() ) + )); + + msgs.addAll( + Text.formatTreeMapStats(cPlayer.getTokensByMine(), 5 ) ); + } + + + msgs.add( String.format( + " &7Timings By Mine&8: &2Online&8: &3%s &2Mining&8: &3%s", + Text.formatTimeDaysHhMmSs( cPlayer.getOnlineTimeTotal() ), + Text.formatTimeDaysHhMmSs( cPlayer.getOnlineMiningTimeTotal()) ) + ); + + msgs.addAll( + Text.formatTreeMapStats(cPlayer.getTimeByMine(), 5, true ) ); + + + // Print all earnings for all mines: + String totalBlocks = PlaceholdersUtil.formattedKmbtSISize( + cPlayer.getBlocksTotal(), dFmt, " &9" ); + msgs.add( String.format( + " &7Blocks By Mine&8: &2Blocks Total&8: &3%s", + totalBlocks) ); + msgs.addAll( + Text.formatTreeMapStats(cPlayer.getBlocksByMine(), 5 ) ); + + + msgs.add( " &7Blocks By Type&8:" ); + msgs.addAll( + Text.formatTreeMapStats(cPlayer.getBlocksByType(), 3 ) ); + + +// Set keysEarnings = cPlayer.getEarningsByMine().keySet(); +// +// int count = 0; +// StringBuilder sbErn = new StringBuilder(); +// for ( String earningKey : keysEarnings ) +// { +// Double mineEarnings = cPlayer.getEarningsByMine().get( earningKey ); +// +// String earnings = PlaceholdersUtil.formattedKmbtSISize( mineEarnings, dFmt, " " ); +// +// sbErn.append( String.format( "%s %s ", earningKey, earnings ) ); +// +// if ( count++ % 5 == 0 ) { +// msgs.add( String.format( +// " " + sbErn.toString() ) ); +// sbErn.setLength( 0 ); +// +// } +// } +// +// if ( sbErn.length() > 0 ) { +// +// msgs.add( String.format( +// " " + sbErn.toString() ) ); +// } + + + +// msgs.add( String.format( +// " " ) ); +// +// cPlayer.getEarningsByMine() + + } + + + + + + sendToPlayerAndConsole( sender, msgs ); + + + if ( sender.hasPermission("ranks.admin") ) { // This is admin-exclusive content @@ -1595,7 +1779,135 @@ public void rankPlayer(CommandSender sender, // ranksPlayerNoRanksFoundMsg( sender, player.getDisplayName() ); // } } - + +// private String formatTimeMs( long timeMs ) { +// +// DecimalFormat iFmt = new DecimalFormat("#,##0"); +// DecimalFormat tFmt = new DecimalFormat("00"); +//// SimpleDateFormat sdFmt = new SimpleDateFormat( "HH:mm:ss" ); +// +// long _sec = 1000; +// long _min = _sec * 60; +// long _hour = _min * 60; +// long _day = _hour * 24; +// +// long ms = timeMs; +// long days = _day < ms ? ms / _day : 0; +// +// ms -= (days * _day); +// long hours = _hour < ms ? ms / _hour : 0; +// +// ms -= (hours * _hour); +// long mins = _min < ms ? ms / _min : 0; +// +// ms -= (mins * _min); +// long secs = _sec < ms ? ms / _sec : 0; +// +// +// String results = +// (days == 0 ? "" : iFmt.format( days ) + "d ") + +// tFmt.format( hours ) + ":" + +// tFmt.format( mins ) + ":" + +// tFmt.format( secs ) +// ; +// +// return results; +// } + +// private void formatTreeMapStats( TreeMap statMap, List msgs, +// DecimalFormat dFmt, DecimalFormat iFmt, +// int columns ) { +// +// Set keysEarnings = statMap.keySet(); +// +// +// List values = new ArrayList<>(); +// List valueMaxLen = new ArrayList<>(); +// +// +// int count = 0; +// StringBuilder sb = new StringBuilder(); +// for ( String earningKey : keysEarnings ) +// { +// String value = null; +// Object valueObj = statMap.get( earningKey ); +// +// if ( valueObj instanceof Double ) { +// +// value = PlaceholdersUtil.formattedKmbtSISize( (Double) valueObj, dFmt, " &9" ); +// } +// else if ( valueObj instanceof Integer ) { +// int intVal = (Integer) valueObj; +// value = PlaceholdersUtil.formattedKmbtSISize( intVal, +// ( intVal < 1000 ? iFmt : dFmt ), " &9" ); +// } +// else if ( valueObj instanceof Long ) { +// +// value = Text.formatTimeDaysHhMmSs( (Long) valueObj ); +// } +// +// String msg = String.format( "&3%s&8: &b%s", earningKey, value ).trim(); +// +// String msgNoColor = Text.stripColor( msg ); +// int lenMNC = msgNoColor.length(); +// +// +// int col = values.size() % columns; +// values.add( msg ); +// +// if ( col >= valueMaxLen.size() || lenMNC > valueMaxLen.get( col ) ) { +// +// if ( col > valueMaxLen.size() - 1 ) { +// valueMaxLen.add( lenMNC ); +// } +// else { +// +// valueMaxLen.set( col, lenMNC ); +// } +// } +// } +// +// +// for ( int j = 0; j < values.size(); j++ ) +// { +// String msg = values.get( j ); +// +// int col = j % columns; +// +// int maxColumnWidth = col > valueMaxLen.size() - 1 ? +// msg.length() : +// valueMaxLen.get( col ); +// +// sb.append( msg ); +// +// // Pad the right of all content with spaces to align columns, up to a +// // given maxLength: +// String msgNoColor = Text.stripColor( msg ); +// int lenMNC = msgNoColor.length(); +// for( int i = lenMNC; i < maxColumnWidth; i++ ) { +// sb.append( " " ); +// } +// +// // The spacer: +// sb.append( " " ); +// +// if ( ++count % columns == 0 ) { +// msgs.add( String.format( +// " " + sb.toString() ) ); +// sb.setLength( 0 ); +// +// } +// } +// +// if ( sb.length() > 0 ) { +// +// msgs.add( String.format( +// " " + sb.toString() ) ); +// } +// +// +// } + //// @Command(identifier = "ranks playerInventory", permissions = "mines.set", //// description = "For listing what's in a player's inventory by dumping it to console.", @@ -1646,6 +1958,23 @@ private void listPermissions( CommandSender sender, String prefix, List } } + private void sendToPlayerAndConsole( CommandSender sender, List messages ) + { + + // If not a console user then send the message to the sender, other wise if a console + // user then they will see duplicate messages: + if ( sender.getName() != null && !sender.getName().equalsIgnoreCase( "console" ) ) { + sender.sendMessage( messages.toArray( new String[0] ) ); + } + + for ( String message : messages ) + { + // log the rank. There was one issue with the ranks suddenly being changed so this + // will help document what ranks were. + Output.get().log( message, LogLevel.PLAIN ); + } + } + private void sendToPlayerAndConsole( CommandSender sender, String messageRank ) { // If not a console user then send the message to the sender, other wise if a console @@ -1656,7 +1985,7 @@ private void sendToPlayerAndConsole( CommandSender sender, String messageRank ) // log the rank. There was one issue with the ranks suddenly being changed so this // will help document what ranks were. - Output.get().logInfo( messageRank ); + Output.get().log( messageRank, LogLevel.PLAIN ); } diff --git a/prison-ranks/src/main/java/tech/mcprison/prison/ranks/data/PlayerRank.java b/prison-ranks/src/main/java/tech/mcprison/prison/ranks/data/PlayerRank.java deleted file mode 100644 index a095bc354..000000000 --- a/prison-ranks/src/main/java/tech/mcprison/prison/ranks/data/PlayerRank.java +++ /dev/null @@ -1,114 +0,0 @@ -package tech.mcprison.prison.ranks.data; - -public class PlayerRank -{ - - private final Rank rank; - - private Double rankMultiplier = null; - private Double rankCost = null; - - public PlayerRank( Rank rank ) { - super(); - - this.rank = rank; - - double rankMultiplier = getLadderBasedRankMultiplier(); - - setRankCost( rankMultiplier ); -// this.rankCost = rank.getCost() * (1.0 + rankMultiplier); - } - - private PlayerRank( Rank rank, double rankMultiplier ) { - this( rank ); - - this.rankMultiplier = rankMultiplier; - - setRankCost( rankMultiplier ); -// this.rankCost = rank.getCost() * (1.0 + rankMultiplier); - } - - public void applyMultiplier( double rankMultiplier ) { - - this.rankMultiplier = rankMultiplier; - - setRankCost( rankMultiplier ); -// this.rankCost = rank.getCost() * (1.0 + rankMultiplier); - } - - private void setRankCost( double rankMultiplier ) { - - this.rankCost = rank.getCost() * (1.0 + rankMultiplier); - } - - public double getLadderBasedRankMultiplier() { - - return getLadderBaseRankdMultiplier( getRank() ); - } - - public static double getLadderBaseRankdMultiplier( Rank rank ) { - double rankMultiplier = 0; - - if ( rank != null && rank.getLadder() != null ) { - double ladderMultiplier = rank.getLadder().getRankCostMultiplierPerRank(); - - // Because it's zero based... so add a 1 - rankMultiplier = ladderMultiplier * (1 + rank.getPosition()); - } - - return rankMultiplier; - } - public static double getRawRankCost( Rank rank ) { - return rank.getCost(); - } - public static void setRawRankCost( Rank rank, double rawCost ) { - rank.setCost( rawCost ); - } - - public static PlayerRank getTargetPlayerRankForPlayer( RankPlayer player, Rank targetRank ) { - PlayerRank targetPlayerRank = null; - - if ( targetRank != null ) { - - double targetRankMultiplier = getLadderBaseRankdMultiplier( targetRank ); - - PlayerRank pRankForPLayer = player.getRank( targetRank.getLadder() ); - double existingRankMultiplier = pRankForPLayer == null ? 0 : - getLadderBaseRankdMultiplier( pRankForPLayer.getRank() ); - - // Get the player's total rankMultiplier from the default ladder - // because they will always have a rank there: - PlayerRank pRank = player.getRank( "default" ); - double playerMultipler = pRank == null ? 0 : pRank.getRankMultiplier(); - - // So the actual rank multiplier that needs to be used, is based upon the - // Player's current multiplier PLUS the multiplier for the target rank - // AND MINUS the multiplier for the current rank the player has within the - // target rank's ladder. - double rankMultiplier = playerMultipler + targetRankMultiplier - existingRankMultiplier; - - targetPlayerRank = new PlayerRank( targetRank, rankMultiplier ); - } - - return targetPlayerRank; - } - - public Rank getRank() { - return rank; - } - - public Double getRankMultiplier() { - return rankMultiplier; - } -// public void setRankMultiplier( Double rankMultiplier ) { -// this.rankMultiplier = rankMultiplier; -// } - - public Double getRankCost() { - return rankCost; - } -// public void setRankCost( Double rankCost ) { -// this.rankCost = rankCost; -// } - -} diff --git a/prison-ranks/src/main/java/tech/mcprison/prison/ranks/data/RankFactory.java b/prison-ranks/src/main/java/tech/mcprison/prison/ranks/data/RankFactory.java new file mode 100644 index 000000000..127610aac --- /dev/null +++ b/prison-ranks/src/main/java/tech/mcprison/prison/ranks/data/RankFactory.java @@ -0,0 +1,139 @@ +package tech.mcprison.prison.ranks.data; + +import java.util.ArrayList; +import java.util.List; + +import tech.mcprison.prison.modules.ModuleElement; +import tech.mcprison.prison.output.Output; +import tech.mcprison.prison.store.Document; +import tech.mcprison.prison.util.ConversionUtil; + +public class RankFactory + extends RankMessages +{ + + @SuppressWarnings( "unchecked" ) + public Rank createRank( Document document ) + { + Rank rank = null; + + try + { + // Object pos = document.get("position"); + // this.position = RankUtil.doubleToInt( pos == null ? 0.0d : pos ); + + int id = ConversionUtil.doubleToInt( document.get( "id" ) ); + String name = (String) document.get( "name" ); + String tag = (String) document.get( "tag" ); + double cost = (double) document.get( "cost" ); + + rank = new Rank( id, name, tag, cost ); + + String currency = (String) document.get( "currency" ); + rank.setCurrency( (currency == null || "null".equalsIgnoreCase( currency ) ? null : currency) ); + + rank.getRankUpCommands().clear(); + Object cmds = document.get( "commands" ); + if ( cmds != null ) + { + + List commands = (List) cmds; + for ( String cmd : commands ) + { + if ( cmd != null ) + { + rank.getRankUpCommands().add( cmd ); + } + } + + // This was allowing nulls to be added to the live commands... + // this.rankUpCommands = (List) cmds; + } + + rank.getMines().clear(); + rank.getMineStrings().clear(); + Object minesObj = document.get( "mines" ); + if ( minesObj != null ) + { + List mineStrings = (List) minesObj; + rank.setMineStrings( mineStrings ); + } + + // getPermissions().clear(); + // Object perms = document.get( "permissions" ); + // if ( perms != null ) { + // List permissions = (List) perms; + // for ( String permission : permissions ) { + // getPermissions().add( permission ); + // } + // } + // + // + // getPermissionGroups().clear(); + // Object permsGroups = document.get( "permissionGroups" ); + // if ( perms != null ) { + // List permissionGroups = (List) permsGroups; + // for ( String permissionGroup : permissionGroups ) { + // getPermissionGroups().add( permissionGroup ); + // } + // } + + +// // Hook up the ladder if it has not been setup yet: +// if ( rank.getLadder() == null ) { +// +// RankLadder ladder = PrisonRanks.getInstance().getLadderManager().getLadder( rank ); +// +// rank.setLadder( ladder ); +// } + } + catch ( Exception e ) + { + String id = rank == null ? "(null rank)" : Integer.toString( rank.getId() ); + String rankName = rank.getName() == null ? "null" : rank.getName(); + String message = rankFailureLoadingRanksMsg( id, + rankName, e.getMessage() ); + + Output.get().logError( message ); + } + + return rank; + } + + public Document toDocument( Rank rank ) { + Document ret = new Document(); +// ret.put("position", this.position ); + ret.put("id", rank.getId()); + ret.put("name", rank.getName() ); + ret.put("tag", (rank.getTag() == null ? "none" : rank.getTag()) ); + ret.put("cost", rank.getCost() ); + ret.put("currency", rank.getCurrency() ); + + List cmds = new ArrayList<>(); + for ( String cmd : rank.getRankUpCommands() ) { + // Filters out possible nulls: + if ( cmd != null ) { + cmds.add( cmd ); + } + } + ret.put("commands", cmds); + + List mineStrings = new ArrayList<>(); + if ( rank.getMines() != null ) { + for ( ModuleElement mine : rank.getMines() ) { + String mineString = mine.getModuleElementType() + "," + mine.getName() + "," + + mine.getId() + "," + (mine.getTag() == null ? "none" : mine.getTag()); + mineStrings.add( mineString ); + } + } + ret.put("mines", mineStrings); + +// ret.put( "permissions", getPermissions() ); +// ret.put( "permissionGroups", getPermissionGroups() ); + + return ret; + } + + + +} diff --git a/prison-ranks/src/main/java/tech/mcprison/prison/ranks/data/RankLadderFactory.java b/prison-ranks/src/main/java/tech/mcprison/prison/ranks/data/RankLadderFactory.java new file mode 100644 index 000000000..370e82f2e --- /dev/null +++ b/prison-ranks/src/main/java/tech/mcprison/prison/ranks/data/RankLadderFactory.java @@ -0,0 +1,145 @@ +package tech.mcprison.prison.ranks.data; + +import java.util.List; + +import com.google.gson.internal.LinkedTreeMap; + +import tech.mcprison.prison.ranks.PrisonRanks; +import tech.mcprison.prison.ranks.managers.RankManager; +import tech.mcprison.prison.store.Document; +import tech.mcprison.prison.util.ConversionUtil; + +public class RankLadderFactory +{ + + @SuppressWarnings( "unchecked" ) + public RankLadder createRankLadder(Document document, PrisonRanks prisonRanks) { + RankLadder rankLadder = null; + + boolean isDirty = false; + + int id = ConversionUtil.doubleToInt(document.get("id")); + String name = (String) document.get("name"); + + rankLadder = new RankLadder( id, name ); + + RankManager rankManager = prisonRanks.getRankManager(); + + if ( rankManager == null ) { + + RankMessages rMessages = new RankMessages(); + rMessages.rankFailureLoadingRankManagerMsg( name, id ); + + return null; + } + + List> ranksLocal = + (List>) document.get("ranks"); + + rankLadder.getRankUpCommands().clear(); + Object cmds = document.get("commands"); + if ( cmds != null ) { + + List commands = (List) cmds; + for ( String cmd : commands ) { + if ( cmd != null ) { + rankLadder.getRankUpCommands().add( cmd ); + } + } + + // This was allowing nulls to be added to the live commands... +// this.rankUpCommands = (List) cmds; + } + + +// rankLadder.ranks = new ArrayList<>(); // already initialized + for (LinkedTreeMap rank : ranksLocal) { + + + // The only real field that is important here is rankId to tie the + // rank back to this ladder. Name helps clarify the contents of the + // Ladder file. + int rRankId = ConversionUtil.doubleToInt((rank.get("rankId"))); + String rRankName = (String) rank.get( "rankName" ); + + Rank rankPrison = rankManager.getRank( rRankId ); + + if ( rankPrison != null && rankPrison.getLadder() != null ) { + + RankMessages rMessages = new RankMessages(); + rMessages.rankFailureLoadingDuplicateRankMsg( + rankPrison.getName(), rankPrison.getLadder().getName(), + rankLadder.getName() ); + + isDirty = true; + } + else if ( rankPrison != null) { + + rankLadder.addRank( rankPrison ); + +// Output.get().logInfo( "RankLadder load : " + getName() + +// " rank= " + rankPrison.getName() + " " + rankPrison.getId() + +// ); + +// // if null look it up from loaded ranks: +// if ( rRankName == null ) { +// rRankName = rankPrison.getName(); +// dirty = true; +// } + } + else { + // Rank not found. Try to create it? The name maybe wrong. + String rankName = rRankName != null && !rRankName.trim().isEmpty() ? + rRankName : "Rank " + rRankId; + + // NOTE: The following is valid use of getCost(): + double cost = rankLadder.getRanks().size() == 0 ? 0 : + rankLadder.getRanks().get( rankLadder.getRanks().size() - 1 ).getCost() * 3; + Rank newRank = new Rank( rRankId, rankName, null, cost ); + + rankLadder.addRank( newRank ); + +// String message = String.format( +// "Loading RankLadder Error: A rank for %s was not found so it was " + +// "fabricated: %s id=%d tag=%s cost=%d", getName(), newRank.getName(), newRank.getId(), +// newRank.getTag(), newRank.getCost() ); +// Output.get().logError( message ); + } + + } + +// this.maxPrestige = RankUtil.doubleToInt(document.get("maxPrestige")); + + + Double rankCostMultiplier = (Double) document.get( "rankCostMultiplierPerRank" ); + rankLadder.setRankCostMultiplierPerRank( rankCostMultiplier == null ? 0 : rankCostMultiplier ); + + +// getPermissions().clear(); +// Object perms = document.get( "permissions" ); +// if ( perms != null ) { +// List permissions = (List) perms; +// for ( String permission : permissions ) { +// getPermissions().add( permission ); +// } +// } +// +// +// getPermissionGroups().clear(); +// Object permsGroups = document.get( "permissionGroups" ); +// if ( perms != null ) { +// List permissionGroups = (List) permsGroups; +// for ( String permissionGroup : permissionGroups ) { +// getPermissionGroups().add( permissionGroup ); +// } +// } + + if ( isDirty ) { + PrisonRanks.getInstance().getLadderManager().save( rankLadder ); + } + + return rankLadder; + } + + +} diff --git a/prison-ranks/src/main/java/tech/mcprison/prison/ranks/data/RankPlayerFactory.java b/prison-ranks/src/main/java/tech/mcprison/prison/ranks/data/RankPlayerFactory.java new file mode 100644 index 000000000..5e425c58f --- /dev/null +++ b/prison-ranks/src/main/java/tech/mcprison/prison/ranks/data/RankPlayerFactory.java @@ -0,0 +1,336 @@ +package tech.mcprison.prison.ranks.data; + +import java.util.ArrayList; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.UUID; + +import com.google.gson.internal.LinkedTreeMap; + +import tech.mcprison.prison.Prison; +import tech.mcprison.prison.output.Output; +import tech.mcprison.prison.ranks.FirstJoinHandlerMessages; +import tech.mcprison.prison.ranks.PrisonRanks; +import tech.mcprison.prison.ranks.events.FirstJoinEvent; +import tech.mcprison.prison.store.Document; +import tech.mcprison.prison.util.ConversionUtil; + +public class RankPlayerFactory +{ + + @SuppressWarnings( "unchecked" ) + public RankPlayer createRankPlayer(Document document) { + RankPlayer rankPlayer = null; + + + UUID uuid = UUID.fromString((String) document.get("uid")); + + rankPlayer = new RankPlayer( uuid ); + + LinkedTreeMap ranksLocal = + (LinkedTreeMap) document.get("ranks"); +// LinkedTreeMap prestigeLocal = +// (LinkedTreeMap) document.get("prestige"); + +// LinkedTreeMap blocksMinedLocal = +// (LinkedTreeMap) document.get("blocksMined"); + + Object namesListObject = document.get( "names" ); + + + for (String key : ranksLocal.keySet()) { + + int rankId = ConversionUtil.doubleToInt(ranksLocal.get(key)); + rankPlayer.getRanksRefs().put(key, rankId ); + + } + + + // Sets up the Ladder and Rank objects: + setupLadderRanks( rankPlayer ); + + + + +// for (String key : prestigeLocal.keySet()) { +// prestige.put(key, RankUtil.doubleToInt(prestigeLocal.get(key))); +// } + +//// rankPlayer.setBlocksMined( new HashMap<>() ); +// if ( blocksMinedLocal != null ) { +// for (String key : blocksMinedLocal.keySet()) { +// rankPlayer.getBlocksMined().put(key, ConversionUtil.doubleToInt(blocksMinedLocal.get(key))); +// } +// } + + if ( namesListObject != null ) { + + for ( Object rankPlayerNameMap : (ArrayList) namesListObject ) { + LinkedTreeMap rpnMap = (LinkedTreeMap) rankPlayerNameMap; + + if ( rpnMap.size() > 0 ) { + String name = (String) rpnMap.get( "name" ); + long date = ConversionUtil.doubleToLong( rpnMap.get( "date" ) ); + + RankPlayerName rankPlayerName = new RankPlayerName( name, date ); + rankPlayer.getNames().add( rankPlayerName ); +// Output.get().logInfo( "RankPlayer: uuid: " + uid + " RankPlayerName: " + rankPlayerName.toString() ); + } + + } + } + + return rankPlayer; + } + + public Document toDocument( RankPlayer rankPlayer ) { + Document ret = new Document(); + ret.put("uid", rankPlayer.getUUID()); + ret.put("ranks", rankPlayer.getRanksRefs() ); +// ret.put("prestige", this.prestige); + + ret.put("names", rankPlayer.getNames()); + +// ret.put("blocksMined", rankPlayer.getBlocksMined() ); + return ret; + } + + + + /** + *

This function will check to see if the player is on the default rank on + * the default ladder. If not, then it will add them. + *

+ * + *

This is safe to run on anyone, even if they already are on the default ladder. + *

+ * + *

Note, this will not save the player's new rank. The save function must be + * managed and called outside of this. + *

+ */ + public void firstJoin( RankPlayer rankPlayer) { + + RankLadder defaultLadder = PrisonRanks.getInstance().getDefaultLadder(); + + if ( !rankPlayer.getLadderRanks().containsKey( defaultLadder ) ) { + + Optional firstRank = defaultLadder.getLowestRank(); + + if ( firstRank.isPresent() ) { + Rank rank = firstRank.get(); + + rankPlayer.addRank( rank ); + + Prison.get().getEventBus().post(new FirstJoinEvent( rankPlayer )); + + FirstJoinHandlerMessages messages = new FirstJoinHandlerMessages(); + Output.get().logWarn( messages.firstJoinSuccess( rankPlayer.getName() ) ); + + } else { + + FirstJoinHandlerMessages messages = new FirstJoinHandlerMessages(); + Output.get().logWarn( messages.firstJoinWarningNoRanksOnServer() ); + } + } + + } + + + /** + * Removes a ladder from this player, including whichever rank this player had in it. + * Cannot remove the default ladder. + * + * @param ladderName The ladder's name. + */ + public boolean removeLadder( RankPlayer rankPlayer, String ladderName ) { + boolean results = false; + if ( !ladderName.equalsIgnoreCase("default") ) { + Integer id = rankPlayer.getRanksRefs().remove(ladderName); + results = (id != null); + + RankLadder ladder = PrisonRanks.getInstance().getLadderManager().getLadder( ladderName ); + if ( ladder != null && !ladder.getName().equalsIgnoreCase( "default" ) ) { + rankPlayer.getLadderRanks().remove( ladder ); + } + } + + return results; + } + + /** + * Retrieves the rank that this player has in a certain ladder, if any. + * + * @param ladder The ladder to check. + * @return An optional containing the {@link Rank} if found, or empty if there isn't a rank by that ladder for this player. + */ + public PlayerRank getRank( RankPlayer rankPlayer, RankLadder ladder ) { + PlayerRank results = null; + + if ( ladder != null ) { + + Set keys = rankPlayer.getLadderRanks().keySet(); + for ( RankLadder key : keys ) + { + if ( key != null && key.getName().equalsIgnoreCase( ladder.getName() ) ) { + results = rankPlayer.getLadderRanks().get( key ); + } + } + } + + return results; + +// if (!ranksRefs.containsKey(ladder.getName())) { +// return null; +// } +// int id = ranksRefs.get(ladder.getName()); +// return PrisonRanks.getInstance().getRankManager().getRank(id); + } + + +// /** +// * Returns all ladders this player is a part of, along with each rank the player has in that ladder. +// * +// * @return The map containing this data. +// */ +// public Map getLadderRanksx( RankPlayer rankPlayer ) { +// +// if ( rankPlayer.getLadderRanks().isEmpty() && !rankPlayer.getRanksRefs().isEmpty() ) { +// +// //Map ret = new HashMap<>(); +// +// for (Map.Entry entry : rankPlayer.getRanksRefs().entrySet()) { +// RankLadder ladder = PrisonRanks.getInstance().getLadderManager().getLadder(entry.getKey()); +// +// if ( ladder == null ) { +// continue; // Skip it +// } +// +// Rank rank = PrisonRanks.getInstance().getRankManager().getRank(entry.getValue()); +// if ( rank == null ) { +// continue; // Skip it +// } +// +// PlayerRank pRank = new PlayerRank( rank ); +// +// rankPlayer.getLadderRanks().put(ladder, pRank); +// } +// +// // Need to recalculate all rank multipliers: +// rankPlayer.recalculateRankMultipliers(); +// } +// +// return rankPlayer.getLadderRanks(); +// } + + + public void setupLadderRanks( RankPlayer rankPlayer ) { + + if ( rankPlayer.getLadderRanks().isEmpty() && !rankPlayer.getRanksRefs().isEmpty() ) { + + //Map ret = new HashMap<>(); + + for (Map.Entry entry : rankPlayer.getRanksRefs().entrySet()) { + String ladderName = entry.getKey(); + int rankId = entry.getValue(); + + RankLadder ladder = PrisonRanks.getInstance().getLadderManager().getLadder( ladderName ); + + if ( ladder != null ) { + + for ( Rank rank : ladder.getRanks() ) { + if ( rank.getId() == rankId ) { + + PlayerRank pRank = createPlayerRank( rank ); + rankPlayer.getLadderRanks().put( ladder, pRank ); + + break; + } + } + } + } + + // Need to recalculate all rank multipliers: + rankPlayer.recalculateRankMultipliers(); + } + + } + + + + /** + * Retrieves the rank that this player has the specified ladder. + * + * @param ladder The ladder name to check. + * @return The {@link Rank} if found, otherwise null; + */ + public PlayerRank getRank( RankPlayer rankPlayer, String ladderName ) { + + RankLadder ladder = PrisonRanks.getInstance().getLadderManager().getLadder( ladderName ); + return getRank( rankPlayer, ladder ); + +// Rank results = null; +// if (ladder != null && ranksRefs.containsKey(ladder)) { +// int id = ranksRefs.get(ladder); +// results = PrisonRanks.getInstance().getRankManager().getRank(id); +// } +// return results; + } + + + public PlayerRank createPlayerRank( Rank rank ) { + PlayerRank results = new PlayerRank( rank ); + + double rankMultiplier = results.getLadderBasedRankMultiplier( rank ); + + results.setRankCost( rankMultiplier ); + + return results; + } + + private PlayerRank createPlayerRank( Rank rank, double rankMultiplier ) { + PlayerRank results = new PlayerRank( rank, rankMultiplier ); + + return results; + } + + public PlayerRank getTargetPlayerRankForPlayer( PlayerRank playerRank, + RankPlayer player, Rank targetRank ) { + PlayerRank targetPlayerRank = null; + + if ( targetRank != null ) { + + double targetRankMultiplier = playerRank.getLadderBasedRankMultiplier( targetRank ); + + PlayerRank pRankForPLayer = getRank( player, targetRank.getLadder() ); + double existingRankMultiplier = pRankForPLayer == null ? 0 : + playerRank.getLadderBasedRankMultiplier( pRankForPLayer.getRank() ); + + // Get the player's total rankMultiplier from the default ladder + // because they will always have a rank there: + PlayerRank pRank = getRank( player, "default" ); + double playerMultipler = pRank == null ? 0 : pRank.getRankMultiplier(); + + // So the actual rank multiplier that needs to be used, is based upon the + // Player's current multiplier PLUS the multiplier for the target rank + // AND MINUS the multiplier for the current rank the player has within the + // target rank's ladder. + double rankMultiplier = playerMultipler + targetRankMultiplier - existingRankMultiplier; + + targetPlayerRank = createPlayerRank( targetRank, rankMultiplier ); + } + + return targetPlayerRank; + } + + + public double getRawRankCost( Rank rank ) { + return rank.getCost(); + } + public void setRawRankCost( Rank rank, double rawCost ) { + rank.setCost( rawCost ); + } + + +} diff --git a/prison-ranks/src/main/java/tech/mcprison/prison/ranks/top/RankPlayerSortableLadderRankBalance.java b/prison-ranks/src/main/java/tech/mcprison/prison/ranks/data/RankPlayerSortableLadderRankBalance.java similarity index 90% rename from prison-ranks/src/main/java/tech/mcprison/prison/ranks/top/RankPlayerSortableLadderRankBalance.java rename to prison-ranks/src/main/java/tech/mcprison/prison/ranks/data/RankPlayerSortableLadderRankBalance.java index 78e8858d1..a0505eb78 100644 --- a/prison-ranks/src/main/java/tech/mcprison/prison/ranks/top/RankPlayerSortableLadderRankBalance.java +++ b/prison-ranks/src/main/java/tech/mcprison/prison/ranks/data/RankPlayerSortableLadderRankBalance.java @@ -1,12 +1,8 @@ -package tech.mcprison.prison.ranks.top; +package tech.mcprison.prison.ranks.data; import java.util.Comparator; 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; public class RankPlayerSortableLadderRankBalance implements Comparator @@ -85,10 +81,16 @@ else if ( rp2 == null ) { results = 1; } else { - Rank r1 = rp1.getRank( getLadder() ) == null ? - null : rp1.getRank( getLadder() ).getRank(); - Rank r2 = rp2.getRank( getLadder() ) == null ? - null : rp2.getRank( getLadder() ).getRank(); + + RankLadder targetLadder = getLadder(); + + PlayerRank pr1 = rp1.getLadderRanks().get( targetLadder ); + PlayerRank pr2 = rp2.getLadderRanks().get( targetLadder ); + + Rank r1 = pr1 == null ? + null : pr1.getRank(); + Rank r2 = pr2 == null ? + null : pr2.getRank(); if ( r1 == null ) { results = -1; @@ -159,10 +161,11 @@ private double calculateTopScore( RankPlayer rp1, Rank rank, double balance ) { if ( balance != 0 ) { Rank nextRank = rank.getRankNext(); - PlayerRank pRank = rp1.getRank( rank.getLadder() ); + PlayerRank pRank = rp1.getLadderRanks().get( rank.getLadder() ); +// PlayerRank pRank = rp1.getRank( rank.getLadder() ); // This calculates the target rank, and takes in to consideration the player's existing rank: - PlayerRank pRankNext = PlayerRank.getTargetPlayerRankForPlayer( rp1, nextRank ); + PlayerRank pRankNext = pRank.getTargetPlayerRankForPlayer( rp1, nextRank ); // PlayerRank pRankNext = nextRank == null ? null : // new PlayerRank( nextRank, pRank.getRankMultiplier() ); diff --git a/prison-ranks/src/main/java/tech/mcprison/prison/ranks/managers/LadderManager.java b/prison-ranks/src/main/java/tech/mcprison/prison/ranks/managers/LadderManager.java index dced2b207..821d34951 100644 --- a/prison-ranks/src/main/java/tech/mcprison/prison/ranks/managers/LadderManager.java +++ b/prison-ranks/src/main/java/tech/mcprison/prison/ranks/managers/LadderManager.java @@ -26,7 +26,9 @@ import tech.mcprison.prison.ranks.PrisonRanks; import tech.mcprison.prison.ranks.data.Rank; import tech.mcprison.prison.ranks.data.RankLadder; +import tech.mcprison.prison.ranks.data.RankLadderFactory; import tech.mcprison.prison.ranks.data.RankPlayer; +import tech.mcprison.prison.ranks.data.RankPlayerFactory; import tech.mcprison.prison.store.Collection; import tech.mcprison.prison.store.Document; @@ -74,8 +76,12 @@ public LadderManager(Collection collection, PrisonRanks prisonRanks) { * @throws IOException If the file could not be read or does not exist. */ public void loadLadder(String fileKey) throws IOException { - Document doc = collection.get(fileKey).orElseThrow(IOException::new); - RankLadder ladder = new RankLadder(doc, prisonRanks); + + Document doc = collection.get(fileKey).orElseThrow(IOException::new); + + RankLadderFactory rlFactory = new RankLadderFactory(); + + RankLadder ladder = rlFactory.createRankLadder(doc, prisonRanks); loadedLadders.add(ladder); // Will be dirty if load a ladder and the rank name does not exist and it adds them: @@ -91,7 +97,11 @@ public void loadLadder(String fileKey) throws IOException { */ public void loadLadders() throws IOException { List documents = collection.getAll(); - documents.forEach(document -> loadedLadders.add(new RankLadder(document, prisonRanks))); + + final RankLadderFactory rlFactory = new RankLadderFactory(); + + documents.forEach(document -> loadedLadders.add( + rlFactory.createRankLadder(document, prisonRanks)) ); for ( RankLadder ladder : loadedLadders ) { // Will be dirty if load a ladder and the rank name does not exist and it adds them: @@ -220,8 +230,11 @@ public boolean removeLadder(RankLadder ladder) { .stream() .filter(rankPlayer -> rankPlayer.hasLadder(ladder.getName())) .collect(Collectors.toList()); + + RankPlayerFactory rankPlayerFactory = new RankPlayerFactory(); + for (RankPlayer player : playersWithLadder) { - player.removeLadder(ladder.getName()); + rankPlayerFactory.removeLadder( player, ladder.getName() ); } // Remove it from the list... 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 9412847e4..9b9ad9b11 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 @@ -50,6 +50,7 @@ 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.ranks.data.RankPlayerFactory; import tech.mcprison.prison.store.Collection; import tech.mcprison.prison.store.Document; import tech.mcprison.prison.tasks.PrisonTaskSubmitter; @@ -78,6 +79,7 @@ public PlayerManager(Collection collection) { super("PlayerMangager"); this.collection = collection; + this.players = new ArrayList<>(); this.playersByName = new TreeMap<>(); @@ -90,27 +92,30 @@ public PlayerManager(Collection collection) { * Methods */ - /** - * Loads a player from a file and stores it in the registry for use on the server. - * - * @param playerFile The key that the player data is stored as. Case-sensitive. - * @throws IOException If the file could not be read, or if the file does not exist. - */ - public void loadPlayer(String playerFile) throws IOException { - Document document = collection.get(playerFile).orElseThrow(IOException::new); - RankPlayer rankPlayer = new RankPlayer(document); - - players.add( rankPlayer ); - - // add by uuid: - playersByName.put( rankPlayer.getUUID().toString(), rankPlayer ); - - // add by name: - if ( rankPlayer.getNames().size() > 0 ) { - playersByName.put( rankPlayer.getDisplayName(), rankPlayer ); - - } - } +// /** +// * Loads a player from a file and stores it in the registry for use on the server. +// * +// * @param playerFile The key that the player data is stored as. Case-sensitive. +// * @throws IOException If the file could not be read, or if the file does not exist. +// */ +// public void loadPlayer(String playerFile) throws IOException { +// Document document = collection.get(playerFile).orElseThrow(IOException::new); +// +// RankPlayerFactory rankPlayerFactory = new RankPlayerFactory(); +// +// RankPlayer rankPlayer = rankPlayerFactory.createRankPlayer(document); +// +// players.add( rankPlayer ); +// +// // add by uuid: +// playersByName.put( rankPlayer.getUUID().toString(), rankPlayer ); +// +// // add by name: +// if ( rankPlayer.getNames().size() > 0 ) { +// playersByName.put( rankPlayer.getDisplayName(), rankPlayer ); +// +// } +// } /** * Loads every player in the specified playerFolder. @@ -118,11 +123,32 @@ public void loadPlayer(String playerFile) throws IOException { * @throws IOException If one of the files could not be read, or if the playerFolder does not exist. */ public void loadPlayers() throws IOException { - List players = collection.getAll(); - players.forEach( - document -> - this.players.add( - new RankPlayer(document))); + List playerDocss = collection.getAll(); + + final RankPlayerFactory rankPlayerFactory = new RankPlayerFactory(); + + for ( Document playerDocument : playerDocss ) + { + RankPlayer rankPlayer = rankPlayerFactory.createRankPlayer(playerDocument); + + players.add( rankPlayer ); + + // add by uuid: + playersByName.put( rankPlayer.getUUID().toString(), rankPlayer ); + + // add by name: + if ( rankPlayer.getNames().size() > 0 ) { + playersByName.put( rankPlayer.getDisplayName(), rankPlayer ); + + } + } + + + +// players.forEach( +// document -> +// this.players.add( +// rankPlayerFactory.createRankPlayer(document) )); } /** @@ -134,7 +160,10 @@ public void loadPlayers() throws IOException { * @see #savePlayer(RankPlayer) To save with the default conventional filename. */ public void savePlayer(RankPlayer player, String playerFile) throws IOException { - collection.save(playerFile, player.toDocument()); + + RankPlayerFactory rankPlayerFactory = new RankPlayerFactory(); + + collection.save(playerFile, rankPlayerFactory.toDocument( player ) ); // collection.insert(playerFile, player.toDocument()); } @@ -184,12 +213,12 @@ public void savePlayers() throws IOException { *

* */ - public void connectPlayersToRanks() { + public void connectPlayersToRanks( boolean checkPlayerBalances ) { for ( RankPlayer player : players ) { for ( PlayerRank pRank : player.getLadderRanks().values() ) { - pRank.getRank().addPlayer( player ); + pRank.getRank().addPlayer( player, checkPlayerBalances ); } } } @@ -327,11 +356,13 @@ protected RankPlayer addPlayerSyncTask( UUID uid, String playerName ) { if ( !getPlayersByName().containsKey( playerName ) ) { + RankPlayerFactory rankPlayerFactory = new RankPlayerFactory(); + // We need to create a new player data file. newPlayer = new RankPlayer( uid, playerName ); newPlayer.checkName( playerName ); - newPlayer.firstJoin(); + rankPlayerFactory.firstJoin( newPlayer ); players.add(newPlayer); getPlayersByName().put( playerName, newPlayer ); @@ -479,9 +510,12 @@ public List getPlayerNextRanks( RankPlayer rankPlayer ) { List results = new ArrayList<>(); if ( !rankPlayer.getLadderRanks().isEmpty()) { + + RankPlayerFactory rankPlayerFactory = new RankPlayerFactory(); + for ( RankLadder ladder : rankPlayer.getLadderRanks().keySet() ) { - Rank rank = rankPlayer.getRank( ladder ).getRank(); + Rank rank = rankPlayerFactory.getRank( rankPlayer, ladder ).getRank(); if ( rank != null && rank.getRankNext() != null ) { Rank nextRank = rank.getRankNext(); @@ -500,37 +534,48 @@ public String getPlayerNextRankCost( RankPlayer rankPlayer, String ladderName, if ( !rankPlayer.getLadderRanks().isEmpty()) { DecimalFormat dFmt = new DecimalFormat("#,##0"); + RankPlayerFactory rankPlayerFactory = new RankPlayerFactory(); + for ( RankLadder ladder : rankPlayer.getLadderRanks().keySet() ) { if ( ladderName == null || ladderName != null && ladder.getName().equalsIgnoreCase( ladderName )) { - PlayerRank pRank = rankPlayer.getRank( ladder ); - if ( pRank != null && pRank.getRank().getRankNext() != null ) { - Rank nextRank = pRank.getRank().getRankNext(); + boolean isDefault = ladder.getName().equals( "default" ) ; + + PlayerRank pRank = rankPlayerFactory.getRank( rankPlayer, ladder ); + Rank nextRank = pRank.getRank().getRankNext(); + + if ( pRank != null && + ( nextRank != null || nextRank == null && isDefault )) { + + nextRank = getNextPrestigeRank( rankPlayer, isDefault, nextRank ); // This calculates the target rank, and takes in to consideration the player's existing rank: - PlayerRank nextPRank = PlayerRank.getTargetPlayerRankForPlayer( rankPlayer, nextRank ); + PlayerRank nextPRank = pRank.getTargetPlayerRankForPlayer( rankPlayer, nextRank ); //PlayerRank nextPRank = new PlayerRank( nextRank, pRank.getRankMultiplier() ); - if ( sb.length() > 0 ) { - sb.append(", "); - } - - double cost = nextPRank.getRankCost(); - - if ( attribute != null && attribute instanceof PlaceholderAttributeNumberFormat ) { - PlaceholderAttributeNumberFormat attributeNF = - (PlaceholderAttributeNumberFormat) attribute; - sb.append( attributeNF.format( cost ) ); - } - else if ( formatted ) { - sb.append( PlaceholdersUtil.formattedMetricSISize( cost )); - } - else { - sb.append( dFmt.format( cost )); - } + if ( nextPRank != null ) { + + if ( sb.length() > 0 ) { + sb.append(", "); + } + + double cost = nextPRank.getRankCost(); + + if ( attribute != null && attribute instanceof PlaceholderAttributeNumberFormat ) { + PlaceholderAttributeNumberFormat attributeNF = + (PlaceholderAttributeNumberFormat) attribute; + sb.append( attributeNF.format( cost ) ); + } + else if ( formatted ) { + sb.append( PlaceholdersUtil.formattedMetricSISize( cost )); + } + else { + sb.append( dFmt.format( cost )); + } + } } } } @@ -539,6 +584,36 @@ else if ( formatted ) { return sb.toString(); } + + private Rank getNextPrestigeRank( RankPlayer rankPlayer, boolean isDefault, Rank nextRank ) + { + Rank results = nextRank; + + // if nextRank is null and if prestiges are enabled, then get the next prestige rank: + if ( nextRank == null && + rankPlayer != null && + isDefault && + Prison.get().getPlatform().getConfigBooleanFalse( "prestige.enabled" ) ) { + + RankLadder rLadder = PrisonRanks.getInstance().getLadderManager().getLadder( "prestiges" ); + + if ( rLadder != null ) { + + PlayerRank pLadder = rankPlayer.getLadderRanks().get( rLadder ); + + if ( pLadder == null ) { + + results = rLadder.getLowestRank().orElse( null ); + } + else { + + results = pLadder.getRank().getRankNext(); + } + } + } + + return results; + } public String getPlayerNextRankCostPercent( RankPlayer rankPlayer, String ladderName ) { StringBuilder sb = new StringBuilder(); @@ -560,34 +635,45 @@ public String getPlayerNextRankCostPercent( RankPlayer rankPlayer, String ladder if ( !rankPlayer.getLadderRanks().isEmpty()) { DecimalFormat dFmt = new DecimalFormat("#,##0"); + RankPlayerFactory rankPlayerFactory = new RankPlayerFactory(); + for ( RankLadder ladder : rankPlayer.getLadderRanks().keySet() ) { if ( ladderName == null || ladderName != null && ladder.getName().equalsIgnoreCase( ladderName )) { - PlayerRank pRank = rankPlayer.getRank( ladder ); - if ( pRank != null && pRank.getRank().getRankNext() != null ) { - Rank nextRank = pRank.getRank().getRankNext(); - - // This calculates the target rank, and takes in to consideration the player's existing rank: - PlayerRank nextPRank = PlayerRank.getTargetPlayerRankForPlayer( rankPlayer, nextRank ); + boolean isDefault = ladder.getName().equals( "default" ) ; + + PlayerRank pRank = rankPlayerFactory.getRank( rankPlayer, ladder ); + Rank nextRank = pRank.getRank().getRankNext(); -// PlayerRank nextPRank = new PlayerRank( nextRank, pRank.getRankMultiplier() ); + if ( pRank != null && + ( nextRank != null || nextRank == null && isDefault ) ) { - if ( sb.length() > 0 ) { - sb.append(", "); - } - -// Rank rank = key.getNext(key.getPositionOfRank(entry.getValue())).get(); - double cost = nextPRank.getRankCost(); - double balance = rankPlayer.getBalance( pRank.getRank().getCurrency() ); -// double balance = getPlayerBalance(prisonPlayer,nextRank); + nextRank = getNextPrestigeRank( rankPlayer, isDefault, nextRank ); - double percent = (balance < 0 ? 0 : - (cost == 0.0d || balance > cost ? 100.0 : - balance / cost * 100.0 ) - ); - sb.append( dFmt.format( percent )); + // This calculates the target rank, and takes in to consideration the player's existing rank: + PlayerRank nextPRank = pRank.getTargetPlayerRankForPlayer( rankPlayer, nextRank ); + +// PlayerRank nextPRank = new PlayerRank( nextRank, pRank.getRankMultiplier() ); + + if ( nextPRank != null ) { + + if ( sb.length() > 0 ) { + sb.append(", "); + } + +// Rank rank = key.getNext(key.getPositionOfRank(entry.getValue())).get(); + double cost = nextPRank.getRankCost(); + double balance = rankPlayer.getBalance( pRank.getRank().getCurrency() ); +// double balance = getPlayerBalance(prisonPlayer,nextRank); + + double percent = (balance < 0 ? 0 : + (cost == 0.0d || balance > cost ? 100.0 : + balance / cost * 100.0 ) + ); + sb.append( dFmt.format( percent )); + } } } } @@ -618,33 +704,44 @@ public String getPlayerNextRankCostBar( RankPlayer rankPlayer, String ladderName if ( !rankPlayer.getLadderRanks().isEmpty()) { // DecimalFormat dFmt = new DecimalFormat("#,##0.00"); + + RankPlayerFactory rankPlayerFactory = new RankPlayerFactory(); for ( RankLadder ladder : rankPlayer.getLadderRanks().keySet() ) { if ( ladderName == null || ladderName != null && ladder.getName().equalsIgnoreCase( ladderName )) { - PlayerRank pRank = rankPlayer.getRank( ladder ); + boolean isDefault = ladder.getName().equals( "default" ) ; + + PlayerRank pRank = rankPlayerFactory.getRank( rankPlayer, ladder ); Rank rank = pRank.getRank(); - if ( rank != null && rank.getRankNext() != null ) { - Rank nextRank = rank.getRankNext(); + Rank nextRank = rank.getRankNext(); + + if ( rank != null && + ( nextRank != null || nextRank == null && isDefault )) { + + nextRank = getNextPrestigeRank( rankPlayer, isDefault, nextRank ); // This calculates the target rank, and takes in to consideration the player's existing rank: - PlayerRank nextPRank = PlayerRank.getTargetPlayerRankForPlayer( rankPlayer, nextRank ); + PlayerRank nextPRank = pRank.getTargetPlayerRankForPlayer( rankPlayer, nextRank ); // PlayerRank nextPRank = new PlayerRank( nextRank, pRank.getRankMultiplier() ); - if ( sb.length() > 0 ) { - sb.append(", "); - } - - double cost = nextPRank.getRankCost(); - double balance = rankPlayer.getBalance( rank.getCurrency() ); -// double balance = getPlayerBalance(prisonPlayer,nextRank); - - - sb.append( Prison.get().getPlaceholderManager(). - getProgressBar( balance, cost, false, attribute )); + if ( nextPRank != null ) { + + if ( sb.length() > 0 ) { + sb.append(", "); + } + + double cost = nextPRank.getRankCost(); + double balance = rankPlayer.getBalance( rank.getCurrency() ); +// double balance = getPlayerBalance(prisonPlayer,nextRank); + + + sb.append( Prison.get().getPlaceholderManager(). + getProgressBar( balance, cost, false, attribute )); + } } } @@ -687,52 +784,63 @@ public String getPlayerNextRankCostRemaining( RankPlayer rankPlayer, String ladd if ( !rankPlayer.getLadderRanks().isEmpty()) { DecimalFormat dFmt = new DecimalFormat("#,##0"); + + RankPlayerFactory rankPlayerFactory = new RankPlayerFactory(); for ( RankLadder ladder : rankPlayer.getLadderRanks().keySet() ) { if ( ladderName == null || ladderName != null && ladder.getName().equalsIgnoreCase( ladderName )) { - PlayerRank pRank = rankPlayer.getRank( ladder ); + boolean isDefault = ladder.getName().equals( "default" ) ; + + PlayerRank pRank = rankPlayerFactory.getRank( rankPlayer, ladder ); Rank rank = pRank.getRank(); - if ( rank != null && rank.getRankNext() != null ) { - Rank nextRank = rank.getRankNext(); + Rank nextRank = rank.getRankNext(); + + if ( rank != null && + ( nextRank != null || nextRank == null && isDefault ) ) { + + nextRank = getNextPrestigeRank( rankPlayer, isDefault, nextRank ); // This calculates the target rank, and takes in to consideration the player's existing rank: - PlayerRank nextPRank = PlayerRank.getTargetPlayerRankForPlayer( rankPlayer, nextRank ); + PlayerRank nextPRank = pRank.getTargetPlayerRankForPlayer( rankPlayer, nextRank ); // PlayerRank nextPRank = new PlayerRank( nextRank, pRank.getRankMultiplier() ); - if ( sb.length() > 0 ) { - sb.append(", "); - } - - double cost = nextPRank.getRankCost(); - double balance = rankPlayer.getBalance( rank.getCurrency() ); + if ( nextPRank != null ) { + + if ( sb.length() > 0 ) { + sb.append(", "); + } + + double cost = nextPRank.getRankCost(); + double balance = rankPlayer.getBalance( rank.getCurrency() ); // double balance = getPlayerBalance(prisonPlayer,nextRank); - - double remaining = cost - balance; - - // Without the following, if the player has more money than what the rank will cost, - // then it would result in a negative amount, which is wrong. - // This is cost remaining... once they are able to afford a rankup, then remaining - // cost will be zero. - if ( remaining < 0 ) { - remaining = 0; - } - - if ( attribute != null && attribute instanceof PlaceholderAttributeNumberFormat ) { - PlaceholderAttributeNumberFormat attributeNF = - (PlaceholderAttributeNumberFormat) attribute; - sb.append( attributeNF.format( remaining ) ); - } - - else if ( formatted ) { - sb.append( PlaceholdersUtil.formattedMetricSISize( remaining )); - } - else { - sb.append( dFmt.format( remaining )); - } + + double remaining = cost - balance; + + // Without the following, if the player has more money than what the rank will cost, + // then it would result in a negative amount, which is wrong. + // This is cost remaining... once they are able to afford a rankup, then remaining + // cost will be zero. + if ( remaining < 0 ) { + remaining = 0; + } + + if ( attribute != null && attribute instanceof PlaceholderAttributeNumberFormat ) { + PlaceholderAttributeNumberFormat attributeNF = + (PlaceholderAttributeNumberFormat) attribute; + sb.append( attributeNF.format( remaining ) ); + } + + else if ( formatted ) { + sb.append( PlaceholdersUtil.formattedMetricSISize( remaining )); + } + else { + sb.append( dFmt.format( remaining )); + } + } } } } @@ -762,43 +870,54 @@ public String getPlayerNextRankCostRemainingPercent( RankPlayer rankPlayer, Stri if ( !rankPlayer.getLadderRanks().isEmpty()) { DecimalFormat dFmt = new DecimalFormat("#,##0"); + RankPlayerFactory rankPlayerFactory = new RankPlayerFactory(); + for ( RankLadder ladder : rankPlayer.getLadderRanks().keySet() ) { if ( ladderName == null || ladderName != null && ladder.getName().equalsIgnoreCase( ladderName )) { - PlayerRank pRank = rankPlayer.getRank( ladder ); + boolean isDefault = ladder.getName().equals( "default" ) ; + + PlayerRank pRank = rankPlayerFactory.getRank( rankPlayer, ladder ); Rank rank = pRank.getRank(); - if ( rank != null && rank.getRankNext() != null ) { - Rank nextRank = rank.getRankNext(); + Rank nextRank = rank.getRankNext(); + + if ( rank != null && + ( nextRank != null || nextRank == null && isDefault ) ) { + + nextRank = getNextPrestigeRank( rankPlayer, isDefault, nextRank ); // This calculates the target rank, and takes in to consideration the player's existing rank: - PlayerRank nextPRank = PlayerRank.getTargetPlayerRankForPlayer( rankPlayer, nextRank ); + PlayerRank nextPRank = pRank.getTargetPlayerRankForPlayer( rankPlayer, nextRank ); // PlayerRank nextPRank = new PlayerRank( nextRank, pRank.getRankMultiplier() ); - if ( sb.length() > 0 ) { - sb.append(", "); - } - - double cost = nextPRank.getRankCost(); - double balance = rankPlayer.getBalance( rank.getCurrency() ); + if ( nextPRank != null ) { + + if ( sb.length() > 0 ) { + sb.append(", "); + } + + double cost = nextPRank.getRankCost(); + double balance = rankPlayer.getBalance( rank.getCurrency() ); // double balance = getPlayerBalance(prisonPlayer,nextRank); - - double remaining = cost - balance; - - // Without the following, if the player has more money than what the rank will cost, - // then it would result in a negative amount, which is wrong. - // This is cost remaining... once they are able to afford a rankup, then remaining - // cost will be zero. - if ( remaining < 0 ) { - remaining = 0; - } - double percent = (remaining < 0 ? 0.0 : - (cost == 0.0d || remaining > cost ? 100.0 : - remaining / cost * 100.0 ) - ); - sb.append( dFmt.format( percent )); + + double remaining = cost - balance; + + // Without the following, if the player has more money than what the rank will cost, + // then it would result in a negative amount, which is wrong. + // This is cost remaining... once they are able to afford a rankup, then remaining + // cost will be zero. + if ( remaining < 0 ) { + remaining = 0; + } + double percent = (remaining < 0 ? 0.0 : + (cost == 0.0d || remaining > cost ? 100.0 : + remaining / cost * 100.0 ) + ); + sb.append( dFmt.format( percent )); + } } } } @@ -828,47 +947,58 @@ public String getPlayerNextRankCostRemainingBar( RankPlayer rankPlayer, String l if ( !rankPlayer.getLadderRanks().isEmpty()) { // DecimalFormat dFmt = new DecimalFormat("#,##0"); + RankPlayerFactory rankPlayerFactory = new RankPlayerFactory(); + for ( RankLadder ladder : rankPlayer.getLadderRanks().keySet() ) { if ( ladderName == null || ladderName != null && ladder.getName().equalsIgnoreCase( ladderName )) { - PlayerRank pRank = rankPlayer.getRank( ladder ); + boolean isDefault = ladder.getName().equals( "default" ) ; + + PlayerRank pRank = rankPlayerFactory.getRank( rankPlayer, ladder ); Rank rank = pRank.getRank(); - if ( rank != null && rank.getRankNext() != null ) { + Rank nextRank = rank.getRankNext(); + + if ( rank != null && + ( nextRank != null || nextRank == null && isDefault ) ) { - Rank nextRank = rank.getRankNext(); + + nextRank = getNextPrestigeRank( rankPlayer, isDefault, nextRank ); // This calculates the target rank, and takes in to consideration the player's existing rank: - PlayerRank nextPRank = PlayerRank.getTargetPlayerRankForPlayer( rankPlayer, nextRank ); + PlayerRank nextPRank = pRank.getTargetPlayerRankForPlayer( rankPlayer, nextRank ); // PlayerRank nextPRank = new PlayerRank( nextRank, pRank.getRankMultiplier() ); - if ( sb.length() > 0 ) { - sb.append(", "); - } - - double cost = nextPRank.getRankCost(); - double balance = rankPlayer.getBalance( rank.getCurrency() ); + if ( nextPRank != null ) { + + if ( sb.length() > 0 ) { + sb.append(", "); + } + + double cost = nextPRank.getRankCost(); + double balance = rankPlayer.getBalance( rank.getCurrency() ); // double balance = getPlayerBalance(prisonPlayer,nextRank); - - double remaining = cost - balance; - - // Without the following, if the player has more money than what the rank will cost, - // then it would result in a negative amount, which is wrong. - // This is cost remaining... once they are able to afford a rankup, then remaining - // cost will be zero. - if ( remaining < 0 ) { - remaining = 0; - } - // double percent = (remaining < 0 ? 0.0 : - // (cost == 0.0d || remaining > cost ? 100.0 : - // remaining / cost * 100.0 ) - // ); - // sb.append( dFmt.format( percent )); - - sb.append( Prison.get().getPlaceholderManager(). - getProgressBar( remaining, cost, false, attribute )); + + double remaining = cost - balance; + + // Without the following, if the player has more money than what the rank will cost, + // then it would result in a negative amount, which is wrong. + // This is cost remaining... once they are able to afford a rankup, then remaining + // cost will be zero. + if ( remaining < 0 ) { + remaining = 0; + } + // double percent = (remaining < 0 ? 0.0 : + // (cost == 0.0d || remaining > cost ? 100.0 : + // remaining / cost * 100.0 ) + // ); + // sb.append( dFmt.format( percent )); + + sb.append( Prison.get().getPlaceholderManager(). + getProgressBar( remaining, cost, false, attribute )); + } } } @@ -913,12 +1043,14 @@ private String getPlayerBalance( RankPlayer rankPlayer, String ladderName, if ( !rankPlayer.getLadderRanks().isEmpty()) { DecimalFormat dFmt = new DecimalFormat("#,##0"); + RankPlayerFactory rankPlayerFactory = new RankPlayerFactory(); + for ( RankLadder ladder : rankPlayer.getLadderRanks().keySet() ) { if ( ladderName == null || ladderName != null && ladder.getName().equalsIgnoreCase( ladderName )) { - PlayerRank pRank = rankPlayer.getRank( ladder ); + PlayerRank pRank = rankPlayerFactory.getRank( rankPlayer, ladder ); Rank rank = pRank.getRank(); if ( rank != null ) { if ( sb.length() > 0 ) { @@ -976,6 +1108,84 @@ else if ( formatted ) { } + private String getPlayerTokenBalance( RankPlayer rankPlayer, + int formatMode, PlaceholderAttribute attribute ) { + StringBuilder sb = new StringBuilder(); + + DecimalFormat dFmt = new DecimalFormat("#,##0"); + + long tokens = rankPlayer.getPlayerCachePlayerData().getTokens(); + + if ( attribute != null && attribute instanceof PlaceholderAttributeNumberFormat ) { + PlaceholderAttributeNumberFormat attributeNF = + (PlaceholderAttributeNumberFormat) attribute; + sb.append( attributeNF.format( tokens ) ); + } + + else { + switch ( formatMode ) + { + case 1: { + sb.append( dFmt.format( tokens )); + + break; + } + case 2: { + sb.append( PlaceholdersUtil.formattedMetricSISize( tokens )); + + break; + } + case 3: { + sb.append( PlaceholdersUtil.formattedKmbtSISize( tokens, dFmt, " " )); + + break; + } + default: + sb.append( Long.toString( tokens )); + } + } + +// if ( formatted ) { +// sb.append( PlaceholdersUtil.formattedMetricSISize( tokens )); +// } +// else { +// sb.append( dFmt.format( tokens )); +// } + + return sb.toString(); + } + + + private String getPlayerTokenAverageEarningsPerMinute( RankPlayer rankPlayer, + boolean formatted, PlaceholderAttribute attribute ) { + StringBuilder sb = new StringBuilder(); + + + if ( !rankPlayer.getLadderRanks().isEmpty()) { + DecimalFormat dFmt = new DecimalFormat("#,##0"); + + + double tpm = rankPlayer.getPlayerCachePlayerData().getAverageTokensPerMinute(); + + if ( attribute != null && attribute instanceof PlaceholderAttributeNumberFormat ) { + PlaceholderAttributeNumberFormat attributeNF = + (PlaceholderAttributeNumberFormat) attribute; + sb.append( attributeNF.format( tpm ) ); + } + + else if ( formatted ) { + sb.append( PlaceholdersUtil.formattedMetricSISize( tpm )); + } + else { + sb.append( dFmt.format( tpm )); + } + + } + + return sb.toString(); + } + + // /** // *

This gets the player's balance, and if the rank is provided, it will check to @@ -1036,12 +1246,15 @@ public String getPlayerNextRankName( RankPlayer rankPlayer, String ladderName ) StringBuilder sb = new StringBuilder(); if ( !rankPlayer.getLadderRanks().isEmpty()) { + + RankPlayerFactory rankPlayerFactory = new RankPlayerFactory(); + for ( RankLadder ladder : rankPlayer.getLadderRanks().keySet() ) { if ( ladderName == null || ladderName != null && ladder.getName().equalsIgnoreCase( ladderName )) { - PlayerRank pRank = rankPlayer.getRank( ladder ); + PlayerRank pRank = rankPlayerFactory.getRank( rankPlayer, ladder ); Rank rank = pRank.getRank(); if ( rank != null && rank.getRankNext() != null ) { @@ -1064,12 +1277,14 @@ public String getPlayerNextRankTag( RankPlayer rankPlayer, String ladderName ) { if ( !rankPlayer.getLadderRanks().isEmpty()) { + RankPlayerFactory rankPlayerFactory = new RankPlayerFactory(); + for ( RankLadder ladder : rankPlayer.getLadderRanks().keySet() ) { if ( ladderName == null || ladderName != null && ladder.getName().equalsIgnoreCase( ladderName )) { - PlayerRank pRank = rankPlayer.getRank( ladder ); + PlayerRank pRank = rankPlayerFactory.getRank( rankPlayer, ladder ); Rank rank = pRank.getRank(); if ( rank != null && rank.getRankNext() != null ) { Rank nextRank = rank.getRankNext(); @@ -1233,7 +1448,8 @@ public String getTranslatePlayerPlaceHolder( UUID playerUuid, String playerName, case prison_rlp_laddername: { // rank may be null: - PlayerRank pRank = rankPlayer.getRank( ladderName ); + RankPlayerFactory rankPlayerFactory = new RankPlayerFactory(); + PlayerRank pRank = rankPlayerFactory.getRank( rankPlayer, ladderName ); if ( pRank != null ) { Rank rank = pRank.getRank(); @@ -1321,6 +1537,13 @@ public String getTranslatePlayerPlaceHolder( UUID playerUuid, String playerName, results = getPlayerBalance( rankPlayer, ladderName, false, attribute ); break; + case prison_pbf: + case prison_player_balance_formatted: + case prison_pbf_laddername: + case prison_player_balance_formatted_laddername: + results = getPlayerBalance( rankPlayer, ladderName, true, attribute ); + break; + case prison_pb_epm: case prison_player_balance_earnings_per_minute: @@ -1333,13 +1556,76 @@ public String getTranslatePlayerPlaceHolder( UUID playerUuid, String playerName, results = getPlayerAverageEarningsPerMinute( rankPlayer, ladderName, true, attribute ); break; + + + case prison_ptb: + case prison_player_token_balance: + results = getPlayerTokenBalance( rankPlayer, 0, attribute ); + break; + + case prison_ptbf: + case prison_player_token_balance_formatted: + results = getPlayerTokenBalance( rankPlayer, 1, attribute ); + break; + + case prison_ptbfm: + case prison_player_token_balance_formatted_metric: + results = getPlayerTokenBalance( rankPlayer, 2, attribute ); + break; + + case prison_ptbfk: + case prison_player_token_balance_formatted_kmbt: + results = getPlayerTokenBalance( rankPlayer, 3, attribute ); + break; + + case prison_ptb_epm: + case prison_player_token_balance_earnings_per_minute: + + results = getPlayerTokenAverageEarningsPerMinute( rankPlayer, false, attribute ); + break; + + case prison_ptb_epmf: + case prison_player_token_balance_earnings_per_minute_formatted: + + results = getPlayerTokenAverageEarningsPerMinute( rankPlayer, true, attribute ); + break; + + + + case prison_psm: case prison_player_sellall_multiplier: results = getPlayerSellallMultiplier( rankPlayer, attribute ); break; - + case prison_pbt: + case prison_pbtf: + case prison_player_blocks_total: + case prison_player_blocks_total_formatted: + long blocksTotal = PlayerCache.getInstance().getPlayerBlocksTotal( rankPlayer ); + + if ( attribute != null && attribute instanceof PlaceholderAttributeNumberFormat ) { + PlaceholderAttributeNumberFormat attributeNF = + (PlaceholderAttributeNumberFormat) attribute; + results = attributeNF.format( blocksTotal ); + } + else { + if ( placeHolder == PrisonPlaceHolders.prison_pbtf || + placeHolder == PrisonPlaceHolders.prison_player_blocks_total_formatted ) { + + DecimalFormat iFmt = new DecimalFormat("#,##0"); + results = iFmt.format( blocksTotal ); + } + else { + + results = Long.toString( blocksTotal ); + } + } + break; + + + case prison_player_tool_id: case prison_ptid: 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 c2d93b33c..9c4019b91 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 @@ -48,8 +48,10 @@ import tech.mcprison.prison.ranks.commands.RanksCommands; import tech.mcprison.prison.ranks.data.PlayerRank; import tech.mcprison.prison.ranks.data.Rank; +import tech.mcprison.prison.ranks.data.RankFactory; import tech.mcprison.prison.ranks.data.RankLadder; import tech.mcprison.prison.ranks.data.RankPlayer; +import tech.mcprison.prison.ranks.data.RankPlayerFactory; import tech.mcprison.prison.ranks.data.StatsRankPlayerBalanceData; import tech.mcprison.prison.store.Collection; import tech.mcprison.prison.store.Document; @@ -179,7 +181,9 @@ private void resetRankPositions( Rank rank ) { public void loadRank(String rankFile) throws IOException { Document document = collection.get(rankFile).orElseThrow(IOException::new); - addRank( new Rank(document) ); + RankFactory rankFactory = new RankFactory(); + + addRank( rankFactory.createRank( document ) ); // loadedRanks.add(new Rank(document)); } @@ -191,9 +195,12 @@ public void loadRank(String rankFile) throws IOException { */ public void loadRanks() throws IOException { List ranks = collection.getAll(); + + RankFactory rankFactory = new RankFactory(); for ( Document rankDocument : ranks ) { - Rank rank = new Rank( rankDocument ); + + Rank rank = rankFactory.createRank( rankDocument ); addRank( rank ); } @@ -208,7 +215,10 @@ public void loadRanks() throws IOException { * @param saveFile The key to write the rank as. Case sensitive. */ public void saveRank(Rank rank, String saveFile) { - collection.save(saveFile, rank.toDocument()); + + RankFactory rankFactory = new RankFactory(); + + collection.save(saveFile, rankFactory.toDocument( rank ) ); } /** @@ -348,9 +358,11 @@ public boolean removeRank(Rank rank) { // for (RankLadder ladder : PrisonRanks.getInstance().getLadderManager() .getLadder( rank )) { + RankPlayerFactory rankPlayerFactory = new RankPlayerFactory(); + // Move each player in this ladder to the new rank PrisonRanks.getInstance().getPlayerManager().getPlayers().forEach(rankPlayer -> { - PlayerRank pRank = rankPlayer.getRank(ladder); + PlayerRank pRank = rankPlayerFactory.getRank( rankPlayer, ladder ); if ( pRank != null && pRank.getRank() != null ) { Rank curRank = pRank.getRank(); @@ -519,8 +531,13 @@ public void identifyAllRankCurrencies( List prisonStartupDetails ) { public String listAllRanks( String ladderName, List ranks, RanksByLadderOptions option ) { StringBuilder sb = new StringBuilder(); + sb.append( "&7 " ); + sb.append( ladderName ); + sb.append( ": " ); + // PlayerManager playerManager = PrisonRanks.getInstance().getPlayerManager(); + int count = 0; for (Rank rank : ranks ) { int players = rank.getPlayers().size(); @@ -534,8 +551,12 @@ public String listAllRanks( String ladderName, List ranks, RanksByLadderOp if ( option == RanksByLadderOptions.allRanks || option == RanksByLadderOptions.full || players > 0 ) { - if ( sb.length() > 0 ) { + if ( count++ > 0 ) { sb.append( ", " ); + + if ( count >= 10 && (count - 1) % 15 == 0 ) { + sb.append( "\n " ); + } } @@ -564,13 +585,11 @@ public String listAllRanks( String ladderName, List ranks, RanksByLadderOp } } + + } } - sb.insert( 0, ": " ); - sb.insert( 0, ladderName ); - sb.insert( 0, "&7 " ); - return sb.toString(); } @@ -640,7 +659,7 @@ private void rankByLadderOutput( CommandSender sender, String ranksByLadder ) { private String getRankCost( Rank rank, PlaceholderAttribute attribute, boolean formatted ) { - double cost = PlayerRank.getRawRankCost( rank ); + double cost = rank.getRawRankCost(); String resultsx = null; DecimalFormat dFmt = new DecimalFormat("#,##0"); @@ -763,7 +782,7 @@ public String getTranslateRanksPlaceHolder( PlaceHolderKey placeHolderKey, case prison_rank__tag_rankname: case prison_r_t_rankname: - results = rank.getTag(); + results = (rank.getTag() == null ? "" : rank.getTag()); break; case prison_rank__ladder_rankname: @@ -788,7 +807,11 @@ public String getTranslateRanksPlaceHolder( PlaceHolderKey placeHolderKey, case prison_rank__cost_multiplier_rankname: case prison_r_cm_rankname: - results = Double.toString( PlayerRank.getLadderBaseRankdMultiplier( rank ) ); + + RankPlayerFactory rankPlayerFactory = new RankPlayerFactory(); + PlayerRank pRank = rankPlayerFactory.createPlayerRank( rank ); + + results = Double.toString( pRank.getLadderBasedRankMultiplier() ); break; @@ -1044,7 +1067,10 @@ private double calculateRankCost( RankPlayer rankPlayer, Rank rank ) { double cost = 0; // Get player's rank: - PlayerRank playerRank = rankPlayer.getRank( rank.getLadder() ); + + RankPlayerFactory rankPlayerFactory = new RankPlayerFactory(); + + PlayerRank playerRank = rankPlayerFactory.getRank( rankPlayer, rank.getLadder() ); if ( playerRank != null ) { @@ -1055,14 +1081,20 @@ private double calculateRankCost( RankPlayer rankPlayer, Rank rank ) cost = 0; } else { - cost = playerRank.getRankCost(); + //cost = playerRank.getRankCost(); Rank nextRank = playerRank.getRank(); while ( nextRank != null && - nextRank.getPosition() < rank.getPosition() ) { + nextRank.getPosition() <= rank.getPosition() ) { // Need to calculate the next PlayerRank value for the next rank: - playerRank = new PlayerRank(nextRank); + + // This calculates the target rank, and takes in to consideration the player's existing rank: + playerRank = playerRank.getTargetPlayerRankForPlayer( rankPlayer, nextRank ); + + +// playerRank = rankPlayerFactory.createPlayerRank( nextRank ); +// playerRank = new PlayerRank(nextRank); cost += playerRank.getRankCost(); nextRank = nextRank.getRankNext(); @@ -1165,5 +1197,5 @@ public LadderCommands getLadderCommands() { public void setLadderCommands( LadderCommands ladderCommands ) { this.ladderCommands = ladderCommands; } - + } diff --git a/prison-spigot/build.gradle b/prison-spigot/build.gradle index 388480ab2..733da3809 100644 --- a/prison-spigot/build.gradle +++ b/prison-spigot/build.gradle @@ -105,7 +105,7 @@ dependencies { // implementation 'com.github.cryptomorin:xseries:b95d195482' // https://mvnrepository.com/artifact/com.github.cryptomorin/XSeries - implementation 'com.github.cryptomorin:XSeries:8.3.0' + implementation 'com.github.cryptomorin:XSeries:8.5.0.1' @@ -187,7 +187,7 @@ shadowJar { include(dependency('me.clip:placeholderapi:2.10.9')) - include(dependency('com.github.cryptomorin:XSeries:8.3.0')) + include(dependency('com.github.cryptomorin:XSeries:8.5.0.1')) //include(dependency('org.inventivetalent.spiget-update:bukkit:1.4.2-SNAPSHOT')) //include(dependency('me.badbones69:crazyenchantments-plugin:1.8-Dev-Build-v8')) diff --git a/prison-spigot/lib/PrisonEnchants-API-1.0.jar b/prison-spigot/lib/PrisonEnchants-API-1.0.jar index 839d83d28..a5fc3fe07 100644 Binary files a/prison-spigot/lib/PrisonEnchants-API-1.0.jar and b/prison-spigot/lib/PrisonEnchants-API-1.0.jar differ diff --git a/prison-spigot/lib/old/PrisonEnchants-API-1.0.jar b/prison-spigot/lib/old/PrisonEnchants-API-1.0.jar new file mode 100644 index 000000000..839d83d28 Binary files /dev/null and b/prison-spigot/lib/old/PrisonEnchants-API-1.0.jar differ diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/SpigotListener.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/SpigotListener.java index 2436295f4..96c407585 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/SpigotListener.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/SpigotListener.java @@ -42,19 +42,16 @@ import org.bukkit.plugin.PluginManager; import tech.mcprison.prison.Prison; -import tech.mcprison.prison.autofeatures.AutoFeaturesFileConfig.AutoFeatures; import tech.mcprison.prison.internal.events.Cancelable; import tech.mcprison.prison.internal.events.player.PlayerChatEvent; import tech.mcprison.prison.internal.events.player.PlayerPickUpItemEvent; import tech.mcprison.prison.internal.events.player.PlayerSuffocationEvent; +import tech.mcprison.prison.internal.events.player.PrisonPlayerInteractEvent; import tech.mcprison.prison.internal.events.world.PrisonWorldLoadEvent; import tech.mcprison.prison.output.Output; -import tech.mcprison.prison.spigot.autofeatures.events.AutoManagerBlockBreakEvents.AutoManagerBlockBreakEventListener; -import tech.mcprison.prison.spigot.autofeatures.events.AutoManagerBlockBreakEvents.OnBlockBreakEventListenerNormal; -import tech.mcprison.prison.spigot.autofeatures.events.AutoManagerBlockBreakEvents.OnBlockBreakEventListenerNormalMonitor; -import tech.mcprison.prison.spigot.block.OnBlockBreakEventListener; import tech.mcprison.prison.spigot.block.OnBlockBreakEventListener.BlockBreakPriority; 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.game.SpigotWorld; import tech.mcprison.prison.util.BlockType; @@ -217,27 +214,27 @@ public void onPlayerInteract(PlayerInteractEvent e) { // TODO Accept air events (block is null when air is clicked...) // Check to see if we support the Action - tech.mcprison.prison.internal.events.player.PlayerInteractEvent.Action[] values = tech.mcprison.prison.internal.events.player.PlayerInteractEvent.Action.values(); + PrisonPlayerInteractEvent.Action[] values = PrisonPlayerInteractEvent.Action.values(); + boolean has = false; - for (tech.mcprison.prison.internal.events.player.PlayerInteractEvent.Action value : values) { + for ( PrisonPlayerInteractEvent.Action value : values) { if(value.name().equals(e.getAction().name())) has = true; } if(!has) return; // we don't support this Action // This one's a workaround for the double-interact event glitch. // The wand can only be used in the main hand - if ( SpigotPrison.getInstance().getCompatibility().getHand(e) != + if ( SpigotCompatibility.getInstance().getHand(e) != Compatibility.EquipmentSlot.HAND) { return; } org.bukkit.Location block = e.getClickedBlock().getLocation(); - tech.mcprison.prison.internal.events.player.PlayerInteractEvent event = - new tech.mcprison.prison.internal.events.player.PlayerInteractEvent( + PrisonPlayerInteractEvent event = new PrisonPlayerInteractEvent( new SpigotPlayer(e.getPlayer()), SpigotUtil.bukkitItemStackToPrison( - SpigotPrison.getInstance().getCompatibility().getItemInMainHand(e)), - tech.mcprison.prison.internal.events.player.PlayerInteractEvent.Action + SpigotCompatibility.getInstance().getItemInMainHand(e)), + PrisonPlayerInteractEvent.Action .valueOf(e.getAction().name()), new Location(new SpigotWorld(block.getWorld()), block.getX(), block.getY(), block.getZ())); 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 7d260aaf7..1db975034 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 @@ -25,6 +25,7 @@ import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.TreeSet; import java.util.UUID; import java.util.stream.Collectors; @@ -42,6 +43,7 @@ import org.bukkit.event.EventPriority; import org.bukkit.event.player.AsyncPlayerChatEvent; import org.bukkit.event.player.PlayerChatEvent; +import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.plugin.Plugin; import org.bukkit.plugin.RegisteredListener; @@ -85,15 +87,18 @@ import tech.mcprison.prison.ranks.data.PlayerRank; import tech.mcprison.prison.ranks.data.Rank; import tech.mcprison.prison.ranks.data.RankPlayer; +import tech.mcprison.prison.ranks.data.RankPlayerFactory; import tech.mcprison.prison.ranks.managers.PlayerManager; import tech.mcprison.prison.ranks.managers.RankManager; import tech.mcprison.prison.spigot.autofeatures.events.AutoManagerBlockBreakEvents; import tech.mcprison.prison.spigot.autofeatures.events.AutoManagerCrazyEnchants; import tech.mcprison.prison.spigot.autofeatures.events.AutoManagerPrisonEnchants; +import tech.mcprison.prison.spigot.autofeatures.events.AutoManagerPrisonsExplosiveBlockBreakEvents; import tech.mcprison.prison.spigot.autofeatures.events.AutoManagerTokenEnchant; import tech.mcprison.prison.spigot.autofeatures.events.AutoManagerZenchantments; import tech.mcprison.prison.spigot.block.OnBlockBreakEventListener.BlockBreakPriority; import tech.mcprison.prison.spigot.commands.PrisonSpigotSellAllCommands; +import tech.mcprison.prison.spigot.compat.SpigotCompatibility; import tech.mcprison.prison.spigot.game.SpigotCommandSender; import tech.mcprison.prison.spigot.game.SpigotHandlerList; import tech.mcprison.prison.spigot.game.SpigotOfflinePlayer; @@ -133,7 +138,7 @@ public class SpigotPlatform private SpigotPlaceholders placeholders; - + private TreeSet excludedWorlds = null; /** * This is only for junit testing. @@ -142,6 +147,7 @@ protected SpigotPlatform() { super(); this.plugin = null; + //this.scoreboardManager = new SpigotScoreboardManager(); //this.storage = initStorage(); @@ -158,7 +164,7 @@ public SpigotPlatform(SpigotPrison plugin) { this.storage = initStorage(); this.placeholders = new SpigotPlaceholders(); - + ActionBarUtil.init(plugin); } @@ -394,6 +400,12 @@ else if ( oPlayer == null || oPlayer.getName() == null ) { @Override public boolean execute(CommandSender sender, String commandLabel, String[] args) { if (sender instanceof org.bukkit.entity.Player) { + + org.bukkit.World bWorld = ((org.bukkit.entity.Player) sender).getLocation().getWorld(); + if ( isWorldExcluded( bWorld.getName() ) ) { + return false; + } + return Prison.get().getCommandHandler() .onCommand(new SpigotPlayer((org.bukkit.entity.Player) sender), command, commandLabel, args); @@ -538,7 +550,7 @@ public void toggleDoor(Location doorLocation) { // state.setData((MaterialData) openable); // state.update(); - SpigotPrison.getInstance().getCompatibility() + SpigotCompatibility.getInstance() .playIronDoorSound(block.getLocation()); } @@ -795,6 +807,10 @@ public YamlFileIO getYamlFileIO( File yamlFile ) { public void reloadConfig() { SpigotPrison.getInstance().reloadConfig(); + + + // Reload excluded worlds list: + excludedWorlds = null; } @Override @@ -807,6 +823,13 @@ public String getConfigString( String key, String defaultValue ) { return SpigotPrison.getInstance().getConfig().getString( key, defaultValue ); } + + @Override + public List getConfigStringArray( String key ) { + return SpigotPrison.getInstance().getConfig().getList( key, new ArrayList() ); + } + + /** *

This returns the boolean value that is associated with the key. * It has to match on true to return a true value. If the key does @@ -937,13 +960,52 @@ public double getConfigDouble( String key, double defaultValue ) { } - /** + @Override + public boolean isWorldExcluded( String worldName ) { + boolean exclude = false; + + if ( worldName != null && getExcludedWorlds().size() > 0 ) { + + exclude = getExcludedWorlds().contains( worldName.toLowerCase() ); + } + + return exclude; + } + + + @Override + public TreeSet getExcludedWorlds() + { + + if ( excludedWorlds == null ) { + + excludedWorlds = new TreeSet<>(); + + List exWorlds = getConfigStringArray( "prisonCommandHandler.exclude-worlds" ); + + for ( Object worldObj : exWorlds ) + { + if ( worldObj instanceof String ) { + + String world = (String) worldObj; + + excludedWorlds.add( world.toLowerCase() ); + } + } + + } + + return excludedWorlds; + } + + /** * Setup hooks in to the valid prison block types. This will be only the * block types that have tested to be valid on the server that is running * prison. This provides full compatibility to the admins that if a block * is listed, then it's usable. No more guessing or finding out after the * fact that a block that was used was invalid for their version of minecraft. */ + @Override public PrisonBlockTypes getPrisonBlockTypes() { return SpigotPrison.getInstance().getPrisonBlockTypes(); } @@ -1257,8 +1319,10 @@ public ModuleElement getPlayerDefaultMine( tech.mcprison.prison.internal.Command Player player = pm.getPlayer( sender ); RankPlayer rankPlayer = pm.getPlayer( player ); - if ( rankPlayer != null && rankPlayer.getRank( "default" ) != null ) { - PlayerRank pRank = rankPlayer.getRank( "default" ); + RankPlayerFactory rankPlayerFactory = new RankPlayerFactory(); + + if ( rankPlayer != null && rankPlayerFactory.getRank( rankPlayer, "default" ) != null ) { + PlayerRank pRank = rankPlayerFactory.getRank( rankPlayer, "default" ); Rank rank = pRank.getRank(); @@ -1639,33 +1703,48 @@ public List buildBlockListXMaterial() { blockList.add( new SellAllBlockData( XMaterial.ANDESITE, 5, true) ); blockList.add( new SellAllBlockData( XMaterial.DIORITE, 6, true) ); blockList.add( new SellAllBlockData( XMaterial.COAL_ORE, 13, true) ); + blockList.add( new SellAllBlockData( XMaterial.GRANITE, 8, true) ); - blockList.add( new SellAllBlockData( XMaterial.STONE, 9, true) ); blockList.add( new SellAllBlockData( XMaterial.IRON_ORE, 18, true) ); blockList.add( new SellAllBlockData( XMaterial.POLISHED_ANDESITE, 7, true) ); + blockList.add( new SellAllBlockData( XMaterial.GOLD_ORE, 45, true) ); blockList.add( new SellAllBlockData( XMaterial.MOSSY_COBBLESTONE, 29, true) ); - blockList.add( new SellAllBlockData( XMaterial.COAL_BLOCK, 135, true) ); - blockList.add( new SellAllBlockData( XMaterial.IRON_BLOCK, 190, true) ); + + + blockList.add( new SellAllBlockData( XMaterial.NETHER_QUARTZ_ORE, 34, true) ); blockList.add( new SellAllBlockData( XMaterial.LAPIS_ORE, 100, true) ); + + + blockList.add( new SellAllBlockData( XMaterial.END_STONE, 14, true ) ); + blockList.add( new SellAllBlockData( XMaterial.IRON_BLOCK, 190, true) ); + blockList.add( new SellAllBlockData( XMaterial.REDSTONE_ORE, 45, true) ); blockList.add( new SellAllBlockData( XMaterial.DIAMOND_ORE, 200, true) ); + blockList.add( new SellAllBlockData( XMaterial.QUARTZ_BLOCK, 136, true) ); blockList.add( new SellAllBlockData( XMaterial.EMERALD_ORE, 250, true) ); + blockList.add( new SellAllBlockData( XMaterial.GOLD_BLOCK, 450, true) ); + blockList.add( new SellAllBlockData( XMaterial.PRISMARINE, 52, true ) ); + + blockList.add( new SellAllBlockData( XMaterial.LAPIS_BLOCK, 950, true) ); blockList.add( new SellAllBlockData( XMaterial.REDSTONE_BLOCK, 405, true) ); + + blockList.add( new SellAllBlockData( XMaterial.OBSIDIAN, 450, true ) ); + blockList.add( new SellAllBlockData( XMaterial.DIAMOND_BLOCK, 2000, true) ); + blockList.add( new SellAllBlockData( XMaterial.DARK_PRISMARINE, 54, true ) ); blockList.add( new SellAllBlockData( XMaterial.EMERALD_BLOCK, 2250, true) ); // blockList.add( XMaterial.SLIME_BLOCK.name() ); - blockList.add( new SellAllBlockData( XMaterial.OBSIDIAN, 450 ) ); @@ -1691,9 +1770,7 @@ public List buildBlockListXMaterial() { - blockList.add( new SellAllBlockData( XMaterial.NETHER_QUARTZ_ORE, 34, true) ); blockList.add( new SellAllBlockData( XMaterial.QUARTZ, 34 ) ); - blockList.add( new SellAllBlockData( XMaterial.QUARTZ_BLOCK, 136, true) ); blockList.add( new SellAllBlockData( XMaterial.QUARTZ_SLAB, 68, true) ); blockList.add( new SellAllBlockData( XMaterial.CHISELED_QUARTZ_BLOCK, 136 ) ); @@ -1712,7 +1789,6 @@ public List buildBlockListXMaterial() { blockList.add( new SellAllBlockData( XMaterial.CRACKED_STONE_BRICKS, 14 ) ); blockList.add( new SellAllBlockData( XMaterial.EMERALD, 14 ) ); - blockList.add( new SellAllBlockData( XMaterial.END_STONE, 14 ) ); blockList.add( new SellAllBlockData( XMaterial.END_STONE_BRICKS, 14 ) ); @@ -1724,12 +1800,10 @@ public List buildBlockListXMaterial() { blockList.add( new SellAllBlockData( XMaterial.PRISMARINE_SHARD, 13 ) ); - blockList.add( new SellAllBlockData( XMaterial.PRISMARINE, 52 ) ); blockList.add( new SellAllBlockData( XMaterial.PRISMARINE_BRICKS, 52 ) ); blockList.add( new SellAllBlockData( XMaterial.PRISMARINE_BRICK_SLAB, 52 ) ); blockList.add( new SellAllBlockData( XMaterial.PRISMARINE_CRYSTALS, 37 ) ); - blockList.add( new SellAllBlockData( XMaterial.DARK_PRISMARINE, 52 ) ); blockList.add( new SellAllBlockData( XMaterial.DARK_PRISMARINE_SLAB, 52 ) ); blockList.add( new SellAllBlockData( XMaterial.PURPUR_BLOCK, 14 ) ); @@ -1819,9 +1893,12 @@ protected List buildBlockListBlockType() { blockList.add( BlockType.MOSSY_COBBLESTONE.name() ); blockList.add( BlockType.COAL_BLOCK.name() ); blockList.add( BlockType.NETHER_QUARTZ_ORE.name() ); + blockList.add( BlockType.LAPIS_ORE.name() ); + + + blockList.add( BlockType.END_STONE.name() ); blockList.add( BlockType.IRON_BLOCK.name() ); - blockList.add( BlockType.LAPIS_ORE.name() ); blockList.add( BlockType.REDSTONE_ORE.name() ); blockList.add( BlockType.DIAMOND_ORE.name() ); @@ -1829,11 +1906,13 @@ protected List buildBlockListBlockType() { blockList.add( BlockType.EMERALD_ORE.name() ); blockList.add( BlockType.GOLD_BLOCK.name() ); + blockList.add( BlockType.PRISMARINE.name() ); blockList.add( BlockType.LAPIS_BLOCK.name() ); blockList.add( BlockType.REDSTONE_BLOCK.name() ); -// blockList.add( BlockType.SLIME_BLOCK.name() ); + blockList.add( BlockType.OBSIDIAN.name() ); blockList.add( BlockType.DIAMOND_BLOCK.name() ); + blockList.add( BlockType.DARK_PRISMARINE.name() ); blockList.add( BlockType.EMERALD_BLOCK.name() ); return blockList; @@ -1852,71 +1931,116 @@ public List getActiveFeatures() { if ( isAutoManagerEnabled ) { + + + boolean bbeAbbtst = afw.isBoolean( AutoFeatures.applyBlockBreaksThroughSyncTask ); + results.add( String.format(". Apply Block Breaks through Sync Tasks:&b %s", + Boolean.toString( bbeAbbtst ) ) ); + + + boolean bbeCabbe = afw.isBoolean( AutoFeatures.cancelAllBlockBreakEvents ); + results.add( String.format(". Cancel all Block Break Events:&b %s", + Boolean.toString( bbeCabbe ) ) ); + + + boolean bbeCabebd = afw.isBoolean( AutoFeatures.cancelAllBlockEventBlockDrops ); + results.add( String.format(". Cancel All Block Break Events Block Drops:&b %s", + Boolean.toString( bbeCabebd ) ) ); + + + + String bbePriority = afw.getMessage( AutoFeatures.blockBreakEventPriority ); BlockBreakPriority blockBreakPriority = BlockBreakPriority.fromString( bbePriority ); - results.add( String.format(". Block Break Event Priority:&b %s", + results.add( String.format(". '&7org.bukkit.BlockBreakEvent&3' Priority:&b %s", blockBreakPriority.name() ) ); + String pebbePriority = afw.getMessage( AutoFeatures.ProcessPrisons_ExplosiveBlockBreakEventsPriority ); + boolean isPebbeEnabled = pebbePriority != null && !"DISABLED".equalsIgnoreCase( pebbePriority ); + BlockBreakPriority pebbeEventPriority = BlockBreakPriority.fromString( pebbePriority ); + results.add( String.format("%s. Prison's own '&7ExplosiveBlockBreakEvent&3' Priority:&b %s %s", + (isPebbeEnabled ? "" : "+" ), + pebbeEventPriority.name(), + (isPebbeEnabled ? "&2Enabled" : "&cDisabled") + ) ); + + String peeePriority = afw.getMessage( AutoFeatures.PrisonEnchantsExplosiveEventPriority ); + boolean isPeeeEnabled = peeePriority != null && !"DISABLED".equalsIgnoreCase( peeePriority ); + BlockBreakPriority peeeEventPriority = BlockBreakPriority.fromString( peeePriority ); + results.add( String.format("%s. Pulsi_'s PrisonEnchants '&7PEExplosiveEvent&3' Priority:&b %s %s", + (isPeeeEnabled ? "" : "+" ), + peeeEventPriority.name(), + (isPeeeEnabled ? "&2Enabled" : "&cDisabled") + ) ); + String tebePriority = afw.getMessage( AutoFeatures.TokenEnchantBlockExplodeEventPriority ); - boolean isTebeEnabled = afw.isBoolean( AutoFeatures.isProcessTokensEnchantExplosiveEvents ); + boolean isTebeEnabled = tebePriority != null && !"DISABLED".equalsIgnoreCase( tebePriority ); BlockBreakPriority tebEventPriority = BlockBreakPriority.fromString( tebePriority ); - results.add( String.format("%s. Token Enchant BlockExplodeEvent Priority:&b %s %s", + results.add( String.format("%s. TokenEnchant '&7BlockExplodeEvent&3' Priority:&b %s %s", (isTebeEnabled ? "" : "+" ), tebEventPriority.name(), (isTebeEnabled ? "&2Enabled" : "&cDisabled") ) ); String cebuePriority = afw.getMessage( AutoFeatures.CrazyEnchantsBlastUseEventPriority ); - boolean isCebueEnabled = afw.isBoolean( AutoFeatures.isProcessCrazyEnchantsBlockExplodeEvents ); + boolean isCebueEnabled = cebuePriority != null && !"DISABLED".equalsIgnoreCase( cebuePriority ); BlockBreakPriority cebuEventPriority = BlockBreakPriority.fromString( cebuePriority ); - results.add( String.format("%s. Crazy Enchant BlastUseEvent Priority:&b %s %s", + results.add( String.format("%s. CrazyEnchant '&7BlastUseEvent&3' Priority:&b %s %s", (isCebueEnabled ? "" : "+" ), cebuEventPriority.name(), (isCebueEnabled ? "&2Enabled" : "&cDisabled") ) ); String zbsePriority = afw.getMessage( AutoFeatures.ZenchantmentsBlockShredEventPriority ); - boolean isZbseEnabled = afw.isBoolean( AutoFeatures.isProcessZenchantsBlockExplodeEvents ); + boolean isZbseEnabled = zbsePriority != null && !"DISABLED".equalsIgnoreCase( zbsePriority ); BlockBreakPriority zbsEventPriority = BlockBreakPriority.fromString( zbsePriority ); - results.add( String.format("%s. Zenchantments BlockShredEvent Priority:&b %s %s", + results.add( String.format("%s. Zenchantments '&7BlockShredEvent&3' Priority:&b %s %s", (isZbseEnabled ? "" : "+" ), zbsEventPriority.name(), (isZbseEnabled ? "&2Enabled" : "&cDisabled") ) ); - String peeePriority = afw.getMessage( AutoFeatures.PrisonEnchantsExplosiveEventPriority ); - boolean isPeeeeEnabled = afw.isBoolean( AutoFeatures.isProcessPrisonEnchantsExplosiveEvents ); - BlockBreakPriority peeEventPriority = BlockBreakPriority.fromString( peeePriority ); - results.add( String.format("%s. PrisonEnchants BlockExplodeEvent Priority:&b %s %s", - (isPeeeeEnabled ? "" : "+" ), - peeEventPriority.name(), - (isPeeeeEnabled ? "&2Enabled" : "&cDisabled") - ) ); +// String peeePriority = afw.getMessage( AutoFeatures.PrisonEnchantsExplosiveEventPriority ); +// boolean isPeeeeEnabled = afw.isBoolean( AutoFeatures.isProcessPrisonEnchantsExplosiveEvents ); +// BlockBreakPriority peeEventPriority = BlockBreakPriority.fromString( peeePriority ); +// results.add( String.format("%s. PrisonEnchants BlockExplodeEvent Priority:&b %s %s", +// (isPeeeeEnabled ? "" : "+" ), +// peeEventPriority.name(), +// (isPeeeeEnabled ? "&2Enabled" : "&cDisabled") +// ) ); +// +// results.add( " " ); - results.add( " " ); + + boolean isAutoFeaturesEnabled = afw.isBoolean( AutoFeatures.isAutoFeaturesEnabled ); + if ( !isAutoFeaturesEnabled ) { + results.add( ". AutoFeatures are disabled:" ); + } boolean isAutoPickup = afw.isBoolean( AutoFeatures.autoPickupEnabled ); - results.add( String.format(". Auto Pickup:&b %s", isAutoPickup ) ); + results.add( String.format(". Auto Pickup:&b %s", (!isAutoFeaturesEnabled ? "disabled" : + isAutoPickup )) ); + + results.add( String.format(". Auto Smelt:&b %s", (!isAutoFeaturesEnabled ? "disabled" : + afw.isBoolean( AutoFeatures.autoSmeltEnabled ))) ); - results.add( String.format(". Auto Smelt:&b %s", (!isAutoPickup ? "disabled" : - afw.isBoolean( AutoFeatures.autoSmeltEnabled ))) ); - results.add( String.format(". Auto Block:&b %s", (!isAutoPickup ? "disabled" : - afw.isBoolean( AutoFeatures.autoBlockEnabled ))) ); + results.add( String.format(". Auto Block:&b %s", (!isAutoFeaturesEnabled ? "disabled" : + afw.isBoolean( AutoFeatures.autoBlockEnabled ))) ); results.add( String.format("%s. Handle Normal Drops:&b %s %s", - (isAutoPickup ? "+" : ""), + (isAutoFeaturesEnabled ? "+" : ""), (afw.isBoolean( AutoFeatures.handleNormalDropsEvents ) ? "&2Enabled" : "&cDisabled" ), - (isAutoPickup ? "&d[disabled by Exended Bukkit Fortune]" : "") ) ); + (isAutoFeaturesEnabled ? "&d[Overridden by AutoPickup]" : "") ) ); results.add( String.format("%s. Normal Drop Smelt:&b %s", - (isAutoPickup ? "+" : ""), + (isAutoFeaturesEnabled ? "+" : ""), (afw.isBoolean( AutoFeatures.normalDropSmelt ) ? "&2Enabled" : "&cDisabled" ), - (isAutoPickup ? "&d[disabled by Exended Bukkit Fortune]" : "") ) ); + (isAutoFeaturesEnabled ? "&d[Overridden by AutoPickup]" : "") ) ); results.add( String.format("%s. Normal Drop Block:&b %s", - (isAutoPickup ? "+" : ""), + (isAutoFeaturesEnabled ? "+" : ""), (afw.isBoolean( AutoFeatures.normalDropBlock ) ? "&2Enabled" : "&cDisabled" ), - (isAutoPickup ? "&d[disabled by Exended Bukkit Fortune]" : "") ) ); + (isAutoFeaturesEnabled ? "&d[Overridden by AutoPickup]" : "") ) ); @@ -1967,6 +2091,17 @@ public List getActiveFeatures() { (isXpEnabled ? "" : "+"), afw.isBoolean( AutoFeatures.givePlayerXPAsOrbDrops )) ); + boolean isFoodExhustionEnabled = afw.isBoolean( AutoFeatures.isCalculateFoodExhustion ); + results.add( String.format("%s. Calculate Food Exhustion:&b %s", + (isFoodExhustionEnabled ? "" : "+"), + isFoodExhustionEnabled ) ); + + boolean isCalcAdditionalItemsEnabled = afw.isBoolean( AutoFeatures.isCalculateDropAdditionsEnabled ); + results.add( String.format("%s. Calculate Additional Items in Drop:&b %s (like flint in gravel)", + (isCalcAdditionalItemsEnabled ? "" : "+"), + isCalcAdditionalItemsEnabled ) ); + + @@ -2030,7 +2165,9 @@ public String dumpEventListenersBlockBreakEvents() { sb.append( "&2. . Prison Internal BlockBreakEvents: " + "tech.mcprison.prison.spigot.SpigotListener\n" ); sb.append( "&2. . Auto Feature Core: Non-AutoManager: " + - "OnBlockBreakEventListeners$OnBlockBreakEventListener*\n" ); + "AutoManagerBlockBreakEvents$OnBlockBreakEventListenerNormal\n" ); + sb.append( "&2. . Auto Feature Core: AutoManager: " + + "AutoManagerBlockBreakEvents$AutoManagerBlockBreakEventListener\n" ); sb.append( "&2. . Prison MONITOR Events manages block counts, " + "Mine Sweeper, and zero block conditions.\n" ); sb.append( "&2. . AutoManager and enchantment event listeners are " + @@ -2038,12 +2175,17 @@ public String dumpEventListenersBlockBreakEvents() { sb.append( "\n" ); - AutoManagerCrazyEnchants crazyEnchants = new AutoManagerCrazyEnchants(); - crazyEnchants.dumpEventListeners( sb ); - + // Pulsi_'s plugin: AutoManagerPrisonEnchants prisonEnchants = new AutoManagerPrisonEnchants(); prisonEnchants.dumpEventListeners( sb ); + // Prison's Explosion event. Used by mine bombs. + AutoManagerPrisonsExplosiveBlockBreakEvents prisonExplosiveEnchants = new AutoManagerPrisonsExplosiveBlockBreakEvents(); + prisonExplosiveEnchants.dumpEventListeners( sb ); + + AutoManagerCrazyEnchants crazyEnchants = new AutoManagerCrazyEnchants(); + crazyEnchants.dumpEventListeners( sb ); + AutoManagerTokenEnchant tokenEnchant = new AutoManagerTokenEnchant(); tokenEnchant.dumpEventListeners( sb ); @@ -2077,6 +2219,20 @@ public String dumpEventListenersPlayerChatEvents() { return sb.toString(); } + @Override + public String dumpEventListenersPlayerInteractEvents() { + StringBuilder sb = new StringBuilder(); + + ChatDisplay eventDisplay = dumpEventListenersChatDisplay( + "PlayerInteractEvent", + new SpigotHandlerList( PlayerInteractEvent.getHandlerList()) ); + if ( eventDisplay != null ) { + sb.append( eventDisplay.toStringBuilder() ); + } + + return sb.toString(); + } + /** *

Some information on events... *

@@ -2270,4 +2426,63 @@ public String getRanksListString() { + @Override + public void setTitle( Player player, String title, String subtitle, int fadeIn, int stay, int fadeOut ) { + + if ( player != null ) { + + SpigotPlayer sPlayer = null; + + if ( player instanceof SpigotPlayer ) { + sPlayer = (SpigotPlayer) player; + } + else { + Player p = getPlayer( player.getName() ).orElse( null ); + + if ( p != null ) { + + sPlayer = (SpigotPlayer) p; + } + } + + if ( sPlayer != null ) { + + sPlayer.setTitle( title, subtitle, fadeIn, stay, fadeOut );; + } + + } + } + + + @Override + public void setActionBar( Player player, String actionBar ) { + + if ( player != null ) { + + SpigotPlayer sPlayer = null; + + if ( player instanceof SpigotPlayer ) { + sPlayer = (SpigotPlayer) player; + } + else { + Player p = getPlayer( player.getName() ).orElse( null ); + + if ( p != null ) { + + sPlayer = (SpigotPlayer) p; + } + } + + if ( sPlayer != null ) { + + sPlayer.setActionBar( actionBar ); + } + + } + } + + @Override + public int compareServerVerisonTo( String comparisonVersion ) { + return new BluesSpigetSemVerComparator().compareMCVersionTo( comparisonVersion ); + } } 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 bf39354bc..56ce81571 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 @@ -48,15 +48,18 @@ import tech.mcprison.prison.alerts.Alerts; import tech.mcprison.prison.integration.Integration; import tech.mcprison.prison.internal.block.PrisonBlockTypes; +import tech.mcprison.prison.localization.LocaleManager; import tech.mcprison.prison.mines.PrisonMines; import tech.mcprison.prison.mines.data.Mine; import tech.mcprison.prison.mines.managers.MineManager; import tech.mcprison.prison.modules.Module; import tech.mcprison.prison.modules.ModuleElementType; +import tech.mcprison.prison.modules.PluginEntity; import tech.mcprison.prison.output.ChatDisplay; import tech.mcprison.prison.output.LogLevel; import tech.mcprison.prison.output.Output; import tech.mcprison.prison.ranks.PrisonRanks; +import tech.mcprison.prison.ranks.commands.FailedRankCommands; import tech.mcprison.prison.ranks.data.Rank; import tech.mcprison.prison.ranks.managers.RankManager; import tech.mcprison.prison.spigot.autofeatures.AutoManagerFeatures; @@ -71,10 +74,7 @@ import tech.mcprison.prison.spigot.commands.PrisonSpigotSellAllCommands; import tech.mcprison.prison.spigot.compat.Compatibility; import tech.mcprison.prison.spigot.compat.SpigotCompatibility; -import tech.mcprison.prison.spigot.configs.BackpacksConfig; -import tech.mcprison.prison.spigot.configs.GuiConfig; -import tech.mcprison.prison.spigot.configs.MessagesConfig; -import tech.mcprison.prison.spigot.configs.SellAllConfig; +import tech.mcprison.prison.spigot.configs.*; import tech.mcprison.prison.spigot.customblock.CustomItems; import tech.mcprison.prison.spigot.economies.EssentialsEconomy; import tech.mcprison.prison.spigot.economies.GemsEconomy; @@ -86,6 +86,7 @@ import tech.mcprison.prison.spigot.permissions.VaultPermissions; import tech.mcprison.prison.spigot.placeholder.MVdWPlaceholderIntegration; import tech.mcprison.prison.spigot.placeholder.PlaceHolderAPIIntegration; +import tech.mcprison.prison.spigot.sellall.SellAllUtil; import tech.mcprison.prison.spigot.slime.SlimeBlockFunEventListener; import tech.mcprison.prison.spigot.spiget.BluesSpigetSemVerComparator; import tech.mcprison.prison.spigot.tasks.PrisonInitialStartupTask; @@ -98,7 +99,9 @@ * @author Faizaan A. Datoo * @author GABRYCA */ -public class SpigotPrison extends JavaPlugin { +public class SpigotPrison + extends JavaPlugin + implements PluginEntity { private static SpigotPrison config; @@ -113,7 +116,7 @@ public class SpigotPrison extends JavaPlugin { private AutoManagerFeatures autoFeatures = null; // private FileConfiguration autoFeaturesConfig = null; - + private MessagesConfig messagesConfig; private GuiConfig guiConfig; private SellAllConfig sellAllConfig; @@ -122,7 +125,11 @@ public class SpigotPrison extends JavaPlugin { private PrisonBlockTypes prisonBlockTypes; private static boolean isBackPacksEnabled = false; + private static boolean isSellAllEnabled = false; + + private LocaleManager localeManager; + private File moduleDataFolder; private List registeredBlockListeners; @@ -136,6 +143,7 @@ public SpigotPrison() { config = this; this.registeredBlockListeners = new ArrayList<>(); + } @Override @@ -195,6 +203,9 @@ public void onEnable() { .init(new SpigotPlatform(this), Bukkit.getVersion()); + // Enable the spigot locale manager: + getLocaleManager(); + this.compatibility = SpigotCompatibility.getInstance(); // initCompatibility(); Obsolete... @@ -220,6 +231,16 @@ protected void onEnableDelayedStart() { delayedStartupTask.submit(); } + + public void onEnableFail() { + // Register the failure /ranks command handler: + + FailedRankCommands failedRanksCommands = new FailedRankCommands(); +// rankManager.setFailedRanksCommands( failedRanksCommands ); + Prison.get().getCommandHandler().registerCommands( failedRanksCommands ); + + + } public void onEnableStartup() { @@ -243,6 +264,14 @@ public void onEnableStartup() { Bukkit.getPluginManager().registerEvents(new BackpacksListeners(), this); } + try { + isSellAllEnabled = getConfig().getBoolean("sellall"); + } catch (NullPointerException ignored){} + + if (isSellAllEnabled){ + SellAllUtil.get(); + } + initIntegrations(); @@ -318,6 +347,44 @@ public void onDisable() { Prison.get().deinit(); } + + + + /** + * Lazy load LocalManager which ensures Prison is already loaded so + * can get the default language to use from the plugin configs. + * + * Returns the {@link LocaleManager} for the plugin. This contains the global messages that Prison + * uses to run its command library, and the like. {@link Module}s have their own {@link + * LocaleManager}s, so that each module can have independent localization. + * + * @return The global locale manager instance. + */ + public LocaleManager getLocaleManager() { + + if ( this.localeManager == null ) { + + this.localeManager = new LocaleManager(this, "lang/spigot"); + } + return localeManager; + } + + /** + * Returns this module's data folder, where all data can be stored. + * It is located in the Prison data folder, and has the name of the module. + * It is automatically generated. + * + * @return The {@link File} representing the data folder. + */ + public File getModuleDataFolder() { + + if ( moduleDataFolder == null ) { + this.moduleDataFolder = Module.setupModuleDataFolder( "spigot" ); + } + return moduleDataFolder; + } + + public FileConfiguration getGuiConfig() { if (guiConfig == null) { guiConfig = new GuiConfig(); @@ -330,18 +397,18 @@ public FileConfiguration getSellAllConfig(){ } public FileConfiguration updateSellAllConfig() { - // Let this like this or it wont update when you do /Sellall etc and will need a server restart. + // Let this like this or it won't update when you do /Sellall etc and will need a server restart. sellAllConfig = new SellAllConfig(); sellAllConfig.initialize(); return sellAllConfig.getFileSellAllConfig(); } - public FileConfiguration getMessagesConfig() { + public MessagesConfig getMessagesConfig() { if (messagesConfig == null) { - messagesConfig = new MessagesConfig(); + messagesConfig = MessagesConfig.get(); } - return messagesConfig.getFileGuiMessagesConfig(); + return messagesConfig; } public FileConfiguration getBackpacksConfig() { @@ -364,6 +431,14 @@ public AutoManagerFeatures getAutoFeatures() { return autoFeatures; } + public SellAllUtil getSellAllUtil(){ + return SellAllUtil.get(); + } + + public boolean isSellAllEnabled(){ + return isSellAllEnabled; + } + public void setAutoFeatures( AutoManagerFeatures autoFeatures ) { this.autoFeatures = autoFeatures; } @@ -644,18 +719,18 @@ private void initModulesAndCommands() { // } // Load sellAll if enabled - if (PrisonSpigotSellAllCommands.isEnabled()){ - Prison.get().getCommandHandler().registerCommands(new PrisonSpigotSellAllCommands()); + if (isSellAllEnabled){ + Prison.get().getCommandHandler().registerCommands( new PrisonSpigotSellAllCommands() ); } // Load backpacks commands if enabled if (isBackPacksEnabled){ - Prison.get().getCommandHandler().registerCommands(new PrisonSpigotBackpackCommands()); + Prison.get().getCommandHandler().registerCommands( new PrisonSpigotBackpackCommands() ); } // This registers the admin's /gui commands if (getConfig().getString("prison-gui-enabled").equalsIgnoreCase("true")) { - Prison.get().getCommandHandler().registerCommands(new PrisonSpigotGUICommands()); + Prison.get().getCommandHandler().registerCommands( new PrisonSpigotGUICommands() ); } @@ -664,7 +739,7 @@ private void initModulesAndCommands() { Prison.get().getModuleManager() .registerModule(new PrisonUtilsModule(getDescription().getVersion(), modulesConf)); - Prison.get().getCommandHandler().registerCommands( new PrisonSpigotMinesCommands() ); +// Prison.get().getCommandHandler().registerCommands( new PrisonSpigotMinesCommands() ); } else { Output.get().logInfo("&7Modules: &cPrison Utils are disabled and were not Loaded. "); 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 81293545d..cc817bd44 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 @@ -19,6 +19,7 @@ package tech.mcprison.prison.spigot; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -49,6 +50,7 @@ import tech.mcprison.prison.spigot.block.SpigotBlock; import tech.mcprison.prison.spigot.block.SpigotItemStack; import tech.mcprison.prison.spigot.compat.BlockTestStats; +import tech.mcprison.prison.spigot.compat.SpigotCompatibility; import tech.mcprison.prison.spigot.game.SpigotWorld; import tech.mcprison.prison.spigot.integrations.IntegrationMinepacksPlugin; import tech.mcprison.prison.util.BlockType; @@ -90,7 +92,7 @@ public static XMaterial getXMaterial( String materialName ) { */ public static XMaterial getXMaterial( BlockType prisonBlockType ) { - XMaterial xMat = SpigotPrison.getInstance().getCompatibility() + XMaterial xMat = SpigotCompatibility.getInstance() .getXMaterial( prisonBlockType ); return xMat; @@ -112,7 +114,7 @@ public static Material getMaterial( BlockType prisonBlockType ) { public static BlockType blockToBlockType( Block spigotBlock ) { - BlockType results = SpigotPrison.getInstance().getCompatibility() + BlockType results = SpigotCompatibility.getInstance() .getBlockType( spigotBlock ); // @@ -610,6 +612,20 @@ public static List getAllPlatformBlockTypes() { if ( xMat.isSupported() ) { ItemStack itemStack = xMat.parseItem(); + + if ( xMat.name().toLowerCase().contains( "_wood" ) ) { + + // This validates that XMaterials can map to a Material and back to the correct XMaterial + // Bukkit versions < 1.13.0 fails on _WOOD blocks since XMaterial maps them to logs. + Material bMat = xMat.parseMaterial(); + XMaterial xMatCheck = XMaterial.matchXMaterial( bMat ); + + if ( bMat != null && xMat != xMatCheck ) { + // Incorrect mapping: + continue; + } + } + if ( itemStack != null ) { //if ( itemStack.getType().isBlock() ) @@ -809,7 +825,7 @@ else if ( !xMat.isSupported() ) { } // Next test all of the spigot/bukkit Materials: - BlockTestStats stats = SpigotPrison.getInstance().getCompatibility() + BlockTestStats stats = SpigotCompatibility.getInstance() .testCountAllBlockTypes(); @@ -1010,12 +1026,25 @@ public static ItemStack prisonItemStackToBukkit( public static List getDrops(SpigotBlock block, SpigotItemStack tool) { List ret = new ArrayList<>(); - block.getWrapper().getDrops( tool.getBukkitStack() ) - .forEach(itemStack -> ret.add(SpigotUtil.bukkitItemStackToPrison(itemStack))); + Collection drops = block.getWrapper().getDrops( tool.getBukkitStack() ); + + for ( ItemStack drop : drops ) + { + ret.add( SpigotUtil.bukkitItemStackToPrison(drop) ); + } + +// block.getWrapper().getDrops( tool.getBukkitStack() ) +// .forEach(itemStack -> ret.add(SpigotUtil.bukkitItemStackToPrison(itemStack))); return ret; } + +// public static void clearDrops(SpigotBlock block) { +// +// block.getWrapper().getDrops().clear();; +// } + /* * InventoryType */ diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/api/ExplosiveBlockBreakEvent.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/api/ExplosiveBlockBreakEvent.java index 493030918..6147bebaa 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/api/ExplosiveBlockBreakEvent.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/api/ExplosiveBlockBreakEvent.java @@ -9,6 +9,9 @@ import org.bukkit.event.HandlerList; import org.bukkit.event.block.BlockBreakEvent; +import tech.mcprison.prison.bombs.MineBombData; +import tech.mcprison.prison.internal.ItemStack; + /** *

This is an example of an explosive event that should be used for * enchantments that will break more than one block at a time. @@ -50,15 +53,32 @@ public class ExplosiveBlockBreakEvent private String triggeredBy; + private MineBombData mineBomb; + + /** + * ToolInHand is optional. It should only be used if the player did not directly initiate + * the explosion event with a tool. For example, if they set off a mine bomb, and when the + * explosion event is processed, they won't be holding a tool, but an item instead, or even + * AIR. + */ + private ItemStack toolInHand; + + private boolean forceIfAirBlock = false; + + private boolean calculateDurability = true; + +// private boolean processedSuccessfully = false; + + public ExplosiveBlockBreakEvent( Block theBlock, Player player, - List explodedBlocks, String triggeredBy ) { + List explodedBlocks, String triggeredBy ) { super( theBlock, player ); this.explodedBlocks = explodedBlocks; this.triggeredBy = triggeredBy; } public ExplosiveBlockBreakEvent( Block theBlock, Player player, - List explodedBlocks ) { + List explodedBlocks ) { this( theBlock, player, explodedBlocks, null ); } public ExplosiveBlockBreakEvent( Block theBlock, Player player ) { @@ -103,11 +123,40 @@ public void setTriggeredBy( String triggeredBy ) { this.triggeredBy = triggeredBy; } + public MineBombData getMineBomb() { + return mineBomb; + } + public void setMineBomb( MineBombData mineBomb ) { + this.mineBomb = mineBomb; + } + + public ItemStack getToolInHand() { + return toolInHand; + } + public void setToolInHand( ItemStack toolInHand ) { + this.toolInHand = toolInHand; + } + + public boolean isForceIfAirBlock() { + return forceIfAirBlock; + } + public void setForceIfAirBlock( boolean forceIfAirBlock ) { + this.forceIfAirBlock = forceIfAirBlock; + } + + public boolean isCalculateDurability() { + return calculateDurability; + } + public void setCalculateDurability( boolean calculateDurability ) { + this.calculateDurability = calculateDurability; + } + @Override public HandlerList getHandlers(){ return handlers; } - public static HandlerList getHandlersList(){ + + public static HandlerList getHandlerList(){ return handlers; } } 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 ba5811ce2..627317d97 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 @@ -2,16 +2,19 @@ import java.util.ArrayList; import java.util.List; +import java.util.TreeMap; import org.bukkit.block.Block; import org.bukkit.entity.Player; import org.bukkit.event.HandlerList; import org.bukkit.event.block.BlockBreakEvent; +import tech.mcprison.prison.internal.block.MineTargetPrisonBlock; import tech.mcprison.prison.mines.data.Mine; import tech.mcprison.prison.mines.features.MineBlockEvent.BlockEventType; -import tech.mcprison.prison.mines.features.MineTargetPrisonBlock; import tech.mcprison.prison.spigot.block.SpigotBlock; +import tech.mcprison.prison.spigot.block.SpigotItemStack; +import tech.mcprison.prison.spigot.compat.SpigotCompatibility; import tech.mcprison.prison.spigot.game.SpigotPlayer; /** @@ -57,20 +60,60 @@ public class PrisonMinesBlockBreakEvent private Mine mine; - private SpigotBlock spigotBlock; private SpigotPlayer spigotPlayer; + private SpigotItemStack itemInHand; + + private SpigotBlock spigotBlock; + private MineTargetPrisonBlock targetBlock; + //private SpigotBlock overRideSpigotBlock; private List explodedBlocks; + // The targetBlocks are the blocks that were used to reset the mine with. + // They identify what the blocks were supposed to be. + private List targetExplodedBlocks; + private BlockEventType blockEventType; private String triggered; + + // If this is set during the validation process, and the validation fails, then this it will + // force the canceling of the original block event. private boolean cancelOriginalEvent = false; + + + // This will control if durability is calculated, but only if in the auto features configs + // has the AutoFeatures.isCalculateDurabilityEnabled set to true. If it is set to false + // then this setting will do nothing. + private boolean calculateDurability = true; + + + // The use of forceAutoSell will sell the drops before they are added to the + // player's inventory. This would actually be much faster to process than + // going through the normal sellall functionality since that will have to process + // all of the player's inventory slots, including their backpacks. + private boolean forceAutoSell = false; + + private boolean monitor = false; + + + // blockEventsOnly was intended to be able to run the block events when + // the the AutoManager is disabled. But now, as of 2021-11-23, if + // AutoManager is disabled, then nothing related to auto features, + // including block events will be active. private boolean blockEventsOnly = false; + + // Normally the explosion will ONLY work if the center target block was non-AIR. + // This setting allows the explosion to be processed even if it is air. + private boolean forceIfAirBlock = false; + + + private List bukkitDrops; + private List unprocessedRawBlocks; @@ -84,6 +127,8 @@ public PrisonMinesBlockBreakEvent( Block theBlock, Player player, this.spigotBlock = spigotBlock; this.spigotPlayer = spigotPlayer; + this.itemInHand = SpigotCompatibility.getInstance().getPrisonItemInMainHand( player ); + this.monitor = monitor; this.blockEventsOnly = blockEventsOnly; @@ -91,8 +136,12 @@ public PrisonMinesBlockBreakEvent( Block theBlock, Player player, this.triggered = triggered; this.explodedBlocks = new ArrayList<>(); + this.targetExplodedBlocks = new ArrayList<>(); + this.unprocessedRawBlocks = new ArrayList<>(); + this.bukkitDrops = new ArrayList<>(); + } public PrisonMinesBlockBreakEvent( Block theBlock, Player player, @@ -103,15 +152,21 @@ public PrisonMinesBlockBreakEvent( Block theBlock, Player player, { super( theBlock, player ); - this.mine = mine; this.spigotBlock = spigotBlock; + this.spigotPlayer = new SpigotPlayer( player ); + + this.itemInHand = SpigotCompatibility.getInstance().getPrisonItemInMainHand( player ); + + this.mine = mine; this.explodedBlocks = explodedBlocks; this.blockEventType = blockEventType; + this.targetExplodedBlocks = new ArrayList<>(); + this.triggered = triggered; - //this.overRideSpigotBlock = null; + this.bukkitDrops = new ArrayList<>(); } @@ -163,6 +218,24 @@ public MineTargetPrisonBlock getOriginalTargetBlock( Block bukkitBlock ) { return getOriginalTargetBlock( spigotBlock ); } + + public TreeMap getTargetBlockCounts() { + TreeMap results = new TreeMap<>(); + + if ( getTargetBlock() != null ) { + results.put( getTargetBlock().getPrisonBlock().getBlockName(), 1 ); + } + + for ( MineTargetPrisonBlock targetBlock : getTargetExplodedBlocks() ) + { + String blockName = targetBlock.getPrisonBlock().getBlockName(); + int count = 1 + ( results.containsKey( blockName ) ? results.get( blockName ) : 0) ; + results.put( blockName, count ); + } + + return results; + } + public Mine getMine() { return mine; } @@ -177,6 +250,13 @@ public void setSpigotBlock( SpigotBlock spigotBlock ) { this.spigotBlock = spigotBlock; } + public MineTargetPrisonBlock getTargetBlock() { + return targetBlock; + } + public void setTargetBlock( MineTargetPrisonBlock targetBlock ) { + this.targetBlock = targetBlock; + } + public SpigotPlayer getSpigotPlayer() { return spigotPlayer; } @@ -184,6 +264,13 @@ public void setSpigotPlayer( SpigotPlayer spigotPlayer ) { this.spigotPlayer = spigotPlayer; } + public SpigotItemStack getItemInHand() { + return itemInHand; + } + public void setItemInHand( SpigotItemStack itemInHand ) { + this.itemInHand = itemInHand; + } + public List getExplodedBlocks() { return explodedBlocks; } @@ -191,6 +278,20 @@ public void setExplodedBlocks( List explodedBlocks ) { this.explodedBlocks = explodedBlocks; } + public List getTargetExplodedBlocks() { + return targetExplodedBlocks; + } + public void setTargetExplodedBlocks( List targetBlocks ) { + this.targetExplodedBlocks = targetBlocks; + } + + public List getBukkitDrops() { + return bukkitDrops; + } + public void setBukkitDrops( List drops ) { + this.bukkitDrops = drops; + } + public BlockEventType getBlockEventType() { return blockEventType; } @@ -219,6 +320,20 @@ public void setCancelOriginalEvent( boolean cancelOriginalEvent ) { this.cancelOriginalEvent = cancelOriginalEvent; } + public boolean isCalculateDurability() { + return calculateDurability; + } + public void setCalculateDurability( boolean calculateDurability ) { + this.calculateDurability = calculateDurability; + } + + public boolean isForceAutoSell() { + return forceAutoSell; + } + public void setForceAutoSell( boolean forceAutoSell ) { + this.forceAutoSell = forceAutoSell; + } + public boolean isMonitor() { return monitor; } @@ -240,6 +355,13 @@ public void setUnprocessedRawBlocks( List unprocessedRawBlocks ) { this.unprocessedRawBlocks = unprocessedRawBlocks; } + public boolean isForceIfAirBlock() { + return forceIfAirBlock; + } + public void setForceIfAirBlock( boolean forceIfAirBlock ) { + this.forceIfAirBlock = forceIfAirBlock; + } + @Override public HandlerList getHandlers() { return handlers; diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/api/PrisonMinesBlockEventEvent.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/api/PrisonMinesBlockEventEvent.java index b9face552..1ff0b45cb 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/api/PrisonMinesBlockEventEvent.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/api/PrisonMinesBlockEventEvent.java @@ -6,9 +6,9 @@ import org.bukkit.entity.Player; import org.bukkit.event.HandlerList; +import tech.mcprison.prison.internal.block.MineTargetPrisonBlock; import tech.mcprison.prison.mines.data.Mine; import tech.mcprison.prison.mines.features.MineBlockEvent.BlockEventType; -import tech.mcprison.prison.mines.features.MineTargetPrisonBlock; import tech.mcprison.prison.spigot.block.SpigotBlock; /** 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 496800f69..9347363d9 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 @@ -6,6 +6,7 @@ import java.util.TreeMap; import org.bukkit.Material; +import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.entity.Player; import org.bukkit.event.block.BlockBreakEvent; @@ -18,17 +19,21 @@ import tech.mcprison.prison.mines.managers.MineManager; import tech.mcprison.prison.mines.managers.MineManager.MineSortOrder; import tech.mcprison.prison.modules.Module; +import tech.mcprison.prison.output.Output; import tech.mcprison.prison.ranks.PrisonRanks; import tech.mcprison.prison.ranks.data.Rank; import tech.mcprison.prison.ranks.data.RankPlayer; import tech.mcprison.prison.ranks.managers.PlayerManager; import tech.mcprison.prison.ranks.managers.RankManager; +import tech.mcprison.prison.selection.Selection; import tech.mcprison.prison.spigot.SpigotPrison; import tech.mcprison.prison.spigot.backpacks.BackpacksUtil; import tech.mcprison.prison.spigot.block.SpigotBlock; import tech.mcprison.prison.spigot.game.SpigotPlayer; +import tech.mcprison.prison.spigot.game.SpigotWorld; import tech.mcprison.prison.spigot.sellall.SellAllUtil; import tech.mcprison.prison.util.BlockType; +import tech.mcprison.prison.util.Location; import tech.mcprison.prison.util.MaterialType; /** @@ -163,7 +168,7 @@ public String getPrisonBlockName( String blockName ) { } /** - *

Provides a list of all mines that contains the specfied block. + *

Provides a list of all mines that contains the specified block. *

* * @param prisonBlockName - The prison block name @@ -309,6 +314,71 @@ public Mine getPrisonMine( Player player, Block block, boolean isCanceledEvent) return results; } + /** + *

This creates a prison Location. It must include a valid world, and + * then the x, y, z coordinates. + *

+ * + * @param world + * @param x + * @param y + * @param z + * @return + */ + public Location createLocation( World world, int x, int y, int z ) { + Location results = null; + + if ( world != null ) { + + results = new Location( new SpigotWorld(world), x, y, z ); + } + return results; + } + + /** + *

This creates a mine at the given two coordinates. The provided tag + * value is optional. Minimal checks are performed. This checks to ensure the + * mines module is active, and a mine by the same name does not exist. + *

+ * + * @param mineName + * @param tag + * @param location1 + * @param location2 + * @return + */ + public boolean createMine( String mineName, String tag, + Location location1, Location location2 ) { + boolean results = false; + + if ( mineName != null && tag != null && location1 != null && location2 != null ) { + PrisonMines mm = getPrisonMineManager(); + if ( mm != null ) { + + if ( mm.getMine(mineName) != null) { + + String message = String.format( "Cannot create requested mine. " + + "Mine already exists by the name of '%s'.", + mineName); + Output.get().logError( message ); + + } + else { + Selection selection = new Selection( location1, location2 ); + + Mine mine = new Mine(mineName, selection); + + if ( tag != null ) { + mine.setTag( tag ); + } + + mm.getMineManager().add(mine); + } + } + } + + return results; + } private TreeMap getPlayerCache() { return getPrisonMineManager().getPlayerCache(); @@ -378,7 +448,7 @@ public BackpacksUtil getPrisonBackpacks(){ public SellAllUtil getPrisonSellAll(){ if (sellAll == null){ - sellAll = SellAllUtil.get(); + sellAll = SpigotPrison.getInstance().getSellAllUtil(); } return sellAll; @@ -396,11 +466,11 @@ public SellAllUtil getPrisonSellAll(){ public Double getSellAllMoneyWithMultiplier(Player player){ if (sellAll == null){ - sellAll = SellAllUtil.get(); + sellAll = SpigotPrison.getInstance().getSellAllUtil(); } if (sellAll != null){ - return sellAll.getMoneyWithMultiplier(player, false); + return sellAll.getSellMoney(player); } return null; diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/autofeatures/AutoManagerBreakBlockTask.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/autofeatures/AutoManagerBreakBlockTask.java new file mode 100644 index 000000000..cf6ef2e0c --- /dev/null +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/autofeatures/AutoManagerBreakBlockTask.java @@ -0,0 +1,90 @@ +package tech.mcprison.prison.spigot.autofeatures; + +import java.util.List; + +import tech.mcprison.prison.internal.block.PrisonBlock; +import tech.mcprison.prison.mines.data.Mine; +import tech.mcprison.prison.mines.data.MineStateMutex; +import tech.mcprison.prison.spigot.block.SpigotBlock; +import tech.mcprison.prison.tasks.PrisonRunnable; +import tech.mcprison.prison.tasks.PrisonTaskSubmitter; + +public class AutoManagerBreakBlockTask + implements PrisonRunnable +{ + private SpigotBlock block; + private List blocks; + + private Mine mine; + private MineStateMutex mineStateMutexClone; + + public AutoManagerBreakBlockTask( SpigotBlock block, Mine mine ) { + super(); + + this.block = block; + this.blocks = null; + + this.mine = mine; + + if ( mine != null ) { + this.mineStateMutexClone = mine.getMineStateMutex().clone(); + } + } + + public AutoManagerBreakBlockTask( List blocks, Mine mine ) { + super(); + + this.block = null; + this.blocks = blocks; + + this.mine = mine; + + if ( mine != null ) { + this.mineStateMutexClone = mine.getMineStateMutex().clone(); + } + } + + public static void submitTask( SpigotBlock block, Mine mine ) { + + AutoManagerBreakBlockTask blockTask = new AutoManagerBreakBlockTask( block, mine ); + + PrisonTaskSubmitter.runTaskLater( blockTask, 0 ); + } + + public static void submitTask( List blocks, Mine mine ) { + + AutoManagerBreakBlockTask blockTask = new AutoManagerBreakBlockTask( blocks, mine ); + + PrisonTaskSubmitter.runTaskLater( blockTask, 0 ); + } + + @Override + public void run() { + + if ( mineStateMutexClone != null && + !mine.getMineStateMutex().isValidState( mineStateMutexClone ) ) { + return; + } + +// // Set the broken block to AIR and cancel the event + if ( block != null && !block.isEmpty() ) { + + block.setPrisonBlock( PrisonBlock.AIR ); + } + + if ( blocks != null ) { + int count = 0; + for ( SpigotBlock spigotBlock : blocks ) + { + if ( count++ % 10 == 0 && mineStateMutexClone != null && + !mine.getMineStateMutex().isValidState( mineStateMutexClone ) ) { + return; + } + + spigotBlock.setPrisonBlock( PrisonBlock.AIR ); + + } + } + } + +} 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 6a913240f..c4c12c63d 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 @@ -4,16 +4,15 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map.Entry; import java.util.Random; import java.util.Set; import java.util.TreeMap; -import java.util.UUID; import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.Sound; import org.bukkit.block.Block; -import org.bukkit.configuration.Configuration; import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.ArmorStand; import org.bukkit.entity.EntityType; @@ -23,22 +22,21 @@ import com.cryptomorin.xseries.XMaterial; -import net.md_5.bungee.api.ChatMessageType; -import net.md_5.bungee.api.chat.TextComponent; -import tech.mcprison.prison.Prison; import tech.mcprison.prison.autofeatures.AutoFeaturesFileConfig.AutoFeatures; +import tech.mcprison.prison.cache.PlayerCache; import tech.mcprison.prison.internal.block.PrisonBlock; import tech.mcprison.prison.mines.data.Mine; -import tech.mcprison.prison.mines.features.MineBlockEvent.BlockEventType; import tech.mcprison.prison.output.Output; import tech.mcprison.prison.output.Output.DebugTarget; import tech.mcprison.prison.spigot.SpigotPrison; import tech.mcprison.prison.spigot.SpigotUtil; +import tech.mcprison.prison.spigot.api.PrisonMinesBlockBreakEvent; import tech.mcprison.prison.spigot.block.OnBlockBreakEventCore; import tech.mcprison.prison.spigot.block.SpigotBlock; import tech.mcprison.prison.spigot.block.SpigotItemStack; -import tech.mcprison.prison.spigot.commands.PrisonSpigotSellAllCommands; +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.spiget.BluesSpigetSemVerComparator; import tech.mcprison.prison.util.BlockType; import tech.mcprison.prison.util.Text; @@ -144,7 +142,7 @@ protected short getFortune(SpigotItemStack itemInHand){ } int maxFortuneLevel = getInteger( AutoFeatures.fortuneMultiplierMax ); - if ( maxFortuneLevel != 0 && results > maxFortuneLevel ) { + if ( maxFortuneLevel > 0 && results > maxFortuneLevel ) { results = (short) maxFortuneLevel; } @@ -154,11 +152,11 @@ protected short getFortune(SpigotItemStack itemInHand){ - @Override - public boolean doAction( SpigotBlock block, Mine mine, Player player, StringBuilder debugInfo ) { - - return processAutoEvents( block, player, mine, debugInfo ); - } +// @Override +// public boolean doAction( PrisonMinesBlockBreakEvent pmEvent, StringBuilder debugInfo ) { +// +// return processAutoEvents( pmEvent, debugInfo ); +// } /** @@ -168,50 +166,51 @@ public boolean doAction( SpigotBlock block, Mine mine, Player player, StringBuil * */ @Override - public boolean doAction( Mine mine, Player player, List explodedBlocks, - BlockEventType blockEventType, String triggered, - StringBuilder debugInfo ) { - return applyAutoEvents( player, mine, explodedBlocks, blockEventType, triggered, debugInfo ); + public boolean doAction( PrisonMinesBlockBreakEvent pmEvent, StringBuilder debugInfo ) { + return applyAutoEvents( pmEvent, debugInfo ); } - private boolean processAutoEvents( SpigotBlock spigotBlock, Player player, Mine mine, StringBuilder debugInfo ) { - boolean cancel = false; - - if (isBoolean(AutoFeatures.isAutoManagerEnabled) && !spigotBlock.isEmpty() ) { - - debugInfo.append( "(processAutoEvent) " ); - -// Output.get().logInfo( "#### AutoManager.applyAutoEvents: BlockBreakEvent: :: " + mine.getName() + " " + -// " blocks remaining= " + -// mine.getRemainingBlockCount() + " [" + block.toString() + "]" -// ); - - SpigotItemStack itemInHand = SpigotPrison.getInstance().getCompatibility().getPrisonItemInMainHand( player ); - - int count = applyAutoEvents( player, spigotBlock, mine, debugInfo ); - - if ( count > 0 ) { - processBlockBreakage( spigotBlock, mine, player, count, BlockEventType.blockBreak, - null, itemInHand, true, debugInfo ); - - cancel = true; - } - - checkZeroBlockReset( mine ); - - } - - return cancel; - } +// private boolean processAutoEvents( PrisonMinesBlockBreakEvent pmEvent, StringBuilder debugInfo ) { +// boolean cancel = false; +// +// if (isBoolean(AutoFeatures.isAutoManagerEnabled) && !pmEvent.getSpigotBlock().isEmpty() ) { +// +// +// debugInfo.append( "(doAction autoManager processAutoEvent single-block) "); +// +// +//// Output.get().logInfo( "#### AutoManager.applyAutoEvents: BlockBreakEvent: :: " + mine.getName() + " " + +//// " blocks remaining= " + +//// mine.getRemainingBlockCount() + " [" + block.toString() + "]" +//// ); +// +// +// int count = applyAutoEventsDetails( pmEvent, debugInfo ); +// +// if ( count > 0 ) { +// processBlockBreakage( pmEvent, count, true, debugInfo ); +// +// cancel = true; +// } +// +// checkZeroBlockReset( pmEvent.getMine() ); +// +// } +// +// return cancel; +// } - private int applyAutoEvents( Player player, SpigotBlock block, Mine mine, StringBuilder debugInfo ) { + private int applyAutoEventsDetails( PrisonMinesBlockBreakEvent pmEvent, StringBuilder debugInfo ) { int count = 0; - SpigotItemStack itemInHand = SpigotPrison.getInstance().getCompatibility().getPrisonItemInMainHand( player ); + Player player = pmEvent.getPlayer(); + Mine mine = pmEvent.getMine(); + + SpigotItemStack itemInHand = SpigotCompatibility.getInstance().getPrisonItemInMainHand( player ); boolean isLoreEnabled = isBoolean( AutoFeatures.isLoreEnabled ); @@ -247,7 +246,7 @@ private int applyAutoEvents( Player player, SpigotBlock block, Mine mine, String if ( Output.get().isDebug( DebugTarget.blockBreak ) ) { debugInfo.append( "(applyAutoEvents: " ) - .append( block.getBlockName() ) + .append( pmEvent.getSpigotBlock().getBlockName() ) .append( " Pickup [") .append( isAutoPickup ? "enabled: " : "disabled:" ) @@ -284,7 +283,8 @@ private int applyAutoEvents( Player player, SpigotBlock block, Mine mine, String if ( (mine != null || mine == null && !isBoolean( AutoFeatures.pickupLimitToMines )) && isAutoPickup ) { - count = autoFeaturePickup( block, player, itemInHand, isAutoSmelt, isAutoBlock, debugInfo ); + count = autoFeaturePickup( pmEvent, isAutoSmelt, isAutoBlock, debugInfo ); +// count = autoFeaturePickup( pmEvent.getSpigotBlock(), player, itemInHand, isAutoSmelt, isAutoBlock, debugInfo ); // Cannot set to air yet, or auto smelt and auto block will only get AIR: // autoPickupCleanup( block, count ); @@ -325,13 +325,13 @@ private int applyAutoEvents( Player player, SpigotBlock block, Mine mine, String - // AutoPickup - Clean up (set block to air) - if ( (mine != null || mine == null && !isBoolean( AutoFeatures.pickupLimitToMines )) && - isAutoPickup ) { - - autoPickupCleanup( block, count ); - - } +// // AutoPickup - Clean up (set block to air) +// if ( (mine != null || mine == null && !isBoolean( AutoFeatures.pickupLimitToMines )) && +// isAutoPickup ) { +// +// autoPickupCleanup( pmEvent.getSpigotBlock(), count ); +// +// } return count; @@ -361,46 +361,47 @@ private int applyAutoEvents( Player player, SpigotBlock block, Mine mine, String * @param e * @param mine */ - private boolean applyAutoEvents( Player player, Mine mine, - List explodedBlocks, BlockEventType blockEventType, - String triggered, StringBuilder debugInfo ) { - boolean cancel = false; + private boolean applyAutoEvents( PrisonMinesBlockBreakEvent pmEvent, StringBuilder debugInfo ) { +// boolean success = false; - int totalCount = 0; + int totalDrops = applyAutoEventsDetails( pmEvent, debugInfo ); - SpigotItemStack itemInHand = SpigotPrison.getInstance().getCompatibility() - .getPrisonItemInMainHand( player ); + debugInfo.append( "(autoEvents totalDropa: " + totalDrops + ") "); - debugInfo.append( "(applyAutoEvents multi-blocks: " + explodedBlocks.size() ); - - // The explodedBlocks list have already been validated as being within the mine: - boolean applyExhaustion = true; - for ( SpigotBlock spigotBlock : explodedBlocks ) { - - if ( spigotBlock != null && !spigotBlock.isEmpty() ) { - - int drop = applyAutoEvents( player, spigotBlock, mine, debugInfo ); - totalCount += drop; - - if ( drop > 0 ) { - - processBlockBreakage( spigotBlock, mine, player, drop, - blockEventType, triggered, itemInHand, - applyExhaustion, debugInfo ); - applyExhaustion = false; - } - } - } + return applyDropsBlockBreakage( pmEvent, totalDrops, debugInfo ); - if ( mine != null ) { - checkZeroBlockReset( mine ); - } - - if ( totalCount > 0 ) { - cancel = true; - } - - return cancel; +// debugInfo.append( "(doAction autoManager applyAutoEvents multi-blocks: " + pmEvent.getExplodedBlocks().size() + ") "); +// +// +// // The explodedBlocks list have already been validated as being within the mine: +// boolean applyExhaustion = true; +// +// // First process the block that was hit by the player: +// if ( pmEvent.getTargetBlock() != null ) { +// +// processBlockBreakage( pmEvent, pmEvent.getTargetBlock(), 1, applyExhaustion, debugInfo ); +// applyExhaustion = false; +// +// } +// +// // Then process all of the other blocks that were included in the explosion event, if there was one: +// for ( MineTargetPrisonBlock targetBlock : pmEvent.getTargetExplodedBlocks() ) +// { +// +// processBlockBreakage( pmEvent, targetBlock, 1, applyExhaustion, debugInfo ); +// } +// +// autosellPerBlockBreak( pmEvent.getPlayer() ); +// +// if ( pmEvent.getMine() != null ) { +// checkZeroBlockReset( pmEvent.getMine() ); +// } +// +// if ( totalDrops > 0 ) { +// success = true; +// } +// +// return success; } @@ -412,19 +413,32 @@ private boolean applyAutoEvents( Player player, Mine mine, * For older versions, a good way to get the right drops would be to use * BlockDropItemEvent.getItems(), but it's deprecated * */ - protected int autoPickup( Player player, - SpigotItemStack itemInHand, SpigotBlock block, + protected int autoPickup( PrisonMinesBlockBreakEvent pmEvent, boolean isAutoSmelt, boolean isAutoBlock, StringBuilder debugInfo ) { //, BlockBreakEvent e ) { int count = 0; + Player player = pmEvent.getPlayer(); + SpigotItemStack itemInHand = pmEvent.getItemInHand(); +// SpigotBlock block = pmEvent.getSpigotBlock(); + List drops = pmEvent.getBukkitDrops(); + // The following may not be the correct drops for all versions of spigot, // plus there are some extra items, such as flint, that will never be dropped. - List drops = new ArrayList<>( SpigotUtil.getDrops(block, itemInHand) ); +// List drops = new ArrayList<>( SpigotUtil.getDrops(block, itemInHand) ); + + + // This clears the drops for the given block, so if the event is not canceled, it will + // not result in duplicate drops. +// if ( isBoolean( AutoFeatures.cancelAllBlockEventBlockDrops ) ) { +// block.clearDrops(); +// } if (drops != null && drops.size() > 0 ) { + debugInfo.append( "[autoPickupDrops]" ); + // Need better drop calculation that is not using the getDrops function. calculateSilkTouch( itemInHand, drops ); @@ -465,19 +479,108 @@ protected int autoPickup( Player player, normalDropBlock( drops ); } + String mineName = pmEvent.getMine() == null ? null : pmEvent.getMine().getName(); + + // PlayerCache log block breaks: + TreeMap targetBlockCounts = pmEvent.getTargetBlockCounts(); + for ( Entry targetBlockCount : targetBlockCounts.entrySet() ) + { + + PlayerCache.getInstance().addPlayerBlocks( pmEvent.getSpigotPlayer(), mineName, + targetBlockCount.getKey(), targetBlockCount.getValue().intValue() ); + } + + + + double autosellTotal = 0; + double autosellUnsellableCount = 0; for ( SpigotItemStack itemStack : drops ) { count += itemStack.getAmount(); - HashMap extras = SpigotUtil.addItemToPlayerInventory( player, itemStack ); + + // Try to autosell if enabled: + if ( SellAllUtil.get() != null && (isBoolean(AutoFeatures.isAutoSellPerBlockBreakEnabled) || + pmEvent.isForceAutoSell()) ) { + + double amount = SellAllUtil.get().sellAllSell( player, itemStack, false, false, true ); + autosellTotal += amount; + + PlayerCache.getInstance().addPlayerEarnings( pmEvent.getSpigotPlayer(), + amount, mineName ); + + if ( amount != 0 ) { + debugInfo.append( "(sold: " + itemStack.getName() + " qty: " + itemStack.getAmount() + " value: " + amount + ") "); + + // Set to zero quantity since they have all been sold. + itemStack.setAmount( 0 ); + } + else { + + // Unable to sell since amount was zero. Not configured to be sold. + debugInfo.append( "(unsellable: " + itemStack.getName() + " qty: " + itemStack.getAmount() + ") "); + autosellUnsellableCount += itemStack.getAmount(); + } + + } + - dropExtra( extras, player ); + + // Add blocks to player's inventory IF autosell was unable to sell the item stack, hence + // it will have an amount of more than 0. + if ( itemStack.getAmount() > 0 ) { + + if ( Output.get().isDebug() && SellAllUtil.get() != null ) { + + // Just get the calculated value for the drops... do not sell: + double amount = SellAllUtil.get().sellAllSell( player, itemStack, true, false, false ); + autosellTotal += amount; + + debugInfo.append( "(keeping: " + itemStack.getName() + " qty: " + itemStack.getAmount() + " value: " + amount + ") "); + } + + HashMap extras = SpigotUtil.addItemToPlayerInventory( player, itemStack ); + + + // Warning: The following is now obsolete since there is now a sellall function that will sell on a + // per SpigotItemStack so it eliminates a ton of overhead. It also supports thousands of + // items per stack. + +// if ( extras.size() > 0 && autosellPerBlockBreak( player ) ) { +// +// // Try to add the extras back to the player's inventory if they had autosellPerBlockBrean enabled: +// for ( SpigotItemStack extraItemStack : extras.values() ) { +// +// HashMap extras2 = SpigotUtil.addItemToPlayerInventory( player, extraItemStack ); +// +// autosellPerBlockBreak( player ); +// +// // If the remainder of the extras still as too much, then just drop them and move on: +// dropExtra( extras2, player ); +// } +// extras.clear(); +// } + + dropExtra( extras, player ); // dropExtra( player.getInventory().addItem(itemStack), player, block ); + } + + + } + + if ( count > 0 || autosellTotal > 0 ) { + + debugInfo.append( "[autoPickupDrops total: qty: " + count + " value: " + autosellTotal + + " unsellableCount: " + autosellUnsellableCount + " ] "); } - autosellPerBlockBreak( player ); +// if ( !isBoolean(AutoFeatures.isAutoSellPerBlockBreakEnabled) && +// !pmEvent.isForceAutoSell() ) { +// +// autosellPerBlockBreak( player ); +// } // autoPickupCleanup( player, itemInHand, count ); } @@ -489,23 +592,37 @@ protected int autoPickup( Player player, - public int calculateNormalDrop( SpigotItemStack itemInHand, SpigotBlock block ) { + public int calculateNormalDrop( PrisonMinesBlockBreakEvent pmEvent, StringBuilder debugInfo ) { + + // Count should be the total number of items that are to be "dropped". + // So effectively it will be the sum of all bukkitDrops counts. int count = 0; - // The following may not be the correct drops for all versions of spigot, - // plus there are some extra items, such as flint, that will never be dropped. - List drops = new ArrayList<>( SpigotUtil.getDrops(block, itemInHand) ); - - +// // The following may not be the correct drops for all versions of spigot, +// // plus there are some extra items, such as flint, that will never be dropped. +// List drops = new ArrayList<>( SpigotUtil.getDrops(block, itemInHand) ); +// +// +// // This clears the drops for the given block, so if the event is not canceled, it will +// // not result in duplicate drops. +// if ( isBoolean( AutoFeatures.cancelAllBlockEventBlockDrops ) ) { +// block.clearDrops(); +// } + + List drops = pmEvent.getBukkitDrops(); + + if (drops != null && drops.size() > 0 ) { + + debugInfo.append( "[normalDrops]" ); // Need better drop calculation that is not using the getDrops function. - short fortuneLevel = getFortune(itemInHand); + short fortuneLevel = getFortune( pmEvent.getItemInHand() ); - calculateSilkTouch( itemInHand, drops ); + calculateSilkTouch( pmEvent.getItemInHand(), drops ); // Adds in additional drop items: Add Flint with gravel drops: - calculateDropAdditions( itemInHand, drops ); + calculateDropAdditions( pmEvent.getItemInHand(), drops ); if ( isBoolean( AutoFeatures.isCalculateFortuneEnabled ) ) { @@ -535,168 +652,216 @@ public int calculateNormalDrop( SpigotItemStack itemInHand, SpigotBlock block ) } - // Drop the items where the origional block was located: + String mineName = pmEvent.getMine() == null ? null : pmEvent.getMine().getName(); + + // PlayerCache log block breaks: + TreeMap targetBlockCounts = pmEvent.getTargetBlockCounts(); + for ( Entry targetBlockCount : targetBlockCounts.entrySet() ) + { + + PlayerCache.getInstance().addPlayerBlocks( pmEvent.getSpigotPlayer(), mineName, + targetBlockCount.getKey(), targetBlockCount.getValue().intValue() ); + } + + + + double autosellTotal = 0; + + // Drop the items where the original block was located: for ( SpigotItemStack itemStack : drops ) { count += itemStack.getAmount(); - dropAtBlock( itemStack, block ); + // Since this is not auto pickup, then only autosell if set in the pmEvent: + if ( pmEvent.isForceAutoSell() ) { + + Player player = pmEvent.getPlayer(); + + double amount = SellAllUtil.get().sellAllSell( player, itemStack, false, false, true ); + autosellTotal += amount; + + if ( amount != 0 ) { + debugInfo.append( "(sold: " + itemStack.getName() + " qty: " + itemStack.getAmount() + " value: " + amount + ") "); + + // Set to zero quantity since they have all been sold. + itemStack.setAmount( 0 ); + } + + } + + if ( itemStack.getAmount() != 0 ) { + + if ( Output.get().isDebug() ) { + + // Just get the calculated value for the drops... do not sell: + Player player = pmEvent.getPlayer(); + + double amount = SellAllUtil.get().sellAllSell( player, itemStack, true, false, false ); + autosellTotal += amount; + + debugInfo.append( "(adding: " + itemStack.getName() + " qty: " + itemStack.getAmount() + " value: " + amount + ") "); + } + + dropAtBlock( itemStack, pmEvent.getSpigotBlock() ); + } + + } - // Break the block and change it to air: - block.setPrisonBlock( PrisonBlock.AIR );; + if ( count > 0 || autosellTotal > 0 ) { + + debugInfo.append( "[normalDrops total: qty: " + count + " value: " + autosellTotal + ") "); + + } + + +// // Break the block and change it to air: +// if ( !pmEvent.getSpigotBlock().isEmpty() ) { +// +// if ( isBoolean( AutoFeatures.applyBlockBreaksThroughSyncTask ) ) { +// +// AutoManagerBreakBlockTask.submitTask( pmEvent.getSpigotBlock() ); +// } +// else { +// +// pmEvent.getSpigotBlock().setPrisonBlock( PrisonBlock.AIR ); +// } +// +// } } return count; } - - public void autosellPerBlockBreak( Player player ) { - // This won't try to sell on every item stack, but assuming that sellall will hit on very block - // break, then the odds of inventory being overflowed on one explosion would be more rare than anything - if ( isBoolean( AutoFeatures.isAutoSellPerBlockBreakEnabled ) ) { - // Run sell all - if ( isBoolean( AutoFeatures.isAutoSellPerBlockBreakInlinedEnabled ) ) { - // run sellall inline with the block break event: - if (PrisonSpigotSellAllCommands.get() != null) { - PrisonSpigotSellAllCommands.get().sellAllSellWithDelayCommand(new SpigotPlayer(player)); - } - } - else { - // Submit sellall to run in the future (0 ticks in the future): - String registeredCmd = Prison.get().getCommandHandler().findRegisteredCommand( "sellall sell silent" ); - Bukkit.dispatchCommand(player, registeredCmd); - } - } - } - - public void playerSmelt( SpigotPlayer player ) { - - List smelts = new ArrayList<>(); - - smelts.add( XMaterial.COBBLESTONE ); - smelts.add( XMaterial.GOLD_ORE ); - smelts.add( XMaterial.NETHER_GOLD_ORE ); - smelts.add( XMaterial.DEEPSLATE_GOLD_ORE ); - smelts.add( XMaterial.RAW_GOLD ); - - smelts.add( XMaterial.IRON_ORE ); - smelts.add( XMaterial.DEEPSLATE_IRON_ORE ); - smelts.add( XMaterial.RAW_IRON ); - - smelts.add( XMaterial.COAL_ORE ); - smelts.add( XMaterial.DEEPSLATE_COAL_ORE ); - - smelts.add( XMaterial.DIAMOND_ORE ); - smelts.add( XMaterial.DEEPSLATE_DIAMOND_ORE ); - - smelts.add( XMaterial.EMERALD_ORE ); - smelts.add( XMaterial.DEEPSLATE_EMERALD_ORE ); - - smelts.add( XMaterial.LAPIS_ORE ); - smelts.add( XMaterial.DEEPSLATE_LAPIS_ORE ); - - smelts.add( XMaterial.REDSTONE_ORE ); - smelts.add( XMaterial.DEEPSLATE_REDSTONE_ORE ); - - smelts.add( XMaterial.NETHER_QUARTZ_ORE ); - smelts.add( XMaterial.ANCIENT_DEBRIS ); - - smelts.add( XMaterial.COPPER_ORE ); - smelts.add( XMaterial.DEEPSLATE_COPPER_ORE ); - smelts.add( XMaterial.RAW_COPPER ); - - - for ( XMaterial xMat : smelts ) { - autoFeatureSmelt( player.getWrapper(), xMat ); - } - } - public void playerBlock( SpigotPlayer player ) { - - List blocks = new ArrayList<>(); - - blocks.add( XMaterial.GOLD_INGOT ); - blocks.add( XMaterial.IRON_INGOT ); - blocks.add( XMaterial.COAL ); - blocks.add( XMaterial.DIAMOND ); - blocks.add( XMaterial.REDSTONE ); - blocks.add( XMaterial.EMERALD ); - blocks.add( XMaterial.QUARTZ ); - blocks.add( XMaterial.PRISMARINE_SHARD ); - blocks.add( XMaterial.SNOW_BLOCK ); - blocks.add( XMaterial.GLOWSTONE_DUST ); - blocks.add( XMaterial.LAPIS_LAZULI ); - - - for ( XMaterial xMat : blocks ) { - autoFeatureBlock( player.getWrapper(), xMat ); - } - - } +// public void playerSmelt( SpigotPlayer player ) { +// +// List smelts = new ArrayList<>(); +// +// smelts.add( XMaterial.COBBLESTONE ); +// smelts.add( XMaterial.GOLD_ORE ); +// smelts.add( XMaterial.NETHER_GOLD_ORE ); +// smelts.add( XMaterial.DEEPSLATE_GOLD_ORE ); +// smelts.add( XMaterial.RAW_GOLD ); +// +// smelts.add( XMaterial.IRON_ORE ); +// smelts.add( XMaterial.DEEPSLATE_IRON_ORE ); +// smelts.add( XMaterial.RAW_IRON ); +// +// smelts.add( XMaterial.COAL_ORE ); +// smelts.add( XMaterial.DEEPSLATE_COAL_ORE ); +// +// smelts.add( XMaterial.DIAMOND_ORE ); +// smelts.add( XMaterial.DEEPSLATE_DIAMOND_ORE ); +// +// smelts.add( XMaterial.EMERALD_ORE ); +// smelts.add( XMaterial.DEEPSLATE_EMERALD_ORE ); +// +// smelts.add( XMaterial.LAPIS_ORE ); +// smelts.add( XMaterial.DEEPSLATE_LAPIS_ORE ); +// +// smelts.add( XMaterial.REDSTONE_ORE ); +// smelts.add( XMaterial.DEEPSLATE_REDSTONE_ORE ); +// +// smelts.add( XMaterial.NETHER_QUARTZ_ORE ); +// smelts.add( XMaterial.ANCIENT_DEBRIS ); +// +// smelts.add( XMaterial.COPPER_ORE ); +// smelts.add( XMaterial.DEEPSLATE_COPPER_ORE ); +// smelts.add( XMaterial.RAW_COPPER ); +// +// +// for ( XMaterial xMat : smelts ) { +// autoFeatureSmelt( player.getWrapper(), xMat ); +// } +// +// } - /** - *

The List of drops must have only one ItemStack per block type (name). - * This function combines multiple occurrences together and adds up their - * counts to properly represent the total quantity in the original drops collection - * that had duplicate entries. - *

- * - * @param List of SpigotItemStack drops with duplicate entries - * @return List of SpigotItemStack drops without duplicates - */ - private List mergeDrops( List drops ) - { - TreeMap results = new TreeMap<>(); - - for ( SpigotItemStack drop : drops ) { - String key = drop.getName(); - if ( !results.containsKey( key ) ) { - results.put( key, drop ); - } - else { - SpigotItemStack sItemStack = results.get( key ); - - sItemStack.setAmount( sItemStack.getAmount() + drop.getAmount() ); - } - } - - return new ArrayList<>( results.values() ); - } - +// public void playerBlock( SpigotPlayer player ) { +// +// List blocks = new ArrayList<>(); +// +// blocks.add( XMaterial.GOLD_INGOT ); +// blocks.add( XMaterial.IRON_INGOT ); +// blocks.add( XMaterial.COAL ); +// blocks.add( XMaterial.DIAMOND ); +// blocks.add( XMaterial.REDSTONE ); +// blocks.add( XMaterial.EMERALD ); +// blocks.add( XMaterial.QUARTZ ); +// blocks.add( XMaterial.PRISMARINE_SHARD ); +// blocks.add( XMaterial.SNOW_BLOCK ); +// blocks.add( XMaterial.GLOWSTONE_DUST ); +// blocks.add( XMaterial.LAPIS_LAZULI ); +// +// +// for ( XMaterial xMat : blocks ) { +// autoFeatureBlock( player.getWrapper(), xMat ); +// } +// +// } + +// /** +// *

The List of drops must have only one ItemStack per block type (name). +// * This function combines multiple occurrences together and adds up their +// * counts to properly represent the total quantity in the original drops collection +// * that had duplicate entries. +// *

+// * +// * @param List of SpigotItemStack drops with duplicate entries +// * @return List of SpigotItemStack drops without duplicates +// */ +// private List mergeDrops( List drops ) +// { +// TreeMap results = new TreeMap<>(); +// +// for ( SpigotItemStack drop : drops ) { +// String key = drop.getName(); +// if ( !results.containsKey( key ) ) { +// results.put( key, drop ); +// } +// else { +// SpigotItemStack sItemStack = results.get( key ); +// +// sItemStack.setAmount( sItemStack.getAmount() + drop.getAmount() ); +// } +// } +// +// return new ArrayList<>( results.values() ); +// } - protected void autoPickupCleanup( SpigotBlock block, int count ) - { - // Auto pickup has been successful. Now clean up. - if ( count > 0 ) { -// // Set the broken block to AIR and cancel the event - if ( !block.isEmpty() ) { - block.setPrisonBlock( PrisonBlock.AIR ); - } - - } - } +// protected void autoPickupCleanupX( SpigotBlock block, int count ) +// { +// // Auto pickup has been successful. Now clean up. +// if ( count > 0 ) { +// +// +//// // Set the broken block to AIR and cancel the event +// if ( !block.isEmpty() ) { +// +// if ( isBoolean( AutoFeatures.applyBlockBreaksThroughSyncTask ) ) { +// +// // submit a task to change the block to air: +// AutoManagerBreakBlockTask.submitTask( block ); +// } +// +// else { +// +// block.setPrisonBlock( PrisonBlock.AIR ); +// } +// } +// +// } +// } - public void checkZeroBlockReset( Mine mine ) { - if ( mine != null ) { - - // submit a mine sweeper task. It will only run if it is enabled and another - // mine sweeper task has not been submitted. - mine.submitMineSweeperTask(); - - // Checks to see if the mine ran out of blocks, and if it did, then - // it will reset the mine: - mine.checkZeroBlockReset(); - } - } + protected boolean checkLore( SpigotItemStack itemInHand, String loreValue ) { boolean results = false; @@ -711,31 +876,31 @@ protected boolean checkLore( SpigotItemStack itemInHand, String loreValue ) { } - - protected void autoSmelt( boolean autoSmelt, XMaterial source, XMaterial target, Player p ) { - - if ( autoSmelt && source != null && target != null ) { - - HashMap overflow = SpigotUtil.itemStackReplaceItems( p, source, target, 1 ); - dropExtra( overflow, p ); - - } - } - - - protected void autoBlock( boolean autoBlock, XMaterial source, XMaterial target, Player p ) { - autoBlock(autoBlock, source, target, 9, p ); - } - - - protected void autoBlock( boolean autoBlock, XMaterial source, XMaterial target, int ratio, Player p ) { - - if ( autoBlock && source != null && target != null ) { - HashMap overflow = SpigotUtil.itemStackReplaceItems( p, source, target, ratio ); - dropExtra( overflow, p ); - - } - } +// +// protected void autoSmelt( boolean autoSmelt, XMaterial source, XMaterial target, Player p ) { +// +// if ( autoSmelt && source != null && target != null ) { +// +// HashMap overflow = SpigotUtil.itemStackReplaceItems( p, source, target, 1 ); +// dropExtra( overflow, p ); +// +// } +// } +// +// +// protected void autoBlock( boolean autoBlock, XMaterial source, XMaterial target, Player p ) { +// autoBlock(autoBlock, source, target, 9, p ); +// } +// +// +// protected void autoBlock( boolean autoBlock, XMaterial source, XMaterial target, int ratio, Player p ) { +// +// if ( autoBlock && source != null && target != null ) { +// HashMap overflow = SpigotUtil.itemStackReplaceItems( p, source, target, ratio ); +// dropExtra( overflow, p ); +// +// } +// } @@ -747,72 +912,89 @@ protected void autoBlock( boolean autoBlock, XMaterial source, XMaterial target, * @param player * @param block */ - private void dropExtra( HashMap extra, Player player ) { - - if ( extra != null && extra.size() > 0 ) { + protected void dropExtra( HashMap extra, Player player ) { + if ( extra != null && extra.size() > 0 && SpigotPrison.getInstance().isSellAllEnabled()) { + + SellAllUtil sellAllUtil = SellAllUtil.get(); - Configuration sellAllConfig = SpigotPrison.getInstance().updateSellAllConfig(); - - if ( isBoolean( sellAllConfig, "Options.Full_Inv_AutoSell") ) { - if ( isBoolean( sellAllConfig, "Options.Full_Inv_AutoSell_perUserToggleable") ){ - - UUID playerUUID = player.getUniqueId(); - - if (isBoolean( sellAllConfig, "Users." + playerUUID + ".isEnabled") ) { - - if (isBoolean( sellAllConfig, "Options.Full_Inv_AutoSell_Notification") ) { - Output.get().sendInfo(new SpigotPlayer(player), SpigotPrison.format( - SpigotPrison.getInstance().getMessagesConfig().getString("Message.SellAllAutoSell"))); - } - - PrisonSpigotSellAllCommands.get().sellAllSellCommand( new SpigotPlayer( player ), "" ); - -// String registeredCmd = Prison.get().getCommandHandler().findRegisteredCommand( "sellall sell" ); -// Bukkit.dispatchCommand(player, registeredCmd); -// return; - } - } else { - if (isBoolean( sellAllConfig, "Options.Full_Inv_AutoSell_Notification") ) { - Output.get().sendInfo(new SpigotPlayer(player), SpigotPrison.format( - SpigotPrison.getInstance().getMessagesConfig().getString("Message.SellAllAutoSell"))); - } - PrisonSpigotSellAllCommands.get().sellAllSellCommand( new SpigotPlayer( player ), "" ); -// String registeredCmd = Prison.get().getCommandHandler().findRegisteredCommand( "sellall sell" ); -// Bukkit.dispatchCommand(player, registeredCmd); -// return; + // On inventory is full, will auto sell if auto sell is enabled in either + // the sellall configs, or the auto feature configs. + if (sellAllUtil != null && ( + sellAllUtil.isAutoSellEnabled || + isBoolean(AutoFeatures.isAutoSellIfInventoryIsFull) )) { + + + if ( !sellAllUtil.isAutoSellPerUserToggleable || + sellAllUtil.isAutoSellPerUserToggleable && sellAllUtil.isPlayerAutoSellEnabled(player) ) { + + boolean saNote = sellAllUtil.isAutoSellNotificationEnabled; + SellAllUtil.get().sellAllSell(player, false, !saNote, saNote, saNote, false, true); } - // Now that something might have been sold, try to add all the extra inventory items back to the - // player's inventory so it is not lost then pass the moreExtras along to be handled as the + +// if (sellAllUtil.isAutoSellPerUserToggleable) { +// if (sellAllUtil.isPlayerAutoSellEnabled(player)) { +// if (sellAllUtil.isAutoSellNotificationEnabled) { +// SellAllUtil.get().sellAllSell(player, false, false, true, true, false, true); +// } else { +// SellAllUtil.get().sellAllSell(player, false, true, false, false, false, true); +// } +// } +// } else { +// if (sellAllUtil.isAutoSellNotificationEnabled) { +// SellAllUtil.get().sellAllSell(player, false, false, true, true, false, true); +// } else { +// SellAllUtil.get().sellAllSell(player, false, true, false, false, false, true); +// } +// } + + // Now that something might have been sold, try to add all the extra inventory items back to the + // player's inventory so it is not lost then pass the moreExtras along to be handled as the // configurations require. HashMap moreExtras = new HashMap<>(); - for ( SpigotItemStack itemStack : extra.values() ) { - moreExtras.putAll( SpigotUtil.addItemToPlayerInventory( player, itemStack )); + for (SpigotItemStack itemStack : extra.values()) { + moreExtras.putAll(SpigotUtil.addItemToPlayerInventory(player, itemStack)); } extra = moreExtras; } - for ( SpigotItemStack itemStack : extra.values() ) { + + // drop the player's items if they should be dropped. Also check to see if + // the player should be notified. Ignore zero count itemStacks. + boolean needToNotify = false; + for (SpigotItemStack itemStack : extra.values()) { - if ( isBoolean( AutoFeatures.dropItemsIfInventoryIsFull ) ) { + if ( itemStack.getAmount() > 0 ) { + + if (isBoolean(AutoFeatures.dropItemsIfInventoryIsFull)) { + + SpigotUtil.dropPlayerItems(player, itemStack); + } - SpigotUtil.dropPlayerItems( player, itemStack ); - notifyPlayerThatInventoryIsFull( player ); - } - else { - notifyPlayerThatInventoryIsFullLosingItems( player ); + needToNotify = true; } } + + // Only send one notification, not matter how many stacks need to be dropped or lost: + if ( needToNotify ) { + if (isBoolean(AutoFeatures.dropItemsIfInventoryIsFull)) { + + notifyPlayerThatInventoryIsFull(player); + } else { + notifyPlayerThatInventoryIsFullLosingItems(player); + } + } + } } - private boolean isBoolean( Configuration sellAllConfig, String config ) { - String configValue = sellAllConfig.getString( config ); - return configValue != null && configValue.equalsIgnoreCase( "true" ); - } +// private boolean isBoolean( Configuration sellAllConfig, String config ) { +// String configValue = sellAllConfig.getString( config ); +// return configValue != null && configValue.equalsIgnoreCase( "true" ); +// } private void dropAtBlock( SpigotItemStack itemStack, SpigotBlock block ) { @@ -842,14 +1024,59 @@ private void notifyPlayerWithSound( Player player, AutoFeatures messageId ) { // not used: Prison.get().getMinecraftVersion() ; // This hard coding the Sound enum causes failures in spigot 1.8.8 since it does not exist: - Sound sound; - try { - sound = Sound.valueOf("ANVIL_USE"); // pre 1.9 sound - } catch(IllegalArgumentException e) { - sound = Sound.valueOf("BLOCK_ANVIL_PLACE"); // post 1.9 sound + Sound sound = null; + + String soundName = getMessage(AutoFeatures.playSoundIfInventoryIsFullSound); + if ( soundName != null && soundName.trim().length() > 0 ) { + + sound = getSound( soundName ); + } + + + if ( sound == null ) { + + if ( new BluesSpigetSemVerComparator().compareMCVersionTo( "1.9.0" ) < 0 ) { + + // 1.8.x + sound = getSound("NOTE_PLING"); + } + else if ( new BluesSpigetSemVerComparator().compareMCVersionTo( "1.13.0" ) < 0 ) { + + // 1.9.x through 1.12.x + sound = getSound("BLOCK_NOTE_PLING"); + } + + else { + // 1.13.x and up: + + sound = getSound("BLOCK_NOTE_BLOCK_PLING"); + } } + +// try { +// sound = Sound.valueOf("ANVIL_USE"); // pre 1.9 sound +// } catch(IllegalArgumentException e) { +// sound = Sound.valueOf("BLOCK_NOTE_PLING "); // post 1.9 sound +// } - player.playSound(player.getLocation(), sound, 10F, 1F); + float volume = (float) getDouble(AutoFeatures.playSoundIfInventoryIsFullSoundVolume); + float pitch = (float) getDouble(AutoFeatures.playSoundIfInventoryIsFullSoundPitch); +// player.playSound(player.getLocation(), sound, volume, pitch); +// player.playSound(player.getLocation(), sound, 4F, 1F); + + + player.getWorld().playSound( player.getLocation(), sound, volume, pitch ); + + } + + + if ( isBoolean( AutoFeatures.actionBarMessageIfInventoryIsFull ) ) { + + (new SpigotPlayer( player )).setActionBar( message ); + } + else { + + player.sendMessage( message ); } // holographic display for showing full inventory does not work well. @@ -857,18 +1084,44 @@ private void notifyPlayerWithSound( Player player, AutoFeatures messageId ) { // displayMessageHologram( block, message , player); // } // else { - actionBarVersion(player, message); +// actionBarVersion(player, message); // } } - private void actionBarVersion(Player player, String message) { - if (new BluesSpigetSemVerComparator().compareMCVersionTo("1.9.0") < 0) { - displayActionBarMessage(player, message); + private Sound getSound( String soundName ) { + Sound results = null; + Sound altSound = null; + + for ( Sound s : Sound.values() ) { + if ( altSound == null && s.name().toLowerCase().contains( "plink" ) ) { + altSound = s; + } + if ( s.name().equalsIgnoreCase( soundName ) ) { + results = s; + break; + } } - else { - player.spigot().sendMessage(ChatMessageType.ACTION_BAR, TextComponent.fromLegacyText(SpigotPrison.format(message))); + + if ( results == null && altSound != null ) { + results = altSound; } + + return results; } + +// private void actionBarVersion(Player player, String message) { +// +// PlayerMessagingTask.submitTask( player, MessageType.actionBar, message ); +// +//// SpigotCompatibility.getInstance().sendActionBar( player, message ); +// +//// if (new BluesSpigetSemVerComparator().compareMCVersionTo("1.9.0") < 0) { +//// displayActionBarMessage(player, message); +//// } +//// else { +//// player.spigot().sendMessage(ChatMessageType.ACTION_BAR, TextComponent.fromLegacyText(SpigotPrison.format(message))); +//// } +// } /** * This is not usable since it not only prevents the player from mining when it is @@ -892,10 +1145,10 @@ private void displayMessageHologram(Block block, String message, Player p){ Bukkit.getScheduler().scheduleSyncDelayedTask(SpigotPrison.getInstance(), as::remove, (7L * 20L)); } - private void displayActionBarMessage(Player player, String message) { - SpigotPlayer prisonPlayer = new SpigotPlayer(player); - Prison.get().getPlatform().showActionBar(prisonPlayer, message, 80); - } +// private void displayActionBarMessage(Player player, String message) { +// SpigotPlayer prisonPlayer = new SpigotPlayer(player); +// Prison.get().getPlatform().showActionBar(prisonPlayer, message, 80); +// } /** @@ -919,7 +1172,7 @@ private void displayActionBarMessage(Player player, String message) { protected double doesItemHaveAutoFeatureLore( ItemLoreEnablers loreEnabler, Player player ) { double results = 0.0; - ItemStack itemInHand = SpigotPrison.getInstance().getCompatibility().getItemInMainHand( player ); + ItemStack itemInHand = SpigotCompatibility.getInstance().getItemInMainHand( player ); if ( itemInHand != null && itemInHand.getType() != Material.AIR && itemInHand.getItemMeta() != null ) { // (itemInHand.hasItemMeta()) { NOTE: hasItemMeta() always returns nulls @@ -1034,13 +1287,14 @@ protected double getLoreValue( SpigotItemStack itemInHand, String loreValue ) { * @param debugInfo * @return */ - protected int autoFeaturePickup( SpigotBlock block, Player p, SpigotItemStack itemInHand, + protected int autoFeaturePickup( PrisonMinesBlockBreakEvent pmEvent, + // SpigotBlock block, Player p, SpigotItemStack itemInHand, boolean isAutoSmelt, boolean isAutoBlock, StringBuilder debugInfo ) { int count = 0; boolean isAll = isBoolean( AutoFeatures.pickupAllBlocks ); - PrisonBlock prisonBlock = block.getPrisonBlock(); + PrisonBlock prisonBlock = pmEvent.getSpigotBlock().getPrisonBlock(); // Use this is a block name list based upon the following: blockType:blockName if not minecraft, or blockName List pickupBlockNameList = @@ -1048,13 +1302,13 @@ protected int autoFeaturePickup( SpigotBlock block, Player p, SpigotItemStack it getListString( AutoFeatures.pickupBlockNameList ) : null; if ( isAll ) { - count += autoPickup( p, itemInHand, block, isAutoSmelt, isAutoBlock, debugInfo ); + count += autoPickup( pmEvent, isAutoSmelt, isAutoBlock, debugInfo ); } else if ( isBoolean( AutoFeatures.pickupBlockNameListEnabled ) && pickupBlockNameList.size() > 0 && pickupBlockNameList.contains( prisonBlock.getBlockName() ) ) { - count += autoPickup( p, itemInHand, block, isAutoSmelt, isAutoBlock, debugInfo ); + count += autoPickup( pmEvent, isAutoSmelt, isAutoBlock, debugInfo ); } else { @@ -1062,67 +1316,67 @@ else if ( isBoolean( AutoFeatures.pickupBlockNameListEnabled ) && pickupBlockNam switch ( prisonBlock.getBlockName() ) { case "cobblestone": - count += autoPickup( p, itemInHand, block, isAutoSmelt, isAutoBlock, debugInfo ); + count += autoPickup( pmEvent, isAutoSmelt, isAutoBlock, debugInfo ); break; case "stone": - count += autoPickup( p, itemInHand, block, isAutoSmelt, isAutoBlock, debugInfo ); + count += autoPickup( pmEvent, isAutoSmelt, isAutoBlock, debugInfo ); break; case "gold_ore": case "nether_gold_ore": case "deepslate_gold_ore": case "raw_gold": - count += autoPickup( p, itemInHand, block, isAutoSmelt, isAutoBlock, debugInfo ); + count += autoPickup( pmEvent, isAutoSmelt, isAutoBlock, debugInfo ); break; case "iron_ore": case "deepslate_iron_ore": case "raw_iron": - count += autoPickup( p, itemInHand, block, isAutoSmelt, isAutoBlock, debugInfo ); + count += autoPickup( pmEvent, isAutoSmelt, isAutoBlock, debugInfo ); break; case "coal_ore": case "deepslate_coal_ore": - count += autoPickup( p, itemInHand, block, isAutoSmelt, isAutoBlock, debugInfo ); + count += autoPickup( pmEvent, isAutoSmelt, isAutoBlock, debugInfo ); break; case "diamond_ore": case "deepslate_diamond_ore": - count += autoPickup( p, itemInHand, block, isAutoSmelt, isAutoBlock, debugInfo ); + count += autoPickup( pmEvent, isAutoSmelt, isAutoBlock, debugInfo ); break; case "redstone_ore": case "deepslate_redstone_ore": - count += autoPickup( p, itemInHand, block, isAutoSmelt, isAutoBlock, debugInfo ); + count += autoPickup( pmEvent, isAutoSmelt, isAutoBlock, debugInfo ); break; case "emerald_ore": case "deepslate_emerald_ore": - count += autoPickup( p, itemInHand, block, isAutoSmelt, isAutoBlock, debugInfo ); + count += autoPickup( pmEvent, isAutoSmelt, isAutoBlock, debugInfo ); break; case "quartz_ore": - count += autoPickup( p, itemInHand, block, isAutoSmelt, isAutoBlock, debugInfo ); + count += autoPickup( pmEvent, isAutoSmelt, isAutoBlock, debugInfo ); break; case "lapis_ore": case "deepslate_lapis_ore": - count += autoPickup( p, itemInHand, block, isAutoSmelt, isAutoBlock, debugInfo ); + count += autoPickup( pmEvent, isAutoSmelt, isAutoBlock, debugInfo ); break; case "snow_ball": - count += autoPickup( p, itemInHand, block, isAutoSmelt, isAutoBlock, debugInfo ); + count += autoPickup( pmEvent, isAutoSmelt, isAutoBlock, debugInfo ); break; case "glowstone_dust": // works 1.15.2 - count += autoPickup( p, itemInHand, block, isAutoSmelt, isAutoBlock, debugInfo ); + count += autoPickup( pmEvent, isAutoSmelt, isAutoBlock, debugInfo ); break; case "copper_ore": case "deepslate_copper_ore": case "raw_copper": - count += autoPickup( p, itemInHand, block, isAutoSmelt, isAutoBlock, debugInfo ); + count += autoPickup( pmEvent, isAutoSmelt, isAutoBlock, debugInfo ); break; default: @@ -1143,173 +1397,173 @@ else if ( isBoolean( AutoFeatures.pickupBlockNameListEnabled ) && pickupBlockNam return count; } - - protected XMaterial autoFeatureSmelt( Player p, XMaterial source ) - { - XMaterial results = source; - - boolean isAll = isBoolean( AutoFeatures.smeltAllBlocks ); - -// XMaterial source = SpigotUtil.getXMaterial( block.getPrisonBlock() ); - if ( source != null ) { - - switch ( source ) - { - case COBBLESTONE: - autoSmelt( isAll || isBoolean( AutoFeatures.smeltCobblestone ), source, XMaterial.STONE, p ); - results = XMaterial.STONE; - break; - - case GOLD_ORE: - case NETHER_GOLD_ORE: - case DEEPSLATE_GOLD_ORE: - case RAW_GOLD: - autoSmelt( isAll || isBoolean( AutoFeatures.smeltGoldOre ), source, XMaterial.GOLD_INGOT, p ); - results = XMaterial.GOLD_INGOT; - break; - - case IRON_ORE: - case DEEPSLATE_IRON_ORE: - case RAW_IRON: - autoSmelt( isAll || isBoolean( AutoFeatures.smeltIronOre ), source, XMaterial.IRON_INGOT, p ); - results = XMaterial.IRON_INGOT; - break; - - case COAL_ORE: - case DEEPSLATE_COAL_ORE: - autoSmelt( isAll || isBoolean( AutoFeatures.smeltCoalOre ), source, XMaterial.COAL, p ); - results = XMaterial.COAL; - break; - - case DIAMOND_ORE: - case DEEPSLATE_DIAMOND_ORE: - autoSmelt( isAll || isBoolean( AutoFeatures.smeltDiamondlOre ), source, XMaterial.DIAMOND, p ); - results = XMaterial.DIAMOND; - break; - - case EMERALD_ORE: - case DEEPSLATE_EMERALD_ORE: - autoSmelt( isAll || isBoolean( AutoFeatures.smeltEmeraldOre ), source, XMaterial.EMERALD, p ); - results = XMaterial.EMERALD; - break; - - case LAPIS_ORE: - case DEEPSLATE_LAPIS_ORE: - autoSmelt( isAll || isBoolean( AutoFeatures.smeltLapisOre ), source, XMaterial.LAPIS_LAZULI, p ); - results = XMaterial.LAPIS_LAZULI; - break; - - case REDSTONE_ORE: - case DEEPSLATE_REDSTONE_ORE: - autoSmelt( isAll || isBoolean( AutoFeatures.smeltRedstoneOre ), source, XMaterial.REDSTONE, p ); - results = XMaterial.REDSTONE; - break; - - case NETHER_QUARTZ_ORE: - autoSmelt( isAll || isBoolean( AutoFeatures.smeltNetherQuartzOre ), source, XMaterial.QUARTZ, p ); - results = XMaterial.QUARTZ; - break; - - case ANCIENT_DEBRIS: - autoSmelt( isAll || isBoolean( AutoFeatures.smeltAncientDebris ), source, XMaterial.NETHERITE_SCRAP, p ); - results = XMaterial.NETHERITE_SCRAP; - break; - - // v1.17 !! - case COPPER_ORE: - case DEEPSLATE_COPPER_ORE: - case RAW_COPPER: - autoSmelt( isAll || isBoolean( AutoFeatures.smeltCopperOre ), source, XMaterial.COPPER_INGOT, p ); - results = XMaterial.COPPER_INGOT; - break; - - default: - break; - } - } - - - return results; - } - - protected void autoFeatureBlock( Player p, XMaterial source ) { - - boolean isAll = isBoolean( AutoFeatures.smeltAllBlocks ); - - if ( source != null ) { - - // Any autoBlock target could be enabled, and could have multiples of 9, so perform the - // checks within each block type's function call. So in one pass, could hit on more - // than one of these for multiple times too. - switch ( source ) - { - case GOLD_INGOT: - autoBlock( isAll || isBoolean( AutoFeatures.blockGoldBlock ), source, XMaterial.GOLD_BLOCK, p ); - - break; - - case IRON_INGOT: - autoBlock( isAll || isBoolean( AutoFeatures.blockIronBlock ), source, XMaterial.IRON_BLOCK, p ); - - break; - - case COAL: - autoBlock( isAll || isBoolean( AutoFeatures.blockCoalBlock ), source, XMaterial.COAL_BLOCK, p ); - - break; - - case DIAMOND: - autoBlock( isAll || isBoolean( AutoFeatures.blockDiamondBlock ), source, XMaterial.DIAMOND_BLOCK, p ); - - break; - - case REDSTONE: - autoBlock( isAll || isBoolean( AutoFeatures.blockRedstoneBlock ), source,XMaterial.REDSTONE_BLOCK, p ); - - break; - - case EMERALD: - autoBlock( isAll || isBoolean( AutoFeatures.blockEmeraldBlock ), source, XMaterial.EMERALD_BLOCK, p ); - - break; - - case QUARTZ: - autoBlock( isAll || isBoolean( AutoFeatures.blockQuartzBlock ), source, XMaterial.QUARTZ_BLOCK, 4, p ); - - break; - - case PRISMARINE_SHARD: - autoBlock( isAll || isBoolean( AutoFeatures.blockPrismarineBlock ), source, XMaterial.PRISMARINE, 4, p ); - - break; - - case SNOWBALL: - autoBlock( isAll || isBoolean( AutoFeatures.blockSnowBlock ), source, XMaterial.SNOW_BLOCK, 4, p ); - - break; - - case GLOWSTONE_DUST: - autoBlock( isAll || isBoolean( AutoFeatures.blockGlowstone ), source, XMaterial.GLOWSTONE, 4, p ); - - break; - - case LAPIS_LAZULI: - autoBlock( isAll || isBoolean( AutoFeatures.blockLapisBlock ), source, XMaterial.LAPIS_BLOCK, p ); - - break; - - case COPPER_INGOT: - autoBlock( isAll || isBoolean( AutoFeatures.blockCopperBlock ), source, XMaterial.COPPER_BLOCK, p ); - - break; - - default: - break; - } - } - - } - +// +// protected XMaterial autoFeatureSmelt( Player p, XMaterial source ) +// { +// XMaterial results = source; +// +// boolean isAll = isBoolean( AutoFeatures.smeltAllBlocks ); +// +//// XMaterial source = SpigotUtil.getXMaterial( block.getPrisonBlock() ); +// if ( source != null ) { +// +// switch ( source ) +// { +// case COBBLESTONE: +// autoSmelt( isAll || isBoolean( AutoFeatures.smeltCobblestone ), source, XMaterial.STONE, p ); +// results = XMaterial.STONE; +// break; +// +// case GOLD_ORE: +// case NETHER_GOLD_ORE: +// case DEEPSLATE_GOLD_ORE: +// case RAW_GOLD: +// autoSmelt( isAll || isBoolean( AutoFeatures.smeltGoldOre ), source, XMaterial.GOLD_INGOT, p ); +// results = XMaterial.GOLD_INGOT; +// break; +// +// case IRON_ORE: +// case DEEPSLATE_IRON_ORE: +// case RAW_IRON: +// autoSmelt( isAll || isBoolean( AutoFeatures.smeltIronOre ), source, XMaterial.IRON_INGOT, p ); +// results = XMaterial.IRON_INGOT; +// break; +// +// case COAL_ORE: +// case DEEPSLATE_COAL_ORE: +// autoSmelt( isAll || isBoolean( AutoFeatures.smeltCoalOre ), source, XMaterial.COAL, p ); +// results = XMaterial.COAL; +// break; +// +// case DIAMOND_ORE: +// case DEEPSLATE_DIAMOND_ORE: +// autoSmelt( isAll || isBoolean( AutoFeatures.smeltDiamondlOre ), source, XMaterial.DIAMOND, p ); +// results = XMaterial.DIAMOND; +// break; +// +// case EMERALD_ORE: +// case DEEPSLATE_EMERALD_ORE: +// autoSmelt( isAll || isBoolean( AutoFeatures.smeltEmeraldOre ), source, XMaterial.EMERALD, p ); +// results = XMaterial.EMERALD; +// break; +// +// case LAPIS_ORE: +// case DEEPSLATE_LAPIS_ORE: +// autoSmelt( isAll || isBoolean( AutoFeatures.smeltLapisOre ), source, XMaterial.LAPIS_LAZULI, p ); +// results = XMaterial.LAPIS_LAZULI; +// break; +// +// case REDSTONE_ORE: +// case DEEPSLATE_REDSTONE_ORE: +// autoSmelt( isAll || isBoolean( AutoFeatures.smeltRedstoneOre ), source, XMaterial.REDSTONE, p ); +// results = XMaterial.REDSTONE; +// break; +// +// case NETHER_QUARTZ_ORE: +// autoSmelt( isAll || isBoolean( AutoFeatures.smeltNetherQuartzOre ), source, XMaterial.QUARTZ, p ); +// results = XMaterial.QUARTZ; +// break; +// +// case ANCIENT_DEBRIS: +// autoSmelt( isAll || isBoolean( AutoFeatures.smeltAncientDebris ), source, XMaterial.NETHERITE_SCRAP, p ); +// results = XMaterial.NETHERITE_SCRAP; +// break; +// +// // v1.17 !! +// case COPPER_ORE: +// case DEEPSLATE_COPPER_ORE: +// case RAW_COPPER: +// autoSmelt( isAll || isBoolean( AutoFeatures.smeltCopperOre ), source, XMaterial.COPPER_INGOT, p ); +// results = XMaterial.COPPER_INGOT; +// break; +// +// default: +// break; +// } +// } +// +// +// return results; +// } +// +// protected void autoFeatureBlock( Player p, XMaterial source ) { +// +// boolean isAll = isBoolean( AutoFeatures.smeltAllBlocks ); +// +// if ( source != null ) { +// +// // Any autoBlock target could be enabled, and could have multiples of 9, so perform the +// // checks within each block type's function call. So in one pass, could hit on more +// // than one of these for multiple times too. +// switch ( source ) +// { +// case GOLD_INGOT: +// autoBlock( isAll || isBoolean( AutoFeatures.blockGoldBlock ), source, XMaterial.GOLD_BLOCK, p ); +// +// break; +// +// case IRON_INGOT: +// autoBlock( isAll || isBoolean( AutoFeatures.blockIronBlock ), source, XMaterial.IRON_BLOCK, p ); +// +// break; +// +// case COAL: +// autoBlock( isAll || isBoolean( AutoFeatures.blockCoalBlock ), source, XMaterial.COAL_BLOCK, p ); +// +// break; +// +// case DIAMOND: +// autoBlock( isAll || isBoolean( AutoFeatures.blockDiamondBlock ), source, XMaterial.DIAMOND_BLOCK, p ); +// +// break; +// +// case REDSTONE: +// autoBlock( isAll || isBoolean( AutoFeatures.blockRedstoneBlock ), source,XMaterial.REDSTONE_BLOCK, p ); +// +// break; +// +// case EMERALD: +// autoBlock( isAll || isBoolean( AutoFeatures.blockEmeraldBlock ), source, XMaterial.EMERALD_BLOCK, p ); +// +// break; +// +// case QUARTZ: +// autoBlock( isAll || isBoolean( AutoFeatures.blockQuartzBlock ), source, XMaterial.QUARTZ_BLOCK, 4, p ); +// +// break; +// +// case PRISMARINE_SHARD: +// autoBlock( isAll || isBoolean( AutoFeatures.blockPrismarineBlock ), source, XMaterial.PRISMARINE, 4, p ); +// +// break; +// +// case SNOWBALL: +// autoBlock( isAll || isBoolean( AutoFeatures.blockSnowBlock ), source, XMaterial.SNOW_BLOCK, 4, p ); +// +// break; +// +// case GLOWSTONE_DUST: +// autoBlock( isAll || isBoolean( AutoFeatures.blockGlowstone ), source, XMaterial.GLOWSTONE, 4, p ); +// +// break; +// +// case LAPIS_LAZULI: +// autoBlock( isAll || isBoolean( AutoFeatures.blockLapisBlock ), source, XMaterial.LAPIS_BLOCK, p ); +// +// break; +// +// case COPPER_INGOT: +// autoBlock( isAll || isBoolean( AutoFeatures.blockCopperBlock ), source, XMaterial.COPPER_BLOCK, p ); +// +// break; +// +// default: +// break; +// } +// } +// +// } +// /** *

This processes the normal drop smelting if it's enabled. Only the 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 a0e901f1d..f9b2d53e2 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 @@ -28,19 +28,33 @@ public AutoManagerBlockBreakEvents() { } - + /** + *

When a listener is registered within prison's auto manager, the events + * are tracked internally and can be unregistered later. This function does not + * make it obvious the instantiated object is "stored", but it is. + *

+ * + *

For more info on the storage of these registered events, please see: + *

+ * + *
SpigotPrison.getRegisteredBlockListeners()
+ * + */ @Override public void registerEvents() { - initialize(); + // Prison's own internal event and listener: + new AutoManagerPrisonsExplosiveBlockBreakEvents().registerEvents(); new AutoManagerCrazyEnchants().registerEvents(); new AutoManagerPrisonEnchants().registerEvents(); new AutoManagerTokenEnchant().registerEvents(); new AutoManagerZenchantments().registerEvents(); + + new PrisonDebugBlockInspector().init(); } @@ -50,6 +64,9 @@ public class AutoManagerBlockBreakEventListener @EventHandler(priority=EventPriority.NORMAL) public void onBlockBreak(BlockBreakEvent e) { + if ( isDisabled( e.getBlock().getLocation().getWorld().getName() ) ) { + return; + } genericBlockEventAutoManager( e ); } } @@ -60,6 +77,9 @@ public class OnBlockBreakEventListenerNormal @EventHandler(priority=EventPriority.NORMAL) public void onBlockBreak(BlockBreakEvent e) { + if ( isDisabled( e.getBlock().getLocation().getWorld().getName() ) ) { + return; + } genericBlockEvent( e ); } } @@ -70,6 +90,9 @@ public class OnBlockBreakEventListenerNormalMonitor @EventHandler(priority=EventPriority.MONITOR) public void onBlockBreak(BlockBreakEvent e) { + if ( isDisabled( e.getBlock().getLocation().getWorld().getName() ) ) { + return; + } genericBlockEventMonitor( e ); } } @@ -118,39 +141,44 @@ public void execute(Listener l, Event e) { prison); prison.getRegisteredBlockListeners().add( autoManagerlListener ); } + else if ( isBoolean( AutoFeatures.normalDrop ) ) { + + OnBlockBreakEventListenerNormal normalListener = + new OnBlockBreakEventListenerNormal(); + + pm.registerEvent(BlockBreakEvent.class, normalListener, ePriority, + new EventExecutor() { + public void execute(Listener l, Event e) { + if ( l instanceof OnBlockBreakEventListenerNormal && + e instanceof BlockBreakEvent ) { + ((OnBlockBreakEventListenerNormal)l) + .onBlockBreak((BlockBreakEvent)e); + } + } + }, + prison); + prison.getRegisteredBlockListeners().add( normalListener ); + } - OnBlockBreakEventListenerNormal normalListener = - new OnBlockBreakEventListenerNormal(); - pm.registerEvent(BlockBreakEvent.class, normalListener, ePriority, + } + else { + + pm.registerEvent(BlockBreakEvent.class, normalListenerMonitor, EventPriority.MONITOR, new EventExecutor() { - public void execute(Listener l, Event e) { - if ( l instanceof OnBlockBreakEventListenerNormal && + public void execute(Listener l, Event e) { + if ( l instanceof OnBlockBreakEventListenerNormalMonitor && e instanceof BlockBreakEvent ) { - ((OnBlockBreakEventListenerNormal)l) + ((OnBlockBreakEventListenerNormalMonitor)l) .onBlockBreak((BlockBreakEvent)e); } } }, prison); - prison.getRegisteredBlockListeners().add( normalListener ); - + prison.getRegisteredBlockListeners().add( normalListenerMonitor ); } - pm.registerEvent(BlockBreakEvent.class, normalListenerMonitor, EventPriority.MONITOR, - new EventExecutor() { - public void execute(Listener l, Event e) { - if ( l instanceof OnBlockBreakEventListenerNormalMonitor && - e instanceof BlockBreakEvent ) { - ((OnBlockBreakEventListenerNormalMonitor)l) - .onBlockBreak((BlockBreakEvent)e); - } - } - }, - prison); - prison.getRegisteredBlockListeners().add( normalListenerMonitor ); - } } @@ -207,6 +235,7 @@ public void dumpEventListeners( StringBuilder sb ) { if ( eventDisplay != null ) { sb.append( eventDisplay.toStringBuilder() ); + sb.append( "\n" ); } } catch ( Exception e ) { diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/autofeatures/events/AutoManagerCrazyEnchants.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/autofeatures/events/AutoManagerCrazyEnchants.java index 720d6663c..c81ae901c 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/autofeatures/events/AutoManagerCrazyEnchants.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/autofeatures/events/AutoManagerCrazyEnchants.java @@ -39,6 +39,9 @@ public class AutoManagerBlastUseEventListener @EventHandler(priority=EventPriority.NORMAL) public void onCrazyEnchantsBlockExplode(BlastUseEvent e) { + if ( isDisabled( e.getPlayer().getLocation().getWorld().getName() ) ) { + return; + } genericBlockExplodeEventAutoManager( e ); } } @@ -49,6 +52,9 @@ public class OnBlockBreakBlastUseEventListener @EventHandler(priority=EventPriority.NORMAL) public void onCrazyEnchantsBlockExplode(BlastUseEvent e) { + if ( isDisabled( e.getPlayer().getLocation().getWorld().getName() ) ) { + return; + } genericBlockExplodeEvent( e ); } } @@ -59,6 +65,9 @@ public class OnBlockBreakBlastUseEventListenerMonitor @EventHandler(priority=EventPriority.MONITOR) public void onCrazyEnchantsBlockExplode(BlastUseEvent e) { + if ( isDisabled( e.getPlayer().getLocation().getWorld().getName() ) ) { + return; + } genericBlockExplodeEventMonitor( e ); } } @@ -66,7 +75,9 @@ public void onCrazyEnchantsBlockExplode(BlastUseEvent e) { @Override public void initialize() { - boolean isEventEnabled = isBoolean( AutoFeatures.isProcessCrazyEnchantsBlockExplodeEvents ); + + String eP = getMessage( AutoFeatures.CrazyEnchantsBlastUseEventPriority ); + boolean isEventEnabled = eP != null && !"DISABLED".equalsIgnoreCase( eP ); if ( !isEventEnabled ) { return; @@ -81,7 +92,6 @@ public void initialize() { Output.get().logInfo( "AutoManager: Trying to register CrazyEnchants" ); - String eP = getMessage( AutoFeatures.CrazyEnchantsBlastUseEventPriority ); BlockBreakPriority eventPriority = BlockBreakPriority.fromString( eP ); if ( eventPriority != BlockBreakPriority.DISABLED ) { @@ -114,31 +124,36 @@ public void execute(Listener l, Event e) { prison); prison.getRegisteredBlockListeners().add( autoManagerlListener ); } + else if ( isBoolean( AutoFeatures.normalDrop ) ) { + + OnBlockBreakBlastUseEventListener normalListener = + new OnBlockBreakBlastUseEventListener(); + + pm.registerEvent(BlastUseEvent.class, normalListener, ePriority, + new EventExecutor() { + public void execute(Listener l, Event e) { + ((OnBlockBreakBlastUseEventListener)l) + .onCrazyEnchantsBlockExplode((BlastUseEvent)e); + } + }, + prison); + prison.getRegisteredBlockListeners().add( normalListener ); + } - OnBlockBreakBlastUseEventListener normalListener = - new OnBlockBreakBlastUseEventListener(); - - pm.registerEvent(BlastUseEvent.class, normalListener, ePriority, + } + else { + + pm.registerEvent(BlastUseEvent.class, normalListenerMonitor, EventPriority.MONITOR, new EventExecutor() { public void execute(Listener l, Event e) { - ((OnBlockBreakBlastUseEventListener)l) + ((OnBlockBreakBlastUseEventListenerMonitor)l) .onCrazyEnchantsBlockExplode((BlastUseEvent)e); } }, prison); - prison.getRegisteredBlockListeners().add( normalListener ); + prison.getRegisteredBlockListeners().add( normalListenerMonitor ); } - pm.registerEvent(BlastUseEvent.class, normalListenerMonitor, EventPriority.MONITOR, - new EventExecutor() { - public void execute(Listener l, Event e) { - ((OnBlockBreakBlastUseEventListenerMonitor)l) - .onCrazyEnchantsBlockExplode((BlastUseEvent)e); - } - }, - prison); - prison.getRegisteredBlockListeners().add( normalListenerMonitor ); - } // The following is paper code: @@ -188,8 +203,10 @@ public void dumpEventListeners() { @Override public void dumpEventListeners( StringBuilder sb ) { - boolean isEventEnabled = isBoolean( AutoFeatures.isProcessCrazyEnchantsBlockExplodeEvents ); + String eP = getMessage( AutoFeatures.CrazyEnchantsBlastUseEventPriority ); + boolean isEventEnabled = eP != null && !"DISABLED".equalsIgnoreCase( eP ); + if ( !isEventEnabled ) { return; } @@ -207,6 +224,7 @@ public void dumpEventListeners( StringBuilder sb ) { if ( eventDisplay != null ) { sb.append( eventDisplay.toStringBuilder() ); + sb.append( "\n" ); } } catch ( ClassNotFoundException e ) { diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/autofeatures/events/AutoManagerEventsManager.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/autofeatures/events/AutoManagerEventsManager.java index d45e4a53c..30a1a7ee3 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/autofeatures/events/AutoManagerEventsManager.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/autofeatures/events/AutoManagerEventsManager.java @@ -3,6 +3,7 @@ import org.bukkit.event.HandlerList; import org.bukkit.event.Listener; +import tech.mcprison.prison.Prison; import tech.mcprison.prison.output.Output; import tech.mcprison.prison.spigot.SpigotPrison; import tech.mcprison.prison.spigot.autofeatures.AutoManagerFeatures; @@ -17,6 +18,10 @@ public AutoManagerEventsManager() { } + public boolean isDisabled( String worldName ) { + return Prison.get().getPlatform().isWorldExcluded( worldName ); + } + /** *

If one BlockBreak related event needs to be unregistered, then this function will * unregisters all of them that has been registered through the auto features. If diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/autofeatures/events/AutoManagerPrisonEnchants.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/autofeatures/events/AutoManagerPrisonEnchants.java index 39a3e6172..3dba79a87 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/autofeatures/events/AutoManagerPrisonEnchants.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/autofeatures/events/AutoManagerPrisonEnchants.java @@ -34,12 +34,16 @@ public void registerEvents() { } - public class AutoManagerExplosiveEventListener + public class AutoManagerPEExplosiveEventListener extends AutoManagerBlockBreakEvents implements Listener { @EventHandler(priority=EventPriority.NORMAL) public void onPrisonEnchantsExplosiveEvent(PEExplosionEvent e) { + if ( isDisabled( e.getBlockBroken().getLocation().getWorld().getName() ) ) { + return; + } + // me.pulsi_.prisonenchants.events.PEExplosionEvent @@ -47,45 +51,52 @@ public void onPrisonEnchantsExplosiveEvent(PEExplosionEvent e) { } } - public class OnBlockBreakExplosiveEventListener + public class OnBlockBreakPEExplosiveEventListener extends OnBlockBreakEventListener implements Listener { @EventHandler(priority=EventPriority.NORMAL) public void onPrisonEnchantsExplosiveEvent(PEExplosionEvent e) { + if ( isDisabled( e.getBlockBroken().getLocation().getWorld().getName() ) ) { + return; + } genericBlockExplodeEvent( e ); } } - public class OnBlockBreakExplosiveEventListenerMonitor + public class OnBlockBreakPEExplosiveEventListenerMonitor extends OnBlockBreakEventListener implements Listener { @EventHandler(priority=EventPriority.MONITOR) public void onPrisonEnchantsExplosiveEvent(PEExplosionEvent e) { + if ( isDisabled( e.getBlockBroken().getLocation().getWorld().getName() ) ) { + return; + } genericBlockExplodeEventMonitor( e ); } } @Override public void initialize() { - boolean isEventEnabled = isBoolean( AutoFeatures.isProcessPrisonEnchantsExplosiveEvents ); - + + String eP = getMessage( AutoFeatures.PrisonEnchantsExplosiveEventPriority ); + boolean isEventEnabled = eP != null && !"DISABLED".equalsIgnoreCase( eP ); + if ( !isEventEnabled ) { return; } // Check to see if the class ExplosiveEvent even exists: try { - Output.get().logInfo( "AutoManager: checking if loaded: PrisonEnchants" ); + Output.get().logInfo( "AutoManager: checking if loaded: Pulsi_'s PrisonEnchants" ); - Class.forName( "me.pulsi_.prisonenchants.enchantments.custom.explosive.PEExplosionEvent", false, + Class.forName( "me.pulsi_.prisonenchants.events.PEExplosionEvent", false, this.getClass().getClassLoader() ); - Output.get().logInfo( "AutoManager: Trying to register PrisonEnchants" ); + Output.get().logInfo( "AutoManager: Trying to register Pulsi_'s PrisonEnchants" ); - String eP = getMessage( AutoFeatures.PrisonEnchantsExplosiveEventPriority ); BlockBreakPriority eventPriority = BlockBreakPriority.fromString( eP ); if ( eventPriority != BlockBreakPriority.DISABLED ) { @@ -93,8 +104,8 @@ public void initialize() { EventPriority ePriority = EventPriority.valueOf( eventPriority.name().toUpperCase() ); - OnBlockBreakExplosiveEventListenerMonitor normalListenerMonitor = - new OnBlockBreakExplosiveEventListenerMonitor(); + OnBlockBreakPEExplosiveEventListenerMonitor normalListenerMonitor = + new OnBlockBreakPEExplosiveEventListenerMonitor(); SpigotPrison prison = SpigotPrison.getInstance(); @@ -106,43 +117,49 @@ public void initialize() { if ( isBoolean( AutoFeatures.isAutoFeaturesEnabled )) { - AutoManagerExplosiveEventListener autoManagerlListener = - new AutoManagerExplosiveEventListener(); + AutoManagerPEExplosiveEventListener autoManagerlListener = + new AutoManagerPEExplosiveEventListener(); pm.registerEvent(PEExplosionEvent.class, autoManagerlListener, ePriority, new EventExecutor() { public void execute(Listener l, Event e) { - ((AutoManagerExplosiveEventListener)l) + ((AutoManagerPEExplosiveEventListener)l) .onPrisonEnchantsExplosiveEvent((PEExplosionEvent)e); } }, prison); prison.getRegisteredBlockListeners().add( autoManagerlListener ); } + else if ( isBoolean( AutoFeatures.normalDrop ) ) { + + OnBlockBreakPEExplosiveEventListener normalListener = + new OnBlockBreakPEExplosiveEventListener(); + + pm.registerEvent(PEExplosionEvent.class, normalListener, ePriority, + new EventExecutor() { + public void execute(Listener l, Event e) { + ((OnBlockBreakPEExplosiveEventListener)l) + .onPrisonEnchantsExplosiveEvent((PEExplosionEvent)e); + } + }, + prison); + prison.getRegisteredBlockListeners().add( normalListener ); + } - OnBlockBreakExplosiveEventListener normalListener = - new OnBlockBreakExplosiveEventListener(); + } + else { - pm.registerEvent(PEExplosionEvent.class, normalListener, ePriority, + pm.registerEvent(PEExplosionEvent.class, normalListenerMonitor, EventPriority.MONITOR, new EventExecutor() { public void execute(Listener l, Event e) { - ((OnBlockBreakExplosiveEventListener)l) + ((OnBlockBreakPEExplosiveEventListenerMonitor)l) .onPrisonEnchantsExplosiveEvent((PEExplosionEvent)e); } }, prison); - prison.getRegisteredBlockListeners().add( normalListener ); + prison.getRegisteredBlockListeners().add( normalListenerMonitor ); } - pm.registerEvent(PEExplosionEvent.class, normalListenerMonitor, EventPriority.MONITOR, - new EventExecutor() { - public void execute(Listener l, Event e) { - ((OnBlockBreakExplosiveEventListenerMonitor)l) - .onPrisonEnchantsExplosiveEvent((PEExplosionEvent)e); - } - }, - prison); - prison.getRegisteredBlockListeners().add( normalListenerMonitor ); } @@ -150,10 +167,10 @@ public void execute(Listener l, Event e) { } catch ( ClassNotFoundException e ) { // PrisonEnchants is not loaded... so ignore. - Output.get().logInfo( "AutoManager: PrisonEnchants is not loaded" ); + Output.get().logInfo( "AutoManager: Pulsi_'s PrisonEnchants is not loaded" ); } catch ( Exception e ) { - Output.get().logInfo( "AutoManager: PrisonEnchants failed to load. [%s]", e.getMessage() ); + Output.get().logInfo( "AutoManager: Pulsi_'s PrisonEnchants failed to load. [%s]", e.getMessage() ); } } @@ -187,8 +204,10 @@ public void dumpEventListeners() { @Override public void dumpEventListeners( StringBuilder sb ) { - boolean isEventEnabled = isBoolean( AutoFeatures.isProcessPrisonEnchantsExplosiveEvents ); - + + String eP = getMessage( AutoFeatures.PrisonEnchantsExplosiveEventPriority ); + boolean isEventEnabled = eP != null && !"DISABLED".equalsIgnoreCase( eP ); + if ( !isEventEnabled ) { return; } @@ -196,16 +215,17 @@ public void dumpEventListeners( StringBuilder sb ) { // Check to see if the class ExplosiveEvent even exists: try { - Class.forName( "me.pulsi_.prisonenchants.enchantments.custom.explosive.PEExplosionEvent", false, + Class.forName( "me.pulsi_.prisonenchants.events.PEExplosionEvent", false, this.getClass().getClassLoader() ); ChatDisplay eventDisplay = Prison.get().getPlatform().dumpEventListenersChatDisplay( - "PEExplosionEvent", + "Pulsi_'s PEExplosionEvent", new SpigotHandlerList( PEExplosionEvent.getHandlerList()) ); if ( eventDisplay != null ) { sb.append( eventDisplay.toStringBuilder() ); + sb.append( "\n" ); } } catch ( ClassNotFoundException e ) { 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 3b1d4de72..41133d4b0 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 @@ -41,7 +41,10 @@ public class AutoManagerExplosiveBlockBreakEventListener @EventHandler(priority=EventPriority.NORMAL) public void onPrisonsExplosiveBlockBreakEvent(ExplosiveBlockBreakEvent e) { - + if ( isDisabled( e.getBlock().getLocation().getWorld().getName() ) ) { + return; + } + // me.pulsi_.prisonenchants.events.PEExplosionEvent genericBlockExplodeEventAutoManager( e ); @@ -54,6 +57,9 @@ public class OnBlockBreakExplosiveBlockBreakEventListener @EventHandler(priority=EventPriority.NORMAL) public void onPrisonExplosiveBlockBreakEvent(ExplosiveBlockBreakEvent e) { + if ( isDisabled( e.getBlock().getLocation().getWorld().getName() ) ) { + return; + } genericBlockExplodeEvent( e ); } } @@ -64,14 +70,19 @@ public class OnBlockBreakExplosiveBlockBreakEventListenerMonitor @EventHandler(priority=EventPriority.MONITOR) public void onPrisonExplosiveBlockBreakEventMonitor(ExplosiveBlockBreakEvent e) { + if ( isDisabled( e.getBlock().getLocation().getWorld().getName() ) ) { + return; + } genericBlockExplodeEventMonitor( e ); } } @Override public void initialize() { - boolean isEventEnabled = isBoolean( AutoFeatures.isProcessPrisons_ExplosiveBlockBreakEvents ); + String eP = getMessage( AutoFeatures.ProcessPrisons_ExplosiveBlockBreakEventsPriority ); + boolean isEventEnabled = eP != null && !"DISABLED".equalsIgnoreCase( eP ); + if ( !isEventEnabled ) { return; } @@ -81,7 +92,6 @@ public void initialize() { Output.get().logInfo( "AutoManager: Trying to register ExplosiveBlockBreakEvent Listener" ); - String eP = getMessage( AutoFeatures.ProcessPrisons_ExplosiveBlockBreakEvents ); BlockBreakPriority eventPriority = BlockBreakPriority.fromString( eP ); if ( eventPriority != BlockBreakPriority.DISABLED ) { @@ -115,31 +125,37 @@ public void execute(Listener l, Event e) { prison); prison.getRegisteredBlockListeners().add( autoManagerlListener ); } + else if ( isBoolean( AutoFeatures.normalDrop ) ) { + + OnBlockBreakExplosiveBlockBreakEventListener normalListener = + new OnBlockBreakExplosiveBlockBreakEventListener(); + + pm.registerEvent(ExplosiveBlockBreakEvent.class, normalListener, ePriority, + new EventExecutor() { + public void execute(Listener l, Event e) { + ((OnBlockBreakExplosiveBlockBreakEventListener)l) + .onPrisonExplosiveBlockBreakEvent((ExplosiveBlockBreakEvent)e); + } + }, + prison); + prison.getRegisteredBlockListeners().add( normalListener ); + } - OnBlockBreakExplosiveBlockBreakEventListener normalListener = - new OnBlockBreakExplosiveBlockBreakEventListener(); + } + else { - pm.registerEvent(ExplosiveBlockBreakEvent.class, normalListener, ePriority, + pm.registerEvent(ExplosiveBlockBreakEvent.class, normalListenerMonitor, EventPriority.MONITOR, new EventExecutor() { public void execute(Listener l, Event e) { - ((OnBlockBreakExplosiveBlockBreakEventListener)l) - .onPrisonExplosiveBlockBreakEvent((ExplosiveBlockBreakEvent)e); + ((OnBlockBreakExplosiveBlockBreakEventListenerMonitor)l) + .onPrisonExplosiveBlockBreakEventMonitor((ExplosiveBlockBreakEvent)e); } }, prison); - prison.getRegisteredBlockListeners().add( normalListener ); + prison.getRegisteredBlockListeners().add( normalListenerMonitor ); + } - pm.registerEvent(ExplosiveBlockBreakEvent.class, normalListenerMonitor, EventPriority.MONITOR, - new EventExecutor() { - public void execute(Listener l, Event e) { - ((OnBlockBreakExplosiveBlockBreakEventListenerMonitor)l) - .onPrisonExplosiveBlockBreakEventMonitor((ExplosiveBlockBreakEvent)e); - } - }, - prison); - prison.getRegisteredBlockListeners().add( normalListenerMonitor ); - } @@ -179,8 +195,10 @@ public void dumpEventListeners() { @Override public void dumpEventListeners( StringBuilder sb ) { - boolean isEventEnabled = isBoolean( AutoFeatures.isProcessPrisonEnchantsExplosiveEvents ); - + + String eP = getMessage( AutoFeatures.ProcessPrisons_ExplosiveBlockBreakEventsPriority ); + boolean isEventEnabled = eP != null && !"DISABLED".equalsIgnoreCase( eP ); + if ( !isEventEnabled ) { return; } @@ -194,6 +212,7 @@ public void dumpEventListeners( StringBuilder sb ) { if ( eventDisplay != null ) { sb.append( eventDisplay.toStringBuilder() ); + sb.append( "\n" ); } } catch ( Exception e ) { diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/autofeatures/events/AutoManagerTokenEnchant.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/autofeatures/events/AutoManagerTokenEnchant.java index 608278a2e..a9cc01921 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/autofeatures/events/AutoManagerTokenEnchant.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/autofeatures/events/AutoManagerTokenEnchant.java @@ -41,6 +41,9 @@ public class AutoManagerTokenEnchantEventListener @EventHandler(priority=EventPriority.LOW) public void onTEBlockExplode(TEBlockExplodeEvent e) { + if ( isDisabled( e.getBlock().getLocation().getWorld().getName() ) ) { + return; + } genericBlockExplodeEventAutoManager( e ); } } @@ -51,6 +54,9 @@ public class OnBlockBreakEventTokenEnchantEventListener @EventHandler(priority=EventPriority.NORMAL) public void onTEBlockExplode(TEBlockExplodeEvent e) { + if ( isDisabled( e.getBlock().getLocation().getWorld().getName() ) ) { + return; + } genericBlockExplodeEvent( e ); } } @@ -61,14 +67,19 @@ public class OnBlockBreakEventTokenEnchantEventListenerMonitor @EventHandler(priority=EventPriority.MONITOR) public void onTEBlockExplode(TEBlockExplodeEvent e) { + if ( isDisabled( e.getBlock().getLocation().getWorld().getName() ) ) { + return; + } genericBlockExplodeEventMonitor( e ); } } @Override public void initialize() { - boolean isEventEnabled = isBoolean( AutoFeatures.isProcessTokensEnchantExplosiveEvents ); - + + String eP = getMessage( AutoFeatures.TokenEnchantBlockExplodeEventPriority ); + boolean isEventEnabled = eP != null && !"DISABLED".equalsIgnoreCase( eP ); + if ( !isEventEnabled ) { return; } @@ -83,7 +94,6 @@ public void initialize() { Output.get().logInfo( "AutoManager: Trying to register TokenEnchant" ); - String eP = getMessage( AutoFeatures.TokenEnchantBlockExplodeEventPriority ); BlockBreakPriority eventPriority = BlockBreakPriority.fromString( eP ); if ( eventPriority != BlockBreakPriority.DISABLED ) { @@ -116,30 +126,36 @@ public void execute(Listener l, Event e) { prison); prison.getRegisteredBlockListeners().add( autoManagerlListener ); } + else if ( isBoolean( AutoFeatures.normalDrop ) ) { + + OnBlockBreakEventTokenEnchantEventListener normalListener = + new OnBlockBreakEventTokenEnchantEventListener(); + + pm.registerEvent(TEBlockExplodeEvent.class, normalListener, ePriority, + new EventExecutor() { + public void execute(Listener l, Event e) { + ((OnBlockBreakEventTokenEnchantEventListener)l) + .onTEBlockExplode((TEBlockExplodeEvent)e); + } + }, + prison); + prison.getRegisteredBlockListeners().add( normalListener ); + } - OnBlockBreakEventTokenEnchantEventListener normalListener = - new OnBlockBreakEventTokenEnchantEventListener(); + } + else { - pm.registerEvent(TEBlockExplodeEvent.class, normalListener, ePriority, + pm.registerEvent(TEBlockExplodeEvent.class, normalListenerMonitor, EventPriority.MONITOR, new EventExecutor() { public void execute(Listener l, Event e) { - ((OnBlockBreakEventTokenEnchantEventListener)l) + ((OnBlockBreakEventTokenEnchantEventListenerMonitor)l) .onTEBlockExplode((TEBlockExplodeEvent)e); } }, prison); - prison.getRegisteredBlockListeners().add( normalListener ); + prison.getRegisteredBlockListeners().add( normalListenerMonitor ); } - pm.registerEvent(TEBlockExplodeEvent.class, normalListenerMonitor, EventPriority.MONITOR, - new EventExecutor() { - public void execute(Listener l, Event e) { - ((OnBlockBreakEventTokenEnchantEventListenerMonitor)l) - .onTEBlockExplode((TEBlockExplodeEvent)e); - } - }, - prison); - prison.getRegisteredBlockListeners().add( normalListenerMonitor ); } } @@ -182,8 +198,10 @@ public void dumpEventListeners() { @Override public void dumpEventListeners( StringBuilder sb ) { - boolean isEventEnabled = isBoolean( AutoFeatures.isProcessTokensEnchantExplosiveEvents ); + String eP = getMessage( AutoFeatures.TokenEnchantBlockExplodeEventPriority ); + boolean isEventEnabled = eP != null && !"DISABLED".equalsIgnoreCase( eP ); + if ( !isEventEnabled ) { return; } @@ -201,6 +219,7 @@ public void dumpEventListeners( StringBuilder sb ) { if ( eventDisplay != null ) { sb.append( eventDisplay.toStringBuilder() ); + sb.append( "\n" ); } } catch ( ClassNotFoundException e ) { diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/autofeatures/events/AutoManagerZenchantments.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/autofeatures/events/AutoManagerZenchantments.java index 1eb311a92..1528a2b1e 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/autofeatures/events/AutoManagerZenchantments.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/autofeatures/events/AutoManagerZenchantments.java @@ -40,6 +40,9 @@ public class AutoManagerBlockShredEventListener @EventHandler(priority=EventPriority.NORMAL) public void onBlockShredBreak(BlockShredEvent e) { + if ( isDisabled( e.getBlock().getLocation().getWorld().getName() ) ) { + return; + } genericBlockEventAutoManager( e ); } } @@ -50,6 +53,9 @@ public class OnBlockBreakBlockShredEventListener @EventHandler(priority=EventPriority.NORMAL) public void onBlockShredBreak(BlockShredEvent e) { + if ( isDisabled( e.getBlock().getLocation().getWorld().getName() ) ) { + return; + } genericBlockEvent( e ); } } @@ -60,6 +66,9 @@ public class OnBlockBreakBlockShredEventListenerMonitor @EventHandler(priority=EventPriority.MONITOR) public void onBlockShredBreakMonitor(BlockShredEvent e) { + if ( isDisabled( e.getBlock().getLocation().getWorld().getName() ) ) { + return; + } genericBlockEventMonitor( e ); } } @@ -67,8 +76,10 @@ public void onBlockShredBreakMonitor(BlockShredEvent e) { @Override public void initialize() { - boolean isEventEnabled = isBoolean( AutoFeatures.isProcessZenchantsBlockExplodeEvents ); + String eP = getMessage( AutoFeatures.ZenchantmentsBlockShredEventPriority ); + boolean isEventEnabled = eP != null && !"DISABLED".equalsIgnoreCase( eP ); + if ( !isEventEnabled ) { return; } @@ -83,7 +94,6 @@ public void initialize() { Output.get().logInfo( "AutoManager: Trying to register Zenchantments" ); - String eP = getMessage( AutoFeatures.ZenchantmentsBlockShredEventPriority ); BlockBreakPriority eventPriority = BlockBreakPriority.fromString( eP ); if ( eventPriority != BlockBreakPriority.DISABLED ) { @@ -121,11 +131,31 @@ public void execute(Listener l, Event e) { prison); prison.getRegisteredBlockListeners().add( autoManagerlListener ); } + else if ( isBoolean( AutoFeatures.normalDrop ) ) { + + OnBlockBreakBlockShredEventListener normalListener = + new OnBlockBreakBlockShredEventListener(); + + pm.registerEvent(BlockShredEvent.class, normalListener, ePriority, + new EventExecutor() { + public void execute(Listener l, Event e) { + if ( l instanceof OnBlockBreakBlockShredEventListenerMonitor && + e instanceof BlockShredEvent ) { + OnBlockBreakBlockShredEventListenerMonitor lmon = + (OnBlockBreakBlockShredEventListenerMonitor) l; + BlockShredEvent event = (BlockShredEvent) e; + lmon.onBlockShredBreakMonitor( event ); + } + } + }, + prison); + prison.getRegisteredBlockListeners().add( normalListener ); + } - OnBlockBreakBlockShredEventListener normalListener = - new OnBlockBreakBlockShredEventListener(); - - pm.registerEvent(BlockShredEvent.class, normalListener, ePriority, + } + else { + + pm.registerEvent(BlockShredEvent.class, normalListenerMonitor, EventPriority.MONITOR, new EventExecutor() { public void execute(Listener l, Event e) { if ( l instanceof OnBlockBreakBlockShredEventListenerMonitor && @@ -138,23 +168,9 @@ public void execute(Listener l, Event e) { } }, prison); - prison.getRegisteredBlockListeners().add( normalListener ); + prison.getRegisteredBlockListeners().add( normalListenerMonitor ); } - pm.registerEvent(BlockShredEvent.class, normalListenerMonitor, EventPriority.MONITOR, - new EventExecutor() { - public void execute(Listener l, Event e) { - if ( l instanceof OnBlockBreakBlockShredEventListenerMonitor && - e instanceof BlockShredEvent ) { - OnBlockBreakBlockShredEventListenerMonitor lmon = - (OnBlockBreakBlockShredEventListenerMonitor) l; - BlockShredEvent event = (BlockShredEvent) e; - lmon.onBlockShredBreakMonitor( event ); - } - } - }, - prison); - prison.getRegisteredBlockListeners().add( normalListenerMonitor ); } } @@ -195,7 +211,9 @@ public void dumpEventListeners() { @Override public void dumpEventListeners( StringBuilder sb ) { - boolean isEventEnabled = isBoolean( AutoFeatures.isProcessZenchantsBlockExplodeEvents ); + + String eP = getMessage( AutoFeatures.ZenchantmentsBlockShredEventPriority ); + boolean isEventEnabled = eP != null && !"DISABLED".equalsIgnoreCase( eP ); if ( !isEventEnabled ) { return; @@ -214,6 +232,9 @@ public void dumpEventListeners( StringBuilder sb ) { if ( eventDisplay != null ) { sb.append( eventDisplay.toStringBuilder() ); + sb.append( "NOTE: Zenchantments uses the same HandlerList as BlockBreakEvent so " + + "listeners are combined due to this bug.\n" ); + sb.append( "\n" ); } } catch ( ClassNotFoundException e ) { diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/autofeatures/events/PrisonDebugBlockInspector.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/autofeatures/events/PrisonDebugBlockInspector.java new file mode 100644 index 000000000..9719a26a0 --- /dev/null +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/autofeatures/events/PrisonDebugBlockInspector.java @@ -0,0 +1,307 @@ +package tech.mcprison.prison.spigot.autofeatures.events; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +import org.bukkit.event.EventException; +import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.plugin.RegisteredListener; + +import com.cryptomorin.xseries.XMaterial; +import com.google.common.eventbus.Subscribe; + +import tech.mcprison.prison.Prison; +import tech.mcprison.prison.internal.ItemStack; +import tech.mcprison.prison.internal.block.MineTargetPrisonBlock; +import tech.mcprison.prison.internal.events.player.PrisonPlayerInteractEvent; +import tech.mcprison.prison.mines.data.Mine; +import tech.mcprison.prison.output.Output; +import tech.mcprison.prison.selection.SelectionManager; +import tech.mcprison.prison.spigot.block.OnBlockBreakMines; +import tech.mcprison.prison.spigot.block.SpigotBlock; +import tech.mcprison.prison.spigot.block.SpigotItemStack; +import tech.mcprison.prison.spigot.compat.SpigotCompatibility; +import tech.mcprison.prison.spigot.game.SpigotPlayer; +import tech.mcprison.prison.util.Location; + +public class PrisonDebugBlockInspector +// extends OnBlockBreakMines +{ + OnBlockBreakMines obbMines; + + public PrisonDebugBlockInspector() { + super(); + + obbMines = new OnBlockBreakMines(); + } + + public void init() { + Prison.get().getEventBus().register(this); + } + + @Subscribe + public void onPlayerInteract( PrisonPlayerInteractEvent e ) { + ItemStack ourItem = e.getItemInHand(); + ItemStack toolItem = SelectionManager.SELECTION_TOOL; + + if ( !ourItem.equals(toolItem) || !Output.get().isDebug() ) { + return; + } + //e.setCanceled(true); + + SpigotPlayer player = (SpigotPlayer) e.getPlayer(); + + boolean isSneaking = player.isSneaking(); + + Location location = e.getClicked(); + SpigotBlock sBlock = (SpigotBlock) location.getBlockAt(); + + UUID playerUUID = e.getPlayer().getUUID(); + Mine mine = obbMines.findMine( playerUUID, sBlock, null, null ); + + if ( mine == null ) { + + player.sendMessage( + String.format( + "&dDebugBlockInfo: &7Not in a mine. &5%s &7%s", + sBlock.getBlockName(), location.toWorldCoordinates()) ); + + } + else { + player.sendMessage( + String.format( + "&dDebugBlockInfo: &3Mine &7%s. " + + "&5%s &7%s", + mine.getName(), + sBlock.getBlockName(), + location.toWorldCoordinates()) ); + + // Get the mine's targetBlock: + MineTargetPrisonBlock tBlock = mine.getTargetPrisonBlock( sBlock ); + + + String message = String.format( "&3TargetBlock: &7%s " + + "&3Mined: %s%b &3Broke: &7%b", + tBlock.getPrisonBlock().getBlockName(), + (tBlock.isMined() ? "&d" : "&2"), + tBlock.isMined(), + tBlock.isAirBroke() + ); + + player.sendMessage( message ); + + String message2 = String.format( " &3Counted: &7%b &3Edge: &7%b " + + "&3Exploded: %s%b &3IgnorAllEvents: &7%b", + tBlock.isCounted(), + tBlock.isEdge(), + (tBlock.isExploded() ? "&d" : "&2"), + tBlock.isExploded(), + tBlock.isIgnoreAllBlockEvents() + ); + + player.sendMessage( message2 ); + } + + + if ( !isSneaking ) { + player.sendMessage( + String.format( + "&dDebugBlockInfo: &7Sneak to test BlockBreakEvent with block." + ) ); + } + + else { +// player.sendMessage( +// String.format( +// "&dDebugBlockInfo: &7Sneak enabled! Block testing coming soon..." +// ) ); + + // Debug the block break events: + + dumpBlockBreakEvent( player, sBlock ); + + + + + + + } + +// if (e.getAction() == PrisonPlayerInteractEvent.Action.LEFT_CLICK_BLOCK) { +// // Set first position +// Selection sel = Prison.get().getSelectionManager().getSelection(e.getPlayer()); +// sel.setMin(e.getClicked()); +// Prison.get().getSelectionManager().setSelection(e.getPlayer(), sel); +// e.getPlayer() +// .sendMessage("&7First position set to &8" + e.getClicked().toBlockCoordinates()); +// +// checkForEvent(e.getPlayer(), sel); +// } else if (e.getAction() == PrisonPlayerInteractEvent.Action.RIGHT_CLICK_BLOCK) { +// // Set second position +// Selection sel = Prison.get().getSelectionManager().getSelection(e.getPlayer()); +// sel.setMax(e.getClicked()); +// Prison.get().getSelectionManager().setSelection(e.getPlayer(), sel); +// e.getPlayer() +// .sendMessage("&7Second position set to &8" + e.getClicked().toBlockCoordinates()); +// +// checkForEvent(e.getPlayer(), sel); +// } + } + + public void dumpBlockBreakEvent( SpigotPlayer player, SpigotBlock sBlock ) { + List output = new ArrayList<>(); + + // Save the item held in the player's hand, which should be the prison wand: + org.bukkit.inventory.ItemStack heldItem = SpigotCompatibility.getInstance().getItemInMainHand( player.getWrapper() ); + + BlockBreakEvent bbe = new BlockBreakEvent( sBlock.getWrapper(), player.getWrapper() ); + + String blockName = sBlock.getBlockName().toLowerCase(); + + boolean useShovel = blockName.matches( + "^clay$|farmland|grass_block|dirt|gravel|mycelium|" + + "podzol|^sand$|^red_sand$|soul_sand|soul_soil|" + + "concrete_powder|^snow$|snow_block|powder_snow" ); + +// XMaterial. + + boolean useAxe = blockName.matches( + "wood$|acacia|birch|jungle|spruce|leaves|crimson|" + + "sapling|bamboo|ladder|vine|bed$|fence|chest$|" + + "table|bookshelf|jack_o_lantern|^melon$|^pumpkn$|" + + "sign|^cocoa$|mushroom_block|note_block|campfire|" + + "banner|beehive|loom|barrel|jukebox|composter|" + + "daylight_detector" + ); + +// boolean isLeaves = blockName.contains( "leaves" ); +// boolean isWood = blockName.matches( "wood|log|planks|sapling" ); + + + SpigotItemStack tool = useShovel ? + new SpigotItemStack( XMaterial.DIAMOND_SHOVEL.parseItem() ) : + ( useAxe ? + new SpigotItemStack( XMaterial.DIAMOND_AXE.parseItem() ) : + new SpigotItemStack( XMaterial.DIAMOND_PICKAXE.parseItem() + ) ); + + + // Temporaily put the tool in the player's hand: + SpigotCompatibility.getInstance().setItemInMainHand( player.getWrapper(), tool.getBukkitStack() ); + + output.add( + String.format( "&dBlockBreakEvent Dump: &7%s &3%s", + sBlock.getBlockName(), + sBlock.getLocation().toBlockCoordinates() + ) ); + output.add( + String.format( " &3Tool Used for drops: &2%s", + tool.getName() + ) ); + + + printEventStatus( bbe, "-initial-", "", sBlock, tool, output ); + + for ( RegisteredListener listener : bbe.getHandlers().getRegisteredListeners() ) { + + try { + listener.callEvent( bbe ); + } + catch ( EventException e ) { + output.add( + String.format( " &cError calling event: &3%s &2[%s]", + listener.getPlugin().getName(), + e.getMessage() + ) ); + + } + + printEventStatus( bbe, + listener.getPlugin().getName(), listener.getPriority().name(), sBlock, tool, output ); + + } + + + // Put the heldItem back in the player's hand, which should be the prison wand: + SpigotCompatibility.getInstance().setItemInMainHand( player.getWrapper(), heldItem ); + + for ( String outputLine : output ) + { + Output.get().logInfo( outputLine ); + } + } + + private void printEventStatus( BlockBreakEvent bbe, + String plugin, String priority, SpigotBlock sBlock, + SpigotItemStack tool, + List output ) { + StringBuilder sb = new StringBuilder(); + sb.append( " " ); + + boolean isCanceled = bbe.isCancelled(); + boolean isDropItems = isDropItems( bbe ); + + // Get a fresh copy of the block to ensure we pickup the latest status: + SpigotBlock sBlk = (SpigotBlock) sBlock.getLocation().getBlockAt(); + + + List bukkitDrops = new ArrayList<>(); + obbMines.collectBukkitDrops( bukkitDrops, null, tool, sBlk ); + bukkitDrops = obbMines.mergeDrops( bukkitDrops ); + + sb.append( " &3Plugin: &7" ).append( plugin ).append( " " ) + .append( priority == null ? "" : priority ).append( " " ); + + sb.append( "&3Canceled: " ).append( isCanceled ? "&c" : "&a" ) + .append( isCanceled ? "true " : "false" ); + + if ( !sBlock.getBlockName().equalsIgnoreCase( sBlk.getBlockName() )) { + + sb.append( "&a" ).append( sBlk.getBlockName() ).append( " " ); + } + + + + if ( !isDropItems ) { + + sb.append( "&3No Drops" ); + } + + output.add( sb.toString() ); + + if ( isDropItems ) { + sb.setLength( 0 ); + + sb.append( " &3Drops:" ); +// List drops = sBlk.getDrops( tool ); + for ( ItemStack itemStack : bukkitDrops ) + { + sb.append( " &a" ).append( itemStack.getName() ); + if ( itemStack.getAmount() > 0 ) { + sb.append( "&3(&2" ).append( itemStack.getAmount() ).append( "&3)" ); + } + } + + if ( bukkitDrops.size() > 0 ) { + output.add( sb.toString() ); + } + } + } + + private boolean isDropItems( BlockBreakEvent bbe ) { + boolean results = true; + + try { + results = bbe.isDropItems(); + } + catch ( NoSuchMethodError e ) { + // ignore.... not supported in this version of spigot: + } + catch ( Exception e ) { + // ignore.... not supported in this version of spigot: + } + + return results; + } +} diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/backpacks/BackpacksListeners.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/backpacks/BackpacksListeners.java index 727759784..d380712b0 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/backpacks/BackpacksListeners.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/backpacks/BackpacksListeners.java @@ -14,10 +14,11 @@ import tech.mcprison.prison.spigot.SpigotPrison; import tech.mcprison.prison.spigot.SpigotUtil; import tech.mcprison.prison.spigot.compat.Compatibility; +import tech.mcprison.prison.spigot.compat.SpigotCompatibility; public class BackpacksListeners implements Listener { - Compatibility compat = SpigotPrison.getInstance().getCompatibility(); + Compatibility compat = SpigotCompatibility.getInstance(); @EventHandler public void onPlayerJoinBackpack(PlayerJoinEvent e){ @@ -31,7 +32,7 @@ public void onBackpackCloseEvent(InventoryCloseEvent e){ @EventHandler public void onDeadBackpack(PlayerDeathEvent e){ - onDeadBackpackAction(e); + onDeathBackpackAction(e); } @@ -49,7 +50,7 @@ public void onPlayerClickBackpackItem(PlayerInteractEvent e){ backpackItemClickAction(e); } - private void onDeadBackpackAction(PlayerDeathEvent e) { + private void onDeathBackpackAction(PlayerDeathEvent e) { if (getBoolean(BackpacksUtil.get().getBackpacksConfig().getString("Options.BackPack_Lose_Items_On_Death"))) { BackpacksUtil.get().resetBackpack(e.getEntity()); if (getBoolean(BackpacksUtil.get().getBackpacksConfig().getString("Options.Multiple-BackPacks-For-Player-Enabled"))) { diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/backpacks/BackpacksUtil.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/backpacks/BackpacksUtil.java index 156d9e3dc..d01a8cf4a 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/backpacks/BackpacksUtil.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/backpacks/BackpacksUtil.java @@ -25,7 +25,9 @@ import tech.mcprison.prison.spigot.SpigotPrison; import tech.mcprison.prison.spigot.SpigotUtil; import tech.mcprison.prison.spigot.compat.Compatibility; +import tech.mcprison.prison.spigot.compat.SpigotCompatibility; import tech.mcprison.prison.spigot.configs.BackpacksConfig; +import tech.mcprison.prison.spigot.configs.MessagesConfig; import tech.mcprison.prison.spigot.game.SpigotPlayer; /** @@ -34,13 +36,12 @@ public class BackpacksUtil { private static BackpacksUtil instance; - private final Configuration messages = SpigotPrison.getInstance().getMessagesConfig(); private Configuration backpacksConfig = SpigotPrison.getInstance().getBackpacksConfig(); private File backpacksFile = new File(SpigotPrison.getInstance().getDataFolder() + "/backpacks/backpacksData.yml"); private FileConfiguration backpacksDataConfig = YamlConfiguration.loadConfiguration(backpacksFile); public static List openBackpacks = new ArrayList<>(); public static List backpackEdited = new ArrayList<>(); - private final Compatibility compat = SpigotPrison.getInstance().getCompatibility(); + private final Compatibility compat = SpigotCompatibility.getInstance(); private final int backpackDefaultSize = Integer.parseInt(backpacksConfig.getString("Options.BackPack_Default_Size")); /** @@ -1280,7 +1281,7 @@ private void backPackItem(Player p) { ItemStack item; List itemLore = createLore( - messages.getString("Lore.ClickToOpenBackpack") + SpigotPrison.getInstance().getMessagesConfig().getString(MessagesConfig.StringID.spigot_gui_lore_click_to_open) ); item = createButton(SpigotUtil.getXMaterial(backpacksConfig.getString("Options.BackPack_Item")).parseItem(), itemLore, backpacksConfig.getString("Options.BackPack_Item_Title")); diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/backpacks/NewBackpacksUtil.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/backpacks/NewBackpacksUtil.java new file mode 100644 index 000000000..cd9617ba9 --- /dev/null +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/backpacks/NewBackpacksUtil.java @@ -0,0 +1,679 @@ +package tech.mcprison.prison.spigot.backpacks; + +import com.cryptomorin.xseries.XMaterial; +import com.cryptomorin.xseries.XSound; +import org.bukkit.Bukkit; +import org.bukkit.Sound; +import org.bukkit.configuration.Configuration; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.entity.Player; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import tech.mcprison.prison.cache.PlayerCache; +import tech.mcprison.prison.cache.PlayerCachePlayerData; +import tech.mcprison.prison.output.Output; +import tech.mcprison.prison.spigot.SpigotPrison; +import tech.mcprison.prison.spigot.configs.MessagesConfig; +import tech.mcprison.prison.spigot.game.SpigotPlayer; +import tech.mcprison.prison.spigot.gui.backpacks.BackpacksPlayerGUI; +import tech.mcprison.prison.spigot.gui.guiutility.ButtonLore; +import tech.mcprison.prison.spigot.inventory.SpigotInventory; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +/** + * @author AnonymousGCA (GABRYCA) + */ +public class NewBackpacksUtil { + + private static NewBackpacksUtil instance; + private MessagesConfig messages; + private Configuration backpacksConfig; + private Configuration backpacksData; + private boolean isFoundDeprecatedData; + private boolean isBackpackUsePermissionEnabled; + private boolean isBackpackAutoPickupEnabled; + private boolean isBackpackOpenItemEnabled; + private boolean isBackpackOpenItemGivenOnJoin; + private boolean isBackpackEnabledIfLimitZero; + private boolean isBackpackLostOnDeath; + private boolean isBackpackOpenSoundEnabled; + private boolean isBackpackCloseSoundEnabled; + private boolean isMultipleBackpacksEnabled; + private String backpackUsePermission; + private String backpackOpenItemTitle; + private XSound backpackOpenSound = XSound.BLOCK_CHEST_OPEN; + private XSound backpackCloseSound = XSound.BLOCK_CHEST_CLOSE; + private int defaultBackpackSize; + private int defaultBackpackLimitForPlayer; + private XMaterial backpackOpenItem = XMaterial.CHEST; + + + /** + * Get an instance of Backpacks to get full access to the API. + * + * If Backpacks are disabled, this will return null. + * + * @return BackpacksUtil + */ + public static NewBackpacksUtil get() { + + if (!getBoolean(SpigotPrison.getInstance().getConfig().getString("backpacks"))) { + return null; + } + + if (instance == null) { + instance = new NewBackpacksUtil(); + instance.initCachedData(); + } + + return instance; + } + + /** + * Check if Backpack AutoPickup is enabled. + * + * @return boolean. + */ + public boolean isBackpackAutoPickupEnabled() { + return this.isBackpackAutoPickupEnabled; + } + + /** + * Check if the Backpack Open Item is enabled. + * + * @return boolean. + */ + public boolean isBackpackOpenItemEnabled() { + return this.isBackpackOpenItemEnabled; + } + + /** + * Check if the Backpack Open Item is given on join. + * + * @return boolean. + */ + public boolean isBackpackOpenItemGivenOnJoin() { + return this.isBackpackOpenItemGivenOnJoin; + } + + /** + * Check if Backpack can be used and Backpack item too + * if the Player's limit is set to 0. + * + * @return boolean. + */ + public boolean isBackpackEnabledIfLimitZero() { + return this.isBackpackEnabledIfLimitZero; + } + + /** + * Check if Backpack is deleted/reset on death. + * + * @return boolean. + */ + public boolean isBackpackLostOnDeath() { + return this.isBackpackLostOnDeath; + } + + /** + * Check if Backpack open sound is enabled. + * + * @return boolean. + * */ + public boolean isBackpackOpenSoundEnabled(){ + return this.isBackpackOpenSoundEnabled; + } + + /** + * Check if Backpack close sound is enabled. + * + * @return boolean. + * */ + public boolean isBackpackCloseSoundEnabled(){ + return this.isBackpackCloseSoundEnabled; + } + + /** + * Get Backpack Open Item Title. + * + * @return String. + * */ + public String getBackpackOpenItemTitle(){ + return this.backpackOpenItemTitle; + } + + /** + * Get Backpack Open Permission. + * + * @return String. + * */ + public String getBackpackUsePermission(){ + return this.backpackUsePermission; + } + + /** + * Get Backpack Open Sound. + * + * @return Sound. + * */ + public Sound getBackpackOpenSound(){ + return this.backpackOpenSound.parseSound(); + } + + /** + * Get Backpack Close Sound. + * + * @return Sound. + * */ + public Sound getBackpackCloseSound(){ + return this.backpackCloseSound.parseSound(); + } + + /** + * Get Backpack Open Item. + * + * @return ItemStack. + * */ + public ItemStack getBackpackOpenItem(){ + + ItemStack backPackOpenItemStack = new ItemStack(backpackOpenItem.parseMaterial(), 1); + ItemMeta meta = backPackOpenItemStack.getItemMeta(); + meta.setDisplayName(SpigotPrison.format(SpigotPrison.format(backpackOpenItemTitle))); + ButtonLore lore = new ButtonLore(); + lore.setLoreAction("Click to open Backpack!"); + meta.setLore(lore.getLore()); + backPackOpenItemStack.setItemMeta(meta); + + return backPackOpenItemStack; + } + + /** + * Return boolean value from String. + * + * @param string - Boolean string. + * @return boolean. + */ + public static boolean getBoolean(String string) { + return string != null && string.equalsIgnoreCase("true"); + } + + /** + * Init options that will be cached. + */ + private void initCachedData() { + messages = SpigotPrison.getInstance().getMessagesConfig(); + backpacksConfig = SpigotPrison.getInstance().getBackpacksConfig(); + if (new File(SpigotPrison.getInstance().getDataFolder() + "/backpacks/backpacksData.yml").exists()) { + backpacksData = YamlConfiguration.loadConfiguration(new File(SpigotPrison.getInstance().getDataFolder() + "/backpacks/backpacksData.yml")); + isFoundDeprecatedData = true; + } else { + isFoundDeprecatedData = false; + } + isBackpackUsePermissionEnabled = getBoolean(backpacksConfig.getString("Options.BackPack_Use_Permission_Enabled")); + isBackpackAutoPickupEnabled = getBoolean(backpacksConfig.getString("Options.BackPack_AutoPickup_Usable")); + isBackpackOpenItemEnabled = getBoolean(backpacksConfig.getString("Options.Back_Pack_GUI_Opener_Item")); + isBackpackOpenItemGivenOnJoin = getBoolean(backpacksConfig.getString("Options.BackPack_Item_OnJoin")); + isBackpackEnabledIfLimitZero = getBoolean(backpacksConfig.getString("Options.BackPack_Access_And_Item_If_Limit_Is_0")); + isBackpackLostOnDeath = getBoolean(backpacksConfig.getString("Options.BackPack_Lose_Items_On_Death")); + isBackpackOpenSoundEnabled = getBoolean(backpacksConfig.getString("Options.BackPack_Open_Sound_Enabled")); + isBackpackCloseSoundEnabled = getBoolean(backpacksConfig.getString("Options.BackPack_Close_Sound_Enabled")); + isMultipleBackpacksEnabled = getBoolean(backpacksConfig.getString("Options.Multiple-BackPacks-For-Player-Enabled")); + if (XSound.matchXSound(backpacksConfig.getString("Options.BackPack_Open_Sound")).isPresent()) { + backpackOpenSound = XSound.matchXSound(backpacksConfig.getString("Options.BackPack_Open_Sound")).get(); + } + if (XSound.matchXSound(backpacksConfig.getString("Options.BackPack_Close_Sound")).isPresent()) { + backpackCloseSound = XSound.matchXSound(backpacksConfig.getString("Options.BackPack_Close_Sound")).get(); + } + if (XMaterial.matchXMaterial(backpacksConfig.getString("Options.BackPack_Item")).isPresent()) { + backpackOpenItem = XMaterial.matchXMaterial(backpacksConfig.getString("Options.BackPack_Item")).get(); + } + backpackUsePermission = backpacksConfig.getString("Options.BackPack_Use_Permission"); + backpackOpenItemTitle = backpacksConfig.getString("Options.BackPack_Item_Title"); + defaultBackpackSize = Integer.parseInt(backpacksConfig.getString("Options.BackPack_Default_Size")); + defaultBackpackLimitForPlayer = Integer.parseInt(backpacksConfig.getString("Options.Multiple-BackPacks-For-Player")); + } + + /** + * Save a Player's Backpack. + * This method will return true if ran with success, false if Player is missing permission (if enabled) + * or some conditions aren't met, or even errors. + * Essentially, return true if success, false if fail. + * + * @param p - Player. + * @param inv - Backpack. + * @return boolean. + */ + public boolean setBackpack(Player p, Inventory inv, int id) { + + if (!canOwnBackpacks(p)) { + return false; + } + + PlayerCachePlayerData pData = PlayerCache.getInstance().getOnlinePlayer(new SpigotPlayer(p)); + + if (pData == null) { + Output.get().sendInfo(new SpigotPlayer(p), "Sorry, unable to find cached data about you, this may be a bug! Please report it."); + return false; + } + + List inventories = prisonInventoryToNormalConverter(pData.getBackpacks()); + + if (inventories.get(id) != null) { + // No need to check more conditions here, Player already owns a backpack here. + inventories.set(id, inv); + + pData.setBackpacks(normalInventoryToPrisonConverter(inventories)); + pData.isDirty(); + } else { + + return addBackpack(p, inv); + } + return true; + } + + /** + * Add a Backpack to a Player. + *

+ * Return true if success, false if fail. + * + * @param p - Player. + * @param inv - Inventory. + * @return boolean. + */ + public boolean addBackpack(Player p, Inventory inv) { + + if (!canOwnBackpacks(p)) { + return false; + } + + if (inv.getSize() <= getBackpackPermSize(p)) { + Output.get().sendWarn(new SpigotPlayer(p), "Sorry but you can't own a Backpack of this size."); + return false; + } + + PlayerCachePlayerData pData = PlayerCache.getInstance().getOnlinePlayer(new SpigotPlayer(p)); + + if (pData == null) { + Output.get().sendInfo(new SpigotPlayer(p), "Sorry, unable to find cached data on you, this may be a bug! Please report it."); + return false; + } + + List inventories = prisonInventoryToNormalConverter(pData.getBackpacks()); + + if (reachedBackpacksLimit(p)) { + Output.get().sendWarn(new SpigotPlayer(p), "Sorry, you can't own more Backpacks!"); + return false; + } + + inventories.add(inv); + pData.setBackpacks(normalInventoryToPrisonConverter(inventories)); + pData.isDirty(); + return true; + } + + /** + * Check if player reached limit of own backpacks. + * + * @return boolean - True if reached, false if not. + */ + public boolean reachedBackpacksLimit(Player p) { + return isMultipleBackpacksEnabled && (getBackpacksLimit(p) <= getNumberOwnedBackpacks(p)); + } + + /** + * Get number of Backpacks own by Player. + * + * @param p - Player. + */ + public int getNumberOwnedBackpacks(Player p) { + PlayerCachePlayerData pData = PlayerCache.getInstance().getOnlinePlayer(new SpigotPlayer(p)); + + if (pData == null) { + return 0; + } + + return pData.getBackpacks().size(); + } + + // TODO + // Not sure if this data is cached yet. + private int getBackpacksLimit(Player p) { + return defaultBackpackLimitForPlayer; + } + + /** + * Check if Player can own Backpacks. + * Return true if can, False otherwise. + * + * @param p - Player. + * @return boolean. + */ + public boolean canOwnBackpacks(Player p) { + return !isBackpackUsePermissionEnabled || p.hasPermission(backpackUsePermission); + } + + /** + * Get a Player's Backpack, there may be multiple ones. + * + * @param p - Player. + * @param id - int. + * @return Inventory - Backpack. + */ + public Inventory getBackpack(Player p, int id) { + + PlayerCachePlayerData pData = PlayerCache.getInstance().getOnlinePlayer(new SpigotPlayer(p)); + + if (pData == null) { + return null; + } + + oldBackpacksConverter(p); + + if (pData.getBackpacks() == null || pData.getBackpacks().get(id) == null) { + return null; + } + SpigotInventory sInv = (SpigotInventory) pData.getBackpacks().get(id); + + return sInv.getWrapper(); + } + + /** + * Get Backpacks of a Player in a List of Inventories. + * + * @param p - Player. + * @return Inventory - List. + */ + public List getBackpacks(Player p) { + + PlayerCachePlayerData pData = PlayerCache.getInstance().getOnlinePlayer(new SpigotPlayer(p)); + + if (pData == null) { + return null; + } + + oldBackpacksConverter(p); + + if (pData.getBackpacks() == null) { + return null; + } + + return prisonInventoryToNormalConverter(pData.getBackpacks()); + } + + /** + * Open Player's Backpack. + * + * Return true if open with success, false if fail or error. + * + * @param p - Player. + * @param id - Int. + * + * return boolean. + * */ + public boolean openBackpack(Player p, int id){ + + // Check if Player owns a Backpack with this ID. + if (getBackpack(p, id) == null){ + + Output.get().sendWarn(new SpigotPlayer(p), "Backpack not found!"); + return false; + } + + BackpacksPlayerGUI gui = new BackpacksPlayerGUI(p, id); + gui.open(); + return true; + } + + /** + * Converts a Prison's Inventory List to the spigot standard one. + * + * @param pInv - PrisonInventory List. + * @return List - Inventory. + */ + private List prisonInventoryToNormalConverter(List pInv) { + List inventories = new ArrayList<>(); + for (tech.mcprison.prison.internal.inventory.Inventory pInvRead : pInv) { + SpigotInventory sInv = (SpigotInventory) pInvRead; + inventories.add(sInv.getWrapper()); + } + + return inventories; + } + + /** + * Converts a Spigot's normal Inventory List to the Prison one. + * + * @param inventories - Inventories. + * @return List - Prison Inventories. + */ + private List normalInventoryToPrisonConverter(List inventories) { + List pInv = new ArrayList<>(); + for (Inventory readInv : inventories) { + pInv.add(SpigotInventory.fromWrapper(readInv)); + } + return pInv; + } + + /** + * Converts old Backpacks storage to the new one, deleting the deprecated one for this player. + * + * @param p - Player. + */ + private void oldBackpacksConverter(Player p) { + if (isFoundDeprecatedData) { + if (backpacksData.getString("Inventories." + p.getUniqueId() + ".PlayerName") != null) { + + PlayerCachePlayerData pData = PlayerCache.getInstance().getOnlinePlayer(new SpigotPlayer(p)); + + List prisonBackpacks = pData.getBackpacks(); + List readBackpacks = new ArrayList<>(); + + Output.get().sendWarn(new SpigotPlayer(p), "The Backpack data got updated, conversion started..."); + File backpacksFile = new File(SpigotPrison.getInstance().getDataFolder() + "/backpacks/backpacksData.yml"); + FileConfiguration backpacksFileData = YamlConfiguration.loadConfiguration(backpacksFile); + + // Check if multiple backpacks is enabled and get the backpacks. + if (isMultipleBackpacksEnabled) { + for (String backpackIds : getBackpacksIDsList(p)) { + readBackpacks.add(getOldBackpackOwn(p, backpackIds)); + } + } else { + readBackpacks.add(getOldBackpackOwn(p)); + } + + // Set to null this data and save it in the old config. + backpacksFileData.set("Inventories." + p.getUniqueId(), null); + try { + backpacksFileData.save(backpacksFile); + } catch (IOException e) { + e.printStackTrace(); + } + + int numberConverted = 0; + for (Inventory inv : readBackpacks) { + numberConverted++; + prisonBackpacks.add(SpigotInventory.fromWrapper(inv)); + } + + pData.setBackpacks(prisonBackpacks); + pData.isDirty(); + Output.get().sendInfo(new SpigotPlayer(p), numberConverted + " Backpacks converted with success, will open soon..."); + } + } + } + + /** + * Get backpack size of a Player Backpack with the permission for a custom one. + */ + private int getBackpackPermSize(Player p, int backPackSize) { + SpigotPlayer sPlayer = new SpigotPlayer(p); + List perms = sPlayer.getPermissions("prison.backpack.size."); + int value = 0; + for (String permNumber : perms) { + int newValue = Integer.parseInt(permNumber.substring(21)); + if (newValue > value) { + value = (int) Math.ceil((float) newValue / 9) * 9; + } + } + + if (value != 0) { + return value; + } + return backPackSize; + } + + /** + * Get backpack size from permissions of a Player and/or defaults. + * + * @param p - Player. + * @return int - size. + */ + public int getBackpackPermSize(Player p) { + int backPackSize = defaultBackpackSize; + + if (backPackSize % 9 != 0) { + backPackSize = (int) Math.ceil((float) backPackSize / 9) * 9; + } + + if (backPackSize == 0) backPackSize = 9; + + return getBackpackPermSize(p, backPackSize); + } + + /** + * This method exists only for the conversion of the old deprecated one. + */ + @Deprecated + private Inventory getOldBackpackOwn(Player p) { + + int size = getOldSize(p); + Inventory inv = Bukkit.createInventory(p, size, SpigotPrison.format("&3" + p.getName() + " -> Backpack")); + + // Get the Items config section. + Set slots; + try { + slots = backpacksData.getConfigurationSection("Inventories." + p.getUniqueId() + ".Items").getKeys(false); + } catch (NullPointerException ex) { + return inv; + } + if (slots.size() != 0) { + for (String slot : slots) { + ItemStack finalItem = backpacksData.getItemStack("Inventories." + p.getUniqueId() + ".Items." + slot + ".ITEMSTACK"); + if (finalItem != null) { + int slotNumber = Integer.parseInt(slot); + if (size > slotNumber) { + inv.setItem(slotNumber, finalItem); + } + } + } + } + + return inv; + } + + /** + * This method exists only for the conversion of the old deprecated one. + */ + @Deprecated + private Inventory getOldBackpackOwn(Player p, String id) { + + int size = getOldSize(p, id); + Inventory inv = Bukkit.createInventory(p, size, SpigotPrison.format("&3" + p.getName() + " -> Backpack-" + id)); + + // Get the Items config section + Set slots; + try { + slots = backpacksData.getConfigurationSection("Inventories." + p.getUniqueId() + ".Items-" + id).getKeys(false); + } catch (NullPointerException ex) { + return inv; + } + if (slots.size() != 0) { + for (String slot : slots) { + ItemStack finalItem = backpacksData.getItemStack("Inventories." + p.getUniqueId() + ".Items-" + id + "." + slot + ".ITEMSTACK"); + if (finalItem != null) { + int slotNumber = Integer.parseInt(slot); + if (size > slotNumber) { + inv.setItem(slotNumber, finalItem); + } + } + } + } + + return inv; + } + + /** + * Don't use this method. + */ + @Deprecated + private int getOldSize(Player p) { + + int backPackSize = defaultBackpackSize; + + try { + backPackSize = Integer.parseInt(backpacksData.getString("Inventories." + p.getUniqueId() + ".Items.Size")); + } catch (NumberFormatException ignored) { + } + + if (backPackSize % 9 != 0) { + backPackSize = (int) Math.ceil((float) backPackSize / 9) * 9; + } + + if (backPackSize == 0) backPackSize = 9; + + return getBackpackPermSize(p, backPackSize); + } + + /** + * Don't use this method. + */ + @Deprecated + private int getOldSize(Player p, String id) { + int backPackSize = defaultBackpackSize; + + try { + backPackSize = Integer.parseInt(backpacksData.getString("Inventories." + p.getUniqueId() + ".Items-" + id + ".Size")); + } catch (NumberFormatException ignored) { + } + + if (backPackSize % 9 != 0) { + backPackSize = (int) Math.ceil((float) backPackSize / 9) * 9; + } + + if (backPackSize == 0) backPackSize = 9; + + return getBackpackPermSize(p, backPackSize); + } + + /** + * This method exists only for the conversion of the old deprecated one. + */ + @Deprecated + private List getBackpacksIDsList(Player p) { + List backpacksIDs = new ArrayList<>(); + + // Items can be -> Items- or just Items in the config, the default and old backpacks will have Items only, newer will be like + // Items-1 or anyway an ID, I'm just getting the ID with this which's what I need. + try { + for (String key : backpacksData.getConfigurationSection("Inventories." + p.getUniqueId()).getKeys(false)) { + if (!key.equalsIgnoreCase("Items") && !key.equalsIgnoreCase("Limit") && !key.equalsIgnoreCase("PlayerName") && !key.equalsIgnoreCase("UniqueID")) { + backpacksIDs.add(key.substring(6)); + } else { + if (!backpacksIDs.contains(null) && !key.equalsIgnoreCase("PlayerName") && !key.equalsIgnoreCase("UniqueID") && !key.equalsIgnoreCase("Limit")) { + backpacksIDs.add(null); + } + } + } + } catch (NullPointerException ignored) { + } + + return backpacksIDs; + } +} 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 d6cf03fba..91923243c 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 @@ -4,13 +4,13 @@ import java.util.List; import java.util.Optional; import java.util.Random; -import java.util.TreeMap; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.block.Block; import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; @@ -24,30 +24,31 @@ import tech.mcprison.prison.autofeatures.AutoFeaturesFileConfig.AutoFeatures; import tech.mcprison.prison.autofeatures.AutoFeaturesWrapper; import tech.mcprison.prison.cache.PlayerCache; +import tech.mcprison.prison.internal.block.MineTargetPrisonBlock; import tech.mcprison.prison.internal.block.PrisonBlock; +import tech.mcprison.prison.internal.block.PrisonBlockStatusData; import tech.mcprison.prison.mines.PrisonMines; import tech.mcprison.prison.mines.data.Mine; import tech.mcprison.prison.mines.features.MineBlockEvent.BlockEventType; -import tech.mcprison.prison.mines.features.MineTargetPrisonBlock; import tech.mcprison.prison.modules.Module; import tech.mcprison.prison.output.Output; import tech.mcprison.prison.output.Output.DebugTarget; import tech.mcprison.prison.spigot.SpigotPrison; import tech.mcprison.prison.spigot.api.ExplosiveBlockBreakEvent; import tech.mcprison.prison.spigot.api.PrisonMinesBlockBreakEvent; +import tech.mcprison.prison.spigot.autofeatures.AutoManagerBreakBlockTask; import tech.mcprison.prison.spigot.autofeatures.AutoManagerFeatures; 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.integrations.IntegrationCrazyEnchantmentsPickaxes; import tech.mcprison.prison.spigot.utils.BlockUtils; -import tech.mcprison.prison.spigot.utils.PrisonUtilsTitles; import tech.mcprison.prison.util.Text; public class OnBlockBreakEventCore + extends OnBlockBreakMines { - private PrisonMines prisonMineManager; - private boolean mineModuleDisabled = false; private int uses = 0; private long usesElapsedTimeNano = 0L; @@ -67,7 +68,7 @@ public OnBlockBreakEventCore() { this.autoFeatureWrapper = AutoFeaturesWrapper.getInstance(); - this.prisonMineManager = null; + this.teExplosionTriggerEnabled = true; @@ -122,6 +123,10 @@ public int getInteger( AutoFeatures feature ) { return autoFeatureWrapper.getInteger( feature ); } + public double getDouble( AutoFeatures feature ) { + return autoFeatureWrapper.getDouble( feature ); + } + protected List getListString( AutoFeatures feature ) { return autoFeatureWrapper.getListString( feature ); } @@ -204,7 +209,7 @@ protected void genericBlockExplodeEvent( BlastUseEvent e ) { protected void genericBlockExplodeEventAutoManager( BlastUseEvent e ) { // NOTE: If autoManager is turned off, then process only the blockEvents: boolean blockEventsOnly = !isBoolean(AutoFeatures.isAutoManagerEnabled); - genericBlastUseEvent( e, true, blockEventsOnly, true ); + genericBlastUseEvent( e, false, blockEventsOnly, true ); } @@ -236,7 +241,7 @@ protected void genericBlockExplodeEvent( PEExplosionEvent e ) { protected void genericBlockExplodeEventAutoManager( PEExplosionEvent e ) { // NOTE: If autoManager is turned off, then process only the blockEvents: boolean blockEventsOnly = !isBoolean(AutoFeatures.isAutoManagerEnabled); - genericExplosiveEvent( e, true, blockEventsOnly, true ); + genericExplosiveEvent( e, false, blockEventsOnly, true ); } @@ -270,9 +275,44 @@ protected void genericBlockExplodeEvent( ExplosiveBlockBreakEvent e ) { protected void genericBlockExplodeEventAutoManager( ExplosiveBlockBreakEvent e ) { // NOTE: If autoManager is turned off, then process only the blockEvents: boolean blockEventsOnly = !isBoolean(AutoFeatures.isAutoManagerEnabled); - genericExplosiveEvent( e, true, blockEventsOnly, true ); + genericExplosiveEvent( e, false, blockEventsOnly, true ); } +// protected boolean processMinesBlockBreakEvent( Cancellable event, Player player, Block block ) { +// boolean processEvent = true; +// +// SpigotBlock sBlock = new SpigotBlock( block ); +// if ( BlockUtils.getInstance().isUnbreakable( sBlock ) ) { +// event.setCancelled( true ); +// processEvent = false; +// } +// +// Mine mine = findMine( player, sBlock, null, null ); +// +// if ( mine == null ) { +// // Prison is unable to process blocks outside of mines right now, so exit: +// processEvent = false; +// } +// +// // If not minable, then display message and exit. +// if ( !mine.getMineStateMutex().isMinable() ) { +// +// SpigotPlayer sPlayer = new SpigotPlayer( player ); +// sPlayer.setActionBar( "Mine " + mine.getTag() + " is being reset... please wait." ); +// event.setCancelled( true ); +// processEvent = false; +// } +// MineTargetPrisonBlock targetBlock = mine.getTargetPrisonBlock( sBlock ); +// +// // If ignore all block events, then exit this function without logging anything: +// if ( targetBlock.isIgnoreAllBlockEvents() ) { +// event.setCancelled( true ); +// processEvent = false; +// } +// +// +// return processEvent; +// } /** *

This genericBlockEvent handles the basics of a BlockBreakEvent to see if it has happened @@ -291,6 +331,14 @@ protected void genericBlockEvent( BlockBreakEvent e, boolean monitor, boolean bl return; } + long start = System.nanoTime(); + + if ( e.isCancelled() || ignoreMinesBlockBreakEvent( e, e.getPlayer(), e.getBlock()) ) { + return; + } + + + // Register all external events such as mcMMO and EZBlocks: OnBlockBreakExternalEvents.getInstance().registerAllExternalEvents(); @@ -327,71 +375,9 @@ protected void genericBlockEvent( BlockBreakEvent e, boolean monitor, boolean bl } } -// boolean isAir = e.getBlock().getType() == null || e.getBlock().getType() == Material.AIR; - - -// Long playerUUIDLSB = Long.valueOf( pmEvent.getPlayer().getUniqueId().getLeastSignificantBits() ); -// -// // Get the cached mine, if it exists: -// Mine mine = getPlayerCache().get( playerUUIDLSB ); -// -// if ( mine == null || !mine.isInMineExact( pmEvent.getSpigotBlock().getLocation() ) ) { -// // Look for the correct mine to use. -// // Set mine to null so if cannot find the right one it will return a null: -// mine = findMineLocation( pmEvent.getSpigotBlock() ); -// -// // Store the mine in the player cache if not null: -// if ( mine != null ) { -// getPlayerCache().put( playerUUIDLSB, mine ); -// } -// } -// pmEvent.setMine( mine ); -// -// debugInfo.append( "mine=" + (mine == null ? "none" : mine.getName()) + " " ); -// -// -// if ( isToolDisabled( e.getPlayer() ) ) { -// -// PrisonUtilsTitles uTitles = new PrisonUtilsTitles(); -// uTitles.utilsTitlesActionBar( pmEvent.getSpigotPlayer(), "", -// "&cYour tool is worn-out and cannot be used." ); -// -// e.setCancelled( true ); -// debugInfo.append( "UNUSABLE_TOOL__WORN_OUT (event canceled) " ); -// } -// else if ( mine != null && BlockUtils.getInstance().isUnbreakable( sBlock ) ) { -// // The block is unbreakable because a utility has it locked: -// -// e.setCancelled( true ); -// debugInfo.append( "UNBREAKABLE_BLOCK_UTILS (event canceled) " ); -// } -// else if ( mine != null && (mine.isMineAccessByRank() || mine.isAccessPermissionEnabled()) && -// !mine.hasMiningAccess( pmEvent.getSpigotPlayer() ) ) { -// // The player does not have permission to access this mine, so do not process -// // -// -// e.setCancelled( true ); -// debugInfo.append( "ACCESS_DENIED (event canceled) " ); -// } -// else if ( blockEventsOnly ) { -// -// String triggered = null; -// -// doActionBlockEventOnly( sBlock, mine, e.getPlayer(), BlockEventType.blockBreak, triggered ); -// -// debugInfo.append( "(actionBlockEventOnly) " ); -// } -// else if ( monitor && mine == null ) { -// // bypass all processing since the block break is outside any mine: -// -// debugInfo.append( "(bypassed monitor no mine) " ); -// } -// else if ( monitor && mine != null ) { -// -// doActionMonitor( sBlock, mine ); -// -// debugInfo.append( "(monitor) " ); -// } + else if ( pmEvent.isMonitor() ) { + // Stop here, and prevent additional processing. Monitors should never process the event beyond this. + } // This is where the processing actually happens: else if ( pmEvent.getMine() != null || pmEvent.getMine() == null && @@ -419,10 +405,29 @@ else if ( pmEvent.getMine() != null || pmEvent.getMine() == null && } else { + // Cancel drops if so configured: + if ( isBoolean( AutoFeatures.cancelAllBlockEventBlockDrops ) ) { + + try + { + e.setDropItems( false ); + } + catch ( NoSuchMethodError e1 ) + { + String message = String.format( + "Warning: The autoFeaturesConfig.yml setting `cancelAllBlockEventBlockDrops` " + + "is not valid for this version of Spigot. Modify the config settings and set " + + "this value to `false`. [%s]", + e1.getMessage() ); + Output.get().logWarn( message ); + } + } + // doAction returns a boolean that indicates if the event should be canceled or not: - if ( doAction( sBlock, pmEvent.getMine(), pmEvent.getPlayer(), debugInfo ) ) { + if ( doAction( pmEvent, debugInfo ) ) { +// if ( doAction( sBlock, pmEvent.getMine(), pmEvent.getPlayer(), debugInfo ) ) { - if ( !isBoolean( AutoFeatures.isDebugSupressOnBlockBreakEventCancels ) ) { + if ( isBoolean( AutoFeatures.cancelAllBlockBreakEvents ) ) { e.setCancelled( true ); } else { @@ -430,6 +435,10 @@ else if ( pmEvent.getMine() != null || pmEvent.getMine() == null && debugInfo.append( "(event was not canceled) " ); } + finalizeBreakTheBlocks( pmEvent ); + + doBlockEvents( pmEvent ); + } else { @@ -448,10 +457,130 @@ else if ( pmEvent.getMine() != null || pmEvent.getMine() == null && } - Output.get().logDebug( DebugTarget.blockBreak, debugInfo.toString() ); + if ( debugInfo.length() > 0 ) { + + long stop = System.nanoTime(); + debugInfo.append( " [" ).append( (stop - start) / 1000000d ).append( " ms]" ); + + Output.get().logDebug( DebugTarget.blockBreak, debugInfo.toString() ); + } + } + + protected boolean ignoreMinesBlockBreakEvent( Cancellable event, Player player, Block block ) { + + MinesEventResults eventResults = ignoreMinesBlockBreakEvent( player, block ); + + if ( eventResults.isCancelEvent() ) { + event.setCancelled( eventResults.isCancelEvent() ); + } + return eventResults.isIgnoreEvent(); +} + +protected boolean processMinesBlockBreakEvent( PEExplosionEvent event, Player player, Block block ) { + + MinesEventResults eventResults = ignoreMinesBlockBreakEvent( player, block ); + + if ( eventResults.isCancelEvent() ) { + event.setCancelled( eventResults.isCancelEvent() ); + } + return eventResults.isIgnoreEvent(); +} + + + /** + *

This processes the block finalizations, which are counting the block breakage, + * and also processes the blockEvents. It's important to process the block events + * after the blocks are broken (set to AIR) to ensure that when the blockEvents are + * ran, then the block would already be set to AIR if it is being broke inline. + *

+ * + * @param pmEvent + */ + private void doBlockEvents( PrisonMinesBlockBreakEvent pmEvent ) + { + + if ( pmEvent.getMine() != null ) { + + // apply to ALL blocks including exploded: + applyBlockFinalizations( pmEvent, pmEvent.getTargetBlock() ); + + + for ( MineTargetPrisonBlock teBlock : pmEvent.getTargetExplodedBlocks() ) { + + applyBlockFinalizations( pmEvent, teBlock ); + } + + checkZeroBlockReset( pmEvent.getMine() ); + } + } + + private void finalizeBreakTheBlocks( PrisonMinesBlockBreakEvent pmEvent ) + { + List blocks = finalizeBreakTheBlocksCollectEm( pmEvent ); + + if ( isBoolean( AutoFeatures.applyBlockBreaksThroughSyncTask ) ) { + + AutoManagerBreakBlockTask.submitTask( blocks, pmEvent.getMine() ); + } + else { + + int count = 0; + for ( SpigotBlock spigotBlock : blocks ) { + + if ( count++ % 10 == 0 && pmEvent.getMine() != null && + !pmEvent.getMine().getMineStateMutex().isMinable() ) { + + SpigotPlayer sPlayer = pmEvent.getSpigotPlayer(); + sPlayer.setActionBar( "Mine " + pmEvent.getMine().getTag() + " is being reset... please wait." ); + break; + } + + spigotBlock.setPrisonBlock( PrisonBlock.AIR ); + } + } + + } + private List finalizeBreakTheBlocksCollectEm( PrisonMinesBlockBreakEvent pmEvent ) { + List blocks = new ArrayList<>(); + + if ( pmEvent.getTargetBlock() != null && pmEvent.getTargetBlock().getMinedBlock() != null ) { + + SpigotBlock minedBlock = ((SpigotBlock) pmEvent.getTargetBlock().getMinedBlock()); + + // Only add the minedBlock to the blocks list if it matches the expected targetBlock name, which + // indicates it has not been replaced by something else, such as the result of a block event. + if ( pmEvent.getTargetBlock().getPrisonBlock().getBlockName().equalsIgnoreCase( minedBlock.getBlockName() )) { + + blocks.add( minedBlock ); + pmEvent.getTargetBlock().setAirBroke( true ); +// pmEvent.getTargetBlock().setMinedBlock( null ); + } + + } + + for ( MineTargetPrisonBlock targetBlock : pmEvent.getTargetExplodedBlocks() ) { + + if ( targetBlock != null && targetBlock.getMinedBlock() != null ) { + + SpigotBlock minedBlock = ((SpigotBlock) targetBlock.getMinedBlock()); + + // Only add the minedBlock to the blocks list if it matches the expected targetBlock name, which + // indicates it has not been replaced by something else, such as the result of a block event. + if ( targetBlock.getPrisonBlock().getBlockName().equalsIgnoreCase( minedBlock.getBlockName() )) { + + blocks.add( minedBlock ); + targetBlock.setAirBroke( true ); +// targetBlock.setMinedBlock( null ); + } + + } + } + + return blocks; } + /** *

This function an attempt to provide a uniform procedure to validate if the event should * be processed. This will eliminate a lot of duplicate code, and will make supporting other @@ -469,70 +598,269 @@ else if ( pmEvent.getMine() != null || pmEvent.getMine() == null && private boolean validateEvent( PrisonMinesBlockBreakEvent pmEvent, StringBuilder debugInfo ) { boolean results = true; + - Long playerUUIDLSB = Long.valueOf( pmEvent.getPlayer().getUniqueId().getLeastSignificantBits() ); + SpigotBlock sBlockHit = pmEvent.getSpigotBlock(); - // Get the cached mine, if it exists: - Mine mine = getPlayerCache().get( playerUUIDLSB ); + Mine mine = findMine( pmEvent.getPlayer(), sBlockHit, + pmEvent.getUnprocessedRawBlocks(), pmEvent ); - if ( mine == null || !mine.isInMineExact( pmEvent.getSpigotBlock().getLocation() ) ) { - // Look for the correct mine to use. - // Set mine to null so if cannot find the right one it will return a null: - mine = findMineLocation( pmEvent.getSpigotBlock() ); - - // Thanks to CrazyEnchant, where they do not identify the block the player breaks, we - // have to go through all of the unprecessedRawBlocks to see if any are within a mine. - // If we find a block that's in a mine, then use that block as the primary block. - for ( Block bBlock : pmEvent.getUnprocessedRawBlocks() ) - { - SpigotBlock sBlock = new SpigotBlock( bBlock ); - mine = findMineLocation( sBlock ); - if ( mine != null ) { - pmEvent.setSpigotBlock( sBlock ); - break; - } - } - - // Store the mine in the player cache if not null: - if ( mine != null ) { - getPlayerCache().put( playerUUIDLSB, mine ); - } - } pmEvent.setMine( mine ); debugInfo.append( "mine=" + (mine == null ? "none" : mine.getName()) + " " ); + debugInfo.append( sBlockHit.getLocation().toWorldCoordinates() ).append( " " ); + + // Since BlastUseEvent (crazy enchant) does not identify the block that is initially + // broke, an explosion for them is greater than 1. + boolean isExplosionEvent = pmEvent.getUnprocessedRawBlocks().size() > + (pmEvent.getBlockEventType() == BlockEventType.CEXplosion ? 0 : 1); // validate the blocks, if there are some. Add them to the exploded blocks list - if ( mine != null && pmEvent.getUnprocessedRawBlocks().size() > 0 ) { + if ( mine != null ) { int unbreakable = 0; int outsideOfMine = 0; + int alreadyMined = 0; + int noTargetBlock = 0; + int blockTypeNotExpected = 0; + + boolean targetBlockAlreadyMined = false; + + // Get the mine's targetBlock: + MineTargetPrisonBlock targetBlock = mine.getTargetPrisonBlock( sBlockHit ); + pmEvent.setTargetBlock( targetBlock ); + + // If ignore all block events has been set on this target block, then shutdown. + // Same if this block was already included in an explosion... prevent it from spawning + // more explosions, which could result in a chain reaction. + if ( targetBlock != null && + (targetBlock.isIgnoreAllBlockEvents() || + targetBlock.isExploded()) ) { + debugInfo.setLength( 0 ); + + pmEvent.setForceIfAirBlock( false ); + + // do not cancel event so some other listener can process it + pmEvent.setCancelOriginalEvent( false ); + + return false; + } - for ( Block bukkitBlock : pmEvent.getUnprocessedRawBlocks() ) - { - SpigotBlock sBlock = new SpigotBlock( bukkitBlock ); + // NOTE: for the primary block pmEvent.getSpigotBlock() the unbreakable will be checked later: + if ( targetBlock != null && sBlockHit != null ) { + + if ( !targetBlock.isMined() || !targetBlock.isAirBroke() ) { - // Thanks to CrazyEnchant, there is no telling which block was actually hit, so - // if using CrazyEnchant one of the unprocessedRawBlocks may be the same as the - // pmEvent.getSpigotBlock(), so ignore if both are the same. - if ( !sBlock.equals( pmEvent.getSpigotBlock() ) ) { + // The field isMined() is used to "reserve" a block to indicate that it is in + // the stages of being processed, since much later in the processing will the + // block be set to setAirBreak() or even setCounted(). This prevents + // high-speed or concurrent operations from multiple players from trying to + // process the same block. + + PrisonBlockStatusData pbTargetBlock = targetBlock.getPrisonBlock(); + PrisonBlock pbBlockHit = sBlockHit == null ? null : sBlockHit.getPrisonBlock(); - if ( BlockUtils.getInstance().isUnbreakable( sBlock ) ) { + if ( pbBlockHit != null && pbTargetBlock != null && + pbTargetBlock.equals( pbBlockHit ) && + collectBukkitDrops( pmEvent.getBukkitDrops(), targetBlock, pmEvent.getItemInHand(), sBlockHit )) { - unbreakable++; - } - else if ( mine.isInMineExact( sBlock.getLocation() ) ) { - pmEvent.getExplodedBlocks().add( sBlock ); + // If a chain reaction on explosions, this will prevent the same block from + // being processed more than once: + targetBlock.setMined( true ); + + targetBlock.setMinedBlock( sBlockHit ); + + + // Mark the block as being part of an explosion, if it was: + targetBlock.setExploded( isExplosionEvent ); + } else { - outsideOfMine++; + // The block is not the correct type. It has been changed since the mine was reset + // so it cannot be processed. + + + if ( Output.get().isDebug( DebugTarget.targetBlockMismatch ) ) { + + String blockHitName = sBlockHit == null ? "--=--" : + pbBlockHit == null ? + "----" : pbBlockHit.getBlockName(); + String targetBlockName = pbTargetBlock == null ? "--:--" : + pbTargetBlock.getBlockName(); + String message = String.format( + "TargetBlock mismatch error - primaryBlock: targetBlock: %s blockBroke: %s", + targetBlockName, + blockHitName + ); + + Output.get().logWarn( message ); + + } + + // Prevent this block from being processed again, or attempted to be processed: + + targetBlockAlreadyMined = true; + + targetBlock.setMined( true ); + targetBlock.setAirBroke( true ); + targetBlock.setIgnoreAllBlockEvents( true ); + + // do not cancel event so some other listener can process it + pmEvent.setCancelOriginalEvent( false ); + + blockTypeNotExpected++; + + if ( !pmEvent.isForceIfAirBlock() ) { + + results = false; + } + } + + } + else { + alreadyMined++; + targetBlockAlreadyMined = true; + + if ( !targetBlock.isMined() ) { + targetBlock.setMined( true ); + } + + // A mine bomb will be "set" above a valid mine block, so it would generally be air and + // it probably was already mined if it's not on top of the top layer of the mine. + if ( !pmEvent.isForceIfAirBlock() ) { + + // This block has already been mined and is not a mine bomb, so fail the validation + // and cancel the event since if it's not an air block, it may be another effect that + // is placing a block within the mine, such as a prison util's decay function. + debugInfo.append( "VALIDATION_FAILED_BLOCK_ALREADY_MINED " ); + + results = false; + + pmEvent.setCancelOriginalEvent( true ); + } + + } + } + else { + noTargetBlock++; + debugInfo.append( "VALIDATION_FAILED_NO_TARGETBLOCK " ); + results = false; } + + // Don't start processing the unprocessedRawBlocks unless results is true, otherwise some + // of the blocks could be marked as being mined but then never processed. + if ( results ) { + + for ( Block bukkitBlock : pmEvent.getUnprocessedRawBlocks() ) + { + SpigotBlock sBlock = new SpigotBlock( bukkitBlock ); + + // Thanks to CrazyEnchant, there is no telling which block was actually hit, so + // if using CrazyEnchant one of the unprocessedRawBlocks may be the same as the + // pmEvent.getSpigotBlock(), so ignore if both are the same. + if ( !sBlock.equals( sBlockHit ) ) { + + if ( !mine.isInMineExact( sBlock.getLocation() ) ) { + outsideOfMine++; + } + else if ( BlockUtils.getInstance().isUnbreakable( sBlock ) ) { + + unbreakable++; + } + + else if ( sBlock.isEmpty() ) { + alreadyMined++; + } + else { + + // Get the mine's targetBlock: + MineTargetPrisonBlock targetExplodedBlock = mine.getTargetPrisonBlock( sBlock ); + + if ( targetExplodedBlock == null || targetExplodedBlock.getPrisonBlock() == null ) { + + // No targetBlock so add it anyway: + pmEvent.getExplodedBlocks().add( sBlock ); + + noTargetBlock++; + } + + else if ( targetExplodedBlock.isMined() ) { + + alreadyMined++; + } + else { + + if ( !targetExplodedBlock.isMined() ) { + + // Check to make sure the block is the same block that was placed there. + // If not, then do not process it. + SpigotBlock sBlockMined = new SpigotBlock( bukkitBlock ); + PrisonBlock pBlockMined = sBlockMined.getPrisonBlock(); + + PrisonBlockStatusData pbTargetExploded = targetExplodedBlock.getPrisonBlock(); + + if ( pBlockMined!= null && pbTargetExploded != null && + pbTargetExploded.equals( pBlockMined ) && + collectBukkitDrops( pmEvent.getBukkitDrops(), targetExplodedBlock, pmEvent.getItemInHand(), sBlockMined ) ) { + + // If a chain reaction on explosions, this will prevent the same block from + // being processed more than once: + targetExplodedBlock.setMined( true ); + + targetExplodedBlock.setMinedBlock( sBlock ); + + + // Mark the block as being part of an explosion, if it was: + targetExplodedBlock.setExploded( isExplosionEvent ); + + + pmEvent.getExplodedBlocks().add( sBlock ); + pmEvent.getTargetExplodedBlocks().add( targetExplodedBlock ); + + + } + else { + // The block is not the correct type. It has been changed since the mine was reset + // so it cannot be processed. + + + if ( Output.get().isDebug( DebugTarget.targetBlockMismatch ) ) { + + String message = String.format( + "TargetBlock mismatch error - multiBLock: targetBlock: %s blockBroke: %s", + pbTargetExploded == null ? "--:--" : pbTargetExploded.getBlockName() , + pBlockMined == null ? "--=--" : pBlockMined.getBlockName() + ); + + Output.get().logWarn( message ); + + } + + + // Prevent this block from being processed again, or attempted to be processed: + + targetExplodedBlock.setMined( true ); + targetExplodedBlock.setAirBroke( true ); + targetExplodedBlock.setIgnoreAllBlockEvents( true ); + + blockTypeNotExpected++; + } + + + } + } + } + } + } + } + + if ( pmEvent.getExplodedBlocks().size() > 0 ) { debugInfo.append( "VALIDATED_BLOCKS_IN_EXPLOSION (" + @@ -549,41 +877,99 @@ else if ( mine.isInMineExact( sBlock.getLocation() ) ) { debugInfo.append( "BLOCKS_OUTSIDE_OF_MINE (" + outsideOfMine + " blocks, event not canceled) " ); } + if ( alreadyMined > 0 ) { + + debugInfo.append( "BLOCKS_ALREADY_MINED (" + alreadyMined + + " ) " ); + } + if ( noTargetBlock > 0 ) { + + debugInfo.append( "NO_TARGET_BLOCKS (" + noTargetBlock + + " ) " ); + } + if ( blockTypeNotExpected > 0 ) { + + debugInfo.append( "BLOCK_TYPE_NOT_EXPECTED__CANNOT_PROCESS (" + blockTypeNotExpected + + " ) " ); + } + + + // Need to compress the drops to eliminate duplicates: + pmEvent.setBukkitDrops( mergeDrops( pmEvent.getBukkitDrops() ) ); + + + // If target block already was mined and there are no exploded blocks, then this whole event + // needs to be canceled since it sounds like a blockevent fired a prison util explosion that + // has zero blocks tied to it. + if ( targetBlockAlreadyMined && pmEvent.isForceIfAirBlock() && pmEvent.getExplodedBlocks().size() == 0 ) { + + // Since this was a dud event, we must set the flag to ignore all + // future block events that include this block as the primary block. + // This code block cancels the current event, but we must ensure that + // the monitor event is also canceled. + pmEvent.getTargetBlock().setIgnoreAllBlockEvents( true ); + + pmEvent.setForceIfAirBlock( false ); + + results = false; + + pmEvent.setCancelOriginalEvent( true ); + + // Ignore event and clear debugInfo: + debugInfo.setLength( 0 ); + + return results; + } + } + debugInfo.append( "blocks(" ) + .append( pmEvent.getBlock() == null ? "0" : "1" ) + .append( "+" ) + .append( pmEvent.getExplodedBlocks().size() ) + .append( ") " ); if ( isToolDisabled( pmEvent.getPlayer() ) ) { - PrisonUtilsTitles uTitles = new PrisonUtilsTitles(); - uTitles.utilsTitlesActionBar( pmEvent.getSpigotPlayer(), "", - "&cYour tool is worn-out and cannot be used." ); + // This will prevent sending too many messages since it is using PlayerMessagingTask: + pmEvent.getSpigotPlayer().setActionBar( "&cYour tool is worn-out and cannot be used." ); + +// PrisonUtilsTitles uTitles = new PrisonUtilsTitles(); +// uTitles.utilsTitlesActionBarForce( pmEvent.getSpigotPlayer(), null, +// "&cYour tool is worn-out and cannot be used." ); pmEvent.setCancelOriginalEvent( true ); debugInfo.append( "UNUSABLE_TOOL__WORN_OUT (event canceled) " ); results = false; } - else if ( mine != null && BlockUtils.getInstance().isUnbreakable( pmEvent.getSpigotBlock() ) ) { + if ( mine != null && BlockUtils.getInstance().isUnbreakable( sBlockHit ) ) { // The block is unbreakable because a utility has it locked: pmEvent.setCancelOriginalEvent( true ); debugInfo.append( "UNBREAKABLE_BLOCK_UTILS (event canceled) " ); results = false; } - else if ( mine != null && (mine.isMineAccessByRank() || mine.isAccessPermissionEnabled()) && + if ( mine != null && (mine.isMineAccessByRank() || mine.isAccessPermissionEnabled()) && !mine.hasMiningAccess( pmEvent.getSpigotPlayer() ) ) { // The player does not have permission to access this mine, so do not process // pmEvent.setCancelOriginalEvent( true ); - debugInfo.append( "ACCESS_DENIED (event canceled) " ); + debugInfo.append( "ACCESS_DENIED (event canceled - Access by rank/perm/perms) " ); results = false; } - else if ( pmEvent.isBlockEventsOnly() ) { + + + + if ( results && pmEvent.isBlockEventsOnly() ) { + // NOTE: This "should" never be activated since blockEventsOnly used to be enabled + // when AutoManager is disabled. As of 2021-11-23 if AutoManager is disabled, + // then everything related to auto manager is disabled. String triggered = null; - doActionBlockEventOnly( pmEvent.getSpigotBlock(), mine, pmEvent.getPlayer(), + doActionBlockEventOnly( sBlockHit, mine, pmEvent.getPlayer(), BlockEventType.blockBreak, triggered ); debugInfo.append( "(actionBlockEventOnly singluar) " ); @@ -603,15 +989,15 @@ else if ( pmEvent.isBlockEventsOnly() ) { results = false; } - else if ( pmEvent.isMonitor() && mine == null ) { + else if ( results && pmEvent.isMonitor() && mine == null ) { // bypass all processing since the block break is outside any mine: debugInfo.append( "(bypassed monitor no mine) " ); results = false; } - else if ( pmEvent.isMonitor() && mine != null ) { + else if ( results && pmEvent.isMonitor() && mine != null ) { - doActionMonitor( pmEvent.getSpigotBlock(), mine ); + doActionMonitor( sBlockHit, mine ); debugInfo.append( "(monitor - singular) " ); @@ -627,13 +1013,123 @@ else if ( pmEvent.isMonitor() && mine != null ) { " Exploded Blocks - finalized) " ); } - results = false; + // should be true at this point: + //results = true; + } + + + if ( results && isBoolean( AutoFeatures.cancelAllBlockEventBlockDrops ) ) { + + clearBukkitDrops( pmEvent.getBukkitDrops(), pmEvent.getTargetBlock() ); + + for ( MineTargetPrisonBlock targetBlock : pmEvent.getTargetExplodedBlocks() ) + { + clearBukkitDrops( pmEvent.getBukkitDrops(), targetBlock ); + + } + + } + +// if ( results ) { +// // Collect the bukkit drops && cancel the drops if needed +// +// collectBukkitDrops( pmEvent.getBukkitDrops(), pmEvent.getTargetBlock(), +// pmEvent.getItemInHand() ); +// +// for ( MineTargetPrisonBlock targetBlock : pmEvent.getTargetExplodedBlocks() ) +// { +// collectBukkitDrops( pmEvent.getBukkitDrops(), targetBlock, +// pmEvent.getItemInHand() ); +// +// } +// +// // Need to compress the drops to eliminate duplicates: +// pmEvent.setBukkitDrops( mergeDrops( pmEvent.getBukkitDrops() ) ); +// } + + + if ( results ) { + debugInfo.append( "(PassedValidation) " ); + } + else { + debugInfo.append( "(ValidationFailed) " ); } return results; } +// private boolean collectBukkitDrops( List bukkitDrops, MineTargetPrisonBlock targetBlock, +// SpigotItemStack itemInHand, SpigotBlock sBlockMined ) +// { +// boolean results = false; +// +//// if ( sBlockMined == null && targetBlock.getMinedBlock() != null ) { +//// sBlockMined = (SpigotBlock) targetBlock.getMinedBlock(); +//// } +// //SpigotBlock sBlock = (SpigotBlock) targetBlock.getMinedBlock(); +// +// if ( sBlockMined != null && targetBlock.getPrisonBlock().equals( sBlockMined.getPrisonBlock() ) ) { +// +// List drops = SpigotUtil.getDrops(sBlockMined, itemInHand); +// +// bukkitDrops.addAll( drops ); +// +//// // This clears the drops for the given block, so if the event is not canceled, it will +//// // not result in duplicate drops. +//// if ( isBoolean( AutoFeatures.cancelAllBlockEventBlockDrops ) ) { +//// sBlock.clearDrops(); +//// } +// +// results = true; +// +// } +// else if ( sBlockMined != null) { +// Output.get().logWarn( "collectBukkitDrops: block was changed and not what was expected. " + +// "Block: " + sBlockMined.getBlockName() + " expecting: " + targetBlock.getPrisonBlock().getBlockName() ); +// } +// +// return results; +// } + + +// private void clearBukkitDrops( List bukkitDrops, MineTargetPrisonBlock targetBlock ) +// { +// +// SpigotBlock sBlock = (SpigotBlock) targetBlock.getMinedBlock(); +// sBlock.clearDrops(); +// +// } + +// /** +// *

The List of drops must have only one ItemStack per block type (name). +// * This function combines multiple occurrences together and adds up their +// * counts to properly represent the total quantity in the original drops collection +// * that had duplicate entries. +// *

+// * +// * @param List of SpigotItemStack drops with duplicate entries +// * @return List of SpigotItemStack drops without duplicates +// */ +// private List mergeDrops( List drops ) +// { +// TreeMap results = new TreeMap<>(); +// +// for ( SpigotItemStack drop : drops ) { +// String key = drop.getName(); +// if ( !results.containsKey( key ) ) { +// results.put( key, drop ); +// } +// else { +// SpigotItemStack sItemStack = results.get( key ); +// +// sItemStack.setAmount( sItemStack.getAmount() + drop.getAmount() ); +// } +// } +// +// return new ArrayList<>( results.values() ); +// } + /** *

Since there are multiple blocks associated with this event, pull out the player first and * get the mine, then loop through those blocks to make sure they are within the mine. @@ -649,6 +1145,13 @@ else if ( pmEvent.isMonitor() && mine != null ) { private void genericBlockExplodeEvent( TEBlockExplodeEvent e, boolean monitor, boolean blockEventsOnly, boolean autoManager ) { + long start = System.nanoTime(); + + if ( e.isCancelled() || ignoreMinesBlockBreakEvent( e, e.getPlayer(), e.getBlock()) ) { + return; + } + + // Register all external events such as mcMMO and EZBlocks: OnBlockBreakExternalEvents.getInstance().registerAllExternalEvents(); @@ -664,7 +1167,10 @@ private void genericBlockExplodeEvent( TEBlockExplodeEvent e, boolean monitor, b // NOTE that check for auto manager has happened prior to accessing this function. if ( !monitor && !e.isCancelled() || monitor ) { - boolean isTEExplosiveEnabled = isBoolean( AutoFeatures.isProcessTokensEnchantExplosiveEvents ); + + String eP = getMessage( AutoFeatures.TokenEnchantBlockExplodeEventPriority ); + boolean isTEExplosiveEnabled = eP != null && !"DISABLED".equalsIgnoreCase( eP ); + // Need to wrap in a Prison block so it can be used with the mines: SpigotBlock sBlock = new SpigotBlock(e.getBlock()); @@ -676,6 +1182,12 @@ private void genericBlockExplodeEvent( TEBlockExplodeEvent e, boolean monitor, b PrisonMinesBlockBreakEvent pmEvent = new PrisonMinesBlockBreakEvent( e.getBlock(), e.getPlayer(), sBlock, sPlayer, monitor, blockEventsOnly, eventType, triggered ); + // NOTE: Token Enchant will pass the event's block to prison, but that block may + // have already been processed by prison. Therefore the PrisonMinesBlockBreakEvent + // must enable the feature setForceIfAirBlock( true ). That block will not be used a + // second time, but it will allow the explosion event to be processed. + pmEvent.setForceIfAirBlock( true ); + pmEvent.setUnprocessedRawBlocks( e.blockList() ); if ( !validateEvent( pmEvent, debugInfo ) ) { @@ -689,193 +1201,17 @@ private void genericBlockExplodeEvent( TEBlockExplodeEvent e, boolean monitor, b } } + else if ( pmEvent.isMonitor() ) { + // Stop here, and prevent additional processing. Monitors should never process the event beyond this. + } -// List explodedBlocks = new ArrayList<>(); - -// // Need to wrap in a Prison block so it can be used with the mines: -// SpigotBlock block = new SpigotBlock(e.getBlock()); -// -// // long startNano = System.nanoTime(); -// Long playerUUIDLSB = Long.valueOf( e.getPlayer().getUniqueId().getLeastSignificantBits() ); -// -// // Get the cached mine, if it exists: -// Mine mine = getPlayerCache().get( playerUUIDLSB ); -// -// if ( mine == null || !mine.isInMineExact( block.getLocation() ) ) { -// -// -// // Look for the correct mine to use. -// // Set mine to null so if cannot find the right one it will return a null: -// mine = findMineLocation( block ); -// -// // Store the mine in the player cache if not null: -// if ( mine != null ) { -// getPlayerCache().put( playerUUIDLSB, mine ); -// -// // we found the mine! -// } -// -// } -// -// debugInfo.append( "mine=" + (mine == null ? "none" : mine.getName()) + " " ); - - -// if ( isToolDisabled( e.getPlayer() ) ) { -// -// PrisonUtilsTitles uTitles = new PrisonUtilsTitles(); -// uTitles.utilsTitlesActionBar( new SpigotPlayer( e.getPlayer() ), "", -// "&cYour tool is worn-out and cannot be used." ); -// -// e.setCancelled( true ); -// debugInfo.append( "UNUSABLE_TOOL__WORN_OUT (event canceled) " ); -// } -// else if ( mine != null && BlockUtils.getInstance().isUnbreakable( block ) ) { -// // The block is unbreakable because a utility has it locked: -// -// e.setCancelled( true ); -// debugInfo.append( "UNBREAKABLE_BLOCK_UTILS (event canceled) " ); -// } -// else if ( mine != null && (mine.isMineAccessByRank() || mine.isAccessPermissionEnabled()) && -// !mine.hasMiningAccess( new SpigotPlayer( e.getPlayer() ) ) ) { -// // The player does not have permission to access this mine, so do not process -// // -// -// e.setCancelled( true ); -// debugInfo.append( "ACCESS_DENIED (event canceled) " ); -// } -// else if ( blockEventsOnly ) { -// int unbreakable = 0; -// int outsideOfMine = 0; -// -// if ( mine != null ) { -// -// String triggered = null; -// -// // This was already checked to ensure it's breakable: -// doActionBlockEventOnly( block, mine, e.getPlayer(), BlockEventType.blockBreak, triggered ); -// -// // All other blocks in the explosion: -// for ( Block blk : e.blockList() ) { -// -// // Need to wrap in a Prison block so it can be used with the mines. -// // Since this is a monitor, there is no need to check to see if the -// // block is in a mine since the getTargetPrisonBlock function will -// // perform that check indirectly. -// SpigotBlock sBlock = new SpigotBlock(blk); -// -// if ( BlockUtils.getInstance().isUnbreakable( sBlock ) ) { -// -// unbreakable++; -// } -// else if ( mine.isInMineExact( sBlock.getLocation() ) ) { -// -// doActionBlockEventOnly( sBlock, mine, e.getPlayer(), BlockEventType.blockBreak, triggered ); -// } -// else { -// outsideOfMine++; -// } -// -// } -// -// } -// -// if ( unbreakable > 0 ) { -// -// // e.setCancelled( true ); -// debugInfo.append( "UNBREAKABLE_BLOCK_UTILS (" + unbreakable + -// " blocks, event not canceled) " ); -// } -// if ( outsideOfMine > 0 ) { -// -// debugInfo.append( "BLOCKS_OUTSIDE_OF_MINE (" + outsideOfMine + -// " blocks, event not canceled) " ); -// } -// -// debugInfo.append( "(actionBlockEventOnly) " ); -// } -// else if ( monitor && mine == null ) { -// // bypass all processing since the block break is outside any mine: -// -// debugInfo.append( "(bypassed monitor no mine) " ); -// } -// else if ( monitor && mine != null ) { -// int unbreakable = 0; -// int outsideOfMine = 0; -// -// // Initial block that was hit: -// doActionMonitor( block, mine ); -// -// // All other blocks in the explosion: -// for ( Block blk : e.blockList() ) { -// -// // Need to wrap in a Prison block so it can be used with the mines. -// // Since this is a monitor, there is no need to check to see if the -// // block is in a mine since the getTargetPrisonBlock function will -// // perform that check indirectly. -// SpigotBlock sBlock = new SpigotBlock(blk); -// -// if ( BlockUtils.getInstance().isUnbreakable( new SpigotBlock( blk ) ) ) { -// -// unbreakable++; -// } -// else if ( mine.isInMineExact( sBlock.getLocation() ) ) { -// -// doActionMonitor( sBlock, mine ); -// } -// else { -// outsideOfMine++; -// } -// } -// -// if ( unbreakable > 0 ) { -// -// // e.setCancelled( true ); -// debugInfo.append( "UNBREAKABLE_BLOCK_UTILS (" + unbreakable + -// " blocks, event not canceled) " ); -// } -// if ( outsideOfMine > 0 ) { -// -// debugInfo.append( "BLOCKS_OUTSIDE_OF_MINE (" + outsideOfMine + -// " blocks, event not canceled) " ); -// } -// debugInfo.append( "(monitor) " ); -// } // now process all blocks (non-monitor): else if ( isTEExplosiveEnabled && ( pmEvent.getMine() != null || pmEvent.getMine() == null && !isBoolean( AutoFeatures.pickupLimitToMines )) ) { -// int unbreakable = 0; -// int outsideOfMine = 0; - - // have to go through all blocks since some blocks may be outside the mine. - // but terminate search upon first find: - -// for ( Block blk : e.blockList() ) { -// //boolean isAir = blk.getType() != null && blk.getType() == Material.AIR; -// -// // Need to wrap in a Prison block so it can be used with the mines: -//// SpigotBlock sBlock = new SpigotBlock(blk); -// -// -// if ( BlockUtils.getInstance().isUnbreakable( pmEvent.getSpigotBlock() ) ) { -// -// unbreakable++; -// } -// else if ( pmEvent.getMine().isInMineExact( sBlock.getLocation() ) ) { -// -// pmEvent.getExplodedBlocks().add( sBlock ); -// -// -// // check all external events such as mcMMO and EZBlocks: -// OnBlockBreakExternalEvents.getInstance().checkAllExternalEvents( e.getPlayer(), blk ); -// } -// else { -// outsideOfMine++; -// } -// -// } + if ( pmEvent.getExplodedBlocks().size() > 0 ) { @@ -890,11 +1226,29 @@ else if ( isTEExplosiveEnabled && } else { + // Cancel drops if so configured: + if ( isBoolean( AutoFeatures.cancelAllBlockEventBlockDrops ) ) { + + try + { + e.setYield( 0 ); +// e.setDropItems( false ); + } + catch ( NoSuchMethodError e1 ) + { + String message = String.format( + "Warning: The autoFeaturesConfig.yml setting `cancelAllBlockEventBlockDrops` " + + "is not valid for this version of Spigot. Modify the config settings and set " + + "this value to `false`. [%s]", + e1.getMessage() ); + Output.get().logWarn( message ); + } + } + // This is where the processing actually happens: - if ( doAction( pmEvent.getMine(), pmEvent.getPlayer(), - pmEvent.getExplodedBlocks(), BlockEventType.TEXplosion, triggered, debugInfo ) ) { + if ( doAction( pmEvent, debugInfo ) ) { - if ( !isBoolean( AutoFeatures.isDebugSupressOnTEExplodeEventCancels ) ) { + if ( isBoolean( AutoFeatures.cancelAllBlockBreakEvents ) ) { e.setCancelled( true ); } @@ -902,6 +1256,11 @@ else if ( isTEExplosiveEnabled && debugInfo.append( "(event was not canceled) " ); } + + finalizeBreakTheBlocks( pmEvent ); + + doBlockEvents( pmEvent ); + } else { @@ -913,17 +1272,6 @@ else if ( isTEExplosiveEnabled && } -// if ( unbreakable > 0 ) { -// -// // e.setCancelled( true ); -// debugInfo.append( "UNBREAKABLE_BLOCK_UTILS (" + unbreakable + -// " blocks, event not canceled) " ); -// } -// if ( outsideOfMine > 0 ) { -// -// debugInfo.append( "BLOCKS_OUTSIDE_OF_MINE (" + outsideOfMine + -// " blocks, event not canceled) " ); -// } debugInfo.append( "(normal processing) " ); } @@ -934,7 +1282,13 @@ else if ( isTEExplosiveEnabled && } - Output.get().logDebug( DebugTarget.blockBreak, debugInfo.toString() ); + if ( debugInfo.length() > 0 ) { + + long stop = System.nanoTime(); + debugInfo.append( " [" ).append( (stop - start) / 1000000d ).append( " ms]" ); + + Output.get().logDebug( DebugTarget.blockBreak, debugInfo.toString() ); + } } @@ -986,6 +1340,13 @@ private String checkCEExplosionTriggered( TEBlockExplodeEvent e ) protected void genericBlastUseEvent( BlastUseEvent e, boolean monitor, boolean blockEventsOnly, boolean autoManager ) { + long start = System.nanoTime(); + + if ( e.isCancelled() || ignoreMinesBlockBreakEvent( e, e.getPlayer(), e.getBlockList().get( 0 )) ) { + return; + } + + // Register all external events such as mcMMO and EZBlocks: OnBlockBreakExternalEvents.getInstance().registerAllExternalEvents(); @@ -1002,8 +1363,11 @@ protected void genericBlastUseEvent( BlastUseEvent e, boolean monitor, boolean b if ( (!monitor && !e.isCancelled() || monitor) && e.getBlockList().size() > 0 ) { - boolean isCEBlockExplodeEnabled = isBoolean( AutoFeatures.isProcessCrazyEnchantsBlockExplodeEvents ); - + + String eP = getMessage( AutoFeatures.CrazyEnchantsBlastUseEventPriority ); + boolean isCEBlockExplodeEnabled = eP != null && !"DISABLED".equalsIgnoreCase( eP ); + + Block bukkitBlock = e.getBlockList().get( 0 ); // Need to wrap in a Prison block so it can be used with the mines: @@ -1035,222 +1399,17 @@ protected void genericBlastUseEvent( BlastUseEvent e, boolean monitor, boolean b } -// -// List explodedBlocks = new ArrayList<>(); -// -// -// // long startNano = System.nanoTime(); -// Long playerUUIDLSB = Long.valueOf( e.getPlayer().getUniqueId().getLeastSignificantBits() ); -// -// // Get the cached mine, if it exists: -// Mine mine = getPlayerCache().get( playerUUIDLSB ); -// -// if ( mine == null ) { -// -// -// // NOTE: The crazy enchantment's blast use event does not identify the block that -// // was hit, so will have to check them all. -// -// // have to go through all blocks since some blocks may be outside the mine. -// // but terminate search upon first find: -// for ( Block blk : e.getBlockList() ) { -// // Need to wrap in a Prison block so it can be used with the mines: -// SpigotBlock block = new SpigotBlock(blk); -// -// // Look for the correct mine to use. -// // Set mine to null so if cannot find the right one it will return a null: -// mine = findMineLocation( block ); -// -// // Store the mine in the player cache if not null: -// if ( mine != null ) { -// getPlayerCache().put( playerUUIDLSB, mine ); -// -// // we found the mine! -// break; -// } -// } -// } -// else { -// -// // NOTE: Just because the mine is not null, does not mean that the block was tested to be -// // within the mine. The mine from the player cache could be a different mine -// // altogether. The block must be tested. -// -// // have to go through all blocks since some blocks may be outside the mine. -// // but terminate search upon first find: -// for ( Block blk : e.getBlockList() ) { -// // Need to wrap in a Prison block so it can be used with the mines: -// SpigotBlock block = new SpigotBlock(blk); -// -// // Look for the correct mine to use. -// // Set mine to null so if cannot find the right one it will return a null: -// mine = findMineLocation( block ); -// -// // Store the mine in the player cache if not null: -// if ( mine != null ) { -// getPlayerCache().put( playerUUIDLSB, mine ); -// -// // we found the mine! -// break; -// } -// } -// -// } -// -// debugInfo.append( "mine=" + (mine == null ? "none" : mine.getName()) + " " ); -// -// boolean isCEBlockExplodeEnabled = isBoolean( AutoFeatures.isProcessCrazyEnchantsBlockExplodeEvents ); -// -// if ( isToolDisabled( e.getPlayer() ) ) { -// -// PrisonUtilsTitles uTitles = new PrisonUtilsTitles(); -// uTitles.utilsTitlesActionBar( new SpigotPlayer( e.getPlayer() ), "", -// "&cYour tool is worn-out and cannot be used." ); -// -// e.setCancelled( true ); -// debugInfo.append( "UNUSABLE_TOOL__WORN_OUT (event canceled) " ); -// } -//// else if ( mine != null && BlockUtils.getInstance().isUnbreakable( block ) ) { -//// // The block is unbreakable because a utility has it locked: -//// -//// e.setCancelled( true ); -//// debugInfo += "UNBREAKABLE_BLOCK_UTILS (event canceled) "; -//// } -// else if ( mine != null && (mine.isMineAccessByRank() || mine.isAccessPermissionEnabled()) && -// !mine.hasMiningAccess( new SpigotPlayer( e.getPlayer() ) ) ) { -// // The player does not have permission to access this mine, so do not process -// // -// -// e.setCancelled( true ); -// debugInfo.append( "ACCESS_DENIED (event canceled) " ); -// } -// else if ( blockEventsOnly ) { -// int unbreakable = 0; -// int outsideOfMine = 0; -// -// if ( mine != null ) { -// -// String triggered = null; -// -// // All other blocks in the explosion: -// for ( Block blk : e.getBlockList() ) { -// -// -// // Need to wrap in a Prison block so it can be used with the mines. -// // Since this is a monitor, there is no need to check to see if the -// // block is in a mine since the getTargetPrisonBlock function will -// // perform that check indirectly. -// SpigotBlock sBlock = new SpigotBlock(blk); -// -// if ( BlockUtils.getInstance().isUnbreakable( new SpigotBlock( blk ) ) ) { -// -// unbreakable++; -// } -// else if ( mine.isInMineExact( sBlock.getLocation() ) ) { -// -// doActionBlockEventOnly( sBlock, mine, e.getPlayer(), BlockEventType.CEXplosion, triggered ); -// } -// else { -// outsideOfMine++; -// } -// -// } -// } -// -// if ( unbreakable > 0 ) { -// -// // e.setCancelled( true ); -// debugInfo.append( "UNBREAKABLE_BLOCK_UTILS (" + unbreakable + -// " blocks, event not canceled) " ); -// } -// if ( outsideOfMine > 0 ) { -// -// debugInfo.append( "BLOCKS_OUTSIDE_OF_MINE (" + outsideOfMine + -// " blocks, event not canceled) " ); -// } -// -// debugInfo.append( "(actionBlockEventOnly) " ); -// } -// else if ( monitor && mine == null ) { -// // bypass all processing since the block break is outside any mine: -// -// debugInfo.append( "(bypassed monitor no mine) " ); -// } -// else if ( monitor && mine != null ) { -// int unbreakable = 0; -// int outsideOfMine = 0; -// -// // Initial block that was hit: CrazyE does not have the main block: -// // doActionMonitor( block, mine ); -// -// // All other blocks in the explosion: -// for ( Block blk : e.getBlockList() ) { -// -// // Need to wrap in a Prison block so it can be used with the mines. -// // Since this is a monitor, there is no need to check to see if the -// // block is in a mine since the getTargetPrisonBlock function will -// // perform that check indirectly. -// SpigotBlock sBlock = new SpigotBlock(blk); -// -// if ( BlockUtils.getInstance().isUnbreakable( new SpigotBlock( blk ) ) ) { -// -// unbreakable++; -// } -// else if ( mine.isInMineExact( sBlock.getLocation() ) ) { -// -// doActionMonitor( sBlock, mine ); -// } -// else { -// outsideOfMine++; -// } -// -// } -// -// if ( unbreakable > 0 ) { -// -// // e.setCancelled( true ); -// debugInfo.append( "UNBREAKABLE_BLOCK_UTILS (" + unbreakable + -// " blocks, event not canceled) " ); -// } -// if ( outsideOfMine > 0 ) { -// -// debugInfo.append( "BLOCKS_OUTSIDE_OF_MINE (" + outsideOfMine + -// " blocks, event not canceled) " ); -// } -// -// debugInfo.append( "(monitor) " ); -// } + else if ( pmEvent.isMonitor() ) { + // Stop here, and prevent additional processing. Monitors should never process the event beyond this. + } + + // now process all blocks (non-monitor): else if ( isCEBlockExplodeEnabled && ( pmEvent.getMine() != null || pmEvent.getMine() == null && !isBoolean( AutoFeatures.pickupLimitToMines )) ) { -// int unbreakable = 0; -// int outsideOfMine = 0; - - // have to go through all blocks since some blocks may be outside the mine. - // but terminate search upon first find: - -// for ( Block blk : e.getBlockList() ) { -// -// // Need to wrap in a Prison block so it can be used with the mines: -// SpigotBlock sBlock = new SpigotBlock(blk); -// -// if ( BlockUtils.getInstance().isUnbreakable( new SpigotBlock( blk ) ) ) { -// -// unbreakable++; -// } -// else if ( mine.isInMineExact( sBlock.getLocation() ) ) { -// -// explodedBlocks.add( sBlock ); -// -// // check all external events such as mcMMO and EZBlocks: -// OnBlockBreakExternalEvents.getInstance().checkAllExternalEvents( e.getPlayer(), blk ); -// } -// else { -// outsideOfMine++; -// } -// -// } + + if ( pmEvent.getExplodedBlocks().size() > 0 ) { // String triggered = null; @@ -1269,10 +1428,27 @@ else if ( isCEBlockExplodeEnabled && } else { - if ( doAction( pmEvent.getMine(), e.getPlayer(), pmEvent.getExplodedBlocks(), - BlockEventType.CEXplosion, triggered, debugInfo ) ) { +// // Cancel drops if so configured: +// if ( isBoolean( AutoFeatures.cancelAllBlockEventBlockDrops ) ) { +// +// try +// { +// e.setDropItems( false ); +// } +// catch ( NoSuchMethodError e1 ) +// { +// String message = String.format( +// "Warning: The autoFeaturesConfig.yml setting `cancelAllBlockEventBlockDrops` " + +// "is not valid for this version of Spigot. Modify the config settings and set " + +// "this value to `false`. [%s]", +// e1.getMessage() ); +// Output.get().logWarn( message ); +// } +// } + + if ( doAction( pmEvent, debugInfo ) ) { - if ( !isBoolean( AutoFeatures.isDebugSupressOnCEBlastUseEventCancels ) ) { + if ( isBoolean( AutoFeatures.cancelAllBlockBreakEvents ) ) { e.setCancelled( true ); } @@ -1280,6 +1456,11 @@ else if ( isCEBlockExplodeEnabled && debugInfo.append( "(event was not canceled) " ); } + + finalizeBreakTheBlocks( pmEvent ); + + doBlockEvents( pmEvent ); + } else { @@ -1290,17 +1471,6 @@ else if ( isCEBlockExplodeEnabled && } } -// if ( unbreakable > 0 ) { -// -// // e.setCancelled( true ); -// debugInfo.append( "UNBREAKABLE_BLOCK_UTILS (" + unbreakable + -// " blocks, event not canceled) " ); -// } -// if ( outsideOfMine > 0 ) { -// -// debugInfo.append( "BLOCKS_OUTSIDE_OF_MINE (" + outsideOfMine + -// " blocks, event not canceled) " ); -// } debugInfo.append( "(normal processing) " ); } @@ -1311,8 +1481,13 @@ else if ( isCEBlockExplodeEnabled && } - Output.get().logDebug( DebugTarget.blockBreak, debugInfo.toString() ); - + if ( debugInfo.length() > 0 ) { + + long stop = System.nanoTime(); + debugInfo.append( " [" ).append( (stop - start) / 1000000d ).append( " ms]" ); + + Output.get().logDebug( DebugTarget.blockBreak, debugInfo.toString() ); + } } @@ -1332,6 +1507,13 @@ else if ( isCEBlockExplodeEnabled && protected void genericExplosiveEvent( PEExplosionEvent e, boolean monitor, boolean blockEventsOnly, boolean autoManager ) { + long start = System.nanoTime(); + + if ( e.isCancelled() || processMinesBlockBreakEvent( e, e.getPlayer(), e.getBlockBroken()) ) { + return; + } + + // Register all external events such as mcMMO and EZBlocks: OnBlockBreakExternalEvents.getInstance().registerAllExternalEvents(); @@ -1348,21 +1530,23 @@ protected void genericExplosiveEvent( PEExplosionEvent e, boolean monitor, boole if ( !monitor && !e.isCancelled() || monitor ) { - boolean isPEExplosiveEnabled = isBoolean( AutoFeatures.isProcessPrisonEnchantsExplosiveEvents ); - + String eP = getMessage( AutoFeatures.PrisonEnchantsExplosiveEventPriority ); + boolean isPEExplosiveEnabled = eP != null && !"DISABLED".equalsIgnoreCase( eP ); + // Need to wrap in a Prison block so it can be used with the mines: - SpigotBlock sBlock = new SpigotBlock(e.getBlock()); + SpigotBlock sBlock = new SpigotBlock(e.getBlockBroken()); SpigotPlayer sPlayer = new SpigotPlayer(e.getPlayer()); BlockEventType eventType = BlockEventType.PEExplosive; - String triggered = e.getTriggeredBy(); + String triggered = null; // e.getTriggeredBy(); - PrisonMinesBlockBreakEvent pmEvent = new PrisonMinesBlockBreakEvent( e.getBlock(), e.getPlayer(), + PrisonMinesBlockBreakEvent pmEvent = new PrisonMinesBlockBreakEvent( e.getBlockBroken(), e.getPlayer(), sBlock, sPlayer, monitor, blockEventsOnly, eventType, triggered ); pmEvent.setUnprocessedRawBlocks( e.getExplodedBlocks() ); + if ( !validateEvent( pmEvent, debugInfo ) ) { // The event has not passed validation. All logging and Errors have been recorded @@ -1375,8 +1559,12 @@ protected void genericExplosiveEvent( PEExplosionEvent e, boolean monitor, boole } + else if ( pmEvent.isMonitor() ) { + // Stop here, and prevent additional processing. Monitors should never process the event beyond this. + } + // now process all blocks (non-monitor): else if ( isPEExplosiveEnabled && ( pmEvent.getMine() != null || pmEvent.getMine() == null && !isBoolean( AutoFeatures.pickupLimitToMines )) ) { @@ -1393,10 +1581,27 @@ else if ( isPEExplosiveEnabled && } else { - if ( doAction( pmEvent.getMine(), e.getPlayer(), pmEvent.getExplodedBlocks(), - BlockEventType.PEExplosive, triggered, debugInfo ) ) { +// // Cancel drops if so configured: +// if ( isBoolean( AutoFeatures.cancelAllBlockEventBlockDrops ) ) { +// +// try +// { +// e.setDropItems( false ); +// } +// catch ( NoSuchMethodError e1 ) +// { +// String message = String.format( +// "Warning: The autoFeaturesConfig.yml setting `cancelAllBlockEventBlockDrops` " + +// "is not valid for this version of Spigot. Modify the config settings and set " + +// "this value to `false`. [%s]", +// e1.getMessage() ); +// Output.get().logWarn( message ); +// } +// } + + if ( doAction( pmEvent, debugInfo ) ) { - if ( !isBoolean( AutoFeatures.isDebugSupressOnPEExplosiveEventCancels ) ) { + if ( isBoolean( AutoFeatures.cancelAllBlockBreakEvents ) ) { e.setCancelled( true ); } @@ -1404,6 +1609,11 @@ else if ( isPEExplosiveEnabled && debugInfo.append( "(event was not canceled) " ); } + + finalizeBreakTheBlocks( pmEvent ); + + doBlockEvents( pmEvent ); + } else { @@ -1424,13 +1634,26 @@ else if ( isPEExplosiveEnabled && } - Output.get().logDebug( DebugTarget.blockBreak, debugInfo.toString() ); + if ( debugInfo.length() > 0 ) { + + long stop = System.nanoTime(); + debugInfo.append( " [" ).append( (stop - start) / 1000000d ).append( " ms]" ); + + Output.get().logDebug( DebugTarget.blockBreak, debugInfo.toString() ); + } } protected void genericExplosiveEvent( ExplosiveBlockBreakEvent e, boolean monitor, boolean blockEventsOnly, boolean autoManager ) { + long start = System.nanoTime(); + + if ( e.isCancelled() || ignoreMinesBlockBreakEvent( e, e.getPlayer(), e.getBlock()) ) { + return; + } + + // Register all external events such as mcMMO and EZBlocks: OnBlockBreakExternalEvents.getInstance().registerAllExternalEvents(); @@ -1441,26 +1664,43 @@ protected void genericExplosiveEvent( ExplosiveBlockBreakEvent e, boolean monito (e.isCancelled() ? "CANCELED " : ""), (monitor ? "MONITOR " : ""), (blockEventsOnly ? "BlockEventsOnly" : "" )) ); - - // NOTE that check for auto manager has happened prior to accessing this function. if ( !monitor && !e.isCancelled() || monitor ) { - boolean isPEExplosiveEnabled = isBoolean( AutoFeatures.isProcessPrisonEnchantsExplosiveEvents ); - + String eP = getMessage( AutoFeatures.ProcessPrisons_ExplosiveBlockBreakEventsPriority ); + boolean isPPrisonExplosiveBlockBreakEnabled = eP != null && !"DISABLED".equalsIgnoreCase( eP ); + // Need to wrap in a Prison block so it can be used with the mines: SpigotBlock sBlock = new SpigotBlock(e.getBlock()); SpigotPlayer sPlayer = new SpigotPlayer(e.getPlayer()); - BlockEventType eventType = BlockEventType.PEExplosive; + BlockEventType eventType = BlockEventType.PrisonExplosion; String triggered = e.getTriggeredBy(); PrisonMinesBlockBreakEvent pmEvent = new PrisonMinesBlockBreakEvent( e.getBlock(), e.getPlayer(), sBlock, sPlayer, monitor, blockEventsOnly, eventType, triggered ); + + + // If this event is fired, but yet there are no exploded blocks, then do not set + // forceIfAirBlock to true so this event is skipped. + if ( e.getExplodedBlocks() != null && e.getExplodedBlocks().size() > 0 ) { + + pmEvent.setUnprocessedRawBlocks( e.getExplodedBlocks() ); + pmEvent.setForceIfAirBlock( e.isForceIfAirBlock() ); + } + - pmEvent.setUnprocessedRawBlocks( e.getExplodedBlocks() ); + + // Warning: toolInHand really needs to be defined in the event if the source is a + // Mine Bomb, otherwise auto features will detect the player is holding + // a mine bomb which is not a pickaxe so the drops will be ZERO. If they + // used their last mine bomb, then auto features will detect only AIR + // in their hand. + if ( e.getToolInHand() != null ) { + pmEvent.setItemInHand( (SpigotItemStack) e.getToolInHand() ); + } if ( !validateEvent( pmEvent, debugInfo ) ) { @@ -1474,10 +1714,17 @@ protected void genericExplosiveEvent( ExplosiveBlockBreakEvent e, boolean monito } + else if ( pmEvent.isMonitor() ) { + // Stop here, and prevent additional processing. Monitors should never process the event beyond this. + } + + // now process all blocks (non-monitor): - else if ( isPEExplosiveEnabled && - ( pmEvent.getMine() != null || pmEvent.getMine() == null && !isBoolean( AutoFeatures.pickupLimitToMines )) ) { + else if ( isPPrisonExplosiveBlockBreakEnabled && + ( pmEvent.getMine() != null || pmEvent.getMine() == null && + !isBoolean( AutoFeatures.pickupLimitToMines )) ) { + if ( pmEvent.getExplodedBlocks().size() > 0 ) { // String triggered = null; @@ -1491,10 +1738,27 @@ else if ( isPEExplosiveEnabled && } else { - if ( doAction( pmEvent.getMine(), e.getPlayer(), pmEvent.getExplodedBlocks(), - BlockEventType.PEExplosive, triggered, debugInfo ) ) { + // Cancel drops if so configured: + if ( isBoolean( AutoFeatures.cancelAllBlockEventBlockDrops ) ) { + + try + { + e.setDropItems( false ); + } + catch ( NoSuchMethodError e1 ) + { + String message = String.format( + "Warning: The autoFeaturesConfig.yml setting `cancelAllBlockEventBlockDrops` " + + "is not valid for this version of Spigot. Modify the config settings and set " + + "this value to `false`. [%s]", + e1.getMessage() ); + Output.get().logWarn( message ); + } + } + + if ( doAction( pmEvent, debugInfo ) ) { - if ( !isBoolean( AutoFeatures.isDebugSupressOnPEExplosiveEventCancels ) ) { + if ( isBoolean( AutoFeatures.cancelAllBlockBreakEvents ) ) { e.setCancelled( true ); } @@ -1502,6 +1766,11 @@ else if ( isPEExplosiveEnabled && debugInfo.append( "(event was not canceled) " ); } + + finalizeBreakTheBlocks( pmEvent ); + + doBlockEvents( pmEvent ); + } else { @@ -1522,7 +1791,13 @@ else if ( isPEExplosiveEnabled && } - Output.get().logDebug( DebugTarget.blockBreak, debugInfo.toString() ); + if ( debugInfo.length() > 0 ) { + + long stop = System.nanoTime(); + debugInfo.append( " [" ).append( (stop - start) / 1000000d ).append( " ms]" ); + + Output.get().logDebug( DebugTarget.blockBreak, debugInfo.toString() ); + } } @@ -1533,18 +1808,19 @@ public void doActionMonitor( SpigotBlock block, Mine mine ) { // Good chance the block was already counted, but just in case it wasn't: MineTargetPrisonBlock targetBlock = mine.getTargetPrisonBlock( block ); - // Record the block break: - mine.incrementBlockMiningCount( targetBlock ); - - // Never process BlockEvents in a monitor. - // submit a mine sweeper task. It will only run if it is enabled and another - // mine sweeper task has not been submitted. - mine.submitMineSweeperTask(); + // Record the block break: + if ( mine.incrementBlockMiningCount( targetBlock ) ) { + + // submit a mine sweeper task. It will only run if it is enabled and another + // mine sweeper task has not been submitted. + mine.submitMineSweeperTask(); + + // Checks to see if the mine ran out of blocks, and if it did, then + // it will reset the mine: + mine.checkZeroBlockReset(); + } - // Checks to see if the mine ran out of blocks, and if it did, then - // it will reset the mine: - mine.checkZeroBlockReset(); } } @@ -1554,66 +1830,70 @@ public void doActionBlockEventOnly( SpigotBlock spigotBlock, Mine mine, Player p MineTargetPrisonBlock targetBlock = mine.getTargetPrisonBlock( spigotBlock ); - if ( targetBlock != null && targetBlock.getPrisonBlock() != null ) { + if ( targetBlock != null && targetBlock.getPrisonBlock() != null && !targetBlock.isCounted() ) { + // String targetBlockName = mine == null ? // spigotBlock.getPrisonBlock().getBlockName() // : targetBlock.getPrisonBlock().getBlockName(); // Process mine block break events: - SpigotPlayer sPlayer = new SpigotPlayer( player ); - PrisonBlock prisonBlock = spigotBlock.getPrisonBlock(); - - PlayerCache.getInstance().addPlayerBlocks( sPlayer, mine.getName(), targetBlock.getPrisonBlock(), 1 ); + if ( mine.incrementBlockMiningCount( targetBlock ) ) { + + SpigotPlayer sPlayer = new SpigotPlayer( player ); + PlayerCache.getInstance().addPlayerBlocks( sPlayer, mine.getName(), targetBlock.getPrisonBlock(), 1 ); + + + PrisonBlock prisonBlock = spigotBlock.getPrisonBlock(); + mine.processBlockBreakEventCommands( prisonBlock, targetBlock, sPlayer, blockEventType, triggered ); + } + - mine.processBlockBreakEventCommands( prisonBlock, targetBlock, sPlayer, blockEventType, triggered ); } } } - public boolean doAction( SpigotBlock spigotBlock, Mine mine, Player player, StringBuilder debugInfo ) { - boolean cancel = false; - debugInfo.append( "(doAction: starting EventCore) " ); - - SpigotItemStack itemInHand = SpigotPrison.getInstance().getCompatibility().getPrisonItemInMainHand( player ); - - AutoManagerFeatures aMan = SpigotPrison.getInstance().getAutoFeatures(); - - - // Do not have to check if auto manager is enabled because it isn't if it's calling this function: -// boolean isAutoManagerEnabled = aMan.isBoolean( AutoFeatures.isAutoManagerEnabled ); - boolean isProcessNormalDropsEnabled = isBoolean( AutoFeatures.handleNormalDropsEvents ); - - int drop = 1; - - if ( isProcessNormalDropsEnabled ) { - - debugInfo.append( "(doAction calculateNormalDrop) " ); - - // Drop the contents of the individual block breaks - drop = aMan.calculateNormalDrop( itemInHand, spigotBlock ); - - } - - if ( drop > 0 ) { - debugInfo.append( "(doAction processBlockBreakage) " ); - - aMan.processBlockBreakage( spigotBlock, mine, player, drop, BlockEventType.blockBreak, - null, itemInHand, true, debugInfo ); - - cancel = true; - - aMan.autosellPerBlockBreak( player ); - } - - if ( mine != null ) { - aMan.checkZeroBlockReset( mine ); - } - - return cancel; - } +// public boolean doActionX( PrisonMinesBlockBreakEvent pmEvent, StringBuilder debugInfo ) { +// boolean cancel = false; +// debugInfo.append( "(doAction: starting EventCore) " ); +// +// +// AutoManagerFeatures aMan = SpigotPrison.getInstance().getAutoFeatures(); +// +// +// // Do not have to check if auto manager is enabled because it isn't if it's calling this function: +//// boolean isAutoManagerEnabled = aMan.isBoolean( AutoFeatures.isAutoManagerEnabled ); +// boolean isProcessNormalDropsEnabled = isBoolean( AutoFeatures.handleNormalDropsEvents ); +// +// int drop = 1; +// +// if ( isProcessNormalDropsEnabled ) { +// +// debugInfo.append( "(doAction calculateNormalDrop) " ); +// +// // Drop the contents of the individual block breaks +// drop = aMan.calculateNormalDrop( pmEvent ); +// +// } +// +// if ( drop > 0 ) { +// debugInfo.append( "(doAction processBlockBreakage) " ); +// +// aMan.processBlockBreakage( pmEvent, drop, true, debugInfo ); +// +// cancel = true; +// +// aMan.autosellPerBlockBreak( pmEvent.getPlayer() ); +// } +// +// if ( pmEvent.getMine() != null ) { +// aMan.checkZeroBlockReset( pmEvent.getMine() ); +// } +// +// return cancel; +// } /** @@ -1626,48 +1906,40 @@ public boolean doAction( SpigotBlock spigotBlock, Mine mine, Player player, Stri * @param e * @param teExplosiveBlocks */ - public boolean doAction( Mine mine, Player player, List explodedBlocks, - BlockEventType blockEventType, String triggered, StringBuilder debugInfo ) { - boolean cancel = false; - - int totalCount = 0; - - SpigotItemStack itemInHand = SpigotPrison.getInstance().getCompatibility().getPrisonItemInMainHand( player ); + public boolean doAction( PrisonMinesBlockBreakEvent pmEvent, StringBuilder debugInfo ) { AutoManagerFeatures aMan = SpigotPrison.getInstance().getAutoFeatures(); + int totalDrops = aMan.calculateNormalDrop( pmEvent, debugInfo ); - debugInfo.append( "(doAction multi-blocks: " + explodedBlocks.size() ); + debugInfo.append( "(normalDrops totalDrops: " + totalDrops + ") "); + return applyDropsBlockBreakage( pmEvent, totalDrops, debugInfo ); + } + + + public boolean applyDropsBlockBreakage( PrisonMinesBlockBreakEvent pmEvent, int totalDrops, StringBuilder debugInfo ) { + boolean success = false; + // The explodedBlocks list have already been validated as being within the mine: - boolean applyExhaustion = true; - for ( SpigotBlock spigotBlock : explodedBlocks ) { - - - // Drop the contents of the individual block breaks - int drop = aMan.calculateNormalDrop( itemInHand, spigotBlock ); - totalCount += drop; - - if ( drop > 0 ) { - - aMan.processBlockBreakage( spigotBlock, mine, player, drop, - blockEventType, triggered, itemInHand, - applyExhaustion, debugInfo ); - applyExhaustion = false; - - aMan.autosellPerBlockBreak( player ); - } - - } + debugInfo.append( "(applyDropsBlockBreakage multi-blocks: " + pmEvent.getTargetExplodedBlocks().size() + ") "); - if ( mine != null ) { - aMan.checkZeroBlockReset( mine ); - } + + // Process the blockBreakage which actually breaks the block, calculates and gives the player xp, + // calculates the durability, applies food exhaustion: + processBlockBreakage( pmEvent, debugInfo ); + + +// autosellPerBlockBreak( pmEvent.getPlayer() ); + +// if ( pmEvent.getMine() != null ) { +// checkZeroBlockReset( pmEvent.getMine() ); +// } - if ( totalCount > 0 ) { - cancel = true; + if ( totalDrops > 0 ) { + success = true; } - return cancel; + return success; } @@ -1754,125 +2026,247 @@ public boolean doAction( Mine mine, Player player, List explodedBlo - public void processBlockBreakage( SpigotBlock spigotBlock, - Mine mine, Player player, int count, - BlockEventType blockEventType, String triggered, SpigotItemStack itemInHand, - boolean applyExhaustion, StringBuilder debugInfo ) + public void processBlockBreakage( PrisonMinesBlockBreakEvent pmEvent, StringBuilder debugInfo ) { - MineTargetPrisonBlock targetBlock = null; - - if ( mine != null ) { - targetBlock = mine.getTargetPrisonBlock( spigotBlock ); - } - // If this block is not in the mine (if null) and it has not been broke before // and wasn't originally air, then process the breakage: - if ( mine == null || targetBlock != null && !targetBlock.isAirBroke() ) { + if ( pmEvent.getMine() != null ) { + + - String targetBlockName = mine == null ? - spigotBlock.getPrisonBlock().getBlockName() - : targetBlock.getPrisonBlock().getBlockName(); - - debugInfo.append( "(processBlockBreakage targetBlock: " + targetBlockName + ")" ); + // Calculate XP for all blocks if enabled: + int totalXp = xpCalculateXP( pmEvent, debugInfo ); + xpGivePlayerXp( pmEvent.getSpigotPlayer(), totalXp, debugInfo ); - // Process mine block break events: - SpigotPlayer sPlayer = new SpigotPlayer( player ); + int blocksMined = (pmEvent.getTargetBlock() == null ? 0 : 1 ) + pmEvent.getTargetExplodedBlocks().size(); - int bonusXp = checkCrazyEnchant( player, spigotBlock.getWrapper(), ( itemInHand == null ? null : itemInHand.getBukkitStack()) ); + // A block was broke... so record that event on the tool: + itemLoreCounter( pmEvent.getItemInHand(), getMessage( AutoFeatures.loreBlockBreakCountName ), blocksMined ); - // Calculate XP on block break if enabled: - calculateAndGivePlayerXP( sPlayer, targetBlockName, count, bonusXp, debugInfo ); // calculate durability impact: Include item durability resistance. - if ( isBoolean( AutoFeatures.isCalculateDurabilityEnabled ) ) { + if ( isBoolean( AutoFeatures.isCalculateDurabilityEnabled ) && + pmEvent.isCalculateDurability() ) { // value of 0 = normal durability. Value 100 = never calculate durability. int durabilityResistance = 0; if ( isBoolean( AutoFeatures.loreDurabiltyResistance ) ) { - durabilityResistance = getDurabilityResistance( itemInHand, + durabilityResistance = getDurabilityResistance( pmEvent.getItemInHand(), getMessage( AutoFeatures.loreDurabiltyResistanceName ) ); } - calculateAndApplyDurability( player, itemInHand, durabilityResistance ); + calculateAndApplyDurability( pmEvent.getPlayer(), pmEvent.getItemInHand(), + blocksMined, durabilityResistance, debugInfo ); } - if ( applyExhaustion && isBoolean( AutoFeatures.isCalculateFoodExhustion ) ) { - sPlayer.incrementFoodExhaustionBlockBreak(); + + + + // Only calculate once, no matter how many blocks are included in the explosion blocks: + if ( isBoolean( AutoFeatures.isCalculateFoodExhustion ) ) { + pmEvent.getSpigotPlayer().incrementFoodExhaustionBlockBreak(); } - // A block was broke... so record that event on the tool: - itemLoreCounter( itemInHand, getMessage( AutoFeatures.loreBlockBreakCountName ), 1 ); +// if ( pmEvent.getMine() != null ) { +// // Record the block break: +// +// // apply to ALL blocks including exploded: +// applyBlockFinalizations( pmEvent, pmEvent.getTargetBlock() ); +// +// +// for ( MineTargetPrisonBlock teBlock : pmEvent.getTargetExplodedBlocks() ) { +// +// applyBlockFinalizations( pmEvent, teBlock ); +// } +// +// checkZeroBlockReset( pmEvent.getMine() ); +// } - if ( mine != null ) { - // Record the block break: - mine.incrementBlockMiningCount( targetBlock ); - - PrisonBlock prisonBlock = spigotBlock.getPrisonBlock(); + } + } + + + + // Warning: The following is now obsolete since there is now a sellall function that will sell on a + // per SpigotItemStack so it eliminates a ton of overhead. It also supports thousands of + // items per stack. +// public boolean autosellPerBlockBreak( Player player ) { +// boolean enabled = false; +// +// +//// if (isBoolean(AutoFeatures.isAutoSellPerBlockBreakEnabled) || +//// pmEvent.isForceAutoSell() ) { +//// +//// SellAllUtil.get().sellAllSell( player, itemStack, true, false, false ); +//// } +// +// +// // This won't try to sell on every item stack, but assuming that sellall will hit on very block +// // break, then the odds of inventory being overflowed on one explosion would be more rare than anything +// if ( isBoolean( AutoFeatures.isAutoSellPerBlockBreakEnabled ) ) { +// +// enabled = true; +// +// // Run sell all +// if ( isBoolean( AutoFeatures.isAutoSellPerBlockBreakInlinedEnabled ) ) { +// // run sellall inline with the block break event: +// if (PrisonSpigotSellAllCommands.get() != null) { +// PrisonSpigotSellAllCommands.get().sellAllSellWithDelayCommand(new SpigotPlayer(player)); +// } +// } +// else { +// // Submit sellall to run in the future (0 ticks in the future): +// String registeredCmd = Prison.get().getCommandHandler().findRegisteredCommand( "sellall sell silent" ); +// Bukkit.dispatchCommand(player, registeredCmd); +// } +// } +// +// return enabled; +// } + +// +// public void checkZeroBlockReset( Mine mine ) { +// if ( mine != null ) { +// +// // submit a mine sweeper task. It will only run if it is enabled and another +// // mine sweeper task has not been submitted. +// mine.submitMineSweeperTask(); +// +// // Checks to see if the mine ran out of blocks, and if it did, then +// // it will reset the mine: +// mine.checkZeroBlockReset(); +// } +// } + + private void applyBlockFinalizations( PrisonMinesBlockBreakEvent pmEvent, MineTargetPrisonBlock targetBlock ) { + + if ( targetBlock != null ) { + + Mine mine = pmEvent.getMine(); + + // Increment the block break counts if they have not been processed before. + // Since the function return true if it can count the block, then we can + // then have the player counts be incremented. + if ( mine.incrementBlockMiningCount( targetBlock ) ) { - PlayerCache.getInstance().addPlayerBlocks( sPlayer, mine.getName(), targetBlock.getPrisonBlock(), 1 ); + // Now in AutoManagerFeatures.autoPickup and calculateNormalDrop: +// PlayerCache.getInstance().addPlayerBlocks( pmEvent.getSpigotPlayer(), +// mine.getName(), targetBlock.getPrisonBlock(), 1 ); - mine.processBlockBreakEventCommands( prisonBlock, - targetBlock, sPlayer, blockEventType, triggered ); } + + SpigotBlock sBlock = (SpigotBlock) targetBlock.getMinedBlock(); + PrisonBlock pBlock = sBlock == null ? null : sBlock.getPrisonBlock(); + + mine.processBlockBreakEventCommands( pBlock, + targetBlock, pmEvent.getSpigotPlayer(), pmEvent.getBlockEventType(), pmEvent.getTriggered() ); + } } - protected void calculateAndGivePlayerXP(SpigotPlayer player, String blockName, - int count, int bonusXp, StringBuilder debugInfo ) { - - int totalXp = 0; + protected int xpCalculateXP( PrisonMinesBlockBreakEvent pmEvent, StringBuilder debugInfo ) { + int xp = 0; - if (isBoolean(AutoFeatures.isCalculateXPEnabled) && blockName != null ) { - -// String blockName = block.getPrisonBlock() == null ? null : block.getPrisonBlock().getBlockName(); - - if ( blockName != null ) { - - int xp = bonusXp; - for ( int i = 0; i < count; i++ ) { - xp += calculateXP( blockName ); - } - - if (xp > 0) { + if (isBoolean(AutoFeatures.isCalculateXPEnabled) ) { + + int totalXp = 0; + int totalBonusXp = 0; + int totalBlocks = 0; + + SpigotPlayer player = pmEvent.getSpigotPlayer(); + ItemStack itemInHand = pmEvent.getItemInHand() == null ? null : pmEvent.getItemInHand().getBukkitStack(); - totalXp += xp; - if ( isBoolean( AutoFeatures.givePlayerXPAsOrbDrops )) { + // Calculate the XP for the primary block: + MineTargetPrisonBlock targetBlock = pmEvent.getTargetBlock(); + totalXp = xpCalculateBlockXP( targetBlock, player ); + totalBlocks += (totalXp == 0 ? 0 : 1 ); + + // Calculate the XP for any exploded block: + for ( MineTargetPrisonBlock targetExplodedBlock : pmEvent.getTargetExplodedBlocks() ) { + + totalXp += xpCalculateBlockXP( targetExplodedBlock, player ); + totalBonusXp += xpCalculateBonusXP( targetExplodedBlock, player, itemInHand ); + + totalBlocks++; + } + + xp = totalXp + totalBonusXp; + + if ( totalXp > 0 || totalBonusXp > 0 ) { + + String message = String.format( "(XP calcs: blocks: %d xp: %d bonusXp: %d) ", + totalBlocks, totalXp, totalBonusXp ); + + debugInfo.append( message ); - player.dropXPOrbs( xp ); -// tech.mcprison.prison.util.Location dropPoint = player.getLocation().add( player.getLocation().getDirection()); -// ((ExperienceOrb) player.getWorld().spawn(dropPoint, ExperienceOrb.class)).setExperience(xp); - } - else { - player.giveExp( xp ); - } - } } } - if ( Output.get().isDebug() || Output.get().isDebug( DebugTarget.blockBreak ) || - Output.get().isDebug( DebugTarget.blockBreakXpCalcs )) { + + return xp; + } + + private int xpCalculateBlockXP( MineTargetPrisonBlock targetBlock, SpigotPlayer player ) + { + int xp = 0; + + if ( targetBlock != null && targetBlock.getMinedBlock() != null ) { + + SpigotBlock sBlock = ((SpigotBlock) targetBlock.getMinedBlock()); + + xp += calculateXP( sBlock.getPrisonBlock().getBlockName() ); + + } + return xp; + } + private int xpCalculateBonusXP( MineTargetPrisonBlock targetBlock, SpigotPlayer player, ItemStack itemInHand ) + { + int xp = 0; + + if ( targetBlock != null && targetBlock.getMinedBlock() != null ) { + + SpigotBlock sBlock = ((SpigotBlock) targetBlock.getMinedBlock()); + + // Bonus XP: + xp = checkCrazyEnchant( player.getWrapper(), sBlock.getWrapper(), itemInHand ); + + } + return xp; + } + + + /** + *

Gives XP to the player, either as Orbs or directly. + *

+ * + * @param player + * @param totalXp + * @param debugInfo + */ + protected void xpGivePlayerXp(SpigotPlayer player, int totalXp, StringBuilder debugInfo ) { + + if ( totalXp > 0 ) { - String message = String.format( "XP calculations: %s %s blocks: %d xp: %d bonusXp: %d " + - " isCalculateXPEnabled: %s givePlayerXPAsOrbDrops %s ", - player.getName(), blockName, count, totalXp, bonusXp, - Boolean.toString( isBoolean(AutoFeatures.isCalculateXPEnabled) ), - Boolean.toString( isBoolean( AutoFeatures.givePlayerXPAsOrbDrops ) ) ); + boolean giveXpOrbs = isBoolean( AutoFeatures.givePlayerXPAsOrbDrops ); - if ( Output.get().isDebug() || Output.get().isDebug( DebugTarget.blockBreak ) ) { - debugInfo.append( "(" ).append( message ).append( ")" ); + if ( giveXpOrbs ) { + player.dropXPOrbs( totalXp ); +// tech.mcprison.prison.util.Location dropPoint = player.getLocation().add( player.getLocation().getDirection()); +// ((ExperienceOrb) player.getWorld().spawn(dropPoint, ExperienceOrb.class)).setExperience(xp); } - if ( Output.get().isDebug( DebugTarget.blockBreakXpCalcs ) ) { - - Output.get().logDebug( DebugTarget.blockBreakXpCalcs, message ); + else { + player.giveExp( totalXp ); } + debugInfo.append( "(xp " + totalXp + ( giveXpOrbs ? "Orbs" : "direct") + ") " ); } + } @@ -2038,12 +2432,12 @@ private boolean isToolDisabled( Player player ) { if ( isBoolean( AutoFeatures.isPreventToolBreakage ) ) { SpigotItemStack itemInHand = - SpigotPrison.getInstance().getCompatibility().getPrisonItemInMainHand( player ); + SpigotCompatibility.getInstance().getPrisonItemInMainHand( player ); if ( itemInHand != null && !itemInHand.isAir() ) { int breakageThreshold = getInteger( AutoFeatures.preventToolBreakageThreshold ); - Compatibility compat = SpigotPrison.getInstance().getCompatibility(); + Compatibility compat = SpigotCompatibility.getInstance(); int maxDurability = compat.getDurabilityMax( itemInHand ); int durability = compat.getDurability( itemInHand ); @@ -2056,6 +2450,10 @@ private boolean isToolDisabled( Player player ) { } /** + *

This is calculated only once per block break event, no matter how many blocks + * are involved. + *

+ * *

This should calculate and apply the durability consumption on the tool. *

* @@ -2092,51 +2490,67 @@ private boolean isToolDisabled( Player player ) { * Zero always disables this calculation and allows normal durability calculations * to be performed. 100 always prevents wear. */ - protected void calculateAndApplyDurability(Player player, SpigotItemStack itemInHand, int durabilityResistance) { + protected void calculateAndApplyDurability(Player player, SpigotItemStack itemInHand, int blocksMined, + int durabilityResistance, StringBuilder debugInfo ) { - if ( itemInHand != null && !itemInHand.isAir() ) { + // If no tool, or durabilityResistance is less than 100: + if ( itemInHand != null && !itemInHand.isAir() && durabilityResistance < 100 ) { - Compatibility compat = SpigotPrison.getInstance().getCompatibility(); + Compatibility compat = SpigotCompatibility.getInstance(); int maxDurability = compat.getDurabilityMax( itemInHand ); int durability = compat.getDurability( itemInHand ); - short damage = 1; // Generally 1 unless instant break block then zero. + short totalDamage = 1; // Generally 1 unless instant break block then zero. int durabilityLevel = 0; boolean toolBreak = false; // Need to skip processing on empty item stacks and items that have no max durability if ( maxDurability > 0 ) { + short damage = 1; + if ( itemInHand.getBukkitStack().containsEnchantment( Enchantment.DURABILITY)) { + durabilityLevel = itemInHand.getBukkitStack().getEnchantmentLevel( Enchantment.DURABILITY ); + } - if ( durabilityResistance >= 100 ) { - damage = 0; - } else if ( durabilityResistance > 0 ) { - if ( getRandom().nextInt( 100 ) <= durabilityResistance ) { + for ( int y = 0; y < blocksMined; y++ ) { + if ( durabilityResistance >= 100 ) { damage = 0; + } + else if ( durabilityResistance > 0 ) { + if ( getRandom().nextInt( 100 ) <= durabilityResistance ) { + damage = 0; + } } - } - - if ( damage > 0 && itemInHand.getBukkitStack().containsEnchantment( Enchantment.DURABILITY)) { - durabilityLevel = itemInHand.getBukkitStack().getEnchantmentLevel( Enchantment.DURABILITY ); - // the chance of losing durability is 1 in (1+level) - // So if the random int == 0, then take damage, otherwise none. - if (getRandom().nextInt( 1 + durabilityLevel ) > 0) { - damage = 0; + if ( damage > 0 && durabilityLevel > 0 ) { + + // the chance of losing durability is 1 in (1+level) + // So if the random int == 0, then take damage, otherwise none. + if (getRandom().nextInt( 1 + durabilityLevel ) > 0) { + damage = 0; + } } + + totalDamage += damage; } - if (damage > 0) { + int newDurability = durability + totalDamage; + int remainingDurability = maxDurability - newDurability; + + if (totalDamage > 0 && + (!isBoolean( AutoFeatures.isPreventToolBreakage ) || + isBoolean( AutoFeatures.isPreventToolBreakage ) && + remainingDurability >= getInteger( AutoFeatures.preventToolBreakageThreshold ) ) ) { // Compatibility compat = SpigotPrison.getInstance().getCompatibility(); // int maxDurability = compat.getDurabilityMax( itemInHand ); // int durability = compat.getDurability( itemInHand ); - int newDurability = durability + damage; if (newDurability > maxDurability) { // Item breaks! ;( compat.breakItemInMainHand( player ); + itemInHand = null; toolBreak = true; } else { compat.setDurability( itemInHand, newDurability ); @@ -2145,21 +2559,13 @@ protected void calculateAndApplyDurability(Player player, SpigotItemStack itemIn } } - - if ( Output.get().isDebug( DebugTarget.blockBreakDurability ) ) { - - String message = String.format( "calculateAndApplyDurability: %s: maxDurability= %d " + - "durability: %d damage: %d durResistance: %d toolDurabilityLvl: %d %s", - itemInHand.getName(), maxDurability, durability, damage, - durabilityResistance, durabilityLevel, - (toolBreak ? "[Broke]" : "") ); - -// if ( Output.get().isDebug() || Output.get().isDebug( DebugTarget.blockBreak ) ) { -// debugInfo.append( "(" ).append( message ).append( ")" ); -// -// } - Output.get().logDebug( DebugTarget.blockBreakDurability, message ); - } + String message = String.format( "(calcDurability: %s: maxDurability= %d " + + "durability: %d damage: %d durResistance: %d toolDurabilityLvl: %d %s) ", + (itemInHand == null ? "(empty hand)" : itemInHand.getName() ), + maxDurability, durability, totalDamage, + durabilityResistance, durabilityLevel, + (toolBreak ? "[Broke]" : "") ); + debugInfo.append( message ); } } @@ -2364,38 +2770,9 @@ private int checkCrazyEnchant( Player player, Block block, ItemStack item ) { return bonusXp; } - - private Mine findMineLocation( SpigotBlock block ) { - return getPrisonMineManager() == null ? - null : getPrisonMineManager().findMineLocationExact( block.getLocation() ); - } - - private TreeMap getPlayerCache() { - return getPrisonMineManager() == null ? - new TreeMap() : - getPrisonMineManager().getPlayerCache(); - } - private PrisonMines getPrisonMineManager() { - if ( prisonMineManager == null && !isMineModuleDisabled() ) { - Optional mmOptional = Prison.get().getModuleManager().getModule( PrisonMines.MODULE_NAME ); - if ( mmOptional.isPresent() && mmOptional.get().isEnabled() ) { - PrisonMines prisonMines = (PrisonMines) mmOptional.get(); - this.prisonMineManager = prisonMines; - } else { - setMineModuleDisabled( true ); - } - } - return prisonMineManager; - } - private boolean isMineModuleDisabled() { - return mineModuleDisabled; - } - private void setMineModuleDisabled( boolean mineModuleDisabled ) { - this.mineModuleDisabled = mineModuleDisabled; - } @SuppressWarnings( "unused" ) diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/block/OnBlockBreakEventListener.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/block/OnBlockBreakEventListener.java index f481196cc..527e4ec89 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/block/OnBlockBreakEventListener.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/block/OnBlockBreakEventListener.java @@ -1,5 +1,6 @@ package tech.mcprison.prison.spigot.block; +import tech.mcprison.prison.autofeatures.AutoFeaturesFileConfig.AutoFeatures; import tech.mcprison.prison.output.Output; import tech.mcprison.prison.spigot.SpigotPrison; import tech.mcprison.prison.spigot.autofeatures.events.AutoManagerBlockBreakEvents; @@ -124,9 +125,23 @@ public void registerAllBlockBreakEvents(SpigotPrison spigotPrison ) { // Only register these event listeners if these are enabled. // In order to be enabled, the prison mines module must be enabled. + if ( !isBoolean(AutoFeatures.isAutoManagerEnabled) ) { + + Output.get().logWarn( "AutoMager: AutoFeatures is dsabled. " + + "No block break listeners are registered. " + + "The setting 'autoManager.isAutoManagerEnabled' is set to 'false' " + + "in autoFeaturesConfig.yml." ); + + return; + } + if ( isEnabled() ) { + Output.get().logInfo( "AutoManager: AutoFeatures and the Mine module are enabled. Prison " + + "will register the selected block break listeners." ); + + // This will register all events that should be enabled, for both // auto manager and the normal events too. new AutoManagerBlockBreakEvents().registerEvents(); @@ -135,8 +150,8 @@ public void registerAllBlockBreakEvents(SpigotPrison spigotPrison ) { } else { - Output.get().logWarn( "BlockBreak event listeners cannot be registered " + - "since the mine module is disabled." ); + Output.get().logWarn( "AutoManager: AutoFeaturs are enabled, but the Mines module is disabled." + + "Prison will not register any block break listeners." ); } } diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/block/OnBlockBreakMines.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/block/OnBlockBreakMines.java new file mode 100644 index 000000000..903ddecfe --- /dev/null +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/block/OnBlockBreakMines.java @@ -0,0 +1,349 @@ +package tech.mcprison.prison.spigot.block; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.TreeMap; +import java.util.UUID; + +import org.bukkit.block.Block; +import org.bukkit.entity.Player; + +import tech.mcprison.prison.Prison; +import tech.mcprison.prison.internal.block.MineTargetPrisonBlock; +import tech.mcprison.prison.mines.PrisonMines; +import tech.mcprison.prison.mines.data.Mine; +import tech.mcprison.prison.modules.Module; +import tech.mcprison.prison.output.Output; +import tech.mcprison.prison.spigot.SpigotUtil; +import tech.mcprison.prison.spigot.api.PrisonMinesBlockBreakEvent; +import tech.mcprison.prison.spigot.game.SpigotPlayer; +import tech.mcprison.prison.spigot.utils.BlockUtils; + +public class OnBlockBreakMines +{ + private PrisonMines prisonMineManager; + private boolean mineModuleDisabled = false; + + public OnBlockBreakMines() { + super(); + + this.prisonMineManager = null; + + } + + public class MinesEventResults { + private boolean cancelEvent = false; + private boolean ignoreEvent = false; + + public MinesEventResults() { + super(); + } + + public boolean isCancelEvent() { + return cancelEvent; + } + public void setCancelEvent( boolean cancelEvent ) { + this.cancelEvent = cancelEvent; + } + + public boolean isIgnoreEvent() { + return ignoreEvent; + } + public void setIgnoreEvent( boolean ignoreEvent ) { + this.ignoreEvent = ignoreEvent; + } + } + + public Mine findMine( Player player, SpigotBlock sBlock, List altBlocksSource, PrisonMinesBlockBreakEvent pmEvent ) + { + return findMine( player.getUniqueId(), sBlock, altBlocksSource, pmEvent ); + } + + public Mine findMine( UUID playerUUID, SpigotBlock sBlock, List altBlocksSource, PrisonMinesBlockBreakEvent pmEvent ) + { + Long playerUUIDLSB = Long.valueOf( playerUUID.getLeastSignificantBits() ); + + // Get the cached mine, if it exists: + Mine mine = getPlayerCache().get( playerUUIDLSB ); + + if ( mine == null || sBlock != null && !mine.isInMineExact( sBlock.getLocation() ) ) + { + // Look for the correct mine to use. + // Set mine to null so if cannot find the right one it will return a + // null: + mine = findMineLocation( sBlock ); + + // Thanks to CrazyEnchant, where they do not identify the block the + // player breaks, we + // have to go through all of the unprecessedRawBlocks to see if any + // are within a mine. + // If we find a block that's in a mine, then use that block as the + // primary block. + if ( mine == null && altBlocksSource != null ) + { + + for ( Block bBlock : altBlocksSource ) + { + SpigotBlock sBlockAltBlock = new SpigotBlock( bBlock ); + mine = findMineLocation( sBlockAltBlock ); + if ( mine != null ) + { + + if ( pmEvent != null ) + { + pmEvent.setSpigotBlock( sBlockAltBlock ); + } + + break; + } + } + } + + // Store the mine in the player cache if not null: + if ( mine != null ) + { + getPlayerCache().put( playerUUIDLSB, mine ); + } + } + + return mine; + } + + + // NOTE: The following two commented out functions need to be copied and actived in + // in the class that is using these functions for these two events: + +// protected boolean ignoreMinesBlockBreakEvent( Cancellable event, Player player, Block block ) { +// +// MinesEventResults eventResults = ignoreMinesBlockBreakEvent( player, block ); +// +// if ( eventResults.isCancelEvent() ) { +// event.setCancelled( eventResults.isCancelEvent() ); +// } +// return eventResults.isIgnoreEvent(); +// } +// +// protected boolean processMinesBlockBreakEvent( PEExplosionEvent event, Player player, Block block ) { +// +// MinesEventResults eventResults = ignoreMinesBlockBreakEvent( player, block ); +// +// if ( eventResults.isCancelEvent() ) { +// event.setCancelled( eventResults.isCancelEvent() ); +// } +// return eventResults.isIgnoreEvent(); +// } + + + protected MinesEventResults ignoreMinesBlockBreakEvent( Player player, Block block ) { + MinesEventResults results = new MinesEventResults(); + + SpigotBlock sBlock = new SpigotBlock( block ); + if ( BlockUtils.getInstance().isUnbreakable( sBlock ) ) { + results.setCancelEvent( true ); + results.setIgnoreEvent( true ); + } + + Mine mine = findMine( player, sBlock, null, null ); + + if ( mine == null ) { + // Prison is unable to process blocks outside of mines right now, so exit: + results.setIgnoreEvent( true ); + } + else { + + // If not minable, then display message and exit. + if ( !mine.getMineStateMutex().isMinable() ) { + + SpigotPlayer sPlayer = new SpigotPlayer( player ); + sPlayer.setActionBar( "Mine " + mine.getTag() + " is being reset... please wait." ); + results.setCancelEvent( true ); + results.setIgnoreEvent( true ); + } + MineTargetPrisonBlock targetBlock = mine.getTargetPrisonBlock( sBlock ); + + // If ignore all block events, then exit this function without logging anything: + if ( targetBlock != null && targetBlock.isIgnoreAllBlockEvents() ) { + + // Do not cancel the event... let other plugins deal with it... prison does not care about this block. + //event.setCancelled( true ); + results.setIgnoreEvent( true ); + } + } + + return results; + } + +// /** +// *

Warning... this is a temp copy of the real function and will be removed +// * if PEExplosionEvent adds the interface Cancellable. +// *

+// * +// * @param event +// * @param player +// * @param block +// * @return +// */ +// protected boolean processMinesBlockBreakEvent( PEExplosionEvent event, Player player, Block block ) { +// boolean processEvent = true; +// +// SpigotBlock sBlock = new SpigotBlock( block ); +// if ( BlockUtils.getInstance().isUnbreakable( sBlock ) ) { +// event.setCancelled( true ); +// processEvent = false; +// } +// +// Mine mine = findMine( player, sBlock, null, null ); +// +// if ( mine == null ) { +// // Prison is unable to process blocks outside of mines right now, so exit: +// processEvent = false; +// } +// +// // If not minable, then display message and exit. +// if ( !mine.getMineStateMutex().isMinable() ) { +// +// SpigotPlayer sPlayer = new SpigotPlayer( player ); +// sPlayer.setActionBar( "Mine " + mine.getTag() + " is being reset... please wait." ); +// event.setCancelled( true ); +// processEvent = false; +// } +// MineTargetPrisonBlock targetBlock = mine.getTargetPrisonBlock( sBlock ); +// +// // If ignore all block events, then exit this function without logging anything: +// if ( targetBlock.isIgnoreAllBlockEvents() ) { +// event.setCancelled( true ); +// processEvent = false; +// } +// +// +// return processEvent; +// } + + public void checkZeroBlockReset( Mine mine ) { + if ( mine != null ) { + + // submit a mine sweeper task. It will only run if it is enabled and another + // mine sweeper task has not been submitted. + mine.submitMineSweeperTask(); + + // Checks to see if the mine ran out of blocks, and if it did, then + // it will reset the mine: + mine.checkZeroBlockReset(); + } + } + + + public boolean collectBukkitDrops( List bukkitDrops, MineTargetPrisonBlock targetBlock, + SpigotItemStack itemInHand, SpigotBlock sBlockMined ) + { + boolean results = false; + + // if ( sBlockMined == null && targetBlock.getMinedBlock() != null ) { + // sBlockMined = (SpigotBlock) targetBlock.getMinedBlock(); + // } + // SpigotBlock sBlock = (SpigotBlock) targetBlock.getMinedBlock(); + + // If in the mine, then need a targetBlock, otherwise if it's null then get drops anyway: + if ( sBlockMined != null && + ( targetBlock == null || + targetBlock.getPrisonBlock().equals( sBlockMined.getPrisonBlock() ) + ) ) + { + + List drops = SpigotUtil.getDrops( sBlockMined, itemInHand ); + + bukkitDrops.addAll( drops ); + + //// This clears the drops for the given block, so if the event is + //// not canceled, it will + //// not result in duplicate drops. + // if ( isBoolean( AutoFeatures.cancelAllBlockEventBlockDrops ) ) { + // sBlock.clearDrops(); + // } + + results = true; + + } + else if ( sBlockMined != null ) + { + Output.get().logWarn( "collectBukkitDrops: block was changed and not what was expected. " + "Block: " + + sBlockMined.getBlockName() + " expecting: " + + (targetBlock == null ? "(nothing)" : targetBlock.getPrisonBlock().getBlockName()) ); + } + + return results; + } + + + public void clearBukkitDrops( List bukkitDrops, MineTargetPrisonBlock targetBlock ) + { + + SpigotBlock sBlock = (SpigotBlock) targetBlock.getMinedBlock(); + sBlock.clearDrops(); + + } + + + /** + *

The List of drops must have only one ItemStack per block type (name). + * This function combines multiple occurrences together and adds up their + * counts to properly represent the total quantity in the original drops collection + * that had duplicate entries. + *

+ * + * @param List of SpigotItemStack drops with duplicate entries + * @return List of SpigotItemStack drops without duplicates + */ + public List mergeDrops( List drops ) + { + TreeMap results = new TreeMap<>(); + + for ( SpigotItemStack drop : drops ) { + String key = drop.getName(); + if ( !results.containsKey( key ) ) { + results.put( key, drop ); + } + else { + SpigotItemStack sItemStack = results.get( key ); + + sItemStack.setAmount( sItemStack.getAmount() + drop.getAmount() ); + } + } + + return new ArrayList<>( results.values() ); + } + + + private Mine findMineLocation( SpigotBlock block ) { + return getPrisonMineManager() == null ? + null : getPrisonMineManager().findMineLocationExact( block.getLocation() ); + } + + + private TreeMap getPlayerCache() { + return getPrisonMineManager() == null ? + new TreeMap() : + getPrisonMineManager().getPlayerCache(); + } + + private PrisonMines getPrisonMineManager() { + if ( prisonMineManager == null && !isMineModuleDisabled() ) { + Optional mmOptional = Prison.get().getModuleManager().getModule( PrisonMines.MODULE_NAME ); + if ( mmOptional.isPresent() && mmOptional.get().isEnabled() ) { + PrisonMines prisonMines = (PrisonMines) mmOptional.get(); + this.prisonMineManager = prisonMines; + } else { + setMineModuleDisabled( true ); + } + } + return prisonMineManager; + } + + private boolean isMineModuleDisabled() { + return mineModuleDisabled; + } + private void setMineModuleDisabled( boolean mineModuleDisabled ) { + this.mineModuleDisabled = mineModuleDisabled; + } +} diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/block/OnBlockBreakPlayerManualCore.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/block/OnBlockBreakPlayerManualCore.java new file mode 100644 index 000000000..db847e715 --- /dev/null +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/block/OnBlockBreakPlayerManualCore.java @@ -0,0 +1,292 @@ +package tech.mcprison.prison.spigot.block; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import org.bukkit.entity.Player; + +import com.cryptomorin.xseries.XMaterial; + +import tech.mcprison.prison.autofeatures.AutoFeaturesFileConfig.AutoFeatures; +import tech.mcprison.prison.spigot.SpigotUtil; +import tech.mcprison.prison.spigot.autofeatures.AutoManagerFeatures; +import tech.mcprison.prison.spigot.game.SpigotPlayer; + +/** + *

This is a manual way of dealing with player inventory directly. It is + * added here to keep it out of the auto features. + * The use of this is through the prison utils functions blocking and smelting. + *

+ * + *

These should not be used with normal block break event handling since + * these manipulate the player's inventory for each process, + * instead of dealing with item stacks during the processing, then adding + * the drops, and the product of the smelting and blocking. + *

+ */ +public class OnBlockBreakPlayerManualCore + extends AutoManagerFeatures +{ + + + public void playerSmelt( SpigotPlayer player ) { + + List smelts = new ArrayList<>(); + + smelts.add( XMaterial.COBBLESTONE ); + smelts.add( XMaterial.GOLD_ORE ); + smelts.add( XMaterial.NETHER_GOLD_ORE ); + smelts.add( XMaterial.DEEPSLATE_GOLD_ORE ); + smelts.add( XMaterial.RAW_GOLD ); + + smelts.add( XMaterial.IRON_ORE ); + smelts.add( XMaterial.DEEPSLATE_IRON_ORE ); + smelts.add( XMaterial.RAW_IRON ); + + smelts.add( XMaterial.COAL_ORE ); + smelts.add( XMaterial.DEEPSLATE_COAL_ORE ); + + smelts.add( XMaterial.DIAMOND_ORE ); + smelts.add( XMaterial.DEEPSLATE_DIAMOND_ORE ); + + smelts.add( XMaterial.EMERALD_ORE ); + smelts.add( XMaterial.DEEPSLATE_EMERALD_ORE ); + + smelts.add( XMaterial.LAPIS_ORE ); + smelts.add( XMaterial.DEEPSLATE_LAPIS_ORE ); + + smelts.add( XMaterial.REDSTONE_ORE ); + smelts.add( XMaterial.DEEPSLATE_REDSTONE_ORE ); + + smelts.add( XMaterial.NETHER_QUARTZ_ORE ); + smelts.add( XMaterial.ANCIENT_DEBRIS ); + + smelts.add( XMaterial.COPPER_ORE ); + smelts.add( XMaterial.DEEPSLATE_COPPER_ORE ); + smelts.add( XMaterial.RAW_COPPER ); + + + for ( XMaterial xMat : smelts ) { + autoFeatureSmelt( player.getWrapper(), xMat ); + } + + } + + public void playerBlock( SpigotPlayer player ) { + + List blocks = new ArrayList<>(); + + blocks.add( XMaterial.GOLD_INGOT ); + blocks.add( XMaterial.IRON_INGOT ); + blocks.add( XMaterial.COAL ); + blocks.add( XMaterial.DIAMOND ); + blocks.add( XMaterial.REDSTONE ); + blocks.add( XMaterial.EMERALD ); + blocks.add( XMaterial.QUARTZ ); + blocks.add( XMaterial.PRISMARINE_SHARD ); + blocks.add( XMaterial.SNOW_BLOCK ); + blocks.add( XMaterial.GLOWSTONE_DUST ); + blocks.add( XMaterial.LAPIS_LAZULI ); + + + for ( XMaterial xMat : blocks ) { + autoFeatureBlock( player.getWrapper(), xMat ); + } + + } + + + protected XMaterial autoFeatureSmelt( Player p, XMaterial source ) + { + XMaterial results = source; + + boolean isAll = isBoolean( AutoFeatures.smeltAllBlocks ); + +// XMaterial source = SpigotUtil.getXMaterial( block.getPrisonBlock() ); + if ( source != null ) { + + switch ( source ) + { + case COBBLESTONE: + autoSmelt( isAll || isBoolean( AutoFeatures.smeltCobblestone ), source, XMaterial.STONE, p ); + results = XMaterial.STONE; + break; + + case GOLD_ORE: + case NETHER_GOLD_ORE: + case DEEPSLATE_GOLD_ORE: + case RAW_GOLD: + autoSmelt( isAll || isBoolean( AutoFeatures.smeltGoldOre ), source, XMaterial.GOLD_INGOT, p ); + results = XMaterial.GOLD_INGOT; + break; + + case IRON_ORE: + case DEEPSLATE_IRON_ORE: + case RAW_IRON: + autoSmelt( isAll || isBoolean( AutoFeatures.smeltIronOre ), source, XMaterial.IRON_INGOT, p ); + results = XMaterial.IRON_INGOT; + break; + + case COAL_ORE: + case DEEPSLATE_COAL_ORE: + autoSmelt( isAll || isBoolean( AutoFeatures.smeltCoalOre ), source, XMaterial.COAL, p ); + results = XMaterial.COAL; + break; + + case DIAMOND_ORE: + case DEEPSLATE_DIAMOND_ORE: + autoSmelt( isAll || isBoolean( AutoFeatures.smeltDiamondlOre ), source, XMaterial.DIAMOND, p ); + results = XMaterial.DIAMOND; + break; + + case EMERALD_ORE: + case DEEPSLATE_EMERALD_ORE: + autoSmelt( isAll || isBoolean( AutoFeatures.smeltEmeraldOre ), source, XMaterial.EMERALD, p ); + results = XMaterial.EMERALD; + break; + + case LAPIS_ORE: + case DEEPSLATE_LAPIS_ORE: + autoSmelt( isAll || isBoolean( AutoFeatures.smeltLapisOre ), source, XMaterial.LAPIS_LAZULI, p ); + results = XMaterial.LAPIS_LAZULI; + break; + + case REDSTONE_ORE: + case DEEPSLATE_REDSTONE_ORE: + autoSmelt( isAll || isBoolean( AutoFeatures.smeltRedstoneOre ), source, XMaterial.REDSTONE, p ); + results = XMaterial.REDSTONE; + break; + + case NETHER_QUARTZ_ORE: + autoSmelt( isAll || isBoolean( AutoFeatures.smeltNetherQuartzOre ), source, XMaterial.QUARTZ, p ); + results = XMaterial.QUARTZ; + break; + + case ANCIENT_DEBRIS: + autoSmelt( isAll || isBoolean( AutoFeatures.smeltAncientDebris ), source, XMaterial.NETHERITE_SCRAP, p ); + results = XMaterial.NETHERITE_SCRAP; + break; + + // v1.17 !! + case COPPER_ORE: + case DEEPSLATE_COPPER_ORE: + case RAW_COPPER: + autoSmelt( isAll || isBoolean( AutoFeatures.smeltCopperOre ), source, XMaterial.COPPER_INGOT, p ); + results = XMaterial.COPPER_INGOT; + break; + + default: + break; + } + } + + + return results; + } + + protected void autoFeatureBlock( Player p, XMaterial source ) { + + boolean isAll = isBoolean( AutoFeatures.smeltAllBlocks ); + + if ( source != null ) { + + // Any autoBlock target could be enabled, and could have multiples of 9, so perform the + // checks within each block type's function call. So in one pass, could hit on more + // than one of these for multiple times too. + switch ( source ) + { + case GOLD_INGOT: + autoBlock( isAll || isBoolean( AutoFeatures.blockGoldBlock ), source, XMaterial.GOLD_BLOCK, p ); + + break; + + case IRON_INGOT: + autoBlock( isAll || isBoolean( AutoFeatures.blockIronBlock ), source, XMaterial.IRON_BLOCK, p ); + + break; + + case COAL: + autoBlock( isAll || isBoolean( AutoFeatures.blockCoalBlock ), source, XMaterial.COAL_BLOCK, p ); + + break; + + case DIAMOND: + autoBlock( isAll || isBoolean( AutoFeatures.blockDiamondBlock ), source, XMaterial.DIAMOND_BLOCK, p ); + + break; + + case REDSTONE: + autoBlock( isAll || isBoolean( AutoFeatures.blockRedstoneBlock ), source,XMaterial.REDSTONE_BLOCK, p ); + + break; + + case EMERALD: + autoBlock( isAll || isBoolean( AutoFeatures.blockEmeraldBlock ), source, XMaterial.EMERALD_BLOCK, p ); + + break; + + case QUARTZ: + autoBlock( isAll || isBoolean( AutoFeatures.blockQuartzBlock ), source, XMaterial.QUARTZ_BLOCK, 4, p ); + + break; + + case PRISMARINE_SHARD: + autoBlock( isAll || isBoolean( AutoFeatures.blockPrismarineBlock ), source, XMaterial.PRISMARINE, 4, p ); + + break; + + case SNOWBALL: + autoBlock( isAll || isBoolean( AutoFeatures.blockSnowBlock ), source, XMaterial.SNOW_BLOCK, 4, p ); + + break; + + case GLOWSTONE_DUST: + autoBlock( isAll || isBoolean( AutoFeatures.blockGlowstone ), source, XMaterial.GLOWSTONE, 4, p ); + + break; + + case LAPIS_LAZULI: + autoBlock( isAll || isBoolean( AutoFeatures.blockLapisBlock ), source, XMaterial.LAPIS_BLOCK, p ); + + break; + + case COPPER_INGOT: + autoBlock( isAll || isBoolean( AutoFeatures.blockCopperBlock ), source, XMaterial.COPPER_BLOCK, p ); + + break; + + default: + break; + } + } + + } + + + + protected void autoSmelt( boolean autoSmelt, XMaterial source, XMaterial target, Player p ) { + + if ( autoSmelt && source != null && target != null ) { + + HashMap overflow = SpigotUtil.itemStackReplaceItems( p, source, target, 1 ); + dropExtra( overflow, p ); + + } + } + + + protected void autoBlock( boolean autoBlock, XMaterial source, XMaterial target, Player p ) { + autoBlock(autoBlock, source, target, 9, p ); + } + + + protected void autoBlock( boolean autoBlock, XMaterial source, XMaterial target, int ratio, Player p ) { + + if ( autoBlock && source != null && target != null ) { + HashMap overflow = SpigotUtil.itemStackReplaceItems( p, source, target, ratio ); + dropExtra( overflow, p ); + + } + } +} diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/block/SpigotBlock.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/block/SpigotBlock.java index 339924aac..bf33df38e 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/block/SpigotBlock.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/block/SpigotBlock.java @@ -34,8 +34,8 @@ import tech.mcprison.prison.internal.block.PrisonBlock; import tech.mcprison.prison.internal.block.PrisonBlock.PrisonBlockType; import tech.mcprison.prison.output.Output; -import tech.mcprison.prison.spigot.SpigotPrison; import tech.mcprison.prison.spigot.SpigotUtil; +import tech.mcprison.prison.spigot.compat.SpigotCompatibility; import tech.mcprison.prison.util.BlockType; import tech.mcprison.prison.util.Location; @@ -66,7 +66,7 @@ public String toString() { StringBuilder sb = new StringBuilder(); sb.append( getPrisonBlock().getBlockName() ).append( " " ) - .append( getLocation().toCoordinates() ); + .append( getLocation().toWorldCoordinates() ); return sb.toString(); @@ -77,7 +77,8 @@ public String getBlockName() { } @Override public Location getLocation() { - return SpigotUtil.bukkitLocationToPrison(getWrapper().getLocation()); + return getWrapper() == null ? null : + SpigotUtil.bukkitLocationToPrison(getWrapper().getLocation()); } @Override public Block getRelative(BlockFace face) { @@ -88,7 +89,7 @@ public String getBlockName() { } @Override public BlockType getType() { - return SpigotPrison.getInstance().getCompatibility().getBlockType( getWrapper() ); + return SpigotCompatibility.getInstance().getBlockType( getWrapper() ); // return SpigotUtil.materialToBlockType(bBlock.getType()); } @@ -109,11 +110,11 @@ public PrisonBlock getPrisonBlock() { } } - if ( results == null ) { - results = SpigotPrison.getInstance().getCompatibility().getPrisonBlock( getWrapper() ); + if ( results == null && getWrapper() != null ) { + results = SpigotCompatibility.getInstance().getPrisonBlock( getWrapper() ); } - if ( results.getLocation() == null && getLocation() != null ) { + if ( results != null && results.getLocation() == null && getLocation() != null ) { // Clone the block that was found in the mine. This will allow us to // set the location: results = new PrisonBlock( results ); @@ -167,14 +168,16 @@ public void setPrisonBlock( XMaterial xMat ) { public void setPrisonBlock( PrisonBlock prisonBlock ) { + if ( prisonBlock == null ) { + prisonBlock = PrisonBlock.AIR; + } + switch ( prisonBlock.getBlockType() ) { case minecraft: - { - SpigotPrison.getInstance().getCompatibility(). - updateSpigotBlock( prisonBlock, getWrapper() ); - } + SpigotCompatibility.getInstance(). + updateSpigotBlock( prisonBlock, getWrapper() ); break; @@ -203,7 +206,7 @@ public void setPrisonBlock( PrisonBlock prisonBlock ) { public void setBlockFace( BlockFace blockFace ) { - SpigotPrison.getInstance().getCompatibility() + SpigotCompatibility.getInstance() .setBlockFace( getWrapper(), blockFace ); } /** @@ -215,7 +218,7 @@ public void setBlockFace( BlockFace blockFace ) { @Override public void setType(BlockType blockType) { - SpigotPrison.getInstance().getCompatibility() + SpigotCompatibility.getInstance() .updateSpigotBlock( blockType, getWrapper() ); // if ( type != null && type != BlockType.IGNORE ) { @@ -298,7 +301,8 @@ public void setType(BlockType blockType) { return results; } - @Override public List getDrops() { + @Override + public List getDrops() { List ret = new ArrayList<>(); if ( getWrapper() != null ) { @@ -317,13 +321,42 @@ public List getDrops(ItemStack tool) { if ( getWrapper() != null ) { - getWrapper().getDrops(SpigotUtil.prisonItemStackToBukkit(tool)) + if ( tool == null ) { + ret.addAll( getDrops() ); + } + else { + + org.bukkit.inventory.ItemStack bukkitItemStack = SpigotUtil.prisonItemStackToBukkit(tool); + + if ( bukkitItemStack != null ) { + + getWrapper().getDrops( bukkitItemStack ) .forEach(itemStack -> ret.add(SpigotUtil.bukkitItemStackToPrison(itemStack))); + } + } + } return ret; } + /** + *

This clears the drops for the given block, so if the event is not canceled, it will + * not result in duplicate drops. + *

+ */ + public void clearDrops() { + + if ( getWrapper() != null && getWrapper().getDrops() != null ) { + for ( org.bukkit.inventory.ItemStack iStack : getWrapper().getDrops() ) + { + iStack.setAmount( 0 ); + } +// getWrapper().getDrops().clear(); + } + } + + // public List getDrops(SpigotItemStack tool) { // List ret = new ArrayList<>(); // 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 54c02ce85..eece37be3 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 @@ -11,7 +11,7 @@ import tech.mcprison.prison.Prison; import tech.mcprison.prison.internal.ItemStack; -import tech.mcprison.prison.spigot.SpigotPrison; +import tech.mcprison.prison.spigot.compat.SpigotCompatibility; import tech.mcprison.prison.util.BlockType; public class SpigotItemStack @@ -44,7 +44,7 @@ public SpigotItemStack( org.bukkit.inventory.ItemStack bukkitStack ) { // in the bukkitStack: int amount = bukkitStack.getAmount(); - BlockType type = SpigotPrison.getInstance().getCompatibility() + BlockType type = SpigotCompatibility.getInstance() .getBlockType( bukkitStack ); // BlockType type = materialToBlockType(bukkitStack.getType()); diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/bombs/MineBombData.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/bombs/MineBombData.java deleted file mode 100644 index 93950d8a7..000000000 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/bombs/MineBombData.java +++ /dev/null @@ -1,48 +0,0 @@ -package tech.mcprison.prison.spigot.bombs; - -import java.util.List; - -import com.cryptomorin.xseries.XMaterial; - -public class MineBombData { - - private String name; - - - /** - *

The String name of an XMaterial item to use as the "bomb". - *

- */ - private String itemType; - - /* - *

A transient reference to the actual XMaterial item that is used - * for the bomb. This is converted from the String itemType. - *

- */ - private transient XMaterial item; - - - private List lore; - - /** - *

The radius identifies how large the blast should be. - *

- */ - private int radius = 1; - - /** - *

The chance of complete removal. So if the radius includes - * 100 blocks, but the chance is only 50%, each block will be given - * a chance if it is to be included, or excluded. - *

- */ - private double chance; - - - private String explosionShape; - - - - -} diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/bombs/MineBombs.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/bombs/MineBombs.java deleted file mode 100644 index c41d94dd0..000000000 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/bombs/MineBombs.java +++ /dev/null @@ -1,51 +0,0 @@ -package tech.mcprison.prison.spigot.bombs; - -import java.util.ArrayList; -import java.util.List; - -import tech.mcprison.prison.util.Location; - -public class MineBombs -{ - - public enum ExplosionShape { - sphere, - sphereHollow - ; - - } - - public List calculateSphere( Location loc, int radius, boolean hollow ) { - List results = new ArrayList<>(); - - if ( loc != null && radius > 0 ) { - int cenX = loc.getBlockX(); - int cenY = loc.getBlockY(); - int cenZ = loc.getBlockZ(); - - double radiusSqr = radius * radius; - double radiusHSqr = (radius - 1) * (radius - 1); - - for ( int x = cenX - radius ; x <= cenX + radius ; x++ ) { - double xSqr = (cenX - x) * (cenX - x); - for ( int y = cenY - radius ; y <= cenY + radius ; y++ ) { - double ySqr = (cenY - y) * (cenY - y); - for ( int z = cenZ - radius ; z <= cenZ + radius ; z++ ) { - double zSqr = (cenZ - z) * (cenZ - z); - - double distSqr = xSqr + ySqr + zSqr; - - if ( distSqr <= radiusSqr && - (!hollow || - hollow && distSqr >= radiusHSqr )) { - - Location l = new Location( loc.getWorld(), x, y, z ); - results.add( l ); - } - } - } - } - } - return results; - } -} diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/commands/PrisonSpigotBackpackCommands.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/commands/PrisonSpigotBackpackCommands.java index 92cff7af5..9913c3c4d 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/commands/PrisonSpigotBackpackCommands.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/commands/PrisonSpigotBackpackCommands.java @@ -1,8 +1,6 @@ package tech.mcprison.prison.spigot.commands; -import at.pcgamingfreaks.Minepacks.Bukkit.API.Backpack; import org.bukkit.Bukkit; -import org.bukkit.configuration.Configuration; import org.bukkit.entity.Player; import tech.mcprison.prison.Prison; @@ -12,6 +10,7 @@ import tech.mcprison.prison.output.Output; import tech.mcprison.prison.spigot.SpigotPrison; import tech.mcprison.prison.spigot.backpacks.BackpacksUtil; +import tech.mcprison.prison.spigot.configs.MessagesConfig; import tech.mcprison.prison.spigot.gui.backpacks.BackpacksAdminGUI; import tech.mcprison.prison.spigot.gui.backpacks.BackpacksListPlayerGUI; @@ -22,7 +21,7 @@ * */ public class PrisonSpigotBackpackCommands extends PrisonSpigotBaseCommands { - private final Configuration messages = SpigotPrison.getInstance().getMessagesConfig(); + private final MessagesConfig messages = SpigotPrison.getInstance().getMessagesConfig(); @Command(identifier = "backpack", description = "Backpacks", onlyPlayers = false) private void backpackMainCommand(CommandSender sender, @@ -49,7 +48,7 @@ private void backpackItemGive(CommandSender sender){ Player p = getSpigotPlayer(sender); if (p == null) { - Output.get().sendInfo(sender, SpigotPrison.format( getMessages().getString("Message.CantGiveItemFromConsole"))); + Output.get().sendInfo(sender, SpigotPrison.format(messages.getString(MessagesConfig.StringID.spigot_message_console_error))); return; } @@ -64,7 +63,7 @@ private void backpacksListCommand(CommandSender sender){ Player p = getSpigotPlayer(sender); if (p == null) { - Output.get().sendInfo(sender, SpigotPrison.format( getMessages().getString("Message.CantGiveItemFromConsole"))); + Output.get().sendInfo(sender, SpigotPrison.format( messages.getString(MessagesConfig.StringID.spigot_message_console_error))); return; } @@ -81,7 +80,7 @@ private void deleteBackpackCommand(CommandSender sender, @Arg(name = "id", description = "The backpack ID optional", def = "null") String id){ if (name.equalsIgnoreCase("null")){ - Output.get().sendWarn(sender, SpigotPrison.format(getMessages().getString("Message.BackPackNeedPlayer"))); + Output.get().sendWarn(sender, SpigotPrison.format(messages.getString(MessagesConfig.StringID.spigot_message_backpack_missing_playername))); return; } @@ -101,9 +100,9 @@ private void deleteBackpackCommand(CommandSender sender, } } if (success) { - Output.get().sendInfo(sender, SpigotPrison.format(getMessages().getString("Message.BackPackDeleteOperationSuccess"))); + Output.get().sendInfo(sender, SpigotPrison.format(messages.getString(MessagesConfig.StringID.spigot_message_backpack_delete_success))); } else { - Output.get().sendWarn(sender, SpigotPrison.format(getMessages().getString("Message.BackPackDeleteOperationFail"))); + Output.get().sendWarn(sender, SpigotPrison.format(messages.getString(MessagesConfig.StringID.spigot_message_backpack_delete_error))); } } @@ -114,7 +113,7 @@ private void resizeBackpackCommand(CommandSender sender, @Arg(name = "id", description = "The backpack ID optional", def = "null") String id){ if (name.equalsIgnoreCase("null")){ - Output.get().sendWarn(sender, SpigotPrison.format(getMessages().getString("Message.BackPackNeedPlayer"))); + Output.get().sendWarn(sender, SpigotPrison.format(messages.getString(MessagesConfig.StringID.spigot_message_backpack_missing_playername))); return; } @@ -122,13 +121,13 @@ private void resizeBackpackCommand(CommandSender sender, try{ sizeInt = Integer.parseInt(size); } catch (NumberFormatException ex){ - Output.get().sendWarn(sender, SpigotPrison.format(getMessages().getString("Message.BackPackResizeNotInt"))); + Output.get().sendWarn(sender, SpigotPrison.format(messages.getString(MessagesConfig.StringID.spigot_message_backpack_size_must_be_multiple_of_9))); return; } // Must be multiple of 9. if ((sizeInt % 9 != 0 || sizeInt > 54) && sizeInt != 0){ - Output.get().sendWarn(sender, SpigotPrison.format(getMessages().getString("Message.BackPackResizeNotMultiple9"))); + Output.get().sendWarn(sender, SpigotPrison.format(messages.getString(MessagesConfig.StringID.spigot_message_backpack_size_must_be_multiple_of_9))); return; } @@ -155,7 +154,7 @@ private void resizeBackpackCommand(CommandSender sender, } } - Output.get().sendInfo(sender, SpigotPrison.format(getMessages().getString("Message.BackPackResizeDone"))); + Output.get().sendInfo(sender, SpigotPrison.format(messages.getString(MessagesConfig.StringID.spigot_message_backpack_resize_success))); } @Command(identifier = "backpack limit", permissions = "prison.admin", description = "Backpacks limit for player, to use this multiple backpacks must be enabled from the backpacks config or it won't have effect.", onlyPlayers = false) @@ -169,7 +168,7 @@ private void setBackpackLimitCommand(CommandSender sender, @Arg(name = "Limit", description = "The Backpacks limit that a player can own", def = "null") String limit) { if (name.equalsIgnoreCase("null") || limit.equalsIgnoreCase("null")){ - Output.get().sendWarn(sender, SpigotPrison.format(messages.getString("Message.BackPackLimitMissingParam"))); + Output.get().sendWarn(sender, SpigotPrison.format(messages.getString(MessagesConfig.StringID.spigot_message_command_wrong_format))); return; } @@ -177,7 +176,7 @@ private void setBackpackLimitCommand(CommandSender sender, try{ limitInt = Integer.parseInt(limit); } catch (NumberFormatException ex){ - Output.get().sendWarn(sender, SpigotPrison.format(messages.getString("Message.BackPackLimitNotNumber"))); + Output.get().sendWarn(sender, SpigotPrison.format(messages.getString(MessagesConfig.StringID.spigot_message_backpack_limit_not_number))); return; } @@ -187,16 +186,16 @@ private void setBackpackLimitCommand(CommandSender sender, BackpacksUtil.get().setBackpacksLimit(BackpacksUtil.get().getBackpackOwnerOffline(name), limitInt); } - Output.get().sendInfo(sender, SpigotPrison.format(messages.getString("Message.BackPackLimitSuccess"))); + Output.get().sendInfo(sender, SpigotPrison.format(messages.getString(MessagesConfig.StringID.spigot_message_backpack_limit_edit_success))); } - @Command(identifier = "backpack limit add", permissions = "prison.admin", description = "Increment backpacks limit of a player, to use this multiple backpacks must be enabled or it won't have effect.", onlyPlayers = false) + @Command(identifier = "backpack limit add", permissions = "prison.admin", description = "Increment backpacks limit of a player, multiple backpacks must be enabled or this won't take effect.", onlyPlayers = false) private void addBackpackLimitCommand(CommandSender sender, @Arg(name = "Owner", description = "The backpack owner name", def = "null") String name, @Arg(name = "Limit", description = "The Backpacks increment value", def = "null") String limit) { if (name.equalsIgnoreCase("null") || limit.equalsIgnoreCase("null")){ - Output.get().sendWarn(sender, SpigotPrison.format(messages.getString("Message.BackPackLimitMissingParam"))); + Output.get().sendWarn(sender, SpigotPrison.format(messages.getString(MessagesConfig.StringID.spigot_message_command_wrong_format))); return; } @@ -204,7 +203,7 @@ private void addBackpackLimitCommand(CommandSender sender, try{ limitInt = Integer.parseInt(limit); } catch (NumberFormatException ex){ - Output.get().sendWarn(sender, SpigotPrison.format(messages.getString("Message.BackPackLimitNotNumber"))); + Output.get().sendWarn(sender, SpigotPrison.format(messages.getString(MessagesConfig.StringID.spigot_message_backpack_limit_not_number))); return; } @@ -216,7 +215,7 @@ private void addBackpackLimitCommand(CommandSender sender, BackpacksUtil.get().setBackpacksLimit(BackpacksUtil.get().getBackpackOwnerOffline(name), limitInt); } - Output.get().sendInfo(sender, SpigotPrison.format(messages.getString("Message.BackPackLimitSuccess"))); + Output.get().sendInfo(sender, SpigotPrison.format(messages.getString(MessagesConfig.StringID.spigot_message_backpack_limit_edit_success))); } @Command(identifier = "backpack limit decrement", permissions = "prison.admin", description = "Decrement backpacks limit of a player, to use this multiple backpacks must be enabled or it won't have effect.", onlyPlayers = false) @@ -225,7 +224,7 @@ private void decrementBackpackLimitCommand(CommandSender sender, @Arg(name = "Value", description = "The Backpacks decrement value", def = "null") String limit) { if (name.equalsIgnoreCase("null") || limit.equalsIgnoreCase("null")){ - Output.get().sendWarn(sender, SpigotPrison.format(messages.getString("Message.BackPackLimitMissingParam"))); + Output.get().sendWarn(sender, SpigotPrison.format(messages.getString(MessagesConfig.StringID.spigot_message_command_wrong_format))); return; } @@ -233,7 +232,7 @@ private void decrementBackpackLimitCommand(CommandSender sender, try{ limitInt = Integer.parseInt(limit); } catch (NumberFormatException ex){ - Output.get().sendWarn(sender, SpigotPrison.format(messages.getString("Message.BackPackLimitNotNumber"))); + Output.get().sendWarn(sender, SpigotPrison.format(messages.getString(MessagesConfig.StringID.spigot_message_backpack_limit_not_number))); return; } @@ -242,7 +241,7 @@ private void decrementBackpackLimitCommand(CommandSender sender, if (limitInt >= 0) { BackpacksUtil.get().setBackpacksLimit(Bukkit.getPlayerExact(name), limitInt); } else { - Output.get().sendWarn(sender, SpigotPrison.format(messages.getString("Message.BackPackLimitDecrementFail"))); + Output.get().sendWarn(sender, SpigotPrison.format(messages.getString(MessagesConfig.StringID.spigot_message_backpack_limit_decrement_fail))); return; } } else { @@ -250,12 +249,12 @@ private void decrementBackpackLimitCommand(CommandSender sender, if (limitInt >= 0) { BackpacksUtil.get().setBackpacksLimit(BackpacksUtil.get().getBackpackOwnerOffline(name), limitInt); } else { - Output.get().sendWarn(sender, SpigotPrison.format(messages.getString("Message.BackPackLimitDecrementFail"))); + Output.get().sendWarn(sender, SpigotPrison.format(messages.getString(MessagesConfig.StringID.spigot_message_backpack_limit_decrement_fail))); return; } } - Output.get().sendInfo(sender, SpigotPrison.format(messages.getString("Message.BackPackLimitSuccess"))); + Output.get().sendInfo(sender, SpigotPrison.format(messages.getString(MessagesConfig.StringID.spigot_message_backpack_limit_edit_success))); } @Command(identifier = "backpack admin", description = "Open backpack admin GUI", permissions = "prison.admin", onlyPlayers = true) @@ -264,7 +263,7 @@ private void openBackpackAdminGUI(CommandSender sender){ Player p = getSpigotPlayer(sender); if (p == null) { - Output.get().sendInfo(sender, SpigotPrison.format( getMessages().getString("Message.CantGiveItemFromConsole"))); + Output.get().sendInfo(sender, SpigotPrison.format( messages.getString(MessagesConfig.StringID.spigot_message_console_error))); return; } @@ -279,24 +278,24 @@ private void backpackGUIOpenCommand(CommandSender sender, Player p = getSpigotPlayer(sender); if (p == null) { - Output.get().sendInfo(sender, SpigotPrison.format( getMessages().getString("Message.CantRunGUIFromConsole"))); + Output.get().sendInfo(sender, SpigotPrison.format( messages.getString(MessagesConfig.StringID.spigot_message_console_error))); return; } if (isDisabledWorld(p)) return; if (getBoolean(BackpacksUtil.get().getBackpacksConfig().getString("Options.Multiple-BackPacks-For-Player-Enabled")) && (BackpacksUtil.get().reachedBackpacksLimit(p) && !BackpacksUtil.get().getBackpacksIDs(p).contains(id))){ - Output.get().sendInfo(sender, SpigotPrison.format(messages.getString("Message.BackPackOwnLimitReached") + " [" + BackpacksUtil.get().getNumberOwnedBackpacks(p) + "]")); + Output.get().sendInfo(sender, SpigotPrison.format(messages.getString(MessagesConfig.StringID.spigot_message_backpack_limit_reached) + " [" + BackpacksUtil.get().getNumberOwnedBackpacks(p) + "]")); return; } 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("Message.MissingPermission") + " [" + 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; } if (!BackpacksUtil.get().canOwnBackpack(p)){ - Output.get().sendInfo(sender, SpigotPrison.format(messages.getString("Message.BackPackCantOwn"))); + Output.get().sendInfo(sender, SpigotPrison.format(messages.getString(MessagesConfig.StringID.spigot_message_backpack_cant_own))); return; } @@ -313,7 +312,7 @@ private void backpackListGUICommand(CommandSender sender){ Player p = getSpigotPlayer(sender); if (p == null) { - Output.get().sendInfo(sender, SpigotPrison.format( getMessages().getString("Message.CantRunGUIFromConsole"))); + Output.get().sendInfo(sender, SpigotPrison.format( messages.getString(MessagesConfig.StringID.spigot_message_console_error))); return; } @@ -322,7 +321,7 @@ 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("Message.MissingPermission") + " [" + 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); @@ -336,7 +335,7 @@ private void openBackpackAdminCommandGUI(CommandSender sender){ Player p = getSpigotPlayer(sender); if (p == null) { - Output.get().sendInfo(sender, SpigotPrison.format( getMessages().getString("Message.CantGiveItemFromConsole"))); + Output.get().sendInfo(sender, SpigotPrison.format( messages.getString(MessagesConfig.StringID.spigot_message_console_error))); return; } diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/commands/PrisonSpigotBaseCommands.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/commands/PrisonSpigotBaseCommands.java index 699e3b90e..729a9b43b 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/commands/PrisonSpigotBaseCommands.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/commands/PrisonSpigotBaseCommands.java @@ -5,6 +5,7 @@ import tech.mcprison.prison.internal.CommandSender; import tech.mcprison.prison.spigot.SpigotPrison; +import tech.mcprison.prison.spigot.configs.MessagesConfig; import tech.mcprison.prison.spigot.game.SpigotCommandSender; /** @@ -12,9 +13,9 @@ */ public class PrisonSpigotBaseCommands { - private final Configuration messages = SpigotPrison.getInstance().getMessagesConfig(); + private final MessagesConfig messages = SpigotPrison.getInstance().getMessagesConfig(); - public Configuration getMessages() { + public MessagesConfig getMessages() { return messages; } diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/commands/PrisonSpigotGUICommands.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/commands/PrisonSpigotGUICommands.java index e89db1c57..78e0529d6 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 @@ -1,18 +1,23 @@ package tech.mcprison.prison.spigot.commands; -import org.bukkit.configuration.Configuration; import org.bukkit.entity.Player; -import tech.mcprison.prison.Prison; +import tech.mcprison.prison.commands.Arg; import tech.mcprison.prison.commands.Command; import tech.mcprison.prison.internal.CommandSender; import tech.mcprison.prison.output.Output; +import tech.mcprison.prison.ranks.PrisonRanks; +import tech.mcprison.prison.ranks.data.RankLadder; import tech.mcprison.prison.spigot.SpigotPrison; -import tech.mcprison.prison.spigot.gui.guiutility.SpigotGUIComponents; +import tech.mcprison.prison.spigot.configs.MessagesConfig; +import tech.mcprison.prison.spigot.game.SpigotPlayer; import tech.mcprison.prison.spigot.gui.SpigotPrisonGUI; +import tech.mcprison.prison.spigot.gui.guiutility.SpigotGUIComponents; +import tech.mcprison.prison.spigot.gui.mine.SpigotMinesGUI; import tech.mcprison.prison.spigot.gui.mine.SpigotPlayerMinesGUI; -import tech.mcprison.prison.spigot.gui.rank.SpigotPlayerPrestigesGUI; +import tech.mcprison.prison.spigot.gui.rank.SpigotLaddersGUI; import tech.mcprison.prison.spigot.gui.rank.SpigotPlayerRanksGUI; +import tech.mcprison.prison.spigot.gui.rank.SpigotRanksGUI; /** * @author GABRYCA @@ -20,7 +25,7 @@ */ public class PrisonSpigotGUICommands extends PrisonSpigotBaseCommands { - private final Configuration messages = getMessages(); + private final MessagesConfig messages = getMessages(); /** * NOTE: onlyPlayers needs to be false so players can use /gui help on the command, even from console. @@ -37,7 +42,7 @@ private void prisonManagerGUI(CommandSender sender) { Player player = getSpigotPlayer(sender); if (player == null) { - Output.get().sendInfo(sender, SpigotPrison.format( getMessages().getString("Message.CantRunGUIFromConsole"))); + Output.get().sendInfo(sender, SpigotPrison.format( getMessages().getString(MessagesConfig.StringID.spigot_message_console_error))); return; } @@ -46,22 +51,32 @@ private void prisonManagerGUI(CommandSender sender) { gui.open(); return; } + + // If the player will be shown the /gui help, then force close any open inventory: + player.closeInventory(); sender.dispatchCommand("gui help"); } @Command( identifier = "gui prestiges", description = "GUI Prestiges", onlyPlayers = true ) - private void prisonManagerPrestiges( CommandSender sender ) { + private void prisonManagerPrestiges( CommandSender sender, + @Arg(name = "page", description = "If there are more than 45 prestiges, then the " + + "prestiges are shown on multiple pages. The page parameter starts with " + + "page 1.", def = "1" ) int page + ) { + cmdPrisonManagerPrestiges( sender, page, "gui prestiges", "gui" ); + } + protected void cmdPrisonManagerPrestiges( CommandSender sender, int page, String cmdPage, String cmdReturn ) { if ( !isPrisonConfig("prestiges") && !isPrisonConfig( "prestige.enabled" ) ) { - Output.get().sendInfo(sender, SpigotPrison.format(messages.getString("Message.PrestigesAreDisabled"))); + Output.get().sendInfo(sender, SpigotPrison.format(messages.getString(MessagesConfig.StringID.spigot_message_prestiges_disabled))); return; } if ( !isPrisonConfig("prison-gui-enabled") || !isConfig("Options.Prestiges.GUI_Enabled")){ - Output.get().sendInfo(sender, SpigotPrison.format(messages.getString("Message.GuiOrPrestigesDisabled"))); + Output.get().sendInfo(sender, SpigotPrison.format(messages.getString(MessagesConfig.StringID.spigot_message_prestiges_or_gui_disabled))); return; } @@ -69,7 +84,7 @@ private void prisonManagerPrestiges( CommandSender sender ) { String perm = getConfig( "Options.Prestiges.Permission_GUI"); if ( !sender.hasPermission( perm ) ){ - Output.get().sendInfo(sender, SpigotPrison.format(messages.getString("Message.missingGuiPrestigesPermission") + " [" + + Output.get().sendInfo(sender, SpigotPrison.format(messages.getString(MessagesConfig.StringID.spigot_message_missing_permission) + " [" + perm + "]")); return; } @@ -78,27 +93,37 @@ private void prisonManagerPrestiges( CommandSender sender ) { Player player = getSpigotPlayer( sender ); if (player == null) { - Output.get().sendInfo(sender, SpigotPrison.format( getMessages().getString("Message.CantRunGUIFromConsole"))); + Output.get().sendInfo(sender, SpigotPrison.format( getMessages().getString(MessagesConfig.StringID.spigot_message_console_error))); return; } - SpigotPlayerPrestigesGUI gui = new SpigotPlayerPrestigesGUI( player ); + + SpigotPlayerRanksGUI gui = new SpigotPlayerRanksGUI( player, "prestiges", page, cmdPage, cmdReturn ); +// SpigotPlayerPrestigesGUI gui = new SpigotPlayerPrestigesGUI( player, page, cmdPage, cmdReturn ); gui.open(); } @Command( identifier = "gui mines", description = "GUI Mines", onlyPlayers = true ) - private void prisonManagerMines(CommandSender sender) { + private void prisonManagerMines(CommandSender sender, + @Arg(name = "page", description = "If there are more than 45 mines, then the " + + "mines are shown on multiple pages. The page parameter starts with " + + "page 1.", def = "1" ) int page + ) { + cmdPrisonManagerMines( sender, page, "gui mines", "gui" ); + } + + protected void cmdPrisonManagerMines( CommandSender sender, int page, String cmdPage, String cmdReturn ) { Player player = getSpigotPlayer(sender); if (player == null) { - Output.get().sendInfo(sender, SpigotPrison.format( getMessages().getString("Message.CantRunGUIFromConsole"))); + Output.get().sendInfo(sender, SpigotPrison.format( getMessages().getString(MessagesConfig.StringID.spigot_message_console_error))); return; } if ( !isPrisonConfig("prison-gui-enabled") || !isConfig("Options.Mines.GUI_Enabled") ){ - Output.get().sendInfo(sender, SpigotPrison.format( getMessages().getString("Message.mineOrGuiDisabled"))); + Output.get().sendInfo(sender, SpigotPrison.format( getMessages().getString(MessagesConfig.StringID.spigot_message_mines_or_gui_disabled))); return; } @@ -107,30 +132,80 @@ private void prisonManagerMines(CommandSender sender) { String perm = getConfig( "Options.Mines.Permission_GUI"); if ( !sender.hasPermission( perm ) ){ - Output.get().sendInfo(sender, SpigotPrison.format( getMessages().getString("Message.mineMissingGuiPermission") + " [" + + Output.get().sendInfo(sender, SpigotPrison.format( getMessages().getString(MessagesConfig.StringID.spigot_message_missing_permission) + " [" + perm + "]")); return; } } - SpigotPlayerMinesGUI gui = new SpigotPlayerMinesGUI( player ); + SpigotPlayerMinesGUI gui = new SpigotPlayerMinesGUI( player, page, cmdPage, cmdReturn ); gui.open(); } + + @Command( identifier = "gui admin mines", description = "GUI Mines", + onlyPlayers = true ) + private void prisonManagerAdminMines(CommandSender sender, + @Arg(name = "page", description = "If there are more than 45 mines, then the " + + "mines are shown on multiple pages. The page parameter starts with " + + "page 1.", def = "1" ) int page + ) { + + cmdPrisonManagerAdminMines( sender, page, "gui admin mines", "gui admin" ); + } + + protected void cmdPrisonManagerAdminMines( CommandSender sender, int page, String cmdPage, String cmdReturn ) { + Player player = getSpigotPlayer(sender); + + if (player == null) { + Output.get().sendInfo(sender, SpigotPrison.format( getMessages().getString(MessagesConfig.StringID.spigot_message_console_error))); + return; + } + + if ( !player.hasPermission("prison.admin") && !player.hasPermission("prison.prisonmanagergui")) { + return; + } + +// if ( !isPrisonConfig("prison-gui-enabled") || !isConfig("Options.Mines.GUI_Enabled") ){ +// Output.get().sendInfo(sender, SpigotPrison.format( getMessages().getString(MessagesConfig.StringID.spigot_message_mines_or_gui_disabled))); +// return; +// } + + +// if ( isConfig("Options.Mines.Permission_GUI_Enabled") ){ +// 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 + "]")); +// return; +// } +// } + + SpigotMinesGUI gui = new SpigotMinesGUI( player, page, cmdPage, cmdReturn ); + gui.open(); + } @Command( identifier = "gui ranks", description = "GUI Ranks", onlyPlayers = true ) - private void prisonManagerRanks(CommandSender sender) { - + private void prisonManagerRanks(CommandSender sender, + @Arg(name = "page", description = "If there are more than 45 ranks, then the " + + "ranks are shown on multiple pages. The page parameter starts with " + + "page 1.", def = "1" ) int page + ) { + + cmdPrisonManagerRanks( sender, page, "gui ranks", "gui" ); + } + protected void cmdPrisonManagerRanks(CommandSender sender, int page, String cmdPage, String cmdReturn ) { Player player = getSpigotPlayer(sender); if (player == null) { - Output.get().sendInfo(sender, SpigotPrison.format( getMessages().getString("Message.CantRunGUIFromConsole"))); + Output.get().sendInfo(sender, SpigotPrison.format( getMessages().getString(MessagesConfig.StringID.spigot_message_console_error))); return; } if (!isPrisonConfig("prison-gui-enabled") || !isConfig("Options.Ranks.GUI_Enabled")) { Output.get().sendInfo(sender, SpigotPrison.format(String.format(String.format( - getMessages().getString("Message.rankGuiDisabledOrAllGuiDisabled"), + getMessages().getString(MessagesConfig.StringID.spigot_message_ranks_or_gui_disabled), getPrisonConfig("prison-gui-enabled"), getConfig("Options.Ranks.GUI_Enabled") )))); return; } @@ -139,22 +214,124 @@ private void prisonManagerRanks(CommandSender sender) { String perm = getConfig( "Options.Ranks.Permission_GUI"); if (!sender.hasPermission(perm)) { - Output.get().sendInfo(sender, SpigotPrison.format( getMessages().getString("Message.rankGuiMissingPermission") + " [" + + Output.get().sendInfo(sender, SpigotPrison.format( getMessages().getString(MessagesConfig.StringID.spigot_message_missing_permission) + " [" + perm + "]")); return; } } - SpigotPlayerRanksGUI gui = new SpigotPlayerRanksGUI( player ); + SpigotPlayerRanksGUI gui = new SpigotPlayerRanksGUI( player, "default", page, cmdPage, cmdReturn ); gui.open(); } - - @Command(identifier = "gui sellall", description = "SellAll GUI command", onlyPlayers = true) - private void sellAllGuiCommandNew(CommandSender sender){ - - String registeredCmd = Prison.get().getCommandHandler().findRegisteredCommand( "sellall gui" ); - sender.dispatchCommand(registeredCmd); + + @Command( identifier = "gui admin ranks", description = "GUI Ranks", + onlyPlayers = true ) + private void prisonManagerAdminRanks(CommandSender sender, + + @Arg(name = "ladder", description = "Ladder to use for displaying all the ranks", + def = "default" ) String ladder, + + @Arg(name = "page", description = "If there are more than 45 ranks, then the " + + "ranks are shown on multiple pages. The page parameter starts with " + + "page 1.", def = "1" ) int page + ) { + + String cmdPage = "gui admin ranks " + ladder; + cmdPrisonManagerAdminRanks( sender, ladder, page, cmdPage, "gui admin" ); } + protected void cmdPrisonManagerAdminRanks(CommandSender sender, String ladder, + int page, String cmdPage, String cmdReturn ) { + Player player = getSpigotPlayer(sender); + + if (player == null) { + Output.get().sendInfo(sender, SpigotPrison.format( getMessages().getString(MessagesConfig.StringID.spigot_message_console_error))); + return; + } + + if ( !player.hasPermission("prison.admin") && !player.hasPermission("prison.prisonmanagergui")) { + return; + } + + + // ladder + RankLadder rLadder = PrisonRanks.getInstance().getLadderManager().getLadder( ladder ); + if ( rLadder == null ) { + + SpigotPlayer sPlayer = new SpigotPlayer(player); + sPlayer.setActionBar( "Invalid ladder name" ); + player.closeInventory(); + return; + } + +// if (!isPrisonConfig("prison-gui-enabled") || !isConfig("Options.Ranks.GUI_Enabled")) { +// Output.get().sendInfo(sender, SpigotPrison.format(String.format(String.format( +// getMessages().getString(MessagesConfig.StringID.spigot_message_ranks_or_gui_disabled), +// getPrisonConfig("prison-gui-enabled"), getConfig("Options.Ranks.GUI_Enabled") )))); +// return; +// } +// +// if (isConfig("Options.Ranks.Permission_GUI_Enabled")) { +// 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 + "]")); +// return; +// } +// } + + SpigotRanksGUI gui = new SpigotRanksGUI( player, rLadder, page, cmdPage, cmdReturn ); + //SpigotPlayerRanksGUI gui = new SpigotPlayerRanksGUI( player, page, cmdPage, cmdReturn ); + gui.open(); + } + + @Command( identifier = "gui ladders", + description = "GUI Ladders. The permissions are based upon the ranks perms.", + onlyPlayers = true ) + private void prisonManagerLadders(CommandSender sender, + @Arg(name = "page", description = "If there are more than 45 ladders, then the " + + "ladders are shown on multiple pages. The page parameter starts with " + + "page 1.", def = "1" ) int page + ) { + + cmdPrisonManagerLadders( sender, page, "gui ladders", "gui" ); + } + protected void cmdPrisonManagerLadders(CommandSender sender, int page, String cmdPage, String cmdReturn ) { + + Player player = getSpigotPlayer(sender); + + if (player == null) { + Output.get().sendInfo(sender, SpigotPrison.format( getMessages().getString(MessagesConfig.StringID.spigot_message_console_error))); + return; + } + + if (!isPrisonConfig("prison-gui-enabled") || !isConfig("Options.Ranks.GUI_Enabled")) { + Output.get().sendInfo(sender, SpigotPrison.format(String.format(String.format( + getMessages().getString(MessagesConfig.StringID.spigot_message_ranks_or_gui_disabled), + getPrisonConfig("prison-gui-enabled"), getConfig("Options.Ranks.GUI_Enabled") )))); + return; + } + + if (isConfig("Options.Ranks.Permission_GUI_Enabled")) { + 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 + "]")); + return; + } + } + + SpigotLaddersGUI gui = new SpigotLaddersGUI( player, page, cmdPage, cmdReturn ); + gui.open(); + } + +// @Command(identifier = "gui sellall", description = "SellAll GUI command", onlyPlayers = true) +// private void sellAllGuiCommandNew(CommandSender sender){ +// +// String registeredCmd = Prison.get().getCommandHandler().findRegisteredCommand( "sellall gui" ); +// sender.dispatchCommand(registeredCmd); +// } // Backpack GUI commands got moved to the Backpacks class so they won't be loaded if backpacks are disabled. @@ -163,6 +340,6 @@ public void reloadGUICommand(CommandSender sender){ SpigotGUIComponents.updateMessages(); SpigotGUIComponents.updateSellAllConfig(); SpigotGUIComponents.updateGUIConfig(); - Output.get().sendInfo(sender, SpigotPrison.format(messages.getString("Message.GUIReloadSuccess"))); + Output.get().sendInfo(sender, SpigotPrison.format(messages.getString(MessagesConfig.StringID.spigot_message_gui_reload_success))); } } diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/commands/PrisonSpigotMinesCommands.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/commands/PrisonSpigotMinesCommands.java index d51d26c97..a68113bdc 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/commands/PrisonSpigotMinesCommands.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/commands/PrisonSpigotMinesCommands.java @@ -1,5 +1,7 @@ package tech.mcprison.prison.spigot.commands; +import tech.mcprison.prison.Prison; +import tech.mcprison.prison.commands.Arg; import tech.mcprison.prison.commands.Command; import tech.mcprison.prison.internal.CommandSender; @@ -11,11 +13,28 @@ public class PrisonSpigotMinesCommands @Command(identifier = "mines", onlyPlayers = false, altPermissions = {"-none-", "mines.admin"}) - public void minesGUICommand(CommandSender sender) { + public void minesGUICommand(CommandSender sender, + @Arg(name = "page", description = "If there are more than 45 mines, then the " + + "mines are shown on multiple pages. The page parameter starts with " + + "page 1.", def = "1" ) int page + ) { if (!sender.hasPermission("mines.admin")) { if (isPrisonConfig("prison-gui-enabled") && isConfig("Options.Mines.GUI_Enabled")){ - sender.dispatchCommand("gui mines"); + + Object regCommand = Prison.get().getCommandHandler() + .getRegisteredCommandClass( PrisonSpigotGUICommands.class ); + if ( regCommand != null ) { + PrisonSpigotGUICommands psGUICmd = (PrisonSpigotGUICommands) regCommand; + psGUICmd.cmdPrisonManagerMines( sender, page, "gui mines", "close" ); + + return; + } +// sender.dispatchCommand("gui mines"); + } + else { + + sender.dispatchCommand("mines help"); } } else { diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/commands/PrisonSpigotPrestigeCommands.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/commands/PrisonSpigotPrestigeCommands.java index 9da1d7658..3e6048ffe 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/commands/PrisonSpigotPrestigeCommands.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/commands/PrisonSpigotPrestigeCommands.java @@ -14,6 +14,7 @@ import tech.mcprison.prison.ranks.data.RankLadder; import tech.mcprison.prison.ranks.managers.LadderManager; import tech.mcprison.prison.spigot.SpigotPrison; +import tech.mcprison.prison.spigot.configs.MessagesConfig; import tech.mcprison.prison.spigot.gui.ListenersPrisonManager; import tech.mcprison.prison.spigot.gui.rank.SpigotConfirmPrestigeGUI; @@ -23,13 +24,13 @@ public class PrisonSpigotPrestigeCommands extends PrisonSpigotBaseCommands { - private final Configuration messages = SpigotPrison.getInstance().getMessagesConfig(); + private final MessagesConfig messages = SpigotPrison.getInstance().getMessagesConfig(); @Command(identifier = "prestiges", onlyPlayers = true) public void prestigesGUICommand(CommandSender sender) { if ( !isPrisonConfig( "prestiges") && !isPrisonConfig( "prestige.enabled" ) ) { - Output.get().sendInfo(sender, SpigotPrison.format(messages.getString("Message.PrestigesDisabledDefault"))); + Output.get().sendInfo(sender, SpigotPrison.format(messages.getString(MessagesConfig.StringID.spigot_message_prestiges_disabled))); return; } @@ -75,7 +76,7 @@ public void prisonManagerPrestige(CommandSender sender ) { if ( ( ladderDefault == null || !(ladderDefault.getLowestRank().isPresent()) || ladderDefault.getLowestRank().get().getName() == null)) { - Output.get().sendInfo(sender, SpigotPrison.format(messages.getString("Message.DefaultLadderEmpty"))); + Output.get().sendInfo(sender, SpigotPrison.format(messages.getString(MessagesConfig.StringID.spigot_message_ladder_default_empty))); return; } @@ -83,7 +84,7 @@ public void prisonManagerPrestige(CommandSender sender ) { if ( ( ladderPrestiges == null || !(ladderPrestiges.getLowestRank().isPresent()) || ladderPrestiges.getLowestRank().get().getName() == null)) { - Output.get().sendInfo(sender, SpigotPrison.format(messages.getString("Message.CantFindPrestiges"))); + Output.get().sendInfo(sender, SpigotPrison.format(messages.getString(MessagesConfig.StringID.spigot_message_prestiges_empty))); return; } } @@ -119,15 +120,13 @@ private void prestigeByChat(CommandSender sender) { ListenersPrisonManager listenersPrisonManager = ListenersPrisonManager.get(); listenersPrisonManager.chatEventActivator(); - sender.sendMessage( SpigotPrison.format(getPrisonConfig("Lore.PrestigeWarning") + - getPrisonConfig("Lore.PrestigeWarning2") + - getPrisonConfig("Lore.PrestigeWarning3"))); - - sender.sendMessage( SpigotPrison.format(messages.getString("Message.ConfirmPrestige"))); - sender.sendMessage( SpigotPrison.format(messages.getString("Message.CancelPrestige"))); + Output.get().sendInfo(sender, messages.getString(MessagesConfig.StringID.spigot_gui_lore_prestige_warning_1) + " " + + messages.getString(MessagesConfig.StringID.spigot_gui_lore_prestige_warning_2) + " " + messages.getString(MessagesConfig.StringID.spigot_gui_lore_prestige_warning_3)); - final Player player = getSpigotPlayer( sender ); + Output.get().sendInfo(sender, "&a" + messages.getString(MessagesConfig.StringID.spigot_message_prestiges_confirm)); + Output.get().sendInfo(sender, "&c" + messages.getString(MessagesConfig.StringID.spigot_message_prestiges_cancel)); + final Player player = getSpigotPlayer( sender ); listenersPrisonManager.chatInteractData(player, ListenersPrisonManager.ChatMode.Prestige); } } diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/commands/PrisonSpigotRanksCommands.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/commands/PrisonSpigotRanksCommands.java index 325caba1b..81d668dc4 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/commands/PrisonSpigotRanksCommands.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/commands/PrisonSpigotRanksCommands.java @@ -1,5 +1,6 @@ package tech.mcprison.prison.spigot.commands; +import tech.mcprison.prison.Prison; import tech.mcprison.prison.commands.Arg; import tech.mcprison.prison.commands.Command; import tech.mcprison.prison.internal.CommandSender; @@ -14,20 +15,54 @@ public class PrisonSpigotRanksCommands altPermissions = {"-none-", "ranks.admin"}) public void ranksGUICommand(CommandSender sender, @Arg(name = "ladder", def = "default", - description = "If player has no permission to /ranks then /ranks list will be ran instead.") - String ladderName) { + description = "Ladder name, such as 'default' or 'prestige'. Use 'all' for " + + "all ranks on the server. " + + "If player has no permission to /ranks then /ranks list will be ran instead.") + String ladderName, + @Arg(name = "page", description = "If there are more than 45 entries, then they will " + + "be shown on multiple pages. The page parameter starts with " + + "page 1.", def = "1" ) int page + ) { if (!sender.hasPermission("ranks.admin")) { + + try { + page = Integer.parseInt( ladderName ); + + // Ladder name was actually the page number, so set ladderName to "default" + ladderName = "default"; + } + catch ( NumberFormatException e ) { + // Ignore since ladderName was not a page, which is OK + } if ((ladderName.equalsIgnoreCase("default") || ladderName.equalsIgnoreCase("ranks")) && isConfig("Options.Ranks.GUI_Enabled")) { - sender.dispatchCommand("gui ranks"); - } else if (ladderName.equalsIgnoreCase("prestiges") && isConfig( "Options.Prestiges.GUI_Enabled")) { + Object regCommand = Prison.get().getCommandHandler() + .getRegisteredCommandClass( PrisonSpigotGUICommands.class ); + if ( regCommand != null ) { + PrisonSpigotGUICommands psGUICmd = (PrisonSpigotGUICommands) regCommand; + psGUICmd.cmdPrisonManagerRanks( sender, page, "ranks", "close" ); + return; + } + +// sender.dispatchCommand("gui ranks"); + } else if (ladderName.equalsIgnoreCase("prestiges") && + isConfig( "Options.Prestiges.GUI_Enabled")) { + + Object regCommand = Prison.get().getCommandHandler() + .getRegisteredCommandClass( PrisonSpigotGUICommands.class ); + if ( regCommand != null ) { + PrisonSpigotGUICommands psGUICmd = (PrisonSpigotGUICommands) regCommand; + psGUICmd.cmdPrisonManagerPrestiges( sender, page, "ranks", "close" ); + return; + } - sender.dispatchCommand("gui prestiges"); - } else { - sender.dispatchCommand("ranks list " + ladderName); - } +// sender.dispatchCommand("gui prestiges"); + } + + + sender.dispatchCommand("ranks list " + ladderName); } else { sender.dispatchCommand("ranks help"); 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 8208feb18..7bc955e16 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,7 +1,9 @@ package tech.mcprison.prison.spigot.commands; -import org.bukkit.configuration.Configuration; +import java.util.ArrayList; + import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; import com.cryptomorin.xseries.XMaterial; @@ -15,7 +17,10 @@ import tech.mcprison.prison.output.Output; import tech.mcprison.prison.spigot.SpigotPlatform; import tech.mcprison.prison.spigot.SpigotPrison; +import tech.mcprison.prison.spigot.compat.Compatibility; +import tech.mcprison.prison.spigot.configs.MessagesConfig; import tech.mcprison.prison.spigot.game.SpigotPlayer; +import tech.mcprison.prison.spigot.gui.sellall.SellAllAdminBlocksGUI; import tech.mcprison.prison.spigot.sellall.SellAllBlockData; import tech.mcprison.prison.spigot.sellall.SellAllUtil; @@ -26,8 +31,8 @@ public class PrisonSpigotSellAllCommands extends PrisonSpigotBaseCommands { private static PrisonSpigotSellAllCommands instance; - private SellAllUtil sellAllUtil = SellAllUtil.get(); - private final Configuration messages = SpigotPrison.getInstance().getMessagesConfig(); + private final MessagesConfig messages = SpigotPrison.getInstance().getMessagesConfig(); + private final Compatibility compat = SpigotPrison.getInstance().getCompatibility(); /** * Check if SellAll's enabled. @@ -51,17 +56,22 @@ public static PrisonSpigotSellAllCommands get() { @Command(identifier = "sellall set currency", description = "SellAll set currency command", onlyPlayers = false, permissions = "prison.sellall.currency") private void sellAllCurrency(CommandSender sender, - @Arg(name = "currency", description = "Currency name.", def = "default") @Wildcard String currency){ + @Arg(name = "currency", description = "Currency name.", def = "default") @Wildcard String currency){ EconomyCurrencyIntegration currencyEcon = PrisonAPI.getIntegrationManager().getEconomyForCurrency(currency); if (currencyEcon == null && !currency.equalsIgnoreCase("default")) { - Output.get().sendError(sender, SpigotPrison.format(messages.getString("Message.SellAllCurrencyNotFound")), currency); + Output.get().sendError(sender, messages.getString(MessagesConfig.StringID.spigot_message_sellall_currency_not_found), currency); return; } - if (sellAllUtil.setCurrency(currency)) return; + SellAllUtil sellAllUtil = SellAllUtil.get(); + if (sellAllUtil == null){ + return; + } - Output.get().sendInfo(sender, SpigotPrison.format(messages.getString("Message.SellAllCurrencyEditedSuccess") + " [" + sellAllUtil.getSellAllConfig().getString("Options.SellAll_Currency") + "]")); + if (sellAllUtil.setCurrency(currency)){ + Output.get().sendInfo(sender, messages.getString(MessagesConfig.StringID.spigot_message_sellall_currency_edit_success) + " [" + currency + "]"); + } } @Command(identifier = "sellall", description = "SellAll main command", onlyPlayers = false) @@ -70,10 +80,10 @@ private void sellAllCommands(CommandSender sender) { if (!isEnabled()) return; if (sender.hasPermission("prison.admin")) { - String registeredCmd = Prison.get().getCommandHandler().findRegisteredCommand( "sellall help" ); + String registeredCmd = Prison.get().getCommandHandler().findRegisteredCommand( "sellall help" ); sender.dispatchCommand(registeredCmd); } else { - String registeredCmd = Prison.get().getCommandHandler().findRegisteredCommand( "sellall sell" ); + String registeredCmd = Prison.get().getCommandHandler().findRegisteredCommand( "sellall sell" ); sender.dispatchCommand(registeredCmd); } } @@ -85,47 +95,57 @@ private void sellAllDelay(CommandSender sender, if (!isEnabled()) return; if (!(enable.equalsIgnoreCase("true") || enable.equalsIgnoreCase("false"))){ - Output.get().sendInfo(sender, SpigotPrison.format(messages.getString("Message.InvalidBooleanInput"))); + Output.get().sendInfo(sender, messages.getString(MessagesConfig.StringID.spigot_message_sellall_boolean_input_invalid)); + return; + } + + SellAllUtil sellAllUtil = SellAllUtil.get(); + + if (sellAllUtil == null){ return; } boolean enableBoolean = getBoolean(enable); - boolean sellDelayEnabled = getBoolean(sellAllUtil.getSellAllConfig().getString("Options.Sell_Delay_Enabled")); - if (sellDelayEnabled == enableBoolean){ + if (sellAllUtil.isSellAllDelayEnabled == enableBoolean){ if (enableBoolean){ - Output.get().sendWarn(sender, SpigotPrison.format(messages.getString("Message.SellAllDelayAlreadyEnabled"))); + Output.get().sendWarn(sender, messages.getString(MessagesConfig.StringID.spigot_message_sellall_delay_already_enabled)); } else { - Output.get().sendWarn(sender, SpigotPrison.format(messages.getString("Message.SellAllDelayAlreadyDisabled"))); + Output.get().sendWarn(sender, messages.getString(MessagesConfig.StringID.spigot_message_sellall_delay_already_disabled)); } return; } - if (sellAllUtil.enableDelay(enableBoolean)) return; - - if (enableBoolean){ - Output.get().sendInfo(sender, SpigotPrison.format(messages.getString("Message.SellAllDelayEnabled"))); - } else { - Output.get().sendInfo(sender, SpigotPrison.format(messages.getString("Message.SellAllDelayDisabled"))); + if (sellAllUtil.setDelayEnable(enableBoolean)){ + if (enableBoolean){ + Output.get().sendInfo(sender, messages.getString(MessagesConfig.StringID.spigot_message_sellall_delay_enabled)); + } else { + Output.get().sendInfo(sender, messages.getString(MessagesConfig.StringID.spigot_message_sellall_delay_disabled)); + } } } @Command(identifier = "sellall set delay", description = "Edit SellAll delay.", onlyPlayers = false, permissions = "prison.sellall.delay") private void sellAllDelaySet(CommandSender sender, - @Arg(name = "delay", description = "Set delay value in seconds.", def = "0") String delay){ + @Arg(name = "delay", description = "Set delay value in seconds.", def = "0") String delay){ if (!isEnabled()) return; + SellAllUtil sellAllUtil = SellAllUtil.get(); + if (sellAllUtil == null){ + return; + } + int delayValue; try { delayValue = Integer.parseInt(delay); } catch (NumberFormatException ex){ - Output.get().sendError(sender, SpigotPrison.format(messages.getString("Message.SellAllDelayNotNumber"))); + Output.get().sendError(sender, messages.getString(MessagesConfig.StringID.spigot_message_sellall_delay_not_number)); return; } - if (sellAllUtil.setDelay(delayValue)) return; - - Output.get().sendInfo(sender, SpigotPrison.format(messages.getString("Message.SellAllDelayEditedWithSuccess") + " [" + delayValue + "s]")); + if (sellAllUtil.setDelay(delayValue)){ + Output.get().sendInfo(sender, messages.getString(MessagesConfig.StringID.spigot_message_sellall_delay_edit_success) + " [" + delayValue + "s]"); + } } @Command(identifier = "sellall autosell", description = "Enable SellAll AutoSell.", onlyPlayers = false, permissions = "prison.autosell.edit") @@ -140,91 +160,172 @@ private void sellAllAutoSell(CommandSender sender, } if (!(enable.equalsIgnoreCase("true") || enable.equalsIgnoreCase("false"))){ - Output.get().sendWarn(sender, SpigotPrison.format(messages.getString("Message.InvalidBooleanInput"))); + Output.get().sendWarn(sender, messages.getString(MessagesConfig.StringID.spigot_message_sellall_boolean_input_invalid)); + return; + } + + SellAllUtil sellAllUtil = SellAllUtil.get(); + if (sellAllUtil == null){ return; } boolean enableBoolean = getBoolean(enable); - boolean fullInvAutoSellEnabled = getBoolean(sellAllUtil.getSellAllConfig().getString("Options.Full_Inv_AutoSell")); - if (fullInvAutoSellEnabled == enableBoolean){ + if (sellAllUtil.isAutoSellEnabled == enableBoolean){ if (enableBoolean){ - Output.get().sendWarn(sender, SpigotPrison.format(messages.getString("Message.SellAllAutoSellAlreadyEnabled"))); + Output.get().sendWarn(sender, messages.getString(MessagesConfig.StringID.spigot_message_sellall_auto_already_enabled)); } else { - Output.get().sendWarn(sender, SpigotPrison.format(messages.getString("Message.SellAllAutoSellAlreadyDisabled"))); + Output.get().sendWarn(sender, messages.getString(MessagesConfig.StringID.spigot_message_sellall_auto_already_disabled)); } return; } - if (sellAllUtil.enableAutoSell(enableBoolean)) return; - - if (enableBoolean){ - Output.get().sendInfo(sender, SpigotPrison.format(messages.getString("Message.SellAllAutoSellEnabled"))); - } else { - Output.get().sendInfo(sender, SpigotPrison.format(messages.getString("Message.SellAllAutoSellDisabled"))); + if (sellAllUtil.setAutoSell(enableBoolean)){ + if (enableBoolean){ + Output.get().sendInfo(sender, messages.getString(MessagesConfig.StringID.spigot_message_sellall_auto_enabled)); + } else { + Output.get().sendInfo(sender, messages.getString(MessagesConfig.StringID.spigot_message_sellall_auto_disabled)); + } } } - @Command(identifier = "sellall autosell perUserToggleable", description = "Enable AutoSell perUserToggleable", onlyPlayers = false, permissions = "prison.autosell.edit") + @Command(identifier = "sellall autosell perUserToggleable", description = "Enable AutoSell perUserToggleable.", onlyPlayers = false, permissions = "prison.autosell.edit") private void sellAllAutoSellPerUserToggleable(CommandSender sender, @Arg(name = "boolean", description = "True to enable or false to disable", def = "null") String enable){ if (!isEnabled()) return; if (!(enable.equalsIgnoreCase("true") || enable.equalsIgnoreCase("false"))){ - Output.get().sendWarn(sender, SpigotPrison.format(messages.getString("Message.InvalidBooleanInput"))); + Output.get().sendWarn(sender, messages.getString(MessagesConfig.StringID.spigot_message_sellall_boolean_input_invalid)); + return; + } + + SellAllUtil sellAllUtil = SellAllUtil.get(); + if (sellAllUtil == null){ return; } boolean enableBoolean = getBoolean(enable); - boolean perUserToggleableEnabled = getBoolean(sellAllUtil.getSellAllConfig().getString("Options.Full_Inv_AutoSell_perUserToggleable")); - if (perUserToggleableEnabled == enableBoolean){ + if (sellAllUtil.isAutoSellPerUserToggleable == enableBoolean){ if (enableBoolean){ - Output.get().sendInfo(sender, SpigotPrison.format(messages.getString("Message.SellAllAutoPerUserToggleableAlreadyEnabled"))); + Output.get().sendInfo(sender, messages.getString(MessagesConfig.StringID.spigot_message_sellall_auto_perusertoggleable_already_enabled)); } else { - Output.get().sendInfo(sender, SpigotPrison.format(messages.getString("Message.SellAllAutoPerUserToggleableAlreadyDisabled"))); + Output.get().sendInfo(sender, messages.getString(MessagesConfig.StringID.spigot_message_sellall_auto_perusertoggleable_already_disabled)); } return; } - if (sellAllUtil.enableAutoSellPerUserToggleable(enableBoolean)) return; + if (sellAllUtil.setAutoSellPerUserToggleable(enableBoolean)){ + if (enableBoolean){ + Output.get().sendInfo(sender, messages.getString(MessagesConfig.StringID.spigot_message_sellall_auto_perusertoggleable_enabled)); + } else { + Output.get().sendInfo(sender, messages.getString(MessagesConfig.StringID.spigot_message_sellall_auto_perusertoggleable_disabled)); + } + } + } - if (enableBoolean){ - Output.get().sendInfo(sender, SpigotPrison.format(messages.getString("Message.SellAllAutoPerUserToggleableEnabled"))); - } else { - Output.get().sendInfo(sender, SpigotPrison.format(messages.getString("Message.SellAllAutoPerUserToggleableDisabled"))); + @Command(identifier = "sellall sell", description = "SellAll sell command.", onlyPlayers = true) + public void sellAllSellCommand(CommandSender sender, + @Arg(name = "notification", def="", + description = "Notification about the sellall transaction. Defaults to normal. " + + "'silent' suppresses results. [silent]") String notification ){ + + if (!isEnabled()) return; + + Player p = getSpigotPlayer(sender); + + if (p == null){ + Output.get().sendInfo(sender, "&cSorry but you can't use that from the console!"); + return; + } + + SellAllUtil sellAllUtil = SellAllUtil.get(); + if (sellAllUtil == null){ + return; } + + if (sellAllUtil.isPlayerInDisabledWorld(p)) return; + + 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 + "]"); + return; + } + } + + boolean notifications = (notification != null && "silent".equalsIgnoreCase( notification )); + + sellAllUtil.sellAllSell(p, false, notifications, true, true, false, true); } - @Command(identifier = "sellall sell", description = "SellAll sell command", onlyPlayers = true) - public void sellAllSellCommand(CommandSender sender, - @Arg(name = "notification", def="", - description = "Notification about the sellall transaction. Defaults to normal. " + - "'silent' suppresses results. [silent]") String notification ){ + @Command(identifier = "sellall hand", description = "Sell only what is in your hand if sellable.", onlyPlayers = true) + public void sellAllSellHandCommand(CommandSender sender){ if (!isEnabled()) return; + SellAllUtil sellAllUtil = SellAllUtil.get(); + + if (sellAllUtil == null){ + return; + } + + if (!sellAllUtil.isSellAllHandEnabled){ + Output.get().sendWarn(sender, "The command /sellall hand is disabled from the config!"); + return; + } + Player p = getSpigotPlayer(sender); if (p == null){ - Output.get().sendInfo(sender, SpigotPrison.format("&cSorry but you can't use that from the console!")); + Output.get().sendInfo(sender, "&cSorry but you can't use that from the console!"); return; } - if (sellAllUtil.isDisabledWorld(p)) return; + if (sellAllUtil.isPlayerInDisabledWorld(p)) return; - boolean sellPermissionEnabled = getBoolean(sellAllUtil.getSellAllConfig().getString("Options.Sell_Permission_Enabled")); - if (sellPermissionEnabled){ - String permission = sellAllUtil.getSellAllConfig().getString("Options.Sell_Permission"); + if (sellAllUtil.isSellAllSellPermissionEnabled){ + String permission = sellAllUtil.permissionSellAllSell; if (permission == null || !p.hasPermission(permission)){ - Output.get().sendWarn(new SpigotPlayer(p), SpigotPrison.format(messages.getString("Message.SellAllMissingPermission") + " [" + permission + "]")); + Output.get().sendWarn(new SpigotPlayer(p), messages.getString(MessagesConfig.StringID.spigot_message_missing_permission) + " [" + permission + "]"); return; } } - boolean notifications = !(notification != null && "silent".equalsIgnoreCase( notification )); - boolean bySignOnly = notification != null && "bySignOnly".equalsIgnoreCase( notification ); + ArrayList itemStacks = new ArrayList<>(); + itemStacks.add(compat.getItemInMainHand(p)); - sellAllUtil.sellAllSell(p, notifications, bySignOnly); + itemStacks = sellAllUtil.sellAllSell(p, itemStacks, false, false, true, true, false, true, true); + if (itemStacks.isEmpty()){ + compat.setItemInMainHand(p, XMaterial.AIR.parseItem()); + } else { + compat.setItemInMainHand(p, itemStacks.get(0)); + } + } + + public void sellAllSell(Player p){ + if (!isEnabled()) return; + + if (p == null){ + Output.get().sendInfo(new SpigotPlayer(p), "&cSorry but you can't use that from the console!"); + return; + } + + SellAllUtil sellAllUtil = SellAllUtil.get(); + if (sellAllUtil == null){ + return; + } + + if (sellAllUtil.isPlayerInDisabledWorld(p)) return; + + 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 + "]"); + return; + } + } + + sellAllUtil.sellAllSell(p, true, false, true, true, false, true); } @Command(identifier = "sellall delaysell", description = "Like SellAll Sell command but this will be delayed for some " + @@ -239,32 +340,35 @@ public void sellAllSellWithDelayCommand(CommandSender sender){ Player p = getSpigotPlayer(sender); if (p == null){ - Output.get().sendInfo(sender, SpigotPrison.format("&cSorry but you can't use that from the console!")); + Output.get().sendInfo(sender, "&cSorry but you can't use that from the console!"); + return; + } + + SellAllUtil sellAllUtil = SellAllUtil.get(); + if (sellAllUtil == null){ return; } - if (sellAllUtil.isDisabledWorld(p)) return; + if (sellAllUtil.isPlayerInDisabledWorld(p)) return; - boolean sellPermissionEnabled = getBoolean(sellAllUtil.getSellAllConfig().getString("Options.Sell_Permission_Enabled")); - if (sellPermissionEnabled){ - String permission = sellAllUtil.getSellAllConfig().getString("Options.Sell_Permission"); + if (sellAllUtil.isSellAllSellPermissionEnabled){ + String permission = sellAllUtil.permissionSellAllSell; if (permission == null || !p.hasPermission(permission)){ - Output.get().sendWarn(new SpigotPlayer(p), SpigotPrison.format(messages.getString("Message.SellAllMissingPermission") + " [" + permission + "]")); + Output.get().sendWarn(new SpigotPlayer(p), messages.getString(MessagesConfig.StringID.spigot_message_missing_permission) + " [" + permission + "]"); return; } } - if (!getBoolean(sellAllUtil.sellAllConfig.getString("Options.Full_Inv_AutoSell_EarnedMoneyNotificationDelay_Enabled"))){ + if (!sellAllUtil.isAutoSellEarningNotificationDelayEnabled){ sellAllSellCommand(sender, "silent"); return; } - SellAllUtil.get().addToAutoSellTask(p); - sellAllSellCommand(sender, "silent"); + sellAllUtil.sellAllSell(p, false, false, false, false, true, false); } - @Command(identifier = "sellall auto toggle", description = "Let the user enable or disable sellall auto", onlyPlayers = true) + @Command(identifier = "sellall auto toggle", description = "Let the user enable or disable sellall auto", altPermissions = "prison.sellall.toggle", onlyPlayers = true) private void sellAllAutoEnableUser(CommandSender sender){ if (!isEnabled()) return; @@ -273,29 +377,44 @@ private void sellAllAutoEnableUser(CommandSender sender){ // Sender must be a Player, not something else like the Console. if (p == null) { - Output.get().sendError(sender, SpigotPrison.format(getMessages().getString("Message.CantRunGUIFromConsole"))); + Output.get().sendError(sender, getMessages().getString(MessagesConfig.StringID.spigot_message_console_error)); return; } - if (sellAllUtil.isDisabledWorld(p)) return; + SellAllUtil sellAllUtil = SellAllUtil.get(); + if (sellAllUtil == null){ + return; + } - boolean perUserToggleableEnabled = getBoolean(sellAllUtil.getSellAllConfig().getString("Options.Full_Inv_AutoSell_perUserToggleable")); - if (!perUserToggleableEnabled){ + if (sellAllUtil.isPlayerInDisabledWorld(p)) return; + + if (!sellAllUtil.isAutoSellPerUserToggleable){ return; } - boolean perUserToggleablePermEnabled = getBoolean(sellAllUtil.getSellAllConfig().getString("Options.Full_Inv_AutoSell_perUserToggleable_Need_Perm")); - String permission = sellAllUtil.getSellAllConfig().getString("Options.Full_Inv_AutoSell_PerUserToggleable_Permission"); - if (perUserToggleablePermEnabled && (permission != null && !p.hasPermission(permission))){ - Output.get().sendWarn(sender, SpigotPrison.format(messages.getString("Message.SellAllMissingPermissionToToggleAutoSell") + " [" + permission + "]")); + 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 + "]"); return; } - if (sellAllUtil.autoSellPlayerToggle(p)) return; + if (sellAllUtil.setAutoSellPlayer(p, !sellAllUtil.isPlayerAutoSellEnabled(p))){ + if (sellAllUtil.isPlayerAutoSellEnabled(p)){ + Output.get().sendInfo(new SpigotPlayer(p), messages.getString(MessagesConfig.StringID.spigot_message_sellall_auto_enabled)); + } else { + Output.get().sendInfo(new SpigotPlayer(p), messages.getString(MessagesConfig.StringID.spigot_message_sellall_auto_disabled)); + } + } } - @Command(identifier = "sellall gui", description = "SellAll GUI command", altPermissions = "prison.admin", onlyPlayers = true) - private void sellAllGuiCommand(CommandSender sender){ + @Command(identifier = "sellall gui", + description = "SellAll GUI command", + aliases = "gui sellall", + altPermissions = "prison.admin", onlyPlayers = true) + private void sellAllGuiCommand(CommandSender sender, + @Arg(name = "page", description = "If there are more than 45 items, then they " + + "will be shown on multiple pages. The page parameter starts with " + + "page 1.", def = "1" ) int page){ if (!isEnabled()) return; @@ -303,17 +422,46 @@ private void sellAllGuiCommand(CommandSender sender){ // Sender must be a Player, not something else like the Console. if (p == null) { - Output.get().sendError(sender, SpigotPrison.format(getMessages().getString("Message.CantRunGUIFromConsole"))); + Output.get().sendError(sender, getMessages().getString(MessagesConfig.StringID.spigot_message_console_error)); return; } - if (sellAllUtil.openGUI(p)) return; + SellAllUtil sellAllUtil = SellAllUtil.get(); + if (sellAllUtil == null){ + return; + } - // If the sender's an admin (OP or have the prison.admin permission) it'll send an error message. - if (p.hasPermission("prison.admin")) { - Output.get().sendError(sender, SpigotPrison.format(messages.getString("Message.SellAllGUIDisabled"))); + if (!sellAllUtil.openSellAllGUI( p, page, "sellall gui", "close" )){ + // If the sender's an admin (OP or have the prison.admin permission) it'll send an error message. + if (p.hasPermission("prison.admin")) { + Output.get().sendError(sender, messages.getString(MessagesConfig.StringID.spigot_message_gui_sellall_disabled)); + } } } + + @Command(identifier = "sellall gui blocks", + description = "SellAll GUI Blocks command", + aliases = "gui sellall", + altPermissions = "prison.admin", onlyPlayers = true) + private void sellAllGuiBlocksCommand(CommandSender sender, + @Arg(name = "page", description = "If there are more than 45 items, then they " + + "will be shown on multiple pages. The page parameter starts with " + + "page 1.", def = "1" ) int page){ + + if (!isEnabled()) return; + + Player p = getSpigotPlayer(sender); + + // Sender must be a Player, not something else like the Console. + if (p == null) { + Output.get().sendError(sender, getMessages().getString(MessagesConfig.StringID.spigot_message_console_error)); + return; + } + + SellAllAdminBlocksGUI saBlockGui = new SellAllAdminBlocksGUI( p, page, "sellall gui blocks", "sellall gui" ); + saBlockGui.open(); + + } @Command(identifier = "sellall add", description = "SellAll add an item to the sellAll shop.", permissions = "prison.admin", onlyPlayers = false) private void sellAllAddCommand(CommandSender sender, @@ -323,18 +471,23 @@ private void sellAllAddCommand(CommandSender sender, if (!isEnabled()) return; if (itemID == null){ - Output.get().sendWarn(sender, SpigotPrison.format(messages.getString("Message.SellAllPleaseAddItem"))); + Output.get().sendWarn(sender, messages.getString(MessagesConfig.StringID.spigot_message_sellall_item_missing_name)); return; } itemID = itemID.toUpperCase(); if (value == null){ - Output.get().sendWarn(sender, SpigotPrison.format(messages.getString("Message.SellAllAddPrice"))); + Output.get().sendWarn(sender, messages.getString(MessagesConfig.StringID.spigot_message_sellall_item_missing_price)); + return; + } + + SellAllUtil sellAllUtil = SellAllUtil.get(); + if (sellAllUtil == null){ return; } - if (sellAllUtil.getSellAllConfig().getConfigurationSection("Items." + itemID) != null){ - Output.get().sendWarn(sender, SpigotPrison.format(itemID + messages.getString("Message.SellAllAlreadyAdded"))); + if (sellAllUtil.sellAllConfig.getConfigurationSection("Items." + itemID) != null){ + Output.get().sendWarn(sender, itemID + " " + messages.getString(MessagesConfig.StringID.spigot_message_sellall_item_already_added)); return; } @@ -343,18 +496,17 @@ private void sellAllAddCommand(CommandSender sender, try { blockAdd = XMaterial.valueOf(itemID); } catch (IllegalArgumentException ex){ - Output.get().sendInfo(sender, SpigotPrison.format(messages.getString("Message.SellAllWrongID") + " [" + itemID + "]")); + Output.get().sendInfo(sender, messages.getString(MessagesConfig.StringID.spigot_message_sellall_item_id_not_found) + " [" + itemID + "]"); return; } - if (sellAllUtil.addBlock(blockAdd, value)) return; + if (sellAllUtil.addSellAllBlock(blockAdd, value)){ + Output.get().sendInfo(sender, "&3 ITEM [" + itemID + ", " + value + " " + messages.getString(MessagesConfig.StringID.spigot_message_sellall_item_add_success)); + } } catch (IllegalArgumentException ex){ - Output.get().sendError(sender, SpigotPrison.format(messages.getString("Message.SellAllWrongID") + " [" + itemID + "]")); - return; + Output.get().sendError(sender, messages.getString(MessagesConfig.StringID.spigot_message_sellall_item_id_not_found) + " [" + itemID + "]"); } - - Output.get().sendInfo(sender, SpigotPrison.format("&3 ITEM [" + itemID + ", " + value + messages.getString("Message.SellAllAddSuccess"))); } /** @@ -367,16 +519,21 @@ private void sellAllAddCommand(CommandSender sender, */ public void sellAllAddCommand(XMaterial blockAdd, Double value){ - String itemID = blockAdd.name(); + String itemID = blockAdd.name(); + + SellAllUtil sellAllUtil = SellAllUtil.get(); + if (sellAllUtil == null){ + return; + } - // If the block or item was already configured, then skip this: - if (sellAllUtil.getSellAllConfig().getConfigurationSection("Items." + itemID) != null){ + // If the block or item was already configured, then skip this: + if (sellAllUtil.sellAllConfig.getConfigurationSection("Items." + itemID) != null){ return; } - if (sellAllUtil.addBlock(blockAdd, value)) return; + if (sellAllUtil.addSellAllBlock(blockAdd, value)) return; - Output.get().logInfo(SpigotPrison.format("&3 ITEM [" + itemID + ", " + value + messages.getString("Message.SellAllAddSuccess"))); + Output.get().logInfo("&3 ITEM [" + itemID + ", " + value + " " + messages.getString(MessagesConfig.StringID.spigot_message_sellall_item_add_success)); } @Command(identifier = "sellall delete", description = "SellAll delete command, remove an item from shop.", permissions = "prison.admin", onlyPlayers = false) @@ -385,18 +542,26 @@ private void sellAllDeleteCommand(CommandSender sender, @Arg(name = "Item_ID", d if (!isEnabled()) return; if (itemID == null){ - Output.get().sendWarn(sender, SpigotPrison.format(messages.getString("Message.SellAllMissingID"))); + Output.get().sendWarn(sender, messages.getString(MessagesConfig.StringID.spigot_message_sellall_item_missing_name)); return; } + itemID = itemID.toUpperCase(); - if (sellAllUtil.getSellAllConfig().getConfigurationSection("Items." + itemID) == null){ - Output.get().sendWarn(sender, SpigotPrison.format(itemID + messages.getString("Message.SellAllNotFoundStringConfig"))); + SellAllUtil sellAllUtil = SellAllUtil.get(); + if (sellAllUtil == null){ return; } - if (sellAllUtil.deleteBlock(itemID)) return; + if (sellAllUtil.sellAllConfig.getConfigurationSection("Items." + itemID) == null){ + Output.get().sendWarn(sender, itemID + " " + messages.getString(MessagesConfig.StringID.spigot_message_sellall_cant_find_item_config)); + return; + } - Output.get().sendInfo(sender, SpigotPrison.format(itemID + messages.getString("Message.SellAllDeletedSuccess"))); + if (XMaterial.matchXMaterial(itemID).isPresent()) { + if (sellAllUtil.removeSellAllBlock(XMaterial.matchXMaterial(itemID).get())) { + Output.get().sendInfo(sender, itemID + " " + messages.getString(MessagesConfig.StringID.spigot_message_sellall_item_delete_success)); + } + } } @Command(identifier = "sellall edit", description = "SellAll edit command, edit an item of Shop.", permissions = "prison.admin", onlyPlayers = false) @@ -407,18 +572,23 @@ private void sellAllEditCommand(CommandSender sender, if (!isEnabled()) return; if (itemID == null){ - Output.get().sendWarn(sender, SpigotPrison.format(messages.getString("Message.SellAllPleaseAddItem"))); + Output.get().sendWarn(sender, messages.getString(MessagesConfig.StringID.spigot_message_sellall_item_missing_name)); return; } itemID = itemID.toUpperCase(); if (value == null){ - Output.get().sendWarn(sender, SpigotPrison.format(messages.getString("Message.SellAllAddPrice"))); + Output.get().sendWarn(sender, messages.getString(MessagesConfig.StringID.spigot_message_sellall_item_missing_price)); return; } - if (sellAllUtil.getSellAllConfig().getConfigurationSection("Items." + itemID) == null){ - Output.get().sendWarn(sender, SpigotPrison.format(itemID + messages.getString("Message.SellAllNotFoundEdit"))); + SellAllUtil sellAllUtil = SellAllUtil.get(); + if (sellAllUtil == null){ + return; + } + + if (sellAllUtil.sellAllConfig.getConfigurationSection("Items." + itemID) == null){ + Output.get().sendWarn(sender, itemID + " " + messages.getString(MessagesConfig.StringID.spigot_message_sellall_item_not_found)); return; } @@ -427,18 +597,17 @@ private void sellAllEditCommand(CommandSender sender, try{ blockAdd = XMaterial.valueOf(itemID); } catch (IllegalArgumentException ex){ - Output.get().sendError(sender, SpigotPrison.format(messages.getString("Message.SellAllWrongID") + " [" + itemID + "]")); + Output.get().sendError(sender, messages.getString(MessagesConfig.StringID.spigot_message_sellall_item_id_not_found) + " [" + itemID + "]"); return; } - if (sellAllUtil.editBlock(blockAdd, value)) return; + if (sellAllUtil.editPrice(blockAdd, value)){ + Output.get().sendInfo(sender, "&3ITEM [" + itemID + ", " + value + " " + messages.getString(MessagesConfig.StringID.spigot_message_sellall_item_edit_success)); + } } catch (IllegalArgumentException ex){ - Output.get().sendError(sender, SpigotPrison.format(messages.getString("Message.SellAllWrongID") + " [" + itemID + "]")); - return; + Output.get().sendError(sender, messages.getString(MessagesConfig.StringID.spigot_message_sellall_item_id_not_found) + " [" + itemID + "]"); } - - Output.get().sendInfo(sender, SpigotPrison.format("&3ITEM [" + itemID + ", " + value + messages.getString("Message.SellAllCommandEditSuccess"))); } @Command(identifier = "sellall multiplier", description = "SellAll multiplier command list", permissions = "prison.admin", onlyPlayers = false) @@ -446,9 +615,13 @@ private void sellAllMultiplierCommand(CommandSender sender){ if (!isEnabled()) return; - boolean multiplierEnabled = getBoolean(sellAllUtil.getSellAllConfig().getString("Options.Multiplier_Enabled")); - if (!multiplierEnabled){ - Output.get().sendWarn(sender, SpigotPrison.format(messages.getString("Message.SellAllMultipliersAreDisabled"))); + SellAllUtil sellAllUtil = SellAllUtil.get(); + if (sellAllUtil == null){ + return; + } + + if (!sellAllUtil.isSellAllMultiplierEnabled){ + Output.get().sendWarn(sender, messages.getString(MessagesConfig.StringID.spigot_message_sellall_multiplier_are_disabled)); return; } @@ -456,7 +629,9 @@ private void sellAllMultiplierCommand(CommandSender sender){ sender.dispatchCommand(registeredCmd); } - @Command(identifier = "sellall multiplier add", description = "SellAll add a multiplier. Permission multipliers for player's prison.sellall.multiplier., example prison.sellall.multiplier.2 will add a 2x multiplier", + @Command(identifier = "sellall multiplier add", description = "SellAll add a multiplier. Permission multipliers for player's prison.sellall.multiplier., example prison.sellall.multiplier.2 will add a 2x multiplier," + + "There's also another kind of Multiplier called permission multipliers, they're permissions that you can give to players to give them a multiplier, remember that their format is prison.sellall.multiplier.2 (for example), and this example will give you a " + + "total of 3x multiplier (1x default + 2x permission = 3x).", permissions = "prison.admin", onlyPlayers = false) private void sellAllAddMultiplierCommand(CommandSender sender, @Arg(name = "Prestige", description = "Prestige to hook to the multiplier.") String prestige, @@ -464,15 +639,19 @@ private void sellAllAddMultiplierCommand(CommandSender sender, if (!isEnabled()) return; - boolean multiplierEnabled = getBoolean(sellAllUtil.getSellAllConfig().getString("Options.Multiplier_Enabled")); - if (!multiplierEnabled){ - Output.get().sendWarn(sender, SpigotPrison.format(messages.getString("Message.SellAllMultipliersAreDisabled"))); + SellAllUtil sellAllUtil = SellAllUtil.get(); + if (sellAllUtil == null){ return; } - if (sellAllUtil.addMultiplier(prestige, multiplier)) return; + if (!sellAllUtil.isSellAllMultiplierEnabled){ + Output.get().sendWarn(sender, messages.getString(MessagesConfig.StringID.spigot_message_sellall_multiplier_are_disabled)); + return; + } - Output.get().sendInfo(sender, SpigotPrison.format(messages.getString("Message.SellAllMultiplierEditSaveSuccess"))); + if (sellAllUtil.addPrestigeMultiplier(prestige, multiplier)){ + Output.get().sendInfo(sender, messages.getString(MessagesConfig.StringID.spigot_message_sellall_multiplier_add_success)); + } } @Command(identifier = "sellall multiplier delete", description = "SellAll delete a multiplier.", permissions = "prison.admin", onlyPlayers = false) @@ -481,31 +660,29 @@ private void sellAllDeleteMultiplierCommand(CommandSender sender, if (!isEnabled()) return; - boolean multiplierEnabled = getBoolean(sellAllUtil.getSellAllConfig().getString("Options.Multiplier_Enabled")); - if (!multiplierEnabled){ - Output.get().sendWarn(sender, SpigotPrison.format(messages.getString("Message.SellAllMultipliersAreDisabled"))); + SellAllUtil sellAllUtil = SellAllUtil.get(); + if (sellAllUtil == null){ return; } - String permission = sellAllUtil.getSellAllConfig().getString("Options.Multiplier_Command_Permission"); - if (permission != null && !sender.hasPermission(permission)){ - Output.get().sendWarn(sender, SpigotPrison.format(messages.getString("Message.SellAllMissingPermission") + " [" + permission + "]")); + if (!sellAllUtil.isSellAllMultiplierEnabled){ + Output.get().sendWarn(sender, messages.getString(MessagesConfig.StringID.spigot_message_sellall_multiplier_are_disabled)); return; } if (prestige == null){ - Output.get().sendWarn(sender, SpigotPrison.format(messages.getString("Message.SellAllMultiplierFormat"))); + Output.get().sendWarn(sender, messages.getString(MessagesConfig.StringID.spigot_message_command_wrong_format)); return; } - if (sellAllUtil.getSellAllConfig().getConfigurationSection("Multiplier." + prestige) == null){ - Output.get().sendWarn(sender, SpigotPrison.format(messages.getString("Message.SellAllCantFindMultiplier") + prestige + messages.getString("Message.SellAllCantFindMultiplier2"))); + if (sellAllUtil.sellAllConfig.getConfigurationSection("Multiplier." + prestige) == null){ + Output.get().sendWarn(sender, messages.getString(MessagesConfig.StringID.spigot_message_sellall_multiplier_cant_find) + " [" + prestige + "]"); return; } - if (sellAllUtil.deleteMultiplier(prestige)) return; - - Output.get().sendInfo(sender, SpigotPrison.format(messages.getString("Message.SellAllMultiplierDeleteSuccess"))); + if (sellAllUtil.removePrestigeMultiplier(prestige)){ + Output.get().sendInfo(sender, messages.getString(MessagesConfig.StringID.spigot_message_sellall_multiplier_delete_success)); + } } @Command(identifier = "sellall Trigger", description = "Toggle SellAll Shift+Right Click on a tool to trigger the /sellall sell command, true -> Enabled or False -> Disabled.", permissions = "prison.admin", onlyPlayers = false) @@ -515,35 +692,37 @@ private void sellAllToolsTriggerToggle(CommandSender sender, if (!isEnabled()) return; if (enable.equalsIgnoreCase("null")){ - String registeredCmd = Prison.get().getCommandHandler().findRegisteredCommand( "sellall toolsTrigger help" ); + String registeredCmd = Prison.get().getCommandHandler().findRegisteredCommand( "sellall toolsTrigger help" ); sender.dispatchCommand(registeredCmd); return; } if (!enable.equalsIgnoreCase("true") && !enable.equalsIgnoreCase("false")){ - Output.get().sendWarn(sender, SpigotPrison.format(messages.getString("Message.InvalidBooleanInput"))); + Output.get().sendWarn(sender, messages.getString(MessagesConfig.StringID.spigot_message_sellall_boolean_input_invalid)); return; } - boolean sellAllTriggerStatus = getBoolean(sellAllUtil.getSellAllConfig().getString("Options.ShiftAndRightClickSellAll.Enabled")); - boolean enableInput = getBoolean(enable); - if (sellAllTriggerStatus == enableInput) { - if (sellAllTriggerStatus) { + SellAllUtil sellAllUtil = SellAllUtil.get(); + if (sellAllUtil == null){ + return; + } - Output.get().sendWarn(sender, SpigotPrison.format(messages.getString("Message.SellAllTriggerAlreadyEnabled"))); + boolean enableInput = getBoolean(enable); + if (sellAllUtil.isSellAllItemTriggerEnabled == enableInput) { + if (sellAllUtil.isSellAllItemTriggerEnabled) { + Output.get().sendWarn(sender, messages.getString(MessagesConfig.StringID.spigot_message_sellall_trigger_already_enabled)); } else { - - Output.get().sendWarn(sender, SpigotPrison.format(messages.getString("Message.SellAllTriggerAlreadyDisabled"))); + Output.get().sendWarn(sender, messages.getString(MessagesConfig.StringID.spigot_message_sellall_trigger_already_disabled)); } return; } - if (sellAllUtil.toggleItemTrigger(enableInput)) return; - - if (enableInput){ - Output.get().sendInfo(sender, SpigotPrison.format(messages.getString("Message.SellAllTriggerEnabled"))); - } else { - Output.get().sendInfo(sender, SpigotPrison.format(messages.getString("Message.SellAllTriggerDisabled"))); + if (sellAllUtil.setItemTrigger(enableInput)){ + if (enableInput){ + Output.get().sendInfo(sender, messages.getString(MessagesConfig.StringID.spigot_message_sellall_trigger_enabled)); + } else { + Output.get().sendInfo(sender, messages.getString(MessagesConfig.StringID.spigot_message_sellall_trigger_disabled)); + } } } @@ -553,14 +732,18 @@ private void sellAllTriggerAdd(CommandSender sender, if (!isEnabled()) return; - boolean sellAllTriggerStatus = getBoolean(sellAllUtil.getSellAllConfig().getString("Options.ShiftAndRightClickSellAll.Enabled")); - if (!sellAllTriggerStatus){ - Output.get().sendWarn(sender, SpigotPrison.format(messages.getString("Message.SellAllTriggerIsDisabled"))); + SellAllUtil sellAllUtil = SellAllUtil.get(); + if (sellAllUtil == null){ + return; + } + + if (!sellAllUtil.isSellAllItemTriggerEnabled){ + Output.get().sendWarn(sender, messages.getString(MessagesConfig.StringID.spigot_message_sellall_trigger_is_disabled)); return; } if (itemID == null){ - Output.get().sendWarn(sender, SpigotPrison.format(messages.getString("Message.SellAllTriggerMissingItem"))); + Output.get().sendWarn(sender, messages.getString(MessagesConfig.StringID.spigot_message_sellall_item_missing_name)); return; } itemID = itemID.toUpperCase(); @@ -570,46 +753,54 @@ private void sellAllTriggerAdd(CommandSender sender, try{ blockAdd = XMaterial.valueOf(itemID); } catch (IllegalArgumentException ex){ - Output.get().sendError(sender, SpigotPrison.format(messages.getString("Message.SellAllWrongID") + " [" + itemID + "]")); + Output.get().sendError(sender, messages.getString(MessagesConfig.StringID.spigot_message_sellall_item_id_not_found) + " [" + itemID + "]"); return; } - if (sellAllUtil.addItemTrigger(blockAdd)) return; + if (sellAllUtil.addItemTrigger(blockAdd)){ + Output.get().sendInfo(sender, messages.getString(MessagesConfig.StringID.spigot_message_sellall_trigger_item_add_success) + " [" + itemID + "]"); + } } catch (IllegalArgumentException ex){ - Output.get().sendError(sender, SpigotPrison.format(messages.getString("Message.SellAllWrongID") + " [" + itemID + "]")); - return; + Output.get().sendError(sender, messages.getString(MessagesConfig.StringID.spigot_message_sellall_item_id_not_found) + " [" + itemID + "]"); } - - Output.get().sendInfo(sender, SpigotPrison.format(messages.getString("Message.SellAllTriggerItemAddSuccess") + " [" + itemID + " ]")); } @Command(identifier = "sellall Trigger delete", description = "Delete an Item from the Shift+Right Click trigger -> /sellall sell command.", permissions = "prison.admin", onlyPlayers = false) private void sellAllTriggerDelete(CommandSender sender, - @Arg(name = "Item", description = "Item name") String itemID){ + @Arg(name = "Item", description = "Item name") String itemID){ if (!isEnabled()) return; - boolean sellAllTriggerStatus = getBoolean(sellAllUtil.getSellAllConfig().getString("Options.ShiftAndRightClickSellAll.Enabled")); - if (!sellAllTriggerStatus){ - Output.get().sendWarn(sender, SpigotPrison.format(messages.getString("Message.SellAllTriggerIsDisabled"))); + SellAllUtil sellAllUtil = SellAllUtil.get(); + if (sellAllUtil == null){ + return; + } + + if (!sellAllUtil.isSellAllItemTriggerEnabled){ + Output.get().sendWarn(sender, messages.getString(MessagesConfig.StringID.spigot_message_sellall_trigger_is_disabled)); return; } if (itemID == null){ - Output.get().sendWarn(sender, SpigotPrison.format(messages.getString("Message.SellAllTriggerMissingItem"))); + Output.get().sendWarn(sender, messages.getString(MessagesConfig.StringID.spigot_message_sellall_item_missing_name)); return; } itemID = itemID.toUpperCase(); - if (sellAllUtil.getSellAllConfig().getString("Options.ShiftAndRightClickSellAll.Items." + itemID + ".ITEM_ID") == null){ - - Output.get().sendWarn(sender, SpigotPrison.format(messages.getString("Message.SellAllTriggerMissingItem"))); + if (!XMaterial.matchXMaterial(itemID).isPresent()){ + Output.get().sendError(sender, messages.getString(MessagesConfig.StringID.spigot_message_sellall_item_id_not_found) + " [" + itemID + "]"); return; } + XMaterial xMaterial = XMaterial.matchXMaterial(itemID).get(); - if (sellAllUtil.deleteItemTrigger(itemID)) return; + if (!sellAllUtil.getItemTriggerXMaterials().contains(xMaterial)){ + Output.get().sendWarn(sender, messages.getString(MessagesConfig.StringID.spigot_message_sellall_item_missing_name)); + return; + } - Output.get().sendInfo(sender, SpigotPrison.format(messages.getString("Message.SellAllTriggerItemDeleteSuccess") + " [" + itemID + " ]")); + if (sellAllUtil.removeItemTrigger(xMaterial)) { + Output.get().sendInfo(sender, messages.getString(MessagesConfig.StringID.spigot_message_sellall_trigger_item_delete_success) + " [" + itemID + "]"); + } } @Command(identifier = "sellall setdefault", description = "SellAll default values ready to go.", permissions = "prison.admin", onlyPlayers = false) @@ -617,14 +808,14 @@ private void sellAllSetDefaultCommand(CommandSender sender){ if (!isEnabled()) return; - // Setup all the prices in sellall: + // Setup all the prices in sellall: SpigotPlatform platform = (SpigotPlatform) Prison.get().getPlatform(); - for ( SellAllBlockData xMatCost : platform.buildBlockListXMaterial() ) { + for ( SellAllBlockData xMatCost : platform.buildBlockListXMaterial() ) { - // Add blocks to sellall: - sellAllAddCommand( xMatCost.getBlock(), xMatCost.getPrice() ); - } + // Add blocks to sellall: + sellAllAddCommand(sender, xMatCost.getBlock().name(), xMatCost.getPrice() ); + } - Output.get().sendInfo(sender, SpigotPrison.format(messages.getString("Message.SellAllDefaultSuccess"))); + Output.get().sendInfo(sender, messages.getString(MessagesConfig.StringID.spigot_message_sellall_default_values_success)); } -} +} \ No newline at end of file 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 0c891fec2..ca416693a 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 @@ -57,6 +57,8 @@ public interface Compatibility public ItemStack getItemInOffHand(PlayerInventory playerInventory); public void setItemStackInMainHand( SpigotPlayerInventory inventory, SpigotItemStack itemStack ); + + public void setItemInMainHand(Player p, ItemStack itemStack); public void setItemStackInOffHand( SpigotPlayerInventory inventory, SpigotItemStack itemStack ); diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/compat/CompatibilityBlocks.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/compat/CompatibilityBlocks.java index 1e52c4660..17393edfa 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/compat/CompatibilityBlocks.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/compat/CompatibilityBlocks.java @@ -9,6 +9,7 @@ import tech.mcprison.prison.internal.block.PrisonBlock; import tech.mcprison.prison.spigot.block.SpigotItemStack; import tech.mcprison.prison.util.BlockType; +import tech.mcprison.prison.util.Location; public interface CompatibilityBlocks extends CompatibilityPlayer { @@ -23,14 +24,27 @@ public interface CompatibilityBlocks public XMaterial getXMaterial( BlockType blockType ); - public void updateSpigotBlock( BlockType blockType, Block spigotBlock ); + public BlockType getBlockType( ItemStack spigotStack ); - public void updateSpigotBlock( PrisonBlock prisonBlock, Block spigotBlock ); - public BlockType getBlockType( ItemStack spigotStack ); + + public void updateSpigotBlock( BlockType blockType, Block spigotBlock ); + + public void updateSpigotBlock( PrisonBlock prisonBlock, Block spigotBlock ); public void updateSpigotBlock( XMaterial xMat, Block spigotBlock ); + + + public void updateSpigotBlockAsync( PrisonBlock prisonBlock, Location location ); + +// public void updateSpigotBlockAsync( BlockType blockType, Block spigotBlock ); +// +// public void updateSpigotBlockAsync( PrisonBlock prisonBlock, Block spigotBlock ); +// +// public void updateSpigotBlockAsync( XMaterial xMat, Block spigotBlock ); + + public BlockTestStats testCountAllBlockTypes(); diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/compat/CompatibilityCache.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/compat/CompatibilityCache.java index fc10cebc5..76973803a 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/compat/CompatibilityCache.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/compat/CompatibilityCache.java @@ -9,6 +9,7 @@ import com.cryptomorin.xseries.XMaterial; import tech.mcprison.prison.internal.block.PrisonBlock; +import tech.mcprison.prison.spigot.SpigotPrison; import tech.mcprison.prison.util.BlockType; /** @@ -30,6 +31,9 @@ public class CompatibilityCache { private Map xMaterialCache; + private final SpigotPrison plugin; + + public CompatibilityCache() { super(); @@ -37,6 +41,8 @@ public CompatibilityCache() { this.xMaterialCache = new TreeMap<>(); initializeForcedCache(); + + this.plugin = SpigotPrison.getInstance(); } /** @@ -144,5 +150,9 @@ public void putCachedXMaterial( BlockType blockType, byte data, XMaterial xMat ) xMaterialCache.put( key, xMat == null ? NULL_TOKEN : xMat ); } } + + public SpigotPrison getPlugin() { + return plugin; + } } diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/compat/Spigot110.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/compat/Spigot110.java deleted file mode 100644 index f08aba417..000000000 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/compat/Spigot110.java +++ /dev/null @@ -1,17 +0,0 @@ -package tech.mcprison.prison.spigot.compat; - -/** - * Important note: Spigot 1.10 support is represented in Spigot110 and is - * identical to Spigot19 except for two spigot 1.10 functions: sendTitle() - * and sendActionBar(). Therefore, all that needs to be done is to have - * the class Spigot110Player extend Spigot19 and then Override - * those two functons. - * - */ -public class Spigot110 - extends Spigot110Player - implements Compatibility { - - - -} diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/compat/Spigot110Player.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/compat/Spigot110Player.java deleted file mode 100644 index 0062bcca9..000000000 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/compat/Spigot110Player.java +++ /dev/null @@ -1,23 +0,0 @@ -package tech.mcprison.prison.spigot.compat; - -import org.bukkit.entity.Player; - -import net.md_5.bungee.api.ChatMessageType; -import net.md_5.bungee.api.chat.TextComponent; - -public abstract class Spigot110Player - extends Spigot19 -{ - @Override - public void sendTitle( Player player, String title, String subtitle, int fadeIn, int stay, int fadeOut ) { - player.sendTitle( title, subtitle, fadeIn, stay, fadeOut ); - } - - @Override - public void sendActionBar( Player player, String actionBar ) { - player.spigot().sendMessage( ChatMessageType.ACTION_BAR, - new TextComponent( actionBar ) ); - -// player.sendTitle( null, actionBar ); - } -} diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/compat/Spigot113.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/compat/Spigot113.java index 9fa5562de..50b260f85 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/compat/Spigot113.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/compat/Spigot113.java @@ -71,6 +71,11 @@ public void setItemStackInMainHand( SpigotPlayerInventory inventory, SpigotItemS ((org.bukkit.inventory.PlayerInventory) inventory.getWrapper()) .setItemInMainHand( itemStack.getBukkitStack() ); } + + @Override + public void setItemInMainHand(Player p, ItemStack itemStack){ + p.getInventory().setItemInMainHand(itemStack); + } @Override public void setItemStackInOffHand( SpigotPlayerInventory inventory, SpigotItemStack itemStack ) { diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/compat/Spigot113Blocks.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/compat/Spigot113Blocks.java index dec668754..8492a4bb4 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/compat/Spigot113Blocks.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/compat/Spigot113Blocks.java @@ -7,6 +7,7 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.Damageable; import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.scheduler.BukkitRunnable; import com.cryptomorin.xseries.XMaterial; @@ -14,11 +15,13 @@ import tech.mcprison.prison.internal.block.PrisonBlock; import tech.mcprison.prison.internal.block.PrisonBlockTypes.InternalBlockTypes; import tech.mcprison.prison.output.Output; +import tech.mcprison.prison.spigot.block.SpigotBlock; import tech.mcprison.prison.spigot.block.SpigotItemStack; import tech.mcprison.prison.util.BlockType; +import tech.mcprison.prison.util.Location; public abstract class Spigot113Blocks - extends Spigot110Player + extends Spigot19Player implements CompatibilityBlocks { @Override @@ -84,11 +87,14 @@ public XMaterial getXMaterial( Block spigotBlock ) { results = getCachedXMaterial( spigotBlock, NO_DATA_VALUE ); if ( results == null ) { - results = XMaterial.matchXMaterial( spigotBlock.getType() ); + results = XMaterial.matchXMaterial( spigotBlock.getType() ); - putCachedXMaterial( spigotBlock, NO_DATA_VALUE, results ); + if ( results == null ) { + results = XMaterial.matchXMaterial( spigotBlock.getType().name() ).orElse( null ); + } if ( results == null ) { + Output.get().logWarn( "Spigot113Blocks.getXMaterial() : " + "Spigot block cannot be mapped to a XMaterial : " + spigotBlock.getType().name() + @@ -96,6 +102,11 @@ public XMaterial getXMaterial( Block spigotBlock ) { spigotBlock.getType().name())); } + + if ( results != null ) { + + putCachedXMaterial( spigotBlock, NO_DATA_VALUE, results ); + } } } @@ -210,6 +221,94 @@ public void updateSpigotBlock( XMaterial xMat, Block spigotBlock ) { } } + +// @Override +// public void updateSpigotBlockAsync( BlockType blockType, Block spigotBlock ) { +// +// if ( blockType != null && blockType != BlockType.IGNORE && spigotBlock != null ) { +// +// XMaterial xMat = getXMaterial( blockType ); +// +// updateSpigotBlockAsync( xMat, spigotBlock ); +// } +// } +// +// +// @Override +// public void updateSpigotBlockAsync( PrisonBlock prisonBlock, Block spigotBlock ) { +// +// if ( prisonBlock != null && +// !prisonBlock.getBlockName().equalsIgnoreCase( InternalBlockTypes.IGNORE.name() ) && +// spigotBlock != null ) { +// +// XMaterial xMat = getXMaterial( prisonBlock ); +// +// if ( xMat != null ) { +// +// updateSpigotBlockAsync( xMat, spigotBlock ); +// } +// } +// } +// +// +// @Override +// public void updateSpigotBlockAsync( XMaterial xMat, Block spigotBlock ) { +// +// if ( xMat != null ) { +// Material newType = xMat.parseMaterial(); +// if ( newType != null ) { +// +// new BukkitRunnable() { +// @Override +// public void run() { +// +// // No physics update: +// spigotBlock.setType( newType, false ); +// } +// }.runTaskLater( getPlugin(), 0 ); +// +// } +// } +// } + + /** + *

This function both get's the block and then updates it within + * the same runnable transaction. This should eliminate the need to + * risk reading the block in an async thread, and improve performance. + *

+ * + * @param prisonBlock + * @param location + */ + @Override + public void updateSpigotBlockAsync( PrisonBlock prisonBlock, Location location ) { + + XMaterial xMat = getXMaterial( prisonBlock ); + + if ( xMat != null && location != null ) { + Material newType = xMat.parseMaterial(); + if ( newType != null ) { + + new BukkitRunnable() { + @Override + public void run() { + + // No physics update: + Block spigotBlock = ((SpigotBlock) location.getBlockAt()).getWrapper(); + + // For 1.13.x and higher: + spigotBlock.setType( newType, false ); + + } + }.runTaskLater( getPlugin(), 0 ); + + } + + } + } + + + /** *

This function is supposed to find all possible blocks available * on the server. The number of available items, and blocks, will vary based diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/compat/Spigot18.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/compat/Spigot18.java index 4061d664e..c22439a8b 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/compat/Spigot18.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/compat/Spigot18.java @@ -93,7 +93,13 @@ public void setItemStackInMainHand( SpigotPlayerInventory inventory, SpigotItemS ((org.bukkit.inventory.PlayerInventory) inventory.getWrapper()) .setItemInHand( itemStack.getBukkitStack() ); } - + + @SuppressWarnings("deprecation") + @Override + public void setItemInMainHand(Player p, ItemStack itemStack) { + p.getInventory().setItemInHand(itemStack); + } + /** * Spigot v1.8 does not have an off hand, so set it to main hand. */ diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/compat/Spigot18Blocks.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/compat/Spigot18Blocks.java index 0d5d9b90f..e71862590 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/compat/Spigot18Blocks.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/compat/Spigot18Blocks.java @@ -4,6 +4,7 @@ import org.bukkit.block.Block; import org.bukkit.block.BlockState; import org.bukkit.inventory.ItemStack; +import org.bukkit.scheduler.BukkitRunnable; import com.cryptomorin.xseries.XMaterial; @@ -11,8 +12,10 @@ import tech.mcprison.prison.internal.block.PrisonBlock; import tech.mcprison.prison.output.Output; import tech.mcprison.prison.spigot.SpigotPrison; +import tech.mcprison.prison.spigot.block.SpigotBlock; import tech.mcprison.prison.spigot.block.SpigotItemStack; import tech.mcprison.prison.util.BlockType; +import tech.mcprison.prison.util.Location; public abstract class Spigot18Blocks extends Spigot18Player @@ -262,6 +265,11 @@ public XMaterial getXMaterial( PrisonBlock prisonBlock ) { results = XMaterial.matchXMaterial( blockName ).orElse( null ); + if ( results == XMaterial.MELON_SLICE && + prisonBlock.getBlockName().equalsIgnoreCase( "melon" ) ) { + results = XMaterial.MELON; + } + putCachedXMaterial( prisonBlock, results ); } } @@ -386,7 +394,15 @@ public void updateSpigotBlock( PrisonBlock prisonBlock, Block spigotBlock ) { public void updateSpigotBlock( XMaterial xMat, Block spigotBlock ) { if ( xMat != null ) { + +// XBlock.setType( spigotBlock, xMat ); +// +// BlockState bState = spigotBlock.getState(); +// // Force the update but don't apply the physics: +// bState.update( true, false ); + Material newType = xMat.parseMaterial(); + if ( newType != null ) { BlockState bState = spigotBlock.getState(); @@ -403,6 +419,116 @@ public void updateSpigotBlock( XMaterial xMat, Block spigotBlock ) { } + + +// @Override +// public void updateSpigotBlockAsync( BlockType blockType, Block spigotBlock ) { +// +// if ( blockType != null && blockType != BlockType.IGNORE && spigotBlock != null ) { +// +// XMaterial xMat = getXMaterial( blockType ); +// +// if ( xMat != null ) { +// +// updateSpigotBlockAsync( xMat, spigotBlock ); +// } +// } +// } +// +// +// @Override +// public void updateSpigotBlockAsync( PrisonBlock prisonBlock, Block spigotBlock ) { +// +// if ( prisonBlock != null && +// !prisonBlock.equals( PrisonBlock.IGNORE ) && +// spigotBlock != null ) { +// +// XMaterial xMat = getXMaterial( prisonBlock ); +// +// if ( xMat != null ) { +// +// updateSpigotBlockAsync( xMat, spigotBlock ); +// } +// } +// } +// +// +// @SuppressWarnings( "deprecation" ) +// @Override +// public void updateSpigotBlockAsync( XMaterial xMat, Block spigotBlock ) { +// +// if ( xMat != null ) { +// Material newType = xMat.parseMaterial(); +// if ( newType != null ) { +// +// new BukkitRunnable() { +// @Override +// public void run() { +// +// BlockState bState = spigotBlock.getState(); +// +// // Set the block state with the new type and rawData: +// bState.setType( newType ); +// bState.setRawData( xMat.getData() ); +// +// // Force the update but don't apply the physics: +// bState.update( true, false ); +// } +// }.runTaskLater( getPlugin(), 0 ); +// +// } +// } +// } + + + /** + *

This function both get's the block and then updates it within + * the same runnable transaction. This should eliminate the need to + * risk reading the block in an async thread, and improve performance. + *

+ * + * @param prisonBlock + * @param location + */ + @Override + public void updateSpigotBlockAsync( PrisonBlock prisonBlock, Location location ) { + + XMaterial xMat = getXMaterial( prisonBlock ); + + if ( xMat != null && location != null ) { + Material newType = xMat.parseMaterial(); + if ( newType != null ) { + + new BukkitRunnable() { + @SuppressWarnings( "deprecation" ) + @Override + public void run() { + + // No physics update: + Block spigotBlock = ((SpigotBlock) location.getBlockAt()).getWrapper(); + + // For 1.13.x and higher: + // spigotblock.setType( newType, false ); + + + // No physics update: + BlockState bState = spigotBlock.getState(); + + // Set the block state with the new type and rawData: + bState.setType( newType ); + bState.setRawData( xMat.getData() ); + + // Force the update but don't apply the physics: + bState.update( true, false ); + + } + }.runTaskLater( getPlugin(), 0 ); + + } + + } + } + /** *

This function is supposed to find all possible blocks available diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/compat/Spigot18Player.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/compat/Spigot18Player.java index bfd4e9896..32de7241f 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/compat/Spigot18Player.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/compat/Spigot18Player.java @@ -2,6 +2,11 @@ import org.bukkit.entity.Player; +import com.cryptomorin.xseries.messages.ActionBar; +import com.cryptomorin.xseries.messages.Titles; + +import tech.mcprison.prison.util.Text; + public abstract class Spigot18Player extends CompatibilityCache implements CompatibilityPlayer @@ -37,9 +42,14 @@ public void setMaxHealth( Player player, double maxHealth ) { * @param fadeOut - parameter ignored */ @Override - @SuppressWarnings( "deprecation" ) public void sendTitle( Player player, String title, String subtitle, int fadeIn, int stay, int fadeOut ) { - player.sendTitle( title, subtitle ); + //player.sendTitle( title, subtitle ); + + title = title == null ? null : Text.translateAmpColorCodes( title ); + subtitle = subtitle == null ? null : Text.translateAmpColorCodes( subtitle ); + + Titles.sendTitle( player, fadeIn, stay, fadeOut, title, subtitle ); + } /** @@ -50,11 +60,14 @@ public void sendTitle( Player player, String title, String subtitle, int fadeIn, * @param player * @param actionBar */ - @SuppressWarnings( "deprecation" ) @Override public void sendActionBar( Player player, String actionBar ) { - player.sendTitle( "", actionBar ); + String message = Text.translateAmpColorCodes( actionBar ); + ActionBar.sendActionBar( player, message ); + + // Was using the following until it was replaced with XSeries' ActionBar: +// player.sendTitle( "", actionBar ); // The following class does not exist under spigot 1.8.8 // player.spigot().sendMessage( ChatMessageType.ACTION_BAR, diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/compat/Spigot19.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/compat/Spigot19.java index efc6757fe..018c72b46 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/compat/Spigot19.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/compat/Spigot19.java @@ -94,7 +94,12 @@ public void setItemStackInMainHand( SpigotPlayerInventory inventory, SpigotItemS ((org.bukkit.inventory.PlayerInventory) inventory.getWrapper()) .setItemInMainHand( itemStack.getBukkitStack() ); } - + + @Override + public void setItemInMainHand(Player p, ItemStack itemStack) { + p.getInventory().setItemInMainHand(itemStack); + } + @Override public void setItemStackInOffHand( SpigotPlayerInventory inventory, SpigotItemStack itemStack ) { diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/compat/Spigot19Player.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/compat/Spigot19Player.java index 52fbdfe59..370aa8045 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/compat/Spigot19Player.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/compat/Spigot19Player.java @@ -4,8 +4,10 @@ import org.bukkit.attribute.AttributeInstance; import org.bukkit.entity.Player; -import net.md_5.bungee.api.ChatMessageType; -import net.md_5.bungee.api.chat.TextComponent; +import com.cryptomorin.xseries.messages.ActionBar; +import com.cryptomorin.xseries.messages.Titles; + +import tech.mcprison.prison.util.Text; public abstract class Spigot19Player extends Spigot18Blocks @@ -35,15 +37,25 @@ public double getMaxHealth( Player player ) { } @Override - @SuppressWarnings( "deprecation" ) + //@SuppressWarnings( "deprecation" ) public void sendTitle( Player player, String title, String subtitle, int fadeIn, int stay, int fadeOut ) { - player.sendTitle( title, subtitle ); + + title = title == null ? null : Text.translateAmpColorCodes( title ); + subtitle = subtitle == null ? null : Text.translateAmpColorCodes( subtitle ); + + Titles.sendTitle( player, fadeIn, stay, fadeOut, title, subtitle ); + } @Override public void sendActionBar( Player player, String actionBar ) { - player.spigot().sendMessage( ChatMessageType.ACTION_BAR, - new TextComponent( actionBar ) ); + + String message = Text.translateAmpColorCodes( actionBar ); + ActionBar.sendActionBar( player, message ); + + // Was using the following until it was replaced with XSeries' ActionBar: +// player.spigot().sendMessage( ChatMessageType.ACTION_BAR, +// new TextComponent( actionBar ) ); // player.sendTitle( "", actionBar ); } diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/compat/SpigotCompatibility.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/compat/SpigotCompatibility.java index c6824ed01..60381bd77 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/compat/SpigotCompatibility.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/compat/SpigotCompatibility.java @@ -37,14 +37,14 @@ private static synchronized void setup() { results = new Spigot18(); } - else if ( svData.compareTo( new BluesSemanticVersionData( "1.10.0" ) ) < 0 ) { - - results = new Spigot19(); - } else if ( svData.compareTo( new BluesSemanticVersionData( "1.13.0" ) ) < 0 ) { - results = new Spigot110(); + results = new Spigot19(); } +// else if ( svData.compareTo( new BluesSemanticVersionData( "1.13.0" ) ) < 0 ) { +// +// results = new Spigot110(); +// } else { results = new Spigot113(); 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 b1ad26237..4b0beb1d3 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 @@ -40,17 +40,98 @@ public void initialize() { List lore = new ArrayList<>(); lore.add(" "); lore.add("&8-----------------------"); + lore.add("&3Ladder: &a{ladderName}"); + lore.add("&3Mines: &a{linkedMines}"); lore.add(" "); - lore.add("&8&l|&3Info&8|"); lore.add("&3Rank Price: &a${rankPrice}"); lore.add(" "); + lore.add("&7Players: &3%prison_rank__player_count_{rankName}%"); + lore.add("&8-----------------------"); + lore.add("&7Total Cost: &3%prison_rank__player_cost_formatted_{rankName}%"); + lore.add("&7Multiplier: &3{rankMultiplier}"); + lore.add("&7Balance: &3%prison_player_balance_default%"); + lore.add("&7Remaining: &3%prison_rank__player_cost_remaining_formatted_{rankName}%"); + lore.add("%prison_rank__player_cost_bar_{rankName}%"); lore.add("&8-----------------------"); - lore.add("%prison_rcb_default%"); conf.set("EditableLore.Ranks", lore); changeCount++; } + if ( conf.getList( "EditableLore.README" ) == null ) { + List lore = new ArrayList<>(); + lore.add(" "); + lore.add("&8-----------------------"); + lore.add("&7 WARNING!! DO NOT EDIT THESE!!"); + lore.add("&7 THESE ARE JUST INFORMATIONAL NOTES AND WILL BE IGNORED BY PRISON."); + lore.add("&8-----------------------"); + lore.add("&7 There are three types of placeholders that will work with EditableLore:"); + lore.add("&7 1. GUI placeholders"); + lore.add("&7 2. '/prison placeholders list'"); + lore.add("&7 3. Any other placeholder through PlaceholderAPI"); + lore.add("&8-----------------------"); + lore.add("&7GUI Placeholders are only the following and they are evaluated first "); + lore.add("&7so they can be nested in the prison placeholders: "); + lore.add("&7 {rankName} {rankTag} {rankPrice} {rankMultiplier} {ladderName} {linkedMines}"); + lore.add("&7 Not yet available: {mineName} {mineTag} "); + lore.add("&8-----------------------"); + lore.add("&7Prison placeholders can include any that are within these placeholder "); + lore.add("&7Groups: PLAYER, RANKS, RANKPLAYERS, MINES, STATSMINES, and STATSRANKS"); + lore.add("&8-----------------------"); + lore.add("&7To use dyanamic placeholders, you need to use a combination of these two"); + lore.add("&7types of placeholders. You use the GUI placeholders to inject the rank"); + lore.add("&7name, or mine name, in to the prison placeholders. When injecting the "); + lore.add("&7names, do not use the tags since those will also inject formatting codes"); + lore.add("&7which will corrupt the placeholders."); + lore.add("&7Cost: &3%prison_rank__player_cost_formatted_{rankName}%"); + lore.add("&7Remaining: &3%prison_rank__player_cost_remaining_formatted_{rankName}%"); + lore.add("%prison_rank__player_cost_bar_{rankName}%"); + lore.add("&8-----------------------"); + + + conf.set("EditableLore.README", lore); + changeCount++; + } + + + + if (conf.getList("EditableLore.Rank.default.A") == null){ + List lore = new ArrayList<>(); + lore.add(" "); + lore.add("&8-----------------------"); + lore.add("&3The start of an amazing adventure."); + lore.add("&8-----------------------"); + + conf.set("EditableLore.Rank.default.A", lore); + changeCount++; + } + + if (conf.getList("EditableLore.Rank.default.Z") == null){ + List lore = new ArrayList<>(); + lore.add(" "); + lore.add("&8-----------------------"); + lore.add("&3The end of the most amazing adventure."); + lore.add("&3But... if you do '/prestige' you can start"); + lore.add("&3start over and have even more fun!"); + lore.add("&8-----------------------"); + + conf.set("EditableLore.Rank.default.Z", lore); + changeCount++; + } + + if (conf.getList("EditableLore.Rank.prestiges.p1") == null){ + List lore = new ArrayList<>(); + lore.add(" "); + lore.add("&8-----------------------"); + lore.add("&3This is a very prestigious rank!"); + lore.add("&8-----------------------"); + + conf.set("EditableLore.Rank.prestiges.p1", lore); + changeCount++; + } + + + // Count and save if (changeCount > 0) { try { diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/configs/MessagesConfig.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/configs/MessagesConfig.java index ab85f886d..71174ab27 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/configs/MessagesConfig.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/configs/MessagesConfig.java @@ -1,359 +1,299 @@ package tech.mcprison.prison.spigot.configs; -import java.io.File; -import java.io.IOException; - -import org.bukkit.configuration.file.FileConfiguration; -import org.bukkit.configuration.file.YamlConfiguration; - -import tech.mcprison.prison.output.Output; import tech.mcprison.prison.spigot.SpigotPrison; -/** - * @author GABRYCA - **/ -public class MessagesConfig extends SpigotConfigComponents{ +import java.io.*; +import java.util.Properties; - // Initialize parameters and variables - private FileConfiguration conf; - private int changeCount = 0; - - public MessagesConfig() { - initialize(); - } +public class MessagesConfig { - public void initialize() { + private static MessagesConfig instance; + private Properties properties = new Properties(); + private final String defaultLanguage = SpigotPrison.getInstance().getConfig().getString("default-language"); + private final String path = "/module_conf/spigot/lang/"; - // Filepath - File file = new File(SpigotPrison.getInstance().getDataFolder() + "/module_conf/lang/" + SpigotPrison.getInstance().getConfig().getString("default-language") + ".yml"); + /** + * Get MessagesConfig class and initialize it if necessary. + * */ + public static MessagesConfig get(){ + if (instance == null){ + instance = new MessagesConfig(); + instance.initConfig(); + } + return instance; + } - // Check if the config exists - fileMaker(file); + /** + * Initialize the config, reading and caching data. + * */ + private void initConfig(){ + try(FileInputStream data = new FileInputStream(SpigotPrison.getInstance().getDataFolder() + path + defaultLanguage + ".properties")){ - // Get the config - conf = YamlConfiguration.loadConfiguration(file); - - // Call method - values(); + Properties temp = new Properties(); + temp.load(new InputStreamReader(data)); + properties = temp; - if (changeCount > 0) { - try { - conf.save(file); - Output.get().logInfo("&aThere were &b%d &anew values added for the language files " + "used by the GuiConfig.yml file located at &b%s", changeCount, file.getAbsoluteFile()); - } - catch (IOException e) { - Output.get().logInfo("&4Failed to save &b%d &4new values for the language files " + "used by the GuiConfig.yml file located at &b%s&4. " + "&a %s", changeCount, file.getAbsoluteFile(), e.getMessage()); - } + } catch (IOException ex){ + ex.printStackTrace(); } - - conf = YamlConfiguration.loadConfiguration(file); } - private void dataConfig(String key, String value){ - if (conf.get(key) == null) { - conf.set(key, value); - changeCount++; - } + /** + * Get String. + * */ + public String getString(StringID message){ + + String msg = properties.getProperty(message.toString()); + + if ( msg == null || msg.trim().isEmpty() ) { + msg = message.name(); + } + + return msg; } - private void dataConfig(String key, boolean value){ - if (conf.get(key) == null) { - conf.set(key, value); - changeCount++; - } + public void reload(){ + initConfig(); } - // All the strings should be here - private void values(){ - dataConfig("Lore.ActivateWithinMode","&8Activate Within mode."); - dataConfig("Lore.ActivateRadiusMode","&8Activate Radius mode."); - dataConfig("Lore.AutoPickupGuiManager","&8AutoPickup Manager."); - dataConfig("Lore.AutoSmeltGuiManager","&8AutoSmelt Manager."); - dataConfig("Lore.AutoBlockGuiManager","&8AutoBlock Manager."); - dataConfig("Lore.BlockType","&3BlockType: "); - dataConfig("Lore.Blocks","&3Blocks:"); - dataConfig("Lore.Blocks2","&8Manage blocks of the Mine."); - dataConfig("Lore.BackpackID", "&3Backpack ID: "); - dataConfig("Lore.ClickToAddBackpack", "&8Click to add backpack."); - dataConfig("Lore.ClickToAddBackpackInst0", "&3Instructions: "); - dataConfig("Lore.ClickToAddBackpackInst1", "&8Remember to add an item"); - dataConfig("Lore.ClickToAddBackpackInst2", "&8Inside the backpack to"); - dataConfig("Lore.ClickToAddBackpackInst3", "&8Save it"); - dataConfig("Lore.ClickToChoose","&8Click to choose."); - dataConfig("Lore.ClickToConfirm","&8Click to confirm."); - dataConfig("Lore.ClickToCancel","&8Click to cancel."); - dataConfig("Lore.ClickToDecrease","&8Click to decrease."); - dataConfig("Lore.ClickToIncrease","&8Click to increase."); - dataConfig("Lore.ClickToManageRank","&8Manage this rank."); - dataConfig("Lore.ClickToManageCommands","&8Manage RankUPCommands."); - dataConfig("Lore.ClickToOpen","&8Click to open."); - dataConfig("Lore.ClickToOpenBackpack", "&8Click to open Prison Backpack."); - dataConfig("Lore.ClickToRename", "&8Click to rename."); - dataConfig("Lore.ClickToTeleport","&8Click to teleport."); - dataConfig("Lore.ClickToUse","&8Click to use."); - dataConfig("Lore.ClickToRankup","&8Click to rankup"); - dataConfig("Lore.ClickToEditBlock", "&8Click to edit percentage."); - dataConfig("Lore.ClickToEdit", "&8Click to edit."); - dataConfig("Lore.ClickToClose", "&8Click to close the GUI."); - dataConfig("Lore.ClickToPriorPage", "&aClick to see the prior page."); - dataConfig("Lore.ClickToNextPage", "&aClick to see the next page."); - dataConfig("Lore.ClickToStartBlockSetup", "&aClick to setup block."); - dataConfig("Lore.ClickToSelect", "&7Click to select."); - dataConfig("Lore.ClickToAddBlock", "&aClick to add a block."); - dataConfig("Lore.ClickToEnable", "&aClick to enable."); - dataConfig("Lore.ClickToDisable", "&cClick to disable."); - dataConfig("Lore.Chance","&3Chance: "); - dataConfig("Lore.Command","&3Command: &7"); - dataConfig("Lore.ContainsTheRank","&3The Rank "); - dataConfig("Lore.ContainsNoCommands"," &3contains no commands."); - dataConfig("Lore.DelaySellAll", "&3Delay: &8"); - dataConfig("Lore.DisableNotifications","&8Disable notifications."); - dataConfig("Lore.DisabledAll","&3All features &cOFF&3."); - dataConfig("Lore.EnabledAll","&aAll features ON"); - dataConfig("Lore.EmptyMultiplier", "&c[!] There aren't multipliers!"); - dataConfig("Lore.FullSoundEnabled","&aFull Inv., notify with sound ON"); - dataConfig("Lore.FullSoundDisabled","&cFull Inv., notify with sound OFF"); - dataConfig("Lore.FullHologramEnabled","&aFull Inv., notify with hologram ON"); - dataConfig("Lore.FullHologramDisabled","&cFull Inv., notify with hologram OFF"); - dataConfig("Lore.Id","&3Rank id: &7"); - dataConfig("Lore.Info","&8&l|&3Info&8|"); - dataConfig("Lore.IfYouHaveEnoughMoney","&8If you have enough money"); - dataConfig("Lore.LadderThereAre","&8There're &3"); - dataConfig("Lore.LadderCommands"," &3Commands at ladder:"); - dataConfig("Lore.LeftClickToConfirm","&aLeft-Click to confirm."); - dataConfig("Lore.LeftClickToOpen","&8Left Click to open."); - dataConfig("Lore.LeftClickToReset","&aLeft Click to reset"); - dataConfig("Lore.LeftClickToEdit", "&aLeft-Click to edit value"); - dataConfig("Lore.ManageResetTime","&8Manage the reset time of Mine."); - dataConfig("Lore.MinesButton","&3Mines GUI manager."); - dataConfig("Lore.MineName", "&3Mine Name: &f"); - dataConfig("Lore.Multiplier", "&3Multiplier: &f"); - dataConfig("Lore.Name","&3Rank Name: &7"); - dataConfig("Lore.Notifications","&8Edit Mines notifications."); - dataConfig("Lore.Permission", "&3Permission: "); - dataConfig("Lore.PlayerOwner", "&3Backpack owner: "); - dataConfig("Lore.PlayersWithTheRank","&3Players at rank: &7"); - dataConfig("Lore.PrestigeWarning", "&3Prestige will reset: "); - dataConfig("Lore.PrestigeWarning2", "&3 - &bRank"); - dataConfig("Lore.PrestigeWarning3", "&3 - &bBalance"); - dataConfig("Lore.PrestigeName", "&8Prestige name: &3"); - dataConfig("Lore.PrestigeMultiplier", "&8Multiplier: &3"); - dataConfig("Lore.PrestigeMultiplierInfoGUI", "&3Manage multipliers."); - dataConfig("Lore.Price","&3Price: &a$"); - dataConfig("Lore.Price2","&8Price: &a$"); - dataConfig("Lore.Price3","&3Rank Price: &a$"); - dataConfig("Lore.Percentage", "&8Percentage: "); - dataConfig("Lore.PrisonTasksButton","&3Prison Tasks Manager."); - dataConfig("Lore.ResetTime","&3Reset time(s): &7"); - dataConfig("Lore.Radius","&8Radius: "); - dataConfig("Lore.RankupCommands","&8&l|&3RankUPCommands&8| &8&l- &3"); - dataConfig("Lore.Rankup","&aRankup"); - dataConfig("Lore.RanksButton","&3Ranks GUI manager."); - dataConfig("Lore.ResetButton","&8Resets the mine."); - dataConfig("Lore.RightClickToCancel","&cRight-Click to cancel."); - dataConfig("Lore.RightClickToEnable","&cRight-Click to &aenable&c."); - dataConfig("Lore.RightClickToDisable", "&cRight-Click to disable."); - dataConfig("Lore.RightClickToToggle","&3Right click to toggle."); - dataConfig("Lore.RightClickToDelete", "&cRight-Click to delete."); - dataConfig("Lore.RightClickToEdit", "&8Right click to edit."); - dataConfig("Lore.SpawnPoint","&3Spawnpoint: &7"); - dataConfig("Lore.StatusLockedMine","&8Status: &cLocked"); - dataConfig("Lore.StatusUnlockedMine","&8Status: &aUnlocked"); - dataConfig("Lore.SpawnPoint2","&8Set the mine spawn point."); - dataConfig("Lore.SizeOfMine","&3Size of Mine: &7"); - dataConfig("Lore.Selected","&3Selected"); - dataConfig("Lore.ShowItem", "&3Show Item: &7"); - dataConfig("Lore.ShowItemDescription", "&7This's the item"); - dataConfig("Lore.ShowItemDescription2", "&7Shown in the Player's GUI"); - dataConfig("Lore.ShowItemDescription3", "&7Or /mines GUI."); - dataConfig("Lore.SellAllDelayInfo", "&8Short delay before using again"); - dataConfig("Lore.SellAllDelayInfo2", "&8the &3/sellall sell &8command."); - dataConfig("Lore.SellAllCurrencyInfo", "&3Edit SellAll Currency."); - dataConfig("Lore.SellAllActiveCurrency", "&3Currency: &a"); - dataConfig("Lore.ShiftAndRightClickToDelete","&cShift + Right click to delete."); - dataConfig("Lore.ShiftAndRightClickToDisable","&cShift + Right click to disable"); - dataConfig("Lore.ShiftAndRightClickToToggle","&cShift + Right click to toggle"); - dataConfig("Lore.StatusEnabled","&8Enabled"); - dataConfig("Lore.StatusDisabled","&8Disabled"); - dataConfig("Lore.SkipReset1","&8Skip the reset if "); - dataConfig("Lore.SkipReset2","&8not enough blocks "); - dataConfig("Lore.SkipReset3","&8have been mined."); - dataConfig("Lore.Tp","&8Tp to the mine."); - dataConfig("Lore.Tag","&3Tag: &8"); - dataConfig("Lore.Tag2","&3Rank Tag: &7"); - dataConfig("Lore.Time","&8Time: "); - dataConfig("Lore.Volume","&3Volume: &7"); - dataConfig("Lore.Value", "&3Value: &a$"); - dataConfig("Lore.World","&3World: &7"); - dataConfig("Lore.noRanksFoundSetup", "&3There aren't Ranks!"); - dataConfig("Lore.noRanksFoundSetup2", "&3If you want continue the setup."); - dataConfig("Lore.noRanksFoundSetup3", "&3All Ranks and Mines from A to Z will be made"); - dataConfig("Lore.noRanksFoundSetup4", "&3With &adefault &3values!"); - dataConfig("Lore.noRanksFoundSetup5", "&3You can do the same by command:"); - dataConfig("Lore.noRanksFoundSetup6", "&1/ranks autoConfigure full !"); - dataConfig("Lore.noRanksFoundSetup7", "&3Please replace the X with the starting price and"); - dataConfig("Lore.noRanksFoundSetup8", "&3multiplier, default price = 50000, multiplier = 1.5."); - dataConfig("Lore.ZeroBlocksReset1","&8Set a mine's delay "); - dataConfig("Lore.ZeroBlocksReset2","&8before reset when it "); - dataConfig("Lore.ZeroBlocksReset3","&8reaches zero blocks."); - dataConfig("Message.BackPackIsDisabled", "Backpacks are disabled in the config.yml, you can't use this!"); - dataConfig("Message.BackPackNeedPlayer", "Please add a playername."); - dataConfig("Message.BackPackDeleteOperationSuccess", "The backpack should've been deleted with success!"); - dataConfig("Message.BackPackDeleteOperationFail", "Can't find the backpack or something went wrong...?"); - dataConfig("Message.BackPackPlayerNotFound", "Player not found."); - dataConfig("Message.BackPackDoNotOwnAny", "Sorry but you don't own any inventory, please use /backpack to make one."); - dataConfig("Message.BackPackOwnLimitReached", "Sorry but you already have the max amount of backpacks allowed for Player!"); - dataConfig("Message.BackPackResizeNotInt", "Backpack's size value isn't a number."); - dataConfig("Message.BackPackResizeNotMultiple9", "Backpack's size must be a multiple of 9 and max 54."); - dataConfig("Message.BackPackResizeDone", "If the Backpack wasn't missing, it got resized with success!"); - dataConfig("Message.BackPackLimitMissingParam", "You're missing some arguments required to set the backpacks limit!"); - dataConfig("Message.BackPackLimitNotNumber", "The Backpacks Limit number isn't a number!"); - dataConfig("Message.BackPackLimitSuccess", "The Backpacks Limit got edited with success!"); - dataConfig("Message.BackPackLimitDecrementFail", "The Backpacks limit decremented of that value would be negative, operation canceled!"); - dataConfig("Message.BackPackListEmpty", "There aren't backpacks in this server."); - dataConfig("Message.BackPackCantOwn", "Sorry but looks like you can't own Backpacks!"); - dataConfig("Message.CantGetRanksAdmin", "Can't get Ranks, there might be &cno ranks&7 or the Ranks module's &cdisabled&7."); - dataConfig("Message.CantRunGUIFromConsole", "You cannot run the GUI from the console."); - dataConfig("Message.CantGiveItemFromConsole", "You can't get an item as the console."); - dataConfig("Message.DefaultLadderEmpty", "The default ladder is &cempty&7."); - dataConfig("Message.NoSellAllItems", "Sorry but &cthere aren't&7 SellAll Items to show."); - dataConfig("Message.EmptyGui", "Sorry, the GUI's &cempty."); - dataConfig("Message.EnableAutoSellToUse", "Sorry, but AutoSell's &cdisabled&7, please enable it!"); - dataConfig("Message.EnableSellDelayToUse", "Sorry, but the SellAll Delay's &cdisabled&7, please enable it!"); - dataConfig("Message.EventCancelled", "&cEvent cancelled."); - dataConfig("Message.InvalidBooleanInput", "Sorry, you should type &a-true-&7 or &c-false-&7 here."); - dataConfig("Message.MissingPermission", "Sorry but you don't have the &cpermission&7 to use that!"); - dataConfig("Message.NoBlocksMine", "Sorry but this Mine's &cempty&7."); - dataConfig("Message.NoMines", "Sorry but &cthere aren't &7Mines to show."); - dataConfig("Message.NoRankupCommands", "Sorry, but there &caren't rankUpCommands&7 for this Rank!"); - dataConfig("Message.NoLadders", "Sorry but &cthere aren't &7ladders to show."); - dataConfig("Message.NoRanksPrestigesLadder", "There &caren't ranks&7 in the -prestiges- ladder!"); - dataConfig("Message.NoRanksFoundAdmin", "Sorry, the Ladder's &cempty&7!"); - dataConfig("Message.NoRanksFound", "Sorry, but this Ladder's &cempty&7!"); - dataConfig("Message.NoRanksFoundHelp1", "Sorry, the Ladder's &cempty&7 or &7["); - dataConfig("Message.NoRanksFoundHelp2", "] &cdoesn't exists!"); - dataConfig("Message.LadderPrestigesNotFound", "Ladder -prestiges- &cnot found&7!"); - dataConfig("Message.TooManyBlocks", "Sorry, but there're &ctoo many&7 Blocks and the max's 54 for the GUI"); - dataConfig("Message.TooManyLadders", "Sorry, but there're &ctoo many&7 Ladders and the max's 54 for the GUI"); - dataConfig("Message.TooManyMines", "Sorry, but there're &ctoo many&7 Mines and the max's 54 for the GUI"); - dataConfig("Message.TooManyRankupCommands", "Sorry, but there're &ctoo many&7 RankupCommands and the max's 54 for the GUI"); - dataConfig("Message.TooManyRanks", "Sorry, but there're &ctoo many&7 Ranks and the max's 54 for the GUI"); - dataConfig("Message.TooManySellAllItems", "There are &ctoo many&7 Items and the MAX for the GUI's 54!"); - dataConfig("Message.mineNameRename", "Please write the &6mineName &7you'd like to use and &6submit&7."); - dataConfig("Message.mineNameRenameClose", "Input &cclose &7to cancel or wait &c30 seconds&7."); - dataConfig("Message.mineNameRenameClosed", "Rename Mine &cclosed&7, nothing got changed!"); - dataConfig("Message.mineOrGuiDisabled", "GUI and/or GUI Mines is &cdisabled&7. Check GuiConfig.yml."); - dataConfig("Message.mineMissingGuiPermission", "You lack the &cpermissions&7 to use GUI Mines"); - dataConfig("Message.MineShowItemEditSuccess", "Mine show item edited with success."); - dataConfig("Message.OutOfTimeNoChanges", "You ran out of time, &cnothing changed&7."); - dataConfig("Message.PrestigeCancelled", "Prestige &ccancelled&7!"); - dataConfig("Message.PrestigeCancelledWrongKeyword", "Prestige &ccancelled&7, you didn't type the word: &aconfirm&7."); - dataConfig("Message.PrestigeRanOutOfTime", "You ran out of time, &cPrestige cancelled&7."); - dataConfig("Message.PrestigesDisabledDefault", "Prestiges are &cdisabled&7 by default, please edit it in your config.yml!"); - dataConfig("Message.ConfirmPrestige", "&aConfirm&7: Type the word &aconfirm&7 to confirm"); - dataConfig("Message.CancelPrestige", "&cCancel&7: Type the word &ccancel&7 to cancel, &cyou've 30 seconds."); - dataConfig("Message.PrestigesAreDisabled", "Prestiges are &cdisabled&7. Check config.yml."); - dataConfig("Message.GuiOrPrestigesDisabled", "GUI and/or GUI Prestiges is &cdisabled&7. Check GuiConfig.yml."); - dataConfig("Message.GuiClosedWithSuccess", "The GUI got closed."); - dataConfig("Message.CantFindPrestiges", "The prestige ladder has &cno prestiges&7!"); - dataConfig("Message.missingGuiPrestigesPermission", "You lack the &cpermissions&7 to use GUI prestiges"); - dataConfig("Message.rankTagRename", "Please write the &6tag &7you'd like to use and &6submit&7."); - dataConfig("Message.rankTagRenameClose", "Input &cclose &7to cancel or wait &c30 seconds&7."); - dataConfig("Message.rankTagRenameClosed", "Rename tag &cclosed&7, nothing got changed!"); - dataConfig("Message.rankGuiDisabledOrAllGuiDisabled", "GUI and/or GUI Ranks is &cdisabled&7. Check GuiConfig.yml (%s %s)"); - dataConfig("Message.rankGuiMissingPermission", "You lack the &cpermissions&7 to use the Ranks GUI."); - dataConfig("Message.SellAllAutoSellEarnedMoney", "You earned with AutoSell: "); - dataConfig("Message.SellAllAutoSellEarnedMoneyCurrency", "$"); - dataConfig("Message.SellAllAutoSellMissingPermission", "You don't have the &cpermission&7 to edit AutoSell."); - dataConfig("Message.SellAllAutoSellEnabled", "Autosell has been &aenabled&7."); - dataConfig("Message.SellAllAutoSellDisabled", "Autosell has been &cdisabled&7."); - dataConfig("Message.SellAllAutoSellAlreadyEnabled", "AutoSell has already been &aenabled&7!"); - dataConfig("Message.SellAllAutoSellAlreadyDisabled", "AutoSell has already been &cdisabled&7!"); - dataConfig("Message.SellAllAutoPerUserToggleableAlreadyEnabled", "AutoSell perUserToggleable's already &aenabled&7!"); - dataConfig("Message.SellAllAutoPerUserToggleableAlreadyDisabled", "AutoSell perUserToggleable's already &cdisabled&7!"); - dataConfig("Message.SellAllAutoPerUserToggleableEnabled", "SellAll PerUserToggleable &aEnabled&7!"); - dataConfig("Message.SellAllAutoPerUserToggleableDisabled", "SellAll PerUserToggleable &cDisabled&7!"); - dataConfig("Message.SellAllCurrencyChat1", "&3Started setup of new currency for SellAll!"); - dataConfig("Message.SellAllCurrencyChat2", "Type &ccancel &7to cancel."); - dataConfig("Message.SellAllCurrencyChat3", "Type &3default &7to set to default currency."); - dataConfig("Message.SellAllCurrencyChat4", "Type the &aCurrency name &7to set the new currency."); - dataConfig("Message.SellAllCurrencyEditedSuccess", "SellAll Currency edited with success!"); - dataConfig("Message.SellAllCurrencyEditCancelled", "SellAll edit currency &ccancelled&7."); - dataConfig("Message.SellAllCurrencyNotFound", "No active economy supports the currency named '%s'."); - dataConfig("Message.SellAllDefaultSuccess", "Default Values added with &asuccess&7!"); - dataConfig("Message.SellAllDefaultMissingPermission", "Sorry but you're missing the &cpermission!"); - dataConfig("Message.SellAllIsDisabled", "Sorry but the SellAll Feature's &cdisabled&7 in the config.yml"); - dataConfig("Message.SellAllEditedWithSuccess", "&7] edited with &asuccess&7!"); - dataConfig("Message.SellAllSubCommandNotFound", "Sub-command &cnot found&7, please use /sellall help for help!"); - dataConfig("Message.SellAllMultipliersAreDisabled", "Multipliers are &cdisabled&7 in the SellAll config!"); - dataConfig("Message.SellAllMultiplierWrongFormat", "&cWrong format&7, please use /sellall multiplier add/delete "); - dataConfig("Message.SellAllMissingPermission", "Sorry, but you don't have the &cpermission&7"); - dataConfig("Message.SellAllMissingPermissionToToggleAutoSell", "Sorry but you're missing the &cpermission&7 to use that! "); - dataConfig("Message.SellAllRanksDisabled", "The Ranks module's &cdisabled&7 or not found!"); - dataConfig("Message.SellAllPrestigeLadderNotFound", "&cCan't find&7 the Prestiges Ladder, they might be &cdisabled&7 in the config.yml!"); - dataConfig("Message.SellAllCantFindPrestigeOrRank", "&cCan't find&7 the Prestige/Rank: "); - dataConfig("Message.SellAllRankNotFoundInPrestigeLadder", "The -prestiges- ladder &cdoesn't contain&7 the Rank: "); - dataConfig("Message.SellAllMultiplierNotANumber", "Sorry but the multiplier &cisn't a number&7!"); - dataConfig("Message.SellAllMultiplierNotNumber2", " Here-> "); - dataConfig("Message.SellAllConfigSaveFail", "Sorry, &csomething went wrong&7 while saving the config!"); - dataConfig("Message.SellAllMultiplierEditSaveSuccess", "Multiplier got added or edited with &asuccess&7!"); - dataConfig("Message.SellAllMultiplierFormat", "Please use this format: /sellall multiplier delete ."); - dataConfig("Message.SellAllCantFindMultiplier", "&cCan't find&7 the Multiplier of the prestige "); - dataConfig("Message.SellAllCantFindMultiplier2", " &7in the sellallconfig.yml"); - dataConfig("Message.SellAllMultiplierDeleteSuccess", "Multiplier &cdeleted&7 with &asuccess&7!"); - dataConfig("Message.SellAllWrongFormatCommand", "&cWrong format&7, use /sellall help for help."); - dataConfig("Message.SellAllPleaseAddItem", "Please &aadd&7 an ITEM_ID [example: /sellall add COAL_ORE ]"); - dataConfig("Message.SellAllAddPrice", "Please &aadd&7 a price or value for the item [example: /sellall add COAL_ORE 100]"); - dataConfig("Message.SellAllWrongID", "Sorry but the &cITEM_ID's wrong&7, please check it!"); - dataConfig("Message.SellAllValueNotNumber", "Sorry but the value &cisn't a number&7!"); - dataConfig("Message.SellAllMissingID", "Please &aadd&7 an ITEM_ID [example: /sellall delete COAL_ORE]"); - dataConfig("Message.SellAllNotFoundStringConfig", " not found in the config or got already &cdeleted&7."); - dataConfig("Message.SellAllNotFoundEdit", " not found in the config!"); - dataConfig("Message.SellAllDeletedSuccess", " &cDeleted&7 with &asuccess&7!"); - dataConfig("Message.SellAllAddSuccess", "] &aadded&7 with &asuccess&7!"); - dataConfig("Message.SellAllAlreadyAdded", " &cgot already added before&7, to edit it please use the /sellall edit command!"); - dataConfig("Message.SellAllCommandEditSuccess", "] &aedited&7 with &asuccess&7!"); - dataConfig("Message.SellAllYouArentPlayer", "You &caren't&a a player"); - dataConfig("Message.SellAllNothingToSell", "You have &cnothing&7 to sell!"); - dataConfig("Message.SellAllYouGotMoney", "You got &a$"); - dataConfig("Message.SellAllGUIDisabled", "Sorry but the GUI's &cdisabled&7 in the SellAllConfig.yml."); - dataConfig("Message.SellAllAutoSell", "Your inventory's full, &aAutoSell activated&7!"); - dataConfig("Message.SellAllSignOnly", "Sorry but you can use SellAll only by touching a sign (or with the ByPass permission)."); - dataConfig("Message.SellAllSignNotify", "Using &aSellAll&7 from a Sign with &asuccess&7!"); - dataConfig("Message.SellAllSignMissingPermission", "Sorry, but you don't have the &cpermission&7 to use this!"); - dataConfig("Message.SellAllEmpty", "&cThere aren't&7 items in the sellall config,\n please add one and/or restart the server!"); - dataConfig("Message.SellAllAutoEnabled", "SellAll-Auto &aenabled &7with &asuccess&7!"); - dataConfig("Message.SellAllAutoDisabled", "SellAll-Auto &cdisabled &7with &asuccess&7!"); - dataConfig("Message.SellAllWaitDelay", "Please &cwait&7 before using this command again!"); - dataConfig("Message.SellAllDelayAlreadyEnabled", "SellAll Delay already &aenabled&7!"); - dataConfig("Message.SellAllDelayAlreadyDisabled", "SellAll Delay already &cdisabled&7!"); - dataConfig("Message.SellAllDelayEnabled", "SellAll Delay &aenabled &7with &asuccess&7!"); - dataConfig("Message.SellAllDelayDisabled", "SellAll Delay &cdisabled &7with &asuccess&7!"); - dataConfig("Message.SellAllDelayEditedWithSuccess", "SellAll Delay edited with &asuccess&7!"); - dataConfig("Message.SellAllDelayNotNumber", "Delay value &cisn't&7 a number!"); - dataConfig("Message.SellAllGUIEmpty", "Sorry but there &caren't&7 Blocks in the SellAll Shop!"); - dataConfig("Message.SellAllGUIEmpty2", "&7[&cTIP&7] &7You can &aadd&7 one using the command /sellall add!"); - dataConfig("Message.SellAllTriggerAlreadyEnabled", "SellAll trigger's already &aenabled&7."); - dataConfig("Message.SellAllTriggerAlreadyDisabled", "SellAll trigger's already &cdisabled&7."); - dataConfig("Message.SellAllTriggerEnabled", "SellAll trigger &aEnabled&7."); - dataConfig("Message.SellAllTriggerDisabled", "SellAll trigger &cDisabled&7."); - dataConfig("Message.SellAllTriggerIsDisabled", "SellAll trigger's &cdisabled&7 in the SellAllConfig.yml."); - dataConfig("Message.SellAllTriggerMissingItem", "Please add a valid Item ID for SellAll Shift+Right Click Trigger."); - dataConfig("Message.SellAllTriggerItemAddSuccess", "SellAll trigger Item added with &asuccess&7!"); - dataConfig("Message.SellAllTriggerItemEditSuccess", "SellAll trigger Item edited with &asuccess&7!"); - dataConfig("Message.SellAllTriggerItemDeleteSuccess", "SellAll trigger Item deleted with &asuccess&7!"); - dataConfig("Message.SellAllTriggerMissingItem", "There isn't an item in the SellAllConfig.yml trigger like that."); - dataConfig("Message.TooLowValue", "&cToo low value."); - dataConfig("Message.TooHighValue", "&cToo high value."); - dataConfig("Message.GUIReloadSuccess", "GUIs reloaded with success!"); - dataConfig("Setup.Message.MissingPermission", "Sorry but you don't have the &cpermission&7 [-prison.setup- or -prison.admin-]!"); - dataConfig("Setup.Message.WrongFormat", "You're &cmissing&7 the last argument -mines- or -ranks-, / setup -mines- or -ranks- !"); - dataConfig("Setup.Message.WelcomeToRanksSetup", "Hi and welcome to the Ranks Setup, please &cwait&7 until it'll be completed!"); - dataConfig("Setup.Message.SuccessRanksSetup", "The Ranks Setup got &acompleted&7 with &asuccess&7 and the Ranks got &aadded&7 to the default ladder, please check the logs if something's missing!"); - dataConfig("Setup.Message.Aborted", "Prison Setup &cCancelled&7."); - } + public enum StringID { + + spigot_gui_lore_click_to_add, + spigot_gui_lore_click_to_add_backpack, + spigot_gui_lore_click_to_cancel, + spigot_gui_lore_click_to_close, + spigot_gui_lore_click_to_confirm, + spigot_gui_lore_click_to_decrease, + spigot_gui_lore_click_to_delete, + spigot_gui_lore_click_to_disable, + spigot_gui_lore_click_to_edit, + spigot_gui_lore_click_to_enable, + spigot_gui_lore_click_to_increase, + spigot_gui_lore_click_to_manage_rank, + spigot_gui_lore_click_to_open, + spigot_gui_lore_click_to_rankup, + spigot_gui_lore_click_to_rename, + spigot_gui_lore_click_to_select, + spigot_gui_lore_click_to_start_block_setup, + spigot_gui_lore_click_to_teleport, + spigot_gui_lore_click_to_use, + + spigot_gui_lore_click_left_to_confirm, + spigot_gui_lore_click_left_to_edit, + spigot_gui_lore_click_left_to_open, + spigot_gui_lore_click_left_to_reset, + + spigot_gui_lore_click_right_to_cancel, + spigot_gui_lore_click_right_to_delete, + spigot_gui_lore_click_right_to_disable, + spigot_gui_lore_click_right_to_enable, + spigot_gui_lore_click_right_to_toggle, + + spigot_gui_lore_click_right_and_shift_to_delete, + spigot_gui_lore_click_right_and_shift_to_disable, + spigot_gui_lore_click_right_and_shift_to_toggle, + + spigot_gui_lore_backpack_id, + spigot_gui_lore_blocks, + spigot_gui_lore_blocktype, + spigot_gui_lore_chance, + spigot_gui_lore_command, + spigot_gui_lore_currency, + spigot_gui_lore_delay, + spigot_gui_lore_id, + spigot_gui_lore_info, + spigot_gui_lore_minename, + spigot_gui_lore_multiplier, + spigot_gui_lore_name, + spigot_gui_lore_owner, + spigot_gui_lore_percentage, + spigot_gui_lore_permission, + spigot_gui_lore_players_at_rank, + spigot_gui_lore_prestige_name, + spigot_gui_lore_price, + spigot_gui_lore_radius, + spigot_gui_lore_rank_tag, + spigot_gui_lore_reset_time, + spigot_gui_lore_show_item, + spigot_gui_lore_size, + spigot_gui_lore_spawnpoint, + spigot_gui_lore_volume, + spigot_gui_lore_value, + spigot_gui_lore_world, + + spigot_gui_lore_disabled, + spigot_gui_lore_enabled, + spigot_gui_lore_locked, + spigot_gui_lore_next_page, + spigot_gui_lore_prior_page, + spigot_gui_lore_rankup, + spigot_gui_lore_selected, + spigot_gui_lore_unlocked, + + spigot_gui_lore_add_backpack_instruction_1, + spigot_gui_lore_add_backpack_instruction_2, + spigot_gui_lore_add_backpack_instruction_3, + spigot_gui_lore_prestige_warning_1, + spigot_gui_lore_prestige_warning_2, + spigot_gui_lore_prestige_warning_3, + spigot_gui_lore_ranks_setup_1, + spigot_gui_lore_ranks_setup_2, + spigot_gui_lore_ranks_setup_3, + spigot_gui_lore_ranks_setup_4, + spigot_gui_lore_ranks_setup_5, + spigot_gui_lore_ranks_setup_6, + spigot_gui_lore_ranks_setup_7, + spigot_gui_lore_ranks_setup_8, + spigot_gui_lore_sellall_delay_use_1, + spigot_gui_lore_sellall_delay_use_2, + spigot_gui_lore_set_mine_delay_instruction_1, + spigot_gui_lore_set_mine_delay_instruction_2, + spigot_gui_lore_set_mine_delay_instruction_3, + spigot_gui_lore_show_item_description_1, + spigot_gui_lore_show_item_description_2, + spigot_gui_lore_show_item_description_3, + spigot_gui_lore_skip_reset_instruction_1, + spigot_gui_lore_skip_reset_instruction_2, + spigot_gui_lore_skip_reset_instruction_3, + + spigot_gui_lore_autofeatures_button_description, + spigot_gui_lore_backpacks_button_description, + spigot_gui_lore_disable_notifications, + spigot_gui_lore_enable_radius_mode, + spigot_gui_lore_enable_within_mode, + spigot_gui_lore_mines_button_description, + spigot_gui_lore_no_multipliers, + spigot_gui_lore_ranks_button_description, + spigot_gui_lore_rankup_if_enough_money, + spigot_gui_lore_sellall_button_description, + spigot_gui_lore_sellall_edit_info, + spigot_gui_lore_tp_to_mine, + + + spigot_message_missing_permission, + spigot_message_chat_event_time_end, + spigot_message_event_cancelled, + spigot_message_command_wrong_format, + spigot_message_console_error, + + spigot_message_ladder_default_empty, + + spigot_message_mines_disabled, + spigot_message_mines_name_chat_1, + spigot_message_mines_name_chat_2, + spigot_message_mines_name_chat_cancelled, + spigot_message_mines_item_show_edit_success, + spigot_message_mines_or_gui_disabled, + + spigot_message_backpack_cant_own, + spigot_message_backpack_delete_error, + spigot_message_backpack_delete_success, + spigot_message_backpack_format_error, + spigot_message_backpack_limit_decrement_fail, + spigot_message_backpack_limit_edit_success, + spigot_message_backpack_limit_not_number, + spigot_message_backpack_limit_reached, + spigot_message_backpack_missing_playername, + spigot_message_backpack_resize_success, + spigot_message_backpack_size_must_be_multiple_of_9, + + spigot_message_prestiges_disabled, + spigot_message_prestiges_empty, + spigot_message_prestiges_or_gui_disabled, + spigot_message_prestiges_confirm, + spigot_message_prestiges_cancel, + spigot_message_prestiges_cancelled, + spigot_message_prestiges_cancelled_wrong_keyword, + + spigot_message_ranks_disabled, + spigot_message_ranks_or_gui_disabled, + spigot_message_ranks_tag_chat_rename_1, + spigot_message_ranks_tag_chat_rename_2, + spigot_message_ranks_tag_chat_cancelled, + + spigot_message_ladders_disabled, + spigot_message_ladders_or_gui_disabled, + + spigot_message_sellall_auto_already_enabled, + spigot_message_sellall_auto_already_disabled, + spigot_message_sellall_auto_disabled, + spigot_message_sellall_auto_disabled_cant_use, + spigot_message_sellall_auto_enabled, + spigot_message_sellall_auto_perusertoggleable_enabled, + spigot_message_sellall_auto_perusertoggleable_disabled, + spigot_message_sellall_auto_perusertoggleable_already_enabled, + spigot_message_sellall_auto_perusertoggleable_already_disabled, + spigot_message_sellall_boolean_input_invalid, + spigot_message_sellall_cant_find_item_config, + spigot_message_sellall_currency_chat_1, + spigot_message_sellall_currency_chat_2, + spigot_message_sellall_currency_chat_3, + spigot_message_sellall_currency_chat_4, + spigot_message_sellall_currency_edit_success, + spigot_message_sellall_currency_not_found, + spigot_message_sellall_hand_disabled, + spigot_message_sellall_hand_enabled, + spigot_message_sellall_hand_is_disabled, + spigot_message_sellall_item_add_success, + spigot_message_sellall_item_already_added, + spigot_message_sellall_item_delete_success, + spigot_message_sellall_item_edit_success, + spigot_message_sellall_item_id_not_found, + spigot_message_sellall_item_missing_name, + spigot_message_sellall_item_missing_price, + spigot_message_sellall_item_not_found, + spigot_message_sellall_default_values_success, + spigot_message_sellall_delay_already_enabled, + spigot_message_sellall_delay_already_disabled, + spigot_message_sellall_delay_disabled, + spigot_message_sellall_delay_disabled_cant_use, + spigot_message_sellall_delay_edit_success, + spigot_message_sellall_delay_enabled, + spigot_message_sellall_delay_not_number, + spigot_message_sellall_delay_wait, + spigot_message_sellall_gui_disabled, + spigot_message_sellall_money_earned, + spigot_message_sellall_multiplier_add_success, + spigot_message_sellall_multiplier_are_disabled, + spigot_message_sellall_multiplier_cant_find, + spigot_message_sellall_multiplier_delete_success, + spigot_message_sellall_multiplier_disabled, + spigot_message_sellall_multiplier_edit_success, + spigot_message_sellall_multiplier_enabled, + spigot_message_sellall_sell_empty, + spigot_message_sellall_sell_nothing_sellable, + spigot_message_sellall_sell_sign_only, + spigot_message_sellall_sell_sign_notify, + spigot_message_sellall_trigger_already_disabled, + spigot_message_sellall_trigger_already_enabled, + spigot_message_sellall_trigger_disabled, + spigot_message_sellall_trigger_enabled, + spigot_message_sellall_trigger_is_disabled, + spigot_message_sellall_trigger_item_add_success, + spigot_message_sellall_trigger_item_cant_find, + spigot_message_sellall_trigger_item_delete_success, + spigot_message_sellall_trigger_item_missing, - public FileConfiguration getFileGuiMessagesConfig(){ - return conf; + spigot_message_gui_backpack_disabled, + spigot_message_gui_backpack_empty, + spigot_message_gui_backpack_too_many, + spigot_message_gui_close_success, + spigot_message_gui_error, + spigot_message_gui_error_empty, + spigot_message_gui_ladder_empty, + spigot_message_gui_ladder_too_many, + spigot_message_gui_mines_empty, + spigot_message_gui_mines_too_many, + spigot_message_gui_prestiges_empty, + spigot_message_gui_prestiges_too_many, + spigot_message_gui_ranks_empty, + spigot_message_gui_ranks_rankup_commands_empty, + spigot_message_gui_ranks_rankup_commands_too_many, + spigot_message_gui_ranks_too_many, + spigot_message_gui_reload_success, + spigot_message_gui_sellall_disabled, + spigot_message_gui_sellall_empty, + spigot_message_gui_too_high, + spigot_message_gui_too_low_value, } } diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/configs/SellAllConfig.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/configs/SellAllConfig.java index ca8a3c01c..46ac1ee81 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/configs/SellAllConfig.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/configs/SellAllConfig.java @@ -91,6 +91,7 @@ private void values(){ dataConfig("Options.SellAll_By_Sign_Only_Bypass_Permission", "prison.admin"); dataConfig("Options.SellAll_Sign_Notify", false); dataConfig("Options.SellAll_Sign_Visible_Tag", "&7[&3SellAll&7]"); + dataConfig("Options.SellAll_Hand_Enabled", true); dataConfig("Options.Player_GUI_Enabled", true); dataConfig("Options.Player_GUI_Permission_Enabled",false); dataConfig("Options.Player_GUI_Permission","prison.sellall.playergui"); diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/customblock/CustomItems.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/customblock/CustomItems.java index edb653cf6..06dfe5cad 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/customblock/CustomItems.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/customblock/CustomItems.java @@ -12,6 +12,7 @@ import tech.mcprison.prison.output.Output; import tech.mcprison.prison.spigot.SpigotPrison; import tech.mcprison.prison.spigot.spiget.BluesSpigetSemVerComparator; +import tech.mcprison.prison.util.Location; /** * Custom Items 3.7.11 — New API features @@ -114,6 +115,12 @@ public Block setCustomBlockId( Block block, String customId, boolean doBlockUpda return customItemsWrapper.setCustomBlockId( block, customId, doBlockUpdate ); } + + @Override + public void setCustomBlockIdAsync( PrisonBlock prisonBlock, Location location ) { + customItemsWrapper.setCustomBlockIdAsync( prisonBlock, location ); + } + @Override public List getCustomBlockList() { diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/customblock/CustomItemsWrapper.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/customblock/CustomItemsWrapper.java index 7e714dd5b..def042598 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/customblock/CustomItemsWrapper.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/customblock/CustomItemsWrapper.java @@ -2,32 +2,89 @@ import java.util.List; +import org.bukkit.scheduler.BukkitRunnable; + import com.jojodmo.customitems.api.CustomItemsAPI; import tech.mcprison.prison.internal.block.Block; +import tech.mcprison.prison.internal.block.PrisonBlock; +import tech.mcprison.prison.spigot.SpigotPrison; import tech.mcprison.prison.spigot.block.SpigotBlock; +import tech.mcprison.prison.util.Location; public class CustomItemsWrapper { + + + private final SpigotPrison plugin; public CustomItemsWrapper() { - + this.plugin = SpigotPrison.getInstance(); } public String getCustomBlockId( Block block ) { org.bukkit.block.Block spigotBlock = ((SpigotBlock) block).getWrapper(); - CustomItemsAPI.getCustomItemIDAtBlock( spigotBlock ); - return null; + return CustomItemsAPI.getCustomItemIDAtBlock( spigotBlock ); } + /** + *

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

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

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

+ * + * @param prisonBlock + * @param location + * @param doBlockUpdate + * @return + */ + public void setCustomBlockIdAsync( PrisonBlock prisonBlock, Location location ) + { + + new BukkitRunnable() { + @Override + public void run() { + + // No physics update: + org.bukkit.block.Block spigotBlock = ((SpigotBlock) location.getBlockAt()).getWrapper(); + //org.bukkit.block.Block spigotBlock = ((SpigotBlock) prisonBlock).getWrapper(); + + // Request the block change, but we don't need the results so ignore it +// org.bukkit.block.Block resultBlock = + CustomItemsAPI.setCustomItemIDAtBlock( spigotBlock, prisonBlock.getBlockName(), true ); + + } + }.runTaskLater( getPlugin(), 0 ); + + } public List getCustomBlockList() { return CustomItemsAPI.listBlockCustomItemIDs(); } + + public SpigotPrison getPlugin() { + return plugin; + } } diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/customblock/HeadsCustomBlocks.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/customblock/HeadsCustomBlocks.java new file mode 100644 index 000000000..0a96df8df --- /dev/null +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/customblock/HeadsCustomBlocks.java @@ -0,0 +1,62 @@ +package tech.mcprison.prison.spigot.customblock; + +import java.util.List; + +import tech.mcprison.prison.integration.CustomBlockIntegration; +import tech.mcprison.prison.internal.block.Block; +import tech.mcprison.prison.internal.block.PrisonBlock; +import tech.mcprison.prison.internal.block.PrisonBlock.PrisonBlockType; +import tech.mcprison.prison.util.Location; + +public class HeadsCustomBlocks + extends CustomBlockIntegration { + + + private HeadsCustomBlocksWrapper headsCustomBlocksWrapper; + + + public HeadsCustomBlocks() { + super("HeadsCustomBlocks", "HeadsCustomBlocks", PrisonBlockType.heads, "heads:" ); + } + + + @Override + public String getCustomBlockId( Block block ) + { + // TODO Auto-generated method stub + return null; + } + + + @Override + public PrisonBlock getCustomBlock( Block block ) + { + // TODO Auto-generated method stub + return null; + } + + + @Override + public Block setCustomBlockId( Block block, String customId, boolean doBlockUpdate ) + { + // TODO Auto-generated method stub + return null; + } + + + @Override + public void setCustomBlockIdAsync( PrisonBlock prisonBlock, Location location ) + { + // TODO Auto-generated method stub + + } + + + @Override + public List getCustomBlockList() + { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/customblock/HeadsCustomBlocksWrapper.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/customblock/HeadsCustomBlocksWrapper.java new file mode 100644 index 000000000..357558aa2 --- /dev/null +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/customblock/HeadsCustomBlocksWrapper.java @@ -0,0 +1,16 @@ +package tech.mcprison.prison.spigot.customblock; + +import java.util.ArrayList; +import java.util.List; + +public class HeadsCustomBlocksWrapper +{ + + public List getCustomBlockList() { + List heads = new ArrayList<>(); + + + + return heads; + } +} 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 36db6a797..697d6fd40 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 @@ -100,7 +100,8 @@ public double getBalance(Player player) { OfflinePlayer oPlayer = getOfflinePlayer( player ); if ( oPlayer == null ) { Output.get().logInfo( "VaultEconomyWrapper.getBalance(): Error: " + - "Cannot get economy for player %s so returning a value of 0.", + "Cannot get economy for player %s so returning a value of 0. " + + "Failed to get an bukkit offline player.", player.getName()); results = 0; } 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 b89ea0601..455b3d0e4 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 @@ -32,6 +32,7 @@ import tech.mcprison.prison.integration.PermissionIntegration; import tech.mcprison.prison.internal.CommandSender; import tech.mcprison.prison.internal.Player; +import tech.mcprison.prison.spigot.SpigotPrison; import tech.mcprison.prison.spigot.sellall.SellAllUtil; import tech.mcprison.prison.util.Text; @@ -136,10 +137,10 @@ public double getSellAllMultiplier() { if ( isPlayer() ) { - SellAllUtil sellall = SellAllUtil.get(); + SellAllUtil sellall = SpigotPrison.getInstance().getSellAllUtil(); if ( sellall != null && getWrapper() != null ) { - results = sellall.getMultiplier( new SpigotPlayer( (org.bukkit.entity.Player) getWrapper() ) ); + results = sellall.getPlayerMultiplier((org.bukkit.entity.Player) getWrapper()); } } 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 e47f16db8..29d5d1a6d 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,8 @@ import org.bukkit.entity.Player; import org.bukkit.permissions.PermissionAttachmentInfo; +import tech.mcprison.prison.cache.PlayerCache; +import tech.mcprison.prison.cache.PlayerCachePlayerData; import tech.mcprison.prison.internal.ItemStack; import tech.mcprison.prison.internal.OfflineMcPlayer; import tech.mcprison.prison.internal.inventory.Inventory; @@ -300,5 +302,20 @@ public void setTitle( String title, String subtitle, int fadeIn, int stay, int f @Override public void setActionBar( String actionBar ) { } + + @Override + public PlayerCache getPlayerCache() { + return PlayerCache.getInstance(); + } + + @Override + public PlayerCachePlayerData getPlayerCachePlayerData() { + return PlayerCache.getInstance().getOnlinePlayer( this ); + } + + @Override + public boolean isSneaking() { + return false; + } } 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 73e62b68c..601356849 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 @@ -29,17 +29,22 @@ import org.bukkit.entity.ExperienceOrb; import org.bukkit.event.player.PlayerTeleportEvent; +import tech.mcprison.prison.autofeatures.PlayerMessaging.MessageType; +import tech.mcprison.prison.cache.PlayerCache; +import tech.mcprison.prison.cache.PlayerCachePlayerData; import tech.mcprison.prison.internal.ItemStack; import tech.mcprison.prison.internal.Player; import tech.mcprison.prison.internal.inventory.Inventory; import tech.mcprison.prison.internal.scoreboard.Scoreboard; +import tech.mcprison.prison.mines.data.Mine; import tech.mcprison.prison.output.Output; -import tech.mcprison.prison.spigot.SpigotPrison; import tech.mcprison.prison.spigot.SpigotUtil; import tech.mcprison.prison.spigot.block.SpigotBlock; +import tech.mcprison.prison.spigot.compat.SpigotCompatibility; import tech.mcprison.prison.spigot.compat.SpigotNMSPlayer; import tech.mcprison.prison.spigot.inventory.SpigotPlayerInventory; import tech.mcprison.prison.spigot.scoreboard.SpigotScoreboard; +import tech.mcprison.prison.spigot.utils.tasks.PlayerMessagingTask; import tech.mcprison.prison.util.Gamemode; import tech.mcprison.prison.util.Location; @@ -494,14 +499,14 @@ public double getMaxHealth() { double maxHealth = 0; if ( getWrapper() != null ) { - maxHealth = SpigotPrison.getInstance().getCompatibility() + maxHealth = SpigotCompatibility.getInstance() .getMaxHealth( getWrapper() ); } return maxHealth; } public void setMaxHealth( double maxHealth ) { if ( getWrapper() != null ) { - SpigotPrison.getInstance().getCompatibility() + SpigotCompatibility.getInstance() .setMaxHealth( getWrapper(), maxHealth ); } } @@ -605,7 +610,7 @@ public double getWalkSpeed() { @Override public void setTitle( String title, String subtitle, int fadeIn, int stay, int fadeOut ) { if ( getWrapper() != null) { - SpigotPrison.getInstance().getCompatibility() + SpigotCompatibility.getInstance() .sendTitle( getWrapper(), title, subtitle, fadeIn, stay, fadeOut ); } } @@ -613,8 +618,80 @@ public void setTitle( String title, String subtitle, int fadeIn, int stay, int f @Override public void setActionBar( String actionBar ) { if ( getWrapper() != null) { - SpigotPrison.getInstance().getCompatibility() - .sendActionBar( getWrapper(), actionBar ); + PlayerMessagingTask.submitTask( getWrapper(), MessageType.actionBar, actionBar ); + +// SpigotCompatibility.getInstance() +// .sendActionBar( getWrapper(), actionBar ); + } + } + + @Override + public PlayerCache getPlayerCache() { + return PlayerCache.getInstance(); + } + + @Override + public PlayerCachePlayerData getPlayerCachePlayerData() { + return PlayerCache.getInstance().getOnlinePlayer( this ); + } + + public boolean enableFlying( Mine mine, float flightSpeed ) { + boolean enabled = false; + + if ( mine.isInMineExact( getLocation() ) ) { + // Within mine: + + // save the current mine reference in the player's object: +// this.lastEffectsMine = mine; + + if ( getWrapper() != null ) { + org.bukkit.entity.Player bukkitPlayer = getWrapper(); + + bukkitPlayer.setAllowFlight( true ); + bukkitPlayer.setFlySpeed( flightSpeed ); + enabled = true; + } + } + + return enabled; + } + +// public Mine getEffectsMine() { +// Mine effectsMine = null; +// +// if ( lastEffectsMine != null ) { +// +// if ( !lastEffectsMine.isInMineExact( getLocation() ) ) { +// lastEffectsMine = null; +// +// // cancel all effects for player +// } +// effectsMine = lastEffectsMine; +// } +// return effectsMine; +// } + + public boolean isFlying() { + boolean flying = false; + + if ( getWrapper() != null ) { + org.bukkit.entity.Player bukkitPlayer = getWrapper(); + + flying = bukkitPlayer.isFlying(); } + return flying; } + + @Override + public boolean isSneaking() { + boolean sneaking = false; + + if ( getWrapper() != null ) { + org.bukkit.entity.Player bukkitPlayer = getWrapper(); + + sneaking = bukkitPlayer.isSneaking(); + } + return sneaking; + } + } diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/game/SpigotPlayerUtil.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/game/SpigotPlayerUtil.java index fd9952514..df736630f 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/game/SpigotPlayerUtil.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/game/SpigotPlayerUtil.java @@ -1,5 +1,6 @@ package tech.mcprison.prison.spigot.game; +import java.lang.reflect.Method; import java.util.UUID; import org.bukkit.enchantments.Enchantment; @@ -7,9 +8,9 @@ import tech.mcprison.prison.Prison; import tech.mcprison.prison.internal.ItemStack; import tech.mcprison.prison.internal.PlayerUtil; -import tech.mcprison.prison.spigot.SpigotPrison; import tech.mcprison.prison.spigot.block.SpigotItemStack; import tech.mcprison.prison.spigot.compat.Compatibility; +import tech.mcprison.prison.spigot.compat.SpigotCompatibility; public class SpigotPlayerUtil extends PlayerUtil @@ -167,7 +168,7 @@ public SpigotItemStack getItemInHand() { SpigotItemStack itemInHand = null; if ( isActive() && spigotPlayer.getWrapper() != null ) { - itemInHand = SpigotPrison.getInstance().getCompatibility() + itemInHand = SpigotCompatibility.getInstance() .getPrisonItemInMainHand( spigotPlayer.getWrapper() ); } return itemInHand; @@ -273,7 +274,7 @@ public int getItemInHandDurabilityUsed() { SpigotItemStack itemStack = getItemInHand(); if ( itemStack != null ) { - Compatibility compat = SpigotPrison.getInstance().getCompatibility(); + Compatibility compat = SpigotCompatibility.getInstance(); results = compat.getDurability( itemStack ); } @@ -287,7 +288,7 @@ public int getItemInHandDurabilityMax() { SpigotItemStack itemStack = getItemInHand(); if ( itemStack != null ) { - Compatibility compat = SpigotPrison.getInstance().getCompatibility(); + Compatibility compat = SpigotCompatibility.getInstance(); results = compat.getDurabilityMax( itemStack ); } @@ -301,7 +302,7 @@ public int getItemInHandDurabilityRemaining() { SpigotItemStack itemStack = getItemInHand(); if ( itemStack != null ) { - Compatibility compat = SpigotPrison.getInstance().getCompatibility(); + Compatibility compat = SpigotCompatibility.getInstance(); int durabilityUsed = compat.getDurability( itemStack ); int durabilityMax = compat.getDurabilityMax( itemStack ); results = durabilityMax - durabilityUsed; @@ -317,7 +318,7 @@ public double getItemInHandDurabilityPercent() { SpigotItemStack itemStack = getItemInHand(); if ( itemStack != null ) { - Compatibility compat = SpigotPrison.getInstance().getCompatibility(); + Compatibility compat = SpigotCompatibility.getInstance(); int durabilityUsed = compat.getDurability( itemStack ); int durabilityMax = compat.getDurabilityMax( itemStack ); @@ -333,12 +334,35 @@ private int getEnchantment( String enchant ) { Enchantment enchantment = null; - for ( Enchantment e : Enchantment.values() ) { - if ( e.getKey().getKey().equalsIgnoreCase( enchant ) ) { - enchantment = e; - break; + try + { + @SuppressWarnings( "unused" ) + Method methodGetKey = Enchantment.LUCK.getClass().getMethod( "getKey" ); + + for ( Enchantment e : Enchantment.values() ) { + if (e.getKey().getKey().equalsIgnoreCase( enchant ) ) { + enchantment = e; + break; + } } } + catch ( NoSuchMethodException | SecurityException e1 ) { + // Ignore the fact that the method does not exist, which just means this is + // spigot 1.8 or so. + + for ( Enchantment e : Enchantment.values() ) { + if ( e.toString().toLowerCase().contains( enchant.toLowerCase() ) ) { + enchantment = e; + } + } + } + +// for ( Enchantment e : Enchantment.values() ) { +// if (e.getKey().getKey().equalsIgnoreCase( enchant ) ) { +// enchantment = e; +// break; +// } +// } if ( enchantment != null ) { diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/game/SpigotWorld.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/game/SpigotWorld.java index 95d06bcdf..1b715f182 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/game/SpigotWorld.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/game/SpigotWorld.java @@ -18,20 +18,30 @@ package tech.mcprison.prison.spigot.game; +import java.util.List; +import java.util.function.Function; +import java.util.stream.Collectors; + import org.bukkit.Bukkit; +import org.bukkit.scheduler.BukkitRunnable; + +import tech.mcprison.prison.PrisonAPI; +import tech.mcprison.prison.integration.CustomBlockIntegration; +import tech.mcprison.prison.internal.ItemStack; import tech.mcprison.prison.internal.Player; +import tech.mcprison.prison.internal.PrisonStatsElapsedTimeNanos; import tech.mcprison.prison.internal.World; import tech.mcprison.prison.internal.block.Block; +import tech.mcprison.prison.internal.block.MineResetType; +import tech.mcprison.prison.internal.block.MineTargetPrisonBlock; import tech.mcprison.prison.internal.block.PrisonBlock; +import tech.mcprison.prison.spigot.SpigotPrison; import tech.mcprison.prison.spigot.SpigotUtil; import tech.mcprison.prison.spigot.block.SpigotBlock; +import tech.mcprison.prison.spigot.block.SpigotItemStack; import tech.mcprison.prison.spigot.compat.SpigotCompatibility; import tech.mcprison.prison.util.Location; -import java.util.List; -import java.util.function.Function; -import java.util.stream.Collectors; - /** * @author Faizaan A. Datoo */ @@ -56,11 +66,32 @@ public SpigotWorld(org.bukkit.World bukkitWorld) { .collect(Collectors.toList()); } + /** + *

This does get the actual from the world, but it only reads, and does not + * update. I cannot say this is safe to run asynchronously, but so far I have + * not see any related problems when it is. + * + */ @Override public Block getBlockAt(Location location) { return new SpigotBlock( bukkitWorld.getBlockAt(SpigotUtil.prisonLocationToBukkit(location))); } + public SpigotBlock getSpigotBlockAt(Location location) { + return new SpigotBlock( + bukkitWorld.getBlockAt(SpigotUtil.prisonLocationToBukkit(location))); + } + + public org.bukkit.Location getBukkitLocation(Location location) { + return SpigotUtil.prisonLocationToBukkit(location); + } + + public org.bukkit.inventory.ItemStack getBukkitItemStack( ItemStack itemStack ) { + + SpigotItemStack sItemStack = (SpigotItemStack) itemStack; + + return sItemStack.getBukkitStack(); + } @Override public void setBlock( PrisonBlock block, int x, int y, int z ) { @@ -71,8 +102,92 @@ public void setBlock( PrisonBlock block, int x, int y, int z ) { SpigotCompatibility.getInstance().updateSpigotBlock( block, bukkitBlock ); } + + + /** + *

This function should be called from an async task, and it will + * drop down in to the synchronous thread to first get the block + * from the world, then it will change to the specified PrisonBlock type. + *

+ * + * @param prisonBlock + * @param location + */ + public void setBlockAsync( PrisonBlock prisonBlock, Location location ) { + + switch ( prisonBlock.getBlockType() ) + { + case minecraft: + + SpigotCompatibility.getInstance().updateSpigotBlockAsync( prisonBlock, location ); + + break; + + case CustomItems: + { + CustomBlockIntegration customItemsIntegration = + PrisonAPI.getIntegrationManager().getCustomBlockIntegration( prisonBlock.getBlockType() ); + + customItemsIntegration.setCustomBlockIdAsync( prisonBlock, location ); + } + + break; + + default: + break; + } + } + + + /** + *

This list of blocks to be updated, should be ran from an asynchronous thread. + * This function will take it's code block and run it in bukkit's synchronous + * thread so the block updates will be thread safe. + *

+ * + *

The MineTargetPrisonBlock List should be a fairly short list of blocks that + * will be updated in one synchronous slice. + *

+ * + */ + @Override + public void setBlocksSynchronously( List tBlocks, MineResetType resetType, + PrisonStatsElapsedTimeNanos nanos ) { + + new BukkitRunnable() { + @Override + public void run() { + + long start = System.nanoTime(); + + for ( MineTargetPrisonBlock tBlock : tBlocks ) + { + final PrisonBlock pBlock = tBlock.getPrisonBlock( resetType ); + + if ( pBlock != null ) { + + Location location = tBlock.getLocation(); + + SpigotBlock sBlock = (SpigotBlock) location.getBlockAt(); + sBlock.setPrisonBlock( pBlock ); + } + } + + long elapsedNanos = System.nanoTime() - start; + + + if ( nanos != null ) { + nanos.addNanos( elapsedNanos ); + } + + } + }.runTaskLater( SpigotPrison.getInstance(), 0 ); + + } public org.bukkit.World getWrapper() { return bukkitWorld; } + + } diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/ListenersPrisonManager.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/ListenersPrisonManager.java index 97d5fb1bf..26884226f 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 @@ -4,8 +4,6 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; -import java.util.Optional; -import java.util.Set; import org.bukkit.Bukkit; import org.bukkit.Material; @@ -40,10 +38,13 @@ 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.ranks.data.RankPlayerFactory; import tech.mcprison.prison.spigot.SpigotPrison; import tech.mcprison.prison.spigot.SpigotUtil; import tech.mcprison.prison.spigot.backpacks.BackpacksUtil; import tech.mcprison.prison.spigot.compat.Compatibility; +import tech.mcprison.prison.spigot.compat.SpigotCompatibility; +import tech.mcprison.prison.spigot.configs.MessagesConfig; import tech.mcprison.prison.spigot.game.SpigotPlayer; import tech.mcprison.prison.spigot.gui.autofeatures.SpigotAutoBlockGUI; import tech.mcprison.prison.spigot.gui.autofeatures.SpigotAutoFeaturesGUI; @@ -72,10 +73,10 @@ import tech.mcprison.prison.spigot.gui.sellall.SellAllAdminBlocksGUI; import tech.mcprison.prison.spigot.gui.sellall.SellAllAdminGUI; import tech.mcprison.prison.spigot.gui.sellall.SellAllDelayGUI; -import tech.mcprison.prison.spigot.gui.sellall.SellAllPlayerGUI; import tech.mcprison.prison.spigot.gui.sellall.SellAllPrestigesMultiplierGUI; import tech.mcprison.prison.spigot.gui.sellall.SellAllPrestigesSetMultiplierGUI; import tech.mcprison.prison.spigot.gui.sellall.SellAllPriceGUI; +import tech.mcprison.prison.spigot.sellall.SellAllUtil; /** * @author GABRYCA @@ -91,13 +92,11 @@ public class ListenersPrisonManager implements Listener { private String tempChatVariable; private final Configuration config = SpigotPrison.getInstance().getConfig(); private final Configuration guiConfig = SpigotPrison.getInstance().getGuiConfig(); + private final MessagesConfig messages = SpigotPrison.getInstance().getMessagesConfig(); + boolean guiNotEnabled = !getBoolean(config.getString("prison-gui-enabled")); - // NOTE: sellAllConfig will be null if sellall is not enbled. - private Configuration sellAllConfig = SpigotPrison.getInstance().updateSellAllConfig(); +// private Optional ladder; // makes no sense... not thread safe. - private final Configuration messages = SpigotPrison.getInstance().getMessagesConfig(); - boolean guiNotEnabled = !(config.getString("prison-gui-enabled").equalsIgnoreCase("true")); - private Optional ladder; public ChatMode mode; public enum ChatMode{ @@ -144,19 +143,19 @@ public void addChatEventPlayer(Player p){ @EventHandler(priority = EventPriority.HIGHEST) public void onSignEditing(SignChangeEvent e){ - sellAllConfig = SpigotPrison.getInstance().getSellAllConfig(); - - if (sellAllConfig == null){ + if (!SpigotPrison.getInstance().isSellAllEnabled()){ return; } + SellAllUtil sellAllUtil = SpigotPrison.getInstance().getSellAllUtil(); + // Check if the feature's enabled - if (!getBoolean(sellAllConfig.getString("Options.SellAll_Sign_Enabled"))){ + if (!sellAllUtil.isSellAllSignEnabled){ return; } Player p = e.getPlayer(); - String signTag = sellAllConfig.getString("Options.SellAll_Sign_Visible_Tag"); + String signTag = sellAllUtil.sellAllSignTag;; if (signTag == null){ signTag = "&7[&3SellAll&7]"; } @@ -179,45 +178,44 @@ public void onSignEditing(SignChangeEvent e){ @EventHandler(priority = EventPriority.MONITOR) public void onPlayerInteractEvent(PlayerInteractEvent e){ - sellAllConfig = SpigotPrison.getInstance().getSellAllConfig(); - if (sellAllConfig != null) { + if (!SpigotPrison.getInstance().isSellAllEnabled()){ + return; + } + SellAllUtil sellAllUtil = SpigotPrison.getInstance().getSellAllUtil(); + + if (sellAllUtil != null) { // Check if SellAll Shift + Right Click is enabled. - boolean sellAllTriggerEnabled = getBoolean(sellAllConfig.getString("Options.ShiftAndRightClickSellAll.Enabled")); - if (sellAllTriggerEnabled) { + if (sellAllUtil.isSellAllItemTriggerEnabled) { // Check if the action if Shift + Right Click. Player p = e.getPlayer(); if (e.getAction().equals(Action.RIGHT_CLICK_AIR) && p.isSneaking()) { // Check if a permission's required. - boolean permissionSellAllTriggerEnabled = getBoolean(sellAllConfig.getString("Options.ShiftAndRightClickSellAll.PermissionEnabled")); - if (permissionSellAllTriggerEnabled) { - String permission = sellAllConfig.getString("Options.ShiftAndRightClickSellAll.Permission"); + if (sellAllUtil.isSellAllItemTriggerPermissionEnabled) { + String permission = sellAllUtil.permissionItemTrigger; if (permission != null && !p.hasPermission(permission)) { return; } } // Get the Items config section - Set items = null; - try { - items = sellAllConfig.getConfigurationSection("ShiftAndRightClickSellAll.Items").getKeys(false); - } catch (NullPointerException ignored) {} + ArrayList items = sellAllUtil.getItemTriggerXMaterials(); + if (items != null && items.size() != 0) { - for (String itemID : items) { - XMaterial xMaterialConf = SpigotUtil.getXMaterial(sellAllConfig.getString("ShiftAndRightClickSellAll.Items." + itemID + ".ITEM_ID")); - XMaterial inHandXMaterial = null; - if (e.getItem() != null){ - inHandXMaterial = SpigotUtil.getXMaterial(e.getItem().getType()); - } - if (inHandXMaterial != null && xMaterialConf == inHandXMaterial) { - String registeredCmd = Prison.get().getCommandHandler().findRegisteredCommand( "sellall sell" ); - Bukkit.dispatchCommand(p, registeredCmd); - return; - } else if (xMaterialConf == SpigotUtil.getXMaterial(p.getInventory().getItemInMainHand().getType())){ - String registeredCmd = Prison.get().getCommandHandler().findRegisteredCommand( "sellall sell" ); - Bukkit.dispatchCommand(p, registeredCmd); - return; + XMaterial inHandXMaterial = null; + if (e.getItem() != null) { + inHandXMaterial = SpigotUtil.getXMaterial(e.getItem().getType()); + } + if (inHandXMaterial != null) { + for (XMaterial xMaterialConf : items) { + if (xMaterialConf == inHandXMaterial) { + sellAllUtil.sellAllSell(p, false, false, true, false, false, true); + return; + } else if (xMaterialConf == SpigotUtil.getXMaterial(p.getInventory().getItemInMainHand().getType())) { + sellAllUtil.sellAllSell(p, false, false, true, false, false, true); + return; + } } } } @@ -225,12 +223,11 @@ public void onPlayerInteractEvent(PlayerInteractEvent e){ } // Check if the feature's enabled. - boolean sellAllSignEnabled = getBoolean(sellAllConfig.getString("Options.SellAll_Sign_Enabled")); - if (sellAllSignEnabled) { + if (sellAllUtil.isSellAllSignEnabled) { // Get clicked block. Material clickedBlock = null; - if (e.getClickedBlock() != null){ + if (e.getClickedBlock() != null) { clickedBlock = e.getClickedBlock().getType(); } @@ -239,7 +236,7 @@ public void onPlayerInteractEvent(PlayerInteractEvent e){ // Get the player Player p = e.getPlayer(); - String signTag = sellAllConfig.getString("Options.SellAll_Sign_Visible_Tag"); + String signTag = sellAllUtil.sellAllSignTag; if (signTag == null) { signTag = "&7[&3SellAll&7]"; } @@ -258,27 +255,20 @@ public void onPlayerInteractEvent(PlayerInteractEvent e){ // Check if the first like of the sign have the right tag if (sign.getLine(0).equalsIgnoreCase(SpigotPrison.format(signTag))) { - - if (sellAllConfig.getString("Options.SellAll_Sign_Use_Permission_Enabled").equalsIgnoreCase("true") && !p.hasPermission(sellAllConfig.getString("Options.SellAll_Sign_Use_Permission"))) { - Output.get().sendWarn(new SpigotPlayer(p), messages.getString("Message.SellAllSignMissingPermission") + " [&3" + sellAllConfig.getString("Options.SellAll_Sign_Use_Permission") + "&7]"); + 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]"); return; } - boolean bySignOnly = sellAllConfig.getString("Options.SellAll_By_Sign_Only").equalsIgnoreCase("true"); - // SellAllUtil sellAll = SellAllUtil.get(); - // if (sellAll != null) { - // sellAll.toggleSellAllSign(); - // } - - if (sellAllConfig.getString("Options.SellAll_Sign_Notify").equalsIgnoreCase("true")) { - Output.get().sendInfo(new SpigotPlayer(p), messages.getString("Message.SellAllSignNotify")); + if (sellAllUtil.isSellAllSignNotifyEnabled) { + Output.get().sendInfo(new SpigotPlayer(p), messages.getString(MessagesConfig.StringID.spigot_message_sellall_sell_sign_notify)); } - // Execute the sellall command - String registeredCmd = Prison.get().getCommandHandler().findRegisteredCommand( "sellall sell" ); - Bukkit.dispatchCommand(p, registeredCmd + ( bySignOnly ? " bySignOnly" : "")); + sellAllUtil.sellAllSell(p, true, false, true, false, false, true); } - } catch (IndexOutOfBoundsException ignored) {} + } catch (IndexOutOfBoundsException ignored) { + } } } } @@ -329,8 +319,6 @@ public void onChat(AsyncPlayerChatEvent e) { // Check if the boolean is true, this's set manually if (isChatEventActive) { - sellAllConfig = SpigotPrison.getInstance().getSellAllConfig(); - // Get the player Player p = e.getPlayer(); // Check if the player's in the list to not use another one for mistake/conflicting @@ -361,7 +349,7 @@ public void chatInteractData(Player p, ChatMode activeMode) { id = Bukkit.getScheduler().scheduleSyncDelayedTask(SpigotPrison.getInstance(), () -> { if (isChatEventActive) { removeChatEventPlayer(p); - Output.get().sendInfo(new SpigotPlayer(p), messages.getString("Message.OutOfTimeNoChanges")); + Output.get().sendInfo(new SpigotPlayer(p), messages.getString(MessagesConfig.StringID.spigot_message_chat_event_time_end)); isChatEventActive = false; } mode = null; @@ -400,13 +388,12 @@ public void onClick(InventoryClickEvent e){ // GUIs must have the good conditions to work. if (guiConditions(e, p)) return; - Compatibility compat = SpigotPrison.getInstance().getCompatibility(); + Compatibility compat = SpigotCompatibility.getInstance(); String buttonNameMain; String[] parts; Module module; String title; - sellAllConfig = SpigotPrison.getInstance().getSellAllConfig(); try { // Get parameters. @@ -422,18 +409,25 @@ public void onClick(InventoryClickEvent e){ // Close GUI button globally. if (buttonNameMain.equalsIgnoreCase("Close")) { - Output.get().sendInfo(new SpigotPlayer(p), messages.getString("Message.GuiClosedWithSuccess")); + Output.get().sendInfo(new SpigotPlayer(p), messages.getString(MessagesConfig.StringID.spigot_message_gui_close_success)); p.closeInventory(); return; } - + + // If a GUI Tools Page action, then process the request and just exit: + else if ( SpigotGUIMenuTools.getInstance().processGUIPage( p, title, e ) ) { + + return; + } + + String playerRanksTitle = guiConfig.getString("Options.Titles.PlayerRanksGUI").substring(2); String playerPrestigeTitle = guiConfig.getString("Options.Titles.PlayerPrestigesGUI").substring(2); String minesPlayerTitle = guiConfig.getString("Options.Titles.PlayerMinesGUI").substring(2); // Check if the GUI have the right title and do the actions. switch (title) { - + // Check the title and do the actions. case "PrisonManager": @@ -446,7 +440,8 @@ public void onClick(InventoryClickEvent e){ case "RanksManager -> Ladders": { // Call the method. - laddersGUI(e, p, buttonNameMain, module, parts); + laddersGUI(e, p, buttonNameMain, module); +// laddersGUI(e, p, buttonNameMain, module, parts); break; } @@ -737,22 +732,60 @@ public void onClick(InventoryClickEvent e){ } } - private void sellAllPlayerGUI(InventoryClickEvent e, Player p, String[] parts) { - if (parts[0].equalsIgnoreCase("Prior")){ - - SellAllPlayerGUI gui = new SellAllPlayerGUI(p, Integer.parseInt(parts[1])); - gui.open(); - - e.setCancelled(true); - return; - } else if (parts[0].equalsIgnoreCase("Next")){ - - SellAllPlayerGUI gui = new SellAllPlayerGUI(p, Integer.parseInt(parts[1])); - gui.open(); - - e.setCancelled(true); - return; - } + + + +// private boolean processGUIPage( Player p, String title, InventoryClickEvent e ) { +// boolean isPageAction = false; +// +// ItemStack currentItem = e.getCurrentItem(); +// if ( currentItem != null && currentItem.hasItemMeta() ) { +// +// ItemMeta meta = currentItem.getItemMeta(); +// +// if ( meta.hasLore() ) { +// +// String command = null; +// +// List lores = meta.getLore(); +// +// for ( String lore : lores ) { +// +// if ( lore.contains( SpigotGUIMenuTools.GUI_MENU_TOOLS_PAGE ) ) { +// isPageAction = true; +// } +// if ( lore.contains( SpigotGUIMenuTools.GUI_MENU_TOOLS_COMMAND ) ) { +// command = Text.stripColor( lore ).replace( SpigotGUIMenuTools.GUI_MENU_TOOLS_COMMAND, "" ).trim(); +// } +// } +// +// if ( isPageAction && command != null ) { +// Bukkit.dispatchCommand(p, command); +// +// } +// } +// +// } +// +// return isPageAction; +// } + + private void sellAllPlayerGUI(InventoryClickEvent e, Player p, String[] parts) { +// if (parts[0].equalsIgnoreCase("Prior")){ +// +// SellAllPlayerGUI gui = new SellAllPlayerGUI(p, Integer.parseInt(parts[1])); +// gui.open(); +// +// e.setCancelled(true); +// return; +// } else if (parts[0].equalsIgnoreCase("Next")){ +// +// SellAllPlayerGUI gui = new SellAllPlayerGUI(p, Integer.parseInt(parts[1])); +// gui.open(); +// +// e.setCancelled(true); +// return; +// } p.closeInventory(); e.setCancelled(true); @@ -826,12 +859,11 @@ private void showBlock(InventoryClickEvent e, Player p, String[] parts) { conf.set("Options.Mines.MaterialType." + parts[1], parts[0]); conf.save(sellAllFile); } catch (IOException ex){ - Output.get().sendWarn(new SpigotPlayer(p), messages.getString("Message.SellAllConfigSaveFail")); ex.printStackTrace(); return; } - Output.get().sendInfo(new SpigotPlayer(p), messages.getString("Message.MineShowItemEditSuccess") + " [" + parts[0] + "]"); + Output.get().sendInfo(new SpigotPlayer(p), messages.getString(MessagesConfig.StringID.spigot_message_mines_item_show_edit_success) + " [" + parts[0] + "]"); p.closeInventory(); } @@ -904,7 +936,7 @@ private void setSellAllPrestigeMultiplier(InventoryClickEvent e, Player p, Strin } else { // Tell to the player that the value's too low - Output.get().sendWarn(new SpigotPlayer(p), messages.getString("Message.TooLowValue")); + Output.get().sendWarn(new SpigotPlayer(p), messages.getString(MessagesConfig.StringID.spigot_message_gui_too_low_value)); e.setCancelled(true); @@ -930,7 +962,7 @@ private void setSellAllPrestigeMultiplier(InventoryClickEvent e, Player p, Strin } else { // Close the GUI and tell it to the player - Output.get().sendWarn(new SpigotPlayer(p), messages.getString("Message.TooHighValue")); + Output.get().sendWarn(new SpigotPlayer(p), messages.getString(MessagesConfig.StringID.spigot_message_gui_too_high)); e.setCancelled(true); p.closeInventory(); return; @@ -968,6 +1000,8 @@ private void sellAllMultipliersGUI(InventoryClickEvent e, Player p, String butto return; } else { + Configuration sellAllConfig = SpigotPrison.getInstance().getSellAllConfig(); + // Open setMultiplierGUI String doubleString = sellAllConfig.getString("Multiplier." + parts[0] + ".MULTIPLIER"); if (doubleString != null) { @@ -1014,7 +1048,7 @@ private void sellAllDelayGUI(InventoryClickEvent e, Player p, String[] parts) { } else if (e.isRightClick()){ // Send a message to the player - Output.get().sendWarn(new SpigotPlayer(p), messages.getString("Message.EventCancelled")); + Output.get().sendWarn(new SpigotPlayer(p), messages.getString(MessagesConfig.StringID.spigot_message_event_cancelled)); e.setCancelled(true); @@ -1046,7 +1080,7 @@ private void sellAllDelayGUI(InventoryClickEvent e, Player p, String[] parts) { } else { // Tell to the player that the value's too low - Output.get().sendWarn(new SpigotPlayer(p), messages.getString("Message.TooLowValue")); + Output.get().sendWarn(new SpigotPlayer(p), messages.getString(MessagesConfig.StringID.spigot_message_gui_too_low_value)); e.setCancelled(true); @@ -1056,7 +1090,7 @@ private void sellAllDelayGUI(InventoryClickEvent e, Player p, String[] parts) { } // Open an updated GUI after the value changed - SellAllDelayGUI gui = new SellAllDelayGUI(p, val); + SellAllDelayGUI gui = new SellAllDelayGUI(p, val, 1, "sellall gui", "sellall gui"); gui.open(); // Check the calculator symbol @@ -1072,14 +1106,14 @@ private void sellAllDelayGUI(InventoryClickEvent e, Player p, String[] parts) { } else { // Close the GUI and tell it to the player - Output.get().sendWarn(new SpigotPlayer(p), messages.getString("Message.TooHighValue")); + Output.get().sendWarn(new SpigotPlayer(p), messages.getString(MessagesConfig.StringID.spigot_message_gui_too_high)); e.setCancelled(true); p.closeInventory(); return; } // Open a new updated GUI with new values - SellAllDelayGUI gui = new SellAllDelayGUI(p, val); + SellAllDelayGUI gui = new SellAllDelayGUI(p, val, 1, "sellall gui", "sellall gui"); gui.open(); } } @@ -1111,7 +1145,7 @@ private void sellAllAutoSellAdminGUI(InventoryClickEvent e, Player p, String but String registeredCmd = Prison.get().getCommandHandler().findRegisteredCommand( "sellall autosell" ); Bukkit.dispatchCommand(p, registeredCmd + " false"); - SellAllAdminGUI gui = new SellAllAdminGUI(p); + SellAllAdminGUI gui = new SellAllAdminGUI( p, 1, "sellall gui", "gui" ); gui.open(); break; @@ -1121,7 +1155,7 @@ private void sellAllAutoSellAdminGUI(InventoryClickEvent e, Player p, String but String registeredCmd = Prison.get().getCommandHandler().findRegisteredCommand( "sellall autosell" ); Bukkit.dispatchCommand(p, registeredCmd + " true"); - SellAllAdminGUI gui = new SellAllAdminGUI(p); + SellAllAdminGUI gui = new SellAllAdminGUI( p, 1, "sellall gui", "gui" ); gui.open(); break; @@ -1132,11 +1166,13 @@ private void sellAllAutoSellAdminGUI(InventoryClickEvent e, Player p, String but } private void sellAllAdminGUI(InventoryClickEvent e, Player p, String buttonNameMain) { + + Configuration sellAllConfig = SpigotPrison.getInstance().getSellAllConfig(); switch (buttonNameMain){ case "Blocks-Shop":{ - SellAllAdminBlocksGUI gui = new SellAllAdminBlocksGUI(p, 0); + SellAllAdminBlocksGUI gui = new SellAllAdminBlocksGUI( p, 1, "sellall gui blocks", "sellall gui" ); gui.open(); break; } @@ -1146,7 +1182,7 @@ private void sellAllAdminGUI(InventoryClickEvent e, Player p, String buttonNameM if (e.getClick().isRightClick()){ String registeredCmd = Prison.get().getCommandHandler().findRegisteredCommand( "sellall autosell" ); Bukkit.dispatchCommand(p, registeredCmd + " false"); - SellAllAdminGUI gui = new SellAllAdminGUI(p); + SellAllAdminGUI gui = new SellAllAdminGUI( p, 1, "sellall gui", "gui" ); gui.open(); } else { SellAllAdminAutoSellGUI gui = new SellAllAdminAutoSellGUI(p); @@ -1161,10 +1197,10 @@ private void sellAllAdminGUI(InventoryClickEvent e, Player p, String buttonNameM String registeredCmd = Prison.get().getCommandHandler().findRegisteredCommand( "sellall autosell" ); Bukkit.dispatchCommand(p, registeredCmd + " true"); p.closeInventory(); - SellAllAdminGUI gui = new SellAllAdminGUI(p); + SellAllAdminGUI gui = new SellAllAdminGUI( p, 1, "sellall gui", "gui" ); gui.open(); } else { - Output.get().sendInfo(new SpigotPlayer(p), messages.getString("Message.EnableAutoSellToUse")); + Output.get().sendInfo(new SpigotPlayer(p), messages.getString(MessagesConfig.StringID.spigot_message_sellall_auto_disabled_cant_use)); } break; } @@ -1175,9 +1211,10 @@ private void sellAllAdminGUI(InventoryClickEvent e, Player p, String buttonNameM String registeredCmd = Prison.get().getCommandHandler().findRegisteredCommand( "sellall delay" ); Bukkit.dispatchCommand(p, registeredCmd + " false"); p.closeInventory(); - SellAllAdminGUI gui = new SellAllAdminGUI(p); + SellAllAdminGUI gui = new SellAllAdminGUI( p, 1, "sellall gui", "gui" ); gui.open(); - } else { + } + else { p.closeInventory(); int val = 0; @@ -1190,7 +1227,7 @@ private void sellAllAdminGUI(InventoryClickEvent e, Player p, String buttonNameM } catch (NumberFormatException ignored){} p.closeInventory(); - SellAllDelayGUI gui = new SellAllDelayGUI(p, val); + SellAllDelayGUI gui = new SellAllDelayGUI(p, val, 1, "sellall gui", "sellall gui" ); gui.open(); } @@ -1203,10 +1240,10 @@ private void sellAllAdminGUI(InventoryClickEvent e, Player p, String buttonNameM String registeredCmd = Prison.get().getCommandHandler().findRegisteredCommand( "sellall delay" ); Bukkit.dispatchCommand(p, registeredCmd + " true"); p.closeInventory(); - SellAllAdminGUI gui = new SellAllAdminGUI(p); + SellAllAdminGUI gui = new SellAllAdminGUI(p, 1, "sellall gui", "gui"); gui.open(); } else { - Output.get().sendInfo(new SpigotPlayer(p), messages.getString("Message.EnableSellDelayToUse")); + Output.get().sendInfo(new SpigotPlayer(p), messages.getString(MessagesConfig.StringID.spigot_message_sellall_delay_disabled_cant_use)); } break; } @@ -1214,10 +1251,10 @@ private void sellAllAdminGUI(InventoryClickEvent e, Player p, String buttonNameM case "SellAll-Currency":{ // Send messages to the player - Output.get().sendInfo(new SpigotPlayer(p), messages.getString("Message.SellAllCurrencyChat1")); - Output.get().sendInfo(new SpigotPlayer(p), messages.getString("Message.SellAllCurrencyChat2")); - Output.get().sendInfo(new SpigotPlayer(p), messages.getString("Message.SellAllCurrencyChat3")); - Output.get().sendInfo(new SpigotPlayer(p), messages.getString("Message.SellAllCurrencyChat4")); + Output.get().sendInfo(new SpigotPlayer(p), messages.getString(MessagesConfig.StringID.spigot_message_sellall_currency_chat_1)); + Output.get().sendInfo(new SpigotPlayer(p), messages.getString(MessagesConfig.StringID.spigot_message_sellall_currency_chat_2)); + Output.get().sendInfo(new SpigotPlayer(p), messages.getString(MessagesConfig.StringID.spigot_message_sellall_currency_chat_3)); + Output.get().sendInfo(new SpigotPlayer(p), messages.getString(MessagesConfig.StringID.spigot_message_sellall_currency_chat_4)); chatInteractData(p, ChatMode.SellAll_Currency); p.closeInventory(); @@ -1230,13 +1267,13 @@ private void sellAllAdminGUI(InventoryClickEvent e, Player p, String buttonNameM boolean multiplierEnabled = getBoolean(sellAllConfig.getString("Options.Multiplier_Enabled")); if (!multiplierEnabled){ - Output.get().sendWarn(new SpigotPlayer(p), messages.getString("Message.SellAllMultipliersAreDisabled")); + Output.get().sendWarn(new SpigotPlayer(p), messages.getString(MessagesConfig.StringID.spigot_message_sellall_multiplier_are_disabled)); return; } else { if (sellAllConfig.getConfigurationSection("Multiplier").getKeys(false).size() == 0) { - Output.get().sendWarn(new SpigotPlayer(p), messages.getString("Message.EmptyGui")); + Output.get().sendWarn(new SpigotPlayer(p), messages.getString(MessagesConfig.StringID.spigot_message_gui_error_empty)); e.setCancelled(true); return; } else { @@ -1279,7 +1316,7 @@ private void prisonSetupConfirmGUI(InventoryClickEvent e, Player p, String[] par if (parts[0].equalsIgnoreCase("Confirm:")){ Bukkit.dispatchCommand(p, "ranks autoConfigure"); } else if (parts[0].equalsIgnoreCase("Cancel:")){ - Output.get().sendInfo(new SpigotPlayer(p), messages.getString("Setup.Message.Aborted")); + Output.get().sendInfo(new SpigotPlayer(p), messages.getString(MessagesConfig.StringID.spigot_message_event_cancelled)); } p.closeInventory(); e.setCancelled(true); @@ -1333,25 +1370,6 @@ private void mineBlockPercentage(InventoryClickEvent e, Player p, String[] parts return; } - // If Close, part 4 won't be defined so handle the close first. - - // What? - /*if (part1.equalsIgnoreCase( "Close" )) { - - int pos = 0; - try { - pos = Integer.parseInt( part3 ); - } - catch(NumberFormatException ignored) {} - - SpigotBlocksListGUI gui = new SpigotBlocksListGUI(p, part2, pos); - - p.closeInventory(); - - gui.open(); - return; - }*/ - String part4 = null; try{ part4 = parts[3]; @@ -1583,21 +1601,21 @@ private void sellAllItemValue(InventoryClickEvent e, Player p, String[] parts) { private void sellAllAdminBlocksGUI(InventoryClickEvent e, Player p, String[] parts) { - if (parts[0].equalsIgnoreCase("Prior")){ - - SellAllAdminBlocksGUI gui = new SellAllAdminBlocksGUI(p, Integer.parseInt(parts[1])); - gui.open(); - - e.setCancelled(true); - return; - } else if (parts[0].equalsIgnoreCase("Next")){ - - SellAllAdminBlocksGUI gui = new SellAllAdminBlocksGUI(p, Integer.parseInt(parts[1])); - gui.open(); - - e.setCancelled(true); - return; - } +// if (parts[0].equalsIgnoreCase("Prior")){ +// +// SellAllAdminBlocksGUI gui = new SellAllAdminBlocksGUI(p, Integer.parseInt(parts[1])); +// gui.open(); +// +// e.setCancelled(true); +// return; +// } else if (parts[0].equalsIgnoreCase("Next")){ +// +// SellAllAdminBlocksGUI gui = new SellAllAdminBlocksGUI(p, Integer.parseInt(parts[1])); +// gui.open(); +// +// e.setCancelled(true); +// return; +// } if (e.isRightClick()){ @@ -1607,6 +1625,8 @@ private void sellAllAdminBlocksGUI(InventoryClickEvent e, Player p, String[] par } else if (e.isLeftClick()){ + Configuration sellAllConfig = SpigotPrison.getInstance().getSellAllConfig(); + String valueString = sellAllConfig.getString("Items." + parts[0] + ".ITEM_VALUE"); if (valueString != null) { SellAllPriceGUI gui = new SellAllPriceGUI(p, Double.parseDouble(valueString), parts[0]); @@ -1622,7 +1642,7 @@ private void prisonManagerGUI(InventoryClickEvent e, Player p, String buttonName // Check the Item display name and do open the right GUI. switch (buttonNameMain) { case "Ranks - Ladders": { - SpigotLaddersGUI gui = new SpigotLaddersGUI(p, 0); + SpigotLaddersGUI gui = new SpigotLaddersGUI(p, 1, "gui ladders", "gui" ); gui.open(); break; } @@ -1642,14 +1662,14 @@ private void prisonManagerGUI(InventoryClickEvent e, Player p, String buttonName // Check the Item display name and do open the right GUI. case "Mines": { - SpigotMinesGUI gui = new SpigotMinesGUI(p, 0); + SpigotMinesGUI gui = new SpigotMinesGUI(p, 1, "gui admin mines", "gui"); gui.open(); break; } // Check the Item display name and do open the right GUI. case "SellAll": { - SellAllAdminGUI gui = new SellAllAdminGUI(p); + SellAllAdminGUI gui = new SellAllAdminGUI(p, 1, "sellall gui", "gui"); gui.open(); break; } @@ -1664,7 +1684,7 @@ private void prisonManagerGUI(InventoryClickEvent e, Player p, String buttonName e.setCancelled(true); } - private void laddersGUI(InventoryClickEvent e, Player p, String buttonNameMain, Module module, String[] parts) { + private void laddersGUI(InventoryClickEvent e, Player p, String buttonNameMain, Module module ) { // Check if the Ranks module's loaded. if(!(module instanceof PrisonRanks)){ @@ -1674,34 +1694,49 @@ private void laddersGUI(InventoryClickEvent e, Player p, String buttonNameMain, return; } - if (parts[0].equalsIgnoreCase("Next") || parts[0].equalsIgnoreCase("Prior")){ - - // Open a new SpigotLadders GUI page. - SpigotLaddersGUI gui = new SpigotLaddersGUI(p, Integer.parseInt(parts[1])); - p.closeInventory(); - gui.open(); - return; - } +// if (parts[0].equalsIgnoreCase("Next") || parts[0].equalsIgnoreCase("Prior")){ +// +// // Open a new SpigotLadders GUI page. +// SpigotLaddersGUI gui = new SpigotLaddersGUI(p, Integer.parseInt(parts[1]), 1); +// p.closeInventory(); +// gui.open(); +// return; +// } // Get the ladder by the name of the button got before. - ladder = Optional.of(PrisonRanks.getInstance().getLadderManager().getLadder(buttonNameMain)); + RankLadder rLadder = PrisonRanks.getInstance().getLadderManager().getLadder(buttonNameMain); + + if ( rLadder == null ) { + // Do nothing since it's not a valid ladder name: + return; + } +// ladder = rLadder; // When the player click an item with shift and right click, e.isShiftClick should be enough but i want // to be sure's a right click. if (e.isShiftClick() && e.isRightClick()) { - - // Execute the command - Bukkit.dispatchCommand(p, "ranks ladder delete " + buttonNameMain); - e.setCancelled(true); - p.closeInventory(); - SpigotLaddersGUI gui = new SpigotLaddersGUI(p, 0); - gui.open(); - return; + + if ( rLadder.getRanks().size() > 0 ) { + + SpigotPlayer sPlayer = new SpigotPlayer( p ); + sPlayer.setActionBar( "Cannot delete a non-empty ladder" ); + } + else { + + // Execute the command + Bukkit.dispatchCommand(p, "ranks ladder delete " + buttonNameMain); + e.setCancelled(true); + p.closeInventory(); + SpigotLaddersGUI gui = new SpigotLaddersGUI(p, 1, "gui ladders", "gui" ); + gui.open(); + return; + } } // Open the GUI of ranks. - SpigotRanksGUI gui = new SpigotRanksGUI(p, ladder, 0); + String cmdPage = "gui admin ranks " + rLadder.getName(); + SpigotRanksGUI gui = new SpigotRanksGUI( p, rLadder, 1, cmdPage, "gui" ); gui.open(); // Cancel the event. @@ -1710,14 +1745,14 @@ private void laddersGUI(InventoryClickEvent e, Player p, String buttonNameMain, private void ranksGUI(InventoryClickEvent e, Player p, String buttonNameMain, String[] parts) { - if (parts[0].equalsIgnoreCase("Next") || parts[0].equalsIgnoreCase("Prior")){ - - // Open a new SpigotLadders GUI page. - SpigotRanksGUI gui = new SpigotRanksGUI(p, ladder, Integer.parseInt(parts[1])); - p.closeInventory(); - gui.open(); - return; - } +// if (parts[0].equalsIgnoreCase("Next") || parts[0].equalsIgnoreCase("Prior")){ +// +// // Open a new SpigotLadders GUI page. +// SpigotRanksGUI gui = new SpigotRanksGUI(p, ladder, Integer.parseInt(parts[1])); +// p.closeInventory(); +// gui.open(); +// return; +// } // Get the rank. Rank rank = PrisonRanks.getInstance().getRankManager().getRank(buttonNameMain); @@ -1731,11 +1766,13 @@ private void ranksGUI(InventoryClickEvent e, Player p, String buttonNameMain, St // Check clicks. if (e.isShiftClick() && e.isRightClick()) { + RankLadder rLadder = rank.getLadder(); + // Execute the command. Bukkit.dispatchCommand(p, "ranks delete " + buttonNameMain); e.setCancelled(true); p.closeInventory(); - SpigotRanksGUI gui = new SpigotRanksGUI(p, ladder, 0); + SpigotRanksGUI gui = new SpigotRanksGUI( p, rLadder, 1, "gui admin ranks", "gui" ); gui.open(); return; @@ -1827,7 +1864,10 @@ private void rankManagerGUI(InventoryClickEvent e, Player p, String[] parts) { // Check and open a GUI. if(rank != null) { RankPlayer rankPlayer = PrisonRanks.getInstance().getPlayerManager().getPlayer( new SpigotPlayer(p) ); - PlayerRank pRank = rankPlayer.getRank( rank.getLadder() ); + + RankPlayerFactory rankPlayerFactory = new RankPlayerFactory(); + + PlayerRank pRank = rankPlayerFactory.getRank( rankPlayer, rank.getLadder() ); SpigotRankPriceGUI gui = new SpigotRankPriceGUI(p, pRank.getRankCost().intValue(), rank.getName()); gui.open(); @@ -1837,8 +1877,8 @@ private void rankManagerGUI(InventoryClickEvent e, Player p, String[] parts) { } else if (buttonName.equalsIgnoreCase("RankTag")){ // Send messages to the player. - Output.get().sendInfo(new SpigotPlayer(p), messages.getString("Message.rankTagRename")); - Output.get().sendInfo(new SpigotPlayer(p), messages.getString("Message.rankTagRenameClose")); + Output.get().sendInfo(new SpigotPlayer(p), messages.getString(MessagesConfig.StringID.spigot_message_ranks_tag_chat_rename_1)); + Output.get().sendInfo(new SpigotPlayer(p), messages.getString(MessagesConfig.StringID.spigot_message_ranks_tag_chat_rename_2)); // Start the async task. tempChatVariable = rankName; chatInteractData(p, ChatMode.RankName); @@ -1852,7 +1892,7 @@ private void rankManagerGUI(InventoryClickEvent e, Player p, String[] parts) { private void playerRanksGUI(InventoryClickEvent e, Player p, String buttonNameMain) { // Check the buttonName and do the actions. - if (buttonNameMain.equals(SpigotPrison.format(messages.getString("Lore.Rankup").substring(2)))){ + if (buttonNameMain.equals(SpigotPrison.format(messages.getString(MessagesConfig.StringID.spigot_gui_lore_rankup).substring(2)))){ Bukkit.dispatchCommand(p, "rankup " + guiConfig.getString("Options.Ranks.Ladder")); p.closeInventory(); } @@ -1986,14 +2026,14 @@ private void rankPriceGUI(InventoryClickEvent e, Player p, String[] parts) { private void minesGUI(InventoryClickEvent e, Player p, String buttonNameMain, String[] parts) { - if (parts[0].equalsIgnoreCase("Next") || parts[0].equalsIgnoreCase("Prior")){ - - // Open a new SpigotLadders GUI page. - SpigotMinesGUI gui = new SpigotMinesGUI(p, Integer.parseInt(parts[1])); - p.closeInventory(); - gui.open(); - return; - } +// if (parts[0].equalsIgnoreCase("Next") || parts[0].equalsIgnoreCase("Prior")){ +// +// // Open a new SpigotLadders GUI page. +// SpigotMinesGUI gui = new SpigotMinesGUI(p, Integer.parseInt(parts[1])); +// p.closeInventory(); +// gui.open(); +// return; +// } // Variables. PrisonMines pMines = PrisonMines.getInstance(); @@ -2036,10 +2076,22 @@ private void playerMinesGUI(Player p, InventoryClickEvent e) { // Confirm the player has access to the mine before trying to TP them there: Mine mine = PrisonMines.getInstance().getMine( mineName ); SpigotPlayer spigotPlayer = new SpigotPlayer(p); - if (mine.hasMiningAccess(spigotPlayer) || p.hasPermission(permission + mineName) || - p.hasPermission(permission.substring(0, permission.length() - 1))) { - Bukkit.dispatchCommand(p, SpigotPrison.format(guiConfig.getString("Options.Mines.CommandWarpPlugin") + " " + mineName)); - } + boolean errorHasMiningPermission = false; + boolean hasMiningPermission = false; + + try { + hasMiningPermission = mine.hasMiningAccess(spigotPlayer); + } catch (NullPointerException ex){ + errorHasMiningPermission = true; + } + + if (errorHasMiningPermission && (p.hasPermission(permission + mineName) || + p.hasPermission(permission.substring(0, permission.length() - 1)))){ + Bukkit.dispatchCommand(p, SpigotPrison.format(guiConfig.getString("Options.Mines.CommandWarpPlugin") + " " + mineName)); + } else if (hasMiningPermission || p.hasPermission(permission + mineName) || + p.hasPermission(permission.substring(0, permission.length() - 1))){ + Bukkit.dispatchCommand(p, SpigotPrison.format(guiConfig.getString("Options.Mines.CommandWarpPlugin") + " " + mineName)); + } } } @@ -2125,8 +2177,8 @@ private void mineInfoGUI(InventoryClickEvent e, Player p, String[] parts) { case "Mine_Name:": { // Send messages to the player - Output.get().sendInfo(new SpigotPlayer(p), messages.getString("Message.mineNameRename")); - Output.get().sendInfo(new SpigotPlayer(p), messages.getString("Message.mineNameRenameClose")); + Output.get().sendInfo(new SpigotPlayer(p), messages.getString(MessagesConfig.StringID.spigot_message_mines_name_chat_1)); + Output.get().sendInfo(new SpigotPlayer(p), messages.getString(MessagesConfig.StringID.spigot_message_mines_name_chat_2)); // Start the async task tempChatVariable = mineName; @@ -2355,7 +2407,7 @@ private void mineNotificationsGUI(InventoryClickEvent e, Player p, String[] part typeNotification = "within"; // Execute command - Bukkit.dispatchCommand(p, "mines set notification " + mineName + " " + typeNotification + " " + "0"); + Bukkit.dispatchCommand(p, "mines set notification " + mineName + " " + typeNotification + " 0"); // Cancel the event and close the inventory e.setCancelled(true); @@ -2381,7 +2433,7 @@ private void mineNotificationsGUI(InventoryClickEvent e, Player p, String[] part typeNotification = "disabled"; // Execute the command - Bukkit.dispatchCommand(p, "mines set notification " + mineName + " " + typeNotification + " " + "0"); + Bukkit.dispatchCommand(p, "mines set notification " + mineName + " " + typeNotification + " 0"); // Cancel the event and close the inventory e.setCancelled(true); @@ -2531,8 +2583,8 @@ private void autoFeaturesGUI(InventoryClickEvent e, Player p, String[] parts) { saveConfigAutoFeatures(e, p); } - if (buttonName.equalsIgnoreCase("Full-Inventory-Hologram")){ - afConfig.setFeature(AutoFeatures.hologramIfInventoryIsFull, !enabled); + if (buttonName.equalsIgnoreCase("Full-Inventory-ActionBar")){ + afConfig.setFeature(AutoFeatures.actionBarMessageIfInventoryIsFull, !enabled); saveConfigAutoFeatures(e,p); } @@ -2813,7 +2865,7 @@ private void sellAllCurrencyChat(AsyncPlayerChatEvent e, Player p, String messag // Check message and do the action String registeredCmd = Prison.get().getCommandHandler().findRegisteredCommand( "sellall set currency" ); if (message.equalsIgnoreCase("cancel")){ - Output.get().sendInfo(new SpigotPlayer(p), messages.getString("Message.SellAllCurrencyEditCancelled")); + Output.get().sendInfo(new SpigotPlayer(p), messages.getString(MessagesConfig.StringID.spigot_message_event_cancelled)); } else if (message.equalsIgnoreCase("default")){ Bukkit.getScheduler().runTask(SpigotPrison.getInstance(), () -> Bukkit.getServer().dispatchCommand(p, registeredCmd + " default")); } else { @@ -2830,11 +2882,11 @@ private void prestigeAction(AsyncPlayerChatEvent e, Player p, String message) { // Check the chat message and do the actions if (message.equalsIgnoreCase("cancel")) { - Output.get().sendInfo(new SpigotPlayer(p), messages.getString("Message.PrestigeCancelled")); + Output.get().sendInfo(new SpigotPlayer(p), messages.getString(MessagesConfig.StringID.spigot_message_prestiges_cancelled)); } else if (message.equalsIgnoreCase("confirm")) { Bukkit.getScheduler().runTask(SpigotPrison.getInstance(), () -> Bukkit.getServer().dispatchCommand(p, "rankup prestiges")); } else { - Output.get().sendInfo(new SpigotPlayer(p), messages.getString("Message.PrestigeCancelledWrongKeyword")); + Output.get().sendInfo(new SpigotPlayer(p), messages.getString(MessagesConfig.StringID.spigot_message_prestiges_cancelled_wrong_keyword)); } // Cancel the event e.setCancelled(true); @@ -2846,7 +2898,7 @@ private void mineAction(AsyncPlayerChatEvent e, Player p, String message) { // Check the chat message and do the action if (message.equalsIgnoreCase("close")) { - Output.get().sendInfo(new SpigotPlayer(p), messages.getString("Message.mineNameRenameClosed")); + Output.get().sendInfo(new SpigotPlayer(p), messages.getString(MessagesConfig.StringID.spigot_message_mines_name_chat_cancelled)); } else { Bukkit.getScheduler().runTask(SpigotPrison.getInstance(), () -> Bukkit.getServer().dispatchCommand(p, "mines rename " + tempChatVariable + " " + message)); } @@ -2858,7 +2910,7 @@ private void mineAction(AsyncPlayerChatEvent e, Player p, String message) { private void rankAction(AsyncPlayerChatEvent e, Player p, String message) { // Check the chat message and do the action if (message.equalsIgnoreCase("close")) { - Output.get().sendInfo(new SpigotPlayer(p), messages.getString("Message.rankTagRenameClosed")); + Output.get().sendInfo(new SpigotPlayer(p), messages.getString(MessagesConfig.StringID.spigot_message_ranks_tag_chat_cancelled)); } else { Bukkit.getScheduler().runTask(SpigotPrison.getInstance(), () -> Bukkit.getServer().dispatchCommand(p, "ranks set tag " + tempChatVariable + " " + message)); } diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/PrisonSetupGUI.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/PrisonSetupGUI.java index c3ce8c842..ed4227bd8 100644 --- a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/PrisonSetupGUI.java +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/PrisonSetupGUI.java @@ -2,6 +2,7 @@ import com.cryptomorin.xseries.XMaterial; import org.bukkit.entity.Player; +import tech.mcprison.prison.spigot.configs.MessagesConfig; import tech.mcprison.prison.spigot.gui.guiutility.Button; import tech.mcprison.prison.spigot.gui.guiutility.ButtonLore; import tech.mcprison.prison.spigot.gui.guiutility.PrisonGUI; @@ -24,23 +25,22 @@ public void open(){ PrisonGUI gui = new PrisonGUI(p, 9, "&3Prison Setup -> Confirmation"); // Create lore. - ButtonLore lore = new ButtonLore(createLore(messages.getString("Lore.ClickToConfirm")), createLore( - messages.getString("Lore.noRanksFoundSetup"), - messages.getString("Lore.noRanksFoundSetup1"), - messages.getString("Lore.noRanksFoundSetup2"), - messages.getString("Lore.noRanksFoundSetup3"), - messages.getString("Lore.noRanksFoundSetup4"), - messages.getString("Lore.noRanksFoundSetup5"), - messages.getString("Lore.noRanksFoundSetup6"), - messages.getString("Lore.noRanksFoundSetup7"), - messages.getString("Lore.noRanksFoundSetup8"))); + ButtonLore lore = new ButtonLore(createLore(messages.getString(MessagesConfig.StringID.spigot_gui_lore_click_to_confirm)), createLore( + messages.getString(MessagesConfig.StringID.spigot_gui_lore_ranks_setup_1), + messages.getString(MessagesConfig.StringID.spigot_gui_lore_ranks_setup_2), + messages.getString(MessagesConfig.StringID.spigot_gui_lore_ranks_setup_3), + messages.getString(MessagesConfig.StringID.spigot_gui_lore_ranks_setup_4), + messages.getString(MessagesConfig.StringID.spigot_gui_lore_ranks_setup_5), + messages.getString(MessagesConfig.StringID.spigot_gui_lore_ranks_setup_6), + messages.getString(MessagesConfig.StringID.spigot_gui_lore_ranks_setup_7), + messages.getString(MessagesConfig.StringID.spigot_gui_lore_ranks_setup_8))); // Add button. - gui.addButton(new Button(2, XMaterial.EMERALD_BLOCK, lore, "&3" + "Confirm: Setup")); + gui.addButton(new Button(2, XMaterial.EMERALD_BLOCK, lore, "&3Confirm: Setup")); // Add button. gui.addButton(new Button(6, XMaterial.REDSTONE_BLOCK, createLore( - messages.getString("Lore.ClickToCancel")), "&3" + "Cancel: Setup")); + messages.getString(MessagesConfig.StringID.spigot_gui_lore_click_to_cancel)), "&3Cancel: Setup")); // Open Prison GUI. gui.open(); diff --git a/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/SpigotGUIMenuTools.java b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/SpigotGUIMenuTools.java new file mode 100644 index 000000000..75f3c5c5e --- /dev/null +++ b/prison-spigot/src/main/java/tech/mcprison/prison/spigot/gui/SpigotGUIMenuTools.java @@ -0,0 +1,607 @@ +package tech.mcprison.prison.spigot.gui; + +import java.util.ArrayList; +import java.util.List; + +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; + +import com.cryptomorin.xseries.XMaterial; + +import tech.mcprison.prison.spigot.gui.guiutility.Button; +import tech.mcprison.prison.spigot.gui.guiutility.ButtonLore; +import tech.mcprison.prison.spigot.gui.guiutility.PrisonGUI; +import tech.mcprison.prison.util.Text; + +public class SpigotGUIMenuTools +{ + + public static final String GUI_MENU_TOOLS_PAGE = "GUIPage"; + public static final String GUI_MENU_TOOLS_COMMAND = "Command: "; + public static final String GUI_MENU_TOOLS_COMMANDS_BACK = "CommandsBack: "; + + private static SpigotGUIMenuTools instance; + + private XMaterial menuStateOn1; + private XMaterial menuStateOn2; + + private XMaterial menuStateOff1; + private XMaterial menuStateOff2; + + private XMaterial menuBackground; + + private XMaterial menuGoBack; + + private boolean useDisabledButtons; + + +// private String loreCommand; + + private SpigotGUIMenuTools() { + super(); + + this.useDisabledButtons = false; + + this.menuStateOn1 = XMaterial.LIME_STAINED_GLASS_PANE; + this.menuStateOn2 = XMaterial.GREEN_STAINED_GLASS_PANE; + + this.menuStateOff1 = XMaterial.PINK_STAINED_GLASS_PANE; + this.menuStateOff2 = XMaterial.RED_STAINED_GLASS_PANE; + + this.menuBackground = XMaterial.BLACK_STAINED_GLASS_PANE; + + this.menuGoBack = XMaterial.BARRIER; + +// this.menuStateOff1 = XMaterial.BLACK_STAINED_GLASS_PANE; +// this.menuStateOff2 = XMaterial.GRAY_STAINED_GLASS_PANE; + + } + + public static SpigotGUIMenuTools getInstance() { + if ( instance == null ) { + synchronized ( SpigotGUIMenuTools.class ) + { + if ( instance == null ) { + + instance = new SpigotGUIMenuTools(); + instance.internalInitalize(); + } + } + } + return instance; + } + + + + public class GUIMenuPageData { + + private int totalArraySize; + + private int pageSize = 45; + private int page; + + private int dimension; + + private int posStart; + private int posEnd; + + private int pagePrior = -1; + private int pageNext = -1; + + private int pageLast = 1; + + private String commandToRun; + + private String commandGoBack; + + private List