Compare commits

..
289 Commits
Author SHA1 Message Date
Thijs Wiefferink 769f8ee4ca Set version to 2.5.0, ready for release! 2018-10-20 21:58:14 +02:00
Thijs Wiefferink 2c04b87a9f Add the latest Transifex translations for DE, ES and FR 2018-10-20 21:57:05 +02:00
Thijs Wiefferink 8ce1ed0264 Fix showing /as del and /as add in /help for landlords 2018-10-20 18:36:51 +02:00
Thijs Wiefferink 035f8e1932 Possibly fix default value for areashop.limits.default (documentation is inconsistent for not op) 2018-10-20 18:36:51 +02:00
Thijs Wiefferink 4d3482994f Smaller discord image 2018-10-20 15:53:14 +02:00
Thijs Wiefferink 45f1c510e5 Add link to the AreaShop Discord 2018-10-20 15:49:36 +02:00
Thijs Wiefferink 5c13223b9e Fix for 1.13.1, depend on WorldGuard and WorldEdit 7 beta-01 2018-10-20 14:54:52 +02:00
Thijs Wiefferink 8c47ae9b3c Add README.md files in a couple of packages, closes #128 2018-08-12 16:41:03 +02:00
Thijs Wiefferink 28d03a6a3a Small fixes suggested by Intellij IDEA 2018-08-12 16:23:43 +02:00
Thijs Wiefferink aa585e9b11 Deal with empty date/time settings (handle as 'unlimited'/'disabled')
- Fixes #412
2018-08-12 16:17:02 +02:00
Thijs Wiefferink 36d2ce60b9 Disable copying entities (WorldEdit 7), and enable removing entities (WorldEdit 6)
- Fixes security problem of #273:
    - Throw item into a region
    - Rent/buy the region -> it gets saved as schematic
    - Pick up items
    - Unrent/sell the region -> items appear again
    - Pick up second set of items, they got duplicated
2018-08-11 22:31:15 +02:00
Thijs Wiefferink bdea9448a4 Update WorldEdit 7 to build 3817, update WorldGuard 7 to build 1735 2018-08-11 22:19:25 +02:00
Thijs Wiefferink bd2f40f5c8 Use new schematic format when using WorldEdit 7 2018-08-11 22:18:48 +02:00
Thijs Wiefferink 9e908cee73 Fix getting region by location for WorldGuard 7 2018-08-11 22:17:13 +02:00
Thijs Wiefferink 0d326d973d Fix saving/restoring schematics with WorldEdit 7 2018-08-05 12:23:32 +02:00
Thijs Wiefferink 27eaa27765 Add WorldGuard 7 and WorldEdit 7 support, now 1.13 works
- Closes #411
2018-08-05 00:34:50 +02:00
Thijs Wiefferink fb35153eb2 Pull translations from Transifex 2018-07-22 17:52:25 +02:00
Thijs Wiefferink aec6295516 Remove dependency on javafx 2018-06-17 17:14:23 +02:00
Thijs Wiefferink 38cd77e487 Fix compilation error in the import command 2018-06-01 19:54:02 +02:00
Thijs Wiefferink 6b9866a4c4 Ignore hidden files in the /regions directory (like .DS_Store) 2018-05-29 22:58:15 +02:00
Thijs Wiefferink 5aceb81cfd Import: setup permanent region settings when not rentable and buyable 2018-05-29 22:21:43 +02:00
Thijs Wiefferink 50f6bce64e Fix region limits, thanks @ZachryWilsn for reporting! 2018-05-29 21:59:55 +02:00
Thijs Wiefferink f713edc5b5 Disable moneyback message in /as info if sellDisabled is true 2018-05-26 01:33:23 +02:00
Thijs Wiefferink 012920a51c Cleanups because of Intellij IDEA inspections 2018-05-23 23:46:57 +02:00
Thijs Wiefferink 6154454f96 Indicate if a region has already been added with another world
- Closes #287
2018-05-23 22:53:07 +02:00
Thijs Wiefferink e34daeb5ff Update readme to use issue template selection link 2018-05-23 22:38:12 +02:00
Thijs Wiefferink 0a2dc22c59 Setup issue templates 2018-05-23 22:29:29 +02:00
Thijs Wiefferink 2482bd88c2 Add option to ignore regions for limit calculation
Set `countForLimit` to `false` in default.yml, a group or the region file to ignore it for limits
2018-05-23 22:13:42 +02:00
Thijs Wiefferink e86281ab28 Safer sign update, don't assume location/world still exists 2018-05-12 14:41:45 +02:00
Thijs Wiefferink 5a9ca74b75 Add option to disable selling and reselling your own regions 2018-05-10 20:07:10 +02:00
Thijs Wiefferink d301be2304 Add licence, issues and CI to the root pom file 2018-04-03 22:44:16 +02:00
Thijs Wiefferink a23c6fa66f Hide progress messages of region update, speed up region updates 2018-04-02 20:05:38 +02:00
Thijs Wiefferink cd63517041 Fix list of region names for error indicating missing worlds 2018-04-02 20:00:22 +02:00
Thijs Wiefferink e3043c476b Fix available languages link 2018-04-02 12:10:34 +02:00
Thijs Wiefferink 3be7573863 Parse currency prefix and suffix with InteractiveMessenger
- Allows proper colors and escaping
2018-03-09 11:50:08 +01:00
Thijs Wiefferink 51161fffee Remove unused chunkunload event 2018-03-09 11:08:15 +01:00
Thijs Wiefferink c82067ad0b Add back Paypal donate button 2018-02-17 19:04:18 +01:00
Thijs Wiefferink 46dbb8d22c More customizable metric suffixes, better currency formatting
- 'metricSymbols' section in 'config.yml' to customize the used suffixes for large numbers
- Remove trailing zeros from numbers with metric suffix
- Properly handle rounding of 1.235 to 1.24 (different double to BigDecimal conversion)
- Closes #373
2018-02-12 14:44:48 +01:00
Thijs Wiefferink cace086466 Add UTF8 awareness flag in plugin.yml
- I think it only does something if you use JavaPlugin#getConfig(), but it does not harm either
2018-02-12 12:49:04 +01:00
Thijs Wiefferink 06a716b1fd Make %uuid% available to schematics when selling a region
- Schematic save/restore would happen after removing the owner, which means %uuid% would be null
- Unrenting already does the save/restore before removing the renter, so now it is more consistent
- Thanks to Behoston on Github for reporting the issue
- Closes #383
2018-02-01 13:59:48 +01:00
Thijs Wiefferink 4530717045 Command confirmation for /as import
- Can also be used for all WordEdit based add/delete actions in the future
2018-01-26 16:16:11 +01:00
Thijs Wiefferink 741bbd879f Fix hashCode() of RegionSign 2018-01-26 14:33:27 +01:00
Thijs Wiefferink 8474edd29d Save region name as given to /as add and /as stack
- Previously the WorldGuard region id was used, converting the name to lowercase
2018-01-26 13:55:41 +01:00
Thijs Wiefferink d4df691166 FIx usage of > in javadocs 2018-01-26 12:15:10 +01:00
Thijs Wiefferink 3e247e6cb1 Move sign listeners into SignsFeature
- Fix removing signs not removing it from the signsByChunk map
2018-01-26 12:08:22 +01:00
Thijs Wiefferink f3527134e8 Prevent chunk loading by sign updates
- When sign needs update, only do it if the chunk is already loaded
- If a chunk gets loaded (by a player or something else), update any signs in that chunk
- Improve some javadocs, let checkstyle require @param, @throws and @returns
2018-01-22 18:12:15 +01:00
Thijs Wiefferink 0e14b121b8 InfoCommand: fix showing list of signs (was only showing the first one) 2018-01-22 18:08:16 +01:00
Thijs Wiefferink 8cc632fc05 Pull latest translations from Transifex (automated script) 2018-01-22 16:31:03 +01:00
Thijs Wiefferink 77c1b3f288 Fix error in help message of the import command 2018-01-22 16:10:02 +01:00
Thijs Wiefferink 21339cbf7c Fix incorrect message reference for /as message 2018-01-22 16:07:52 +01:00
Thijs Wiefferink 0351188671 Update live support link 2018-01-21 22:10:02 +01:00
Thijs Wiefferink 47e1d80821 Add live support chat link to 99messages 2018-01-18 16:16:40 +01:00
Thijs Wiefferink 1d0472b052 Improve feedback when placing [as] sign for region that is not added 2017-12-22 12:25:30 +01:00
Thijs Wiefferink 22dcfc76af Fix confirmation messages of /as del (failed refactor)
Thanks Noudux for reporting it!
2017-12-21 18:09:55 +01:00
Thijs Wiefferink 6b59176048 Fix startup error: call init method of the scheduling library 2017-11-27 10:02:51 +01:00
Thijs Wiefferink 5dc4d11408 Fix missing spaces in /as message messages 2017-11-26 23:49:42 +01:00
Thijs Wiefferink 00bd305381 Use Map#putIfAbsent where applicable 2017-11-26 16:01:05 +01:00
Thijs Wiefferink 9daa50b23b Use BukkitDo scheduling library
- Much cleaner code for scheduling tasks,
- Makes proper use of Java 8 functionality
2017-11-26 15:47:51 +01:00
Thijs Wiefferink 33b73a0369 Remove Paypal donate button 2017-11-25 17:07:54 +01:00
Thijs Wiefferink 591540af30 Partially fix problem with importing regions from RegionForSale
- When checking the type of a region AreaShop would only look at the settings of the region, not the settings of the world, parent regions and config.yml
- Checking parent regions for these settings should still be added (requires bigger changes)
2017-11-23 22:54:55 +01:00
Thijs Wiefferink 4e1e50e993 Fix /as linksigns <profile> for configs without signProfiles
The `signProfiles` section is not in the default config.yml file anymore, so getting that section can return null
2017-11-20 09:19:35 +01:00
Thijs Wiefferink 9a52ca3d9b Add missing @return Javadoc for RegionGroup#getAutoRegions() 2017-11-10 00:04:39 +01:00
Thijs Wiefferink 858b019806 Add option to teleport X blocks away from the sign
- Implements #364
- Option `general.teleportSignDistance` to `default.yml` to set the number of blocks to teleport away from the sign
- Changes the pitch/yaw of the player so that he faces the sign
- Handles wall and floor signs in any direction
- Improve SignsFeature code structure
2017-11-09 23:56:18 +01:00
Thijs Wiefferink b1dfe93088 Add RegionForSale import, rental auto-extend and other things
- `/as import RegionForSale`, as requested in #98:
    - Imports all regions from RegionForSale
    - Converts almost all settings to their AreaShop equivalent
    - Handles parent regions
- Add `rent.autoExtend` for use with rental regions to automatically extend the rent when the time is out, start of #29, still need the command
    - Vault compatible permissions plugin is required to let this work while the player is offline
    - All permissions, limits and the player balance are checked as during a normal rent
- Add option to region groups to automatically add all regions of a certain world
- BREAKING: Region events now use OfflinePlayer instead of Player
- Automatically import existing region owners/members when adding a region to AreaShop

There are still a couple of things missing in the import and it needs to be tested a lot.
2017-10-20 13:41:30 +02:00
Thijs Wiefferink 0bf2314f2a Add licence (as already listed on BukkitDev) 2017-10-16 11:56:04 +02:00
Thijs Wiefferink 33ddb8ae88 Fix %volume% for polygon regions
- WorldGuard does not implement volume() for Polygon regions, always returns 0
- Volume result is cached, calculating it for polygon regions could be slow
2017-10-05 16:53:42 +02:00
Thijs Wiefferink 234e4b6261 Prevent indirectly breaking signs with non-solid blocks
- Fixes #358
2017-10-05 13:43:27 +02:00
Thijs Wiefferink ed2ffaeaa3 Move base command to EN.yml for /as info paging 2017-10-05 13:15:51 +02:00
Thijs Wiefferink e073438862 Add %volume% variable to get the number of blocks in a region
- Works properly for polygon regions
2017-10-05 12:20:03 +02:00
Thijs Wiefferink 07194f07da Add region masking to schematic restore
- When restoring a schematic the paste is masked to the region blocks, so that only blocks that are actually inside the region are pasted (necessary for polygon regions)
- Closes #20
2017-10-01 19:49:05 +02:00
Thijs Wiefferink dfa3e0be66 Checkstyle fix 2017-09-04 17:09:31 +02:00
Thijs Wiefferink 8eef029400 Fix %month% variable using 0-11 instead of 1-12
- Fixes #354, thanks skippyaut
2017-09-04 16:58:39 +02:00
Thijs Wiefferink c8d869ce15 Fix usage of teleport location set by '/as settp'
- It was accidentally trying to get the teleport location from the plugin config file instead of the region config file.
- Also added the possibility to set the teleport location in groups and default.yml
2017-08-05 20:25:06 +02:00
Thijs Wiefferink 053d75181d Update to InteractiveMessenger 1.1-SNAPSHOT
- Ensures AreaShop is rebuild when InteractiveMessenger updates
- Fixes crash bug that was in InteractiveMessenger
- Fixes #334
2017-07-30 17:25:49 +02:00
Thijs Wiefferink f0128c221b Update README.md 2017-06-23 14:59:16 +02:00
Thijs Wiefferink ce6c01c5d0 Add Transifex translation stats image 2017-06-23 14:54:19 +02:00
Thijs Wiefferink b835c4dded Only reset WorldGuard flag/groupFlag if not already empty 2017-06-12 22:05:09 +02:00
Thijs Wiefferink 07e6782714 Fix /as setowner for regions that are not rented yet
Add a rental period to the time when setting owner of a rental region that is not rented yet, otherwise it would get expired immediately
2017-06-12 21:58:42 +02:00
Thijs Wiefferink 4002956aeb Fix javadoc comments 2017-06-12 20:42:36 +02:00
Thijs Wiefferink 0b96b9cb42 Github update checker, Java 8
- Add Github update checker, closes #201, it is implemented to allow reuse by other plugins, it will probably move to a separate repository later
- Switch to Java 8, if people did not update already they probably never will
- Add used Bukkit version as property, use that in all pom files
- Add Task class with methods to easily use BukkitRunnable (not all code is migrated to this pattern yet)
2017-06-12 20:39:28 +02:00
Thijs Wiefferink 0c192c2444 Cleanup setOwners/setMembers, only edit WorldGuard region if different
- Improve code layout for changing owners and members of WorldGuard regions
- Only edit flags and other WorldGuard region settings if they are different than the current option, this prevents useless saves in WorldGuard (which shows a message in console)
2017-06-12 20:39:28 +02:00
Thijs Wiefferink 2381aaeacc Remove link to Shop plugin because it is not fixed yet 2017-04-30 14:15:35 +02:00
Thijs Wiefferink 906b331758 Fix line endings in config.yml 2017-04-20 23:35:49 +02:00
Thijs Wiefferink f0f2e09be0 Always add English time indicators
- Internal timers specified using settings in hiddenConfig.yml use the English words, so if you remove the English words from config.yml timers do not run (regions not expiring, no notifications, no file saving)
- Warn in console when an unknown time specifier is found, might get spammy but at least gets the point across
2017-04-20 23:23:57 +02:00
Thijs Wiefferink 395cc6de07 Fix usage of 'resale' in 'default.yml' for 'flagProfile' section
- 'resale' was used instead of 'resell' (as defined in GeneralRegion#RegionState) in the 'flagProfile' section, causing the flags not getting applied when the region is in reselling state.
- Added fallback to 'resale' section if 'resell' section is not present (to properly read old config.yml/default.yml files)
- Fixed usage of '%resaleprice%' in the resale greeting, should be '%resellprice%'
- Fixes #303, thanks electro2560 for the great bug report!
2017-04-20 15:26:26 +02:00
Thijs Wiefferink 3b9d6187ca Fix checkstyle fail 2017-04-17 21:34:32 +02:00
Thijs Wiefferink 9d1585f513 Fix groups file getting cleared on server start
- Fixes #299
- Because of an earlier change the groups file is loaded before regions are loaded on server start, and region groups remove themselves if there are no valid regions in them anymore.
- Keep groups even though they are empty (so that configuration done in the group is not lost)
2017-04-17 21:32:15 +02:00
Thijs Wiefferink 9d6955039a Fix '/as groupdel' with non-existing group creating an empty one 2017-04-17 21:26:24 +02:00
Thijs Wiefferink 747b47057b Allow # in region name for /as stack to determine counter position 2017-04-11 21:22:35 +02:00
Thijs Wiefferink a973e254e6 Fix '/as addfriend' not allowing you to add players that are playing for the first time
- Fixes #297
2017-04-02 22:34:02 +02:00
Thijs Wiefferink a5105af3ad Add 'use' flag to default.yml again since people mess it up 2017-03-29 20:18:14 +02:00
Thijs Wiefferink 0bb0a05b76 Cleanup checkstyle from pom.xml in AreaShop module 2017-03-29 20:17:42 +02:00
Thijs Wiefferink dad502ec0c Add checkstyle to enforce formatting, change all formatting to comply 2017-03-29 20:15:44 +02:00
Thijs Wiefferink f471b9bbf0 Don't show 'in advance renting:' in '/as info' if maxExtends is zero
- Thanks to R0bstar for noticing this weird weird message combination
2017-03-09 16:14:30 +01:00
Thijs Wiefferink f69d1c41e6 Code cleanup and stricter visibility of methods/variables 2017-03-09 16:01:36 +01:00
Thijs Wiefferink 4ea6f59c49 Remove GeneralRegion#is{Rent|Buy}Region()
- It served no purpose and prevents IDEs from detecting type safety
2017-03-09 15:29:01 +01:00
Thijs Wiefferink 0b7158290f Add some more bStats statistics 2017-03-09 15:09:05 +01:00
Thijs Wiefferink e6757d23de Add bStats analytics
- Add bStats analytics because MCStats is down constantly
- Add custom graphs:
  - Language pie chart
  - Number of registered regions
  - Number of rental regions
  - Number of buy regions
- Closes #287
- In the future MCStats can be removed, for now I would like to keep complete data there for the times it does work
- Could add more graphs in the future for number of friends and things like that
2017-03-02 18:14:07 +01:00
Thijs Wiefferink 7cda35f4da Remove duplicate link in the readme 2017-02-12 20:04:35 +01:00
Thijs Wiefferink ee293d14b9 Fix link to CI in the readme 2017-02-12 20:03:46 +01:00
Thijs Wiefferink 2e0fce4955 Update repository url 2017-02-09 14:59:53 +01:00
Thijs Wiefferink 7afdefc9ed Add missing javadoc to loadFiles methods 2017-02-02 23:03:55 +01:00
Thijs Wiefferink 11f80e7ed1 Start using InteractiveMessenger
- Messaging functionality has been split into the InteractiveMessenger project: https://github.com/NLthijs48/InteractiveMessenger
- Jenkins build server has been changed to publish a Maven repository: http://jenkins.wiefferink.me/plugin/repository/everything
2017-02-02 22:59:00 +01:00
Thijs Wiefferink 40d45c7786 Fix using landlordName setting without using landlord (uuid) setting 2017-02-02 17:20:26 +01:00
Thijs Wiefferink 6b8e161e43 Ensure buy/rent/resell price is never below zero
This prevents problems with negative payment or withdrawal in Vault if input validation of a command is not good enough or if a price has manually been set below zero.
2017-02-02 17:18:26 +01:00
Thijs Wiefferink e1b2f7391c Improve message when you cannot rent/buy a region
The message did not specify which region cannot be rented/bought, which has now been added.
2017-02-02 16:45:15 +01:00
leNic 89ae8b9b4a Fixed reselling with negative prices (#280)
Prevents setting a negative resell price,. Some economy plugins accept a withdraw with a negative number, which has bad consequences (for example EssentialsEco does not accept it).
2017-01-28 20:25:24 +01:00
Thijs Wiefferink fab415bf19 Speed up expiration and expireWarning tasks
The expire task was triggering more often than the expireWarning task, causing lost warnings when warnings with a low time are specified
2017-01-23 14:26:25 +01:00
Thijs Wiefferink c7aa92be81 Indicate in default.yml that expressions can be used for region prices 2017-01-13 19:25:31 +01:00
Thijs Wiefferink 705c8d6891 Update README.md 2017-01-13 18:42:04 +01:00
Thijs Wiefferink 429d87c9ff Improve feature list 2017-01-13 18:41:16 +01:00
Thijs Wiefferink 1fdd8b32cc Add prices depending on a formula
- Price can be specified with an expression (JavaScript syntax)
- You can also use a block of JavaScript code, the value of the last line is used as result (for more complex logic)
- Supported settings: rent.price, buy.price, rent.moneyBack, buy.moneyBack (need more? ask me)
- Before evaluating the expression all region variables as defined in the config.yml file will be replaced (allows you to use %width% etc)
- Added %timesExtended% variable for use in expressions (to know how long the user is renting for)
- '/as setprice' and signs still only allow number input to prevent security problems (this means actual config access is required to do anything of harm with JavaScript)
- Closes #23
2017-01-13 16:56:02 +01:00
Thijs Wiefferink 7900f78a8c Change default WorldGuard flags to include block-place and block-break
Way too many people set the block-break and block-place flags on bigger or even the global region to deny (which is unnecessary and wrong relatively, for global use 'passthrough: deny' instead) so this patches up those mistakes by setting them at the AreaShop region
2017-01-13 16:06:18 +01:00
Thijs Wiefferink 3a65a88849 Fix replacing variables into language variables
- Previously it would insert it as a message, causing the language variable to be split up into multiple parts (which prevents recognizing it later)
- If a Message is marked as inline with Message#inline() it will be inserted without breaking up the message
2016-12-27 16:17:04 +01:00
Thijs Wiefferink 7b491d0389 Lazily instantiate feature classes to improve performance 2016-12-27 16:15:17 +01:00
Thijs Wiefferink fd02c51492 Add setting to prevent cross-world teleportation with '/as find'
- If a region is in another world and 'findCrossWorld' is off, it will be filtered from the results
- 'teleportCrossWorld' will not be checked anymore if the teleport is called from '/as find'
- Resolves  #234
2016-12-26 23:29:40 +01:00
Thijs Wiefferink bb1f592807 Add setting to prevent cross-world teleportation with '/as tp'
Related to #234
2016-12-26 23:20:12 +01:00
Thijs Wiefferink 16c7a044ea Add and make use of escaping in messages
- Add escaping support to FancyMessageFormat: put a backslash before a tag and it will not be interpreted, also works for color codes (&2 and §2) and variables
- Make use of escaping in the Message class to properly handle user input as plaintext (previously user input that got printed back also got interpreted, like colors apply to it)
- All replacements given to Message are escaped, unless you wrap them in a Message before it.
- Replacement limits and infinite replacing detection have changed slightly
2016-12-26 22:56:35 +01:00
Thijs Wiefferink 152f183670 Fix region update after /as reload, cleanup unused code 2016-12-25 23:02:23 +01:00
Thijs Wiefferink 09b6e4c584 Fix string setting as profile in default.yml
- This has been broken in b525c5902c
- Fixes #267
2016-12-25 22:40:11 +01:00
Thijs Wiefferink aeb70196a3 Fix shutdown exception in SignsFeature 2016-12-24 19:59:04 +01:00
Thijs Wiefferink 62148ea577 Move teleportation code to a feature class 2016-12-23 23:25:41 +01:00
Thijs Wiefferink fcc9fb0945 Refactor to introduce Manager and RegionFeature
- Manager to serve as abstract class for managers (like FileManager), implements a lifecycle to allow for shutdown operations (like save all files)
- RegionFeature to server as abstract class for region features
- Improve instantiation and lifecycle of features (global features and region specific ones)
- This is preparation for moving more region functionality into feature specific classes (which makes GeneralRegion smaller and easier to maintain)
2016-12-23 16:03:22 +01:00
Thijs Wiefferink b525c5902c Fix default settings leaking when getting configuration sections
- Default settings and custom settings are in separate YamlConfiguration instances now to prevent leaking
- When getting a configuration section you now know that either it is from the current default.yml file or the default.yml file in the jar (querying settings from the section will always have the same source)
- Fixed a startup null pointer
- Fixed #266
2016-12-23 14:07:26 +01:00
Thijs Wiefferink b18a7cc6d5 Fix [break] in hover lines
Hover lines are still a bit broken when trying to insert complex messages into them, this is hard to do in a proper way though.
2016-12-10 15:19:34 +01:00
Thijs Wiefferink 54b6e84558 File loading improvements to be more robust 2016-12-04 21:14:31 +01:00
Thijs Wiefferink bae3c0a199 Ask for config files in the issue template 2016-12-04 17:56:37 +01:00
Very Evil Olaf 508270a280 Update ISSUE_TEMPLATE.md (#258)
Note that 'latest' is not a correct version
2016-12-04 17:48:36 +01:00
Thijs Wiefferink 87b2cb9ecd Prevent exceptions if a schematicProfile does not exist 2016-12-04 17:31:22 +01:00
Thijs Wiefferink 271b17b6be Set version to 2.4.0 and update language files 2016-12-02 14:37:27 +01:00
Desjardins Jérôme 1dfedea50c Create a permission for teleporting to available regions (#241)
* Update GeneralRegion.java
Add Available abstract function
Check Permission modification

Update BuyRegion.java
Add Available function for selled

Update RentRegion.java
Add Available function for rented

Update TeleportCommand.java
Check new permission

Finish feature teleport available region

* Fix translation
2016-11-19 17:15:23 +01:00
Thijs Wiefferink d9abe2e347 FIx problem with null regionFlags sections 2016-11-14 18:02:59 +01:00
Thijs Wiefferink 1ba2e21ae9 Make profile based settings easier to understand
- Remove 'signProfiles', 'flagProfiles', 'eventCommandProfiles', 'schematicProfiles' and 'expirationWarningProfiles' from the config.yml file
- Add the removed profile contents directly to the setting without the trailing 's' in the default.yml file (this prevents the need to understand the creation of profiles, and then assigning them, taking out a step in the thought process of users)
- Added method in GeneralRegion to get a ConfigurationSection from the region file, group files or default file while also taking into account the translation from a string to a profile that is defined in the config.yml file. This ensures backwards compatibility with current config files (the old style will not be promoted anymore though).
- The 'expirationWarningProfiles' does not have the subkeys 'warnPlayer' and 'commands' anymore, it is just a list of commands now, using the '/areashop message' command to warn a player.
- Add a workaround for the empty sign problem after unrent/sell of a region while having restore enabled, an AsyncWorldEdit plugin installed and signs inside the region (sign will be updated again half a second after unrent/sell).
2016-11-13 00:44:35 +01:00
Thijs Wiefferink fcdfdc6094 Update language files
- Swedish is added
- German, French and Russian are improved
2016-11-07 14:13:03 +01:00
Thijs Wiefferink 8a7e2ba5c2 Indicate limits when a MaxChangedBlocksException is thrown by WorldEdit 2016-11-07 13:52:54 +01:00
Thijs Wiefferink 0950452692 Fix a couple of problems caused by vertical /as stack addition 2016-10-31 21:07:08 +01:00
Thijs Wiefferink 293978f068 Decouple Message class from replacement providers
- Instead of applying replacements by testing for a replacement that has the GeneralRegion type, it now checks for a ReplacementProvider instances (one step closer to making Message independent of AreaShop).
- Replacements are handled one by one with a switch-case instead of getting them from a map, helps performance a lot.
2016-10-25 20:57:58 +02:00
Thijs Wiefferink 5efe14b8e9 Add up and down direction for '/as stack'
Prevents creating regions above and below the world limits, still needs
testing.
Progress for #105
2016-10-24 15:02:49 +02:00
Thijs Wiefferink 839d510151 Switch from Bukkit to Spigot Maven repo since it is down
Also switched from Bukkit 1.7.9 to Bukkit 1.8.0 because that is the lowest version available on the Spigot repo
2016-10-17 23:45:08 +02:00
Thijs Wiefferink 9180d9b8ee Fix small language file issue
When you only have a formatting code before a language variable, the hover/click effects will accidentally be applied to one text part earlier
2016-10-16 18:29:26 +02:00
Thijs Wiefferink 7aa786f4ce Fix default config trying to execute /as message as player
Fixes #221
2016-09-04 22:43:03 +02:00
Thijs Wiefferink 10ea8540e7 Add tab completion for '/as me [player]'
Closes #220
2016-09-04 00:59:04 +02:00
Thijs Wiefferink dba00769f6 Fix problem with line breaks 2016-09-03 20:58:45 +02:00
Thijs Wiefferink 44c70c6a33 Cleanup messages about region that does not exist in WorldGuard 2016-09-03 19:46:05 +02:00
Thijs Wiefferink 570f7b4055 Don't extend rent when using '/as setowner' to set a different owner
Also remove new owner from the friends list.
Fixes #219
2016-09-03 19:19:40 +02:00
Thijs Wiefferink feafa012dd Fix issue with \n on 1.7.x servers
- Each line of a message will now be sent separately instead of using '\n' in the text
- Drastically reduced the number of StringBuilders that are instantiated during message construction
- Fixes #222
2016-09-03 17:22:40 +02:00
Thijs Wiefferink 82b340ce1a Messages: also parse section signs into color tags properly
Fixes line-wrapping removing color in some cases
2016-09-02 21:43:58 +02:00
Thijs Wiefferink 93809f27fc Rename events to be consistent with commands
- AddFriendEvent -> AddedFriendEvent
- DeleteFriendEvent -> DeletedFriendEvent
- RemovedRegionEvent -> DeletedRegionEvent
2016-08-28 22:45:20 +02:00
Thijs Wiefferink f8ed3654fd Fix compilation error 2016-08-28 22:31:06 +02:00
Thijs Wiefferink 58a1afccf3 Invert inheritance of RegionEvent and CancellabelRegionEvent/NotifyRegionEvent 2016-08-28 22:29:45 +02:00
Thijs Wiefferink d9c3573225 Change RegionUpdateEvent to UpdateRegionEvent
This breaks plugins using the event
2016-08-28 22:21:33 +02:00
Thijs Wiefferink 1577443203 Generalize events better
Adds generic classes for events with a region (BuyRegion, RentRegion or GeneralRegion)
2016-08-28 22:11:17 +02:00
Thijs Wiefferink ab7a92c57d Update README.md 2016-08-26 19:49:21 +02:00
Thijs Wiefferink 2e09b0f60f Update README.md 2016-08-26 19:48:59 +02:00
Thijs Wiefferink 6e5c35f95b Add extension plugins section 2016-08-26 19:45:37 +02:00
Thijs Wiefferink 066ceedafd Add 'build' flag by default to prevent inheriting from parent regions. 2016-08-21 22:20:25 +02:00
Thijs Wiefferink c8ebe24bd3 Put break in '/as info' help message in the right spot 2016-08-19 20:52:07 +02:00
Thijs Wiefferink ad7db5ee23 Attempt to fix unable to add new players with '/as addfriend' 2016-08-16 22:43:09 +02:00
Thijs Wiefferink f80a8178ff Fix formatting not clearing on new lines 2016-08-13 22:28:15 +02:00
Thijs Wiefferink 05c8e1a7e4 Make loggin methods more generic 2016-08-10 16:07:39 +02:00
Thijs Wiefferink 9904805310 Improve version detection of WorldGuard
- First detect version 5
- Then detect lower than 6.1.3
- Else check build number:
  - Build number exists and lower than 1672: 6
  - Build number exists and Is 1672: broken
  - Else: 6_1_3
2016-08-09 22:56:21 +02:00
Thijs Wiefferink 0df2f429c0 Only print build number warning if we found it 2016-08-09 22:38:33 +02:00
Thijs Wiefferink b3408a2648 Fix compilation error and WorldGuard version detection 2016-08-09 21:52:53 +02:00
Thijs Wiefferink e1f89e7904 Cleanup some leftover logging in an old style 2016-08-08 22:06:31 +02:00
Thijs Wiefferink 064b129205 Change version to 2.3.2 and update languages
- Russian has been added
- Spelling errors in French have been corrected
2016-08-07 22:21:57 +02:00
Thijs Wiefferink 8111387f32 Improve friend line of /as me, add click hint
Change blue color of hover popup to gold, which will be used as action color
2016-08-07 22:06:09 +02:00
Thijs Wiefferink a4b23bebba Improve line of rented regions in info command 2016-08-07 21:49:44 +02:00
Thijs Wiefferink 7421e685fa Improve robustness of variable replacing in messages
- Once the limit is reached the argument replacer would still continue sometimes (if a the replacement itself triggers the limit and the inserted message increases the size of the message we are building and adds a parameter tag again, like %0%)
- The language tag replacer also stops earlier now, it did not have the above problem though
- Fixed FancyMessageFormat.insertMessage() not checking its parameters
- Message.get() with a limit will now return an empty message if the limit is reached to prevent problems like above.
- Closes #205
2016-08-07 00:09:30 +02:00
Christoph Krüger @Androkai 374b68d8fa Update VaultAPI-repo (#206)
The url of the Vault Maven repository has changed.
2016-08-06 22:36:26 +02:00
Thijs Wiefferink ca7a9664f3 Fix error in info command of rental region 2016-08-02 22:27:55 +02:00
Thijs Wiefferink e957b4fc73 Remove all reflection for sending fancy messages
- Reflection removed
- JSON is now fully escaped instead of lenient escaping
- Sending is now done with /tellraw
2016-08-01 21:31:14 +02:00
Thijs Wiefferink 6493bc4f78 Add empty lines if a page does not fill the screen
Relevant for commands like `/as info all` that can have pages
2016-08-01 21:28:11 +02:00
Thijs Wiefferink 2db1b6a243 Prevent updater throwing errors sometimes when BukkitDev is offline 2016-08-01 20:46:40 +02:00
Thijs Wiefferink 864662a3c4 Add javadocs to limitgroup inner class and setting methods 2016-08-01 20:23:49 +02:00
Thijs Wiefferink 59b960b87c Update languages, set version number to 2.3.1
- Added German translation
- Added French translation
- Added Norwegian translation
2016-08-01 19:36:50 +02:00
Thijs Wiefferink 2de653d73f Add automatic conversion of language files downloaded from Transifex 2016-08-01 18:03:09 +02:00
Thijs Wiefferink 4feee59834 Cleanup info and warning messages. 2016-08-01 16:18:05 +02:00
Thijs Wiefferink 816d136a62 Change version number to 2.3.0, update languages
- Only English and Dutch are available yet
2016-07-24 21:48:39 +02:00
Thijs Wiefferink 121de7dc7e Add build number option to Maven
- Build number option can be used by Jenkins to add the build number
- Build number of soruce on Github will be #CUSTOM to mark custom builds
- Release versions will not contain a build number
- Closes #185
2016-07-24 20:59:25 +02:00
Thijs Wiefferink f7c86881cc Fix the default flagProfiles settings, fix migration issues. 2016-07-24 20:25:58 +02:00
Thijs Wiefferink 351d51b664 Correct message for reselling region entries. 2016-07-23 19:31:45 +02:00
Thijs Wiefferink 5a28476cf0 Add better limits for messages
- Recursive replacements are handled by catching stackoverflow exceptions
- Messages are limited 30000 in length for the produced JSON string since the client cannot handle more
- Error message print out the message key and start of the message
2016-07-23 17:21:08 +02:00
Thijs Wiefferink 8143bdae27 Add pages to the /as info command to prevent crashes
- Output displayed in pages of 18 (+ header and footer it fills the max of 20 you can see without scrolling)
- Footer shows current and max page, and has buttons to go to next/previous
- Commands accept [group] [page] both as optional arguments, works because page is a number (number as group would be weird)
- Entries show basic info about regions (owner/price/duration), and of course can be clicked to show all info
- Made debug command more generic
- Closes #172
2016-07-23 02:57:31 +02:00
Thijs Wiefferink b62744fe10 Add warnings for missing settings in limit groups.
Closes #164
2016-07-21 23:00:19 +02:00
Thijs Wiefferink fe0b63c760 Remove incorrect check 2016-07-17 23:51:24 +02:00
Thijs Wiefferink def774c7a1 Link javadoc of external classes properly
Classes of Bukkit, WorldGuard and WorldEdit that appear in the javadoc now link to the javadoc of them.
2016-06-27 23:38:44 +02:00
Thijs Wiefferink 7c5cb5f5aa Add javadoc to getApplicableRegions methods 2016-06-27 23:16:21 +02:00
Thijs Wiefferink 8af6e1d6f1 Fix small Maven warning 2016-06-25 22:20:21 +02:00
Thijs Wiefferink e0e6c39dae Fix WorldGuard version detection for later stable releases 2016-06-21 22:42:56 +02:00
Thijs Wiefferink dabe46bd47 Move all sign related methods into SignsFeature
- Each GeneralRegion now has a SignsFeature
- Each SignsFeature contains RegionSign instances representing the actual signs
 - The RegionSign class contains methods to update them etc
 - There is one SignsFeature that is not linked to a region, but registered as listener to update the signs at events
2016-06-20 20:16:13 +02:00
Thijs Wiefferink ec478a05d1 Move region friends code to separate Feature class 2016-06-20 18:22:35 +02:00
Thijs Wiefferink e21c0aafde Add events for adding/removing friends
- Cancellable event for adding friends: AddFriendEvent (region, friend and who is trying to add it available)
- Cancellable event for removing friends: DeleteFriendEvent (region, friend and who is trying to delete it available)
- Closes #54
2016-06-20 17:03:12 +02:00
Thijs Wiefferink 52bf88f4a5 Prevent RemovedRegionEvent triggering twice
Add debug logging for RemovedRegionEvent and AddedRegionEvent
2016-06-20 16:32:10 +02:00
Thijs Wiefferink e4de560a65 Prevent Maven warning
It was trying to include the WorldGuard6 handler class twice in the jar file
2016-06-20 16:28:23 +02:00
Thijs Wiefferink 6481da29e4 Add compatibility for WorldGuard build 1674 and up.
- Added a module for WorldGuard 6.1.3 to adapt to changes in flag related methods.
- No compatibility with build 1672, since there is no dependency in the Maven repo of WorldGuard to target this (this is a dev build though so I don't expect people using it long-term)
- Move properties for setting Java version to the parent pom file (other modules inherit them)
- Move repositories to the parent pom file (other modules inherit them)
- Fix AreaShop module not declaring its parent
- Fixes #170
2016-06-18 23:23:22 +02:00
Thijs Wiefferink f287cc91a6 Remove leftover logging 2016-06-13 21:11:00 +02:00
Thijs Wiefferink 95b7b50346 Add development builds and javadocs links 2016-06-13 20:59:08 +02:00
Thijs Wiefferink 21db2ff440 Improve Maven setup for javadoc and source
- Generate a .jar file with the sources if -Dsources is provided
- Generate javadocs if -Djavadoc=/path/to/destination is provided
- Copy final .jar file to directory if -DcopyResult=/path/to/server is provided
- Adding missing javadoc comments
2016-06-13 20:36:17 +02:00
Thijs Wiefferink 36dd978a92 Cleanup the config file and settings
- Moved scheduled task settings to hiddenConfig.yml (settings that are not visible, but still usable)
- Remove 'postCommandErrors' setting
- Also execute commands defined in 'expirationWarningProfiles' when player is not online
- Move around settings in config.yml and improve explanations
- Closes #168
2016-06-13 17:03:20 +02:00
Thijs Wiefferink 6cc3f2a52f Combine all messages about region not registered
And replace mentions of 'this region' with the actual region name.
2016-06-13 14:47:10 +02:00
Thijs Wiefferink 852731b1ad Add action confirmations when using signs
- Confirmations by default for selling/unrenting by signs, not for renting/buying
- Fixed a bug with message composing which would duplicate hover/click parts.
- Added `/as message <player> <message...>` for internal/console use (not shown in help).
- Closes #50
2016-06-12 21:39:12 +02:00
Thijs Wiefferink 30faa77da9 Fix small error in multiple regions found message 2016-06-12 19:38:05 +02:00
Thijs Wiefferink ec57b922b8 Messages: Version fixes, fallback to plain.
- Properly parse NMS version number to support 1.10
- Fallback to plain messages if sending a fancy message breaks (we try again after restart/reload)
2016-06-12 16:48:47 +02:00
Thijs Wiefferink c2bcc6008b Add hover/click to some forgotten mentions of regions 2016-06-12 13:25:55 +02:00
Thijs Wiefferink 72a05bedce Merge personal/all help messages. 2016-06-11 22:40:09 +02:00
Thijs Wiefferink bc73a8b20d Cleanup links to issues 2016-06-11 17:35:00 +02:00
Thijs Wiefferink 832e8218b6 Add issue template for bugs/feature requests 2016-06-11 17:29:47 +02:00
Thijs Wiefferink 6fcb629133 Move to the me.wiefferink package
The nl.evolutioncoding domain is soon not mine anymore, and this new one I do intend on keeping.
2016-06-07 22:39:45 +02:00
Thijs Wiefferink 7d6a1f35c1 Messages: Add hover/click items to region info
- The hover/click parts only appear if you have permission to use the command linked to it
- Red crosses added next to the friends in the friend list to remove them
2016-06-05 17:04:38 +02:00
Thijs Wiefferink 60257d45c2 Messages: Add a bunch of click/hover actions to '/as info region <region>'
- rent/unrent/buy/sell/extend
- teleport, set teleport location
2016-06-04 22:46:10 +02:00
Thijs Wiefferink 2300227d87 Messages: Fix problem with message insertion sometimes missing leftover part 2016-06-04 20:57:14 +02:00
Thijs Wiefferink b1852b10bb Improve /as me, remove /as info player
And change underline to bold for clickable things (underline leaks through in the next line, giving annoying layout issues)
2016-06-02 22:39:30 +02:00
Thijs Wiefferink 88fdb0c3fc Add 'ALL' flagProfiles state that is always applied
And add block-break and block-place by default.
2016-05-31 22:36:18 +02:00
Christoph Krüger 491e55fc77 Change Vault dependency to Maven repo instead of .jar
Use the Maven repository of Vault instead of including a jar file in the repository.
2016-05-28 23:19:23 +02:00
Thijs Wiefferink c7b0a2c663 Let /as help respect the areashop.help permission
Closes #155
2016-05-28 17:04:06 +02:00
Thijs Wiefferink 868f4d6b58 Events: Add refunded money to UnrentedRegionEvent and SoldRegionEvent
Closes #147
2016-05-28 17:00:52 +02:00
Thijs Wiefferink 0d4b034181 Messages: Detect and stop replacement loops. 2016-05-28 16:51:32 +02:00
Thijs Wiefferink 5f20689ba3 Improve language variable argument detection 2016-05-27 21:01:14 +02:00
Thijs Wiefferink 38b658fccf Message changes: click on regions/players
- Click on region name for region details
- Click on player name for regions of the player
- Click on landlord name for regions of the landlord
- Change color codes to things like [blue] instead of &9 (both are supported though)
2016-05-24 23:18:25 +02:00
Thijs Wiefferink 28ed20c0b5 Message system fixes and improved robustness
Hover/click message for '/as info'
2016-05-23 12:16:19 +02:00
Thijs Wiefferink aaff36b2eb Add hover/click support for messages #18
- Language files support a way to add hover tooltips, click commands and click insert commands (using FancyMessageFormat created together with PhoenixIV)
- Language variables support arguments
- Help listing (/as help) uses the new hover/click things, more to come
- See #18 for the TODO list
2016-05-22 21:36:58 +02:00
Spidev46 49b536cab0 There is a mistake with the messages (#153)
Confirmation message of reselling a region does not go to the old owner.
2016-05-22 21:19:10 +02:00
Thijs Wiefferink 9a9969dea3 Fix problems with detecting most important region when placing a sign.
WorldGuard filters child regions from the ApplicableRegionSet for some reason, so setting parent/child relations on regions messes up the detection because the children can never be found.
2016-03-07 12:21:33 +01:00
Thijs Wiefferink 84e4b49bfd Update language files
English, Dutch and German are complete, others are only partially complete.
2016-03-06 00:07:31 +01:00
Thijs Wiefferink 6daaf6997d 1.9 compatibility fixes (getOnlinePlayers() method) 2016-03-05 22:15:21 +01:00
Thijs Wiefferink c445a62334 Add variable support to all messages where a region is known (mostly messages of commands were not using it yet). 2016-02-08 19:39:33 +01:00
Thijs Wiefferink 0d205b0d9e Change general.teleportLocationY to also accept a number. 2016-02-08 14:43:24 +01:00
Thijs Wiefferink 8c33826c2c Add build flag to default flagprofiles, users are often having trouble with this 2016-01-26 22:35:01 +01:00
Thijs Wiefferink 51e1dbafb7 Fix running sign commands going wrong.
Player commands are run first, which normally rents/buys a region, so when the console commands are ran after that, then it will run the commands of the wrong state (since the state just changed). Also fixed a minor WorldGuard version dependency issue.
2016-01-26 22:20:45 +01:00
Thijs Wiefferink 6edad3faff Add priority and interact flag to config.yml by default
50% of the issues are having more regions at the same place, and therefore requiring a higher priority for the AreaShop region and having chests accessible by anyone instead of only the region owner/member. This should fix these problems.
2016-01-12 21:43:04 +01:00
Thijs Wiefferink f89e0f861b Add a link to a preview server 2016-01-08 20:18:47 +01:00
Thijs Wiefferink 770b1d98df Refactoring:
- Move a bunch of utility methods from the AreaShop class to Utils
- Comments styling cleanup
- Display warning in console when region file does not load correctly (is empty)
2016-01-05 22:31:55 +01:00
Thijs Wiefferink 8e5baa47af Fix variables of sell messages 2015-12-26 20:08:01 +01:00
Thijs Wiefferink 367466735e Fix the 'n:<name>' option for member/owner region flags
Before it would keep the 'n:' part when adding the name to the region, therefore adding an incorrect name.
2015-12-26 00:45:05 +01:00
Thijs Wiefferink ade6bc3971 Add AddedRegionEvent+RemovedRegionEvent, moved sign/flags updating
- Sign updating now uses the event system
- WorldGuard region flag updating now uses the event system
- After changes made by commands/other user input it will now use update() on the region instead of the sign and region flag commands.
2015-12-13 19:55:47 +01:00
Thijs Wiefferink 05fd8c0156 Implement event system
- 'ask' type events that can be cancelled, broadcasted before the action happens
- 'notify' type events that cannot be cancelled, but only let you know that it has happened
- Events for renting (with extending flag), unrenting, buying, selling, reselling
- General 'RegionUpdateEvent' to listen to as display service (update signs, update regions flags, etc)

All messages in the GeneralRegion, RentRegion and BuyRegion classes can now use all region variables (in the future all other messages will also be worked through)

Closes #84
Closes #86
2015-12-11 20:54:12 +01:00
Thijs Wiefferink 5403472476 Cleanup/update config.yml and default.yml comments
- Add links to the wiki.
- Make things more consistent.
2015-12-10 23:16:19 +01:00
Thijs Wiefferink c4ee7bc7aa Add 'areashop.linksigns' to the 'areashop.*' permission group 2015-11-24 20:59:58 +01:00
Thijs Wiefferink 940f1969b6 Add link to dev builds on Jenkins 2015-11-24 20:43:44 +01:00
Thijs Wiefferink 07eb5477b8 Update Metrics 2015-11-17 21:21:27 +01:00
Thijs Wiefferink a4112092b5 Fix inclusion of the version specific classes of WorldGuard/WorldEdit in the final jar 2015-11-15 23:47:23 +01:00
Thijs Wiefferink 872d81b0a9 Cleanup code, fix some small bugs
Most of these things have been found with help of Intellij IDEA, preferring it over Eclipse already
2015-11-15 23:35:48 +01:00
Thijs Wiefferink b04871c553 Add rental to max when rental would go above maxRentTime otherwise
- Setting `extendToFullWhenAboveMaxRentTime` to set if AreaShop should
automatically extend to max when the player cannot rent a full duration
because of `maxRentTime`.

Fixes #94
2015-11-11 11:56:16 +01:00
Thijs Wiefferink fd1b8fba4c Fix inactiveSetting debug messages
The messages still assumed the inactiveSettings was in minutes instead
of in milliseconds.
2015-11-02 22:39:40 +01:00
Thijs Wiefferink 991e7b1961 Fix lastActive sometimes not updating correctly
- Update the lastActive time at rent/buy to ensure it is non-zero
- Ignore lastActive time of zero, give back current time
- Update lastActive time at server shutdown for players that are still
online, quit events are not fired at shutdown
2015-11-02 22:32:51 +01:00
Thijs Wiefferink aac963325a CI run :) 2015-11-01 23:03:41 +01:00
Thijs Wiefferink 3e7c7ce76b Fix message variables for '/as info player <player>' feedback 2015-10-31 23:15:11 +01:00
Thijs Wiefferink c858d30481 Add .gitignore to the repository 2015-10-19 19:07:31 +02:00
Thijs Wiefferink b090fd5577 Remove MCStats image, site is more offline than online 2015-10-17 22:10:38 +02:00
Thijs Wiefferink 8d132c66c4 Prepare for the v2.2.1 release
- Update version number
- Update language files from Transifex
2015-10-17 21:03:30 +02:00
Thijs Wiefferink 50e3e59543 Fix indentation and error message of WorldEdit 6 integration handler 2015-10-15 12:13:15 +02:00
Thijs Wiefferink eb21b9567e Change signtags from [arent] and [abuy] to [asrent] and [asbuy]
Changes #45
2015-10-08 22:49:41 +02:00
Thijs Wiefferink 4dba305f6d Change the default sign tags to something more specific
Note: Change documentation pages to include this.

Fixes #45
2015-10-06 22:41:59 +02:00
Thijs Wiefferink 7481d8287f Retrieve money from landlords when unrenting/selling a region.
Prevents exploits by giving money to landlords, and then
unrenting/selling to get money back from 'the server' (nobody). Now it
will get the money back from the landlord, or if that is not possible
then not give anything back.

Fixes #75
2015-10-06 22:15:09 +02:00
Thijs Wiefferink 4d41decbe5 Config part of week indicators 2015-10-03 21:14:24 +02:00
Thijs Wiefferink 7fc5a5af81 Add weeks time indicators, clean other indicators
The old Dutch time indicators have been removed from the lists, this
might cause problems for people if they regenerate their config but
don't add these tags again.

Added console warnings at startup to indicate incorrect duration
strings.

Fixes #32
2015-10-03 21:12:38 +02:00
Thijs Wiefferink d26fa99b95 Fix using the seconds modifier with /as setduration
AreaShop could correctly read and use all seconds modifiers that are
defined in the config, but the `/as setduration` command would not
accept it as input.

Fixes #82
2015-10-03 20:38:38 +02:00
Thijs Wiefferink 39d755d2db Make removing regions from AreaShop less destructible for region flags
First AreaShop would reset all flags, now it will only reset the
greeting and farewell flags. This is to make sure players do not get
confused about the region, if the greeting is still there then players
might think it is still connected to AreaShop.

Fixes #72
2015-10-03 20:27:19 +02:00
Thijs Wiefferink 48ab46ecf7 Fix indirect breaking of signs causing it to disconnect
If you would break a block behind/below a sign AreaShop would disconnect
it from the region, which is most of the times not the wanted behaviour.
This commit changes it to simply leave a floating sign there, so that it
is still visible and not disconnected from the region.

Fixes #15
2015-10-03 20:10:44 +02:00
Thijs Wiefferink b3fa31e1cc Remove debug message 2015-10-02 20:44:25 +02:00
Thijs Wiefferink 783085fbf7 Cache region variable replacements 2015-10-02 20:41:00 +02:00
Thijs Wiefferink aa093b0c8a Fix sign clicking still executing while event is cancelled. 2015-09-26 01:06:22 +02:00
Thijs Wiefferink 9c357fe929 Remove lastActive from region file when unrented/sold
No problems if it is there, but just keeping the region file clean.
2015-09-11 22:44:12 +02:00
Thijs Wiefferink 4d70571a23 Improve failed file loading
- Detects incorrectly loaded config.yml and default.yml
(YamlConfiguration prints errors to console and continues silently,
returning an empty configuration if something is wrong normally)
- Will go into error state when loading fails
- Improved some error handling to make sure that no extra errors are
thrown because of trying to close non-existing streams.
2015-09-10 21:58:57 +02:00
Thijs Wiefferink 29a4105ece Add Vault to the repo to make it easier to compile 2015-09-06 17:05:38 +02:00
Thijs Wiefferink edc7136063 Fix '/as info' always showing landlord line
It would always show the landlord line, if there was no actual landlord
it would show '<UNKNOWN>' as name, which is very confusing.

Fixes #46
2015-09-06 16:42:16 +02:00
Thijs Wiefferink 6fabc75be4 Fix '/as info' trying to filter by group too much
'/as info region' would also try to filter by group using the region
name, which would almost always cause an error message (group not found)
2015-09-06 16:38:23 +02:00
Thijs Wiefferink 085507bf8b Add required dependencies section 2015-08-30 00:10:12 +02:00
Thijs Wiefferink 73ed3366ae Update README.md 2015-08-29 22:27:14 +02:00
Thijs Wiefferink 9ca029176d Fix '/as find' not getting your balance correctly
- If you search with your balance (and do not give a maxprice) it would
always use 0.0 as your balance, therefore not finding any regions.
- Also fixes the incorrect feedback, it would say it searched with a
maxprice instead of your balance and the other way around if no regions
are found.
- Fixed maxprice and balance display to use correct currency symbols and
layouts (decimals, metric prefixes, separator).

Fixes #59
2015-08-29 20:06:16 +02:00
Thijs Wiefferink bf181d69d7 Update README.md 2015-08-29 19:46:05 +02:00
Thijs Wiefferink 68c57515da Update README.md 2015-08-29 19:44:54 +02:00
Thijs Wiefferink 903d6c309f Update README.md 2015-08-29 19:44:39 +02:00
Thijs Wiefferink 0a02eb3254 Update README.md 2015-08-29 19:42:57 +02:00
Thijs Wiefferink bf04589fab Merge links to issues with the top menu 2015-08-29 19:42:11 +02:00
Thijs Wiefferink 14dd094803 Update README.md 2015-08-27 22:51:49 +02:00
Thijs Wiefferink 02df35304c Update README.md 2015-08-27 22:48:11 +02:00
Thijs Wiefferink 4321667ec5 Merge branch 'master' of https://github.com/NLthijs48/AreaShop 2015-08-26 20:05:03 +02:00
Thijs Wiefferink 5cf5df78c8 Add permissions to prevent buying resell regions
- Permission 'areashop.buynormal' can be negated to only allow buying
regions that are in resell mode
- Permission 'areashop.buyresell' can be negated to only allow buying
regions that are not in resell mode

This change does not affect existing permissions setups (above
permissions are true by default)
2015-08-26 20:04:50 +02:00
Thijs Wiefferink 8608d6ce1d Update README.md 2015-08-25 17:40:08 +02:00
Thijs Wiefferink 614336862e Update README.md 2015-08-25 17:38:02 +02:00
Thijs Wiefferink a4ea175f1b Update README.md 2015-08-25 17:33:52 +02:00
Thijs Wiefferink c96043aa38 Update README.md 2015-08-25 17:30:11 +02:00
Thijs Wiefferink d5a29f6c32 Update README.MD: WIP frontpage
Frontpage like the BukkitDev and Spigot Resources section.
2015-08-25 17:29:21 +02:00
Thijs Wiefferink 5176a1c2c5 Update README.md 2015-08-21 21:45:42 +02:00
Thijs Wiefferink 89569ea182 Update README.md 2015-08-17 23:11:46 +02:00
Thijs Wiefferink f349657a59 Fix bug with teleporting to signs
Fixes #47
2015-08-13 22:04:22 +02:00
Thijs Wiefferink 40d3d4d8af Add group filtering to /as info <rented|forrent|sold|forsale>
- Filter regions by group for the mentioned subcommands of /as info
- Clean/refactor code
- Sort the output
- Add Comparable, equals() and toString() to GeneralRegion

Closes #44
2015-08-11 22:41:30 +02:00
Thijs Wiefferink 0d5db8fa4e Add option to deny extending when over rent/total limits
Turned on by default, added config setting
'allowRegionExtendsWhenAboveLimits' to disable this change. Normally
this is expected behaviour, which pushes users to let the region run out
if they should not be able to rent it anymore (was impossible to do
before).

Closes #41
2015-08-10 21:43:29 +02:00
168 changed files with 23915 additions and 17268 deletions

No files matched your search

+36
View File
@@ -0,0 +1,36 @@
---
name: Bug report
about: Report a problem in the plugin
---
**Current behavior**
<!--- Tell what happens currently and/or show the stacktrace if an error occured -->
**Expected behavior**
<!--- Tell what you expected to happen instead -->
**Steps to reproduce**
<!--- Exactly show how this bug can be triggered -->
1.
2.
3.
4.
**Your environment**
<!--- Indicate which versions you use -->
<!--- Attention: "LATEST" or "NEWEST" are invalid answers! -->
<!--- Use '/version' for the Platform version and '/version <plugin>' for plugin versions -->
* Server platform (Bukkit, Spigot, etc.):
* Server version:
* AreaShop version:
* WorldEdit version:
* WorldGuard version:
* Vault version:
**Your config files**
<!--- Attach a '.zip' file of the '/plugins/AreaShop' and '/plugins/WorldGuard' directories to show your configuration setup -->
+12
View File
@@ -0,0 +1,12 @@
---
name: Feature request
about: Suggest an idea
---
**Describe the problem you are trying to solve with this feature request**
<!-- When I know the problem you are trying to solve I can help you to think about the best solution -->
**Describe the solution you'd like**
<!-- Describe the config settings, commands and other features that should be added -->
@@ -0,0 +1,28 @@
---
name: Support question
about: Ask help with the setup or usage of the plugin
---
**Current behavior**
<!--- Tell what happens currently -->
**Desired behavior**
<!--- Tell what you want to happen instead -->
**Your environment**
<!--- Indicate which versions you use -->
<!--- Attention: "LATEST" or "NEWEST" are invalid answers! -->
<!--- Use '/version' for the Platform version and '/version <plugin>' for plugin versions -->
* Server platform (Bukkit, Spigot, etc.):
* Server version:
* AreaShop version:
* WorldEdit version:
* WorldGuard version:
* Vault version:
**Your config files**
<!--- Attach a '.zip' file of the '/plugins/AreaShop' and '/plugins/WorldGuard' directories to show your configuration setup -->
+25
View File
@@ -0,0 +1,25 @@
# Maven stuff
/target
.project
.metadata
bin/
tmp/
*.tmp
*.bak
*.swp
*~.nib
local.properties
.classpath
.settings/
.loadpath
# Locally stored "Eclipse launch configurations"
*.launch
# IntelliJ IDEA
*.iml
.idea
dependency-reduced-pom.xml
desktop.ini
+274 -153
View File
@@ -1,159 +1,280 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>nl.evolutioncoding</groupId>
<artifactId>areashop</artifactId>
<packaging>jar</packaging>
<name>AreaShop</name>
<version>2.2.0</version> <!-- Main plugin version -->
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>areashop</artifactId>
<packaging>jar</packaging>
<name>AreaShop</name>
<version>2.5.0</version> <!-- Main plugin version -->
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<parent>
<groupId>me.wiefferink</groupId>
<artifactId>areashop-parent</artifactId>
<version>parent</version>
</parent>
<repositories>
<repository>
<id>bukkit-repo</id>
<url>http://repo.bukkit.org/content/groups/public</url>
</repository>
<repository>
<id>sk89q-repo-wg</id>
<url>http://maven.sk89q.com/artifactory/repo/</url>
</repository>
</repositories>
<dependencies>
<!-- Bukkit, AreaShop aims to support 1.7.9+, but this is the lowest Bukkit version available from the Spigot repo, Bukkit repository is gone -->
<dependency>
<groupId>org.bukkit</groupId>
<artifactId>bukkit</artifactId>
<version>${bukkit.version}</version>
<type>jar</type>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependencies>
<dependency>
<groupId>org.bukkit</groupId>
<artifactId>bukkit</artifactId>
<version>1.7.9-R0.2</version>
<type>jar</type>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>nl.evolutioncoding</groupId>
<artifactId>areashop-worldguard-5</artifactId>
<version>WorldGuard-5</version>
<type>jar</type>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>nl.evolutioncoding</groupId>
<artifactId>areashop-worldguard-6</artifactId>
<version>WorldGuard-6</version>
<type>jar</type>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>nl.evolutioncoding</groupId>
<artifactId>areashop-interface</artifactId>
<version>AreaShopInterface</version>
<type>jar</type>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>nl.evolutioncoding</groupId>
<artifactId>areashop-worldedit-5</artifactId>
<version>WorldEdit-5</version>
<type>jar</type>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>nl.evolutioncoding</groupId>
<artifactId>areashop-worldedit-6</artifactId>
<version>WorldEdit-6</version>
<type>jar</type>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.sk89q</groupId>
<artifactId>worldedit</artifactId>
<version>6.0.0-SNAPSHOT</version>
<scope>provided</scope>
<type>jar</type>
</dependency>
<dependency>
<groupId>com.sk89q</groupId>
<artifactId>worldguard</artifactId>
<version>6.0.0-SNAPSHOT</version>
<scope>provided</scope>
<type>jar</type>
</dependency>
<dependency>
<groupId>net.milkbowl</groupId>
<artifactId>vault</artifactId>
<version>1.4.1</version>
<scope>system</scope>
<systemPath>${basedir}/../Dependencies/Vault.jar</systemPath>
</dependency>
</dependencies>
<!-- InteractiveMessenger library -->
<dependency>
<groupId>me.wiefferink</groupId>
<artifactId>interactivemessenger</artifactId>
<version>1.1-SNAPSHOT</version>
</dependency>
<build>
<directory>target</directory>
<finalName>AreaShop</finalName>
<!-- Include all required resources -->
<resources>
<resource>
<targetPath>.</targetPath>
<filtering>true</filtering>
<directory>src/main/resources</directory>
<includes>
<include>plugin.yml</include>
<include>config.yml</include>
<include>default.yml</include>
<include>README.md</include>
<include>lang/*.yml</include>
</includes>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>1.4</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
<!-- Copy resulting file to local server, change to your own path -->
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<configuration>
<tasks>
<copy file="./target/${project.build.finalName}.jar" tofile="C:\Games\Minecraft\Spigot 1.8.7\plugins\${project.build.finalName}.jar"/>
</tasks>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<target failonerror="false"></target>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<!-- BukkitDo library -->
<dependency>
<groupId>me.wiefferink</groupId>
<artifactId>bukkitdo</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>me.wiefferink</groupId>
<artifactId>areashop-worldguard-5</artifactId>
<version>WorldGuard-5</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>me.wiefferink</groupId>
<artifactId>areashop-worldguard-6</artifactId>
<version>WorldGuard-6</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>me.wiefferink</groupId>
<artifactId>areashop-worldguard-6_1_3</artifactId>
<version>WorldGuard-6_1_3</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>me.wiefferink</groupId>
<artifactId>areashop-worldguard-7</artifactId>
<version>WorldGuard-7</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>me.wiefferink</groupId>
<artifactId>areashop-interface</artifactId>
<version>AreaShopInterface</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>me.wiefferink</groupId>
<artifactId>areashop-worldedit-5</artifactId>
<version>WorldEdit-5</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>me.wiefferink</groupId>
<artifactId>areashop-worldedit-6</artifactId>
<version>WorldEdit-6</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>me.wiefferink</groupId>
<artifactId>areashop-worldedit-7</artifactId>
<version>WorldEdit-7</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.sk89q</groupId>
<artifactId>worldedit</artifactId>
<scope>system</scope>
<version>any</version>
<systemPath>${project.basedir}/../dependencies/worldedit-bukkit-7.0.0-beta-01.jar</systemPath>
</dependency>
<dependency>
<groupId>com.sk89q</groupId>
<artifactId>worldguard</artifactId>
<scope>system</scope>
<version>any</version>
<systemPath>${project.basedir}/../dependencies/worldguard-legacy-7.0.0-beta01.jar</systemPath>
</dependency>
<dependency>
<groupId>net.milkbowl.vault</groupId>
<artifactId>VaultAPI</artifactId>
<version>1.4</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.bstats</groupId>
<artifactId>bstats-bukkit</artifactId>
<version>1.1</version>
</dependency>
</dependencies>
<profiles>
<!-- Copy the jar file to a test server, activate by using -DcopyResult="/path/to/test/server" -->
<profile>
<id>test-locally</id>
<activation>
<property>
<name>copyResult</name>
</property>
</activation>
<build>
<plugins>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.8</version>
<configuration>
<target>
<copy file="./target/${project.build.finalName}.jar"
tofile="${copyResult}\${project.build.finalName}.jar"/>
</target>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<!-- Package the source files in a jar, activate by using -Dsources -->
<profile>
<id>package-sources</id>
<activation>
<property>
<name>sources</name>
</property>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<phase>package</phase>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<!-- Produce javadoc files, activate by using -Djavadoc -->
<profile>
<id>generate-javadoc</id>
<activation>
<property>
<name>javadoc</name>
</property>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.10.4</version>
<executions>
<execution>
<phase>package</phase>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
<configuration>
<excludePackageNames>me.wiefferink.areashop.lib</excludePackageNames>
<destDir>${javadoc}</destDir>
<links>
<link>https://hub.spigotmc.org/javadocs/bukkit/</link>
<link>http://docs.sk89q.com/worldedit/apidocs/</link>
<link>http://docs.sk89q.com/worldguard/apidocs/</link>
</links>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<build>
<directory>target</directory>
<finalName>AreaShop</finalName>
<resources>
<resource>
<targetPath>.</targetPath>
<filtering>true</filtering>
<directory>src/main/resources</directory>
<includes>
<include>plugin.yml</include>
<include>config.yml</include>
<include>hiddenConfig.yml</include>
<include>default.yml</include>
<include>README.md</include>
<include>lang/*.yml</include>
</includes>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.4.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<relocations>
<!-- Relocate messaging framework -->
<relocation>
<pattern>me.wiefferink.interactivemessenger</pattern>
<shadedPattern>me.wiefferink.areashop.shaded.interactivemessenger</shadedPattern>
</relocation>
<!-- Relocate BukkitDo -->
<relocation>
<pattern>me.wiefferink.bukkitdo</pattern>
<shadedPattern>me.wiefferink.areashop.shaded.bukkitdo</shadedPattern>
</relocation>
<!-- Relocate bstats -->
<relocation>
<pattern>org.bstats</pattern>
<shadedPattern>me.wiefferink.areashop.shaded.bstats</shadedPattern>
</relocation>
</relocations>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
</plugin>
</plugins>
</build>
</project>
@@ -0,0 +1,780 @@
package me.wiefferink.areashop;
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
import com.sk89q.worldguard.protection.managers.RegionManager;
import me.wiefferink.areashop.interfaces.AreaShopInterface;
import me.wiefferink.areashop.interfaces.WorldEditInterface;
import me.wiefferink.areashop.interfaces.WorldGuardInterface;
import me.wiefferink.areashop.listeners.PlayerLoginLogoutListener;
import me.wiefferink.areashop.managers.CommandManager;
import me.wiefferink.areashop.managers.FeatureManager;
import me.wiefferink.areashop.managers.FileManager;
import me.wiefferink.areashop.managers.Manager;
import me.wiefferink.areashop.managers.SignLinkerManager;
import me.wiefferink.areashop.tools.Analytics;
import me.wiefferink.areashop.tools.GithubUpdateCheck;
import me.wiefferink.areashop.tools.Utils;
import me.wiefferink.bukkitdo.Do;
import me.wiefferink.interactivemessenger.processing.Message;
import me.wiefferink.interactivemessenger.source.LanguageManager;
import net.milkbowl.vault.economy.Economy;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.World;
import org.bukkit.command.CommandSender;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.event.HandlerList;
import org.bukkit.permissions.Permission;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.RegisteredServiceProvider;
import org.bukkit.plugin.java.JavaPlugin;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Main class for the AreaShop plugin.
* Contains methods to get parts of the plugins functionality and definitions for constants.
*/
public final class AreaShop extends JavaPlugin implements AreaShopInterface {
// Statically available instance
private static AreaShop instance = null;
// General variables
private WorldGuardPlugin worldGuard = null;
private WorldGuardInterface worldGuardInterface = null;
private WorldEditPlugin worldEdit = null;
private WorldEditInterface worldEditInterface = null;
private FileManager fileManager = null;
private LanguageManager languageManager = null;
private CommandManager commandManager = null;
private SignLinkerManager signLinkerManager = null;
private FeatureManager featureManager = null;
private Set<Manager> managers = null;
private boolean debug = false;
private List<String> chatprefix = null;
private boolean ready = false;
private GithubUpdateCheck githubUpdateCheck = null;
// Folders and file names
public static final String languageFolder = "lang";
public static final String schematicFolder = "schem";
public static final String regionsFolder = "regions";
public static final String groupsFile = "groups.yml";
public static final String defaultFile = "default.yml";
public static final String configFile = "config.yml";
public static final String configFileHidden = "hiddenConfig.yml";
public static final String versionFile = "versions";
// Euro tag for in the config
public static final String currencyEuro = "%euro%";
// Constants for handling file versions
public static final String versionFiles = "files";
public static final int versionFilesCurrent = 3;
// Keys for replacing parts of flags, commands, strings
public static final String tagPlayerName = "player";
public static final String tagPlayerUUID = "uuid";
public static final String tagWorldName = "world";
public static final String tagRegionName = "region";
public static final String tagRegionType = "type";
public static final String tagPrice = "price";
public static final String tagRawPrice = "rawprice";
public static final String tagDuration = "duration";
public static final String tagRentedUntil = "until";
public static final String tagRentedUntilShort = "untilshort";
public static final String tagWidth = "width"; // x-axis
public static final String tagHeight = "height"; // y-axis
public static final String tagDepth = "depth"; // z-axis
public static final String tagVolume = "volume"; // Number of blocks in the region (accounting for polygon regions)
public static final String tagTimeLeft = "timeleft";
public static final String tagClicker = "clicker";
public static final String tagResellPrice = "resellprice";
public static final String tagRawResellPrice = "rawresellprice";
public static final String tagFriends = "friends";
public static final String tagFriendsUUID = "friendsuuid";
public static final String tagMoneyBackPercentage = "moneybackpercent";
public static final String tagMoneyBackAmount = "moneyback";
public static final String tagRawMoneyBackAmount = "rawmoneyback";
public static final String tagTimesExtended = "timesExtended";
public static final String tagMaxExtends = "maxextends";
public static final String tagExtendsLeft = "extendsleft";
public static final String tagMaxRentTime = "maxrenttime";
public static final String tagMaxInactiveTime = "inactivetime";
public static final String tagLandlord = "landlord";
public static final String tagLandlordUUID = "landlorduuid";
public static final String tagDateTime = "datetime";
public static final String tagDateTimeShort = "datetimeshort";
public static final String tagYear = "year";
public static final String tagMonth = "month";
public static final String tagDay = "day";
public static final String tagHour = "hour";
public static final String tagMinute = "minute";
public static final String tagSecond = "second";
public static final String tagMillisecond = "millisecond";
public static final String tagEpoch = "epoch";
public static final String tagTeleportX = "tpx";
public static final String tagTeleportY = "tpy";
public static final String tagTeleportZ = "tpz";
public static final String tagTeleportBlockX = "tpblockx";
public static final String tagTeleportBlockY = "tpblocky";
public static final String tagTeleportBlockZ = "tpblockz";
public static final String tagTeleportPitch = "tppitch";
public static final String tagTeleportYaw = "tpyaw";
public static final String tagTeleportPitchRound = "tppitchround";
public static final String tagTeleportYawRound = "tpyawround";
public static final String tagTeleportWorld = "tpworld";
public static AreaShop getInstance() {
return AreaShop.instance;
}
/**
* Called on start or reload of the server.
*/
public void onEnable() {
AreaShop.instance = this;
Do.init(this);
managers = new HashSet<>();
boolean error = false;
// Check if WorldGuard is present
String wgVersion = null;
String rawVersion = null;
int major = 0;
int minor = 0;
int fixes = 0;
Integer build = null;
Plugin plugin = getServer().getPluginManager().getPlugin("WorldGuard");
if(!(plugin instanceof WorldGuardPlugin) || !plugin.isEnabled()) {
error("WorldGuard plugin is not present or has not loaded correctly");
error = true;
} else {
worldGuard = (WorldGuardPlugin)plugin;
// Get correct WorldGuardInterface (handles things that changed version to version)
try {
rawVersion = worldGuard.getDescription().getVersion();
if(rawVersion.contains("-SNAPSHOT;")) {
String buildNumber = rawVersion.substring(rawVersion.indexOf("-SNAPSHOT;") + 10, rawVersion.length());
if(buildNumber.contains("-")) {
buildNumber = buildNumber.substring(0, buildNumber.indexOf("-"));
try {
build = Integer.parseInt(buildNumber);
} catch(NumberFormatException e) {
warn("Could not correctly parse the build of WorldGuard, raw version: " + rawVersion + ", buildNumber: " + buildNumber);
}
}
}
// Clear stuff from the version string that is not a number
String[] versionParts = rawVersion.split("\\.");
for(int i = 0; i < versionParts.length; i++) {
Pattern pattern = Pattern.compile("^\\d+");
Matcher matcher = pattern.matcher(versionParts[i]);
if(matcher.find()) {
versionParts[i] = matcher.group();
}
}
// Find major, minor and fix numbers
try {
if(versionParts.length > 0) {
major = Integer.parseInt(versionParts[0]);
}
if(versionParts.length > 1) {
minor = Integer.parseInt(versionParts[1]);
}
if(versionParts.length > 2) {
fixes = Integer.parseInt(versionParts[2]);
}
} catch(NumberFormatException e) {
warn("Something went wrong while parsing WorldGuard version number: " + rawVersion);
}
// Determine correct implementation to use
if(worldGuard.getDescription().getVersion().startsWith("5.")) {
wgVersion = "5";
} else if(major == 6 && minor == 1 && fixes < 3) {
wgVersion = "6";
} else if(major == 6) {
if(build != null && build == 1672) {
error = true;
error("Build 1672 of WorldGuard is broken, update to a later build or a stable version!");
} else if(build != null && build < 1672) {
wgVersion = "6";
} else {
wgVersion = "6_1_3";
}
} else {
wgVersion = "7";
}
} catch(Exception e) { // If version detection fails, at least try to load the latest version
wgVersion = "7";
}
// Load chosen implementation
try {
final Class<?> clazz = Class.forName("me.wiefferink.areashop.handlers.WorldGuardHandler" + wgVersion);
// Check if we have a NMSHandler class at that location.
if(WorldGuardInterface.class.isAssignableFrom(clazz)) { // Make sure it actually implements WorldGuardInterface
worldGuardInterface = (WorldGuardInterface)clazz.getConstructor(AreaShopInterface.class).newInstance(this); // Set our handler
}
} catch(final Exception e) {
error("Could not load the handler for WorldGuard (tried to load " + wgVersion + "), report this problem to the author:" + ExceptionUtils.getStackTrace(e));
error = true;
wgVersion = null;
}
}
// Check if WorldEdit is present
String weVersion = null;
plugin = getServer().getPluginManager().getPlugin("WorldEdit");
if(!(plugin instanceof WorldEditPlugin) || !plugin.isEnabled()) {
error("WorldEdit plugin is not present or has not loaded correctly");
error = true;
} else {
worldEdit = (WorldEditPlugin)plugin;
// Get correct WorldEditInterface (handles things that changed version to version)
if(worldEdit.getDescription().getVersion().startsWith("5.")) {
weVersion = "5";
} else if(worldEdit.getDescription().getVersion().startsWith("6.")) {
weVersion = "6";
} else {
weVersion = "7";
}
try {
final Class<?> clazz = Class.forName("me.wiefferink.areashop.handlers.WorldEditHandler" + weVersion);
// Check if we have a NMSHandler class at that location.
if(WorldEditInterface.class.isAssignableFrom(clazz)) { // Make sure it actually implements WorldEditInterface
worldEditInterface = (WorldEditInterface)clazz.getConstructor(AreaShopInterface.class).newInstance(this); // Set our handler
}
} catch(final Exception e) {
error("Could not load the handler for WorldEdit (tried to load " + weVersion + "), report this problem to the author: " + ExceptionUtils.getStackTrace(e));
error = true;
weVersion = null;
}
}
// Check if Vault is present
if(getServer().getPluginManager().getPlugin("Vault") == null) {
error("Vault plugin is not present or has not loaded correctly");
error = true;
}
// Load all data from files and check versions
fileManager = new FileManager();
managers.add(fileManager);
error = error | !fileManager.loadFiles(false);
// Print loaded version of WG and WE in debug
if(wgVersion != null) {
AreaShop.debug("Loaded WorldGuardHandler" + wgVersion + " (raw version: " + rawVersion + ", major:" + major + ", minor:" + minor + ", fixes:" + fixes + ", build:" + build + ")");
}
if(weVersion != null) {
AreaShop.debug("Loaded WorldEditHandler" + weVersion);
}
setupLanguageManager();
if(error) {
error("The plugin has not started, fix the errors listed above");
} else {
featureManager = new FeatureManager();
managers.add(featureManager);
// Register the event listeners
getServer().getPluginManager().registerEvents(new PlayerLoginLogoutListener(this), this);
setupTasks();
// Startup the CommandManager (registers itself for the command)
commandManager = new CommandManager();
managers.add(commandManager);
// Create a signLinkerManager
signLinkerManager = new SignLinkerManager();
managers.add(signLinkerManager);
// Enable Metrics if config allows it
if(getConfig().getBoolean("sendStats")) {
Analytics.start();
}
// Register dynamic permission (things declared in config)
registerDynamicPermissions();
// Don't initialize the updatechecker if disabled in the config
if(getConfig().getBoolean("checkForUpdates")) {
githubUpdateCheck = new GithubUpdateCheck(
AreaShop.getInstance(),
"NLThijs48",
"AreaShop"
).withVersionComparator((latestVersion, currentVersion) ->
!cleanVersion(latestVersion).equals(cleanVersion(currentVersion))
).checkUpdate((result) -> {
AreaShop.debug("Update check result:", result);
if(!result.hasUpdate()) {
return;
}
AreaShop.info("Update from AreaShop V" + cleanVersion(result.getCurrentVersion()) + " to AreaShop V" + cleanVersion(result.getLatestVersion()) + " available, get the latest version at https://www.spigotmc.org/resources/areashop.2991/");
for(Player player : Utils.getOnlinePlayers()) {
notifyUpdate(player);
}
});
}
}
}
/**
* Notify a player about an update if he wants notifications about it and an update is available.
* @param sender CommandSender to notify
*/
public void notifyUpdate(CommandSender sender) {
if(githubUpdateCheck != null && githubUpdateCheck.hasUpdate() && sender.hasPermission("areashop.notifyupdate")) {
AreaShop.getInstance().message(sender, "update-playerNotify", cleanVersion(githubUpdateCheck.getCurrentVersion()), cleanVersion(githubUpdateCheck.getLatestVersion()));
}
}
/**
* Cleanup a version number.
* @param version Version to clean
* @return Cleaned up version (removed prefixes and suffixes)
*/
private String cleanVersion(String version) {
version = version.toLowerCase();
// Strip 'v' as used on Github tags
if(version.startsWith("v")) {
version = version.substring(1);
}
// Strip build number as used by Jenkins
if(version.contains("#")) {
version = version.substring(0, version.indexOf("#"));
}
return version;
}
/**
* Called on shutdown or reload of the server.
*/
public void onDisable() {
Bukkit.getServer().getScheduler().cancelTasks(this);
// Cleanup managers
for(Manager manager : managers) {
manager.shutdown();
}
managers = null;
fileManager = null;
languageManager = null;
commandManager = null;
signLinkerManager = null;
featureManager = null;
// Cleanup plugins
worldGuard = null;
worldGuardInterface = null;
worldEdit = null;
worldEditInterface = null;
// Cleanup other stuff
chatprefix = null;
debug = false;
ready = false;
HandlerList.unregisterAll(this);
}
/**
* Indicates if the plugin is ready to be used.
* @return true if the plugin is ready, false otherwise
*/
public boolean isReady() {
return ready;
}
/**
* Set if the plugin is ready to be used or not (not to be used from another plugin!).
* @param ready Indicate if the plugin is ready to be used
*/
public void setReady(boolean ready) {
this.ready = ready;
}
/**
* Set if the plugin should output debug messages (loaded from config normally).
* @param debug Indicates if the plugin should output debug messages or not
*/
public void setDebug(boolean debug) {
this.debug = debug;
}
/**
* Setup a new LanguageManager.
*/
private void setupLanguageManager() {
languageManager = new LanguageManager(
this,
languageFolder,
getConfig().getString("language"),
"EN",
chatprefix
);
}
/**
* Set the chatprefix to use in the chat (loaded from config normally).
* @param chatprefix The string to use in front of chat messages (supports formatting codes)
*/
public void setChatprefix(List<String> chatprefix) {
this.chatprefix = chatprefix;
}
/**
* Function to get the WorldGuard plugin.
* @return WorldGuardPlugin
*/
public WorldGuardPlugin getWorldGuard() {
return worldGuard;
}
/**
* Function to get WorldGuardInterface for version dependent things.
* @return WorldGuardInterface
*/
public WorldGuardInterface getWorldGuardHandler() {
return this.worldGuardInterface;
}
/**
* Get the RegionManager.
* @param world World to get the RegionManager for
* @return RegionManager for the given world, if there is one, otherwise null
*/
public RegionManager getRegionManager(World world) {
return this.worldGuardInterface.getRegionManager(world);
}
/**
* Function to get the WorldEdit plugin.
* @return WorldEditPlugin
*/
public WorldEditPlugin getWorldEdit() {
return worldEdit;
}
/**
* Function to get WorldGuardInterface for version dependent things.
* @return WorldGuardInterface
*/
public WorldEditInterface getWorldEditHandler() {
return this.worldEditInterface;
}
/**
* Function to get the LanguageManager.
* @return the LanguageManager
*/
public LanguageManager getLanguageManager() {
return languageManager;
}
/**
* Function to get the CommandManager.
* @return the CommandManager
*/
public CommandManager getCommandManager() {
return commandManager;
}
/**
* Get the SignLinkerManager.
* Handles sign linking mode.
* @return The SignLinkerManager
*/
public SignLinkerManager getSignlinkerManager() {
return signLinkerManager;
}
/**
* Get the FeatureManager.
* Manages region specific features.
* @return The FeatureManager
*/
public FeatureManager getFeatureManager() {
return featureManager;
}
/**
* Function to get the Vault plugin.
* @return Economy
*/
public Economy getEconomy() {
RegisteredServiceProvider<Economy> economy = getServer().getServicesManager().getRegistration(net.milkbowl.vault.economy.Economy.class);
if(economy == null || economy.getProvider() == null) {
error("There is no economy provider to support Vault, make sure you installed an economy plugin");
return null;
}
return economy.getProvider();
}
/**
* Get the Vault permissions provider.
* @return Vault permissions provider
*/
public net.milkbowl.vault.permission.Permission getPermissionProvider() {
RegisteredServiceProvider<net.milkbowl.vault.permission.Permission> permissionProvider = getServer().getServicesManager().getRegistration(net.milkbowl.vault.permission.Permission.class);
if (permissionProvider == null || permissionProvider.getProvider() == null) {
return null;
}
return permissionProvider.getProvider();
}
/**
* Check for a permission of a (possibly offline) player.
* @param offlinePlayer OfflinePlayer to check
* @param permission Permission to check
* @return true if the player has the permission, false if the player does not have permission or, is offline and there is not Vault-compatible permission plugin
*/
public boolean hasPermission(OfflinePlayer offlinePlayer, String permission) {
// Online, return through Bukkit
if(offlinePlayer.getPlayer() != null) {
return offlinePlayer.getPlayer().hasPermission(permission);
}
// Resolve while offline if possible
net.milkbowl.vault.permission.Permission permissionProvider = getPermissionProvider();
if(permissionProvider != null) {
// TODO: Should we provide a world here?
return permissionProvider.playerHas(null, offlinePlayer, permission);
}
// Player offline and no offline permission provider available, safely say that there is no permission
return false;
}
/**
* Method to get the FileManager (loads/save regions and can be used to get regions).
* @return The fileManager
*/
public FileManager getFileManager() {
return fileManager;
}
/**
* Register dynamic permissions controlled by config settings.
*/
private void registerDynamicPermissions() {
// Register limit groups of amount of regions a player can have
ConfigurationSection section = getConfig().getConfigurationSection("limitGroups");
if(section == null) {
return;
}
for(String group : section.getKeys(false)) {
if(!"default".equals(group)) {
Permission perm = new Permission("areashop.limits." + group);
try {
Bukkit.getPluginManager().addPermission(perm);
} catch(IllegalArgumentException e) {
warn("Could not add the following permission to be used as limit: " + perm.getName());
}
}
}
Bukkit.getPluginManager().recalculatePermissionDefaults(Bukkit.getPluginManager().getPermission("playerwarps.limits"));
}
/**
* Register all required tasks.
*/
private void setupTasks() {
// Rent expiration timer
long expirationCheck = Utils.millisToTicks(Utils.getDurationFromSecondsOrString("expiration.delay"));
final AreaShop finalPlugin = this;
if(expirationCheck > 0) {
Do.syncTimer(expirationCheck, () -> {
if(isReady()) {
finalPlugin.getFileManager().checkRents();
AreaShop.debugTask("Checking rent expirations...");
} else {
AreaShop.debugTask("Skipped checking rent expirations, plugin not ready");
}
});
}
// Inactive unrenting/selling timer
long inactiveCheck = Utils.millisToTicks(Utils.getDurationFromMinutesOrString("inactive.delay"));
if(inactiveCheck > 0) {
Do.syncTimer(inactiveCheck, () -> {
if(isReady()) {
finalPlugin.getFileManager().checkForInactiveRegions();
AreaShop.debugTask("Checking for regions with players that are inactive too long...");
} else {
AreaShop.debugTask("Skipped checking for regions of inactive players, plugin not ready");
}
});
}
// Periodic updating of signs for timeleft tags
long periodicUpdate = Utils.millisToTicks(Utils.getDurationFromSecondsOrString("signs.delay"));
if(periodicUpdate > 0) {
Do.syncTimer(periodicUpdate, () -> {
if(isReady()) {
finalPlugin.getFileManager().performPeriodicSignUpdate();
AreaShop.debugTask("Performing periodic sign update...");
} else {
AreaShop.debugTask("Skipped performing periodic sign update, plugin not ready");
}
});
}
// Saving regions and group settings
long saveFiles = Utils.millisToTicks(Utils.getDurationFromMinutesOrString("saving.delay"));
if(saveFiles > 0) {
Do.syncTimer(saveFiles, () -> {
if(isReady()) {
finalPlugin.getFileManager().saveRequiredFiles();
AreaShop.debugTask("Saving required files...");
} else {
AreaShop.debugTask("Skipped saving required files, plugin not ready");
}
});
}
// Sending warnings about rent regions to online players
long expireWarning = Utils.millisToTicks(Utils.getDurationFromMinutesOrString("expireWarning.delay"));
if(expireWarning > 0) {
Do.syncTimer(expireWarning, () -> {
if(isReady()) {
finalPlugin.getFileManager().sendRentExpireWarnings();
AreaShop.debugTask("Sending rent expire warnings...");
} else {
AreaShop.debugTask("Skipped sending rent expire warnings, plugin not ready");
}
});
}
// Update all regions on startup
if(getConfig().getBoolean("updateRegionsOnStartup")) {
Do.syncLater(20, () -> {
finalPlugin.getFileManager().updateAllRegions();
AreaShop.debugTask("Updating all regions at startup...");
});
}
}
/**
* Send a message to a target without a prefix.
* @param target The target to send the message to
* @param key The key of the language string
* @param replacements The replacements to insert in the message
*/
public void messageNoPrefix(Object target, String key, Object... replacements) {
Message.fromKey(key).replacements(replacements).send(target);
}
/**
* Send a message to a target, prefixed by the default chat prefix.
* @param target The target to send the message to
* @param key The key of the language string
* @param replacements The replacements to insert in the message
*/
public void message(Object target, String key, Object... replacements) {
Message.fromKey(key).prefix().replacements(replacements).send(target);
}
/**
* Return the config.
*/
@Override
public YamlConfiguration getConfig() {
return fileManager.getConfig();
}
/**
* Sends an debug message to the console.
* @param message The message that should be printed to the console
*/
public static void debug(Object... message) {
if(AreaShop.getInstance().debug) {
info("Debug: " + StringUtils.join(message, " "));
}
}
/**
* Non-static debug to use as implementation of the interface.
* @param message Object parts of the message that should be logged, toString() will be used
*/
public void debugI(Object... message) {
AreaShop.debug(StringUtils.join(message, " "));
}
/**
* Print an information message to the console.
* @param message The message to print
*/
public static void info(Object... message) {
AreaShop.getInstance().getLogger().info(StringUtils.join(message, " "));
}
/**
* Print a warning to the console.
* @param message The message to print
*/
public static void warn(Object... message) {
AreaShop.getInstance().getLogger().warning(StringUtils.join(message, " "));
}
/**
* Print an error to the console.
* @param message The message to print
*/
public static void error(Object... message) {
AreaShop.getInstance().getLogger().severe(StringUtils.join(message, " "));
}
/**
* Print debug message for periodic task.
* @param message The message to print
*/
public static void debugTask(Object... message) {
if(AreaShop.getInstance().getConfig().getBoolean("debugTask")) {
AreaShop.debug(StringUtils.join(message, " "));
}
}
/**
* Reload all files of the plugin and update all regions.
* @param confirmationReceiver The CommandSender which should be notified when complete, null for nobody
*/
public void reload(final CommandSender confirmationReceiver) {
setReady(false);
fileManager.saveRequiredFilesAtOnce();
fileManager.loadFiles(true);
setupLanguageManager();
message(confirmationReceiver, "reload-reloading");
fileManager.checkRents();
fileManager.updateAllRegions(confirmationReceiver);
}
/**
* Reload all files of the plugin and update all regions.
*/
public void reload() {
reload(null);
}
}
@@ -0,0 +1,300 @@
package me.wiefferink.areashop.commands;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import me.wiefferink.areashop.AreaShop;
import me.wiefferink.areashop.interfaces.WorldEditSelection;
import me.wiefferink.areashop.managers.FileManager;
import me.wiefferink.areashop.regions.BuyRegion;
import me.wiefferink.areashop.regions.GeneralRegion;
import me.wiefferink.areashop.regions.RentRegion;
import me.wiefferink.areashop.tools.Utils;
import me.wiefferink.bukkitdo.Do;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeSet;
import java.util.UUID;
import java.util.stream.Collectors;
public class AddCommand extends CommandAreaShop {
@Override
public String getCommandStart() {
return "areashop add";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.createrent")
|| target.hasPermission("areashop.createrent.member")
|| target.hasPermission("areashop.createrent.owner")
|| target.hasPermission("areashop.createbuy")
|| target.hasPermission("areashop.createbuy.member")
|| target.hasPermission("areashop.createbuy.owner")) {
return "help-add";
}
return null;
}
@Override
public void execute(final CommandSender sender, final String[] args) {
if(!sender.hasPermission("areashop.createrent")
&& !sender.hasPermission("areashop.createrent.member")
&& !sender.hasPermission("areashop.createrent.owner")
&& !sender.hasPermission("areashop.createbuy")
&& !sender.hasPermission("areashop.createbuy.member")
&& !sender.hasPermission("areashop.createbuy.owner")) {
plugin.message(sender, "add-noPermission");
return;
}
if(args.length < 2 || args[1] == null || (!"rent".equals(args[1].toLowerCase()) && !"buy".equals(args[1].toLowerCase()))) {
plugin.message(sender, "add-help");
return;
}
Map<String, ProtectedRegion> regions = new HashMap<>();
World world;
Player player = null;
if(sender instanceof Player) {
player = (Player)sender;
}
if(args.length == 2) {
if(player == null) {
plugin.message(sender, "cmd-weOnlyByPlayer");
return;
}
WorldEditSelection selection = plugin.getWorldEditHandler().getPlayerSelection(player);
if(selection == null) {
plugin.message(player, "cmd-noSelection");
return;
}
world = selection.getWorld();
regions = Utils.getWorldEditRegionsInSelection(selection).stream().collect(Collectors.toMap(ProtectedRegion::getId, region -> region));
if(regions.size() == 0) {
plugin.message(player, "cmd-noWERegionsFound");
return;
}
} else {
if(player != null) {
if(args.length == 4) {
world = Bukkit.getWorld(args[3]);
if(world == null) {
plugin.message(sender, "add-incorrectWorld", args[3]);
return;
}
} else {
world = ((Player)sender).getWorld();
}
} else {
if(args.length < 4) {
plugin.message(sender, "add-specifyWorld");
return;
} else {
world = Bukkit.getWorld(args[3]);
if(world == null) {
plugin.message(sender, "add-incorrectWorld", args[3]);
return;
}
}
}
ProtectedRegion region = plugin.getRegionManager(world).getRegion(args[2]);
if(region == null) {
plugin.message(sender, "cmd-noRegion", args[2]);
return;
}
regions.put(args[2], region);
}
final boolean isRent = "rent".equals(args[1].toLowerCase());
final Player finalPlayer = player;
AreaShop.debug("Starting add task with " + regions.size() + " regions");
TreeSet<GeneralRegion> regionsSuccess = new TreeSet<>();
TreeSet<GeneralRegion> regionsAlready = new TreeSet<>();
TreeSet<GeneralRegion> regionsAlreadyOtherWorld = new TreeSet<>();
TreeSet<String> namesBlacklisted = new TreeSet<>();
TreeSet<String> namesNoPermission = new TreeSet<>();
Do.forAll(
plugin.getConfig().getInt("adding.regionsPerTick"),
regions.entrySet(),
regionEntry -> {
String regionName = regionEntry.getKey();
ProtectedRegion region = regionEntry.getValue();
// Determine if the player is an owner or member of the region
boolean isMember = finalPlayer != null && plugin.getWorldGuardHandler().containsMember(region, finalPlayer.getUniqueId());
boolean isOwner = finalPlayer != null && plugin.getWorldGuardHandler().containsMember(region, finalPlayer.getUniqueId());
String type;
if(isRent) {
type = "rent";
} else {
type = "buy";
}
FileManager.AddResult result = plugin.getFileManager().checkRegionAdd(sender, region, world, isRent ? GeneralRegion.RegionType.RENT : GeneralRegion.RegionType.BUY);
if(result == FileManager.AddResult.ALREADYADDED) {
regionsAlready.add(plugin.getFileManager().getRegion(regionName));
} else if(result == FileManager.AddResult.ALREADYADDEDOTHERWORLD) {
regionsAlreadyOtherWorld.add(plugin.getFileManager().getRegion(regionName));
} else if(result == FileManager.AddResult.BLACKLISTED) {
namesBlacklisted.add(regionName);
} else if(result == FileManager.AddResult.NOPERMISSION) {
namesNoPermission.add(regionName);
} else {
// Check if the player should be landlord
boolean landlord = (!sender.hasPermission("areashop.create" + type)
&& ((sender.hasPermission("areashop.create" + type + ".owner") && isOwner)
|| (sender.hasPermission("areashop.create" + type + ".member") && isMember)));
List<UUID> existing = new ArrayList<>();
existing.addAll(plugin.getWorldGuardHandler().getOwners(region).asUniqueIdList());
existing.addAll(plugin.getWorldGuardHandler().getMembers(region).asUniqueIdList());
if(isRent) {
RentRegion rent = new RentRegion(regionName, world);
// Set landlord
if(landlord) {
rent.setLandlord(finalPlayer.getUniqueId(), finalPlayer.getName());
}
// Run commands
rent.runEventCommands(GeneralRegion.RegionEvent.CREATED, true);
plugin.getFileManager().addRent(rent);
rent.handleSchematicEvent(GeneralRegion.RegionEvent.CREATED);
rent.update();
// Run commands
rent.runEventCommands(GeneralRegion.RegionEvent.CREATED, false);
// Add existing owners/members if any
if(!landlord && !existing.isEmpty()) {
// TODO also execute rent events to notify other plugins?
// Run commands
rent.runEventCommands(GeneralRegion.RegionEvent.RENTED, true);
// Add values to the rent and send it to FileManager
rent.setRentedUntil(Calendar.getInstance().getTimeInMillis() + rent.getDuration());
rent.setRenter(existing.remove(0));
rent.updateLastActiveTime();
// Add others as friends
for(UUID friend : existing) {
rent.getFriendsFeature().addFriend(friend, null);
}
// Fire schematic event and updated times extended
rent.handleSchematicEvent(GeneralRegion.RegionEvent.RENTED);
// Notify about updates
rent.update();
rent.runEventCommands(GeneralRegion.RegionEvent.RENTED, false);
}
regionsSuccess.add(rent);
} else {
BuyRegion buy = new BuyRegion(regionName, world);
// Set landlord
if(landlord) {
buy.setLandlord(finalPlayer.getUniqueId(), finalPlayer.getName());
}
// Run commands
buy.runEventCommands(GeneralRegion.RegionEvent.CREATED, true);
plugin.getFileManager().addBuy(buy);
buy.handleSchematicEvent(GeneralRegion.RegionEvent.CREATED);
buy.update();
// Run commands
buy.runEventCommands(GeneralRegion.RegionEvent.CREATED, false);
// Add existing owners/members if any
if(!landlord && !existing.isEmpty()) {
// TODO also execute buy events to notify for other plugins?
// Run commands
buy.runEventCommands(GeneralRegion.RegionEvent.BOUGHT, true);
// Set the owner
buy.setBuyer(existing.remove(0));
buy.updateLastActiveTime();
// Add others as friends
for(UUID friend : existing) {
buy.getFriendsFeature().addFriend(friend, null);
}
// Notify about updates
buy.update();
// Update everything
buy.handleSchematicEvent(GeneralRegion.RegionEvent.BOUGHT);
// Run commands
buy.runEventCommands(GeneralRegion.RegionEvent.BOUGHT, false);
}
regionsSuccess.add(buy);
}
}
},
() -> {
if(!regionsSuccess.isEmpty()) {
plugin.message(sender, "add-success", args[1], Utils.combinedMessage(regionsSuccess, "region"));
}
if(!regionsAlready.isEmpty()) {
plugin.message(sender, "add-failed", Utils.combinedMessage(regionsAlready, "region"));
}
if(!regionsAlreadyOtherWorld.isEmpty()) {
plugin.message(sender, "add-failedOtherWorld", Utils.combinedMessage(regionsAlreadyOtherWorld, "region"));
}
if(!namesBlacklisted.isEmpty()) {
plugin.message(sender, "add-blacklisted", Utils.createCommaSeparatedList(namesBlacklisted));
}
if(!namesNoPermission.isEmpty()) {
plugin.message(sender, "add-noPermissionRegions", Utils.createCommaSeparatedList(namesNoPermission));
plugin.message(sender, "add-noPermissionOwnerMember");
}
}
);
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
List<String> result = new ArrayList<>();
if(toComplete == 2) {
if(sender.hasPermission("areashop.createrent")) {
result.add("rent");
}
if(sender.hasPermission("areashop.createbuy")) {
result.add("buy");
}
} else if(toComplete == 3) {
if(sender instanceof Player) {
Player player = (Player)sender;
if(sender.hasPermission("areashop.createrent") || sender.hasPermission("areashop.createbuy")) {
for(ProtectedRegion region : plugin.getRegionManager(player.getWorld()).getRegions().values()) {
result.add(region.getId());
}
}
}
}
return result;
}
}
@@ -0,0 +1,141 @@
package me.wiefferink.areashop.commands;
import me.wiefferink.areashop.regions.BuyRegion;
import me.wiefferink.areashop.regions.GeneralRegion;
import me.wiefferink.areashop.regions.RentRegion;
import me.wiefferink.areashop.tools.Utils;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.List;
public class AddfriendCommand extends CommandAreaShop {
@Override
public String getCommandStart() {
return "areashop addfriend";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.addfriendall") || target.hasPermission("areashop.addfriend")) {
return "help-addFriend";
}
return null;
}
@SuppressWarnings("deprecation")
@Override
public void execute(CommandSender sender, String[] args) {
if(!sender.hasPermission("areashop.addfriend") && !sender.hasPermission("areashop.addfriendall")) {
plugin.message(sender, "addfriend-noPermission");
return;
}
if(args.length < 2) {
plugin.message(sender, "addfriend-help");
return;
}
GeneralRegion region;
if(args.length <= 2) {
if(sender instanceof Player) {
// get the region by location
List<GeneralRegion> regions = Utils.getImportantRegions(((Player)sender).getLocation());
if(regions.isEmpty()) {
plugin.message(sender, "cmd-noRegionsAtLocation");
return;
} else if(regions.size() > 1) {
plugin.message(sender, "cmd-moreRegionsAtLocation");
return;
} else {
region = regions.get(0);
}
} else {
plugin.message(sender, "cmd-automaticRegionOnlyByPlayer");
return;
}
} else {
region = plugin.getFileManager().getRegion(args[2]);
if(region == null) {
plugin.message(sender, "cmd-notRegistered", args[2]);
return;
}
}
if(sender.hasPermission("areashop.addfriendall")) {
if((region instanceof RentRegion && !((RentRegion)region).isRented())
|| (region instanceof BuyRegion && !((BuyRegion)region).isSold())) {
plugin.message(sender, "addfriend-noOwner", region);
return;
}
OfflinePlayer friend = Bukkit.getOfflinePlayer(args[1]);
if(friend.getLastPlayed() == 0 && !friend.isOnline() && !plugin.getConfig().getBoolean("addFriendNotExistingPlayers")) {
plugin.message(sender, "addfriend-notVisited", args[1], region);
return;
}
if(region.getFriendsFeature().getFriends().contains(friend.getUniqueId())) {
plugin.message(sender, "addfriend-alreadyAdded", friend.getName(), region);
return;
}
if(region.isOwner(friend.getUniqueId())) {
plugin.message(sender, "addfriend-self", friend.getName(), region);
return;
}
if(region.getFriendsFeature().addFriend(friend.getUniqueId(), sender)) {
region.update();
plugin.message(sender, "addfriend-successOther", friend.getName(), region);
}
} else {
if(sender.hasPermission("areashop.addfriend") && sender instanceof Player) {
if(region.isOwner((Player)sender)) {
OfflinePlayer friend = Bukkit.getOfflinePlayer(args[1]);
if(friend.getLastPlayed() == 0 && !friend.isOnline() && !plugin.getConfig().getBoolean("addFriendNotExistingPlayers")) {
plugin.message(sender, "addfriend-notVisited", args[1], region);
return;
}
if(region.getFriendsFeature().getFriends().contains(friend.getUniqueId())) {
plugin.message(sender, "addfriend-alreadyAdded", friend.getName(), region);
return;
}
if(region.isOwner(friend.getUniqueId())) {
plugin.message(sender, "addfriend-self", friend.getName(), region);
return;
}
if(region.getFriendsFeature().addFriend(friend.getUniqueId(), sender)) {
region.update();
plugin.message(sender, "addfriend-success", friend.getName(), region);
}
} else {
plugin.message(sender, "addfriend-noPermissionOther", region);
}
} else {
plugin.message(sender, "addfriend-noPermission", region);
}
}
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
ArrayList<String> result = new ArrayList<>();
if(toComplete == 2) {
for(Player player : Utils.getOnlinePlayers()) {
result.add(player.getName());
}
} else if(toComplete == 3) {
result.addAll(plugin.getFileManager().getRegionNames());
}
return result;
}
}
@@ -1,132 +1,125 @@
package nl.evolutioncoding.areashop.commands;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import nl.evolutioncoding.areashop.AreaShop;
import nl.evolutioncoding.areashop.Utils;
import nl.evolutioncoding.areashop.regions.GeneralRegion;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.material.Sign;
import org.bukkit.util.BlockIterator;
import com.sk89q.worldedit.bukkit.selections.CuboidSelection;
public class AddsignCommand extends CommandAreaShop {
public AddsignCommand(AreaShop plugin) {
super(plugin);
}
@Override
public String getCommandStart() {
return "areashop addsign";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.addsign")) {
return plugin.getLanguageManager().getLang("help-addsign");
}
return null;
}
@Override
public void execute(CommandSender sender, Command command, String[] args) {
if(!sender.hasPermission("areashop.addsign")) {
plugin.message(sender, "addsign-noPermission");
return;
}
if (!(sender instanceof Player)) {
plugin.message(sender, "cmd-onlyByPlayer");
return;
}
Player player = (Player)sender;
// Get the sign
Block block = null;
BlockIterator blockIterator = new BlockIterator(player, 100);
while(blockIterator.hasNext() && block == null) {
Block next = blockIterator.next();
if(next.getType() != Material.AIR) {
block = next;
}
}
if(block == null || !(block.getType() == Material.WALL_SIGN || block.getType() == Material.SIGN_POST)) {
plugin.message(sender, "addsign-noSign");
return;
}
GeneralRegion region = null;
if(args.length > 1) {
// Get region by argument
region = plugin.getFileManager().getRegion(args[1]);
if(region == null) {
plugin.message(sender, "addsign-noRegion", args[1]);
return;
}
} else {
// Get region by sign position
List<GeneralRegion> regions = Utils.getASRegionsInSelection(new CuboidSelection(block.getWorld(), block.getLocation(), block.getLocation()));
if(regions.isEmpty()) {
plugin.message(sender, "addsign-noRegions");
return;
} else if(regions.size() > 1) {
plugin.message(sender, "addsign-couldNotDetect", regions.get(0).getName(), regions.get(1).getName());
return;
}
region = regions.get(0);
}
Sign sign = (Sign)block.getState().getData();
String profile = null;
if(args.length > 2) {
profile = args[2];
Set<String> profiles = plugin.getConfig().getConfigurationSection("signProfiles").getKeys(false);
if(!profiles.contains(profile)) {
plugin.message(sender, "addsign-wrongProfile", Utils.createCommaSeparatedList(profiles));
return;
}
}
GeneralRegion signRegion = plugin.getFileManager().getRegionBySignLocation(block.getLocation());
if(signRegion != null) {
plugin.message(sender, "addsign-alreadyRegistered", signRegion.getName());
return;
}
region.addSign(block.getLocation(), block.getType(), sign.getFacing(), profile);
if(profile == null) {
plugin.message(sender, "addsign-success", region);
} else {
plugin.message(sender, "addsign-successProfile", region, profile);
}
region.updateSigns();
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
List<String> result = new ArrayList<String>();
if(toComplete == 2) {
result.addAll(plugin.getFileManager().getRegionNames());
} else if(toComplete == 3) {
result.addAll(plugin.getConfig().getStringList("signProfiles"));
}
return result;
}
}
package me.wiefferink.areashop.commands;
import me.wiefferink.areashop.features.signs.RegionSign;
import me.wiefferink.areashop.features.signs.SignsFeature;
import me.wiefferink.areashop.regions.GeneralRegion;
import me.wiefferink.areashop.tools.Utils;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.material.Sign;
import org.bukkit.util.BlockIterator;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
public class AddsignCommand extends CommandAreaShop {
@Override
public String getCommandStart() {
return "areashop addsign";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.addsign")) {
return "help-addsign";
}
return null;
}
@Override
public void execute(CommandSender sender, String[] args) {
if(!sender.hasPermission("areashop.addsign")) {
plugin.message(sender, "addsign-noPermission");
return;
}
if(!(sender instanceof Player)) {
plugin.message(sender, "cmd-onlyByPlayer");
return;
}
Player player = (Player)sender;
// Get the sign
Block block = null;
BlockIterator blockIterator = new BlockIterator(player, 100);
while(blockIterator.hasNext() && block == null) {
Block next = blockIterator.next();
if(next.getType() != Material.AIR) {
block = next;
}
}
if(block == null || !(block.getType() == Material.WALL_SIGN || block.getType() == Material.SIGN_POST)) {
plugin.message(sender, "addsign-noSign");
return;
}
GeneralRegion region;
if(args.length > 1) {
// Get region by argument
region = plugin.getFileManager().getRegion(args[1]);
if(region == null) {
plugin.message(sender, "cmd-notRegistered", args[1]);
return;
}
} else {
// Get region by sign position
List<GeneralRegion> regions = Utils.getImportantRegions(block.getLocation());
if(regions.isEmpty()) {
plugin.message(sender, "addsign-noRegions");
return;
} else if(regions.size() > 1) {
plugin.message(sender, "addsign-couldNotDetect", regions.get(0).getName(), regions.get(1).getName());
return;
}
region = regions.get(0);
}
Sign sign = (Sign)block.getState().getData();
String profile = null;
if(args.length > 2) {
profile = args[2];
Set<String> profiles = plugin.getConfig().getConfigurationSection("signProfiles").getKeys(false);
if(!profiles.contains(profile)) {
plugin.message(sender, "addsign-wrongProfile", Utils.createCommaSeparatedList(profiles), region);
return;
}
}
RegionSign regionSign = SignsFeature.getSignByLocation(block.getLocation());
if(regionSign != null) {
plugin.message(sender, "addsign-alreadyRegistered", regionSign.getRegion());
return;
}
region.getSignsFeature().addSign(block.getLocation(), block.getType(), sign.getFacing(), profile);
if(profile == null) {
plugin.message(sender, "addsign-success", region);
} else {
plugin.message(sender, "addsign-successProfile", profile, region);
}
region.update();
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
List<String> result = new ArrayList<>();
if(toComplete == 2) {
result.addAll(plugin.getFileManager().getRegionNames());
} else if(toComplete == 3) {
result.addAll(plugin.getConfig().getStringList("signProfiles"));
}
return result;
}
}
@@ -1,78 +1,69 @@
package nl.evolutioncoding.areashop.commands;
import java.util.ArrayList;
import java.util.List;
import nl.evolutioncoding.areashop.AreaShop;
import nl.evolutioncoding.areashop.Utils;
import nl.evolutioncoding.areashop.regions.BuyRegion;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
public class BuyCommand extends CommandAreaShop {
public BuyCommand(AreaShop plugin) {
super(plugin);
}
@Override
public String getCommandStart() {
return "areashop buy";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.buy")) {
return plugin.getLanguageManager().getLang("help-buy");
}
return null;
}
@Override
public void execute(CommandSender sender, Command command, String[] args) {
if(!sender.hasPermission("areashop.buy")) {
plugin.message(sender, "buy-noPermission");
return;
}
if (!(sender instanceof Player)) {
plugin.message(sender, "cmd-onlyByPlayer");
return;
}
Player player = (Player)sender;
if(args.length > 1 && args[1] != null) {
BuyRegion region = plugin.getFileManager().getBuy(args[1]);
if(region == null) {
plugin.message(player, "buy-notBuyable");
} else {
region.buy(player);
}
} else {
// get the region by location
List<BuyRegion> regions = Utils.getApplicableBuyRegions(((Player) sender).getLocation());
if (regions.isEmpty()) {
plugin.message(sender, "cmd-noRegionsAtLocation");
return;
} else if (regions.size() > 1) {
plugin.message(sender, "cmd-moreRegionsAtLocation");
return;
} else {
regions.get(0).buy(player);
}
}
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
ArrayList<String> result = new ArrayList<String>();
if(toComplete == 2) {
for(BuyRegion region : plugin.getFileManager().getBuys()) {
if(!region.isSold()) {
result.add(region.getName());
}
}
}
return result;
}
}
package me.wiefferink.areashop.commands;
import me.wiefferink.areashop.regions.BuyRegion;
import me.wiefferink.areashop.tools.Utils;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.List;
public class BuyCommand extends CommandAreaShop {
@Override
public String getCommandStart() {
return "areashop buy";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.buy")) {
return "help-buy";
}
return null;
}
@Override
public void execute(CommandSender sender, String[] args) {
if(!sender.hasPermission("areashop.buy")) {
plugin.message(sender, "buy-noPermission");
return;
}
if(!(sender instanceof Player)) {
plugin.message(sender, "cmd-onlyByPlayer");
return;
}
Player player = (Player)sender;
if(args.length > 1 && args[1] != null) {
BuyRegion region = plugin.getFileManager().getBuy(args[1]);
if(region == null) {
plugin.message(player, "buy-notBuyable", args[1]);
} else {
region.buy(player);
}
} else {
// get the region by location
List<BuyRegion> regions = Utils.getImportantBuyRegions(((Player)sender).getLocation());
if(regions.isEmpty()) {
plugin.message(sender, "cmd-noRegionsAtLocation");
} else if(regions.size() > 1) {
plugin.message(sender, "cmd-moreRegionsAtLocation");
} else {
regions.get(0).buy(player);
}
}
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
ArrayList<String> result = new ArrayList<>();
if(toComplete == 2) {
for(BuyRegion region : plugin.getFileManager().getBuys()) {
if(!region.isSold()) {
result.add(region.getName());
}
}
}
return result;
}
}
@@ -0,0 +1,102 @@
package me.wiefferink.areashop.commands;
import me.wiefferink.areashop.AreaShop;
import me.wiefferink.interactivemessenger.processing.Message;
import org.apache.commons.lang.StringUtils;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Abstract class for generalising command classes.
*/
public abstract class CommandAreaShop {
final AreaShop plugin = AreaShop.getInstance();
private final Map<String, CommandTime> lastUsed;
public CommandAreaShop() {
lastUsed = new HashMap<>();
}
/**
* Check if this Command instance can execute the given command and arguments.
* @param command The command to check for execution
* @param args The arguments to check
* @return true if it can execute the command, false otherwise
*/
public boolean canExecute(Command command, String[] args) {
String commandString = command.getName() + " " + StringUtils.join(args, " ");
if(commandString.length() > getCommandStart().length()) {
return commandString.toLowerCase().startsWith(getCommandStart().toLowerCase() + " ");
}
return commandString.toLowerCase().startsWith(getCommandStart().toLowerCase());
}
/**
* Get a list of string to complete a command with (raw list, not matching ones not filtered out).
* @param toComplete The number of the argument that has to be completed
* @param start The already given start of the command
* @param sender The CommandSender that wants to tab complete
* @return A collection with all the possibilities for argument to complete
*/
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
return new ArrayList<>();
}
/**
* Get the argument that comes after the base command that this command reacts to.
* @return The string that should be in front of the command for this class to act
*/
public abstract String getCommandStart();
/**
* Returns the correct help string key to be used on the help page.
* @param target The CommandSender that the help message is for
* @return The help message key according to the permissions of the reciever
*/
public abstract String getHelp(CommandSender target);
/**
* Execute a (sub)command if the conditions are met.
* @param sender The commandSender that executed the command
* @param args The arguments that are given
*/
public abstract void execute(CommandSender sender, String[] args);
/**
* Confirm a command.
* @param sender To confirm it for, or send a message to confirm
* @param args Command args
* @param message Message to send when confirmation is required
* @return true if confirmed, false if confirmation is required
*/
public boolean confirm(CommandSender sender, String[] args, Message message) {
String command = "/" + getCommandStart() + " " + StringUtils.join(args, " ", 1, args.length);
long now = System.currentTimeMillis();
CommandTime last = lastUsed.get(sender.getName());
if(last != null && last.command.equalsIgnoreCase(command) && last.time > (now - 1000 * 60)) {
return true;
}
message.prefix().append(Message.fromKey("confirm-yes").replacements(command)).send(sender);
lastUsed.put(sender.getName(), new CommandTime(command, now));
return false;
}
private class CommandTime {
public String command;
public long time;
CommandTime(String command, long time) {
this.command = command;
this.time = time;
}
}
}
@@ -1,138 +1,131 @@
package nl.evolutioncoding.areashop.commands;
import java.util.ArrayList;
import java.util.List;
import nl.evolutioncoding.areashop.AreaShop;
import nl.evolutioncoding.areashop.Utils;
import nl.evolutioncoding.areashop.regions.BuyRegion;
import nl.evolutioncoding.areashop.regions.GeneralRegion;
import nl.evolutioncoding.areashop.regions.RentRegion;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import com.sk89q.worldedit.bukkit.selections.Selection;
public class DelCommand extends CommandAreaShop {
public DelCommand(AreaShop plugin) {
super(plugin);
}
@Override
public String getCommandStart() {
return "areashop del";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.destroyrent") || target.hasPermission("areashop.destroybuy")) {
return plugin.getLanguageManager().getLang("help-del");
}
return null;
}
@Override
public void execute(CommandSender sender, Command command, String[] args) {
if( !sender.hasPermission("areashop.destroybuy")
&& !sender.hasPermission("areashop.destroybuy.landlord")
&& !sender.hasPermission("areashop.destroyrent")
&& !sender.hasPermission("areashop.destroyrent.landlord")) {
plugin.message(sender, "del-noPermission");
return;
}
if(args.length < 2) {
// Only players can have a selection
if(!(sender instanceof Player)) {
plugin.message(sender, "cmd-weOnlyByPlayer");
return;
}
Player player = (Player)sender;
Selection selection = plugin.getWorldEdit().getSelection(player);
if(selection == null) {
plugin.message(player, "cmd-noSelection");
return;
}
List<GeneralRegion> regions = Utils.getASRegionsInSelection(selection);
if(regions == null || regions.size() == 0) {
plugin.message(player, "cmd-noRegionsFound");
return;
}
// Start removing the region that he has permission for
ArrayList<String> namesSuccess = new ArrayList<String>();
ArrayList<String> namesFailed = new ArrayList<String>();
for(GeneralRegion region : regions) {
boolean isLandlord = sender instanceof Player && region.isLandlord(((Player)sender).getUniqueId());
if(region.isRentRegion()) {
if(!sender.hasPermission("areashop.destroyrent") && !(isLandlord && sender.hasPermission("areashop.destroyrent.landlord"))) {
namesFailed.add(region.getName());
} else {
plugin.getFileManager().removeRent((RentRegion)region, true);
namesSuccess.add(region.getName());
}
} else if(region.isBuyRegion()) {
if(!sender.hasPermission("areashop.destroybuy") && !(isLandlord && sender.hasPermission("areashop.destroybuy.landlord"))) {
namesFailed.add(region.getName());
} else {
plugin.getFileManager().removeBuy((BuyRegion)region, true);
namesSuccess.add(region.getName());
}
}
}
// send messages
if(namesSuccess.size() != 0) {
plugin.message(sender, "del-success", Utils.createCommaSeparatedList(namesSuccess));
}
if(namesFailed.size() != 0) {
plugin.message(sender, "del-failed", Utils.createCommaSeparatedList(namesFailed));
}
} else {
GeneralRegion region = plugin.getFileManager().getRegion(args[1]);
if(region == null) {
plugin.message(sender, "del-noRegion", args[1]);
return;
}
boolean isLandlord = sender instanceof Player && region.isLandlord(((Player)sender).getUniqueId());
if(region.isRentRegion()) {
/* Remove the rent if the player has permission */
if(sender.hasPermission("areashop.destroyrent") || (isLandlord && sender.hasPermission("areashop.destroyrent.landlord"))) {
plugin.getFileManager().removeRent((RentRegion)region, true);
plugin.message(sender, "destroy-successRent", region.getName());
} else {
plugin.message(sender, "destroy-noPermissionRent");
}
} else if(region.isBuyRegion()) {
/* Remove the buy if the player has permission */
if(sender.hasPermission("areashop.destroybuy") || (isLandlord && sender.hasPermission("areashop.destroybuy.landlord"))) {
plugin.getFileManager().removeBuy((BuyRegion)region, true);
plugin.message(sender, "destroy-successBuy", region.getName());
} else {
plugin.message(sender, "destroy-noPermissionBuy");
}
}
}
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
List<String> result = new ArrayList<String>();
if(toComplete == 2) {
result = plugin.getFileManager().getRegionNames();
}
return result;
}
}
package me.wiefferink.areashop.commands;
import me.wiefferink.areashop.interfaces.WorldEditSelection;
import me.wiefferink.areashop.regions.BuyRegion;
import me.wiefferink.areashop.regions.GeneralRegion;
import me.wiefferink.areashop.regions.RentRegion;
import me.wiefferink.areashop.tools.Utils;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.List;
import java.util.TreeSet;
public class DelCommand extends CommandAreaShop {
@Override
public String getCommandStart() {
return "areashop del";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.destroyrent") || target.hasPermission("areashop.destroybuy") || target.hasPermission("areashop.destroyrent.landlord") || target.hasPermission("areashop.destroybuy.landlord")) {
return "help-del";
}
return null;
}
@Override
public void execute(CommandSender sender, String[] args) {
if(!sender.hasPermission("areashop.destroybuy")
&& !sender.hasPermission("areashop.destroybuy.landlord")
&& !sender.hasPermission("areashop.destroyrent")
&& !sender.hasPermission("areashop.destroyrent.landlord")) {
plugin.message(sender, "del-noPermission");
return;
}
if(args.length < 2) {
// Only players can have a selection
if(!(sender instanceof Player)) {
plugin.message(sender, "cmd-weOnlyByPlayer");
return;
}
Player player = (Player)sender;
WorldEditSelection selection = plugin.getWorldEditHandler().getPlayerSelection(player);
if(selection == null) {
plugin.message(player, "cmd-noSelection");
return;
}
List<GeneralRegion> regions = Utils.getRegionsInSelection(selection);
if(regions == null || regions.size() == 0) {
plugin.message(player, "cmd-noRegionsFound");
return;
}
// Start removing the regions that he has permission for
ArrayList<String> namesSuccess = new ArrayList<>();
TreeSet<GeneralRegion> namesFailed = new TreeSet<>();
for(GeneralRegion region : regions) {
boolean isLandlord = region.isLandlord(((Player)sender).getUniqueId());
if(region instanceof RentRegion) {
if(!sender.hasPermission("areashop.destroyrent") && !(isLandlord && sender.hasPermission("areashop.destroyrent.landlord"))) {
namesFailed.add(region);
} else {
plugin.getFileManager().removeRent((RentRegion)region, true);
namesSuccess.add(region.getName());
}
} else if(region instanceof BuyRegion) {
if(!sender.hasPermission("areashop.destroybuy") && !(isLandlord && sender.hasPermission("areashop.destroybuy.landlord"))) {
namesFailed.add(region);
} else {
plugin.getFileManager().removeBuy((BuyRegion)region, true);
namesSuccess.add(region.getName());
}
}
}
// send messages
if(namesSuccess.size() != 0) {
plugin.message(sender, "del-success", Utils.createCommaSeparatedList(namesSuccess));
}
if(namesFailed.size() != 0) {
plugin.message(sender, "del-failed", Utils.combinedMessage(namesFailed, "region"));
}
} else {
GeneralRegion region = plugin.getFileManager().getRegion(args[1]);
if(region == null) {
plugin.message(sender, "cmd-notRegistered", args[1]);
return;
}
boolean isLandlord = sender instanceof Player && region.isLandlord(((Player)sender).getUniqueId());
if(region instanceof RentRegion) {
// Remove the rent if the player has permission
if(sender.hasPermission("areashop.destroyrent") || (isLandlord && sender.hasPermission("areashop.destroyrent.landlord"))) {
plugin.getFileManager().removeRent((RentRegion)region, true);
plugin.message(sender, "destroy-successRent", region);
} else {
plugin.message(sender, "destroy-noPermissionRent", region);
}
} else if(region instanceof BuyRegion) {
// Remove the buy if the player has permission
if(sender.hasPermission("areashop.destroybuy") || (isLandlord && sender.hasPermission("areashop.destroybuy.landlord"))) {
plugin.getFileManager().removeBuy((BuyRegion)region, true);
plugin.message(sender, "destroy-successBuy", region);
} else {
plugin.message(sender, "destroy-noPermissionBuy", region);
}
}
}
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
List<String> result = new ArrayList<>();
if(toComplete == 2) {
result = plugin.getFileManager().getRegionNames();
}
return result;
}
}
@@ -0,0 +1,139 @@
package me.wiefferink.areashop.commands;
import me.wiefferink.areashop.regions.BuyRegion;
import me.wiefferink.areashop.regions.GeneralRegion;
import me.wiefferink.areashop.regions.RentRegion;
import me.wiefferink.areashop.tools.Utils;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.List;
public class DelfriendCommand extends CommandAreaShop {
@Override
public String getCommandStart() {
return "areashop delfriend";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.delfriendall") || target.hasPermission("areashop.delfriend")) {
return "help-delFriend";
}
return null;
}
/**
* Check if a person can remove friends.
* @param person The person to check
* @param region The region to check for
* @return true if the person can remove friends, otherwise false
*/
public static boolean canUse(CommandSender person, GeneralRegion region) {
if(person.hasPermission("areashop.delfriendall")) {
return true;
}
if(person instanceof Player) {
Player player = (Player)person;
return region.isOwner(player) && player.hasPermission("areashop.delfriend");
}
return false;
}
@SuppressWarnings("deprecation")
@Override
public void execute(CommandSender sender, String[] args) {
if(!sender.hasPermission("areashop.delfriend") && !sender.hasPermission("areashop.delfriendall")) {
plugin.message(sender, "delfriend-noPermission");
return;
}
if(args.length < 2) {
plugin.message(sender, "delfriend-help");
return;
}
GeneralRegion region;
if(args.length <= 2) {
if(sender instanceof Player) {
// get the region by location
List<GeneralRegion> regions = Utils.getImportantRegions(((Player)sender).getLocation());
if(regions.isEmpty()) {
plugin.message(sender, "cmd-noRegionsAtLocation");
return;
} else if(regions.size() > 1) {
plugin.message(sender, "cmd-moreRegionsAtLocation");
return;
} else {
region = regions.get(0);
}
} else {
plugin.message(sender, "cmd-automaticRegionOnlyByPlayer");
return;
}
} else {
region = plugin.getFileManager().getRegion(args[2]);
if(region == null) {
plugin.message(sender, "cmd-notRegistered", args[2]);
return;
}
}
if(sender.hasPermission("areashop.delfriendall")) {
if((region instanceof RentRegion && !((RentRegion)region).isRented())
|| (region instanceof BuyRegion && !((BuyRegion)region).isSold())) {
plugin.message(sender, "delfriend-noOwner", region);
return;
}
OfflinePlayer friend = Bukkit.getOfflinePlayer(args[1]);
if(!region.getFriendsFeature().getFriends().contains(friend.getUniqueId())) {
plugin.message(sender, "delfriend-notAdded", friend.getName(), region);
return;
}
if(region.getFriendsFeature().deleteFriend(friend.getUniqueId(), sender)) {
region.update();
plugin.message(sender, "delfriend-successOther", friend.getName(), region);
}
} else {
if(sender.hasPermission("areashop.delfriend") && sender instanceof Player) {
if(region.isOwner((Player)sender)) {
OfflinePlayer friend = Bukkit.getOfflinePlayer(args[1]);
if(!region.getFriendsFeature().getFriends().contains(friend.getUniqueId())) {
plugin.message(sender, "delfriend-notAdded", friend.getName(), region);
return;
}
if(region.getFriendsFeature().deleteFriend(friend.getUniqueId(), sender)) {
region.update();
plugin.message(sender, "delfriend-success", friend.getName(), region);
}
} else {
plugin.message(sender, "delfriend-noPermissionOther", region);
}
} else {
plugin.message(sender, "delfriend-noPermission", region);
}
}
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
ArrayList<String> result = new ArrayList<>();
if(toComplete == 2) {
for(Player player : Utils.getOnlinePlayers()) {
result.add(player.getName());
}
} else if(toComplete == 3) {
result.addAll(plugin.getFileManager().getRegionNames());
}
return result;
}
}
@@ -1,85 +1,78 @@
package nl.evolutioncoding.areashop.commands;
import java.util.ArrayList;
import java.util.List;
import nl.evolutioncoding.areashop.AreaShop;
import nl.evolutioncoding.areashop.regions.GeneralRegion;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.util.BlockIterator;
public class DelsignCommand extends CommandAreaShop {
public DelsignCommand(AreaShop plugin) {
super(plugin);
}
@Override
public String getCommandStart() {
return "areashop delsign";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.delsign")) {
return plugin.getLanguageManager().getLang("help-delsign");
}
return null;
}
@Override
public void execute(CommandSender sender, Command command, String[] args) {
if(!sender.hasPermission("areashop.delsign")) {
plugin.message(sender, "delsign-noPermission");
return;
}
if (!(sender instanceof Player)) {
plugin.message(sender, "cmd-onlyByPlayer");
return;
}
Player player = (Player)sender;
// Get the sign
Block block = null;
BlockIterator blockIterator = new BlockIterator(player, 100);
while(blockIterator.hasNext() && block == null) {
Block next = blockIterator.next();
if(next.getType() != Material.AIR) {
block = next;
}
}
if(block == null || !(block.getType() == Material.WALL_SIGN || block.getType() == Material.SIGN_POST)) {
plugin.message(sender, "delsign-noSign");
return;
}
GeneralRegion region = plugin.getFileManager().getRegionBySignLocation(block.getLocation());
if(region == null) {
plugin.message(sender, "delsign-noRegion");
return;
}
plugin.message(sender, "delsign-success", region.getName());
region.removeSign(block.getLocation());
region.updateSigns();
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
return new ArrayList<String>();
}
}
package me.wiefferink.areashop.commands;
import me.wiefferink.areashop.features.signs.RegionSign;
import me.wiefferink.areashop.features.signs.SignsFeature;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.util.BlockIterator;
import java.util.ArrayList;
import java.util.List;
public class DelsignCommand extends CommandAreaShop {
@Override
public String getCommandStart() {
return "areashop delsign";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.delsign")) {
return "help-delsign";
}
return null;
}
@Override
public void execute(CommandSender sender, String[] args) {
if(!sender.hasPermission("areashop.delsign")) {
plugin.message(sender, "delsign-noPermission");
return;
}
if(!(sender instanceof Player)) {
plugin.message(sender, "cmd-onlyByPlayer");
return;
}
Player player = (Player)sender;
// Get the sign
Block block = null;
BlockIterator blockIterator = new BlockIterator(player, 100);
while(blockIterator.hasNext() && block == null) {
Block next = blockIterator.next();
if(next.getType() != Material.AIR) {
block = next;
}
}
if(block == null || !(block.getType() == Material.WALL_SIGN || block.getType() == Material.SIGN_POST)) {
plugin.message(sender, "delsign-noSign");
return;
}
RegionSign regionSign = SignsFeature.getSignByLocation(block.getLocation());
if(regionSign == null) {
plugin.message(sender, "delsign-noRegion");
return;
}
plugin.message(sender, "delsign-success", regionSign.getRegion());
regionSign.remove();
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
return new ArrayList<>();
}
}
@@ -0,0 +1,190 @@
package me.wiefferink.areashop.commands;
import me.wiefferink.areashop.regions.BuyRegion;
import me.wiefferink.areashop.regions.RegionGroup;
import me.wiefferink.areashop.regions.RentRegion;
import me.wiefferink.areashop.tools.Utils;
import me.wiefferink.interactivemessenger.processing.Message;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class FindCommand extends CommandAreaShop {
@Override
public String getCommandStart() {
return "areashop find";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.find")) {
return "help-find";
}
return null;
}
@Override
public void execute(CommandSender sender, String[] args) {
if(!sender.hasPermission("areashop.find")) {
plugin.message(sender, "find-noPermission");
return;
}
if(!(sender instanceof Player)) {
plugin.message(sender, "cmd-onlyByPlayer");
return;
}
if(args.length <= 1 || args[1] == null || (!args[1].equalsIgnoreCase("buy") && !args[1].equalsIgnoreCase("rent"))) {
plugin.message(sender, "find-help");
return;
}
Player player = (Player)sender;
double balance = 0.0;
if(plugin.getEconomy() != null) {
balance = plugin.getEconomy().getBalance(player);
}
double maxPrice = 0;
boolean maxPriceSet = false;
RegionGroup group = null;
// Parse optional price argument
if(args.length >= 3) {
try {
maxPrice = Double.parseDouble(args[2]);
maxPriceSet = true;
} catch(NumberFormatException e) {
plugin.message(sender, "find-wrongMaxPrice", args[2]);
return;
}
}
// Parse optional group argument
if(args.length >= 4) {
group = plugin.getFileManager().getGroup(args[3]);
if(group == null) {
plugin.message(sender, "find-wrongGroup", args[3]);
return;
}
}
// Find buy regions
if(args[1].equalsIgnoreCase("buy")) {
List<BuyRegion> regions = plugin.getFileManager().getBuys();
List<BuyRegion> results = new ArrayList<>();
for(BuyRegion region : regions) {
if(!region.isSold()
&& ((region.getPrice() <= balance && !maxPriceSet) || (region.getPrice() <= maxPrice && maxPriceSet))
&& (group == null || group.isMember(region))
&& (region.getBooleanSetting("general.findCrossWorld") || player.getWorld().equals(region.getWorld()))) {
results.add(region);
}
}
if(!results.isEmpty()) {
// Draw a random one
BuyRegion region = results.get(new Random().nextInt(results.size()));
Message onlyInGroup = Message.empty();
if(group != null) {
onlyInGroup = Message.fromKey("find-onlyInGroup").replacements(args[3]);
}
// Teleport
if(maxPriceSet) {
plugin.message(player, "find-successMax", "buy", Utils.formatCurrency(maxPrice), onlyInGroup, region);
} else {
plugin.message(player, "find-success", "buy", Utils.formatCurrency(balance), onlyInGroup, region);
}
region.getTeleportFeature().teleportPlayer(player, region.getBooleanSetting("general.findTeleportToSign"), false);
} else {
Message onlyInGroup = Message.empty();
if(group != null) {
onlyInGroup = Message.fromKey("find-onlyInGroup").replacements(args[3]);
}
if(maxPriceSet) {
plugin.message(player, "find-noneFoundMax", "buy", Utils.formatCurrency(maxPrice), onlyInGroup);
} else {
plugin.message(player, "find-noneFound", "buy", Utils.formatCurrency(balance), onlyInGroup);
}
}
}
// Find rental regions
else {
List<RentRegion> regions = plugin.getFileManager().getRents();
List<RentRegion> results = new ArrayList<>();
for(RentRegion region : regions) {
if(!region.isRented()
&& ((region.getPrice() <= balance && !maxPriceSet) || (region.getPrice() <= maxPrice && maxPriceSet))
&& (group == null || group.isMember(region))
&& (region.getBooleanSetting("general.findCrossWorld") || player.getWorld().equals(region.getWorld()))) {
results.add(region);
}
}
if(!results.isEmpty()) {
// Draw a random one
RentRegion region = results.get(new Random().nextInt(results.size()));
Message onlyInGroup = Message.empty();
if(group != null) {
onlyInGroup = Message.fromKey("find-onlyInGroup").replacements(args[3]);
}
// Teleport
if(maxPriceSet) {
plugin.message(player, "find-successMax", "rent", Utils.formatCurrency(maxPrice), onlyInGroup, region);
} else {
plugin.message(player, "find-success", "rent", Utils.formatCurrency(balance), onlyInGroup, region);
}
region.getTeleportFeature().teleportPlayer(player, region.getBooleanSetting("general.findTeleportToSign"), false);
} else {
Message onlyInGroup = Message.empty();
if(group != null) {
onlyInGroup = Message.fromKey("find-onlyInGroup").replacements(args[3]);
}
if(maxPriceSet) {
plugin.message(player, "find-noneFoundMax", "rent", Utils.formatCurrency(maxPrice), onlyInGroup);
} else {
plugin.message(player, "find-noneFound", "rent", Utils.formatCurrency(balance), onlyInGroup);
}
}
}
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
ArrayList<String> result = new ArrayList<>();
if(toComplete == 2) {
result.add("buy");
result.add("rent");
}
return result;
}
}
@@ -1,123 +1,113 @@
package nl.evolutioncoding.areashop.commands;
import java.util.ArrayList;
import java.util.List;
import nl.evolutioncoding.areashop.AreaShop;
import nl.evolutioncoding.areashop.Utils;
import nl.evolutioncoding.areashop.regions.GeneralRegion;
import nl.evolutioncoding.areashop.regions.RegionGroup;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import com.sk89q.worldedit.bukkit.selections.Selection;
public class GroupaddCommand extends CommandAreaShop {
public GroupaddCommand(AreaShop plugin) {
super(plugin);
}
@Override
public String getCommandStart() {
return "areashop groupadd";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.groupadd")) {
return plugin.getLanguageManager().getLang("help-groupadd");
}
return null;
}
@Override
public void execute(CommandSender sender, Command command, String[] args) {
if(!sender.hasPermission("areashop.groupadd")) {
plugin.message(sender, "groupadd-noPermission");
return;
}
if(args.length < 2 || args[1] == null) {
plugin.message(sender, "groupadd-help");
return;
}
RegionGroup group = plugin.getFileManager().getGroup(args[1]);
if(group == null) {
group = new RegionGroup(plugin, args[1]);
plugin.getFileManager().addGroup(group);
}
if(args.length == 2) {
if(!(sender instanceof Player)) {
plugin.message(sender, "cmd-weOnlyByPlayer");
return;
}
Player player = (Player)sender;
Selection selection = plugin.getWorldEdit().getSelection(player);
if(selection == null) {
plugin.message(player, "cmd-noSelection");
return;
}
List<GeneralRegion> regions = Utils.getASRegionsInSelection(selection);
if(regions.size() == 0) {
plugin.message(player, "cmd-noRegionsFound");
return;
}
ArrayList<String> namesSuccess = new ArrayList<String>();
ArrayList<String> namesFailed = new ArrayList<String>();
ArrayList<GeneralRegion> toUpdate = new ArrayList<GeneralRegion>();
for(GeneralRegion region : regions) {
if(group.addMember(region)) {
namesSuccess.add(region.getName());
toUpdate.add(region);
} else {
namesFailed.add(region.getName());
}
}
if(namesSuccess.size() != 0) {
plugin.message(player, "groupadd-weSuccess", group.getName(), Utils.createCommaSeparatedList(namesSuccess));
}
if(namesFailed.size() != 0) {
plugin.message(player, "groupadd-weFailed", group.getName(), Utils.createCommaSeparatedList(namesFailed));
}
// Update all regions, this does it in a task, updating them without lag
plugin.getFileManager().updateRegions(toUpdate, player);
} else {
GeneralRegion region = plugin.getFileManager().getRegion(args[2]);
if(region == null) {
plugin.message(sender, "groupadd-noRegion", args[2]);
return;
}
if(group.addMember(region)) {
region.updateRegionFlags();
region.updateSigns();
plugin.message(sender, "groupadd-success", region.getName(), group.getName(), group.getMembers().size());
} else {
plugin.message(sender, "groupadd-failed", region.getName(), group.getName());
}
}
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
List<String> result = new ArrayList<String>();
if(toComplete == 2) {
result = plugin.getFileManager().getGroupNames();
} else if(toComplete == 3) {
result = plugin.getFileManager().getRegionNames();
}
return result;
}
}
package me.wiefferink.areashop.commands;
import me.wiefferink.areashop.interfaces.WorldEditSelection;
import me.wiefferink.areashop.regions.GeneralRegion;
import me.wiefferink.areashop.regions.RegionGroup;
import me.wiefferink.areashop.tools.Utils;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.List;
import java.util.TreeSet;
public class GroupaddCommand extends CommandAreaShop {
@Override
public String getCommandStart() {
return "areashop groupadd";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.groupadd")) {
return "help-groupadd";
}
return null;
}
@Override
public void execute(CommandSender sender, String[] args) {
if(!sender.hasPermission("areashop.groupadd")) {
plugin.message(sender, "groupadd-noPermission");
return;
}
if(args.length < 2 || args[1] == null) {
plugin.message(sender, "groupadd-help");
return;
}
RegionGroup group = plugin.getFileManager().getGroup(args[1]);
if(group == null) {
group = new RegionGroup(plugin, args[1]);
plugin.getFileManager().addGroup(group);
}
if(args.length == 2) {
if(!(sender instanceof Player)) {
plugin.message(sender, "cmd-weOnlyByPlayer");
return;
}
Player player = (Player)sender;
WorldEditSelection selection = plugin.getWorldEditHandler().getPlayerSelection(player);
if(selection == null) {
plugin.message(player, "cmd-noSelection");
return;
}
List<GeneralRegion> regions = Utils.getRegionsInSelection(selection);
if(regions.size() == 0) {
plugin.message(player, "cmd-noRegionsFound");
return;
}
TreeSet<GeneralRegion> regionsSuccess = new TreeSet<>();
TreeSet<GeneralRegion> regionsFailed = new TreeSet<>();
for(GeneralRegion region : regions) {
if(group.addMember(region)) {
regionsSuccess.add(region);
} else {
regionsFailed.add(region);
}
}
if(regionsSuccess.size() != 0) {
plugin.message(player, "groupadd-weSuccess", group.getName(), Utils.combinedMessage(regionsSuccess, "region"));
}
if(regionsFailed.size() != 0) {
plugin.message(player, "groupadd-weFailed", group.getName(), Utils.combinedMessage(regionsFailed, "region"));
}
// Update all regions, this does it in a task, updating them without lag
plugin.getFileManager().updateRegions(new ArrayList<>(regionsSuccess), player);
} else {
GeneralRegion region = plugin.getFileManager().getRegion(args[2]);
if(region == null) {
plugin.message(sender, "cmd-notRegistered", args[2]);
return;
}
if(group.addMember(region)) {
region.update();
plugin.message(sender, "groupadd-success", group.getName(), group.getMembers().size(), region);
} else {
plugin.message(sender, "groupadd-failed", group.getName(), region);
}
}
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
List<String> result = new ArrayList<>();
if(toComplete == 2) {
result = plugin.getFileManager().getGroupNames();
} else if(toComplete == 3) {
result = plugin.getFileManager().getRegionNames();
}
return result;
}
}
@@ -0,0 +1,115 @@
package me.wiefferink.areashop.commands;
import me.wiefferink.areashop.interfaces.WorldEditSelection;
import me.wiefferink.areashop.regions.GeneralRegion;
import me.wiefferink.areashop.regions.RegionGroup;
import me.wiefferink.areashop.tools.Utils;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.List;
import java.util.TreeSet;
public class GroupdelCommand extends CommandAreaShop {
@Override
public String getCommandStart() {
return "areashop groupdel";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.groupdel")) {
return "help-groupdel";
}
return null;
}
@Override
public void execute(CommandSender sender, String[] args) {
if(!sender.hasPermission("areashop.groupdel")) {
plugin.message(sender, "groupdel-noPermission");
return;
}
if(args.length < 2 || args[1] == null) {
plugin.message(sender, "groupdel-help");
return;
}
RegionGroup group = plugin.getFileManager().getGroup(args[1]);
if(group == null) {
plugin.message(sender, "groupdel-wrongGroup", args[1]);
return;
}
if(args.length == 2) {
if(!(sender instanceof Player)) {
plugin.message(sender, "cmd-weOnlyByPlayer");
return;
}
Player player = (Player)sender;
WorldEditSelection selection = plugin.getWorldEditHandler().getPlayerSelection(player);
if(selection == null) {
plugin.message(player, "cmd-noSelection");
return;
}
List<GeneralRegion> regions = Utils.getRegionsInSelection(selection);
if(regions.size() == 0) {
plugin.message(player, "cmd-noRegionsFound");
return;
}
TreeSet<GeneralRegion> regionsSuccess = new TreeSet<>();
TreeSet<GeneralRegion> regionsFailed = new TreeSet<>();
for(GeneralRegion region : regions) {
if(group.removeMember(region)) {
regionsSuccess.add(region);
} else {
regionsFailed.add(region);
}
}
if(regionsSuccess.size() != 0) {
plugin.message(player, "groupdel-weSuccess", group.getName(), Utils.combinedMessage(regionsSuccess, "region"));
}
if(regionsFailed.size() != 0) {
plugin.message(player, "groupdel-weFailed", group.getName(), Utils.combinedMessage(regionsFailed, "region"));
}
// Update all regions, this does it in a task, updating them without lag
plugin.getFileManager().updateRegions(new ArrayList<>(regionsSuccess), player);
group.saveRequired();
} else {
GeneralRegion region = plugin.getFileManager().getRegion(args[2]);
if(region == null) {
plugin.message(sender, "cmd-notRegistered", args[2]);
return;
}
if(group.removeMember(region)) {
region.update();
plugin.message(sender, "groupdel-success", group.getName(), group.getMembers().size(), region);
} else {
plugin.message(sender, "groupdel-failed", group.getName(), region);
}
}
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
List<String> result = new ArrayList<>();
if(toComplete == 2) {
result = plugin.getFileManager().getGroupNames();
} else if(toComplete == 3) {
result = plugin.getFileManager().getRegionNames();
}
return result;
}
}
@@ -1,75 +1,69 @@
package nl.evolutioncoding.areashop.commands;
import java.util.ArrayList;
import java.util.List;
import nl.evolutioncoding.areashop.AreaShop;
import nl.evolutioncoding.areashop.Utils;
import nl.evolutioncoding.areashop.regions.RegionGroup;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
public class GroupinfoCommand extends CommandAreaShop {
public GroupinfoCommand(AreaShop plugin) {
super(plugin);
}
@Override
public String getCommandStart() {
return "areashop groupinfo";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.groupinfo")) {
return plugin.getLanguageManager().getLang("help-groupinfo");
}
return null;
}
@Override
public void execute(CommandSender sender, Command command, String[] args) {
if(!sender.hasPermission("areashop.groupinfo")) {
plugin.message(sender, "groupinfo-noPermission");
return;
}
if(args.length < 2 || args[1] == null) {
plugin.message(sender, "groupinfo-help");
return;
}
RegionGroup group = plugin.getFileManager().getGroup(args[1]);
if(group == null) {
plugin.message(sender, "groupinfo-noGroup", args[1]);
return;
}
List<String> members = group.getMembers();
if(members.size() == 0) {
plugin.message(sender, "groupinfo-noMembers", group.getName());
} else {
plugin.message(sender, "groupinfo-members", group.getName(), Utils.createCommaSeparatedList(members));
}
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
List<String> result = new ArrayList<String>();
if(toComplete == 2) {
result = plugin.getFileManager().getGroupNames();
}
return result;
}
}
package me.wiefferink.areashop.commands;
import me.wiefferink.areashop.regions.RegionGroup;
import me.wiefferink.areashop.tools.Utils;
import org.bukkit.command.CommandSender;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
public class GroupinfoCommand extends CommandAreaShop {
@Override
public String getCommandStart() {
return "areashop groupinfo";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.groupinfo")) {
return "help-groupinfo";
}
return null;
}
@Override
public void execute(CommandSender sender, String[] args) {
if(!sender.hasPermission("areashop.groupinfo")) {
plugin.message(sender, "groupinfo-noPermission");
return;
}
if(args.length < 2 || args[1] == null) {
plugin.message(sender, "groupinfo-help");
return;
}
RegionGroup group = plugin.getFileManager().getGroup(args[1]);
if(group == null) {
plugin.message(sender, "groupinfo-noGroup", args[1]);
return;
}
Set<String> members = group.getMembers();
if(members.size() == 0) {
plugin.message(sender, "groupinfo-noMembers", group.getName());
} else {
plugin.message(sender, "groupinfo-members", group.getName(), Utils.createCommaSeparatedList(members));
}
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
List<String> result = new ArrayList<>();
if(toComplete == 2) {
result = plugin.getFileManager().getGroupNames();
}
return result;
}
}
@@ -1,60 +1,53 @@
package nl.evolutioncoding.areashop.commands;
import java.util.ArrayList;
import java.util.List;
import nl.evolutioncoding.areashop.AreaShop;
import nl.evolutioncoding.areashop.Utils;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
public class GrouplistCommand extends CommandAreaShop {
public GrouplistCommand(AreaShop plugin) {
super(plugin);
}
@Override
public String getCommandStart() {
return "areashop grouplist";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.grouplist")) {
return plugin.getLanguageManager().getLang("help-grouplist");
}
return null;
}
@Override
public void execute(CommandSender sender, Command command, String[] args) {
if(!sender.hasPermission("areashop.grouplist")) {
plugin.message(sender, "grouplist-noPermission");
return;
}
List<String> groups = plugin.getFileManager().getGroupNames();
if(groups.size() == 0) {
plugin.message(sender, "grouplist-noGroups");
} else {
plugin.message(sender, "grouplist-success", Utils.createCommaSeparatedList(groups));
}
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
return new ArrayList<String>();
}
}
package me.wiefferink.areashop.commands;
import me.wiefferink.areashop.tools.Utils;
import org.bukkit.command.CommandSender;
import java.util.ArrayList;
import java.util.List;
public class GrouplistCommand extends CommandAreaShop {
@Override
public String getCommandStart() {
return "areashop grouplist";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.grouplist")) {
return "help-grouplist";
}
return null;
}
@Override
public void execute(CommandSender sender, String[] args) {
if(!sender.hasPermission("areashop.grouplist")) {
plugin.message(sender, "grouplist-noPermission");
return;
}
List<String> groups = plugin.getFileManager().getGroupNames();
if(groups.size() == 0) {
plugin.message(sender, "grouplist-noGroups");
} else {
plugin.message(sender, "grouplist-success", Utils.createCommaSeparatedList(groups));
}
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
return new ArrayList<>();
}
}
@@ -0,0 +1,24 @@
package me.wiefferink.areashop.commands;
import org.bukkit.command.CommandSender;
public class HelpCommand extends CommandAreaShop {
@Override
public String getCommandStart() {
return "areashop help";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.help")) {
return "help-help";
}
return null;
}
@Override
public void execute(CommandSender sender, String[] args) {
plugin.getCommandManager().showHelp(sender);
}
}
@@ -0,0 +1,79 @@
package me.wiefferink.areashop.commands;
import me.wiefferink.interactivemessenger.processing.Message;
import org.bukkit.command.CommandSender;
import java.util.ArrayList;
import java.util.List;
public class ImportCommand extends CommandAreaShop {
/* RegionGroup priority usage:
0: Settings from /config.yml
1: Settings from /worlds/<world>/config.yml
2: Settings from /worlds/<world>/parent-regions.yml (if their priority is set it is added to this value)
*/
@Override
public String getCommandStart() {
return "areashop import";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.import")) {
return "help-import";
}
return null;
}
// TODO
// - Landlord?
// - Friends
// - Region flags?
// - Settings from the 'permissions' section in RegionForSale/config.yml?
@Override
public void execute(CommandSender sender, String[] args) {
if(!sender.hasPermission("areashop.import")) {
plugin.message(sender, "import-noPermission");
return;
}
if(args.length < 2) {
plugin.message(sender, "import-help");
return;
}
if(!"RegionForSale".equalsIgnoreCase(args[1])) {
plugin.message(sender, "import-wrongSource");
return;
}
if(!confirm(sender, args, Message.fromKey("import-confirm"))) {
return;
}
ImportJob importJob = new ImportJob(sender);
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
List<String> result = new ArrayList<>();
if(toComplete == 2) {
result.add("RegionForSale");
}
return result;
}
}
@@ -0,0 +1,477 @@
package me.wiefferink.areashop.commands;
import com.google.common.base.Charsets;
import com.sk89q.worldguard.protection.managers.RegionManager;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import me.wiefferink.areashop.AreaShop;
import me.wiefferink.areashop.features.signs.RegionSign;
import me.wiefferink.areashop.features.signs.SignsFeature;
import me.wiefferink.areashop.regions.BuyRegion;
import me.wiefferink.areashop.regions.GeneralRegion;
import me.wiefferink.areashop.regions.RegionGroup;
import me.wiefferink.areashop.regions.RentRegion;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.OfflinePlayer;
import org.bukkit.World;
import org.bukkit.command.CommandSender;
import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.YamlConfiguration;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
public class ImportJob {
private final AreaShop plugin;
private final CommandSender sender;
/**
* Create and execute the import.
* @param sender CommandSender that should receive progress updates
*/
public ImportJob(CommandSender sender) {
this.sender = sender;
this.plugin = AreaShop.getInstance();
execute();
}
/**
* Execute the job.
*/
private void execute() {
// Check for RegionForSale data
File regionForSaleFolder = new File(plugin.getDataFolder().getParentFile().getAbsolutePath(), "RegionForSale");
if(!regionForSaleFolder.exists()) {
message("import-noPluginFolder", regionForSaleFolder.getName());
return;
}
File worldsFolder = new File(regionForSaleFolder.getAbsolutePath(), "worlds");
if(!worldsFolder.exists()) {
message("import-noWorldsFolder");
return;
}
File[] worldFolders = worldsFolder.listFiles();
if(worldFolders == null) {
message("import-noWorldsFolder");
return;
}
// Import data for each world
message("import-start");
// Group with settings for all imported regions
RegionGroup regionForSaleGroup = new RegionGroup(plugin, "RegionForSale");
plugin.getFileManager().addGroup(regionForSaleGroup);
// Import /RegionForSale/config.yml settings
File regionForSaleConfigFile = new File(regionForSaleFolder.getAbsolutePath(), "config.yml");
YamlConfiguration regionForSaleConfig = loadConfiguration(regionForSaleConfigFile);
if(regionForSaleConfig == null) {
messageNoPrefix("import-loadConfigFailed", regionForSaleConfigFile.getAbsolutePath());
regionForSaleConfig = new YamlConfiguration();
} else {
importRegionSettings(regionForSaleConfig, regionForSaleGroup.getSettings(), null, false);
regionForSaleGroup.setSetting("priority", 0);
}
// Import /RegionForSale/general.yml settings
File regionForSaleGeneralFile = new File(regionForSaleFolder.getAbsolutePath(), "config.yml");
YamlConfiguration regionForSaleGeneral = loadConfiguration(regionForSaleConfigFile);
if(regionForSaleGeneral == null) {
messageNoPrefix("import-loadConfigFailed", regionForSaleGeneralFile.getAbsolutePath());
} else {
// Collection interval of RegionForSale maps to rent duration
String duration = "1 day";
if(regionForSaleGeneral.isLong("interval.collect_money")) {
duration = minutesToString(regionForSaleGeneral.getLong("interval.collect_money"));
}
regionForSaleGroup.setSetting("rent.duration", duration);
// Global economy account has an effect close to landlord in AreaShop
if(regionForSaleGeneral.isString("global_econ_account")) {
regionForSaleGroup.setSetting("general.landlordName", regionForSaleGeneral.getString("global_econ_account"));
}
}
regionForSaleGroup.saveRequired();
////////// Handle defaults of RegionForSale
// Set autoExtend, to keep the same behavior as RegionForSale had
regionForSaleGroup.setSetting("rent.autoExtend", true);
// Import regions from each world
for(File worldFolder : worldFolders) {
// Skip files
if(!worldFolder.isDirectory() || worldFolder.isHidden()) {
continue;
}
messageNoPrefix("import-doWorld", worldFolder.getName());
// Get the Bukkit world
World world = Bukkit.getWorld(worldFolder.getName());
if(world == null) {
messageNoPrefix("import-noBukkitWorld");
continue;
}
// Get the WorldGuard RegionManager
RegionManager regionManager = plugin.getRegionManager(world);
if(regionManager == null) {
messageNoPrefix("import-noRegionManger");
continue;
}
// Load the /worlds/<world>/regions.yml file
File regionsFile = new File(worldFolder.getAbsolutePath(), "regions.yml");
YamlConfiguration regions = loadConfiguration(regionsFile);
if(regions == null) {
messageNoPrefix("import-loadRegionsFailed", regionsFile.getAbsolutePath());
continue;
}
// Load /worlds/<world>/config.yml file
File worldConfigFile = new File(worldFolder.getAbsolutePath(), "config.yml");
YamlConfiguration worldConfig = loadConfiguration(worldConfigFile);
if(worldConfig == null) {
messageNoPrefix("import-loadWorldConfigFailed", worldConfigFile.getAbsolutePath());
// Simply skip importing the settings, since this is not really fatal
worldConfig = new YamlConfiguration();
} else {
// RegionGroup with all world settings
RegionGroup worldGroup = new RegionGroup(plugin, "RegionForSale-" + worldFolder.getName());
importRegionSettings(worldConfig, worldGroup.getSettings(), null, false);
worldGroup.setSetting("priority", 1);
worldGroup.addWorld(worldFolder.getName());
plugin.getFileManager().addGroup(regionForSaleGroup);
worldGroup.saveRequired();
}
// Create groups to hold settings of /worlds/<world>/parent-regions.yml
File parentRegionsFile = new File(worldFolder.getAbsolutePath(), "parent-regions.yml");
YamlConfiguration parentRegions = loadConfiguration(parentRegionsFile);
if(parentRegions == null) {
messageNoPrefix("import-loadParentRegionsFailed", parentRegionsFile.getAbsolutePath());
// Non-fatal, so just continue
} else {
for(String parentRegionName : parentRegions.getKeys(false)) {
// Get WorldGuard region
ProtectedRegion worldGuardRegion = regionManager.getRegion(parentRegionName);
if(worldGuardRegion == null) {
messageNoPrefix("import-noWorldGuardRegionParent", parentRegionName);
continue;
}
// Get settings section
ConfigurationSection parentRegionSection = parentRegions.getConfigurationSection(parentRegionName);
if(parentRegionSection == null) {
messageNoPrefix("import-improperParentRegion", parentRegionName);
continue;
}
// Skip if it does not have any settings
if(parentRegionSection.getKeys(false).isEmpty()) {
continue;
}
// Import parent region settings into a RegionGroup
RegionGroup parentRegionGroup = new RegionGroup(plugin, "RegionForSale-" + worldFolder.getName() + "-" + parentRegionName);
importRegionSettings(parentRegionSection, parentRegionGroup.getSettings(), null, false);
parentRegionGroup.setSetting("priority", 2 + parentRegionSection.getLong("info.priority", 0));
parentRegionGroup.saveRequired();
// TODO add all regions that are contained in this parent region
// Utils.getWorldEditRegionsInSelection()
}
}
// Read and import regions
for(String regionKey : regions.getKeys(false)) {
GeneralRegion existingRegion = plugin.getFileManager().getRegion(regionKey);
if(existingRegion != null) {
if(world.getName().equalsIgnoreCase(existingRegion.getWorldName())) {
messageNoPrefix("import-alreadyAdded", regionKey);
} else {
messageNoPrefix("import-alreadyAddedOtherWorld", regionKey, existingRegion.getWorldName(), world.getName());
}
continue;
}
ConfigurationSection regionSection = regions.getConfigurationSection(regionKey);
if(regionSection == null) {
messageNoPrefix("import-invalidRegionSection", regionKey);
continue;
}
// Get WorldGuard region
ProtectedRegion worldGuardRegion = regionManager.getRegion(regionKey);
if(worldGuardRegion == null) {
messageNoPrefix("import-noWorldGuardRegion", regionKey);
continue;
}
String owner = regionSection.getString("info.owner", null);
boolean isBought = regionSection.getBoolean("info.is-bought");
// TODO: should also take into config settings of parent regions
boolean rentable = regionSection.getBoolean("economic-settings.rentable", worldConfig.getBoolean("economic-settings.rentable", regionForSaleConfig.getBoolean("economic-settings.rentable")));
boolean buyable = regionSection.getBoolean("economic-settings.buyable", worldConfig.getBoolean("economic-settings.buyable", regionForSaleConfig.getBoolean("economic-settings.buyable")));
// Can be bought and rented, import as buy
if(buyable && rentable) {
messageNoPrefix("import-buyAndRent", regionKey);
}
// Cannot be bought or rented, skip
if(!buyable && !rentable && owner == null) {
messageNoPrefix("import-noBuyAndNoRent", regionKey);
continue;
}
// Create region
GeneralRegion region;
if(rentable || (owner != null && !isBought)) {
region = new RentRegion(regionKey, world);
plugin.getFileManager().addRent((RentRegion)region);
} else {
region = new BuyRegion(regionKey, world);
plugin.getFileManager().addBuy((BuyRegion)region);
}
// Import settings
importRegionSettings(regionSection, region.getConfig(), region, !buyable && !rentable);
region.getConfig().set("general.importedFrom", "RegionForSale");
// Get existing owners and members
List<UUID> existing = new ArrayList<>();
if(owner != null) {
@SuppressWarnings("deprecation")
OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(owner);
if(offlinePlayer != null) {
existing.add(offlinePlayer.getUniqueId());
}
}
for(UUID uuid : plugin.getWorldGuardHandler().getOwners(worldGuardRegion).asUniqueIdList()) {
if(!existing.contains(uuid)) {
existing.add(uuid);
}
}
for(UUID uuid : plugin.getWorldGuardHandler().getMembers(worldGuardRegion).asUniqueIdList()) {
if(!existing.contains(uuid)) {
existing.add(uuid);
}
}
// First owner (or if none, the first member) will be the renter/buyer
if(!existing.isEmpty()) {
region.setOwner(existing.remove(0));
}
// Add others as friends
for(UUID friend : existing) {
region.getFriendsFeature().addFriend(friend, null);
}
region.saveRequired();
messageNoPrefix("import-imported", regionKey);
}
}
// Update all regions
plugin.getFileManager().updateAllRegions(sender);
// Write all imported regions and settings to disk
plugin.getFileManager().saveRequiredFiles();
}
/**
* Load a YamlConfiguration from disk using UTF-8 encoding.
* @param from File to read the configuration from
* @return YamlConfiguration if the file exists and got read wihout problems, otherwise null
*/
private YamlConfiguration loadConfiguration(File from) {
try(
InputStreamReader reader = new InputStreamReader(new FileInputStream(from), Charsets.UTF_8)
) {
return YamlConfiguration.loadConfiguration(reader);
} catch(IOException e) {
return null;
}
}
/**
* Import region specific settings from a RegionForSale source to an AreaShop target ConfigurationSection.
* @param from RegionForSale config section that specifies region settings
* @param to AreaShop config section that specifies region settings
* @param region GeneralRegion to copy settings to, or null if doing generic settings
* @param permanent Region cannot be rented or bought, disables some features
*/
private void importRegionSettings(ConfigurationSection from, ConfigurationSection to, GeneralRegion region, boolean permanent) {
// Maximum rental time, TODO check if this is actually the same
if(from.isLong("permissions.max-rent-time")) {
to.set("rent.maxRentTime", minutesToString(from.getLong("permissions.max-rent-time")));
}
// Region rebuild
if(from.getBoolean("region-rebuilding.auto-rebuild")) {
to.set("general.enableRestore", true);
}
// Get price settings
String unit = from.getString("economic-settings.unit-type");
String rentPrice = from.getString("economic-settings.cost-per-unit.rent");
String buyPrice = from.getString("economic-settings.cost-per-unit.buy");
String sellPrice = from.getString("economic-settings.cost-per-unit.selling-price");
// TODO: There is no easy way to import this, setup eventCommandsProfile?
String taxes = from.getString("economic-settings.cost-per-unit.taxes");
// Determine unit and add that to the price
String unitSuffix = "";
if("region".equalsIgnoreCase(unit)) {
// add nothing
} else if("m3".equalsIgnoreCase(unit)) {
unitSuffix = "*%volume%";
} else { // m2 or nothing (in case not set, we should actually look in parent files to correctly set this...)
unitSuffix = "*(%volume%/%height%)"; // This is better than width*depth because of polygon regions
}
// Apply settings
if(rentPrice != null) {
to.set("rent.price", rentPrice + unitSuffix);
}
if(buyPrice != null) {
to.set("buy.price", buyPrice + unitSuffix);
if(sellPrice != null) {
try {
double buyPriceAmount = Double.parseDouble(buyPrice);
double sellPriceAmount = Double.parseDouble(sellPrice);
to.set("buy.moneyBack", sellPriceAmount / buyPriceAmount * 100);
} catch(NumberFormatException e) {
// There is not always a region here for the message, should probably indicate something though
message("import-moneyBackFailed", buyPrice, sellPrice);
}
}
}
// Apply permanent region settings
if(permanent) {
to.set("buy.resellDisabled", true);
to.set("buy.sellDisabled", true);
to.set("general.countForLimits", false);
}
// Set rented until
if(from.isLong("info.last-withdrawal")
&& region instanceof RentRegion) {
RentRegion rentRegion = (RentRegion)region;
long lastWithdrawal = from.getLong("info.last-withdrawal");
// Because the rental duration is already imported into the region and its parents this should be correct
rentRegion.setRentedUntil(lastWithdrawal + rentRegion.getDuration());
}
// Import signs (list of strings like "297, 71, -22")
if(from.isList("info.signs") && region != null) {
for(String signLocation : from.getStringList("info.signs")) {
String[] locationParts = signLocation.split(", ");
if(locationParts.length != 3) {
message("import-invalidSignLocation", region.getName(), signLocation);
continue;
}
// Parse the location
Location location;
try {
location = new Location(region.getWorld(), Double.parseDouble(locationParts[0]), Double.parseDouble(locationParts[1]), Double.parseDouble(locationParts[2]));
} catch(NumberFormatException e) {
message("import-invalidSignLocation", region.getName(), signLocation);
continue;
}
// Check if this location is already added to a region
RegionSign regionSign = SignsFeature.getSignByLocation(location);
if(regionSign != null) {
if(!regionSign.getRegion().equals(region)) {
message("import-signAlreadyAdded", region.getName(), signLocation, regionSign.getRegion().getName());
}
continue;
}
// SignType and Facing will be written when the sign is updated later
region.getSignsFeature().addSign(location, null, null, null);
}
}
}
private static class TimeUnit {
public long minutes;
public String identifier;
TimeUnit(long minutes, String identifier) {
this.minutes = minutes;
this.identifier = identifier;
}
}
private static final List<TimeUnit> timeUnitLookup = new ArrayList<TimeUnit>() {
{
add(new TimeUnit(60 * 24 * 30 * 12, "year"));
add(new TimeUnit(60 * 24 * 30, "month"));
add(new TimeUnit(60 * 24, "day"));
add(new TimeUnit(60, "hour"));
}
};
/**
* Convert minutes to a human-readable string.
* @param minutes Value to convert
* @return String that represents the same length of time in a readable format, like "1 day", "5 minutes", "3 months"
*/
private String minutesToString(long minutes) {
// If the specified number of minutes can map nicely to a higher unit, use that one
String resultUnit = "minute";
long resultValue = minutes;
for(TimeUnit unit : timeUnitLookup) {
long result = minutes / unit.minutes;
if(resultValue * unit.minutes == minutes) {
resultUnit = unit.identifier;
resultValue = result;
break;
}
}
return resultValue + " " + resultUnit + (resultValue == 1 ? "" : "s");
}
/**
* Send a message to a target without a prefix.
* @param key The key of the language string
* @param replacements The replacements to insert in the message
*/
public void messageNoPrefix(String key, Object... replacements) {
plugin.messageNoPrefix(sender, key, replacements);
if(!(sender instanceof ConsoleCommandSender)) {
plugin.messageNoPrefix(Bukkit.getConsoleSender(), key, replacements);
}
}
/**
* Send a message to a target, prefixed by the default chat prefix.
* @param key The key of the language string
* @param replacements The replacements to insert in the message
*/
public void message(String key, Object... replacements) {
plugin.message(sender, key, replacements);
if(!(sender instanceof ConsoleCommandSender)) {
plugin.message(Bukkit.getConsoleSender(), key, replacements);
}
}
}
@@ -0,0 +1,484 @@
package me.wiefferink.areashop.commands;
import me.wiefferink.areashop.regions.BuyRegion;
import me.wiefferink.areashop.regions.GeneralRegion;
import me.wiefferink.areashop.regions.RegionGroup;
import me.wiefferink.areashop.regions.RentRegion;
import me.wiefferink.areashop.tools.Utils;
import me.wiefferink.interactivemessenger.processing.Message;
import org.bukkit.Location;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
// TODO fix '/as info' help message hitting replacement limit (improve depth tracking?)
// TODO add info about autoExtend
public class InfoCommand extends CommandAreaShop {
@Override
public String getCommandStart() {
return "areashop info";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.info")) {
return "help-info";
}
return null;
}
/**
* Display a page of a list of regions.
* @param sender The CommandSender to send the messages to
* @param regions The regions to display
* @param filterGroup The group to filter the regions by
* @param keyHeader The header to print above the page
* @param pageInput The page number, if any
* @param baseCommand The command to execute for next/previous page (/areashop will be added)
*/
private void showSortedPagedList(CommandSender sender, List<? extends GeneralRegion> regions, RegionGroup filterGroup, String keyHeader, String pageInput, String baseCommand) {
int maximumItems = 20;
int itemsPerPage = maximumItems - 2;
int page = 1;
if(pageInput != null && Utils.isNumeric(pageInput)) {
try {
page = Integer.parseInt(pageInput);
} catch(NumberFormatException e) {
plugin.message(sender, "info-wrongPage", pageInput);
return;
}
}
if(filterGroup != null) {
regions.removeIf(generalRegion -> !filterGroup.isMember(generalRegion));
}
if(regions.isEmpty()) {
plugin.message(sender, "info-noRegions");
} else {
// First sort by type, then by name
regions.sort((one, two) -> {
int typeCompare = getTypeOrder(two).compareTo(getTypeOrder(one));
if(typeCompare != 0) {
return typeCompare;
} else {
return one.getName().compareTo(two.getName());
}
});
// Header
Message limitedToGroup = Message.empty();
if(filterGroup != null) {
limitedToGroup = Message.fromKey("info-limitedToGroup").replacements(filterGroup.getName());
}
plugin.message(sender, keyHeader, limitedToGroup);
// Page entries
int totalPages = (int)Math.ceil(regions.size() / (double)itemsPerPage); // Clip page to correct boundaries, not much need to tell the user
if(regions.size() == itemsPerPage + 1) { // 19 total items is mapped to 1 page of 19
itemsPerPage++;
totalPages = 1;
}
page = Math.max(1, Math.min(totalPages, page));
int linesPrinted = 1; // header
for(int i = (page - 1) * itemsPerPage; i < page * itemsPerPage && i < regions.size(); i++) {
String state;
GeneralRegion region = regions.get(i);
if(region.getType() == GeneralRegion.RegionType.RENT) {
if(region.getOwner() == null) {
state = "Forrent";
} else {
state = "Rented";
}
} else {
if(region.getOwner() == null) {
state = "Forsale";
} else if(!((BuyRegion)region).isInResellingMode()) {
state = "Sold";
} else {
state = "Reselling";
}
}
plugin.messageNoPrefix(sender, "info-entry" + state, region);
linesPrinted++;
}
Message footer = Message.empty();
// Previous button
if(page > 1) {
footer.append(Message.fromKey("info-pagePrevious").replacements(baseCommand + " " + (page - 1)));
} else {
footer.append(Message.fromKey("info-pageNoPrevious"));
}
// Page status
if(totalPages > 1) {
String pageString = "" + page;
for(int i = pageString.length(); i < (totalPages + "").length(); i++) {
pageString = "0" + pageString;
}
footer.append(Message.fromKey("info-pageStatus").replacements(page, totalPages));
if(page < totalPages) {
footer.append(Message.fromKey("info-pageNext").replacements(baseCommand + " " + (page + 1)));
} else {
footer.append(Message.fromKey("info-pageNoNext"));
}
// Fill up space if the page is not full (aligns header nicely)
for(int i = linesPrinted; i < maximumItems - 1; i++) {
sender.sendMessage(" ");
}
footer.send(sender);
}
}
}
/**
* Get an integer to order by type, usable for Comparators.
* @param region The region to get the order for
* @return An integer for sorting by type
*/
private Integer getTypeOrder(GeneralRegion region) {
if(region.getType() == GeneralRegion.RegionType.RENT) {
if(region.getOwner() == null) {
return 1;
} else {
return 2;
}
} else {
if(region.getOwner() == null) {
return 3;
} else if(!((BuyRegion)region).isInResellingMode()) {
return 4;
} else {
return 5;
}
}
}
@Override
public void execute(CommandSender sender, String[] args) {
if(!sender.hasPermission("areashop.info")) {
plugin.message(sender, "info-noPermission");
return;
}
if(args.length > 1 && args[1] != null) {
// Get filter group (only used by some commands)
RegionGroup filterGroup = null;
Set<String> groupFilters = new HashSet<>(Arrays.asList("all", "rented", "forrent", "sold", "forsale", "reselling"));
if(groupFilters.contains(args[1].toLowerCase()) && args.length > 2) {
if(!Utils.isNumeric(args[2])) {
filterGroup = plugin.getFileManager().getGroup(args[2]);
if(filterGroup == null) {
plugin.message(sender, "info-noFiltergroup", args[2]);
return;
}
// Pass page number to args[2] if available
if(args.length > 3) {
args[2] = args[3];
}
}
}
// All regions
if(args[1].equalsIgnoreCase("all")) {
showSortedPagedList(sender, plugin.getFileManager().getRegions(), filterGroup, "info-allHeader", (args.length > 2 ? args[2] : null), "info all");
}
// Rented regions
else if(args[1].equalsIgnoreCase("rented")) {
List<RentRegion> regions = plugin.getFileManager().getRents();
regions.removeIf(RentRegion::isAvailable);
showSortedPagedList(sender, regions, filterGroup, "info-rentedHeader", (args.length > 2 ? args[2] : null), "info rented");
}
// Forrent regions
else if(args[1].equalsIgnoreCase("forrent")) {
List<RentRegion> regions = plugin.getFileManager().getRents();
regions.removeIf(RentRegion::isRented);
showSortedPagedList(sender, regions, filterGroup, "info-forrentHeader", (args.length > 2 ? args[2] : null), "info forrent");
}
// Sold regions
else if(args[1].equalsIgnoreCase("sold")) {
List<BuyRegion> regions = plugin.getFileManager().getBuys();
regions.removeIf(BuyRegion::isAvailable);
showSortedPagedList(sender, regions, filterGroup, "info-soldHeader", (args.length > 2 ? args[2] : null), "info sold");
}
// Forsale regions
else if(args[1].equalsIgnoreCase("forsale")) {
List<BuyRegion> regions = plugin.getFileManager().getBuys();
regions.removeIf(BuyRegion::isSold);
showSortedPagedList(sender, regions, filterGroup, "info-forsaleHeader", (args.length > 2 ? args[2] : null), "info forsale");
}
// Reselling regions
else if(args[1].equalsIgnoreCase("reselling")) {
List<BuyRegion> regions = plugin.getFileManager().getBuys();
regions.removeIf(region -> !region.isInResellingMode());
showSortedPagedList(sender, regions, filterGroup, "info-resellingHeader", (args.length > 2 ? args[2] : null), "info reselling");
}
// List of regions without a group
else if(args[1].equalsIgnoreCase("nogroup")) {
List<GeneralRegion> regions = plugin.getFileManager().getRegions();
for(RegionGroup group : plugin.getFileManager().getGroups()) {
regions.removeAll(group.getMemberRegions());
}
if(regions.isEmpty()) {
plugin.message(sender, "info-nogroupNone");
} else {
showSortedPagedList(sender, regions, filterGroup, "info-nogroupHeader", (args.length > 2 ? args[2] : null), "info nogroup");
}
}
// Region info
else if(args[1].equalsIgnoreCase("region")) {
if(args.length > 1) {
RentRegion rent = null;
BuyRegion buy = null;
if(args.length > 2) {
rent = plugin.getFileManager().getRent(args[2]);
buy = plugin.getFileManager().getBuy(args[2]);
} else {
if(sender instanceof Player) {
// get the region by location
List<GeneralRegion> regions = Utils.getImportantRegions(((Player)sender).getLocation());
if(regions.isEmpty()) {
plugin.message(sender, "cmd-noRegionsAtLocation");
return;
} else if(regions.size() > 1) {
plugin.message(sender, "cmd-moreRegionsAtLocation");
return;
} else {
if(regions.get(0) instanceof RentRegion) {
rent = (RentRegion)regions.get(0);
} else if(regions.get(0) instanceof BuyRegion) {
buy = (BuyRegion)regions.get(0);
}
}
} else {
plugin.message(sender, "cmd-automaticRegionOnlyByPlayer");
return;
}
}
if(rent == null && buy == null) {
plugin.message(sender, "info-regionNotExisting", args[2]);
return;
}
if(rent != null) {
plugin.message(sender, "info-regionHeaderRent", rent);
if(rent.isRented()) {
plugin.messageNoPrefix(sender, "info-regionRented", rent);
plugin.messageNoPrefix(sender, "info-regionExtending", rent);
// Money back
if(UnrentCommand.canUse(sender, rent)) {
plugin.messageNoPrefix(sender, "info-regionMoneyBackRentClick", rent);
} else {
plugin.messageNoPrefix(sender, "info-regionMoneyBackRent", rent);
}
// Friends
if(!rent.getFriendsFeature().getFriendNames().isEmpty()) {
String messagePart = "info-friend";
if(DelfriendCommand.canUse(sender, rent)) {
messagePart = "info-friendRemove";
}
plugin.messageNoPrefix(sender, "info-regionFriends", rent, Utils.combinedMessage(rent.getFriendsFeature().getFriendNames(), messagePart));
}
} else {
plugin.messageNoPrefix(sender, "info-regionCanBeRented", rent);
}
if(rent.getLandlordName() != null) {
plugin.messageNoPrefix(sender, "info-regionLandlord", rent);
}
// Maximum extends
if(rent.getMaxExtends() != -1) {
if(rent.getMaxExtends() == 0) {
plugin.messageNoPrefix(sender, "info-regionNoExtending", rent);
} else if(rent.isRented()) {
plugin.messageNoPrefix(sender, "info-regionExtendsLeft", rent);
} else {
plugin.messageNoPrefix(sender, "info-regionMaxExtends", rent);
}
}
// If maxExtends is zero it does not make sense to show this message
if(rent.getMaxRentTime() != -1 && rent.getMaxExtends() != 0) {
plugin.messageNoPrefix(sender, "info-regionMaxRentTime", rent);
}
if(rent.getInactiveTimeUntilUnrent() != -1) {
plugin.messageNoPrefix(sender, "info-regionInactiveUnrent", rent);
}
// Teleport
Message tp = Message.fromKey("info-prefix");
boolean foundSomething = false;
if(TeleportCommand.canUse(sender, rent)) {
foundSomething = true;
tp.append(Message.fromKey("info-regionTeleport").replacements(rent));
}
if(SetteleportCommand.canUse(sender, rent)) {
if(foundSomething) {
tp.append(", ");
}
foundSomething = true;
tp.append(Message.fromKey("info-setRegionTeleport").replacements(rent));
}
if(foundSomething) {
tp.append(".");
tp.send(sender);
}
// Signs
List<String> signLocations = new ArrayList<>();
for(Location location : rent.getSignsFeature().getSignLocations()) {
signLocations.add(Message.fromKey("info-regionSignLocation").replacements(location.getWorld().getName(), location.getBlockX(), location.getBlockY(), location.getBlockZ()).getPlain());
}
if(!signLocations.isEmpty()) {
plugin.messageNoPrefix(sender, "info-regionSigns", Utils.createCommaSeparatedList(signLocations));
}
// Groups
if(sender.hasPermission("areashop.groupinfo") && !rent.getGroupNames().isEmpty()) {
plugin.messageNoPrefix(sender, "info-regionGroups", Utils.createCommaSeparatedList(rent.getGroupNames()));
}
// Restoring
if(rent.isRestoreEnabled()) {
plugin.messageNoPrefix(sender, "info-regionRestoringRent", rent);
}
// Restrictions
if(!rent.isRented()) {
if(rent.restrictedToRegion()) {
plugin.messageNoPrefix(sender, "info-regionRestrictedRegionRent", rent);
} else if(rent.restrictedToWorld()) {
plugin.messageNoPrefix(sender, "info-regionRestrictedWorldRent", rent);
}
}
plugin.messageNoPrefix(sender, "info-regionFooterRent", rent);
} else if(buy != null) {
plugin.message(sender, "info-regionHeaderBuy", buy);
if(buy.isSold()) {
if(buy.isInResellingMode()) {
plugin.messageNoPrefix(sender, "info-regionReselling", buy);
plugin.messageNoPrefix(sender, "info-regionReselPrice", buy);
} else {
plugin.messageNoPrefix(sender, "info-regionBought", buy);
}
// Money back
if(!buy.getBooleanSetting("buy.sellDisabled")) {
if (SellCommand.canUse(sender, buy)) {
plugin.messageNoPrefix(sender, "info-regionMoneyBackBuyClick", buy);
} else {
plugin.messageNoPrefix(sender, "info-regionMoneyBackBuy", buy);
}
}
// Friends
if(!buy.getFriendsFeature().getFriendNames().isEmpty()) {
String messagePart = "info-friend";
if(DelfriendCommand.canUse(sender, buy)) {
messagePart = "info-friendRemove";
}
plugin.messageNoPrefix(sender, "info-regionFriends", buy, Utils.combinedMessage(buy.getFriendsFeature().getFriendNames(), messagePart));
}
} else {
plugin.messageNoPrefix(sender, "info-regionCanBeBought", buy);
}
if(buy.getLandlord() != null) {
plugin.messageNoPrefix(sender, "info-regionLandlord", buy);
}
if(buy.getInactiveTimeUntilSell() != -1) {
plugin.messageNoPrefix(sender, "info-regionInactiveSell", buy);
}
// Teleport
Message tp = Message.fromKey("info-prefix");
boolean foundSomething = false;
if(TeleportCommand.canUse(sender, buy)) {
foundSomething = true;
tp.append(Message.fromKey("info-regionTeleport").replacements(buy));
}
if(SetteleportCommand.canUse(sender, buy)) {
if(foundSomething) {
tp.append(", ");
}
foundSomething = true;
tp.append(Message.fromKey("info-setRegionTeleport").replacements(buy));
}
if(foundSomething) {
tp.append(".");
tp.send(sender);
}
// Signs
List<String> signLocations = new ArrayList<>();
for(Location location : buy.getSignsFeature().getSignLocations()) {
signLocations.add(Message.fromKey("info-regionSignLocation").replacements(location.getWorld().getName(), location.getBlockX(), location.getBlockY(), location.getBlockZ()).getPlain());
}
if(!signLocations.isEmpty()) {
plugin.messageNoPrefix(sender, "info-regionSigns", Utils.createCommaSeparatedList(signLocations));
}
// Groups
if(sender.hasPermission("areashop.groupinfo") && !buy.getGroupNames().isEmpty()) {
plugin.messageNoPrefix(sender, "info-regionGroups", Utils.createCommaSeparatedList(buy.getGroupNames()));
}
// Restoring
if(buy.isRestoreEnabled()) {
plugin.messageNoPrefix(sender, "info-regionRestoringBuy", buy);
}
// Restrictions
if(!buy.isSold()) {
if(buy.restrictedToRegion()) {
plugin.messageNoPrefix(sender, "info-regionRestrictedRegionBuy", buy);
} else if(buy.restrictedToWorld()) {
plugin.messageNoPrefix(sender, "info-regionRestrictedWorldBuy", buy);
}
}
plugin.messageNoPrefix(sender, "info-regionFooterBuy", buy);
}
} else {
plugin.message(sender, "info-regionHelp");
}
} else {
plugin.message(sender, "info-help");
}
} else {
plugin.message(sender, "info-help");
}
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
List<String> result = new ArrayList<>();
if(toComplete == 2) {
result.addAll(Arrays.asList("all", "rented", "forrent", "sold", "forsale", "player", "region", "nogroup", "reselling"));
} else if(toComplete == 3) {
if(start[2].equalsIgnoreCase("player")) {
for(Player player : Utils.getOnlinePlayers()) {
result.add(player.getName());
}
} else if(start[2].equalsIgnoreCase("region")) {
result.addAll(plugin.getFileManager().getBuyNames());
result.addAll(plugin.getFileManager().getRentNames());
}
}
return result;
}
}
@@ -1,83 +1,87 @@
package nl.evolutioncoding.areashop.commands;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import nl.evolutioncoding.areashop.AreaShop;
import nl.evolutioncoding.areashop.Utils;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
public class LinksignsCommand extends CommandAreaShop {
public LinksignsCommand(AreaShop plugin) {
super(plugin);
}
@Override
public String getCommandStart() {
return "areashop linksigns";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.linksigns")) {
return plugin.getLanguageManager().getLang("help-linksigns");
}
return null;
}
@Override
public void execute(CommandSender sender, Command command, String[] args) {
if(!sender.hasPermission("areashop.linksigns")) {
plugin.message(sender, "linksigns-noPermission");
return;
}
if (!(sender instanceof Player)) {
plugin.message(sender, "cmd-onlyByPlayer");
return;
}
Player player = (Player)sender;
if(plugin.getSignlinkerManager().isInSignLinkMode(player)) {
plugin.getSignlinkerManager().exitSignLinkMode(player);
} else {
// Get the profile
String profile = null;
if(args.length > 1) {
profile = args[1];
Set<String> profiles = plugin.getConfig().getConfigurationSection("signProfiles").getKeys(false);
if(!profiles.contains(profile)) {
plugin.message(sender, "addsign-wrongProfile", Utils.createCommaSeparatedList(profiles));
return;
}
}
plugin.getSignlinkerManager().enterSignLinkMode(player, profile);
}
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
List<String> result = new ArrayList<String>();
if(toComplete == 2) {
result.addAll(plugin.getFileManager().getRegionNames());
} else if(toComplete == 3) {
result.addAll(plugin.getConfig().getStringList("signProfiles"));
}
return result;
}
}
package me.wiefferink.areashop.commands;
import me.wiefferink.interactivemessenger.processing.Message;
import org.bukkit.command.CommandSender;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
public class LinksignsCommand extends CommandAreaShop {
@Override
public String getCommandStart() {
return "areashop linksigns";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.linksigns")) {
return "help-linksigns";
}
return null;
}
@Override
public void execute(CommandSender sender, String[] args) {
if(!sender.hasPermission("areashop.linksigns")) {
plugin.message(sender, "linksigns-noPermission");
return;
}
if(!(sender instanceof Player)) {
plugin.message(sender, "cmd-onlyByPlayer");
return;
}
Player player = (Player)sender;
if(plugin.getSignlinkerManager().isInSignLinkMode(player)) {
plugin.getSignlinkerManager().exitSignLinkMode(player);
} else {
// Get the profile
String profile = null;
if(args.length > 1) {
profile = args[1];
ConfigurationSection signProfilesSection = plugin.getConfig().getConfigurationSection("signProfiles");
if(signProfilesSection != null) {
Set<String> profiles = signProfilesSection.getKeys(false);
if(!profiles.contains(profile)) {
ArrayList<String> message = new ArrayList<>();
for(String p : profiles) {
if(!message.isEmpty()) {
message.add(", ");
}
message.addAll(Message.fromKey("addsign-profile").replacements(p).get());
}
plugin.message(sender, "addsign-wrongProfile", Message.fromList(message));
return;
}
}
}
plugin.getSignlinkerManager().enterSignLinkMode(player, profile);
}
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
List<String> result = new ArrayList<>();
if(toComplete == 2) {
result.addAll(plugin.getFileManager().getRegionNames());
} else if(toComplete == 3) {
result.addAll(plugin.getConfig().getStringList("signProfiles"));
}
return result;
}
}
@@ -0,0 +1,143 @@
package me.wiefferink.areashop.commands;
import me.wiefferink.areashop.regions.BuyRegion;
import me.wiefferink.areashop.regions.GeneralRegion;
import me.wiefferink.areashop.regions.RentRegion;
import me.wiefferink.areashop.tools.Utils;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class MeCommand extends CommandAreaShop {
@Override
public String getCommandStart() {
return "areashop me";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.me")) {
return "help-me";
}
return null;
}
@Override
public void execute(CommandSender sender, String[] args) {
if(!sender.hasPermission("areashop.me")) {
plugin.message(sender, "me-noPermission");
return;
}
OfflinePlayer player = null;
if(!(sender instanceof Player)) {
if(args.length <= 1) {
plugin.message(sender, "me-notAPlayer");
return;
}
} else {
player = (OfflinePlayer)sender;
}
if(args.length > 1) {
player = Bukkit.getOfflinePlayer(args[1]);
if(player == null) {
plugin.message(sender, "me-noPlayer", args[1]);
return;
}
}
if(player == null) {
return;
}
// Get the regions owned by the player
Set<RentRegion> rentRegions = new HashSet<>();
for(RentRegion region : plugin.getFileManager().getRents()) {
if(region.isOwner(player)) {
rentRegions.add(region);
}
}
Set<BuyRegion> buyRegions = new HashSet<>();
for(BuyRegion region : plugin.getFileManager().getBuys()) {
if(region.isOwner(player)) {
buyRegions.add(region);
}
}
// Get the regions the player is added as friend
Set<GeneralRegion> friendRegions = new HashSet<>();
for(GeneralRegion region : plugin.getFileManager().getRegions()) {
if(region.getFriendsFeature().getFriends().contains(player.getUniqueId())) {
friendRegions.add(region);
}
}
// Send messages
boolean foundSome = !rentRegions.isEmpty() || !buyRegions.isEmpty() || !friendRegions.isEmpty();
if(foundSome) {
plugin.message(sender, "me-header", player.getName());
}
if(!rentRegions.isEmpty()) {
for(RentRegion region : rentRegions) {
plugin.messageNoPrefix(sender, "me-rentLine", region);
}
}
if(!buyRegions.isEmpty()) {
for(BuyRegion region : buyRegions) {
plugin.messageNoPrefix(sender, "me-buyLine", region);
}
}
if(!friendRegions.isEmpty()) {
for(GeneralRegion region : friendRegions) {
plugin.messageNoPrefix(sender, "me-friendLine", region);
}
}
if(!foundSome) {
plugin.message(sender, "me-nothing", player.getName());
} else {
plugin.messageNoPrefix(sender, "me-clickHint");
}
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
ArrayList<String> result = new ArrayList<>();
if(toComplete == 2) {
for(Player player : Utils.getOnlinePlayers()) {
result.add(player.getName());
}
}
return result;
}
}
@@ -0,0 +1,74 @@
package me.wiefferink.areashop.commands;
import me.wiefferink.areashop.tools.Utils;
import me.wiefferink.interactivemessenger.processing.Message;
import org.apache.commons.lang.StringUtils;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.List;
public class MessageCommand extends CommandAreaShop {
@Override
public String getCommandStart() {
return "areashop message";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.message")) {
return null; // Internal command, no need to show in the help list
}
return null;
}
@Override
public void execute(final CommandSender sender, final String[] args) {
if(!sender.hasPermission("areashop.message")) {
plugin.message(sender, "message-noPermission");
return;
}
if(args.length < 3) {
plugin.message(sender, "message-help");
return;
}
Player player = Bukkit.getPlayer(args[1]);
if(player == null) {
plugin.message(sender, "message-notOnline", args[1]);
return;
}
String[] messageArgs = new String[args.length - 2];
System.arraycopy(args, 2, messageArgs, 0, args.length - 2);
String message = StringUtils.join(messageArgs, " ");
Message.fromString(message).send(player);
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
List<String> result = new ArrayList<>();
if(toComplete == 2) {
for(Player player : Utils.getOnlinePlayers()) {
result.add(player.getName());
}
}
return result;
}
}
@@ -0,0 +1,7 @@
# Commands
This module contains all AreaShop commands.
* `CommandAreaShop` is extended by all other classes, and implements some general functionality and defines which methods should be implemented.
* Other classes implement specific sub-commands, supply their help messages and tab completion.
* `CommandManager` class in the `managers` package handles incoming commands and dispatches them to the classes in this package.
@@ -0,0 +1,29 @@
package me.wiefferink.areashop.commands;
import org.bukkit.command.CommandSender;
public class ReloadCommand extends CommandAreaShop {
@Override
public String getCommandStart() {
return "areashop reload";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.reload")) {
return "help-reload";
}
return null;
}
@Override
public void execute(CommandSender sender, String[] args) {
if(sender.hasPermission("areashop.reload")) {
// Reload the configuration files and update all region flags/signs
plugin.reload(sender);
} else {
plugin.message(sender, "reload-noPermission");
}
}
}
@@ -1,78 +1,69 @@
package nl.evolutioncoding.areashop.commands;
import java.util.ArrayList;
import java.util.List;
import nl.evolutioncoding.areashop.AreaShop;
import nl.evolutioncoding.areashop.Utils;
import nl.evolutioncoding.areashop.regions.RentRegion;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
public class RentCommand extends CommandAreaShop {
public RentCommand(AreaShop plugin) {
super(plugin);
}
@Override
public String getCommandStart() {
return "areashop rent";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.rent")) {
return plugin.getLanguageManager().getLang("help-rent");
}
return null;
}
@Override
public void execute(CommandSender sender, Command command, String[] args) {
if(!sender.hasPermission("areashop.rent")) {
plugin.message(sender, "rent-noPermission");
return;
}
if (!(sender instanceof Player)) {
plugin.message(sender, "cmd-onlyByPlayer");
return;
}
Player player = (Player)sender;
if(args.length > 1 && args[1] != null) {
RentRegion rent = plugin.getFileManager().getRent(args[1]);
if(rent == null) {
plugin.message(sender, "rent-notRentable");
} else {
rent.rent(player);
}
} else {
// get the region by location
List<RentRegion> regions = Utils.getApplicableRentRegions(((Player) sender).getLocation());
if (regions.isEmpty()) {
plugin.message(sender, "cmd-noRegionsAtLocation");
return;
} else if (regions.size() > 1) {
plugin.message(sender, "cmd-moreRegionsAtLocation");
return;
} else {
regions.get(0).rent(player);
}
}
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
ArrayList<String> result = new ArrayList<String>();
if(toComplete == 2) {
for(RentRegion region : plugin.getFileManager().getRents()) {
if(!region.isRented()) {
result.add(region.getName());
}
}
}
return result;
}
}
package me.wiefferink.areashop.commands;
import me.wiefferink.areashop.regions.RentRegion;
import me.wiefferink.areashop.tools.Utils;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.List;
public class RentCommand extends CommandAreaShop {
@Override
public String getCommandStart() {
return "areashop rent";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.rent")) {
return "help-rent";
}
return null;
}
@Override
public void execute(CommandSender sender, String[] args) {
if(!sender.hasPermission("areashop.rent")) {
plugin.message(sender, "rent-noPermission");
return;
}
if(!(sender instanceof Player)) {
plugin.message(sender, "cmd-onlyByPlayer");
return;
}
Player player = (Player)sender;
if(args.length > 1 && args[1] != null) {
RentRegion rent = plugin.getFileManager().getRent(args[1]);
if(rent == null) {
plugin.message(sender, "rent-notRentable", args[1]);
} else {
rent.rent(player);
}
} else {
// get the region by location
List<RentRegion> regions = Utils.getImportantRentRegions(((Player)sender).getLocation());
if(regions.isEmpty()) {
plugin.message(sender, "cmd-noRegionsAtLocation");
} else if(regions.size() > 1) {
plugin.message(sender, "cmd-moreRegionsAtLocation");
} else {
regions.get(0).rent(player);
}
}
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
ArrayList<String> result = new ArrayList<>();
if(toComplete == 2) {
for(RentRegion region : plugin.getFileManager().getRents()) {
if(!region.isRented()) {
result.add(region.getName());
}
}
}
return result;
}
}
@@ -1,133 +1,134 @@
package nl.evolutioncoding.areashop.commands;
import java.util.ArrayList;
import java.util.List;
import nl.evolutioncoding.areashop.AreaShop;
import nl.evolutioncoding.areashop.Utils;
import nl.evolutioncoding.areashop.regions.BuyRegion;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
public class ResellCommand extends CommandAreaShop {
public ResellCommand(AreaShop plugin) {
super(plugin);
}
@Override
public String getCommandStart() {
return "areashop resell";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.resellall")) {
return plugin.getLanguageManager().getLang("help-resellAll");
} else if(target.hasPermission("areashop.resell")) {
return plugin.getLanguageManager().getLang("help-resell");
}
return null;
}
@Override
public void execute(CommandSender sender, Command command, String[] args) {
if(!sender.hasPermission("areashop.resell") && !sender.hasPermission("areashop.resellall")) {
plugin.message(sender, "resell-noPermissionOther");
return;
}
if(args.length <= 1) {
plugin.message(sender, "resell-help");
return;
}
double price = 0.0;
try {
price = Double.parseDouble(args[1]);
} catch(NumberFormatException e) {
plugin.message(sender, "resell-wrongPrice", args[1]);
return;
}
BuyRegion buy = null;
if(args.length <= 2) {
if (sender instanceof Player) {
// get the region by location
List<BuyRegion> regions = Utils.getApplicableBuyRegions(((Player) sender).getLocation());
if (regions.isEmpty()) {
plugin.message(sender, "cmd-noRegionsAtLocation");
return;
} else if (regions.size() > 1) {
plugin.message(sender, "cmd-moreRegionsAtLocation");
return;
} else {
buy = regions.get(0);
}
} else {
plugin.message(sender, "cmd-automaticRegionOnlyByPlayer");
return;
}
} else {
buy = plugin.getFileManager().getBuy(args[2]);
if(buy == null) {
plugin.message(sender, "resell-notRegistered", args[2]);
return;
}
}
if(buy == null) {
plugin.message(sender, "resell-noRegionFound");
return;
}
if(!buy.isSold()) {
plugin.message(sender, "resell-notBought", buy);
return;
}
if(sender.hasPermission("areashop.resellall")) {
buy.enableReselling(price);
plugin.message(sender, "resell-success", buy);
buy.updateSigns();
buy.updateRegionFlags();
} else if(sender.hasPermission("areashop.resell") && sender instanceof Player) {
if(buy.isOwner((Player)sender)) {
buy.enableReselling(price);
plugin.message(sender, "resell-success", buy);
buy.updateSigns();
buy.updateRegionFlags();
} else {
plugin.message(sender, "resell-noPermissionOther");
}
} else {
plugin.message(sender, "resell-noPermission");
}
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
ArrayList<String> result = new ArrayList<String>();
if(toComplete == 3) {
for(BuyRegion region : plugin.getFileManager().getBuys()) {
if(region.isSold() && !region.isInResellingMode()) {
result.add(region.getName());
}
}
}
return result;
}
}
package me.wiefferink.areashop.commands;
import me.wiefferink.areashop.regions.BuyRegion;
import me.wiefferink.areashop.tools.Utils;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.List;
public class ResellCommand extends CommandAreaShop {
@Override
public String getCommandStart() {
return "areashop resell";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.resellall") || target.hasPermission("areashop.resell")) {
return "help-resell";
}
return null;
}
@Override
public void execute(CommandSender sender, String[] args) {
if(!sender.hasPermission("areashop.resell") && !sender.hasPermission("areashop.resellall")) {
plugin.message(sender, "resell-noPermissionOther");
return;
}
if(args.length <= 1) {
plugin.message(sender, "resell-help");
return;
}
double price;
try {
price = Double.parseDouble(args[1]);
} catch(NumberFormatException e) {
plugin.message(sender, "resell-wrongPrice", args[1]);
return;
}
if(price < 0) {
plugin.message(sender, "resell-wrongPrice", args[1]);
return;
}
BuyRegion buy;
if(args.length <= 2) {
if(sender instanceof Player) {
// get the region by location
List<BuyRegion> regions = Utils.getImportantBuyRegions(((Player)sender).getLocation());
if(regions.isEmpty()) {
plugin.message(sender, "cmd-noRegionsAtLocation");
return;
} else if(regions.size() > 1) {
plugin.message(sender, "cmd-moreRegionsAtLocation");
return;
} else {
buy = regions.get(0);
}
} else {
plugin.message(sender, "cmd-automaticRegionOnlyByPlayer");
return;
}
} else {
buy = plugin.getFileManager().getBuy(args[2]);
if(buy == null) {
plugin.message(sender, "resell-notRegistered", args[2]);
return;
}
}
if(buy == null) {
plugin.message(sender, "cmd-noRegionsAtLocation");
return;
}
if(!buy.isSold()) {
plugin.message(sender, "resell-notBought", buy);
return;
}
if(sender.hasPermission("areashop.resellall")) {
buy.enableReselling(price);
buy.update();
plugin.message(sender, "resell-success", buy);
} else if(sender.hasPermission("areashop.resell") && sender instanceof Player) {
if(!buy.isOwner((Player)sender)) {
plugin.message(sender, "resell-noPermissionOther", buy);
return;
}
if(buy.getBooleanSetting("buy.resellDisabled")) {
plugin.message(sender, "resell-disabled", buy);
return;
}
buy.enableReselling(price);
buy.update();
plugin.message(sender, "resell-success", buy);
} else {
plugin.message(sender, "resell-noPermission", buy);
}
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
ArrayList<String> result = new ArrayList<>();
if(toComplete == 3) {
for(BuyRegion region : plugin.getFileManager().getBuys()) {
if(region.isSold() && !region.isInResellingMode()) {
result.add(region.getName());
}
}
}
return result;
}
}
@@ -1,91 +1,86 @@
package nl.evolutioncoding.areashop.commands;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import nl.evolutioncoding.areashop.AreaShop;
import nl.evolutioncoding.areashop.Utils;
import nl.evolutioncoding.areashop.regions.GeneralRegion;
import nl.evolutioncoding.areashop.regions.GeneralRegion.RegionEvent;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
public class SchematiceventCommand extends CommandAreaShop {
public SchematiceventCommand(AreaShop plugin) {
super(plugin);
}
@Override
public String getCommandStart() {
return "areashop schemevent";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.schematicevents")) {
return plugin.getLanguageManager().getLang("help-schemevent");
}
return null;
}
@Override
public void execute(CommandSender sender, Command command, String[] args) {
if(!sender.hasPermission("areashop.schematicevents")) {
plugin.message(sender, "schemevent-noPermission");
return;
}
if(args.length < 3 || args[1] == null || args[2] == null) {
plugin.message(sender, "schemevent-help");
return;
}
GeneralRegion region = plugin.getFileManager().getRegion(args[1]);
if(region == null) {
plugin.message(sender, "schemevent-noRegion", args[1]);
return;
}
if(region.getRegion() == null) {
plugin.message(sender, "general-noRegion", region.getName());
return;
}
RegionEvent event = null;
boolean exception = false;
try {
event = RegionEvent.valueOf(args[2].toUpperCase());
} catch(IllegalArgumentException e) {
exception = true;
}
// Check for a totally wrong event or a non matching event
if(exception) {
ArrayList<String> values = new ArrayList<String>();
for(RegionEvent value : RegionEvent.values()) {
values.add(value.getValue().toLowerCase());
}
plugin.message(sender, "schemevent-wrongEvent", args[2], Utils.createCommaSeparatedList(values));
return;
}
region.handleSchematicEvent(event);
plugin.message(sender, "schemevent-success", args[2], region.getName());
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
ArrayList<String> result = new ArrayList<String>();
if(toComplete == 2) {
result.addAll(plugin.getFileManager().getRegionNames());
} else if(toComplete == 3) {
GeneralRegion region = plugin.getFileManager().getRegion(start[2]);
if(region != null) {
if(region.isRentRegion()) {
result.addAll(Arrays.asList("created", "deleted", "rented", "unrented"));
} else if(region.isBuyRegion()) {
result.addAll(Arrays.asList("created", "deleted", "bought", "sold"));
}
}
}
return result;
}
}
package me.wiefferink.areashop.commands;
import me.wiefferink.areashop.regions.BuyRegion;
import me.wiefferink.areashop.regions.GeneralRegion;
import me.wiefferink.areashop.regions.RentRegion;
import me.wiefferink.areashop.tools.Utils;
import org.bukkit.command.CommandSender;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class SchematiceventCommand extends CommandAreaShop {
@Override
public String getCommandStart() {
return "areashop schemevent";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.schematicevents")) {
return "help-schemevent";
}
return null;
}
@Override
public void execute(CommandSender sender, String[] args) {
if(!sender.hasPermission("areashop.schematicevents")) {
plugin.message(sender, "schemevent-noPermission");
return;
}
if(args.length < 3 || args[1] == null || args[2] == null) {
plugin.message(sender, "schemevent-help");
return;
}
GeneralRegion region = plugin.getFileManager().getRegion(args[1]);
if(region == null) {
plugin.message(sender, "cmd-notRegistered", args[1]);
return;
}
if(region.getRegion() == null) {
plugin.message(sender, "general-noRegion", region);
return;
}
GeneralRegion.RegionEvent event = null;
boolean exception = false;
try {
event = GeneralRegion.RegionEvent.valueOf(args[2].toUpperCase());
} catch(IllegalArgumentException e) {
exception = true;
}
// Check for a totally wrong event or a non matching event
if(exception) {
ArrayList<String> values = new ArrayList<>();
for(GeneralRegion.RegionEvent value : GeneralRegion.RegionEvent.values()) {
values.add(value.getValue().toLowerCase());
}
plugin.message(sender, "schemevent-wrongEvent", args[2], Utils.createCommaSeparatedList(values), region);
return;
}
region.handleSchematicEvent(event);
region.update();
plugin.message(sender, "schemevent-success", args[2], region);
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
ArrayList<String> result = new ArrayList<>();
if(toComplete == 2) {
result.addAll(plugin.getFileManager().getRegionNames());
} else if(toComplete == 3) {
GeneralRegion region = plugin.getFileManager().getRegion(start[2]);
if(region != null) {
if(region instanceof RentRegion) {
result.addAll(Arrays.asList("created", "deleted", "rented", "unrented"));
} else if(region instanceof BuyRegion) {
result.addAll(Arrays.asList("created", "deleted", "bought", "sold"));
}
}
}
return result;
}
}
@@ -0,0 +1,110 @@
package me.wiefferink.areashop.commands;
import me.wiefferink.areashop.regions.BuyRegion;
import me.wiefferink.areashop.regions.GeneralRegion;
import me.wiefferink.areashop.tools.Utils;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.List;
public class SellCommand extends CommandAreaShop {
@Override
public String getCommandStart() {
return "areashop sell";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.sell") || target.hasPermission("areashop.sellown")) {
return "help-sell";
}
return null;
}
/**
* Check if a person can sell the region.
* @param person The person to check
* @param region The region to check for
* @return true if the person can sell it, otherwise false
*/
public static boolean canUse(CommandSender person, GeneralRegion region) {
if(person.hasPermission("areashop.sell")) {
return true;
}
if(person instanceof Player) {
Player player = (Player)person;
return region.isOwner(player) && person.hasPermission("areashop.sellown");
}
return false;
}
@Override
public void execute(CommandSender sender, String[] args) {
if(!sender.hasPermission("areashop.sell") && !sender.hasPermission("areashop.sellown")) {
plugin.message(sender, "sell-noPermission");
return;
}
BuyRegion buy;
if(args.length <= 1) {
if(sender instanceof Player) {
// get the region by location
List<BuyRegion> regions = Utils.getImportantBuyRegions(((Player)sender).getLocation());
if(regions.isEmpty()) {
plugin.message(sender, "cmd-noRegionsAtLocation");
return;
} else if(regions.size() > 1) {
plugin.message(sender, "cmd-moreRegionsAtLocation");
return;
} else {
buy = regions.get(0);
}
} else {
plugin.message(sender, "cmd-automaticRegionOnlyByPlayer");
return;
}
} else {
buy = plugin.getFileManager().getBuy(args[1]);
}
if(buy == null) {
plugin.message(sender, "sell-notRegistered");
return;
}
if(!buy.isSold()) {
plugin.message(sender, "sell-notBought", buy);
return;
}
buy.sell(true, sender);
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
ArrayList<String> result = new ArrayList<>();
if(toComplete == 2) {
for(BuyRegion region : plugin.getFileManager().getBuys()) {
if(region.isSold()) {
result.add(region.getName());
}
}
}
return result;
}
}
@@ -1,114 +1,105 @@
package nl.evolutioncoding.areashop.commands;
import java.util.ArrayList;
import java.util.List;
import nl.evolutioncoding.areashop.AreaShop;
import nl.evolutioncoding.areashop.Utils;
import nl.evolutioncoding.areashop.regions.RentRegion;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
public class SetdurationCommand extends CommandAreaShop {
public SetdurationCommand(AreaShop plugin) {
super(plugin);
}
@Override
public String getCommandStart() {
return "areashop setduration";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.setduration")) {
return plugin.getLanguageManager().getLang("help-setduration");
}
return null;
}
@Override
public void execute(CommandSender sender, Command command, String[] args) {
if(!sender.hasPermission("areashop.setduration") && (!sender.hasPermission("areashop.setduration.landlord") && sender instanceof Player)) {
plugin.message(sender, "setduration-noPermission");
return;
}
if(args.length < 3 || args[1] == null || args[2] == null) {
plugin.message(sender, "setduration-help");
return;
}
int regionArgument = 3;
if(args.length >= 2 && ("default".equalsIgnoreCase(args[1]) || "reset".equalsIgnoreCase(args[1]))) {
regionArgument = 2;
}
RentRegion rent = null;
if(args.length <= regionArgument) {
if (sender instanceof Player) {
// get the region by location
List<RentRegion> regions = Utils.getApplicableRentRegions(((Player) sender).getLocation());
if (regions.isEmpty()) {
plugin.message(sender, "cmd-noRegionsAtLocation");
return;
} else if (regions.size() > 1) {
plugin.message(sender, "cmd-moreRegionsAtLocation");
return;
} else {
rent = regions.get(0);
}
} else {
plugin.message(sender, "cmd-automaticRegionOnlyByPlayer");
return;
}
} else {
rent = plugin.getFileManager().getRent(args[regionArgument]);
}
if(rent == null) {
plugin.message(sender, "setduration-notRegistered", args[regionArgument]);
return;
}
if(!sender.hasPermission("areashop.setduration") && !rent.isLandlord(((Player)sender).getUniqueId())) {
plugin.message(sender, "setduration-noLandlord", rent);
return;
}
if("default".equalsIgnoreCase(args[1]) || "reset".equalsIgnoreCase(args[1])) {
plugin.message(sender, "setduration-successRemoved", rent);
rent.setDuration(null);
rent.updateRegionFlags();
rent.updateSigns();
return;
}
try {
Integer.parseInt(args[1]);
} catch(NumberFormatException e) {
plugin.message(sender, "setduration-wrongAmount", args[1]);
return;
}
if(!plugin.checkTimeFormat(args[1] + " " + args[2])) {
plugin.message(sender, "setduration-wrongFormat", args[1]+" "+args[2]);
return;
}
rent.setDuration(args[1]+" "+args[2]);
rent.updateRegionFlags();
rent.updateSigns();
plugin.message(sender, "setduration-success", rent.getName(), rent.getDurationString());
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
List<String> result = new ArrayList<String>();
if(toComplete == 2) {
result = plugin.getFileManager().getRentNames();
} else if(toComplete == 4) {
result.addAll(plugin.getConfig().getStringList("minutes"));
result.addAll(plugin.getConfig().getStringList("hours"));
result.addAll(plugin.getConfig().getStringList("days"));
result.addAll(plugin.getConfig().getStringList("months"));
result.addAll(plugin.getConfig().getStringList("years"));
}
return result;
}
}
package me.wiefferink.areashop.commands;
import me.wiefferink.areashop.regions.RentRegion;
import me.wiefferink.areashop.tools.Utils;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.List;
public class SetdurationCommand extends CommandAreaShop {
@Override
public String getCommandStart() {
return "areashop setduration";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.setduration")) {
return "help-setduration";
}
return null;
}
@Override
public void execute(CommandSender sender, String[] args) {
if(!sender.hasPermission("areashop.setduration") && (!sender.hasPermission("areashop.setduration.landlord") && sender instanceof Player)) {
plugin.message(sender, "setduration-noPermission");
return;
}
if(args.length < 3 || args[1] == null || args[2] == null) {
plugin.message(sender, "setduration-help");
return;
}
int regionArgument = 3;
if(args.length >= 2 && ("default".equalsIgnoreCase(args[1]) || "reset".equalsIgnoreCase(args[1]))) {
regionArgument = 2;
}
RentRegion rent;
if(args.length <= regionArgument) {
if(sender instanceof Player) {
// get the region by location
List<RentRegion> regions = Utils.getImportantRentRegions(((Player)sender).getLocation());
if(regions.isEmpty()) {
plugin.message(sender, "cmd-noRegionsAtLocation");
return;
} else if(regions.size() > 1) {
plugin.message(sender, "cmd-moreRegionsAtLocation");
return;
} else {
rent = regions.get(0);
}
} else {
plugin.message(sender, "cmd-automaticRegionOnlyByPlayer");
return;
}
} else {
rent = plugin.getFileManager().getRent(args[regionArgument]);
}
if(rent == null) {
plugin.message(sender, "setduration-notRegistered", args[regionArgument]);
return;
}
if(!sender.hasPermission("areashop.setduration") && !(sender instanceof Player && rent.isLandlord(((Player)sender).getUniqueId()))) {
plugin.message(sender, "setduration-noLandlord", rent);
return;
}
if("default".equalsIgnoreCase(args[1]) || "reset".equalsIgnoreCase(args[1])) {
rent.setDuration(null);
rent.update();
plugin.message(sender, "setduration-successRemoved", rent);
return;
}
try {
Integer.parseInt(args[1]);
} catch(NumberFormatException e) {
plugin.message(sender, "setduration-wrongAmount", args[1], rent);
return;
}
if(!Utils.checkTimeFormat(args[1] + " " + args[2])) {
plugin.message(sender, "setduration-wrongFormat", args[1] + " " + args[2], rent);
return;
}
rent.setDuration(args[1] + " " + args[2]);
rent.update();
plugin.message(sender, "setduration-success", rent);
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
List<String> result = new ArrayList<>();
if(toComplete == 2) {
result = plugin.getFileManager().getRentNames();
} else if(toComplete == 4) {
result.addAll(plugin.getConfig().getStringList("minutes"));
result.addAll(plugin.getConfig().getStringList("hours"));
result.addAll(plugin.getConfig().getStringList("days"));
result.addAll(plugin.getConfig().getStringList("months"));
result.addAll(plugin.getConfig().getStringList("years"));
}
return result;
}
}
@@ -1,93 +1,87 @@
package nl.evolutioncoding.areashop.commands;
import java.util.ArrayList;
import java.util.List;
import nl.evolutioncoding.areashop.AreaShop;
import nl.evolutioncoding.areashop.Utils;
import nl.evolutioncoding.areashop.regions.GeneralRegion;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
public class SetlandlordCommand extends CommandAreaShop {
public SetlandlordCommand(AreaShop plugin) {
super(plugin);
}
@Override
public String getCommandStart() {
return "areashop setlandlord";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.setlandlord")) {
return plugin.getLanguageManager().getLang("help-setlandlord");
}
return null;
}
@Override
public void execute(CommandSender sender, Command command, String[] args) {
if(!sender.hasPermission("areashop.setlandlord")) {
plugin.message(sender, "setlandlord-noPermission");
return;
}
if(args.length < 2) {
plugin.message(sender, "setlandlord-help");
return;
}
@SuppressWarnings("deprecation")
OfflinePlayer player = Bukkit.getOfflinePlayer(args[1]);
GeneralRegion region = null;
if(args.length < 3) {
if (sender instanceof Player) {
// get the region by location
List<GeneralRegion> regions = Utils.getAllApplicableRegions(((Player) sender).getLocation());
if (regions.isEmpty()) {
plugin.message(sender, "cmd-noRegionsAtLocation");
return;
} else if (regions.size() > 1) {
plugin.message(sender, "cmd-moreRegionsAtLocation");
return;
} else {
region = regions.get(0);
}
} else {
plugin.message(sender, "cmd-automaticRegionOnlyByPlayer");
return;
}
} else {
region = plugin.getFileManager().getRegion(args[2]);
}
if(region == null) {
plugin.message(sender, "setlandlord-noRegion", args[2]);
return;
}
String playerName = player.getName();
if(playerName == null || playerName.isEmpty()) {
playerName = args[1];
}
region.setLandlord(player.getUniqueId(), playerName);
plugin.message(sender, "setlandlord-success", playerName, region.getName());
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
ArrayList<String> result = new ArrayList<String>();
if(toComplete == 2) {
for(Player player : Bukkit.getOnlinePlayers()) {
result.add(player.getName());
}
} else if(toComplete == 3) {
result.addAll(plugin.getFileManager().getRegionNames());
}
return result;
}
}
package me.wiefferink.areashop.commands;
import me.wiefferink.areashop.regions.GeneralRegion;
import me.wiefferink.areashop.tools.Utils;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.List;
public class SetlandlordCommand extends CommandAreaShop {
@Override
public String getCommandStart() {
return "areashop setlandlord";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.setlandlord")) {
return "help-setlandlord";
}
return null;
}
@Override
public void execute(CommandSender sender, String[] args) {
if(!sender.hasPermission("areashop.setlandlord")) {
plugin.message(sender, "setlandlord-noPermission");
return;
}
if(args.length < 2) {
plugin.message(sender, "setlandlord-help");
return;
}
@SuppressWarnings("deprecation")
OfflinePlayer player = Bukkit.getOfflinePlayer(args[1]);
GeneralRegion region;
if(args.length < 3) {
if(sender instanceof Player) {
// get the region by location
List<GeneralRegion> regions = Utils.getImportantRegions(((Player)sender).getLocation());
if(regions.isEmpty()) {
plugin.message(sender, "cmd-noRegionsAtLocation");
return;
} else if(regions.size() > 1) {
plugin.message(sender, "cmd-moreRegionsAtLocation");
return;
} else {
region = regions.get(0);
}
} else {
plugin.message(sender, "cmd-automaticRegionOnlyByPlayer");
return;
}
} else {
region = plugin.getFileManager().getRegion(args[2]);
}
if(region == null) {
plugin.message(sender, "cmd-notRegistered", args[2]);
return;
}
String playerName = player.getName();
if(playerName == null || playerName.isEmpty()) {
playerName = args[1];
}
region.setLandlord(player.getUniqueId(), playerName);
region.update();
plugin.message(sender, "setlandlord-success", playerName, region);
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
ArrayList<String> result = new ArrayList<>();
if(toComplete == 2) {
for(Player player : Utils.getOnlinePlayers()) {
result.add(player.getName());
}
} else if(toComplete == 3) {
result.addAll(plugin.getFileManager().getRegionNames());
}
return result;
}
}
@@ -1,152 +1,134 @@
package nl.evolutioncoding.areashop.commands;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.UUID;
import nl.evolutioncoding.areashop.AreaShop;
import nl.evolutioncoding.areashop.Utils;
import nl.evolutioncoding.areashop.regions.BuyRegion;
import nl.evolutioncoding.areashop.regions.GeneralRegion;
import nl.evolutioncoding.areashop.regions.RentRegion;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
public class SetownerCommand extends CommandAreaShop {
public SetownerCommand(AreaShop plugin) {
super(plugin);
}
@Override
public String getCommandStart() {
return "areashop setowner";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.setownerrent") || target.hasPermission("areashop.setownerbuy")) {
return plugin.getLanguageManager().getLang("help-setowner");
}
return null;
}
@Override
public void execute(CommandSender sender, Command command, String[] args) {
if(!sender.hasPermission("areashop.setownerrent") && !sender.hasPermission("areashop.setownerbuy")) {
plugin.message(sender, "setowner-noPermission");
return;
}
GeneralRegion region;
if(args.length < 2) {
plugin.message(sender, "setowner-help");
return;
}
if(args.length == 2) {
if (sender instanceof Player) {
// get the region by location
List<GeneralRegion> regions = Utils.getAllApplicableRegions(((Player) sender).getLocation());
if (regions.isEmpty()) {
plugin.message(sender, "cmd-noRegionsAtLocation");
return;
} else if (regions.size() > 1) {
plugin.message(sender, "cmd-moreRegionsAtLocation");
return;
} else {
region = regions.get(0);
}
} else {
plugin.message(sender, "cmd-automaticRegionOnlyByPlayer");
return;
}
} else {
region = plugin.getFileManager().getRegion(args[2]);
}
if(region == null) {
plugin.message(sender, "setowner-notRegistered");
return;
}
if(region.isRentRegion() && !sender.hasPermission("areashop.setownerrent")) {
plugin.message(sender, "setowner-noPermissionRent");
return;
}
if(region.isBuyRegion() && !sender.hasPermission("areashop.setownerbuy")) {
plugin.message(sender, "setowner-noPermissionBuy");
return;
}
UUID uuid = null;
@SuppressWarnings("deprecation")
OfflinePlayer player = Bukkit.getOfflinePlayer(args[1]);
if(player != null) {
uuid = player.getUniqueId();
}
if(uuid == null) {
plugin.message(sender, "setowner-noPlayer", args[1]);
return;
}
if(region.isRentRegion()) {
RentRegion rent = (RentRegion)region;
if(rent.isRenter(uuid)) {
// extend
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(rent.getRentedUntil() + rent.getDuration());
rent.setRentedUntil(calendar.getTimeInMillis());
rent.setRenter(uuid);
plugin.message(sender, "setowner-succesRentExtend", region);
rent.updateRegionFlags();
rent.updateSigns();
} else {
// change
Calendar calendar = Calendar.getInstance();
long current = calendar.getTimeInMillis();
if(rent.isRented()) {
current = rent.getRentedUntil();
}
calendar.setTimeInMillis(current + rent.getDuration());
rent.setRentedUntil(calendar.getTimeInMillis());
rent.setRenter(uuid);
plugin.message(sender, "setowner-succesRent", region);
rent.updateRegionFlags();
rent.updateSigns();
}
rent.updateRegionFlags();
rent.updateSigns();
}
if(region.isBuyRegion()) {
BuyRegion buy = (BuyRegion)region;
buy.setBuyer(uuid);
plugin.message(sender, "setowner-succesBuy", region);
buy.updateRegionFlags();
buy.updateSigns();
}
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
ArrayList<String> result = new ArrayList<String>();
if(toComplete == 2) {
for(Player player : Bukkit.getOnlinePlayers()) {
result.add(player.getName());
}
} else if(toComplete == 3) {
result.addAll(plugin.getFileManager().getRegionNames());
}
return result;
}
}
package me.wiefferink.areashop.commands;
import me.wiefferink.areashop.regions.BuyRegion;
import me.wiefferink.areashop.regions.GeneralRegion;
import me.wiefferink.areashop.regions.RentRegion;
import me.wiefferink.areashop.tools.Utils;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.UUID;
public class SetownerCommand extends CommandAreaShop {
@Override
public String getCommandStart() {
return "areashop setowner";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.setownerrent") || target.hasPermission("areashop.setownerbuy")) {
return "help-setowner";
}
return null;
}
@Override
public void execute(CommandSender sender, String[] args) {
if(!sender.hasPermission("areashop.setownerrent") && !sender.hasPermission("areashop.setownerbuy")) {
plugin.message(sender, "setowner-noPermission");
return;
}
GeneralRegion region;
if(args.length < 2) {
plugin.message(sender, "setowner-help");
return;
}
if(args.length == 2) {
if(sender instanceof Player) {
// get the region by location
List<GeneralRegion> regions = Utils.getImportantRegions(((Player)sender).getLocation());
if(regions.isEmpty()) {
plugin.message(sender, "cmd-noRegionsAtLocation");
return;
} else if(regions.size() > 1) {
plugin.message(sender, "cmd-moreRegionsAtLocation");
return;
} else {
region = regions.get(0);
}
} else {
plugin.message(sender, "cmd-automaticRegionOnlyByPlayer");
return;
}
} else {
region = plugin.getFileManager().getRegion(args[2]);
}
if(region == null) {
plugin.message(sender, "setowner-notRegistered");
return;
}
if(region instanceof RentRegion && !sender.hasPermission("areashop.setownerrent")) {
plugin.message(sender, "setowner-noPermissionRent", region);
return;
}
if(region instanceof BuyRegion && !sender.hasPermission("areashop.setownerbuy")) {
plugin.message(sender, "setowner-noPermissionBuy", region);
return;
}
UUID uuid = null;
@SuppressWarnings("deprecation")
OfflinePlayer player = Bukkit.getOfflinePlayer(args[1]);
if(player != null) {
uuid = player.getUniqueId();
}
if(uuid == null) {
plugin.message(sender, "setowner-noPlayer", args[1], region);
return;
}
if(region instanceof RentRegion) {
RentRegion rent = (RentRegion)region;
if(rent.isRenter(uuid)) {
// extend
rent.setRentedUntil(rent.getRentedUntil() + rent.getDuration());
rent.setRenter(uuid);
plugin.message(sender, "setowner-succesRentExtend", region);
} else {
// change
if(!rent.isRented()) {
rent.setRentedUntil(Calendar.getInstance().getTimeInMillis() + rent.getDuration());
}
rent.setRenter(uuid);
plugin.message(sender, "setowner-succesRent", region);
}
}
if(region instanceof BuyRegion) {
BuyRegion buy = (BuyRegion)region;
buy.setBuyer(uuid);
plugin.message(sender, "setowner-succesBuy", region);
}
region.getFriendsFeature().deleteFriend(region.getOwner(), null);
region.update();
region.saveRequired();
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
ArrayList<String> result = new ArrayList<>();
if(toComplete == 2) {
for(Player player : Utils.getOnlinePlayers()) {
result.add(player.getName());
}
} else if(toComplete == 3) {
result.addAll(plugin.getFileManager().getRegionNames());
}
return result;
}
}
@@ -1,113 +1,103 @@
package nl.evolutioncoding.areashop.commands;
import java.util.ArrayList;
import java.util.List;
import nl.evolutioncoding.areashop.AreaShop;
import nl.evolutioncoding.areashop.Utils;
import nl.evolutioncoding.areashop.regions.BuyRegion;
import nl.evolutioncoding.areashop.regions.GeneralRegion;
import nl.evolutioncoding.areashop.regions.RentRegion;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
public class SetpriceCommand extends CommandAreaShop {
public SetpriceCommand(AreaShop plugin) {
super(plugin);
}
@Override
public String getCommandStart() {
return "areashop setprice";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.setprice")) {
return plugin.getLanguageManager().getLang("help-setprice");
}
return null;
}
@Override
public void execute(CommandSender sender, Command command, String[] args) {
if(!sender.hasPermission("areashop.setprice") && (!sender.hasPermission("areashop.setprice.landlord") && sender instanceof Player)) {
plugin.message(sender, "setprice-noPermission");
return;
}
if(args.length < 2 || args[1] == null) {
plugin.message(sender, "setprice-help");
return;
}
GeneralRegion region = null;
if(args.length < 3) {
if (sender instanceof Player) {
// get the region by location
List<GeneralRegion> regions = Utils.getAllApplicableRegions(((Player) sender).getLocation());
if (regions.isEmpty()) {
plugin.message(sender, "cmd-noRegionsAtLocation");
return;
} else if (regions.size() > 1) {
plugin.message(sender, "cmd-moreRegionsAtLocation");
return;
} else {
region = regions.get(0);
}
} else {
plugin.message(sender, "cmd-automaticRegionOnlyByPlayer");
return;
}
} else {
region = plugin.getFileManager().getRegion(args[2]);
}
if(region == null) {
plugin.message(sender, "setprice-notRegistered", args[2]);
return;
}
if(!sender.hasPermission("areashop.setprice") && !region.isLandlord(((Player)sender).getUniqueId())) {
plugin.message(sender, "setprice-noLandlord", region);
return;
}
if("default".equalsIgnoreCase(args[1]) || "reset".equalsIgnoreCase(args[1])) {
if(region.isRentRegion()) {
((RentRegion)region).removePrice();
} else if(region.isBuyRegion()) {
((BuyRegion)region).removePrice();
}
plugin.message(sender, "setprice-successRemoved", region);
region.updateSigns();
region.updateRegionFlags();
return;
}
double price = 0.0;
try {
price = Double.parseDouble(args[1]);
} catch(NumberFormatException e) {
plugin.message(sender, "setprice-wrongPrice", args[1]);
return;
}
AreaShop.debug("price: " + price + ", raw: " + args[1]);
if(region.isRentRegion()) {
((RentRegion)region).setPrice(price);
plugin.message(sender, "setprice-successRent", region);
} else if(region.isBuyRegion()) {
((BuyRegion)region).setPrice(price);
plugin.message(sender, "setprice-successBuy", region);
}
region.updateSigns();
region.updateRegionFlags();
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
List<String> result = new ArrayList<String>();
if(toComplete == 3) {
result = plugin.getFileManager().getRegionNames();
}
return result;
}
}
package me.wiefferink.areashop.commands;
import me.wiefferink.areashop.regions.BuyRegion;
import me.wiefferink.areashop.regions.GeneralRegion;
import me.wiefferink.areashop.regions.RentRegion;
import me.wiefferink.areashop.tools.Utils;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.List;
public class SetpriceCommand extends CommandAreaShop {
@Override
public String getCommandStart() {
return "areashop setprice";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.setprice")) {
return "help-setprice";
}
return null;
}
@Override
public void execute(CommandSender sender, String[] args) {
if(!sender.hasPermission("areashop.setprice") && (!sender.hasPermission("areashop.setprice.landlord") && sender instanceof Player)) {
plugin.message(sender, "setprice-noPermission");
return;
}
if(args.length < 2 || args[1] == null) {
plugin.message(sender, "setprice-help");
return;
}
GeneralRegion region;
if(args.length < 3) {
if(sender instanceof Player) {
// get the region by location
List<GeneralRegion> regions = Utils.getImportantRegions(((Player)sender).getLocation());
if(regions.isEmpty()) {
plugin.message(sender, "cmd-noRegionsAtLocation");
return;
} else if(regions.size() > 1) {
plugin.message(sender, "cmd-moreRegionsAtLocation");
return;
} else {
region = regions.get(0);
}
} else {
plugin.message(sender, "cmd-automaticRegionOnlyByPlayer");
return;
}
} else {
region = plugin.getFileManager().getRegion(args[2]);
}
if(region == null) {
plugin.message(sender, "setprice-notRegistered", args[2]);
return;
}
if(!sender.hasPermission("areashop.setprice") && !(sender instanceof Player && region.isLandlord(((Player)sender).getUniqueId()))) {
plugin.message(sender, "setprice-noLandlord", region);
return;
}
if("default".equalsIgnoreCase(args[1]) || "reset".equalsIgnoreCase(args[1])) {
if(region instanceof RentRegion) {
((RentRegion)region).setPrice(null);
} else if(region instanceof BuyRegion) {
((BuyRegion)region).setPrice(null);
}
region.update();
plugin.message(sender, "setprice-successRemoved", region);
return;
}
double price;
try {
price = Double.parseDouble(args[1]);
} catch(NumberFormatException e) {
plugin.message(sender, "setprice-wrongPrice", args[1], region);
return;
}
if(region instanceof RentRegion) {
((RentRegion)region).setPrice(price);
plugin.message(sender, "setprice-successRent", region);
} else if(region instanceof BuyRegion) {
((BuyRegion)region).setPrice(price);
plugin.message(sender, "setprice-successBuy", region);
}
region.update();
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
List<String> result = new ArrayList<>();
if(toComplete == 3) {
result = plugin.getFileManager().getRegionNames();
}
return result;
}
}
@@ -1,79 +1,73 @@
package nl.evolutioncoding.areashop.commands;
import java.util.ArrayList;
import java.util.List;
import nl.evolutioncoding.areashop.AreaShop;
import nl.evolutioncoding.areashop.regions.GeneralRegion;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
public class SetrestoreCommand extends CommandAreaShop {
public SetrestoreCommand(AreaShop plugin) {
super(plugin);
}
@Override
public String getCommandStart() {
return "areashop setrestore";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.setrestore")) {
return plugin.getLanguageManager().getLang("help-setrestore");
}
return null;
}
@Override
public void execute(CommandSender sender, Command command, String[] args) {
if(!sender.hasPermission("areashop.setrestore")) {
plugin.message(sender, "setrestore-noPermission");
return;
}
if(args.length <= 2 || args[1] == null || args[2] == null) {
plugin.message(sender, "setrestore-help");
return;
}
GeneralRegion region = plugin.getFileManager().getRegion(args[1]);
if(region == null) {
plugin.message(sender, "setrestore-notRegistered", args[1]);
return;
}
Boolean value = null;
if(args[2].equalsIgnoreCase("true")) {
value = true;
} else if(args[2].equalsIgnoreCase("false")) {
value = false;
}
region.setRestoreSetting(value);
String valueString = "general";
if(value != null) {
valueString = value+"";
}
if(args.length > 3) {
region.setSchematicProfile(args[3]);
plugin.message(sender, "setrestore-successProfile", region.getName(), valueString, args[3]);
} else {
plugin.message(sender, "setrestore-success", region.getName(), valueString);
}
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
List<String> result = new ArrayList<String>();
if(toComplete == 2) {
result = plugin.getFileManager().getRegionNames();
} else if(toComplete == 3) {
result.add("true");
result.add("false");
result.add("general");
} else if(toComplete == 4) {
result.addAll(plugin.getConfig().getConfigurationSection("schematicProfiles").getKeys(false));
}
return result;
}
}
package me.wiefferink.areashop.commands;
import me.wiefferink.areashop.regions.GeneralRegion;
import org.bukkit.command.CommandSender;
import java.util.ArrayList;
import java.util.List;
public class SetrestoreCommand extends CommandAreaShop {
@Override
public String getCommandStart() {
return "areashop setrestore";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.setrestore")) {
return "help-setrestore";
}
return null;
}
@Override
public void execute(CommandSender sender, String[] args) {
if(!sender.hasPermission("areashop.setrestore")) {
plugin.message(sender, "setrestore-noPermission");
return;
}
if(args.length <= 2 || args[1] == null || args[2] == null) {
plugin.message(sender, "setrestore-help");
return;
}
GeneralRegion region = plugin.getFileManager().getRegion(args[1]);
if(region == null) {
plugin.message(sender, "setrestore-notRegistered", args[1]);
return;
}
Boolean value = null;
if(args[2].equalsIgnoreCase("true")) {
value = true;
} else if(args[2].equalsIgnoreCase("false")) {
value = false;
}
region.setRestoreSetting(value);
String valueString = "general";
if(value != null) {
valueString = value + "";
}
if(args.length > 3) {
region.setSchematicProfile(args[3]);
plugin.message(sender, "setrestore-successProfile", valueString, args[3], region);
} else {
plugin.message(sender, "setrestore-success", valueString, region);
}
region.update();
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
List<String> result = new ArrayList<>();
if(toComplete == 2) {
result = plugin.getFileManager().getRegionNames();
} else if(toComplete == 3) {
result.add("true");
result.add("false");
result.add("general");
} else if(toComplete == 4) {
result.addAll(plugin.getConfig().getConfigurationSection("schematicProfiles").getKeys(false));
}
return result;
}
}
@@ -1,116 +1,118 @@
package nl.evolutioncoding.areashop.commands;
import java.util.ArrayList;
import java.util.List;
import nl.evolutioncoding.areashop.AreaShop;
import nl.evolutioncoding.areashop.Utils;
import nl.evolutioncoding.areashop.regions.BuyRegion;
import nl.evolutioncoding.areashop.regions.GeneralRegion;
import nl.evolutioncoding.areashop.regions.RentRegion;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
public class SetteleportCommand extends CommandAreaShop {
public SetteleportCommand(AreaShop plugin) {
super(plugin);
}
@Override
public String getCommandStart() {
return "areashop settp";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.teleportall")) {
return plugin.getLanguageManager().getLang("help-setteleportAll");
} else if(target.hasPermission("areashop.teleport")) {
return plugin.getLanguageManager().getLang("help-setteleport");
}
return null;
}
@Override
public void execute(CommandSender sender, Command command, String[] args) {
if(!sender.hasPermission("areashop.setteleport") && !sender.hasPermission("areashop.setteleportall")) {
plugin.message(sender, "setteleport-noPermission");
return;
}
if (!(sender instanceof Player)) {
plugin.message(sender, "onlyByPlayer");
return;
}
Player player = (Player)sender;
GeneralRegion region = null;
if(args.length < 2) {
if (sender instanceof Player) {
// get the region by location
List<GeneralRegion> regions = Utils.getAllApplicableRegions(((Player) sender).getLocation());
if (regions.isEmpty()) {
plugin.message(sender, "cmd-noRegionsAtLocation");
return;
} else if (regions.size() > 1) {
plugin.message(sender, "cmd-moreRegionsAtLocation");
return;
} else {
region = regions.get(0);
}
} else {
plugin.message(sender, "cmd-automaticRegionOnlyByPlayer");
return;
}
} else {
region = plugin.getFileManager().getRegion(args[1]);
}
boolean owner = false;
if(region == null) {
plugin.message(player, "setteleport-noRentOrBuy", args[1]);
return;
}
if(region.isRentRegion()) {
owner = player.getUniqueId().equals(((RentRegion)region).getRenter());
} else {
owner = player.getUniqueId().equals(((BuyRegion)region).getBuyer());
}
if(!player.hasPermission("areashop.setteleport")) {
plugin.message(player, "setteleport-noPermission");
return;
} else if(!owner && !player.hasPermission("areashop.setteleportall")) {
plugin.message(player, "setteleport-noPermissionOther");
return;
}
ProtectedRegion wgRegion = region.getRegion();
if(args.length > 2 && args[2] != null && (args[2].equalsIgnoreCase("reset") || args[2].equalsIgnoreCase("yes") || args[2].equalsIgnoreCase("true"))) {
region.setTeleport(null);
plugin.message(player, "setteleport-reset", region.getName());
return;
}
if(!player.hasPermission("areashop.setteleportoutsideregion") && (wgRegion == null || !wgRegion.contains(player.getLocation().getBlockX(), player.getLocation().getBlockY(), player.getLocation().getBlockZ()))) {
plugin.message(player, "setteleport-notInside", region.getName());
return;
}
region.setTeleport(player.getLocation());
plugin.message(player, "setteleport-success", region.getName());
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
ArrayList<String> result = new ArrayList<String>();
if(toComplete == 2) {
result.addAll(plugin.getFileManager().getRegionNames());
} else if(toComplete == 3) {
result.add("reset");
}
return result;
}
}
package me.wiefferink.areashop.commands;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import me.wiefferink.areashop.regions.BuyRegion;
import me.wiefferink.areashop.regions.GeneralRegion;
import me.wiefferink.areashop.regions.RentRegion;
import me.wiefferink.areashop.tools.Utils;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.List;
public class SetteleportCommand extends CommandAreaShop {
@Override
public String getCommandStart() {
return "areashop settp";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.teleportall") || target.hasPermission("areashop.teleport")) {
return "help-setteleport";
}
return null;
}
/**
* Check if a person can set the teleport location of the region.
* @param person The person to check
* @param region The region to check for
* @return true if the person can set the teleport location, otherwise false
*/
public static boolean canUse(CommandSender person, GeneralRegion region) {
if(!(person instanceof Player)) {
return false;
}
Player player = (Player)person;
return player.hasPermission("areashop.setteleportall")
|| region.isOwner(player) && player.hasPermission("areashop.setteleport");
}
@Override
public void execute(CommandSender sender, String[] args) {
if(!sender.hasPermission("areashop.setteleport") && !sender.hasPermission("areashop.setteleportall")) {
plugin.message(sender, "setteleport-noPermission");
return;
}
if(!(sender instanceof Player)) {
plugin.message(sender, "onlyByPlayer");
return;
}
Player player = (Player)sender;
GeneralRegion region;
if(args.length < 2) {
// get the region by location
List<GeneralRegion> regions = Utils.getImportantRegions(((Player)sender).getLocation());
if(regions.isEmpty()) {
plugin.message(sender, "cmd-noRegionsAtLocation");
return;
} else if(regions.size() > 1) {
plugin.message(sender, "cmd-moreRegionsAtLocation");
return;
} else {
region = regions.get(0);
}
} else {
region = plugin.getFileManager().getRegion(args[1]);
}
boolean owner;
if(region == null) {
plugin.message(player, "setteleport-noRentOrBuy", args[1]);
return;
}
if(region instanceof RentRegion) {
owner = player.getUniqueId().equals(((RentRegion)region).getRenter());
} else {
owner = player.getUniqueId().equals(((BuyRegion)region).getBuyer());
}
if(!player.hasPermission("areashop.setteleport")) {
plugin.message(player, "setteleport-noPermission", region);
return;
} else if(!owner && !player.hasPermission("areashop.setteleportall")) {
plugin.message(player, "setteleport-noPermissionOther", region);
return;
}
ProtectedRegion wgRegion = region.getRegion();
if(args.length > 2 && args[2] != null && (args[2].equalsIgnoreCase("reset") || args[2].equalsIgnoreCase("yes") || args[2].equalsIgnoreCase("true"))) {
region.getTeleportFeature().setTeleport(null);
region.update();
plugin.message(player, "setteleport-reset", region);
return;
}
if(!player.hasPermission("areashop.setteleportoutsideregion") && (wgRegion == null || !wgRegion.contains(player.getLocation().getBlockX(), player.getLocation().getBlockY(), player.getLocation().getBlockZ()))) {
plugin.message(player, "setteleport-notInside", region);
return;
}
region.getTeleportFeature().setTeleport(player.getLocation());
region.update();
plugin.message(player, "setteleport-success", region);
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
ArrayList<String> result = new ArrayList<>();
if(toComplete == 2) {
result.addAll(plugin.getFileManager().getRegionNames());
} else if(toComplete == 3) {
result.add("reset");
}
return result;
}
}
@@ -1,229 +1,262 @@
package nl.evolutioncoding.areashop.commands;
import java.util.ArrayList;
import java.util.List;
import nl.evolutioncoding.areashop.AreaShop;
import nl.evolutioncoding.areashop.Utils;
import nl.evolutioncoding.areashop.regions.BuyRegion;
import nl.evolutioncoding.areashop.regions.GeneralRegion.RegionEvent;
import nl.evolutioncoding.areashop.regions.RegionGroup;
import nl.evolutioncoding.areashop.regions.RentRegion;
import org.bukkit.Location;
import org.bukkit.block.BlockFace;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitRunnable;
import com.sk89q.worldedit.BlockVector;
import com.sk89q.worldedit.bukkit.selections.Selection;
import com.sk89q.worldguard.protection.managers.RegionManager;
import com.sk89q.worldguard.protection.regions.ProtectedCuboidRegion;
public class StackCommand extends CommandAreaShop {
public StackCommand(AreaShop plugin) {
super(plugin);
}
@Override
public String getCommandStart() {
return "areashop stack";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.stack")) {
return plugin.getLanguageManager().getLang("help-stack");
}
return null;
}
@Override
public void execute(CommandSender sender, Command command, String[] args) {
// Check permission
if(!sender.hasPermission("areashop.stack")) {
plugin.message(sender, "stack-noPermission");
return;
}
// Only from ingame
if (!(sender instanceof Player)) {
plugin.message(sender, "cmd-onlyByPlayer");
return;
}
final Player player = (Player)sender;
// Specify enough arguments
if(args.length < 5) {
plugin.message(sender, "stack-help");
return;
}
// Check amount
int tempAmount = -1;
try {
tempAmount = Integer.parseInt(args[1]);
} catch(NumberFormatException e) {}
if(tempAmount <= 0) {
plugin.message(player, "stack-wrongAmount", args[1]);
return;
}
// Check gap
int gap = -1;
try {
gap = Integer.parseInt(args[2]);
} catch(NumberFormatException e) {
plugin.message(player, "stack-wrongGap", args[2]);
return;
}
// Check region type
if(!"rent".equalsIgnoreCase(args[4]) && !"buy".equalsIgnoreCase(args[4])) {
plugin.message(sender, "stack-help");
return;
}
// Get WorldEdit selection
final Selection selection = plugin.getWorldEdit().getSelection(player);
if(selection == null) {
plugin.message(player, "stack-noSelection");
return;
}
// Get or create group
RegionGroup group = null;
if(args.length > 5) {
group = plugin.getFileManager().getGroup(args[5]);
if(group == null) {
group = new RegionGroup(plugin, args[5]);
plugin.getFileManager().addGroup(group);
}
}
// Get facing of the player (must be clearly one of the four directions to make sure it is no mistake)
BlockFace facing = Utils.yawToFacing(player.getLocation().getYaw());
if(!(facing == BlockFace.NORTH || facing == BlockFace.EAST || facing == BlockFace.SOUTH || facing == BlockFace.WEST)) {
plugin.message(player, "stack-unclearDirection", facing.toString().toLowerCase().replace('_', '-'));
return;
}
final Location shift = new Location(selection.getWorld(), 0, 0, 0);
if(facing == BlockFace.SOUTH) {
shift.setZ(-selection.getLength() - gap);
} else if(facing == BlockFace.WEST) {
shift.setX(selection.getWidth() + gap);
} else if(facing == BlockFace.NORTH) {
shift.setZ(selection.getLength() + gap);
} else if(facing == BlockFace.EAST) {
shift.setX(-selection.getWidth() - gap);
}
AreaShop.debug(" calculated shift vector: " + shift + ", with facing=" + facing);
// Create regions and add them to AreaShop
final String namePrefix = args[3];
final int regionsPerTick = plugin.getConfig().getInt("adding.regionsPerTick");
final boolean rentRegions = "rent".equalsIgnoreCase(args[4]);
final int amount = tempAmount;
final RegionGroup finalGroup = group;
String type = null;
if(rentRegions) {
type = "rent";
} else {
type = "buy";
}
String groupsMessage = "";
if(group != null) {
groupsMessage = plugin.getLanguageManager().getLang("stack-addToGroup", group.getName());
}
plugin.message(player, "stack-accepted", amount, type, gap, namePrefix, groupsMessage);
plugin.message(player, "stack-addStart", amount, regionsPerTick*20);
new BukkitRunnable() {
private int current = 0;
private RegionManager manager = AreaShop.getInstance().getWorldGuard().getRegionManager(selection.getWorld());
private int counter = 1;
@Override
public void run() {
for(int i=0; i<regionsPerTick; i++) {
if(current < amount) {
// Create the region name
String counterName = counter+"";
int minimumLength = plugin.getConfig().getInt("stackRegionNumberLength");
while(counterName.length() < minimumLength) {
counterName = "0"+counterName;
}
String regionName = namePrefix + counterName;
while(manager.getRegion(regionName) != null || AreaShop.getInstance().getFileManager().getRegion(regionName) != null) {
counter++;
counterName = counter+"";
minimumLength = plugin.getConfig().getInt("stackRegionNumberLength");
while(counterName.length() < minimumLength) {
counterName = "0"+counterName;
}
regionName = namePrefix + counterName;
}
// Add the region to WorldGuard (at startposition shifted by the number of this region times the blocks it should shift)
ProtectedCuboidRegion region = new ProtectedCuboidRegion(regionName,
new BlockVector(
selection.getMinimumPoint().getBlockX() + shift.getBlockX()*current,
selection.getMinimumPoint().getBlockY() + shift.getBlockY()*current,
selection.getMinimumPoint().getBlockZ() + shift.getBlockZ()*current
),
new BlockVector(
selection.getMaximumPoint().getBlockX() + shift.getBlockX()*current,
selection.getMaximumPoint().getBlockY() + shift.getBlockY()*current,
selection.getMaximumPoint().getBlockZ() + shift.getBlockZ()*current
)
);
manager.addRegion(region);
// Add the region to AreaShop
if(rentRegions) {
RentRegion rent = new RentRegion(plugin, region.getId(), selection.getWorld());
if(finalGroup != null) {
finalGroup.addMember(rent);
}
rent.runEventCommands(RegionEvent.CREATED, true);
plugin.getFileManager().addRent(rent);
rent.handleSchematicEvent(RegionEvent.CREATED);
rent.updateRegionFlags();
rent.runEventCommands(RegionEvent.CREATED, false);
} else {
BuyRegion buy = new BuyRegion(plugin, region.getId(), selection.getWorld());
if(finalGroup != null) {
finalGroup.addMember(buy);
}
buy.runEventCommands(RegionEvent.CREATED, true);
plugin.getFileManager().addBuy(buy);
buy.handleSchematicEvent(RegionEvent.CREATED);
buy.updateRegionFlags();
buy.runEventCommands(RegionEvent.CREATED, false);
}
current++;
}
}
if(current >= amount) {
if(player.isOnline()) {
plugin.message(player, "stack-addComplete");
}
this.cancel();
}
}
}.runTaskTimer(plugin, 1, 1);
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
List<String> result = new ArrayList<String>();
if(toComplete == 5) {
result.add("rent");
result.add("buy");
} else if(toComplete == 6) {
result.addAll(plugin.getFileManager().getGroupNames());
}
return result;
}
}
package me.wiefferink.areashop.commands;
import com.sk89q.worldedit.BlockVector;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldguard.protection.managers.RegionManager;
import com.sk89q.worldguard.protection.regions.ProtectedCuboidRegion;
import me.wiefferink.areashop.AreaShop;
import me.wiefferink.areashop.interfaces.WorldEditSelection;
import me.wiefferink.areashop.regions.BuyRegion;
import me.wiefferink.areashop.regions.GeneralRegion;
import me.wiefferink.areashop.regions.RegionGroup;
import me.wiefferink.areashop.regions.RentRegion;
import me.wiefferink.areashop.tools.Utils;
import me.wiefferink.interactivemessenger.processing.Message;
import org.bukkit.Location;
import org.bukkit.block.BlockFace;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitRunnable;
import java.util.ArrayList;
import java.util.List;
public class StackCommand extends CommandAreaShop {
@Override
public String getCommandStart() {
return "areashop stack";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.stack")) {
return "help-stack";
}
return null;
}
@Override
public void execute(CommandSender sender, String[] args) {
// Check permission
if(!sender.hasPermission("areashop.stack")) {
plugin.message(sender, "stack-noPermission");
return;
}
// Only from ingame
if(!(sender instanceof Player)) {
plugin.message(sender, "cmd-onlyByPlayer");
return;
}
final Player player = (Player)sender;
// Specify enough arguments
if(args.length < 5) {
plugin.message(sender, "stack-help");
return;
}
// Check amount
int tempAmount = -1;
try {
tempAmount = Integer.parseInt(args[1]);
} catch(NumberFormatException e) {
// Incorrect number
}
if(tempAmount <= 0) {
plugin.message(player, "stack-wrongAmount", args[1]);
return;
}
// Check gap
int gap;
try {
gap = Integer.parseInt(args[2]);
} catch(NumberFormatException e) {
plugin.message(player, "stack-wrongGap", args[2]);
return;
}
// Check region type
if(!"rent".equalsIgnoreCase(args[4]) && !"buy".equalsIgnoreCase(args[4])) {
plugin.message(sender, "stack-help");
return;
}
// Get WorldEdit selection
final WorldEditSelection selection = plugin.getWorldEditHandler().getPlayerSelection(player);
if(selection == null) {
plugin.message(player, "stack-noSelection");
return;
}
// Get or create group
RegionGroup group = null;
if(args.length > 5) {
group = plugin.getFileManager().getGroup(args[5]);
if(group == null) {
group = new RegionGroup(plugin, args[5]);
plugin.getFileManager().addGroup(group);
}
}
// Get facing of the player (must be clearly one of the four directions to make sure it is no mistake)
BlockFace facing = Utils.yawToFacing(player.getLocation().getYaw());
if(player.getLocation().getPitch() > 45) {
facing = BlockFace.DOWN;
} else if(player.getLocation().getPitch() < -45) {
facing = BlockFace.UP;
}
if(!(facing == BlockFace.NORTH || facing == BlockFace.EAST || facing == BlockFace.SOUTH || facing == BlockFace.WEST || facing == BlockFace.UP || facing == BlockFace.DOWN)) {
plugin.message(player, "stack-unclearDirection", facing.toString().toLowerCase().replace('_', '-'));
return;
}
Vector shift = new BlockVector(0, 0, 0);
if(facing == BlockFace.SOUTH) {
shift = shift.setZ(-selection.getLength() - gap);
} else if(facing == BlockFace.WEST) {
shift = shift.setX(selection.getWidth() + gap);
} else if(facing == BlockFace.NORTH) {
shift = shift.setZ(selection.getLength() + gap);
} else if(facing == BlockFace.EAST) {
shift = shift.setX(-selection.getWidth() - gap);
} else if(facing == BlockFace.DOWN) {
shift = shift.setY(-selection.getHeight() - gap);
} else if(facing == BlockFace.UP) {
shift = shift.setY(selection.getHeight() + gap);
}
AreaShop.debug(" calculated shift vector: " + shift + ", with facing=" + facing);
// Create regions and add them to AreaShop
final String nameTemplate = args[3];
final int regionsPerTick = plugin.getConfig().getInt("adding.regionsPerTick");
final boolean rentRegions = "rent".equalsIgnoreCase(args[4]);
final int amount = tempAmount;
final RegionGroup finalGroup = group;
final Vector finalShift = shift;
String type;
if(rentRegions) {
type = "rent";
} else {
type = "buy";
}
Message groupsMessage = Message.empty();
if(group != null) {
groupsMessage = Message.fromKey("stack-addToGroup").replacements(group.getName());
}
plugin.message(player, "stack-accepted", amount, type, gap, nameTemplate, groupsMessage);
plugin.message(player, "stack-addStart", amount, regionsPerTick * 20);
Location minimumLocation = selection.getMinimumLocation();
Vector minimumVector = new Vector(minimumLocation.getX(), minimumLocation.getY(), minimumLocation.getZ());
Location maximumLocation = selection.getMaximumLocation();
Vector maximumVector = new Vector(maximumLocation.getX(), maximumLocation.getY(), maximumLocation.getZ());
new BukkitRunnable() {
private int current = -1;
private final RegionManager manager = AreaShop.getInstance().getRegionManager(selection.getWorld());
private int counter = 1;
private int tooLow = 0;
private int tooHigh = 0;
@Override
public void run() {
for(int i = 0; i < regionsPerTick; i++) {
current++;
if(current < amount) {
// Create the region name
String counterName = counter + "";
int minimumLength = plugin.getConfig().getInt("stackRegionNumberLength");
while(counterName.length() < minimumLength) {
counterName = "0" + counterName;
}
String regionName;
if(nameTemplate.contains("#")) {
regionName = nameTemplate.replace("#", counterName);
} else {
regionName = nameTemplate + counterName;
}
while(manager.getRegion(regionName) != null || AreaShop.getInstance().getFileManager().getRegion(regionName) != null) {
counter++;
counterName = counter + "";
minimumLength = plugin.getConfig().getInt("stackRegionNumberLength");
while(counterName.length() < minimumLength) {
counterName = "0" + counterName;
}
if(nameTemplate.contains("#")) {
regionName = nameTemplate.replace("#", counterName);
} else {
regionName = nameTemplate + counterName;
}
}
// Add the region to WorldGuard (at startposition shifted by the number of this region times the blocks it should shift)
BlockVector minimum = new BlockVector(minimumVector.add(finalShift.multiply(current)));
BlockVector maximum = new BlockVector(maximumVector.add(finalShift.multiply(current)));
// Check for out of bounds
if(minimum.getBlockY() < 0) {
tooLow++;
continue;
} else if(maximum.getBlockY() > 256) {
tooHigh++;
continue;
}
ProtectedCuboidRegion region = new ProtectedCuboidRegion(regionName, minimum, maximum);
manager.addRegion(region);
// Add the region to AreaShop
if(rentRegions) {
RentRegion rent = new RentRegion(regionName, selection.getWorld());
if(finalGroup != null) {
finalGroup.addMember(rent);
}
rent.runEventCommands(GeneralRegion.RegionEvent.CREATED, true);
plugin.getFileManager().addRent(rent);
rent.handleSchematicEvent(GeneralRegion.RegionEvent.CREATED);
rent.runEventCommands(GeneralRegion.RegionEvent.CREATED, false);
rent.update();
} else {
BuyRegion buy = new BuyRegion(regionName, selection.getWorld());
if(finalGroup != null) {
finalGroup.addMember(buy);
}
buy.runEventCommands(GeneralRegion.RegionEvent.CREATED, true);
plugin.getFileManager().addBuy(buy);
buy.handleSchematicEvent(GeneralRegion.RegionEvent.CREATED);
buy.runEventCommands(GeneralRegion.RegionEvent.CREATED, false);
buy.update();
}
}
}
if(current >= amount) {
if(player.isOnline()) {
int added = amount - tooLow - tooHigh;
Message wrong = Message.empty();
if(tooHigh > 0) {
wrong.append(Message.fromKey("stack-tooHigh").replacements(tooHigh));
}
if(tooLow > 0) {
wrong.append(Message.fromKey("stack-tooLow").replacements(tooLow));
}
plugin.message(player, "stack-addComplete", added, wrong);
}
this.cancel();
}
}
}.runTaskTimer(plugin, 1, 1);
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
List<String> result = new ArrayList<>();
if(toComplete == 5) {
result.add("rent");
result.add("buy");
} else if(toComplete == 6) {
result.addAll(plugin.getFileManager().getGroupNames());
}
return result;
}
}
@@ -1,122 +1,111 @@
package nl.evolutioncoding.areashop.commands;
import java.util.ArrayList;
import java.util.List;
import nl.evolutioncoding.areashop.AreaShop;
import nl.evolutioncoding.areashop.Utils;
import nl.evolutioncoding.areashop.regions.BuyRegion;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
public class StopresellCommand extends CommandAreaShop {
public StopresellCommand(AreaShop plugin) {
super(plugin);
}
@Override
public String getCommandStart() {
return "areashop stopresell";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.stopresellall")) {
return plugin.getLanguageManager().getLang("help-stopResellAll");
} else if(target.hasPermission("areashop.stopresell")) {
return plugin.getLanguageManager().getLang("help-stopResell");
}
return null;
}
@Override
public void execute(CommandSender sender, Command command, String[] args) {
if(!sender.hasPermission("areashop.stopresell") && !sender.hasPermission("areashop.stopresellall")) {
plugin.message(sender, "stopresell-noPermissionOther");
return;
}
BuyRegion buy = null;
if(args.length <= 1) {
if (sender instanceof Player) {
// get the region by location
List<BuyRegion> regions = Utils.getApplicableBuyRegions(((Player) sender).getLocation());
if (regions.isEmpty()) {
plugin.message(sender, "cmd-noRegionsAtLocation");
return;
} else if (regions.size() > 1) {
plugin.message(sender, "cmd-moreRegionsAtLocation");
return;
} else {
buy = regions.get(0);
}
} else {
plugin.message(sender, "cmd-automaticRegionOnlyByPlayer");
return;
}
} else {
buy = plugin.getFileManager().getBuy(args[1]);
if(buy == null) {
plugin.message(sender, "stopresell-notRegistered", args[1]);
return;
}
}
if(buy == null) {
plugin.message(sender, "stopresell-noRegionFound");
return;
}
if(!buy.isInResellingMode()) {
plugin.message(sender, "stopresell-notResell", buy);
return;
}
if(sender.hasPermission("areashop.stopresellall")) {
buy.disableReselling();
plugin.message(sender, "stopresell-success", buy);
buy.updateSigns();
buy.updateRegionFlags();
} else if(sender.hasPermission("areashop.stopresell") && sender instanceof Player) {
if(buy.isOwner((Player)sender)) {
buy.disableReselling();
plugin.message(sender, "stopresell-success", buy);
buy.updateSigns();
buy.updateRegionFlags();
} else {
plugin.message(sender, "stopresell-noPermissionOther");
}
} else {
plugin.message(sender, "stopresell-noPermission");
}
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
ArrayList<String> result = new ArrayList<String>();
if(toComplete == 2) {
for(BuyRegion region : plugin.getFileManager().getBuys()) {
if(region.isSold() && region.isInResellingMode()) {
result.add(region.getName());
}
}
}
return result;
}
}
package me.wiefferink.areashop.commands;
import me.wiefferink.areashop.regions.BuyRegion;
import me.wiefferink.areashop.tools.Utils;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.List;
public class StopresellCommand extends CommandAreaShop {
@Override
public String getCommandStart() {
return "areashop stopresell";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.stopresellall") || target.hasPermission("areashop.stopresell")) {
return "help-stopResell";
}
return null;
}
@Override
public void execute(CommandSender sender, String[] args) {
if(!sender.hasPermission("areashop.stopresell") && !sender.hasPermission("areashop.stopresellall")) {
plugin.message(sender, "stopresell-noPermissionOther");
return;
}
BuyRegion buy;
if(args.length <= 1) {
if(sender instanceof Player) {
// get the region by location
List<BuyRegion> regions = Utils.getImportantBuyRegions(((Player)sender).getLocation());
if(regions.isEmpty()) {
plugin.message(sender, "cmd-noRegionsAtLocation");
return;
} else if(regions.size() > 1) {
plugin.message(sender, "cmd-moreRegionsAtLocation");
return;
} else {
buy = regions.get(0);
}
} else {
plugin.message(sender, "cmd-automaticRegionOnlyByPlayer");
return;
}
} else {
buy = plugin.getFileManager().getBuy(args[1]);
if(buy == null) {
plugin.message(sender, "stopresell-notRegistered", args[1]);
return;
}
}
if(buy == null) {
plugin.message(sender, "cmd-noRegionsAtLocation");
return;
}
if(!buy.isInResellingMode()) {
plugin.message(sender, "stopresell-notResell", buy);
return;
}
if(sender.hasPermission("areashop.stopresellall")) {
buy.disableReselling();
buy.update();
plugin.message(sender, "stopresell-success", buy);
} else if(sender.hasPermission("areashop.stopresell") && sender instanceof Player) {
if(buy.isOwner((Player)sender)) {
buy.disableReselling();
buy.update();
plugin.message(sender, "stopresell-success", buy);
} else {
plugin.message(sender, "stopresell-noPermissionOther", buy);
}
} else {
plugin.message(sender, "stopresell-noPermission", buy);
}
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
ArrayList<String> result = new ArrayList<>();
if(toComplete == 2) {
for(BuyRegion region : plugin.getFileManager().getBuys()) {
if(region.isSold() && region.isInResellingMode()) {
result.add(region.getName());
}
}
}
return result;
}
}
@@ -0,0 +1,81 @@
package me.wiefferink.areashop.commands;
import me.wiefferink.areashop.regions.GeneralRegion;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.List;
public class TeleportCommand extends CommandAreaShop {
@Override
public String getCommandStart() {
return "areashop tp";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.teleportall") || target.hasPermission("areashop.teleport")) {
return "help-teleport";
}
return null;
}
/**
* Check if a person can teleport to the region (assuming he is not teleporting to a sign).
* @param person The person to check
* @param region The region to check for
* @return true if the person can teleport to it, otherwise false
*/
public static boolean canUse(CommandSender person, GeneralRegion region) {
if(!(person instanceof Player)) {
return false;
}
Player player = (Player)person;
return player.hasPermission("areashop.teleportall")
|| region.isOwner(player) && player.hasPermission("areashop.teleport")
|| region.isAvailable() && player.hasPermission("areashop.teleportavailable")
|| region.getFriendsFeature().getFriends().contains(player.getUniqueId()) && player.hasPermission("areashop.teleportfriend");
}
@Override
public void execute(CommandSender sender, String[] args) {
if(!sender.hasPermission("areashop.teleport") && !sender.hasPermission("areashop.teleportall") && !sender.hasPermission("areashop.teleportavailable") && !sender.hasPermission("areashop.teleportavailablesign") && !sender.hasPermission("areashop.teleportsign") && !sender.hasPermission("areashop.teleportsignall") && !sender.hasPermission("areashop.teleportfriend") && !sender.hasPermission("teleportfriendsign")) {
plugin.message(sender, "teleport-noPermission");
return;
}
if(!(sender instanceof Player)) {
plugin.message(sender, "cmd-onlyByPlayer");
return;
}
if(args.length <= 1 || args[1] == null) {
plugin.message(sender, "teleport-help");
return;
}
Player player = (Player)sender;
GeneralRegion region = plugin.getFileManager().getRegion(args[1]);
if(region == null) {
plugin.message(player, "teleport-noRentOrBuy", args[1]);
return;
}
if(args.length >= 3 && (args[2].equalsIgnoreCase("sign") || args[2].equalsIgnoreCase("yes") || args[2].equalsIgnoreCase("true"))) {
region.getTeleportFeature().teleportPlayer(player, true);
} else {
region.getTeleportFeature().teleportPlayer(player, false);
}
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
ArrayList<String> result = new ArrayList<>();
if(toComplete == 2) {
result.addAll(plugin.getFileManager().getRegionNames());
} else if(toComplete == 3) {
result.add("sign");
}
return result;
}
}
@@ -0,0 +1,102 @@
package me.wiefferink.areashop.commands;
import me.wiefferink.areashop.regions.GeneralRegion;
import me.wiefferink.areashop.regions.RentRegion;
import me.wiefferink.areashop.tools.Utils;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.List;
public class UnrentCommand extends CommandAreaShop {
@Override
public String getCommandStart() {
return "areashop unrent";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.unrent") || target.hasPermission("areashop.unrentown")) {
return "help-unrent";
}
return null;
}
/**
* Check if a person can unrent the region.
* @param person The person to check
* @param region The region to check for
* @return true if the person can unrent it, otherwise false
*/
public static boolean canUse(CommandSender person, GeneralRegion region) {
if(person.hasPermission("areashop.unrent")) {
return true;
}
if(person instanceof Player) {
Player player = (Player)person;
return region.isOwner(player) && person.hasPermission("areashop.unrentown");
}
return false;
}
@Override
public void execute(CommandSender sender, String[] args) {
if(!sender.hasPermission("areashop.unrent") && !sender.hasPermission("areashop.unrentown")) {
plugin.message(sender, "unrent-noPermission");
return;
}
RentRegion rent;
if(args.length <= 1) {
if(sender instanceof Player) {
// get the region by location
List<RentRegion> regions = Utils.getImportantRentRegions(((Player)sender).getLocation());
if(regions.isEmpty()) {
plugin.message(sender, "cmd-noRegionsAtLocation");
return;
} else if(regions.size() > 1) {
plugin.message(sender, "cmd-moreRegionsAtLocation");
return;
} else {
rent = regions.get(0);
}
} else {
plugin.message(sender, "cmd-automaticRegionOnlyByPlayer");
return;
}
} else {
rent = plugin.getFileManager().getRent(args[1]);
}
if(rent == null) {
plugin.message(sender, "unrent-notRegistered");
return;
}
if(!rent.isRented()) {
plugin.message(sender, "unrent-notRented", rent);
return;
}
rent.unRent(true, sender);
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
ArrayList<String> result = new ArrayList<>();
if(toComplete == 2) {
for(RentRegion region : plugin.getFileManager().getRents()) {
if(region.isRented()) {
result.add(region.getName());
}
}
}
return result;
}
}
@@ -0,0 +1,45 @@
package me.wiefferink.areashop.events;
public class CancellableRegionEvent<T> extends RegionEvent<T> {
private boolean cancelled;
private String reason;
public CancellableRegionEvent(T region) {
super(region);
}
/**
* Cancel the event from happening.
* @param reason The reason of cancelling, used for display to the user, should end with a dot
*/
public void cancel(String reason) {
this.cancelled = true;
this.reason = reason;
}
/**
* Let the event continue, possible overwriting a cancel() call from another plugin.
*/
public void allow() {
this.cancelled = false;
this.reason = null;
}
/**
* Check if the event has been cancelled.
* @return true if the event has been cancelled, otherwise false
*/
public boolean isCancelled() {
return cancelled;
}
/**
* Get the reason why this event is cancelled.
* @return null if there is no reason or the event is not cancelled, otherwise a string
*/
public String getReason() {
return reason;
}
}
@@ -0,0 +1,7 @@
package me.wiefferink.areashop.events;
public class NotifyRegionEvent<T> extends RegionEvent<T> {
public NotifyRegionEvent(T region) {
super(region);
}
}
@@ -0,0 +1,7 @@
# Events
This package contains event classes that allow other plugins to listen to events about AreaShop regions.
* `RegionEvent` class represents a generic event.
* `CancellableRegionEvent` represents an event that has a region and can be cancelled.
* `NotifyRegionEvent` represents events that are to inform only, and cannot be cancelled anymore (an `CancellableRegionEvent` would be sent first).
@@ -0,0 +1,30 @@
package me.wiefferink.areashop.events;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
public class RegionEvent<T> extends Event {
protected T region;
private static final HandlerList handlers = new HandlerList();
public RegionEvent(T region) {
this.region = region;
}
@Override
public HandlerList getHandlers() {
return handlers;
}
public static HandlerList getHandlerList() {
return handlers;
}
/**
* Get the region of this event.
* @return The region the event is about
*/
public T getRegion() {
return region;
}
}
@@ -0,0 +1,31 @@
package me.wiefferink.areashop.events.ask;
import me.wiefferink.areashop.events.CancellableRegionEvent;
import me.wiefferink.areashop.regions.BuyRegion;
import org.bukkit.OfflinePlayer;
/**
* Broadcasted when a player tries to buy a region.
*/
public class BuyingRegionEvent extends CancellableRegionEvent<BuyRegion> {
private final OfflinePlayer player;
/**
* Constructor.
* @param region The region that is about to get bought
* @param player The player that tries to buy the region
*/
public BuyingRegionEvent(BuyRegion region, OfflinePlayer player) {
super(region);
this.player = player;
}
/**
* Get the player that is trying to buy the region.
* @return The player that is trying to buy the region
*/
public OfflinePlayer getPlayer() {
return player;
}
}
@@ -0,0 +1,42 @@
package me.wiefferink.areashop.events.ask;
import me.wiefferink.areashop.events.CancellableRegionEvent;
import me.wiefferink.areashop.regions.RentRegion;
import org.bukkit.OfflinePlayer;
/**
* Broadcasted when a player tries to rent a region.
*/
public class RentingRegionEvent extends CancellableRegionEvent<RentRegion> {
private final OfflinePlayer player;
private final boolean extending;
/**
* Constructor.
* @param region The region that is about to be rented
* @param player The player that tries to rent the region
* @param extending true if the player is extending the rental of the region, otherwise false
*/
public RentingRegionEvent(RentRegion region, OfflinePlayer player, boolean extending) {
super(region);
this.player = player;
this.extending = extending;
}
/**
* Get the player that is trying to rent the region.
* @return The player that is trying to rent the region
*/
public OfflinePlayer getPlayer() {
return player;
}
/**
* Check if the player is extending the region or renting it for the first time.
* @return true if the player tries to extend the region, false if he tries to rent it the first time
*/
public boolean isExtending() {
return extending;
}
}
@@ -0,0 +1,31 @@
package me.wiefferink.areashop.events.ask;
import me.wiefferink.areashop.events.CancellableRegionEvent;
import me.wiefferink.areashop.regions.BuyRegion;
import org.bukkit.OfflinePlayer;
/**
* Broadcasted when a player tries to resell a region.
*/
public class ResellingRegionEvent extends CancellableRegionEvent<BuyRegion> {
private final OfflinePlayer player;
/**
* Contructor.
* @param region The region that the player is trying to resell
* @param player The player that is trying to buy this region from the current owner
*/
public ResellingRegionEvent(BuyRegion region, OfflinePlayer player) {
super(region);
this.player = player;
}
/**
* Get the player that is trying to buy the region.
* @return The player that is trying to buy the region
*/
public OfflinePlayer getBuyer() {
return player;
}
}
@@ -0,0 +1,18 @@
package me.wiefferink.areashop.events.ask;
import me.wiefferink.areashop.events.CancellableRegionEvent;
import me.wiefferink.areashop.regions.BuyRegion;
/**
* Broadcasted when a region is about to get sold.
*/
public class SellingRegionEvent extends CancellableRegionEvent<BuyRegion> {
/**
* Constructor.
* @param region The region that is about to get sold
*/
public SellingRegionEvent(BuyRegion region) {
super(region);
}
}
@@ -0,0 +1,18 @@
package me.wiefferink.areashop.events.ask;
import me.wiefferink.areashop.events.CancellableRegionEvent;
import me.wiefferink.areashop.regions.RentRegion;
/**
* Broadcasted when a region is about to be unrented.
*/
public class UnrentingRegionEvent extends CancellableRegionEvent<RentRegion> {
/**
* Constructor.
* @param region The region that is about to be unrented
*/
public UnrentingRegionEvent(RentRegion region) {
super(region);
}
}
@@ -0,0 +1,43 @@
package me.wiefferink.areashop.events.askandnotify;
import me.wiefferink.areashop.events.CancellableRegionEvent;
import me.wiefferink.areashop.regions.GeneralRegion;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.CommandSender;
/**
* Broadcasted when a friend is being added to a region.
*/
public class AddedFriendEvent extends CancellableRegionEvent<GeneralRegion> {
private final OfflinePlayer friend;
private final CommandSender by;
/**
* Constructor.
* @param region The region the friend is getting added to
* @param friend The friend that is about to be added
* @param by The CommandSender that is adding the friend, or null if none
*/
public AddedFriendEvent(GeneralRegion region, OfflinePlayer friend, CommandSender by) {
super(region);
this.friend = friend;
this.by = by;
}
/**
* Get the OfflinePlayer that is getting added as friend.
* @return The friend that is getting added
*/
public OfflinePlayer getFriend() {
return friend;
}
/**
* Get the CommandSender that is adding the friend.
* @return null if none, a CommandSender if done by someone (likely Player or ConsoleCommandSender)
*/
public CommandSender getBy() {
return by;
}
}
@@ -0,0 +1,43 @@
package me.wiefferink.areashop.events.askandnotify;
import me.wiefferink.areashop.events.CancellableRegionEvent;
import me.wiefferink.areashop.regions.GeneralRegion;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.CommandSender;
/**
* Broadcasted when a friend is being added to a region.
*/
public class DeletedFriendEvent extends CancellableRegionEvent<GeneralRegion> {
private final OfflinePlayer friend;
private final CommandSender by;
/**
* Constructor.
* @param region The region the friend is getting added to
* @param friend The friend that is about to be added
* @param by The CommandSender that is adding the friend, or null if none
*/
public DeletedFriendEvent(GeneralRegion region, OfflinePlayer friend, CommandSender by) {
super(region);
this.friend = friend;
this.by = by;
}
/**
* Get the OfflinePlayer that is getting added as friend.
* @return The friend that is getting added
*/
public OfflinePlayer getFriend() {
return friend;
}
/**
* Get the CommandSender that is adding the friend.
* @return null if none, a CommandSender if done by someone (likely Player or ConsoleCommandSender)
*/
public CommandSender getBy() {
return by;
}
}
@@ -0,0 +1,19 @@
package me.wiefferink.areashop.events.notify;
import me.wiefferink.areashop.events.NotifyRegionEvent;
import me.wiefferink.areashop.regions.GeneralRegion;
/**
* Broadcasted when a region has been added to AreaShop.
*/
public class AddedRegionEvent extends NotifyRegionEvent<GeneralRegion> {
/**
* Constructor.
* @param region The region that has been added
*/
public AddedRegionEvent(GeneralRegion region) {
super(region);
}
}
@@ -0,0 +1,19 @@
package me.wiefferink.areashop.events.notify;
import me.wiefferink.areashop.events.NotifyRegionEvent;
import me.wiefferink.areashop.regions.BuyRegion;
/**
* Broadcasted when a region has been bought.
*/
public class BoughtRegionEvent extends NotifyRegionEvent<BuyRegion> {
/**
* Constructor.
* @param region The region that has been bought
*/
public BoughtRegionEvent(BuyRegion region) {
super(region);
}
}
@@ -0,0 +1,18 @@
package me.wiefferink.areashop.events.notify;
import me.wiefferink.areashop.events.NotifyRegionEvent;
import me.wiefferink.areashop.regions.GeneralRegion;
/**
* Broadcasted when a region has been removed from AreaShop.
*/
public class DeletedRegionEvent extends NotifyRegionEvent<GeneralRegion> {
/**
* Constructor.
* @param region The region that has been removed
*/
public DeletedRegionEvent(GeneralRegion region) {
super(region);
}
}
@@ -0,0 +1,31 @@
package me.wiefferink.areashop.events.notify;
import me.wiefferink.areashop.events.NotifyRegionEvent;
import me.wiefferink.areashop.regions.RentRegion;
/**
* Broadcasted when a region has been rented.
*/
public class RentedRegionEvent extends NotifyRegionEvent<RentRegion> {
private final boolean extended;
/**
* Constructor.
* @param region The region that has been rented
* @param extended true if the region has been extended, false if this is the first time buying the region
*/
public RentedRegionEvent(RentRegion region, boolean extended) {
super(region);
this.region = region;
this.extended = extended;
}
/**
* Check if the region was extended or rented for the first time.
* @return true if the region was extended, false when rented for the first time
*/
public boolean hasExtended() {
return extended;
}
}
@@ -0,0 +1,32 @@
package me.wiefferink.areashop.events.notify;
import me.wiefferink.areashop.events.NotifyRegionEvent;
import me.wiefferink.areashop.regions.BuyRegion;
import java.util.UUID;
/**
* Broadcasted when a region has been resold.
*/
public class ResoldRegionEvent extends NotifyRegionEvent<BuyRegion> {
private final UUID from;
/**
* Constructor.
* @param region The region that has been resold
* @param from The player from who the region has been resold to the current owner
*/
public ResoldRegionEvent(BuyRegion region, UUID from) {
super(region);
this.from = from;
}
/**
* Get the player that the region has been bought from.
* @return The UUID of the player that the region has been bought from
*/
public UUID getFromPlayer() {
return from;
}
}
@@ -0,0 +1,43 @@
package me.wiefferink.areashop.events.notify;
import me.wiefferink.areashop.events.NotifyRegionEvent;
import me.wiefferink.areashop.regions.BuyRegion;
import java.util.UUID;
/**
* Broadcasted when a region is sold.
*/
public class SoldRegionEvent extends NotifyRegionEvent<BuyRegion> {
private final UUID oldBuyer;
private final double refundedMoney;
/**
* Constructor.
* @param region The region that has been sold
* @param oldBuyer The player for which the region has been sold
* @param refundedMoney The amount of money that has been refunded
*/
public SoldRegionEvent(BuyRegion region, UUID oldBuyer, double refundedMoney) {
super(region);
this.oldBuyer = oldBuyer;
this.refundedMoney = refundedMoney;
}
/**
* Get the player that the region is sold for.
* @return The UUID of the player that the region is sold for
*/
public UUID getOldBuyer() {
return oldBuyer;
}
/**
* Get the amount that is paid back to the player.
* @return The amount of money paid back to the player
*/
public double getRefundedMoney() {
return refundedMoney;
}
}
@@ -0,0 +1,43 @@
package me.wiefferink.areashop.events.notify;
import me.wiefferink.areashop.events.NotifyRegionEvent;
import me.wiefferink.areashop.regions.RentRegion;
import java.util.UUID;
/**
* Broadcasted when a region has been unrented.
*/
public class UnrentedRegionEvent extends NotifyRegionEvent<RentRegion> {
private final UUID oldRenter;
private final double refundedMoney;
/**
* Constructor.
* @param region The region that has been unrented
* @param oldRenter The player that rented the region before it was unrented
* @param refundedMoney The amount of money that has been refunded
*/
public UnrentedRegionEvent(RentRegion region, UUID oldRenter, double refundedMoney) {
super(region);
this.oldRenter = oldRenter;
this.refundedMoney = refundedMoney;
}
/**
* Get the player that the region was unrented for.
* @return The UUID of the player that the region was unrented for
*/
public UUID getOldRenter() {
return oldRenter;
}
/**
* Get the amount that is paid back to the player.
* @return The amount of money paid back to the player
*/
public double getRefundedMoney() {
return refundedMoney;
}
}
@@ -0,0 +1,19 @@
package me.wiefferink.areashop.events.notify;
import me.wiefferink.areashop.events.NotifyRegionEvent;
import me.wiefferink.areashop.regions.GeneralRegion;
/**
* Broadcasted when the data of a region changes.
* Should be used for updating displays that use region data.
*/
public class UpdateRegionEvent extends NotifyRegionEvent<GeneralRegion> {
/**
* Contructor.
* @param region The region that has been updated
*/
public UpdateRegionEvent(GeneralRegion region) {
super(region);
}
}
@@ -0,0 +1,98 @@
package me.wiefferink.areashop.features;
import me.wiefferink.areashop.AreaShop;
import me.wiefferink.areashop.events.ask.BuyingRegionEvent;
import me.wiefferink.areashop.events.ask.RentingRegionEvent;
import me.wiefferink.areashop.events.ask.ResellingRegionEvent;
import me.wiefferink.areashop.events.ask.SellingRegionEvent;
import me.wiefferink.areashop.events.ask.UnrentingRegionEvent;
import me.wiefferink.areashop.events.askandnotify.AddedFriendEvent;
import me.wiefferink.areashop.events.askandnotify.DeletedFriendEvent;
import me.wiefferink.areashop.events.notify.AddedRegionEvent;
import me.wiefferink.areashop.events.notify.BoughtRegionEvent;
import me.wiefferink.areashop.events.notify.DeletedRegionEvent;
import me.wiefferink.areashop.events.notify.RentedRegionEvent;
import me.wiefferink.areashop.events.notify.ResoldRegionEvent;
import me.wiefferink.areashop.events.notify.SoldRegionEvent;
import me.wiefferink.areashop.events.notify.UnrentedRegionEvent;
import me.wiefferink.areashop.events.notify.UpdateRegionEvent;
import me.wiefferink.areashop.tools.Utils;
import org.bukkit.event.EventHandler;
public class DebugFeature extends RegionFeature {
@EventHandler
public void buyingRegion(BuyingRegionEvent event) {
AreaShop.debug("BuyingRegionEvent: " + event.getPlayer().getName() + " is trying to buy " + event.getRegion().getName());
}
@EventHandler
public void boughtRegion(BoughtRegionEvent event) {
AreaShop.debug("BoughtRegionEvent: " + event.getRegion().getPlayerName() + " bought " + event.getRegion().getName());
}
@EventHandler
public void sellingRegion(SellingRegionEvent event) {
AreaShop.debug("SellingRegionEvent: " + event.getRegion().getName() + " is trying to sell " + event.getRegion().getName());
}
@EventHandler
public void soldRegion(SoldRegionEvent event) {
AreaShop.debug("SoldRegionEvent: " + Utils.toName(event.getOldBuyer()) + " sold " + event.getRegion().getName());
}
@EventHandler
public void resellingRegion(ResellingRegionEvent event) {
AreaShop.debug("ResellingRegionEvent: " + event.getRegion().getName() + " is trying to resell " + event.getRegion().getName());
}
@EventHandler
public void resoldRegion(ResoldRegionEvent event) {
AreaShop.debug("ResoldRegionEvent: " + Utils.toName(event.getFromPlayer()) + " resold " + event.getRegion().getName() + " to " + event.getRegion().getPlayerName());
}
@EventHandler
public void rentingRegion(RentingRegionEvent event) {
AreaShop.debug("RentingRegionEvent: " + event.getPlayer().getName() + " is trying to rent " + event.getRegion().getName() + ", extending=" + event.isExtending());
}
@EventHandler
public void rentedRegion(RentedRegionEvent event) {
AreaShop.debug("RentedRegionEvent: " + event.getRegion().getPlayerName() + " rented " + event.getRegion().getName() + ", extending=" + event.hasExtended());
}
@EventHandler
public void unrentingRegion(UnrentingRegionEvent event) {
AreaShop.debug("UnrentingRegionEvent: " + event.getRegion().getPlayerName() + " is trying to unrent " + event.getRegion().getName());
}
@EventHandler
public void unrentedRegion(UnrentedRegionEvent event) {
AreaShop.debug("UnrentedRegionEvent: " + Utils.toName(event.getOldRenter()) + " unrented " + event.getRegion().getName());
}
@EventHandler
public void regionUpdate(UpdateRegionEvent event) {
//AreaShop.debug("UpdateRegionEvent: " + event.getRegion().getName() + " updated");
}
@EventHandler
public void addedRegion(AddedRegionEvent event) {
AreaShop.debug("AddedRegionEvent: " + event.getRegion().getName());
}
@EventHandler
public void removedRegion(DeletedRegionEvent event) {
AreaShop.debug("DeletedRegionEvent: " + event.getRegion().getName());
}
@EventHandler
public void addedFriend(AddedFriendEvent event) {
AreaShop.debug("AddedFriendEvent: region " + event.getRegion().getName() + ", " + event.getFriend().getName() + " by " + (event.getBy() == null ? "<nobody>" : event.getBy().getName()));
}
@EventHandler
public void deleteFriend(DeletedFriendEvent event) {
AreaShop.debug("DeletedFriendEvent: region " + event.getRegion().getName() + ", " + event.getFriend().getName() + " by " + (event.getBy() == null ? "<nobody>" : event.getBy().getName()));
}
}
@@ -0,0 +1,109 @@
package me.wiefferink.areashop.features;
import me.wiefferink.areashop.events.askandnotify.AddedFriendEvent;
import me.wiefferink.areashop.events.askandnotify.DeletedFriendEvent;
import me.wiefferink.areashop.regions.GeneralRegion;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.CommandSender;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
public class FriendsFeature extends RegionFeature {
public FriendsFeature(GeneralRegion region) {
setRegion(region);
}
/**
* Add a friend to the region.
* @param player The UUID of the player to add
* @param by The CommandSender that is adding the friend, or null
* @return true if the friend has been added, false if adding a friend was cancelled by another plugin
*/
public boolean addFriend(UUID player, CommandSender by) {
// Fire and check event
AddedFriendEvent event = new AddedFriendEvent(getRegion(), Bukkit.getOfflinePlayer(player), by);
Bukkit.getPluginManager().callEvent(event);
if(event.isCancelled()) {
plugin.message(by, "general-cancelled", event.getReason(), this);
return false;
}
Set<String> friends = new HashSet<>(getRegion().getConfig().getStringList("general.friends"));
friends.add(player.toString());
List<String> list = new ArrayList<>(friends);
getRegion().setSetting("general.friends", list);
return true;
}
/**
* Delete a friend from the region.
* @param player The UUID of the player to delete
* @param by The CommandSender that is adding the friend, or null
* @return true if the friend has been added, false if adding a friend was cancelled by another plugin
*/
public boolean deleteFriend(UUID player, CommandSender by) {
// Fire and check event
DeletedFriendEvent event = new DeletedFriendEvent(getRegion(), Bukkit.getOfflinePlayer(player), by);
Bukkit.getPluginManager().callEvent(event);
if(event.isCancelled()) {
plugin.message(by, "general-cancelled", event.getReason(), this);
return false;
}
Set<String> friends = new HashSet<>(getRegion().getConfig().getStringList("general.friends"));
friends.remove(player.toString());
List<String> list = new ArrayList<>(friends);
if(list.isEmpty()) {
getRegion().setSetting("general.friends", null);
} else {
getRegion().setSetting("general.friends", list);
}
return true;
}
/**
* Get the list of friends added to this region.
* @return Friends added to this region
*/
public Set<UUID> getFriends() {
HashSet<UUID> result = new HashSet<>();
for(String friend : getRegion().getConfig().getStringList("general.friends")) {
try {
UUID id = UUID.fromString(friend);
result.add(id);
} catch(IllegalArgumentException e) {
// Don't add it
}
}
return result;
}
/**
* Get the list of friends added to this region.
* @return Friends added to this region
*/
public Set<String> getFriendNames() {
HashSet<String> result = new HashSet<>();
for(UUID friend : getFriends()) {
OfflinePlayer player = Bukkit.getOfflinePlayer(friend);
if(player != null && player.getName() != null) {
result.add(player.getName());
}
}
return result;
}
/**
* Remove all friends that are added to this region.
*/
public void clearFriends() {
getRegion().setSetting("general.friends", null);
}
}
@@ -0,0 +1,6 @@
# Features
This package contains classes that represent a certain feature and implement it for all regions.
* `RegionFeature` represents a single feature, for each implementing class one instance is created without an assigned region, to listen for events etc, and an instance per region is created on-demand to handle region specific things.
* More features will be moved from `GeneralRegion` to these kind of classes, to keep all code for a feature together and cleanup `GeneralRegion`.
@@ -0,0 +1,52 @@
package me.wiefferink.areashop.features;
import me.wiefferink.areashop.AreaShop;
import me.wiefferink.areashop.regions.GeneralRegion;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
public abstract class RegionFeature implements Listener {
public static final AreaShop plugin = AreaShop.getInstance();
public YamlConfiguration config = plugin.getConfig();
private GeneralRegion region;
/**
* Set the region for this feature.
* @param region Feature region
*/
public void setRegion(GeneralRegion region) {
this.region = region;
}
/**
* Get the region of this feature.
* @return region of this feature, or null if generic
*/
public GeneralRegion getRegion() {
return region;
}
/**
* Start listening to events.
*/
public void listen() {
plugin.getServer().getPluginManager().registerEvents(this, plugin);
}
/**
* Destroy the feature and deregister everything.
*/
public void shutdownFeature() {
HandlerList.unregisterAll(this);
shutdown();
}
/**
* Dummy method a RegionFeature implementation can override.
*/
public void shutdown() {
}
}
@@ -0,0 +1,520 @@
package me.wiefferink.areashop.features;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import me.wiefferink.areashop.AreaShop;
import me.wiefferink.areashop.features.signs.RegionSign;
import me.wiefferink.areashop.regions.GeneralRegion;
import me.wiefferink.areashop.tools.Utils;
import me.wiefferink.areashop.tools.Value;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.entity.Player;
import org.bukkit.util.Vector;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class TeleportFeature extends RegionFeature {
private static final ArrayList<Material> canSpawnIn = new ArrayList<>(Arrays.asList(Material.WOOD_DOOR, Material.WOODEN_DOOR, Material.SIGN_POST, Material.WALL_SIGN, Material.STONE_PLATE, Material.IRON_DOOR_BLOCK, Material.WOOD_PLATE, Material.TRAP_DOOR, Material.REDSTONE_LAMP_OFF, Material.REDSTONE_LAMP_ON, Material.DRAGON_EGG, Material.GOLD_PLATE, Material.IRON_PLATE));
private static final ArrayList<Material> cannotSpawnOn = new ArrayList<>(Arrays.asList(Material.PISTON_EXTENSION, Material.PISTON_MOVING_PIECE, Material.SIGN_POST, Material.WALL_SIGN, Material.STONE_PLATE, Material.IRON_DOOR_BLOCK, Material.WOOD_PLATE, Material.TRAP_DOOR, Material.REDSTONE_LAMP_OFF, Material.REDSTONE_LAMP_ON, Material.CACTUS, Material.IRON_FENCE, Material.FENCE_GATE, Material.THIN_GLASS, Material.NETHER_FENCE, Material.DRAGON_EGG, Material.GOLD_PLATE, Material.IRON_PLATE, Material.STAINED_GLASS_PANE));
private static final ArrayList<Material> cannotSpawnBeside = new ArrayList<>(Arrays.asList(Material.LAVA, Material.STATIONARY_LAVA, Material.CACTUS));
public TeleportFeature() {
}
public TeleportFeature(GeneralRegion region) {
setRegion(region);
}
/**
* Get the teleportlocation set for this region.
* @return The teleport location, or null if not set
*/
public Location getTeleportLocation() {
return Utils.configToLocation(getRegion().getConfigurationSectionSetting("general.teleportLocation"));
}
/**
* Check if the region has a teleportLocation specified.
* @return true if the region has a teleportlocation, false otherwise
*/
public boolean hasTeleportLocation() {
return getRegion().getConfigurationSectionSetting("general.teleportLocation") != null;
}
/**
* Set the teleport location of this region.
* @param location The location to set as teleport location
*/
public void setTeleport(Location location) {
if(location == null) {
getRegion().setSetting("general.teleportLocation", null);
} else {
getRegion().setSetting("general.teleportLocation", Utils.locationToConfig(location, true));
}
}
/**
* Teleport a player to the region or sign.
* @param player Player that should be teleported
* @param toSign true to teleport to the first sign of the region, false for teleporting to the region itself
* @param checkRestrictions Set to true if teleport permissions should be checked, false otherwise, also toggles cross-world check
* @return true if the teleport succeeded, otherwise false
*/
public boolean teleportPlayer(Player player, boolean toSign, boolean checkRestrictions) {
// Check basics
if(getRegion().getWorld() == null) {
getRegion().message(player, "general-noWorld");
return false;
}
if(getRegion().getRegion() == null) {
getRegion().message(player, "general-noRegion");
return false;
}
if(checkRestrictions) {
// Check correct world
if(!getRegion().getBooleanSetting("general.teleportCrossWorld") && !player.getWorld().equals(getRegion().getWorld())) {
getRegion().message(player, "teleport-wrongWorld", player.getWorld().getName());
return false;
}
boolean owner = player.getUniqueId().equals(getRegion().getOwner());
boolean friend = getRegion().getFriendsFeature().getFriends().contains(player.getUniqueId());
boolean available = getRegion().isAvailable();
// Teleport to sign instead if they dont have permission for teleporting to region
if((!toSign && owner && !player.hasPermission("areashop.teleport") && player.hasPermission("areashop.teleportsign")
|| !toSign && !owner && !friend && !player.hasPermission("areashop.teleportall") && player.hasPermission("areashop.teleportsignall")
|| !toSign && !owner && friend && !player.hasPermission("areashop.teleportfriend") && player.hasPermission("areashop.teleportfriendsign")
|| !toSign && !owner && !friend && available && !player.hasPermission("areashop.teleportavailable") && player.hasPermission("areashop.teleportavailablesign"))) {
getRegion().message(player, "teleport-changedToSign");
toSign = true;
}
// Check permissions
if(owner && !available && !player.hasPermission("areashop.teleport") && !toSign) {
getRegion().message(player, "teleport-noPermission");
return false;
} else if(!owner && !available && !player.hasPermission("areashop.teleportall") && !toSign && !friend) {
getRegion().message(player, "teleport-noPermissionOther");
return false;
} else if(!owner && !available && !player.hasPermission("areashop.teleportfriend") && !toSign && friend) {
getRegion().message(player, "teleport-noPermissionFriend");
return false;
} else if(available && !player.hasPermission("areashop.teleportavailable") && !toSign) {
getRegion().message(player, "teleport-noPermissionAvailable");
return false;
} else if(owner && !available && !player.hasPermission("areashop.teleportsign") && toSign) {
getRegion().message(player, "teleport-noPermissionSign");
return false;
} else if(!owner && !available && !player.hasPermission("areashop.teleportsignall") && toSign && !friend) {
getRegion().message(player, "teleport-noPermissionOtherSign");
return false;
} else if(!owner && !available && !player.hasPermission("areashop.teleportfriendsign") && toSign && friend) {
getRegion().message(player, "teleport-noPermissionFriendSign");
return false;
} else if(available && !player.hasPermission("areashop.teleportavailablesign") && toSign) {
getRegion().message(player, "teleport-noPermissionAvailableSign");
return false;
}
}
// Get the starting location
Value<Boolean> toSignRef = new Value<>(toSign);
Location startLocation = getStartLocation(player, toSignRef);
toSign = toSignRef.get();
boolean insideRegion;
if(toSign) {
insideRegion = getRegion().getBooleanSetting("general.teleportToSignIntoRegion");
} else {
insideRegion = getRegion().getBooleanSetting("general.teleportIntoRegion");
}
// Check locations starting from startLocation and then a cube that increases
// radius around that (until no block in the region is found at all cube sides)
Location safeLocation = startLocation;
ProtectedRegion worldguardRegion = getRegion().getRegion();
boolean blocksInRegion = worldguardRegion.contains(startLocation.getBlockX(), startLocation.getBlockY(), startLocation.getBlockZ());
if(!blocksInRegion && insideRegion) {
getRegion().message(player, "teleport-blocked");
return false;
}
// Tries limit tracking
int radius = 1;
int checked = 1;
int maxTries = plugin.getConfig().getInt("maximumTries");
// Tracking of which sides to continue the search
boolean done = isSafe(safeLocation) && (blocksInRegion || !insideRegion);
boolean northDone = false, eastDone = false, southDone = false, westDone = false, topDone = false, bottomDone = false;
boolean continueThisDirection;
while((blocksInRegion || !insideRegion) && !done) {
blocksInRegion = false;
// North side
continueThisDirection = false;
for(int x = -radius + 1; x <= radius && !done && !northDone; x++) {
for(int y = -radius + 1; y < radius && !done; y++) {
safeLocation = startLocation.clone().add(x, y, -radius);
if(safeLocation.getBlockY() > 256 || safeLocation.getBlockY() < 0) {
continue;
}
if(worldguardRegion.contains(safeLocation.getBlockX(), safeLocation.getBlockY(), safeLocation.getBlockZ()) || !insideRegion) {
checked++;
done = isSafe(safeLocation) || checked > maxTries;
blocksInRegion = true;
continueThisDirection = true;
}
}
}
northDone = northDone || !continueThisDirection;
// East side
continueThisDirection = false;
for(int z = -radius + 1; z <= radius && !done && !eastDone; z++) {
for(int y = -radius + 1; y < radius && !done; y++) {
safeLocation = startLocation.clone().add(radius, y, z);
if(safeLocation.getBlockY() > 256 || safeLocation.getBlockY() < 0) {
continue;
}
if(worldguardRegion.contains(safeLocation.getBlockX(), safeLocation.getBlockY(), safeLocation.getBlockZ()) || !insideRegion) {
checked++;
done = isSafe(safeLocation) || checked > maxTries;
blocksInRegion = true;
continueThisDirection = true;
}
}
}
eastDone = eastDone || !continueThisDirection;
// South side
continueThisDirection = false;
for(int x = radius - 1; x >= -radius && !done && !southDone; x--) {
for(int y = -radius + 1; y < radius && !done; y++) {
safeLocation = startLocation.clone().add(x, y, radius);
if(safeLocation.getBlockY() > 256 || safeLocation.getBlockY() < 0) {
continue;
}
if(worldguardRegion.contains(safeLocation.getBlockX(), safeLocation.getBlockY(), safeLocation.getBlockZ()) || !insideRegion) {
checked++;
done = isSafe(safeLocation) || checked > maxTries;
blocksInRegion = true;
continueThisDirection = true;
}
}
}
southDone = southDone || !continueThisDirection;
// West side
continueThisDirection = false;
for(int z = radius - 1; z >= -radius && !done && !westDone; z--) {
for(int y = -radius + 1; y < radius && !done; y++) {
safeLocation = startLocation.clone().add(-radius, y, z);
if(safeLocation.getBlockY() > 256 || safeLocation.getBlockY() < 0) {
continue;
}
if(worldguardRegion.contains(safeLocation.getBlockX(), safeLocation.getBlockY(), safeLocation.getBlockZ()) || !insideRegion) {
checked++;
done = isSafe(safeLocation) || checked > maxTries;
blocksInRegion = true;
continueThisDirection = true;
}
}
}
westDone = westDone || !continueThisDirection;
// Top side
continueThisDirection = false;
// Middle block of the top
if((startLocation.getBlockY() + radius) > 256) {
topDone = true;
}
if(!done && !topDone) {
safeLocation = startLocation.clone().add(0, radius, 0);
if(worldguardRegion.contains(safeLocation.getBlockX(), safeLocation.getBlockY(), safeLocation.getBlockZ()) || !insideRegion) {
checked++;
done = isSafe(safeLocation) || checked > maxTries;
blocksInRegion = true;
continueThisDirection = true;
}
}
for(int r = 1; r <= radius && !done && !topDone; r++) {
// North
for(int x = -r + 1; x <= r && !done; x++) {
safeLocation = startLocation.clone().add(x, radius, -r);
if(worldguardRegion.contains(safeLocation.getBlockX(), safeLocation.getBlockY(), safeLocation.getBlockZ()) || !insideRegion) {
checked++;
done = isSafe(safeLocation) || checked > maxTries;
blocksInRegion = true;
continueThisDirection = true;
}
}
// East
for(int z = -r + 1; z <= r && !done; z++) {
safeLocation = startLocation.clone().add(r, radius, z);
if(worldguardRegion.contains(safeLocation.getBlockX(), safeLocation.getBlockY(), safeLocation.getBlockZ()) || !insideRegion) {
checked++;
done = isSafe(safeLocation) || checked > maxTries;
blocksInRegion = true;
continueThisDirection = true;
}
}
// South side
for(int x = r - 1; x >= -r && !done; x--) {
safeLocation = startLocation.clone().add(x, radius, r);
if(worldguardRegion.contains(safeLocation.getBlockX(), safeLocation.getBlockY(), safeLocation.getBlockZ()) || !insideRegion) {
checked++;
done = isSafe(safeLocation) || checked > maxTries;
blocksInRegion = true;
continueThisDirection = true;
}
}
// West side
for(int z = r - 1; z >= -r && !done; z--) {
safeLocation = startLocation.clone().add(-r, radius, z);
if(worldguardRegion.contains(safeLocation.getBlockX(), safeLocation.getBlockY(), safeLocation.getBlockZ()) || !insideRegion) {
checked++;
done = isSafe(safeLocation) || checked > maxTries;
blocksInRegion = true;
continueThisDirection = true;
}
}
}
topDone = topDone || !continueThisDirection;
// Bottom side
continueThisDirection = false;
// Middle block of the bottom
if(startLocation.getBlockY() - radius < 0) {
bottomDone = true;
}
if(!done && !bottomDone) {
safeLocation = startLocation.clone().add(0, -radius, 0);
if(worldguardRegion.contains(safeLocation.getBlockX(), safeLocation.getBlockY(), safeLocation.getBlockZ()) || !insideRegion) {
checked++;
done = isSafe(safeLocation) || checked > maxTries;
blocksInRegion = true;
continueThisDirection = true;
}
}
for(int r = 1; r <= radius && !done && !bottomDone; r++) {
// North
for(int x = -r + 1; x <= r && !done; x++) {
safeLocation = startLocation.clone().add(x, -radius, -r);
if(worldguardRegion.contains(safeLocation.getBlockX(), safeLocation.getBlockY(), safeLocation.getBlockZ()) || !insideRegion) {
checked++;
done = isSafe(safeLocation) || checked > maxTries;
blocksInRegion = true;
continueThisDirection = true;
}
}
// East
for(int z = -r + 1; z <= r && !done; z++) {
safeLocation = startLocation.clone().add(r, -radius, z);
if(worldguardRegion.contains(safeLocation.getBlockX(), safeLocation.getBlockY(), safeLocation.getBlockZ()) || !insideRegion) {
checked++;
done = isSafe(safeLocation) || checked > maxTries;
blocksInRegion = true;
continueThisDirection = true;
}
}
// South side
for(int x = r - 1; x >= -r && !done; x--) {
safeLocation = startLocation.clone().add(x, -radius, r);
if(worldguardRegion.contains(safeLocation.getBlockX(), safeLocation.getBlockY(), safeLocation.getBlockZ()) || !insideRegion) {
checked++;
done = isSafe(safeLocation) || checked > maxTries;
blocksInRegion = true;
continueThisDirection = true;
}
}
// West side
for(int z = r - 1; z >= -r && !done; z--) {
safeLocation = startLocation.clone().add(-r, -radius, z);
if(worldguardRegion.contains(safeLocation.getBlockX(), safeLocation.getBlockY(), safeLocation.getBlockZ()) || !insideRegion) {
checked++;
done = isSafe(safeLocation) || checked > maxTries;
blocksInRegion = true;
continueThisDirection = true;
}
}
}
bottomDone = bottomDone || !continueThisDirection;
// Increase cube radius
radius++;
}
if(done && isSafe(safeLocation)) {
if(toSign) {
getRegion().message(player, "teleport-successSign");
// Let the player look at the sign
Vector playerVector = safeLocation.toVector();
playerVector.setY(playerVector.getY() + player.getEyeHeight(true));
Vector signVector = getRegion().getSignsFeature().getSigns().get(0).getLocation().toVector().add(new Vector(0.5, 0.5, 0.5));
Vector direction = playerVector.clone().subtract(signVector).normalize();
safeLocation.setYaw(180 - (float)Math.toDegrees(Math.atan2(direction.getX(), direction.getZ())));
safeLocation.setPitch(90 - (float)Math.toDegrees(Math.acos(direction.getY())));
} else {
getRegion().message(player, "teleport-success");
}
player.teleport(safeLocation);
AreaShop.debug("Found location: " + safeLocation.toString() + " Tries: " + (checked - 1));
return true;
} else {
getRegion().message(player, "teleport-noSafe", checked - 1, maxTries);
AreaShop.debug("No location found, checked " + (checked - 1) + " spots of max " + maxTries);
return false;
}
}
/**
* Teleport a player to the region or sign when he has permissions for it.
* @param player Player that should be teleported
* @param toSign true to teleport to the first sign of the region, false for teleporting to the region itself
* @return true if the teleport succeeded, otherwise false
*/
public boolean teleportPlayer(Player player, boolean toSign) {
return teleportPlayer(player, toSign, true);
}
/**
* Teleport a player to the region when he has permissions for it.
* @param player Player that should be teleported
* @return true if the teleport succeeded, otherwise false
*/
public boolean teleportPlayer(Player player) {
return teleportPlayer(player, false, true);
}
/**
* Checks if a certain location is safe to teleport to.
* @param location The location to check
* @return true if it is safe, otherwise false
*/
private boolean isSafe(Location location) {
Block feet = location.getBlock();
Block head = feet.getRelative(BlockFace.UP);
Block below = feet.getRelative(BlockFace.DOWN);
Block above = head.getRelative(BlockFace.UP);
// Check the block at the feet and head of the player
if((feet.getType().isSolid() && !canSpawnIn.contains(feet.getType())) || feet.isLiquid()) {
return false;
} else if((head.getType().isSolid() && !canSpawnIn.contains(head.getType())) || head.isLiquid()) {
return false;
} else if(!below.getType().isSolid() || cannotSpawnOn.contains(below.getType()) || below.isLiquid()) {
return false;
} else if(above.isLiquid() || cannotSpawnBeside.contains(above.getType())) {
return false;
}
// Get all blocks around the player (below foot level, foot level, head level and above head level)
Set<Material> around = new HashSet<>();
for(int y = 0; y <= 3; y++) {
for(int x = -1; x <= 1; x++) {
for(int z = -1; z <= 1; z++) {
// Skip blocks in the column of the player
if(x == 0 && z == 0) {
continue;
}
around.add(below.getRelative(x, y, z).getType());
}
}
}
// Check the blocks around the player
for(Material material : around) {
if(cannotSpawnBeside.contains(material)) {
return false;
}
}
return true;
}
/**
* Get the start location of a safe teleport search.
* @param player The player to get it for
* @param toSign true to try teleporting to the first sign, false for teleporting to the region
* @return The start location
*/
private Location getStartLocation(Player player, Value<Boolean> toSign) {
Location startLocation = null;
ProtectedRegion worldguardRegion = getRegion().getRegion();
// Try to get sign location
List<RegionSign> signs = getRegion().getSignsFeature().getSigns();
boolean signAvailable = !signs.isEmpty();
if(toSign.get()) {
if(signAvailable) {
// Use the location 1 below the sign to prevent weird spawing above the sign
startLocation = signs.get(0).getLocation(); //.subtract(0.0, 1.0, 0.0);
startLocation.setPitch(player.getLocation().getPitch());
startLocation.setYaw(player.getLocation().getYaw());
// Move player x blocks away from the sign
double distance = getRegion().getDoubleSetting("general.teleportSignDistance");
if(distance > 0) {
BlockFace facing = getRegion().getSignsFeature().getSigns().get(0).getFacing();
Vector facingVector = new Vector(facing.getModX(), facing.getModY(), facing.getModZ())
.normalize()
.multiply(distance);
startLocation.setX(startLocation.getBlockX() + 0.5);
startLocation.setZ(startLocation.getBlockZ() + 0.5);
startLocation.add(facingVector);
}
} else {
// No sign available
getRegion().message(player, "teleport-changedToNoSign");
toSign.set(false);
}
}
// Use teleportation location that is set for the region
if(startLocation == null && hasTeleportLocation()) {
startLocation = getTeleportLocation();
}
// Calculate a default location
if(startLocation == null) {
// Set to block in the middle, y configured in the config
com.sk89q.worldedit.Vector middle = com.sk89q.worldedit.Vector.getMidpoint(worldguardRegion.getMaximumPoint(), worldguardRegion.getMinimumPoint());
String configSetting = getRegion().getStringSetting("general.teleportLocationY");
if("bottom".equalsIgnoreCase(configSetting)) {
middle = middle.setY(worldguardRegion.getMinimumPoint().getBlockY());
} else if("top".equalsIgnoreCase(configSetting)) {
middle = middle.setY(worldguardRegion.getMaximumPoint().getBlockY());
} else if("middle".equalsIgnoreCase(configSetting)) {
middle = middle.setY(middle.getBlockY());
} else {
try {
int vertical = Integer.parseInt(configSetting);
middle = middle.setY(vertical);
} catch(NumberFormatException e) {
AreaShop.warn("Could not parse general.teleportLocationY: '" + configSetting + "'");
}
}
startLocation = new Location(getRegion().getWorld(), middle.getX(), middle.getY(), middle.getZ(), player.getLocation().getYaw(), player.getLocation().getPitch());
}
// Set location in the center of the block
startLocation.setX(startLocation.getBlockX() + 0.5);
startLocation.setZ(startLocation.getBlockZ() + 0.5);
return startLocation;
}
}
@@ -0,0 +1,266 @@
package me.wiefferink.areashop.features;
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
import com.sk89q.worldguard.protection.flags.Flag;
import com.sk89q.worldguard.protection.flags.InvalidFlagFormat;
import com.sk89q.worldguard.protection.flags.RegionGroupFlag;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import me.wiefferink.areashop.AreaShop;
import me.wiefferink.areashop.events.notify.UpdateRegionEvent;
import me.wiefferink.areashop.interfaces.RegionAccessSet;
import me.wiefferink.areashop.regions.GeneralRegion;
import me.wiefferink.interactivemessenger.processing.Message;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.event.EventHandler;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
public class WorldGuardRegionFlagsFeature extends RegionFeature {
@EventHandler
public void regionUpdate(UpdateRegionEvent event) {
updateRegionFlags(event.getRegion());
}
/**
* Set the region flags/options to the values of a ConfigurationSection.
* @param region The region to update the flags for
* @return true if the flags have been set correctly, otherwise false
*/
private boolean updateRegionFlags(GeneralRegion region) {
boolean result = true;
// Get section defining the region flag profile
ConfigurationSection flagProfileSection = region.getConfigurationSectionSetting("general.flagProfile", "flagProfiles");
if(flagProfileSection == null) {
return false;
}
// Region flags for all states
ConfigurationSection allFlags = flagProfileSection.getConfigurationSection("ALL");
if(allFlags != null) {
result = result && updateRegionFlags(region, allFlags);
}
// Region flags for the current state
ConfigurationSection stateFlags = flagProfileSection.getConfigurationSection(region.getState().getValue());
// If in reselling mode, fallback to 'resale' section if 'resell' is not found (legacy configuration problem: https://github.com/NLthijs48/AreaShop/issues/303)
if(stateFlags == null && region.getState() == GeneralRegion.RegionState.RESELL) {
stateFlags = flagProfileSection.getConfigurationSection("resale");
}
if(stateFlags != null) {
result = result && updateRegionFlags(region, stateFlags);
}
return result;
}
/**
* Set the region flags/options to the values of a ConfigurationSection.
* @param region The region to update the flags for
* @param flags The flags to apply
* @return true if the flags have been set correctly, otherwise false
*/
private boolean updateRegionFlags(GeneralRegion region, ConfigurationSection flags) {
boolean result = true;
Set<String> flagNames = flags.getKeys(false);
WorldGuardPlugin worldGuard = plugin.getWorldGuard();
// Get the region
ProtectedRegion worldguardRegion = region.getRegion();
if(worldguardRegion == null) {
AreaShop.debug("Region '" + region.getName() + "' does not exist, setting flags failed");
return false;
}
// Loop through all flags that are set in the config
for(String flagName : flagNames) {
String value = Message.fromString(flags.getString(flagName)).replacements(region).getPlain();
// In the config normal Bukkit color codes are used, those only need to be translated on 5.X WorldGuard versions
if(plugin.getWorldGuard().getDescription().getVersion().startsWith("5.")) {
value = translateBukkitToWorldGuardColors(value);
}
if(flagName.equalsIgnoreCase("members")) {
plugin.getWorldGuardHandler().setMembers(worldguardRegion, parseAccessSet(value));
//AreaShop.debug(" Flag " + flagName + " set: " + members.toUserFriendlyString());
} else if(flagName.equalsIgnoreCase("owners")) {
plugin.getWorldGuardHandler().setOwners(worldguardRegion, parseAccessSet(value));
//AreaShop.debug(" Flag " + flagName + " set: " + owners.toUserFriendlyString());
} else if(flagName.equalsIgnoreCase("priority")) {
try {
int priority = Integer.parseInt(value);
if(worldguardRegion.getPriority() != priority) {
worldguardRegion.setPriority(priority);
}
//AreaShop.debug(" Flag " + flagName + " set: " + value);
} catch(NumberFormatException e) {
AreaShop.warn("The value of flag " + flagName + " is not a number");
result = false;
}
} else if(flagName.equalsIgnoreCase("parent")) {
if(region.getWorld() == null || plugin.getRegionManager(region.getWorld()) == null) {
continue;
}
ProtectedRegion parentRegion = plugin.getRegionManager(region.getWorld()).getRegion(value);
if(parentRegion != null) {
if(!parentRegion.equals(worldguardRegion.getParent())) {
try {
worldguardRegion.setParent(parentRegion);
//AreaShop.debug(" Flag " + flagName + " set: " + value);
} catch(ProtectedRegion.CircularInheritanceException e) {
AreaShop.warn("The parent set in the config is not correct (circular inheritance)");
}
}
} else {
AreaShop.warn("The parent set in the config is not correct (region does not exist)");
}
} else {
// Parse all other normal flags (groups are also handled)
String flagSetting = null;
com.sk89q.worldguard.protection.flags.RegionGroup groupValue = null;
Flag<?> foundFlag = plugin.getWorldGuardHandler().fuzzyMatchFlag(flagName);
if(foundFlag == null) {
AreaShop.warn("Found wrong flag in flagProfiles section: " + flagName + ", check if that is the correct WorldGuard flag");
continue;
}
RegionGroupFlag groupFlag = foundFlag.getRegionGroupFlag();
if(value == null || value.isEmpty()) {
if(worldguardRegion.getFlag(foundFlag) != null) {
worldguardRegion.setFlag(foundFlag, null);
}
if(groupFlag != null && worldguardRegion.getFlag(groupFlag) != null) {
worldguardRegion.setFlag(groupFlag, null);
}
//AreaShop.debug(" Flag " + flagName + " reset (+ possible group of flag)");
} else {
if(groupFlag == null) {
flagSetting = value;
} else {
for(String part : value.split(" ")) {
if(part.startsWith("g:")) {
if(part.length() > 2) {
try {
groupValue = plugin.getWorldGuardHandler().parseFlagGroupInput(groupFlag, part.substring(2));
} catch(InvalidFlagFormat e) {
AreaShop.warn("Found wrong group value for flag " + flagName);
}
}
} else {
if(flagSetting == null) {
flagSetting = part;
} else {
flagSetting += " " + part;
}
}
}
}
if(flagSetting != null) {
try {
setFlag(worldguardRegion, foundFlag, flagSetting);
//AreaShop.debug(" Flag " + flagName + " set: " + flagSetting);
} catch(InvalidFlagFormat e) {
AreaShop.warn("Found wrong value for flag " + flagName);
}
}
if(groupValue != null) {
if(groupValue == groupFlag.getDefault()) {
worldguardRegion.setFlag(groupFlag, null);
//AreaShop.debug(" Group of flag " + flagName + " set to default: " + groupValue);
} else {
worldguardRegion.setFlag(groupFlag, groupValue);
//AreaShop.debug(" Group of flag " + flagName + " set: " + groupValue);
}
}
}
}
}
// Indicate that the regions needs to be saved
if(worldGuard.getDescription().getVersion().startsWith("5.")) {
plugin.getFileManager().saveIsRequiredForRegionWorld(region.getWorldName());
}
return result;
}
/**
* Build an RegionAccessSet from an input that specifies player names, player uuids and groups.
* @param input Input string defining the access set
* @return RegionAccessSet containing the entities parsed from the input
*/
public RegionAccessSet parseAccessSet(String input) {
RegionAccessSet result = new RegionAccessSet();
String[] inputParts = input.split(", ");
for(String access : inputParts) {
if(access != null && !access.isEmpty()) {
// Check for groups
if(access.startsWith("g:")) {
if(access.length() > 2) {
result.getGroupNames().add(access.substring(2));
}
} else if(access.startsWith("n:")) {
if(access.length() > 2) {
result.getPlayerNames().add(access.substring(2));
}
} else {
try {
result.getPlayerUniqueIds().add(UUID.fromString(access));
} catch(IllegalArgumentException e) {
AreaShop.warn("Tried using '" + access + "' as uuid for a region member/owner, is your flagProfiles section correct?");
}
}
}
}
return result;
}
/**
* Set a WorldGuard region flag.
* @param region The WorldGuard region to set
* @param flag The flag to set
* @param value The value to set the flag to
* @param <V> They type of flag to set
* @throws InvalidFlagFormat When the value of the flag is wrong
*/
private <V> void setFlag(ProtectedRegion region, Flag<V> flag, String value) throws InvalidFlagFormat {
V current = region.getFlag(flag);
V next = plugin.getWorldGuardHandler().parseFlagInput(flag, value);
if(!Objects.equals(current, next)) {
region.setFlag(flag, next);
}
}
/**
* Translate the color codes you put in greeting/farewell messages to the weird color codes of WorldGuard.
* @param message The message where the color codes should be translated (this message has bukkit color codes)
* @return The string with the WorldGuard color codes
*/
private String translateBukkitToWorldGuardColors(String message) {
String result = message;
result = result.replace("&c", "&r");
result = result.replace("&4", "&R");
result = result.replace("&e", "&y");
result = result.replace("&6", "&Y");
result = result.replace("&a", "&g");
result = result.replace("&2", "&G");
result = result.replace("&b", "&c");
result = result.replace("&3", "&C");
result = result.replace("&9", "&b");
result = result.replace("&1", "&B");
result = result.replace("&d", "&p");
result = result.replace("&5", "&P");
result = result.replace("&0", "&0");
result = result.replace("&8", "&1");
result = result.replace("&7", "&2");
result = result.replace("&f", "&w");
result = result.replace("&r", "&x");
return result;
}
}
@@ -0,0 +1,252 @@
package me.wiefferink.areashop.features.signs;
import com.google.common.base.Objects;
import me.wiefferink.areashop.AreaShop;
import me.wiefferink.areashop.regions.GeneralRegion;
import me.wiefferink.areashop.tools.Utils;
import me.wiefferink.interactivemessenger.processing.Message;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.Sign;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.List;
/**
* Sign that is connected to a region to display information and interact with the region.
*/
public class RegionSign {
private final SignsFeature signsFeature;
private final String key;
public RegionSign(SignsFeature signsFeature, String key) {
this.signsFeature = signsFeature;
this.key = key;
}
/**
* Get the location of this sign.
* @return The location of this sign
*/
public Location getLocation() {
return Utils.configToLocation(getRegion().getConfig().getConfigurationSection("general.signs." + key + ".location"));
}
/**
* Location string to be used as key in maps.
* @return Location string
*/
public String getStringLocation() {
return SignsFeature.locationToString(getLocation());
}
/**
* Chunk string to be used as key in maps.
* @return Chunk string
*/
public String getStringChunk() {
return SignsFeature.chunkToString(getLocation());
}
/**
* Get the region this sign is linked to.
* @return The region this sign is linked to
*/
public GeneralRegion getRegion() {
return signsFeature.getRegion();
}
/**
* Remove this sign from the region.
*/
public void remove() {
getLocation().getBlock().setType(Material.AIR);
signsFeature.getSignsRef().remove(getStringLocation());
SignsFeature.getAllSigns().remove(getStringLocation());
SignsFeature.getSignsByChunk().get(getStringChunk()).remove(this);
getRegion().setSetting("general.signs." + key, null);
}
/**
* Get the ConfigurationSection defining the sign layout.
* @return The sign layout config
*/
public ConfigurationSection getProfile() {
return getRegion().getConfigurationSectionSetting("general.signProfile", "signProfiles", getRegion().getConfig().get("general.signs." + key + ".profile"));
}
/**
* Get the facing of the sign.
* @return BlockFace the sign faces, or null if unknown
*/
public BlockFace getFacing() {
try {
return BlockFace.valueOf(getRegion().getConfig().getString("general.signs." + key + ".facing"));
} catch(NullPointerException | IllegalArgumentException e) {
return null;
}
}
/**
* Get the material of the sign
* @return Material of the sign, normally {@link Material#WALL_SIGN} or {@link Material#SIGN_POST}, but could be something else or null.
*/
public Material getMaterial() {
try {
return Material.valueOf(getRegion().getConfig().getString("general.signs." + key + ".signType"));
} catch(NullPointerException | IllegalArgumentException e) {
return null;
}
}
/**
* Update this sign.
* @return true if the update was successful, otherwise false
*/
public boolean update() {
// Ignore updates of signs in chunks that are not loaded
Location signLocation = getLocation();
if(signLocation == null
|| signLocation.getWorld() == null
|| !signLocation.getWorld().isChunkLoaded(signLocation.getBlockX() >> 4, signLocation.getBlockZ() >> 4)) {
return false;
}
if(getRegion().isDeleted()) {
return false;
}
YamlConfiguration regionConfig = getRegion().getConfig();
ConfigurationSection signConfig = getProfile();
Block block = signLocation.getBlock();
if(signConfig == null || !signConfig.isSet(getRegion().getState().getValue())) {
block.setType(Material.AIR);
return true;
}
ConfigurationSection stateConfig = signConfig.getConfigurationSection(getRegion().getState().getValue());
// Get the lines
String[] signLines = new String[4];
boolean signEmpty = true;
for(int i = 0; i < 4; i++) {
signLines[i] = stateConfig.getString("line" + (i + 1));
signEmpty &= (signLines[i] == null || signLines[i].isEmpty());
}
if(signEmpty) {
block.setType(Material.AIR);
return true;
}
Sign signState = null;
// Place the sign back (with proper rotation and type) after it has been hidden or (indirectly) destroyed
if(block.getType() != Material.WALL_SIGN && block.getType() != Material.SIGN_POST) {
Material signType = getMaterial();
if(signType != Material.WALL_SIGN && signType != Material.SIGN_POST) {
AreaShop.debug("Setting sign", key, "of region", getRegion().getName(), "failed, could not set sign block back");
return false;
}
block.setType(signType);
signState = (Sign)block.getState();
org.bukkit.material.Sign signData = (org.bukkit.material.Sign)signState.getData();
BlockFace signFace = getFacing();
if(signFace != null) {
signData.setFacingDirection(signFace);
signState.setData(signData);
}
}
if(signState == null) {
signState = (Sign)block.getState();
}
// Save current rotation and type
org.bukkit.material.Sign signData = (org.bukkit.material.Sign)signState.getData();
if(!regionConfig.isString("general.signs." + key + ".signType")) {
getRegion().setSetting("general.signs." + key + ".signType", signState.getType().toString());
}
if(!regionConfig.isString("general.signs." + key + ".facing")) {
getRegion().setSetting("general.signs." + key + ".facing", signData.getFacing().toString());
}
// Apply replacements and color and then set it on the sign
for(int i = 0; i < signLines.length; i++) {
if(signLines[i] == null) {
signState.setLine(i, "");
continue;
}
signLines[i] = Message.fromString(signLines[i]).replacements(getRegion()).getSingle();
signLines[i] = Utils.applyColors(signLines[i]);
signState.setLine(i, signLines[i]);
}
signState.update();
return true;
}
/**
* Check if the sign needs to update periodically.
* @return true if it needs periodic updates, otherwise false
*/
public boolean needsPeriodicUpdate() {
ConfigurationSection signConfig = getProfile();
if(signConfig == null || !signConfig.isSet(getRegion().getState().getValue().toLowerCase())) {
return false;
}
ConfigurationSection stateConfig = signConfig.getConfigurationSection(getRegion().getState().getValue().toLowerCase());
// Check the lines for the timeleft tag
for(int i = 1; i <= 4; i++) {
String line = stateConfig.getString("line" + i);
if(line != null && !line.isEmpty() && line.contains(Message.VARIABLE_START + AreaShop.tagTimeLeft + Message.VARIABLE_END)) {
return true;
}
}
return false;
}
/**
* Run commands when a player clicks a sign.
* @param clicker The player that clicked the sign
* @param clickType The type of clicking
* @return true if the commands ran successfully, false if any of them failed
*/
public boolean runSignCommands(Player clicker, GeneralRegion.ClickType clickType) {
ConfigurationSection signConfig = getProfile();
if(signConfig == null) {
return false;
}
ConfigurationSection stateConfig = signConfig.getConfigurationSection(getRegion().getState().getValue().toLowerCase());
// Run player commands if specified
List<String> playerCommands = new ArrayList<>();
for(String command : stateConfig.getStringList(clickType.getValue() + "Player")) {
// TODO move variable checking code to InteractiveMessenger?
playerCommands.add(command.replace(Message.VARIABLE_START + AreaShop.tagClicker + Message.VARIABLE_END, clicker.getName()));
}
getRegion().runCommands(clicker, playerCommands);
// Run console commands if specified
List<String> consoleCommands = new ArrayList<>();
for(String command : stateConfig.getStringList(clickType.getValue() + "Console")) {
consoleCommands.add(command.replace(Message.VARIABLE_START + AreaShop.tagClicker + Message.VARIABLE_END, clicker.getName()));
}
getRegion().runCommands(Bukkit.getConsoleSender(), consoleCommands);
return !playerCommands.isEmpty() || !consoleCommands.isEmpty();
}
@Override
public boolean equals(Object object) {
return object instanceof RegionSign && ((RegionSign)object).getRegion().equals(this.getRegion()) && ((RegionSign)object).key.equals(this.key);
}
@Override
public int hashCode() {
return Objects.hashCode(key, getRegion().getName());
}
}
@@ -0,0 +1,600 @@
package me.wiefferink.areashop.features.signs;
import com.sk89q.worldguard.protection.managers.RegionManager;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import me.wiefferink.areashop.AreaShop;
import me.wiefferink.areashop.events.notify.UpdateRegionEvent;
import me.wiefferink.areashop.features.RegionFeature;
import me.wiefferink.areashop.managers.FileManager;
import me.wiefferink.areashop.regions.BuyRegion;
import me.wiefferink.areashop.regions.GeneralRegion;
import me.wiefferink.areashop.regions.RentRegion;
import me.wiefferink.areashop.tools.Utils;
import me.wiefferink.bukkitdo.Do;
import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.block.Action;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockPhysicsEvent;
import org.bukkit.event.block.SignChangeEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.world.ChunkLoadEvent;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class SignsFeature extends RegionFeature {
private static final Map<String, RegionSign> allSigns = Collections.synchronizedMap(new HashMap<>());
private static final Map<String, List<RegionSign>> signsByChunk = Collections.synchronizedMap(new HashMap<>());
private Map<String, RegionSign> signs;
public SignsFeature() {
}
/**
* Constructor.
* @param region The region to bind to
*/
public SignsFeature(GeneralRegion region) {
setRegion(region);
signs = new HashMap<>();
// Setup current signs
ConfigurationSection signSection = region.getConfig().getConfigurationSection("general.signs");
if(signSection != null) {
for(String signKey : signSection.getKeys(false)) {
RegionSign sign = new RegionSign(this, signKey);
Location location = sign.getLocation();
if(location == null) {
AreaShop.warn("Sign with key " + signKey + " of region " + region.getName() + " does not have a proper location");
continue;
}
signs.put(sign.getStringLocation(), sign);
signsByChunk.computeIfAbsent(sign.getStringChunk(), key -> new ArrayList<>())
.add(sign);
}
allSigns.putAll(signs);
}
}
@Override
public void shutdown() {
// Deregister signs from the registry
if(signs != null) {
for(Map.Entry<String, RegionSign> entry : signs.entrySet()) {
allSigns.remove(entry.getKey());
signsByChunk.get(entry.getValue().getStringChunk()).remove(entry.getValue());
}
}
}
@EventHandler(priority = EventPriority.HIGH)
public void onSignBreak(BlockBreakEvent event) {
if(event.isCancelled()) {
return;
}
Block block = event.getBlock();
// Check if it is a sign
if(block.getType() == Material.WALL_SIGN || block.getType() == Material.SIGN_POST) {
// Check if the rent sign is really the same as a saved rent
RegionSign regionSign = SignsFeature.getSignByLocation(block.getLocation());
if(regionSign == null) {
return;
}
// Remove the sign of the rental region if the player has permission
if(event.getPlayer().hasPermission("areashop.delsign")) {
regionSign.remove();
plugin.message(event.getPlayer(), "delsign-success", regionSign.getRegion());
} else { // Cancel the breaking of the sign
event.setCancelled(true);
plugin.message(event.getPlayer(), "delsign-noPermission", regionSign.getRegion());
}
}
}
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onIndirectSignBreak(BlockPhysicsEvent event) {
if(event.getBlock().getType() == Material.SIGN_POST || event.getBlock().getType() == Material.WALL_SIGN) {
// Check if the rent sign is really the same as a saved rent
if(SignsFeature.getSignByLocation(event.getBlock().getLocation()) != null) {
// Cancel the sign breaking, will create a floating sign but at least it is not disconnected/gone
event.setCancelled(true);
}
}
}
@EventHandler(priority = EventPriority.HIGH)
public void onSignClick(PlayerInteractEvent event) {
if(event.isCancelled()) {
return;
}
Block block = event.getClickedBlock();
// Check for clicking a sign and rightclicking
if((event.getAction() == Action.RIGHT_CLICK_BLOCK || event.getAction() == Action.LEFT_CLICK_BLOCK)
&& (block.getType() == Material.SIGN_POST || block.getType() == Material.WALL_SIGN)) {
// Check if the rent sign is really the same as a saved rent
RegionSign regionSign = SignsFeature.getSignByLocation(block.getLocation());
if(regionSign == null) {
return;
}
Player player = event.getPlayer();
if(plugin.getSignlinkerManager().isInSignLinkMode(player)) {
return;
}
// Get the clicktype
GeneralRegion.ClickType clickType = null;
if(player.isSneaking() && event.getAction() == Action.LEFT_CLICK_BLOCK) {
clickType = GeneralRegion.ClickType.SHIFTLEFTCLICK;
} else if(!player.isSneaking() && event.getAction() == Action.LEFT_CLICK_BLOCK) {
clickType = GeneralRegion.ClickType.LEFTCLICK;
} else if(player.isSneaking() && event.getAction() == Action.RIGHT_CLICK_BLOCK) {
clickType = GeneralRegion.ClickType.SHIFTRIGHTCLICK;
} else if(!player.isSneaking() && event.getAction() == Action.RIGHT_CLICK_BLOCK) {
clickType = GeneralRegion.ClickType.RIGHTCLICK;
}
// Run the commands
boolean ran = regionSign.runSignCommands(player, clickType);
// Only cancel event if at least one command has been executed
event.setCancelled(ran);
}
}
@EventHandler(priority = EventPriority.MONITOR)
public void onSignChange(SignChangeEvent event) {
if(event.isCancelled()) {
return;
}
Player player = event.getPlayer();
if(!plugin.isReady()) {
plugin.message(player, "general-notReady");
return;
}
// Check if the sign is meant for this plugin
if(event.getLine(0).contains(plugin.getConfig().getString("signTags.rent"))) {
if(!player.hasPermission("areashop.createrent") && !player.hasPermission("areashop.createrent.member") && !player.hasPermission("areashop.createrent.owner")) {
plugin.message(player, "setup-noPermissionRent");
return;
}
// Get the other lines
String secondLine = event.getLine(1);
String thirdLine = event.getLine(2);
String fourthLine = event.getLine(3);
// Get the regionManager for accessing regions
RegionManager regionManager = plugin.getRegionManager(event.getPlayer().getWorld());
// If the secondLine does not contain a name try to find the region by location
if(secondLine == null || secondLine.length() == 0) {
Set<ProtectedRegion> regions = plugin.getWorldGuardHandler().getApplicableRegionsSet(event.getBlock().getLocation());
if(regions != null) {
boolean first = true;
ProtectedRegion candidate = null;
for(ProtectedRegion pr : regions) {
if(first) {
candidate = pr;
first = false;
} else {
if(pr.getPriority() > candidate.getPriority()) {
candidate = pr;
} else if(pr.getPriority() < candidate.getPriority()) {
// Already got the correct one
} else if(pr.getParent() != null && pr.getParent().equals(candidate)) {
candidate = pr;
} else if(candidate.getParent() != null && candidate.getParent().equals(pr)) {
// Already got the correct one
} else {
plugin.message(player, "setup-couldNotDetect", candidate.getId(), pr.getId());
return;
}
}
}
if(candidate != null) {
secondLine = candidate.getId();
}
}
}
boolean priceSet = fourthLine != null && fourthLine.length() != 0;
boolean durationSet = thirdLine != null && thirdLine.length() != 0;
// check if all the lines are correct
if(secondLine == null || secondLine.length() == 0) {
plugin.message(player, "setup-noRegion");
return;
}
ProtectedRegion region = regionManager.getRegion(secondLine);
if(region == null) {
plugin.message(player, "cmd-noRegion", secondLine);
return;
}
FileManager.AddResult addResult = plugin.getFileManager().checkRegionAdd(player, regionManager.getRegion(secondLine), event.getPlayer().getWorld(), GeneralRegion.RegionType.RENT);
if(addResult == FileManager.AddResult.BLACKLISTED) {
plugin.message(player, "setup-blacklisted", secondLine);
} else if(addResult == FileManager.AddResult.ALREADYADDED) {
plugin.message(player, "setup-alreadyRentSign");
} else if(addResult == FileManager.AddResult.ALREADYADDEDOTHERWORLD) {
plugin.message(player, "setup-alreadyOtherWorld");
} else if(addResult == FileManager.AddResult.NOPERMISSION) {
plugin.message(player, "setup-noPermission", secondLine);
} else if(thirdLine != null && thirdLine.length() != 0 && !Utils.checkTimeFormat(thirdLine)) {
plugin.message(player, "setup-wrongDuration");
} else {
double price = 0.0;
if(priceSet) {
// Check the fourth line
try {
price = Double.parseDouble(fourthLine);
} catch(NumberFormatException e) {
plugin.message(player, "setup-wrongPrice");
return;
}
}
// Add rent to the FileManager
final RentRegion rent = new RentRegion(secondLine, event.getPlayer().getWorld());
boolean isMember = plugin.getWorldGuardHandler().containsMember(rent.getRegion(), player.getUniqueId());
boolean isOwner = plugin.getWorldGuardHandler().containsOwner(rent.getRegion(), player.getUniqueId());
boolean landlord = (!player.hasPermission("areashop.createrent")
&& ((player.hasPermission("areashop.createrent.owner") && isOwner)
|| (player.hasPermission("areashop.createrent.member") && isMember)));
if(landlord) {
rent.setLandlord(player.getUniqueId(), player.getName());
}
if(priceSet) {
rent.setPrice(price);
}
if(durationSet) {
rent.setDuration(thirdLine);
}
org.bukkit.material.Sign sign = (org.bukkit.material.Sign)event.getBlock().getState().getData();
rent.getSignsFeature().addSign(event.getBlock().getLocation(), event.getBlock().getType(), sign.getFacing(), null);
// Run commands
rent.runEventCommands(GeneralRegion.RegionEvent.CREATED, true);
plugin.getFileManager().addRent(rent);
rent.handleSchematicEvent(GeneralRegion.RegionEvent.CREATED);
plugin.message(player, "setup-rentSuccess", rent);
// Update the region after the event has written its lines
Do.sync(rent::update);
// Run commands
rent.runEventCommands(GeneralRegion.RegionEvent.CREATED, false);
}
} else if(event.getLine(0).contains(plugin.getConfig().getString("signTags.buy"))) {
// Check for permission
if(!player.hasPermission("areashop.createbuy") && !player.hasPermission("areashop.createbuy.member") && !player.hasPermission("areashop.createbuy.owner")) {
plugin.message(player, "setup-noPermissionBuy");
return;
}
// Get the other lines
String secondLine = event.getLine(1);
String thirdLine = event.getLine(2);
// Get the regionManager for accessing regions
RegionManager regionManager = plugin.getRegionManager(event.getPlayer().getWorld());
// If the secondLine does not contain a name try to find the region by location
if(secondLine == null || secondLine.length() == 0) {
Set<ProtectedRegion> regions = plugin.getWorldGuardHandler().getApplicableRegionsSet(event.getBlock().getLocation());
if(regions != null) {
boolean first = true;
ProtectedRegion candidate = null;
for(ProtectedRegion pr : regions) {
if(first) {
candidate = pr;
first = false;
} else {
if(pr.getPriority() > candidate.getPriority()) {
candidate = pr;
} else if(pr.getPriority() < candidate.getPriority()) {
// Already got the correct one
} else if(pr.getParent() != null && pr.getParent().equals(candidate)) {
candidate = pr;
} else if(candidate.getParent() != null && candidate.getParent().equals(pr)) {
// Already got the correct one
} else {
plugin.message(player, "setup-couldNotDetect", candidate.getId(), pr.getId());
return;
}
}
}
if(candidate != null) {
secondLine = candidate.getId();
}
}
}
boolean priceSet = thirdLine != null && thirdLine.length() != 0;
// Check if all the lines are correct
if(secondLine == null || secondLine.length() == 0) {
plugin.message(player, "setup-noRegion");
return;
}
ProtectedRegion region = regionManager.getRegion(secondLine);
if(region == null) {
plugin.message(player, "cmd-noRegion", secondLine);
return;
}
FileManager.AddResult addResult = plugin.getFileManager().checkRegionAdd(player, region, event.getPlayer().getWorld(), GeneralRegion.RegionType.BUY);
if(addResult == FileManager.AddResult.BLACKLISTED) {
plugin.message(player, "setup-blacklisted", secondLine);
} else if(addResult == FileManager.AddResult.ALREADYADDED) {
plugin.message(player, "setup-alreadyRentSign");
} else if(addResult == FileManager.AddResult.ALREADYADDEDOTHERWORLD) {
plugin.message(player, "setup-alreadyOtherWorld");
} else if(addResult == FileManager.AddResult.NOPERMISSION) {
plugin.message(player, "setup-noPermission", secondLine);
} else {
double price = 0.0;
if(priceSet) {
// Check the fourth line
try {
price = Double.parseDouble(thirdLine);
} catch(NumberFormatException e) {
plugin.message(player, "setup-wrongPrice");
return;
}
}
// Add buy to the FileManager
final BuyRegion buy = new BuyRegion(secondLine, event.getPlayer().getWorld());
boolean isMember = plugin.getWorldGuardHandler().containsMember(buy.getRegion(), player.getUniqueId());
boolean isOwner = plugin.getWorldGuardHandler().containsOwner(buy.getRegion(), player.getUniqueId());
boolean landlord = (!player.hasPermission("areashop.createbuy")
&& ((player.hasPermission("areashop.createbuy.owner") && isOwner)
|| (player.hasPermission("areashop.createbuy.member") && isMember)));
if(landlord) {
buy.setLandlord(player.getUniqueId(), player.getName());
}
if(priceSet) {
buy.setPrice(price);
}
org.bukkit.material.Sign sign = (org.bukkit.material.Sign)event.getBlock().getState().getData();
buy.getSignsFeature().addSign(event.getBlock().getLocation(), event.getBlock().getType(), sign.getFacing(), null);
// Run commands
buy.runEventCommands(GeneralRegion.RegionEvent.CREATED, true);
plugin.getFileManager().addBuy(buy);
buy.handleSchematicEvent(GeneralRegion.RegionEvent.CREATED);
plugin.message(player, "setup-buySuccess", buy);
// Update the region after the event has written its lines
Do.sync(buy::update);
// Run commands
buy.runEventCommands(GeneralRegion.RegionEvent.CREATED, false);
}
} else if(event.getLine(0).contains(plugin.getConfig().getString("signTags.add"))) {
// Check for permission
if(!player.hasPermission("areashop.addsign")) {
plugin.message(player, "addsign-noPermission");
return;
}
// Get the other lines
String secondLine = event.getLine(1);
String thirdLine = event.getLine(2);
GeneralRegion region;
if(secondLine != null && secondLine.length() != 0) {
// Get region by secondLine of the sign
region = plugin.getFileManager().getRegion(secondLine);
if(region == null) {
plugin.message(player, "addSign-notRegistered", secondLine);
return;
}
} else {
// Get region by sign position
List<GeneralRegion> regions = Utils.getImportantRegions(event.getBlock().getLocation());
if(regions.isEmpty()) {
plugin.message(player, "addsign-noRegions");
return;
} else if(regions.size() > 1) {
plugin.message(player, "addsign-couldNotDetectSign", regions.get(0).getName(), regions.get(1).getName());
return;
}
region = regions.get(0);
}
org.bukkit.material.Sign sign = (org.bukkit.material.Sign)event.getBlock().getState().getData();
if(thirdLine == null || thirdLine.length() == 0) {
region.getSignsFeature().addSign(event.getBlock().getLocation(), event.getBlock().getType(), sign.getFacing(), null);
plugin.message(player, "addsign-success", region);
} else {
region.getSignsFeature().addSign(event.getBlock().getLocation(), event.getBlock().getType(), sign.getFacing(), thirdLine);
plugin.message(player, "addsign-successProfile", thirdLine, region);
}
// Update the region later because this event will do it first
Do.sync(region::update);
}
}
/**
* Convert a location to a string to use as map key.
* @param location The location to get the key for
* @return A string to use in a map for a location
*/
public static String locationToString(Location location) {
return location.getWorld().getName() + ";" + location.getBlockX() + ";" + location.getBlockY() + ";" + location.getBlockZ();
}
/**
* Convert a chunk to a string to use as map key.
* @param location The location to get the key for
* @return A string to use in a map for a chunk
*/
public static String chunkToString(Location location) {
return location.getWorld().getName() + ";" + (location.getBlockX() >> 4) + ";" + (location.getBlockZ() >> 4);
}
/**
* Convert a chunk to a string to use as map key.
* Use a Location argument to prevent chunk loading!
* @param chunk The location to get the key for
* @return A string to use in a map for a chunk
*/
public static String chunkToString(Chunk chunk) {
return chunk.getWorld().getName() + ";" + chunk.getX() + ";" + chunk.getZ();
}
/**
* Get a sign by a location.
* @param location The location to get the sign for
* @return The RegionSign that is at the location, or null if none
*/
public static RegionSign getSignByLocation(Location location) {
return allSigns.get(locationToString(location));
}
/**
* Get the map with all signs.
* @return Map with all signs: locationString -&gt; RegionSign
*/
public static Map<String, RegionSign> getAllSigns() {
return allSigns;
}
/**
* Get the map with signs by chunk.
* @return Map with signs by chunk: chunkString -&gt; List&lt;RegionSign&gt;
*/
public static Map<String, List<RegionSign>> getSignsByChunk() {
return signsByChunk;
}
@EventHandler
public void regionUpdate(UpdateRegionEvent event) {
event.getRegion().getSignsFeature().update();
}
@EventHandler(priority = EventPriority.MONITOR)
public void onChunkLoad(ChunkLoadEvent event) {
List<RegionSign> chunkSigns = signsByChunk.get(chunkToString(event.getChunk()));
if(chunkSigns == null) {
return;
}
Do.forAll(chunkSigns, RegionSign::update);
}
/**
* Update all signs connected to this region.
* @return true if all signs are updated correctly, false if one or more updates failed
*/
public boolean update() {
boolean result = true;
for(RegionSign sign : signs.values()) {
result = result & sign.update();
}
return result;
}
/**
* Check if any of the signs need periodic updating.
* @return true if one or more of the signs need periodic updating, otherwise false
*/
public boolean needsPeriodicUpdate() {
boolean result = false;
for(RegionSign sign : signs.values()) {
result = result | sign.needsPeriodicUpdate();
}
return result;
}
/**
* Get the signs of this region.
* @return List of signs
*/
public List<RegionSign> getSigns() {
return Collections.unmodifiableList(new ArrayList<>(signs.values()));
}
/**
* Get the signs of this region.
* @return Map with signs: locationString -&gt; RegionSign
*/
Map<String, RegionSign> getSignsRef() {
return signs;
}
/**
* Get a list with all sign locations.
* @return A List with all sign locations
*/
public List<Location> getSignLocations() {
List<Location> result = new ArrayList<>();
for(RegionSign sign : signs.values()) {
result.add(sign.getLocation());
}
return result;
}
/**
* Add a sign to this region.
* @param location The location of the sign
* @param signType The type of the sign (WALL_SIGN or SIGN_POST)
* @param facing The orientation of the sign
* @param profile The profile to use with this sign (null for default)
*/
public void addSign(Location location, Material signType, BlockFace facing, String profile) {
int i = 0;
while(getRegion().getConfig().isSet("general.signs." + i)) {
i++;
}
String signPath = "general.signs." + i + ".";
getRegion().setSetting(signPath + "location", Utils.locationToConfig(location));
getRegion().setSetting(signPath + "facing", facing != null ? facing.name() : null);
getRegion().setSetting(signPath + "signType", signType != null ? signType.name() : null);
if(profile != null && profile.length() != 0) {
getRegion().setSetting(signPath + "profile", profile);
}
// Add to the map
RegionSign sign = new RegionSign(this, i + "");
signs.put(sign.getStringLocation(), sign);
allSigns.put(sign.getStringLocation(), sign);
signsByChunk.computeIfAbsent(sign.getStringChunk(), key -> new ArrayList<>())
.add(sign);
}
/**
* Checks if there is a sign from this region at the specified location.
* @param location Location to check
* @return true if this region has a sign at the location, otherwise false
*/
public boolean isSignOfRegion(Location location) {
Set<String> signs;
if(getRegion().getConfig().getConfigurationSection("general.signs") == null) {
return false;
}
signs = getRegion().getConfig().getConfigurationSection("general.signs").getKeys(false);
for(String sign : signs) {
Location signLocation = Utils.configToLocation(getRegion().getConfig().getConfigurationSection("general.signs." + sign + ".location"));
if(signLocation != null
&& signLocation.getWorld().equals(location.getWorld())
&& signLocation.getBlockX() == location.getBlockX()
&& signLocation.getBlockY() == location.getBlockY()
&& signLocation.getBlockZ() == location.getBlockZ()) {
return true;
}
}
return false;
}
}
@@ -0,0 +1,769 @@
/*
* Copyright 2011-2013 Tyler Blair. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and contributors and should not be interpreted as representing official policies,
* either expressed or implied, of anybody else.
*/
package me.wiefferink.areashop.lib;
import org.bukkit.Bukkit;
import org.bukkit.Server;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginDescriptionFile;
import org.bukkit.scheduler.BukkitTask;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.net.Proxy;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.UUID;
import java.util.logging.Level;
import java.util.zip.GZIPOutputStream;
public class Metrics {
/**
* The current revision number.
*/
private static final int REVISION = 7;
/**
* The base url of the metrics domain.
*/
private static final String BASE_URL = "http://report.mcstats.org";
/**
* The url used to report a server's status.
*/
private static final String REPORT_URL = "/plugin/%s";
/**
* Interval of time to ping (in minutes).
*/
private static final int PING_INTERVAL = 15;
/**
* The plugin this metrics submits for.
*/
private final Plugin plugin;
/**
* All of the custom graphs to submit to metrics.
*/
private final Set<Graph> graphs = Collections.synchronizedSet(new HashSet<Graph>());
/**
* The plugin configuration file.
*/
private final YamlConfiguration configuration;
/**
* The plugin configuration file.
*/
private final File configurationFile;
/**
* Unique server id.
*/
private final String guid;
/**
* Debug mode.
*/
private final boolean debug;
/**
* Lock for synchronization.
*/
private final Object optOutLock = new Object();
/**
* The scheduled task.
*/
private volatile BukkitTask task = null;
/**
* Constructor.
* @param plugin The plugin to report stats for
* @throws IOException When the plugin or configuration is wrong
*/
public Metrics(final Plugin plugin) throws IOException {
if(plugin == null) {
throw new IllegalArgumentException("Plugin cannot be null");
}
this.plugin = plugin;
// load the config
configurationFile = getConfigFile();
configuration = YamlConfiguration.loadConfiguration(configurationFile);
// add some defaults
configuration.addDefault("opt-out", false);
configuration.addDefault("guid", UUID.randomUUID().toString());
configuration.addDefault("debug", false);
// Do we need to create the file?
if(configuration.get("guid", null) == null) {
configuration.options().header("http://mcstats.org").copyDefaults(true);
configuration.save(configurationFile);
}
// Load the guid then
guid = configuration.getString("guid");
debug = configuration.getBoolean("debug", false);
}
/**
* Construct and create a Graph that can be used to separate specific plotters to their own graphs on the metrics
* website. Plotters can be added to the graph object returned.
* @param name The name of the graph
* @return Graph object created. Will never return NULL under normal circumstances unless bad parameters are given
*/
public Graph createGraph(final String name) {
if(name == null) {
throw new IllegalArgumentException("Graph name cannot be null");
}
// Construct the graph object
final Graph graph = new Graph(name);
// Now we can add our graph
graphs.add(graph);
// and return back
return graph;
}
/**
* Add a Graph object to BukkitMetrics that represents data for the plugin that should be sent to the backend.
* @param graph The name of the graph
*/
public void addGraph(final Graph graph) {
if(graph == null) {
throw new IllegalArgumentException("Graph cannot be null");
}
graphs.add(graph);
}
/**
* Start measuring statistics. This will immediately create an async repeating task as the plugin and send the
* initial data to the metrics backend, and then after that it will post in increments of PING_INTERVAL * 1200
* ticks.
* @return True if statistics measuring is running, otherwise false.
*/
public boolean start() {
synchronized(optOutLock) {
// Did we opt out?
if(isOptOut()) {
return false;
}
// Is metrics already running?
if(task != null) {
return true;
}
// Begin hitting the server with glorious data
task = plugin.getServer().getScheduler().runTaskTimerAsynchronously(plugin, new Runnable() {
private boolean firstPost = true;
public void run() {
try {
// This has to be synchronized or it can collide with the disable method.
synchronized(optOutLock) {
// Disable Task, if it is running and the server owner decided to opt-out
if(isOptOut() && task != null) {
task.cancel();
task = null;
// Tell all plotters to stop gathering information.
for(Graph graph : graphs) {
graph.onOptOut();
}
}
}
// We use the inverse of firstPost because if it is the first time we are posting,
// it is not a interval ping, so it evaluates to FALSE
// Each time thereafter it will evaluate to TRUE, i.e PING!
postPlugin(!firstPost);
// After the first post we set firstPost to false
// Each post thereafter will be a ping
firstPost = false;
} catch(IOException e) {
if(debug) {
Bukkit.getLogger().log(Level.INFO, "[Metrics] " + e.getMessage());
}
}
}
}, 0, PING_INTERVAL * 1200);
return true;
}
}
/**
* If the server owner denied plugin metrics.
* @return true if metrics should be opted out of it
*/
public boolean isOptOut() {
synchronized(optOutLock) {
try {
// Reload the metrics file
configuration.load(getConfigFile());
} catch(IOException ex) {
if(debug) {
Bukkit.getLogger().log(Level.INFO, "[Metrics] " + ex.getMessage());
}
return true;
} catch(InvalidConfigurationException ex) {
if(debug) {
Bukkit.getLogger().log(Level.INFO, "[Metrics] " + ex.getMessage());
}
return true;
}
return configuration.getBoolean("opt-out", false);
}
}
/**
* Enables metrics for the server by setting "opt-out" to false in the config file and starting the metrics task.
* @throws IOException when saving the config file fails
*/
public void enable() throws IOException {
// This has to be synchronized or it can collide with the check in the task.
synchronized(optOutLock) {
// Check if the server owner has already set opt-out, if not, set it.
if(isOptOut()) {
configuration.set("opt-out", false);
configuration.save(configurationFile);
}
// Enable Task, if it is not running
if(task == null) {
start();
}
}
}
/**
* Disables metrics for the server by setting "opt-out" to true in the config file and canceling the metrics task.
* @throws IOException when saving the config file fails
*/
public void disable() throws IOException {
// This has to be synchronized or it can collide with the check in the task.
synchronized(optOutLock) {
// Check if the server owner has already set opt-out, if not, set it.
if(!isOptOut()) {
configuration.set("opt-out", true);
configuration.save(configurationFile);
}
// Disable Task, if it is running
if(task != null) {
task.cancel();
task = null;
}
}
}
/**
* Gets the File object of the config file that should be used to store data such as the GUID and opt-out status.
* @return the File object for the config file
*/
public File getConfigFile() {
// I believe the easiest way to get the base folder (e.g craftbukkit set via -P) for plugins to use
// is to abuse the plugin object we already have
// plugin.getDataFolder() => base/plugins/PluginA/
// pluginsFolder => base/plugins/
// The base is not necessarily relative to the startup directory.
File pluginsFolder = plugin.getDataFolder().getParentFile();
// return => base/plugins/PluginMetrics/config.yml
return new File(new File(pluginsFolder, "PluginMetrics"), "config.yml");
}
/**
* Gets the online player (backwards compatibility).
* @return online player amount
*/
private int getOnlinePlayers() {
try {
Method onlinePlayerMethod = Server.class.getMethod("getOnlinePlayers");
if(onlinePlayerMethod.getReturnType().equals(Collection.class)) {
return ((Collection<?>)onlinePlayerMethod.invoke(Bukkit.getServer())).size();
} else {
return ((Player[])onlinePlayerMethod.invoke(Bukkit.getServer())).length;
}
} catch(Exception ex) {
if(debug) {
Bukkit.getLogger().log(Level.INFO, "[Metrics] " + ex.getMessage());
}
}
return 0;
}
/**
* Generic method that posts a plugin to the metrics website.
*/
private void postPlugin(final boolean isPing) throws IOException {
// Server software specific section
PluginDescriptionFile description = plugin.getDescription();
String pluginName = description.getName();
boolean onlineMode = Bukkit.getServer().getOnlineMode(); // TRUE if online mode is enabled
String pluginVersion = description.getVersion();
String serverVersion = Bukkit.getVersion();
int playersOnline = this.getOnlinePlayers();
// END server software specific section -- all code below does not use any code outside of this class / Java
// Construct the post data
StringBuilder json = new StringBuilder(1024);
json.append('{');
// The plugin's description file containg all of the plugin data such as name, version, author, etc
appendJsonPair(json, "guid", guid);
appendJsonPair(json, "plugin_version", pluginVersion);
appendJsonPair(json, "server_version", serverVersion);
appendJsonPair(json, "players_online", Integer.toString(playersOnline));
// New data as of R6
String osname = System.getProperty("os.name");
String osarch = System.getProperty("os.arch");
String osversion = System.getProperty("os.version");
String javaVersion = System.getProperty("java.version");
int coreCount = Runtime.getRuntime().availableProcessors();
// normalize os arch .. amd64 -> x86_64
if(osarch.equals("amd64")) {
osarch = "x86_64";
}
appendJsonPair(json, "osname", osname);
appendJsonPair(json, "osarch", osarch);
appendJsonPair(json, "osversion", osversion);
appendJsonPair(json, "cores", Integer.toString(coreCount));
appendJsonPair(json, "auth_mode", onlineMode ? "1" : "0");
appendJsonPair(json, "java_version", javaVersion);
// If we're pinging, append it
if(isPing) {
appendJsonPair(json, "ping", "1");
}
if(graphs.size() > 0) {
synchronized(graphs) {
json.append(',');
json.append('"');
json.append("graphs");
json.append('"');
json.append(':');
json.append('{');
boolean firstGraph = true;
final Iterator<Graph> iter = graphs.iterator();
while(iter.hasNext()) {
Graph graph = iter.next();
StringBuilder graphJson = new StringBuilder();
graphJson.append('{');
for(Plotter plotter : graph.getPlotters()) {
appendJsonPair(graphJson, plotter.getColumnName(), Integer.toString(plotter.getValue()));
}
graphJson.append('}');
if(!firstGraph) {
json.append(',');
}
json.append(escapeJson(graph.getName()));
json.append(':');
json.append(graphJson);
firstGraph = false;
}
json.append('}');
}
}
// close json
json.append('}');
// Create the url
URL url = new URL(BASE_URL + String.format(REPORT_URL, urlEncode(pluginName)));
// Connect to the website
URLConnection connection;
// Mineshafter creates a socks proxy, so we can safely bypass it
// It does not reroute POST requests so we need to go around it
if(isMineshafterPresent()) {
connection = url.openConnection(Proxy.NO_PROXY);
} else {
connection = url.openConnection();
}
byte[] uncompressed = json.toString().getBytes();
byte[] compressed = gzip(json.toString());
// Headers
connection.addRequestProperty("User-Agent", "MCStats/" + REVISION);
connection.addRequestProperty("Content-Type", "application/json");
connection.addRequestProperty("Content-Encoding", "gzip");
connection.addRequestProperty("Content-Length", Integer.toString(compressed.length));
connection.addRequestProperty("Accept", "application/json");
connection.addRequestProperty("Connection", "close");
connection.setDoOutput(true);
if(debug) {
System.out.println("[Metrics] Prepared request for " + pluginName + " uncompressed=" + uncompressed.length + " compressed=" + compressed.length);
}
// Write the data
OutputStream os = connection.getOutputStream();
os.write(compressed);
os.flush();
// Now read the response
final BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String response = reader.readLine();
// close resources
os.close();
reader.close();
if(response == null || response.startsWith("ERR") || response.startsWith("7")) {
if(response == null) {
response = "null";
} else if(response.startsWith("7")) {
response = response.substring(response.startsWith("7,") ? 2 : 1);
}
throw new IOException(response);
} else {
// Is this the first update this hour?
if(response.equals("1") || response.contains("This is your first update this hour")) {
synchronized(graphs) {
final Iterator<Graph> iter = graphs.iterator();
while(iter.hasNext()) {
final Graph graph = iter.next();
for(Plotter plotter : graph.getPlotters()) {
plotter.reset();
}
}
}
}
}
}
/**
* GZip compress a string of bytes.
* @param input Content to gzip
* @return byte[] of the gzipped input
*/
public static byte[] gzip(String input) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GZIPOutputStream gzos = null;
try {
gzos = new GZIPOutputStream(baos);
gzos.write(input.getBytes(StandardCharsets.UTF_8));
} catch(IOException e) {
e.printStackTrace();
} finally {
if(gzos != null) {
try {
gzos.close();
} catch(IOException ignore) {
// ignore
}
}
}
return baos.toByteArray();
}
/**
* Check if mineshafter is present. If it is, we need to bypass it to send POST requests
* @return true if mineshafter is installed on the server
*/
private boolean isMineshafterPresent() {
try {
Class.forName("mineshafter.MineServer");
return true;
} catch(Exception e) {
return false;
}
}
/**
* Appends a json encoded key/value pair to the given string builder.
*/
private static void appendJsonPair(StringBuilder json, String key, String value) throws UnsupportedEncodingException {
boolean isValueNumeric = false;
try {
if(value.equals("0") || !value.endsWith("0")) {
Double.parseDouble(value);
isValueNumeric = true;
}
} catch(NumberFormatException e) {
isValueNumeric = false;
}
if(json.charAt(json.length() - 1) != '{') {
json.append(',');
}
json.append(escapeJson(key));
json.append(':');
if(isValueNumeric) {
json.append(value);
} else {
json.append(escapeJson(value));
}
}
/**
* Escape a string to create a valid JSON string.
*/
private static String escapeJson(String text) {
StringBuilder builder = new StringBuilder();
builder.append('"');
for(int index = 0; index < text.length(); index++) {
char chr = text.charAt(index);
switch(chr) {
case '"':
case '\\':
builder.append('\\');
builder.append(chr);
break;
case '\b':
builder.append("\\b");
break;
case '\t':
builder.append("\\t");
break;
case '\n':
builder.append("\\n");
break;
case '\r':
builder.append("\\r");
break;
default:
if(chr < ' ') {
String t = "000" + Integer.toHexString(chr);
builder.append("\\u" + t.substring(t.length() - 4));
} else {
builder.append(chr);
}
break;
}
}
builder.append('"');
return builder.toString();
}
/**
* Encode text as UTF-8.
* @param text the text to encode
* @return the encoded text, as UTF-8
*/
private static String urlEncode(final String text) throws UnsupportedEncodingException {
return URLEncoder.encode(text, "UTF-8");
}
/**
* Represents a custom graph on the website.
*/
public static class Graph {
/**
* The graph's name, alphanumeric and spaces only :) If it does not comply to the above when submitted, it is
* rejected.
*/
private final String name;
/**
* The set of plotters that are contained within this graph.
*/
private final Set<Plotter> plotters = new LinkedHashSet<Plotter>();
private Graph(final String name) {
this.name = name;
}
/**
* Gets the graph's name.
* @return the Graph's name
*/
public String getName() {
return name;
}
/**
* Add a plotter to the graph, which will be used to plot entries.
* @param plotter the plotter to add to the graph
*/
public void addPlotter(final Plotter plotter) {
plotters.add(plotter);
}
/**
* Remove a plotter from the graph.
* @param plotter the plotter to remove from the graph
*/
public void removePlotter(final Plotter plotter) {
plotters.remove(plotter);
}
/**
* Gets an <b>unmodifiable</b> set of the plotter objects in the graph.
* @return an unmodifiable {@link java.util.Set} of the plotter objects
*/
public Set<Plotter> getPlotters() {
return Collections.unmodifiableSet(plotters);
}
@Override
public int hashCode() {
return name.hashCode();
}
@Override
public boolean equals(final Object object) {
if(!(object instanceof Graph)) {
return false;
}
final Graph graph = (Graph)object;
return graph.name.equals(name);
}
/**
* Called when the server owner decides to opt-out of BukkitMetrics while the server is running.
*/
protected void onOptOut() {
}
}
/**
* Interface used to collect custom data for a plugin.
*/
public abstract static class Plotter {
/**
* The plot's name.
*/
private final String name;
/**
* Construct a plotter with the default plot name.
*/
public Plotter() {
this("Default");
}
/**
* Construct a plotter with a specific plot name.
* @param name the name of the plotter to use, which will show up on the website
*/
public Plotter(final String name) {
this.name = name;
}
/**
* Get the current value for the plotted point. Since this function defers to an external function it may or may
* not return immediately thus cannot be guaranteed to be thread friendly or safe. This function can be called
* from any thread so care should be taken when accessing resources that need to be synchronized.
* @return the current value for the point to be plotted.
*/
public abstract int getValue();
/**
* Get the column name for the plotted point.
* @return the plotted point's column name
*/
public String getColumnName() {
return name;
}
/**
* Called after the website graphs have been updated.
*/
public void reset() {
}
@Override
public int hashCode() {
return getColumnName().hashCode();
}
@Override
public boolean equals(final Object object) {
if(!(object instanceof Plotter)) {
return false;
}
final Plotter plotter = (Plotter)object;
return plotter.name.equals(name) && plotter.getValue() == getValue();
}
}
}
@@ -0,0 +1,163 @@
package me.wiefferink.areashop.listeners;
import me.wiefferink.areashop.AreaShop;
import me.wiefferink.areashop.regions.BuyRegion;
import me.wiefferink.areashop.regions.GeneralRegion;
import me.wiefferink.areashop.regions.RentRegion;
import me.wiefferink.areashop.tools.Utils;
import me.wiefferink.bukkitdo.Do;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerKickEvent;
import org.bukkit.event.player.PlayerLoginEvent;
import org.bukkit.event.player.PlayerLoginEvent.Result;
import org.bukkit.event.player.PlayerQuitEvent;
import java.util.ArrayList;
import java.util.List;
/**
* Notify region expiry and track activity time.
*/
public final class PlayerLoginLogoutListener implements Listener {
private final AreaShop plugin;
/**
* Constructor.
* @param plugin The AreaShop plugin
*/
public PlayerLoginLogoutListener(AreaShop plugin) {
this.plugin = plugin;
}
/**
* Called when a sign is changed.
* @param event The event
*/
@EventHandler(priority = EventPriority.MONITOR)
public void onPlayerLogin(PlayerLoginEvent event) {
if(event.getResult() != Result.ALLOWED) {
return;
}
final Player player = event.getPlayer();
// Schedule task to check for notifications, prevents a lag spike at login
Do.syncTimerLater(25, 25, () -> {
// Delay until all regions are loaded
if(!plugin.isReady()) {
return true;
}
if(!player.isOnline()) {
return false;
}
// Notify for rents that almost run out
for(RentRegion region : plugin.getFileManager().getRents()) {
if(region.isRenter(player)) {
String warningSetting = region.getStringSetting("rent.warningOnLoginTime");
if(warningSetting == null || warningSetting.isEmpty()) {
continue;
}
long warningTime = Utils.durationStringToLong(warningSetting);
if(region.getTimeLeft() < warningTime) {
// Send the warning message later to let it appear after general MOTD messages
AreaShop.getInstance().message(player, "rent-expireWarning", region);
}
}
}
// Notify admins for plugin updates
AreaShop.getInstance().notifyUpdate(player);
return false;
});
// Check if the player has regions that use an old name of him and update them
Do.syncTimerLater(22, 10, () -> {
if(!plugin.isReady()) {
return true;
}
List<GeneralRegion> regions = new ArrayList<>();
for(GeneralRegion region : plugin.getFileManager().getRegions()) {
if(region.isOwner(player)) {
regions.add(region);
}
}
Do.forAll(
plugin.getConfig().getInt("nameupdate.regionsPerTick"),
regions,
region -> {
if(region instanceof BuyRegion) {
if(!player.getName().equals(region.getStringSetting("buy.buyerName"))) {
region.setSetting("buy.buyerName", player.getName());
region.update();
}
} else if(region instanceof RentRegion) {
if(!player.getName().equals(region.getStringSetting("rent.renterName"))) {
region.setSetting("rent.renterName", player.getName());
region.update();
}
}
}
);
return false;
});
}
// Active time updates
@EventHandler(priority = EventPriority.MONITOR)
public void onPlayerLogout(PlayerQuitEvent event) {
updateLastActive(event.getPlayer());
}
@EventHandler(priority = EventPriority.MONITOR)
public void onPlayerKick(PlayerKickEvent event) {
updateLastActive(event.getPlayer());
}
/**
* Update the last active time for all regions the player is owner off.
* @param player The player to update the active times for
*/
private void updateLastActive(Player player) {
for(GeneralRegion region : plugin.getFileManager().getRegions()) {
if(region.isOwner(player)) {
region.updateLastActiveTime();
}
}
}
}
@@ -0,0 +1,214 @@
package me.wiefferink.areashop.managers;
import me.wiefferink.areashop.commands.AddCommand;
import me.wiefferink.areashop.commands.AddfriendCommand;
import me.wiefferink.areashop.commands.AddsignCommand;
import me.wiefferink.areashop.commands.BuyCommand;
import me.wiefferink.areashop.commands.CommandAreaShop;
import me.wiefferink.areashop.commands.DelCommand;
import me.wiefferink.areashop.commands.DelfriendCommand;
import me.wiefferink.areashop.commands.DelsignCommand;
import me.wiefferink.areashop.commands.FindCommand;
import me.wiefferink.areashop.commands.GroupaddCommand;
import me.wiefferink.areashop.commands.GroupdelCommand;
import me.wiefferink.areashop.commands.GroupinfoCommand;
import me.wiefferink.areashop.commands.GrouplistCommand;
import me.wiefferink.areashop.commands.HelpCommand;
import me.wiefferink.areashop.commands.ImportCommand;
import me.wiefferink.areashop.commands.InfoCommand;
import me.wiefferink.areashop.commands.LinksignsCommand;
import me.wiefferink.areashop.commands.MeCommand;
import me.wiefferink.areashop.commands.MessageCommand;
import me.wiefferink.areashop.commands.ReloadCommand;
import me.wiefferink.areashop.commands.RentCommand;
import me.wiefferink.areashop.commands.ResellCommand;
import me.wiefferink.areashop.commands.SchematiceventCommand;
import me.wiefferink.areashop.commands.SellCommand;
import me.wiefferink.areashop.commands.SetdurationCommand;
import me.wiefferink.areashop.commands.SetlandlordCommand;
import me.wiefferink.areashop.commands.SetownerCommand;
import me.wiefferink.areashop.commands.SetpriceCommand;
import me.wiefferink.areashop.commands.SetrestoreCommand;
import me.wiefferink.areashop.commands.SetteleportCommand;
import me.wiefferink.areashop.commands.StackCommand;
import me.wiefferink.areashop.commands.StopresellCommand;
import me.wiefferink.areashop.commands.TeleportCommand;
import me.wiefferink.areashop.commands.UnrentCommand;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabCompleter;
import java.util.ArrayList;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;
public class CommandManager extends Manager implements CommandExecutor, TabCompleter {
private final ArrayList<CommandAreaShop> commands;
/**
* Constructor.
*/
public CommandManager() {
commands = new ArrayList<>();
commands.add(new HelpCommand());
commands.add(new RentCommand());
commands.add(new UnrentCommand());
commands.add(new BuyCommand());
commands.add(new SellCommand());
commands.add(new MeCommand());
commands.add(new InfoCommand());
commands.add(new TeleportCommand());
commands.add(new SetteleportCommand());
commands.add(new AddfriendCommand());
commands.add(new DelfriendCommand());
commands.add(new FindCommand());
commands.add(new ResellCommand());
commands.add(new StopresellCommand());
commands.add(new SetrestoreCommand());
commands.add(new SetpriceCommand());
commands.add(new SetownerCommand());
commands.add(new SetdurationCommand());
commands.add(new ReloadCommand());
commands.add(new GroupaddCommand());
commands.add(new GroupdelCommand());
commands.add(new GrouplistCommand());
commands.add(new GroupinfoCommand());
commands.add(new SchematiceventCommand());
commands.add(new AddCommand());
commands.add(new DelCommand());
commands.add(new AddsignCommand());
commands.add(new DelsignCommand());
commands.add(new LinksignsCommand());
commands.add(new StackCommand());
commands.add(new SetlandlordCommand());
commands.add(new MessageCommand());
commands.add(new ImportCommand());
// Register commands in bukkit
plugin.getCommand("AreaShop").setExecutor(this);
plugin.getCommand("AreaShop").setTabCompleter(this);
}
/**
* Get the list with AreaShop commands.
* @return The list with AreaShop commands
*/
public ArrayList<CommandAreaShop> getCommands() {
return commands;
}
/**
* Shows the help page for the CommandSender.
* @param target The CommandSender to show the help to
*/
public void showHelp(CommandSender target) {
if(!target.hasPermission("areashop.help")) {
plugin.message(target, "help-noPermission");
return;
}
// Add all messages to a list
ArrayList<String> messages = new ArrayList<>();
plugin.message(target, "help-header");
plugin.message(target, "help-alias");
for(CommandAreaShop command : commands) {
String help = command.getHelp(target);
if(help != null && help.length() != 0) {
messages.add(help);
}
}
// Send the messages to the target
for(String message : messages) {
plugin.messageNoPrefix(target, message);
}
}
@Override
public boolean onCommand(CommandSender sender, Command command, String alias, String[] args) {
if(!plugin.isReady()) {
plugin.message(sender, "general-notReady");
return true;
}
// Redirect `/as info player <player>` to `/as me <player>`
if(args.length == 3 && "info".equals(args[0]) && "player".equals(args[1])) {
args[0] = "me";
args[1] = args[2];
}
// Execute command
boolean executed = false;
for(int i = 0; i < commands.size() && !executed; i++) {
if(commands.get(i).canExecute(command, args)) {
commands.get(i).execute(sender, args);
executed = true;
}
}
if(!executed && args.length == 0) {
this.showHelp(sender);
} else if(!executed && args.length > 0) {
// Indicate that the '/as updaterents' and '/as updatebuys' commands are removed
if("updaterents".equalsIgnoreCase(args[0]) || "updatebuys".equalsIgnoreCase(args[0])) {
plugin.message(sender, "reload-updateCommandChanged");
} else {
plugin.message(sender, "cmd-notValid");
}
}
return true;
}
@Override
public List<String> onTabComplete(CommandSender sender, Command command, String alias, String[] args) {
List<String> result = new ArrayList<>();
if(!sender.hasPermission("areashop.tabcomplete")) {
return result;
}
int toCompleteNumber = args.length;
String toCompletePrefix = args[args.length - 1].toLowerCase();
//AreaShop.debug("toCompleteNumber=" + toCompleteNumber + ", toCompletePrefix=" + toCompletePrefix + ", length=" + toCompletePrefix.length());
if(toCompleteNumber == 1) {
for(CommandAreaShop c : commands) {
String begin = c.getCommandStart();
result.add(begin.substring(begin.indexOf(' ') + 1));
}
} else {
String[] start = new String[args.length];
start[0] = command.getName();
System.arraycopy(args, 0, start, 1, args.length - 1);
for(CommandAreaShop c : commands) {
if(c.canExecute(command, args)) {
result = c.getTabCompleteList(toCompleteNumber, start, sender);
}
}
}
// Filter and sort the results
if(result.size() > 0) {
SortedSet<String> set = new TreeSet<>();
for(String suggestion : result) {
if(suggestion.toLowerCase().startsWith(toCompletePrefix)) {
set.add(suggestion);
}
}
result.clear();
result.addAll(set);
}
//AreaShop.debug("Tabcomplete #" + toCompleteNumber + ", prefix="+ toCompletePrefix + ", result=" + result.toString());
return result;
}
}
@@ -0,0 +1,88 @@
package me.wiefferink.areashop.managers;
import me.wiefferink.areashop.AreaShop;
import me.wiefferink.areashop.features.DebugFeature;
import me.wiefferink.areashop.features.FriendsFeature;
import me.wiefferink.areashop.features.RegionFeature;
import me.wiefferink.areashop.features.TeleportFeature;
import me.wiefferink.areashop.features.WorldGuardRegionFlagsFeature;
import me.wiefferink.areashop.features.signs.SignsFeature;
import me.wiefferink.areashop.regions.GeneralRegion;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public class FeatureManager extends Manager {
// List of defined features
private static final Set<Class<? extends RegionFeature>> featureClasses = new HashSet<>(Arrays.asList(
DebugFeature.class,
SignsFeature.class,
FriendsFeature.class,
WorldGuardRegionFlagsFeature.class,
TeleportFeature.class
));
// One instance of each feature, registered for event handling
private final Set<RegionFeature> globalFeatures;
private final Map<Class<? extends RegionFeature>, Constructor<? extends RegionFeature>> regionFeatureConstructors;
/**
* Constructor.
*/
public FeatureManager() {
// Instantiate and register global features (one per type, for event handling)
globalFeatures = new HashSet<>();
for(Class<? extends RegionFeature> clazz : featureClasses) {
try {
Constructor<? extends RegionFeature> constructor = clazz.getConstructor();
try {
RegionFeature feature = constructor.newInstance();
feature.listen();
globalFeatures.add(feature);
} catch(InstantiationException | IllegalAccessException | InvocationTargetException | IllegalArgumentException e) {
AreaShop.error("Failed to instantiate global feature:", clazz, e);
}
} catch(NoSuchMethodException e) {
// Feature does not have a global part
}
}
// Setup constructors for region specific features
regionFeatureConstructors = new HashMap<>();
for(Class<? extends RegionFeature> clazz : featureClasses) {
try {
regionFeatureConstructors.put(clazz, clazz.getConstructor(GeneralRegion.class));
} catch(NoSuchMethodException | IllegalArgumentException e) {
// The feature does not have a region specific part
}
}
}
@Override
public void shutdown() {
for(RegionFeature feature : globalFeatures) {
feature.shutdown();
}
}
/**
* Instanciate a feature for a certain region.
* @param region The region to create a feature for
* @param featureClazz The class of the feature to create
* @return The feature class
*/
public RegionFeature getRegionFeature(GeneralRegion region, Class<? extends RegionFeature> featureClazz) {
try {
return regionFeatureConstructors.get(featureClazz).newInstance(region);
} catch(InstantiationException | InvocationTargetException | IllegalAccessException | IllegalArgumentException e) {
AreaShop.error("Failed to instanciate feature", featureClazz, "for region", region, e, e.getCause());
}
return null;
}
}
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,16 @@
package me.wiefferink.areashop.managers;
import me.wiefferink.areashop.AreaShop;
public abstract class Manager {
final AreaShop plugin = AreaShop.getInstance();
/**
* Called at shutdown of the plugin.
*/
public void shutdown() {
// To override by extending classes
}
}
@@ -1,225 +1,231 @@
package nl.evolutioncoding.areashop.managers;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import nl.evolutioncoding.areashop.AreaShop;
import nl.evolutioncoding.areashop.Utils;
import nl.evolutioncoding.areashop.regions.GeneralRegion;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.material.Sign;
import org.bukkit.util.BlockIterator;
public class SignLinkerManager implements Listener {
private AreaShop plugin = null;
private Map<UUID, SignLinker> signLinkers;
private boolean eventsRegistered;
public SignLinkerManager(AreaShop plugin) {
this.plugin = plugin;
signLinkers = new HashMap<UUID, SignLinker>();
eventsRegistered = false;
}
/**
* Let a player enter sign linking mode
* @param player The player that has to enter sign linking mode
* @param profile The profile to use for the signs (null for default)
*/
public void enterSignLinkMode(Player player, String profile) {
signLinkers.put(player.getUniqueId(), new SignLinker(player, profile));
plugin.message(player, "linksigns-first");
plugin.message(player, "linksigns-next");
if(!eventsRegistered) {
eventsRegistered = true;
plugin.getServer().getPluginManager().registerEvents(this, plugin);
}
}
/**
* Let a player exit sign linking mode
* @param player The player that has to exit sign linking mode
*/
public void exitSignLinkMode(Player player) {
signLinkers.remove(player.getUniqueId());
if(eventsRegistered && signLinkers.isEmpty()) {
eventsRegistered = false;
HandlerList.unregisterAll(this);
}
plugin.message(player, "linksigns-stopped");
}
/**
* Check if the player is in sign linking mode
* @param player The player to check
* @return true if the player is in sign linking mode, otherwise false
*/
public boolean isInSignLinkMode(Player player) {
return signLinkers.containsKey(player.getUniqueId());
}
@EventHandler(priority = EventPriority.HIGH)
public void onPlayerInteract(PlayerInteractEvent event) {
AreaShop.debug("PlayerInteractEvent of " + event.getPlayer().getName() + ", " + signLinkers.size() + " signlinkers");
if(isInSignLinkMode(event.getPlayer())) {
event.setCancelled(true);
Player player = event.getPlayer();
SignLinker linker = signLinkers.get(event.getPlayer().getUniqueId());
if(event.getAction() == Action.RIGHT_CLICK_AIR || event.getAction() == Action.RIGHT_CLICK_BLOCK) {
// Get the region
BlockIterator blockIterator = new BlockIterator(player, 100);
while(blockIterator.hasNext()) {
Block next = blockIterator.next();
List<GeneralRegion> regions = Utils.getASRegionsByLocation(next.getLocation());
if(regions.size() == 1) {
linker.setRegion(regions.get(0));
return;
} else if(regions.size() > 1) {
Set<String> names = new HashSet<String>();
for(GeneralRegion region : regions) {
names.add(region.getName());
}
plugin.message(player, "linksigns-multipleRegions", Utils.createCommaSeparatedList(names));
plugin.message(player, "linksigns-multipleRegionsAdvice");
return;
}
}
// No regions found within the maximum range
plugin.message(player, "linksigns-noRegions");
return;
} else if(event.getAction() == Action.LEFT_CLICK_AIR || event.getAction() == Action.LEFT_CLICK_BLOCK) {
Block block = null;
BlockIterator blockIterator = new BlockIterator(player, 100);
while(blockIterator.hasNext() && block == null) {
Block next = blockIterator.next();
if(next.getType() != Material.AIR) {
block = next;
}
}
if(block == null || !(block.getType() == Material.WALL_SIGN || block.getType() == Material.SIGN_POST)) {
plugin.message(player, "linksigns-noSign");
return;
}
GeneralRegion signRegion = plugin.getFileManager().getRegionBySignLocation(block.getLocation());
if(signRegion != null) {
plugin.message(player, "linksigns-alreadyRegistered", signRegion);
return;
}
Sign sign = (Sign)block.getState().getData();
linker.setSign(block.getLocation(), block.getType(), sign.getFacing());
return;
}
}
}
/**
* Handle disconnection players
*/
@EventHandler(priority = EventPriority.MONITOR)
public void onPlayerLeave(PlayerQuitEvent event) {
AreaShop.debug("PlayerQuitEvent of " + event.getPlayer().getName() + ", " + signLinkers.size() + " signlinkers");
signLinkers.remove(event.getPlayer().getUniqueId());
}
/**
* Class to keep track of the signlinking data
*/
private class SignLinker {
private boolean hasSign = false;
private boolean hasRegion = false;
public Player linker = null;
public String profile = null;
public GeneralRegion region = null;
public Location location = null;
public Material type = null;
public BlockFace facing = null;
public SignLinker(Player linker, String profile) {
this.linker = linker;
this.profile = profile;
}
public void setRegion(GeneralRegion region) {
this.region = region;
hasRegion = true;
if(!isComplete()) {
plugin.message(linker, "linksigns-regionFound", region);
}
finalize();
}
public void setSign(Location location, Material type, BlockFace facing) {
this.location = location;
this.type = type;
this.facing = facing;
hasSign = true;
if(!isComplete()) {
plugin.message(linker, "linksigns-signFound", location.getBlockX(), location.getBlockY(), location.getBlockZ());
}
finalize();
}
public void finalize() {
if(isComplete()) {
region.addSign(location, type, facing, profile);
if(profile == null) {
plugin.message(linker, "addsign-success", region);
} else {
plugin.message(linker, "addsign-successProfile", region, profile);
}
region.updateSigns();
reset();
plugin.message(linker, "linksigns-next");
}
}
public void reset() {
hasSign = false;
hasRegion = false;
}
public boolean isComplete() {
return hasSign && hasRegion;
}
}
}
package me.wiefferink.areashop.managers;
import me.wiefferink.areashop.features.signs.RegionSign;
import me.wiefferink.areashop.features.signs.SignsFeature;
import me.wiefferink.areashop.regions.GeneralRegion;
import me.wiefferink.areashop.tools.Utils;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.material.Sign;
import org.bukkit.util.BlockIterator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
public class SignLinkerManager extends Manager implements Listener {
private final Map<UUID, SignLinker> signLinkers;
private boolean eventsRegistered;
public SignLinkerManager() {
signLinkers = new HashMap<>();
eventsRegistered = false;
}
@Override
public void shutdown() {
for(UUID uuid : signLinkers.keySet()) {
exitSignLinkMode(Bukkit.getPlayer(uuid));
}
}
/**
* Let a player enter sign linking mode.
* @param player The player that has to enter sign linking mode
* @param profile The profile to use for the signs (null for default)
*/
public void enterSignLinkMode(Player player, String profile) {
signLinkers.put(player.getUniqueId(), new SignLinker(player, profile));
plugin.message(player, "linksigns-first");
plugin.message(player, "linksigns-next");
if(!eventsRegistered) {
eventsRegistered = true;
plugin.getServer().getPluginManager().registerEvents(this, plugin);
}
}
/**
* Let a player exit sign linking mode.
* @param player The player that has to exit sign linking mode
*/
public void exitSignLinkMode(Player player) {
signLinkers.remove(player.getUniqueId());
if(eventsRegistered && signLinkers.isEmpty()) {
eventsRegistered = false;
HandlerList.unregisterAll(this);
}
plugin.message(player, "linksigns-stopped");
}
/**
* Check if the player is in sign linking mode.
* @param player The player to check
* @return true if the player is in sign linking mode, otherwise false
*/
public boolean isInSignLinkMode(Player player) {
return signLinkers.containsKey(player.getUniqueId());
}
/**
* On player interactions.
* @param event The PlayerInteractEvent
*/
@EventHandler(priority = EventPriority.HIGH)
public void onPlayerInteract(PlayerInteractEvent event) {
if(isInSignLinkMode(event.getPlayer())) {
event.setCancelled(true);
Player player = event.getPlayer();
SignLinker linker = signLinkers.get(event.getPlayer().getUniqueId());
if(event.getAction() == Action.RIGHT_CLICK_AIR || event.getAction() == Action.RIGHT_CLICK_BLOCK) {
// Get the region
BlockIterator blockIterator = new BlockIterator(player, 100);
while(blockIterator.hasNext()) {
Block next = blockIterator.next();
List<GeneralRegion> regions = Utils.getRegions(next.getLocation());
if(regions.size() == 1) {
linker.setRegion(regions.get(0));
return;
} else if(regions.size() > 1) {
Set<String> names = new HashSet<>();
for(GeneralRegion region : regions) {
names.add(region.getName());
}
plugin.message(player, "linksigns-multipleRegions", Utils.createCommaSeparatedList(names));
plugin.message(player, "linksigns-multipleRegionsAdvice");
return;
}
}
// No regions found within the maximum range
plugin.message(player, "linksigns-noRegions");
} else if(event.getAction() == Action.LEFT_CLICK_AIR || event.getAction() == Action.LEFT_CLICK_BLOCK) {
Block block = null;
BlockIterator blockIterator = new BlockIterator(player, 100);
while(blockIterator.hasNext() && block == null) {
Block next = blockIterator.next();
if(next.getType() != Material.AIR) {
block = next;
}
}
if(block == null || !(block.getType() == Material.WALL_SIGN || block.getType() == Material.SIGN_POST)) {
plugin.message(player, "linksigns-noSign");
return;
}
RegionSign regionSign = SignsFeature.getSignByLocation(block.getLocation());
if(regionSign != null) {
plugin.message(player, "linksigns-alreadyRegistered", regionSign.getRegion());
return;
}
Sign sign = (Sign)block.getState().getData();
linker.setSign(block.getLocation(), block.getType(), sign.getFacing());
}
}
}
/**
* Handle disconnection players.
* @param event The PlayerQuitEvent
*/
@EventHandler(priority = EventPriority.MONITOR)
public void onPlayerLeave(PlayerQuitEvent event) {
exitSignLinkMode(event.getPlayer());
}
/**
* Class to keep track of the signlinking data.
*/
private class SignLinker {
private boolean hasSign = false;
private boolean hasRegion = false;
public final Player linker;
public final String profile;
public GeneralRegion region = null;
public Location location = null;
public Material type = null;
public BlockFace facing = null;
public SignLinker(Player linker, String profile) {
this.linker = linker;
this.profile = profile;
}
public void setRegion(GeneralRegion region) {
this.region = region;
hasRegion = true;
if(!isComplete()) {
plugin.message(linker, "linksigns-regionFound", region);
}
finish();
}
public void setSign(Location location, Material type, BlockFace facing) {
this.location = location;
this.type = type;
this.facing = facing;
hasSign = true;
if(!isComplete()) {
plugin.message(linker, "linksigns-signFound", location.getBlockX(), location.getBlockY(), location.getBlockZ());
}
finish();
}
public void finish() {
if(isComplete()) {
region.getSignsFeature().addSign(location, type, facing, profile);
if(profile == null) {
plugin.message(linker, "addsign-success", region);
} else {
plugin.message(linker, "addsign-successProfile", region, profile);
}
region.update();
reset();
plugin.message(linker, "linksigns-next");
}
}
public void reset() {
hasSign = false;
hasRegion = false;
}
public boolean isComplete() {
return hasSign && hasRegion;
}
}
}
@@ -0,0 +1,595 @@
package me.wiefferink.areashop.regions;
import me.wiefferink.areashop.AreaShop;
import me.wiefferink.areashop.events.ask.BuyingRegionEvent;
import me.wiefferink.areashop.events.ask.ResellingRegionEvent;
import me.wiefferink.areashop.events.ask.SellingRegionEvent;
import me.wiefferink.areashop.events.notify.BoughtRegionEvent;
import me.wiefferink.areashop.events.notify.ResoldRegionEvent;
import me.wiefferink.areashop.events.notify.SoldRegionEvent;
import me.wiefferink.areashop.tools.Utils;
import net.milkbowl.vault.economy.EconomyResponse;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.World;
import org.bukkit.command.CommandSender;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
import java.util.Calendar;
import java.util.UUID;
public class BuyRegion extends GeneralRegion {
public BuyRegion(YamlConfiguration config) {
super(config);
}
public BuyRegion(String name, World world) {
super(name, world);
}
@Override
public RegionType getType() {
return RegionType.BUY;
}
@Override
public RegionState getState() {
if(isSold() && isInResellingMode()) {
return RegionState.RESELL;
} else if(isSold() && !isInResellingMode()) {
return RegionState.SOLD;
} else {
return RegionState.FORSALE;
}
}
@Override
public boolean isAvailable() {
return !isSold();
}
/**
* Get the UUID of the owner of this region.
* @return The UUID of the owner of this region
*/
public UUID getBuyer() {
String buyer = config.getString("buy.buyer");
if(buyer != null) {
try {
return UUID.fromString(buyer);
} catch(IllegalArgumentException e) {
// Incorrect UUID
}
}
return null;
}
/**
* Check if a player is the buyer of this region.
* @param player Player to check
* @return true if this player owns this region, otherwise false
*/
public boolean isBuyer(OfflinePlayer player) {
return player != null && isBuyer(player.getUniqueId());
}
public boolean isBuyer(UUID player) {
UUID buyer = getBuyer();
return !(buyer == null || player == null) && buyer.equals(player);
}
/**
* Set the buyer of this region.
* @param buyer The UUID of the player that should be set as buyer
*/
public void setBuyer(UUID buyer) {
if(buyer == null) {
setSetting("buy.buyer", null);
setSetting("buy.buyerName", null);
} else {
setSetting("buy.buyer", buyer.toString());
setSetting("buy.buyerName", Utils.toName(buyer));
}
}
/**
* Get the name of the player that owns this region.
* @return The name of the player that owns this region, if unavailable by UUID it will return the old cached name, if that is unavailable it will return &lt;UNKNOWN&gt;
*/
public String getPlayerName() {
String result = Utils.toName(getBuyer());
if(result == null || result.isEmpty()) {
result = getStringSetting("buy.buyerName");
if(result == null || result.isEmpty()) {
result = "<UNKNOWN>";
}
}
return result;
}
/**
* Check if the region is sold.
* @return true if the region is sold, otherwise false
*/
public boolean isSold() {
return getBuyer() != null;
}
/**
* Check if the region is being resold.
* @return true if the region is available for reselling, otherwise false
*/
public boolean isInResellingMode() {
return config.getBoolean("buy.resellMode");
}
/**
* Get the price of the region.
* @return The price of the region
*/
public double getPrice() {
return Math.max(0, Utils.evaluateToDouble(getStringSetting("buy.price"), this));
}
/**
* Get the resell price of this region.
* @return The resell price if isInResellingMode(), otherwise 0.0
*/
public double getResellPrice() {
return Math.max(0, config.getDouble("buy.resellPrice"));
}
/**
* Get the formatted string of the price (includes prefix and suffix).
* @return The formatted string of the price
*/
public String getFormattedPrice() {
return Utils.formatCurrency(getPrice());
}
/**
* Get the formatted string of the resellprice (includes prefix and suffix).
* @return The formatted string of the resellprice
*/
public String getFormattedResellPrice() {
return Utils.formatCurrency(getResellPrice());
}
/**
* Change the price of the region.
* @param price The price to set this region to
*/
public void setPrice(Double price) {
setSetting("buy.price", price);
}
/**
* Set the region into resell mode with the given price.
* @param price The price this region should be put up for sale
*/
public void enableReselling(double price) {
setSetting("buy.resellMode", true);
setSetting("buy.resellPrice", price);
}
/**
* Stop this region from being in resell mode.
*/
public void disableReselling() {
setSetting("buy.resellMode", null);
setSetting("buy.resellPrice", null);
}
/**
* Get the moneyBack percentage.
* @return The % of money the player will get back when selling
*/
public double getMoneyBackPercentage() {
return Utils.evaluateToDouble(getStringSetting("buy.moneyBack"), this);
}
/**
* Get the amount of money that should be paid to the player when selling the region.
* @return The amount of money the player should get back
*/
public double getMoneyBackAmount() {
return getPrice() * (getMoneyBackPercentage() / 100.0);
}
/**
* Get the formatted string of the amount of the moneyBack amount.
* @return String with currency symbols and proper fractional part
*/
public String getFormattedMoneyBackAmount() {
return Utils.formatCurrency(getMoneyBackAmount());
}
@Override
public Object provideReplacement(String variable) {
switch(variable) {
case AreaShop.tagPrice:
return getFormattedPrice();
case AreaShop.tagRawPrice:
return getPrice();
case AreaShop.tagPlayerName:
return getPlayerName();
case AreaShop.tagPlayerUUID:
return getBuyer();
case AreaShop.tagResellPrice:
return getFormattedResellPrice();
case AreaShop.tagRawResellPrice:
return getResellPrice();
case AreaShop.tagMoneyBackAmount:
return getFormattedMoneyBackAmount();
case AreaShop.tagRawMoneyBackAmount:
return getMoneyBackAmount();
case AreaShop.tagMoneyBackPercentage:
return getMoneyBackPercentage() % 1.0 == 0.0 ? (int)getMoneyBackPercentage() : getMoneyBackPercentage();
case AreaShop.tagMaxInactiveTime:
return this.getFormattedInactiveTimeUntilSell();
default:
return super.provideReplacement(variable);
}
}
/**
* Minutes until automatic unrent when player is offline.
* @return The number of milliseconds until the region is unrented while player is offline
*/
public long getInactiveTimeUntilSell() {
return Utils.getDurationFromMinutesOrStringInput(getStringSetting("buy.inactiveTimeUntilSell"));
}
/**
* Get a human readable string indicating how long the player can be offline until automatic unrent.
* @return String indicating the inactive time until unrent
*/
public String getFormattedInactiveTimeUntilSell() {
return Utils.millisToHumanFormat(getInactiveTimeUntilSell());
}
/**
* Buy a region.
* @param offlinePlayer The player that wants to buy the region
* @return true if it succeeded and false if not
*/
@SuppressWarnings("deprecation")
public boolean buy(OfflinePlayer offlinePlayer) {
// Check if the player has permission
if(plugin.hasPermission(offlinePlayer, "areashop.buy")) {
if(plugin.getEconomy() == null) {
message(offlinePlayer, "general-noEconomy");
return false;
}
if(isInResellingMode()) {
if(!plugin.hasPermission(offlinePlayer, "areashop.buyresell")) {
message(offlinePlayer, "buy-noPermissionResell");
return false;
}
} else {
if(!plugin.hasPermission(offlinePlayer, "areashop.buynormal")) {
message(offlinePlayer, "buy-noPermissionNoResell");
return false;
}
}
if(getWorld() == null) {
message(offlinePlayer, "general-noWorld");
return false;
}
if(getRegion() == null) {
message(offlinePlayer, "general-noRegion");
return false;
}
if(!isSold() || (isInResellingMode() && !isBuyer(offlinePlayer))) {
boolean isResell = isInResellingMode();
// Only relevant if the player is online
Player player = offlinePlayer.getPlayer();
if(player != null) {
// Check if the players needs to be in the region for buying
if(restrictedToRegion() && (!player.getWorld().getName().equals(getWorldName())
|| !getRegion().contains(player.getLocation().getBlockX(), player.getLocation().getBlockY(), player.getLocation().getBlockZ()))) {
message(offlinePlayer, "buy-restrictedToRegion");
return false;
}
// Check if the players needs to be in the world for buying
if(restrictedToWorld() && !player.getWorld().getName().equals(getWorldName())) {
message(offlinePlayer, "buy-restrictedToWorld", player.getWorld().getName());
return false;
}
}
// Check region limits
LimitResult limitResult = this.limitsAllow(RegionType.BUY, offlinePlayer);
AreaShop.debug("LimitResult: " + limitResult.toString());
if(!limitResult.actionAllowed()) {
if(limitResult.getLimitingFactor() == LimitType.TOTAL) {
message(offlinePlayer, "total-maximum", limitResult.getMaximum(), limitResult.getCurrent(), limitResult.getLimitingGroup());
return false;
}
if(limitResult.getLimitingFactor() == LimitType.BUYS) {
message(offlinePlayer, "buy-maximum", limitResult.getMaximum(), limitResult.getCurrent(), limitResult.getLimitingGroup());
return false;
}
// Should not be reached, but is safe like this
return false;
}
// Check if the player has enough money
if((!isResell && plugin.getEconomy().has(offlinePlayer, getWorldName(), getPrice())) || (isResell && plugin.getEconomy().has(offlinePlayer, getWorldName(), getResellPrice()))) {
UUID oldOwner = getBuyer();
if(isResell && oldOwner != null) {
// Broadcast and check event
ResellingRegionEvent event = new ResellingRegionEvent(this, offlinePlayer);
Bukkit.getPluginManager().callEvent(event);
if(event.isCancelled()) {
message(offlinePlayer, "general-cancelled", event.getReason());
return false;
}
getFriendsFeature().clearFriends();
double resellPrice = getResellPrice();
// Transfer the money to the previous owner
EconomyResponse r = plugin.getEconomy().withdrawPlayer(offlinePlayer, getWorldName(), getResellPrice());
if(!r.transactionSuccess()) {
message(offlinePlayer, "buy-payError");
AreaShop.debug("Something went wrong with getting money from " + offlinePlayer.getName() + " while buying " + getName() + ": " + r.errorMessage);
return false;
}
r = null;
OfflinePlayer oldOwnerPlayer = Bukkit.getOfflinePlayer(oldOwner);
String oldOwnerName = getPlayerName();
if(oldOwnerPlayer != null && oldOwnerPlayer.getName() != null) {
r = plugin.getEconomy().depositPlayer(oldOwnerPlayer, getWorldName(), getResellPrice());
oldOwnerName = oldOwnerPlayer.getName();
} else if(oldOwnerName != null) {
r = plugin.getEconomy().depositPlayer(oldOwnerName, getWorldName(), getResellPrice());
}
if(r == null || !r.transactionSuccess()) {
AreaShop.warn("Something went wrong with paying '" + oldOwnerName + "' " + getFormattedPrice() + " for his resell of region " + getName() + " to " + offlinePlayer.getName());
}
// Resell is done, disable that now
disableReselling();
// Run commands
this.runEventCommands(RegionEvent.RESELL, true);
// Set the owner
setBuyer(offlinePlayer.getUniqueId());
updateLastActiveTime();
// Update everything
handleSchematicEvent(RegionEvent.RESELL);
// Notify about updates
this.notifyAndUpdate(new ResoldRegionEvent(this, oldOwner));
// Send message to the player
message(offlinePlayer, "buy-successResale", oldOwnerName);
Player seller = Bukkit.getPlayer(oldOwner);
if(seller != null) {
message(seller, "buy-successSeller", resellPrice);
}
// Run commands
this.runEventCommands(RegionEvent.RESELL, false);
} else {
// Broadcast and check event
BuyingRegionEvent event = new BuyingRegionEvent(this, offlinePlayer);
Bukkit.getPluginManager().callEvent(event);
if(event.isCancelled()) {
message(offlinePlayer, "general-cancelled", event.getReason());
return false;
}
// Substract the money from the players balance
EconomyResponse r = plugin.getEconomy().withdrawPlayer(offlinePlayer, getWorldName(), getPrice());
if(!r.transactionSuccess()) {
message(offlinePlayer, "buy-payError");
return false;
}
// Optionally give money to the landlord
OfflinePlayer landlordPlayer = null;
if(getLandlord() != null) {
landlordPlayer = Bukkit.getOfflinePlayer(getLandlord());
}
String landlordName = getLandlordName();
if(landlordName != null) {
if(landlordPlayer != null && landlordPlayer.getName() != null) {
r = plugin.getEconomy().depositPlayer(landlordPlayer, getWorldName(), getPrice());
} else {
r = plugin.getEconomy().depositPlayer(landlordName, getWorldName(), getPrice());
}
if(r != null && !r.transactionSuccess()) {
AreaShop.warn("Something went wrong with paying '" + landlordName + "' " + getFormattedPrice() + " for his sell of region " + getName() + " to " + offlinePlayer.getName());
}
}
// Run commands
this.runEventCommands(RegionEvent.BOUGHT, true);
// Set the owner
setBuyer(offlinePlayer.getUniqueId());
updateLastActiveTime();
// Notify about updates
this.notifyAndUpdate(new BoughtRegionEvent(this));
// Update everything
handleSchematicEvent(RegionEvent.BOUGHT);
// Send message to the player
message(offlinePlayer, "buy-succes");
// Run commands
this.runEventCommands(RegionEvent.BOUGHT, false);
}
return true;
} else {
// Player has not enough money
if(isResell) {
message(offlinePlayer, "buy-lowMoneyResell", Utils.formatCurrency(plugin.getEconomy().getBalance(offlinePlayer, getWorldName())));
} else {
message(offlinePlayer, "buy-lowMoney", Utils.formatCurrency(plugin.getEconomy().getBalance(offlinePlayer, getWorldName())));
}
}
} else {
if(isBuyer(offlinePlayer)) {
message(offlinePlayer, "buy-yours");
} else {
message(offlinePlayer, "buy-someoneElse");
}
}
} else {
message(offlinePlayer, "buy-noPermission");
}
return false;
}
/**
* Sell a buyed region, get part of the money back.
* @param giveMoneyBack true if the player should be given money back, otherwise false
* @param executor CommandSender to receive a message when the sell fails, or null
* @return true if the region has been sold, otherwise false
*/
@SuppressWarnings("deprecation")
public boolean sell(boolean giveMoneyBack, CommandSender executor) {
boolean own = executor instanceof Player && this.isBuyer((Player)executor);
if(executor != null) {
if(!executor.hasPermission("areashop.sell") && !own) {
message(executor, "sell-noPermissionOther");
return false;
}
if(!executor.hasPermission("areashop.sell") && !executor.hasPermission("areashop.sellown") && own) {
message(executor, "sell-noPermission");
return false;
}
if(!executor.hasPermission("areashop.sell")
&& executor.hasPermission("areashop.sellown")
&& own
&& getBooleanSetting("buy.sellDisabled")) {
message(executor, "sell-disabled");
return false;
}
}
if(plugin.getEconomy() == null) {
return false;
}
// Broadcast and check event
SellingRegionEvent event = new SellingRegionEvent(this);
Bukkit.getPluginManager().callEvent(event);
if(event.isCancelled()) {
message(executor, "general-cancelled", event.getReason());
return false;
}
// Run commands
this.runEventCommands(RegionEvent.SOLD, true);
disableReselling();
// Give part of the buying price back
double moneyBack = getMoneyBackAmount();
if(moneyBack > 0 && giveMoneyBack) {
boolean noPayBack = false;
OfflinePlayer landlordPlayer = null;
if(getLandlord() != null) {
landlordPlayer = Bukkit.getOfflinePlayer(getLandlord());
}
String landlordName = getLandlordName();
EconomyResponse r;
if(landlordName != null) {
if(landlordPlayer != null && landlordPlayer.getName() != null) {
r = plugin.getEconomy().withdrawPlayer(landlordPlayer, getWorldName(), moneyBack);
} else {
r = plugin.getEconomy().withdrawPlayer(landlordName, getWorldName(), moneyBack);
}
if(r == null || !r.transactionSuccess()) {
noPayBack = true;
}
}
// Give back the money
OfflinePlayer player = Bukkit.getOfflinePlayer(getBuyer());
if(player != null && !noPayBack) {
EconomyResponse response = null;
boolean error = false;
try {
if(player.getName() != null) {
response = plugin.getEconomy().depositPlayer(player, getWorldName(), moneyBack);
} else if(getPlayerName() != null) {
response = plugin.getEconomy().depositPlayer(getPlayerName(), getWorldName(), moneyBack);
}
} catch(Exception e) {
error = true;
}
if(error || response == null || !response.transactionSuccess()) {
AreaShop.warn("Something went wrong with paying back money to " + getPlayerName() + " while selling region " + getName());
}
}
}
message(executor, "sell-sold");
// Handle schematic save/restore (while %uuid% is still available)
handleSchematicEvent(RegionEvent.SOLD);
// Remove friends and the owner
getFriendsFeature().clearFriends();
UUID oldBuyer = getBuyer();
setBuyer(null);
removeLastActiveTime();
// Notify about updates
this.notifyAndUpdate(new SoldRegionEvent(this, oldBuyer, Math.max(moneyBack, 0)));
// Run commands
this.runEventCommands(RegionEvent.SOLD, false);
return true;
}
@Override
public boolean checkInactive() {
if(isDeleted() || !isSold()) {
return false;
}
long inactiveSetting = getInactiveTimeUntilSell();
OfflinePlayer player = Bukkit.getOfflinePlayer(getBuyer());
if(inactiveSetting <= 0 || player.isOp()) {
return false;
}
long lastPlayed = getLastActiveTime();
//AreaShop.debug("currentTime=" + Calendar.getInstance().getTimeInMillis() + ", getLastPlayed()=" + lastPlayed + ", timeInactive=" + (Calendar.getInstance().getTimeInMillis()-player.getLastPlayed()) + ", inactiveSetting=" + inactiveSetting);
if(Calendar.getInstance().getTimeInMillis() > (lastPlayed + inactiveSetting)) {
AreaShop.info("Region " + getName() + " unrented because of inactivity for player " + getPlayerName());
AreaShop.debug("currentTime=" + Calendar.getInstance().getTimeInMillis() + ", getLastPlayed()=" + lastPlayed + ", timeInactive=" + (Calendar.getInstance().getTimeInMillis() - player.getLastPlayed()) + ", inactiveSetting=" + inactiveSetting);
return this.sell(true, null);
}
return false;
}
}
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,7 @@
# Regions
This package contains the `GeneralRegion` class which represents a region in AreaShop. Such a region is linked to a WorldGuard region and has its own configuration file at `/plugins/AreaShop/regions/<name>.yml`.
The `BuyRegion` and `RentRegion` classes represent buy and rental regions (mutually exclusive) and inherit from `GeneralRegion`.
To group regions there is `RegionGroup`, which allows configuring settings for a lot of regions at once.
@@ -0,0 +1,225 @@
package me.wiefferink.areashop.regions;
import me.wiefferink.areashop.AreaShop;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.YamlConfiguration;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
// TODO consider switching to saving lowercase regions
public class RegionGroup {
private final AreaShop plugin;
private final String name;
private final Set<String> regions;
private Set<String> autoRegions;
private boolean autoDirty;
private final Set<String> worlds;
/**
* Constructor, used when creating new groups or restoring them from groups.yml at server boot.
* @param plugin The AreaShop plugin
* @param name Name of the group, has to be unique
*/
public RegionGroup(AreaShop plugin, String name) {
this.plugin = plugin;
this.name = name;
this.autoDirty = true;
setSetting("name", name);
// Load regions and worlds
regions = new HashSet<>(getSettings().getStringList("regions"));
worlds = new HashSet<>(getSettings().getStringList("worlds"));
}
/**
* Get automatically added regions.
* @return Set of regions automatically added by the configuration
*/
public Set<String> getAutoRegions() {
if(autoDirty) {
autoRegions = new HashSet<>();
for(GeneralRegion region : plugin.getFileManager().getRegions()) {
if(worlds.contains(region.getWorldName())) {
autoRegions.add(region.getName());
}
}
autoDirty = false;
}
return autoRegions;
}
/**
* Mark that automatically added regions should be regenerated.
*/
public void autoDirty() {
autoDirty = true;
}
/**
* Adds a world from which all regions should be added to the group.
* @param world World from which all regions should be added
* @return true if the region was not already added, otherwise false
*/
public boolean addWorld(String world) {
if(worlds.add(world)) {
setSetting("regionsFromWorlds", new ArrayList<>(worlds));
saveRequired();
autoDirty();
return true;
}
return false;
}
/**
* Remove a member from the group.
* @param world World to remove
* @return true if the region was in the group before, otherwise false
*/
public boolean removeWorld(String world) {
if(worlds.remove(world)) {
setSetting("regionsFromWorlds", new ArrayList<>(worlds));
saveRequired();
autoDirty();
return true;
}
return false;
}
/**
* Get all worlds from which regions are added automatically.
* @return A list with the names of all worlds (immutable)
*/
public Set<String> getWorlds() {
return new HashSet<>(worlds);
}
/**
* Adds a member to a group.
* @param region The region to add to the group (GeneralRegion or a subclass of it)
* @return true if the region was not already added, otherwise false
*/
public boolean addMember(GeneralRegion region) {
if(regions.add(region.getName())) {
setSetting("regions", new ArrayList<>(regions));
saveRequired();
return true;
}
return false;
}
/**
* Remove a member from the group.
* @param region The region to remove
* @return true if the region was in the group before, otherwise false
*/
public boolean removeMember(GeneralRegion region) {
if(regions.remove(region.getName())) {
setSetting("regions", new ArrayList<>(regions));
saveRequired();
return true;
}
return false;
}
/**
* Get all members of the group.
* @return A list with the names of all members of the group (immutable)
*/
public Set<String> getMembers() {
HashSet<String> result = new HashSet<>(regions);
result.addAll(getAutoRegions());
return result;
}
/**
* Get all manually added members of the group.
* @return A list with the names of all members of the group (immutable)
*/
public Set<String> getManualMembers() {
return new HashSet<>(regions);
}
/**
* Get all members of the group as GeneralRegions.
* @return A Set with all group members
*/
public Set<GeneralRegion> getMemberRegions() {
Set<GeneralRegion> result = new HashSet<>();
for(String name : getMembers()) {
result.add(plugin.getFileManager().getRegion(name));
}
return result;
}
/**
* Get the name of the group.
* @return The name of the group
*/
public String getName() {
return name;
}
/**
* Get the lowercase name of the group (used for getting the config etc).
* @return The name of the group in lowercase
*/
public String getLowerCaseName() {
return getName().toLowerCase();
}
/**
* Check if a region is member of the group.
* @param region Region to check
* @return true if the region is in the group, otherwise false
*/
public boolean isMember(GeneralRegion region) {
return getMembers().contains(region.getName());
}
/**
* Get the priority of the group (higher overwrites).
* @return The priority of the group
*/
public int getPriority() {
return getSettings().getInt("priority");
}
/**
* Get the configurationsection with the settings of this group.
* @return The ConfigurationSection with the settings of the group
*/
public ConfigurationSection getSettings() {
ConfigurationSection result = plugin.getFileManager().getGroupSettings(name);
if(result != null) {
return result;
} else {
return new YamlConfiguration();
}
}
/**
* Set a setting of this group.
* @param path The path to set
* @param setting The value to set
*/
public void setSetting(String path, Object setting) {
plugin.getFileManager().setGroupSetting(this, path, setting);
}
/**
* Indicates this file needs to be saved, will actually get saved later by a task.
*/
public void saveRequired() {
plugin.getFileManager().saveGroupsIsRequired();
}
/**
* Save the groups to disk now, normally saveRequired() is preferred because of performance.
*/
public void saveNow() {
plugin.getFileManager().saveGroupsNow();
}
}
@@ -0,0 +1,762 @@
package me.wiefferink.areashop.regions;
import me.wiefferink.areashop.AreaShop;
import me.wiefferink.areashop.events.ask.RentingRegionEvent;
import me.wiefferink.areashop.events.ask.UnrentingRegionEvent;
import me.wiefferink.areashop.events.notify.RentedRegionEvent;
import me.wiefferink.areashop.events.notify.UnrentedRegionEvent;
import me.wiefferink.areashop.tools.Utils;
import net.milkbowl.vault.economy.EconomyResponse;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.World;
import org.bukkit.command.CommandSender;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import static me.wiefferink.areashop.tools.Utils.millisToHumanFormat;
public class RentRegion extends GeneralRegion {
private long warningsDoneUntil = Calendar.getInstance().getTimeInMillis();
/**
* Constructor.
* @param config All settings of this region
*/
public RentRegion(YamlConfiguration config) {
super(config);
}
/**
* Create a new RentRegion.
* @param name The name of the region (correct casing)
* @param world The world of the WorldGuard region
*/
public RentRegion(String name, World world) {
super(name, world);
}
@Override
public RegionType getType() {
return RegionType.RENT;
}
@Override
public RegionState getState() {
if(isRented()) {
return RegionState.RENTED;
} else {
return RegionState.FORRENT;
}
}
@Override
public boolean isAvailable() {
return !isRented();
}
/**
* Get the UUID of the player renting the region.
* @return The UUID of the renter
*/
public UUID getRenter() {
String renter = config.getString("rent.renter");
if(renter != null) {
try {
return UUID.fromString(renter);
} catch(IllegalArgumentException e) {
// Incorrect UUID
}
}
return null;
}
/**
* Check if a player is the renter of this region.
* @param player Player to check
* @return true if this player rents this region, otherwise false
*/
public boolean isRenter(Player player) {
return player != null && isRenter(player.getUniqueId());
}
public boolean isRenter(UUID player) {
UUID renter = getRenter();
return !(player == null || renter == null) && renter.equals(player);
}
/**
* Set the renter of this region.
* @param renter The UUID of the player that should be set as the renter
*/
public void setRenter(UUID renter) {
if(renter == null) {
setSetting("rent.renter", null);
setSetting("rent.renterName", null);
} else {
setSetting("rent.renter", renter.toString());
setSetting("rent.renterName", Utils.toName(renter));
}
}
/**
* Get the max number of extends of this region.
* @return -1 if infinite otherwise the maximum number
*/
public int getMaxExtends() {
return getIntegerSetting("rent.maxExtends");
}
/**
* Get how many times the rent has already been extended.
* @return The number of times extended
*/
public int getTimesExtended() {
return config.getInt("rent.timesExtended");
}
/**
* Set the number of times the region has been extended.
* @param times The number of times the region has been extended
*/
public void setTimesExtended(int times) {
if(times < 0) {
setSetting("rent.timesExtended", null);
} else {
setSetting("rent.timesExtended", times);
}
}
@Override
public Object provideReplacement(String variable) {
switch(variable) {
case AreaShop.tagPrice:
return getFormattedPrice();
case AreaShop.tagRawPrice:
return getPrice();
case AreaShop.tagDuration:
return getDurationString();
case AreaShop.tagPlayerName:
return getPlayerName();
case AreaShop.tagPlayerUUID:
return getRenter();
case AreaShop.tagRentedUntil:
return new SimpleDateFormat(plugin.getConfig().getString("timeFormatChat")).format(new Date(getRentedUntil()));
case AreaShop.tagRentedUntilShort:
return new SimpleDateFormat(plugin.getConfig().getString("timeFormatSign")).format(new Date(getRentedUntil()));
case AreaShop.tagTimeLeft:
return getTimeLeftString();
case AreaShop.tagMoneyBackAmount:
return getFormattedMoneyBackAmount();
case AreaShop.tagRawMoneyBackAmount:
return getMoneyBackAmount();
case AreaShop.tagMoneyBackPercentage:
return (getMoneyBackPercentage() % 1.0) == 0.0 ? (int)getMoneyBackPercentage() : getMoneyBackPercentage();
case AreaShop.tagTimesExtended:
return this.getTimesExtended();
case AreaShop.tagMaxExtends:
return this.getMaxExtends();
case AreaShop.tagExtendsLeft:
return getMaxExtends() - getTimesExtended();
case AreaShop.tagMaxRentTime:
return millisToHumanFormat(getMaxRentTime());
case AreaShop.tagMaxInactiveTime:
return this.getFormattedInactiveTimeUntilUnrent();
default:
return super.provideReplacement(variable);
}
}
/**
* Check if the region is rented.
* @return true if the region is rented, otherwise false
*/
public boolean isRented() {
return getRenter() != null;
}
/**
* Get the name of the player renting this region.
* @return Name of the player renting this region, if unavailable by UUID it will return the old cached name, if that is unavailable it will return &lt;UNKNOWN&gt;
*/
public String getPlayerName() {
String result = Utils.toName(getRenter());
if(result == null || result.isEmpty()) {
result = config.getString("rent.renterName");
if(result == null || result.isEmpty()) {
result = "<UNKNOWN>";
}
}
return result;
}
/**
* Get the time until this region is rented (time from 1970 epoch).
* @return The epoch time until which this region is rented
*/
public long getRentedUntil() {
return getLongSetting("rent.rentedUntil");
}
/**
* Set the time until the region is rented (milliseconds from 1970, system time).
* @param rentedUntil The time until the region is rented
*/
public void setRentedUntil(Long rentedUntil) {
if(rentedUntil == null) {
setSetting("rent.rentedUntil", null);
} else {
setSetting("rent.rentedUntil", rentedUntil);
}
}
/**
* Get the price of the region.
* @return The price of the region
*/
public double getPrice() {
return Math.max(0, Utils.evaluateToDouble(getStringSetting("rent.price"), this));
}
/**
* Get the formatted string of the price (includes prefix and suffix).
* @return The formatted string of the price
*/
public String getFormattedPrice() {
return Utils.formatCurrency(getPrice());
}
/**
* Get the duration of 1 rent period.
* @return The duration in milliseconds of 1 rent period
*/
public long getDuration() {
return Utils.durationStringToLong(getDurationString());
}
/**
* Get the duration string, includes 'number indentifier'.
* @return The duration string
*/
public String getDurationString() {
return getStringSetting("rent.duration");
}
/**
* Get the time that is left on the region.
* @return The time left on the region
*/
public long getTimeLeft() {
if(isRented()) {
return this.getRentedUntil() - Calendar.getInstance().getTimeInMillis();
} else {
return 0;
}
}
/**
* Get a formatted string indicating the rent time that is left.
* @return Time left on the rent, for example '29 days', '3 months', '1 second'
*/
public String getTimeLeftString() {
return Utils.millisToHumanFormat(getTimeLeft());
}
/**
* Minutes until automatic unrent when player is offline.
* @return The number of milliseconds until the region is unrented while player is offline
*/
public long getInactiveTimeUntilUnrent() {
return Utils.getDurationFromMinutesOrStringInput(getStringSetting("rent.inactiveTimeUntilUnrent"));
}
/**
* Get a human readable string indicating how long the player can be offline until automatic unrent.
* @return String indicating the inactive time until unrent
*/
public String getFormattedInactiveTimeUntilUnrent() {
return Utils.millisToHumanFormat(getInactiveTimeUntilUnrent());
}
/**
* Change the price of the region.
* @param price The price of the region
*/
public void setPrice(Double price) {
setSetting("rent.price", price);
}
/**
* Set the duration of the rent.
* @param duration The duration of the rent (as specified on the documentation pages)
*/
public void setDuration(String duration) {
setSetting("rent.duration", duration);
}
/**
* Get the moneyBack percentage.
* @return The % of money the player will get back when unrenting
*/
public double getMoneyBackPercentage() {
return Utils.evaluateToDouble(getStringSetting("rent.moneyBack"), this);
}
/**
* Get the amount of money that should be paid to the player when unrenting the region.
* @return The amount of money the player should get back
*/
public double getMoneyBackAmount() {
Long currentTime = Calendar.getInstance().getTimeInMillis();
Double timeLeft = (double)((getRentedUntil() - currentTime));
double percentage = (getMoneyBackPercentage()) / 100.0;
Double timePeriod = (double)(getDuration());
double periods = timeLeft / timePeriod;
return Math.max(0, periods * getPrice() * percentage);
}
/**
* Get the formatted string of the amount of the moneyBack amount.
* @return String with currency symbols and proper fractional part
*/
public String getFormattedMoneyBackAmount() {
return Utils.formatCurrency(getMoneyBackAmount());
}
/**
* Get the maximum time the player can rent the region in advance (milliseconds).
* @return The maximum rent time in milliseconds
*/
public long getMaxRentTime() {
return Utils.getDurationFromMinutesOrStringInput(getStringSetting("rent.maxRentTime"));
}
/**
* Check if the rent should expire.
* @return true if the rent has expired and has been unrented, false otherwise
*/
public boolean checkExpiration() {
long now = Calendar.getInstance().getTimeInMillis();
if(!isDeleted() && isRented() && now > getRentedUntil()) {
// Extend rent if configured for that
if(getBooleanSetting("rent.autoExtend")) {
if(extend()) {
return false;
}
}
// Send message to the player if online
Player player = Bukkit.getPlayer(getRenter());
if(unRent(false, null)) {
if(player != null) {
message(player, "unrent-expired");
}
return true;
}
}
return false;
}
/**
* Send the expiration warnings from the selected profile which is specified in the config.
* Sends all warnings since previous call until (now + normal delay), delay can be found in the config as well.
*/
public void sendExpirationWarnings() {
// Send from warningsDoneUntil to current+delay
if(isDeleted() || !isRented()) {
return;
}
ConfigurationSection profileSection = getConfigurationSectionSetting("rent.expirationWarningProfile", "expirationWarningProfiles");
if(profileSection == null) {
return;
}
// Check if a warning needs to be send for each defined point in time
Player player = Bukkit.getPlayer(getRenter());
long sendUntil = Calendar.getInstance().getTimeInMillis() + (plugin.getConfig().getInt("expireWarning.delay") * 60 * 1000);
for(String timeBefore : profileSection.getKeys(false)) {
long timeBeforeParsed = Utils.durationStringToLong(timeBefore);
if(timeBeforeParsed <= 0) {
return;
}
long checkTime = getRentedUntil() - timeBeforeParsed;
if(checkTime > warningsDoneUntil && checkTime <= sendUntil) {
List<String> commands;
if(profileSection.isConfigurationSection(timeBefore)) {
/* Legacy config layout:
* "1 minute":
* warnPlayer: true
* commands: ["say hi"]
*/
commands = profileSection.getStringList(timeBefore + ".commands");
// Warn player
if(profileSection.getBoolean(timeBefore + ".warnPlayer") && player != null) {
message(player, "rent-expireWarning");
}
} else {
commands = profileSection.getStringList(timeBefore);
}
this.runCommands(Bukkit.getConsoleSender(), commands);
}
}
warningsDoneUntil = sendUntil;
}
/**
* Try to extend the rent for the current owner, respecting all restrictions.
* @return true if successful, otherwise false
*/
public boolean extend() {
if(!isRented()) {
return false;
}
OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(getRenter());
return offlinePlayer != null && rent(offlinePlayer);
}
/**
* Rent a region.
* @param offlinePlayer The player that wants to rent the region
* @return true if it succeeded and false if not
*/
public boolean rent(OfflinePlayer offlinePlayer) {
if(plugin.getEconomy() == null) {
message(offlinePlayer, "general-noEconomy");
return false;
}
//Check if the player has permission
if(plugin.hasPermission(offlinePlayer, "areashop.rent")) {
if(getWorld() == null) {
message(offlinePlayer, "general-noWorld");
return false;
}
if(getRegion() == null) {
message(offlinePlayer, "general-noRegion");
return false;
}
boolean extend = false;
if(getRenter() != null && offlinePlayer.getUniqueId().equals(getRenter())) {
extend = true;
}
// Check if the region is available for renting or if the player wants to extend the rent
if(!isRented() || extend) {
// These checks are only relevant for online players doing the renting/buying themselves
Player player = offlinePlayer.getPlayer();
if(player != null) {
// Check if the players needs to be in the region for renting
if(restrictedToRegion() && (!player.getWorld().getName().equals(getWorldName())
|| !getRegion().contains(player.getLocation().getBlockX(), player.getLocation().getBlockY(), player.getLocation().getBlockZ()))) {
message(offlinePlayer, "rent-restrictedToRegion");
return false;
}
// Check if the players needs to be in the world for renting
if(restrictedToWorld() && !player.getWorld().getName().equals(getWorldName())) {
message(offlinePlayer, "rent-restrictedToWorld", player.getWorld().getName());
return false;
}
}
// Check region limits if this is not extending
if(!(extend && config.getBoolean("allowRegionExtendsWhenAboveLimits"))) {
LimitResult limitResult;
if(extend) {
limitResult = this.limitsAllow(RegionType.RENT, offlinePlayer, true);
} else {
limitResult = this.limitsAllow(RegionType.RENT, offlinePlayer);
}
AreaShop.debug("LimitResult: " + limitResult.toString());
if(!limitResult.actionAllowed()) {
if(limitResult.getLimitingFactor() == LimitType.TOTAL) {
message(offlinePlayer, "total-maximum", limitResult.getMaximum(), limitResult.getCurrent(), limitResult.getLimitingGroup());
return false;
}
if(limitResult.getLimitingFactor() == LimitType.RENTS) {
message(offlinePlayer, "rent-maximum", limitResult.getMaximum(), limitResult.getCurrent(), limitResult.getLimitingGroup());
return false;
}
if(limitResult.getLimitingFactor() == LimitType.EXTEND) {
message(offlinePlayer, "rent-maximumExtend", limitResult.getMaximum(), limitResult.getCurrent() + 1, limitResult.getLimitingGroup());
return false;
}
return false;
}
}
// Check if the player can still extend this rent
if(extend && !plugin.hasPermission(offlinePlayer, "areashop.rentextendbypass")) {
if(getMaxExtends() >= 0 && getTimesExtended() >= getMaxExtends()) {
message(offlinePlayer, "rent-maxExtends");
return false;
}
}
// Check if there is enough time left before hitting maxRentTime
boolean extendToMax = false;
double price = getPrice();
long timeNow = Calendar.getInstance().getTimeInMillis();
long timeRented = 0;
long maxRentTime = getMaxRentTime();
if(isRented()) {
timeRented = getRentedUntil() - timeNow;
}
if((timeRented + getDuration()) > (maxRentTime)
&& !plugin.hasPermission(offlinePlayer, "areashop.renttimebypass")
&& maxRentTime != -1) {
// Extend to the maximum instead of adding a full period
if(getBooleanSetting("rent.extendToFullWhenAboveMaxRentTime")) {
if(timeRented >= maxRentTime) {
message(offlinePlayer, "rent-alreadyAtFull");
return false;
} else {
long toRentPart = maxRentTime - timeRented;
extendToMax = true;
price = ((double)toRentPart) / getDuration() * price;
}
} else {
message(offlinePlayer, "rent-maxRentTime");
return false;
}
}
if(plugin.getEconomy().has(offlinePlayer, getWorldName(), price)) {
// Broadcast and check event
RentingRegionEvent event = new RentingRegionEvent(this, offlinePlayer, extend);
Bukkit.getPluginManager().callEvent(event);
if(event.isCancelled()) {
message(offlinePlayer, "general-cancelled", event.getReason());
return false;
}
// Substract the money from the players balance
EconomyResponse r = plugin.getEconomy().withdrawPlayer(offlinePlayer, getWorldName(), price);
if(!r.transactionSuccess()) {
message(offlinePlayer, "rent-payError");
AreaShop.debug("Something went wrong with getting money from " + offlinePlayer.getName() + " while renting " + getName() + ": " + r.errorMessage);
return false;
}
// Optionally give money to the landlord
OfflinePlayer landlordPlayer = null;
if(getLandlord() != null) {
landlordPlayer = Bukkit.getOfflinePlayer(getLandlord());
}
String landlordName = getLandlordName();
if(landlordName != null) {
if(landlordPlayer != null && landlordPlayer.getName() != null) {
r = plugin.getEconomy().depositPlayer(landlordPlayer, getWorldName(), price);
} else {
r = plugin.getEconomy().depositPlayer(landlordName, getWorldName(), price);
}
if(r == null || !r.transactionSuccess()) {
AreaShop.warn("Something went wrong with paying '" + landlordName + "' " + Utils.formatCurrency(price) + " for his rent of region " + getName() + " to " + offlinePlayer.getName());
}
}
if(!extend) {
// Run commands
runEventCommands(RegionEvent.RENTED, true);
} else {
// Run commands
runEventCommands(RegionEvent.EXTENDED, true);
}
// Get the time until the region will be rented
Calendar calendar = Calendar.getInstance();
if(extendToMax) {
calendar.setTimeInMillis(calendar.getTimeInMillis() + getMaxRentTime());
} else if(extend) {
calendar.setTimeInMillis(getRentedUntil() + getDuration());
} else {
calendar.setTimeInMillis(calendar.getTimeInMillis() + getDuration());
}
// Add values to the rent and send it to FileManager
setRentedUntil(calendar.getTimeInMillis());
setRenter(offlinePlayer.getUniqueId());
updateLastActiveTime();
// Fire schematic event and updated times extended
if(!extend) {
this.handleSchematicEvent(RegionEvent.RENTED);
setTimesExtended(0);
} else {
setTimesExtended(getTimesExtended() + 1);
}
// Notify about updates
this.notifyAndUpdate(new RentedRegionEvent(this, extend));
// Send message to the player
if(extendToMax) {
message(offlinePlayer, "rent-extendedToMax");
} else if(extend) {
message(offlinePlayer, "rent-extended");
} else {
message(offlinePlayer, "rent-rented");
}
if(!extend) {
// Run commands
this.runEventCommands(RegionEvent.RENTED, false);
} else {
// Run commands
this.runEventCommands(RegionEvent.EXTENDED, false);
}
return true;
} else {
// Player has not enough money
if(extend) {
message(offlinePlayer, "rent-lowMoneyExtend", Utils.formatCurrency(plugin.getEconomy().getBalance(offlinePlayer, getWorldName())));
} else {
message(offlinePlayer, "rent-lowMoneyRent", Utils.formatCurrency(plugin.getEconomy().getBalance(offlinePlayer, getWorldName())));
}
}
} else {
message(offlinePlayer, "rent-someoneElse");
}
} else {
message(offlinePlayer, "rent-noPermission");
}
return false;
}
/**
* Unrent a region, reset to unrented.
* @param giveMoneyBack true if money should be given back to the player, false otherwise
* @param executor The CommandSender that should get the cancelled message if there is any, or null
* @return true if unrenting succeeded, othwerwise false
*/
@SuppressWarnings("deprecation")
public boolean unRent(boolean giveMoneyBack, CommandSender executor) {
boolean own = executor instanceof Player && this.isRenter((Player) executor);
if(executor != null) {
if(!executor.hasPermission("areashop.unrent") && !own) {
message(executor, "unrent-noPermissionOther");
return false;
}
if(!executor.hasPermission("areashop.unrent") && !executor.hasPermission("areashop.unrentown") && own) {
message(executor, "unrent-noPermission");
return false;
}
}
if(plugin.getEconomy() == null) {
return false;
}
// Broadcast and check event
UnrentingRegionEvent event = new UnrentingRegionEvent(this);
Bukkit.getPluginManager().callEvent(event);
if(event.isCancelled()) {
message(executor, "general-cancelled", event.getReason());
return false;
}
// Run commands
this.runEventCommands(RegionEvent.UNRENTED, true);
double moneyBack = getMoneyBackAmount();
if(moneyBack > 0 && giveMoneyBack) {
boolean noPayBack = false;
OfflinePlayer landlordPlayer = null;
if(getLandlord() != null) {
landlordPlayer = Bukkit.getOfflinePlayer(getLandlord());
}
String landlordName = getLandlordName();
EconomyResponse r;
if(landlordName != null) {
if(landlordPlayer != null && landlordPlayer.getName() != null) {
r = plugin.getEconomy().withdrawPlayer(landlordPlayer, getWorldName(), moneyBack);
} else {
r = plugin.getEconomy().withdrawPlayer(landlordName, getWorldName(), moneyBack);
}
if(r == null || !r.transactionSuccess()) {
noPayBack = true;
}
}
// Give back the money
OfflinePlayer player = Bukkit.getOfflinePlayer(getRenter());
if(player != null && !noPayBack) {
r = null;
boolean error = false;
try {
if(player.getName() != null) {
r = plugin.getEconomy().depositPlayer(player, getWorldName(), moneyBack);
} else if(getPlayerName() != null) {
r = plugin.getEconomy().depositPlayer(getPlayerName(), getWorldName(), moneyBack);
}
} catch(Exception e) {
error = true;
}
if(error || r == null || !r.transactionSuccess()) {
AreaShop.warn("Something went wrong with paying back to " + getPlayerName() + " money while unrenting region " + getName());
}
}
}
// Send messages
message(executor, "unrent-unrented");
// Handle schematic save/restore (while %uuid% is still available)
handleSchematicEvent(RegionEvent.UNRENTED);
// Remove friends, the owner and renteduntil values
getFriendsFeature().clearFriends();
UUID oldRenter = getRenter();
setRenter(null);
setRentedUntil(null);
setTimesExtended(-1);
removeLastActiveTime();
// Notify about updates
this.notifyAndUpdate(new UnrentedRegionEvent(this, oldRenter, Math.max(0, moneyBack)));
// Run commands
this.runEventCommands(RegionEvent.UNRENTED, false);
return true;
}
@Override
public boolean checkInactive() {
if(isDeleted() || !isRented()) {
return false;
}
long inactiveSetting = getInactiveTimeUntilUnrent();
OfflinePlayer player = Bukkit.getOfflinePlayer(getRenter());
if(inactiveSetting <= 0 || player.isOp()) {
return false;
}
long lastPlayed = getLastActiveTime();
//AreaShop.debug("currentTime=" + Calendar.getInstance().getTimeInMillis() + ", getLastPlayed()=" + lastPlayed + ", timeInactive=" + (Calendar.getInstance().getTimeInMillis()-player.getLastPlayed()) + ", inactiveSetting=" + inactiveSetting);
if(Calendar.getInstance().getTimeInMillis() > (lastPlayed + inactiveSetting)) {
AreaShop.info("Region " + getName() + " unrented because of inactivity for player " + getPlayerName());
AreaShop.debug("currentTime=" + Calendar.getInstance().getTimeInMillis() + ", getLastPlayed()=" + lastPlayed + ", timeInactive=" + (Calendar.getInstance().getTimeInMillis() - player.getLastPlayed()) + ", inactiveSetting=" + inactiveSetting);
return this.unRent(true, null);
}
return false;
}
}
@@ -0,0 +1,147 @@
package me.wiefferink.areashop.tools;
import me.wiefferink.areashop.AreaShop;
import me.wiefferink.areashop.regions.BuyRegion;
import me.wiefferink.areashop.regions.GeneralRegion;
import me.wiefferink.areashop.regions.RentRegion;
import org.bstats.Metrics;
import java.util.HashMap;
public class Analytics {
/**
* Start analytics tracking.
*/
public static void start() {
// Legacy MCstats statistics (remove at some point)
try {
new me.wiefferink.areashop.lib.Metrics(AreaShop.getInstance()).start();
AreaShop.debug("Started mcstats.org statistics service");
} catch(Exception e) {
AreaShop.debug("Could not start mcstats.org statistics service");
}
// bStats statistics
try {
Metrics metrics = new Metrics(AreaShop.getInstance());
// Number of regions
metrics.addCustomChart(new Metrics.SingleLineChart("region_count") {
@Override
public int getValue() {
return AreaShop.getInstance().getFileManager().getRegions().size();
}
});
// Number of rental regions
metrics.addCustomChart(new Metrics.SingleLineChart("rental_region_count") {
@Override
public int getValue() {
return AreaShop.getInstance().getFileManager().getRents().size();
}
});
// Number of buy regions
metrics.addCustomChart(new Metrics.SingleLineChart("buy_region_count") {
@Override
public int getValue() {
return AreaShop.getInstance().getFileManager().getBuys().size();
}
});
// Language
metrics.addCustomChart(new Metrics.SimplePie("language") {
@Override
public String getValue() {
return AreaShop.getInstance().getConfig().getString("language");
}
});
// Pie with region states
metrics.addCustomChart(new Metrics.AdvancedPie("region_state") {
@Override
public HashMap<String, Integer> getValues(HashMap<String, Integer> result) {
RegionStateStats stats = getStateStats();
result.put("For Rent", stats.forrent);
result.put("Rented", stats.rented);
result.put("For Sale", stats.forsale);
result.put("Sold", stats.sold);
result.put("Reselling", stats.reselling);
return result;
}
});
// Time series of each region state
metrics.addCustomChart(new Metrics.SingleLineChart("forrent_region_count") {
@Override
public int getValue() {
return getStateStats().forrent;
}
});
metrics.addCustomChart(new Metrics.SingleLineChart("rented_region_count") {
@Override
public int getValue() {
return getStateStats().rented;
}
});
metrics.addCustomChart(new Metrics.SingleLineChart("forsale_region_count") {
@Override
public int getValue() {
return getStateStats().forsale;
}
});
metrics.addCustomChart(new Metrics.SingleLineChart("sold_region_count") {
@Override
public int getValue() {
return getStateStats().sold;
}
});
metrics.addCustomChart(new Metrics.SingleLineChart("reselling_region_count") {
@Override
public int getValue() {
return getStateStats().reselling;
}
});
// TODO track rent/buy/unrent/sell/resell actions (so that it can be reported per collection interval)
AreaShop.debug("Started bstats.org statistics service");
} catch(Exception e) {
AreaShop.debug("Could not start bstats.org statistics service");
}
}
private static class RegionStateStats {
int forrent = 0;
int forsale = 0;
int rented = 0;
int sold = 0;
int reselling = 0;
}
private static RegionStateStats getStateStats() {
RegionStateStats result = new RegionStateStats();
for(GeneralRegion region : AreaShop.getInstance().getFileManager().getRegions()) {
if(region instanceof RentRegion) {
RentRegion rent = (RentRegion)region;
if(rent.isAvailable()) {
result.forrent++;
} else {
result.rented++;
}
} else if(region instanceof BuyRegion) {
BuyRegion buy = (BuyRegion)region;
if(buy.isAvailable()) {
result.forsale++;
} else if(buy.isInResellingMode()) {
result.reselling++;
} else {
result.sold++;
}
}
}
return result;
}
}
@@ -0,0 +1,251 @@
package me.wiefferink.areashop.tools;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.bukkit.plugin.Plugin;
import org.bukkit.scheduler.BukkitRunnable;
import org.json.simple.JSONObject;
import org.json.simple.JSONValue;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.Arrays;
import java.util.logging.Logger;
public class GithubUpdateCheck {
public static final String API_HOST = "https://api.github.com/repos";
public static final String API_LATEST_RELEASE = "releases/latest";
public static final String USER_AGENT = "GithubUpdateCheck by NLThijs48";
public static final boolean DEBUG = false;
private final String author;
private final String repository;
private final Plugin plugin;
private final Logger logger;
private URL url;
private VersionComparator versionComparator;
// Status
private boolean checking;
private boolean error;
private boolean hasUpdate;
private String latestVersion;
private final String currentVersion;
/**
* Create a new GithubUpdateCheck with the required information.
* @param plugin The plugin to create it for (used for logging and checking version)
* @param author The author of the plugin as used on Github
* @param repository The repository name of the plugin on Github
*/
public GithubUpdateCheck(Plugin plugin, String author, String repository) {
this.plugin = plugin;
this.logger = plugin.getLogger();
this.author = author;
this.repository = repository;
this.currentVersion = plugin.getDescription().getVersion();
this.versionComparator = (latestVersion, currentVersion) ->
!latestVersion.equalsIgnoreCase(currentVersion);
this.checking = false;
this.error = false;
this.hasUpdate = false;
}
/**
* Change the version comparator.
* @param versionComparator VersionComparator to use for checking if one version is newer than the other
* @return this
*/
public GithubUpdateCheck withVersionComparator(VersionComparator versionComparator) {
this.versionComparator = versionComparator;
return this;
}
/**
* Check if an update is available.
*/
public void checkUpdate() {
checkUpdate(null);
}
/**
* Check if an update is available.
* @param callback Callback to execute when the update check is done
* @return GithubUpdateCheck containing the status of the check
*/
public GithubUpdateCheck checkUpdate(UpdateCallback callback) {
checking = true;
final GithubUpdateCheck self = this;
// Check for update on asyn thread
new BukkitRunnable() {
@Override
public void run() {
try {
try {
String rawUrl = API_HOST + "/" + author + "/" + repository + "/" + API_LATEST_RELEASE;
url = new URL(rawUrl);
} catch(MalformedURLException e) {
logger.severe("Invalid url: '" + url + "', are the author '" + author + "' and repository '" + repository + "' correct?");
error = true;
return;
}
try {
URLConnection conn = url.openConnection();
// Give up after 15 seconds
conn.setConnectTimeout(15000);
// Identify ourselves
conn.addRequestProperty("User-Agent", USER_AGENT);
// Make sure we access the correct api version
conn.addRequestProperty("Accept", "application/vnd.github.v3+json");
// We want to read the result
conn.setDoOutput(true);
// Open connection
try(BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()))) {
String response = reader.readLine();
debug("Response:", response);
JSONObject latestRelease = (JSONObject)JSONValue.parse(response);
if(latestRelease.isEmpty()) {
logger.warning("Failed to get api response from " + url);
error = true;
return;
}
debug("json: " + latestRelease.toJSONString());
// Latest version
latestVersion = (String)latestRelease.get("tag_name");
debug("Tag name:", latestVersion);
// Current version
debug("Plugin version:", currentVersion);
// Compare version
hasUpdate = versionComparator.isNewer(latestVersion, currentVersion);
}
} catch(IOException e) {
logger.severe("Failed to get latest release:" + ExceptionUtils.getStackTrace(e));
error = true;
} catch(ClassCastException e) {
logger.info("Unexpected structure of the result, failed to parse it");
error = true;
}
} finally {
checking = false;
debug("result:", self);
if(callback != null) {
// Switch back to main thread and call the callback
new BukkitRunnable() {
@Override
public void run() {
callback.run(self);
}
}.runTask(plugin);
}
}
}
}.runTaskAsynchronously(plugin);
return this;
}
/**
* Check if an update check is running.
* @return true if an update check is running
*/
public boolean isChecking() {
return checking;
}
/**
* Check if the update check failed.
* @return true if the update check failed (an error message has been logged)
*/
public boolean hasFailed() {
return error;
}
/**
* Check if an update has been found.
* @return true if an update has been found
*/
public boolean hasUpdate() {
return hasUpdate;
}
/**
* Get the repository that this update checker is checking.
* @return Used repository
*/
public String getRepository() {
return repository;
}
/**
* Get the author that this update checker is checking.
* @return Used author
*/
public String getAuthor() {
return author;
}
/**
* Get the current version.
* @return Current version of the plugin
*/
public String getCurrentVersion() {
return currentVersion;
}
/**
* Get the latest version.
* @return Latest version of the plugin (if checking is complete)
*/
public String getLatestVersion() {
return latestVersion;
}
public interface VersionComparator {
/**
* Check if a version should be considered 'newer' than another.
* @param latestVersion Version that is available on Github
* @param currentVersion Version of the current plugin
* @return true if the latestVersion is newer than the localVersion, otherwise false
*/
boolean isNewer(String latestVersion, String currentVersion);
}
public interface UpdateCallback {
void run(GithubUpdateCheck result);
}
/**
* Print a debug message if DEBUG is enabled.
* @param message Message to print
*/
private void debug(Object... message) {
if(DEBUG) {
logger.info("[" + this.getClass().getSimpleName() + "] [DEBUG] " + StringUtils.join(message, " "));
}
}
@Override
public String toString() {
return "GithubUpdateCheck(" + StringUtils.join(Arrays.asList(
"author=" + author,
"repository=" + repository,
"plugin=" + plugin.getName(),
"checking=" + checking,
"hasUpdate=" + hasUpdate,
"error=" + error,
"currentVersion=" + currentVersion,
"latestVersion=" + latestVersion
), ", ") + ")";
}
}
@@ -0,0 +1,848 @@
package me.wiefferink.areashop.tools;
import com.sk89q.worldedit.BlockVector;
import com.sk89q.worldguard.protection.managers.RegionManager;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import me.wiefferink.areashop.AreaShop;
import me.wiefferink.areashop.interfaces.WorldEditSelection;
import me.wiefferink.areashop.regions.BuyRegion;
import me.wiefferink.areashop.regions.GeneralRegion;
import me.wiefferink.areashop.regions.RentRegion;
import me.wiefferink.interactivemessenger.Log;
import me.wiefferink.interactivemessenger.processing.Message;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.Server;
import org.bukkit.World;
import org.bukkit.block.BlockFace;
import org.bukkit.configuration.Configuration;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
public class Utils {
// Not used
private Utils() {
}
private static YamlConfiguration config;
private static Set<String> identifiers;
private static Set<String> seconds;
private static Set<String> minutes;
private static Set<String> hours;
private static Set<String> days;
private static Set<String> weeks;
private static Set<String> months;
private static Set<String> years;
private static ScriptEngine scriptEngine;
private static Map<Double, String> suffixes;
/**
* Initialize the utilities class with constants.
* @param pluginConfig The config of the plugin
*/
public static void initialize(YamlConfiguration pluginConfig) {
config = pluginConfig;
// Setup individual identifiers
seconds = getSetAndDefaults("seconds");
minutes = getSetAndDefaults("minutes");
hours = getSetAndDefaults("hours");
days = getSetAndDefaults("days");
weeks = getSetAndDefaults("weeks");
months = getSetAndDefaults("months");
years = getSetAndDefaults("years");
// Setup all time identifiers
identifiers = new HashSet<>();
identifiers.addAll(seconds);
identifiers.addAll(minutes);
identifiers.addAll(hours);
identifiers.addAll(days);
identifiers.addAll(weeks);
identifiers.addAll(months);
identifiers.addAll(years);
suffixes = new HashMap<>();
// This stuff should not be necessary, but it is, getConfigurationSection() does not do proper fallback to defaults!
// TODO: Create a custom configuration that fixes this behavior
ConfigurationSection suffixesSection = null;
if(config.isSet("metricSymbols")) {
suffixesSection = config.getConfigurationSection("metricSymbols");
} else {
Configuration defaults = config.getDefaults();
if(defaults != null) {
suffixesSection = defaults.getConfigurationSection("metricSymbols");
}
}
if(suffixesSection != null) {
for(String key : suffixesSection.getKeys(false)) {
try {
suffixes.put(Double.parseDouble(key), suffixesSection.getString(key));
} catch(NumberFormatException e) {
Log.warn("Key '" + key + "' in the metricSymbols section of config.yml is not a number!");
}
}
}
}
/**
* Get a string list from the config, combined with the entries specified in the default config.
* @param path The path to read the lists from
* @return List with all values defined in the config and the default config combined
*/
private static Set<String> getSetAndDefaults(String path) {
Set<String> result = new HashSet<>(config.getStringList(path));
ConfigurationSection defaults = config.getDefaults();
if(defaults != null) {
result.addAll(defaults.getStringList(path));
}
return result;
}
/**
* Create a message with a list of parts.
* @param replacements The parts to use
* @param messagePart The message to use for the parts
* @return A Message object containing the parts combined into one message
*/
public static Message combinedMessage(Collection<?> replacements, String messagePart) {
return combinedMessage(replacements, messagePart, ", ");
}
/**
* Create a message with a list of parts.
* @param replacements The parts to use
* @param messagePart The message to use for the parts
* @param combiner The string to use as combiner
* @return A Message object containing the parts combined into one message
*/
public static Message combinedMessage(Collection<?> replacements, String messagePart, String combiner) {
Message result = Message.empty();
boolean first = true;
for(Object part : replacements) {
if(first) {
first = false;
} else {
result.append(combiner);
}
result.append(Message.fromKey(messagePart).replacements(part));
}
return result;
}
/**
* Gets the online players.
* Provides backwards compatibility for 1.7- where it returns an array
* @return Online players
*/
@SuppressWarnings("unchecked")
public static Collection<? extends Player> getOnlinePlayers() {
try {
Method onlinePlayerMethod = Server.class.getMethod("getOnlinePlayers");
if(onlinePlayerMethod.getReturnType().equals(Collection.class)) {
return ((Collection<? extends Player>)onlinePlayerMethod.invoke(Bukkit.getServer()));
} else {
return Arrays.asList((Player[])onlinePlayerMethod.invoke(Bukkit.getServer()));
}
} catch(Exception ex) {
AreaShop.debug("getOnlinePlayers error: " + ex.getMessage());
}
return new HashSet<>();
}
/**
* Create a map from a location, to save it in the config.
* @param location The location to transform
* @param setPitchYaw true to save the pitch and yaw, otherwise false
* @return The map with the location values
*/
public static ConfigurationSection locationToConfig(Location location, boolean setPitchYaw) {
if(location == null) {
return null;
}
ConfigurationSection result = new YamlConfiguration();
result.set("world", location.getWorld().getName());
result.set("x", location.getX());
result.set("y", location.getY());
result.set("z", location.getZ());
if(setPitchYaw) {
result.set("yaw", Float.toString(location.getYaw()));
result.set("pitch", Float.toString(location.getPitch()));
}
return result;
}
/**
* Create a map from a location, to save it in the config (without pitch and yaw).
* @param location The location to transform
* @return The map with the location values
*/
public static ConfigurationSection locationToConfig(Location location) {
return locationToConfig(location, false);
}
/**
* Create a location from a map, reconstruction from the config values.
* @param config The config section to reconstruct from
* @return The location
*/
public static Location configToLocation(ConfigurationSection config) {
if(config == null
|| !config.isString("world")
|| !config.isDouble("x")
|| !config.isDouble("y")
|| !config.isDouble("z")
|| Bukkit.getWorld(config.getString("world")) == null) {
return null;
}
Location result = new Location(
Bukkit.getWorld(config.getString("world")),
config.getDouble("x"),
config.getDouble("y"),
config.getDouble("z"));
if(config.isString("yaw") && config.isString("pitch")) {
result.setPitch(Float.parseFloat(config.getString("pitch")));
result.setYaw(Float.parseFloat(config.getString("yaw")));
}
return result;
}
/**
* Create a comma-separated list.
* @param input Collection of object which should be concatenated with comma's in between (skipping null values)
* @return Innput object concatenated with comma's in between
*/
public static String createCommaSeparatedList(Collection<?> input) {
StringBuilder result = new StringBuilder();
boolean first = true;
for(Object object : input) {
if(object != null) {
if(first) {
first = false;
result.append(object.toString());
} else {
result.append(", ").append(object.toString());
}
}
}
return result.toString();
}
/**
* Convert milliseconds to ticks.
* @param milliseconds Milliseconds to convert
* @return milliseconds divided by 50 (20 ticks per second)
*/
public static long millisToTicks(long milliseconds) {
return milliseconds / 50;
}
/**
* Convert milliseconds to a human readable format.
* @param milliseconds The amount of milliseconds to convert
* @return A formatted string based on the language file
*/
public static String millisToHumanFormat(long milliseconds) {
long timeLeft = milliseconds + 500;
// To seconds
timeLeft = timeLeft / 1000;
if(timeLeft <= 0) {
return Message.fromKey("timeleft-ended").getPlain();
} else if(timeLeft == 1) {
return Message.fromKey("timeleft-second").replacements(timeLeft).getPlain();
} else if(timeLeft <= 120) {
return Message.fromKey("timeleft-seconds").replacements(timeLeft).getPlain();
}
// To minutes
timeLeft = timeLeft / 60;
if(timeLeft <= 120) {
return Message.fromKey("timeleft-minutes").replacements(timeLeft).getPlain();
}
// To hours
timeLeft = timeLeft / 60;
if(timeLeft <= 48) {
return Message.fromKey("timeleft-hours").replacements(timeLeft).getPlain();
}
// To days
timeLeft = timeLeft / 24;
if(timeLeft <= 60) {
return Message.fromKey("timeleft-days").replacements(timeLeft).getPlain();
}
// To months
timeLeft = timeLeft / 30;
if(timeLeft <= 24) {
return Message.fromKey("timeleft-months").replacements(timeLeft).getPlain();
}
// To years
timeLeft = timeLeft / 12;
return Message.fromKey("timeleft-years").replacements(timeLeft).getPlain();
}
private static final BlockFace[] facings = {BlockFace.NORTH, BlockFace.NORTH_EAST, BlockFace.EAST, BlockFace.SOUTH_EAST, BlockFace.SOUTH, BlockFace.SOUTH_WEST, BlockFace.WEST, BlockFace.NORTH_WEST};
/**
* Get the facing direction based on the yaw.
* @param yaw The horizontal angle that for example the player is looking
* @return The Block Face of the angle
*/
public static BlockFace yawToFacing(float yaw) {
return facings[Math.round(yaw / 45f) & 0x7];
}
// ======================================================================
// Methods to get WorldGuard or AreaShop regions by location or selection
// ======================================================================
/**
* Get all AreaShop regions intersecting with a WorldEdit selection.
* @param selection The selection to check
* @return A list with all the AreaShop regions intersecting with the selection
*/
public static List<GeneralRegion> getRegionsInSelection(WorldEditSelection selection) {
ArrayList<GeneralRegion> result = new ArrayList<>();
for(ProtectedRegion region : getWorldEditRegionsInSelection(selection)) {
GeneralRegion asRegion = AreaShop.getInstance().getFileManager().getRegion(region.getId());
if(asRegion != null) {
result.add(asRegion);
}
}
return result;
}
/**
* Get all AreaShop regions containing a location.
* @param location The location to check
* @return A list with all the AreaShop regions that contain the location
*/
public static List<GeneralRegion> getRegions(Location location) {
return getRegionsInSelection(new WorldEditSelection(location.getWorld(), location, location));
}
/**
* Get all WorldGuard regions intersecting with a WorldEdit selection.
* @param selection The selection to check
* @return A list with all the WorldGuard regions intersecting with the selection
*/
public static List<ProtectedRegion> getWorldEditRegionsInSelection(WorldEditSelection selection) {
// Get all regions inside or intersecting with the WorldEdit selection of the player
World world = selection.getWorld();
RegionManager regionManager = AreaShop.getInstance().getRegionManager(world);
ArrayList<ProtectedRegion> result = new ArrayList<>();
Location selectionMin = selection.getMinimumLocation();
Location selectionMax = selection.getMaximumLocation();
for(ProtectedRegion region : regionManager.getRegions().values()) {
BlockVector regionMin = region.getMinimumPoint();
BlockVector regionMax = region.getMaximumPoint();
if(
( // x part, resolves to true if the selection and region overlap anywhere on the x-axis
(regionMin.getBlockX() <= selectionMax.getBlockX() && regionMin.getBlockX() >= selectionMin.getBlockX())
|| (regionMax.getBlockX() <= selectionMax.getBlockX() && regionMax.getBlockX() >= selectionMin.getBlockX())
|| (selectionMin.getBlockX() >= regionMin.getBlockX() && selectionMin.getBlockX() <= regionMax.getBlockX())
|| (selectionMax.getBlockX() >= regionMin.getBlockX() && selectionMax.getBlockX() <= regionMax.getBlockX())
) && ( // Y part, resolves to true if the selection and region overlap anywhere on the y-axis
(regionMin.getBlockY() <= selectionMax.getBlockY() && regionMin.getBlockY() >= selectionMin.getBlockY())
|| (regionMax.getBlockY() <= selectionMax.getBlockY() && regionMax.getBlockY() >= selectionMin.getBlockY())
|| (selectionMin.getBlockY() >= regionMin.getBlockY() && selectionMin.getBlockY() <= regionMax.getBlockY())
|| (selectionMax.getBlockY() >= regionMin.getBlockY() && selectionMax.getBlockY() <= regionMax.getBlockY())
) && ( // Z part, resolves to true if the selection and region overlap anywhere on the z-axis
(regionMin.getBlockZ() <= selectionMax.getBlockZ() && regionMin.getBlockZ() >= selectionMin.getBlockZ())
|| (regionMax.getBlockZ() <= selectionMax.getBlockZ() && regionMax.getBlockZ() >= selectionMin.getBlockZ())
|| (selectionMin.getBlockZ() >= regionMin.getBlockZ() && selectionMin.getBlockZ() <= regionMax.getBlockZ())
|| (selectionMax.getBlockZ() >= regionMin.getBlockZ() && selectionMax.getBlockZ() <= regionMax.getBlockZ())
)
) {
result.add(region);
}
}
return result;
}
/**
* Get a list of regions around a location.
* - Returns highest priority, child instead of parent regions
* @param location The location to check for regions
* @return empty list if no regions found, 1 member if 1 region is a priority, more if regions with the same priority
*/
public static List<ProtectedRegion> getImportantWorldEditRegions(Location location) {
List<ProtectedRegion> result = new ArrayList<>();
Set<ProtectedRegion> regions = AreaShop.getInstance().getWorldGuardHandler().getApplicableRegionsSet(location);
if(regions != null) {
boolean first = true;
for(ProtectedRegion pr : regions) {
if(first) {
result.add(pr);
first = false;
} else {
if(pr.getPriority() > result.get(0).getPriority()) {
result.clear();
result.add(pr);
} else if(pr.getParent() != null && pr.getParent().equals(result.get(0))) {
result.clear();
result.add(pr);
} else {
result.add(pr);
}
}
}
}
return result;
}
/**
* Get the most important rental AreaShop regions.
* - Returns highest priority, child instead of parent regions.
* @param location The location to check for regions
* @return empty list if no regions found, 1 member if 1 region is a priority, more if regions with the same priority
*/
public static List<RentRegion> getImportantRentRegions(Location location) {
List<RentRegion> result = new ArrayList<>();
for(GeneralRegion region : getImportantRegions(location, GeneralRegion.RegionType.RENT)) {
result.add((RentRegion)region);
}
return result;
}
/**
* Get the most important buy AreaShop regions.
* - Returns highest priority, child instead of parent regions.
* @param location The location to check for regions
* @return empty list if no regions found, 1 member if 1 region is a priority, more if regions with the same priority
*/
public static List<BuyRegion> getImportantBuyRegions(Location location) {
List<BuyRegion> result = new ArrayList<>();
for(GeneralRegion region : getImportantRegions(location, GeneralRegion.RegionType.BUY)) {
result.add((BuyRegion)region);
}
return result;
}
/**
* Get the most important AreaShop regions.
* - Returns highest priority, child instead of parent regions.
* @param location The location to check for regions
* @return empty list if no regions found, 1 member if 1 region is a priority, more if regions with the same priority
*/
public static List<GeneralRegion> getImportantRegions(Location location) {
return getImportantRegions(location, null);
}
/**
* Get the most important AreaShop regions.
* - Returns highest priority, child instead of parent regions.
* @param location The location to check for regions
* @param type The type of regions to look for, null for all
* @return empty list if no regions found, 1 member if 1 region is a priority, more if regions with the same priority
*/
public static List<GeneralRegion> getImportantRegions(Location location, GeneralRegion.RegionType type) {
List<GeneralRegion> result = new ArrayList<>();
Set<ProtectedRegion> regions = AreaShop.getInstance().getWorldGuardHandler().getApplicableRegionsSet(location);
if(regions != null) {
List<GeneralRegion> candidates = new ArrayList<>();
for(ProtectedRegion pr : regions) {
GeneralRegion region = AreaShop.getInstance().getFileManager().getRegion(pr.getId());
if(region != null && (
(type == GeneralRegion.RegionType.RENT && region instanceof RentRegion)
|| (type == GeneralRegion.RegionType.BUY && region instanceof BuyRegion)
|| type == null)) {
candidates.add(region);
}
}
boolean first = true;
for(GeneralRegion region : candidates) {
if(region == null) {
AreaShop.debug("skipped null region");
continue;
}
if(first) {
result.add(region);
first = false;
} else {
if(region.getRegion().getPriority() > result.get(0).getRegion().getPriority()) {
result.clear();
result.add(region);
} else if(region.getRegion().getParent() != null && region.getRegion().getParent().equals(result.get(0).getRegion())) {
result.clear();
result.add(region);
} else {
result.add(region);
}
}
}
}
return new ArrayList<>(result);
}
/**
* Convert color and formatting codes to bukkit values.
* @param input Start string with color and formatting codes in it
* @return String with the color and formatting codes in the bukkit format
*/
public static String applyColors(String input) {
String result = null;
if(input != null) {
result = ChatColor.translateAlternateColorCodes('&', input);
}
return result;
}
/**
* Format the currency amount with the characters before and after.
* @param amount Amount of money to format
* @return Currency character format string
*/
public static String formatCurrency(double amount) {
String before = config.getString("moneyCharacter");
before = before.replace(AreaShop.currencyEuro, "€");
String after = config.getString("moneyCharacterAfter");
after = after.replace(AreaShop.currencyEuro, "€");
String result;
// Check for infinite and NaN
if(Double.isInfinite(amount)) {
result = "\u221E"; // Infinite symbol
} else if(Double.isNaN(amount)) {
result = "NaN";
} else {
BigDecimal bigDecimal = BigDecimal.valueOf(amount);
boolean stripTrailingZeros = false;
int fractionalNumber = config.getInt("fractionalNumbers");
// Add metric suffix if necessary
if(config.getDouble("metricSuffixesAbove") != -1) {
String suffix = null;
double divider = 1;
for(Double number : suffixes.keySet()) {
if(amount >= number && number > divider) {
divider = number;
suffix = suffixes.get(number);
}
}
if(suffix != null) {
bigDecimal = BigDecimal.valueOf(amount / divider);
after = suffix + after;
fractionalNumber = config.getInt("fractionalNumbersShort");
stripTrailingZeros = true;
}
}
// Round if necessary
if(fractionalNumber >= 0) {
bigDecimal = bigDecimal.setScale(fractionalNumber, RoundingMode.HALF_UP);
}
result = bigDecimal.toString();
if(config.getBoolean("hideEmptyFractionalPart")) {
// Strip zero fractional: 12.00 -> 12
if(bigDecimal.remainder(BigDecimal.ONE).compareTo(BigDecimal.ZERO) == 0 && result.contains(".")) {
result = result.substring(0, result.indexOf('.'));
}
// Strip zeros from suffixed numbers: 1.20M -> 1.2M
if(stripTrailingZeros && result.contains(".")) {
result = result.replaceAll("0+$", "");
}
}
}
result = result.replace(".", config.getString("decimalMark"));
Message resultMessage = Message.fromString(result);
resultMessage.prepend(before);
resultMessage.append(after);
return resultMessage.getSingle();
}
/**
* Checks if the string is a correct time period.
* @param time String that has to be checked
* @return true if format is correct, false if not
*/
public static boolean checkTimeFormat(String time) {
// Check if the string is not empty and check the length
if(time == null || time.length() <= 1 || time.indexOf(' ') == -1 || time.indexOf(' ') >= (time.length() - 1)) {
return false;
}
// Check if the suffix is one of these values
String suffix = time.substring(time.indexOf(' ') + 1);
if(!identifiers.contains(suffix)) {
return false;
}
// check if the part before the space is a number
String prefix = time.substring(0, (time.indexOf(' ')));
return prefix.matches("\\d+");
}
/**
* Methode to tranlate a duration string to a millisecond value.
* @param duration The duration string
* @return The duration in milliseconds translated from the durationstring, or if it is invalid then 0
*/
public static long durationStringToLong(String duration) {
if(duration == null) {
return 0;
} else if(duration.equalsIgnoreCase("disabled") || duration.equalsIgnoreCase("unlimited") || duration.length() == 0) {
return -1;
} else if(duration.indexOf(' ') == -1) {
return 0;
}
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(0);
String durationString = duration.substring(duration.indexOf(' ') + 1);
int durationInt = 0;
try {
durationInt = Integer.parseInt(duration.substring(0, duration.indexOf(' ')));
} catch(NumberFormatException exception) {
// No Number found, add zero
}
if(seconds.contains(durationString)) {
calendar.add(Calendar.SECOND, durationInt);
} else if(minutes.contains(durationString)) {
calendar.add(Calendar.MINUTE, durationInt);
} else if(hours.contains(durationString)) {
calendar.add(Calendar.HOUR, durationInt);
} else if(days.contains(durationString)) {
calendar.add(Calendar.DAY_OF_MONTH, durationInt);
} else if(weeks.contains(durationString)) {
calendar.add(Calendar.DAY_OF_MONTH, durationInt * 7);
} else if(months.contains(durationString)) {
calendar.add(Calendar.MONTH, durationInt);
} else if(years.contains(durationString)) {
calendar.add(Calendar.YEAR, durationInt);
} else {
AreaShop.warn("Unknown duration indicator:", durationString, "check if config.yml has the correct time indicators");
}
return calendar.getTimeInMillis();
}
// LEGACY TIME INPUT CONVERSION
/**
* Get setting from config that could be only a number indicating seconds.
* or a string indicating a duration string
* @param path Path of the setting to read
* @return milliseconds that the setting indicates
*/
public static long getDurationFromSecondsOrString(String path) {
if(config.isLong(path) || config.isInt(path)) {
long setting = config.getLong(path);
if(setting != -1) {
setting = setting * 1000;
}
return setting;
} else {
return durationStringToLong(config.getString(path));
}
}
/**
* Get setting from config that could be only a number indicating minutes.
* or a string indicating a duration string.
* @param path Path of the setting to read
* @return milliseconds that the setting indicates
*/
public static long getDurationFromMinutesOrString(String path) {
if(config.isLong(path) || config.isInt(path)) {
long setting = config.getLong(path);
if(setting != -1) {
setting = setting * 60 * 1000;
}
return setting;
} else {
return durationStringToLong(config.getString(path));
}
}
/**
* Parse a time setting that could be minutes or a duration string.
* @param input The string to parse
* @return milliseconds that the string indicates
*/
public static long getDurationFromMinutesOrStringInput(String input) {
long number;
try {
number = Long.parseLong(input);
if(number != -1) {
number = number * 60 * 1000;
}
return number;
} catch(NumberFormatException e) {
return durationStringToLong(input);
}
}
/**
* Parse a time setting that could be seconds or a duration string.
* @param input The string to parse
* @return seconds that the string indicates
*/
public static long getDurationFromSecondsOrStringInput(String input) {
long number;
try {
number = Long.parseLong(input);
if(number != -1) {
number = number * 1000;
}
return number;
} catch(NumberFormatException e) {
return durationStringToLong(input);
}
}
/**
* Check if an input is numeric.
* @param input The input to check
* @return true if the input is numeric, otherwise false
*/
@SuppressWarnings("ResultOfMethodCallIgnored")
public static boolean isNumeric(String input) {
try {
Integer.parseInt(input);
return true;
} catch(NumberFormatException ignored) {
return false;
}
}
/**
* Check if a string is a double.
* @param input The input
* @return true if the input is a double, otherwise false
*/
@SuppressWarnings("ResultOfMethodCallIgnored")
public static boolean isDouble(String input) {
try {
Double.parseDouble(input);
return true;
} catch(NumberFormatException e) {
return false;
}
}
/**
* Evaluate string input to a number.
* Uses JavaScript for expressions.
* @param input The input string
* @param region The region to apply replacements for and use for logging
* @return double evaluated from the input or a very high default in case of a script exception
*/
public static double evaluateToDouble(String input, GeneralRegion region) {
// Replace variables
input = Message.fromString(input).replacements(region).getSingle();
// Check for simple number
if(isDouble(input)) {
return Double.parseDouble(input);
}
// Lazy init scriptEngine
if(scriptEngine == null) {
scriptEngine = new ScriptEngineManager().getEngineByName("JavaScript");
}
// Evaluate expression
Object result;
try {
result = scriptEngine.eval(input);
} catch(ScriptException e) {
AreaShop.warn("Price of region", region.getName(), "is set with an invalid expression: '" + input + "', exception:", ExceptionUtils.getStackTrace(e));
return 99999999999.0; // High fallback for safety
}
// Handle the result
if(Utils.isDouble(result.toString())) {
return Double.parseDouble(result.toString());
} else {
AreaShop.warn("Price of region", region.getName(), "is set with the expression '" + input + "' that returns a result that is not a number:", result);
return 99999999999.0; // High fallback for safety
}
}
// NAME <-> UUID CONVERSION
/**
* Conversion to name by uuid.
* @param uuid The uuid in string format
* @return the name of the player
*/
public static String toName(String uuid) {
String result = "";
if(uuid != null) {
try {
UUID parsed = UUID.fromString(uuid);
result = toName(parsed);
} catch(IllegalArgumentException e) {
// Incorrect UUID
}
}
return result;
}
/**
* Conversion to name by uuid object.
* @param uuid The uuid in string format
* @return the name of the player
*/
public static String toName(UUID uuid) {
if(uuid == null) {
return "";
} else {
String name = Bukkit.getOfflinePlayer(uuid).getName();
if(name != null) {
return name;
}
return "";
}
}
/**
* Conversion from name to uuid.
* @param name The name of the player
* @return The uuid of the player
*/
@SuppressWarnings("deprecation") // Fake deprecation by Bukkit to inform developers, method will stay
public static String toUniqueId(String name) {
if(name == null) {
return null;
} else {
return Bukkit.getOfflinePlayer(name).getUniqueId().toString();
}
}
}
@@ -0,0 +1,30 @@
package me.wiefferink.areashop.tools;
public class Value<T> {
private T value;
/**
* Create a container with a default value.
* @param value The value to set
*/
public Value(T value) {
this.value = value;
}
/**
* Get the stored value.
* @return The stored value
*/
public T get() {
return value;
}
/**
* Set the value.
* @param value The new value
*/
public void set(T value) {
this.value = value;
}
}
@@ -1,914 +0,0 @@
package nl.evolutioncoding.areashop;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.UUID;
import java.util.logging.Logger;
import net.milkbowl.vault.economy.Economy;
import nl.evolutioncoding.areashop.Updater.UpdateResult;
import nl.evolutioncoding.areashop.Updater.UpdateType;
import nl.evolutioncoding.areashop.interfaces.AreaShopInterface;
import nl.evolutioncoding.areashop.interfaces.WorldEditInterface;
import nl.evolutioncoding.areashop.interfaces.WorldGuardInterface;
import nl.evolutioncoding.areashop.listeners.PlayerLoginLogoutListener;
import nl.evolutioncoding.areashop.listeners.SignBreakListener;
import nl.evolutioncoding.areashop.listeners.SignChangeListener;
import nl.evolutioncoding.areashop.listeners.SignClickListener;
import nl.evolutioncoding.areashop.managers.CommandManager;
import nl.evolutioncoding.areashop.managers.FileManager;
import nl.evolutioncoding.areashop.managers.LanguageManager;
import nl.evolutioncoding.areashop.managers.SignLinkerManager;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.permissions.Permission;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.RegisteredServiceProvider;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitRunnable;
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
/**
* Main class for the AreaShop plugin
* @author NLThijs48
*/
public final class AreaShop extends JavaPlugin implements AreaShopInterface {
/* General variables */
private static AreaShop instance = null;
private WorldGuardPlugin worldGuard = null;
private WorldGuardInterface worldGuardInterface = null;
private WorldEditPlugin worldEdit = null;
private WorldEditInterface worldEditInterface = null;
private FileManager fileManager = null;
private LanguageManager languageManager = null;
private CommandManager commandManager = null;
private SignLinkerManager signLinkerManager = null;
private boolean debug = false;
private String chatprefix = null;
private Updater updater = null;
private boolean updateAvailable = false;
private boolean ready = false;
/* Folders and file names */
public static final String languageFolder = "lang";
public static final String schematicFolder = "schem";
public static final String schematicExtension = ".schematic";
public static final String regionsFolder = "regions";
public static final String groupsFile = "groups.yml";
public static final String defaultFile = "default.yml";
public static final String configFile = "config.yml";
public static final String versionFile = "versions";
/* Euro tag for in the config */
public static final String currencyEuro = "%euro%";
/* Constants for handling file versions */
public static final String versionFiles = "files";
public static final int versionFilesCurrent = 3;
/* Keys for replacing parts of flags, commands, strings */
public static final String tagPlayerName = "%player%";
public static final String tagPlayerUUID = "%uuid%";
public static final String tagWorldName = "%world%";
public static final String tagRegionName = "%region%";
public static final String tagRegionType = "%type%";
public static final String tagPrice = "%price%";
public static final String tagRawPrice = "%rawprice%";
public static final String tagDuration = "%duration%";
public static final String tagRentedUntil = "%until%";
public static final String tagRentedUntilShort = "%untilshort%";
public static final String tagWidth = "%width%"; // x-axis
public static final String tagHeight = "%height%"; // y-axis
public static final String tagDepth = "%depth%"; // z-axis
public static final String tagTimeLeft = "%timeleft%";
public static final String tagClicker = "%clicker%";
public static final String tagResellPrice = "%resellprice%";
public static final String tagRawResellPrice = "%rawresellprice%";
public static final String tagFriends = "%friends%";
public static final String tagFriendsUUID = "%friendsuuid%";
public static final String tagMoneyBackPercentage = "%moneybackpercent%";
public static final String tagMoneyBackAmount = "%moneyback%";
public static final String tagRawMoneyBackAmount = "%rawmoneyback%";
public static final String tagMaxExtends = "%maxextends%";
public static final String tagExtendsLeft = "%extendsleft%";
public static final String tagMaxRentTime = "%maxrenttime%";
public static final String tagMaxInactiveTime = "%inactivetime%";
public static final String tagLandlord = "%landlord%";
public static final String tagLandlordUUID = "%landlorduuid%";
public static final String tagDateTime = "%datetime%";
public static final String tagDateTimeShort = "%datetimeshort%";
public static final String tagYear = "%year%";
public static final String tagMonth = "%month%";
public static final String tagDay = "%day%";
public static final String tagHour = "%hour%";
public static final String tagMinute = "%minute%";
public static final String tagSecond = "%second%";
public static final String tagMillisecond = "%millisecond%";
public static final String tagEpoch = "%epoch%";
public static AreaShop getInstance() {
return AreaShop.instance;
}
/**
* Called on start or reload of the server
*/
public void onEnable() {
AreaShop.instance = this;
boolean error = false;
// Check if WorldGuard is present
String wgVersion = null;
Plugin plugin = getServer().getPluginManager().getPlugin("WorldGuard");
if (plugin == null || !(plugin instanceof WorldGuardPlugin)) {
this.getLogger().severe("WorldGuard plugin is not present or has not loaded correctly");
error = true;
} else {
worldGuard = (WorldGuardPlugin)plugin;
// Get correct WorldGuardInterface (handles things that changed version to version)
if(worldGuard.getDescription().getVersion().startsWith("5.")) {
wgVersion = "5";
} else {
wgVersion = "6";
}
try {
final Class<?> clazz = Class.forName("nl.evolutioncoding.areashop.handlers.WorldGuardHandler" + wgVersion);
// Check if we have a NMSHandler class at that location.
if (WorldGuardInterface.class.isAssignableFrom(clazz)) { // Make sure it actually implements WorldGuardInterface
this.worldGuardInterface = (WorldGuardInterface) clazz.getConstructor(AreaShopInterface.class).newInstance(this); // Set our handler
}
} catch (final Exception e) {
e.printStackTrace();
this.getLogger().severe("Could not load the handler for WorldGuard (tried to load " + wgVersion + "), report this problem to the author.");
error = true;
wgVersion = null;
}
}
// Check if WorldEdit is present
String weVersion = null;
plugin = getServer().getPluginManager().getPlugin("WorldEdit");
if (plugin == null || !(plugin instanceof WorldEditPlugin)) {
this.getLogger().severe("WorldEdit plugin is not present or has not loaded correctly");
error = true;
} else {
worldEdit = (WorldEditPlugin)plugin;
// Get correct WorldEditInterface (handles things that changed version to version)
if(worldEdit.getDescription().getVersion().startsWith("5.")) {
weVersion = "5";
} else {
weVersion = "6";
}
try {
final Class<?> clazz = Class.forName("nl.evolutioncoding.areashop.handlers.WorldEditHandler" + weVersion);
// Check if we have a NMSHandler class at that location.
if (WorldEditInterface.class.isAssignableFrom(clazz)) { // Make sure it actually implements WorldEditInterface
this.worldEditInterface = (WorldEditInterface) clazz.getConstructor(AreaShopInterface.class).newInstance(this); // Set our handler
}
} catch (final Exception e) {
e.printStackTrace();
this.getLogger().severe("Could not load the handler for WorldEdit (tried to load " + weVersion + "), report this problem to the author.");
error = true;
weVersion = null;
}
}
// Check if Vault is present
if(getServer().getPluginManager().getPlugin("Vault") == null) {
this.getLogger().severe("Vault plugin is not present or has not loaded correctly");
error = true;
}
// Load all data from files and check versions
fileManager = new FileManager(this);
error = error & !fileManager.loadFiles();
// Print loaded version of WG and WE in debug
if(wgVersion != null) {
AreaShop.debug("Loaded WorldGuardHandler" + wgVersion);
}
if(weVersion != null) {
AreaShop.debug("Loaded WorldEditHandler" + weVersion);
}
// Create a LanguageMananager
languageManager = new LanguageManager(this);
if(error) {
this.getLogger().severe("The plugin has not started, fix the errors listed above");
} else {
// Register the event listeners
this.getServer().getPluginManager().registerEvents(new SignChangeListener(this), this);
this.getServer().getPluginManager().registerEvents(new SignBreakListener(this), this);
this.getServer().getPluginManager().registerEvents(new SignClickListener(this), this);
this.getServer().getPluginManager().registerEvents(new PlayerLoginLogoutListener(this), this);
setupTasks();
// Startup the CommandManager (registers itself for the command)
commandManager = new CommandManager(this);
// Create a signLinkerManager
signLinkerManager = new SignLinkerManager(this);
// Enable Metrics if config allows it
if(this.getConfig().getBoolean("sendStats")) {
this.startMetrics();
}
// Register dynamic permission (things declared in config)
registerDynamicPermissions();
// Dont initialize the updatechecker if disabled in the config
if(this.getConfig().getBoolean("checkForUpdates")) {
new BukkitRunnable() {
@Override
public void run() {
try {
updater = new Updater(AreaShop.getInstance(), 76518, null, UpdateType.NO_DOWNLOAD, false);
AreaShop.debug("Result=" + updater.getResult().toString() + ", Latest=" + updater.getLatestName() + ", Type=" + updater.getLatestType());
updateAvailable = updater.getResult() == UpdateResult.UPDATE_AVAILABLE;
if(updateAvailable) {
AreaShop.getInstance().getLogger().info("Update from AreaShop V" + AreaShop.getInstance().getDescription().getVersion() + " to " + updater.getLatestName() + " available, get the latest version at http://dev.bukkit.org/bukkit-plugins/regionbuyandrent/");
new BukkitRunnable() {
@Override
public void run() {
for(Player player : Bukkit.getOnlinePlayers()) {
if(player.hasPermission("areashop.notifyupdate")) {
AreaShop.getInstance().message(player, "update-playerNotify", AreaShop.getInstance().getDescription().getVersion(), AreaShop.getInstance().getUpdater().getLatestName());
}
}
}
}.runTask(AreaShop.getInstance());
}
} catch(Exception e) {
AreaShop.debug("Something went wrong with the Updater:");
AreaShop.debug(e.getMessage());
updateAvailable = false;
}
}
}.runTaskAsynchronously(this);
}
}
}
/**
* Called on shutdown or reload of the server
*/
public void onDisable() {
fileManager.saveRequiredFilesAtOnce();
Bukkit.getServer().getScheduler().cancelTasks(this);
/* set variables to null to prevent memory leaks */
worldGuard = null;
worldEdit = null;
fileManager = null;
languageManager = null;
commandManager = null;
chatprefix = null;
debug = false;
ready = false;
updater = null;
}
/**
* Indicates if the plugin is ready to be used
* @return true if the plugin is ready, false otherwise
*/
public boolean isReady() {
return ready;
}
/**
* Set if the plugin is ready to be used or not (not to be used from another plugin!)
* @param ready Indicate if the plugin is ready to be used
*/
public void setReady(boolean ready) {
this.ready = ready;
}
/**
* Set if the plugin should output debug messages (loaded from config normally)
* @param debug Indicates if the plugin should output debug messages or not
*/
public void setDebug(boolean debug) {
this.debug = debug;
}
/**
* Set the chatprefix to use in the chat (loaded from config normally)
* @param chatprefix The string to use in front of chat messages (supports formatting codes like &1)
*/
public void setChatprefix(String chatprefix) {
this.chatprefix = chatprefix;
}
/**
* Function to get the WorldGuard plugin
* @return WorldGuardPlugin
*/
public WorldGuardPlugin getWorldGuard() {
return worldGuard;
}
/**
* Function to get WorldGuardInterface for version dependent things
* @return WorldGuardInterface
*/
public WorldGuardInterface getWorldGuardHandler() {
return this.worldGuardInterface;
}
/**
* Function to get the WorldEdit plugin
* @return WorldEditPlugin
*/
public WorldEditPlugin getWorldEdit() {
return worldEdit;
}
/**
* Function to get WorldGuardInterface for version dependent things
* @return WorldGuardInterface
*/
public WorldEditInterface getWorldEditHandler() {
return this.worldEditInterface;
}
/**
* Function to get the LanguageManager
* @return the LanguageManager
*/
public LanguageManager getLanguageManager() {
return languageManager;
}
/**
* Function to get the CommandManager
* @return the CommandManager
*/
public CommandManager getCommandManager() {
return commandManager;
}
public SignLinkerManager getSignlinkerManager() {
return signLinkerManager;
}
/**
* Function to get the Vault plugin
* @return Economy
*/
public Economy getEconomy() {
RegisteredServiceProvider<Economy> economy = getServer().getServicesManager().getRegistration(net.milkbowl.vault.economy.Economy.class);
if (economy == null || economy.getProvider() == null) {
this.getLogger().severe("There is no economy provider to support Vault, make sure you installed an economy plugin");
return null;
}
return economy.getProvider();
}
/**
* Get the current chatPrefix
* @return
*/
public String getChatPrefix() {
return chatprefix;
}
/**
* Method to get the FileManager (loads/save regions and can be used to get regions)
* @return The fileManager
*/
public FileManager getFileManager() {
return fileManager;
}
/**
* Get the updater (check the update result)
* @return The updater
*/
public Updater getUpdater() {
return updater;
}
/**
* Check if an update for AreaShop is available
* @return true if an update is available, otherwise false
*/
public boolean updateAvailable() {
return updateAvailable;
}
/**
* Register dynamic permissions controlled by config settings
*/
public void registerDynamicPermissions() {
// Register limit groups of amount of regions a player can have
ConfigurationSection section = getConfig().getConfigurationSection("limitGroups");
if(section == null) {
return;
}
for(String group : section.getKeys(false)) {
if(!"default".equals(group)) {
Permission perm = new Permission("areashop.limits." + group);
try {
Bukkit.getPluginManager().addPermission(perm);
} catch(IllegalArgumentException e) {
this.getLogger().warning("Could not add the following permission to be used as limit: " + perm.getName());
}
}
}
Bukkit.getPluginManager().recalculatePermissionDefaults(Bukkit.getPluginManager().getPermission("playerwarps.limits"));
}
/**
* Register all required tasks
*/
public void setupTasks() {
// Rent expiration timer
long expirationCheck = Utils.millisToTicks(getDurationFromSecondsOrString("expiration.delay"));
final AreaShop finalPlugin = this;
if(expirationCheck > 0) {
new BukkitRunnable() {
@Override
public void run() {
if(isReady()) {
finalPlugin.getFileManager().checkRents();
AreaShop.debug("Checking rent expirations...");
} else {
AreaShop.debug("Skipped checking rent expirations, plugin not ready");
}
}
}.runTaskTimer(this, 1, expirationCheck);
}
// Inactive unrenting/selling timer
long inactiveCheck = Utils.millisToTicks(getDurationFromMinutesOrString("inactive.delay"));
if(inactiveCheck > 0) {
new BukkitRunnable() {
@Override
public void run() {
if(isReady()) {
finalPlugin.getFileManager().checkForInactiveRegions();
AreaShop.debug("Checking for regions with players that are inactive too long...");
} else {
AreaShop.debug("Skipped checking for regions of inactive players, plugin not ready");
}
}
}.runTaskTimer(this, inactiveCheck, inactiveCheck);
}
// Periodic updating of signs for timeleft tags
long periodicUpdate = Utils.millisToTicks(getDurationFromSecondsOrString("signs.delay"));
if(periodicUpdate > 0) {
new BukkitRunnable() {
@Override
public void run() {
if(isReady()) {
finalPlugin.getFileManager().performPeriodicSignUpdate();
AreaShop.debug("Performing periodic sign update...");
} else {
AreaShop.debug("Skipped performing periodic sign update, plugin not ready");
}
}
}.runTaskTimer(this, periodicUpdate, periodicUpdate);
}
// Saving regions and group settings
long saveFiles = Utils.millisToTicks(getDurationFromMinutesOrString("saving.delay"));
if(saveFiles > 0) {
new BukkitRunnable() {
@Override
public void run() {
if(isReady()) {
finalPlugin.getFileManager().saveRequiredFiles();
AreaShop.debug("Saving required files...");
} else {
AreaShop.debug("Skipped saving required files, plugin not ready");
}
}
}.runTaskTimer(this, saveFiles, saveFiles);
}
// Sending warnings about rent regions to online players
long expireWarning = Utils.millisToTicks(getDurationFromMinutesOrString("expireWarning.delay"));
if(expireWarning > 0) {
new BukkitRunnable() {
@Override
public void run() {
if(isReady()) {
finalPlugin.getFileManager().sendRentExpireWarnings();
AreaShop.debug("Sending rent expire warnings...");
} else {
AreaShop.debug("Skipped sending rent expire warnings, plugin not ready");
}
}
}.runTaskTimer(this, expireWarning, expireWarning);
}
// Update all regions on startup
if(getConfig().getBoolean("updateRegionsOnStartup")) {
new BukkitRunnable() {
@Override
public void run() {
finalPlugin.getFileManager().updateAllRegions();
AreaShop.debug("Updating all regions at startup...");
}
}.runTaskLater(this, 20L);
}
}
/**
* Method to send a message to a CommandSender, using chatprefix if it is a player
* @param target The CommandSender you wan't to send the message to (e.g. a player)
* @param key The key to get the translation
* @param prefix Specify if the message should have a prefix
* @param params The parameters to inject into the message string
*/
public void configurableMessage(Object target, String key, boolean prefix, Object... params) {
String langString = this.fixColors(languageManager.getLang(key, params));
if(langString == null || langString.equals("")) {
// Do nothing, message is not available or disabled
} else {
if(target instanceof Player) {
if(prefix) {
((Player)target).sendMessage(this.fixColors(chatprefix) + langString);
} else {
((Player)target).sendMessage(langString);
}
} else if(target instanceof CommandSender) {
if(!getConfig().getBoolean("useColorsInConsole")) {
langString = ChatColor.stripColor(langString);
}
((CommandSender)target).sendMessage(langString);
}
else if(target instanceof Logger) {
if(!getConfig().getBoolean("useColorsInConsole")) {
langString = ChatColor.stripColor(langString);
}
((Logger)target).info(langString);
} else {
langString = ChatColor.stripColor(langString);
this.getLogger().info("Could not send message, target is wrong: " + langString);
}
}
}
public void messageNoPrefix(Object target, String key, Object... params) {
configurableMessage(target, key, false, params);
}
public void message(Object target, String key, Object... params) {
configurableMessage(target, key, true, params);
}
/**
* Convert color and formatting codes to bukkit values
* @param input Start string with color and formatting codes in it
* @return String with the color and formatting codes in the bukkit format
*/
public String fixColors(String input) {
String result = null;
if(input != null) {
result = ChatColor.translateAlternateColorCodes('&', input);
result = result.replaceAll("�", "\u20AC");
}
return result;
}
/**
* Format the currency amount with the characters before and after
* @return Currency character format string
* @param amount Amount of money to format
*/
public String formatCurrency(double amount) {
String before = this.getConfig().getString("moneyCharacter");
before = before.replace(currencyEuro, "\u20ac");
String after = this.getConfig().getString("moneyCharacterAfter");
after = after.replace(currencyEuro, "\u20ac");
String result;
// Check for infinite and NaN
if(Double.isInfinite(amount)) {
result = "\u221E"; // Infinite symbol
} else if(Double.isNaN(amount)) {
result = "NaN";
} else {
// Add metric
double metricAbove = getConfig().getDouble("metricSuffixesAbove");
if(metricAbove != -1 && amount >= metricAbove) {
if(amount >= 1000000000000000000000000.0) {
amount = amount/1000000000000000000000000.0;
after = "Y" + after;
} else if(amount >= 1000000000000000000000.0) {
amount = amount/1000000000000000000000.0;
after = "Z" + after;
} else if(amount >= 1000000000000000000.0) {
amount = amount/1000000000000000000.0;
after = "E" + after;
} else if(amount >= 1000000000000000.0) {
amount = amount/1000000000000000.0;
after = "P" + after;
} else if(amount >= 1000000000000.0) {
amount = amount/1000000000000.0;
after = "T" + after;
} else if(amount >= 1000000000.0) {
amount = amount/1000000000.0;
after = "G" + after;
} else if(amount >= 1000000.0) {
amount = amount/1000000.0;
after = "M" + after;
} else if(amount >= 1000.0) {
amount = amount/1000.0;
after = "k" + after;
}
BigDecimal bigDecimal = new BigDecimal(amount);
if(bigDecimal.toString().contains(".")) {
int frontLength = bigDecimal.toString().substring(0, bigDecimal.toString().indexOf('.')).length();
bigDecimal = bigDecimal.setScale(getConfig().getInt("fractionalNumbers") + (3-frontLength), RoundingMode.HALF_UP);
}
result = bigDecimal.toString();
} else {
BigDecimal bigDecimal = new BigDecimal(amount);
bigDecimal = bigDecimal.setScale(getConfig().getInt("fractionalNumbers"), RoundingMode.HALF_UP);
amount = bigDecimal.doubleValue();
result = bigDecimal.toString();
if(getConfig().getBoolean("hideEmptyFractionalPart") && (amount%1.0) == 0.0 && result.contains(".")) {
result = result.substring(0, result.indexOf('.'));
}
}
}
result = result.replace(".", getConfig().getString("decimalMark"));
return before + result + after;
}
/**
* Function for quitting the plugin, NOT USED ATM
*/
public void quit() {
this.getLogger().info("Plugin will be stopped");
Bukkit.getPluginManager().disablePlugin(this);
}
/**
* Return the config configured by the user or the default
*/
@Override
public YamlConfiguration getConfig() {
return fileManager.getConfig();
}
/**
* Start the Metrics stats collection
*/
private void startMetrics() {
try {
Metrics metrics = new Metrics(this);
metrics.start();
} catch (Exception e) {
AreaShop.debug("Could not start Metrics");
}
}
/**
* Checks if the string is a correct time period
* @param time String that has to be checked
* @return true if format is correct, false if not
*/
public boolean checkTimeFormat(String time) {
/* Check if the string is not empty and check the length */
if(time == null || time.length() <= 1 || time.indexOf(' ') == -1 || time.indexOf(' ') >= (time.length()-1)) {
return false;
}
/* Check if the suffix is one of these values */
String suffix = time.substring(time.indexOf(' ')+1, time.length());
ArrayList<String> identifiers = new ArrayList<String>();
identifiers.addAll(this.getConfig().getStringList("minutes"));
identifiers.addAll(this.getConfig().getStringList("hours"));
identifiers.addAll(this.getConfig().getStringList("days"));
identifiers.addAll(this.getConfig().getStringList("months"));
identifiers.addAll(this.getConfig().getStringList("years"));
if(!identifiers.contains(suffix)) {
return false;
}
/* check if the part before the space is a number */
String prefix = time.substring(0, (time.indexOf(' ')));
return prefix.matches("\\d+");
}
/**
* Methode to tranlate a duration string to a millisecond value
* @param duration The duration string
* @return The duration in milliseconds translated from the durationstring, or if it is invalid then 0
*/
public long durationStringToLong(String duration) {
if(duration == null) {
return 0;
} else if(duration.equalsIgnoreCase("disabled") || duration.equalsIgnoreCase("unlimited")) {
return -1;
} else if(duration.indexOf(' ') == -1) {
return 0;
}
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(0);
ArrayList<String> seconds = new ArrayList<String>(this.getConfig().getStringList("seconds"));
ArrayList<String> minutes = new ArrayList<String>(this.getConfig().getStringList("minutes"));
ArrayList<String> hours = new ArrayList<String>(this.getConfig().getStringList("hours"));
ArrayList<String> days = new ArrayList<String>(this.getConfig().getStringList("days"));
ArrayList<String> months = new ArrayList<String>(this.getConfig().getStringList("months"));
ArrayList<String> years = new ArrayList<String>(this.getConfig().getStringList("years"));
String durationString = duration.substring(duration.indexOf(' ')+1, duration.length());
int durationInt = 0;
try {
durationInt = Integer.parseInt(duration.substring(0, duration.indexOf(' ')));
} catch(NumberFormatException exception) {}
if(seconds.contains(durationString)) {
calendar.add(Calendar.SECOND, durationInt);
} else if(minutes.contains(durationString)) {
calendar.add(Calendar.MINUTE, durationInt);
} else if(hours.contains(durationString)) {
calendar.add(Calendar.HOUR, durationInt);
} else if(days.contains(durationString)) {
calendar.add(Calendar.DAY_OF_MONTH, durationInt);
} else if(months.contains(durationString)) {
calendar.add(Calendar.MONTH, durationInt);
} else if(years.contains(durationString)) {
calendar.add(Calendar.YEAR, durationInt);
}
return calendar.getTimeInMillis();
}
/**
* Get setting from config that could be only a number indicating seconds
* or a string indicating a duration string
* @param path Path of the setting to read
* @return milliseconds that the setting indicates
*/
public long getDurationFromSecondsOrString(String path) {
if(getConfig().isLong(path) || getConfig().isInt(path)) {
long setting = getConfig().getLong(path);
if(setting != -1) {
setting = setting*1000;
}
return setting;
} else {
return durationStringToLong(getConfig().getString(path));
}
}
/**
* Get setting from config that could be only a number indicating minutes
* or a string indicating a duration string
* @param path Path of the setting to read
* @return milliseconds that the setting indicates
*/
public long getDurationFromMinutesOrString(String path) {
if(getConfig().isLong(path) || getConfig().isInt(path)) {
long setting = getConfig().getLong(path);
if(setting != -1) {
setting = setting*60*1000;
}
return setting;
} else {
return durationStringToLong(getConfig().getString(path));
}
}
/**
* Parse a time setting that could be minutes or a duration string
* @param input The string to parse
* @return milliseconds that the string indicates
*/
public long getDurationFromMinutesOrStringInput(String input) {
long number;
try {
number = Long.parseLong(input);
if(number != -1) {
number = number*60*1000;
}
return number;
} catch(NumberFormatException e) {
return durationStringToLong(input);
}
}
/**
* Parse a time setting that could be seconds or a duration string
* @param input The string to parse
* @return seconds that the string indicates
*/
public long getDurationFromSecondsOrStringInput(String input) {
long number;
try {
number = Long.parseLong(input);
if(number != -1) {
number = number*1000;
}
return number;
} catch(NumberFormatException e) {
return durationStringToLong(input);
}
}
/**
* Sends an debug message to the console
* @param message The message that should be printed to the console
*/
public static void debug(String message) {
if(AreaShop.getInstance().debug) {
AreaShop.getInstance().getLogger().info("Debug: " + message);
}
}
/**
* Non-static debug to use as implementation of the interface
*/
public void debugI(String message) {
AreaShop.debug(message);
}
/**
* Reload all files of the plugin and update all regions
* confirmationReceiver The CommandSender that should receive confirmation messages, null for nobody
*/
public void reload(final CommandSender confirmationReceiver) {
setReady(false);
fileManager.saveRequiredFilesAtOnce();
chatprefix = this.getConfig().getString("chatPrefix");
debug = this.getConfig().getBoolean("debug");
fileManager.loadFiles();
languageManager.startup();
message(confirmationReceiver, "reload-reloading");
fileManager.checkRents();
fileManager.updateAllRegions(confirmationReceiver);
}
/**
* Reload all files of the plugin and update all regions
*/
public void reload() {
reload(null);
}
/**
* Conversion to name by uuid
* @param uuid The uuid in string format
* @return the name of the player
*/
public String toName(String uuid) {
if(uuid == null) {
return "";
} else {
UUID parsed = null;
try {
parsed = UUID.fromString(uuid);
} catch(IllegalArgumentException e) {}
if(parsed == null) {
return "";
}
return this.toName(parsed);
}
}
/**
* Conversion to name by uuid object
* @param uuid The uuid in string format
* @return the name of the player
*/
public String toName(UUID uuid) {
if(uuid == null) {
return "";
} else {
String name = Bukkit.getOfflinePlayer(uuid).getName();
if(name != null) {
return name;
}
return "";
}
}
/**
* Conversion from name to uuid
* @param name The name of the player
* @return The uuid of the player
*/
@SuppressWarnings("deprecation") // Fake deprecation by Bukkit to inform developers, method will stay
public String toUUID(String name) {
if(name == null) {
return null;
} else {
return Bukkit.getOfflinePlayer(name).getUniqueId().toString();
}
}
}
@@ -1,760 +0,0 @@
/*
* Copyright 2011-2013 Tyler Blair. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and contributors and should not be interpreted as representing official policies,
* either expressed or implied, of anybody else.
*/
package nl.evolutioncoding.areashop;
import org.bukkit.Bukkit;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginDescriptionFile;
import org.bukkit.scheduler.BukkitTask;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.Proxy;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.UUID;
import java.util.logging.Level;
import java.util.zip.GZIPOutputStream;
public class Metrics {
/**
* The current revision number
*/
private final static int REVISION = 7;
/**
* The base url of the metrics domain
*/
private static final String BASE_URL = "http://report.mcstats.org";
/**
* The url used to report a server's status
*/
private static final String REPORT_URL = "/plugin/%s";
/**
* Interval of time to ping (in minutes)
*/
private static final int PING_INTERVAL = 15;
/**
* The plugin this metrics submits for
*/
private final Plugin plugin;
/**
* All of the custom graphs to submit to metrics
*/
private final Set<Graph> graphs = Collections.synchronizedSet(new HashSet<Graph>());
/**
* The plugin configuration file
*/
private final YamlConfiguration configuration;
/**
* The plugin configuration file
*/
private final File configurationFile;
/**
* Unique server id
*/
private final String guid;
/**
* Debug mode
*/
private final boolean debug;
/**
* Lock for synchronization
*/
private final Object optOutLock = new Object();
/**
* The scheduled task
*/
private volatile BukkitTask task = null;
public Metrics(final Plugin plugin) throws IOException {
if (plugin == null) {
throw new IllegalArgumentException("Plugin cannot be null");
}
this.plugin = plugin;
// load the config
configurationFile = getConfigFile();
configuration = YamlConfiguration.loadConfiguration(configurationFile);
// add some defaults
configuration.addDefault("opt-out", false);
configuration.addDefault("guid", UUID.randomUUID().toString());
configuration.addDefault("debug", false);
// Do we need to create the file?
if (configuration.get("guid", null) == null) {
configuration.options().header("http://mcstats.org").copyDefaults(true);
configuration.save(configurationFile);
}
// Load the guid then
guid = configuration.getString("guid");
debug = configuration.getBoolean("debug", false);
}
/**
* Construct and create a Graph that can be used to separate specific plotters to their own graphs on the metrics
* website. Plotters can be added to the graph object returned.
*
* @param name The name of the graph
* @return Graph object created. Will never return NULL under normal circumstances unless bad parameters are given
*/
public Graph createGraph(final String name) {
if (name == null) {
throw new IllegalArgumentException("Graph name cannot be null");
}
// Construct the graph object
final Graph graph = new Graph(name);
// Now we can add our graph
graphs.add(graph);
// and return back
return graph;
}
/**
* Add a Graph object to BukkitMetrics that represents data for the plugin that should be sent to the backend
*
* @param graph The name of the graph
*/
public void addGraph(final Graph graph) {
if (graph == null) {
throw new IllegalArgumentException("Graph cannot be null");
}
graphs.add(graph);
}
/**
* Start measuring statistics. This will immediately create an async repeating task as the plugin and send the
* initial data to the metrics backend, and then after that it will post in increments of PING_INTERVAL * 1200
* ticks.
*
* @return True if statistics measuring is running, otherwise false.
*/
public boolean start() {
synchronized (optOutLock) {
// Did we opt out?
if (isOptOut()) {
return false;
}
// Is metrics already running?
if (task != null) {
return true;
}
// Begin hitting the server with glorious data
task = plugin.getServer().getScheduler().runTaskTimerAsynchronously(plugin, new Runnable() {
private boolean firstPost = true;
public void run() {
try {
// This has to be synchronized or it can collide with the disable method.
synchronized (optOutLock) {
// Disable Task, if it is running and the server owner decided to opt-out
if (isOptOut() && task != null) {
task.cancel();
task = null;
// Tell all plotters to stop gathering information.
for (Graph graph : graphs) {
graph.onOptOut();
}
}
}
// We use the inverse of firstPost because if it is the first time we are posting,
// it is not a interval ping, so it evaluates to FALSE
// Each time thereafter it will evaluate to TRUE, i.e PING!
postPlugin(!firstPost);
// After the first post we set firstPost to false
// Each post thereafter will be a ping
firstPost = false;
} catch (IOException e) {
if (debug) {
Bukkit.getLogger().log(Level.INFO, "[Metrics] " + e.getMessage());
}
}
}
}, 0, PING_INTERVAL * 1200);
return true;
}
}
/**
* Has the server owner denied plugin metrics?
*
* @return true if metrics should be opted out of it
*/
public boolean isOptOut() {
synchronized (optOutLock) {
try {
// Reload the metrics file
configuration.load(getConfigFile());
} catch (IOException ex) {
if (debug) {
Bukkit.getLogger().log(Level.INFO, "[Metrics] " + ex.getMessage());
}
return true;
} catch (InvalidConfigurationException ex) {
if (debug) {
Bukkit.getLogger().log(Level.INFO, "[Metrics] " + ex.getMessage());
}
return true;
}
return configuration.getBoolean("opt-out", false);
}
}
/**
* Enables metrics for the server by setting "opt-out" to false in the config file and starting the metrics task.
*
* @throws java.io.IOException
*/
public void enable() throws IOException {
// This has to be synchronized or it can collide with the check in the task.
synchronized (optOutLock) {
// Check if the server owner has already set opt-out, if not, set it.
if (isOptOut()) {
configuration.set("opt-out", false);
configuration.save(configurationFile);
}
// Enable Task, if it is not running
if (task == null) {
start();
}
}
}
/**
* Disables metrics for the server by setting "opt-out" to true in the config file and canceling the metrics task.
*
* @throws java.io.IOException
*/
public void disable() throws IOException {
// This has to be synchronized or it can collide with the check in the task.
synchronized (optOutLock) {
// Check if the server owner has already set opt-out, if not, set it.
if (!isOptOut()) {
configuration.set("opt-out", true);
configuration.save(configurationFile);
}
// Disable Task, if it is running
if (task != null) {
task.cancel();
task = null;
}
}
}
/**
* Gets the File object of the config file that should be used to store data such as the GUID and opt-out status
*
* @return the File object for the config file
*/
public File getConfigFile() {
// I believe the easiest way to get the base folder (e.g craftbukkit set via -P) for plugins to use
// is to abuse the plugin object we already have
// plugin.getDataFolder() => base/plugins/PluginA/
// pluginsFolder => base/plugins/
// The base is not necessarily relative to the startup directory.
File pluginsFolder = plugin.getDataFolder().getParentFile();
// return => base/plugins/PluginMetrics/config.yml
return new File(new File(pluginsFolder, "PluginMetrics"), "config.yml");
}
/**
* Generic method that posts a plugin to the metrics website
*/
private void postPlugin(final boolean isPing) throws IOException {
// Server software specific section
PluginDescriptionFile description = plugin.getDescription();
String pluginName = description.getName();
boolean onlineMode = Bukkit.getServer().getOnlineMode(); // TRUE if online mode is enabled
String pluginVersion = description.getVersion();
String serverVersion = Bukkit.getVersion();
// TODO change to different method
int playersOnline = Bukkit.getServer().getOnlinePlayers().length;
// END server software specific section -- all code below does not use any code outside of this class / Java
// Construct the post data
StringBuilder json = new StringBuilder(1024);
json.append('{');
// The plugin's description file containg all of the plugin data such as name, version, author, etc
appendJSONPair(json, "guid", guid);
appendJSONPair(json, "plugin_version", pluginVersion);
appendJSONPair(json, "server_version", serverVersion);
appendJSONPair(json, "players_online", Integer.toString(playersOnline));
// New data as of R6
String osname = System.getProperty("os.name");
String osarch = System.getProperty("os.arch");
String osversion = System.getProperty("os.version");
String java_version = System.getProperty("java.version");
int coreCount = Runtime.getRuntime().availableProcessors();
// normalize os arch .. amd64 -> x86_64
if (osarch.equals("amd64")) {
osarch = "x86_64";
}
appendJSONPair(json, "osname", osname);
appendJSONPair(json, "osarch", osarch);
appendJSONPair(json, "osversion", osversion);
appendJSONPair(json, "cores", Integer.toString(coreCount));
appendJSONPair(json, "auth_mode", onlineMode ? "1" : "0");
appendJSONPair(json, "java_version", java_version);
// If we're pinging, append it
if (isPing) {
appendJSONPair(json, "ping", "1");
}
if (graphs.size() > 0) {
synchronized (graphs) {
json.append(',');
json.append('"');
json.append("graphs");
json.append('"');
json.append(':');
json.append('{');
boolean firstGraph = true;
final Iterator<Graph> iter = graphs.iterator();
while (iter.hasNext()) {
Graph graph = iter.next();
StringBuilder graphJson = new StringBuilder();
graphJson.append('{');
for (Plotter plotter : graph.getPlotters()) {
appendJSONPair(graphJson, plotter.getColumnName(), Integer.toString(plotter.getValue()));
}
graphJson.append('}');
if (!firstGraph) {
json.append(',');
}
json.append(escapeJSON(graph.getName()));
json.append(':');
json.append(graphJson);
firstGraph = false;
}
json.append('}');
}
}
// close json
json.append('}');
// Create the url
URL url = new URL(BASE_URL + String.format(REPORT_URL, urlEncode(pluginName)));
// Connect to the website
URLConnection connection;
// Mineshafter creates a socks proxy, so we can safely bypass it
// It does not reroute POST requests so we need to go around it
if (isMineshafterPresent()) {
connection = url.openConnection(Proxy.NO_PROXY);
} else {
connection = url.openConnection();
}
byte[] uncompressed = json.toString().getBytes();
byte[] compressed = gzip(json.toString());
// Headers
connection.addRequestProperty("User-Agent", "MCStats/" + REVISION);
connection.addRequestProperty("Content-Type", "application/json");
connection.addRequestProperty("Content-Encoding", "gzip");
connection.addRequestProperty("Content-Length", Integer.toString(compressed.length));
connection.addRequestProperty("Accept", "application/json");
connection.addRequestProperty("Connection", "close");
connection.setDoOutput(true);
if (debug) {
System.out.println("[Metrics] Prepared request for " + pluginName + " uncompressed=" + uncompressed.length + " compressed=" + compressed.length);
}
// Write the data
OutputStream os = connection.getOutputStream();
os.write(compressed);
os.flush();
// Now read the response
final BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String response = reader.readLine();
// close resources
os.close();
reader.close();
if (response == null || response.startsWith("ERR") || response.startsWith("7")) {
if (response == null) {
response = "null";
} else if (response.startsWith("7")) {
response = response.substring(response.startsWith("7,") ? 2 : 1);
}
throw new IOException(response);
} else {
// Is this the first update this hour?
if (response.equals("1") || response.contains("This is your first update this hour")) {
synchronized (graphs) {
final Iterator<Graph> iter = graphs.iterator();
while (iter.hasNext()) {
final Graph graph = iter.next();
for (Plotter plotter : graph.getPlotters()) {
plotter.reset();
}
}
}
}
}
}
/**
* GZip compress a string of bytes
*
* @param input
* @return
*/
public static byte[] gzip(String input) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GZIPOutputStream gzos = null;
try {
gzos = new GZIPOutputStream(baos);
gzos.write(input.getBytes("UTF-8"));
} catch (IOException e) {
e.printStackTrace();
} finally {
if (gzos != null) try {
gzos.close();
} catch (IOException ignore) {
}
}
return baos.toByteArray();
}
/**
* Check if mineshafter is present. If it is, we need to bypass it to send POST requests
*
* @return true if mineshafter is installed on the server
*/
private boolean isMineshafterPresent() {
try {
Class.forName("mineshafter.MineServer");
return true;
} catch (Exception e) {
return false;
}
}
/**
* Appends a json encoded key/value pair to the given string builder.
*
* @param json
* @param key
* @param value
* @throws UnsupportedEncodingException
*/
private static void appendJSONPair(StringBuilder json, String key, String value) throws UnsupportedEncodingException {
boolean isValueNumeric = false;
try {
if (value.equals("0") || !value.endsWith("0")) {
Double.parseDouble(value);
isValueNumeric = true;
}
} catch (NumberFormatException e) {
isValueNumeric = false;
}
if (json.charAt(json.length() - 1) != '{') {
json.append(',');
}
json.append(escapeJSON(key));
json.append(':');
if (isValueNumeric) {
json.append(value);
} else {
json.append(escapeJSON(value));
}
}
/**
* Escape a string to create a valid JSON string
*
* @param text
* @return
*/
private static String escapeJSON(String text) {
StringBuilder builder = new StringBuilder();
builder.append('"');
for (int index = 0; index < text.length(); index++) {
char chr = text.charAt(index);
switch (chr) {
case '"':
case '\\':
builder.append('\\');
builder.append(chr);
break;
case '\b':
builder.append("\\b");
break;
case '\t':
builder.append("\\t");
break;
case '\n':
builder.append("\\n");
break;
case '\r':
builder.append("\\r");
break;
default:
if (chr < ' ') {
String t = "000" + Integer.toHexString(chr);
builder.append("\\u" + t.substring(t.length() - 4));
} else {
builder.append(chr);
}
break;
}
}
builder.append('"');
return builder.toString();
}
/**
* Encode text as UTF-8
*
* @param text the text to encode
* @return the encoded text, as UTF-8
*/
private static String urlEncode(final String text) throws UnsupportedEncodingException {
return URLEncoder.encode(text, "UTF-8");
}
/**
* Represents a custom graph on the website
*/
public static class Graph {
/**
* The graph's name, alphanumeric and spaces only :) If it does not comply to the above when submitted, it is
* rejected
*/
private final String name;
/**
* The set of plotters that are contained within this graph
*/
private final Set<Plotter> plotters = new LinkedHashSet<Plotter>();
private Graph(final String name) {
this.name = name;
}
/**
* Gets the graph's name
*
* @return the Graph's name
*/
public String getName() {
return name;
}
/**
* Add a plotter to the graph, which will be used to plot entries
*
* @param plotter the plotter to add to the graph
*/
public void addPlotter(final Plotter plotter) {
plotters.add(plotter);
}
/**
* Remove a plotter from the graph
*
* @param plotter the plotter to remove from the graph
*/
public void removePlotter(final Plotter plotter) {
plotters.remove(plotter);
}
/**
* Gets an <b>unmodifiable</b> set of the plotter objects in the graph
*
* @return an unmodifiable {@link java.util.Set} of the plotter objects
*/
public Set<Plotter> getPlotters() {
return Collections.unmodifiableSet(plotters);
}
@Override
public int hashCode() {
return name.hashCode();
}
@Override
public boolean equals(final Object object) {
if (!(object instanceof Graph)) {
return false;
}
final Graph graph = (Graph) object;
return graph.name.equals(name);
}
/**
* Called when the server owner decides to opt-out of BukkitMetrics while the server is running.
*/
protected void onOptOut() {
}
}
/**
* Interface used to collect custom data for a plugin
*/
public static abstract class Plotter {
/**
* The plot's name
*/
private final String name;
/**
* Construct a plotter with the default plot name
*/
public Plotter() {
this("Default");
}
/**
* Construct a plotter with a specific plot name
*
* @param name the name of the plotter to use, which will show up on the website
*/
public Plotter(final String name) {
this.name = name;
}
/**
* Get the current value for the plotted point. Since this function defers to an external function it may or may
* not return immediately thus cannot be guaranteed to be thread friendly or safe. This function can be called
* from any thread so care should be taken when accessing resources that need to be synchronized.
*
* @return the current value for the point to be plotted.
*/
public abstract int getValue();
/**
* Get the column name for the plotted point
*
* @return the plotted point's column name
*/
public String getColumnName() {
return name;
}
/**
* Called after the website graphs have been updated
*/
public void reset() {
}
@Override
public int hashCode() {
return getColumnName().hashCode();
}
@Override
public boolean equals(final Object object) {
if (!(object instanceof Plotter)) {
return false;
}
final Plotter plotter = (Plotter) object;
return plotter.name.equals(name) && plotter.getValue() == getValue();
}
}
}
@@ -1,746 +0,0 @@
package nl.evolutioncoding.areashop;
import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.Enumeration;
import java.util.logging.Level;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.plugin.Plugin;
import org.bukkit.scheduler.BukkitRunnable;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.JSONValue;
/**
* Check for updates on BukkitDev for a given plugin, and download the updates if needed.
* <p/>
* <b>VERY, VERY IMPORTANT</b>: Because there are no standards for adding auto-update toggles in your plugin's config, this system provides NO CHECK WITH YOUR CONFIG to make sure the user has allowed auto-updating.
* <br>
* It is a <b>BUKKIT POLICY</b> that you include a boolean value in your config that prevents the auto-updater from running <b>AT ALL</b>.
* <br>
* If you fail to include this option in your config, your plugin will be <b>REJECTED</b> when you attempt to submit it to dev.bukkit.org.
* <p/>
* An example of a good configuration option would be something similar to 'auto-update: true' - if this value is set to false you may NOT run the auto-updater.
* <br>
* If you are unsure about these rules, please read the plugin submission guidelines: http://goo.gl/8iU5l
*
* @author Gravity
* @version 2.3
*/
public class Updater {
/* Constants */
// Remote file's title
private static final String TITLE_VALUE = "name";
// Remote file's download link
private static final String LINK_VALUE = "downloadUrl";
// Remote file's release type
private static final String TYPE_VALUE = "releaseType";
// Remote file's build version
private static final String VERSION_VALUE = "gameVersion";
// Path to GET
private static final String QUERY = "/servermods/files?projectIds=";
// Slugs will be appended to this to get to the project's RSS feed
private static final String HOST = "https://api.curseforge.com";
// User-agent when querying Curse
private static final String USER_AGENT = "Updater (by Gravity)";
// Used for locating version numbers in file names
private static final String DELIMETER = "^V|[\\s_-]V";
// If the version number contains one of these, don't update.
private static final String[] NO_UPDATE_TAG = { "-DEV", "-PRE", "-SNAPSHOT" };
// Used for downloading files
private static final int BYTE_SIZE = 1024;
// Config key for api key
private static final String API_KEY_CONFIG_KEY = "api-key";
// Config key for disabling Updater
private static final String DISABLE_CONFIG_KEY = "disable";
// Default api key value in config
private static final String API_KEY_DEFAULT = "PUT_API_KEY_HERE";
// Default disable value in config
private static final boolean DISABLE_DEFAULT = false;
/* User-provided variables */
// Plugin running Updater
private final Plugin plugin;
// Type of update check to run
private final UpdateType type;
// Whether to announce file downloads
private final boolean announce;
// The plugin file (jar)
private final File file;
// The folder that downloads will be placed in
private final File updateFolder;
// The provided callback (if any)
private final UpdateCallback callback;
// Project's Curse ID
private int id = -1;
// BukkitDev ServerMods API key
private String apiKey = null;
/* Collected from Curse API */
private String versionName;
private String versionLink;
private String versionType;
private String versionGameVersion;
/* Update process variables */
// Connection to RSS
private URL url;
// Updater thread
private Thread thread;
// Used for determining the outcome of the update process
private Updater.UpdateResult result = Updater.UpdateResult.SUCCESS;
/**
* Gives the developer the result of the update process. Can be obtained by called {@link #getResult()}
*/
public enum UpdateResult {
/**
* The updater found an update, and has readied it to be loaded the next time the server restarts/reloads.
*/
SUCCESS,
/**
* The updater did not find an update, and nothing was downloaded.
*/
NO_UPDATE,
/**
* The server administrator has disabled the updating system.
*/
DISABLED,
/**
* The updater found an update, but was unable to download it.
*/
FAIL_DOWNLOAD,
/**
* For some reason, the updater was unable to contact dev.bukkit.org to download the file.
*/
FAIL_DBO,
/**
* When running the version check, the file on DBO did not contain a recognizable version.
*/
FAIL_NOVERSION,
/**
* The id provided by the plugin running the updater was invalid and doesn't exist on DBO.
*/
FAIL_BADID,
/**
* The server administrator has improperly configured their API key in the configuration.
*/
FAIL_APIKEY,
/**
* The updater found an update, but because of the UpdateType being set to NO_DOWNLOAD, it wasn't downloaded.
*/
UPDATE_AVAILABLE
}
/**
* Allows the developer to specify the type of update that will be run.
*/
public enum UpdateType {
/**
* Run a version check, and then if the file is out of date, download the newest version.
*/
DEFAULT,
/**
* Don't run a version check, just find the latest update and download it.
*/
NO_VERSION_CHECK,
/**
* Get information about the version and the download size, but don't actually download anything.
*/
NO_DOWNLOAD
}
/**
* Represents the various release types of a file on BukkitDev.
*/
public enum ReleaseType {
/**
* An "alpha" file.
*/
ALPHA,
/**
* A "beta" file.
*/
BETA,
/**
* A "release" file.
*/
RELEASE
}
/**
* Initialize the updater.
*
* @param plugin The plugin that is checking for an update.
* @param id The dev.bukkit.org id of the project.
* @param file The file that the plugin is running from, get this by doing this.getFile() from within your main class.
* @param type Specify the type of update this will be. See {@link UpdateType}
* @param announce True if the program should announce the progress of new updates in console.
*/
public Updater(Plugin plugin, int id, File file, UpdateType type, boolean announce) {
this(plugin, id, file, type, null, announce);
}
/**
* Initialize the updater with the provided callback.
*
* @param plugin The plugin that is checking for an update.
* @param id The dev.bukkit.org id of the project.
* @param file The file that the plugin is running from, get this by doing this.getFile() from within your main class.
* @param type Specify the type of update this will be. See {@link UpdateType}
* @param callback The callback instance to notify when the Updater has finished
*/
public Updater(Plugin plugin, int id, File file, UpdateType type, UpdateCallback callback) {
this(plugin, id, file, type, callback, false);
}
/**
* Initialize the updater with the provided callback.
*
* @param plugin The plugin that is checking for an update.
* @param id The dev.bukkit.org id of the project.
* @param file The file that the plugin is running from, get this by doing this.getFile() from within your main class.
* @param type Specify the type of update this will be. See {@link UpdateType}
* @param callback The callback instance to notify when the Updater has finished
* @param announce True if the program should announce the progress of new updates in console.
*/
public Updater(Plugin plugin, int id, File file, UpdateType type, UpdateCallback callback, boolean announce) {
this.plugin = plugin;
this.type = type;
this.announce = announce;
this.file = file;
this.id = id;
this.updateFolder = this.plugin.getServer().getUpdateFolderFile();
this.callback = callback;
final File pluginFile = this.plugin.getDataFolder().getParentFile();
final File updaterFile = new File(pluginFile, "Updater");
final File updaterConfigFile = new File(updaterFile, "config.yml");
YamlConfiguration config = new YamlConfiguration();
config.options().header("This configuration file affects all plugins using the Updater system (version 2+ - http://forums.bukkit.org/threads/96681/ )" + '\n'
+ "If you wish to use your API key, read http://wiki.bukkit.org/ServerMods_API and place it below." + '\n'
+ "Some updating systems will not adhere to the disabled value, but these may be turned off in their plugin's configuration.");
config.addDefault(API_KEY_CONFIG_KEY, API_KEY_DEFAULT);
config.addDefault(DISABLE_CONFIG_KEY, DISABLE_DEFAULT);
if (!updaterFile.exists()) {
this.fileIOOrError(updaterFile, updaterFile.mkdir(), true);
}
boolean createFile = !updaterConfigFile.exists();
try {
if (createFile) {
this.fileIOOrError(updaterConfigFile, updaterConfigFile.createNewFile(), true);
config.options().copyDefaults(true);
config.save(updaterConfigFile);
} else {
config.load(updaterConfigFile);
}
} catch (final Exception e) {
final String message;
if (createFile) {
message = "The updater could not create configuration at " + updaterFile.getAbsolutePath();
} else {
message = "The updater could not load configuration at " + updaterFile.getAbsolutePath();
}
this.plugin.getLogger().log(Level.SEVERE, message, e);
}
if (config.getBoolean(DISABLE_CONFIG_KEY)) {
this.result = UpdateResult.DISABLED;
return;
}
String key = config.getString(API_KEY_CONFIG_KEY);
if (API_KEY_DEFAULT.equalsIgnoreCase(key) || "".equals(key)) {
key = null;
}
this.apiKey = key;
try {
this.url = new URL(Updater.HOST + Updater.QUERY + this.id);
} catch (final MalformedURLException e) {
this.plugin.getLogger().log(Level.SEVERE, "The project ID provided for updating, " + this.id + " is invalid.", e);
this.result = UpdateResult.FAIL_BADID;
}
if (this.result != UpdateResult.FAIL_BADID) {
this.thread = new Thread(new UpdateRunnable());
this.thread.start();
} else {
runUpdater();
}
}
/**
* Get the result of the update process.
*
* @return result of the update process.
* @see UpdateResult
*/
public Updater.UpdateResult getResult() {
this.waitForThread();
return this.result;
}
/**
* Get the latest version's release type.
*
* @return latest version's release type.
* @see ReleaseType
*/
public ReleaseType getLatestType() {
this.waitForThread();
if (this.versionType != null) {
for (ReleaseType type : ReleaseType.values()) {
if (this.versionType.equalsIgnoreCase(type.name())) {
return type;
}
}
}
return null;
}
/**
* Get the latest version's game version (such as "CB 1.2.5-R1.0").
*
* @return latest version's game version.
*/
public String getLatestGameVersion() {
this.waitForThread();
return this.versionGameVersion;
}
/**
* Get the latest version's name (such as "Project v1.0").
*
* @return latest version's name.
*/
public String getLatestName() {
this.waitForThread();
return this.versionName;
}
/**
* Get the latest version's direct file link.
*
* @return latest version's file link.
*/
public String getLatestFileLink() {
this.waitForThread();
return this.versionLink;
}
/**
* As the result of Updater output depends on the thread's completion, it is necessary to wait for the thread to finish
* before allowing anyone to check the result.
*/
private void waitForThread() {
if ((this.thread != null) && this.thread.isAlive()) {
try {
this.thread.join();
} catch (final InterruptedException e) {
this.plugin.getLogger().log(Level.SEVERE, null, e);
}
}
}
/**
* Save an update from dev.bukkit.org into the server's update folder.
*
* @param file the name of the file to save it as.
*/
private void saveFile(String file) {
final File folder = this.updateFolder;
deleteOldFiles();
if (!folder.exists()) {
this.fileIOOrError(folder, folder.mkdir(), true);
}
downloadFile();
// Check to see if it's a zip file, if it is, unzip it.
final File dFile = new File(folder.getAbsolutePath(), file);
if (dFile.getName().endsWith(".zip")) {
// Unzip
this.unzip(dFile.getAbsolutePath());
}
if (this.announce) {
this.plugin.getLogger().info("Finished updating.");
}
}
/**
* Download a file and save it to the specified folder.
*/
private void downloadFile() {
BufferedInputStream in = null;
FileOutputStream fout = null;
try {
URL fileUrl = new URL(this.versionLink);
final int fileLength = fileUrl.openConnection().getContentLength();
in = new BufferedInputStream(fileUrl.openStream());
fout = new FileOutputStream(new File(this.updateFolder, file.getName()));
final byte[] data = new byte[Updater.BYTE_SIZE];
int count;
if (this.announce) {
this.plugin.getLogger().info("About to download a new update: " + this.versionName);
}
long downloaded = 0;
while ((count = in.read(data, 0, Updater.BYTE_SIZE)) != -1) {
downloaded += count;
fout.write(data, 0, count);
final int percent = (int) ((downloaded * 100) / fileLength);
if (this.announce && ((percent % 10) == 0)) {
this.plugin.getLogger().info("Downloading update: " + percent + "% of " + fileLength + " bytes.");
}
}
} catch (Exception ex) {
this.plugin.getLogger().log(Level.WARNING, "The auto-updater tried to download a new update, but was unsuccessful.", ex);
this.result = Updater.UpdateResult.FAIL_DOWNLOAD;
} finally {
try {
if (in != null) {
in.close();
}
} catch (final IOException ex) {
this.plugin.getLogger().log(Level.SEVERE, null, ex);
}
try {
if (fout != null) {
fout.close();
}
} catch (final IOException ex) {
this.plugin.getLogger().log(Level.SEVERE, null, ex);
}
}
}
/**
* Remove possibly leftover files from the update folder.
*/
private void deleteOldFiles() {
//Just a quick check to make sure we didn't leave any files from last time...
File[] list = listFilesOrError(this.updateFolder);
for (final File xFile : list) {
if (xFile.getName().endsWith(".zip")) {
this.fileIOOrError(xFile, xFile.mkdir(), true);
}
}
}
/**
* Part of Zip-File-Extractor, modified by Gravity for use with Updater.
*
* @param file the location of the file to extract.
*/
private void unzip(String file) {
final File fSourceZip = new File(file);
try {
final String zipPath = file.substring(0, file.length() - 4);
ZipFile zipFile = new ZipFile(fSourceZip);
Enumeration<? extends ZipEntry> e = zipFile.entries();
while (e.hasMoreElements()) {
ZipEntry entry = e.nextElement();
File destinationFilePath = new File(zipPath, entry.getName());
this.fileIOOrError(destinationFilePath.getParentFile(), destinationFilePath.getParentFile().mkdirs(), true);
if (!entry.isDirectory()) {
final BufferedInputStream bis = new BufferedInputStream(zipFile.getInputStream(entry));
int b;
final byte[] buffer = new byte[Updater.BYTE_SIZE];
final FileOutputStream fos = new FileOutputStream(destinationFilePath);
final BufferedOutputStream bos = new BufferedOutputStream(fos, Updater.BYTE_SIZE);
while ((b = bis.read(buffer, 0, Updater.BYTE_SIZE)) != -1) {
bos.write(buffer, 0, b);
}
bos.flush();
bos.close();
bis.close();
final String name = destinationFilePath.getName();
if (name.endsWith(".jar") && this.pluginExists(name)) {
File output = new File(this.updateFolder, name);
this.fileIOOrError(output, destinationFilePath.renameTo(output), true);
}
}
}
zipFile.close();
// Move any plugin data folders that were included to the right place, Bukkit won't do this for us.
moveNewZipFiles(zipPath);
} catch (final IOException e) {
this.plugin.getLogger().log(Level.SEVERE, "The auto-updater tried to unzip a new update file, but was unsuccessful.", e);
this.result = Updater.UpdateResult.FAIL_DOWNLOAD;
} finally {
this.fileIOOrError(fSourceZip, fSourceZip.delete(), false);
}
}
/**
* Find any new files extracted from an update into the plugin's data directory.
* @param zipPath path of extracted files.
*/
private void moveNewZipFiles(String zipPath) {
File[] list = listFilesOrError(new File(zipPath));
for (final File dFile : list) {
if (dFile.isDirectory() && this.pluginExists(dFile.getName())) {
// Current dir
final File oFile = new File(this.plugin.getDataFolder().getParent(), dFile.getName());
// List of existing files in the new dir
final File[] dList = listFilesOrError(dFile);
// List of existing files in the current dir
final File[] oList = listFilesOrError(oFile);
for (File cFile : dList) {
// Loop through all the files in the new dir
boolean found = false;
for (final File xFile : oList) {
// Loop through all the contents in the current dir to see if it exists
if (xFile.getName().equals(cFile.getName())) {
found = true;
break;
}
}
if (!found) {
// Move the new file into the current dir
File output = new File(oFile, cFile.getName());
this.fileIOOrError(output, cFile.renameTo(output), true);
} else {
// This file already exists, so we don't need it anymore.
this.fileIOOrError(cFile, cFile.delete(), false);
}
}
}
this.fileIOOrError(dFile, dFile.delete(), false);
}
File zip = new File(zipPath);
this.fileIOOrError(zip, zip.delete(), false);
}
/**
* Check if the name of a jar is one of the plugins currently installed, used for extracting the correct files out of a zip.
*
* @param name a name to check for inside the plugins folder.
* @return true if a file inside the plugins folder is named this.
*/
private boolean pluginExists(String name) {
File[] plugins = listFilesOrError(new File("plugins"));
for (final File file : plugins) {
if (file.getName().equals(name)) {
return true;
}
}
return false;
}
/**
* Check to see if the program should continue by evaluating whether the plugin is already updated, or shouldn't be updated.
*
* @return true if the version was located and is not the same as the remote's newest.
*/
private boolean versionCheck() {
final String title = this.versionName;
if (this.type != UpdateType.NO_VERSION_CHECK) {
final String localVersion = this.plugin.getDescription().getVersion();
if (title.split(DELIMETER).length == 2) {
// Get the newest file's version number
final String remoteVersion = title.split(DELIMETER)[1].split(" ")[0];
if (this.hasTag(localVersion) || !this.shouldUpdate(localVersion, remoteVersion)) {
// We already have the latest version, or this build is tagged for no-update
this.result = Updater.UpdateResult.NO_UPDATE;
return false;
}
} else {
// The file's name did not contain the string 'vVersion'
final String authorInfo = this.plugin.getDescription().getAuthors().isEmpty() ? "" : " (" + this.plugin.getDescription().getAuthors().get(0) + ")";
this.plugin.getLogger().warning("The author of this plugin" + authorInfo + " has misconfigured their Auto Update system");
this.plugin.getLogger().warning("File versions should follow the format 'PluginName vVERSION'");
this.plugin.getLogger().warning("Please notify the author of this error.");
this.result = Updater.UpdateResult.FAIL_NOVERSION;
return false;
}
}
return true;
}
/**
* <b>If you wish to run mathematical versioning checks, edit this method.</b>
* <p>
* With default behavior, Updater will NOT verify that a remote version available on BukkitDev
* which is not this version is indeed an "update".
* If a version is present on BukkitDev that is not the version that is currently running,
* Updater will assume that it is a newer version.
* This is because there is no standard versioning scheme, and creating a calculation that can
* determine whether a new update is actually an update is sometimes extremely complicated.
* </p>
* <p>
* Updater will call this method from {@link #versionCheck()} before deciding whether
* the remote version is actually an update.
* If you have a specific versioning scheme with which a mathematical determination can
* be reliably made to decide whether one version is higher than another, you may
* revise this method, using the local and remote version parameters, to execute the
* appropriate check.
* </p>
* <p>
* Returning a value of <b>false</b> will tell the update process that this is NOT a new version.
* Without revision, this method will always consider a remote version at all different from
* that of the local version a new update.
* </p>
* @param localVersion the current version
* @param remoteVersion the remote version
* @return true if Updater should consider the remote version an update, false if not.
*/
public boolean shouldUpdate(String localVersion, String remoteVersion) {
return !localVersion.equalsIgnoreCase(remoteVersion);
}
/**
* Evaluate whether the version number is marked showing that it should not be updated by this program.
*
* @param version a version number to check for tags in.
* @return true if updating should be disabled.
*/
private boolean hasTag(String version) {
for (final String string : Updater.NO_UPDATE_TAG) {
if (version.contains(string)) {
return true;
}
}
return false;
}
/**
* Make a connection to the BukkitDev API and request the newest file's details.
*
* @return true if successful.
*/
private boolean read() {
try {
final URLConnection conn = this.url.openConnection();
conn.setConnectTimeout(5000);
if (this.apiKey != null) {
conn.addRequestProperty("X-API-Key", this.apiKey);
}
conn.addRequestProperty("User-Agent", Updater.USER_AGENT);
conn.setDoOutput(true);
final BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
final String response = reader.readLine();
final JSONArray array = (JSONArray) JSONValue.parse(response);
if (array.isEmpty()) {
this.plugin.getLogger().warning("The updater could not find any files for the project id " + this.id);
this.result = UpdateResult.FAIL_BADID;
return false;
}
JSONObject latestUpdate = (JSONObject) array.get(array.size() - 1);
this.versionName = (String) latestUpdate.get(Updater.TITLE_VALUE);
this.versionLink = (String) latestUpdate.get(Updater.LINK_VALUE);
this.versionType = (String) latestUpdate.get(Updater.TYPE_VALUE);
this.versionGameVersion = (String) latestUpdate.get(Updater.VERSION_VALUE);
return true;
} catch (final IOException e) {
if (e.getMessage().contains("HTTP response code: 403")) {
this.plugin.getLogger().severe("dev.bukkit.org rejected the API key provided in plugins/Updater/config.yml");
this.plugin.getLogger().severe("Please double-check your configuration to ensure it is correct.");
this.result = UpdateResult.FAIL_APIKEY;
} else {
this.plugin.getLogger().severe("The updater could not contact dev.bukkit.org for updating.");
this.plugin.getLogger().severe("If you have not recently modified your configuration and this is the first time you are seeing this message, the site may be experiencing temporary downtime.");
this.result = UpdateResult.FAIL_DBO;
}
AreaShop.debug(ExceptionUtils.getStackTrace(e));
return false;
}
}
/**
* Perform a file operation and log any errors if it fails.
* @param file file operation is performed on.
* @param result result of file operation.
* @param create true if a file is being created, false if deleted.
*/
private void fileIOOrError(File file, boolean result, boolean create) {
if (!result) {
this.plugin.getLogger().severe("The updater could not " + (create ? "create" : "delete") + " file at: " + file.getAbsolutePath());
}
}
private File[] listFilesOrError(File folder) {
File[] contents = folder.listFiles();
if (contents == null) {
this.plugin.getLogger().severe("The updater could not access files at: " + this.updateFolder.getAbsolutePath());
return new File[0];
} else {
return contents;
}
}
/**
* Called on main thread when the Updater has finished working, regardless
* of result.
*/
public interface UpdateCallback {
/**
* Called when the updater has finished working.
* @param updater The updater instance
*/
void onFinish(Updater updater);
}
private class UpdateRunnable implements Runnable {
@Override
public void run() {
runUpdater();
}
}
private void runUpdater() {
if (this.url != null && (this.read() && this.versionCheck())) {
// Obtain the results of the project's file feed
if ((this.versionLink != null) && (this.type != UpdateType.NO_DOWNLOAD)) {
String name = this.file.getName();
// If it's a zip file, it shouldn't be downloaded as the plugin's name
if (this.versionLink.endsWith(".zip")) {
name = this.versionLink.substring(this.versionLink.lastIndexOf("/") + 1);
}
this.saveFile(name);
} else {
this.result = UpdateResult.UPDATE_AVAILABLE;
}
}
if (this.callback != null) {
new BukkitRunnable() {
@Override
public void run() {
runCallback();
}
}.runTask(this.plugin);
}
}
private void runCallback() {
this.callback.onFinish(this);
}
}
@@ -1,293 +0,0 @@
package nl.evolutioncoding.areashop;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import nl.evolutioncoding.areashop.regions.BuyRegion;
import nl.evolutioncoding.areashop.regions.GeneralRegion;
import nl.evolutioncoding.areashop.regions.GeneralRegion.RegionType;
import nl.evolutioncoding.areashop.regions.RentRegion;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.block.BlockFace;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.YamlConfiguration;
import com.sk89q.worldedit.BlockVector;
import com.sk89q.worldedit.bukkit.selections.CuboidSelection;
import com.sk89q.worldedit.bukkit.selections.Selection;
import com.sk89q.worldguard.protection.managers.RegionManager;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
public class Utils {
// Not used
private Utils() {}
/**
* Create a map from a location, to save it in the config
* @param location The location to transform
* @return The map with the location values
*/
public static ConfigurationSection locationToConfig(Location location, boolean setPitchYaw) {
if(location == null) {
return null;
}
ConfigurationSection result = new YamlConfiguration();
result.set("world", location.getWorld().getName());
result.set("x", location.getX());
result.set("y", location.getY());
result.set("z", location.getZ());
if(setPitchYaw) {
result.set("yaw", Float.toString(location.getYaw()));
result.set("pitch", Float.toString(location.getPitch()));
}
return result;
}
public static ConfigurationSection locationToConfig(Location location) {
return locationToConfig(location, false);
}
/**
* Create a location from a map, reconstruction from the config values
* @param map The map to reconstruct from
* @return The location
*/
public static Location configToLocation(ConfigurationSection config) {
if(config == null
|| !config.isString("world")
|| !config.isDouble("x")
|| !config.isDouble("y")
|| !config.isDouble("z")
|| Bukkit.getWorld(config.getString("world")) == null) {
return null;
}
Location result = new Location(
Bukkit.getWorld(config.getString("world")),
(Double)config.getDouble("x"),
(Double)config.getDouble("y"),
(Double)config.getDouble("z"));
if(config.isString("yaw") && config.isString("pitch")) {
result.setPitch(Float.parseFloat(config.getString("pitch")));
result.setYaw(Float.parseFloat(config.getString("yaw")));
}
return result;
}
/**
* Create a comma-separated list
* @param input Collection of object which should be concatenated with comma's in between
* @return Innput object concatenated with comma's in between
*/
public static String createCommaSeparatedList(Collection<? extends Object> input) {
String result = "";
boolean first = true;
for(Object object : input) {
if(object != null) {
if(first) {
first = false;
result += object.toString();
} else {
result += ", " + object.toString();
}
}
}
return result;
}
/**
* Convert milliseconds to ticks
* @param milliseconds Milliseconds to convert
* @return milliseconds divided by 50 (20 ticks per second)
*/
public static long millisToTicks(long milliseconds) {
return milliseconds/50;
}
public static final BlockFace[] facings = { BlockFace.NORTH, BlockFace.NORTH_EAST, BlockFace.EAST, BlockFace.SOUTH_EAST, BlockFace.SOUTH, BlockFace.SOUTH_WEST, BlockFace.WEST, BlockFace.NORTH_WEST };
/**
* Get the facing direction based on the yaw
* @param yaw The horizontal angle that for example the player is looking
* @return The Block Face of the angle
*/
public static BlockFace yawToFacing(float yaw) {
return facings[Math.round(yaw / 45f) & 0x7];
}
// ======================================================================
// Methods to get WorldGuard or AreaShop regions by location or selection
// ======================================================================
/**
* Get all AreaShop regions intersecting with a WorldEdit selection
* @param selection The selection to check
* @return A list with all the AreaShop regions intersecting with the selection
*/
public static List<GeneralRegion> getASRegionsInSelection(Selection selection) {
ArrayList<GeneralRegion> result = new ArrayList<GeneralRegion>();
for(ProtectedRegion region : getWERegionsInSelection(selection)) {
GeneralRegion asRegion = AreaShop.getInstance().getFileManager().getRegion(region.getId());
if(asRegion != null) {
result.add(asRegion);
}
}
return result;
}
/**
* Get all AreaShop regions containing a location
* @param location The location to check
* @return A list with all the AreaShop regions that contain the location
*/
public static List<GeneralRegion> getASRegionsByLocation(Location location) {
Selection selection = new CuboidSelection(location.getWorld(), location, location);
return getASRegionsInSelection(selection);
}
/**
* Get all WorldGuard regions intersecting with a WorldEdit selection
* @param selection The selection to check
* @return A list with all the WorldGuard regions intersecting with the selection
*/
public static List<ProtectedRegion> getWERegionsInSelection(Selection selection) {
// Get all regions inside or intersecting with the WorldEdit selection of the player
World world = selection.getWorld();
RegionManager regionManager = AreaShop.getInstance().getWorldGuard().getRegionManager(world);
ArrayList<ProtectedRegion> result = new ArrayList<ProtectedRegion>();
Location selectionMin = selection.getMinimumPoint();
Location selectionMax = selection.getMaximumPoint();
for(ProtectedRegion region : regionManager.getRegions().values()) {
BlockVector regionMin = region.getMinimumPoint();
BlockVector regionMax = region.getMaximumPoint();
if(
( // x part, resolves to true if the selection and region overlap anywhere on the x-axis
(regionMin.getBlockX() <= selectionMax.getBlockX() && regionMin.getBlockX() >= selectionMin.getBlockX())
|| (regionMax.getBlockX() <= selectionMax.getBlockX() && regionMax.getBlockX() >= selectionMin.getBlockX())
|| (selectionMin.getBlockX() >= regionMin.getBlockX() && selectionMin.getBlockX() <= regionMax.getBlockX())
|| (selectionMax.getBlockX() >= regionMin.getBlockX() && selectionMax.getBlockX() <= regionMax.getBlockX())
) && ( // Y part, resolves to true if the selection and region overlap anywhere on the y-axis
(regionMin.getBlockY() <= selectionMax.getBlockY() && regionMin.getBlockY() >= selectionMin.getBlockY())
|| (regionMax.getBlockY() <= selectionMax.getBlockY() && regionMax.getBlockY() >= selectionMin.getBlockY())
|| (selectionMin.getBlockY() >= regionMin.getBlockY() && selectionMin.getBlockY() <= regionMax.getBlockY())
|| (selectionMax.getBlockY() >= regionMin.getBlockY() && selectionMax.getBlockY() <= regionMax.getBlockY())
) && ( // Z part, resolves to true if the selection and region overlap anywhere on the z-axis
(regionMin.getBlockZ() <= selectionMax.getBlockZ() && regionMin.getBlockZ() >= selectionMin.getBlockZ())
|| (regionMax.getBlockZ() <= selectionMax.getBlockZ() && regionMax.getBlockZ() >= selectionMin.getBlockZ())
|| (selectionMin.getBlockZ() >= regionMin.getBlockZ() && selectionMin.getBlockZ() <= regionMax.getBlockZ())
|| (selectionMax.getBlockZ() >= regionMin.getBlockZ() && selectionMax.getBlockZ() <= regionMax.getBlockZ())
)
) {
result.add(region);
}
}
return result;
}
/**
* Get a list of regions around a location
* - Returns highest priority, child instead of parent regions
* @param location The location to check for regions
* @return empty list if no regions found, 1 member if 1 region is a priority, more if regions with the same priority
*/
public static List<ProtectedRegion> getApplicableRegions(Location location) {
List<ProtectedRegion> result = new ArrayList<ProtectedRegion>();
Set<ProtectedRegion> regions = AreaShop.getInstance().getWorldGuardHandler().getApplicableRegionsSet(location);
if(regions != null) {
boolean first = true;
for(ProtectedRegion pr : regions) {
if(first) {
result.add(pr);
first = false;
} else {
if(pr.getPriority() > result.get(0).getPriority()) {
result.clear();
result.add(pr);
} else if(pr.getParent() != null && pr.getParent().equals(result.get(0))) {
result.clear();
result.add(pr);
} else {
result.add(pr);
}
}
}
}
return result;
}
// Methods to get the most important AreaShop regions at a certain location
public static List<RentRegion> getApplicableRentRegions(Location location) {
List<RentRegion> result = new ArrayList<RentRegion>();
for(GeneralRegion region : getApplicableASRegions(location, RegionType.RENT)) {
result.add((RentRegion)region);
}
return result;
}
public static List<BuyRegion> getApplicableBuyRegions(Location location) {
List<BuyRegion> result = new ArrayList<BuyRegion>();
for(GeneralRegion region : getApplicableASRegions(location, RegionType.BUY)) {
result.add((BuyRegion)region);
}
return result;
}
public static List<GeneralRegion> getAllApplicableRegions(Location location) {
return getApplicableASRegions(location, null);
}
public static List<GeneralRegion> getApplicableASRegions(Location location, RegionType type) {
List<GeneralRegion> result = new ArrayList<GeneralRegion>();
// TODO move to version specific classes
Set<ProtectedRegion> regions = AreaShop.getInstance().getWorldGuardHandler().getApplicableRegionsSet(location);
if(regions != null) {
List<GeneralRegion> candidates = new ArrayList<GeneralRegion>();
for(ProtectedRegion pr : regions) {
GeneralRegion region = AreaShop.getInstance().getFileManager().getRegion(pr.getId());
if(region != null && (
(type == RegionType.RENT && region.isRentRegion())
|| (type == RegionType.BUY && region.isBuyRegion())
|| type == null)) {
candidates.add(region);
}
}
boolean first = true;
for(GeneralRegion region : candidates) {
if(region == null) {
AreaShop.debug("skipped null region");
continue;
}
if(first) {
result.add(region);
first = false;
} else {
if(region.getRegion().getPriority() > result.get(0).getRegion().getPriority()) {
result.clear();
result.add(region);
} else if(region.getRegion().getParent() != null && region.getRegion().getParent().equals(result.get(0))) {
result.clear();
result.add(region);
} else {
result.add(region);
}
}
}
}
return new ArrayList<GeneralRegion>(result);
}
}
@@ -1,239 +0,0 @@
package nl.evolutioncoding.areashop.commands;
import java.util.ArrayList;
import java.util.List;
import nl.evolutioncoding.areashop.AreaShop;
import nl.evolutioncoding.areashop.Utils;
import nl.evolutioncoding.areashop.managers.FileManager.AddResult;
import nl.evolutioncoding.areashop.regions.BuyRegion;
import nl.evolutioncoding.areashop.regions.GeneralRegion.RegionEvent;
import nl.evolutioncoding.areashop.regions.GeneralRegion.RegionType;
import nl.evolutioncoding.areashop.regions.RentRegion;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitRunnable;
import com.sk89q.worldedit.bukkit.selections.Selection;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
public class AddCommand extends CommandAreaShop {
public AddCommand(AreaShop plugin) {
super(plugin);
}
@Override
public String getCommandStart() {
return "areashop add";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.createrent") || target.hasPermission("areashop.createbuy")) {
return plugin.getLanguageManager().getLang("help-add");
}
return null;
}
@Override
public void execute(final CommandSender sender, Command command, final String[] args) {
if( !sender.hasPermission("areashop.createrent")
&& !sender.hasPermission("areashop.createrent.member")
&& !sender.hasPermission("areashop.createrent.owner")
&& !sender.hasPermission("areashop.createbuy")
&& !sender.hasPermission("areashop.createbuy.member")
&& !sender.hasPermission("areashop.createbuy.owner")) {
plugin.message(sender, "add-noPermission");
return;
}
if(args.length < 2 || args[1] == null || (!"rent".equals(args[1].toLowerCase()) && !"buy".equals(args[1].toLowerCase()))) {
plugin.message(sender, "add-help");
return;
}
List<ProtectedRegion> regions = new ArrayList<ProtectedRegion>();
World world = null;
Player player = null;
if(sender instanceof Player) {
player = (Player)sender;
}
if(args.length == 2) {
if(player == null) {
plugin.message(sender, "cmd-weOnlyByPlayer");
return;
}
Selection selection = plugin.getWorldEdit().getSelection(player);
if(selection == null) {
plugin.message(player, "cmd-noSelection");
return;
}
world = selection.getWorld();
regions = Utils.getWERegionsInSelection(selection);
if(regions.size() == 0) {
plugin.message(player, "cmd-noWERegionsFound");
return;
}
} else {
if(player != null) {
if(args.length == 4) {
world = Bukkit.getWorld(args[3]);
if(world == null) {
plugin.message(sender, "add-incorrectWorld", args[3]);
return;
}
} else {
world = ((Player)sender).getWorld();
}
} else {
if(args.length < 4) {
plugin.message(sender, "add-specifyWorld");
return;
} else {
world = Bukkit.getWorld(args[3]);
if(world == null) {
plugin.message(sender, "add-incorrectWorld", args[3]);
return;
}
}
}
ProtectedRegion region = plugin.getWorldGuard().getRegionManager(world).getRegion(args[2]);
if(region == null) {
plugin.message(sender, "add-noRegion", args[2]);
return;
}
regions.add(region);
}
final boolean isRent = "rent".equals(args[1].toLowerCase());
final List<ProtectedRegion> finalRegions = regions;
final Player finalPlayer = player;
final World finalWorld = world;
AreaShop.debug("Starting add task with " + regions.size() + " regions");
new BukkitRunnable() {
private int current = 0;
private ArrayList<String> namesSuccess = new ArrayList<String>();
private ArrayList<String> namesAlready = new ArrayList<String>();
private ArrayList<String> namesBlacklisted = new ArrayList<String>();
private ArrayList<String> namesNoPermission = new ArrayList<String>();
@Override
public void run() {
for(int i=0; i<plugin.getConfig().getInt("adding.regionsPerTick"); i++) {
if(current < finalRegions.size()) {
ProtectedRegion region = finalRegions.get(current);
// Determine if the player is an owner or member of the region
boolean isMember = finalPlayer != null && plugin.getWorldGuardHandler().containsMember(region, finalPlayer.getUniqueId());
boolean isOwner = finalPlayer != null && plugin.getWorldGuardHandler().containsMember(region, finalPlayer.getUniqueId());
String type = null;
if(isRent) {
type = "rent";
} else {
type = "buy";
}
AddResult result = plugin.getFileManager().checkRegionAdd(sender, region, isRent ? RegionType.RENT : RegionType.BUY);
if(result == AddResult.ALREADYADDED) {
namesAlready.add(region.getId());
} else if(result == AddResult.BLACKLISTED) {
namesBlacklisted.add(region.getId());
} else if(result == AddResult.NOPERMISSION) {
namesNoPermission.add(region.getId());
} else {
namesSuccess.add(region.getId());
// Check if the player should be landlord
boolean landlord = (!sender.hasPermission("areashop.create" + type)
&& ((sender.hasPermission("areashop.create" + type + ".owner") && isOwner)
|| (sender.hasPermission("areashop.create" + type + ".member") && isMember)));
if(isRent) {
RentRegion rent = new RentRegion(plugin, region.getId(), finalWorld);
// Set landlord
if(landlord) {
rent.setLandlord(finalPlayer.getUniqueId(), finalPlayer.getName());
}
// Run commands
rent.runEventCommands(RegionEvent.CREATED, true);
plugin.getFileManager().addRent(rent);
rent.handleSchematicEvent(RegionEvent.CREATED);
// Set the flags for the region
rent.updateRegionFlags();
// Run commands
rent.runEventCommands(RegionEvent.CREATED, false);
} else {
BuyRegion buy = new BuyRegion(plugin, region.getId(), finalWorld);
// Set landlord
if(landlord) {
buy.setLandlord(finalPlayer.getUniqueId(), finalPlayer.getName());
}
// Run commands
buy.runEventCommands(RegionEvent.CREATED, true);
plugin.getFileManager().addBuy(buy);
buy.handleSchematicEvent(RegionEvent.CREATED);
// Set the flags for the region
buy.updateRegionFlags();
// Run commands
buy.runEventCommands(RegionEvent.CREATED, false);
}
}
current++;
}
}
if(current >= finalRegions.size()) {
if(!namesSuccess.isEmpty()) {
plugin.message(sender, "add-success", args[1], Utils.createCommaSeparatedList(namesSuccess));
}
if(!namesAlready.isEmpty()) {
plugin.message(sender, "add-failed", Utils.createCommaSeparatedList(namesAlready));
}
if(!namesBlacklisted.isEmpty()) {
plugin.message(sender, "add-blacklisted", Utils.createCommaSeparatedList(namesBlacklisted));
}
if(!namesNoPermission.isEmpty()) {
plugin.message(sender, "add-noPermissionRegions", Utils.createCommaSeparatedList(namesNoPermission));
plugin.message(sender, "add-noPermissionOwnerMember");
}
this.cancel();
}
}
}.runTaskTimer(plugin, 1, 1);
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
List<String> result = new ArrayList<String>();
if(toComplete == 2) {
if(sender.hasPermission("areashop.createrent")) {
result.add("rent");
}
if(sender.hasPermission("areashop.createbuy")) {
result.add("buy");
}
} else if(toComplete == 3) {
if(sender instanceof Player) {
Player player = (Player)sender;
if(sender.hasPermission("areashop.createrent") || sender.hasPermission("areashop.createbuy")) {
for(ProtectedRegion region : plugin.getWorldGuard().getRegionManager(player.getWorld()).getRegions().values()) {
result.add(region.getId());
}
}
}
}
return result;
}
}
@@ -1,149 +0,0 @@
package nl.evolutioncoding.areashop.commands;
import java.util.ArrayList;
import java.util.List;
import nl.evolutioncoding.areashop.AreaShop;
import nl.evolutioncoding.areashop.Utils;
import nl.evolutioncoding.areashop.regions.BuyRegion;
import nl.evolutioncoding.areashop.regions.GeneralRegion;
import nl.evolutioncoding.areashop.regions.RentRegion;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
public class AddfriendCommand extends CommandAreaShop {
public AddfriendCommand(AreaShop plugin) {
super(plugin);
}
@Override
public String getCommandStart() {
return "areashop addfriend";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.addfriendall")) {
return plugin.getLanguageManager().getLang("help-addFriendAll");
} else if(target.hasPermission("areashop.addfriend")) {
return plugin.getLanguageManager().getLang("help-addFriend");
}
return null;
}
@SuppressWarnings("deprecation")
@Override
public void execute(CommandSender sender, Command command, String[] args) {
if(!sender.hasPermission("areashop.addfriend") && !sender.hasPermission("areashop.addfriendall")) {
plugin.message(sender, "addfriend-noPermission");
return;
}
if(args.length < 2) {
plugin.message(sender, "addfriend-help");
return;
}
GeneralRegion region = null;
if(args.length <= 2) {
if (sender instanceof Player) {
// get the region by location
List<GeneralRegion> regions = Utils.getAllApplicableRegions(((Player) sender).getLocation());
if (regions.isEmpty()) {
plugin.message(sender, "cmd-noRegionsAtLocation");
return;
} else if (regions.size() > 1) {
plugin.message(sender, "cmd-moreRegionsAtLocation");
return;
} else {
region = regions.get(0);
}
} else {
plugin.message(sender, "cmd-automaticRegionOnlyByPlayer");
return;
}
} else {
region = plugin.getFileManager().getRegion(args[2]);
if(region == null) {
plugin.message(sender, "cmd-notRegistered", args[2]);
return;
}
}
if(sender.hasPermission("areashop.addfriendall")) {
if((region.isRentRegion() && !((RentRegion)region).isRented())
|| (region.isBuyRegion() && !((BuyRegion)region).isSold())) {
plugin.message(sender, "addfriend-noOwner");
return;
}
OfflinePlayer friend = Bukkit.getOfflinePlayer(args[1]);
if(friend.getLastPlayed() == 0 && !plugin.getConfig().getBoolean("addFriendNotExistingPlayers")) {
plugin.message(sender, "addfriend-notVisited", args[1]);
return;
}
if(region.getFriends().contains(friend.getUniqueId())) {
plugin.message(sender, "addfriend-alreadyAdded", friend.getName());
return;
}
if(region.isOwner(friend.getUniqueId())) {
plugin.message(sender, "addfriend-self", friend.getName());
return;
}
region.addFriend(friend.getUniqueId());
region.updateRegionFlags();
region.updateSigns();
plugin.message(sender, "addfriend-successOther", friend.getName(), region.getName());
} else {
if(sender.hasPermission("areashop.addfriend") && sender instanceof Player) {
if(region.isOwner((Player)sender)) {
OfflinePlayer friend = Bukkit.getOfflinePlayer(args[1]);
if(friend.getLastPlayed() == 0 && !plugin.getConfig().getBoolean("addFriendNotExistingPlayers")) {
plugin.message(sender, "addfriend-notVisited", args[1]);
return;
}
if(region.getFriends().contains(friend.getUniqueId())) {
plugin.message(sender, "addfriend-alreadyAdded", friend.getName());
return;
}
if(region.isOwner(friend.getUniqueId())) {
plugin.message(sender, "addfriend-self", friend.getName());
return;
}
region.addFriend(friend.getUniqueId());
region.updateRegionFlags();
region.updateSigns();
plugin.message(sender, "addfriend-success", friend.getName(), region.getName());
} else {
plugin.message(sender, "addfriend-noPermissionOther");
}
} else {
plugin.message(sender, "addfriend-noPermission");
}
}
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
ArrayList<String> result = new ArrayList<String>();
if(toComplete == 2) {
for(Player player : Bukkit.getOnlinePlayers()) {
result.add(player.getName());
}
} else if(toComplete == 3) {
result.addAll(plugin.getFileManager().getRegionNames());
}
return result;
}
}
@@ -1,66 +0,0 @@
package nl.evolutioncoding.areashop.commands;
import java.util.List;
import nl.evolutioncoding.areashop.AreaShop;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
/**
* Abstract class for generalising command classes
*/
public abstract class CommandAreaShop {
AreaShop plugin;
/**
* Save the instance of the main plugin class
* @param plugin The main plugin
*/
public CommandAreaShop(AreaShop plugin) {
this.plugin = plugin;
}
public boolean canExecute(Command command, String[] args) {
String commandString = command.getName();
for(String argument : args) {
commandString += " " + argument;
}
if(commandString.length() > getCommandStart().length()) {
return commandString.toLowerCase().startsWith(getCommandStart().toLowerCase() + " ");
}
return commandString.toLowerCase().startsWith(getCommandStart().toLowerCase());
}
/**
* Get a list of string to complete a command with (raw list, not matching ones not filtered out)
* @param toComplete The number of the argument that has to be completed
* @param start The already given start of the command
* @return A collection with all the possibilities for argument to complete
*/
public abstract List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender);
/**
* Get the argument that comes after the base command that this command reacts to
* @return
*/
public abstract String getCommandStart();
/**
* Returns the correct help string for the reciever
* @param target The CommandSender that the help message is for
* @return The help message according to the permissions of the reciever
*/
public abstract String getHelp(CommandSender target);
/**
* Execute a (sub)command if the conditions are met
* @param sender The commandSender that executed the command
* @param commandAreaShop The command that has been executed
* @param args The arguments that are given
*/
public abstract void execute(CommandSender sender, Command command, String[] args);
}
@@ -1,131 +0,0 @@
package nl.evolutioncoding.areashop.commands;
import java.util.ArrayList;
import java.util.List;
import nl.evolutioncoding.areashop.AreaShop;
import nl.evolutioncoding.areashop.Utils;
import nl.evolutioncoding.areashop.regions.BuyRegion;
import nl.evolutioncoding.areashop.regions.GeneralRegion;
import nl.evolutioncoding.areashop.regions.RentRegion;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
public class DelfriendCommand extends CommandAreaShop {
public DelfriendCommand(AreaShop plugin) {
super(plugin);
}
@Override
public String getCommandStart() {
return "areashop delfriend";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.delfriendall")) {
return plugin.getLanguageManager().getLang("help-delFriendAll");
} else if(target.hasPermission("areashop.delfriend")) {
return plugin.getLanguageManager().getLang("help-delFriend");
}
return null;
}
@SuppressWarnings("deprecation")
@Override
public void execute(CommandSender sender, Command command, String[] args) {
if(!sender.hasPermission("areashop.delfriend") && !sender.hasPermission("areashop.delfriendall")) {
plugin.message(sender, "delfriend-noPermission");
return;
}
if(args.length < 2) {
plugin.message(sender, "delfriend-help");
return;
}
GeneralRegion region = null;
if(args.length <= 2) {
if (sender instanceof Player) {
// get the region by location
List<GeneralRegion> regions = Utils.getAllApplicableRegions(((Player) sender).getLocation());
if (regions.isEmpty()) {
plugin.message(sender, "cmd-noRegionsAtLocation");
return;
} else if (regions.size() > 1) {
plugin.message(sender, "cmd-moreRegionsAtLocation");
return;
} else {
region = regions.get(0);
}
} else {
plugin.message(sender, "cmd-automaticRegionOnlyByPlayer");
return;
}
} else {
region = plugin.getFileManager().getRegion(args[2]);
if(region == null) {
plugin.message(sender, "cmd-notRegistered", args[2]);
return;
}
}
if(sender.hasPermission("areashop.delfriendall")) {
if((region.isRentRegion() && !((RentRegion)region).isRented())
|| (region.isBuyRegion() && !((BuyRegion)region).isSold())) {
plugin.message(sender, "delfriend-noOwner");
return;
}
OfflinePlayer friend = Bukkit.getOfflinePlayer(args[1]);
if(!region.getFriends().contains(friend.getUniqueId())) {
plugin.message(sender, "delfriend-notAdded", friend.getName());
return;
}
region.deleteFriend(friend.getUniqueId());
region.updateRegionFlags();
region.updateSigns();
plugin.message(sender, "delfriend-successOther", friend.getName(), region.getName());
} else {
if(sender.hasPermission("areashop.delfriend") && sender instanceof Player) {
if(region.isOwner((Player)sender)) {
OfflinePlayer friend = Bukkit.getOfflinePlayer(args[1]);
if(!region.getFriends().contains(friend.getUniqueId())) {
plugin.message(sender, "delfriend-notAdded", friend.getName());
return;
}
region.deleteFriend(friend.getUniqueId());
region.updateRegionFlags();
region.updateSigns();
plugin.message(sender, "delfriend-success", friend.getName(), region.getName());
} else {
plugin.message(sender, "delfriend-noPermissionOther");
}
} else {
plugin.message(sender, "delfriend-noPermission");
}
}
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
ArrayList<String> result = new ArrayList<String>();
if(toComplete == 2) {
for(Player player : Bukkit.getOnlinePlayers()) {
result.add(player.getName());
}
} else if(toComplete == 3) {
result.addAll(plugin.getFileManager().getRegionNames());
}
return result;
}
}
@@ -1,200 +0,0 @@
package nl.evolutioncoding.areashop.commands;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import nl.evolutioncoding.areashop.AreaShop;
import nl.evolutioncoding.areashop.regions.BuyRegion;
import nl.evolutioncoding.areashop.regions.RegionGroup;
import nl.evolutioncoding.areashop.regions.RentRegion;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
public class FindCommand extends CommandAreaShop {
public FindCommand(AreaShop plugin) {
super(plugin);
}
@Override
public String getCommandStart() {
return "areashop find";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.find")) {
return plugin.getLanguageManager().getLang("help-find");
}
return null;
}
@Override
public void execute(CommandSender sender, Command command, String[] args) {
if(!sender.hasPermission("areashop.find")) {
plugin.message(sender, "find-noPermission");
return;
}
if (!(sender instanceof Player)) {
plugin.message(sender, "cmd-onlyByPlayer");
return;
}
if(args.length <= 1 || args[1] == null || (!args[1].equalsIgnoreCase("buy") && !args[1].equalsIgnoreCase("rent"))) {
plugin.message(sender, "find-help");
return;
}
Player player = (Player)sender;
double balance = 0.0;
if(plugin.getEconomy() != null) {
plugin.getEconomy().getBalance(player);
}
double maxPrice = 0;
boolean maxPriceSet = false;
RegionGroup group = null;
// Parse optional price argument
if(args.length >= 3) {
try {
maxPrice = Double.parseDouble(args[2]);
maxPriceSet = true;
} catch(NumberFormatException e) {
plugin.message(sender, "find-wrongMaxPrice", args[2]);
return;
}
}
// Parse optional group argument
if(args.length >= 4) {
group = plugin.getFileManager().getGroup(args[3]);
if(group == null) {
plugin.message(sender, "find-wrongGroup", args[3]);
return;
}
}
if(args[1].equalsIgnoreCase("buy")) {
List<BuyRegion> regions = plugin.getFileManager().getBuys();
List<BuyRegion> results = new ArrayList<BuyRegion>();
for(BuyRegion region : regions) {
if(!region.isSold()
&& ((region.getPrice() <= balance && !maxPriceSet) || (region.getPrice() <= maxPrice && maxPriceSet))
&& (group == null || group.isMember(region))) {
results.add(region);
}
}
if(!results.isEmpty()) {
// Draw a random one
BuyRegion region = results.get(new Random().nextInt(results.size()));
BigDecimal bigDecimal = new BigDecimal(balance);
bigDecimal = bigDecimal.setScale(2, RoundingMode.HALF_UP);
balance = bigDecimal.doubleValue();
String onlyInGroup = "";
if(group != null) {
onlyInGroup = plugin.getLanguageManager().getLang("find-onlyInGroup", args[3]);
}
if(maxPriceSet) {
plugin.message(player, "find-successMax", "buy", region.getName(), maxPrice, onlyInGroup);
} else {
plugin.message(player, "find-success", "buy", region.getName(), balance, onlyInGroup);
}
region.teleportPlayer(player, region.getBooleanSetting("general.findTeleportToSign"), false);
} else {
BigDecimal bigDecimal = new BigDecimal(balance);
bigDecimal = bigDecimal.setScale(2, RoundingMode.HALF_UP);
balance = bigDecimal.doubleValue();
String onlyInGroup = "";
if(group != null) {
onlyInGroup = plugin.getLanguageManager().getLang("find-onlyInGroup", args[3]);
}
if(maxPriceSet) {
plugin.message(player, "find-noneFound", "buy", maxPrice, onlyInGroup);
} else {
plugin.message(player, "find-noneFoundMax", "buy", balance, onlyInGroup);
}
}
} else {
List<RentRegion> regions = plugin.getFileManager().getRents();
List<RentRegion> results = new ArrayList<RentRegion>();
for(RentRegion region : regions) {
if(!region.isRented()
&& ((region.getPrice() <= balance && !maxPriceSet) || (region.getPrice() <= maxPrice && maxPriceSet))
&& (group == null || group.isMember(region))) {
results.add(region);
}
}
if(!results.isEmpty()) {
// Draw a random one
RentRegion region = results.get(new Random().nextInt(results.size()));
BigDecimal bigDecimal = new BigDecimal(balance);
bigDecimal = bigDecimal.setScale(2, RoundingMode.HALF_UP);
balance = bigDecimal.doubleValue();
String onlyInGroup = "";
if(group != null) {
onlyInGroup = plugin.getLanguageManager().getLang("find-onlyInGroup", args[3]);
}
if(maxPriceSet) {
plugin.message(player, "find-successMax", "rent", region.getName(), maxPrice, onlyInGroup);
} else {
plugin.message(player, "find-success", "rent", region.getName(), balance, onlyInGroup);
}
region.teleportPlayer(player, region.getBooleanSetting("general.findTeleportToSign"), false);
} else {
BigDecimal bigDecimal = new BigDecimal(balance);
bigDecimal = bigDecimal.setScale(2, RoundingMode.HALF_UP);
balance = bigDecimal.doubleValue();
String onlyInGroup = "";
if(group != null) {
onlyInGroup = plugin.getLanguageManager().getLang("find-onlyInGroup", args[3]);
}
if(maxPriceSet) {
plugin.message(player, "find-noneFound", "rent", maxPrice, onlyInGroup);
} else {
plugin.message(player, "find-noneFoundMax", "rent", balance, onlyInGroup);
}
}
}
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
ArrayList<String> result = new ArrayList<String>();
if(toComplete == 2) {
result.add("buy");
result.add("rent");
}
return result;
}
}
@@ -1,124 +0,0 @@
package nl.evolutioncoding.areashop.commands;
import java.util.ArrayList;
import java.util.List;
import nl.evolutioncoding.areashop.AreaShop;
import nl.evolutioncoding.areashop.Utils;
import nl.evolutioncoding.areashop.regions.GeneralRegion;
import nl.evolutioncoding.areashop.regions.RegionGroup;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import com.sk89q.worldedit.bukkit.selections.Selection;
public class GroupdelCommand extends CommandAreaShop {
public GroupdelCommand(AreaShop plugin) {
super(plugin);
}
@Override
public String getCommandStart() {
return "areashop groupdel";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.groupdel")) {
return plugin.getLanguageManager().getLang("help-groupdel");
}
return null;
}
@Override
public void execute(CommandSender sender, Command command, String[] args) {
if(!sender.hasPermission("areashop.groupdel")) {
plugin.message(sender, "groupdel-noPermission");
return;
}
if(args.length < 2 || args[1] == null) {
plugin.message(sender, "groupdel-help");
return;
}
RegionGroup group = plugin.getFileManager().getGroup(args[1]);
if(group == null) {
group = new RegionGroup(plugin, args[1]);
plugin.getFileManager().addGroup(group);
}
if(args.length == 2) {
if(!(sender instanceof Player)) {
plugin.message(sender, "cmd-weOnlyByPlayer");
return;
}
Player player = (Player)sender;
Selection selection = plugin.getWorldEdit().getSelection(player);
if(selection == null) {
plugin.message(player, "cmd-noSelection");
return;
}
List<GeneralRegion> regions = Utils.getASRegionsInSelection(selection);
if(regions.size() == 0) {
plugin.message(player, "cmd-noRegionsFound");
return;
}
ArrayList<String> namesSuccess = new ArrayList<String>();
ArrayList<String> namesFailed = new ArrayList<String>();
ArrayList<GeneralRegion> toUpdate = new ArrayList<GeneralRegion>();
for(GeneralRegion region : regions) {
if(group.removeMember(region)) {
namesSuccess.add(region.getName());
toUpdate.add(region);
} else {
namesFailed.add(region.getName());
}
}
if(namesSuccess.size() != 0) {
plugin.message(player, "groupdel-weSuccess", group.getName(), Utils.createCommaSeparatedList(namesSuccess));
}
if(namesFailed.size() != 0) {
plugin.message(player, "groupdel-weFailed", group.getName(), Utils.createCommaSeparatedList(namesFailed));
}
// Update all regions, this does it in a task, updating them without lag
plugin.getFileManager().updateRegions(toUpdate, player);
group.saveRequired();
} else {
GeneralRegion region = plugin.getFileManager().getRegion(args[2]);
if(region == null) {
plugin.message(sender, "groupdel-noRegion", args[2]);
return;
}
if(group.removeMember(region)) {
region.updateRegionFlags();
region.updateSigns();
plugin.message(sender, "groupdel-success", region.getName(), group.getName(), group.getMembers().size());
} else {
plugin.message(sender, "groupdel-failed", region.getName(), group.getName());
}
}
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
List<String> result = new ArrayList<String>();
if(toComplete == 2) {
result = plugin.getFileManager().getGroupNames();
} else if(toComplete == 3) {
result = plugin.getFileManager().getRegionNames();
}
return result;
}
}
@@ -1,41 +0,0 @@
package nl.evolutioncoding.areashop.commands;
import java.util.ArrayList;
import java.util.List;
import nl.evolutioncoding.areashop.AreaShop;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
public class HelpCommand extends CommandAreaShop {
public HelpCommand(AreaShop plugin) {
super(plugin);
}
@Override
public String getCommandStart() {
return "areashop help";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.help")) {
return plugin.getLanguageManager().getLang("help-help");
}
return null;
}
@Override
public void execute(CommandSender sender, Command command, String[] args) {
plugin.getCommandManager().showHelp(sender);
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
ArrayList<String> result = new ArrayList<String>();
return result;
}
}
@@ -1,488 +0,0 @@
package nl.evolutioncoding.areashop.commands;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import nl.evolutioncoding.areashop.AreaShop;
import nl.evolutioncoding.areashop.Utils;
import nl.evolutioncoding.areashop.regions.BuyRegion;
import nl.evolutioncoding.areashop.regions.GeneralRegion;
import nl.evolutioncoding.areashop.regions.RegionGroup;
import nl.evolutioncoding.areashop.regions.RentRegion;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
public class InfoCommand extends CommandAreaShop {
public InfoCommand(AreaShop plugin) {
super(plugin);
}
@Override
public String getCommandStart() {
return "areashop info";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.info")) {
return plugin.getLanguageManager().getLang("help-info");
}
return null;
}
@Override
public void execute(CommandSender sender, Command command, String[] args) {
if(!sender.hasPermission("areashop.info")) {
plugin.message(sender, "info-noPermission");
return;
}
if(args.length > 1 && args[1] != null) {
/* List of all regions */
if(args[1].equalsIgnoreCase("all")) {
String message = "";
/* Message for rents */
Iterator<RentRegion> itRent = plugin.getFileManager().getRents().iterator();
if(itRent.hasNext()) {
message = itRent.next().getName();
while(itRent.hasNext()) {
message += ", " + itRent.next().getName();
}
}
if(message.equals("")) {
plugin.message(sender, "info-all-noRents");
} else {
plugin.message(sender, "info-all-rents", message);
}
/* Message for buys */
message = "";
Iterator<BuyRegion> itBuy = plugin.getFileManager().getBuys().iterator();
if(itBuy.hasNext()) {
message = itBuy.next().getName();
while(itBuy.hasNext()) {
message += ", " + itBuy.next().getName();
}
}
if(message.equals("")) {
plugin.message(sender, "info-all-noBuys");
} else {
plugin.message(sender, "info-all-buys", message);
}
}
/* List of rented regions */
else if(args[1].equalsIgnoreCase("rented")) {
String message = "";
Iterator<RentRegion> it = plugin.getFileManager().getRents().iterator();
boolean first = true;
while(it.hasNext()) {
RentRegion next = it.next();
if(next.isRented()) {
if(!first) {
message += ", " + next.getName();
} else {
first = false;
message += next.getName();
}
}
}
if(message.equals("")) {
plugin.message(sender, "info-noRented");
} else {
plugin.message(sender, "info-rented", message);
}
}
/* List of unrented regions */
else if(args[1].equalsIgnoreCase("forrent")) {
String message = "";
Iterator<RentRegion> it = plugin.getFileManager().getRents().iterator();
boolean first = true;
while(it.hasNext()) {
RentRegion next = it.next();
if(!next.isRented()) {
if(!first) {
message += ", " + next.getName();
} else {
first = false;
message = next.getName();
}
}
}
if(message.equals("")) {
plugin.message(sender, "info-noUnrented");
} else {
plugin.message(sender, "info-unrented", message);
}
} else if(args[1].equalsIgnoreCase("sold")) {
String message = "";
Iterator<BuyRegion> it = plugin.getFileManager().getBuys().iterator();
boolean first = true;
while(it.hasNext()) {
BuyRegion next = it.next();
if(next.isSold()) {
if(!first) {
message += ", ";
} else {
first = false;
}
message += next.getName();
}
}
if(message.equals("")) {
plugin.message(sender, "info-noSold");
} else {
plugin.message(sender, "info-sold", message);
}
} else if(args[1].equalsIgnoreCase("forsale")) {
String message = "";
Iterator<BuyRegion> it = plugin.getFileManager().getBuys().iterator();
boolean first = true;
while(it.hasNext()) {
BuyRegion next =it.next();
if(!next.isSold()) {
if(!first) {
message += ", " + next.getName();
} else {
first = false;
message = next.getName();
}
}
}
if(message.equals("")) {
plugin.message(sender, "info-noForsale");
} else {
plugin.message(sender, "info-forsale", message);
}
} else if(args[1].equalsIgnoreCase("player")) {
if(args.length > 2 && args[2] != null) {
String message = "";
Iterator<RentRegion> itRent = plugin.getFileManager().getRents().iterator();
boolean first = true;
while(itRent.hasNext()) {
RentRegion next = itRent.next();
if(next.isRented() && next.getPlayerName().equalsIgnoreCase(args[2])) {
if(!first) {
message += ", " + next.getName();
} else {
first = false;
message = next.getName();
}
}
}
if(message.equals("")) {
plugin.message(sender, "info-playerNoRents", args[2]);
} else {
plugin.message(sender, "info-playerRents", args[2], message);
}
message = "";
Iterator<BuyRegion> itBuy = plugin.getFileManager().getBuys().iterator();
first = true;
while(itBuy.hasNext()) {
BuyRegion next = itBuy.next();
if(next.isSold() && next.getPlayerName().equalsIgnoreCase(args[2])) {
if(!first) {
message += ", ";
} else {
first = false;
}
message += next.getName();
}
}
if(message.equals("")) {
plugin.message(sender, "info-playerNoBuys", args[2]);
} else {
plugin.message(sender, "info-playerBuys", args[2], message);
}
} else {
plugin.message(sender, "info-playerHelp");
}
} else if(args[1].equalsIgnoreCase("region")) {
if(args.length > 1) {
RentRegion rent = null;
BuyRegion buy = null;
if(args.length > 2) {
rent = plugin.getFileManager().getRent(args[2]);
buy = plugin.getFileManager().getBuy(args[2]);
} else {
if (sender instanceof Player) {
// get the region by location
List<GeneralRegion> regions = Utils.getAllApplicableRegions(((Player) sender).getLocation());
if (regions.isEmpty()) {
plugin.message(sender, "cmd-noRegionsAtLocation");
return;
} else if (regions.size() > 1) {
plugin.message(sender, "cmd-moreRegionsAtLocation");
return;
} else {
if(regions.get(0).isRentRegion()) {
rent = (RentRegion)regions.get(0);
} else if(regions.get(0).isBuyRegion()) {
buy = (BuyRegion)regions.get(0);
}
}
} else {
plugin.message(sender, "cmd-automaticRegionOnlyByPlayer");
return;
}
}
if(rent == null && buy == null) {
plugin.message(sender, "info-regionNotExisting", args[2]);
return;
}
if(rent != null) {
plugin.message(sender, "info-regionHeaderRent", rent);
if(rent.isRented()) {
plugin.messageNoPrefix(sender, "info-regionRented", rent);
plugin.messageNoPrefix(sender, "info-regionExtending", rent);
plugin.messageNoPrefix(sender, "info-regionMoneyBackRent", rent);
if(!rent.getFriendNames().isEmpty()) {
plugin.messageNoPrefix(sender, "info-regionFriends", rent);
}
} else {
plugin.messageNoPrefix(sender, "info-regionCanBeRented", rent);
}
if(rent.getLandlordName() != null) {
plugin.messageNoPrefix(sender, "info-regionLandlord", rent);
}
if(rent.getMaxExtends() != -1) {
if(rent.getMaxExtends() == 0) {
plugin.messageNoPrefix(sender, "info-regionNoExtending", rent);
} else if(rent.isRented()) {
plugin.messageNoPrefix(sender, "info-regionExtendsLeft", rent);
} else {
plugin.messageNoPrefix(sender, "info-regionMaxExtends", rent);
}
}
if(rent.getMaxRentTime() != -1) {
plugin.messageNoPrefix(sender, "info-regionMaxRentTime", rent);
}
if(rent.getInactiveTimeUntilUnrent() != -1) {
plugin.messageNoPrefix(sender, "info-regionInactiveUnrent", rent);
}
if(sender.hasPermission("areashop.teleport") || sender.hasPermission("areashop.teleportall")) {
Location teleport = rent.getTeleportLocation();
if(teleport == null) {
if(rent.isRented()) {
plugin.messageNoPrefix(sender, "info-regionNoTeleport", rent, plugin.getLanguageManager().getLang("info-regionTeleportHint", rent));
} else {
plugin.messageNoPrefix(sender, "info-regionNoTeleport", rent, "");
}
} else {
plugin.messageNoPrefix(sender, "info-regionTeleportAt", rent, teleport.getWorld().getName(), teleport.getBlockX(), teleport.getBlockY(), teleport.getBlockZ(), (int)teleport.getPitch(), (int)teleport.getYaw());
}
}
List<String> signLocations = new ArrayList<String>();
for(Location location : rent.getSignLocations()) {
signLocations.add(plugin.getLanguageManager().getLang("info-regionSignLocation", location.getWorld().getName(), location.getBlockX(), location.getBlockY(), location.getBlockZ()));
}
if(!signLocations.isEmpty()) {
plugin.messageNoPrefix(sender, "info-regionSigns", Utils.createCommaSeparatedList(signLocations));
}
if(sender.hasPermission("areashop.groupinfo") && !rent.getGroupNames().isEmpty()) {
plugin.messageNoPrefix(sender, "info-regionGroups", Utils.createCommaSeparatedList(rent.getGroupNames()));
}
if(rent.isRestoreEnabled()) {
if(sender.hasPermission("areashop.setrestore")) {
plugin.messageNoPrefix(sender, "info-regionRestoringRent", rent, plugin.getLanguageManager().getLang("info-regionRestoringProfile", rent.getRestoreProfile()));
} else {
plugin.messageNoPrefix(sender, "info-regionRestoringRent", rent, "");
}
}
if(!rent.isRented()) {
if(rent.restrictedToRegion()) {
plugin.messageNoPrefix(sender, "info-regionRestrictedRegionRent", rent);
} else if(rent.restrictedToWorld()) {
plugin.messageNoPrefix(sender, "info-regionRestrictedWorldRent", rent);
}
}
plugin.messageNoPrefix(sender, "info-regionFooterRent", rent);
} else if(buy != null) {
plugin.message(sender, "info-regionHeaderBuy", buy);
if(buy.isSold()) {
if(buy.isInResellingMode()) {
plugin.messageNoPrefix(sender, "info-regionReselling", buy);
plugin.messageNoPrefix(sender, "info-regionReselPrice", buy);
} else {
plugin.messageNoPrefix(sender, "info-regionBought", buy);
}
plugin.messageNoPrefix(sender, "info-regionMoneyBackBuy", buy);
if(!buy.getFriendNames().isEmpty()) {
plugin.messageNoPrefix(sender, "info-regionFriends", buy);
}
} else {
plugin.messageNoPrefix(sender, "info-regionCanBeBought", buy);
}
if(buy.getLandlord() != null) {
plugin.messageNoPrefix(sender, "info-regionLandlord", buy);
}
if(buy.getInactiveTimeUntilSell() != -1) {
plugin.messageNoPrefix(sender, "info-regionInactiveSell", buy);
}
if(sender.hasPermission("areashop.teleport") || sender.hasPermission("areashop.teleportall")) {
Location teleport = buy.getTeleportLocation();
if(teleport == null) {
if(buy.isSold()) {
plugin.messageNoPrefix(sender, "info-regionNoTeleport", buy, plugin.getLanguageManager().getLang("info-regionTeleportHint", buy));
} else {
plugin.messageNoPrefix(sender, "info-regionNoTeleport", buy, "");
}
} else {
plugin.messageNoPrefix(sender, "info-regionTeleportAt", buy, teleport.getWorld().getName(), teleport.getBlockX(), teleport.getBlockY(), teleport.getBlockZ(), (int)teleport.getPitch(), (int)teleport.getYaw());
}
}
List<String> signLocations = new ArrayList<String>();
for(Location location : buy.getSignLocations()) {
signLocations.add(plugin.getLanguageManager().getLang("info-regionSignLocation", location.getWorld().getName(), location.getBlockX(), location.getBlockY(), location.getBlockZ()));
}
if(!signLocations.isEmpty()) {
plugin.messageNoPrefix(sender, "info-regionSigns", Utils.createCommaSeparatedList(signLocations));
}
if(sender.hasPermission("areashop.groupinfo") && !buy.getGroupNames().isEmpty()) {
plugin.messageNoPrefix(sender, "info-regionGroups", Utils.createCommaSeparatedList(buy.getGroupNames()));
}
if(buy.isRestoreEnabled()) {
if(sender.hasPermission("areashop.setrestore")) {
plugin.messageNoPrefix(sender, "info-regionRestoringBuy", buy, plugin.getLanguageManager().getLang("info-regionRestoringProfile", buy.getRestoreProfile()));
} else {
plugin.messageNoPrefix(sender, "info-regionRestoringBuy", buy, "");
}
}
if(!buy.isSold()) {
if(buy.restrictedToRegion()) {
plugin.messageNoPrefix(sender, "info-regionRestrictedRegionBuy", buy);
} else if(buy.restrictedToWorld()) {
plugin.messageNoPrefix(sender, "info-regionRestrictedWorldBuy", buy);
}
}
plugin.messageNoPrefix(sender, "info-regionFooterBuy", buy);
}
} else {
plugin.message(sender, "info-regionHelp");
}
}
/* List of regions without a group */
else if(args[1].equalsIgnoreCase("nogroup")) {
String message = "";
/* Message for rents */
List<String> rents = plugin.getFileManager().getRentNames();
// Remove regions that have a group
for(RegionGroup group : plugin.getFileManager().getGroups()) {
rents.removeAll(group.getMembers());
}
// Create the list message
Iterator<String> itRent = rents.iterator();
if(itRent.hasNext()) {
message = itRent.next();
while(itRent.hasNext()) {
message += ", " + itRent.next();
}
}
if(message.equals("")) {
plugin.message(sender, "info-nogroupNoRents");
} else {
plugin.message(sender, "info-nogroupRents", message);
}
/* Message for buys */
message = "";
// Remove regions that have a group
List<String> buys = plugin.getFileManager().getBuyNames();
for(RegionGroup group : plugin.getFileManager().getGroups()) {
buys.removeAll(group.getMembers());
}
// Create the list message
Iterator<String> itBuy = buys.iterator();
if(itBuy.hasNext()) {
message = itBuy.next();
while(itBuy.hasNext()) {
message += ", " + itBuy.next();
}
}
if(message.equals("")) {
plugin.message(sender, "info-nogroupNoBuys");
} else {
plugin.message(sender, "info-nogroupBuys", message);
}
} else {
plugin.message(sender, "info-help");
}
} else {
plugin.message(sender, "info-help");
}
}
/**
* Create a comma-space separated list from a collection of strings
* @param list The collection with strings
* @return A comma-space separated list of the strings in the collection
*/
public String createCommaString(Collection<String> list) {
String result = "";
boolean first = true;
for(String part : list) {
if(first) {
result += part;
first = false;
} else {
result += ", " + part;
}
}
return result;
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
List<String> result = new ArrayList<String>();
if(toComplete == 2) {
result.addAll(Arrays.asList("all", "rented", "forrent", "sold", "forsale", "player", "region", "nogroup"));
} else if(toComplete == 3) {
if(start[2].equalsIgnoreCase("player")) {
for(Player player : Bukkit.getOnlinePlayers()) {
result.add(player.getName());
}
} else if(start[2].equalsIgnoreCase("region")) {
result.addAll(plugin.getFileManager().getBuyNames());
result.addAll(plugin.getFileManager().getRentNames());
}
}
return result;
}
}
@@ -1,126 +0,0 @@
package nl.evolutioncoding.areashop.commands;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import nl.evolutioncoding.areashop.AreaShop;
import nl.evolutioncoding.areashop.regions.BuyRegion;
import nl.evolutioncoding.areashop.regions.GeneralRegion;
import nl.evolutioncoding.areashop.regions.RentRegion;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
public class MeCommand extends CommandAreaShop {
public MeCommand(AreaShop plugin) {
super(plugin);
}
@Override
public String getCommandStart() {
return "areashop me";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.me")) {
return plugin.getLanguageManager().getLang("help-me");
}
return null;
}
@Override
public void execute(CommandSender sender, Command command, String[] args) {
if(!sender.hasPermission("areashop.me")) {
plugin.message(sender, "me-noPermission");
return;
}
if(!(sender instanceof Player)) {
plugin.message(sender, "me-notAPlayer");
return;
}
Player player = (Player)sender;
// Get the regions owned by the player
Set<RentRegion> rentRegions = new HashSet<RentRegion>();
for(RentRegion region : plugin.getFileManager().getRents()) {
if(region.isOwner(player)) {
rentRegions.add(region);
}
}
Set<BuyRegion> buyRegions = new HashSet<BuyRegion>();
for(BuyRegion region : plugin.getFileManager().getBuys()) {
if(region.isOwner(player)) {
buyRegions.add(region);
}
}
// Send messages
if(rentRegions.isEmpty()) {
plugin.message(player, "me-noRentRegions");
} else {
plugin.message(player, "me-rentRegions");
for(RentRegion region : rentRegions) {
plugin.messageNoPrefix(player, "me-rentLine", region);
}
}
if(buyRegions.isEmpty()) {
plugin.message(player, "me-noBuyRegions");
} else {
plugin.message(player, "me-buyRegions");
for(BuyRegion region : buyRegions) {
plugin.messageNoPrefix(player, "me-buyLine", region);
}
}
Set<GeneralRegion> friendRegions = new HashSet<GeneralRegion>();
for(GeneralRegion region : plugin.getFileManager().getRegions()) {
if(region.getFriends() != null && region.getFriends().contains(player.getUniqueId())) {
friendRegions.add(region);
}
}
if(friendRegions.isEmpty()) {
plugin.message(player, "me-noFriendRegions");
} else {
plugin.message(player, "me-friendRegions");
for(GeneralRegion region : friendRegions) {
plugin.messageNoPrefix(player, "me-friendLine", region);
}
}
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
List<String> result = new ArrayList<String>();
// Nothing to complete
return result;
}
}
@@ -1,46 +0,0 @@
package nl.evolutioncoding.areashop.commands;
import java.util.ArrayList;
import java.util.List;
import nl.evolutioncoding.areashop.AreaShop;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
public class ReloadCommand extends CommandAreaShop {
public ReloadCommand(AreaShop plugin) {
super(plugin);
}
@Override
public String getCommandStart() {
return "areashop reload";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.reload")) {
return plugin.getLanguageManager().getLang("help-reload");
}
return null;
}
@Override
public void execute(CommandSender sender, Command command, String[] args) {
if(sender.hasPermission("areashop.reload")) {
// Reload the configuration files and update all region flags/signs
plugin.reload(sender);
} else {
plugin.message(sender, "reload-noPermission");
}
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
ArrayList<String> result = new ArrayList<String>();
return result;
}
}
@@ -1,115 +0,0 @@
package nl.evolutioncoding.areashop.commands;
import java.util.ArrayList;
import java.util.List;
import nl.evolutioncoding.areashop.AreaShop;
import nl.evolutioncoding.areashop.Utils;
import nl.evolutioncoding.areashop.regions.BuyRegion;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
public class SellCommand extends CommandAreaShop {
public SellCommand(AreaShop plugin) {
super(plugin);
}
@Override
public String getCommandStart() {
return "areashop sell";
}
@Override
public String getHelp(CommandSender target) {
if(target.hasPermission("areashop.sell")) {
return plugin.getLanguageManager().getLang("help-sell");
} else if(target.hasPermission("areashop.sellown")) {
return plugin.getLanguageManager().getLang("help-sellOwn");
}
return null;
}
@Override
public void execute(CommandSender sender, Command command, String[] args) {
if(!sender.hasPermission("areashop.sell") && !sender.hasPermission("areashop.sellown")) {
plugin.message(sender, "sell-noPermission");
return;
}
BuyRegion buy = null;
if(args.length <= 1) {
if (sender instanceof Player) {
// get the region by location
List<BuyRegion> regions = Utils.getApplicableBuyRegions(((Player) sender).getLocation());
if (regions.isEmpty()) {
plugin.message(sender, "cmd-noRegionsAtLocation");
return;
} else if (regions.size() > 1) {
plugin.message(sender, "cmd-moreRegionsAtLocation");
return;
} else {
buy = regions.get(0);
}
} else {
plugin.message(sender, "cmd-automaticRegionOnlyByPlayer");
return;
}
} else {
buy = plugin.getFileManager().getBuy(args[1]);
}
if(buy == null) {
plugin.message(sender, "sell-notRegistered");
return;
}
if(!buy.isSold()) {
plugin.message(sender, "sell-notBought");
return;
}
if(sender.hasPermission("areashop.sell")) {
plugin.message(sender, "sell-sold", buy.getPlayerName());
buy.sell(true);
} else {
if(sender.hasPermission("areashop.sellown") && sender instanceof Player) {
if(buy.getBuyer().equals(((Player)sender).getUniqueId())) {
plugin.message(sender, "sell-soldYours");
buy.sell(true);
} else {
plugin.message(sender, "sell-noPermissionOther");
}
} else {
plugin.message(sender, "sell-noPermission");
}
}
}
@Override
public List<String> getTabCompleteList(int toComplete, String[] start, CommandSender sender) {
ArrayList<String> result = new ArrayList<String>();
if(toComplete == 2) {
for(BuyRegion region : plugin.getFileManager().getBuys()) {
if(region.isSold()) {
result.add(region.getName());
}
}
}
return result;
}
}
Loaded 100 of 168 files, more files were not shown because too many files have changed in this diff. Show more