Compare commits

...
126 Commits
Author SHA1 Message Date
wizjany 5407315799 Release 7.0.3 for MC 1.14/1.15.
Last release before switching to 1.16.
2020-06-25 23:40:40 -04:00
wizjany b769469f5b Changelog for 7.0.3. 2020-06-25 23:11:51 -04:00
wizjany 3a9b1b1525 Add deprecation warnings to StringFlags. 2020-06-25 22:57:28 -04:00
wizjany ff5f933879 Typo. 2020-06-24 10:42:12 -04:00
wizjany 0492fafe30 Color 3rd party flags and unregistered flags in /rg info. 2020-06-21 17:25:38 -04:00
wizjany 36d95ad090 More inventory holder snapshot use. 2020-06-21 16:57:58 -04:00
wizjany c1ec708050 Use Inventory#getHolder(boolean useSnapshot) where available.
Dedicated to @phoenix616
2020-06-21 16:39:28 -04:00
wizjany f4a3e8a936 Allow setting passthrough on global via /rg flags.
Closes #1584.
2020-06-11 14:57:22 -04:00
wizjany 6c5380ba0b Prioritize tamed owners over entity targets.
Fixes #1587.
2020-06-08 13:14:04 -04:00
wizjany 868089b44f Actually read TargetMatchers from world configs.
Previously only read from global.
2020-06-01 15:52:16 -04:00
wizjany 9905d22ddf Add dyes as tools for interact handling. 2020-05-19 14:50:46 -04:00
UltraFaceguy 4eaa376e2c Providing a solution for tools being unable to interact with usable blocks 2020-05-12 20:56:41 -04:00
JOO200 37ae70f35d Add coral-fade flag and world configuration to disable coral fading
Closes #1532
2020-05-10 03:12:20 -04:00
wizjany 1a69250d9b Allow droppers to drop items without using them.
Fixes #1570.
2020-05-10 03:12:18 -04:00
wizjany b2d2d0815b Silence EntityChangeBlock for redstone ore.
We already silence this for Action.PHYSICAL PlayerInteractEvents.
Unfortunately Bukkit throws another event at us without the extra info
about interaction type, which gets fired if the interact flag is allow.
So silence that too.

Closes #1573.
2020-05-10 03:12:17 -04:00
wizjany 47cd96a3af Add tests to validate behavior of non-player causes in multiple regions. 2020-05-02 10:41:51 -04:00
wizjany 0a735e0146 Don't warn about small global regions.
Closes #1567.
2020-05-01 19:39:59 -04:00
stonar96 60590acfe3 Remove unnecessary checks and add comments 2020-04-29 15:15:07 -04:00
stonar96 6030bea13e Improve default teleport-message and remove null check 2020-04-29 15:15:07 -04:00
stonar96 20f89ea2ae Add teleport-message flag 2020-04-29 15:15:07 -04:00
wizjany 4c351fb0e3 Workaround for CraftBukkit's move event throttling. 2020-04-28 16:19:18 -04:00
wizjany 5e7829c3fe Allow FML2 in forge host keys.
Closes #1542.
2020-04-24 11:43:22 -04:00
wizjany 37e66dae7d Track BlockProjectileSource causes. 2020-04-24 10:06:16 -04:00
wizjany 662ae2bc84 Add issue templates. 2020-04-16 09:02:01 -04:00
wizjany fa60582afe Sand/gravel tick now, even if physics is cancelled. 2020-04-09 18:47:01 -04:00
wizjany 17c1647163 Move profile cache updating to join event.
Adding it to onEnable might back up the executor on /reloads.
2020-04-07 11:25:56 -04:00
wizjany 1fcda13469 Check waterlogged blocks for water-flow flag.
Also remove some terribly outdated obsidian generator protection.

Fixes #1546.
2020-03-29 20:16:50 -04:00
wizjany 570b7f7b77 Allow passthrough allow on global to override added members/owners. 2020-03-29 19:48:13 -04:00
wizjany aca0d843f6 Allow WorldEdit's //world override to affect region commands.
Priority is `-w` flag > //world override > player world > error.
Also makes regions selectable from console.
2020-03-23 21:32:25 -04:00
wizjany 1172ebd419 More spawn protection warnings.
Can't have enough of these apparently.
2020-03-23 16:40:12 -04:00
wizjany a09ccc5b45 Fire block breaks for piston extends, not just places. 2020-03-21 11:25:46 -04:00
wizjany e6bdf8abb5 Fix cauldron NPE.
Closes #1541.
2020-03-19 22:34:39 -04:00
wizjany df2ae6a666 Tweak some region info output, fix teleport location. 2020-03-19 13:34:20 -04:00
wizjany e4481f9337 Protect cauldron level change.
Closes #1262.
2020-03-12 15:26:22 -04:00
wizjany 2169aa218e Add option to always use default MC times for sending titles.
Alleviates issues with other plugins setting extremely short/long times.
2020-02-15 16:04:47 -05:00
wizjany 523e45188d Default nether-portal-protection to true.
Pre 1.14, this was false by default as one could repeatedly force portal
searches by entering a portal which would lead into a protected area.

Since 1.14, the event we have access too happens independently of the
portal search, so the player will get teleported regardless of whether
a portal is present or if the creation gets cancelled.
2020-02-15 13:31:38 -05:00
wizjany d95c6af1be Remove metadata when the entity is done.
Apparently Bukkit doesn't actually do this.
Fixes WORLDGUARD-4169.
2020-02-13 23:20:04 -05:00
wizjany 0d860bfca7 Change bypass cache to expireAfterWrite.
This hasn't caused issues for the past 5 years but I guess ¯\_(ツ)_/¯
2020-02-06 18:16:55 -05:00
wizjany 6f6125fe00 Treat farmland and turtle egg PIE as EntityChangeBlock.
Note that as in d37f015f this decouples the event from interact flag,
meaning that block-trampling must be explicitly set to allow to maintain
previous behavior. It also means that setting interact to allow won't
by default allow players to trample turtle eggs (but this wasn't the case
for farmland, since that was already handled by ECB - thanks Bukkit).

Fixes WORLDGUARD-4163.
2020-02-01 11:39:20 -05:00
wizjany 0332929531 Bump bStats to 1.7, adding plugin id. 2020-01-31 11:18:50 -05:00
Wyatt Childers 637665f52d Add a scripts folder to gitignore for dev scripts 2020-01-14 22:51:13 -05:00
wizjany db3838ccfe Add flag to prevent natural health regen and hunger drain. 2020-01-09 20:41:57 -05:00
wizjany 789405d116 Ignore session reset if player doesn't move a block.
So technically we do this block check in Session#testMoveTo, but the
/wg flushstates command can force a session re-initialization even if
the player hasn't moved a full block yet.
The amount of logic going on between the event call and the point where
we test that force boolean is rather lengthy though, so ignoring it for
the time being may be worth it.
TL;DR: Don't want WG in timings for PlayerMoveEvent needlessly.
2020-01-07 17:24:43 -05:00
wizjany d37f015f0c De-couple chest-access from interact. READ BELOW.
This is possibly a breaking change, in that WG will be overprotective
in regions which previously had interact set to allow but didn't change
the chest-access flag. If you previously had regions like this where you
would like to have non-members access chests, you will need to set the
chest-access flag to allow.

This change was made to alleviate some confusion that became more
evident recently with lecterns, since interacting with lecterns allowed
one to read a book, but the chest-access flag controlled taking the book.
This required setting interact to allow and chest-access to deny (at
least for nonmembers) to allow guests to read books but not take them.

This is a tentative change and may be reverted if it is too unpopular.
Thanks for testing dev builds :^)
2020-01-05 22:52:23 -05:00
wizjany 239eda3f96 Bump to snapshot. This will likely become 7.1 soon anyway. 2020-01-05 22:43:00 -05:00
wizjany 0715cbe216 Release 7.0.2. 2020-01-05 22:42:15 -05:00
wizjany 738b24bfc1 Changelog for 7.0.2.
Small one.
2020-01-05 22:35:05 -05:00
wizjany b835ee39d5 Check water/lava placement from dispensers on edge of region.
Fixes WORLDGUARD-4161.
2020-01-03 23:11:56 -05:00
Pieter12345 4a7552e6be Prevent pushing pistons across region borders
Pistons are classified as not pushable regardless of their state, causing WorldGuard to not protect against them moving. This commit fixes that.
2020-01-01 13:53:09 -05:00
Joo200 c6c0fc9d74 Fixed failed checkstyle gradle task 2020-01-01 13:53:01 -05:00
wizjany f43a4eaad8 Add spawn-protection overlap check when defining regions.
Update cached username on login.
Bump WorldEdit dep version.
2019-12-19 15:42:34 -05:00
JOO200 abfa5cb6a5 bee nests can be modified by right click (like beehives) 2019-12-16 14:08:04 -05:00
JOO200 05f7d68705 Use Paper-API 1.15 as Dependency 2019-12-16 14:08:04 -05:00
wizjany 9adac4f239 Initial 1.15 stuff.
Materials is not really cross-version compatible. Really could do with
some rewriting at some point.
2019-12-10 23:48:50 -05:00
wizjany c5355adb4b Back to snapshot. 2019-11-22 23:51:25 -05:00
wizjany fb37342b3c Release 7.0.1. 2019-11-22 23:43:05 -05:00
wizjany 1fd94a3655 Switch blacklist to drilldown since bstats doesn't support bar charts.
See https://github.com/Bastian/bStats/issues/67

Also update blacklist example txt with correct names.
2019-11-17 18:13:45 -05:00
wizjany c413cf4123 Remove pointless iterable. 2019-11-17 18:13:45 -05:00
wizjany 87162acf11 Switch blacklist stat to entry counts. 2019-11-17 18:13:45 -05:00
wizjany 2c14acc28c Add some custom charts to bStats.
Should give a good view of feature usage, especially some badly
supported features like SQL and chest protection.
2019-11-17 18:13:45 -05:00
wizjany 26477406f1 Fix pistons flag not applying to sticky pistons pulling. 2019-10-11 22:12:03 -04:00
wizjany 121b34ecb9 Add applicable regions section to /wg report. 2019-10-06 13:09:08 -04:00
wizjany 3ebaaf9c8b Add /rg toggle-bypass command to turn off region bypass temporarily.
Makes it easier to test things without op/de-op, switching ranks, etc
all the time.
2019-10-06 12:17:07 -04:00
wizjany 4c9812db04 Fix exit-deny-message using wrong region set on enderpearl/chorus-fruit. 2019-10-06 12:17:07 -04:00
wizjany e792dd6f98 Workaround colors on newlines of string flags issue in text lib.
Also fix newline lookbehind replacement, and only replace color macros
in string flags.
2019-10-06 12:17:07 -04:00
wizjany d410e1f84e Re-arrange messages in (re)define commands.
Only send messages after successful add.
2019-10-06 12:17:07 -04:00
wizjany d07f95952d Causes only track blocks, not locations. 2019-09-26 20:24:11 -04:00
wizjany cb9ab3a7b2 Check creeper-explosion flag for all entity damage, not just players. 2019-09-26 10:38:02 -04:00
wizjany 1c3cf02ebd BlockMultiPlace has an immutable state list.
Fixes WORLDGUARD-4143.
2019-09-22 15:16:57 -04:00
wizjany fc0f7acab5 Fix infinite loop in addowner checks.
Fixes WORLDGUARD-4138.
2019-09-22 14:28:38 -04:00
wizjany 20db92541b Make use of BlockFertilizeEvent, various BlockState lists.
Only mostly tested to work. BlockFertilize unfortunately doesn't let
us cancel the preceding stuff like StructureGrow and item use.

Also workaround Bukkit sending 2 events for trampling.
2019-09-18 15:43:36 -04:00
wizjany 5fca3b3c3d Track causes when players ignite creepers.
Fixes WORLDGUARD-4136.
2019-09-13 17:34:37 -04:00
wizjany c633a2d070 Cover some more plants as crop-growth.
Note that spigot doesn't throw events for bamboo yet, so this only
applies to sugar canes and cacti at the moment. Should work if spigot
implements BlockGrowEvent for cacti though.

Fixes WORLDGUARD-4137.
2019-09-13 17:20:51 -04:00
wizjany effbd62e68 Ignore hopper minecarts with the ignore hopper setting. 2019-09-13 16:43:27 -04:00
wizjany 056eaa6587 Teleport async on Paper. 2019-09-13 16:42:35 -04:00
wizjany cb2c0870ec List is not a valid cause. Each element is its own cause.
Fixes WORLDGUARD-4140.

Specifically, fixes not being able to break lilypads while in a boat,
even through the player would normally be able to.

Note that slowdown is client-side and getting stuck is due to Spigot
not updating the client when the break is cancelled, which are unrelated
to this issue (and not fixable by us).
2019-09-13 16:32:28 -04:00
wizjany 179c324c80 Apparently world names are allowed to have spaces. 2019-08-18 23:43:57 -04:00
wizjany 96d15d6dbf Only store existing per-player time/weather in handlers.
Fixes WORLDGUARD-4124.

This will fix various issues with logging in to regions with these flags
set and then moving out of them, or when moving between two adjacent
regions with the flags set and then moving out.
2019-08-18 12:00:50 -04:00
wizjany 120d2e223d Extract/half-fix addowner checks.
Max-region-count-for-player is super bork.

Fixes WORLDGUARD-4129.
2019-08-18 10:39:56 -04:00
wizjany 70ea6bad6e Some cleanup for flag command. 2019-08-18 10:38:07 -04:00
wizjany e59d61e1cf Extract NumberFlag for suggestions, make FlagHelper prettier in console. 2019-08-06 23:08:10 -04:00
wizjany bbed280f62 Update docs links to point to enginehub.
Also don't allow block-place/block-break setting from flag helper.
2019-08-06 21:50:05 -04:00
wizjany f165ae3d95 Back to snapshot. 2019-08-06 00:12:41 -04:00
wizjany 124898ec91 7.0.1 RC 2. 2019-08-06 00:12:26 -04:00
wizjany ba32d24363 Merge pull request #414 from EngineHub/feature/paper
Add some Paper-specific features
2019-08-05 23:49:04 -04:00
wizjany 0bba822295 Link ender crystal entity <-> material. 2019-08-03 18:10:54 -04:00
wizjany 7538af2686 TippedArrow again. 2019-08-02 16:34:26 -04:00
wizjany 48922118b1 Fix fireworks, protect by default (this is a behavioral change).
Add regions.use-paper-entity-origin setting, false by default because
it can have some weird implications.
2019-08-01 23:47:27 -04:00
wizjany 14fe2d0e79 Use Paper player profiles if available.
Also fall back to caching to memory if SQLite can't be linked.
This is a common issue with (bad) server hosts who mount /tmp as noexec,
which causes sqlite's native binaries to fail to link.
2019-08-01 20:24:34 -04:00
wizjany 11a1ac6742 User paper firework tracking. 2019-08-01 20:24:33 -04:00
wizjany c5bfdcb0e6 Use PaperLib for some performance enhancements. 2019-08-01 20:24:32 -04:00
wizjany 93dae282b2 Apparently some plugins do weird things with falling blocks. 2019-08-01 20:12:58 -04:00
wizjany 3468e3d47e Handful of small fixes.
* Fix material loading from config requiring minecraft: namespace.
* Fix disallowed-lightning blocks. Lightning entities are weird.
* Fix /wg reload overwriting config changes.
* General around thread usage/naming/shutdown. If anyone was actually
  making their own managers/indices you deserve to break.
2019-07-31 22:53:20 -04:00
wizjany b7ad0257b7 Remove legacy potion code. 2019-07-30 18:44:24 -04:00
wizjany 070f6e005f Merge pull request #415 from EngineHub/kotlin-dsl
Migrate gradle to kotlin dsl.
2019-07-30 16:56:46 -04:00
wizjany cc3f4d4d44 Relocate squirrelid in source, fix flyway shading. 2019-07-30 09:44:19 -04:00
wizjany 21e65be110 Fix poms, remove bukkit lib project since it's currently unused. 2019-07-29 23:41:38 -04:00
wizjany 61494fd76e Migrate gradle to kotlin dsl. 2019-07-29 23:25:13 -04:00
wizjany 556b638d04 Switch build badge to TC.
And remove dead wiki links.
2019-07-29 11:34:18 -04:00
wizjany 825b3a3f36 Save defaults to config file. 2019-07-27 22:40:03 -04:00
wizjany afe042ef4d Add option for resetting fall distance when void falling teleport is on.
reset-fall-on-void-teleport, defaults to false. (I can't remember if
old WG 6 behavior was to do this or not...?)
2019-07-27 21:57:49 -04:00
wizjany 4044e2b122 Ender crystal explosions can't be cause tracked. 2019-07-26 22:51:19 -04:00
wizjany aa4137822f Fix sleep flag. 2019-07-24 14:35:42 -04:00
wizjany f37acd3de6 Whitelist player->player interacts.
As noted before, any more specific events should still be blocked (such
as potion use).
2019-07-23 20:13:12 -04:00
wizjany b0e4cf148b ItemElytra extends ItemArmor... 2019-07-19 20:45:16 -04:00
wizjany 248ffd0ba8 Maybe fix travis. 2019-07-18 14:54:13 -04:00
wizjany 3272759f25 Check waterlogged blocks when emptying buckets.
Fixes WORLDGUARD-4119.
2019-07-17 07:45:31 -04:00
wizjany 456a16591b Handle UseEntity player->player events as PvP.
Fixes WORLDGUARD-4118.
Tell me if this breaks other intended behaviors somehow.
2019-07-16 18:48:57 -04:00
wizjany 79f6635b8a Make /wg profile text more clear.
This patch dedicated to @phoenix616.
2019-07-16 18:42:48 -04:00
wizjany 1f362bef59 Minecarts spawn in the clicked (rail) block. 2019-07-09 07:47:54 -04:00
wizjany 63209d1174 Null-check for last commit. 2019-07-07 01:22:04 -04:00
wizjany f546700189 Allow interact-whitelist for entities with matching item types. 2019-07-06 11:02:36 -04:00
wizjany 35e0db36d3 Workaround for sign dying issue.
Signs still get dyed even if you deny using dye.
2019-07-03 09:53:11 -04:00
wizjany ab7751e046 Unfix WORLDGUARD-3360.
There's a reason this wasn't done before. This is fundamentally broken.
2019-07-02 23:08:50 -04:00
wizjany a9cd23c6ef Don't replace in comments and strings when you refactor... 2019-07-02 17:39:21 -04:00
wizjany 8ca01b37a4 Add config to disable villagers getting zapped to witches.
"weather.disable-villager-witchification"
2019-06-30 19:58:10 -04:00
wizjany aa8997aeca Add TP button to /rg list where applicable. 2019-06-30 11:37:50 -04:00
wizjany b757fcc88b Send CUI changes when using /rg select. 2019-06-27 08:06:09 -04:00
wizjany 7593e1a01c Initial update to 1.14. 2019-06-25 22:12:18 -04:00
wizjany af3eb85962 Add on-equip blacklist event.
Note that due to deficiencies in the Bukkit API, the event will attempt
to be overprotective and cancel some events that may not actually result
in the player equipping an item. Maintainable PRs welcome. (i.e. would
rather not have to have a list of slot numbers for various inventories
and match them to items :upside_down:)
2019-06-25 22:11:33 -04:00
wizjany aabb0b2345 Treat damaged anvils like regular anvils. 2019-06-24 12:16:19 -04:00
wizjany 6d25513739 Don't allow setting build + passthrough in the flag helper.
It masks the warning message and too many people mess this up.
2019-06-22 14:15:21 -04:00
wizjany 96b61743b9 Fix lava fire being off by default.
No clue how this was never brought up before.

Also add system property to disable the ClassSourceValidator.
2019-06-19 23:50:18 -04:00
wizjany ff7209a58b Only check ride flag for pigs with saddles. 2019-06-19 23:22:21 -04:00
wizjany fe4f0cfc49 Bump dependencies.
Also remove intake. Unsure when that was ever used.
2019-06-13 09:17:20 -04:00
wizjany 9cf1e02506 Bump to 7.0.1-SNAPSHOT 2019-06-11 22:43:26 -04:00
108 changed files with 2851 additions and 1185 deletions

No files matched your search

+31
View File
@@ -0,0 +1,31 @@
---
name: Bug report
about: Report a way in which WorldGuard is not working as intended
title: ''
labels: type:bug, status:pending
assignees: ''
---
**Versions**
<!-- Please include the full version of WorldEdit, WorldGuard and the platform (Bukkit/Spigot/Paper) you are running, e.g. output from `/we version`, `/wg version` `/version` commands. Please ensure you are running up to date software before making a bug report. Old versions will recieve little to no support. -->
WorldEdit version:
WorldGuard version:
Platform version:
**Describe the bug**
<!-- A clear and concise description of what the bug is. -->
**To Reproduce**
<!-- Steps to reproduce the behavior: -->
1. ...
2. ...
**Expected behavior**
<!-- A clear and concise description of what you expected to happen. -->
**Screenshots**
<!-- If applicable, add screenshots to help explain your problem. -->
**Additional context**
<!-- Add any other context about the problem here. -->
+5
View File
@@ -0,0 +1,5 @@
blank_issues_enabled: false
contact_links:
- name: EngineHub Discord
url: https://discord.gg/EngineHub
about: Please ask and answer questions here.
+20
View File
@@ -0,0 +1,20 @@
---
name: Feature request
about: Suggest an idea for WorlGuard
title: ''
labels: type:feature-request, status:pending
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
<!-- A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] -->
**Describe the solution you'd like**
<!-- A clear and concise description of what you want to happen. -->
**Describe alternatives you've considered**
<!-- A clear and concise description of any alternative solutions or features you've considered. -->
**Additional context**
<!-- Add any other context or screenshots about the feature request here. -->
+2
View File
@@ -15,3 +15,5 @@ dependency-reduced-pom.xml
.gradle/
**/build/
out/
scripts/
+1
View File
@@ -1,4 +1,5 @@
language: java
dist: trusty
jdk:
- oraclejdk8
notifications:
+82
View File
@@ -1,5 +1,87 @@
# Changelog
## 7.0.3
* This is the last release supporting MC 1.14 and 1.15.
* Decouple chest-access flag from interact flag. IMPORTANT: If you relied on allowing players to access chests via setting
the interact flag to allow, you will now need to set the chest-access flag to allow instead (or as well). This does not
affect any setups where users were *not* supposed to be able to access chests and other inventories.
* Add natural-health-regen and natural-hunger-drain flags. Unlike the heal/feed flags, these can not restore or deplete health/hunger.
* Fix the interact flag allowing breaking of turtle eggs (now tied directly to block-trampling flag).
* Fix a memory leak that could occur with many many explosives.
* Add regions.titles-always-use-default-times config option. Set this to true if you use greeting/farewell titles and another plugin
makes the titles disappear too quickly.
* Add protection for cauldrons water level changing.
* Improve diagnostic hints and information, such as spawn protection warnings, flag colors in region info, etc.
* Fix waterlogged blocks bypassing water-flow flag.
* Workaround for a CraftBukkit change that made no-physics-sand/gravel non-functional.
* Workaround for CraftBukkit throttling move events.
* Track projectiles shot by dispensers.
* Allowed setting passthrough allow on global to unprotect it if members/owners are added.
* Add support for newer forge clients (FML2) in host keys.
* Allow using WorldEdit's `//world <worldname>` command to select a world for region commands. This removes the need to
use `-w <worldname>` in every command when running commands from console.
* Add a teleport-message flag, shown when using `/rg tp`.
* Add coral-fade flag, which prevents corals from drying when out of water.
* Fix spammy deny-message when walking over redstone ore with certain flag setups.
* Improve handling of interacting with various tools in hand that didn't modify blocks. (eg opening a chest with an axe in hand)
* Fix allow-all-interact option not being read from per-world configs.
* Fix misattribution of pets (eg wolves) in PvP.
* Improve performance of hopper checks when on recent builds of Paper.
* Add event-handling.break-hoppers-on-denied-move config option to prevent hoppers from being broken (but items still won't be moved).
* Note to developers using the WorldGuard API: If you specifically relied on flags such as greeting/farewell, deny-message, etc being
StringFlags, be warned that this will change in a future version to support JSON text components. Please plan accordingly.
## 7.0.2
* Update to MC 1.15. Still compatible with 1.14, and incompatible with 1.13, as before.
* Add an informational message when defining a region that overlaps vanilla spawn protection.
* Protect against pushing a piston with another piston on a region border.
* Protect against buckets in dispensers on region borders.
## 7.0.1
* Add `/rg toggle-bypass` command which temporarily turns off region bypassing until used again.
* More improvements to `/rg flag` and `/rg flags` commands.
* Fix some checks for adding owners to unclaimed regions.
* Fix an issue with time-/weather-lock flags when logging in to a region with the flag set.
* Fix cause tracking in vehicles (incl. breaking lilypads in a boat)
* Use async teleports on Paper.
* Include hopper minecarts in the ignore hoppers config setting.
* Add sugar cane and cacti to the crop-growth flag. Bamboo is also included pending Spigot throwing an event for it.
* Specifically track when players ignite creepers with flint and steel.
* Fix fuzziness when using bonemeal near a protected region.
* Fix color codes not applying in greeting, etc flags when placed after a newline (\n).
* Add applicable region information to `/wg report`.
* Fix pistons flag not applying to sticky pistons pulling blocks.
* Add some custom metrics for bStats.
* Everything in the RC/beta changelog below.
## 7.0.1 RC 2 (inc. beta 1)
* Due to breaking changes in important Bukkit API, this is not compatible with MC 1.13!
* Update to MC 1.14. Adds protection for new blocks, etc.
* To allow players to read from lecterns, but not take the book, flag interact allow, and then flag chest-access -g nonmembers deny.
* Add ravager-grief flag.
* Fix overprotection of unsaddled pigs with the ride flag.
* Fix lava fire defaulting to off (won't change existing configs).
* Fix damaged/chipped anvils not respecting use flag like regular anvils.
* Add on-equip blacklist event. Note that it is overprotective due to deficiencies in Bukkit API.
* Update WorldEdit CUI when using /rg select.
* Add config option to disable villagers getting zapped into witches. ("weather.disable-villager-witchification")
* Add entity support to interact-whitelist config option (use the Material of the corresponding item).
* Fix vehicle-place protecting the rails at the very top of region boundaries incorrectly.
* Fix for emptying buckets on waterloggable blocks.
* Whitelist all player -> player interactions (previously was spammy in pvp).
* Fix sleep flag not protecting against explosions in nether/end.
* Add config for the teleport-on-void to reset fall distance.
* Fix config options taking material lists requiring "minecraft:" namespace.
* Fix disallowed-lightning-blocks situationally not working.
* Fix errors that occurred when plugins used falling block entities with non-item materials.
* Add special support for Paper servers (papermc.io): Paper's API allows us to track who launched fireworks.
* Fireworks are now protected by default. On Paper servers, members can use them by default (to deal damage),
on non-Paper servers, flag firework-damage allow to revert to old behavior (everyone can deal damage with fireworks by default).
* Misc performance enhancements for Paper servers.
* Add 'regions.use-paper-entity-origin' as an experimental setting (default off) for Paper servers. Enabling it will make non-player entities be treated as members of the place they spawned, instead of their current location when flags are checked.
## 7.0.0
* Added support for MC 1.13, dropped support for previous versions.
* Added lots of interactive text in e.g. `/rg info` command.
+16
View File
@@ -0,0 +1,16 @@
WorldGuard, a suite of tools for Minecraft
Copyright (C) sk89q <http://www.sk89q.com>
Copyright (C) WorldGuard team and contributors
This program is free software: you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by the
Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
+3 -4
View File
@@ -22,8 +22,7 @@ Compiling
---------
The project is written for Java 8 and our build process makes use of
[Gradle](http://gradle.org). Detailed compilation information
[can be found on the wiki](http://wiki.sk89q.com/wiki/WorldGuard/Development#Compiling).
[Gradle](http://gradle.org).
Dependencies are automatically handled by Gradle.
@@ -43,5 +42,5 @@ Links
* [Discord](https://discord.gg/enginehub)
* [IRC channel](https://webchat.esper.net/?join=sk89q) (#sk89q on irc.esper.net)
* [Issue tracker](https://dev.enginehub.org/issues/WORLDGUARD)
* [Continuous integration](http://builds.enginehub.org) [![Build Status](https://travis-ci.org/EngineHub/WorldGuard.svg?branch=master)](https://travis-ci.org/EngineHub/WorldGuard)
* [End-user documentation](https://worldguard.readthedocs.io/en/latest/) / [Older Wiki](http://wiki.sk89q.com/wiki/WorldGuard)
* [Continuous integration](http://builds.enginehub.org) [![Build Status](https://ci.enginehub.org/app/rest/builds/buildType:bt11,branch:master/statusIcon.svg)](http://ci.enginehub.org/viewType.html?buildTypeId=bt11&guest=1)
* [End-user documentation](https://worldguard.enginehub.org/en/latest/)
-136
View File
@@ -1,136 +0,0 @@
println """
*******************************************
You are building WorldGuard!
If you encounter trouble:
1) Read COMPILING.md if you haven't yet
2) Try running 'build' in a separate Gradle run
3) Use gradlew and not gradle
4) If you still need help, ask on IRC! irc.esper.net #sk89q
Output files will be in [subproject]/build/libs
*******************************************
"""
buildscript {
repositories {
mavenCentral()
maven { url = "https://oss.sonatype.org/content/repositories/snapshots/" }
jcenter()
}
configurations.all {
resolutionStrategy {
force 'com.google.guava:guava:21.0'
}
}
dependencies {
classpath "com.github.jengelman.gradle.plugins:shadow:4.0.3"
classpath 'org.jfrog.buildinfo:build-info-extractor-gradle:4.7.5'
classpath 'org.ajoberstar:gradle-git:1.7.2'
}
}
allprojects {
group = 'com.sk89q.worldguard'
version = '7.0.0'
}
if (!project.hasProperty("artifactory_contextUrl")) ext.artifactory_contextUrl = "http://localhost"
if (!project.hasProperty("artifactory_user")) ext.artifactory_user = "guest"
if (!project.hasProperty("artifactory_password")) ext.artifactory_password = ""
if (!project.hasProperty("gitCommitHash")) {
try {
def repo = org.ajoberstar.grgit.Grgit.open(project.file('.'))
ext.gitCommitHash = repo.head().abbreviatedId
} catch (Exception e) {
ext.gitCommitHash = "no_git_id"
}
}
apply plugin: 'com.jfrog.artifactory'
artifactory {
contextUrl = "${artifactory_contextUrl}"
publish {
repository {
repoKey = project.version.contains("SNAPSHOT") ? 'libs-snapshot-local' : 'libs-release-local'
username = "${artifactory_user}"
password = "${artifactory_password}"
maven = true
}
}
}
artifactoryPublish.skip = true
subprojects {
apply plugin: 'java'
apply plugin: 'java-library'
apply plugin: 'maven'
apply plugin: 'checkstyle'
apply plugin: 'com.github.johnrengelman.shadow'
apply plugin: 'com.jfrog.artifactory'
ext.internalVersion = version + ";" + gitCommitHash
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
checkstyle.configFile = new File(rootProject.projectDir, "config/checkstyle/checkstyle.xml")
checkstyle.toolVersion = '7.6.1'
repositories {
mavenLocal()
mavenCentral()
maven { url "https://repo.spongepowered.org/maven/" }
maven { url "https://hub.spigotmc.org/nexus/content/groups/public" }
maven { url "https://maven.sk89q.com/repo/" }
maven { url "https://repo.maven.apache.org/maven2" }
}
if (JavaVersion.current().isJava8Compatible()) {
// Java 8 turns on doclint which we fail
tasks.withType(Javadoc) {
options.addStringOption('Xdoclint:none', '-quiet')
}
}
task sourcesJar(type: Jar, dependsOn: classes) {
classifier = 'sources'
from sourceSets.main.allSource
}
task javadocJar(type: Jar, dependsOn: javadoc) {
classifier = 'javadoc'
from javadoc.destinationDir
}
artifacts {
archives jar
archives sourcesJar
archives javadocJar
}
build.dependsOn(checkstyleMain)
build.dependsOn(checkstyleTest)
build.dependsOn(sourcesJar)
build.dependsOn(javadocJar)
shadowJar {
classifier 'dist'
dependencies {
include(dependency('org.khelekore:prtree:1.5.0'))
include(dependency('com.sk89q:squirrelid:0.2.0'))
include(dependency('org.flywaydb:flyway-core:3.0'))
}
exclude 'GradleStart**'
exclude '.cache'
exclude 'LICENSE*'
}
artifactoryPublish {
publishConfigs('archives')
}
}
+26
View File
@@ -0,0 +1,26 @@
import org.ajoberstar.grgit.Grgit
logger.lifecycle("""
*******************************************
You are building WorldGuard!
If you encounter trouble:
1) Try running 'build' in a separate Gradle run
2) Use gradlew and not gradle
3) If you still need help, ask on Discord! https://discord.gg/enginehub
Output files will be in [subproject]/build/libs
*******************************************
""")
applyRootArtifactoryConfig()
if (!project.hasProperty("gitCommitHash")) {
apply(plugin = "org.ajoberstar.grgit")
ext["gitCommitHash"] = try {
(ext["grgit"] as Grgit?)?.head()?.abbreviatedId
} catch (e: Exception) {
logger.warn("Error getting commit hash", e)
"no_git_id"
}
}
+19
View File
@@ -0,0 +1,19 @@
plugins {
`kotlin-dsl`
kotlin("jvm") version embeddedKotlinVersion
}
repositories {
jcenter()
gradlePluginPortal()
}
dependencies {
implementation(gradleApi())
implementation("gradle.plugin.net.minecrell:licenser:0.4.1")
implementation("org.ajoberstar.grgit:grgit-gradle:3.1.1")
implementation("com.github.jengelman.gradle.plugins:shadow:5.1.0")
implementation("net.ltgt.apt-eclipse:net.ltgt.apt-eclipse.gradle.plugin:0.21")
implementation("net.ltgt.apt-idea:net.ltgt.apt-idea.gradle.plugin:0.21")
implementation("org.jfrog.buildinfo:build-info-extractor-gradle:4.9.7")
}
@@ -0,0 +1,40 @@
import org.gradle.api.Project
import org.gradle.kotlin.dsl.apply
import org.gradle.kotlin.dsl.configure
import org.gradle.kotlin.dsl.named
import org.jfrog.gradle.plugin.artifactory.dsl.ArtifactoryPluginConvention
import org.jfrog.gradle.plugin.artifactory.task.ArtifactoryTask
private const val ARTIFACTORY_CONTEXT_URL = "artifactory_contextUrl"
private const val ARTIFACTORY_USER = "artifactory_user"
private const val ARTIFACTORY_PASSWORD = "artifactory_password"
fun Project.applyRootArtifactoryConfig() {
if (!project.hasProperty(ARTIFACTORY_CONTEXT_URL)) ext[ARTIFACTORY_CONTEXT_URL] = "http://localhost"
if (!project.hasProperty(ARTIFACTORY_USER)) ext[ARTIFACTORY_USER] = "guest"
if (!project.hasProperty(ARTIFACTORY_PASSWORD)) ext[ARTIFACTORY_PASSWORD] = ""
apply(plugin = "com.jfrog.artifactory")
configure<ArtifactoryPluginConvention> {
setContextUrl("${project.property(ARTIFACTORY_CONTEXT_URL)}")
clientConfig.publisher.run {
repoKey = when {
"${project.version}".contains("SNAPSHOT") -> "libs-snapshot-local"
else -> "libs-release-local"
}
username = "${project.property(ARTIFACTORY_USER)}"
password = "${project.property(ARTIFACTORY_PASSWORD)}"
isMaven = true
isIvy = false
}
}
tasks.named<ArtifactoryTask>("artifactoryPublish") {
isSkip = true
}
}
fun Project.applyCommonArtifactoryConfig() {
val named = tasks.named<ArtifactoryTask>("artifactoryPublish") {
publishConfigs("archives")
}
}
+18
View File
@@ -0,0 +1,18 @@
import org.gradle.api.Project
import org.gradle.kotlin.dsl.repositories
fun Project.applyCommonConfiguration() {
group = rootProject.group
version = rootProject.version
repositories {
mavenCentral()
maven { url = uri("https://maven.sk89q.com/repo/") }
maven { url = uri("https://oss.sonatype.org/content/repositories/snapshots/") }
}
configurations.all {
resolutionStrategy {
cacheChangingModulesFor(5, "minutes")
}
}
}
+12
View File
@@ -0,0 +1,12 @@
import org.gradle.api.Project
import org.gradle.api.plugins.ExtraPropertiesExtension
import org.gradle.api.plugins.JavaPluginConvention
import org.gradle.api.tasks.SourceSetContainer
import org.gradle.kotlin.dsl.getByType
import org.gradle.kotlin.dsl.the
val Project.ext: ExtraPropertiesExtension
get() = extensions.getByType()
val Project.sourceSets: SourceSetContainer
get() = the<JavaPluginConvention>().sourceSets
+96
View File
@@ -0,0 +1,96 @@
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import org.gradle.api.Project
import org.gradle.api.artifacts.ModuleDependency
import org.gradle.api.internal.HasConvention
import org.gradle.api.plugins.MavenRepositoryHandlerConvention
import org.gradle.api.tasks.Upload
import org.gradle.api.tasks.bundling.Jar
import org.gradle.kotlin.dsl.apply
import org.gradle.kotlin.dsl.get
import org.gradle.kotlin.dsl.getPlugin
import org.gradle.kotlin.dsl.invoke
import org.gradle.kotlin.dsl.register
fun Project.applyLibrariesConfiguration() {
applyCommonConfiguration()
apply(plugin = "java-base")
apply(plugin = "maven")
apply(plugin = "com.github.johnrengelman.shadow")
apply(plugin = "com.jfrog.artifactory")
configurations {
create("shade")
getByName("archives").extendsFrom(getByName("default"))
}
group = "${rootProject.group}.worldguard-libs"
tasks.register<ShadowJar>("jar") {
configurations = listOf(project.configurations["shade"])
archiveClassifier.set("")
dependencies {
exclude(dependency("com.google.code.findbugs:jsr305:1.3.9"))
}
relocate("com.sk89q.squirrelid", "com.sk89q.worldguard.util.profile")
}
val altConfigFiles = { artifactType: String ->
val deps = configurations["shade"].incoming.dependencies
.filterIsInstance<ModuleDependency>()
.map { it.copy() }
.map { dependency ->
dependency.artifact {
name = dependency.name
type = artifactType
extension = "jar"
classifier = artifactType
}
dependency
}
files(configurations.detachedConfiguration(*deps.toTypedArray())
.resolvedConfiguration.lenientConfiguration.artifacts
.filter { it.classifier == artifactType }
.map { zipTree(it.file) })
}
tasks.register<Jar>("sourcesJar") {
from({
altConfigFiles("sources")
})
val filePattern = Regex("(.*)com/sk89q/squirrelid((?:/|$).*)")
val textPattern = Regex("com\\.sk89q\\.squirrelid")
eachFile {
filter {
it.replaceFirst(textPattern, "com.sk89q.worldguard.util.profile")
}
path = path.replaceFirst(filePattern, "$1com/sk89q/worldguard/util/profile$2")
}
archiveClassifier.set("sources")
}
tasks.named("assemble").configure {
dependsOn("jar", "sourcesJar")
}
artifacts {
val jar = tasks.named("jar")
add("default", jar) {
builtBy(jar)
}
val sourcesJar = tasks.named("sourcesJar")
add("archives", sourcesJar) {
builtBy(sourcesJar)
}
}
tasks.register<Upload>("install") {
configuration = configurations["archives"]
(repositories as HasConvention).convention.getPlugin<MavenRepositoryHandlerConvention>().mavenInstaller {
pom.version = project.version.toString()
pom.artifactId = project.name
}
}
applyCommonArtifactoryConfig()
}
+119
View File
@@ -0,0 +1,119 @@
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import net.minecrell.gradle.licenser.LicenseExtension
import org.gradle.api.JavaVersion
import org.gradle.api.Project
import org.gradle.api.plugins.JavaPluginConvention
import org.gradle.api.plugins.quality.CheckstyleExtension
import org.gradle.api.tasks.bundling.Jar
import org.gradle.api.tasks.javadoc.Javadoc
import org.gradle.api.tasks.testing.Test
import org.gradle.external.javadoc.CoreJavadocOptions
import org.gradle.kotlin.dsl.apply
import org.gradle.kotlin.dsl.configure
import org.gradle.kotlin.dsl.dependencies
import org.gradle.kotlin.dsl.get
import org.gradle.kotlin.dsl.getByName
import org.gradle.kotlin.dsl.named
import org.gradle.kotlin.dsl.register
import org.gradle.kotlin.dsl.withType
fun Project.applyPlatformAndCoreConfiguration() {
applyCommonConfiguration()
apply(plugin = "java")
apply(plugin = "eclipse")
apply(plugin = "idea")
apply(plugin = "maven")
apply(plugin = "checkstyle")
apply(plugin = "com.github.johnrengelman.shadow")
apply(plugin = "com.jfrog.artifactory")
apply(plugin = "net.minecrell.licenser")
ext["internalVersion"] = "$version;${rootProject.ext["gitCommitHash"]}"
configure<JavaPluginConvention> {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
configure<CheckstyleExtension> {
configFile = rootProject.file("config/checkstyle/checkstyle.xml")
toolVersion = "7.6.1"
}
tasks.withType<Test>().configureEach {
useJUnit()
}
dependencies {
"testCompile"("junit:junit:${Versions.JUNIT}")
// TODO switch to jupiter - doesn't support abstract test classes so tests need rewriting
//"testImplementation"("org.junit.jupiter:junit-jupiter-api:${Versions.JUNIT}")
//"testRuntime"("org.junit.jupiter:junit-jupiter-engine:${Versions.JUNIT}")
}
// Java 8 turns on doclint which we fail
tasks.withType<Javadoc>().configureEach {
(options as CoreJavadocOptions).addStringOption("Xdoclint:none", "-quiet")
}
tasks.register<Jar>("javadocJar") {
dependsOn("javadoc")
archiveClassifier.set("javadoc")
from(tasks.getByName<Javadoc>("javadoc").destinationDir)
}
tasks.named("assemble").configure {
dependsOn("javadocJar")
}
artifacts {
add("archives", tasks.named("jar"))
add("archives", tasks.named("javadocJar"))
}
if (name == "worldguard-core" || name == "worldguard-bukkit") {
tasks.register<Jar>("sourcesJar") {
dependsOn("classes")
archiveClassifier.set("sources")
from(sourceSets["main"].allSource)
}
artifacts {
add("archives", tasks.named("sourcesJar"))
}
tasks.named("assemble").configure {
dependsOn("sourcesJar")
}
}
tasks.named("check").configure {
dependsOn("checkstyleMain", "checkstyleTest")
}
applyCommonArtifactoryConfig()
configure<LicenseExtension> {
header = rootProject.file("HEADER.txt")
include("**/*.java")
}
}
fun Project.applyShadowConfiguration() {
tasks.named<ShadowJar>("shadowJar") {
archiveClassifier.set("dist")
dependencies {
include(project(":worldguard-libs:core"))
//include(project(":worldguard-libs:${project.name.replace("worldguard-", "")}"))
include(project(":worldguard-core"))
relocate("org.flywaydb", "com.sk89q.worldguard.internal.flywaydb") {
include(dependency("org.flywaydb:flyway-core:3.0"))
}
relocate("com.sk89q.squirrelid", "com.sk89q.worldguard.util.profile")
}
exclude("GradleStart**")
exclude(".cache")
exclude("LICENSE*")
}
}
+7
View File
@@ -0,0 +1,7 @@
object Versions {
// const val PISTON = "0.4.3"
// const val AUTO_VALUE = "1.6.5"
const val WORLDEDIT = "7.1.0-SNAPSHOT"
const val JUNIT = "4.11"
const val SQUIRRELID = "0.2.0"
}
+4 -8
View File
@@ -7,9 +7,11 @@
<module name="FileTabCharacter"/>
<module name="SuppressionFilter">
<property name="file" value="${basedir}/config/checkstyle/suppressions.xml"/>
<property name="file" value="${config_loc}/suppressions.xml"/>
</module>
<module name="TreeWalker">
<!-- Important basics -->
<!-- <module name="PackageDeclaration"/> Unlikely that we would miss this in a PR -->
@@ -20,7 +22,7 @@
It is a bit draconian, so update as necessary!
-->
<module name="ImportControl">
<property name="file" value="${basedir}/config/checkstyle/import-control.xml"/>
<property name="file" value="${config_loc}/import-control.xml"/>
</module>
<!-- Code -->
@@ -58,10 +60,4 @@
<!-- <module name="TypeName"/> Unlikely that we would miss this in a PR -->
</module>
<!-- Require the header, something that many people forget and we hate to fix -->
<!-- You should configure the header in your IDE -->
<module name="Header">
<property name="headerFile" value="${basedir}/config/checkstyle/header.txt"/>
<property name="fileExtensions" value="java"/>
</module>
</module>
-18
View File
@@ -1,18 +0,0 @@
/*
* WorldGuard, a suite of tools for Minecraft
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldGuard team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+8 -11
View File
@@ -16,24 +16,21 @@
<allow pkg="org.khelekore"/>
<allow pkg="org.flywaydb"/>
<allow pkg="org.yaml"/>
<allow pkg="org.json"/>
<allow pkg="org.enginehub.piston"/>
<subpackage name="util.profile.resolver">
<allow pkg="org.bukkit"/>
<allow pkg="io.papermc.lib"/>
<allow pkg="com.destroystokyo.paper"/>
</subpackage>
<subpackage name="bukkit">
<allow pkg="org.bukkit"/>
<allow pkg="org.bstats.bukkit"/>
<allow pkg="io.papermc.lib"/>
<allow pkg="com.destroystokyo.paper"/>
</subpackage>
<subpackage name="sponge">
<allow pkg="org.spongepowered"/>
<allow pkg="org.bstats.sponge"/>
<allow pkg="com.flowpowered"/>
</subpackage>
<subpackage name="forge">
<allow pkg="net.minecraft"/>
<allow pkg="net.minecraftforge"/>
</subpackage>
</subpackage>
</import-control>
+2
View File
@@ -0,0 +1,2 @@
group=com.sk89q.worldguard
version=7.0.3
+1 -1
View File
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.0-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-5.5.1-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-3
View File
@@ -1,3 +0,0 @@
rootProject.name = 'worldguard'
include 'worldguard-core', 'worldguard-bukkit'
+7
View File
@@ -0,0 +1,7 @@
rootProject.name = "worldguard"
include("worldguard-libs")
include("worldguard-libs:core")
include("worldguard-core")
//include("worldguard-libs:bukkit")
include("worldguard-bukkit")
-55
View File
@@ -1,55 +0,0 @@
apply plugin: 'eclipse'
apply plugin: 'idea'
repositories {
maven {
name = 'bstats repo'
url = 'https://repo.codemc.org/repository/maven-public'
}
}
dependencies {
compile project(path: ':worldguard-core', configuration: 'shadow')
api 'org.bukkit:bukkit:1.13-R0.1-SNAPSHOT'
api ('com.sk89q.worldedit:worldedit-bukkit:7.0.0-SNAPSHOT') {
exclude group: 'io.papermc', module: 'paperlib'
}
implementation ('com.sk89q:commandbook:2.3') {
exclude group: 'com.sk89q', module: 'worldedit'
exclude group: 'com.zachsthings.libcomponents'
exclude group: 'org.bukkit'
exclude group: 'net.sf.opencsv'
}
implementation 'org.bstats:bstats-bukkit:1.4'
}
processResources {
from (sourceSets.main.resources.srcDirs) {
expand project.properties
include 'plugin.yml'
}
from (sourceSets.main.resources.srcDirs) {
exclude 'plugin.yml'
}
}
jar {
manifest {
attributes("Implementation-Version": version)
}
}
shadowJar {
dependencies {
include(dependency(':worldguard-core'))
relocate ("org.bstats", "com.sk89q.worldguard.bukkit.bstats") {
include(dependency("org.bstats:bstats-bukkit:1.4"))
}
}
relocate('org.flywaydb', 'com.sk89q.worldguard.internal.flywaydb')
}
build.dependsOn(shadowJar)
+74
View File
@@ -0,0 +1,74 @@
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import org.gradle.api.internal.HasConvention
plugins {
id("java-library")
id("net.ltgt.apt-eclipse")
id("net.ltgt.apt-idea")
}
applyPlatformAndCoreConfiguration()
applyShadowConfiguration()
repositories {
maven {
name = "paper"
url = uri("https://papermc.io/repo/repository/maven-public/")
}
maven {
name = "bstats"
url = uri("https://repo.codemc.org/repository/maven-public")
}
}
dependencies {
"compile"(project(":worldguard-core"))
//"compile"(project(":worldguard-libs:bukkit"))
"api"("com.destroystokyo.paper:paper-api:1.15.2-R0.1-SNAPSHOT")
"implementation"("io.papermc:paperlib:1.0.4")
"api"("com.sk89q.worldedit:worldedit-bukkit:${Versions.WORLDEDIT}") { isTransitive = false }
"implementation"("com.sk89q:commandbook:2.3") { isTransitive = false }
"implementation"("org.bstats:bstats-bukkit:1.7")
}
tasks.named<Upload>("install") {
(repositories as HasConvention).convention.getPlugin<MavenRepositoryHandlerConvention>().mavenInstaller {
pom.whenConfigured {
dependencies.firstOrNull { dep ->
dep!!.withGroovyBuilder {
getProperty("groupId") == "com.destroystokyo.paper" && getProperty("artifactId") == "paper-api"
}
}?.withGroovyBuilder {
setProperty("groupId", "org.bukkit")
setProperty("artifactId", "bukkit")
}
}
}
}
tasks.named<Copy>("processResources") {
filesMatching("plugin.yml") {
expand("internalVersion" to project.ext["internalVersion"])
}
}
tasks.named<Jar>("jar") {
manifest {
attributes("Implementation-Version" to project.version)
}
}
tasks.named<ShadowJar>("shadowJar") {
dependencies {
relocate("org.bstats", "com.sk89q.worldguard.bukkit.bstats") {
include(dependency("org.bstats:bstats-bukkit:1.7"))
}
relocate ("io.papermc.lib", "com.sk89q.worldguard.bukkit.paperlib") {
include(dependency("io.papermc:paperlib:1.0.4"))
}
}
}
tasks.named("assemble").configure {
dependsOn("shadowJar")
}
@@ -26,6 +26,7 @@ import com.sk89q.worldguard.config.YamlConfigurationManager;
import com.sk89q.worldedit.util.report.Unreported;
import java.io.File;
import java.util.Collection;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
@@ -35,6 +36,7 @@ public class BukkitConfigurationManager extends YamlConfigurationManager {
@Unreported private ConcurrentMap<String, BukkitWorldConfiguration> worlds = new ConcurrentHashMap<>();
private boolean hasCommandBookGodMode;
boolean extraStats;
/**
* Construct the object.
@@ -46,6 +48,16 @@ public class BukkitConfigurationManager extends YamlConfigurationManager {
this.plugin = plugin;
}
public Collection<BukkitWorldConfiguration> getWorldConfigs() {
return worlds.values();
}
@Override
public void load() {
super.load();
this.extraStats = getConfig().getBoolean("custom-metrics-charts", true);
}
@Override
public File getDataFolder() {
return plugin.getDataFolder();
@@ -68,6 +80,7 @@ public class BukkitConfigurationManager extends YamlConfigurationManager {
for (World world : WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.GAME_HOOKS).getWorlds()) {
get(world);
}
getConfig().save();
}
/**
@@ -24,6 +24,9 @@ import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.world.weather.WeatherType;
import com.sk89q.worldedit.world.weather.WeatherTypes;
import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.WorldGuard;
import com.sk89q.worldguard.util.MessagingUtil;
import io.papermc.lib.PaperLib;
import org.bukkit.BanList.Type;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
@@ -120,7 +123,8 @@ public class BukkitPlayer extends com.sk89q.worldedit.bukkit.BukkitPlayer implem
@Override
public WeatherType getPlayerWeather() {
return null;
org.bukkit.WeatherType playerWeather = getPlayer().getPlayerWeather();
return playerWeather == null ? null : playerWeather == org.bukkit.WeatherType.CLEAR ? WeatherTypes.CLEAR : WeatherTypes.RAIN;
}
@Override
@@ -170,7 +174,32 @@ public class BukkitPlayer extends com.sk89q.worldedit.bukkit.BukkitPlayer implem
@Override
public void sendTitle(String title, String subtitle) {
getPlayer().sendTitle(title, subtitle, -1, -1, -1);
if (WorldGuard.getInstance().getPlatform().getGlobalStateManager().get(getWorld()).forceDefaultTitleTimes) {
getPlayer().sendTitle(title, subtitle, 10, 70, 20);
} else {
getPlayer().sendTitle(title, subtitle, -1, -1, -1);
}
}
@Override
public void resetFallDistance() {
getPlayer().setFallDistance(0);
}
@Override
public void teleport(Location location, String successMessage, String failMessage) {
PaperLib.teleportAsync(getPlayer(), BukkitAdapter.adapt(location))
.thenApply(success -> {
if (success) {
// The success message can be cleared via flag
if (!successMessage.isEmpty()) {
MessagingUtil.sendStringToChat(this, successMessage);
}
} else {
printError(failMessage);
}
return success;
});
}
@Override
@@ -97,6 +97,10 @@ public class BukkitRegionContainer extends RegionContainer {
Bukkit.getScheduler().scheduleSyncRepeatingTask(plugin, cache::invalidateAll, CACHE_INVALIDATION_INTERVAL, CACHE_INVALIDATION_INTERVAL);
}
public void shutdown() {
container.shutdown();
}
@Override
@Nullable
protected RegionManager load(World world) {
@@ -70,6 +70,7 @@ public class BukkitWorldConfiguration extends YamlWorldConfiguration {
public Set<PotionEffectType> blockPotions;
public TargetMatcherSet allowAllInteract;
public TargetMatcherSet blockUseAtFeet;
public boolean usePaperEntityOrigin;
/* Configuration data end */
/**
@@ -104,6 +105,13 @@ public class BukkitWorldConfiguration extends YamlWorldConfiguration {
if (inputs == null || inputs.isEmpty()) {
parentConfig.setProperty(node, new ArrayList<String>());
}
if (config.getProperty(node) != null) {
inputs = config.getStringList(node, null);
}
if (inputs == null || inputs.isEmpty()) {
return set;
}
@@ -143,6 +151,9 @@ public class BukkitWorldConfiguration extends YamlWorldConfiguration {
allowAllInteract = getTargetMatchers("event-handling.interaction-whitelist");
blockUseAtFeet = getTargetMatchers("event-handling.emit-block-use-at-feet");
ignoreHopperMoveEvents = getBoolean("event-handling.ignore-hopper-item-move-events", false);
breakDeniedHoppers = getBoolean("event-handling.break-hoppers-on-denied-move", true);
usePaperEntityOrigin = getBoolean("regions.use-paper-entity-origin", false);
itemDurability = getBoolean("protection.item-durability", true);
removeInfiniteStacks = getBoolean("protection.remove-infinite-stacks", false);
@@ -179,7 +190,7 @@ public class BukkitWorldConfiguration extends YamlWorldConfiguration {
blockTNTBlockDamage = getBoolean("ignition.block-tnt-block-damage", false);
blockLighter = getBoolean("ignition.block-lighter", false);
preventLavaFire = getBoolean("fire.disable-lava-fire-spread", true);
preventLavaFire = getBoolean("fire.disable-lava-fire-spread", false);
disableFireSpread = getBoolean("fire.disable-all-fire-spread", false);
disableFireSpreadBlocks = new HashSet<>(convertLegacyBlocks(getStringList("fire.disable-fire-spread-blocks", null)));
allowedLavaSpreadOver = new HashSet<>(convertLegacyBlocks(getStringList("fire.lava-spread-blocks", null)));
@@ -216,6 +227,7 @@ public class BukkitWorldConfiguration extends YamlWorldConfiguration {
teleportOnSuffocation = getBoolean("player-damage.teleport-on-suffocation", false);
disableVoidDamage = getBoolean("player-damage.disable-void-damage", false);
teleportOnVoid = getBoolean("player-damage.teleport-on-void-falling", false);
safeFallOnVoid = getBoolean("player-damage.reset-fall-on-void-teleport", false);
disableExplosionDamage = getBoolean("player-damage.disable-explosion-damage", false);
disableMobDamage = getBoolean("player-damage.disable-mob-damage", false);
disableDeathMessages = getBoolean("player-damage.disable-death-messages", false);
@@ -231,6 +243,7 @@ public class BukkitWorldConfiguration extends YamlWorldConfiguration {
disableThunder = getBoolean("weather.disable-thunderstorm", false);
disableWeather = getBoolean("weather.disable-weather", false);
disablePigZap = getBoolean("weather.disable-pig-zombification", false);
disableVillagerZap = getBoolean("weather.disable-villager-witchification", false);
disableCreeperPower = getBoolean("weather.disable-powered-creepers", false);
alwaysRaining = getBoolean("weather.always-raining", false);
alwaysThundering = getBoolean("weather.always-thundering", false);
@@ -246,12 +259,14 @@ public class BukkitWorldConfiguration extends YamlWorldConfiguration {
disableVineGrowth = getBoolean("dynamics.disable-vine-growth", false);
disableCropGrowth = getBoolean("dynamics.disable-crop-growth", false);
disableSoilDehydration = getBoolean("dynamics.disable-soil-dehydration", false);
disableCoralBlockFade = getBoolean("dynamics.disable-coral-block-fade", false);
allowedSnowFallOver = new HashSet<>(convertLegacyBlocks(getStringList("dynamics.snow-fall-blocks", null)));
useRegions = getBoolean("regions.enable", true);
regionInvinciblityRemovesMobs = getBoolean("regions.invincibility-removes-mobs", false);
regionCancelEmptyChatEvents = getBoolean("regions.cancel-chat-without-recipients", true);
regionNetherPortalProtection = getBoolean("regions.nether-portal-protection", false);
regionNetherPortalProtection = getBoolean("regions.nether-portal-protection", true);
forceDefaultTitleTimes = config.getBoolean("regions.titles-always-use-default-times", true); // note: technically not region-specific, but we only use it for the title flags
fakePlayerBuildOverride = getBoolean("regions.fake-player-build-override", true);
explosionFlagCancellation = getBoolean("regions.explosion-flags-block-entity-damage", true);
highFreqFlags = getBoolean("regions.high-frequency-flags", false);
@@ -19,12 +19,19 @@
package com.sk89q.worldguard.bukkit;
import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.bukkit.BukkitWorld;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.util.report.ReportList;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.gamemode.GameMode;
import com.sk89q.worldedit.world.gamemode.GameModes;
import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.WorldGuard;
import com.sk89q.worldguard.protection.regions.ProtectedCuboidRegion;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import com.sk89q.worldguard.util.profile.resolver.PaperProfileService;
import com.sk89q.worldguard.bukkit.protection.events.flags.FlagContextCreateEvent;
import com.sk89q.worldguard.bukkit.session.BukkitSessionManager;
import com.sk89q.worldguard.bukkit.util.report.PerformanceReport;
@@ -39,12 +46,21 @@ import com.sk89q.worldguard.internal.platform.WorldGuardPlatform;
import com.sk89q.worldguard.protection.flags.FlagContext;
import com.sk89q.worldguard.protection.regions.RegionContainer;
import com.sk89q.worldguard.session.SessionManager;
import com.sk89q.worldguard.util.profile.cache.ProfileCache;
import com.sk89q.worldguard.util.profile.resolver.BukkitPlayerService;
import com.sk89q.worldguard.util.profile.resolver.CacheForwardingService;
import com.sk89q.worldguard.util.profile.resolver.CombinedProfileService;
import com.sk89q.worldguard.util.profile.resolver.HttpRepositoryService;
import com.sk89q.worldguard.util.profile.resolver.ProfileService;
import io.papermc.lib.PaperLib;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.permissions.Permissible;
import javax.annotation.Nullable;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
@@ -130,7 +146,7 @@ public class BukkitWorldGuardPlatform implements WorldGuardPlatform {
@Override
public void unload() {
configuration.unload();
regionContainer.unload();
regionContainer.shutdown();
}
@Override
@@ -228,4 +244,36 @@ public class BukkitWorldGuardPlatform implements WorldGuardPlatform {
report.add(new WorldReport());
report.add(new PerformanceReport());
}
@Override
public ProfileService createProfileService(ProfileCache profileCache) {
List<ProfileService> services = new ArrayList<>();
if (PaperLib.isPaper()) {
// Paper has a shared cache
services.add(PaperProfileService.getInstance());
} else {
services.add(BukkitPlayerService.getInstance());
}
services.add(HttpRepositoryService.forMinecraft());
return new CacheForwardingService(new CombinedProfileService(services),
profileCache);
}
@Nullable
@Override
public ProtectedRegion getSpawnProtection(World world) {
if (world instanceof BukkitWorld) {
org.bukkit.World bWorld = ((BukkitWorld) world).getWorld();
if (bWorld.getUID().equals(Bukkit.getServer().getWorlds().get(0).getUID())) {
int radius = Bukkit.getServer().getSpawnRadius();
if (radius > 0) {
BlockVector3 spawnLoc = BukkitAdapter.asBlockVector(bWorld.getSpawnLocation());
return new ProtectedCuboidRegion("__spawn_protection__",
spawnLoc.subtract(radius, 0, radius).withY(world.getMinimumPoint().getY()),
spawnLoc.add(radius, 0, radius).withY(world.getMaxY()));
}
}
}
return null;
}
}
@@ -35,9 +35,7 @@ import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.WorldGuard;
import com.sk89q.worldguard.commands.GeneralCommands;
import com.sk89q.worldguard.commands.ProtectionCommands;
import com.sk89q.worldguard.commands.ToggleCommands;
import com.sk89q.worldguard.blacklist.Blacklist;
import com.sk89q.worldguard.bukkit.event.player.ProcessPlayerEvent;
import com.sk89q.worldguard.bukkit.listener.BlacklistListener;
import com.sk89q.worldguard.bukkit.listener.BlockedPotionsListener;
@@ -63,8 +61,16 @@ import com.sk89q.worldguard.bukkit.listener.WorldRulesListener;
import com.sk89q.worldguard.bukkit.session.BukkitSessionManager;
import com.sk89q.worldguard.bukkit.util.Events;
import com.sk89q.worldguard.bukkit.util.logging.ClassSourceValidator;
import com.sk89q.worldguard.commands.GeneralCommands;
import com.sk89q.worldguard.commands.ProtectionCommands;
import com.sk89q.worldguard.commands.ToggleCommands;
import com.sk89q.worldguard.protection.flags.Flag;
import com.sk89q.worldguard.protection.flags.Flags;
import com.sk89q.worldguard.protection.flags.registry.SimpleFlagRegistry;
import com.sk89q.worldguard.protection.managers.RegionManager;
import com.sk89q.worldguard.protection.managers.storage.RegionDriver;
import com.sk89q.worldguard.protection.managers.storage.file.DirectoryYamlDriver;
import com.sk89q.worldguard.protection.managers.storage.sql.SQLDriver;
import com.sk89q.worldguard.protection.regions.ProtectedCuboidRegion;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import com.sk89q.worldguard.util.logging.RecordMessagePrefixer;
@@ -84,9 +90,10 @@ import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.jar.JarFile;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.zip.ZipEntry;
/**
* The main class for WorldGuard as a Bukkit plugin.
@@ -205,7 +212,51 @@ public class WorldGuardPlugin extends JavaPlugin {
((SimpleFlagRegistry) WorldGuard.getInstance().getFlagRegistry()).setInitialized(true);
// Enable metrics
new Metrics(this);
final Metrics metrics = new Metrics(this, 3283); // bStats plugin id
if (metrics.isEnabled() && platform.getGlobalStateManager().extraStats) {
setupCustomCharts(metrics);
}
}
private void setupCustomCharts(Metrics metrics) {
metrics.addCustomChart(new Metrics.SingleLineChart("region_count", () ->
platform.getRegionContainer().getLoaded().stream().mapToInt(RegionManager::size).sum()));
metrics.addCustomChart(new Metrics.SimplePie("region_driver", () -> {
RegionDriver driver = platform.getGlobalStateManager().selectedRegionStoreDriver;
return driver instanceof DirectoryYamlDriver ? "yaml" : driver instanceof SQLDriver ? "sql" : "unknown";
}));
metrics.addCustomChart(new Metrics.DrilldownPie("blacklist", () -> {
int empty = 0;
Map<String, Integer> blacklistMap = new HashMap<>();
Map<String, Integer> whitelistMap = new HashMap<>();
for (BukkitWorldConfiguration worldConfig : platform.getGlobalStateManager().getWorldConfigs()) {
Blacklist blacklist = worldConfig.getBlacklist();
if (blacklist != null && !blacklist.isEmpty()) {
Map<String, Integer> target = blacklist.isWhitelist() ? whitelistMap : blacklistMap;
int floor = ((blacklist.getItemCount() - 1) / 10) * 10;
String range = floor >= 100 ? "101+" : (floor + 1) + " - " + (floor + 10);
target.merge(range, 1, Integer::sum);
} else {
empty++;
}
}
Map<String, Map<String, Integer>> blacklistCounts = new HashMap<>();
Map<String, Integer> emptyMap = new HashMap<>();
emptyMap.put("empty", empty);
blacklistCounts.put("empty", emptyMap);
blacklistCounts.put("blacklist", blacklistMap);
blacklistCounts.put("whitelist", whitelistMap);
return blacklistCounts;
}));
metrics.addCustomChart(new Metrics.SimplePie("chest_protection", () ->
"" + platform.getGlobalStateManager().getWorldConfigs().stream().anyMatch(cfg -> cfg.signChestProtection)));
metrics.addCustomChart(new Metrics.SimplePie("build_permissions", () ->
"" + platform.getGlobalStateManager().getWorldConfigs().stream().anyMatch(cfg -> cfg.buildPermissions)));
metrics.addCustomChart(new Metrics.SimplePie("custom_flags", () ->
"" + (WorldGuard.getInstance().getFlagRegistry().size() > Flags.INBUILT_FLAGS.size())));
metrics.addCustomChart(new Metrics.SimplePie("custom_handlers", () ->
"" + (WorldGuard.getInstance().getPlatform().getSessionManager().customHandlersRegistered())));
}
@Override
@@ -435,44 +486,25 @@ public class WorldGuardPlugin extends JavaPlugin {
return;
}
InputStream input = null;
try {
JarFile file = new JarFile(getFile());
ZipEntry copy = file.getEntry("defaults/" + defaultName);
if (copy == null) throw new FileNotFoundException();
input = file.getInputStream(copy);
try (InputStream stream = getResource("defaults/" + defaultName)){
if (stream == null) throw new FileNotFoundException();
copyDefaultConfig(stream, actual, defaultName);
} catch (IOException e) {
WorldGuard.logger.severe("Unable to read default configuration: " + defaultName);
getLogger().severe("Unable to read default configuration: " + defaultName);
}
if (input != null) {
FileOutputStream output = null;
}
try {
output = new FileOutputStream(actual);
byte[] buf = new byte[8192];
int length = 0;
while ((length = input.read(buf)) > 0) {
output.write(buf, 0, length);
}
WorldGuard.logger.info("Default configuration file written: "
+ actual.getAbsolutePath());
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
input.close();
} catch (IOException ignore) {
}
try {
if (output != null) {
output.close();
}
} catch (IOException ignore) {
}
private void copyDefaultConfig(InputStream input, File actual, String name) {
try (FileOutputStream output = new FileOutputStream(actual)) {
byte[] buf = new byte[8192];
int length;
while ((length = input.read(buf)) > 0) {
output.write(buf, 0, length);
}
getLogger().info("Default configuration file written: " + name);
} catch (IOException e) {
getLogger().log(Level.WARNING, "Failed to write default config file", e);
}
}
@@ -22,15 +22,28 @@ package com.sk89q.worldguard.bukkit.cause;
import com.google.common.base.Joiner;
import com.google.common.collect.Sets;
import com.sk89q.worldguard.bukkit.internal.WGMetadata;
import io.papermc.lib.PaperLib;
import org.bukkit.Bukkit;
import org.bukkit.block.Block;
import org.bukkit.entity.*;
import org.bukkit.entity.AreaEffectCloud;
import org.bukkit.entity.Creature;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Firework;
import org.bukkit.entity.Player;
import org.bukkit.entity.Projectile;
import org.bukkit.entity.TNTPrimed;
import org.bukkit.entity.Tameable;
import org.bukkit.entity.Vehicle;
import org.bukkit.metadata.Metadatable;
import org.bukkit.projectiles.BlockProjectileSource;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import static com.google.common.base.Preconditions.checkNotNull;
@@ -224,6 +237,15 @@ public final class Cause {
WGMetadata.put(target, CAUSE_KEY, parent);
}
/**
* Remove a parent cause from a {@code Metadatable} object.
*
* @param target the target
*/
public static void untrackParentCause(Metadatable target) {
WGMetadata.remove(target, CAUSE_KEY);
}
/**
* Builds causes.
*/
@@ -249,17 +271,27 @@ public final class Cause {
addAll(((TNTPrimed) o).getSource());
} else if (o instanceof Projectile) {
addAll(((Projectile) o).getShooter());
} else if (o instanceof Firework && PaperLib.isPaper()) {
UUID spawningUUID = ((Firework) o).getSpawningEntity();
if (spawningUUID != null) {
Entity spawningEntity = Bukkit.getEntity(spawningUUID);
if (spawningEntity != null) {
addAll(spawningEntity);
}
}
} else if (o instanceof Vehicle) {
addAll(((Vehicle) o).getPassengers());
((Vehicle) o).getPassengers().forEach(this::addAll);
} else if (o instanceof AreaEffectCloud) {
indirect = true;
addAll(((AreaEffectCloud) o).getSource());
} else if (o instanceof Creature && ((Creature) o).getTarget() != null) {
indirect = true;
addAll(((Creature) o).getTarget());
} else if (o instanceof Tameable) {
indirect = true;
addAll(((Tameable) o).getOwner());
} else if (o instanceof Creature && ((Creature) o).getTarget() != null) {
indirect = true;
addAll(((Creature) o).getTarget());
} else if (o instanceof BlockProjectileSource) {
addAll(((BlockProjectileSource) o).getBlock());
}
// Add manually tracked parent causes
@@ -19,6 +19,7 @@
package com.sk89q.worldguard.bukkit.event.block;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import com.sk89q.worldguard.bukkit.cause.Cause;
@@ -28,12 +29,15 @@ import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.event.Event;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
@@ -44,7 +48,8 @@ import javax.annotation.Nullable;
abstract class AbstractBlockEvent extends DelegateEvent implements BulkEvent {
private final World world;
private final List<Block> blocks;
private List<Block> blocks;
private final List<BlockState> blockStates;
private final Material effectiveMaterial;
protected AbstractBlockEvent(@Nullable Event originalEvent, Cause cause, World world, List<Block> blocks, Material effectiveMaterial) {
@@ -55,6 +60,18 @@ abstract class AbstractBlockEvent extends DelegateEvent implements BulkEvent {
this.world = world;
this.blocks = blocks;
this.effectiveMaterial = effectiveMaterial;
this.blockStates = null;
}
protected AbstractBlockEvent(@Nullable Event originalEvent, Cause cause, World world, List<BlockState> blocks) {
super(originalEvent, cause);
checkNotNull(world);
checkNotNull(blocks);
checkArgument(!blocks.isEmpty());
this.world = world;
this.blockStates = blocks;
this.blocks = null;
this.effectiveMaterial = blocks.get(0).getType();
}
protected AbstractBlockEvent(@Nullable Event originalEvent, Cause cause, Block block) {
@@ -86,6 +103,9 @@ abstract class AbstractBlockEvent extends DelegateEvent implements BulkEvent {
* @return a list of affected block
*/
public List<Block> getBlocks() {
if (blocks == null) { // be lazy here because we often don't call getBlocks internally, just filter
blocks = blockStates.stream().map(BlockState::getBlock).collect(Collectors.toList());
}
return blocks;
}
@@ -99,15 +119,21 @@ abstract class AbstractBlockEvent extends DelegateEvent implements BulkEvent {
* @return true if one or more blocks were filtered out
*/
public boolean filter(Predicate<Location> predicate, boolean cancelEventOnFalse) {
boolean hasRemoval = false;
return blocks == null
? filterInternal(blockStates, BlockState::getLocation, predicate, cancelEventOnFalse)
: filterInternal(blocks, Block::getLocation, predicate, cancelEventOnFalse);
}
Iterator<Block> it = blocks.iterator();
private <B> boolean filterInternal(List<B> blockList, Function<B, Location> locFunc,
Predicate<Location> predicate, boolean cancelEventOnFalse) {
boolean hasRemoval = false;
Iterator<B> it = blockList.iterator();
while (it.hasNext()) {
if (!predicate.test(it.next().getLocation())) {
if (!predicate.test(locFunc.apply(it.next()))) {
hasRemoval = true;
if (cancelEventOnFalse) {
getBlocks().clear();
blockList.clear();
setCancelled(true);
break;
} else {
@@ -115,7 +141,6 @@ abstract class AbstractBlockEvent extends DelegateEvent implements BulkEvent {
}
}
}
return hasRemoval;
}
@@ -147,7 +172,7 @@ abstract class AbstractBlockEvent extends DelegateEvent implements BulkEvent {
@Override
public Result getResult() {
if (blocks.isEmpty()) {
if (blocks == null ? blockStates.isEmpty() : blocks.isEmpty()) {
return Result.DENY;
}
return super.getResult();
@@ -24,6 +24,7 @@ import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
@@ -40,6 +41,10 @@ public class PlaceBlockEvent extends AbstractBlockEvent {
private static final HandlerList handlers = new HandlerList();
public PlaceBlockEvent(@Nullable Event originalEvent, Cause cause, World world, List<BlockState> blocks) {
super(originalEvent, cause, world, blocks);
}
public PlaceBlockEvent(@Nullable Event originalEvent, Cause cause, World world, List<Block> blocks, Material effectiveMaterial) {
super(originalEvent, cause, world, blocks, effectiveMaterial);
}
@@ -75,4 +75,13 @@ public final class WGMetadata {
return null;
}
/**
* Removes metadata from the target.
*
* @param target the target
* @param key the key
*/
public static void remove(Metadatable target, String key) {
target.removeMetadata(key, WorldGuardPlugin.inst());
}
}
@@ -21,12 +21,26 @@ package com.sk89q.worldguard.bukkit.listener;
import static com.google.common.base.Preconditions.checkNotNull;
import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.WorldGuard;
import com.sk89q.worldguard.bukkit.BukkitWorldConfiguration;
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
import com.sk89q.worldguard.bukkit.cause.Cause;
import com.sk89q.worldguard.config.ConfigurationManager;
import com.sk89q.worldguard.config.WorldConfiguration;
import com.sk89q.worldguard.domains.Association;
import com.sk89q.worldguard.protection.DelayedRegionOverlapAssociation;
import com.sk89q.worldguard.protection.association.Associables;
import com.sk89q.worldguard.protection.association.RegionAssociable;
import com.sk89q.worldguard.protection.regions.RegionQuery;
import io.papermc.lib.PaperLib;
import org.bukkit.Location;
import org.bukkit.OfflinePlayer;
import org.bukkit.block.Block;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.event.Listener;
/**
@@ -67,7 +81,7 @@ class AbstractListener implements Listener {
*
* @return the configuration
*/
protected ConfigurationManager getConfig() {
protected static ConfigurationManager getConfig() {
return WorldGuard.getInstance().getPlatform().getGlobalStateManager();
}
@@ -77,7 +91,7 @@ class AbstractListener implements Listener {
* @param world The world to get the configuration for.
* @return The configuration for {@code world}
*/
protected WorldConfiguration getWorldConfig(World world) {
protected static WorldConfiguration getWorldConfig(World world) {
return getConfig().get(world);
}
@@ -87,7 +101,7 @@ class AbstractListener implements Listener {
* @param player The player to get the wold from
* @return The {@link WorldConfiguration} for the player's world
*/
protected WorldConfiguration getWorldConfig(LocalPlayer player) {
protected static WorldConfiguration getWorldConfig(LocalPlayer player) {
return getWorldConfig((World) player.getExtent());
}
@@ -97,8 +111,38 @@ class AbstractListener implements Listener {
* @param world the world
* @return true if region support is enabled
*/
protected boolean isRegionSupportEnabled(World world) {
protected static boolean isRegionSupportEnabled(World world) {
return getWorldConfig(world).useRegions;
}
protected RegionAssociable createRegionAssociable(Cause cause) {
Object rootCause = cause.getRootCause();
if (!cause.isKnown()) {
return Associables.constant(Association.NON_MEMBER);
} else if (rootCause instanceof Player) {
return getPlugin().wrapPlayer((Player) rootCause);
} else if (rootCause instanceof OfflinePlayer) {
return getPlugin().wrapOfflinePlayer((OfflinePlayer) rootCause);
} else if (rootCause instanceof Entity) {
RegionQuery query = WorldGuard.getInstance().getPlatform().getRegionContainer().createQuery();
final Entity entity = (Entity) rootCause;
Location loc;
if (PaperLib.isPaper()
&& ((BukkitWorldConfiguration) getWorldConfig(BukkitAdapter.adapt(entity.getWorld()))).usePaperEntityOrigin) {
loc = entity.getOrigin();
if (loc == null) {
loc = entity.getLocation();
}
} else {
loc = entity.getLocation();
}
return new DelayedRegionOverlapAssociation(query, BukkitAdapter.adapt(loc));
} else if (rootCause instanceof Block) {
RegionQuery query = WorldGuard.getInstance().getPlatform().getRegionContainer().createQuery();
return new DelayedRegionOverlapAssociation(query, BukkitAdapter.adapt(((Block) rootCause).getLocation()));
} else {
return Associables.constant(Association.NON_MEMBER);
}
}
}
@@ -19,8 +19,6 @@
package com.sk89q.worldguard.bukkit.listener;
import static com.sk89q.worldguard.bukkit.BukkitUtil.createTarget;
import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.WorldGuard;
@@ -31,6 +29,7 @@ import com.sk89q.worldguard.blacklist.event.BlockPlaceBlacklistEvent;
import com.sk89q.worldguard.blacklist.event.ItemAcquireBlacklistEvent;
import com.sk89q.worldguard.blacklist.event.ItemDestroyWithBlacklistEvent;
import com.sk89q.worldguard.blacklist.event.ItemDropBlacklistEvent;
import com.sk89q.worldguard.blacklist.event.ItemEquipBlacklistEvent;
import com.sk89q.worldguard.blacklist.event.ItemUseBlacklistEvent;
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
import com.sk89q.worldguard.bukkit.event.block.BreakBlockEvent;
@@ -47,16 +46,21 @@ import org.bukkit.entity.Entity;
import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Item;
import org.bukkit.entity.Player;
import org.bukkit.event.Event;
import org.bukkit.event.EventHandler;
import org.bukkit.event.block.BlockDispenseArmorEvent;
import org.bukkit.event.block.BlockDispenseEvent;
import org.bukkit.event.inventory.InventoryAction;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryCreativeEvent;
import org.bukkit.event.inventory.InventoryDragEvent;
import org.bukkit.event.inventory.InventoryType;
import org.bukkit.event.player.PlayerDropItemEvent;
import org.bukkit.event.player.PlayerItemHeldEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import static com.sk89q.worldguard.bukkit.BukkitUtil.createTarget;
/**
* Handle events that need to be processed by the blacklist.
*/
@@ -89,10 +93,12 @@ public class BlacklistListener extends AbstractListener {
event.filter(target -> {
if (!wcfg.getBlacklist().check(
new BlockBreakBlacklistEvent(localPlayer, BukkitAdapter.asBlockVector(target), createTarget(target.getBlock(), event.getEffectiveMaterial())), false, false)) {
new BlockBreakBlacklistEvent(localPlayer, BukkitAdapter.asBlockVector(target),
createTarget(target.getBlock(), event.getEffectiveMaterial())), false, false)) {
return false;
} else if (!wcfg.getBlacklist().check(
new ItemDestroyWithBlacklistEvent(localPlayer, BukkitAdapter.asBlockVector(target), createTarget(player.getItemInHand())), false, false)) {
new ItemDestroyWithBlacklistEvent(localPlayer, BukkitAdapter.asBlockVector(target),
createTarget(player.getInventory().getItemInMainHand())), false, false)) {
return false;
}
@@ -122,9 +128,6 @@ public class BlacklistListener extends AbstractListener {
@EventHandler(ignoreCancelled = true)
public void onUseBlock(final UseBlockEvent event) {
if (event.getResult() == Event.Result.ALLOW) {
return;
}
Player player = event.getCause().getFirstPlayer();
if (player == null) {
@@ -161,7 +164,8 @@ public class BlacklistListener extends AbstractListener {
Material material = Materials.getRelatedMaterial(event.getEffectiveType());
if (material != null) {
if (!wcfg.getBlacklist().check(new ItemUseBlacklistEvent(localPlayer, BukkitAdapter.asBlockVector(event.getTarget()), createTarget(material)), false, false)) {
if (!wcfg.getBlacklist().check(new ItemUseBlacklistEvent(
localPlayer, BukkitAdapter.asBlockVector(event.getTarget()), createTarget(material)), false, false)) {
event.setCancelled(true);
}
}
@@ -197,7 +201,8 @@ public class BlacklistListener extends AbstractListener {
Material material = Materials.getRelatedMaterial(target.getType());
if (material != null) {
// Not really a block but we only have one on-break blacklist event
if (!wcfg.getBlacklist().check(new BlockBreakBlacklistEvent(localPlayer, BukkitAdapter.asBlockVector(event.getTarget()), createTarget(material)), false, false)) {
if (!wcfg.getBlacklist().check(new BlockBreakBlacklistEvent(
localPlayer, BukkitAdapter.asBlockVector(event.getTarget()), createTarget(material)), false, false)) {
event.setCancelled(true);
}
}
@@ -220,7 +225,14 @@ public class BlacklistListener extends AbstractListener {
return;
}
if (!wcfg.getBlacklist().check(new ItemUseBlacklistEvent(localPlayer, BukkitAdapter.asBlockVector(player.getLocation()), createTarget(target)), false, false)) {
if (!wcfg.getBlacklist().check(new ItemUseBlacklistEvent(
localPlayer, BukkitAdapter.asBlockVector(player.getLocation()), createTarget(target)), false, false)) {
event.setCancelled(true);
return;
}
if (Materials.isArmor(target.getType()) && !wcfg.getBlacklist().check(new ItemEquipBlacklistEvent(
localPlayer, BukkitAdapter.asBlockVector(player.getLocation()), createTarget(target)), false, false)) {
event.setCancelled(true);
}
}
@@ -257,10 +269,11 @@ public class BlacklistListener extends AbstractListener {
@EventHandler(ignoreCancelled = true)
public void onInventoryClick(InventoryClickEvent event) {
HumanEntity entity = event.getWhoClicked();
if (!(entity instanceof Player)) return;
Inventory inventory = event.getInventory();
ItemStack item = event.getCurrentItem();
if (item != null && inventory != null && inventory.getHolder() != null && entity instanceof Player) {
if (item != null && inventory.getHolder() != null) {
Player player = (Player) entity;
ConfigurationManager cfg = WorldGuard.getInstance().getPlatform().getGlobalStateManager();
WorldConfiguration wcfg = cfg.get(BukkitAdapter.adapt(entity.getWorld()));
@@ -274,15 +287,67 @@ public class BlacklistListener extends AbstractListener {
event.setCurrentItem(null);
}
}
ItemStack equipped = checkEquipped(event);
if (equipped != null) {
if (wcfg.getBlacklist() != null && !wcfg.getBlacklist().check(new ItemEquipBlacklistEvent(localPlayer,
BukkitAdapter.asBlockVector(player.getLocation()), createTarget(equipped)), false, false)) {
event.setCancelled(true);
}
}
}
}
@EventHandler(ignoreCancelled = true)
public void onInventoryDrag(InventoryDragEvent event) {
HumanEntity entity = event.getWhoClicked();
if (!(entity instanceof Player)) return;
if (event.getInventory().getType() != InventoryType.PLAYER
&& event.getInventory().getType() != InventoryType.CRAFTING) return;
if (event.getRawSlots().stream().anyMatch(i -> i >= 5 && i <= 8)) { // dropped on armor slots
Player player = (Player) entity;
ConfigurationManager cfg = WorldGuard.getInstance().getPlatform().getGlobalStateManager();
WorldConfiguration wcfg = cfg.get(BukkitAdapter.adapt(entity.getWorld()));
LocalPlayer localPlayer = getPlugin().wrapPlayer(player);
if (wcfg.getBlacklist() != null && !wcfg.getBlacklist().check(new ItemEquipBlacklistEvent(localPlayer,
BukkitAdapter.asBlockVector(player.getLocation()), createTarget(event.getOldCursor())), false, false)) {
event.setCancelled(true);
}
}
}
private ItemStack checkEquipped(InventoryClickEvent event) {
final Inventory clickedInventory = event.getClickedInventory();
if (event.getSlotType() == InventoryType.SlotType.ARMOR) {
switch (event.getAction()) {
case PLACE_ONE:
case PLACE_SOME:
case PLACE_ALL:
case SWAP_WITH_CURSOR:
final ItemStack cursor = event.getCursor();
if (cursor != null) {
return cursor;
}
case HOTBAR_SWAP:
return clickedInventory == null ? null : clickedInventory.getItem(event.getHotbarButton());
default:
break;
}
} else if (clickedInventory != null && clickedInventory.getType() == InventoryType.PLAYER
&& event.getView().getTopInventory().getType() == InventoryType.PLAYER
&& event.getAction() == InventoryAction.MOVE_TO_OTHER_INVENTORY) {
return event.getCurrentItem();
}
return null;
}
@EventHandler(ignoreCancelled = true)
public void onInventoryCreative(InventoryCreativeEvent event) {
HumanEntity entity = event.getWhoClicked();
ItemStack item = event.getCursor();
if (item != null && entity instanceof Player) {
if (item.getType() != Material.AIR && entity instanceof Player) {
Player player = (Player) entity;
ConfigurationManager cfg = WorldGuard.getInstance().getPlatform().getGlobalStateManager();
WorldConfiguration wcfg = cfg.get(BukkitAdapter.adapt(entity.getWorld()));
@@ -291,7 +356,6 @@ public class BlacklistListener extends AbstractListener {
if (wcfg.getBlacklist() != null && !wcfg.getBlacklist().check(
new ItemAcquireBlacklistEvent(localPlayer, BukkitAdapter.asBlockVector(entity.getLocation()), createTarget(item)), false, false)) {
event.setCancelled(true);
event.setCursor(null);
}
}
}
@@ -314,4 +378,18 @@ public class BlacklistListener extends AbstractListener {
}
}
@EventHandler(ignoreCancelled = true)
public void onBlockDispenseArmor(BlockDispenseArmorEvent event) {
if (!(event.getTargetEntity() instanceof Player)) return;
Player player = ((Player) event.getTargetEntity());
ItemStack stack = event.getItem();
ConfigurationManager cfg = WorldGuard.getInstance().getPlatform().getGlobalStateManager();
WorldConfiguration wcfg = cfg.get(BukkitAdapter.adapt(player.getWorld()));
LocalPlayer localPlayer = getPlugin().wrapPlayer(player);
if (wcfg.getBlacklist() != null && !wcfg.getBlacklist().check(
new ItemEquipBlacklistEvent(localPlayer, BukkitAdapter.asBlockVector(player.getLocation()), createTarget(stack)), false, true)) {
event.setCancelled(true);
}
}
}
@@ -22,21 +22,20 @@ package com.sk89q.worldguard.bukkit.listener;
import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldguard.WorldGuard;
import com.sk89q.worldguard.bukkit.BukkitWorldConfiguration;
import com.sk89q.worldguard.config.ConfigurationManager;
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
import com.sk89q.worldguard.bukkit.event.entity.DamageEntityEvent;
import com.sk89q.worldguard.bukkit.event.inventory.UseItemEvent;
import com.sk89q.worldguard.bukkit.util.Entities;
import com.sk89q.worldguard.config.ConfigurationManager;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.entity.Arrow;
import org.bukkit.entity.Player;
import org.bukkit.entity.SpectralArrow;
import org.bukkit.entity.TippedArrow;
import org.bukkit.event.EventHandler;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.PotionMeta;
import org.bukkit.potion.Potion;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
@@ -66,8 +65,8 @@ public class BlockedPotionsListener extends AbstractListener {
if (wcfg.blockPotions.contains(PotionEffectType.GLOWING)) {
blockedEffect = PotionEffectType.GLOWING;
}
} else if (originalEvent.getDamager() instanceof TippedArrow) {
TippedArrow tippedArrow = (TippedArrow) originalEvent.getDamager();
} else if (originalEvent.getDamager() instanceof Arrow) {
Arrow tippedArrow = (Arrow) originalEvent.getDamager();
PotionEffectType baseEffect = tippedArrow.getBasePotionData().getType().getEffectType();
if (wcfg.blockPotions.contains(baseEffect)) {
blockedEffect = baseEffect;
@@ -101,24 +100,12 @@ public class BlockedPotionsListener extends AbstractListener {
BukkitWorldConfiguration wcfg = (BukkitWorldConfiguration) cfg.get(BukkitAdapter.adapt(event.getWorld()));
ItemStack item = event.getItemStack();
// We only care about potions
boolean oldPotions = false;
try {
if (item.getType() != Material.POTION
&& item.getType() != Material.SPLASH_POTION
&& item.getType() != Material.LINGERING_POTION) {
return;
}
} catch (NoSuchFieldError ignored) {
// PotionMeta technically has been around since 1.7, so the code below
// *should* work still. we just have different materials now.
if (item.getType() != Material.POTION) {
return;
}
oldPotions = true;
if (item.getType() != Material.POTION
&& item.getType() != Material.SPLASH_POTION
&& item.getType() != Material.LINGERING_POTION) {
return;
}
if (!wcfg.blockPotions.isEmpty()) {
PotionEffectType blockedEffect = null;
@@ -149,13 +136,8 @@ public class BlockedPotionsListener extends AbstractListener {
if (player != null) {
if (getPlugin().hasPermission(player, "worldguard.override.potions")) {
boolean isSplash = false;
try {
isSplash = (!oldPotions && (item.getType() == Material.SPLASH_POTION || item.getType() == Material.LINGERING_POTION));
} catch (NoSuchFieldError ignored) {
}
isSplash |= (oldPotions && (Potion.fromItemStack(item).isSplash()));
if (isSplash && wcfg.blockPotionsAlways) {
if (wcfg.blockPotionsAlways && (item.getType() == Material.SPLASH_POTION
|| item.getType() == Material.LINGERING_POTION)) {
player.sendMessage(ChatColor.RED + "Sorry, potions with " +
blockedEffect.getName() + " can't be thrown, " +
"even if you have a permission to bypass it, " +
@@ -29,6 +29,7 @@ import com.sk89q.worldguard.bukkit.event.block.PlaceBlockEvent;
import com.sk89q.worldguard.bukkit.event.block.UseBlockEvent;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.Tag;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.block.SignChangeEvent;
@@ -135,7 +136,7 @@ public class ChestProtectionListener extends AbstractListener {
BukkitWorldConfiguration wcfg = (BukkitWorldConfiguration) getWorldConfig(WorldGuardPlugin.inst().wrapPlayer(player));
if (wcfg.signChestProtection) {
if (event.getLine(0).equalsIgnoreCase("[Lock]")) {
if ("[Lock]".equalsIgnoreCase(event.getLine(0))) {
if (wcfg.isChestProtectedPlacement(BukkitAdapter.adapt(event.getBlock().getLocation()), WorldGuardPlugin.inst().wrapPlayer(player))) {
player.sendMessage(ChatColor.DARK_RED + "You do not own the adjacent chest.");
event.getBlock().breakNaturally();
@@ -143,7 +144,7 @@ public class ChestProtectionListener extends AbstractListener {
return;
}
if (event.getBlock().getType() != Material.SIGN) {
if (!Tag.STANDING_SIGNS.isTagged(event.getBlock().getType())) {
player.sendMessage(ChatColor.RED
+ "The [Lock] sign must be a sign post, not a wall sign.");
@@ -152,7 +153,7 @@ public class ChestProtectionListener extends AbstractListener {
return;
}
if (!event.getLine(1).equalsIgnoreCase(player.getName())) {
if (!player.getName().equalsIgnoreCase(event.getLine(1))) {
player.sendMessage(ChatColor.RED
+ "The first owner line must be your name.");
@@ -164,7 +165,7 @@ public class ChestProtectionListener extends AbstractListener {
Material below = event.getBlock().getRelative(0, -1, 0).getType();
if (below == Material.TNT || below == Material.SAND
|| below == Material.GRAVEL || below == Material.SIGN) {
|| below == Material.GRAVEL || Tag.STANDING_SIGNS.isTagged(below)) {
player.sendMessage(ChatColor.RED
+ "That is not a safe block that you're putting this sign on.");
@@ -178,7 +179,7 @@ public class ChestProtectionListener extends AbstractListener {
+ "A chest or double chest above is now protected.");
}
} else if (!wcfg.disableSignChestProtectionCheck) {
if (event.getLine(0).equalsIgnoreCase("[Lock]")) {
if ("[Lock]".equalsIgnoreCase(event.getLine(0))) {
player.sendMessage(ChatColor.RED
+ "WorldGuard's sign chest protection is disabled.");
@@ -21,7 +21,6 @@ package com.sk89q.worldguard.bukkit.listener;
import static com.sk89q.worldguard.bukkit.cause.Cause.create;
import com.google.common.collect.Lists;
import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldguard.WorldGuard;
import com.sk89q.worldguard.bukkit.BukkitWorldConfiguration;
@@ -59,21 +58,27 @@ import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.BlockState;
import org.bukkit.block.Chest;
import org.bukkit.block.Container;
import org.bukkit.block.DoubleChest;
import org.bukkit.block.Dropper;
import org.bukkit.block.Hopper;
import org.bukkit.block.PistonMoveReaction;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.Waterlogged;
import org.bukkit.block.data.type.Dispenser;
import org.bukkit.entity.AreaEffectCloud;
import org.bukkit.entity.Creeper;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.FallingBlock;
import org.bukkit.entity.Firework;
import org.bukkit.entity.Item;
import org.bukkit.entity.LingeringPotion;
import org.bukkit.entity.ItemFrame;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Mob;
import org.bukkit.entity.Painting;
import org.bukkit.entity.Player;
import org.bukkit.entity.Tameable;
import org.bukkit.entity.ThrownPotion;
import org.bukkit.entity.minecart.HopperMinecart;
import org.bukkit.event.Cancellable;
import org.bukkit.event.Event;
import org.bukkit.event.Event.Result;
@@ -85,12 +90,14 @@ import org.bukkit.event.block.BlockDamageEvent;
import org.bukkit.event.block.BlockDispenseEvent;
import org.bukkit.event.block.BlockExpEvent;
import org.bukkit.event.block.BlockExplodeEvent;
import org.bukkit.event.block.BlockFertilizeEvent;
import org.bukkit.event.block.BlockFromToEvent;
import org.bukkit.event.block.BlockIgniteEvent;
import org.bukkit.event.block.BlockMultiPlaceEvent;
import org.bukkit.event.block.BlockPistonExtendEvent;
import org.bukkit.event.block.BlockPistonRetractEvent;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.block.CauldronLevelChangeEvent;
import org.bukkit.event.block.EntityBlockFormEvent;
import org.bukkit.event.block.SignChangeEvent;
import org.bukkit.event.entity.AreaEffectCloudApplyEvent;
@@ -126,20 +133,22 @@ import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerItemConsumeEvent;
import org.bukkit.event.player.PlayerPickupItemEvent;
import org.bukkit.event.player.PlayerShearEntityEvent;
import org.bukkit.event.player.PlayerTakeLecternBookEvent;
import org.bukkit.event.player.PlayerUnleashEntityEvent;
import org.bukkit.event.vehicle.VehicleDamageEvent;
import org.bukkit.event.vehicle.VehicleDestroyEvent;
import org.bukkit.event.world.StructureGrowEvent;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryHolder;
import org.bukkit.inventory.ItemStack;
import org.bukkit.projectiles.ProjectileSource;
import org.bukkit.util.Vector;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Nullable;
import java.util.stream.Collectors;
public class EventAbstractionListener extends AbstractListener {
@@ -150,6 +159,17 @@ public class EventAbstractionListener extends AbstractListener {
private final EventDebounce<BlockPistonRetractKey> pistonRetractDebounce = EventDebounce.create(5000);
private final EventDebounce<BlockPistonExtendKey> pistonExtendDebounce = EventDebounce.create(5000);
private static final boolean HAS_SNAPSHOT_INVHOLDER;
static {
boolean temp;
try {
Inventory.class.getMethod("getHolder", boolean.class);
temp = true;
} catch (NoSuchMethodException e) {
temp = false;
}
HAS_SNAPSHOT_INVHOLDER = temp;
}
/**
* Construct the listener.
*
@@ -174,12 +194,14 @@ public class EventAbstractionListener extends AbstractListener {
@EventHandler(ignoreCancelled = true)
public void onBlockMultiPlace(BlockMultiPlaceEvent event) {
List<Block> blocks = new ArrayList<>();
for (BlockState bs : event.getReplacedBlockStates()) {
blocks.add(bs.getBlock());
List<Block> placed = event.getReplacedBlockStates().stream().map(BlockState::getBlock).collect(Collectors.toList());
int origAmt = placed.size();
PlaceBlockEvent delegateEvent = new PlaceBlockEvent(event, create(event.getPlayer()), event.getBlock().getWorld(),
placed, event.getBlockPlaced().getType());
Events.fireToCancel(event, delegateEvent);
if (origAmt != placed.size()) {
event.setCancelled(true);
}
Events.fireToCancel(event, new PlaceBlockEvent(event, create(event.getPlayer()),
event.getBlock().getWorld(), blocks, event.getBlock().getType()));
}
@EventHandler(ignoreCancelled = true)
@@ -188,7 +210,7 @@ public class EventAbstractionListener extends AbstractListener {
BlockState previousState = event.getBlockReplacedState();
// Some blocks, like tall grass and fire, get replaced
if (previousState.getType() != Material.AIR) {
if (previousState.getType() != Material.AIR && previousState.getType() != event.getBlockReplacedState().getType()) {
Events.fireToCancel(event, new BreakBlockEvent(event, create(event.getPlayer()), previousState.getLocation(), previousState.getType()));
}
@@ -240,39 +262,51 @@ public class EventAbstractionListener extends AbstractListener {
@EventHandler(ignoreCancelled = true)
public void onStructureGrowEvent(StructureGrowEvent event) {
int originalCount = event.getBlocks().size();
List<Block> blockList = Lists.transform(event.getBlocks(), new BlockStateAsBlockFunction());
Player player = event.getPlayer();
if (player != null) {
Events.fireBulkEventToCancel(event, new PlaceBlockEvent(event, create(player), event.getLocation().getWorld(), blockList, Material.AIR));
} else {
Events.fireBulkEventToCancel(event, new PlaceBlockEvent(event, create(event.getLocation().getBlock()), event.getLocation().getWorld(), blockList, Material.AIR));
}
Events.fireBulkEventToCancel(event, new PlaceBlockEvent(event,
create(player == null ? event.getLocation().getBlock() : player),
event.getLocation().getWorld(), event.getBlocks()));
if (!event.isCancelled() && event.getBlocks().size() != originalCount) {
event.getLocation().getBlock().setType(Material.AIR);
}
}
// TODO: Handle EntityCreatePortalEvent?
@EventHandler(ignoreCancelled = true)
public void onEntityChangeBlock(EntityChangeBlockEvent event) {
Block block = event.getBlock();
Entity entity = event.getEntity();
Material to = event.getTo();
// Forget about Redstone ore, especially since we handle it in INTERACT
if (block.getType() == Material.REDSTONE_ORE && to == Material.REDSTONE_ORE) {
return;
}
Material toType = event.getTo();
Material fromType = block.getType();
Cause cause = create(entity);
// Fire two events: one as BREAK and one as PLACE
if (event.getTo() != Material.AIR && event.getBlock().getType() != Material.AIR) {
Events.fireToCancel(event, new BreakBlockEvent(event, create(entity), block));
Events.fireToCancel(event, new PlaceBlockEvent(event, create(entity), block.getLocation(), to));
if (toType != Material.AIR && fromType != Material.AIR) {
boolean trample = fromType == Material.FARMLAND && toType == Material.DIRT;
BreakBlockEvent breakDelagate = new BreakBlockEvent(event, cause, block);
if (trample) {
breakDelagate.setSilent(true);
breakDelagate.getRelevantFlags().add(Flags.TRAMPLE_BLOCKS);
} else if (fromType == Material.REDSTONE_ORE) {
breakDelagate.setSilent(true);
}
boolean denied;
if (!(denied = Events.fireToCancel(event, breakDelagate))) {
PlaceBlockEvent placeDelegate = new PlaceBlockEvent(event, cause, block.getLocation(), toType);
if (trample) {
placeDelegate.setSilent(true);
placeDelegate.getRelevantFlags().add(Flags.TRAMPLE_BLOCKS);
} else if (fromType == Material.REDSTONE_ORE) {
placeDelegate.setSilent(true);
}
denied = Events.fireToCancel(event, placeDelegate);
}
if (denied && entity instanceof Player) {
playDenyEffect((Player) entity, block.getLocation());
}
} else {
if (event.getTo() == Material.AIR) {
if (toType == Material.AIR) {
// Track the source so later we can create a proper chain of causes
if (entity instanceof FallingBlock) {
Cause.trackParentCause(entity, block);
@@ -281,22 +315,26 @@ public class EventAbstractionListener extends AbstractListener {
Events.fireToCancel(event, new SpawnEntityEvent(event, create(block), entity));
} else {
entityBreakBlockDebounce.debounce(
event.getBlock(), event.getEntity(), event, new BreakBlockEvent(event, create(entity), event.getBlock()));
block, event.getEntity(), event, new BreakBlockEvent(event, cause, block));
}
} else {
boolean wasCancelled = event.isCancelled();
Cause cause = create(entity);
Events.fireToCancel(event, new PlaceBlockEvent(event, cause, event.getBlock().getLocation(), to));
Events.fireToCancel(event, new PlaceBlockEvent(event, cause, block.getLocation(), toType));
if (event.isCancelled() && !wasCancelled && entity instanceof FallingBlock) {
FallingBlock fallingBlock = (FallingBlock) entity;
ItemStack itemStack = new ItemStack(fallingBlock.getBlockData().getMaterial(), 1);
Item item = block.getWorld().dropItem(fallingBlock.getLocation(), itemStack);
item.setVelocity(new Vector());
if (Events.fireAndTestCancel(new SpawnEntityEvent(event, create(block, entity), item))) {
item.remove();
if (entity instanceof FallingBlock) {
if (event.isCancelled() && !wasCancelled) {
FallingBlock fallingBlock = (FallingBlock) entity;
final Material material = fallingBlock.getBlockData().getMaterial();
if (!material.isItem()) return;
ItemStack itemStack = new ItemStack(material, 1);
Item item = block.getWorld().dropItem(fallingBlock.getLocation(), itemStack);
item.setVelocity(new Vector());
if (Events.fireAndTestCancel(new SpawnEntityEvent(event, create(block, entity), item))) {
item.remove();
}
}
Cause.untrackParentCause(entity);
}
}
}
@@ -305,12 +343,10 @@ public class EventAbstractionListener extends AbstractListener {
@EventHandler(ignoreCancelled = true)
public void onEntityExplode(EntityExplodeEvent event) {
Entity entity = event.getEntity();
if (event.getYield() == 0 && event.blockList().isEmpty()) {
// avoids ender dragon spam
return;
}
Events.fireBulkEventToCancel(event, new BreakBlockEvent(event, create(entity), event.getLocation().getWorld(), event.blockList(), Material.AIR));
if (entity instanceof Creeper) {
Cause.untrackParentCause(entity);
}
}
@EventHandler(ignoreCancelled = true)
@@ -328,6 +364,7 @@ public class EventAbstractionListener extends AbstractListener {
Events.fireBulkEventToCancel(event, new BreakBlockEvent(event, cause, event.getBlock().getWorld(), blocks, Material.AIR));
if (originalSize != blocks.size()) {
event.setCancelled(true);
return;
}
for (Block b : blocks) {
Location loc = b.getRelative(direction).getLocation();
@@ -347,17 +384,24 @@ public class EventAbstractionListener extends AbstractListener {
public void onBlockPistonExtend(BlockPistonExtendEvent event) {
EventDebounce.Entry entry = pistonExtendDebounce.getIfNotPresent(new BlockPistonExtendKey(event), event);
if (entry != null) {
Cause cause = create(event.getBlock());
List<Block> blocks = new ArrayList<>(event.getBlocks());
int originalLength = blocks.size();
Events.fireBulkEventToCancel(event, new BreakBlockEvent(event, cause, event.getBlock().getWorld(), blocks, Material.AIR));
if (originalLength != blocks.size()) {
event.setCancelled(true);
return;
}
BlockFace dir = event.getDirection();
for (int i = 0; i < blocks.size(); i++) {
Block existing = blocks.get(i);
if (existing.getPistonMoveReaction() == PistonMoveReaction.MOVE
|| existing.getPistonMoveReaction() == PistonMoveReaction.PUSH_ONLY) {
|| existing.getPistonMoveReaction() == PistonMoveReaction.PUSH_ONLY
|| existing.getType() == Material.PISTON || existing.getType() == Material.STICKY_PISTON) {
blocks.set(i, existing.getRelative(dir));
}
}
Events.fireBulkEventToCancel(event, new PlaceBlockEvent(event, create(event.getBlock()), event.getBlock().getWorld(), blocks, Material.STONE));
Events.fireBulkEventToCancel(event, new PlaceBlockEvent(event, cause, event.getBlock().getWorld(), blocks, Material.STONE));
if (blocks.size() != originalLength) {
event.setCancelled(true);
}
@@ -390,23 +434,37 @@ public class EventAbstractionListener extends AbstractListener {
@Nullable ItemStack item = event.getItem();
Block clicked = event.getClickedBlock();
Block placed;
boolean silent = false;
boolean modifiesWorld;
Cause cause = create(player);
switch (event.getAction()) {
case PHYSICAL:
if (event.useInteractedBlock() != Result.DENY) {
if (clicked.getType() == Material.FARMLAND || clicked.getType() == Material.TURTLE_EGG) {
BreakBlockEvent breakDelagate = new BreakBlockEvent(event, cause, clicked);
breakDelagate.setSilent(true);
breakDelagate.getRelevantFlags().add(Flags.TRAMPLE_BLOCKS);
boolean denied;
if (!(denied = Events.fireToCancel(event, breakDelagate))) {
PlaceBlockEvent placeDelegate = new PlaceBlockEvent(event, cause, clicked.getLocation(),
clicked.getType() == Material.FARMLAND ? Material.DIRT : clicked.getType());
placeDelegate.setSilent(true);
placeDelegate.getRelevantFlags().add(Flags.TRAMPLE_BLOCKS);
denied = Events.fireToCancel(event, placeDelegate);
}
if (denied) {
playDenyEffect(player, clicked.getLocation());
}
return;
}
DelegateEvent firedEvent = new UseBlockEvent(event, cause, clicked).setAllowed(hasInteractBypass(clicked));
if (clicked.getType() == Material.REDSTONE_ORE) {
silent = true;
firedEvent.setSilent(true);
}
if (clicked.getType() == Material.FARMLAND || clicked.getType() == Material.TURTLE_EGG) {
silent = true;
firedEvent.getRelevantFlags().add(Flags.TRAMPLE_BLOCKS);
}
firedEvent.setSilent(silent);
interactDebounce.debounce(clicked, event.getPlayer(), event, firedEvent);
if (event.useInteractedBlock() == Result.DENY) {
playDenyEffect(player, clicked.getLocation().add(0, 1, 0));
}
}
break;
@@ -425,8 +483,8 @@ public class EventAbstractionListener extends AbstractListener {
// Only fire events for blocks that are modified when right clicked
final boolean hasItemInteraction = item != null && isItemAppliedToBlock(item, clicked)
&& event.getAction() == Action.RIGHT_CLICK_BLOCK;
modifiesWorld = isBlockModifiedOnClick(clicked, event.getAction() == Action.RIGHT_CLICK_BLOCK)
|| hasItemInteraction;
modifiesWorld = hasItemInteraction
|| isBlockModifiedOnClick(clicked, event.getAction() == Action.RIGHT_CLICK_BLOCK);
if (Events.fireAndTestCancel(new UseBlockEvent(event, cause, clicked).setAllowed(!modifiesWorld))) {
event.setUseInteractedBlock(Result.DENY);
@@ -443,6 +501,7 @@ public class EventAbstractionListener extends AbstractListener {
if (hasItemInteraction) {
if (Events.fireAndTestCancel(new PlaceBlockEvent(event, cause, clicked.getLocation(), clicked.getType()))) {
event.setUseItemInHand(Result.DENY);
event.setUseInteractedBlock(Result.DENY);
}
}
@@ -495,6 +554,12 @@ public class EventAbstractionListener extends AbstractListener {
event.getBlock()).setAllowed(hasInteractBypass(event.getBlock())));
}
@EventHandler(ignoreCancelled = true)
public void onBlockFertilize(BlockFertilizeEvent event) {
Cause cause = create(event.getPlayer(), event.getBlock());
Events.fireToCancel(event, new PlaceBlockEvent(event, cause, event.getBlock().getWorld(), event.getBlocks()));
}
@EventHandler(ignoreCancelled = true)
public void onBlockIgnite(BlockIgniteEvent event) {
Block block = event.getBlock();
@@ -531,7 +596,15 @@ public class EventAbstractionListener extends AbstractListener {
@EventHandler(ignoreCancelled = true)
public void onPlayerBucketEmpty(PlayerBucketEmptyEvent event) {
Player player = event.getPlayer();
Block blockAffected = event.getBlockClicked().getRelative(event.getBlockFace());
Block blockClicked = event.getBlockClicked();
Block blockAffected;
if (blockClicked.getBlockData() instanceof Waterlogged) {
blockAffected = blockClicked;
} else {
blockAffected = blockClicked.getRelative(event.getBlockFace());
}
boolean allowed = false;
// Milk buckets can't be emptied as of writing
@@ -591,7 +664,7 @@ public class EventAbstractionListener extends AbstractListener {
Material toType = to.getType();
// Liquids pass this event when flowing to solid blocks
if (toType.isSolid() && Materials.isLiquid(fromType)) {
if (Materials.isLiquid(fromType) && toType.isSolid()) {
return;
}
@@ -627,27 +700,7 @@ public class EventAbstractionListener extends AbstractListener {
Events.fireToCancel(event, new SpawnEntityEvent(event, Cause.unknown(), event.getEntity()));
}
break;
case NATURAL:
case JOCKEY:
case CHUNK_GEN:
case SPAWNER:
case LIGHTNING:
case BUILD_SNOWMAN:
case BUILD_IRONGOLEM:
case BUILD_WITHER:
case VILLAGE_DEFENSE:
case VILLAGE_INVASION:
case BREEDING:
case SLIME_SPLIT:
case REINFORCEMENTS:
case NETHER_PORTAL:
case INFECTION:
case CURED:
case OCELOT_BABY:
case SILVERFISH_BLOCK:
case MOUNT:
case CUSTOM:
case DEFAULT:
default:
}
}
@@ -670,6 +723,15 @@ public class EventAbstractionListener extends AbstractListener {
if (event.isCancelled() && remover instanceof Player) {
playDenyEffect((Player) remover, event.getEntity().getLocation());
}
} else if (event.getCause() == HangingBreakEvent.RemoveCause.EXPLOSION){
DestroyEntityEvent destroyEntityEvent = new DestroyEntityEvent(event, Cause.unknown(), event.getEntity());
destroyEntityEvent.getRelevantFlags().add(Flags.OTHER_EXPLOSION);
if (event.getEntity() instanceof ItemFrame) {
destroyEntityEvent.getRelevantFlags().add(Flags.ENTITY_ITEM_FRAME_DESTROY);
} else if (event.getEntity() instanceof Painting) {
destroyEntityEvent.getRelevantFlags().add(Flags.ENTITY_PAINTING_DESTROY);
}
Events.fireToCancel(event, destroyEntityEvent);
}
}
@@ -748,8 +810,20 @@ public class EventAbstractionListener extends AbstractListener {
? player.getInventory().getItemInOffHand() : player.getInventory().getItemInMainHand();
Entity entity = event.getRightClicked();
Events.fireToCancel(event, new UseItemEvent(event, create(player), world, item));
Events.fireToCancel(event, new UseEntityEvent(event, create(player), entity));
if (Events.fireToCancel(event, new UseItemEvent(event, create(player), world, item))) {
return;
}
final UseEntityEvent useEntityEvent = new UseEntityEvent(event, create(player), entity);
Material matchingItem = Materials.getRelatedMaterial(entity.getType());
if (matchingItem != null && hasInteractBypass(world, matchingItem)) {
useEntityEvent.setAllowed(true);
}
if (!Events.fireToCancel(event, useEntityEvent)) {
// so this is a hack but CreeperIgniteEvent doesn't actually tell us who, so we need to do it here
if (item.getType() == Material.FLINT_AND_STEEL && entity.getType() == EntityType.CREEPER) {
Cause.trackParentCause(entity, player);
}
}
}
@EventHandler(ignoreCancelled = true)
@@ -766,7 +840,17 @@ public class EventAbstractionListener extends AbstractListener {
} else if (event instanceof EntityDamageByEntityEvent) {
EntityDamageByEntityEvent entityEvent = (EntityDamageByEntityEvent) event;
Entity damager = entityEvent.getDamager();
Events.fireToCancel(event, new DamageEntityEvent(event, create(damager), event.getEntity()));
final DamageEntityEvent eventToFire = new DamageEntityEvent(event, create(damager), event.getEntity());
if (damager instanceof Firework) {
eventToFire.getRelevantFlags().add(Flags.FIREWORK_DAMAGE);
} else if (damager instanceof Creeper) {
eventToFire.getRelevantFlags().add(Flags.CREEPER_EXPLOSION);
}
if (Events.fireToCancel(event, eventToFire)) {
if (damager instanceof Tameable && damager instanceof Mob) {
((Mob) damager).setTarget(null);
}
}
// Item use event with the item in hand
// Older blacklist handler code used this, although it suffers from
@@ -798,7 +882,7 @@ public class EventAbstractionListener extends AbstractListener {
if (event instanceof PlayerUnleashEntityEvent) {
PlayerUnleashEntityEvent playerEvent = (PlayerUnleashEntityEvent) event;
Events.fireToCancel(playerEvent, new UseEntityEvent(playerEvent, create(playerEvent.getPlayer()), event.getEntity()));
} // TODO: Raise anyway?
}
}
@EventHandler(ignoreCancelled = true)
@@ -840,30 +924,42 @@ public class EventAbstractionListener extends AbstractListener {
@EventHandler(ignoreCancelled = true)
public void onInventoryOpen(InventoryOpenEvent event) {
InventoryHolder holder = event.getInventory().getHolder();
if (holder instanceof BlockState) {
Events.fireToCancel(event, new UseBlockEvent(event, create(event.getPlayer()), ((BlockState) holder).getBlock()));
} else if (holder instanceof Entity) {
if (!(holder instanceof Player)) {
Events.fireToCancel(event, new UseEntityEvent(event, create(event.getPlayer()), (Entity) holder));
}
}
if (holder instanceof Entity && holder == event.getPlayer()) return;
handleInventoryHolderUse(event, create(event.getPlayer()), holder);
}
@EventHandler(ignoreCancelled = true)
public void onInventoryMoveItem(InventoryMoveItemEvent event) {
final InventoryHolder causeHolder = event.getInitiator().getHolder();
InventoryHolder sourceHolder = event.getSource().getHolder();
InventoryHolder targetHolder = event.getDestination().getHolder();
InventoryHolder causeHolder;
if (HAS_SNAPSHOT_INVHOLDER) {
causeHolder = event.getInitiator().getHolder(false);
} else {
causeHolder = event.getInitiator().getHolder();
}
if ((causeHolder instanceof Hopper || causeHolder instanceof Dropper)
&& ((BukkitWorldConfiguration) WorldGuard.getInstance().getPlatform().getGlobalStateManager().get(
BukkitAdapter.adapt(((Container) causeHolder).getWorld()))).ignoreHopperMoveEvents) {
WorldConfiguration wcfg = null;
if (causeHolder instanceof Hopper
&& (wcfg = getWorldConfig(BukkitAdapter.adapt((((Hopper) causeHolder).getWorld())))).ignoreHopperMoveEvents) {
return;
} else if (causeHolder instanceof HopperMinecart
&& (wcfg = getWorldConfig(BukkitAdapter.adapt((((HopperMinecart) causeHolder).getWorld())))).ignoreHopperMoveEvents) {
return;
}
Entry entry;
if ((entry = moveItemDebounce.tryDebounce(event)) != null) {
InventoryHolder sourceHolder;
InventoryHolder targetHolder;
if (HAS_SNAPSHOT_INVHOLDER) {
sourceHolder = event.getSource().getHolder(false);
targetHolder = event.getDestination().getHolder(false);
} else {
sourceHolder = event.getSource().getHolder();
targetHolder = event.getDestination().getHolder();
}
Cause cause;
if (causeHolder instanceof Entity) {
@@ -880,7 +976,7 @@ public class EventAbstractionListener extends AbstractListener {
handleInventoryHolderUse(event, cause, targetHolder);
if (event.isCancelled() && causeHolder instanceof Hopper) {
if (event.isCancelled() && causeHolder instanceof Hopper && wcfg.breakDeniedHoppers) {
Bukkit.getScheduler().scheduleSyncDelayedTask(getPlugin(),
() -> ((Hopper) causeHolder).getBlock().breakNaturally());
} else {
@@ -927,15 +1023,18 @@ public class EventAbstractionListener extends AbstractListener {
@EventHandler(ignoreCancelled = true)
public void onBlockDispense(BlockDispenseEvent event) {
Cause cause = create(event.getBlock());
Block dispenserBlock = event.getBlock();
ItemStack item = event.getItem();
Events.fireToCancel(event, new UseItemEvent(event, cause, dispenserBlock.getWorld(), item));
// Simulate right click event as players have it
if (dispenserBlock.getBlockData() instanceof Dispenser) {
Dispenser dispenser = (Dispenser) dispenserBlock.getBlockData();
if (dispenserBlock.getType() == Material.DISPENSER) {
Cause cause = create(event.getBlock());
ItemStack item = event.getItem();
if (Events.fireToCancel(event, new UseItemEvent(event, cause, dispenserBlock.getWorld(), item))) {
return;
}
BlockData blockData = dispenserBlock.getBlockData();
Dispenser dispenser = (Dispenser) blockData; // if this ClassCastExceptions it's a bukkit bug
Block placed = dispenserBlock.getRelative(dispenser.getFacing());
Block clicked = placed.getRelative(dispenser.getFacing());
handleBlockRightClick(event, cause, item, clicked, placed);
@@ -982,6 +1081,21 @@ public class EventAbstractionListener extends AbstractListener {
Events.fireBulkEventToCancel(event, eventToFire);
}
@EventHandler(ignoreCancelled = true)
public void onTakeLecternBook(PlayerTakeLecternBookEvent event) {
final UseBlockEvent useEvent = new UseBlockEvent(event, create(event.getPlayer()), event.getLectern().getBlock());
useEvent.getRelevantFlags().add(Flags.CHEST_ACCESS);
Events.fireToCancel(event, useEvent);
}
@EventHandler(ignoreCancelled = true)
public void onCauldronLevelChange(CauldronLevelChangeEvent event) {
if (event.getEntity() == null) return;
interactDebounce.debounce(event.getBlock(), event.getEntity(), event,
new UseBlockEvent(event, create(event.getEntity()),
event.getBlock()).setAllowed(hasInteractBypass(event.getBlock())));
}
/**
* Handle the right click of a block while an item is held.
*
@@ -1005,14 +1119,16 @@ public class EventAbstractionListener extends AbstractListener {
// Handle created Minecarts
if (item != null && Materials.isMinecart(item.getType())) {
// TODO: Give a more specific Minecart type
Events.fireToCancel(event, new SpawnEntityEvent(event, cause, placed.getLocation().add(0.5, 0, 0.5), EntityType.MINECART));
EntityType entityType = Materials.getRelatedEntity(item.getType());
if (entityType == null) {
entityType = EntityType.MINECART;
}
Events.fireToCancel(event, new SpawnEntityEvent(event, cause, clicked.getLocation().add(0.5, 0, 0.5), entityType));
return;
}
// Handle created boats
if (item != null && Materials.isBoat(item.getType())) {
// TODO as above
Events.fireToCancel(event, new SpawnEntityEvent(event, cause, placed.getLocation().add(0.5, 0, 0.5), EntityType.BOAT));
return;
}
@@ -1034,6 +1150,13 @@ public class EventAbstractionListener extends AbstractListener {
Events.fireToCancel(event, new SpawnEntityEvent(event, cause, placed.getLocation().add(0.5, 0, 0.5), Materials.getEntitySpawnEgg(item.getType())));
return;
}
// handle water/lava placement
if (item != null && (item.getType() == Material.WATER_BUCKET || item.getType() == Material.LAVA_BUCKET)) {
Events.fireToCancel(event, new PlaceBlockEvent(event, cause, placed.getLocation(),
item.getType() == Material.WATER_BUCKET ? Material.WATER : Material.LAVA));
return;
}
}
private static <T extends Event & Cancellable> void handleInventoryHolderUse(T originalEvent, Cause cause, InventoryHolder holder) {
@@ -1042,47 +1165,64 @@ public class EventAbstractionListener extends AbstractListener {
}
if (holder instanceof Entity) {
Events.fireToCancel(originalEvent, new UseEntityEvent(originalEvent, cause, (Entity) holder));
} else if (holder instanceof BlockState) {
Events.fireToCancel(originalEvent, new UseBlockEvent(originalEvent, cause, ((BlockState) holder).getBlock()));
} else if (holder instanceof DoubleChest) {
InventoryHolder left = ((DoubleChest) holder).getLeftSide();
InventoryHolder right = ((DoubleChest) holder).getRightSide();
if (left instanceof Chest) {
Events.fireToCancel(originalEvent, new UseBlockEvent(originalEvent, cause, ((Chest) left).getBlock()));
Entity entity = (Entity) holder;
Material mat = Materials.getRelatedMaterial((entity).getType());
UseEntityEvent useEntityEvent = new UseEntityEvent(originalEvent, cause, entity);
if (mat != null && hasInteractBypass((entity).getWorld(), mat)) {
useEntityEvent.setAllowed(true);
}
if (right instanceof Chest) {
Events.fireToCancel(originalEvent, new UseBlockEvent(originalEvent, cause, ((Chest) right).getBlock()));
Events.fireToCancel(originalEvent, useEntityEvent);
} else {
if (holder instanceof BlockState) {
final BlockState block = (BlockState) holder;
final UseBlockEvent useBlockEvent = new UseBlockEvent(originalEvent, cause, block.getBlock());
if (hasInteractBypass(block.getWorld(), block.getType())) {
useBlockEvent.setAllowed(true);
}
Events.fireToCancel(originalEvent, useBlockEvent);
} else if (holder instanceof DoubleChest) {
InventoryHolder left = ((DoubleChest) holder).getLeftSide();
InventoryHolder right = ((DoubleChest) holder).getRightSide();
if (left instanceof Chest) {
Events.fireToCancel(originalEvent, new UseBlockEvent(originalEvent, cause, ((Chest) left).getBlock()));
}
if (right instanceof Chest) {
Events.fireToCancel(originalEvent, new UseBlockEvent(originalEvent, cause, ((Chest) right).getBlock()));
}
}
}
}
private boolean hasInteractBypass(Block block) {
private static boolean hasInteractBypass(Block block) {
return ((BukkitWorldConfiguration) getWorldConfig(BukkitAdapter.adapt(block.getWorld()))).allowAllInteract.test(block);
}
private boolean hasInteractBypass(World world, ItemStack item) {
private static boolean hasInteractBypass(World world, Material material) {
return ((BukkitWorldConfiguration) getWorldConfig(BukkitAdapter.adapt(world))).allowAllInteract.test(material);
}
private static boolean hasInteractBypass(World world, ItemStack item) {
return ((BukkitWorldConfiguration) getWorldConfig(BukkitAdapter.adapt(world))).allowAllInteract.test(item);
}
private boolean isBlockModifiedOnClick(Block block, boolean rightClick) {
private static boolean isBlockModifiedOnClick(Block block, boolean rightClick) {
return Materials.isBlockModifiedOnClick(block.getType(), rightClick) && !hasInteractBypass(block);
}
private boolean isItemAppliedToBlock(ItemStack item, Block clicked) {
private static boolean isItemAppliedToBlock(ItemStack item, Block clicked) {
return Materials.isItemAppliedToBlock(item.getType(), clicked.getType())
&& !hasInteractBypass(clicked)
&& !hasInteractBypass(clicked.getWorld(), item);
}
private void playDenyEffect(Player player, Location location) {
private static void playDenyEffect(Player player, Location location) {
//player.playSound(location, Sound.SUCCESSFUL_HIT, 0.2f, 0.4f);
if (WorldGuard.getInstance().getPlatform().getGlobalStateManager().particleEffects) {
player.playEffect(location, Effect.SMOKE, BlockFace.UP);
}
}
private void playDenyEffect(Location location) {
private static void playDenyEffect(Location location) {
if (WorldGuard.getInstance().getPlatform().getGlobalStateManager().particleEffects) {
location.getWorld().playEffect(location, Effect.SMOKE, BlockFace.UP);
}
@@ -35,6 +35,7 @@ import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.event.player.PlayerRespawnEvent;
import org.bukkit.event.vehicle.VehicleEnterEvent;
import org.bukkit.plugin.PluginManager;
@@ -77,6 +78,14 @@ public class PlayerMoveListener implements Listener {
@EventHandler(priority = EventPriority.HIGH)
public void onPlayerMove(PlayerMoveEvent event) {
Location from = event.getFrom();
Location to = event.getTo();
if (from.getBlockX() == to.getBlockX()
&& from.getBlockY() == to.getBlockY()
&& from.getBlockZ() == to.getBlockZ()) {
return;
}
final Player player = event.getPlayer();
LocalPlayer localPlayer = plugin.wrapPlayer(player);
@@ -89,15 +98,15 @@ public class PlayerMoveListener implements Listener {
} else if (event.getPlayer().getVehicle() != null && event.getPlayer().getVehicle() instanceof Horse) {
moveType = MoveType.RIDE;
}
com.sk89q.worldedit.util.Location weLocation = session.testMoveTo(localPlayer, BukkitAdapter.adapt(event.getTo()), moveType);
com.sk89q.worldedit.util.Location weLocation = session.testMoveTo(localPlayer, BukkitAdapter.adapt(to), moveType);
if (weLocation != null) {
final Location override = BukkitAdapter.adapt(weLocation);
override.setX(override.getBlockX() + 0.5);
override.setY(override.getBlockY());
override.setZ(override.getBlockZ() + 0.5);
override.setPitch(event.getTo().getPitch());
override.setYaw(event.getTo().getYaw());
override.setPitch(to.getPitch());
override.setYaw(to.getYaw());
event.setTo(override.clone());
@@ -124,4 +133,16 @@ public class PlayerMoveListener implements Listener {
}
}
@EventHandler
public void onPlayerQuit(PlayerQuitEvent event) {
final Player player = event.getPlayer();
LocalPlayer localPlayer = plugin.wrapPlayer(player);
Session session = WorldGuard.getInstance().getPlatform().getSessionManager().get(localPlayer);
com.sk89q.worldedit.util.Location loc = session.testMoveTo(localPlayer,
BukkitAdapter.adapt(event.getPlayer().getLocation()), MoveType.OTHER_CANCELLABLE); // white lie
if (loc != null) {
player.teleport(BukkitAdapter.adapt(loc));
}
}
}
@@ -39,7 +39,6 @@ import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.EntityDamageEvent.DamageCause;
@@ -109,6 +108,10 @@ public class RegionFlagsListener extends AbstractListener {
if (event.getCause().find(EntityType.ENDERMAN) != null) {
event.filter(testState(query, Flags.ENDER_BUILD), false);
}
if (event.getCause().find(EntityType.RAVAGER) != null) {
event.filter(testState(query, Flags.RAVAGER_RAVAGE), false);
}
}
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
@@ -126,27 +129,15 @@ public class RegionFlagsListener extends AbstractListener {
return;
}
} else {
try {
if (entity instanceof Player && event.getCause() == DamageCause.FLY_INTO_WALL) {
LocalPlayer localPlayer = WorldGuardPlugin.inst().wrapPlayer((Player) entity);
if (!query.testState(BukkitAdapter.adapt(entity.getLocation()), localPlayer, Flags.FALL_DAMAGE)) {
event.setCancelled(true);
return;
}
}
} catch (NoSuchFieldError ignored) {
}
}
if (event instanceof EntityDamageByEntityEvent) {
Entity damager = (((EntityDamageByEntityEvent) event)).getDamager();
if (damager != null && damager.getType() == EntityType.FIREWORK) {
if (!query.testState(BukkitAdapter.adapt(entity.getLocation()), (RegionAssociable) null, Flags.FIREWORK_DAMAGE)) {
if (entity instanceof Player && event.getCause() == DamageCause.FLY_INTO_WALL) {
LocalPlayer localPlayer = WorldGuardPlugin.inst().wrapPlayer((Player) entity);
if (!query.testState(BukkitAdapter.adapt(entity.getLocation()), localPlayer, Flags.FALL_DAMAGE)) {
event.setCancelled(true);
return;
}
}
}
}
/**
@@ -41,10 +41,6 @@ import com.sk89q.worldguard.bukkit.util.InteropUtils;
import com.sk89q.worldguard.bukkit.util.Materials;
import com.sk89q.worldguard.commands.CommandUtils;
import com.sk89q.worldguard.config.WorldConfiguration;
import com.sk89q.worldguard.domains.Association;
import com.sk89q.worldguard.internal.permission.RegionPermissionModel;
import com.sk89q.worldguard.protection.DelayedRegionOverlapAssociation;
import com.sk89q.worldguard.protection.association.Associables;
import com.sk89q.worldguard.protection.association.RegionAssociable;
import com.sk89q.worldguard.protection.flags.Flags;
import com.sk89q.worldguard.protection.flags.StateFlag;
@@ -53,7 +49,6 @@ import com.sk89q.worldguard.protection.regions.RegionQuery;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.OfflinePlayer;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.entity.Entity;
@@ -140,38 +135,19 @@ public class RegionProtectionListener extends AbstractListener {
if (rootCause instanceof Player) {
Player player = (Player) rootCause;
LocalPlayer localPlayer = WorldGuardPlugin.inst().wrapPlayer(player);
WorldConfiguration config = getWorldConfig(BukkitAdapter.adapt(world));
com.sk89q.worldedit.world.World localWorld = BukkitAdapter.adapt(world);
WorldConfiguration config = getWorldConfig(localWorld);
if (config.fakePlayerBuildOverride && InteropUtils.isFakePlayer(player)) {
return true;
}
return !pvp && new RegionPermissionModel(localPlayer).mayIgnoreRegionProtection(BukkitAdapter.adapt(world));
return !pvp && WorldGuard.getInstance().getPlatform().getSessionManager().hasBypass(localPlayer, localWorld);
} else {
return false;
}
}
private RegionAssociable createRegionAssociable(Cause cause) {
Object rootCause = cause.getRootCause();
if (!cause.isKnown()) {
return Associables.constant(Association.NON_MEMBER);
} else if (rootCause instanceof Player) {
return getPlugin().wrapPlayer((Player) rootCause);
} else if (rootCause instanceof OfflinePlayer) {
return getPlugin().wrapOfflinePlayer((OfflinePlayer) rootCause);
} else if (rootCause instanceof Entity) {
RegionQuery query = WorldGuard.getInstance().getPlatform().getRegionContainer().createQuery();
return new DelayedRegionOverlapAssociation(query, BukkitAdapter.adapt(((Entity) rootCause).getLocation()));
} else if (rootCause instanceof Block) {
RegionQuery query = WorldGuard.getInstance().getPlatform().getRegionContainer().createQuery();
return new DelayedRegionOverlapAssociation(query, BukkitAdapter.adapt(((Block) rootCause).getLocation()));
} else {
return Associables.constant(Association.NON_MEMBER);
}
}
@EventHandler(ignoreCancelled = true)
public void onPlaceBlock(final PlaceBlockEvent event) {
if (event.getResult() == Result.ALLOW) return; // Don't care about events that have been pre-allowed
@@ -282,7 +258,7 @@ public class RegionProtectionListener extends AbstractListener {
/* Inventory */
} else if (Materials.isInventoryBlock(type)) {
canUse = query.testBuild(BukkitAdapter.adapt(target), associable, combine(event, Flags.INTERACT, Flags.CHEST_ACCESS));
canUse = query.testBuild(BukkitAdapter.adapt(target), associable, combine(event, Flags.CHEST_ACCESS));
what = "open that";
/* Beds */
@@ -416,15 +392,16 @@ public class RegionProtectionListener extends AbstractListener {
String what;
/* Hostile / ambient mob override */
final EntityType type = event.getEntity().getType();
if (Entities.isHostile(event.getEntity()) || Entities.isAmbient(event.getEntity())
|| Entities.isNPC(event.getEntity())) {
final Entity entity = event.getEntity();
final EntityType type = entity.getType();
if (Entities.isHostile(entity) || Entities.isAmbient(entity)
|| Entities.isNPC(entity) || entity instanceof Player) {
canUse = event.getRelevantFlags().isEmpty() || query.queryState(BukkitAdapter.adapt(target), associable, combine(event)) != State.DENY;
what = "use that";
/* Paintings, item frames, etc. */
} else if (Entities.isConsideredBuildingIfUsed(event.getEntity())) {
} else if (Entities.isConsideredBuildingIfUsed(entity)) {
if (type == EntityType.ITEM_FRAME && event.getCause().getFirstPlayer() != null
&& ((ItemFrame) event.getEntity()).getItem().getType() != Material.AIR) {
&& ((ItemFrame) entity).getItem().getType() != Material.AIR) {
canUse = query.testBuild(BukkitAdapter.adapt(target), associable, combine(event, Flags.ITEM_FRAME_ROTATE));
what = "change that";
} else if (Entities.isMinecart(type)) {
@@ -435,7 +412,7 @@ public class RegionProtectionListener extends AbstractListener {
what = "change that";
}
/* Ridden on use */
} else if (Entities.isRiddenOnUse(event.getEntity())) {
} else if (Entities.isRiddenOnUse(entity)) {
canUse = query.testBuild(BukkitAdapter.adapt(target), associable, combine(event, Flags.RIDE, Flags.INTERACT));
what = "ride that";
@@ -34,6 +34,7 @@ import com.sk89q.worldguard.util.SpongeUtil;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.data.Waterlogged;
import org.bukkit.entity.Player;
import org.bukkit.entity.Snowman;
import org.bukkit.event.EventHandler;
@@ -194,7 +195,7 @@ public class WorldGuardBlockListener implements Listener {
}
}
if (wcfg.highFreqFlags && isWater
if (wcfg.highFreqFlags && (isWater || blockFrom.getBlockData() instanceof Waterlogged)
&& WorldGuard.getInstance().getPlatform().getRegionContainer().createQuery().queryState(BukkitAdapter.adapt(blockFrom.getLocation()), (RegionAssociable) null, Flags.WATER_FLOW) == StateFlag.State.DENY) {
event.setCancelled(true);
return;
@@ -205,13 +206,6 @@ public class WorldGuardBlockListener implements Listener {
event.setCancelled(true);
return;
}
if (wcfg.disableObsidianGenerators && (isAir || isLava)
&& (blockTo.getType() == Material.REDSTONE_WIRE
|| blockTo.getType() == Material.TRIPWIRE)) {
blockTo.setType(Material.AIR);
return;
}
}
/*
@@ -620,7 +614,7 @@ public class WorldGuardBlockListener implements Listener {
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void onBlockGrow(BlockGrowEvent event) {
WorldConfiguration wcfg = getWorldConfig(event.getBlock().getWorld());
final Material type = event.getBlock().getType();
final Material type = event.getNewState().getType();
if (Materials.isCrop(type)) {
if (wcfg.disableCropGrowth) {
@@ -682,6 +676,16 @@ public class WorldGuardBlockListener implements Listener {
event.setCancelled(true);
return;
}
} else if (Materials.isCoral(event.getBlock().getType())) {
if (wcfg.disableCoralBlockFade) {
event.setCancelled(true);
return;
}
if (wcfg.useRegions && !StateFlag.test(WorldGuard.getInstance().getPlatform().getRegionContainer().createQuery()
.queryState(BukkitAdapter.adapt(event.getBlock().getLocation()), (RegionAssociable) null, Flags.CORAL_FADE))) {
event.setCancelled(true);
return;
}
}
}
@@ -20,6 +20,7 @@
package com.sk89q.worldguard.bukkit.listener;
import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.WorldGuard;
import com.sk89q.worldguard.bukkit.BukkitWorldConfiguration;
@@ -31,11 +32,14 @@ import com.sk89q.worldguard.protection.ApplicableRegionSet;
import com.sk89q.worldguard.protection.association.RegionAssociable;
import com.sk89q.worldguard.protection.flags.Flags;
import com.sk89q.worldguard.protection.flags.StateFlag;
import com.sk89q.worldguard.protection.managers.RegionManager;
import com.sk89q.worldguard.protection.regions.ProtectedCuboidRegion;
import com.sk89q.worldguard.protection.regions.RegionQuery;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.entity.ArmorStand;
import org.bukkit.entity.Creeper;
import org.bukkit.entity.EnderCrystal;
@@ -43,7 +47,9 @@ import org.bukkit.entity.EnderDragon;
import org.bukkit.entity.Enderman;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.FallingBlock;
import org.bukkit.entity.Fireball;
import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.ItemFrame;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
@@ -62,7 +68,6 @@ import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason;
import org.bukkit.event.entity.CreeperPowerEvent;
import org.bukkit.event.entity.EntityBreakDoorEvent;
import org.bukkit.event.entity.EntityChangeBlockEvent;
import org.bukkit.event.entity.EntityCreatePortalEvent;
import org.bukkit.event.entity.EntityDamageByBlockEvent;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityDamageEvent;
@@ -71,9 +76,13 @@ import org.bukkit.event.entity.EntityDeathEvent;
import org.bukkit.event.entity.EntityExplodeEvent;
import org.bukkit.event.entity.EntityInteractEvent;
import org.bukkit.event.entity.EntityRegainHealthEvent;
import org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason;
import org.bukkit.event.entity.EntityTransformEvent;
import org.bukkit.event.entity.ExplosionPrimeEvent;
import org.bukkit.event.entity.FoodLevelChangeEvent;
import org.bukkit.event.entity.PigZapEvent;
import org.bukkit.event.entity.PlayerDeathEvent;
import org.bukkit.event.world.PortalCreateEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.projectiles.ProjectileSource;
@@ -102,9 +111,6 @@ public class WorldGuardEntityListener implements Listener {
*/
public void registerEvents() {
plugin.getServer().getPluginManager().registerEvents(this, plugin);
if (!EntityCreatePortalEvent.class.isAnnotationPresent(Deprecated.class)) {
plugin.getServer().getPluginManager().registerEvents(new UselessIn114Listener(), plugin);
}
}
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
@@ -162,6 +168,9 @@ public class WorldGuardEntityListener implements Listener {
if (wcfg.teleportOnVoid && type == DamageCause.VOID) {
localPlayer.findFreePosition();
if (wcfg.safeFallOnVoid) {
localPlayer.resetFallDistance();
}
event.setCancelled(true);
return;
}
@@ -277,13 +286,6 @@ public class WorldGuardEntityListener implements Listener {
event.setCancelled(true);
return;
}
if (attacker instanceof Creeper) {
if (!set.testState(localPlayer, Flags.CREEPER_EXPLOSION) && wcfg.explosionFlagCancellation) {
event.setCancelled(true);
return;
}
}
}
}
}
@@ -669,24 +671,69 @@ public class WorldGuardEntityListener implements Listener {
}
}
private static class UselessIn114Listener implements Listener {
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void onCreatePortal(EntityCreatePortalEvent event) {
ConfigurationManager cfg = WorldGuard.getInstance().getPlatform().getGlobalStateManager();
WorldConfiguration wcfg = cfg.get(BukkitAdapter.adapt(event.getEntity().getWorld()));
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void onCreatePortal(PortalCreateEvent event) {
ConfigurationManager cfg = WorldGuard.getInstance().getPlatform().getGlobalStateManager();
final com.sk89q.worldedit.world.World world = BukkitAdapter.adapt(event.getWorld());
WorldConfiguration wcfg = cfg.get(world);
switch (event.getEntityType()) {
case ENDER_DRAGON:
if (wcfg.blockEnderDragonPortalCreation) event.setCancelled(true);
break;
if (wcfg.regionNetherPortalProtection
&& event.getReason() == PortalCreateEvent.CreateReason.NETHER_PAIR
&& !event.getBlocks().isEmpty()) {
final RegionManager regionManager = WorldGuard.getInstance().getPlatform().getRegionContainer()
.get(world);
if (regionManager == null) return;
LocalPlayer associable = null;
if (event.getEntity() instanceof Player) {
associable = plugin.wrapPlayer(((Player) event.getEntity()));
if (WorldGuard.getInstance().getPlatform().getSessionManager().hasBypass(associable, world)) {
return;
}
}
BlockVector3 min = null;
BlockVector3 max = null;
for (BlockState block : event.getBlocks()) {
BlockVector3 loc = BlockVector3.at(block.getX(), block.getY(), block.getZ());
min = min == null ? loc : loc.getMinimum(min);
max = max == null ? loc : loc.getMaximum(max);
}
ProtectedCuboidRegion target = new ProtectedCuboidRegion("__portal_check", true, min, max);
final ApplicableRegionSet regions = regionManager.getApplicableRegions(target);
if (!regions.testState(associable, Flags.BUILD, Flags.BLOCK_PLACE)) {
if (associable != null) {
// NB there is no way to cancel the teleport without PTA (since PlayerPortal doesn't have block info)
// removing PTA was a mistake
associable.print("Destination is an a protected area.");
}
event.setCancelled(true);
}
}
// NOTE: as of right now, bukkit doesn't fire this event for this (despite deprecating EntityCreatePortalEvent for it)
// maybe one day this code will be useful
if (event.getEntity() instanceof EnderDragon && wcfg.blockEnderDragonPortalCreation) {
event.setCancelled(true);
}
}
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void onEntityTransform(EntityTransformEvent event) {
ConfigurationManager cfg = WorldGuard.getInstance().getPlatform().getGlobalStateManager();
final Entity entity = event.getEntity();
WorldConfiguration wcfg = cfg.get(BukkitAdapter.adapt(entity.getWorld()));
final EntityType type = entity.getType();
if (wcfg.disableVillagerZap && type == EntityType.VILLAGER
&& event.getTransformReason() == EntityTransformEvent.TransformReason.LIGHTNING) {
event.setCancelled(true);
}
}
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void onPigZap(PigZapEvent event) {
ConfigurationManager cfg = WorldGuard.getInstance().getPlatform().getGlobalStateManager();
WorldConfiguration wcfg = cfg.get(BukkitAdapter.adapt(event.getEntity().getWorld()));
final Entity entity = event.getEntity();
WorldConfiguration wcfg = cfg.get(BukkitAdapter.adapt(entity.getWorld()));
if (wcfg.disablePigZap) {
event.setCancelled(true);
@@ -705,6 +752,10 @@ public class WorldGuardEntityListener implements Listener {
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void onEntityRegainHealth(EntityRegainHealthEvent event) {
RegainReason regainReason = event.getRegainReason();
if (regainReason != RegainReason.REGEN && regainReason != RegainReason.SATIATED) {
return;
}
Entity ent = event.getEntity();
World world = ent.getWorld();
@@ -716,6 +767,31 @@ public class WorldGuardEntityListener implements Listener {
event.setCancelled(true);
return;
}
if (wcfg.useRegions && ent instanceof Player
&& !WorldGuard.getInstance().getPlatform().getRegionContainer().createQuery().testState(
BukkitAdapter.adapt(ent.getLocation()),
WorldGuardPlugin.inst().wrapPlayer((Player) ent),
Flags.HEALTH_REGEN)) {
event.setCancelled(true);
}
}
@EventHandler(ignoreCancelled = true)
public void onFoodChange(FoodLevelChangeEvent event) {
if (event.getItem() != null) return;
HumanEntity ent = event.getEntity();
if (!(ent instanceof Player)) return;
LocalPlayer player = WorldGuardPlugin.inst().wrapPlayer((Player) ent);
if (event.getFoodLevel() > player.getFoodLevel()) return;
ConfigurationManager cfg = WorldGuard.getInstance().getPlatform().getGlobalStateManager();
WorldConfiguration wcfg = cfg.get(player.getWorld());
if (wcfg.useRegions
&& !WorldGuard.getInstance().getPlatform().getRegionContainer().createQuery().testState(
player.getLocation(), player, Flags.HUNGER_DRAIN)) {
event.setCancelled(true);
}
}
/**
@@ -731,7 +807,19 @@ public class WorldGuardEntityListener implements Listener {
ConfigurationManager cfg = WorldGuard.getInstance().getPlatform().getGlobalStateManager();
WorldConfiguration wcfg = cfg.get(BukkitAdapter.adapt(ent.getWorld()));
if (ent instanceof Enderman) {
if (ent instanceof FallingBlock) {
Material id = event.getBlock().getType();
if (id == Material.GRAVEL && wcfg.noPhysicsGravel) {
event.setCancelled(true);
return;
}
if (id == Material.SAND && wcfg.noPhysicsSand) {
event.setCancelled(true);
return;
}
} else if (ent instanceof Enderman) {
if (wcfg.disableEndermanGriefing) {
event.setCancelled(true);
return;
@@ -31,8 +31,6 @@ import com.sk89q.worldguard.config.ConfigurationManager;
import com.sk89q.worldguard.config.WorldConfiguration;
import com.sk89q.worldguard.protection.ApplicableRegionSet;
import com.sk89q.worldguard.protection.flags.Flags;
import com.sk89q.worldguard.protection.managers.RegionManager;
import com.sk89q.worldguard.protection.regions.ProtectedCuboidRegion;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import com.sk89q.worldguard.protection.regions.RegionQuery;
import com.sk89q.worldguard.session.MoveType;
@@ -40,10 +38,9 @@ import com.sk89q.worldguard.session.Session;
import com.sk89q.worldguard.session.handler.GameModeFlag;
import com.sk89q.worldguard.util.Entities;
import com.sk89q.worldguard.util.command.CommandFilter;
import com.sk89q.worldguard.util.profile.Profile;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.TravelAgent;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.entity.Entity;
@@ -60,20 +57,18 @@ import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerItemHeldEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerLoginEvent;
import org.bukkit.event.player.PlayerPortalEvent;
import org.bukkit.event.player.PlayerRespawnEvent;
import org.bukkit.event.player.PlayerTeleportEvent;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import org.bukkit.inventory.ItemStack;
import org.bukkit.plugin.PluginManager;
import javax.annotation.Nullable;
import java.util.Iterator;
import java.util.Set;
import java.util.logging.Logger;
import java.util.regex.Pattern;
import javax.annotation.Nullable;
/**
* Handles all events thrown in relation to a player.
*/
@@ -143,7 +138,7 @@ public class WorldGuardPlayerListener implements Listener {
if (removed > 10) {
log.info("Halt-Act: " + removed + " entities (>10) auto-removed from "
+ player.getWorld().toString());
+ player.getWorld());
}
}
@@ -153,6 +148,8 @@ public class WorldGuardPlayerListener implements Listener {
}
Events.fire(new ProcessPlayerEvent(player));
WorldGuard.getInstance().getExecutorService().submit(() ->
WorldGuard.getInstance().getProfileCache().put(new Profile(player.getUniqueId(), player.getName())));
}
@EventHandler(ignoreCancelled = true)
@@ -181,7 +178,7 @@ public class WorldGuardPlayerListener implements Listener {
anyRemoved = true;
}
}
if (anyRemoved && event.getRecipients().size() == 0 && wcfg.regionCancelEmptyChatEvents) {
if (anyRemoved && event.getRecipients().isEmpty() && wcfg.regionCancelEmptyChatEvents) {
event.setCancelled(true);
}
}
@@ -205,7 +202,8 @@ public class WorldGuardPlayerListener implements Listener {
}
if (!hostname.equals(hostKey)
&& !(cfg.hostKeysAllowFMLClients && hostname.equals(hostKey + "\u0000FML\u0000"))) {
&& !(cfg.hostKeysAllowFMLClients &&
(hostname.equals(hostKey + "\u0000FML\u0000") || hostname.equals(hostKey + "\u0000FML2\u0000")))) {
event.disallow(PlayerLoginEvent.Result.KICK_OTHER,
"You did not join with the valid host key!");
log.warning("WorldGuard host key check: " +
@@ -368,7 +366,6 @@ public class WorldGuardPlayerListener implements Listener {
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onPlayerTeleport(PlayerTeleportEvent event) {
World world = event.getFrom().getWorld();
Player player = event.getPlayer();
LocalPlayer localPlayer = plugin.wrapPlayer(player);
ConfigurationManager cfg = WorldGuard.getInstance().getPlatform().getGlobalStateManager();
@@ -386,89 +383,41 @@ public class WorldGuardPlayerListener implements Listener {
String message = null;
if (!setFrom.testState(localPlayer, Flags.ENDERPEARL)) {
cancel = true;
message = set.queryValue(localPlayer, Flags.EXIT_DENY_MESSAGE);
message = setFrom.queryValue(localPlayer, Flags.EXIT_DENY_MESSAGE);
} else if (!set.testState(localPlayer, Flags.ENDERPEARL)) {
cancel = true;
message = set.queryValue(localPlayer, Flags.ENTRY_DENY_MESSAGE);
}
if (cancel) {
player.sendMessage(message);
if (message != null) {
player.sendMessage(message);
}
event.setCancelled(true);
return;
}
}
}
if (event.getCause() == TeleportCause.CHORUS_FRUIT) {
} else if (event.getCause() == TeleportCause.CHORUS_FRUIT) {
if (!WorldGuard.getInstance().getPlatform().getSessionManager().hasBypass(localPlayer, localPlayer.getWorld())) {
boolean cancel = false;
String message = null;
if (!setFrom.testState(localPlayer, Flags.CHORUS_TELEPORT)) {
cancel = true;
message = set.queryValue(localPlayer, Flags.EXIT_DENY_MESSAGE);
message = setFrom.queryValue(localPlayer, Flags.EXIT_DENY_MESSAGE);
} else if (!set.testState(localPlayer, Flags.CHORUS_TELEPORT)) {
cancel = true;
message = set.queryValue(localPlayer, Flags.ENTRY_DENY_MESSAGE);
}
if (cancel) {
player.sendMessage(message);
if (message != null) {
player.sendMessage(message);
}
event.setCancelled(true);
return;
}
}
}
if (null != WorldGuard.getInstance().getPlatform().getSessionManager().get(localPlayer).testMoveTo(localPlayer,
BukkitAdapter.adapt(event.getTo()),
MoveType.TELEPORT)) {
event.setCancelled(true);
return;
}
}
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGH)
public void onPlayerPortal(PlayerPortalEvent event) {
if (event.getTo() == null) { // apparently this counts as a cancelled event, implementation specific though
return;
}
ConfigurationManager cfg = WorldGuard.getInstance().getPlatform().getGlobalStateManager();
LocalPlayer localPlayer = plugin.wrapPlayer(event.getPlayer());
WorldConfiguration wcfg = cfg.get(BukkitAdapter.adapt(event.getTo().getWorld()));
if (!wcfg.regionNetherPortalProtection) return;
if (event.getCause() != TeleportCause.NETHER_PORTAL) {
return;
}
try {
if (!event.useTravelAgent()) { // either end travel (even though we checked cause) or another plugin is fucking with us, shouldn't create a portal though
return;
}
} catch (NoSuchMethodError ignored) {
return;
}
TravelAgent pta = event.getPortalTravelAgent();
if (pta == null) { // possible, but shouldn't create a portal
return;
}
if (pta.findPortal(event.getTo()) != null) {
return; // portal exists...it shouldn't make a new one
}
// HOPEFULLY covered everything the server can throw at us...proceed protection checking
// a lot of that is implementation specific though
// hackily estimate the area that could be effected by this event, since the server refuses to tell us
int radius = pta.getCreationRadius();
Location min = event.getTo().clone().subtract(radius, radius, radius);
Location max = event.getTo().clone().add(radius, radius, radius);
com.sk89q.worldedit.world.World world = BukkitAdapter.adapt(event.getTo().getWorld());
ProtectedRegion check = new ProtectedCuboidRegion("__portalcheck__", BukkitAdapter.adapt(min.getBlock().getLocation()).toVector().toBlockPoint(),
BukkitAdapter.adapt(max.getBlock().getLocation()).toVector().toBlockPoint());
if (wcfg.useRegions && !WorldGuard.getInstance().getPlatform().getSessionManager().hasBypass(localPlayer, world)) {
RegionManager mgr = WorldGuard.getInstance().getPlatform().getRegionContainer().get(world);
if (mgr == null) return;
ApplicableRegionSet set = mgr.getApplicableRegions(check);
if (!set.testState(plugin.wrapPlayer(event.getPlayer()), Flags.BUILD)) {
event.getPlayer().sendMessage(ChatColor.RED + "Destination is in a protected area.");
if (null != WorldGuard.getInstance().getPlatform().getSessionManager().get(localPlayer)
.testMoveTo(localPlayer, BukkitAdapter.adapt(event.getTo()), MoveType.TELEPORT)) {
event.setCancelled(true);
return;
}
@@ -29,6 +29,8 @@ import com.sk89q.worldguard.protection.flags.Flags;
import com.sk89q.worldguard.protection.flags.StateFlag;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
@@ -93,8 +95,12 @@ public class WorldGuardWeatherListener implements Listener {
ConfigurationManager cfg = WorldGuard.getInstance().getPlatform().getGlobalStateManager();
WorldConfiguration wcfg = cfg.get(BukkitAdapter.adapt(event.getWorld()));
if (wcfg.disallowedLightningBlocks.size() > 0) {
Material targetId = event.getLightning().getLocation().getBlock().getType();
if (!wcfg.disallowedLightningBlocks.isEmpty()) {
final Block target = event.getLightning().getLocation().getBlock();
Material targetId = target.getType();
if (targetId == Material.AIR) {
targetId = target.getRelative(BlockFace.DOWN).getType();
}
if (wcfg.disallowedLightningBlocks.contains(BukkitAdapter.asBlockType(targetId).getId())) {
event.setCancelled(true);
}
@@ -24,13 +24,13 @@ import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.WorldGuard;
import com.sk89q.worldguard.bukkit.BukkitPlayer;
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
import com.sk89q.worldguard.bukkit.event.player.ProcessPlayerEvent;
import com.sk89q.worldguard.session.AbstractSessionManager;
import com.sk89q.worldguard.session.Session;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import java.util.Collection;
@@ -57,7 +57,7 @@ public class BukkitSessionManager extends AbstractSessionManager implements Runn
}
@EventHandler
public void onPlayerJoin(PlayerJoinEvent event) {
public void onPlayerProcess(ProcessPlayerEvent event) {
// Pre-load a session
LocalPlayer player = WorldGuardPlugin.inst().wrapPlayer(event.getPlayer());
get(player).initialize(player);
@@ -75,7 +75,7 @@ public class BukkitSessionManager extends AbstractSessionManager implements Runn
public boolean hasBypass(LocalPlayer player, World world) {
if (player instanceof BukkitPlayer) {
if (((BukkitPlayer) player).getPlayer().hasMetadata("NPC")
&& WorldGuard.getInstance().getPlatform().getGlobalStateManager().get(world).fakePlayerBuildOverride)
&& WorldGuard.getInstance().getPlatform().getGlobalStateManager().get(world).fakePlayerBuildOverride)
return true;
}
return super.hasBypass(player, world);
@@ -19,6 +19,7 @@
package com.sk89q.worldguard.bukkit.util;
import io.papermc.lib.PaperLib;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.block.data.BlockData;
@@ -45,7 +46,7 @@ public final class Blocks {
* @return a list of connected blocks, not including the given block
*/
public static List<Block> getConnected(Block block) {
BlockState state = block.getState();
BlockState state = PaperLib.getBlockState(block, false).getState();
BlockData data = state.getBlockData();
if (data instanceof Bed) {
@@ -21,6 +21,7 @@ package com.sk89q.worldguard.bukkit.util;
import org.bukkit.entity.Ambient;
import org.bukkit.entity.ArmorStand;
import org.bukkit.entity.Arrow;
import org.bukkit.entity.Creature;
import org.bukkit.entity.EnderCrystal;
import org.bukkit.entity.EnderDragon;
@@ -32,6 +33,7 @@ import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Minecart;
import org.bukkit.entity.Monster;
import org.bukkit.entity.NPC;
import org.bukkit.entity.Pig;
import org.bukkit.entity.Player;
import org.bukkit.entity.Projectile;
import org.bukkit.entity.Shulker;
@@ -39,9 +41,7 @@ import org.bukkit.entity.Slime;
import org.bukkit.entity.SpectralArrow;
import org.bukkit.entity.TNTPrimed;
import org.bukkit.entity.Tameable;
import org.bukkit.entity.TippedArrow;
import org.bukkit.entity.Vehicle;
import org.bukkit.entity.WaterMob;
import org.bukkit.entity.minecart.ExplosiveMinecart;
import org.bukkit.inventory.InventoryHolder;
import org.bukkit.projectiles.ProjectileSource;
@@ -91,7 +91,7 @@ public final class Entities {
* @return true if the entity can be ridden
*/
public static boolean isRiddenOnUse(Entity entity) {
return entity instanceof Vehicle;
return entity instanceof Pig ? ((Pig) entity).hasSaddle() : entity instanceof Vehicle;
}
/**
@@ -163,8 +163,7 @@ public final class Entities {
* @return true if non-hostile
*/
public static boolean isNonHostile(Entity entity) {
return !isHostile(entity)
&& (entity instanceof Creature || entity instanceof WaterMob);
return !isHostile(entity) && entity instanceof Creature;
}
/**
@@ -213,7 +212,7 @@ public final class Entities {
}
public static boolean isPotionArrow(Entity entity) {
return entity instanceof TippedArrow || entity instanceof SpectralArrow;
return entity instanceof Arrow || entity instanceof SpectralArrow;
}
public static boolean isAoECloud(EntityType type) {
@@ -28,6 +28,7 @@ import org.bukkit.entity.EntityType;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import javax.annotation.Nullable;
import java.util.Collection;
import java.util.EnumMap;
import java.util.HashSet;
@@ -36,8 +37,6 @@ import java.util.Set;
import java.util.logging.Logger;
import java.util.stream.Stream;
import javax.annotation.Nullable;
/**
* Material utility class.
*/
@@ -53,7 +52,6 @@ public final class Materials {
private static final Map<Material, Integer> MATERIAL_FLAGS = new EnumMap<>(Material.class);
private static final Set<PotionEffectType> DAMAGE_EFFECTS = new HashSet<>();
private static Set<Material> shulkerBoxes = new HashSet<>();
static {
@@ -94,6 +92,7 @@ public final class Materials {
ENTITY_ITEMS.put(EntityType.SPLASH_POTION, Material.POTION);
ENTITY_ITEMS.put(EntityType.EGG, Material.EGG);
ENTITY_ITEMS.put(EntityType.ARMOR_STAND, Material.ARMOR_STAND);
ENTITY_ITEMS.put(EntityType.ENDER_CRYSTAL, Material.END_CRYSTAL);
MATERIAL_FLAGS.put(Material.AIR, 0);
MATERIAL_FLAGS.put(Material.STONE, 0);
@@ -124,20 +123,10 @@ public final class Materials {
MATERIAL_FLAGS.put(Material.PISTON, 0);
MATERIAL_FLAGS.put(Material.PISTON_HEAD, 0);
MATERIAL_FLAGS.put(Material.MOVING_PISTON, 0);
MATERIAL_FLAGS.put(Material.DANDELION, 0);
MATERIAL_FLAGS.put(Material.BLUE_ORCHID, 0);
MATERIAL_FLAGS.put(Material.ALLIUM, 0);
MATERIAL_FLAGS.put(Material.AZURE_BLUET, 0);
MATERIAL_FLAGS.put(Material.ORANGE_TULIP, 0);
MATERIAL_FLAGS.put(Material.PINK_TULIP, 0);
MATERIAL_FLAGS.put(Material.RED_TULIP, 0);
MATERIAL_FLAGS.put(Material.WHITE_TULIP, 0);
MATERIAL_FLAGS.put(Material.OXEYE_DAISY, 0);
MATERIAL_FLAGS.put(Material.SUNFLOWER, 0);
MATERIAL_FLAGS.put(Material.LILAC, 0);
MATERIAL_FLAGS.put(Material.PEONY, 0);
MATERIAL_FLAGS.put(Material.ROSE_BUSH, 0);
MATERIAL_FLAGS.put(Material.POPPY, 0);
MATERIAL_FLAGS.put(Material.BROWN_MUSHROOM, 0);
MATERIAL_FLAGS.put(Material.RED_MUSHROOM, 0);
MATERIAL_FLAGS.put(Material.GOLD_BLOCK, 0);
@@ -235,7 +224,6 @@ public final class Materials {
MATERIAL_FLAGS.put(Material.EMERALD_BLOCK, 0);
MATERIAL_FLAGS.put(Material.COMMAND_BLOCK, MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.BEACON, MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.COBBLESTONE_WALL, 0);
MATERIAL_FLAGS.put(Material.ANVIL, MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.CHIPPED_ANVIL, MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.DAMAGED_ANVIL, MODIFIED_ON_RIGHT);
@@ -406,7 +394,6 @@ public final class Materials {
MATERIAL_FLAGS.put(Material.MAGENTA_STAINED_GLASS, 0);
MATERIAL_FLAGS.put(Material.MAGENTA_STAINED_GLASS_PANE, 0);
MATERIAL_FLAGS.put(Material.MAGENTA_TERRACOTTA, 0);
MATERIAL_FLAGS.put(Material.MOSSY_COBBLESTONE_WALL, 0);
MATERIAL_FLAGS.put(Material.MUSHROOM_STEM, 0);
MATERIAL_FLAGS.put(Material.OBSERVER, 0);
MATERIAL_FLAGS.put(Material.ORANGE_STAINED_GLASS, 0);
@@ -447,9 +434,29 @@ public final class Materials {
MATERIAL_FLAGS.put(Material.YELLOW_STAINED_GLASS_PANE, 0);
MATERIAL_FLAGS.put(Material.YELLOW_TERRACOTTA, 0);
MATERIAL_FLAGS.put(Material.IRON_SHOVEL, MODIFIES_BLOCKS);
MATERIAL_FLAGS.put(Material.BAMBOO, 0);
MATERIAL_FLAGS.put(Material.BAMBOO_SAPLING, 0);
MATERIAL_FLAGS.put(Material.BARREL, MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.BELL, MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.BLAST_FURNACE, MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.CAMPFIRE, MODIFIED_ON_RIGHT | MODIFIED_ON_LEFT);
MATERIAL_FLAGS.put(Material.CARTOGRAPHY_TABLE, 0);
MATERIAL_FLAGS.put(Material.COMPOSTER, MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.FLETCHING_TABLE, 0);
MATERIAL_FLAGS.put(Material.GRINDSTONE, 0);
MATERIAL_FLAGS.put(Material.JIGSAW, MODIFIED_ON_RIGHT | MODIFIED_ON_LEFT);
MATERIAL_FLAGS.put(Material.LANTERN, 0);
MATERIAL_FLAGS.put(Material.LECTERN, 0);
MATERIAL_FLAGS.put(Material.LOOM, 0);
MATERIAL_FLAGS.put(Material.SCAFFOLDING, 0);
MATERIAL_FLAGS.put(Material.SMITHING_TABLE, 0);
MATERIAL_FLAGS.put(Material.SMOKER, MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.STONECUTTER, 0);
MATERIAL_FLAGS.put(Material.SWEET_BERRY_BUSH, MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.IRON_SHOVEL, 0);
MATERIAL_FLAGS.put(Material.IRON_PICKAXE, 0);
MATERIAL_FLAGS.put(Material.IRON_AXE, MODIFIES_BLOCKS);
MATERIAL_FLAGS.put(Material.IRON_AXE, 0);
MATERIAL_FLAGS.put(Material.FLINT_AND_STEEL, 0);
MATERIAL_FLAGS.put(Material.APPLE, 0);
MATERIAL_FLAGS.put(Material.BOW, 0);
@@ -460,32 +467,32 @@ public final class Materials {
MATERIAL_FLAGS.put(Material.GOLD_INGOT, 0);
MATERIAL_FLAGS.put(Material.IRON_SWORD, 0);
MATERIAL_FLAGS.put(Material.WOODEN_SWORD, 0);
MATERIAL_FLAGS.put(Material.WOODEN_SHOVEL, MODIFIES_BLOCKS);
MATERIAL_FLAGS.put(Material.WOODEN_SHOVEL, 0);
MATERIAL_FLAGS.put(Material.WOODEN_PICKAXE, 0);
MATERIAL_FLAGS.put(Material.WOODEN_AXE, MODIFIES_BLOCKS);
MATERIAL_FLAGS.put(Material.WOODEN_AXE, 0);
MATERIAL_FLAGS.put(Material.STONE_SWORD, 0);
MATERIAL_FLAGS.put(Material.STONE_SHOVEL, MODIFIES_BLOCKS);
MATERIAL_FLAGS.put(Material.STONE_SHOVEL, 0);
MATERIAL_FLAGS.put(Material.STONE_PICKAXE, 0);
MATERIAL_FLAGS.put(Material.STONE_AXE, MODIFIES_BLOCKS);
MATERIAL_FLAGS.put(Material.STONE_AXE, 0);
MATERIAL_FLAGS.put(Material.DIAMOND_SWORD, 0);
MATERIAL_FLAGS.put(Material.DIAMOND_SHOVEL, MODIFIES_BLOCKS);
MATERIAL_FLAGS.put(Material.DIAMOND_SHOVEL, 0);
MATERIAL_FLAGS.put(Material.DIAMOND_PICKAXE, 0);
MATERIAL_FLAGS.put(Material.DIAMOND_AXE, MODIFIES_BLOCKS);
MATERIAL_FLAGS.put(Material.DIAMOND_AXE, 0);
MATERIAL_FLAGS.put(Material.STICK, 0);
MATERIAL_FLAGS.put(Material.BOWL, 0);
MATERIAL_FLAGS.put(Material.MUSHROOM_STEW, 0);
MATERIAL_FLAGS.put(Material.GOLDEN_SWORD, 0);
MATERIAL_FLAGS.put(Material.GOLDEN_SHOVEL, MODIFIES_BLOCKS);
MATERIAL_FLAGS.put(Material.GOLDEN_SHOVEL, 0);
MATERIAL_FLAGS.put(Material.GOLDEN_PICKAXE, 0);
MATERIAL_FLAGS.put(Material.GOLDEN_AXE, MODIFIES_BLOCKS);
MATERIAL_FLAGS.put(Material.GOLDEN_AXE, 0);
MATERIAL_FLAGS.put(Material.STRING, 0);
MATERIAL_FLAGS.put(Material.FEATHER, 0);
MATERIAL_FLAGS.put(Material.GUNPOWDER, 0);
MATERIAL_FLAGS.put(Material.WOODEN_HOE, MODIFIES_BLOCKS);
MATERIAL_FLAGS.put(Material.STONE_HOE, MODIFIES_BLOCKS);
MATERIAL_FLAGS.put(Material.IRON_HOE, MODIFIES_BLOCKS);
MATERIAL_FLAGS.put(Material.DIAMOND_HOE, MODIFIES_BLOCKS);
MATERIAL_FLAGS.put(Material.GOLDEN_HOE, MODIFIES_BLOCKS);
MATERIAL_FLAGS.put(Material.WOODEN_HOE, 0);
MATERIAL_FLAGS.put(Material.STONE_HOE, 0);
MATERIAL_FLAGS.put(Material.IRON_HOE, 0);
MATERIAL_FLAGS.put(Material.DIAMOND_HOE, 0);
MATERIAL_FLAGS.put(Material.GOLDEN_HOE, 0);
MATERIAL_FLAGS.put(Material.WHEAT_SEEDS, 0);
MATERIAL_FLAGS.put(Material.BREAD, 0);
MATERIAL_FLAGS.put(Material.LEATHER_HELMET, 0);
@@ -539,23 +546,30 @@ public final class Materials {
MATERIAL_FLAGS.put(Material.GLOWSTONE_DUST, 0);
MATERIAL_FLAGS.put(Material.COD, 0);
MATERIAL_FLAGS.put(Material.COOKED_COD, 0);
MATERIAL_FLAGS.put(Material.INK_SAC, MODIFIES_BLOCKS);
MATERIAL_FLAGS.put(Material.CYAN_DYE, MODIFIES_BLOCKS);
MATERIAL_FLAGS.put(Material.GRAY_DYE, MODIFIES_BLOCKS);
MATERIAL_FLAGS.put(Material.LIGHT_BLUE_DYE, MODIFIES_BLOCKS);
MATERIAL_FLAGS.put(Material.LIGHT_GRAY_DYE, MODIFIES_BLOCKS);
MATERIAL_FLAGS.put(Material.LIME_DYE, MODIFIES_BLOCKS);
MATERIAL_FLAGS.put(Material.MAGENTA_DYE, MODIFIES_BLOCKS);
MATERIAL_FLAGS.put(Material.ORANGE_DYE, MODIFIES_BLOCKS);
MATERIAL_FLAGS.put(Material.PINK_DYE, MODIFIES_BLOCKS);
MATERIAL_FLAGS.put(Material.PURPLE_DYE, MODIFIES_BLOCKS);
MATERIAL_FLAGS.put(Material.COCOA_BEANS, MODIFIES_BLOCKS);
MATERIAL_FLAGS.put(Material.INK_SAC, 0);
MATERIAL_FLAGS.put(Material.BLACK_DYE, 0);
MATERIAL_FLAGS.put(Material.BLUE_DYE, 0);
MATERIAL_FLAGS.put(Material.BROWN_DYE, 0);
MATERIAL_FLAGS.put(Material.CYAN_DYE, 0);
MATERIAL_FLAGS.put(Material.GRAY_DYE, 0);
MATERIAL_FLAGS.put(Material.GREEN_DYE, 0);
MATERIAL_FLAGS.put(Material.LIGHT_BLUE_DYE, 0);
MATERIAL_FLAGS.put(Material.LIGHT_GRAY_DYE, 0);
MATERIAL_FLAGS.put(Material.LIME_DYE, 0);
MATERIAL_FLAGS.put(Material.MAGENTA_DYE, 0);
MATERIAL_FLAGS.put(Material.ORANGE_DYE, 0);
MATERIAL_FLAGS.put(Material.PINK_DYE, 0);
MATERIAL_FLAGS.put(Material.PURPLE_DYE, 0);
MATERIAL_FLAGS.put(Material.RED_DYE, 0);
MATERIAL_FLAGS.put(Material.WHITE_DYE, 0);
MATERIAL_FLAGS.put(Material.YELLOW_DYE, 0);
MATERIAL_FLAGS.put(Material.COCOA_BEANS, 0);
MATERIAL_FLAGS.put(Material.BONE_MEAL, MODIFIES_BLOCKS);
MATERIAL_FLAGS.put(Material.BONE, 0);
MATERIAL_FLAGS.put(Material.SUGAR, 0);
MATERIAL_FLAGS.put(Material.COOKIE, 0);
MATERIAL_FLAGS.put(Material.MAP, 0);
MATERIAL_FLAGS.put(Material.SHEARS, MODIFIES_BLOCKS);
MATERIAL_FLAGS.put(Material.SHEARS, 0);
MATERIAL_FLAGS.put(Material.MELON_SLICE, 0);
MATERIAL_FLAGS.put(Material.PUMPKIN_SEEDS, 0);
MATERIAL_FLAGS.put(Material.MELON_SEEDS, 0);
@@ -623,6 +637,7 @@ public final class Materials {
MATERIAL_FLAGS.put(Material.RABBIT_FOOT, 0);
MATERIAL_FLAGS.put(Material.RABBIT_HIDE, 0);
MATERIAL_FLAGS.put(Material.ARMOR_STAND, 0);
MATERIAL_FLAGS.put(Material.LEATHER_HORSE_ARMOR, 0);
MATERIAL_FLAGS.put(Material.IRON_HORSE_ARMOR, 0);
MATERIAL_FLAGS.put(Material.GOLDEN_HORSE_ARMOR, 0);
MATERIAL_FLAGS.put(Material.DIAMOND_HORSE_ARMOR, 0);
@@ -668,18 +683,25 @@ public final class Materials {
MATERIAL_FLAGS.put(Material.TROPICAL_FISH, 0);
MATERIAL_FLAGS.put(Material.TROPICAL_FISH_BUCKET, 0);
MATERIAL_FLAGS.put(Material.MUSIC_DISC_11, 0);
MATERIAL_FLAGS.put(Material.MUSIC_DISC_13, 0);
MATERIAL_FLAGS.put(Material.MUSIC_DISC_BLOCKS, 0);
MATERIAL_FLAGS.put(Material.MUSIC_DISC_CAT, 0);
MATERIAL_FLAGS.put(Material.MUSIC_DISC_CHIRP, 0);
MATERIAL_FLAGS.put(Material.MUSIC_DISC_FAR, 0);
MATERIAL_FLAGS.put(Material.MUSIC_DISC_MALL, 0);
MATERIAL_FLAGS.put(Material.MUSIC_DISC_MELLOHI, 0);
MATERIAL_FLAGS.put(Material.MUSIC_DISC_STAL, 0);
MATERIAL_FLAGS.put(Material.MUSIC_DISC_STRAD, 0);
MATERIAL_FLAGS.put(Material.MUSIC_DISC_WAIT, 0);
MATERIAL_FLAGS.put(Material.MUSIC_DISC_WARD, 0);
MATERIAL_FLAGS.put(Material.CREEPER_BANNER_PATTERN, 0);
MATERIAL_FLAGS.put(Material.FLOWER_BANNER_PATTERN, 0);
MATERIAL_FLAGS.put(Material.GLOBE_BANNER_PATTERN, 0);
MATERIAL_FLAGS.put(Material.MOJANG_BANNER_PATTERN, 0);
MATERIAL_FLAGS.put(Material.SKULL_BANNER_PATTERN, 0);
MATERIAL_FLAGS.put(Material.CROSSBOW, 0);
MATERIAL_FLAGS.put(Material.SUSPICIOUS_STEW, 0);
MATERIAL_FLAGS.put(Material.SWEET_BERRIES, 0);
// 1.15
try {
MATERIAL_FLAGS.put(Material.BEEHIVE, MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.BEE_NEST, MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.HONEY_BLOCK, 0);
MATERIAL_FLAGS.put(Material.HONEYCOMB_BLOCK, 0);
MATERIAL_FLAGS.put(Material.HONEY_BOTTLE, 0);
MATERIAL_FLAGS.put(Material.HONEYCOMB, 0);
} catch (NoSuchFieldError ignored) {
}
// Fake tags
for (Material m : shulkerBoxes) {
@@ -729,6 +751,24 @@ public final class Materials {
for (Material pot : Tag.FLOWER_POTS.getValues()) {
MATERIAL_FLAGS.put(pot, MODIFIED_ON_RIGHT);
}
for (Material wall : Tag.WALLS.getValues()) {
MATERIAL_FLAGS.put(wall, 0);
}
for (Material sign : Tag.SIGNS.getValues()) {
MATERIAL_FLAGS.put(sign, 0);
}
for (Material flower : Tag.SMALL_FLOWERS.getValues()) {
MATERIAL_FLAGS.put(flower, 0);
}
for (Material bed : Tag.BEDS.getValues()) {
MATERIAL_FLAGS.put(bed, MODIFIED_ON_RIGHT);
}
for (Material musicDisc : Tag.ITEMS_MUSIC_DISCS.getValues()) {
MATERIAL_FLAGS.put(musicDisc, 0);
}
for (Material bannerPat : Tag.ITEMS_BANNERS.getValues()) {
MATERIAL_FLAGS.put(bannerPat, 0);
}
Stream.concat(Stream.concat(
Tag.CORAL_BLOCKS.getValues().stream(),
Tag.CORALS.getValues().stream()),
@@ -740,57 +780,51 @@ public final class Materials {
}
});
try {
MATERIAL_FLAGS.put(Material.SIGN, 0);
MATERIAL_FLAGS.put(Material.WALL_SIGN, 0);
MATERIAL_FLAGS.put(Material.DANDELION_YELLOW, MODIFIES_BLOCKS);
MATERIAL_FLAGS.put(Material.ROSE_RED, MODIFIES_BLOCKS);
MATERIAL_FLAGS.put(Material.CACTUS_GREEN, MODIFIES_BLOCKS);
} catch (NoSuchFieldError ignored) { // missing fields in 1.14
}
// Check for missing items/blocks
for (Material material : Material.values()) {
//noinspection deprecation
if (material.isLegacy()) continue;
// Add spawn eggs
if (isSpawnEgg(material)) {
MATERIAL_FLAGS.put(material, 0);
} else if (isBed(material)) {
MATERIAL_FLAGS.put(material, MODIFIED_ON_RIGHT);
}
if (!MATERIAL_FLAGS.containsKey(material)) {
logger.fine("Missing material definition for " + (material.isBlock() ? "block " : "item ") + material.name());
MATERIAL_FLAGS.put(material, MODIFIED_ON_LEFT | MODIFIED_ON_RIGHT);
}
}
//DAMAGE_EFFECTS.add(PotionEffectType.ABSORPTION);
DAMAGE_EFFECTS.add(PotionEffectType.BLINDNESS);
DAMAGE_EFFECTS.add(PotionEffectType.CONFUSION);
//DAMAGE_EFFECTS.add(PotionEffectType.DAMAGE_RESISTANCE);
//DAMAGE_EFFECTS.add(PotionEffectType.FAST_DIGGING);
//DAMAGE_EFFECTS.add(PotionEffectType.FIRE_RESISTANCE);
DAMAGE_EFFECTS.add(PotionEffectType.HARM);
//DAMAGE_EFFECTS.add(PotionEffectType.HEAL);
//DAMAGE_EFFECTS.add(PotionEffectType.HEALTH_BOOST);
DAMAGE_EFFECTS.add(PotionEffectType.HUNGER);
//DAMAGE_EFFECTS.add(PotionEffectType.INCREASE_DAMAGE);
//DAMAGE_EFFECTS.add(PotionEffectType.INVISIBILITY);
//DAMAGE_EFFECTS.add(PotionEffectType.JUMP);
//DAMAGE_EFFECTS.add(PotionEffectType.NIGHT_VISION);
DAMAGE_EFFECTS.add(PotionEffectType.POISON);
//DAMAGE_EFFECTS.add(PotionEffectType.REGENERATION);
//DAMAGE_EFFECTS.add(PotionEffectType.SATURATION);
// DAMAGE_EFFECTS.add(PotionEffectType.SPEED);
DAMAGE_EFFECTS.add(PotionEffectType.SLOW);
// DAMAGE_EFFECTS.add(PotionEffectType.FAST_DIGGING);
DAMAGE_EFFECTS.add(PotionEffectType.SLOW_DIGGING);
//DAMAGE_EFFECTS.add(PotionEffectType.SPEED);
//DAMAGE_EFFECTS.add(PotionEffectType.WATER_BREATHING);
// DAMAGE_EFFECTS.add(PotionEffectType.INCREASE_DAMAGE);
// DAMAGE_EFFECTS.add(PotionEffectType.HEAL);
DAMAGE_EFFECTS.add(PotionEffectType.HARM);
// DAMAGE_EFFECTS.add(PotionEffectType.JUMP);
DAMAGE_EFFECTS.add(PotionEffectType.CONFUSION);
// DAMAGE_EFFECTS.add(PotionEffectType.REGENERATION);
// DAMAGE_EFFECTS.add(PotionEffectType.DAMAGE_RESISTANCE);
// DAMAGE_EFFECTS.add(PotionEffectType.FIRE_RESISTANCE);
// DAMAGE_EFFECTS.add(PotionEffectType.WATER_BREATHING);
// DAMAGE_EFFECTS.add(PotionEffectType.INVISIBILITY);
DAMAGE_EFFECTS.add(PotionEffectType.BLINDNESS);
// DAMAGE_EFFECTS.add(PotionEffectType.NIGHT_VISION);
DAMAGE_EFFECTS.add(PotionEffectType.HUNGER);
DAMAGE_EFFECTS.add(PotionEffectType.WEAKNESS);
DAMAGE_EFFECTS.add(PotionEffectType.POISON);
DAMAGE_EFFECTS.add(PotionEffectType.WITHER);
DAMAGE_EFFECTS.add(PotionEffectType.LEVITATION); // considered by game so I guess
// DAMAGE_EFFECTS.add(PotionEffectType.HEALTH_BOOST);
// DAMAGE_EFFECTS.add(PotionEffectType.ABSORPTION);
// DAMAGE_EFFECTS.add(PotionEffectType.SATURATION);
DAMAGE_EFFECTS.add(PotionEffectType.GLOWING);
DAMAGE_EFFECTS.add(PotionEffectType.LEVITATION);
// DAMAGE_EFFECTS.add(PotionEffectType.LUCK);
DAMAGE_EFFECTS.add(PotionEffectType.UNLUCK);
// DAMAGE_EFFECTS.add(PotionEffectType.SLOW_FALLING);
// DAMAGE_EFFECTS.add(PotionEffectType.CONDUIT_POWER);
// DAMAGE_EFFECTS.add(PotionEffectType.DOLPHINS_GRACE);
DAMAGE_EFFECTS.add(PotionEffectType.BAD_OMEN);
// DAMAGE_EFFECTS.add(PotionEffectType.HERO_OF_THE_VILLAGE);
}
private Materials() {
@@ -807,6 +841,17 @@ public final class Materials {
return ENTITY_ITEMS.get(type);
}
/**
* Get the related entity type for a material.
*
* @param material the material
* @return the related entity type or {@code null} if one is not known or exists
*/
@Nullable
public static EntityType getRelatedEntity(Material material) {
return ENTITY_ITEMS.inverse().get(material);
}
/**
* Get the material of the block placed by the given bucket, defaulting
* to water if the bucket type is not known.
@@ -825,7 +870,6 @@ public final class Materials {
case LAVA_BUCKET:
return Material.LAVA;
case WATER_BUCKET:
return Material.WATER;
default:
return Material.WATER;
}
@@ -868,7 +912,7 @@ public final class Materials {
* @return true if a water block
*/
public static boolean isWater(Material material) {
return material == Material.WATER;
return material == Material.WATER || material == Material.BUBBLE_COLUMN;
}
/**
@@ -910,7 +954,8 @@ public final class Materials {
*/
public static boolean isPistonBlock(Material material) {
return material == Material.PISTON
|| material == Material.STICKY_PISTON;
|| material == Material.STICKY_PISTON
|| material == Material.MOVING_PISTON;
}
/**
@@ -927,6 +972,7 @@ public final class Materials {
|| material == Material.FURNACE_MINECART
|| material == Material.CHEST_MINECART;
}
/**
* Test whether the given material is a Boat.
*
@@ -952,14 +998,19 @@ public final class Materials {
|| material == Material.TRAPPED_CHEST
|| material == Material.HOPPER
|| material == Material.DROPPER
|| material == Material.BARREL
|| material == Material.BLAST_FURNACE
|| material == Material.SMOKER
|| shulkerBoxes.contains(material);
}
public static boolean isSpawnEgg(Material material) {
switch(material) {
switch (material) {
case SPIDER_SPAWN_EGG:
case BAT_SPAWN_EGG:
case BEE_SPAWN_EGG:
case BLAZE_SPAWN_EGG:
case CAT_SPAWN_EGG:
case CAVE_SPIDER_SPAWN_EGG:
case CHICKEN_SPAWN_EGG:
case COD_SPAWN_EGG:
@@ -972,6 +1023,7 @@ public final class Materials {
case ENDERMAN_SPAWN_EGG:
case ENDERMITE_SPAWN_EGG:
case EVOKER_SPAWN_EGG:
case FOX_SPAWN_EGG:
case GHAST_SPAWN_EGG:
case GUARDIAN_SPAWN_EGG:
case HORSE_SPAWN_EGG:
@@ -981,12 +1033,15 @@ public final class Materials {
case MOOSHROOM_SPAWN_EGG:
case MULE_SPAWN_EGG:
case OCELOT_SPAWN_EGG:
case PANDA_SPAWN_EGG:
case PARROT_SPAWN_EGG:
case PHANTOM_SPAWN_EGG:
case PIG_SPAWN_EGG:
case PILLAGER_SPAWN_EGG:
case POLAR_BEAR_SPAWN_EGG:
case PUFFERFISH_SPAWN_EGG:
case RABBIT_SPAWN_EGG:
case RAVAGER_SPAWN_EGG:
case SALMON_SPAWN_EGG:
case SHEEP_SPAWN_EGG:
case SHULKER_SPAWN_EGG:
@@ -996,11 +1051,13 @@ public final class Materials {
case SLIME_SPAWN_EGG:
case SQUID_SPAWN_EGG:
case STRAY_SPAWN_EGG:
case TRADER_LLAMA_SPAWN_EGG:
case TROPICAL_FISH_SPAWN_EGG:
case TURTLE_SPAWN_EGG:
case VEX_SPAWN_EGG:
case VILLAGER_SPAWN_EGG:
case VINDICATOR_SPAWN_EGG:
case WANDERING_TRADER_SPAWN_EGG:
case WITCH_SPAWN_EGG:
case WITHER_SKELETON_SPAWN_EGG:
case WOLF_SPAWN_EGG:
@@ -1020,8 +1077,12 @@ public final class Materials {
return EntityType.SPIDER;
case BAT_SPAWN_EGG:
return EntityType.BAT;
case BEE_SPAWN_EGG:
return EntityType.BEE;
case BLAZE_SPAWN_EGG:
return EntityType.BLAZE;
case CAT_SPAWN_EGG:
return EntityType.CAT;
case CAVE_SPIDER_SPAWN_EGG:
return EntityType.CAVE_SPIDER;
case CHICKEN_SPAWN_EGG:
@@ -1046,6 +1107,8 @@ public final class Materials {
return EntityType.ENDERMITE;
case EVOKER_SPAWN_EGG:
return EntityType.EVOKER;
case FOX_SPAWN_EGG:
return EntityType.FOX;
case GHAST_SPAWN_EGG:
return EntityType.GHAST;
case GUARDIAN_SPAWN_EGG:
@@ -1064,18 +1127,22 @@ public final class Materials {
return EntityType.MULE;
case OCELOT_SPAWN_EGG:
return EntityType.OCELOT;
case PANDA_SPAWN_EGG:
return EntityType.PANDA;
case PARROT_SPAWN_EGG:
return EntityType.PARROT;
case PHANTOM_SPAWN_EGG:
return EntityType.PHANTOM;
case PIG_SPAWN_EGG:
return EntityType.PIG;
case PILLAGER_SPAWN_EGG:
return EntityType.PILLAGER;
case POLAR_BEAR_SPAWN_EGG:
return EntityType.POLAR_BEAR;
case PUFFERFISH_SPAWN_EGG:
return EntityType.PUFFERFISH;
case RABBIT_SPAWN_EGG:
return EntityType.RABBIT;
case RAVAGER_SPAWN_EGG:
return EntityType.RAVAGER;
case SALMON_SPAWN_EGG:
return EntityType.SALMON;
case SHEEP_SPAWN_EGG:
@@ -1094,6 +1161,8 @@ public final class Materials {
return EntityType.SQUID;
case STRAY_SPAWN_EGG:
return EntityType.STRAY;
case TRADER_LLAMA_SPAWN_EGG:
return EntityType.TRADER_LLAMA;
case TROPICAL_FISH_SPAWN_EGG:
return EntityType.TROPICAL_FISH;
case TURTLE_SPAWN_EGG:
@@ -1104,6 +1173,8 @@ public final class Materials {
return EntityType.VILLAGER;
case VINDICATOR_SPAWN_EGG:
return EntityType.VINDICATOR;
case WANDERING_TRADER_SPAWN_EGG:
return EntityType.WANDERING_TRADER;
case WITCH_SPAWN_EGG:
return EntityType.WITCH;
case WITHER_SKELETON_SPAWN_EGG:
@@ -1118,33 +1189,21 @@ public final class Materials {
return EntityType.ZOMBIE;
case ZOMBIE_VILLAGER_SPAWN_EGG:
return EntityType.ZOMBIE_VILLAGER;
default:
return EntityType.PIG; // Uhhh
case PIG_SPAWN_EGG:
default: // Uhh
return EntityType.PIG;
}
}
public static boolean isBed(Material material) {
switch (material) {
case BLACK_BED:
case BLUE_BED:
case BROWN_BED:
case CYAN_BED:
case GRAY_BED:
case GREEN_BED:
case LIGHT_BLUE_BED:
case LIGHT_GRAY_BED:
case LIME_BED:
case MAGENTA_BED:
case ORANGE_BED:
case PINK_BED:
case PURPLE_BED:
case RED_BED:
case WHITE_BED:
case YELLOW_BED:
return true;
default:
return false;
}
return Tag.BEDS.isTagged(material);
}
public static boolean isCoral(Material material) {
return Tag.CORAL_BLOCKS.isTagged(material) ||
Tag.CORAL_PLANTS.isTagged(material) ||
Tag.CORALS.isTagged(material) ||
Tag.WALL_CORALS.isTagged(material);
}
/**
@@ -1160,7 +1219,11 @@ public final class Materials {
|| type == Material.MELON_STEM
|| type == Material.PUMPKIN_STEM
|| type == Material.PUMPKIN
|| type == Material.MELON;
|| type == Material.MELON
|| type == Material.CACTUS
|| type == Material.SUGAR_CANE
|| type == Material.BAMBOO
|| type == Material.BAMBOO_SAPLING;
}
/**
@@ -1175,26 +1238,33 @@ public final class Materials {
*/
public static boolean isUseFlagApplicable(Material material) {
if (Tag.BUTTONS.isTagged(material)
|| Tag.DOORS.isTagged(material)
|| Tag.WOODEN_PRESSURE_PLATES.isTagged(material)
|| Tag.WOODEN_TRAPDOORS.isTagged(material)) {
|| Tag.DOORS.isTagged(material)
|| Tag.WOODEN_PRESSURE_PLATES.isTagged(material)
|| Tag.WOODEN_TRAPDOORS.isTagged(material)) {
return true;
}
switch (material) {
case LEVER: return true;
case TRIPWIRE: return true;
case ENCHANTING_TABLE: return true;
case BEACON: return true;
case ANVIL: return true;
case STONE_PRESSURE_PLATE: return true;
case HEAVY_WEIGHTED_PRESSURE_PLATE: return true;
case LIGHT_WEIGHTED_PRESSURE_PLATE: return true;
case OAK_FENCE_GATE: return true;
case SPRUCE_FENCE_GATE: return true;
case BIRCH_FENCE_GATE: return true;
case JUNGLE_FENCE_GATE: return true;
case DARK_OAK_FENCE_GATE: return true;
case ACACIA_FENCE_GATE: return true;
case LEVER:
case LECTERN:
case ACACIA_FENCE_GATE:
case DARK_OAK_FENCE_GATE:
case JUNGLE_FENCE_GATE:
case BIRCH_FENCE_GATE:
case SPRUCE_FENCE_GATE:
case OAK_FENCE_GATE:
case LIGHT_WEIGHTED_PRESSURE_PLATE:
case HEAVY_WEIGHTED_PRESSURE_PLATE:
case STONE_PRESSURE_PLATE:
case ANVIL:
case DAMAGED_ANVIL:
case CHIPPED_ANVIL:
case ENCHANTING_TABLE:
case BELL:
case LOOM:
case CARTOGRAPHY_TABLE:
case STONECUTTER:
case GRINDSTONE:
return true;
default: return false;
}
}
@@ -1229,7 +1299,7 @@ public final class Materials {
*/
public static boolean isItemAppliedToBlock(Material item, Material block) {
Integer flags = MATERIAL_FLAGS.get(item);
return flags == null || (flags & MODIFIES_BLOCKS) == MODIFIES_BLOCKS;
return flags == null || (flags & MODIFIES_BLOCKS) == MODIFIES_BLOCKS || isToolApplicable(item, block);
}
/**
@@ -1262,4 +1332,129 @@ public final class Materials {
return false;
}
// should match instances of ItemArmor
/**
* Check if the material is equippable armor (i.e. that it is equipped on right-click
* not necessarily that it can be put in the armor slots)
*
* @param type material to check
* @return true if equippable armor
*/
public static boolean isArmor(Material type) {
switch (type) {
case LEATHER_HELMET:
case LEATHER_CHESTPLATE:
case LEATHER_LEGGINGS:
case LEATHER_BOOTS:
case CHAINMAIL_HELMET:
case CHAINMAIL_CHESTPLATE:
case CHAINMAIL_LEGGINGS:
case CHAINMAIL_BOOTS:
case IRON_HELMET:
case IRON_CHESTPLATE:
case IRON_LEGGINGS:
case IRON_BOOTS:
case DIAMOND_HELMET:
case DIAMOND_CHESTPLATE:
case DIAMOND_LEGGINGS:
case DIAMOND_BOOTS:
case GOLDEN_HELMET:
case GOLDEN_CHESTPLATE:
case GOLDEN_LEGGINGS:
case GOLDEN_BOOTS:
case TURTLE_HELMET:
case ELYTRA:
return true;
default:
return false;
}
}
/**
* Check if the material is usable via right-click on the target
* material. Returns false if the target material cannot be modified
* by the provided tool, or of the provided tool material isn't
* a tool material.
*
* @param toolMaterial the tool material being used
* @param targetMaterial the target material to check
* @return true if tool has an interact function with this material
*/
public static boolean isToolApplicable(Material toolMaterial, Material targetMaterial) {
switch (toolMaterial) {
case WOODEN_HOE:
case STONE_HOE:
case IRON_HOE:
case GOLDEN_HOE:
case DIAMOND_HOE:
switch (targetMaterial) {
case GRASS_BLOCK:
case DIRT:
case GRASS_PATH:
// case COARSE_DIRT: // already handled by the server...
return true;
}
return false;
case WOODEN_AXE:
case STONE_AXE:
case IRON_AXE:
case GOLDEN_AXE:
case DIAMOND_AXE:
switch (targetMaterial) {
case OAK_LOG:
case DARK_OAK_LOG:
case ACACIA_LOG:
case BIRCH_LOG:
case SPRUCE_LOG:
case JUNGLE_LOG:
case OAK_WOOD:
case DARK_OAK_WOOD:
case ACACIA_WOOD:
case BIRCH_WOOD:
case SPRUCE_WOOD:
case JUNGLE_WOOD:
return true;
}
return false;
case WOODEN_SHOVEL:
case STONE_SHOVEL:
case IRON_SHOVEL:
case GOLDEN_SHOVEL:
case DIAMOND_SHOVEL:
switch (targetMaterial) {
case GRASS_BLOCK:
case CAMPFIRE:
return true;
}
return false;
case SHEARS:
switch (targetMaterial) {
case PUMPKIN:
case BEE_NEST:
case BEEHIVE:
return true;
}
return false;
case BLACK_DYE:
case BLUE_DYE:
case BROWN_DYE:
case CYAN_DYE:
case GRAY_DYE:
case GREEN_DYE:
case LIGHT_BLUE_DYE:
case LIGHT_GRAY_DYE:
case LIME_DYE:
case MAGENTA_DYE:
case ORANGE_DYE:
case PINK_DYE:
case PURPLE_DYE:
case RED_DYE:
case WHITE_DYE:
case YELLOW_DYE:
return Tag.SIGNS.isTagged(targetMaterial);
default:
return false;
}
}
}
@@ -87,6 +87,9 @@ public class ClassSourceValidator {
* @param classes The list of classes to check
*/
public void reportMismatches(List<Class<?>> classes) {
if (Boolean.getBoolean("worldguard.disable.class.validation")) {
return;
}
Map<Class<?>, CodeSource> mismatches = findMismatches(classes);
if (!mismatches.isEmpty()) {
@@ -30,13 +30,8 @@ public class ServerReport extends DataReport {
Server server = Bukkit.getServer();
try {
append("Server ID", server.getServerId());
append("Server Name", server.getServerName());
} catch (NoSuchMethodError ignored) {
}
append("Bukkit Version", server.getBukkitVersion());
append("Implementation", server.getVersion());
append("Implementation", server.getName() + " " + server.getVersion());
append("Player Count", "%d/%d", Bukkit.getOnlinePlayers().size(), server.getMaxPlayers());
append("Server Class Source", server.getClass().getProtectionDomain().getCodeSource().getLocation());
@@ -0,0 +1,57 @@
/*
* WorldGuard, a suite of tools for Minecraft
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldGuard team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldguard.util.profile.resolver;
import com.destroystokyo.paper.profile.PlayerProfile;
import com.sk89q.worldguard.util.profile.Profile;
import io.papermc.lib.PaperLib;
import org.bukkit.Bukkit;
import javax.annotation.Nullable;
public final class PaperProfileService extends SingleRequestService {
private static final PaperProfileService INSTANCE = new PaperProfileService();
private PaperProfileService() {
if (!PaperLib.isPaper()) {
throw new IllegalStateException("Attempt to access PaperProfileService on non-Paper server.");
}
}
@Override
public int getIdealRequestLimit() {
return Integer.MAX_VALUE;
}
@Override
@Nullable
public Profile findByName(String name) {
PlayerProfile profile = Bukkit.createProfile(name);
if (profile.completeFromCache()) {
//noinspection ConstantConditions - completeFromCache guarantees non-null on success
return new Profile(profile.getId(), profile.getName());
}
return null;
}
public static PaperProfileService getInstance() {
return INSTANCE;
}
}
@@ -7,7 +7,7 @@
###############################################################################
#
# Example to block some ore mining and placement:
# [coalore,goldore,ironore]
# [coal_ore,gold_ore,iron_ore]
# on-break=deny,log,kick
# on-place=deny,tell
#
@@ -19,6 +19,8 @@
# - on-interact (when a block in used (doors, chests, etc.))
# - on-drop (an item is being dropped from the player's inventory)
# - on-acquire (an item enters a player's inventory via some method)
# - on-equip (an item is equipped to the player's armor slots)
# NOTE: on-equip is overprotective due to deficiencies in Bukkit API
# - on-dispense (a dispenser is about to dispense an item)
#
# Actions (for events):
@@ -40,7 +42,7 @@
###############################################################################
#
# For more information, see:
# http://wiki.sk89q.com/wiki/WorldGuard/Blacklist
# https://worldguard.enginehub.org/en/latest/blacklist/
#
###############################################################################
#
@@ -49,17 +51,12 @@
#
# Deny lava buckets
#[lavabucket]
#[lava_bucket]
#ignore-perms=my.own.madeup.permission
#ignore-groups=admins,mods
#on-use=deny,tell
# Deny some ore
#[coalore,goldore,ironore]
#[coal_ore,gold_ore,iron_ore]
#ignore-groups=admins,mods
#on-break=notify,deny,log
# Some funky data value tests
#[wood:0;>=2]
#ignore-groups=admins,mods
#on-break=notify,deny,log
@@ -1,6 +1,6 @@
name: WorldGuard
main: com.sk89q.worldguard.bukkit.WorldGuardPlugin
version: "${project.internalVersion}"
version: "${internalVersion}"
depend: [WorldEdit]
softdepend: [CommandBook]
api-version: 1.13
-31
View File
@@ -1,31 +0,0 @@
apply plugin: 'eclipse'
apply plugin: 'idea'
dependencies {
api 'com.sk89q.worldedit:worldedit-core:7.0.0-SNAPSHOT'
implementation 'com.sk89q.intake:intake:4.2-SNAPSHOT'
implementation 'com.sk89q:squirrelid:0.2.0'
implementation 'org.flywaydb:flyway-core:3.0'
implementation 'org.khelekore:prtree:1.5.0'
api 'com.google.code.findbugs:jsr305:1.3.9'
testImplementation 'junit:junit:4.11'
testImplementation 'org.hamcrest:hamcrest-library:1.2.1'
}
sourceSets {
main {
java {
srcDir 'src/main/java'
}
resources {
srcDir 'src/main/resources'
}
}
}
shadowJar {
relocate('com.sk89q.squirrelid', 'com.sk89q.worldguard.util.profile')
}
build.dependsOn(shadowJar { classifier = null })
+31
View File
@@ -0,0 +1,31 @@
plugins {
id("java-library")
id("net.ltgt.apt-eclipse")
id("net.ltgt.apt-idea")
}
applyPlatformAndCoreConfiguration()
dependencies {
"compile"(project(":worldguard-libs:core"))
"compile"("com.sk89q.worldedit:worldedit-core:${Versions.WORLDEDIT}")
"implementation"("org.flywaydb:flyway-core:3.0")
"compileOnly"("com.google.code.findbugs:jsr305:1.3.9")
"testImplementation"("org.hamcrest:hamcrest-library:1.2.1")
}
tasks.withType<JavaCompile>().configureEach {
dependsOn(":worldguard-libs:build")
}
sourceSets {
main {
java {
srcDir("src/main/java")
}
resources {
srcDir("src/main/resources")
}
}
}
@@ -207,4 +207,17 @@ public interface LocalPlayer extends Player, RegionAssociable {
*/
@Beta
void sendTitle(String title, String subtitle);
/**
* Clears fall distance.
*/
void resetFallDistance();
/**
* Teleport the player, potentially async, displaying the message on a success.
* @param location location to teleport to
* @param successMessage message to display on success
* @param failMessage message to display on failure
*/
void teleport(Location location, String successMessage, String failMessage);
}
@@ -24,14 +24,10 @@ import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;
import com.sk89q.minecraft.util.commands.CommandException;
import com.sk89q.squirrelid.cache.HashMapCache;
import com.sk89q.squirrelid.cache.ProfileCache;
import com.sk89q.squirrelid.cache.SQLiteCache;
import com.sk89q.squirrelid.resolver.BukkitPlayerService;
import com.sk89q.squirrelid.resolver.CacheForwardingService;
import com.sk89q.squirrelid.resolver.CombinedProfileService;
import com.sk89q.squirrelid.resolver.HttpRepositoryService;
import com.sk89q.squirrelid.resolver.ProfileService;
import com.sk89q.worldguard.util.profile.cache.HashMapCache;
import com.sk89q.worldguard.util.profile.cache.ProfileCache;
import com.sk89q.worldguard.util.profile.cache.SQLiteCache;
import com.sk89q.worldguard.util.profile.resolver.ProfileService;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.util.task.SimpleSupervisor;
import com.sk89q.worldedit.util.task.Supervisor;
@@ -77,23 +73,20 @@ public final class WorldGuard {
}
public void setup() {
executorService = MoreExecutors.listeningDecorator(EvenMoreExecutors.newBoundedCachedThreadPool(0, 1, 20));
executorService = MoreExecutors.listeningDecorator(EvenMoreExecutors.newBoundedCachedThreadPool(0, 1, 20,
"WorldGuard Task Executor - %s"));
File cacheDir = new File(getPlatform().getConfigDir().toFile(), "cache");
cacheDir.mkdirs();
try {
profileCache = new SQLiteCache(new File(cacheDir, "profiles.sqlite"));
} catch (IOException e) {
logger.log(Level.WARNING, "Failed to initialize SQLite profile cache");
} catch (IOException | UnsatisfiedLinkError ignored) {
logger.log(Level.WARNING, "Failed to initialize SQLite profile cache. Cache is memory-only.");
profileCache = new HashMapCache();
}
profileService = new CacheForwardingService(
new CombinedProfileService(
BukkitPlayerService.getInstance(),
HttpRepositoryService.forMinecraft()),
profileCache);
profileService = getPlatform().createProfileService(profileCache);
getPlatform().load();
}
@@ -27,13 +27,14 @@ public enum EventType {
DISPENSE(BlockDispenseBlacklistEvent.class, "on-dispense"),
DESTROY_WITH(ItemDestroyWithBlacklistEvent.class, "on-destroy-with"),
ACQUIRE(ItemAcquireBlacklistEvent.class, "on-acquire"),
EQUIP(ItemEquipBlacklistEvent.class, "on-equip"),
DROP(ItemDropBlacklistEvent.class, "on-drop"),
USE(ItemUseBlacklistEvent.class, "on-use");
private final Class<? extends BlacklistEvent> eventClass;
private final String ruleName;
private EventType(Class<? extends BlacklistEvent> eventClass, String ruleName) {
EventType(Class<? extends BlacklistEvent> eventClass, String ruleName) {
this.eventClass = eventClass;
this.ruleName = ruleName;
}
@@ -17,19 +17,35 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldguard.bukkit.listener;
package com.sk89q.worldguard.blacklist.event;
import com.google.common.base.Function;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.blacklist.target.Target;
import javax.annotation.Nullable;
class BlockStateAsBlockFunction implements Function<BlockState, Block> {
public final class ItemEquipBlacklistEvent extends ItemBlacklistEvent {
/**
* Construct the object.
*
* @param player The player associated with this event
* @param position The position the event occurred at
* @param target The target of the event
*/
public ItemEquipBlacklistEvent(@Nullable LocalPlayer player, BlockVector3 position, Target target) {
super(player, position, target);
}
@Override
public Block apply(@Nullable BlockState blockState) {
return blockState != null ? blockState.getBlock() : null;
public String getDescription() {
return "equip";
}
@Override
public EventType getEventType() {
return EventType.EQUIP;
}
}
@@ -24,7 +24,9 @@ import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.util.formatting.text.serializer.legacy.LegacyComponentSerializer;
import javax.annotation.Nullable;
import java.util.Arrays;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* Command-related utility methods.
@@ -76,7 +78,12 @@ public final class CommandUtils {
str = str.replace("`x", "&r");
// MC classic
str = LegacyComponentSerializer.INSTANCE.serialize(LegacyComponentSerializer.INSTANCE.deserialize(str, '&'));
// FIXME: workaround for https://github.com/KyoriPowered/text/issues/50
// remove when fixed upstream and updated in WorldEdit
str = Arrays.stream(str.split("\n")).map(line -> {
TextComponent comp = LegacyComponentSerializer.INSTANCE.deserialize(line, '&');
return LegacyComponentSerializer.INSTANCE.serialize(comp);
}).collect(Collectors.joining("\n"));
return str;
}
@@ -52,12 +52,13 @@ import com.sk89q.worldguard.util.profiler.SamplerBuilder;
import com.sk89q.worldguard.util.profiler.SamplerBuilder.Sampler;
import com.sk89q.worldguard.util.profiler.ThreadIdFilter;
import com.sk89q.worldguard.util.profiler.ThreadNameFilter;
import com.sk89q.worldguard.util.report.ApplicableRegionsReport;
import com.sk89q.worldguard.util.report.ConfigReport;
import java.io.File;
import java.io.IOException;
import java.lang.management.ThreadInfo;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.function.Predicate;
@@ -130,11 +131,14 @@ public class WorldGuardCommands {
worldGuard.getPlatform().addPlatformReports(report);
report.add(new SystemInfoReport());
report.add(new ConfigReport());
if (sender instanceof LocalPlayer) {
report.add(new ApplicableRegionsReport((LocalPlayer) sender));
}
String result = report.toString();
try {
File dest = new File(worldGuard.getPlatform().getConfigDir().toFile(), "report.txt");
Files.write(result, dest, Charset.forName("UTF-8"));
Files.write(result, dest, StandardCharsets.UTF_8);
sender.print("WorldGuard report written to " + dest.getAbsolutePath());
} catch (IOException e) {
throw new CommandException("Failed to write report: " + e.getMessage());
@@ -196,7 +200,7 @@ public class WorldGuardCommands {
synchronized (this) {
if (activeSampler != null) {
throw new CommandException("A profile is currently in progress! Please use /wg stopprofile to stop the current profile.");
throw new CommandException("A profile is currently in progress! Please use /wg stopprofile to cancel the current profile.");
}
SamplerBuilder builder = new SamplerBuilder();
@@ -206,10 +210,12 @@ public class WorldGuardCommands {
sampler = activeSampler = builder.start();
}
sender.print(TextComponent.of("Starting CPU profiling. Use ", TextColor.LIGHT_PURPLE)
sender.print(TextComponent.of("Starting CPU profiling. Results will be available in " + minutes + " minutes.", TextColor.LIGHT_PURPLE)
.append(TextComponent.newline())
.append(TextComponent.of("Use ", TextColor.GRAY))
.append(TextComponent.of("/wg stopprofile", TextColor.AQUA)
.clickEvent(ClickEvent.of(ClickEvent.Action.RUN_COMMAND, "/wg stopprofile")))
.append(TextComponent.of(" to stop profiling.", TextColor.LIGHT_PURPLE)));
.clickEvent(ClickEvent.of(ClickEvent.Action.SUGGEST_COMMAND, "/wg stopprofile")))
.append(TextComponent.of(" at any time to cancel CPU profiling.", TextColor.GRAY)));
worldGuard.getSupervisor().monitor(FutureForwardingTask.create(
sampler.getFuture(), "CPU profiling for " + minutes + " minutes", sender));
@@ -227,7 +233,7 @@ public class WorldGuardCommands {
try {
File dest = new File(worldGuard.getPlatform().getConfigDir().toFile(), "profile.txt");
Files.write(output, dest, Charset.forName("UTF-8"));
Files.write(output, dest, StandardCharsets.UTF_8);
sender.print("CPU profiling data written to " + dest.getAbsolutePath());
} catch (IOException e) {
sender.printError("Failed to write CPU profiling data: " + e.getMessage());
@@ -256,7 +262,7 @@ public class WorldGuardCommands {
activeSampler = null;
}
sender.print("The running CPU profile has been stopped.");
sender.print("The running CPU profile has been cancelled.");
}
@Command(aliases = {"flushstates", "clearstates"},
@@ -38,11 +38,10 @@ import com.sk89q.worldedit.world.World;
import com.sk89q.worldguard.WorldGuard;
import com.sk89q.worldguard.internal.permission.RegionPermissionModel;
import com.sk89q.worldguard.protection.flags.BooleanFlag;
import com.sk89q.worldguard.protection.flags.DoubleFlag;
import com.sk89q.worldguard.protection.flags.Flag;
import com.sk89q.worldguard.protection.flags.Flags;
import com.sk89q.worldguard.protection.flags.IntegerFlag;
import com.sk89q.worldguard.protection.flags.LocationFlag;
import com.sk89q.worldguard.protection.flags.NumberFlag;
import com.sk89q.worldguard.protection.flags.RegistryFlag;
import com.sk89q.worldguard.protection.flags.SetFlag;
import com.sk89q.worldguard.protection.flags.StateFlag;
@@ -76,13 +75,15 @@ class FlagHelperBox extends PaginationBox {
.collect(Collectors.toList());
private static final int SIZE = FLAGS.size() == Flags.INBUILT_FLAGS.size() ? FLAGS.size() : FLAGS.size() + 1;
private static final int PAD_PX_SIZE = 180;
static final Set<Flag<?>> DANGER_ZONE = ImmutableSet.of(Flags.BUILD, Flags.PASSTHROUGH, Flags.BLOCK_PLACE, Flags.BLOCK_BREAK);
private final World world;
private final ProtectedRegion region;
private final RegionPermissionModel perms;
private boolean monoSpace;
FlagHelperBox(World world, ProtectedRegion region, RegionPermissionModel perms) {
super("Flags for " + region.getId(), "/rg flags -w " + world.getName() + " -p %page% " + region.getId());
super("Flags for " + region.getId(), "/rg flags -w \"" + world.getName() + "\" -p %page% " + region.getId());
this.world = world;
this.region = region;
this.perms = perms;
@@ -114,25 +115,25 @@ class FlagHelperBox extends PaginationBox {
private void appendFlagName(TextComponent.Builder builder, Flag<?> flag, TextColor color) {
final String name = flag.getName();
int length = FlagFontInfo.getPxLength(name);
int length = monoSpace ? name.length() : FlagFontInfo.getPxLength(name);
builder.append(TextComponent.of(name, color));
if (flag.usesMembershipAsDefault()) {
builder.append(TextComponent.empty().append(TextComponent.of("*", TextColor.AQUA))
.hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT,
TextComponent.of("This is a special flag which defaults to allow for members, and deny for non-members"))));
length += FlagFontInfo.getPxLength('*');
length += monoSpace ? 1 : FlagFontInfo.getPxLength('*');
}
if (flag == Flags.PASSTHROUGH) {
builder.append(TextComponent.empty().append(TextComponent.of("*", TextColor.AQUA))
.hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT,
TextComponent.of("This is a special flag which overrides build checks. (Not movement related!)"))));
length += FlagFontInfo.getPxLength('*');
length += monoSpace ? 1 : FlagFontInfo.getPxLength('*');
}
int leftover = PAD_PX_SIZE - length;
int leftover = (monoSpace ? PAD_PX_SIZE / 3 : PAD_PX_SIZE) - length;
builder.append(TextComponent.space());
leftover -= 4;
if (leftover > 0) {
builder.append(TextComponent.of(Strings.repeat(".", leftover / 2), TextColor.DARK_GRAY));
builder.append(TextComponent.of(Strings.repeat(".", monoSpace ? leftover : leftover / 2), TextColor.DARK_GRAY));
}
}
@@ -149,10 +150,8 @@ class FlagHelperBox extends PaginationBox {
appendStringFlagValue(builder, ((StringFlag) flag));
} else if (flag instanceof LocationFlag) {
appendLocationFlagValue(builder, ((LocationFlag) flag));
} else if (flag instanceof IntegerFlag) {
appendNumericFlagValue(builder, (IntegerFlag) flag);
} else if (flag instanceof DoubleFlag) {
appendNumericFlagValue(builder, (DoubleFlag) flag);
} else if (flag instanceof NumberFlag) {
appendNumericFlagValue(builder, (NumberFlag<? extends Number>) flag);
} else {
String display = String.valueOf(region.getFlag(flag));
if (display.length() > 23) {
@@ -200,6 +199,12 @@ class FlagHelperBox extends PaginationBox {
if (maySet) {
if (isExplicitSet) {
hoverTexts.add(TextComponent.of("Click to unset", TextColor.GOLD));
} else if (DANGER_ZONE.contains(flag) && !(ProtectedRegion.GLOBAL_REGION.equals(region.getId()) && flag == Flags.PASSTHROUGH)) {
hoverTexts.add(TextComponent.of("Setting this flag may have unintended consequences.", TextColor.RED)
.append(TextComponent.newline())
.append(TextComponent.of("Please read the documentation and set this flag manually if you really intend to.")
.append(TextComponent.newline())
.append(TextComponent.of("(Hint: You do not need to set this to protect the region!)"))));
} else {
hoverTexts.add(TextComponent.of("Click to set", TextColor.GOLD));
}
@@ -221,7 +226,7 @@ class FlagHelperBox extends PaginationBox {
HoverEvent.of(HoverEvent.Action.SHOW_TEXT, hoverBuilder.build()));
}
if (maySet) {
if (maySet && (isExplicitSet || !DANGER_ZONE.contains(flag))) {
builder.append(choiceComponent.clickEvent(ClickEvent.of(ClickEvent.Action.RUN_COMMAND,
makeCommand(flag, isExplicitSet ? "" : choice))));
} else {
@@ -296,7 +301,7 @@ class FlagHelperBox extends PaginationBox {
}
private String makeCommand(Flag<?> flag, Object choice) {
return "/rg flag -w " + world.getName() + " -h " + getCurrentPage()
return "/rg flag -w \"" + world.getName() + "\" -h " + getCurrentPage()
+ " " + region.getId() + " " + flag.getName() + " " + choice;
}
@@ -397,13 +402,13 @@ class FlagHelperBox extends PaginationBox {
}
}
private <V extends Number> void appendNumericFlagValue(TextComponent.Builder builder, Flag<V> flag) {
private <V extends Number> void appendNumericFlagValue(TextComponent.Builder builder, NumberFlag<V> flag) {
Number currVal = region.getFlag(flag);
if (currVal == null) {
currVal = getInheritedValue(region, flag);
}
Number defVal = flag.getDefault();
Number[] suggested = getSuggestedNumbers(flag);
Number[] suggested = flag.getSuggestedValues();
SortedSet<Number> choices = new TreeSet<>(Comparator.comparing(Number::doubleValue));
if (currVal != null) {
choices.add(currVal);
@@ -418,19 +423,6 @@ class FlagHelperBox extends PaginationBox {
appendValueChoices(builder, flag, (Iterator<V>) choices.iterator(), choices.isEmpty() ? "unset number" : "[custom]");
}
private Number[] getSuggestedNumbers(Flag<? extends Number> flag) {
if (flag == Flags.HEAL_AMOUNT || flag == Flags.FEED_AMOUNT) {
return new Number[]{0, 5, 10, 20};
} else if (flag == Flags.MIN_FOOD || flag == Flags.MIN_HEAL) {
return new Number[]{0, 10};
} else if (flag == Flags.MAX_FOOD || flag == Flags.MAX_HEAL) {
return new Number[]{10, 20};
} else if (flag == Flags.HEAL_DELAY || flag == Flags.FEED_DELAY) {
return new Number[]{0, 1, 5};
}
return new Number[0];
}
private void appendStringFlagValue(TextComponent.Builder builder, StringFlag flag) {
String currVal = region.getFlag(flag);
if (currVal == null) {
@@ -479,6 +471,10 @@ class FlagHelperBox extends PaginationBox {
}
}
void tryMonoSpacing() {
this.monoSpace = true;
}
private static final class FlagFontInfo {
static int getPxLength(char c) {
switch (c) {
@@ -82,41 +82,19 @@ public class MemberCommands extends RegionCommandsBase {
flags = "nw:",
desc = "Add an owner to a region",
min = 2)
public void addOwner(CommandContext args, Actor sender) throws CommandException, AuthorizationException {
public void addOwner(CommandContext args, Actor sender) throws CommandException {
warnAboutSaveFailures(sender);
World world = checkWorld(args, sender, 'w'); // Get the world
LocalPlayer player = null;
if (sender instanceof LocalPlayer) {
player = (LocalPlayer) sender;
}
String id = args.getString(0);
RegionManager manager = checkRegionManager(world);
ProtectedRegion region = checkExistingRegion(manager, id, true);
id = region.getId();
DefaultDomain owners = region.getOwners();
if (player != null) {
if (owners != null && owners.size() == 0) {
if (!sender.hasPermission("worldguard.region.unlimited")) {
int maxRegionCount = WorldGuard.getInstance().getPlatform().getGlobalStateManager().get(world).getMaxRegionCount(player);
if (maxRegionCount >= 0 && manager.getRegionCountOfPlayer(player)
>= maxRegionCount) {
throw new CommandException("You already own the maximum allowed amount of regions.");
}
}
sender.checkPermission("worldguard.region.addowner.unclaimed." + id.toLowerCase());
} else {
// Check permissions
if (!getPermissionModel(player).mayAddOwners(region)) {
throw new CommandPermissionsException();
}
}
// Check permissions
if (!getPermissionModel(sender).mayAddOwners(region)) {
throw new CommandPermissionsException();
}
// Resolve owners asynchronously
@@ -126,13 +104,46 @@ public class MemberCommands extends RegionCommandsBase {
final String description = String.format("Adding owners to the region '%s' on '%s'", region.getId(), world.getName());
AsyncCommandBuilder.wrap(resolver, sender)
AsyncCommandBuilder.wrap(checkedAddOwners(sender, manager, region, world, resolver), sender)
.registerWithSupervisor(worldGuard.getSupervisor(), description)
.onSuccess(String.format("Region '%s' updated with new owners.", region.getId()), region.getOwners()::addAll)
.onFailure("Failed to add new owners", worldGuard.getExceptionConverter())
.buildAndExec(worldGuard.getExecutorService());
}
private static Callable<DefaultDomain> checkedAddOwners(Actor sender, RegionManager manager, ProtectedRegion region,
World world, DomainInputResolver resolver) {
return () -> {
DefaultDomain owners = resolver.call();
// TODO this was always broken and never checked other players
if (sender instanceof LocalPlayer) {
LocalPlayer player = (LocalPlayer) sender;
if (owners.contains(player) && !sender.hasPermission("worldguard.region.unlimited")) {
int maxRegionCount = WorldGuard.getInstance().getPlatform().getGlobalStateManager()
.get(world).getMaxRegionCount(player);
if (maxRegionCount >= 0 && manager.getRegionCountOfPlayer(player)
>= maxRegionCount) {
throw new CommandException("You already own the maximum allowed amount of regions.");
}
}
}
if (region.getOwners().size() == 0) {
boolean anyOwners = false;
ProtectedRegion parent = region;
while ((parent = parent.getParent()) != null) {
if (parent.getOwners().size() > 0) {
anyOwners = true;
break;
}
}
if (!anyOwners) {
sender.checkPermission("worldguard.region.addowner.unclaimed." + region.getId().toLowerCase());
}
}
return owners;
};
}
@Command(aliases = {"removemember", "remmember", "removemem", "remmem", "rm"},
usage = "<id> <owners...>",
flags = "naw:",
@@ -25,6 +25,7 @@ import com.google.common.collect.Sets;
import com.sk89q.minecraft.util.commands.Command;
import com.sk89q.minecraft.util.commands.CommandContext;
import com.sk89q.minecraft.util.commands.CommandException;
import com.sk89q.minecraft.util.commands.CommandPermissions;
import com.sk89q.minecraft.util.commands.CommandPermissionsException;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.command.util.AsyncCommandBuilder;
@@ -73,12 +74,14 @@ import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import com.sk89q.worldguard.protection.regions.ProtectedRegion.CircularInheritanceException;
import com.sk89q.worldguard.protection.regions.RegionContainer;
import com.sk89q.worldguard.protection.util.DomainInputResolver.UserLocatorPolicy;
import com.sk89q.worldguard.session.Session;
import com.sk89q.worldguard.util.Enums;
import com.sk89q.worldguard.util.logging.LoggerToChatHandler;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
@@ -95,7 +98,29 @@ public final class RegionCommands extends RegionCommandsBase {
checkNotNull(worldGuard);
this.worldGuard = worldGuard;
}
private static TextComponent passthroughFlagWarning = TextComponent.empty()
.append(TextComponent.of("WARNING:", TextColor.RED, Sets.newHashSet(TextDecoration.BOLD)))
.append(ErrorFormat.wrap(" This flag is unrelated to moving through regions."))
.append(TextComponent.newline())
.append(TextComponent.of("It overrides build checks. If you're unsure what this means, see ")
.append(TextComponent.of("[this documentation page]", TextColor.AQUA)
.clickEvent(ClickEvent.of(ClickEvent.Action.OPEN_URL,
"https://worldguard.enginehub.org/en/latest/regions/flags/#overrides")))
.append(TextComponent.of(" for more info.")));
private static TextComponent buildFlagWarning = TextComponent.empty()
.append(TextComponent.of("WARNING:", TextColor.RED, Sets.newHashSet(TextDecoration.BOLD)))
.append(ErrorFormat.wrap(" Setting this flag is not required for protection."))
.append(TextComponent.newline())
.append(TextComponent.of("Setting this flag will completely override default protection, and apply" +
" to members, non-members, pistons, sand physics, and everything else that can modify blocks."))
.append(TextComponent.newline())
.append(TextComponent.of("Only set this flag if you are sure you know what you are doing. See ")
.append(TextComponent.of("[this documentation page]", TextColor.AQUA)
.clickEvent(ClickEvent.of(ClickEvent.Action.OPEN_URL,
"https://worldguard.enginehub.org/en/latest/regions/flags/#protection-related")))
.append(TextComponent.of(" for more info.")));
/**
* Defines a new region.
*
@@ -104,22 +129,22 @@ public final class RegionCommands extends RegionCommandsBase {
* @throws CommandException any error
*/
@Command(aliases = {"define", "def", "d", "create"},
usage = "<id> [<owner1> [<owner2> [<owners...>]]]",
flags = "ng",
usage = "[-w <world>] <id> [<owner1> [<owner2> [<owners...>]]]",
flags = "ngw:",
desc = "Defines a region",
min = 1)
public void define(CommandContext args, Actor sender) throws CommandException {
warnAboutSaveFailures(sender);
LocalPlayer player = worldGuard.checkPlayer(sender);
// Check permissions
if (!getPermissionModel(player).mayDefine()) {
if (!getPermissionModel(sender).mayDefine()) {
throw new CommandPermissionsException();
}
String id = checkRegionId(args.getString(0), false);
RegionManager manager = checkRegionManager(player.getWorld());
World world = checkWorld(args, sender, 'w');
RegionManager manager = checkRegionManager(world);
checkRegionDoesNotExist(manager, id, true);
@@ -128,9 +153,7 @@ public final class RegionCommands extends RegionCommandsBase {
if (args.hasFlag('g')) {
region = new GlobalProtectedRegion(id);
} else {
region = checkRegionFromSelection(player, id);
warnAboutDimensions(player, region);
informNewUser(player, manager, region);
region = checkRegionFromSelection(sender, id);
}
RegionAdder task = new RegionAdder(manager, region);
@@ -139,8 +162,14 @@ public final class RegionCommands extends RegionCommandsBase {
final String description = String.format("Adding region '%s'", region.getId());
AsyncCommandBuilder.wrap(task, sender)
.registerWithSupervisor(worldGuard.getSupervisor(), description)
.onSuccess(String.format("A new region has been made named '%s'.", region.getId()), null)
.onFailure("Failed to add the region '%s'", worldGuard.getExceptionConverter())
.onSuccess((Component) null,
t -> {
sender.print(String.format("A new region has been made named '%s'.", region.getId()));
warnAboutDimensions(sender, region);
informNewUser(sender, manager, region);
checkSpawnOverlap(sender, world, region);
})
.onFailure(String.format("Failed to add the region '%s'", region.getId()), worldGuard.getExceptionConverter())
.buildAndExec(worldGuard.getExecutorService());
}
@@ -152,23 +181,22 @@ public final class RegionCommands extends RegionCommandsBase {
* @throws CommandException any error
*/
@Command(aliases = {"redefine", "update", "move"},
usage = "<id>",
usage = "[-w <world>] <id>",
desc = "Re-defines the shape of a region",
flags = "g",
flags = "gw:",
min = 1, max = 1)
public void redefine(CommandContext args, Actor sender) throws CommandException {
warnAboutSaveFailures(sender);
LocalPlayer player = worldGuard.checkPlayer(sender);
String id = checkRegionId(args.getString(0), false);
RegionManager manager = checkRegionManager(player.getWorld());
World world = checkWorld(args, sender, 'w');
RegionManager manager = checkRegionManager(world);
ProtectedRegion existing = checkExistingRegion(manager, id, false);
// Check permissions
if (!getPermissionModel(player).mayRedefine(existing)) {
if (!getPermissionModel(sender).mayRedefine(existing)) {
throw new CommandPermissionsException();
}
@@ -177,9 +205,7 @@ public final class RegionCommands extends RegionCommandsBase {
if (args.hasFlag('g')) {
region = new GlobalProtectedRegion(id);
} else {
region = checkRegionFromSelection(player, id);
warnAboutDimensions(player, region);
informNewUser(player, manager, region);
region = checkRegionFromSelection(sender, id);
}
region.copyFrom(existing);
@@ -190,7 +216,13 @@ public final class RegionCommands extends RegionCommandsBase {
AsyncCommandBuilder.wrap(task, sender)
.registerWithSupervisor(worldGuard.getSupervisor(), description)
.sendMessageAfterDelay("(Please wait... " + description + ")")
.onSuccess(String.format("Region '%s' has been updated with a new area.", region.getId()), null)
.onSuccess((Component) null,
t -> {
sender.print(String.format("Region '%s' has been updated with a new area.", region.getId()));
warnAboutDimensions(sender, region);
informNewUser(sender, manager, region);
checkSpawnOverlap(sender, world, region);
})
.onFailure(String.format("Failed to update the region '%s'", region.getId()), worldGuard.getExceptionConverter())
.buildAndExec(worldGuard.getExecutorService());
}
@@ -303,28 +335,34 @@ public final class RegionCommands extends RegionCommandsBase {
* @throws CommandException any error
*/
@Command(aliases = {"select", "sel", "s"},
usage = "[id]",
usage = "[-w <world>] [id]",
desc = "Load a region as a WorldEdit selection",
min = 0, max = 1)
min = 0, max = 1,
flags = "w:")
public void select(CommandContext args, Actor sender) throws CommandException {
LocalPlayer player = worldGuard.checkPlayer(sender);
RegionManager manager = checkRegionManager(player.getWorld());
World world = checkWorld(args, sender, 'w');
RegionManager manager = checkRegionManager(world);
ProtectedRegion existing;
// If no arguments were given, get the region that the player is inside
if (args.argsLength() == 0) {
existing = checkRegionStandingIn(manager, player, "/rg select %id%");
LocalPlayer player = worldGuard.checkPlayer(sender);
if (!player.getWorld().equals(world)) { // confusing to get current location regions in another world
throw new CommandException("Please specify a region name."); // just don't allow that
}
world = player.getWorld();
existing = checkRegionStandingIn(manager, player, "/rg select -w \"" + world.getName() + "\" %id%");
} else {
existing = checkExistingRegion(manager, args.getString(0), false);
}
// Check permissions
if (!getPermissionModel(player).maySelect(existing)) {
if (!getPermissionModel(sender).maySelect(existing)) {
throw new CommandPermissionsException();
}
// Select
setPlayerSelection(player, existing);
setPlayerSelection(sender, existing, world);
}
/**
@@ -355,7 +393,7 @@ public final class RegionCommands extends RegionCommandsBase {
}
existing = checkRegionStandingIn(manager, (LocalPlayer) sender, true,
"/rg info -w " + world.getName() + " %id%" + (args.hasFlag('u') ? " -u" : "") + (args.hasFlag('s') ? " -s" : ""));
"/rg info -w \"" + world.getName() + "\" %id%" + (args.hasFlag('u') ? " -u" : "") + (args.hasFlag('s') ? " -s" : ""));
} else { // Get region from the ID
existing = checkExistingRegion(manager, args.getString(0), true);
}
@@ -372,7 +410,7 @@ public final class RegionCommands extends RegionCommandsBase {
throw new CommandPermissionsException();
}
setPlayerSelection(worldGuard.checkPlayer(sender), existing);
setPlayerSelection(worldGuard.checkPlayer(sender), existing, world);
}
// Print region information
@@ -382,7 +420,10 @@ public final class RegionCommands extends RegionCommandsBase {
AsyncCommandBuilder.wrap(printout, sender)
.registerWithSupervisor(WorldGuard.getInstance().getSupervisor(), "Fetching region info")
.sendMessageAfterDelay("(Please wait... fetching region information...)")
.onSuccess((Component) null, sender::print)
.onSuccess((Component) null, component -> {
sender.print(component);
checkSpawnOverlap(sender, world, existing);
})
.onFailure("Failed to fetch region information", WorldGuard.getInstance().getExceptionConverter())
.buildAndExec(WorldGuard.getInstance().getExecutorService());
}
@@ -471,11 +512,6 @@ public final class RegionCommands extends RegionCommandsBase {
value = "";
}
// Add color codes
if (value != null) {
value = CommandUtils.replaceColorMacros(value);
}
// Lookup the existing region
RegionManager manager = checkRegionManager(world);
ProtectedRegion existing = checkExistingRegion(manager, args.getString(0), true);
@@ -484,77 +520,30 @@ public final class RegionCommands extends RegionCommandsBase {
if (!permModel.maySetFlag(existing)) {
throw new CommandPermissionsException();
}
String regionId = existing.getId();
Flag<?> foundFlag = Flags.fuzzyMatchFlag(flagRegistry, flagName);
// We didn't find the flag, so let's print a list of flags that the user
// can use, and do nothing afterwards
if (foundFlag == null) {
ArrayList<String> flagList = new ArrayList<>();
// Need to build a list
for (Flag<?> flag : flagRegistry) {
// Can the user set this flag?
if (!permModel.maySetFlag(existing, flag)) {
continue;
}
flagList.add(flag.getName());
}
Collections.sort(flagList);
final TextComponent.Builder builder = TextComponent.builder("Available flags: ");
final HoverEvent clickToSet = HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to set"));
for (int i = 0; i < flagList.size(); i++) {
String flag = flagList.get(i);
builder.append(TextComponent.of(flag, i % 2 == 0 ? TextColor.GRAY : TextColor.WHITE)
.hoverEvent(clickToSet).clickEvent(ClickEvent.of(ClickEvent.Action.SUGGEST_COMMAND,
"/rg flag -w " + world.getName() + " " + existing.getId() + " " + flag + " ")));
if (i < flagList.size() + 1) {
builder.append(TextComponent.of(", "));
}
}
sender.printError("Unknown flag specified: " + flagName);
sender.print(builder.build());
if (sender.isPlayer()) {
sender.print(TextComponent.of("Or use the command ", TextColor.LIGHT_PURPLE)
.append(TextComponent.of("/rg flags " + existing.getId(), TextColor.AQUA)
.clickEvent(ClickEvent.of(ClickEvent.Action.RUN_COMMAND,
"/rg flags -w " + world.getName() + " " + existing.getId()))));
}
AsyncCommandBuilder.wrap(new FlagListBuilder(flagRegistry, permModel, existing, world,
regionId, sender, flagName), sender)
.registerWithSupervisor(WorldGuard.getInstance().getSupervisor(), "Flag list for invalid flag command.")
.onSuccess((Component) null, sender::print)
.onFailure((Component) null, WorldGuard.getInstance().getExceptionConverter())
.buildAndExec(WorldGuard.getInstance().getExecutorService());
return;
} else if (value != null) {
if (foundFlag == Flags.BUILD || foundFlag == Flags.BLOCK_BREAK || foundFlag == Flags.BLOCK_PLACE) {
sender.print(TextComponent.empty().append(TextComponent.of("WARNING:", TextColor.RED, Sets.newHashSet(TextDecoration.BOLD)))
.append(ErrorFormat.wrap(" Setting the " + foundFlag.getName() + " flag is not required for protection."))
.append(TextComponent.newline())
.append(TextComponent.of("Setting this flag will completely override default protection, and apply" +
" to members, non-members, pistons, and everything else that can modify blocks."))
.append(TextComponent.newline())
.append(TextComponent.of("Only set this flag if you are sure you know what you are doing. See ")
.append(TextComponent.of("[this documentation page]", TextColor.AQUA)
.clickEvent(ClickEvent.of(ClickEvent.Action.OPEN_URL,
"https://worldguard.readthedocs.io/en/latest/regions/flags/#protection-related")))
.append(TextComponent.of(" for more info."))));
sender.print(buildFlagWarning);
if (!sender.isPlayer()) {
sender.printRaw("https://worldguard.readthedocs.io/en/latest/regions/flags/#protection-related");
sender.printRaw("https://worldguard.enginehub.org/en/latest/regions/flags/#protection-related");
}
} else if (foundFlag == Flags.PASSTHROUGH) {
sender.print(TextComponent.empty().append(TextComponent.of("WARNING:", TextColor.RED, Sets.newHashSet(TextDecoration.BOLD)))
.append(ErrorFormat.wrap(" This flag is unrelated to moving through regions."))
.append(TextComponent.newline())
.append(TextComponent.of("It overrides build checks. If you're unsure what this means, see ")
.append(TextComponent.of("[this documentation page]", TextColor.AQUA)
.clickEvent(ClickEvent.of(ClickEvent.Action.OPEN_URL,
"https://worldguard.readthedocs.io/en/latest/regions/flags/#overrides")))
.append(TextComponent.of(" for more info."))));
sender.print(passthroughFlagWarning);
if (!sender.isPlayer()) {
sender.printRaw("https://worldguard.readthedocs.io/en/latest/regions/flags/#overrides");
sender.printRaw("https://worldguard.enginehub.org/en/latest/regions/flags/#overrides");
}
}
}
@@ -590,13 +579,13 @@ public final class RegionCommands extends RegionCommandsBase {
if (value != null) {
// Set the flag if [value] was given even if [-g group] was given as well
try {
setFlag(existing, foundFlag, sender, value);
value = setFlag(existing, foundFlag, sender, value).toString();
} catch (InvalidFlagFormat e) {
throw new CommandException(e.getMessage());
}
if (!args.hasFlag('h')) {
sender.print("Region flag " + foundFlag.getName() + " set on '" + existing.getId() + "' to '" + value + "'.");
sender.print("Region flag " + foundFlag.getName() + " set on '" + regionId + "' to '" + value + "'.");
}
// No value? Clear the flag, if -g isn't specified
@@ -611,7 +600,7 @@ public final class RegionCommands extends RegionCommandsBase {
}
if (!args.hasFlag('h')) {
sender.print("Region flag " + foundFlag.getName() + " removed from '" + existing.getId() + "'. (Any -g(roups) were also removed.)");
sender.print("Region flag " + foundFlag.getName() + " removed from '" + regionId + "'. (Any -g(roups) were also removed.)");
}
}
@@ -639,6 +628,7 @@ public final class RegionCommands extends RegionCommandsBase {
printout.appendFlagsList(false);
printout.append(SubtleFormat.wrap(")"));
printout.send(sender);
checkSpawnOverlap(sender, world, existing);
}
}
@@ -659,7 +649,7 @@ public final class RegionCommands extends RegionCommandsBase {
}
region = checkRegionStandingIn(manager, (LocalPlayer) sender, true,
"/rg flags -w " + world.getName() + " %id%");
"/rg flags -w \"" + world.getName() + "\" %id%");
} else { // Get region from the ID
region = checkExistingRegion(manager, args.getString(0), true);
}
@@ -676,7 +666,15 @@ public final class RegionCommands extends RegionCommandsBase {
private static void sendFlagHelper(Actor sender, World world, ProtectedRegion region, RegionPermissionModel perms, int page) {
final FlagHelperBox flagHelperBox = new FlagHelperBox(world, region, perms);
flagHelperBox.setComponentsPerPage(18);
AsyncCommandBuilder.wrap(() -> flagHelperBox.create(page), sender)
if (!sender.isPlayer()) {
flagHelperBox.tryMonoSpacing();
}
AsyncCommandBuilder.wrap(() -> {
if (checkSpawnOverlap(sender, world, region)) {
flagHelperBox.setComponentsPerPage(15);
}
return flagHelperBox.create(page);
}, sender)
.onSuccess((Component) null, sender::print)
.onFailure("Failed to get region flags", WorldGuard.getInstance().getExceptionConverter())
.buildAndExec(WorldGuard.getInstance().getExecutorService());
@@ -712,6 +710,7 @@ public final class RegionCommands extends RegionCommandsBase {
existing.setPriority(priority);
sender.print("Priority of '" + existing.getId() + "' set to " + priority + " (higher numbers override).");
checkSpawnOverlap(sender, world, existing);
}
/**
@@ -766,7 +765,7 @@ public final class RegionCommands extends RegionCommandsBase {
// Tell the user the current inheritance
RegionPrintoutBuilder printout = new RegionPrintoutBuilder(world.getName(), child, null, sender);
printout.append(LabelFormat.wrap("Inheritance set for region '", child.getId(), "'."));
printout.append(TextComponent.of("Inheritance set for region '" + child.getId() + "'.", TextColor.LIGHT_PURPLE));
if (parent != null) {
printout.newline();
printout.append(SubtleFormat.wrap("(Current inheritance:")).newline();
@@ -1112,7 +1111,94 @@ public final class RegionCommands extends RegionCommandsBase {
}
}
player.setLocation(teleportLocation);
sender.print("Teleported you to the region '" + existing.getId() + "'.");
String message = existing.getFlag(Flags.TELE_MESSAGE);
// If the flag isn't set, use the default message
// If message.isEmpty(), no message is sent by LocalPlayer#teleport(...)
if (message == null) {
message = Flags.TELE_MESSAGE.getDefault();
}
player.teleport(teleportLocation,
message.replace("%id%", existing.getId()),
"Unable to teleport to region '" + existing.getId() + "'.");
}
@Command(aliases = {"toggle-bypass", "bypass"},
desc = "Toggle region bypassing, effectively ignoring bypass permissions.")
@CommandPermissions({"worldguard.region.toggle-bypass"})
public void toggleBypass(CommandContext args, Actor sender) throws CommandException {
LocalPlayer player = worldGuard.checkPlayer(sender);
Session session = WorldGuard.getInstance().getPlatform().getSessionManager().get(player);
if (session.hasBypassDisabled()) {
session.setBypassDisabled(false);
player.print("You are now bypassing region protection (as long as you have permission).");
} else {
session.setBypassDisabled(true);
player.print("You are no longer bypassing region protection.");
}
}
private static class FlagListBuilder implements Callable<Component> {
private final FlagRegistry flagRegistry;
private final RegionPermissionModel permModel;
private final ProtectedRegion existing;
private final World world;
private final String regionId;
private final Actor sender;
private final String flagName;
FlagListBuilder(FlagRegistry flagRegistry, RegionPermissionModel permModel, ProtectedRegion existing,
World world, String regionId, Actor sender, String flagName) {
this.flagRegistry = flagRegistry;
this.permModel = permModel;
this.existing = existing;
this.world = world;
this.regionId = regionId;
this.sender = sender;
this.flagName = flagName;
}
@Override
public Component call() {
ArrayList<String> flagList = new ArrayList<>();
// Need to build a list
for (Flag<?> flag : flagRegistry) {
// Can the user set this flag?
if (!permModel.maySetFlag(existing, flag)) {
continue;
}
flagList.add(flag.getName());
}
Collections.sort(flagList);
final TextComponent.Builder builder = TextComponent.builder("Available flags: ");
final HoverEvent clickToSet = HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to set"));
for (int i = 0; i < flagList.size(); i++) {
String flag = flagList.get(i);
builder.append(TextComponent.of(flag, i % 2 == 0 ? TextColor.GRAY : TextColor.WHITE)
.hoverEvent(clickToSet).clickEvent(ClickEvent.of(ClickEvent.Action.SUGGEST_COMMAND,
"/rg flag -w \"" + world.getName() + "\" " + regionId + " " + flag + " ")));
if (i < flagList.size() + 1) {
builder.append(TextComponent.of(", "));
}
}
Component ret = ErrorFormat.wrap("Unknown flag specified: " + flagName)
.append(TextComponent.newline())
.append(builder.build());
if (sender.isPlayer()) {
return ret.append(TextComponent.of("Or use the command ", TextColor.LIGHT_PURPLE)
.append(TextComponent.of("/rg flags " + regionId, TextColor.AQUA)
.clickEvent(ClickEvent.of(ClickEvent.Action.RUN_COMMAND,
"/rg flags -w \"" + world.getName() + "\" " + regionId))));
}
return ret;
}
}
}
@@ -20,6 +20,7 @@
package com.sk89q.worldguard.commands.region;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
import com.sk89q.minecraft.util.commands.CommandContext;
import com.sk89q.minecraft.util.commands.CommandException;
import com.sk89q.worldedit.IncompleteRegionException;
@@ -32,11 +33,13 @@ import com.sk89q.worldedit.regions.Polygonal2DRegion;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.regions.selector.CuboidRegionSelector;
import com.sk89q.worldedit.regions.selector.Polygonal2DRegionSelector;
import com.sk89q.worldedit.util.formatting.component.ErrorFormat;
import com.sk89q.worldedit.util.formatting.component.SubtleFormat;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.util.formatting.text.event.ClickEvent;
import com.sk89q.worldedit.util.formatting.text.event.HoverEvent;
import com.sk89q.worldedit.util.formatting.text.format.TextColor;
import com.sk89q.worldedit.util.formatting.text.format.TextDecoration;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.WorldGuard;
@@ -81,9 +84,25 @@ class RegionCommandsBase {
* @throws CommandException on error
*/
protected static World checkWorld(CommandContext args, Actor sender, char flag) throws CommandException {
return checkWorld(args, sender, flag, true);
}
protected static World checkWorld(CommandContext args, Actor sender, char flag, boolean allowWorldEditOverride) throws CommandException {
if (args.hasFlag(flag)) {
return WorldGuard.getInstance().getPlatform().getMatcher().matchWorld(sender, args.getFlag(flag));
} else {
if (allowWorldEditOverride) {
try {
World override = WorldEdit.getInstance().getSessionManager().get(sender).getWorldOverride();
if (override != null) {
if (sender instanceof LocalPlayer && !override.equals(((LocalPlayer) sender).getWorld())) {
sender.printDebug(TextComponent.of("Using //world override for region command: " + override.getName()));
}
return override;
}
} catch (NoSuchMethodError ignored) {
}
}
if (sender instanceof LocalPlayer) {
return ((LocalPlayer) sender).getWorld();
} else {
@@ -216,21 +235,22 @@ class RegionCommandsBase {
}
/**
* Get a WorldEdit selection for a player, or emit an exception if there is none
* Get a WorldEdit selection for an actor, or emit an exception if there is none
* available.
*
* @param player the player
* @param actor the actor
* @return the selection
* @throws CommandException thrown on an error
*/
protected static Region checkSelection(LocalPlayer player) throws CommandException {
protected static Region checkSelection(Actor actor) throws CommandException {
try {
return WorldEdit.getInstance().getSessionManager().get(player).getRegionSelector(player.getWorld()).getRegion();
LocalSession localSession = WorldEdit.getInstance().getSessionManager().get(actor);
return localSession.getRegionSelector(localSession.getSelectionWorld()).getRegion();
} catch (IncompleteRegionException e) {
throw new CommandException(
"Please select an area first. " +
"Use WorldEdit to make a selection! " +
"(wiki: http://wiki.sk89q.com/wiki/WorldEdit).");
"(see: https://worldedit.enginehub.org/en/latest/usage/regions/selections/).");
}
}
@@ -254,7 +274,7 @@ class RegionCommandsBase {
* @param world the world
* @throws CommandException thrown if the manager is null
*/
protected static RegionManager checkRegionManager(com.sk89q.worldedit.world.World world) throws CommandException {
protected static RegionManager checkRegionManager(World world) throws CommandException {
if (!WorldGuard.getInstance().getPlatform().getGlobalStateManager().get(world).useRegions) {
throw new CommandException("Region support is disabled in the target world. " +
"It can be enabled per-world in WorldGuard's configuration files. " +
@@ -270,15 +290,15 @@ class RegionCommandsBase {
}
/**
* Create a {@link ProtectedRegion} from the player's selection.
* Create a {@link ProtectedRegion} from the actor's selection.
*
* @param player the player
* @param actor the actor
* @param id the ID of the new region
* @return a new region
* @throws CommandException thrown on an error
*/
protected static ProtectedRegion checkRegionFromSelection(LocalPlayer player, String id) throws CommandException {
Region selection = checkSelection(player);
protected static ProtectedRegion checkRegionFromSelection(Actor actor, String id) throws CommandException {
Region selection = checkSelection(actor);
// Detect the type of region from WorldEdit
if (selection instanceof Polygonal2DRegion) {
@@ -320,6 +340,9 @@ class RegionCommandsBase {
* @param region the region
*/
protected static void warnAboutDimensions(Actor sender, ProtectedRegion region) {
if (region instanceof GlobalProtectedRegion) {
return;
}
int height = region.getMaximumPoint().getBlockY() - region.getMinimumPoint().getBlockY();
if (height <= 2) {
sender.printDebug("(Warning: The height of the region was " + (height + 1) + " block(s).)");
@@ -334,7 +357,7 @@ class RegionCommandsBase {
* @param region the region
*/
protected static void informNewUser(Actor sender, RegionManager manager, ProtectedRegion region) {
if (manager.getRegions().size() <= 2) {
if (manager.size() <= 2) {
sender.print(SubtleFormat.wrap("(This region is NOW PROTECTED from modification from others. Don't want that? Use ")
.append(TextComponent.of("/rg flag " + region.getId() + " passthrough allow", TextColor.AQUA))
.append(TextComponent.of(")", TextColor.GRAY)));
@@ -342,14 +365,34 @@ class RegionCommandsBase {
}
/**
* Set a player's selection to a given region.
* Inform a user if the region overlaps spawn protection.
*
* @param player the player
* @param sender the sender to send the message to
* @param world the world the region is in
* @param region the region
*/
protected static boolean checkSpawnOverlap(Actor sender, World world, ProtectedRegion region) {
ProtectedRegion spawn = WorldGuard.getInstance().getPlatform().getSpawnProtection(world);
if (spawn != null) {
if (!spawn.getIntersectingRegions(ImmutableList.of(region)).isEmpty()) {
sender.print(ErrorFormat.wrap("Warning!")
.append(TextComponent.of(" This region overlaps vanilla's spawn protection. WorldGuard cannot " +
"override this, and only server operators will be able to interact with this area.", TextColor.WHITE)));
return true;
}
}
return false;
}
/**
* Set an actor's selection to a given region.
*
* @param actor the actor
* @param region the region
* @throws CommandException thrown on a command error
*/
protected static void setPlayerSelection(LocalPlayer player, ProtectedRegion region) throws CommandException {
LocalSession session = WorldEdit.getInstance().getSessionManager().get(player);
protected static void setPlayerSelection(Actor actor, ProtectedRegion region, World world) throws CommandException {
LocalSession session = WorldEdit.getInstance().getSessionManager().get(actor);
// Set selection
if (region instanceof ProtectedCuboidRegion) {
@@ -357,17 +400,20 @@ class RegionCommandsBase {
BlockVector3 pt1 = cuboid.getMinimumPoint();
BlockVector3 pt2 = cuboid.getMaximumPoint();
session.setRegionSelector(player.getWorld(), new CuboidRegionSelector(player.getWorld(), pt1, pt2));
player.print("Region selected as a cuboid.");
CuboidRegionSelector selector = new CuboidRegionSelector(world, pt1, pt2);
session.setRegionSelector(world, selector);
selector.explainRegionAdjust(actor, session);
actor.print("Region selected as a cuboid.");
} else if (region instanceof ProtectedPolygonalRegion) {
ProtectedPolygonalRegion poly2d = (ProtectedPolygonalRegion) region;
Polygonal2DRegionSelector selector = new Polygonal2DRegionSelector(
player.getWorld(), poly2d.getPoints(),
world, poly2d.getPoints(),
poly2d.getMinimumPoint().getBlockY(),
poly2d.getMaximumPoint().getBlockY() );
session.setRegionSelector(player.getWorld(), selector);
player.print("Region selected as a polygon.");
poly2d.getMaximumPoint().getBlockY());
session.setRegionSelector(world, selector);
selector.explainRegionAdjust(actor, session);
actor.print("Region selected as a polygon.");
} else if (region instanceof GlobalProtectedRegion) {
throw new CommandException(
@@ -389,8 +435,10 @@ class RegionCommandsBase {
* @param value the value
* @throws InvalidFlagFormat thrown if the value is invalid
*/
protected static <V> void setFlag(ProtectedRegion region, Flag<V> flag, Actor sender, String value) throws InvalidFlagFormat {
region.setFlag(flag, flag.parseInput(FlagContext.create().setSender(sender).setInput(value).setObject("region", region).build()));
protected static <V> V setFlag(ProtectedRegion region, Flag<V> flag, Actor sender, String value) throws InvalidFlagFormat {
V val = flag.parseInput(FlagContext.create().setSender(sender).setInput(value).setObject("region", region).build());
region.setFlag(flag, val);
return val;
}
}
@@ -19,7 +19,8 @@
package com.sk89q.worldguard.commands.region;
import com.sk89q.squirrelid.cache.ProfileCache;
import com.sk89q.worldguard.protection.flags.registry.UnknownFlag;
import com.sk89q.worldguard.util.profile.cache.ProfileCache;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.util.Location;
@@ -86,7 +87,7 @@ public class RegionPrintoutBuilder implements Callable<TextComponent> {
public void appendBasics() {
builder.append(TextComponent.of("Region: ", TextColor.BLUE));
builder.append(TextComponent.of(region.getId(), TextColor.YELLOW)
.clickEvent(ClickEvent.of(ClickEvent.Action.RUN_COMMAND, "/rg info -w " + world + " " + region.getId())));
.clickEvent(ClickEvent.of(ClickEvent.Action.RUN_COMMAND, "/rg info -w \"" + world + "\" " + region.getId())));
builder.append(TextComponent.of(" (type=", TextColor.GRAY));
builder.append(TextComponent.of(region.getType().getName()));
@@ -143,12 +144,26 @@ public class RegionPrintoutBuilder implements Callable<TextComponent> {
flagString = flag.getName() + " -g " + group + ": ";
}
TextComponent flagText = TextComponent.of(flagString, useColors ? TextColor.GOLD : TextColor.WHITE)
.append(TextComponent.of(String.valueOf(val), useColors? TextColor.YELLOW : TextColor.WHITE));
TextColor flagColor = TextColor.WHITE;
if (useColors) {
// passthrough is ok on global
if (FlagHelperBox.DANGER_ZONE.contains(flag)
&& !(region.getId().equals(ProtectedRegion.GLOBAL_REGION) && flag == Flags.PASSTHROUGH)) {
flagColor = TextColor.DARK_RED;
} else if (Flags.INBUILT_FLAGS.contains(flag.getName())) {
flagColor = TextColor.GOLD;
} else if (flag instanceof UnknownFlag) {
flagColor = TextColor.GRAY;
} else {
flagColor = TextColor.LIGHT_PURPLE;
}
}
TextComponent flagText = TextComponent.of(flagString, flagColor)
.append(TextComponent.of(String.valueOf(val), useColors ? TextColor.YELLOW : TextColor.WHITE));
if (perms != null && perms.maySetFlag(region, flag)) {
flagText = flagText.hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to set flag")))
.clickEvent(ClickEvent.of(ClickEvent.Action.SUGGEST_COMMAND,
"/rg flag -w " + world + " " + region.getId() + " " + flag.getName() + " "));
"/rg flag -w \"" + world + "\" " + region.getId() + " " + flag.getName() + " "));
}
builder.append(flagText);
@@ -164,7 +179,7 @@ public class RegionPrintoutBuilder implements Callable<TextComponent> {
builder.append(TextComponent.space())
.append(TextComponent.of("[Flags]", useColors ? TextColor.GREEN : TextColor.GRAY)
.hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to set a flag")))
.clickEvent(ClickEvent.of(ClickEvent.Action.RUN_COMMAND, "/rg flags -w " + world + " " + region.getId())));
.clickEvent(ClickEvent.of(ClickEvent.Action.RUN_COMMAND, "/rg flags -w \"" + world + "\" " + region.getId())));
}
}
@@ -217,7 +232,7 @@ public class RegionPrintoutBuilder implements Callable<TextComponent> {
if (perms != null && perms.mayLookup(cur)) {
builder.append(TextComponent.of(cur.getId(), useColors ? TextColor.GREEN : TextColor.WHITE)
.hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click for info")))
.clickEvent(ClickEvent.of(ClickEvent.Action.RUN_COMMAND, "/rg info -w " + world + " " + cur.getId())));
.clickEvent(ClickEvent.of(ClickEvent.Action.RUN_COMMAND, "/rg info -w \"" + world + "\" " + cur.getId())));
} else {
builder.append(TextComponent.of(cur.getId(), useColors ? TextColor.GREEN : TextColor.WHITE));
}
@@ -232,7 +247,7 @@ public class RegionPrintoutBuilder implements Callable<TextComponent> {
builder.append(TextComponent.space());
builder.append(TextComponent.of("[X]", TextColor.RED)
.hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to unlink parent")))
.clickEvent(ClickEvent.of(ClickEvent.Action.SUGGEST_COMMAND, "/rg setparent -w " + world + " " + cur.getId())));
.clickEvent(ClickEvent.of(ClickEvent.Action.SUGGEST_COMMAND, "/rg setparent -w \"" + world + "\" " + cur.getId())));
}
last = cur;
@@ -272,17 +287,17 @@ public class RegionPrintoutBuilder implements Callable<TextComponent> {
builder.append(TextComponent.space().append(TextComponent.of("[Add]", TextColor.GREEN)
.hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to add a player or group")))
.clickEvent(ClickEvent.of(ClickEvent.Action.SUGGEST_COMMAND,
"/rg " + addCommand + " -w " + world + " " + region.getId() + " "))));
"/rg " + addCommand + " -w \"" + world + "\" " + region.getId() + " "))));
}
if (removeCommand != null && domain.size() > 0) {
builder.append(TextComponent.space().append(TextComponent.of("[Rem]", TextColor.RED)
.hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to remove a player or group")))
.clickEvent(ClickEvent.of(ClickEvent.Action.SUGGEST_COMMAND,
"/rg " + removeCommand + " -w " + world + " " + region.getId() + " "))));
"/rg " + removeCommand + " -w \"" + world + "\" " + region.getId() + " "))));
builder.append(TextComponent.space().append(TextComponent.of("[Clr]", TextColor.RED)
.hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to clear")))
.clickEvent(ClickEvent.of(ClickEvent.Action.SUGGEST_COMMAND,
"/rg " + removeCommand + " -w " + world + " -a " + region.getId()))));
"/rg " + removeCommand + " -w \"" + world + "\" -a " + region.getId()))));
}
}
@@ -293,8 +308,7 @@ public class RegionPrintoutBuilder implements Callable<TextComponent> {
BlockVector3 min = region.getMinimumPoint();
BlockVector3 max = region.getMaximumPoint();
builder.append(TextComponent.of("Bounds:", TextColor.BLUE));
TextComponent bound = TextComponent.of(" (" + min.getBlockX() + "," + min.getBlockY() + "," + min.getBlockZ() + ")"
+ " -> (" + max.getBlockX() + "," + max.getBlockY() + "," + max.getBlockZ() + ")", TextColor.YELLOW);
TextComponent bound = TextComponent.of(" " + min + " -> " + max, TextColor.YELLOW);
if (perms != null && perms.maySelect(region)) {
bound = bound
.hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to select")))
@@ -302,15 +316,15 @@ public class RegionPrintoutBuilder implements Callable<TextComponent> {
}
builder.append(bound);
final Location teleFlag = region.getFlag(Flags.TELE_LOC);
if (perms != null && perms.mayTeleportTo(region) && teleFlag != null) {
if (teleFlag != null && perms != null && perms.mayTeleportTo(region)) {
builder.append(TextComponent.space().append(TextComponent.of("[Teleport]", TextColor.GRAY)
.hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT,
TextComponent.of("Click to teleport").append(TextComponent.newline()).append(
TextComponent.of(teleFlag.getBlockY() + ", "
TextComponent.of(teleFlag.getBlockX() + ", "
+ teleFlag.getBlockY() + ", "
+ teleFlag.getBlockZ()))))
.clickEvent(ClickEvent.of(ClickEvent.Action.RUN_COMMAND,
"/rg tp -w " + world + " " + region.getId()))));
"/rg tp -w \"" + world + "\" " + region.getId()))));
}
newline();
@@ -321,7 +335,7 @@ public class RegionPrintoutBuilder implements Callable<TextComponent> {
if (perms != null && perms.maySetPriority(rg)) {
builder.append(TextComponent.of(content, TextColor.GOLD)
.hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to change")))
.clickEvent(ClickEvent.of(ClickEvent.Action.SUGGEST_COMMAND, "/rg setpriority -w " + world + " " + rg.getId() + " ")));
.clickEvent(ClickEvent.of(ClickEvent.Action.SUGGEST_COMMAND, "/rg setpriority -w \"" + world + "\" " + rg.getId() + " ")));
} else {
builder.append(TextComponent.of(content, TextColor.WHITE));
}
@@ -22,7 +22,7 @@ package com.sk89q.worldguard.commands.task;
import static com.google.common.base.Preconditions.checkNotNull;
import com.sk89q.minecraft.util.commands.CommandException;
import com.sk89q.squirrelid.Profile;
import com.sk89q.worldguard.util.profile.Profile;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.util.formatting.component.PaginationBox;
import com.sk89q.worldedit.util.formatting.text.Component;
@@ -33,6 +33,7 @@ import com.sk89q.worldedit.util.formatting.text.format.TextColor;
import com.sk89q.worldguard.WorldGuard;
import com.sk89q.worldguard.domains.DefaultDomain;
import com.sk89q.worldguard.internal.permission.RegionPermissionModel;
import com.sk89q.worldguard.protection.flags.Flags;
import com.sk89q.worldguard.protection.managers.RegionManager;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
@@ -175,7 +176,7 @@ public class RegionLister implements Callable<Integer> {
RegionPermissionModel perms = sender.isPlayer() ? new RegionPermissionModel(sender) : null;
String title = ownerMatcher == null ? "Regions" : "Regions for " + ownerMatcher.getName();
String cmd = "/rg list -w " + world
String cmd = "/rg list -w \"" + world + "\""
+ (playerName != null ? " -p " + playerName : "")
+ (nameOnly ? " -n" : "")
+ " %page%";
@@ -258,7 +259,13 @@ public class RegionLister implements Callable<Integer> {
builder.append(TextComponent.space().append(TextComponent.of("[Info]", TextColor.GRAY)
.hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click for info")))
.clickEvent(ClickEvent.of(ClickEvent.Action.RUN_COMMAND,
"/rg info -w " + world + " " + entry.region.getId()))));
"/rg info -w \"" + world + "\" " + entry.region.getId()))));
}
if (perms != null && entry.region.getFlag(Flags.TELE_LOC) != null && perms.mayTeleportTo(entry.region)) {
builder.append(TextComponent.space().append(TextComponent.of("[TP]", TextColor.GRAY)
.hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to teleport")))
.clickEvent(ClickEvent.of(ClickEvent.Action.RUN_COMMAND,
"/rg tp -w \"" + world + "\" " + entry.region.getId()))));
}
return builder.build();
}
@@ -19,15 +19,21 @@
package com.sk89q.worldguard.config;
import com.sk89q.worldedit.util.report.Unreported;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockType;
import com.sk89q.worldedit.world.block.BlockTypes;
import com.sk89q.worldedit.world.entity.EntityType;
import com.sk89q.worldedit.world.item.ItemType;
import com.sk89q.worldedit.world.item.ItemTypes;
import com.sk89q.worldedit.world.registry.LegacyMapper;
import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.blacklist.Blacklist;
import com.sk89q.worldedit.util.report.Unreported;
import java.io.File;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.logging.Logger;
import java.util.stream.Collectors;
@@ -55,7 +61,8 @@ public abstract class WorldConfiguration {
protected File blacklistFile;
@Unreported protected Blacklist blacklist;
@Unreported
protected Blacklist blacklist;
public boolean boundedLocationFlags;
public boolean useRegions;
@@ -111,6 +118,7 @@ public abstract class WorldConfiguration {
public boolean teleportOnSuffocation;
public boolean disableVoidDamage;
public boolean teleportOnVoid;
public boolean safeFallOnVoid;
public boolean disableExplosionDamage;
public boolean disableMobDamage;
public boolean highFreqFlags;
@@ -134,6 +142,7 @@ public abstract class WorldConfiguration {
public boolean alwaysRaining;
public boolean alwaysThundering;
public boolean disablePigZap;
public boolean disableVillagerZap;
public boolean disableCreeperPower;
public boolean disableHealthRegain;
public boolean disableMushroomSpread;
@@ -149,16 +158,19 @@ public abstract class WorldConfiguration {
public boolean disableEndermanGriefing;
public boolean disableSnowmanTrails;
public boolean disableSoilDehydration;
public boolean disableCoralBlockFade;
public Set<String> allowedSnowFallOver;
public boolean regionInvinciblityRemovesMobs;
public boolean regionCancelEmptyChatEvents;
public boolean regionNetherPortalProtection;
public boolean forceDefaultTitleTimes;
public boolean fakePlayerBuildOverride;
public boolean explosionFlagCancellation;
public boolean disableDeathMessages;
public boolean disableObsidianGenerators;
public boolean strictEntitySpawn;
public boolean ignoreHopperMoveEvents;
public boolean breakDeniedHoppers;
protected Map<String, Integer> maxRegionCounts;
/**
@@ -171,49 +183,63 @@ public abstract class WorldConfiguration {
}
public List<String> convertLegacyItems(List<String> legacyItems) {
return legacyItems.stream().map(this::convertLegacyItem).collect(Collectors.toList());
return legacyItems.stream().map(this::convertLegacyItem).filter(Objects::nonNull).collect(Collectors.toList());
}
public String convertLegacyItem(String legacy) {
String item = legacy;
String[] splitter = legacy.split(":", 2);
try {
String[] splitter = item.split(":", 2);
int id = 0;
byte data = 0;
int id;
byte data;
if (splitter.length == 1) {
id = Integer.parseInt(item);
id = Integer.parseInt(splitter[0]);
data = 0;
} else {
id = Integer.parseInt(splitter[0]);
data = Byte.parseByte(splitter[1]);
}
item = LegacyMapper.getInstance().getItemFromLegacy(id, data).getId();
} catch (Throwable e) {
ItemType legacyItem = LegacyMapper.getInstance().getItemFromLegacy(id, data);
if (legacyItem != null) {
return legacyItem.getId();
}
} catch (NumberFormatException ignored) {
}
final ItemType itemType = ItemTypes.get(legacy);
if (itemType != null) {
return itemType.getId();
}
return item;
return null;
}
public List<String> convertLegacyBlocks(List<String> legacyBlocks) {
return legacyBlocks.stream().map(this::convertLegacyBlock).collect(Collectors.toList());
return legacyBlocks.stream().map(this::convertLegacyBlock).filter(Objects::nonNull).collect(Collectors.toList());
}
public String convertLegacyBlock(String legacy) {
String block = legacy;
String[] splitter = legacy.split(":", 2);
try {
String[] splitter = block.split(":", 2);
int id = 0;
byte data = 0;
int id;
byte data;
if (splitter.length == 1) {
id = Integer.parseInt(block);
id = Integer.parseInt(splitter[0]);
data = 0;
} else {
id = Integer.parseInt(splitter[0]);
data = Byte.parseByte(splitter[1]);
}
block = LegacyMapper.getInstance().getBlockFromLegacy(id, data).getBlockType().getId();
} catch (Throwable e) {
BlockState legacyBlock = LegacyMapper.getInstance().getBlockFromLegacy(id, data);
if (legacyBlock != null) {
return legacyBlock.getBlockType().getId();
}
} catch (NumberFormatException ignored) {
}
final BlockType blockType = BlockTypes.get(legacy);
if (blockType != null) {
return blockType.getId();
}
return block;
return null;
}
public int getMaxRegionCount(LocalPlayer player) {
@@ -22,8 +22,8 @@ package com.sk89q.worldguard.domains;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.sk89q.squirrelid.Profile;
import com.sk89q.squirrelid.cache.ProfileCache;
import com.sk89q.worldguard.util.profile.Profile;
import com.sk89q.worldguard.util.profile.cache.ProfileCache;
import com.sk89q.worldedit.util.formatting.text.Component;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.util.formatting.text.event.ClickEvent;
@@ -311,7 +311,7 @@ public class DefaultDomain implements Domain, ChangeTracked {
public String toGroupsString() {
StringBuilder str = new StringBuilder();
for (Iterator<String> it = groupDomain.getGroups().iterator(); it.hasNext(); ) {
str.append("*");
str.append("g:");
str.append(it.next());
if (it.hasNext()) {
str.append(", ");
@@ -373,7 +373,8 @@ public class DefaultDomain implements Domain, ChangeTracked {
private Component toGroupsComponent() {
final TextComponent.Builder builder = TextComponent.builder("");
for (Iterator<String> it = groupDomain.getGroups().iterator(); it.hasNext(); ) {
builder.append(TextComponent.of(it.next(), TextColor.GOLD));
builder.append(TextComponent.of("g:", TextColor.GRAY))
.append(TextComponent.of(it.next(), TextColor.GOLD));
if (it.hasNext()) {
builder.append(TextComponent.of(", "));
}
@@ -23,6 +23,7 @@ import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.WorldGuard;
import com.sk89q.worldguard.protection.flags.Flag;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
@@ -37,7 +38,13 @@ public class RegionPermissionModel extends AbstractPermissionModel {
super(sender);
}
/**
* @deprecated Check {@code WorldGuard.getInstance().getPlatform().getSessionManager().hasBypass(..)} instead
*/
@Deprecated
public boolean mayIgnoreRegionProtection(World world) {
if (getSender() instanceof LocalPlayer)
return WorldGuard.getInstance().getPlatform().getSessionManager().hasBypass((LocalPlayer) getSender(), world);
return hasPluginPermission("region.bypass." + world.getName());
}
@@ -21,13 +21,18 @@ package com.sk89q.worldguard.internal.platform;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.util.report.ReportList;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.gamemode.GameMode;
import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.config.ConfigurationManager;
import com.sk89q.worldguard.protection.flags.FlagContext;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import com.sk89q.worldguard.protection.regions.RegionContainer;
import com.sk89q.worldguard.session.SessionManager;
import com.sk89q.worldguard.util.profile.cache.ProfileCache;
import com.sk89q.worldguard.util.profile.resolver.ProfileService;
import javax.annotation.Nullable;
import java.nio.file.Path;
/**
@@ -148,4 +153,20 @@ public interface WorldGuardPlatform {
* @param report The reportlist
*/
void addPlatformReports(ReportList report);
/**
* Internal use.
*/
ProfileService createProfileService(ProfileCache profileCache);
/**
* Get a region that encompasses the Vanilla spawn protection for the given world, if applicable.
*
* @param world world to check spawn protection of
* @return a region, or null if not applicable
*/
@Nullable
default ProtectedRegion getSpawnProtection(World world) {
return null;
}
}
@@ -65,7 +65,7 @@ public interface ApplicableRegionSet extends Iterable<ProtectedRegion> {
*
* <p>{@code subject} can be non-null to satisfy region group requirements,
* otherwise it will be assumed that the caller that is not a member of any
* regions. (FlagUtil on a region can be changed so that they only apply
* regions. (Flags on a region can be changed so that they only apply
* to certain users.) The subject argument is required if the
* {@link Flags#BUILD} flag is in the list of flags.</p>
*
@@ -83,7 +83,7 @@ public interface ApplicableRegionSet extends Iterable<ProtectedRegion> {
*
* <p>{@code subject} can be non-null to satisfy region group requirements,
* otherwise it will be assumed that the caller that is not a member of any
* regions. (FlagUtil on a region can be changed so that they only apply
* regions. (Flags on a region can be changed so that they only apply
* to certain users.) The subject argument is required if the
* {@link Flags#BUILD} flag is in the list of flags.</p>
*
@@ -108,7 +108,7 @@ public interface ApplicableRegionSet extends Iterable<ProtectedRegion> {
*
* <p>{@code subject} can be non-null to satisfy region group requirements,
* otherwise it will be assumed that the caller that is not a member of any
* regions. (FlagUtil on a region can be changed so that they only apply
* regions. (Flags on a region can be changed so that they only apply
* to certain users.) The subject argument is required if the
* {@link Flags#BUILD} flag is the flag being queried.</p>
*
@@ -126,7 +126,7 @@ public interface ApplicableRegionSet extends Iterable<ProtectedRegion> {
*
* <p>{@code subject} can be non-null to satisfy region group requirements,
* otherwise it will be assumed that the caller that is not a member of any
* regions. (FlagUtil on a region can be changed so that they only apply
* regions. (Flags on a region can be changed so that they only apply
* to certain users.) The subject argument is required if the
* {@link Flags#BUILD} flag is the flag being queried.</p>
*
@@ -361,7 +361,8 @@ public class FlagValueCalculator {
if (flag == Flags.PASSTHROUGH) {
// Has members/owners -> the global region acts like
// a regular region without PASSTHROUGH
if (region.hasMembersOrOwners() || region.getFlag(Flags.PASSTHROUGH) == State.DENY) {
State passthrough = region.getFlag(Flags.PASSTHROUGH);
if (passthrough == State.DENY || passthrough != State.ALLOW && region.hasMembersOrOwners()) {
return null;
} else {
return (V) State.ALLOW;
@@ -22,7 +22,7 @@ package com.sk89q.worldguard.protection.flags;
/**
* Stores doubles.
*/
public class DoubleFlag extends Flag<Double> {
public class DoubleFlag extends NumberFlag<Double> {
public DoubleFlag(String name, RegionGroup defaultGroup) {
super(name, defaultGroup);
@@ -34,6 +34,7 @@ import com.sk89q.worldguard.protection.flags.registry.FlagRegistry;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Consumer;
/**
* The flags that are used in WorldGuard.
@@ -68,6 +69,7 @@ public final class Flags {
public static final StateFlag POTION_SPLASH = register(new StateFlag("potion-splash", false));
public static final StateFlag ITEM_FRAME_ROTATE = register(new StateFlag("item-frame-rotation", false));
public static final StateFlag TRAMPLE_BLOCKS = register(new StateFlag("block-trampling", false));
public static final StateFlag FIREWORK_DAMAGE = register(new StateFlag("firework-damage", false));
// These flags are similar to the ones above (used in tandem with BUILD),
// but their defaults are set to TRUE because it is more user friendly.
@@ -86,11 +88,11 @@ public final class Flags {
public static final StateFlag CREEPER_EXPLOSION = register(new StateFlag("creeper-explosion", true));
public static final StateFlag ENDERDRAGON_BLOCK_DAMAGE = register(new StateFlag("enderdragon-block-damage", true));
public static final StateFlag GHAST_FIREBALL = register(new StateFlag("ghast-fireball", true));
public static final StateFlag FIREWORK_DAMAGE = register(new StateFlag("firework-damage", true));
public static final StateFlag OTHER_EXPLOSION = register(new StateFlag("other-explosion", true));
public static final StateFlag WITHER_DAMAGE = register(new StateFlag("wither-damage", true));
public static final StateFlag ENDER_BUILD = register(new StateFlag("enderman-grief", true));
public static final StateFlag SNOWMAN_TRAILS = register(new StateFlag("snowman-trails", true));
public static final StateFlag RAVAGER_RAVAGE = register(new StateFlag("ravager-grief", true));
public static final StateFlag ENTITY_PAINTING_DESTROY = register(new StateFlag("entity-painting-destroy", true));
public static final StateFlag ENTITY_ITEM_FRAME_DESTROY = register(new StateFlag("entity-item-frame-destroy", true));
@@ -116,6 +118,7 @@ public final class Flags {
public static final StateFlag VINE_GROWTH = register(new StateFlag("vine-growth", true));
public static final StateFlag CROP_GROWTH = register(new StateFlag("crop-growth", true));
public static final StateFlag SOIL_DRY = register(new StateFlag("soil-dry", true));
public static final StateFlag CORAL_FADE = register(new StateFlag("coral-fade", true));
public static final StateFlag WATER_FLOW = register(new StateFlag("water-flow", true));
public static final StateFlag LAVA_FLOW = register(new StateFlag("lava-flow", true));
@@ -132,9 +135,20 @@ public final class Flags {
public static final LocationFlag TELE_LOC = register(new LocationFlag("teleport", RegionGroup.MEMBERS));
public static final LocationFlag SPAWN_LOC = register(new LocationFlag("spawn", RegionGroup.MEMBERS));
/**
* @deprecated The type of this flag will change from a StringFlag to a ComponentFlag to support JSON text
* in a future release. If you depend on the type of this flag, take proper precaution for future breakage.
*/
@Deprecated
public static final StringFlag TELE_MESSAGE = register(new StringFlag("teleport-message",
LegacyComponentSerializer.INSTANCE.serialize(TextComponent.of("").append(TextComponent.of(
"Teleported you to the region '%id%'.", TextColor.LIGHT_PURPLE)))));
// idk?
public static final StateFlag INVINCIBILITY = register(new StateFlag("invincible", false));
public static final StateFlag FALL_DAMAGE = register(new StateFlag("fall-damage", true));
public static final StateFlag HEALTH_REGEN = register(new StateFlag("natural-health-regen", true));
public static final StateFlag HUNGER_DRAIN = register(new StateFlag("natural-hunger-drain", true));
// session and movement based flags
public static final StateFlag ENTRY = register(new StateFlag("entry", true, RegionGroup.NON_MEMBERS));
@@ -145,9 +159,29 @@ public final class Flags {
public static final StateFlag ENDERPEARL = register(new StateFlag("enderpearl", true));
public static final StateFlag CHORUS_TELEPORT = register(new StateFlag("chorus-fruit-teleport", true));
/**
* @deprecated The type of this flag will change from a StringFlag to a ComponentFlag to support JSON text
* in a future release. If you depend on the type of this flag, take proper precaution for future breakage.
*/
@Deprecated
public static final StringFlag GREET_MESSAGE = register(new StringFlag("greeting"));
/**
* @deprecated The type of this flag will change from a StringFlag to a ComponentFlag to support JSON text
* in a future release. If you depend on the type of this flag, take proper precaution for future breakage.
*/
@Deprecated
public static final StringFlag FAREWELL_MESSAGE = register(new StringFlag("farewell"));
/**
* @deprecated The type of this flag will change from a StringFlag to a ComponentFlag to support JSON text
* in a future release. If you depend on the type of this flag, take proper precaution for future breakage.
*/
@Deprecated
public static final StringFlag GREET_TITLE = register(new StringFlag("greeting-title"));
/**
* @deprecated The type of this flag will change from a StringFlag to a ComponentFlag to support JSON text
* in a future release. If you depend on the type of this flag, take proper precaution for future breakage.
*/
@Deprecated
public static final StringFlag FAREWELL_TITLE = register(new StringFlag("farewell-title"));
public static final BooleanFlag NOTIFY_ENTER = register(new BooleanFlag("notify-enter"));
@@ -155,25 +189,45 @@ public final class Flags {
public static final RegistryFlag<GameMode> GAME_MODE = register(new RegistryFlag<>("game-mode", GameMode.REGISTRY));
public static final IntegerFlag HEAL_DELAY = register(new IntegerFlag("heal-delay"));
public static final IntegerFlag HEAL_AMOUNT = register(new IntegerFlag("heal-amount"));
public static final DoubleFlag MIN_HEAL = register(new DoubleFlag("heal-min-health"));
public static final DoubleFlag MAX_HEAL = register(new DoubleFlag("heal-max-health"));
private static final Number[] DELAY_VALUES = {0, 1, 5};
private static final Number[] VITALS_VALUES = {0, 5, 10, 20};
private static final Number[] VITALS_MINS = {0, 10};
private static final Number[] VITALS_MAXS = {10, 20};
public static final IntegerFlag FEED_DELAY = register(new IntegerFlag("feed-delay"));
public static final IntegerFlag FEED_AMOUNT = register(new IntegerFlag("feed-amount"));
public static final IntegerFlag MIN_FOOD = register(new IntegerFlag("feed-min-hunger"));
public static final IntegerFlag MAX_FOOD = register(new IntegerFlag("feed-max-hunger"));
public static final IntegerFlag HEAL_DELAY = register(new IntegerFlag("heal-delay"), f -> f.setSuggestedValues(DELAY_VALUES));
public static final IntegerFlag HEAL_AMOUNT = register(new IntegerFlag("heal-amount"), f -> f.setSuggestedValues(VITALS_VALUES));
public static final DoubleFlag MIN_HEAL = register(new DoubleFlag("heal-min-health"), f -> f.setSuggestedValues(VITALS_MINS));
public static final DoubleFlag MAX_HEAL = register(new DoubleFlag("heal-max-health"), f -> f.setSuggestedValues(VITALS_MAXS));
public static final IntegerFlag FEED_DELAY = register(new IntegerFlag("feed-delay"), f -> f.setSuggestedValues(DELAY_VALUES));
public static final IntegerFlag FEED_AMOUNT = register(new IntegerFlag("feed-amount"), f -> f.setSuggestedValues(VITALS_VALUES));
public static final IntegerFlag MIN_FOOD = register(new IntegerFlag("feed-min-hunger"), f -> f.setSuggestedValues(VITALS_MINS));
public static final IntegerFlag MAX_FOOD = register(new IntegerFlag("feed-max-hunger"), f -> f.setSuggestedValues(VITALS_MAXS));
// deny messages
/**
* @deprecated The type of this flag will change from a StringFlag to a ComponentFlag to support JSON text
* in a future release. If you depend on the type of this flag, take proper precaution for future breakage.
*/
@Deprecated
public static final StringFlag DENY_MESSAGE = register(new StringFlag("deny-message",
LegacyComponentSerializer.INSTANCE.serialize(TextComponent.of("").append(TextComponent.of("Hey!",
TextColor.RED, Sets.newHashSet(TextDecoration.BOLD)))
.append(TextComponent.of(" Sorry, but you can't %what% here.", TextColor.GRAY)))));
/**
* @deprecated The type of this flag will change from a StringFlag to a ComponentFlag to support JSON text
* in a future release. If you depend on the type of this flag, take proper precaution for future breakage.
*/
@Deprecated
public static final StringFlag ENTRY_DENY_MESSAGE = register(new StringFlag("entry-deny-message",
LegacyComponentSerializer.INSTANCE.serialize(TextComponent.of("").append(TextComponent.of("Hey!",
TextColor.RED, Sets.newHashSet(TextDecoration.BOLD)))
.append(TextComponent.of(" You are not permitted to enter this area.", TextColor.GRAY)))));
/**
* @deprecated The type of this flag will change from a StringFlag to a ComponentFlag to support JSON text
* in a future release. If you depend on the type of this flag, take proper precaution for future breakage.
*/
@Deprecated
public static final StringFlag EXIT_DENY_MESSAGE = register(new StringFlag("exit-deny-message",
LegacyComponentSerializer.INSTANCE.serialize(TextComponent.of("").append(TextComponent.of("Hey!",
TextColor.RED, Sets.newHashSet(TextDecoration.BOLD)))
@@ -188,6 +242,12 @@ public final class Flags {
return flag;
}
private static <T extends Flag<?>> T register(final T flag, Consumer<T> cfg) throws FlagConflictException {
T f = register(flag);
cfg.accept(f);
return f;
}
/**
* Try to match the flag with the given ID using a fuzzy name match.
*
@@ -22,7 +22,7 @@ package com.sk89q.worldguard.protection.flags;
/**
* Stores an integer.
*/
public class IntegerFlag extends Flag<Integer> {
public class IntegerFlag extends NumberFlag<Integer> {
public IntegerFlag(String name, RegionGroup defaultGroup) {
super(name, defaultGroup);
@@ -0,0 +1,59 @@
/*
* WorldGuard, a suite of tools for Minecraft
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldGuard team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldguard.protection.flags;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.annotations.Beta;
/**
* Stores an Number.
*/
public abstract class NumberFlag<T extends Number> extends Flag<T> {
private static final Number[] EMPTY_NUMBER_ARRAY = new Number[0];
private Number[] suggestions = EMPTY_NUMBER_ARRAY;
protected NumberFlag(String name, RegionGroup defaultGroup) {
super(name, defaultGroup);
}
protected NumberFlag(String name) {
super(name);
}
/**
* Not recommended for public use. Will likely be moved when migrating to piston for commands.
* @param values suggested values
*/
@Beta
public void setSuggestedValues(Number[] values) {
this.suggestions = checkNotNull(values);
}
/**
* Not recommended for public use. Will likely be moved when migrating to piston for commands.
* @return suggested values
*/
@Beta
public Number[] getSuggestedValues() {
return suggestions;
}
}
@@ -19,6 +19,8 @@
package com.sk89q.worldguard.protection.flags;
import com.sk89q.worldguard.commands.CommandUtils;
import javax.annotation.Nullable;
/**
@@ -56,7 +58,10 @@ public class StringFlag extends Flag<String> {
@Override
public String parseInput(FlagContext context) throws InvalidFlagFormat {
return context.getUserInput().replaceAll("(?!<\\\\)\\\\n", "\n").replaceAll("\\\\\\\\n", "\\n");
String lines = context.getUserInput().replaceAll("(?<!\\\\)\\\\n", "\n").replaceAll("\\\\\\\\n", "\\\\n");
// Add color codes
lines = CommandUtils.replaceColorMacros(lines);
return lines;
}
@Override
@@ -24,8 +24,6 @@ import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.sk89q.worldguard.protection.flags.Flag;
import com.sk89q.worldguard.protection.flags.Flags;
import com.sk89q.worldguard.protection.flags.RegionGroup;
import com.sk89q.worldguard.protection.flags.RegionGroupFlag;
import javax.annotation.Nullable;
import java.util.Collection;
@@ -19,6 +19,8 @@
package com.sk89q.worldguard.protection.managers;
import static com.google.common.base.Preconditions.checkNotNull;
import com.sk89q.worldguard.protection.flags.registry.FlagRegistry;
import com.sk89q.worldguard.protection.managers.index.ChunkHashTable;
import com.sk89q.worldguard.protection.managers.index.ConcurrentRegionIndex;
@@ -29,15 +31,22 @@ import com.sk89q.worldguard.protection.managers.storage.StorageException;
import com.sk89q.worldguard.util.Normal;
import javax.annotation.Nullable;
import java.util.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.function.Supplier;
import java.util.function.Function;
import java.util.logging.Level;
import java.util.logging.Logger;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Manages different {@link RegionManager}s for different worlds or dimensions.
*
@@ -52,8 +61,8 @@ public class RegionContainerImpl {
private final ConcurrentMap<Normal, RegionManager> mapping = new ConcurrentHashMap<>();
private final Object lock = new Object();
private final RegionDriver driver;
private final Supplier<? extends ConcurrentRegionIndex> indexFactory = new ChunkHashTable.Factory(new PriorityRTreeIndex.Factory());
private final Timer timer = new Timer();
private final Function<String, ? extends ConcurrentRegionIndex> indexFactory = new ChunkHashTable.Factory(new PriorityRTreeIndex.Factory());
private final Timer timer = new Timer("WorldGuard Region I/O");
private final FlagRegistry flagRegistry;
private final Set<Normal> failingLoads = new HashSet<>();
@@ -182,6 +191,14 @@ public class RegionContainerImpl {
}
}
/**
* Disable completely.
*/
public void shutdown() {
timer.cancel();
unloadAll();
}
/**
* Get the region manager for the given world name.
*
@@ -37,6 +37,7 @@ import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import com.sk89q.worldguard.protection.util.RegionCollectionConsumer;
import com.sk89q.worldguard.util.Normal;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -47,9 +48,7 @@ import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Supplier;
import javax.annotation.Nullable;
import java.util.function.Function;
/**
* A region manager holds the regions for a world.
@@ -57,7 +56,7 @@ import javax.annotation.Nullable;
public final class RegionManager {
private final RegionDatabase store;
private final Supplier<? extends ConcurrentRegionIndex> indexFactory;
private final Function<String, ? extends ConcurrentRegionIndex> indexFactory;
private final FlagRegistry flagRegistry;
private ConcurrentRegionIndex index;
@@ -68,14 +67,14 @@ public final class RegionManager {
* @param indexFactory the factory for creating new instances of the index
* @param flagRegistry the flag registry
*/
public RegionManager(RegionDatabase store, Supplier<? extends ConcurrentRegionIndex> indexFactory, FlagRegistry flagRegistry) {
public RegionManager(RegionDatabase store, Function<String, ? extends ConcurrentRegionIndex> indexFactory, FlagRegistry flagRegistry) {
checkNotNull(store);
checkNotNull(indexFactory);
checkNotNull(flagRegistry, "flagRegistry");
this.store = store;
this.indexFactory = indexFactory;
this.index = indexFactory.get();
this.index = indexFactory.apply(store.getName());
this.flagRegistry = flagRegistry;
}
@@ -218,7 +217,7 @@ public final class RegionManager {
public void setRegions(Collection<ProtectedRegion> regions) {
checkNotNull(regions);
ConcurrentRegionIndex newIndex = indexFactory.get();
ConcurrentRegionIndex newIndex = indexFactory.apply(getName());
newIndex.addAll(regions);
newIndex.getAndClearDifference(); // Clear changes
this.index = newIndex;
@@ -41,8 +41,8 @@ import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import javax.annotation.Nullable;
@@ -52,6 +52,7 @@ import javax.annotation.Nullable;
*/
public class ChunkHashTable implements ConcurrentRegionIndex {
private final String name;
private ListeningExecutorService executor = createExecutor();
private LongHashTable<ChunkState> states = new LongHashTable<>();
private final RegionIndex index;
@@ -63,10 +64,12 @@ public class ChunkHashTable implements ConcurrentRegionIndex {
* Create a new instance.
*
* @param index the index
* @param name
*/
public ChunkHashTable(RegionIndex index) {
public ChunkHashTable(RegionIndex index, String name) {
checkNotNull(index);
this.index = index;
this.name = name;
}
/**
@@ -75,8 +78,8 @@ public class ChunkHashTable implements ConcurrentRegionIndex {
* @return an executor service
*/
private ListeningExecutorService createExecutor() {
return MoreExecutors.listeningDecorator(
EvenMoreExecutors.newBoundedCachedThreadPool(0, 4, Integer.MAX_VALUE));
return MoreExecutors.listeningDecorator(EvenMoreExecutors.newBoundedCachedThreadPool(0, 4, Integer.MAX_VALUE,
"WorldGuard Region Chunk Table - " + name));
}
/**
@@ -361,17 +364,17 @@ public class ChunkHashTable implements ConcurrentRegionIndex {
/**
* A factory for instances of {@code ChunkHashCache}.
*/
public static class Factory implements Supplier<ChunkHashTable> {
private final Supplier<? extends ConcurrentRegionIndex> supplier;
public static class Factory implements Function<String, ChunkHashTable> {
private final Function<String, ? extends ConcurrentRegionIndex> supplier;
public Factory(Supplier<? extends ConcurrentRegionIndex> supplier) {
public Factory(Function<String, ? extends ConcurrentRegionIndex> supplier) {
checkNotNull(supplier);
this.supplier = supplier;
}
@Override
public ChunkHashTable get() {
return new ChunkHashTable(supplier.get());
public ChunkHashTable apply(String name) {
return new ChunkHashTable(supplier.apply(name), name);
}
}
@@ -28,6 +28,7 @@ import com.sk89q.worldguard.protection.managers.RegionDifference;
import com.sk89q.worldguard.protection.managers.RemovalStrategy;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import javax.annotation.Nullable;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
@@ -35,10 +36,8 @@ import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import javax.annotation.Nullable;
/**
* An index that stores regions in a hash map, which allows for fast lookup
@@ -287,9 +286,9 @@ public class HashMapIndex extends AbstractRegionIndex implements ConcurrentRegio
/**
* A factory for new instances using this index.
*/
public static final class Factory implements Supplier<HashMapIndex> {
public static final class Factory implements Function<String, HashMapIndex> {
@Override
public HashMapIndex get() {
public HashMapIndex apply(String name) {
return new HashMapIndex();
}
}
@@ -30,8 +30,8 @@ import org.khelekore.prtree.SimpleMBR;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
/**
* An implementation of an index that uses {@link HashMapIndex} for queries
@@ -103,9 +103,9 @@ public class PriorityRTreeIndex extends HashMapIndex {
/**
* A factory for new instances using this index.
*/
public static final class Factory implements Supplier<PriorityRTreeIndex> {
public static final class Factory implements Function<String, PriorityRTreeIndex> {
@Override
public PriorityRTreeIndex get() {
public PriorityRTreeIndex apply(String name) {
return new PriorityRTreeIndex();
}
}
@@ -20,8 +20,8 @@
package com.sk89q.worldguard.protection.managers.migration;
import com.google.common.base.Predicate;
import com.sk89q.squirrelid.Profile;
import com.sk89q.squirrelid.resolver.ProfileService;
import com.sk89q.worldguard.util.profile.Profile;
import com.sk89q.worldguard.util.profile.resolver.ProfileService;
import com.sk89q.worldguard.domains.DefaultDomain;
import com.sk89q.worldguard.domains.PlayerDomain;
import com.sk89q.worldguard.protection.flags.registry.FlagRegistry;
@@ -31,7 +31,12 @@ import com.sk89q.worldguard.protection.managers.storage.StorageException;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import java.io.IOException;
import java.util.*;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.logging.Level;
@@ -47,7 +52,7 @@ public class UUIDMigration extends AbstractMigration {
private static final Logger log = Logger.getLogger(UUIDMigration.class.getCanonicalName());
private static final int LOG_DELAY = 5000;
private final Timer timer = new Timer();
private final Timer timer = new Timer("WorldGuard UUID Migration");
private final ProfileService profileService;
private final FlagRegistry flagRegistry;
private final ConcurrentMap<String, UUID> resolvedNames = new ConcurrentHashMap<>();
@@ -67,7 +67,6 @@ public class RegionQuery {
this.config = WorldGuard.getInstance().getPlatform().getGlobalStateManager();
this.cache = cache;
//noinspection deprecation
}
/**
@@ -178,7 +177,7 @@ public class RegionQuery {
*
* <p>{@code player} can be non-null to satisfy region group requirements,
* otherwise it will be assumed that the caller that is not a member of any
* regions. (FlagUtil on a region can be changed so that they only apply
* regions. (Flags on a region can be changed so that they only apply
* to certain users.) The player argument is required if the
* {@link Flags#BUILD} flag is in the list of flags.</p>
*
@@ -201,7 +200,7 @@ public class RegionQuery {
*
* <p>{@code player} can be non-null to satisfy region group requirements,
* otherwise it will be assumed that the caller that is not a member of any
* regions. (FlagUtil on a region can be changed so that they only apply
* regions. (Flags on a region can be changed so that they only apply
* to certain users.) The player argument is required if the
* {@link Flags#BUILD} flag is in the list of flags.</p>
*
@@ -225,7 +224,7 @@ public class RegionQuery {
*
* <p>{@code player} can be non-null to satisfy region group requirements,
* otherwise it will be assumed that the caller that is not a member of any
* regions. (FlagUtil on a region can be changed so that they only apply
* regions. (Flags on a region can be changed so that they only apply
* to certain users.) The player argument is required if the
* {@link Flags#BUILD} flag is in the list of flags.</p>
*
@@ -247,7 +246,7 @@ public class RegionQuery {
*
* <p>{@code player} can be non-null to satisfy region group requirements,
* otherwise it will be assumed that the caller that is not a member of any
* regions. (FlagUtil on a region can be changed so that they only apply
* regions. (Flags on a region can be changed so that they only apply
* to certain users.) The player argument is required if the
* {@link Flags#BUILD} flag is in the list of flags.</p>
*
@@ -276,7 +275,7 @@ public class RegionQuery {
*
* <p>{@code player} can be non-null to satisfy region group requirements,
* otherwise it will be assumed that the caller that is not a member of any
* regions. (FlagUtil on a region can be changed so that they only apply
* regions. (Flags on a region can be changed so that they only apply
* to certain users.) The player argument is required if the
* {@link Flags#BUILD} flag is the flag being queried.</p>
*
@@ -305,7 +304,7 @@ public class RegionQuery {
*
* <p>{@code player} can be non-null to satisfy region group requirements,
* otherwise it will be assumed that the caller that is not a member of any
* regions. (FlagUtil on a region can be changed so that they only apply
* regions. (Flags on a region can be changed so that they only apply
* to certain users.) The player argument is required if the
* {@link Flags#BUILD} flag is the flag being queried.</p>
*
@@ -327,7 +326,7 @@ public class RegionQuery {
*
* <p>{@code player} can be non-null to satisfy region group requirements,
* otherwise it will be assumed that the caller that is not a member of any
* regions. (FlagUtil on a region can be changed so that they only apply
* regions. (Flags on a region can be changed so that they only apply
* to certain users.) The player argument is required if the
* {@link Flags#BUILD} flag is the flag being queried.</p>
*
@@ -348,7 +347,7 @@ public class RegionQuery {
*
* <p>{@code player} can be non-null to satisfy region group requirements,
* otherwise it will be assumed that the caller that is not a member of any
* regions. (FlagUtil on a region can be changed so that they only apply
* regions. (Flags on a region can be changed so that they only apply
* to certain users.) The player argument is required if the
* {@link Flags#BUILD} flag is the flag being queried.</p>
*
@@ -21,9 +21,9 @@ package com.sk89q.worldguard.protection.util;
import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.sk89q.squirrelid.Profile;
import com.sk89q.squirrelid.resolver.ProfileService;
import com.sk89q.squirrelid.util.UUIDs;
import com.sk89q.worldguard.util.profile.Profile;
import com.sk89q.worldguard.util.profile.resolver.ProfileService;
import com.sk89q.worldguard.util.profile.util.UUIDs;
import com.sk89q.worldguard.domains.DefaultDomain;
import javax.annotation.Nullable;
@@ -41,7 +41,6 @@ import com.sk89q.worldguard.session.handler.TimeLockFlag;
import com.sk89q.worldguard.session.handler.WaterBreathing;
import com.sk89q.worldguard.session.handler.WeatherLockFlag;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.lang.ref.WeakReference;
import java.util.Arrays;
@@ -60,26 +59,20 @@ public abstract class AbstractSessionManager implements SessionManager {
private final LoadingCache<WorldPlayerTuple, Boolean> bypassCache = CacheBuilder.newBuilder()
.maximumSize(1000)
.expireAfterAccess(2, TimeUnit.SECONDS)
.build(new CacheLoader<WorldPlayerTuple, Boolean>() {
@Override
public Boolean load(@Nonnull WorldPlayerTuple tuple) throws Exception {
return tuple.getPlayer().hasPermission("worldguard.region.bypass." + tuple.getWorld().getName());
}
});
.expireAfterWrite(2, TimeUnit.SECONDS)
.build(CacheLoader.from(tuple ->
tuple.getPlayer().hasPermission("worldguard.region.bypass." + tuple.getWorld().getName())));
private final LoadingCache<CacheKey, Session> sessions = CacheBuilder.newBuilder()
.expireAfterAccess(SESSION_LIFETIME, TimeUnit.MINUTES)
.build(new CacheLoader<CacheKey, Session>() {
@Override
public Session load(@Nonnull CacheKey key) throws Exception {
return createSession(key.playerRef.get());
}
});
.build(CacheLoader.from(key ->
createSession(key.playerRef.get())));
private boolean hasCustom = false;
private List<Handler.Factory<? extends Handler>> handlers = new LinkedList<>();
private static final List<Handler.Factory<? extends Handler>> defaultHandlers = new LinkedList<>();
static {
Handler.Factory<?>[] factories = {
HealFlag.FACTORY,
@@ -104,12 +97,17 @@ public abstract class AbstractSessionManager implements SessionManager {
handlers.addAll(defaultHandlers);
}
@Override
public boolean customHandlersRegistered() {
return hasCustom;
}
@Override
public boolean registerHandler(Handler.Factory<? extends Handler> factory, @Nullable Handler.Factory<? extends Handler> after) {
if (factory == null) return false;
WorldGuard.logger.log(Level.INFO, "Registering session handler "
+ factory.getClass().getEnclosingClass().getName());
hasCustom = true;
if (after == null) {
handlers.add(factory);
} else {
@@ -135,7 +133,9 @@ public abstract class AbstractSessionManager implements SessionManager {
@Override
public boolean hasBypass(LocalPlayer player, World world) {
return bypassCache.getUnchecked(new WorldPlayerTuple(world, player));
Session sess = getIfPresent(player);
return sess != null && !sess.hasBypassDisabled()
&& bypassCache.getUnchecked(new WorldPlayerTuple(world, player));
}
@Override
@@ -44,6 +44,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
public class Session {
private final SessionManager manager;
private boolean disableBypass;
private final HashMap<Class<?>, Handler> handlers = Maps.newLinkedHashMap();
private Location lastValid;
private Set<ProtectedRegion> lastRegionSet;
@@ -217,4 +218,18 @@ public class Session {
return null;
}
/**
* @return true if the owner of this session should not bypass protection, even if they have bypass permissions
*/
public boolean hasBypassDisabled() {
return disableBypass;
}
/**
* Toggle bypass disabling for this session.
* @param disabled true to disable region bypass
*/
public void setBypassDisabled(boolean disabled) {
disableBypass = disabled;
}
}
@@ -54,6 +54,11 @@ public interface SessionManager {
*/
void resetState(LocalPlayer player);
/**
* @return true if custom handlers are or were at some point registered, false otherwise
*/
boolean customHandlersRegistered();
/**
* Register a handler with the BukkitSessionManager.
*
@@ -39,7 +39,7 @@ public class TimeLockFlag extends FlagValueChangeHandler<String> {
}
}
private Long initialTime;
private long initialTime;
private boolean initialRelative;
private static Pattern timePattern = Pattern.compile("([+\\-])?\\d+");
@@ -54,10 +54,7 @@ public class TimeLockFlag extends FlagValueChangeHandler<String> {
return;
}
boolean relative = value.startsWith("+") || value.startsWith("-");
Long time = Long.valueOf(value);
// if (!relative && (time < 0L || time > 24000L)) { // invalid time, reset to 0
// time = 0L;
// }
long time = Long.parseLong(value);
player.setPlayerTime(time, relative);
}
@@ -70,15 +67,20 @@ public class TimeLockFlag extends FlagValueChangeHandler<String> {
@Override
protected boolean onSetValue(LocalPlayer player, Location from, Location to, ApplicableRegionSet toSet, String currentValue, String lastValue, MoveType moveType) {
if (lastValue == null) {
initialRelative = player.isPlayerTimeRelative();
initialTime = player.getPlayerTimeOffset();
}
updatePlayerTime(player, currentValue);
return true;
}
@Override
protected boolean onAbsentValue(LocalPlayer player, Location from, Location to, ApplicableRegionSet toSet, String lastValue, MoveType moveType) {
// in the case that time = 0 and relative = true, this is the same as resetPlayerTime
player.setPlayerTime(initialTime, initialRelative);
initialRelative = true;
initialTime = 0L;
initialRelative = true;
return true;
}
@@ -45,16 +45,17 @@ public class WeatherLockFlag extends FlagValueChangeHandler<WeatherType> {
@Override
protected void onInitialValue(LocalPlayer player, ApplicableRegionSet set, WeatherType value) {
if (value == null) {
initialWeather = null;
return;
initialWeather = player.getPlayerWeather();
if (value != null) {
player.setPlayerWeather(value);
}
initialWeather = value;
player.setPlayerWeather(value);
}
@Override
protected boolean onSetValue(LocalPlayer player, Location from, Location to, ApplicableRegionSet toSet, WeatherType currentValue, WeatherType lastValue, MoveType moveType) {
if (lastValue == null) {
initialWeather = player.getPlayerWeather();
}
player.setPlayerWeather(currentValue);
return true;
}
@@ -19,6 +19,8 @@
package com.sk89q.worldguard.util.concurrent;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
@@ -43,11 +45,28 @@ public final class EvenMoreExecutors {
* @return the newly created thread pool
*/
public static ExecutorService newBoundedCachedThreadPool(int minThreads, int maxThreads, int queueSize) {
return newBoundedCachedThreadPool(minThreads, maxThreads, queueSize, null);}
/**
* Creates a thread pool that creates new threads as needed up to
* a maximum number of threads, but will reuse previously constructed
* threads when they are available.
*
* @param minThreads the minimum number of threads to have at a given time
* @param maxThreads the maximum number of threads to have at a given time
* @param queueSize the size of the queue before new submissions are rejected
* @param threadFormat thread name formatter
* @return the newly created thread pool
*/
public static ExecutorService newBoundedCachedThreadPool(int minThreads, int maxThreads, int queueSize, String threadFormat) {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
minThreads, maxThreads,
60L, TimeUnit.SECONDS,
new LinkedBlockingDeque<>(queueSize));
threadPoolExecutor.allowCoreThreadTimeOut(true);
if (threadFormat != null) {
threadPoolExecutor.setThreadFactory(new ThreadFactoryBuilder().setNameFormat(threadFormat).build());
}
return threadPoolExecutor;
}
@@ -16,6 +16,7 @@
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldguard.util.formatting.component;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
@@ -16,6 +16,7 @@
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldguard.util.formatting.component;
import com.sk89q.worldedit.util.formatting.component.TextComponentProducer;
@@ -0,0 +1,54 @@
/*
* WorldGuard, a suite of tools for Minecraft
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldGuard team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldguard.util.report;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.util.report.DataReport;
import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.WorldGuard;
import com.sk89q.worldguard.protection.ApplicableRegionSet;
import com.sk89q.worldguard.protection.managers.RegionManager;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
public class ApplicableRegionsReport extends DataReport {
public ApplicableRegionsReport(LocalPlayer player) {
super("Applicable regions");
BlockVector3 position = player.getBlockIn().toVector().toBlockPoint();
append("Location", player.getWorld().getName() + " @ " + position);
RegionManager mgr = WorldGuard.getInstance().getPlatform().getRegionContainer().get(player.getWorld());
if (mgr == null) {
append("Regions", "Disabled for current world");
} else {
ApplicableRegionSet rgs = mgr.getApplicableRegions(position);
if (rgs.getRegions().isEmpty()) {
append("Regions", "None");
} else {
DataReport regions = new DataReport("Regions");
for (ProtectedRegion region : rgs.getRegions()) {
boolean inherited = !region.contains(position);
regions.append(region.getId() + (inherited ? "*" : ""), new RegionReport(region));
}
append(regions.getTitle(), regions);
}
}
}
}
Loaded 100 of 108 files, more files were not shown because too many files have changed in this diff. Show more