Compare commits

...
111 Commits
Author SHA1 Message Date
sk89q 9cf85caf3c Set version to 6.1. 2015-06-08 15:04:59 -07:00
sk89q 2f1343f408 Updated changelog for v6.1. 2015-06-08 15:04:52 -07:00
wizjany 3cb6c4e46f Check both attacker and defender locations for PvP.
Fixes WORLDGUARD-3494.
2015-06-08 14:37:32 -07:00
sk89q 7f9b850288 Always generate Javadocs and sources .jar. 2015-06-08 14:37:32 -07:00
sk89q e8d4f2fd84 Turn off doclint. 2015-06-08 14:37:32 -07:00
sk89q f3891aaaf9 Add a workaround for incorrect piston retract information. 2015-06-03 23:46:24 -07:00
wizjany ea75549a29 Clean up Heal and Feed flags.
Allow the flags to increase values for players who are invincible (or in creative mode),
but not decrease them.
Fixes WORLDGUARD-3492.
2015-06-04 02:02:53 -04:00
wizjany fbd8206038 Check for connected chests.
Fixes WORLDGUARD-3021.
2015-05-29 03:56:14 -04:00
wizjany 522ac459db Fix weather lock flag.
Probably. Maybe.
Fixes WORLDGUARD-3452.
2015-05-29 02:26:32 -04:00
wizjany 255dd2d41a Add support for Spigot's BlockExplodeEvent.
Also update Bukkit dependency and guava version quirks.
Fixes WORLDGUARD-3484.
2015-05-29 01:49:20 -04:00
wizjany cf1716ff37 Separate vehicles and animals from INTERACT flag.
Destroying vehicles now checks only the vehicle-destroy flag.
Damaging animals checks the new damage-animals flag.
These are both allowed for members by default, like other build-dependent flags.

Fixes WORLDGUARD-3427 and WORLDGUARD-3358.
2015-05-28 17:21:58 -04:00
sk89q a277e69e9c Get the session during the gamemode event lazily. 2015-05-28 11:28:02 -07:00
sk89q ec5bb32510 Add -s to show stack traces with the event debugging command. 2015-05-27 22:18:30 -07:00
Wizjany 8ddb7d4b99 Don't add a period for custom blacklist messages.
Fixes WORLDGUARD-3472
2015-05-02 22:38:42 -04:00
Wizjany 3258bff2d1 Fix CommandFilter matching emoticons etc.
Fixes WORLDGUARD-3461.
2015-04-18 12:01:21 -04:00
Wizjany 8d7d32a2d2 Check event cancellation before playing deny effect for bucket events. 2015-04-05 15:44:43 -04:00
Wizjany a907eb2348 Move repeaters/comparators from use to build.
This should mirror the protection given in WG 5.9.
2015-03-13 23:34:22 -04:00
wizjany 32132b5b0a Protect against spawn egg usage.
Fixes WORLDGUARD-3347.
2015-03-11 01:46:55 -04:00
wizjany c0c7c3215e Mark Player/Group Domains as dirty in a few missing places.
Fixes WORLDGUARD-3404.
2015-03-11 00:44:41 -04:00
Wizjany ddf0f41061 Actually register WorldRulesListener for events.
Fixes WORLDGUARD-3406.
2015-03-03 13:09:50 -05:00
Wizjany d3ecbcb18a Protect switching inverted daylight detectors too. 2015-02-28 18:39:54 -05:00
wizjany b7f4262978 Add comparators to USE too for consistency. 2015-02-19 21:21:17 -05:00
wizjany 60e6f92c64 Have repeaters be covered by the USE flag. 2015-02-19 21:17:45 -05:00
wizjany 98af7966cd Added weather-lock flag.
Valid values are clear or downfall. Unset to restore to normal world weather.
2015-02-18 02:24:31 -05:00
wizjany 99d042d260 Added time-lock flag.
Valid values are 0 to 24000 for absolute time, or +- any number for relative time.
Closes WORLDGUARD-3379.
2015-02-18 01:59:30 -05:00
wizjany c9d6166fcb Check for null task fields.
Fixes WORLDGUARD-3372.
2015-02-17 16:51:02 -05:00
sk89q 752ccec150 Don't call initialize() on non-cancellable movements.
Fixes WORLDGUARD-3362.
2015-02-11 17:12:10 -08:00
sk89q 91ccb95672 Add classloader override to the build POM. 2015-02-11 17:09:10 -08:00
wizjany 4caff457d3 Add Citizens NPCs to NPC detection for region whitelisting.
Fixes WORLDGUARD-3356.
2015-02-04 17:03:01 -05:00
wizjany a1a6ee7107 Fixed blocks (e.g. sugar canes) adjacent to physics blocks (e.g. sand) not updating.
Fixes WORLDGUARD-3367. This change MAY have breaking unintended consequences,
but the physics configs seem to still be working.
2015-02-04 03:33:37 -05:00
sk89q af157b88bd Handle empty sets in SetFlag. 2015-01-30 00:03:25 -08:00
sk89q ea4f4c088b Have enderchests be covered by the USE flag.
Fixes WORLDGUARD-3336.
2015-01-28 01:36:07 -08:00
sk89q 6559ed5c1a Have tripwire be covered by the USE flag.
Fixes WORLDGUARD-3351.
2015-01-28 01:35:17 -08:00
sk89q deddcf8dd2 Handle null block attacker.
Fixes WORLDGUARD-3350.
2015-01-28 01:26:50 -08:00
sk89q dfe536a2d2 Fix issues with MC 1.7 compatibility. 2015-01-28 01:11:36 -08:00
sk89q 5bfb348354 Add a fall-damage flag.
Closes WORLDGUARD-2279.
2015-01-28 01:01:43 -08:00
sk89q afcf93b7b1 Reset handler caches when a move type is non-cancellable. 2015-01-27 15:21:56 -08:00
sk89q e1843624bb Add exit-via-teleport flag (default allow). 2015-01-27 15:01:01 -08:00
wizjany 0f4e7b5061 Creeper explosions with a player target cause should no longer be ignored.
Also fixed primed tnt being checked twice for tnt flags. TNT Minecarts are not included, as was prior behavior.
Fixes WORLDGUARD-3344
2015-01-24 23:00:19 -05:00
wizjany 869ead63bc Fix armor stands to behave more like item frames.
Placing and modifying them respects permissions, and  they are no longer blocked by mob-spawning deny.
2015-01-24 17:02:55 -05:00
sk89q 6a6de7802b Fix missing material data for 1.8 items.
Fixes WORLDGUARD-3306.
2015-01-22 21:42:53 -08:00
sk89q b50302d9d0 Set version back to 6.0.0-SNAPSHOT. 2015-01-20 19:28:22 -08:00
sk89q c841d74aaf Set version to 6.0.0-beta-05. 2015-01-20 19:26:39 -08:00
sk89q 09cce39aff Update changelog for 6.0 beta 5. 2015-01-20 19:25:34 -08:00
sk89q e5b76a571b Always call boundary crossing handlers. 2015-01-20 19:24:55 -08:00
sk89q 7c58fa4be6 Add BukkitUtil.toRegion(Chunk).
Closes WORLDGUARD-3292.
2015-01-19 23:19:44 -08:00
sk89q f150a41d72 Ensure that region properties are immutable. 2015-01-19 23:11:28 -08:00
sk89q bca1c2bdb3 Fix region intersection tests involving polygons.
Fixes WORLDGUARD-3216.
2015-01-19 22:56:16 -08:00
sk89q 47a8bcc442 Floor components in getApplicableRegions(Location).
Fixes WORLDGUARD-3288.
2015-01-19 19:22:15 -08:00
sk89q 83cad75916 Fix /wg flushstates not doing anything. 2015-01-19 19:04:49 -08:00
sk89q 6b5a12105e Group together invincibility listeners.
Fixes WORLDGUARD-3315.
2015-01-19 19:03:54 -08:00
sk89q 451b679323 Track cause through targets.
Fixes WORLDGUARD-3314.
2015-01-19 18:28:41 -08:00
sk89q 66a8bfd5b1 Fix typo in region gamemode change log message. 2015-01-19 14:12:04 -08:00
sk89q 2a2b2f6f64 Limit the cause chain to 40 items. 2015-01-19 14:08:53 -08:00
sk89q 73dea11de2 Restore game mode flag logic to pre-refactor version.
Fixes WORLDGUARD-3320.
2015-01-19 13:23:23 -08:00
wizjany 9998a6c930 Restore Java 6 compatibility. 2015-01-19 15:01:43 -05:00
wizjany 5111d40aaf Add colorification to entry and exit messages as well. 2015-01-19 14:23:04 -05:00
sk89q 972ccaed7e Rename InteropUtil -> InteropUtils. 2015-01-19 11:20:53 -08:00
sk89q f7d36bc1f3 Protect enderchests as well. 2015-01-19 11:20:23 -08:00
sk89q 8073945af0 Fix color codes in greeting/farewell messages.
Fixes WORLDGUARD-3319.
2015-01-19 11:17:06 -08:00
sk89q 91353d6b01 Improve fake player detection. 2015-01-19 03:23:52 -08:00
sk89q bfbcc8dcf8 Fix a typo in the class source warning message. 2015-01-19 01:55:56 -08:00
sk89q 8f65798141 Check when plugins shade WorldGuard inappropriately. 2015-01-19 01:54:23 -08:00
sk89q fdddb17d2f TypeToken is not available on old Guava. 2015-01-17 19:26:33 -08:00
sk89q 520f9e3fcf Check movement with vehicle enter. 2015-01-17 19:25:15 -08:00
sk89q a3d2a1b127 Don't call boundary crossing handlers unless a boundary was crossed. 2015-01-17 19:17:17 -08:00
sk89q 7ecf73165b Handle entry flag only on boundary crossing. 2015-01-17 19:17:02 -08:00
sk89q e90a7ed075 Add new exit-override flag instead of fiddling with default exit flag values. 2015-01-17 19:13:25 -08:00
sk89q aae521b727 Rewrite session and movement flag code.
Also adds entry-deny-message and exit-deny-message.

Fixes WORLDGUARD-3086, WORLDGUARD-2542, WORLDGUARD-2731.
2015-01-17 18:54:10 -08:00
sk89q 643345b459 Add Locations.isDifferentBlock(). 2015-01-17 15:04:42 -08:00
sk89q a62d9f5617 Reuse set in RegionResultSet for getRegions(). 2015-01-17 14:29:14 -08:00
sk89q 2f3f76c8cf Funnel pre-allowed events too.
Fixes WORLDGUARD-3308.
2015-01-16 15:43:13 -08:00
sk89q a03aaa45b1 Revert "Have the PvP flag apply to self-attack."
This reverts commit d8dd86dfe8.

Fixes WORLDGUARD-3312.
2015-01-16 14:22:46 -08:00
sk89q 372155b5c3 Don't check player inventories for protection.
Fixes WORLDGUARD-3309, WORLDGUARD-3310.
2015-01-16 14:20:01 -08:00
sk89q 159de771bf Fix build perms item use event not working correctly. 2015-01-15 18:42:26 -08:00
sk89q 41d922cb27 Add special case for global regions in RegionOverlapAssociation too. 2015-01-15 16:49:07 -08:00
sk89q 6a4fac63e8 Change version back to 6.0.0-SNAPSHOT. 2015-01-13 12:44:17 -08:00
sk89q 3daf8db113 Bump to 6.0.0 beta 04. 2015-01-13 12:42:11 -08:00
sk89q 9c62a35e07 Update CHANGELOG for 6.0 beta 4. 2015-01-13 12:29:43 -08:00
sk89q 931f438b14 Add material flags for MC 1.8.
Fixes WORLDGUARD-3306.
2015-01-13 12:19:53 -08:00
sk89q 3109612c1b Expand the USE flag to cover 1.8 doors and gates.
Fixes WORLDGUARD-3304.
2015-01-13 12:12:12 -08:00
sk89q e4d63ffbcc Permit org.json.simple package usage. 2015-01-13 03:24:00 -08:00
sk89q 866a554d30 Shade JSON simple. 2015-01-13 03:23:49 -08:00
sk89q ab2811ed2d Remove boot class / library path report values. 2015-01-13 03:19:47 -08:00
sk89q 8cc7bcc849 Improve report output. 2015-01-13 02:44:58 -08:00
sk89q 547e89b85d Add CPU profiling with WarmRoast "lite." 2015-01-13 01:49:59 -08:00
sk89q 477f1188df Use EH pastebin and remove debug code. 2015-01-12 22:19:49 -08:00
sk89q d9e4b27cd2 Handle PlayerInteractAtEntityEvent again.
Fixes WORLDGUARD-3291.
2015-01-11 02:34:12 -08:00
sk89q 37f39eaf66 Use a less coarse can-interact-on-click check.
Fixes WORLDGUARD-3303.
2015-01-11 02:05:31 -08:00
sk89q 223d22e79f Fire UseEntityEvent for InventoryOpenEvent for entities. 2015-01-11 00:10:52 -08:00
sk89q 04214a96eb Ignore unknown cause entity damage.
Fixes WORLDGUARD-3293.
2015-01-11 00:08:41 -08:00
sk89q f40cb69f38 Ignore unknown cause hanging breaks.
Fixes WORLDGUARD-3301.
2015-01-11 00:05:07 -08:00
sk89q 6c1489d434 Make NormativeOrders non-instantiable. 2015-01-10 23:44:31 -08:00
sk89q 6fe63838f5 testState(relevant flags) == DENY on whitelist cases.
Fixes WORLDGUARD-3294.
2015-01-10 23:31:24 -08:00
sk89q d883c22d64 Document flag classes and make BUILD slightly less magic. 2015-01-10 23:15:32 -08:00
sk89q 3bd1c869f1 Sort applicable regions by inheritance too. 2015-01-10 22:45:15 -08:00
sk89q e7273aaf6f ALLOW on a child region should override DENY on a parent. 2015-01-10 18:37:28 -08:00
zml 6e02f80f6c Pass Player objects during WEPIF permission checks 2015-01-10 16:14:17 -08:00
sk89q 01276dfc62 Fix incorrect region group inheritance and broken flag override in children. 2015-01-09 13:21:17 -08:00
sk89q f516fd5e54 Have on-acquire also check inventory transfers.
Fixes WORLDGUARD-2752.
2015-01-08 15:43:02 -08:00
sk89q 79612915a7 Fix NPE caused by flag value permissions. 2015-01-08 14:29:06 -08:00
sk89q f04f9093bc Add &r as a reset color code.
Closes WORLDGUARD-3286.
2015-01-08 13:40:57 -08:00
sk89q 9dac950faf Fix a little typo in the UPGRADE document. 2015-01-08 11:58:20 -08:00
sk89q f2a8ff3f64 Add missing wood plate to USE flag. 2015-01-08 11:25:19 -08:00
sk89q b78317dd42 Add color code support to the blacklist.
Fixes WORLDGUARD-3284.
2015-01-08 11:24:22 -08:00
sk89q 048dd25099 Remove outdated information in the upgrade document. 2015-01-08 01:14:12 -08:00
sk89q 0900289437 Add permissions for individual flag values.
Closes WORLDGUARD-3103.
2015-01-08 01:04:36 -08:00
sk89q d8dd86dfe8 Have the PvP flag apply to self-attack.
Closes WORLDGUARD-3278.
2015-01-08 00:35:30 -08:00
sk89q 9a569d7ed8 Don't throw internal DamageEntityEvents for unknown cause entity combusts.
Fixes WORLDGUARD-3277.
2015-01-08 00:32:57 -08:00
sk89q 53132ce83a Add support for slightly older versions of Bukkit 1.7.9. 2015-01-08 00:25:07 -08:00
sk89q c3bdc33215 Set version to 6.0.0-SNAPSHOT. 2015-01-07 18:51:07 -08:00
111 changed files with 4773 additions and 1505 deletions

No files matched your search

+82
View File
@@ -1,5 +1,87 @@
# Changelog
## 6.1
* Added `exit-via-teleport` flag (default allow) to control exiting an exit=deny region via teleportation.
* Added a `fall-damage` flag to control player damage caused by falling.
* Added a `time-lock` flag to lock players' time of day. Valid values are from 0 to 24000 for absolute time, or +- any number for relative time.
* Added a `weather-lock` flag to lock players' weather. Valid values are "clear" or "downfall". Unset to restore to normal world weather.
* Added `-s` to the event debugging commands to show a stack trace rather than attempt to detect the causing plugin.
* Added support for using the `-e` argument (sets an empty value for the flag) in the flag set command when the type of flag is of the 'set' type.
* Added NPCs from the Citizens plugin to a whitelist so they are not protected.
* Added support for Spigot's BlockExplodeEvent.
* Changed tripwire to fall under the `use` flag.
* Changed enderchests to fall under the `use` flag.
* Changed vehicles and animals so they are not included in the `interact` flag.
* Changed the display of custom blacklist messages to no longer include a period at the end.
* Changed protection logic to consider connected chests.
* Changed the heal and feed flags to increase values for players who are invincible (or in creative mode) but not decrease them.
* Changed PvP protection to consider both attacker and defender locations.
* Fixed missing protection data for some 1.8-added blocks.
* Fixed compatibility issues with MC 1.7.
* Fixed inverted daylight detectors not being protected.
* Fixed spawn eggs not being included in protection.
* Fixed piston blocking not working due to a bug in Spigot.
* Fixed the blocking of certain invalid entity damage events.
* Fixed creeper explosions not being blocked in certain situations with explosion related flags set.
* Fixed "stickiness" with some position-related flags, sometimes resulting in rubber banding in the exit flags.
* Fixed armor stands so that they are treated more like item frames than mobs.
* Fixed blocks (e.g. sugar canes) adjacent to physics blocks (e.g. sand) not updating.
* Fixed a NullPointerException that occurred sometimes when generating the scheduler section of the report function (`/wg report`).
* Fixed the "no XP drops" configuration not functioning following a previous release.
* Fixed changes to region ownership sometimes not triggering a region database save.
* Fixed bucket protection displaying the "deny effect" even if bucket use was not prevented.
* Fixed CommandFilter matching emoticons and other unwanted characters.
* Fixed an exception occurring sometimes during game mode changes.
* Fixed primed TNT being checked twice for TNT flags.
## 6.0 beta 5
MC 1.7.9, 1.7.10 and 1.8 (Spigot only) are supported.
* Added a feature to detect when another plugin (incorrectly) includes WorldGuard's files, causing errors.
* Added a new `exit-override` flag that can be used on an entry=allow region that players can walk into from an entry=deny region.
* Added a new `entry-deny-message` to change the "entry denied" message.
* Added a new `exit-deny-message` to change the "exit denied" message.
* Changed entry/exit blocking to disembark players from their vehicles.
* Changed the PvP flag to no longer apply to self-attack.
* Fixed [#3220](http://youtrack.sk89q.com/issue/WORLDGUARD-3220): Polygon regions sharing points
* Fixed [#3216](http://youtrack.sk89q.com/issue/WORLDGUARD-3216): Polygon regions 'disappearing' or not working correctly
* Fixed [#3315](http://youtrack.sk89q.com/issue/WORLDGUARD-3315): Invincibility flag and mode not blocking knockback from snowballs, etc.
* Fixed [#3314](http://youtrack.sk89q.com/issue/WORLDGUARD-3314): Protection bypassable by getting a skeleton or creeper to target a player
* Fixed [#3326](http://youtrack.sk89q.com/issue/WORLDGUARD-3326): Enderchests cannot be protected with the use flag
* Fixed [#3327](http://youtrack.sk89q.com/issue/WORLDGUARD-3327): Fake players from some Forge mods are not being detected properly
* Fixed [#3328](http://youtrack.sk89q.com/issue/WORLDGUARD-3328): TypeToken error with CraftBukkit 1.7 in `/wg report`
* Fixed [#3086](http://youtrack.sk89q.com/issue/WORLDGUARD-3086): Region entry / exit messages overlap between seprate worlds
* Fixed [#2542](http://youtrack.sk89q.com/issue/WORLDGUARD-2542): Exit deny regions don't handle respawn / logout consistently
* Fixed [#2731](http://youtrack.sk89q.com/issue/WORLDGUARD-2731): Greeting / farewell messages don't understand region inheritance
* Fixed [#3308](http://youtrack.sk89q.com/issue/WORLDGUARD-3308): Enderchest interaction block not functioning with blacklist.txt
* Fixed [#3312](http://youtrack.sk89q.com/issue/WORLDGUARD-3312): PVP flag blocking enderpearl teleport fall damage
* Fixed [#3309](http://youtrack.sk89q.com/issue/WORLDGUARD-3309): Inventory view commands being blocked in protected regions
* Fixed [#3310](http://youtrack.sk89q.com/issue/WORLDGUARD-3310): USE flag is not allowing workbench usage
* Fixed [#3330](http://youtrack.sk89q.com/issue/WORLDGUARD-3330): Build permissions preventing block placement
* API: Added `BukkitUtil.toRegion(Chunk)`
## 6.0 beta 4
MC 1.7.9, 1.7.10 and 1.8 (Spigot only) are supported.
* Added better support for MC 1.8 blocks (regarding the use flag, etc.).
* Added an an experimental "lite" version of WarmRoast to CPU profile your server (try it: `/wg profile -p`)
* Added permissions for individual flag values (i.e. `worldguard.region.flag.flags.use.allow`).
* Added support for slightly older versions of Bukkit 1.7.9.
* Improved `/wg report`'s output (try it: `/wg report -p`)
* Fixed armor stands not being protected properly.
* Fixed lack of wood plate support with the `USE` flag.
* Fixed left click also being blocked when only right click needed to be blocked.
* Fixed items and paintings/item frames not decaying under some versions of Spigot.
* Fixed parent-child inheritance so the child will always inherit the parent.
* Fixed inheritance issues with a flag is set with a region group on a parent region.
* Fixed high CPU usage when Citizens is also installed.
* Fixed `on-acquire` in the blacklist so it also handles item transfers between inventories.
* Fixed the blacklist not supporting color codes.
* Changed the PvP flag so it applies to self-attack like in WG 5 (this change *may* be reverted).
## 6.0 beta 3
MC 1.7.10 and 1.8 (Spigot only) are supported.
+1 -5
View File
@@ -4,7 +4,7 @@ This is a **major upgrade**. However, it is relatively well-tested because many
The version that you downloaded supports Minecraft 1.7.10 and 1.8.
**NEW DOCUMENTATION:** There is [new work-in-progress documentation](http://docs.enginehub.org/manual/worldguard/latest/). However, refer to the [older wiki](http://wiki.sk89q.com/wiki/WorldGuard) for missing pgaes.
**NEW DOCUMENTATION:** There is [new work-in-progress documentation](http://docs.enginehub.org/manual/worldguard/latest/). However, refer to the [older wiki](http://wiki.sk89q.com/wiki/WorldGuard) for missing pages.
## Downgrading to 5.9
@@ -47,10 +47,6 @@ Plugins that utilize WorldGuard's API may not work anymore. They may crash with
* Spigot:
* `settings.global-api-cache`, if enabled, will crash WG UUID lookups (fixed in Spigot build #1625)
* EchoPet
* Can't spawn pets ([issue #393](https://github.com/DSH105/EchoPet/issues/393))
* CraftBook
* Unable to use mechanics unless the `USE` flag is explicitly set to `ALLOW` ([CRAFTBOOK-3057](http://youtrack.sk89q.com/issue/CRAFTBOOK-3057))
## Other Changes
+1
View File
@@ -37,4 +37,5 @@
<allow pkg="com.google.common"/>
<allow pkg="com.jolbox.bonecp"/>
<allow pkg="org.flywaydb.core"/>
<allow pkg="org.json.simple"/>
</import-control>
+47 -51
View File
@@ -2,7 +2,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.sk89q</groupId>
<artifactId>worldguard</artifactId>
<version>6.0.0-beta-03</version>
<version>6.1</version>
<packaging>jar</packaging>
<!-- Project information -->
@@ -66,8 +66,8 @@
<url>http://maven.sk89q.com/repo/</url>
</repository>
<repository>
<id>bukkit-repo</id>
<url>http://repo.bukkit.org/content/groups/public</url>
<id>spigot-repo</id>
<url>https://hub.spigotmc.org/nexus/content/groups/public/</url>
</repository>
</repositories>
@@ -90,10 +90,17 @@
</exclusions>
</dependency>
<dependency>
<groupId>com.sk89q.spigot</groupId>
<artifactId>bukkit-classloader-check</artifactId>
<version>1.8-R0.1-SNAPSHOT</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.bukkit</groupId>
<artifactId>bukkit</artifactId>
<version>1.7.9-R0.3-SNAPSHOT</version>
<version>1.8.6-R0.1-SNAPSHOT</version>
<scope>compile</scope>
<type>jar</type>
</dependency>
@@ -129,14 +136,6 @@
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>10.0.1</version> <!-- Bukkit only bundles 10.0.1 -->
<scope>compile</scope> <!-- required runtime dependency -->
<type>jar</type>
</dependency>
<dependency>
<!-- Contains parts of Guava that are not compatible
between Bukkit 10.0.1 and 17+ -->
@@ -388,6 +387,7 @@
<include>org.flywaydb:flyway-core</include>
<include>com.sk89q:squirrelid</include>
<include>com.sk89q:guavabackport</include>
<include>com.googlecode.json-simple:json-simple</include>
</includes>
</artifactSet>
<relocations>
@@ -403,6 +403,10 @@
<pattern>com.sk89q.squirrelid</pattern>
<shadedPattern>com.sk89q.worldguard.util.profile</shadedPattern>
</relocation>
<relocation>
<pattern>org.json.simple</pattern>
<shadedPattern>com.sk89q.worldguard.util.jsonsimple</shadedPattern>
</relocation>
</relocations>
</configuration>
</execution>
@@ -456,6 +460,37 @@
<tagNameFormat>@{project.version}</tagNameFormat>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.2.1</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.8.1</version>
<configuration>
<additionalparam>-Xdoclint:none</additionalparam>
</configuration>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
@@ -487,43 +522,4 @@
</plugin>
</plugins>
</build>
<profiles>
<!-- Attach javadocs and source .jars -->
<profile>
<id>attach-docs</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.2.1</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.8.1</version>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>
@@ -24,6 +24,7 @@ import com.sk89q.worldguard.domains.Association;
import com.sk89q.worldguard.protection.association.RegionAssociable;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import java.util.List;
import java.util.UUID;
public abstract class LocalPlayer implements RegionAssociable {
@@ -94,14 +95,18 @@ public abstract class LocalPlayer implements RegionAssociable {
public abstract boolean hasPermission(String perm);
@Override
public Association getAssociation(ProtectedRegion region) {
if (region.isOwner(this)) {
return Association.OWNER;
} else if (region.isMember(this)) {
return Association.MEMBER;
} else {
return Association.NON_MEMBER;
public Association getAssociation(List<ProtectedRegion> regions) {
boolean member = false;
for (ProtectedRegion region : regions) {
if (region.isOwner(this)) {
return Association.OWNER;
} else if (!member && region.isMember(this)) {
member = true;
}
}
return member ? Association.MEMBER : Association.NON_MEMBER;
}
@Override
@@ -29,6 +29,7 @@ import com.sk89q.worldguard.blacklist.target.TargetMatcherParser;
import com.sk89q.guavabackport.cache.CacheBuilder;
import com.sk89q.guavabackport.cache.CacheLoader;
import com.sk89q.guavabackport.cache.LoadingCache;
import com.sk89q.worldguard.bukkit.commands.CommandUtils;
import org.bukkit.ChatColor;
import java.io.BufferedReader;
@@ -184,10 +185,10 @@ public abstract class Blacklist {
entry.setIgnorePermissions(parts[1].split(","));
} else if (parts[0].equalsIgnoreCase("message")) {
entry.setMessage(parts[1].trim());
entry.setMessage(CommandUtils.replaceColorMacros(parts[1].trim()));
} else if (parts[0].equalsIgnoreCase("comment")) {
entry.setComment(parts[1].trim());
entry.setComment(CommandUtils.replaceColorMacros(parts[1].trim()));
} else {
boolean found = false;
@@ -44,7 +44,7 @@ public class TellAction extends RepeatGuardedAction {
if (event.getPlayer() != null) {
if (message != null) {
event.getPlayer().printRaw(ChatColor.YELLOW + String.format(message, event.getTarget().getFriendlyName()) + ".");
event.getPlayer().printRaw(ChatColor.YELLOW + String.format(message, event.getTarget().getFriendlyName()));
} else {
event.getPlayer().printRaw(ChatColor.YELLOW + "You're not allowed to " + event.getDescription() + " " +
event.getTarget().getFriendlyName() + ".");
@@ -19,6 +19,7 @@
package com.sk89q.worldguard.bukkit;
import com.google.common.collect.ImmutableList;
import com.sk89q.worldedit.BlockVector;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.blocks.BlockID;
@@ -26,28 +27,23 @@ import com.sk89q.worldedit.blocks.BlockType;
import com.sk89q.worldedit.blocks.ItemID;
import com.sk89q.worldguard.blacklist.target.MaterialTarget;
import com.sk89q.worldguard.blacklist.target.Target;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Server;
import org.bukkit.World;
import com.sk89q.worldguard.protection.regions.ProtectedCuboidRegion;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import org.bukkit.*;
import org.bukkit.block.Block;
import org.bukkit.entity.Entity;
import org.bukkit.entity.ExperienceOrb;
import org.bukkit.entity.FallingBlock;
import org.bukkit.entity.Item;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.entity.TNTPrimed;
import org.bukkit.entity.Tameable;
import org.bukkit.entity.*;
import org.bukkit.inventory.ItemStack;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.List;
import static com.google.common.base.Preconditions.checkNotNull;
public class BukkitUtil {
private static Method ONLINE_PLAYERS_METHOD;
private BukkitUtil() {
}
@@ -93,6 +89,20 @@ public class BukkitUtil {
return new Location(world, vec.getX(), vec.getY(), vec.getZ());
}
/**
* Create a dummy region that encompasses the size of a chunk.
*
* @param chunk The chunk
* @return The dummy region
*/
public static ProtectedRegion toRegion(Chunk chunk) {
World world = chunk.getWorld();
int minX = chunk.getX() << 4;
int minZ = chunk.getZ() << 4;
return new ProtectedCuboidRegion("_", new BlockVector(minX, 0, minZ), new BlockVector(minX + 15, world.getMaxHeight(), minZ + 15));
}
/**
* Matches one player based on name.
*
@@ -350,4 +360,42 @@ public class BukkitUtil {
return new MaterialTarget(material.getId(), (short) 0);
}
/**
* Get a collection of the currently online players.
*
* @return The online players
*/
@SuppressWarnings("unchecked")
public static Collection<? extends Player> getOnlinePlayers() {
try {
return Bukkit.getServer().getOnlinePlayers();
} catch (NoSuchMethodError ignored) {
}
try {
if (ONLINE_PLAYERS_METHOD == null) {
ONLINE_PLAYERS_METHOD = getOnlinePlayersMethod();
}
Object result = ONLINE_PLAYERS_METHOD.invoke(Bukkit.getServer());
if (result instanceof Player[]) {
return ImmutableList.copyOf((Player[]) result);
} else if (result instanceof Collection<?>) {
return (Collection<? extends Player>) result;
} else {
throw new RuntimeException("Result of getOnlinePlayers() call was not a known data type");
}
} catch (Exception e) {
throw new RuntimeException("WorldGuard is not compatible with this version of Bukkit", e);
}
}
private static Method getOnlinePlayersMethod() throws NoSuchMethodException {
try {
return Server.class.getMethod("getOnlinePlayers");
} catch (NoSuchMethodException e1) {
return Server.class.getMethod("_INVALID_getOnlinePlayers");
}
}
}
@@ -20,15 +20,13 @@
package com.sk89q.worldguard.bukkit;
import com.google.common.collect.ImmutableMap;
import com.sk89q.commandbook.CommandBook;
import com.sk89q.commandbook.GodComponent;
import com.sk89q.util.yaml.YAMLFormat;
import com.sk89q.util.yaml.YAMLProcessor;
import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.protection.managers.storage.file.DirectoryYamlDriver;
import com.sk89q.worldguard.protection.managers.storage.DriverType;
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.session.handler.WaterBreathing;
import com.sk89q.worldguard.util.report.Unreported;
import com.sk89q.worldguard.util.sql.DataSourceConfig;
import org.bukkit.World;
@@ -37,9 +35,7 @@ import org.bukkit.entity.Player;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.logging.Logger;
@@ -79,12 +75,9 @@ public class ConfigurationManager {
@Unreported private WorldGuardPlugin plugin;
@Unreported private ConcurrentMap<String, WorldConfiguration> worlds;
@Unreported private YAMLProcessor config;
@Deprecated @Unreported private Set<String> hasGodMode = new HashSet<String>();
@Unreported private Set<String> hasAmphibious = new HashSet<String>();
private boolean hasCommandBookGodMode = false;
public boolean useRegionsScheduler;
public boolean useRegionsCreatureSpawnEvent;
public boolean activityHaltToggle = false;
public boolean useGodPermission;
@@ -152,7 +145,6 @@ public class ConfigurationManager {
}
config.removeProperty("suppress-tick-sync-warnings");
useRegionsScheduler = config.getBoolean("regions.use-scheduler", true);
migrateRegionsToUuid = config.getBoolean("regions.uuid-migration.perform-on-next-start", true);
keepUnresolvedNames = config.getBoolean("regions.uuid-migration.keep-names-that-lack-uuids", true);
useRegionsCreatureSpawnEvent = config.getBoolean("regions.use-creature-spawn-event", true);
@@ -242,37 +234,6 @@ public class ConfigurationManager {
return config;
}
/**
* Forget a player.
*
* @param player The player to forget about
*/
public void forgetPlayer(LocalPlayer player) {
hasGodMode.remove(player.getName());
hasAmphibious.remove(player.getName());
}
/**
* Enable god mode for a player.
*
* @param player The player to enable god mode for.
*/
@Deprecated
public void enableGodMode(Player player) {
hasGodMode.add(player.getName());
}
/**
* Disable god mode for a player.
*
* @param player The player to disable godmode for
*/
@Deprecated
public void disableGodMode(Player player) {
hasGodMode.remove(player.getName());
}
/**
* Check to see if god mode is enabled for a player.
*
@@ -280,13 +241,7 @@ public class ConfigurationManager {
* @return Whether the player has godmode through WorldGuard or CommandBook
*/
public boolean hasGodMode(Player player) {
if (hasCommandBookGodMode) {
GodComponent god = CommandBook.inst().getComponentManager().getComponent(GodComponent.class);
if (god != null) {
return god.hasGodMode(player);
}
}
return hasGodMode.contains(player.getName());
return plugin.getSessionManager().get(player).isInvincible(player);
}
/**
@@ -295,7 +250,10 @@ public class ConfigurationManager {
* @param player The player to enable amphibious mode for
*/
public void enableAmphibiousMode(Player player) {
hasAmphibious.add(player.getName());
WaterBreathing handler = plugin.getSessionManager().get(player).getHandler(WaterBreathing.class);
if (handler != null) {
handler.setWaterBreathing(true);
}
}
/**
@@ -304,7 +262,10 @@ public class ConfigurationManager {
* @param player The player to disable amphibious mode for
*/
public void disableAmphibiousMode(Player player) {
hasAmphibious.remove(player.getName());
WaterBreathing handler = plugin.getSessionManager().get(player).getHandler(WaterBreathing.class);
if (handler != null) {
handler.setWaterBreathing(false);
}
}
/**
@@ -314,7 +275,8 @@ public class ConfigurationManager {
* @return Whether {@code player} has amphibious mode
*/
public boolean hasAmphibiousMode(Player player) {
return hasAmphibious.contains(player.getName());
WaterBreathing handler = plugin.getSessionManager().get(player).getHandler(WaterBreathing.class);
return handler != null && handler.hasWaterBreathing();
}
public void updateCommandBookGodMode() {
@@ -19,6 +19,7 @@
package com.sk89q.worldguard.bukkit;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListeningExecutorService;
@@ -39,10 +40,15 @@ import com.sk89q.worldguard.bukkit.event.player.ProcessPlayerEvent;
import com.sk89q.worldguard.bukkit.listener.*;
import com.sk89q.worldguard.bukkit.util.Events;
import com.sk89q.worldguard.protection.GlobalRegionManager;
import com.sk89q.worldguard.protection.flags.Flag;
import com.sk89q.worldguard.protection.managers.RegionManager;
import com.sk89q.worldguard.protection.managers.storage.StorageException;
import com.sk89q.worldguard.protection.regions.ProtectedCuboidRegion;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import com.sk89q.worldguard.protection.util.UnresolvedNamesException;
import com.sk89q.worldguard.session.SessionManager;
import com.sk89q.worldguard.util.concurrent.EvenMoreExecutors;
import com.sk89q.worldguard.util.logging.ClassSourceValidator;
import com.sk89q.worldguard.util.logging.RecordMessagePrefixer;
import com.sk89q.worldguard.util.task.SimpleSupervisor;
import com.sk89q.worldguard.util.task.Supervisor;
@@ -85,7 +91,7 @@ public class WorldGuardPlugin extends JavaPlugin {
private final ConfigurationManager configuration = new ConfigurationManager(this);
private final RegionContainer regionContainer = new RegionContainer(this);
private final GlobalRegionManager globalRegionManager = new GlobalRegionManager(this, regionContainer);
private FlagStateManager flagStateManager;
private SessionManager sessionManager;
private final Supervisor supervisor = new SimpleSupervisor();
private ListeningExecutorService executorService;
private ProfileService profileService;
@@ -126,9 +132,16 @@ public class WorldGuardPlugin extends JavaPlugin {
executorService = MoreExecutors.listeningDecorator(EvenMoreExecutors.newBoundedCachedThreadPool(0, 1, 20));
sessionManager = new SessionManager(this);
// Set the proper command injector
commands.setInjector(new SimpleInjector(this));
// Catch bad things being done by naughty plugins that include
// WorldGuard's classes
ClassSourceValidator verifier = new ClassSourceValidator(this);
verifier.reportMismatches(ImmutableList.of(WGBukkit.class, ProtectedRegion.class, ProtectedCuboidRegion.class, Flag.class));
// Register command classes
final CommandsManagerRegistration reg = new CommandsManagerRegistration(this, commands);
reg.register(ToggleCommands.class);
@@ -164,14 +177,10 @@ public class WorldGuardPlugin extends JavaPlugin {
log.info("Loading region data...");
regionContainer.initialize();
flagStateManager = new FlagStateManager(this);
if (configuration.useRegionsScheduler) {
getServer().getScheduler().scheduleSyncRepeatingTask(this, flagStateManager,
FlagStateManager.RUN_DELAY, FlagStateManager.RUN_DELAY);
}
getServer().getScheduler().scheduleSyncRepeatingTask(this, sessionManager, SessionManager.RUN_DELAY, SessionManager.RUN_DELAY);
// Register events
getServer().getPluginManager().registerEvents(sessionManager, this);
(new WorldGuardPlayerListener(this)).registerEvents();
(new WorldGuardBlockListener(this)).registerEvents();
(new WorldGuardEntityListener(this)).registerEvents();
@@ -186,10 +195,12 @@ public class WorldGuardPlugin extends JavaPlugin {
(new ChestProtectionListener(this)).registerEvents();
(new RegionProtectionListener(this)).registerEvents();
(new RegionFlagsListener(this)).registerEvents();
(new WorldRulesListener(this)).registerEvents();
(new BlockedPotionsListener(this)).registerEvents();
(new EventAbstractionListener(this)).registerEvents();
(new PlayerModesListener(this)).registerEvents();
(new BuildPermissionListener(this)).registerEvents();
(new InvincibilityListener(this)).registerEvents();
if ("true".equalsIgnoreCase(System.getProperty("worldguard.debug.listener"))) {
(new DebuggingListener(this, log)).registerEvents();
}
@@ -207,7 +218,7 @@ public class WorldGuardPlugin extends JavaPlugin {
}
worldListener.registerEvents();
for (Player player : getServer().getOnlinePlayers()) {
for (Player player : BukkitUtil.getOnlinePlayers()) {
ProcessPlayerEvent event = new ProcessPlayerEvent(player);
Events.fire(event);
}
@@ -327,8 +338,8 @@ public class WorldGuardPlugin extends JavaPlugin {
*
* @return The flag state manager
*/
public FlagStateManager getFlagStateManager() {
return flagStateManager;
public SessionManager getSessionManager() {
return sessionManager;
}
/**
@@ -462,7 +473,7 @@ public class WorldGuardPlugin extends JavaPlugin {
// Invoke the permissions resolver
if (sender instanceof Player) {
Player player = (Player) sender;
return PermissionsResolverManager.getInstance().hasPermission(player.getWorld().getName(), player.getName(), perm);
return PermissionsResolverManager.getInstance().hasPermission(player.getWorld().getName(), player, perm);
}
return false;
@@ -510,7 +521,7 @@ public class WorldGuardPlugin extends JavaPlugin {
* @return A {@link List} of players who match {@code filter}
*/
public List<Player> matchPlayerNames(String filter) {
Collection<? extends Player> players = getServer().getOnlinePlayers();
Collection<? extends Player> players = BukkitUtil.getOnlinePlayers();
filter = filter.toLowerCase();
@@ -591,12 +602,12 @@ public class WorldGuardPlugin extends JavaPlugin {
public Iterable<? extends Player> matchPlayers(CommandSender source, String filter)
throws CommandException {
if (getServer().getOnlinePlayers().isEmpty()) {
if (BukkitUtil.getOnlinePlayers().isEmpty()) {
throw new CommandException("No players matched query.");
}
if (filter.equals("*")) {
return checkPlayerMatch(Lists.newArrayList(getServer().getOnlinePlayers()));
return checkPlayerMatch(Lists.newArrayList(BukkitUtil.getOnlinePlayers()));
}
// Handle special hash tag groups
@@ -608,7 +619,7 @@ public class WorldGuardPlugin extends JavaPlugin {
Player sourcePlayer = checkPlayer(source);
World sourceWorld = sourcePlayer.getWorld();
for (Player player : getServer().getOnlinePlayers()) {
for (Player player : BukkitUtil.getOnlinePlayers()) {
if (player.getWorld().equals(sourceWorld)) {
players.add(player);
}
@@ -624,7 +635,7 @@ public class WorldGuardPlugin extends JavaPlugin {
org.bukkit.util.Vector sourceVector
= sourcePlayer.getLocation().toVector();
for (Player player : getServer().getOnlinePlayers()) {
for (Player player : BukkitUtil.getOnlinePlayers()) {
if (player.getWorld().equals(sourceWorld)
&& player.getLocation().toVector().distanceSquared(
sourceVector) < 900) {
@@ -916,7 +927,7 @@ public class WorldGuardPlugin extends JavaPlugin {
public void broadcastNotification(String msg) {
getServer().broadcast(msg, "worldguard.notify");
Set<Permissible> subs = getServer().getPluginManager().getPermissionSubscriptions("worldguard.notify");
for (Player player : getServer().getOnlinePlayers()) {
for (Player player : BukkitUtil.getOnlinePlayers()) {
if (!(subs.contains(player) && player.hasPermission("worldguard.notify")) &&
hasPermission(player, "worldguard.notify")) { // Make sure the player wasn't already broadcasted to.
player.sendMessage(msg);
@@ -925,15 +936,6 @@ public class WorldGuardPlugin extends JavaPlugin {
log.info(msg);
}
/**
* Forgets a player.
*
* @param player The player to remove state information for
*/
public void forgetPlayer(Player player) {
flagStateManager.forget(player);
}
/**
* Checks to see if a player can build at a location. This will return
* true if region protection is disabled.
@@ -994,7 +996,7 @@ public class WorldGuardPlugin extends JavaPlugin {
* @return The message with macros replaced
*/
public String replaceMacros(CommandSender sender, String message) {
Collection<? extends Player> online = getServer().getOnlinePlayers();
Collection<? extends Player> online = BukkitUtil.getOnlinePlayers();
message = message.replace("%name%", toName(sender));
message = message.replace("%id%", toUniqueName(sender));
@@ -20,21 +20,17 @@
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 org.bukkit.block.Block;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
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.entity.*;
import org.bukkit.metadata.Metadatable;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import static com.google.common.base.Preconditions.checkNotNull;
@@ -47,21 +43,36 @@ import static com.google.common.base.Preconditions.checkNotNull;
* is the initiator, while the arrow is merely controlled by the player to
* hit the item frame.</p>
*/
public class Cause {
public final class Cause {
private static final String CAUSE_KEY = "worldguard.cause";
private static final Cause UNKNOWN = new Cause(Collections.emptyList());
private static final Cause UNKNOWN = new Cause(Collections.emptyList(), false);
private final List<Object> causes;
private final boolean indirect;
/**
* Create a new instance.
*
* @param causes a list of causes
* @param indirect whether the cause is indirect
*/
private Cause(List<Object> causes) {
private Cause(List<Object> causes, boolean indirect) {
checkNotNull(causes);
this.causes = causes;
this.indirect = indirect;
}
/**
* Test whether the traced cause is indirect.
*
* <p>If the cause is indirect, then the root cause may not be notified,
* for example.</p>
*
* @return true if the cause is indirect
*/
public boolean isIndirect() {
return indirect;
}
/**
@@ -118,6 +129,17 @@ public class Cause {
return null;
}
@Nullable
public Entity getFirstNonPlayerEntity() {
for (Object object : causes) {
if (object instanceof Entity && !(object instanceof Player)) {
return (Entity) object;
}
}
return null;
}
@Nullable
public Block getFirstBlock() {
for (Object object : causes) {
@@ -155,44 +177,6 @@ public class Cause {
return Joiner.on(" | ").join(causes);
}
/**
* Expand an cause object.
*
* @param list the list to add elements to
* @param element an array of objects
*/
private static void expand(List<Object> list, @Nullable Object ... element) {
if (element != null) {
for (Object o : element) {
if (o == null) {
continue;
}
if (o instanceof TNTPrimed) {
expand(list, ((TNTPrimed) o).getSource());
} else if (o instanceof Projectile) {
expand(list, ((Projectile) o).getShooter());
} else if (o instanceof Vehicle) {
expand(list, ((Vehicle) o).getPassenger());
} else if (o instanceof Tameable) {
expand(list, ((Tameable) o).getOwner());
}
// Add manually tracked parent causes
Object source = o;
int index = list.size();
while (source instanceof Metadatable && !(source instanceof Block)) {
source = WGMetadata.getIfPresent((Metadatable) source, CAUSE_KEY, Object.class);
if (source != null) {
list.add(index, source);
}
}
list.add(o);
}
}
}
/**
* Create a new instance with the given objects as the cause,
* where the first-most object is the initial initiator and those
@@ -201,11 +185,11 @@ public class Cause {
* @param cause an array of causing objects
* @return a cause
*/
public static Cause create(@Nullable Object ... cause) {
public static Cause create(@Nullable Object... cause) {
if (cause != null) {
List<Object> causes = new ArrayList<Object>(cause.length);
expand(causes, cause);
return new Cause(causes);
Builder builder = new Builder(cause.length);
builder.addAll(cause);
return builder.build();
} else {
return UNKNOWN;
}
@@ -240,4 +224,60 @@ public class Cause {
WGMetadata.put(target, CAUSE_KEY, parent);
}
/**
* Builds causes.
*/
private static final class Builder {
private final List<Object> causes;
private final Set<Object> seen = Sets.newHashSet();
private boolean indirect;
private Builder(int expectedSize) {
this.causes = new ArrayList<Object>(expectedSize);
}
private void addAll(@Nullable Object... element) {
if (element != null) {
for (Object o : element) {
if (o == null || seen.contains(o)) {
continue;
}
seen.add(o);
if (o instanceof TNTPrimed) {
addAll(((TNTPrimed) o).getSource());
} else if (o instanceof Projectile) {
addAll(((Projectile) o).getShooter());
} else if (o instanceof Vehicle) {
addAll(((Vehicle) o).getPassenger());
} 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());
}
// Add manually tracked parent causes
Object source = o;
int index = causes.size();
while (source instanceof Metadatable && !(source instanceof Block)) {
source = WGMetadata.getIfPresent((Metadatable) source, CAUSE_KEY, Object.class);
if (source != null) {
causes.add(index, source);
seen.add(source);
}
}
causes.add(o);
}
}
}
public Cause build() {
return new Cause(causes, indirect);
}
}
}
@@ -20,6 +20,11 @@
package com.sk89q.worldguard.bukkit.commands;
import com.google.common.base.Function;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
import com.sk89q.worldguard.util.paste.EngineHubPaste;
import org.bukkit.ChatColor;
import org.bukkit.command.BlockCommandSender;
import org.bukkit.command.CommandSender;
@@ -27,12 +32,17 @@ import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.entity.Player;
import javax.annotation.Nullable;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Command-related utility methods.
*/
public final class CommandUtils {
private static final Logger log = Logger.getLogger(CommandUtils.class.getCanonicalName());
private CommandUtils() {
}
@@ -110,6 +120,7 @@ public final class CommandUtils {
str = str.replace("&o", ChatColor.ITALIC.toString());
str = str.replace("&x", ChatColor.RESET.toString());
str = str.replace("&r", ChatColor.RESET.toString());
return str;
}
@@ -152,4 +163,34 @@ public final class CommandUtils {
};
}
/**
* Submit data to a pastebin service and inform the sender of
* success or failure.
*
* @param plugin The plugin
* @param sender The sender
* @param content The content
* @param successMessage The message, formatted with {@link String#format(String, Object...)} on success
*/
public static void pastebin(WorldGuardPlugin plugin, final CommandSender sender, String content, final String successMessage) {
ListenableFuture<URL> future = new EngineHubPaste().paste(content);
AsyncCommandHelper.wrap(future, plugin, sender)
.registerWithSupervisor("Submitting content to a pastebin service...")
.sendMessageAfterDelay("(Please wait... sending output to pastebin...)");
Futures.addCallback(future, new FutureCallback<URL>() {
@Override
public void onSuccess(URL url) {
sender.sendMessage(ChatColor.YELLOW + String.format(successMessage, url));
}
@Override
public void onFailure(Throwable throwable) {
log.log(Level.WARNING, "Failed to submit pastebin", throwable);
sender.sendMessage(ChatColor.RED + "Failed to submit to a pastebin. Please see console for the error.");
}
});
}
}
@@ -19,10 +19,7 @@
package com.sk89q.worldguard.bukkit.commands;
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.*;
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
import com.sk89q.worldguard.bukkit.event.debug.*;
import com.sk89q.worldguard.util.report.CancelReport;
@@ -58,45 +55,45 @@ public class DebuggingCommands {
this.plugin = plugin;
}
@Command(aliases = {"testbreak"}, usage = "[player]", desc = "Simulate a block break", min = 1, max = 1, flags = "t")
@Command(aliases = {"testbreak"}, usage = "[player]", desc = "Simulate a block break", min = 1, max = 1, flags = "ts")
@CommandPermissions("worldguard.debug.event")
public void fireBreakEvent(CommandContext args, final CommandSender sender) throws CommandException {
Player target = plugin.matchSinglePlayer(sender, args.getString(0));
Block block = traceBlock(sender, target, args.hasFlag('t'));
sender.sendMessage(ChatColor.AQUA + "Testing BLOCK BREAK at " + ChatColor.DARK_AQUA + block);
LoggingBlockBreakEvent event = new LoggingBlockBreakEvent(block, target);
testEvent(sender, target, event);
testEvent(sender, target, event, args.hasFlag('s'));
}
@Command(aliases = {"testplace"}, usage = "[player]", desc = "Simulate a block place", min = 1, max = 1, flags = "t")
@Command(aliases = {"testplace"}, usage = "[player]", desc = "Simulate a block place", min = 1, max = 1, flags = "ts")
@CommandPermissions("worldguard.debug.event")
public void firePlaceEvent(CommandContext args, final CommandSender sender) throws CommandException {
Player target = plugin.matchSinglePlayer(sender, args.getString(0));
Block block = traceBlock(sender, target, args.hasFlag('t'));
sender.sendMessage(ChatColor.AQUA + "Testing BLOCK PLACE at " + ChatColor.DARK_AQUA + block);
LoggingBlockPlaceEvent event = new LoggingBlockPlaceEvent(block, block.getState(), block.getRelative(BlockFace.DOWN), target.getItemInHand(), target, true);
testEvent(sender, target, event);
testEvent(sender, target, event, args.hasFlag('s'));
}
@Command(aliases = {"testinteract"}, usage = "[player]", desc = "Simulate a block interact", min = 1, max = 1, flags = "t")
@Command(aliases = {"testinteract"}, usage = "[player]", desc = "Simulate a block interact", min = 1, max = 1, flags = "ts")
@CommandPermissions("worldguard.debug.event")
public void fireInteractEvent(CommandContext args, final CommandSender sender) throws CommandException {
Player target = plugin.matchSinglePlayer(sender, args.getString(0));
Block block = traceBlock(sender, target, args.hasFlag('t'));
sender.sendMessage(ChatColor.AQUA + "Testing BLOCK INTERACT at " + ChatColor.DARK_AQUA + block);
LoggingPlayerInteractEvent event = new LoggingPlayerInteractEvent(target, Action.RIGHT_CLICK_BLOCK, target.getItemInHand(), block, BlockFace.SOUTH);
testEvent(sender, target, event);
testEvent(sender, target, event, args.hasFlag('s'));
}
@Command(aliases = {"testdamage"}, usage = "[player]", desc = "Simulate an entity damage", min = 1, max = 1, flags = "t")
@Command(aliases = {"testdamage"}, usage = "[player]", desc = "Simulate an entity damage", min = 1, max = 1, flags = "ts")
@CommandPermissions("worldguard.debug.event")
public void fireDamageEvent(CommandContext args, final CommandSender sender) throws CommandException {
Player target = plugin.matchSinglePlayer(sender, args.getString(0));
Entity entity = traceEntity(sender, target, args.hasFlag('t'));
sender.sendMessage(ChatColor.AQUA + "Testing ENTITY DAMAGE on " + ChatColor.DARK_AQUA + entity);
LoggingEntityDamageByEntityEvent event = new LoggingEntityDamageByEntityEvent(target, entity, DamageCause.ENTITY_ATTACK, 1);
testEvent(sender, target, event);
testEvent(sender, target, event, args.hasFlag('s'));
}
/**
@@ -104,10 +101,11 @@ public class DebuggingCommands {
*
* @param receiver The receiver of the messages
* @param target The target
* @param event THe event
* @param event The event
* @param stacktraceMode Whether stack traces should be generated and posted
* @param <T> The type of event
*/
private <T extends Event & CancelLogging> void testEvent(CommandSender receiver, Player target, T event) {
private <T extends Event & CancelLogging> void testEvent(CommandSender receiver, Player target, T event, boolean stacktraceMode) throws CommandPermissionsException {
boolean isConsole = receiver instanceof ConsoleCommandSender;
if (!receiver.equals(target)) {
@@ -122,12 +120,22 @@ public class DebuggingCommands {
Bukkit.getPluginManager().callEvent(event);
int start = new Exception().getStackTrace().length;
CancelReport report = new CancelReport(event, event.getCancels(), start);
report.setDetectingPlugin(!stacktraceMode);
String result = report.toString();
receiver.sendMessage(result.replaceAll("(?m)^", ChatColor.AQUA.toString()));
if (result.length() >= 500 && !isConsole) {
receiver.sendMessage(ChatColor.GRAY + "The report was also printed to console.");
if (stacktraceMode) {
receiver.sendMessage(ChatColor.GRAY + "The report was printed to console.");
log.info("Event report for " + receiver.getName() + ":\n\n" + result);
plugin.checkPermission(receiver, "worldguard.debug.pastebin");
CommandUtils.pastebin(plugin, receiver, result, "Event debugging report: %s.txt");
} else {
receiver.sendMessage(result.replaceAll("(?m)^", ChatColor.AQUA.toString()));
if (result.length() >= 500 && !isConsole) {
receiver.sendMessage(ChatColor.GRAY + "The report was also printed to console.");
log.info("Event report for " + receiver.getName() + ":\n\n" + result);
}
}
}
@@ -19,11 +19,6 @@
package com.sk89q.worldguard.bukkit.commands;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import com.sk89q.minecraft.util.commands.Command;
import com.sk89q.minecraft.util.commands.CommandContext;
import com.sk89q.minecraft.util.commands.CommandException;
@@ -31,6 +26,12 @@ import com.sk89q.minecraft.util.commands.CommandPermissions;
import com.sk89q.worldedit.blocks.ItemType;
import com.sk89q.worldguard.bukkit.ConfigurationManager;
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
import com.sk89q.worldguard.session.Session;
import com.sk89q.worldguard.session.handler.GodMode;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
public class GeneralCommands {
private final WorldGuardPlugin plugin;
@@ -54,7 +55,7 @@ public class GeneralCommands {
// Check permissions!
plugin.checkPermission(sender, "worldguard.god");
} else if (args.argsLength() == 1) {
} else {
targets = plugin.matchPlayers(sender, args.getString(0));
// Check permissions!
@@ -62,26 +63,29 @@ public class GeneralCommands {
}
for (Player player : targets) {
config.enableGodMode(player);
player.setFireTicks(0);
// Tell the user
if (player.equals(sender)) {
player.sendMessage(ChatColor.YELLOW + "God mode enabled! Use /ungod to disable.");
// Keep track of this
included = true;
} else {
player.sendMessage(ChatColor.YELLOW + "God enabled by "
+ plugin.toName(sender) + ".");
Session session = plugin.getSessionManager().get(player);
if (GodMode.set(player, session, true)) {
player.setFireTicks(0);
// Tell the user
if (player.equals(sender)) {
player.sendMessage(ChatColor.YELLOW + "God mode enabled! Use /ungod to disable.");
// Keep track of this
included = true;
} else {
player.sendMessage(ChatColor.YELLOW + "God enabled by "
+ plugin.toName(sender) + ".");
}
}
}
// The player didn't receive any items, then we need to send the
// user a message so s/he know that something is indeed working
if (!included && args.hasFlag('s')) {
sender.sendMessage(ChatColor.YELLOW.toString() + "Players now have god mode.");
sender.sendMessage(ChatColor.YELLOW + "Players now have god mode.");
}
}
@@ -100,7 +104,7 @@ public class GeneralCommands {
// Check permissions!
plugin.checkPermission(sender, "worldguard.god");
} else if (args.argsLength() == 1) {
} else {
targets = plugin.matchPlayers(sender, args.getString(0));
// Check permissions!
@@ -108,25 +112,27 @@ public class GeneralCommands {
}
for (Player player : targets) {
config.disableGodMode(player);
// Tell the user
if (player.equals(sender)) {
player.sendMessage(ChatColor.YELLOW + "God mode disabled!");
// Keep track of this
included = true;
} else {
player.sendMessage(ChatColor.YELLOW + "God disabled by "
+ plugin.toName(sender) + ".");
Session session = plugin.getSessionManager().get(player);
if (GodMode.set(player, session, false)) {
// Tell the user
if (player.equals(sender)) {
player.sendMessage(ChatColor.YELLOW + "God mode disabled!");
// Keep track of this
included = true;
} else {
player.sendMessage(ChatColor.YELLOW + "God disabled by "
+ plugin.toName(sender) + ".");
}
}
}
// The player didn't receive any items, then we need to send the
// user a message so s/he know that something is indeed working
if (!included && args.hasFlag('s')) {
sender.sendMessage(ChatColor.YELLOW.toString() + "Players no longer have god mode.");
sender.sendMessage(ChatColor.YELLOW + "Players no longer have god mode.");
}
}
@@ -19,15 +19,21 @@
package com.sk89q.worldguard.bukkit.commands;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.io.Files;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.MoreExecutors;
import com.sk89q.minecraft.util.commands.*;
import com.sk89q.worldguard.bukkit.ConfigurationManager;
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
import com.sk89q.worldguard.bukkit.util.logging.LoggerToChatHandler;
import com.sk89q.worldguard.bukkit.util.report.*;
import com.sk89q.worldguard.util.paste.Pastebin;
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.ReportList;
import com.sk89q.worldguard.util.report.SystemInfoReport;
import com.sk89q.worldguard.util.task.Task;
@@ -38,12 +44,14 @@ import org.bukkit.World;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import javax.annotation.Nullable;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.lang.management.ThreadInfo;
import java.nio.charset.Charset;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -52,6 +60,8 @@ public class WorldGuardCommands {
private static final Logger log = Logger.getLogger(WorldGuardCommands.class.getCanonicalName());
private final WorldGuardPlugin plugin;
@Nullable
private Sampler activeSampler;
public WorldGuardCommands(WorldGuardPlugin plugin) {
this.plugin = plugin;
@@ -128,23 +138,111 @@ public class WorldGuardCommands {
if (args.hasFlag('p')) {
plugin.checkPermission(sender, "worldguard.report.pastebin");
sender.sendMessage(ChatColor.YELLOW + "Now uploading to Pastebin...");
CommandUtils.pastebin(plugin, sender, result, "WorldGuard report: %s.report");
}
}
Futures.addCallback(new Pastebin().paste(result), new FutureCallback<URL>() {
@Override
public void onSuccess(URL url) {
sender.sendMessage(ChatColor.YELLOW + "WorldGuard report: " + url);
}
@Command(aliases = {"profile"}, usage = "[<minutes>]",
desc = "Profile the CPU usage of the server", min = 0, max = 1,
flags = "t:p")
@CommandPermissions("worldguard.profile")
public void profile(final CommandContext args, final CommandSender sender) throws CommandException {
Predicate<ThreadInfo> threadFilter;
String threadName = args.getFlag('t');
final boolean pastebin;
@Override
public void onFailure(Throwable throwable) {
log.log(Level.WARNING, "Failed to submit pastebin", throwable);
sender.sendMessage(ChatColor.RED + "The WorldGuard report could not be saved to a pastebin service. Please see console for the error.");
}
});
if (args.hasFlag('p')) {
plugin.checkPermission(sender, "worldguard.report.pastebin");
pastebin = true;
} else {
pastebin = false;
}
if (threadName == null) {
threadFilter = new ThreadIdFilter(Thread.currentThread().getId());
} else if (threadName.equals("*")) {
threadFilter = Predicates.alwaysTrue();
} else {
threadFilter = new ThreadNameFilter(threadName);
}
int minutes;
if (args.argsLength() == 0) {
minutes = 5;
} else {
minutes = args.getInteger(0);
if (minutes < 1) {
throw new CommandException("You must run the profile for at least 1 minute.");
} else if (minutes > 10) {
throw new CommandException("You can profile for, at maximum, 10 minutes.");
}
}
Sampler sampler;
synchronized (this) {
if (activeSampler != null) {
throw new CommandException("A profile is currently in progress! Please use /wg stopprofile to stop the current profile.");
}
SamplerBuilder builder = new SamplerBuilder();
builder.setThreadFilter(threadFilter);
builder.setRunTime(minutes, TimeUnit.MINUTES);
sampler = activeSampler = builder.start();
}
AsyncCommandHelper.wrap(sampler.getFuture(), plugin, sender)
.formatUsing(minutes)
.registerWithSupervisor("Running CPU profiler for %d minute(s)...")
.sendMessageAfterDelay("(Please wait... profiling for %d minute(s)...)")
.thenTellErrorsOnly("CPU profiling failed.");
sampler.getFuture().addListener(new Runnable() {
@Override
public void run() {
synchronized (WorldGuardCommands.this) {
activeSampler = null;
}
}
}, MoreExecutors.sameThreadExecutor());
Futures.addCallback(sampler.getFuture(), new FutureCallback<Sampler>() {
@Override
public void onSuccess(Sampler result) {
String output = result.toString();
try {
File dest = new File(plugin.getDataFolder(), "profile.txt");
Files.write(output, dest, Charset.forName("UTF-8"));
sender.sendMessage(ChatColor.YELLOW + "CPU profiling data written to " + dest.getAbsolutePath());
} catch (IOException e) {
sender.sendMessage(ChatColor.RED + "Failed to write CPU profiling data: " + e.getMessage());
}
if (pastebin) {
CommandUtils.pastebin(plugin, sender, output, "Profile result: %s.profile");
}
}
@Override
public void onFailure(Throwable throwable) {
}
});
}
@Command(aliases = {"stopprofile"}, usage = "",desc = "Stop a running profile", min = 0, max = 0)
@CommandPermissions("worldguard.profile")
public void stopProfile(CommandContext args, final CommandSender sender) throws CommandException {
synchronized (this) {
if (activeSampler == null) {
throw new CommandException("No CPU profile is currently running.");
}
activeSampler.cancel();
activeSampler = null;
}
sender.sendMessage("The running CPU profile has been stopped.");
}
@Command(aliases = {"flushstates", "clearstates"},
@@ -152,12 +250,12 @@ public class WorldGuardCommands {
@CommandPermissions("worldguard.flushstates")
public void flushStates(CommandContext args, CommandSender sender) throws CommandException {
if (args.argsLength() == 0) {
plugin.getFlagStateManager().forgetAll();
plugin.getSessionManager().resetAllStates();
sender.sendMessage("Cleared all states.");
} else {
Player player = plugin.getServer().getPlayer(args.getString(0));
if (player != null) {
plugin.getFlagStateManager().forget(player);
plugin.getSessionManager().resetState(player);
sender.sendMessage("Cleared states for player \"" + player.getName() + "\".");
}
}
@@ -519,7 +519,7 @@ public final class RegionCommands extends RegionCommandsBase {
// Also make sure that we can use this flag
// This permission is confusing and probably should be replaced, but
// but not here -- in the model
if (!permModel.maySetFlag(existing, foundFlag)) {
if (!permModel.maySetFlag(existing, foundFlag, value)) {
throw new CommandPermissionsException();
}
@@ -19,20 +19,21 @@
package com.sk89q.worldguard.bukkit.event;
import org.bukkit.event.Event.Result;
/**
* A bulk event contains several affected objects in a list.
*/
public interface BulkEvent {
/**
* Return whether the event is explicitly cancelled.
* Get the actual result.
*
* <p>By default, bulk events will cancel itself if the number of affected
* objects drops to zero. This method returns the true cancellation
* status.</p>
* <p>By default, bulk events will set the result to DENY if the number of
* affected objects drops to zero. This method returns the true result.</p>
*
* @return true if really cancelled
* @return the explicit result
*/
boolean isExplicitlyCancelled();
Result getExplicitResult();
}
@@ -34,13 +34,13 @@ import static com.google.common.base.Preconditions.checkNotNull;
* This event is an internal event. We do not recommend handling or throwing
* this event or its subclasses as the interface is highly subject to change.
*/
public abstract class DelegateEvent extends Event implements Cancellable {
public abstract class DelegateEvent extends Event implements Cancellable, Handleable {
@Nullable
private final Event originalEvent;
private final Cause cause;
private final List<StateFlag> relevantFlags = Lists.newArrayList();
private boolean cancelled;
private Result result = Result.DEFAULT;
private boolean silent;
/**
@@ -85,12 +85,24 @@ public abstract class DelegateEvent extends Event implements Cancellable {
@Override
public boolean isCancelled() {
return cancelled;
return getResult() == Result.DENY;
}
@Override
public void setCancelled(boolean cancel) {
this.cancelled = cancel;
if (cancel) {
setResult(Result.DENY);
}
}
@Override
public Result getResult() {
return result;
}
@Override
public void setResult(Result result) {
this.result = result;
}
/**
@@ -106,9 +118,25 @@ public abstract class DelegateEvent extends Event implements Cancellable {
* Set whether this should be a silent check.
*
* @param silent true if silent
* @return the same event
*/
void setSilent(boolean silent) {
public DelegateEvent setSilent(boolean silent) {
this.silent = silent;
return this;
}
/**
* Set the event to {@link Result#ALLOW} if {@code allowed} is true.
*
* @param allowed true to set the result
* @return the same event
*/
public DelegateEvent setAllowed(boolean allowed) {
if (allowed) {
setResult(Result.ALLOW);
}
return this;
}
}
@@ -19,6 +19,8 @@
package com.sk89q.worldguard.bukkit.event;
import org.bukkit.event.Event.Result;
/**
* Utility methods for dealing with delegate events.
*/
@@ -52,4 +54,19 @@ public final class DelegateEvents {
return event;
}
/**
* Set an event as handled as {@link Result#ALLOW} if {@code allowed} is
* true, otherwise do nothing.
*
* @param event the event
* @param <T> the type of event
* @return the same event
*/
public static <T extends Handleable> T setAllowed(T event, boolean allowed) {
if (allowed) {
event.setResult(Result.ALLOW);
}
return event;
}
}
@@ -0,0 +1,30 @@
/*
* 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.bukkit.event;
import org.bukkit.event.Event.Result;
public interface Handleable {
Result getResult();
void setResult(Result result);
}
@@ -70,16 +70,6 @@ abstract class AbstractBlockEvent extends DelegateEvent implements BulkEvent {
return blocks;
}
@Override
public boolean isCancelled() {
return super.isCancelled() || blocks.isEmpty();
}
@Override
public boolean isExplicitlyCancelled() {
return super.isCancelled();
}
/**
* Get the world.
*
@@ -153,4 +143,18 @@ abstract class AbstractBlockEvent extends DelegateEvent implements BulkEvent {
public Material getEffectiveMaterial() {
return effectiveMaterial;
}
@Override
public Result getResult() {
if (blocks.isEmpty()) {
return Result.DENY;
}
return super.getResult();
}
@Override
public Result getExplicitResult() {
return super.getResult();
}
}
@@ -1,88 +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/>.
*/
package com.sk89q.worldguard.bukkit.internal;
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
import com.sk89q.worldguard.bukkit.listener.FlagStateManager;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.entity.Player;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldguard.protection.ApplicableRegionSet;
import com.sk89q.worldguard.protection.flags.DefaultFlag;
import com.sk89q.worldguard.protection.flags.StateFlag;
import com.sk89q.worldguard.protection.managers.RegionManager;
public final class RegionQueryUtil {
private RegionQueryUtil() {
}
public static boolean isInvincible(WorldGuardPlugin plugin, Player player) {
return isInvincible(plugin, player, null);
}
public static boolean isInvincible(WorldGuardPlugin plugin, Player player,
ApplicableRegionSet set) {
Location loc = player.getLocation();
World world = player.getWorld();
FlagStateManager.PlayerFlagState state = plugin.getFlagStateManager().getState(player);
if (state.lastInvincibleWorld == null ||
!state.lastInvincibleWorld.equals(world) ||
state.lastInvincibleX != loc.getBlockX() ||
state.lastInvincibleY != loc.getBlockY() ||
state.lastInvincibleZ != loc.getBlockZ()) {
state.lastInvincibleX = loc.getBlockX();
state.lastInvincibleY = loc.getBlockY();
state.lastInvincibleZ = loc.getBlockZ();
state.lastInvincibleWorld = world;
if (set == null) {
Vector vec = new Vector(state.lastInvincibleX,
state.lastInvincibleY, state.lastInvincibleZ);
RegionManager mgr = plugin.getGlobalRegionManager().get(world);
set = mgr.getApplicableRegions(vec);
}
state.wasInvincible = set.allows(DefaultFlag.INVINCIBILITY, plugin.wrapPlayer(player));
}
return state.wasInvincible;
}
public static Boolean isAllowedInvinciblity(WorldGuardPlugin plugin, Player player) {
World world = player.getWorld();
FlagStateManager.PlayerFlagState state = plugin.getFlagStateManager().getState(player);
Vector vec = new Vector(state.lastInvincibleX, state.lastInvincibleY, state.lastInvincibleZ);
StateFlag.State regionState = plugin.getGlobalRegionManager().get(world).
getApplicableRegions(vec).getFlag(DefaultFlag.INVINCIBILITY, plugin.wrapPlayer(player));
if (regionState == StateFlag.State.ALLOW) {
return Boolean.TRUE;
} else if (regionState == StateFlag.State.DENY) {
return Boolean.FALSE;
} else {
return null;
}
}
}
@@ -70,4 +70,9 @@ public class TargetMatcherSet {
return test(new MaterialTarget(itemStack.getTypeId(), itemStack.getDurability()));
}
@Override
public String toString() {
return entries.toString();
}
}
@@ -21,14 +21,7 @@ package com.sk89q.worldguard.bukkit.listener;
import com.google.common.base.Predicate;
import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.blacklist.event.BlockBreakBlacklistEvent;
import com.sk89q.worldguard.blacklist.event.BlockDispenseBlacklistEvent;
import com.sk89q.worldguard.blacklist.event.BlockInteractBlacklistEvent;
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.ItemUseBlacklistEvent;
import com.sk89q.worldguard.blacklist.event.*;
import com.sk89q.worldguard.bukkit.ConfigurationManager;
import com.sk89q.worldguard.bukkit.WorldConfiguration;
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
@@ -42,11 +35,16 @@ import com.sk89q.worldguard.bukkit.util.Materials;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.entity.Entity;
import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Item;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.block.BlockDispenseEvent;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryCreativeEvent;
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;
@@ -259,4 +257,64 @@ public class BlacklistListener extends AbstractListener {
}
}
@EventHandler(ignoreCancelled = true)
public void onInventoryClick(InventoryClickEvent event) {
HumanEntity entity = event.getWhoClicked();
Inventory inventory = event.getInventory();
ItemStack item = event.getCurrentItem();
if (item != null && entity instanceof Player) {
Player player = (Player) entity;
ConfigurationManager cfg = getPlugin().getGlobalStateManager();
WorldConfiguration wcfg = cfg.get(entity.getWorld());
LocalPlayer localPlayer = getPlugin().wrapPlayer(player);
if (wcfg.getBlacklist() != null && !wcfg.getBlacklist().check(
new ItemAcquireBlacklistEvent(localPlayer, toVector(entity.getLocation()), createTarget(item)), false, false)) {
event.setCancelled(true);
if (inventory.getHolder().equals(player)) {
event.setCurrentItem(null);
}
}
}
}
@EventHandler(ignoreCancelled = true)
public void onInventoryCreative(InventoryCreativeEvent event) {
HumanEntity entity = event.getWhoClicked();
ItemStack item = event.getCursor();
if (item != null && entity instanceof Player) {
Player player = (Player) entity;
ConfigurationManager cfg = getPlugin().getGlobalStateManager();
WorldConfiguration wcfg = cfg.get(entity.getWorld());
LocalPlayer localPlayer = getPlugin().wrapPlayer(player);
if (wcfg.getBlacklist() != null && !wcfg.getBlacklist().check(
new ItemAcquireBlacklistEvent(localPlayer, toVector(entity.getLocation()), createTarget(item)), false, false)) {
event.setCancelled(true);
event.setCursor(null);
}
}
}
@EventHandler(ignoreCancelled = true)
public void onPlayerItemHeld(PlayerItemHeldEvent event) {
Player player = event.getPlayer();
Inventory inventory = player.getInventory();
ItemStack item = inventory.getItem(event.getNewSlot());
if (item != null) {
ConfigurationManager cfg = getPlugin().getGlobalStateManager();
WorldConfiguration wcfg = cfg.get(player.getWorld());
LocalPlayer localPlayer = getPlugin().wrapPlayer(player);
if (wcfg.getBlacklist() != null && !wcfg.getBlacklist().check(
new ItemAcquireBlacklistEvent(localPlayer, toVector(player.getLocation()), createTarget(item)), false, false)) {
inventory.setItem(event.getNewSlot(), null);
}
}
}
}
@@ -193,8 +193,12 @@ public class BuildPermissionListener extends AbstractListener {
Player player = (Player) rootCause;
Material material = event.getItemStack().getType();
if (material.isBlock()) {
return;
}
if (!hasBuildPermission(player, "item." + material.name().toLowerCase() + ".use")
|| hasBuildPermission(player, "item.use." + material.name().toLowerCase())) {
&& !hasBuildPermission(player, "item.use." + material.name().toLowerCase())) {
tellErrorMessage(player, event.getWorld());
event.setCancelled(true);
}
@@ -30,6 +30,7 @@ import com.sk89q.worldguard.bukkit.event.inventory.UseItemEvent;
import org.bukkit.Location;
import org.bukkit.block.Block;
import org.bukkit.event.Event;
import org.bukkit.event.Event.Result;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
@@ -67,8 +68,8 @@ public class DebuggingListener extends AbstractListener {
builder.append("[").append(event.getCause()).append("]");
builder.append(" ");
builder.append(":").append(getEventName(event.getOriginalEvent()));
if (event.isCancelled()) {
builder.append(" [CANCELLED]");
if (event.getResult() != Result.DEFAULT) {
builder.append(" [").append(event.getResult()).append("]");
}
logger.info(builder.toString());
}
@@ -85,8 +86,8 @@ public class DebuggingListener extends AbstractListener {
builder.append("@").append(toBlockString(event.getBlocks()));
builder.append(" ");
builder.append(":").append(getEventName(event.getOriginalEvent()));
if (event.isCancelled()) {
builder.append(" [CANCELLED]");
if (event.getResult() != Result.DEFAULT) {
builder.append(" [").append(event.getResult()).append("]");
}
logger.info(builder.toString());
}
@@ -103,8 +104,8 @@ public class DebuggingListener extends AbstractListener {
builder.append("@").append(toBlockString(event.getBlocks()));
builder.append(" ");
builder.append(":").append(getEventName(event.getOriginalEvent()));
if (event.isCancelled()) {
builder.append(" [CANCELLED]");
if (event.getResult() != Result.DEFAULT) {
builder.append(" [").append(event.getResult()).append("]");
}
logger.info(builder.toString());
}
@@ -121,8 +122,8 @@ public class DebuggingListener extends AbstractListener {
builder.append("@").append(toBlockString(event.getTarget()));
builder.append(" ");
builder.append(":").append(getEventName(event.getOriginalEvent()));
if (event.isCancelled()) {
builder.append(" [CANCELLED]");
if (event.getResult() != Result.DEFAULT) {
builder.append(" [").append(event.getResult()).append("]");
}
logger.info(builder.toString());
}
@@ -139,8 +140,8 @@ public class DebuggingListener extends AbstractListener {
builder.append("@").append(toBlockString(event.getTarget()));
builder.append(" ");
builder.append(":").append(getEventName(event.getOriginalEvent()));
if (event.isCancelled()) {
builder.append(" [CANCELLED]");
if (event.getResult() != Result.DEFAULT) {
builder.append(" [").append(event.getResult()).append("]");
}
logger.info(builder.toString());
}
@@ -157,8 +158,8 @@ public class DebuggingListener extends AbstractListener {
builder.append("@").append(toBlockString(event.getTarget()));
builder.append(" ");
builder.append(":").append(getEventName(event.getOriginalEvent()));
if (event.isCancelled()) {
builder.append(" [CANCELLED]");
if (event.getResult() != Result.DEFAULT) {
builder.append(" [").append(event.getResult()).append("]");
}
logger.info(builder.toString());
}
@@ -175,8 +176,8 @@ public class DebuggingListener extends AbstractListener {
builder.append("@").append(event.getWorld().getName());
builder.append(" ");
builder.append(":").append(getEventName(event.getOriginalEvent()));
if (event.isCancelled()) {
builder.append(" [CANCELLED]");
if (event.getResult() != Result.DEFAULT) {
builder.append(" [").append(event.getResult()).append("]");
}
logger.info(builder.toString());
}
@@ -24,7 +24,6 @@ import com.sk89q.worldguard.bukkit.WorldConfiguration;
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
import com.sk89q.worldguard.bukkit.cause.Cause;
import com.sk89q.worldguard.bukkit.event.DelegateEvent;
import com.sk89q.worldguard.bukkit.event.DelegateEvents;
import com.sk89q.worldguard.bukkit.event.block.BreakBlockEvent;
import com.sk89q.worldguard.bukkit.event.block.PlaceBlockEvent;
import com.sk89q.worldguard.bukkit.event.block.UseBlockEvent;
@@ -51,21 +50,22 @@ import org.bukkit.event.Cancellable;
import org.bukkit.event.Event;
import org.bukkit.event.Event.Result;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.*;
import org.bukkit.event.entity.*;
import org.bukkit.event.hanging.HangingBreakByEntityEvent;
import org.bukkit.event.hanging.HangingBreakEvent;
import org.bukkit.event.hanging.HangingPlaceEvent;
import org.bukkit.event.inventory.InventoryMoveItemEvent;
import org.bukkit.event.inventory.InventoryOpenEvent;
import org.bukkit.event.player.*;
import org.bukkit.event.vehicle.VehicleDamageEvent;
import org.bukkit.event.vehicle.VehicleDestroyEvent;
import org.bukkit.event.world.StructureGrowEvent;
import org.bukkit.inventory.InventoryHolder;
import org.bukkit.inventory.ItemStack;
import org.bukkit.material.*;
import org.bukkit.material.Dispenser;
import org.bukkit.material.MaterialData;
import org.bukkit.material.SpawnEgg;
import org.bukkit.projectiles.ProjectileSource;
import org.bukkit.util.Vector;
@@ -93,6 +93,16 @@ public class EventAbstractionListener extends AbstractListener {
super(plugin);
}
@Override
public void registerEvents() {
super.registerEvents();
try {
getPlugin().getServer().getPluginManager().registerEvents(new SpigotCompatListener(), getPlugin());
} catch (LinkageError ignored) {
}
}
//-------------------------------------------------------------------------
// Block break / place
//-------------------------------------------------------------------------
@@ -232,18 +242,28 @@ public class EventAbstractionListener extends AbstractListener {
Events.fireBulkEventToCancel(event, new BreakBlockEvent(event, create(entity), event.getLocation().getWorld(), event.blockList(), Material.AIR));
}
@SuppressWarnings("deprecation")
@EventHandler(ignoreCancelled = true)
public void onBlockPistonRetract(BlockPistonRetractEvent event) {
if (event.isSticky()) {
EventDebounce.Entry entry = pistonRetractDebounce.getIfNotPresent(new BlockPistonRetractKey(event), event);
if (entry != null) {
Cause cause = create(event.getBlock());
Events.fireToCancel(event, new BreakBlockEvent(event, cause, event.getRetractLocation(), Material.AIR));
Events.fireToCancel(event, new PlaceBlockEvent(event, cause, event.getBlock().getRelative(event.getDirection())));
Block piston = event.getBlock();
Cause cause = create(piston);
// Workaround for incorrect piston events
BlockFace direction = event.getDirection();
if (piston.getType() == Material.PISTON_MOVING_PIECE) {
direction = new PistonExtensionMaterial(Material.PISTON_STICKY_BASE.getId(), piston.getData()).getFacing();
}
Location retractLocation = piston.getRelative(direction, 2).getLocation();
Events.fireToCancel(event, new BreakBlockEvent(event, cause, retractLocation, Material.AIR));
Events.fireToCancel(event, new PlaceBlockEvent(event, cause, piston.getRelative(direction)));
entry.setCancelled(event.isCancelled());
if (event.isCancelled()) {
playDenyEffect(event.getBlock().getLocation().add(0.5, 1, 0.5));
playDenyEffect(piston.getLocation().add(0.5, 1, 0.5));
}
}
}
@@ -292,6 +312,7 @@ public class EventAbstractionListener extends AbstractListener {
Block clicked = event.getClickedBlock();
Block placed;
boolean silent = false;
boolean modifiesWorld;
Cause cause = create(player);
switch (event.getAction()) {
@@ -301,9 +322,8 @@ public class EventAbstractionListener extends AbstractListener {
silent = true;
}
if (!hasInteractBypass(clicked)) {
interactDebounce.debounce(clicked, event.getPlayer(), event, DelegateEvents.setSilent(new UseBlockEvent(event, cause, clicked), silent));
}
interactDebounce.debounce(clicked, event.getPlayer(), event,
new UseBlockEvent(event, cause, clicked).setSilent(silent).setAllowed(hasInteractBypass(clicked)));
break;
case RIGHT_CLICK_BLOCK:
@@ -316,17 +336,17 @@ public class EventAbstractionListener extends AbstractListener {
placed = clicked.getRelative(event.getBlockFace());
// Only fire events for blocks that are modified when right clicked
if (isBlockModifiedOnClick(clicked) || (item != null && isItemAppliedToBlock(item, clicked))) {
if (Events.fireAndTestCancel(new UseBlockEvent(event, cause, clicked))) {
event.setUseInteractedBlock(Result.DENY);
}
modifiesWorld = isBlockModifiedOnClick(clicked, event.getAction() == Action.RIGHT_CLICK_BLOCK) || (item != null && isItemAppliedToBlock(item, clicked));
// Handle connected blocks (i.e. beds, chests)
for (Block connected : Blocks.getConnected(clicked)) {
if (Events.fireAndTestCancel(new UseBlockEvent(event, create(event.getPlayer()), connected))) {
event.setUseInteractedBlock(Result.DENY);
break;
}
if (Events.fireAndTestCancel(new UseBlockEvent(event, cause, clicked).setAllowed(!modifiesWorld))) {
event.setUseInteractedBlock(Result.DENY);
}
// Handle connected blocks (i.e. beds, chests)
for (Block connected : Blocks.getConnected(clicked)) {
if (Events.fireAndTestCancel(new UseBlockEvent(event, create(event.getPlayer()), connected).setAllowed(!modifiesWorld))) {
event.setUseInteractedBlock(Result.DENY);
break;
}
}
@@ -365,9 +385,8 @@ public class EventAbstractionListener extends AbstractListener {
@EventHandler(ignoreCancelled = true)
public void onEntityInteract(org.bukkit.event.entity.EntityInteractEvent event) {
if (!hasInteractBypass(event.getBlock())) {
interactDebounce.debounce(event.getBlock(), event.getEntity(), event, new UseBlockEvent(event, create(event.getEntity()), event.getBlock()));
}
interactDebounce.debounce(event.getBlock(), event.getEntity(), event,
new UseBlockEvent(event, create(event.getEntity()), event.getBlock()).setAllowed(hasInteractBypass(event.getBlock())));
}
@EventHandler(ignoreCancelled = true)
@@ -408,31 +427,41 @@ public class EventAbstractionListener extends AbstractListener {
public void onPlayerBucketEmpty(PlayerBucketEmptyEvent event) {
Player player = event.getPlayer();
Block blockAffected = event.getBlockClicked().getRelative(event.getBlockFace());
boolean allowed = false;
// Milk buckets can't be emptied as of writing
if (event.getBucket() != Material.MILK_BUCKET) {
ItemStack item = new ItemStack(event.getBucket(), 1);
Material blockMaterial = Materials.getBucketBlockMaterial(event.getBucket());
Events.fireToCancel(event, new PlaceBlockEvent(event, create(player), blockAffected.getLocation(), blockMaterial));
Events.fireToCancel(event, new UseItemEvent(event, create(player), player.getWorld(), item));
if (event.getBucket() == Material.MILK_BUCKET) {
allowed = true;
}
playDenyEffect(event.getPlayer(), blockAffected.getLocation().add(0.5, 0.5, 0.5));
ItemStack item = new ItemStack(event.getBucket(), 1);
Material blockMaterial = Materials.getBucketBlockMaterial(event.getBucket());
Events.fireToCancel(event, new PlaceBlockEvent(event, create(player), blockAffected.getLocation(), blockMaterial).setAllowed(allowed));
Events.fireToCancel(event, new UseItemEvent(event, create(player), player.getWorld(), item).setAllowed(allowed));
if (event.isCancelled()) {
playDenyEffect(event.getPlayer(), blockAffected.getLocation().add(0.5, 0.5, 0.5));
}
}
@EventHandler(ignoreCancelled = true)
public void onPlayerBucketFill(PlayerBucketFillEvent event) {
Player player = event.getPlayer();
Block blockAffected = event.getBlockClicked().getRelative(event.getBlockFace());
boolean allowed = false;
// Milk buckets can't be filled by right clicking the ground as of writing
if (event.getBucket() != Material.MILK_BUCKET) {
ItemStack item = new ItemStack(event.getBucket(), 1);
Events.fireToCancel(event, new BreakBlockEvent(event, create(player), blockAffected));
Events.fireToCancel(event, new UseItemEvent(event, create(player), player.getWorld(), item));
// Milk buckets can't be emptied as of writing
if (event.getBucket() == Material.MILK_BUCKET) {
allowed = true;
}
playDenyEffect(event.getPlayer(), blockAffected.getLocation().add(0.5, 1, 0.5));
ItemStack item = new ItemStack(event.getBucket(), 1);
Events.fireToCancel(event, new BreakBlockEvent(event, create(player), blockAffected).setAllowed(allowed));
Events.fireToCancel(event, new UseItemEvent(event, create(player), player.getWorld(), item).setAllowed(allowed));
if (event.isCancelled()) {
playDenyEffect(event.getPlayer(), blockAffected.getLocation().add(0.5, 0.5, 0.5));
}
}
// TODO: Handle EntityPortalEnterEvent
@@ -536,8 +565,6 @@ public class EventAbstractionListener extends AbstractListener {
if (event.isCancelled() && remover instanceof Player) {
playDenyEffect((Player) remover, event.getEntity().getLocation());
}
} else {
Events.fireToCancel(event, new DestroyEntityEvent(event, Cause.unknown(), event.getEntity()));
}
}
@@ -605,7 +632,13 @@ public class EventAbstractionListener extends AbstractListener {
@EventHandler(ignoreCancelled = true)
public void onEntityDamage(EntityDamageEvent event) {
if (event instanceof EntityDamageByBlockEvent) {
Events.fireToCancel(event, new DamageEntityEvent(event, create(((EntityDamageByBlockEvent) event).getDamager()), event.getEntity()));
@Nullable Block attacker = ((EntityDamageByBlockEvent) event).getDamager();
// The attacker should NOT be null, but sometimes it is
// See WORLDGUARD-3350
if (attacker != null) {
Events.fireToCancel(event, new DamageEntityEvent(event, create(attacker), event.getEntity()));
}
} else if (event instanceof EntityDamageByEntityEvent) {
EntityDamageByEntityEvent entityEvent = (EntityDamageByEntityEvent) event;
@@ -622,9 +655,6 @@ public class EventAbstractionListener extends AbstractListener {
Events.fireToCancel(event, new UseItemEvent(event, create(damager), event.getEntity().getWorld(), item));
}
}
} else {
Events.fireToCancel(event, new DamageEntityEvent(event, Cause.unknown(), event.getEntity()));
}
}
@@ -635,9 +665,6 @@ public class EventAbstractionListener extends AbstractListener {
} else if (event instanceof EntityCombustByEntityEvent) {
Events.fireToCancel(event, new DamageEntityEvent(event, create(((EntityCombustByEntityEvent) event).getCombuster()), event.getEntity()));
} else {
Events.fireToCancel(event, new DamageEntityEvent(event, Cause.unknown(), event.getEntity()));
}
}
@@ -675,7 +702,7 @@ public class EventAbstractionListener extends AbstractListener {
@EventHandler(ignoreCancelled = true)
public void onVehicleDamage(VehicleDamageEvent event) {
Entity attacker = event.getAttacker();
Events.fireToCancel(event, new DestroyEntityEvent(event, create(attacker), event.getVehicle()));
Events.fireToCancel(event, new DamageEntityEvent(event, create(attacker), event.getVehicle()));
}
@EventHandler(ignoreCancelled = true)
@@ -692,6 +719,18 @@ public class EventAbstractionListener extends AbstractListener {
Events.fireToCancel(event, new UseItemEvent(event, create(event.getPlayer()), event.getPlayer().getWorld(), event.getItem()));
}
@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));
}
}
}
@EventHandler(ignoreCancelled = true)
public void onInventoryMoveItem(InventoryMoveItemEvent event) {
final InventoryHolder causeHolder = event.getInitiator().getHolder();
@@ -813,6 +852,11 @@ public class EventAbstractionListener extends AbstractListener {
Events.fireToCancel(event, new SpawnEntityEvent(event, cause, placed.getLocation().add(0.5, 0, 0.5), EntityType.BOAT));
}
// Handle created armor stands
if (item != null && item.getType() == Materials.ARMOR_STAND) {
Events.fireToCancel(event, new SpawnEntityEvent(event, cause, placed.getLocation().add(0.5, 0, 0.5), EntityType.ARMOR_STAND));
}
// Handle created spawn eggs
if (item != null && item.getType() == Material.MONSTER_EGG) {
MaterialData data = item.getData();
@@ -863,8 +907,8 @@ public class EventAbstractionListener extends AbstractListener {
return getWorldConfig(world).allowAllInteract.test(item);
}
private boolean isBlockModifiedOnClick(Block block) {
return Materials.isBlockModifiedOnClick(block.getType()) && !hasInteractBypass(block);
private boolean isBlockModifiedOnClick(Block block, boolean rightClick) {
return Materials.isBlockModifiedOnClick(block.getType(), rightClick) && !hasInteractBypass(block);
}
private boolean isItemAppliedToBlock(ItemStack item, Block clicked) {
@@ -882,4 +926,17 @@ public class EventAbstractionListener extends AbstractListener {
location.getWorld().playEffect(location, Effect.SMOKE, BlockFace.UP);
}
public class SpigotCompatListener implements Listener {
@EventHandler(ignoreCancelled = true)
public void onPlayerInteractAtEntity(PlayerInteractAtEntityEvent event){
onPlayerInteractEntity(event);
}
@EventHandler(ignoreCancelled = true)
public void onBlockExplode(BlockExplodeEvent event) {
Events.fireBulkEventToCancel(event, new BreakBlockEvent(event, create(event.getBlock()),
event.getBlock().getLocation().getWorld(), event.blockList(), Material.AIR));
}
}
}
@@ -1,251 +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/>.
*/
package com.sk89q.worldguard.bukkit.listener;
import com.sk89q.worldguard.bukkit.ConfigurationManager;
import com.sk89q.worldguard.bukkit.WorldConfiguration;
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
import com.sk89q.worldguard.bukkit.internal.RegionQueryUtil;
import com.sk89q.worldguard.protection.ApplicableRegionSet;
import com.sk89q.worldguard.protection.flags.DefaultFlag;
import org.bukkit.GameMode;
import org.bukkit.World;
import org.bukkit.entity.Player;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
/**
* This processes per-player state information and is also meant to be used
* as a scheduled task.
*
* @author sk89q
*/
public class FlagStateManager implements Runnable {
public static final int RUN_DELAY = 20;
private WorldGuardPlugin plugin;
private Map<String, PlayerFlagState> states;
/**
* Construct the object.
*
* @param plugin The plugin instance
*/
public FlagStateManager(WorldGuardPlugin plugin) {
this.plugin = plugin;
states = new HashMap<String, PlayerFlagState>();
}
/**
* Run the task.
*/
@Override
public void run() {
Collection<? extends Player> players = plugin.getServer().getOnlinePlayers();
ConfigurationManager config = plugin.getGlobalStateManager();
for (Player player : players) {
WorldConfiguration worldConfig = config.get(player.getWorld());
if (!worldConfig.useRegions) {
continue;
}
PlayerFlagState state;
synchronized (this) {
state = states.get(player.getName());
if (state == null) {
state = new PlayerFlagState();
states.put(player.getName(), state);
}
}
ApplicableRegionSet applicable = plugin.getRegionContainer().createQuery().getApplicableRegions(player.getLocation());
if (!RegionQueryUtil.isInvincible(plugin, player, applicable)
&& !plugin.getGlobalStateManager().hasGodMode(player)
&& !(player.getGameMode() == GameMode.CREATIVE)) {
processHeal(applicable, player, state);
processFeed(applicable, player, state);
}
}
}
/**
* Process healing for a player.
*
* @param applicable The set of applicable regions
* @param player The player to process healing flags on
* @param state The player's state
*/
private void processHeal(ApplicableRegionSet applicable, Player player,
PlayerFlagState state) {
if (player.getHealth() <= 0) {
return;
}
long now = System.currentTimeMillis();
Integer healAmount = applicable.getFlag(DefaultFlag.HEAL_AMOUNT);
Integer healDelay = applicable.getFlag(DefaultFlag.HEAL_DELAY);
Double minHealth = applicable.getFlag(DefaultFlag.MIN_HEAL);
Double maxHealth = applicable.getFlag(DefaultFlag.MAX_HEAL);
if (healAmount == null || healDelay == null || healAmount == 0 || healDelay < 0) {
return;
}
if (minHealth == null) {
minHealth = 0.0;
}
if (maxHealth == null) {
maxHealth = player.getMaxHealth();
}
// Apply a cap to prevent possible exceptions
minHealth = Math.min(player.getMaxHealth(), minHealth);
maxHealth = Math.min(player.getMaxHealth(), maxHealth);
if (player.getHealth() >= maxHealth && healAmount > 0) {
return;
}
if (healDelay <= 0) {
player.setHealth(healAmount > 0 ? maxHealth : minHealth); // this will insta-kill if the flag is unset
state.lastHeal = now;
} else if (now - state.lastHeal > healDelay * 1000) {
// clamp health between minimum and maximum
player.setHealth(Math.min(maxHealth, Math.max(minHealth, player.getHealth() + healAmount)));
state.lastHeal = now;
}
}
/**
* Process restoring hunger for a player.
*
* @param applicable The set of applicable regions
* @param player The player to process hunger flags on
* @param state The player's state
*/
private void processFeed(ApplicableRegionSet applicable, Player player,
PlayerFlagState state) {
long now = System.currentTimeMillis();
Integer feedAmount = applicable.getFlag(DefaultFlag.FEED_AMOUNT);
Integer feedDelay = applicable.getFlag(DefaultFlag.FEED_DELAY);
Integer minHunger = applicable.getFlag(DefaultFlag.MIN_FOOD);
Integer maxHunger = applicable.getFlag(DefaultFlag.MAX_FOOD);
if (feedAmount == null || feedDelay == null || feedAmount == 0 || feedDelay < 0) {
return;
}
if (minHunger == null) {
minHunger = 0;
}
if (maxHunger == null) {
maxHunger = 20;
}
// Apply a cap to prevent possible exceptions
minHunger = Math.min(20, minHunger);
maxHunger = Math.min(20, maxHunger);
if (player.getFoodLevel() >= maxHunger && feedAmount > 0) {
return;
}
if (feedDelay <= 0) {
player.setFoodLevel(feedAmount > 0 ? maxHunger : minHunger);
player.setSaturation(player.getFoodLevel());
state.lastFeed = now;
} else if (now - state.lastFeed > feedDelay * 1000) {
// clamp health between minimum and maximum
player.setFoodLevel(Math.min(maxHunger, Math.max(minHunger, player.getFoodLevel() + feedAmount)));
player.setSaturation(player.getFoodLevel());
state.lastFeed = now;
}
}
/**
* Forget a player.
*
* @param player The player to forget
*/
public synchronized void forget(Player player) {
states.remove(player.getName());
}
/**
* Forget all managed players. Use with caution.
*/
public synchronized void forgetAll() {
states.clear();
}
/**
* Get a player's flag state. A new state will be created if there is no existing
* state for the player.
*
* @param player The player to get a state for
* @return The {@code player}'s state
*/
public synchronized PlayerFlagState getState(Player player) {
PlayerFlagState state = states.get(player.getName());
if (state == null) {
state = new PlayerFlagState();
states.put(player.getName(), state);
}
return state;
}
/**
* Keeps state per player.
*/
public static class PlayerFlagState {
public long lastHeal;
public long lastFeed;
public String lastGreeting;
public String lastFarewell;
public Boolean lastExitAllowed = null;
public Boolean notifiedForLeave = false;
public Boolean notifiedForEnter = false;
public GameMode lastGameMode;
public World lastWorld;
public int lastBlockX;
public int lastBlockY;
public int lastBlockZ;
/* Used to cache invincibility status */
public World lastInvincibleWorld;
public int lastInvincibleX;
public int lastInvincibleY;
public int lastInvincibleZ;
public boolean wasInvincible;
}
}
@@ -0,0 +1,105 @@
/*
* 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.bukkit.listener;
import com.sk89q.worldguard.bukkit.WorldConfiguration;
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.entity.Tameable;
import org.bukkit.event.EventHandler;
import org.bukkit.event.entity.EntityCombustEvent;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.FoodLevelChangeEvent;
public class InvincibilityListener extends AbstractListener {
/**
* Construct the listener.
*
* @param plugin an instance of WorldGuardPlugin
*/
public InvincibilityListener(WorldGuardPlugin plugin) {
super(plugin);
}
/**
* Test whether a player should be invincible.
*
* @param player The player
* @return True if invincible
*/
private boolean isInvincible(Player player) {
return getPlugin().getSessionManager().get(player).isInvincible(player);
}
@EventHandler(ignoreCancelled = true)
public void onEntityDamage(EntityDamageEvent event) {
Entity victim = event.getEntity();
WorldConfiguration worldConfig = getPlugin().getGlobalStateManager().get(victim.getWorld());
if (victim instanceof Player) {
Player player = (Player) victim;
if (isInvincible(player)) {
player.setFireTicks(0);
event.setCancelled(true);
if (event instanceof EntityDamageByEntityEvent) {
EntityDamageByEntityEvent byEntityEvent = (EntityDamageByEntityEvent) event;
Entity attacker = byEntityEvent.getDamager();
if (worldConfig.regionInvinciblityRemovesMobs
&& attacker instanceof LivingEntity && !(attacker instanceof Player)
&& !(attacker instanceof Tameable && ((Tameable) attacker).isTamed())) {
attacker.remove();
}
}
}
}
}
@EventHandler(ignoreCancelled = true)
public void onEntityCombust(EntityCombustEvent event) {
Entity entity = event.getEntity();
if (entity instanceof Player) {
Player player = (Player) entity;
if (isInvincible(player)) {
event.setCancelled(true);
}
}
}
@EventHandler(ignoreCancelled = true)
public void onFoodLevelChange(FoodLevelChangeEvent event) {
if (event.getEntity() instanceof Player) {
Player player = (Player) event.getEntity();
if (event.getFoodLevel() < player.getFoodLevel() && isInvincible(player)) {
event.setCancelled(true);
}
}
}
}
@@ -22,6 +22,9 @@ package com.sk89q.worldguard.bukkit.listener;
import com.sk89q.worldguard.bukkit.ConfigurationManager;
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
import com.sk89q.worldguard.bukkit.event.player.ProcessPlayerEvent;
import com.sk89q.worldguard.session.Session;
import com.sk89q.worldguard.session.handler.GodMode;
import com.sk89q.worldguard.session.handler.WaterBreathing;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
@@ -61,17 +64,18 @@ public class PlayerModesListener extends AbstractListener {
public void onProcessPlayer(ProcessPlayerEvent event) {
ConfigurationManager config = getConfig();
Player player = event.getPlayer();
Session session = getPlugin().getSessionManager().get(player);
if (!config.hasCommandBookGodMode()) {
if (hasGodModeGroup(player) || hasGodModePermission(player)) {
if (hasGodModeGroup(player) || hasGodModePermission(player)) {
if (GodMode.set(player, session, true)) {
log.log(Level.INFO, "Enabled auto-god mode for " + player.getName());
config.enableGodMode(player);
}
}
if (hasAmphibiousGroup(player)) {
log.log(Level.INFO, "Enabled no-drowning mode for " + player.getName() + " (player is in group 'wg-amphibious')");
config.enableAmphibiousMode(player);
if (WaterBreathing.set(player, session, true)) {
log.log(Level.INFO, "Enabled water breathing mode for " + player.getName() + " (player is in group 'wg-amphibious')");
}
}
}
@@ -19,46 +19,26 @@
package com.sk89q.worldguard.bukkit.listener;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.bukkit.BukkitUtil;
import com.sk89q.worldguard.bukkit.ConfigurationManager;
import com.sk89q.worldguard.bukkit.WorldConfiguration;
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
import com.sk89q.worldguard.bukkit.listener.FlagStateManager.PlayerFlagState;
import com.sk89q.guavabackport.cache.CacheBuilder;
import com.sk89q.guavabackport.cache.CacheLoader;
import com.sk89q.guavabackport.cache.LoadingCache;
import com.sk89q.worldguard.protection.ApplicableRegionSet;
import com.sk89q.worldguard.protection.flags.DefaultFlag;
import com.sk89q.worldguard.protection.managers.RegionManager;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import org.bukkit.ChatColor;
import org.bukkit.GameMode;
import com.sk89q.worldguard.session.MoveType;
import com.sk89q.worldguard.session.Session;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.event.player.PlayerRespawnEvent;
import org.bukkit.event.vehicle.VehicleEnterEvent;
import org.bukkit.plugin.PluginManager;
import java.util.concurrent.TimeUnit;
import org.bukkit.util.Vector;
public class PlayerMoveListener implements Listener {
private final WorldGuardPlugin plugin;
private LoadingCache<WorldPlayerTuple, Boolean> bypassCache = CacheBuilder.newBuilder()
.maximumSize(1000)
.expireAfterAccess(5, TimeUnit.SECONDS)
.build(new CacheLoader<WorldPlayerTuple, Boolean>() {
@Override
public Boolean load(WorldPlayerTuple tuple) throws Exception {
return plugin.getGlobalRegionManager().hasBypass(tuple.player, tuple.world);
}
});
public PlayerMoveListener(WorldGuardPlugin plugin) {
this.plugin = plugin;
@@ -71,196 +51,68 @@ public class PlayerMoveListener implements Listener {
}
}
private boolean hasBypass(Player player, World world) {
return bypassCache.getUnchecked(new WorldPlayerTuple(world, player));
@EventHandler
public void onPlayerRespawn(PlayerRespawnEvent event) {
Player player = event.getPlayer();
Session session = plugin.getSessionManager().get(player);
session.testMoveTo(player, event.getRespawnLocation(), MoveType.RESPAWN, true);
}
/**
* Handles movement related events, including changing gamemode, sending
* greeting/farewell messages, etc.
*
* @param from The before location
* @param to The to location
* @return True if the movement should not be allowed
*/
public boolean shouldDenyMove(Player player, Location from, Location to) {
PlayerFlagState state = plugin.getFlagStateManager().getState(player);
// Flush states in multi-world scenario
if (state.lastWorld != null && !state.lastWorld.equals(to.getWorld())) {
plugin.getFlagStateManager().forget(player);
state = plugin.getFlagStateManager().getState(player);
}
// TODO: Clean up this disaster
World world = from.getWorld();
World toWorld = to.getWorld();
LocalPlayer localPlayer = plugin.wrapPlayer(player);
boolean hasBypass = hasBypass(player, world);
boolean hasRemoteBypass;
if (world.equals(toWorld)) {
hasRemoteBypass = hasBypass;
} else {
hasRemoteBypass = hasBypass(player, toWorld);
}
RegionManager regions = plugin.getGlobalRegionManager().get(toWorld);
if (regions == null) {
return false;
}
Vector pt = new Vector(to.getBlockX(), to.getBlockY(), to.getBlockZ());
ApplicableRegionSet set = regions.getApplicableRegions(pt);
boolean entryAllowed = set.allows(DefaultFlag.ENTRY, localPlayer);
if (!hasRemoteBypass && !entryAllowed) {
player.sendMessage(ChatColor.DARK_RED + "You are not permitted to enter this area.");
return true;
}
// Have to set this state
if (state.lastExitAllowed == null) {
state.lastExitAllowed = plugin.getRegionContainer().createQuery().getApplicableRegions(from).allows(DefaultFlag.EXIT, localPlayer);
}
boolean exitAllowed = set.allows(DefaultFlag.EXIT, localPlayer);
if (!hasBypass && exitAllowed && !state.lastExitAllowed) {
player.sendMessage(ChatColor.DARK_RED + "You are not permitted to leave this area.");
return true;
}
String greeting = set.getFlag(DefaultFlag.GREET_MESSAGE);
String farewell = set.getFlag(DefaultFlag.FAREWELL_MESSAGE);
Boolean notifyEnter = set.getFlag(DefaultFlag.NOTIFY_ENTER);
Boolean notifyLeave = set.getFlag(DefaultFlag.NOTIFY_LEAVE);
GameMode gameMode = set.getFlag(DefaultFlag.GAME_MODE);
if (state.lastFarewell != null && (farewell == null || !state.lastFarewell.equals(farewell))) {
String replacedFarewell = plugin.replaceMacros(player, BukkitUtil.replaceColorMacros(state.lastFarewell));
player.sendMessage(replacedFarewell.replaceAll("\\\\n", "\n").split("\\n"));
}
if (greeting != null && (state.lastGreeting == null || !state.lastGreeting.equals(greeting))) {
String replacedGreeting = plugin.replaceMacros(player, BukkitUtil.replaceColorMacros(greeting));
player.sendMessage(replacedGreeting.replaceAll("\\\\n", "\n").split("\\n"));
}
if ((notifyLeave == null || !notifyLeave) && state.notifiedForLeave != null && state.notifiedForLeave) {
plugin.broadcastNotification(ChatColor.GRAY + "WG: "
+ ChatColor.LIGHT_PURPLE + player.getName()
+ ChatColor.GOLD + " left NOTIFY region");
}
if (notifyEnter != null && notifyEnter && (state.notifiedForEnter == null || !state.notifiedForEnter)) {
StringBuilder regionList = new StringBuilder();
for (ProtectedRegion region : set) {
if (regionList.length() != 0) {
regionList.append(", ");
}
regionList.append(region.getId());
}
plugin.broadcastNotification(ChatColor.GRAY + "WG: "
+ ChatColor.LIGHT_PURPLE + player.getName()
+ ChatColor.GOLD + " entered NOTIFY region: "
+ ChatColor.WHITE
+ regionList);
}
if (!hasBypass && gameMode != null) {
if (player.getGameMode() != gameMode) {
state.lastGameMode = player.getGameMode();
player.setGameMode(gameMode);
} else if (state.lastGameMode == null) {
state.lastGameMode = player.getServer().getDefaultGameMode();
}
} else {
if (state.lastGameMode != null) {
GameMode mode = state.lastGameMode;
state.lastGameMode = null;
player.setGameMode(mode);
@EventHandler
public void onVehicleEnter(VehicleEnterEvent event) {
Entity entity = event.getEntered();
if (entity instanceof Player) {
Player player = (Player) entity;
Session session = plugin.getSessionManager().get(player);
if (null != session.testMoveTo(player, event.getVehicle().getLocation(), MoveType.EMBARK, true)) {
event.setCancelled(true);
}
}
state.lastGreeting = greeting;
state.lastFarewell = farewell;
state.notifiedForEnter = notifyEnter;
state.notifiedForLeave = notifyLeave;
state.lastExitAllowed = exitAllowed;
state.lastWorld = to.getWorld();
state.lastBlockX = to.getBlockX();
state.lastBlockY = to.getBlockY();
state.lastBlockZ = to.getBlockZ();
return false;
}
@EventHandler(priority = EventPriority.HIGH)
public void onPlayerMove(PlayerMoveEvent event) {
final Player player = event.getPlayer();
World world = player.getWorld();
ConfigurationManager cfg = plugin.getGlobalStateManager();
WorldConfiguration wcfg = cfg.get(world);
Session session = plugin.getSessionManager().get(player);
final Location override = session.testMoveTo(player, event.getTo(), MoveType.MOVE);
if (wcfg.useRegions) {
if (hasMoved(event.getFrom(), event.getTo())) {
if (shouldDenyMove(player, event.getFrom(), event.getTo())) {
Location newLoc = event.getFrom();
newLoc.setX(newLoc.getBlockX() + 0.5);
newLoc.setY(newLoc.getBlockY());
newLoc.setZ(newLoc.getBlockZ() + 0.5);
event.setTo(newLoc);
if (override != null) {
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());
Entity vehicle = player.getVehicle();
if (vehicle != null) {
vehicle.eject();
vehicle.teleport(newLoc);
player.teleport(newLoc);
vehicle.setPassenger(player);
event.setTo(override.clone());
Entity vehicle = player.getVehicle();
if (vehicle != null) {
vehicle.eject();
Entity current = vehicle;
while (current != null) {
current.eject();
vehicle.setVelocity(new Vector());
if (vehicle instanceof LivingEntity) {
vehicle.teleport(override.clone());
} else {
vehicle.teleport(override.clone().add(0, 1, 0));
}
current = current.getVehicle();
}
player.teleport(override.clone().add(0, 1, 0));
Bukkit.getScheduler().runTaskLater(plugin, new Runnable() {
@Override
public void run() {
player.teleport(override.clone().add(0, 1, 0));
}
}, 1);
}
}
}
private static boolean hasMoved(Location loc1, Location loc2) {
return loc1.getBlockX() != loc2.getBlockX()
|| loc1.getBlockY() != loc2.getBlockY()
|| loc1.getBlockZ() != loc2.getBlockZ();
}
private static class WorldPlayerTuple {
private final World world;
private final Player player;
private WorldPlayerTuple(World world, Player player) {
this.world = world;
this.player = player;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
WorldPlayerTuple that = (WorldPlayerTuple) o;
if (!player.equals(that.player)) return false;
if (!world.equals(that.world)) return false;
return true;
}
@Override
public int hashCode() {
int result = world.hashCode();
result = 31 * result + player.hashCode();
return result;
}
}
}
@@ -30,12 +30,16 @@ import com.sk89q.worldguard.protection.association.RegionAssociable;
import com.sk89q.worldguard.protection.flags.DefaultFlag;
import com.sk89q.worldguard.protection.flags.StateFlag;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.entity.Creeper;
import org.bukkit.entity.EnderDragon;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.EntityDamageEvent.DamageCause;
import javax.annotation.Nullable;
@@ -87,7 +91,7 @@ public class RegionFlagsListener extends AbstractListener {
}
Entity entity;
if ((entity = event.getCause().getFirstEntity()) != null) {
if ((entity = event.getCause().getFirstNonPlayerEntity()) != null) {
// ================================================================
// CREEPER_EXPLOSION flag
// ================================================================
@@ -107,6 +111,21 @@ public class RegionFlagsListener extends AbstractListener {
}
}
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onEntityDamage(EntityDamageEvent event) {
Entity entity = event.getEntity();
World world = entity.getWorld();
if (!isRegionSupportEnabled(world)) return; // Region support disabled
RegionQuery query = getPlugin().getRegionContainer().createQuery();
if (entity instanceof Player && event.getCause() == DamageCause.FALL) {
if (!query.testState(entity.getLocation(), (Player) entity, DefaultFlag.FALL_DAMAGE)) {
event.setCancelled(true);
}
}
}
/**
* Create a new predicate to test a state flag for each location.
*
@@ -38,6 +38,7 @@ import com.sk89q.worldguard.bukkit.protection.DelayedRegionOverlapAssociation;
import com.sk89q.worldguard.bukkit.util.Entities;
import com.sk89q.worldguard.bukkit.util.Events;
import com.sk89q.worldguard.bukkit.util.Materials;
import com.sk89q.worldguard.bukkit.util.InteropUtils;
import com.sk89q.worldguard.domains.Association;
import com.sk89q.worldguard.protection.association.Associables;
import com.sk89q.worldguard.protection.association.RegionAssociable;
@@ -48,6 +49,7 @@ import com.sk89q.worldguard.protection.flags.StateFlag.State;
import org.bukkit.*;
import org.bukkit.block.Block;
import org.bukkit.entity.*;
import org.bukkit.event.Event.Result;
import org.bukkit.event.EventHandler;
import org.bukkit.event.vehicle.VehicleExitEvent;
@@ -81,7 +83,7 @@ public class RegionProtectionListener extends AbstractListener {
* @param what what was done
*/
private void tellErrorMessage(DelegateEvent event, Cause cause, Location location, String what) {
if (event.isSilent()) {
if (event.isSilent() || cause.isIndirect()) {
return;
}
@@ -121,7 +123,7 @@ public class RegionProtectionListener extends AbstractListener {
Player player = (Player) rootCause;
WorldConfiguration config = getWorldConfig(world);
if (config.fakePlayerBuildOverride && Entities.isFakePlayer(player)) {
if (config.fakePlayerBuildOverride && InteropUtils.isFakePlayer(player)) {
return true;
}
@@ -153,6 +155,7 @@ public class RegionProtectionListener extends AbstractListener {
@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
if (!isRegionSupportEnabled(event.getWorld())) return; // Region support disabled
if (isWhitelisted(event.getCause(), event.getWorld(), false)) return; // Whitelisted cause
@@ -196,6 +199,7 @@ public class RegionProtectionListener extends AbstractListener {
@EventHandler(ignoreCancelled = true)
public void onBreakBlock(final BreakBlockEvent event) {
if (event.getResult() == Result.ALLOW) return; // Don't care about events that have been pre-allowed
if (!isRegionSupportEnabled(event.getWorld())) return; // Region support disabled
if (isWhitelisted(event.getCause(), event.getWorld(), false)) return; // Whitelisted cause
@@ -211,9 +215,9 @@ public class RegionProtectionListener extends AbstractListener {
String what;
/* TNT */
if (event.getCause().find(EntityType.PRIMED_TNT, EntityType.PRIMED_TNT) != null) {
if (event.getCause().find(EntityType.PRIMED_TNT, EntityType.MINECART_TNT) != null) {
canBreak = query.testBuild(target, associable, combine(event, DefaultFlag.BLOCK_BREAK, DefaultFlag.TNT));
what = "dynamite blocks";
what = "use dynamite";
/* Everything else */
} else {
@@ -234,6 +238,7 @@ public class RegionProtectionListener extends AbstractListener {
@EventHandler(ignoreCancelled = true)
public void onUseBlock(final UseBlockEvent event) {
if (event.getResult() == Result.ALLOW) return; // Don't care about events that have been pre-allowed
if (!isRegionSupportEnabled(event.getWorld())) return; // Region support disabled
if (isWhitelisted(event.getCause(), event.getWorld(), false)) return; // Whitelisted cause
@@ -290,6 +295,7 @@ public class RegionProtectionListener extends AbstractListener {
@EventHandler(ignoreCancelled = true)
public void onSpawnEntity(SpawnEntityEvent event) {
if (event.getResult() == Result.ALLOW) return; // Don't care about events that have been pre-allowed
if (!isRegionSupportEnabled(event.getWorld())) return; // Region support disabled
if (isWhitelisted(event.getCause(), event.getWorld(), false)) return; // Whitelisted cause
@@ -336,6 +342,7 @@ public class RegionProtectionListener extends AbstractListener {
@EventHandler(ignoreCancelled = true)
public void onDestroyEntity(DestroyEntityEvent event) {
if (event.getResult() == Result.ALLOW) return; // Don't care about events that have been pre-allowed
if (!isRegionSupportEnabled(event.getWorld())) return; // Region support disabled
if (isWhitelisted(event.getCause(), event.getWorld(), false)) return; // Whitelisted cause
@@ -371,6 +378,7 @@ public class RegionProtectionListener extends AbstractListener {
@EventHandler(ignoreCancelled = true)
public void onUseEntity(UseEntityEvent event) {
if (event.getResult() == Result.ALLOW) return; // Don't care about events that have been pre-allowed
if (!isRegionSupportEnabled(event.getWorld())) return; // Region support disabled
if (isWhitelisted(event.getCause(), event.getWorld(), false)) return; // Whitelisted cause
@@ -382,8 +390,9 @@ public class RegionProtectionListener extends AbstractListener {
String what;
/* Hostile / ambient mob override */
if (Entities.isHostile(event.getEntity()) || Entities.isAmbient(event.getEntity()) || Entities.isNPC(event.getEntity())) {
canUse = event.getRelevantFlags().isEmpty() || query.testState(target, associable, combine(event));
if (Entities.isHostile(event.getEntity()) || Entities.isAmbient(event.getEntity())
|| Entities.isNPC(event.getEntity()) || Entities.isVehicle(event.getEntity().getType())) {
canUse = event.getRelevantFlags().isEmpty() || query.queryState(target, associable, combine(event)) != State.DENY;
what = "use that";
/* Paintings, item frames, etc. */
@@ -410,6 +419,7 @@ public class RegionProtectionListener extends AbstractListener {
@EventHandler(ignoreCancelled = true)
public void onDamageEntity(DamageEntityEvent event) {
if (event.getResult() == Result.ALLOW) return; // Don't care about events that have been pre-allowed
if (!isRegionSupportEnabled(event.getWorld())) return; // Region support disabled
// Whitelist check is below
@@ -430,8 +440,9 @@ public class RegionProtectionListener extends AbstractListener {
}
/* Hostile / ambient mob override */
if (Entities.isHostile(event.getEntity()) || Entities.isAmbient(event.getEntity())) {
canDamage = event.getRelevantFlags().isEmpty() || query.testState(target, associable, combine(event));
if (Entities.isHostile(event.getEntity()) || Entities.isAmbient(event.getEntity())
|| Entities.isVehicle(event.getEntity().getType())) {
canDamage = event.getRelevantFlags().isEmpty() || query.queryState(target, associable, combine(event)) != State.DENY;
what = "hit that";
/* Paintings, item frames, etc. */
@@ -444,7 +455,8 @@ public class RegionProtectionListener extends AbstractListener {
Player defender = (Player) event.getEntity();
canDamage = query.testBuild(target, associable, combine(event, DefaultFlag.PVP))
&& query.queryState(playerAttacker.getLocation(), playerAttacker, combine(event, DefaultFlag.PVP)) != State.DENY;
&& query.queryState(playerAttacker.getLocation(), playerAttacker, combine(event, DefaultFlag.PVP)) != State.DENY
&& query.queryState(target, playerAttacker, combine(event, DefaultFlag.PVP)) != State.DENY;
// Fire the disallow PVP event
if (!canDamage && Events.fireAndTestCancel(new DisallowedPVPEvent(playerAttacker, defender, event.getOriginalEvent()))) {
@@ -455,9 +467,14 @@ public class RegionProtectionListener extends AbstractListener {
/* Player damage not caused by another player */
} else if (event.getEntity() instanceof Player) {
canDamage = event.getRelevantFlags().isEmpty() || query.testState(target, associable, combine(event));
canDamage = event.getRelevantFlags().isEmpty() || query.queryState(target, associable, combine(event)) != State.DENY;
what = "damage that";
/* damage to non-hostile mobs (e.g. animals) */
} else if (Entities.isNonHostile(event.getEntity())) {
canDamage = query.testBuild(target, associable, combine(event, DefaultFlag.DAMAGE_ANIMALS));
what = "harm that";
/* Everything else */
} else {
canDamage = query.testBuild(target, associable, combine(event, DefaultFlag.INTERACT));
@@ -380,7 +380,7 @@ public class WorldGuardBlockListener implements Listener {
return;
}
int id = event.getChangedTypeId();
int id = event.getBlock().getTypeId();
if (id == 13 && wcfg.noPhysicsGravel) {
event.setCancelled(true);
@@ -21,59 +21,22 @@ package com.sk89q.worldguard.bukkit.listener;
import com.sk89q.worldedit.blocks.BlockID;
import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.bukkit.BukkitUtil;
import com.sk89q.worldguard.bukkit.ConfigurationManager;
import com.sk89q.worldguard.bukkit.RegionQuery;
import com.sk89q.worldguard.bukkit.WorldConfiguration;
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
import com.sk89q.worldguard.bukkit.internal.RegionQueryUtil;
import com.sk89q.worldguard.bukkit.*;
import com.sk89q.worldguard.bukkit.util.Entities;
import com.sk89q.worldguard.protection.ApplicableRegionSet;
import com.sk89q.worldguard.protection.GlobalRegionManager;
import com.sk89q.worldguard.protection.flags.DefaultFlag;
import com.sk89q.worldguard.protection.managers.RegionManager;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.entity.Creeper;
import org.bukkit.entity.EnderDragon;
import org.bukkit.entity.Enderman;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Fireball;
import org.bukkit.entity.ItemFrame;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.entity.Projectile;
import org.bukkit.entity.TNTPrimed;
import org.bukkit.entity.Tameable;
import org.bukkit.entity.ThrownPotion;
import org.bukkit.entity.Wither;
import org.bukkit.entity.WitherSkull;
import org.bukkit.entity.Wolf;
import org.bukkit.entity.*;
import org.bukkit.entity.minecart.ExplosiveMinecart;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.CreatureSpawnEvent;
import org.bukkit.event.entity.*;
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.EntityCombustEvent;
import org.bukkit.event.entity.EntityCreatePortalEvent;
import org.bukkit.event.entity.EntityDamageByBlockEvent;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.EntityDamageEvent.DamageCause;
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.ExplosionPrimeEvent;
import org.bukkit.event.entity.FoodLevelChangeEvent;
import org.bukkit.event.entity.PigZapEvent;
import org.bukkit.event.entity.PlayerDeathEvent;
import org.bukkit.event.entity.PotionSplashEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.projectiles.ProjectileSource;
@@ -144,11 +107,6 @@ public class WorldGuardEntityListener implements Listener {
} else if (defender instanceof Player) {
Player player = (Player) defender;
if (isInvincible(player)) {
event.setCancelled(true);
return;
}
if (wcfg.disableLavaDamage && type == DamageCause.LAVA) {
event.setCancelled(true);
player.setFireTicks(0);
@@ -216,17 +174,6 @@ public class WorldGuardEntityListener implements Listener {
ConfigurationManager cfg = plugin.getGlobalStateManager();
WorldConfiguration wcfg = cfg.get(player.getWorld());
if (isInvincible(player)) {
if (wcfg.regionInvinciblityRemovesMobs
&& attacker instanceof LivingEntity && !(attacker instanceof Player)
&& !(attacker instanceof Tameable && ((Tameable) attacker).isTamed())) {
attacker.remove();
}
event.setCancelled(true);
return;
}
if (wcfg.disableLightningDamage && event.getCause() == DamageCause.LIGHTNING) {
event.setCancelled(true);
return;
@@ -322,12 +269,6 @@ public class WorldGuardEntityListener implements Listener {
ConfigurationManager cfg = plugin.getGlobalStateManager();
WorldConfiguration wcfg = cfg.get(player.getWorld());
// Check Invincible
if (isInvincible(player)) {
event.setCancelled(true);
return;
}
// Check Mob
if (attacker != null && !(attacker instanceof Player)) {
if (wcfg.disableMobDamage) {
@@ -375,12 +316,6 @@ public class WorldGuardEntityListener implements Listener {
} else if (defender instanceof Player) {
Player player = (Player) defender;
if (isInvincible(player)) {
event.setCancelled(true);
player.setFireTicks(0);
return;
}
if (type == DamageCause.WITHER) {
// wither boss DoT tick
if (wcfg.disableMobDamage) {
@@ -445,23 +380,6 @@ public class WorldGuardEntityListener implements Listener {
}
}
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void onEntityCombust(EntityCombustEvent event) {
Entity entity = event.getEntity();
ConfigurationManager cfg = plugin.getGlobalStateManager();
WorldConfiguration wcfg = cfg.get(entity.getWorld());
if (entity instanceof Player) {
Player player = (Player) entity;
if (cfg.hasGodMode(player) || (wcfg.useRegions && RegionQueryUtil.isInvincible(plugin, player))) {
event.setCancelled(true);
return;
}
}
}
/*
* Called on entity explode.
*/
@@ -635,6 +553,11 @@ public class WorldGuardEntityListener implements Listener {
return;
}
// armor stands are living entities, but we check them as blocks/non-living entities, so ignore them here
if (Entities.isConsideredBuildingIfUsed(event.getEntity())) {
return;
}
if (wcfg.allowTamedSpawns
&& event.getEntity() instanceof Tameable // nullsafe check
&& ((Tameable) event.getEntity()).isTamed()) {
@@ -758,45 +681,6 @@ public class WorldGuardEntityListener implements Listener {
}
}
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void onFoodLevelChange(FoodLevelChangeEvent event) {
if (event.getEntity() instanceof Player) {
Player player = (Player) event.getEntity();
if (event.getFoodLevel() < player.getFoodLevel() && isInvincible(player)) {
event.setCancelled(true);
}
}
}
/**
* Check if a player is invincible, via either god mode or region flag. If
* the region denies invincibility, the player must have an extra permission
* to override it. (worldguard.god.override-regions)
*
* @param player The player to check
* @return Whether {@code player} is invincible
*/
private boolean isInvincible(Player player) {
ConfigurationManager cfg = plugin.getGlobalStateManager();
WorldConfiguration wcfg = cfg.get(player.getWorld());
boolean god = cfg.hasGodMode(player);
if (wcfg.useRegions) {
Boolean flag = RegionQueryUtil.isAllowedInvinciblity(plugin, player);
boolean allowed = flag == null || flag;
boolean invincible = RegionQueryUtil.isInvincible(plugin, player);
if (allowed) {
return god || invincible;
} else {
return (god && plugin.hasPermission(player, "worldguard.god.override-regions"))
|| invincible;
}
} else {
return god;
}
}
/**
* Checks regions and config settings to protect items from being knocked
* out of item frames.
@@ -26,11 +26,13 @@ import com.sk89q.worldguard.bukkit.ConfigurationManager;
import com.sk89q.worldguard.bukkit.WorldConfiguration;
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
import com.sk89q.worldguard.bukkit.event.player.ProcessPlayerEvent;
import com.sk89q.worldguard.bukkit.listener.FlagStateManager.PlayerFlagState;
import com.sk89q.worldguard.bukkit.util.Events;
import com.sk89q.worldguard.protection.ApplicableRegionSet;
import com.sk89q.worldguard.protection.flags.DefaultFlag;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import com.sk89q.worldguard.session.MoveType;
import com.sk89q.worldguard.session.Session;
import com.sk89q.worldguard.session.handler.GameModeFlag;
import com.sk89q.worldguard.util.command.CommandFilter;
import org.bukkit.ChatColor;
import org.bukkit.GameMode;
@@ -83,11 +85,15 @@ public class WorldGuardPlayerListener implements Listener {
public void onPlayerGameModeChange(PlayerGameModeChangeEvent event) {
Player player = event.getPlayer();
WorldConfiguration wcfg = plugin.getGlobalStateManager().get(player.getWorld());
if (wcfg.useRegions && !plugin.getGlobalRegionManager().hasBypass(player, player.getWorld())) {
GameMode gameMode = plugin.getRegionContainer().createQuery().getApplicableRegions(player.getLocation()).getFlag(DefaultFlag.GAME_MODE);
if (plugin.getFlagStateManager().getState(player).lastGameMode != null
&& gameMode != null && event.getNewGameMode() != gameMode) {
event.setCancelled(true);
Session session = plugin.getSessionManager().getIfPresent(player);
if (session != null) {
GameModeFlag handler = session.getHandler(GameModeFlag.class);
if (handler != null && wcfg.useRegions && !plugin.getGlobalRegionManager().hasBypass(player, player.getWorld())) {
GameMode expected = handler.getSetGameMode();
if (handler.getOriginalGameMode() != null && expected != null && expected != event.getNewGameMode()) {
log.info("Game mode change on " + player.getName() + " has been blocked due to the region GAMEMODE flag");
event.setCancelled(true);
}
}
}
}
@@ -126,14 +132,7 @@ public class WorldGuardPlayerListener implements Listener {
Events.fire(new ProcessPlayerEvent(player));
if (wcfg.useRegions) {
PlayerFlagState state = plugin.getFlagStateManager().getState(player);
Location loc = player.getLocation();
state.lastWorld = loc.getWorld();
state.lastBlockX = loc.getBlockX();
state.lastBlockY = loc.getBlockY();
state.lastBlockZ = loc.getBlockZ();
}
plugin.getSessionManager().get(player); // Initializes a session
}
@EventHandler(ignoreCancelled = true)
@@ -186,46 +185,6 @@ public class WorldGuardPlayerListener implements Listener {
}
}
@EventHandler
public void onPlayerQuit(PlayerQuitEvent event) {
Player player = event.getPlayer();
World world = player.getWorld();
ConfigurationManager cfg = plugin.getGlobalStateManager();
WorldConfiguration wcfg = cfg.get(world);
// This is to make the enter/exit flags accurate -- move events are not
// sent constantly, so it is possible to move just a little enough to
// not trigger the event and then rejoin so that you are then considered
// outside the border. This should work around that.
if (wcfg.useRegions) {
boolean hasBypass = plugin.getGlobalRegionManager().hasBypass(player, world);
PlayerFlagState state = plugin.getFlagStateManager().getState(player);
if (state.lastWorld != null && !hasBypass) {
LocalPlayer localPlayer = plugin.wrapPlayer(player);
Location loc = player.getLocation();
ApplicableRegionSet set = plugin.getRegionContainer().createQuery().getApplicableRegions(loc);
if (state.lastExitAllowed == null) {
state.lastExitAllowed = set.allows(DefaultFlag.EXIT, localPlayer);
}
if (!state.lastExitAllowed || !set.allows(DefaultFlag.ENTRY, localPlayer)) {
// Only if we have the last location cached
if (state.lastWorld.equals(world)) {
Location newLoc = new Location(world, state.lastBlockX + 0.5,
state.lastBlockY, state.lastBlockZ + 0.5);
player.teleport(newLoc);
}
}
}
}
cfg.forgetPlayer(plugin.wrapPlayer(player));
plugin.forgetPlayer(player);
}
@EventHandler(priority = EventPriority.HIGH)
public void onPlayerInteract(PlayerInteractEvent event) {
Player player = event.getPlayer();
@@ -378,20 +337,20 @@ public class WorldGuardPlayerListener implements Listener {
}
}
@EventHandler(priority= EventPriority.LOW, ignoreCancelled = true)
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onPlayerTeleport(PlayerTeleportEvent event) {
World world = event.getFrom().getWorld();
Player player = event.getPlayer();
ConfigurationManager cfg = plugin.getGlobalStateManager();
WorldConfiguration wcfg = cfg.get(world);
if (wcfg.useRegions) {
ApplicableRegionSet set = plugin.getRegionContainer().createQuery().getApplicableRegions(event.getTo());
ApplicableRegionSet setFrom = plugin.getRegionContainer().createQuery().getApplicableRegions(event.getFrom());
LocalPlayer localPlayer = plugin.wrapPlayer(event.getPlayer());
LocalPlayer localPlayer = plugin.wrapPlayer(player);
if (cfg.usePlayerTeleports) {
boolean result = plugin.getPlayerMoveListener().shouldDenyMove(event.getPlayer(), event.getFrom(), event.getTo());
if (result) {
if (null != plugin.getSessionManager().get(player).testMoveTo(player, event.getTo(), MoveType.TELEPORT)) {
event.setCancelled(true);
return;
}
@@ -401,7 +360,7 @@ public class WorldGuardPlayerListener implements Listener {
if (!plugin.getGlobalRegionManager().hasBypass(localPlayer, world)
&& !(set.allows(DefaultFlag.ENDERPEARL, localPlayer)
&& setFrom.allows(DefaultFlag.ENDERPEARL, localPlayer))) {
event.getPlayer().sendMessage(ChatColor.DARK_RED + "You're not allowed to go there.");
player.sendMessage(ChatColor.DARK_RED + "You're not allowed to go there.");
event.setCancelled(true);
return;
}
@@ -22,12 +22,15 @@ package com.sk89q.worldguard.bukkit.listener;
import com.sk89q.worldguard.bukkit.ConfigurationManager;
import com.sk89q.worldguard.bukkit.WorldConfiguration;
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
import com.sk89q.worldguard.bukkit.util.Locations;
import com.sk89q.worldguard.session.MoveType;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.bukkit.entity.Vehicle;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.vehicle.VehicleMoveEvent;
import org.bukkit.util.Vector;
public class WorldGuardVehicleListener implements Listener {
@@ -52,8 +55,7 @@ public class WorldGuardVehicleListener implements Listener {
@EventHandler
public void onVehicleMove(VehicleMoveEvent event) {
Vehicle vehicle = event.getVehicle();
if (vehicle.getPassenger() == null
|| !(vehicle.getPassenger() instanceof Player)) return;
if (vehicle.getPassenger() == null || !(vehicle.getPassenger() instanceof Player)) return;
Player player = (Player) vehicle.getPassenger();
World world = vehicle.getWorld();
ConfigurationManager cfg = plugin.getGlobalStateManager();
@@ -61,12 +63,9 @@ public class WorldGuardVehicleListener implements Listener {
if (wcfg.useRegions) {
// Did we move a block?
if (event.getFrom().getBlockX() != event.getTo().getBlockX()
|| event.getFrom().getBlockY() != event.getTo().getBlockY()
|| event.getFrom().getBlockZ() != event.getTo().getBlockZ()) {
boolean result = plugin.getPlayerMoveListener().shouldDenyMove(player, event.getFrom(), event.getTo());
if (result) {
vehicle.setVelocity(new org.bukkit.util.Vector(0,0,0));
if (Locations.isDifferentBlock(event.getFrom(), event.getTo())) {
if (null != plugin.getSessionManager().get(player).testMoveTo(player, event.getTo(), MoveType.RIDE)) {
vehicle.setVelocity(new Vector(0,0,0));
vehicle.teleport(event.getFrom());
}
}
@@ -27,6 +27,8 @@ import org.bukkit.World;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import javax.annotation.Nullable;
/**
* Used for querying region-related permissions.
*/
@@ -117,13 +119,30 @@ public class RegionPermissionModel extends AbstractPermissionModel {
public boolean maySetFlag(ProtectedRegion region) {
return hasPatternPermission("flag.regions", region);
}
public boolean maySetFlag(ProtectedRegion region, Flag<?> flag) {
// This is a WTF permission
return hasPatternPermission(
"flag.flags." + flag.getName().toLowerCase(), region);
}
public boolean maySetFlag(ProtectedRegion region, Flag<?> flag, @Nullable String value) {
String sanitizedValue;
if (value != null) {
sanitizedValue = value.trim().toLowerCase().replaceAll("[^a-z0-9]", "");
if (sanitizedValue.length() > 20) {
sanitizedValue = sanitizedValue.substring(0, 20);
}
} else {
sanitizedValue = "unset";
}
// This is a WTF permission
return hasPatternPermission(
"flag.flags." + flag.getName().toLowerCase() + "." + sanitizedValue, region);
}
public boolean mayAddMembers(ProtectedRegion region) {
return hasPatternPermission("addmember", region);
}
@@ -27,6 +27,7 @@ import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import org.bukkit.Location;
import javax.annotation.Nullable;
import java.util.List;
import java.util.Set;
import static com.google.common.base.Preconditions.checkNotNull;
@@ -36,7 +37,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
* region is in a set of source regions.
*
* <p>This class only performs a spatial query if its
* {@link #getAssociation(ProtectedRegion)} method is called.</p>
* {@link #getAssociation(List)} method is called.</p>
*/
public class DelayedRegionOverlapAssociation implements RegionAssociable {
@@ -59,17 +60,19 @@ public class DelayedRegionOverlapAssociation implements RegionAssociable {
}
@Override
public Association getAssociation(ProtectedRegion region) {
public Association getAssociation(List<ProtectedRegion> regions) {
if (source == null) {
ApplicableRegionSet result = query.getApplicableRegions(location);
source = result.getRegions();
}
if ((region.getId().equals(ProtectedRegion.GLOBAL_REGION) && source.isEmpty()) || source.contains(region)) {
return Association.OWNER;
} else {
return Association.NON_MEMBER;
for (ProtectedRegion region : regions) {
if ((region.getId().equals(ProtectedRegion.GLOBAL_REGION) && source.isEmpty()) || source.contains(region)) {
return Association.OWNER;
}
}
return Association.NON_MEMBER;
}
}
@@ -20,9 +20,13 @@
package com.sk89q.worldguard.bukkit.util;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.BlockState;
import org.bukkit.material.Bed;
import org.bukkit.material.Chest;
import org.bukkit.material.MaterialData;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@@ -43,7 +47,8 @@ public final class Blocks {
* @return a list of connected blocks, not including the given block
*/
public static List<Block> getConnected(Block block) {
MaterialData data = block.getState().getData();
BlockState state = block.getState();
MaterialData data = state.getData();
if (data instanceof Bed) {
Bed bed = (Bed) data;
@@ -52,6 +57,28 @@ public final class Blocks {
} else {
return Arrays.asList(block.getRelative(bed.getFacing()));
}
} else if (data instanceof Chest) {
BlockFace facing = ((Chest) data).getFacing();
ArrayList<Block> chests = new ArrayList<Block>();
if (facing == BlockFace.NORTH || facing == BlockFace.SOUTH) {
if (block.getRelative(BlockFace.EAST).getState().getData() instanceof Chest) {
chests.add(block.getRelative(BlockFace.EAST));
}
if (block.getRelative(BlockFace.WEST).getState().getData() instanceof Chest) {
chests.add(block.getRelative(BlockFace.WEST));
}
} else if (facing == BlockFace.EAST || facing == BlockFace.WEST) {
if (block.getRelative(BlockFace.NORTH).getState().getData() instanceof Chest) {
chests.add(block.getRelative(BlockFace.NORTH));
}
if (block.getRelative(BlockFace.SOUTH).getState().getData() instanceof Chest) {
chests.add(block.getRelative(BlockFace.SOUTH));
}
} else {
// don't know how to handle diagonal chests
return Collections.emptyList();
}
return chests;
} else {
return Collections.emptyList();
}
@@ -19,6 +19,7 @@
package com.sk89q.worldguard.bukkit.util;
import com.sk89q.worldguard.util.Enums;
import org.bukkit.entity.*;
import org.bukkit.entity.minecart.ExplosiveMinecart;
import org.bukkit.projectiles.ProjectileSource;
@@ -119,18 +120,6 @@ public final class Entities {
return entity;
}
/**
* Return whether the given player is a fake player using the typical
* fake player convention of [Mod].
*
* @param player the player
* @return true if a fake player
*/
public static boolean isFakePlayer(Player player) {
String name = player.getName();
return name.length() >= 3 && name.charAt(0) == '[' && name.charAt(name.length() - 1) == ']';
}
/**
* Test whether an entity is hostile.
*
@@ -144,6 +133,17 @@ public final class Entities {
|| entity instanceof EnderDragon;
}
/**
* Test whether an entity is a non-hostile creature.
*
* @param entity
* @return true if non-hostile
*/
public static boolean isNonHostile(Entity entity) {
return !isHostile(entity)
&& (entity instanceof Creature || entity instanceof WaterMob);
}
/**
* Test whether an entity is ambient.
*
@@ -161,7 +161,7 @@ public final class Entities {
* @return true if an NPC
*/
public static boolean isNPC(Entity entity) {
return entity instanceof NPC;
return entity instanceof NPC || entity.hasMetadata("NPC");
}
/**
@@ -175,6 +175,9 @@ public final class Entities {
return entity instanceof LivingEntity && !(entity instanceof Player);
}
private static final org.bukkit.entity.EntityType armorStandType =
Enums.findByValue(org.bukkit.entity.EntityType.class, "ARMOR_STAND");
/**
* Test whether using the given entity should be considered "building"
* rather than merely using an entity.
@@ -183,7 +186,8 @@ public final class Entities {
* @return true if considered building
*/
public static boolean isConsideredBuildingIfUsed(Entity entity) {
return entity instanceof Hanging;
return entity instanceof Hanging
|| entity.getType() == armorStandType;
}
}
@@ -110,7 +110,7 @@ public final class Events {
*/
public static <T extends Event & Cancellable & BulkEvent> boolean fireBulkEventToCancel(Cancellable original, T eventToFire) {
Bukkit.getServer().getPluginManager().callEvent(eventToFire);
if (eventToFire.isExplicitlyCancelled()) {
if (eventToFire.getExplicitResult() == Result.DENY) {
original.setCancelled(true);
return true;
}
@@ -0,0 +1,116 @@
/*
* 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.bukkit.util;
import com.google.common.base.Function;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import javax.annotation.Nullable;
import java.lang.reflect.Method;
import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.Logger;
public final class InteropUtils {
@Nullable
private static final Class<?> forgeFakePlayerClass;
// This UUID is from Minecraft Forge (see FakePlayerFactory)
private static final UUID forgeFakePlayerUuid = UUID.fromString("41c82c87-7afb-4024-ba57-13d2c99cae77");
private static final PlayerHandleFunction playerHandleFunction;
static {
forgeFakePlayerClass = findClass("net.minecraftforge.common.util.FakePlayer");
PlayerHandleFunction function;
try {
function = new PlayerHandleFunction();
} catch (Exception e) {
function = null;
}
playerHandleFunction = function;
}
@Nullable
private static Class<?> findClass(String name) {
try {
return Class.forName(name);
} catch (Throwable ignored) {
return null;
}
}
private InteropUtils() {
}
/**
* Return whether the given player is a fake player.
*
* @param player the player
* @return true if a fake player
*/
public static boolean isFakePlayer(Player player) {
UUID uuid = player.getUniqueId();
String name = player.getName();
if (uuid.equals(forgeFakePlayerUuid)) {
return true;
}
if (forgeFakePlayerClass != null && playerHandleFunction != null) {
Object handle = playerHandleFunction.apply(player);
if (handle != null) {
if (forgeFakePlayerClass.isAssignableFrom(handle.getClass())) {
return true;
}
}
}
if (name.length() >= 3 && name.charAt(0) == '[' && name.charAt(name.length() - 1) == ']') {
return true;
}
return false;
}
private static final class PlayerHandleFunction implements Function<Object, Object> {
private final Class<?> craftPlayerClass;
private final Method getHandleMethod;
private PlayerHandleFunction() throws NoSuchMethodException, ClassNotFoundException {
craftPlayerClass = Class.forName(Bukkit.getServer().getClass().getCanonicalName().replaceAll("CraftServer$", "entity.CraftPlayer"));
getHandleMethod = craftPlayerClass.getMethod("getHandle");
}
@Nullable
@Override
public Object apply(Object o) {
if (craftPlayerClass.isAssignableFrom(o.getClass())) {
try {
return getHandleMethod.invoke(o);
} catch (Throwable ignored) {
}
}
return null;
}
}
}
@@ -0,0 +1,40 @@
/*
* 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.bukkit.util;
import org.bukkit.Location;
public final class Locations {
private Locations() {
}
/**
* Tests whether two different locations are in two different blocks.
*
* @param a The first location
* @param b The second location
* @return Whether the two locations are two different blocks
*/
public static boolean isDifferentBlock(Location a, Location b) {
return a.getBlockX() != b.getBlockX() || a.getBlockY() != b.getBlockY() || a.getBlockZ() != b.getBlockZ();
}
}
@@ -38,14 +38,23 @@ import java.util.*;
*/
public final class Materials {
private static final int MODIFIED_ON_CLICK = 1;
private static final int MODIFIES_BLOCKS = 2;
private static final int MODIFIED_ON_RIGHT = 1;
private static final int MODIFIED_ON_LEFT = 2;
private static final int MODIFIES_BLOCKS = 4;
private static final BiMap<EntityType, Material> ENTITY_ITEMS = HashBiMap.create();
private static final Map<Material, Integer> MATERIAL_FLAGS = new HashMap<Material, Integer>();
private static final Set<PotionEffectType> DAMAGE_EFFECTS = new HashSet<PotionEffectType>();
public static Material ARMOR_STAND;
static {
try {
ARMOR_STAND = Material.ARMOR_STAND;
} catch (NoSuchFieldError ignored) {
ARMOR_STAND = null;
}
ENTITY_ITEMS.put(EntityType.PAINTING, Material.PAINTING);
ENTITY_ITEMS.put(EntityType.ARROW, Material.ARROW);
ENTITY_ITEMS.put(EntityType.SNOWBALL, Material.SNOW_BALL);
@@ -65,6 +74,9 @@ public final class Materials {
ENTITY_ITEMS.put(EntityType.MINECART_HOPPER, Material.HOPPER_MINECART);
ENTITY_ITEMS.put(EntityType.SPLASH_POTION, Material.POTION);
ENTITY_ITEMS.put(EntityType.EGG, Material.EGG);
try {
ENTITY_ITEMS.put(EntityType.ARMOR_STAND, Material.ARMOR_STAND);
} catch (NoSuchFieldError ignored) {}
MATERIAL_FLAGS.put(Material.AIR, 0);
MATERIAL_FLAGS.put(Material.STONE, 0);
@@ -89,10 +101,10 @@ public final class Materials {
MATERIAL_FLAGS.put(Material.GLASS, 0);
MATERIAL_FLAGS.put(Material.LAPIS_ORE, 0);
MATERIAL_FLAGS.put(Material.LAPIS_BLOCK, 0);
MATERIAL_FLAGS.put(Material.DISPENSER, MODIFIED_ON_CLICK);
MATERIAL_FLAGS.put(Material.DISPENSER, MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.SANDSTONE, 0);
MATERIAL_FLAGS.put(Material.NOTE_BLOCK, MODIFIED_ON_CLICK);
MATERIAL_FLAGS.put(Material.BED_BLOCK, MODIFIED_ON_CLICK);
MATERIAL_FLAGS.put(Material.NOTE_BLOCK, MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.BED_BLOCK, MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.POWERED_RAIL, 0);
MATERIAL_FLAGS.put(Material.DETECTOR_RAIL, 0);
MATERIAL_FLAGS.put(Material.PISTON_STICKY_BASE, 0);
@@ -112,7 +124,7 @@ public final class Materials {
MATERIAL_FLAGS.put(Material.DOUBLE_STEP, 0);
MATERIAL_FLAGS.put(Material.STEP, 0);
MATERIAL_FLAGS.put(Material.BRICK, 0);
MATERIAL_FLAGS.put(Material.TNT, MODIFIED_ON_CLICK);
MATERIAL_FLAGS.put(Material.TNT, MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.BOOKSHELF, 0);
MATERIAL_FLAGS.put(Material.MOSSY_COBBLESTONE, 0);
MATERIAL_FLAGS.put(Material.OBSIDIAN, 0);
@@ -120,37 +132,37 @@ public final class Materials {
MATERIAL_FLAGS.put(Material.FIRE, 0);
MATERIAL_FLAGS.put(Material.MOB_SPAWNER, 0);
MATERIAL_FLAGS.put(Material.WOOD_STAIRS, 0);
MATERIAL_FLAGS.put(Material.CHEST, MODIFIED_ON_CLICK);
MATERIAL_FLAGS.put(Material.CHEST, MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.REDSTONE_WIRE, 0);
MATERIAL_FLAGS.put(Material.DIAMOND_ORE, 0);
MATERIAL_FLAGS.put(Material.DIAMOND_BLOCK, 0);
MATERIAL_FLAGS.put(Material.WORKBENCH, MODIFIED_ON_CLICK);
MATERIAL_FLAGS.put(Material.WORKBENCH, MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.CROPS, 0);
MATERIAL_FLAGS.put(Material.SOIL, 0);
MATERIAL_FLAGS.put(Material.FURNACE, MODIFIED_ON_CLICK);
MATERIAL_FLAGS.put(Material.BURNING_FURNACE, MODIFIED_ON_CLICK);
MATERIAL_FLAGS.put(Material.FURNACE, MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.BURNING_FURNACE, MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.SIGN_POST, 0);
MATERIAL_FLAGS.put(Material.WOODEN_DOOR, MODIFIED_ON_CLICK);
MATERIAL_FLAGS.put(Material.WOODEN_DOOR, MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.LADDER, 0);
MATERIAL_FLAGS.put(Material.RAILS, 0);
MATERIAL_FLAGS.put(Material.COBBLESTONE_STAIRS, 0);
MATERIAL_FLAGS.put(Material.WALL_SIGN, 0);
MATERIAL_FLAGS.put(Material.LEVER, MODIFIED_ON_CLICK);
MATERIAL_FLAGS.put(Material.LEVER, MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.STONE_PLATE, 0);
MATERIAL_FLAGS.put(Material.IRON_DOOR_BLOCK, MODIFIED_ON_CLICK);
MATERIAL_FLAGS.put(Material.IRON_DOOR_BLOCK, 0);
MATERIAL_FLAGS.put(Material.WOOD_PLATE, 0);
MATERIAL_FLAGS.put(Material.REDSTONE_ORE, 0);
MATERIAL_FLAGS.put(Material.GLOWING_REDSTONE_ORE, 0);
MATERIAL_FLAGS.put(Material.REDSTONE_TORCH_OFF, 0);
MATERIAL_FLAGS.put(Material.REDSTONE_TORCH_ON, 0);
MATERIAL_FLAGS.put(Material.STONE_BUTTON, MODIFIED_ON_CLICK);
MATERIAL_FLAGS.put(Material.STONE_BUTTON, MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.SNOW, 0);
MATERIAL_FLAGS.put(Material.ICE, 0);
MATERIAL_FLAGS.put(Material.SNOW_BLOCK, 0);
MATERIAL_FLAGS.put(Material.CACTUS, 0);
MATERIAL_FLAGS.put(Material.CLAY, 0);
MATERIAL_FLAGS.put(Material.SUGAR_CANE_BLOCK, 0);
MATERIAL_FLAGS.put(Material.JUKEBOX, MODIFIED_ON_CLICK);
MATERIAL_FLAGS.put(Material.JUKEBOX, MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.FENCE, 0);
MATERIAL_FLAGS.put(Material.PUMPKIN, 0);
MATERIAL_FLAGS.put(Material.NETHERRACK, 0);
@@ -158,11 +170,11 @@ public final class Materials {
MATERIAL_FLAGS.put(Material.GLOWSTONE, 0);
MATERIAL_FLAGS.put(Material.PORTAL, 0);
MATERIAL_FLAGS.put(Material.JACK_O_LANTERN, 0);
MATERIAL_FLAGS.put(Material.CAKE_BLOCK, MODIFIED_ON_CLICK);
MATERIAL_FLAGS.put(Material.DIODE_BLOCK_OFF, MODIFIED_ON_CLICK);
MATERIAL_FLAGS.put(Material.DIODE_BLOCK_ON, MODIFIED_ON_CLICK);
MATERIAL_FLAGS.put(Material.CAKE_BLOCK, MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.DIODE_BLOCK_OFF, MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.DIODE_BLOCK_ON, MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.STAINED_GLASS, 0);
MATERIAL_FLAGS.put(Material.TRAP_DOOR, MODIFIED_ON_CLICK);
MATERIAL_FLAGS.put(Material.TRAP_DOOR, MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.MONSTER_EGGS, 0);
MATERIAL_FLAGS.put(Material.SMOOTH_BRICK, 0);
MATERIAL_FLAGS.put(Material.HUGE_MUSHROOM_1, 0);
@@ -173,7 +185,7 @@ public final class Materials {
MATERIAL_FLAGS.put(Material.PUMPKIN_STEM, 0);
MATERIAL_FLAGS.put(Material.MELON_STEM, 0);
MATERIAL_FLAGS.put(Material.VINE, 0);
MATERIAL_FLAGS.put(Material.FENCE_GATE, MODIFIED_ON_CLICK);
MATERIAL_FLAGS.put(Material.FENCE_GATE, MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.BRICK_STAIRS, 0);
MATERIAL_FLAGS.put(Material.SMOOTH_STAIRS, 0);
MATERIAL_FLAGS.put(Material.MYCEL, 0);
@@ -182,13 +194,13 @@ public final class Materials {
MATERIAL_FLAGS.put(Material.NETHER_FENCE, 0);
MATERIAL_FLAGS.put(Material.NETHER_BRICK_STAIRS, 0);
MATERIAL_FLAGS.put(Material.NETHER_WARTS, 0);
MATERIAL_FLAGS.put(Material.ENCHANTMENT_TABLE, MODIFIED_ON_CLICK);
MATERIAL_FLAGS.put(Material.BREWING_STAND, MODIFIED_ON_CLICK);
MATERIAL_FLAGS.put(Material.CAULDRON, MODIFIED_ON_CLICK);
MATERIAL_FLAGS.put(Material.ENCHANTMENT_TABLE, MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.BREWING_STAND, MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.CAULDRON, MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.ENDER_PORTAL, 0);
MATERIAL_FLAGS.put(Material.ENDER_PORTAL_FRAME, 0);
MATERIAL_FLAGS.put(Material.ENDER_STONE, 0);
MATERIAL_FLAGS.put(Material.DRAGON_EGG, MODIFIED_ON_CLICK);
MATERIAL_FLAGS.put(Material.DRAGON_EGG, MODIFIED_ON_LEFT | MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.REDSTONE_LAMP_OFF, 0);
MATERIAL_FLAGS.put(Material.REDSTONE_LAMP_ON, 0);
MATERIAL_FLAGS.put(Material.WOOD_DOUBLE_STEP, 0);
@@ -196,35 +208,35 @@ public final class Materials {
MATERIAL_FLAGS.put(Material.COCOA, 0);
MATERIAL_FLAGS.put(Material.SANDSTONE_STAIRS, 0);
MATERIAL_FLAGS.put(Material.EMERALD_ORE, 0);
MATERIAL_FLAGS.put(Material.ENDER_CHEST, 0);
MATERIAL_FLAGS.put(Material.ENDER_CHEST, MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.TRIPWIRE_HOOK, 0);
MATERIAL_FLAGS.put(Material.TRIPWIRE, 0);
MATERIAL_FLAGS.put(Material.EMERALD_BLOCK, 0);
MATERIAL_FLAGS.put(Material.SPRUCE_WOOD_STAIRS, 0);
MATERIAL_FLAGS.put(Material.BIRCH_WOOD_STAIRS, 0);
MATERIAL_FLAGS.put(Material.JUNGLE_WOOD_STAIRS, 0);
MATERIAL_FLAGS.put(Material.COMMAND, MODIFIED_ON_CLICK);
MATERIAL_FLAGS.put(Material.BEACON, MODIFIED_ON_CLICK);
MATERIAL_FLAGS.put(Material.COMMAND, MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.BEACON, MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.COBBLE_WALL, 0);
MATERIAL_FLAGS.put(Material.FLOWER_POT, MODIFIED_ON_CLICK);
MATERIAL_FLAGS.put(Material.FLOWER_POT, MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.CARROT, 0);
MATERIAL_FLAGS.put(Material.POTATO, 0);
MATERIAL_FLAGS.put(Material.WOOD_BUTTON, MODIFIED_ON_CLICK);
MATERIAL_FLAGS.put(Material.WOOD_BUTTON, MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.SKULL, 0);
MATERIAL_FLAGS.put(Material.ANVIL, MODIFIED_ON_CLICK);
MATERIAL_FLAGS.put(Material.TRAPPED_CHEST, MODIFIED_ON_CLICK);
MATERIAL_FLAGS.put(Material.ANVIL, MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.TRAPPED_CHEST, MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.GOLD_PLATE, 0);
MATERIAL_FLAGS.put(Material.IRON_PLATE, 0);
MATERIAL_FLAGS.put(Material.REDSTONE_COMPARATOR_OFF, MODIFIED_ON_CLICK);
MATERIAL_FLAGS.put(Material.REDSTONE_COMPARATOR_ON, MODIFIED_ON_CLICK);
MATERIAL_FLAGS.put(Material.DAYLIGHT_DETECTOR, MODIFIED_ON_CLICK);
MATERIAL_FLAGS.put(Material.REDSTONE_COMPARATOR_OFF, MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.REDSTONE_COMPARATOR_ON, MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.DAYLIGHT_DETECTOR, MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.REDSTONE_BLOCK, 0);
MATERIAL_FLAGS.put(Material.QUARTZ_ORE, 0);
MATERIAL_FLAGS.put(Material.HOPPER, MODIFIED_ON_CLICK);
MATERIAL_FLAGS.put(Material.HOPPER, MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.QUARTZ_BLOCK, 0);
MATERIAL_FLAGS.put(Material.QUARTZ_STAIRS, 0);
MATERIAL_FLAGS.put(Material.ACTIVATOR_RAIL, 0);
MATERIAL_FLAGS.put(Material.DROPPER, MODIFIED_ON_CLICK);
MATERIAL_FLAGS.put(Material.DROPPER, MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.STAINED_CLAY, 0);
MATERIAL_FLAGS.put(Material.STAINED_GLASS_PANE, 0);
MATERIAL_FLAGS.put(Material.LEAVES_2, 0);
@@ -237,6 +249,31 @@ public final class Materials {
MATERIAL_FLAGS.put(Material.COAL_BLOCK, 0);
MATERIAL_FLAGS.put(Material.PACKED_ICE, 0);
MATERIAL_FLAGS.put(Material.DOUBLE_PLANT, 0);
try {
MATERIAL_FLAGS.put(Material.STANDING_BANNER, 0);
MATERIAL_FLAGS.put(Material.WALL_BANNER, 0);
MATERIAL_FLAGS.put(Material.DAYLIGHT_DETECTOR_INVERTED, MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.RED_SANDSTONE, 0);
MATERIAL_FLAGS.put(Material.RED_SANDSTONE_STAIRS, 0);
MATERIAL_FLAGS.put(Material.DOUBLE_STONE_SLAB2, 0);
MATERIAL_FLAGS.put(Material.STONE_SLAB2, 0);
MATERIAL_FLAGS.put(Material.SPRUCE_FENCE_GATE, MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.BIRCH_FENCE_GATE, MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.JUNGLE_FENCE_GATE, MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.DARK_OAK_FENCE_GATE, MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.ACACIA_FENCE_GATE, MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.SPRUCE_FENCE, 0);
MATERIAL_FLAGS.put(Material.BIRCH_FENCE, 0);
MATERIAL_FLAGS.put(Material.JUNGLE_FENCE, 0);
MATERIAL_FLAGS.put(Material.DARK_OAK_FENCE, 0);
MATERIAL_FLAGS.put(Material.ACACIA_FENCE, 0);
MATERIAL_FLAGS.put(Material.SPRUCE_DOOR, MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.BIRCH_DOOR, MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.JUNGLE_DOOR, MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.ACACIA_DOOR, MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.DARK_OAK_DOOR, MODIFIED_ON_RIGHT);
} catch (NoSuchFieldError ignored) {
}
MATERIAL_FLAGS.put(Material.IRON_SPADE, 0);
MATERIAL_FLAGS.put(Material.IRON_PICKAXE, 0);
@@ -365,7 +402,7 @@ public final class Materials {
MATERIAL_FLAGS.put(Material.CAULDRON_ITEM, 0);
MATERIAL_FLAGS.put(Material.EYE_OF_ENDER, 0);
MATERIAL_FLAGS.put(Material.SPECKLED_MELON, 0);
MATERIAL_FLAGS.put(Material.MONSTER_EGG, 0);
MATERIAL_FLAGS.put(Material.MONSTER_EGG, MODIFIES_BLOCKS);
MATERIAL_FLAGS.put(Material.EXP_BOTTLE, 0);
MATERIAL_FLAGS.put(Material.FIREBALL, 0);
MATERIAL_FLAGS.put(Material.BOOK_AND_QUILL, 0);
@@ -397,6 +434,28 @@ public final class Materials {
MATERIAL_FLAGS.put(Material.LEASH, 0);
MATERIAL_FLAGS.put(Material.NAME_TAG, 0);
MATERIAL_FLAGS.put(Material.COMMAND_MINECART, 0);
try {
MATERIAL_FLAGS.put(Material.PRISMARINE_SHARD, 0);
MATERIAL_FLAGS.put(Material.PRISMARINE_CRYSTALS, 0);
MATERIAL_FLAGS.put(Material.RABBIT, 0);
MATERIAL_FLAGS.put(Material.COOKED_RABBIT, 0);
MATERIAL_FLAGS.put(Material.RABBIT_STEW, 0);
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.IRON_BARDING, 0);
MATERIAL_FLAGS.put(Material.GOLD_BARDING, 0);
MATERIAL_FLAGS.put(Material.DIAMOND_BARDING, 0);;
MATERIAL_FLAGS.put(Material.MUTTON, 0);
MATERIAL_FLAGS.put(Material.COOKED_MUTTON, 0);
MATERIAL_FLAGS.put(Material.BANNER, 0);
MATERIAL_FLAGS.put(Material.SPRUCE_DOOR_ITEM, 0);
MATERIAL_FLAGS.put(Material.BIRCH_DOOR_ITEM, 0);
MATERIAL_FLAGS.put(Material.JUNGLE_DOOR_ITEM, 0);
MATERIAL_FLAGS.put(Material.ACACIA_DOOR_ITEM, 0);
MATERIAL_FLAGS.put(Material.DARK_OAK_DOOR_ITEM, 0);
} catch (NoSuchFieldError ignored) {
}
MATERIAL_FLAGS.put(Material.GOLD_RECORD, 0);
MATERIAL_FLAGS.put(Material.GREEN_RECORD, 0);
MATERIAL_FLAGS.put(Material.RECORD_3, 0);
@@ -614,19 +673,35 @@ public final class Materials {
* @return true if covered by the use flag
*/
public static boolean isUseFlagApplicable(Material material) {
return material == Material.LEVER
|| material == Material.STONE_BUTTON
|| material == Material.WOOD_BUTTON
|| material == Material.WOODEN_DOOR
|| material == Material.TRAP_DOOR
|| material == Material.FENCE_GATE
|| material == Material.WORKBENCH
|| material == Material.ENCHANTMENT_TABLE
|| material == Material.BEACON
|| material == Material.ANVIL
|| material == Material.STONE_PLATE
|| material == Material.IRON_PLATE
|| material == Material.GOLD_PLATE;
switch (material) {
case LEVER: return true;
case STONE_BUTTON: return true;
case WOOD_BUTTON: return true;
case TRIPWIRE: return true;
case WOODEN_DOOR: return true;
case TRAP_DOOR: return true;
case FENCE_GATE: return true;
case WORKBENCH: return true;
case ENCHANTMENT_TABLE: return true;
case ENDER_CHEST: return true;
case BEACON: return true;
case ANVIL: return true;
case WOOD_PLATE: return true;
case STONE_PLATE: return true;
case IRON_PLATE: return true;
case GOLD_PLATE: 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 SPRUCE_DOOR: return true;
case BIRCH_DOOR: return true;
case JUNGLE_DOOR: return true;
case ACACIA_DOOR: return true;
case DARK_OAK_DOOR: return true;
default: return false;
}
}
/**
@@ -647,11 +722,14 @@ public final class Materials {
* aware of.</p>
*
* @param material the material
* @param rightClick whether it is a right click
* @return true if the block is modified
*/
public static boolean isBlockModifiedOnClick(Material material) {
public static boolean isBlockModifiedOnClick(Material material, boolean rightClick) {
Integer flags = MATERIAL_FLAGS.get(material);
return flags == null || (flags & MODIFIED_ON_CLICK) == MODIFIED_ON_CLICK;
return flags == null
|| (rightClick && (flags & MODIFIED_ON_RIGHT) == MODIFIED_ON_RIGHT)
|| (!rightClick && (flags & MODIFIED_ON_LEFT) == MODIFIED_ON_LEFT);
}
/**
@@ -677,7 +755,11 @@ public final class Materials {
* @return true to be considered as used
*/
public static boolean isConsideredBuildingIfUsed(Material type) {
return type == Material.SAPLING;
return type == Material.SAPLING
|| type == Material.DIODE_BLOCK_OFF
|| type == Material.DIODE_BLOCK_ON
|| type == Material.REDSTONE_COMPARATOR_OFF
|| type == Material.REDSTONE_COMPARATOR_ON;
}
/**
@@ -19,14 +19,36 @@
package com.sk89q.worldguard.bukkit.util.report;
import com.google.common.base.Optional;
import com.google.common.reflect.TypeToken;
import com.sk89q.guavabackport.cache.CacheBuilder;
import com.sk89q.guavabackport.cache.CacheLoader;
import com.sk89q.guavabackport.cache.LoadingCache;
import com.sk89q.worldguard.util.report.DataReport;
import org.bukkit.Bukkit;
import org.bukkit.scheduler.BukkitTask;
import javax.annotation.Nullable;
import java.lang.reflect.Field;
import java.util.List;
import java.util.Set;
public class SchedulerReport extends DataReport {
private LoadingCache<Class<?>, Optional<Field>> taskFieldCache = CacheBuilder.newBuilder()
.build(new CacheLoader<Class<?>, Optional<Field>>() {
@Override
public Optional<Field> load(Class<?> clazz) throws Exception {
try {
Field field = clazz.getDeclaredField("task");
field.setAccessible(true);
return Optional.fromNullable(field);
} catch (NoSuchFieldException ignored) {
return Optional.absent();
}
}
});
public SchedulerReport() {
super("Scheduler");
@@ -35,10 +57,34 @@ public class SchedulerReport extends DataReport {
append("Pending Task Count", tasks.size());
for (BukkitTask task : tasks) {
Class<?> taskClass = getTaskClass(task);
DataReport report = new DataReport("Task: #" + task.getTaskId());
report.append("Owner", task.getOwner().getName());
report.append("Runnable", taskClass != null ? taskClass.getName() : "<Unknown>");
report.append("Synchronous?", task.isSync());
append(report.getTitle(), report);
}
}
@SuppressWarnings("unchecked")
@Nullable
private Class<?> getTaskClass(BukkitTask task) {
try {
Class<?> clazz = task.getClass();
Set<Class<?>> classes = (Set) TypeToken.of(clazz).getTypes().rawTypes();
for (Class<?> type : classes) {
Optional<Field> field = taskFieldCache.getUnchecked(type);
if (field.isPresent()) {
Object res = field.get().get(task);
return res == null ? null : res.getClass();
}
}
} catch (IllegalAccessException ignored) {
} catch (NoClassDefFoundError ignored) {
}
return null;
}
}
@@ -19,6 +19,7 @@
package com.sk89q.worldguard.bukkit.util.report;
import com.sk89q.worldguard.bukkit.BukkitUtil;
import com.sk89q.worldguard.util.report.DataReport;
import org.bukkit.Bukkit;
import org.bukkit.Server;
@@ -34,7 +35,9 @@ public class ServerReport extends DataReport {
append("Server Name", server.getServerName());
append("Bukkit Version", server.getBukkitVersion());
append("Implementation", server.getVersion());
append("Player Count", "%d/%d", server.getOnlinePlayers().size(), server.getMaxPlayers());
append("Player Count", "%d/%d", BukkitUtil.getOnlinePlayers().size(), server.getMaxPlayers());
append("Server Class Source", server.getClass().getProtectionDomain().getCodeSource().getLocation());
DataReport spawning = new DataReport("Spawning");
spawning.append("Ambient Spawn Limit", server.getAmbientSpawnLimit());
@@ -43,6 +43,22 @@ public class DefaultDomain implements Domain, ChangeTracked {
private PlayerDomain playerDomain = new PlayerDomain();
private GroupDomain groupDomain = new GroupDomain();
/**
* Create a new domain.
*/
public DefaultDomain() {
}
/**
* Create a new domain from an existing one, making a copy of all values.
*
* @param existing the other domain to copy values from
*/
public DefaultDomain(DefaultDomain existing) {
setPlayerDomain(existing.getPlayerDomain());
setGroupDomain(existing.getGroupDomain());
}
/**
* Get the domain that holds the players.
*
@@ -59,7 +75,7 @@ public class DefaultDomain implements Domain, ChangeTracked {
*/
public void setPlayerDomain(PlayerDomain playerDomain) {
checkNotNull(playerDomain);
this.playerDomain = playerDomain;
this.playerDomain = new PlayerDomain(playerDomain);
}
/**
@@ -78,7 +94,7 @@ public class DefaultDomain implements Domain, ChangeTracked {
*/
public void setGroupDomain(GroupDomain groupDomain) {
checkNotNull(groupDomain);
this.groupDomain = groupDomain;
this.groupDomain = new GroupDomain(groupDomain);
}
/**
@@ -43,6 +43,16 @@ public class GroupDomain implements Domain, ChangeTracked {
public GroupDomain() {
}
/**
* Create a new instance with copies from another domain.
*
* @param domain the domain to copy values from
*/
public GroupDomain(GroupDomain domain) {
checkNotNull(domain, "domain");
groups.addAll(domain.getGroups());
}
/**
* Create a new instance.
*
@@ -117,6 +127,7 @@ public class GroupDomain implements Domain, ChangeTracked {
@Override
public void clear() {
setDirty(true);
groups.clear();
}
@@ -44,6 +44,18 @@ public class PlayerDomain implements Domain, ChangeTracked {
public PlayerDomain() {
}
/**
* Create a new instance.
*
* @param domain the domain to copy values from
*/
public PlayerDomain(PlayerDomain domain) {
checkNotNull(domain, "domain");
uniqueIds.addAll(domain.getUniqueIds());
names.addAll(domain.getPlayers());
dirty = true;
}
/**
* Create a new instance with the given names.
*
@@ -113,6 +125,7 @@ public class PlayerDomain implements Domain, ChangeTracked {
*/
public void removePlayer(UUID uuid) {
checkNotNull(uuid);
setDirty(true);
uniqueIds.remove(uuid);
}
@@ -124,6 +137,7 @@ public class PlayerDomain implements Domain, ChangeTracked {
*/
public void removePlayer(LocalPlayer player) {
checkNotNull(player);
setDirty(true);
removePlayer(player.getName());
removePlayer(player.getUniqueId());
}
@@ -171,6 +185,7 @@ public class PlayerDomain implements Domain, ChangeTracked {
@Override
public void clear() {
setDirty(true);
uniqueIds.clear();
names.clear();
}
@@ -21,6 +21,7 @@ package com.sk89q.worldguard.protection;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
import com.sk89q.worldguard.domains.Association;
import com.sk89q.worldguard.protection.association.RegionAssociable;
import com.sk89q.worldguard.protection.flags.DefaultFlag;
@@ -29,15 +30,10 @@ import com.sk89q.worldguard.protection.flags.RegionGroup;
import com.sk89q.worldguard.protection.flags.StateFlag;
import com.sk89q.worldguard.protection.flags.StateFlag.State;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import com.sk89q.worldguard.protection.util.NormativeOrders;
import javax.annotation.Nullable;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.*;
import static com.google.common.base.Preconditions.checkNotNull;
@@ -61,7 +57,7 @@ public class FlagValueCalculator {
/**
* Create a new instance.
*
* @param regions a list of applicable regions that <strong>must be sorted by priority descending</strong>
* @param regions a list of applicable regions that must be sorted according to {@link NormativeOrders}
* @param globalRegion an optional global region (null to not use one)
*/
public FlagValueCalculator(List<ProtectedRegion> regions, @Nullable ProtectedRegion globalRegion) {
@@ -108,36 +104,9 @@ public class FlagValueCalculator {
checkNotNull(subject);
int minimumPriority = Integer.MIN_VALUE;
boolean foundApplicableRegion = false;
Result result = Result.NO_REGIONS;
// Say there are two regions in one location: CHILD and PARENT (CHILD
// is a child of PARENT). If there are two overlapping regions in WG, a
// subject has to be a member of /both/ (or flags permit) in order to
// build in that location. However, inheritance is supposed
// to allow building if the subject is a member of just CHILD. That
// presents a problem.
//
// To rectify this, we keep two sets. When we iterate over the list of
// regions, there are two scenarios that we may encounter:
//
// 1) PARENT first, CHILD later:
// a) When the loop reaches PARENT, PARENT is added to needsClear.
// b) When the loop reaches CHILD, parents of CHILD (which includes
// PARENT) are removed from needsClear.
// c) needsClear is empty again.
//
// 2) CHILD first, PARENT later:
// a) When the loop reaches CHILD, CHILD's parents (i.e. PARENT) are
// added to hasCleared.
// b) When the loop reaches PARENT, since PARENT is already in
// hasCleared, it does not add PARENT to needsClear.
// c) needsClear stays empty.
//
// As long as the process ends with needsClear being empty, then
// we have satisfied all membership requirements.
Set<ProtectedRegion> needsClear = new HashSet<ProtectedRegion>();
Set<ProtectedRegion> hasCleared = new HashSet<ProtectedRegion>();
Set<ProtectedRegion> ignoredRegions = Sets.newHashSet();
for (ProtectedRegion region : getApplicable()) {
// Don't consider lower priorities below minimumPriority
@@ -153,24 +122,23 @@ public class FlagValueCalculator {
continue;
}
minimumPriority = getPriority(region);
foundApplicableRegion = true;
if (ignoredRegions.contains(region)) {
continue;
}
if (!hasCleared.contains(region)) {
if (!RegionGroup.MEMBERS.contains(subject.getAssociation(region))) {
needsClear.add(region);
} else {
// Need to clear all parents
removeParents(needsClear, hasCleared, region);
}
minimumPriority = getPriority(region);
boolean member = RegionGroup.MEMBERS.contains(subject.getAssociation(Arrays.asList(region)));
if (member) {
result = Result.SUCCESS;
addParents(ignoredRegions, region);
} else {
return Result.FAIL;
}
}
if (foundApplicableRegion) {
return needsClear.isEmpty() ? Result.SUCCESS : Result.FAIL;
} else {
return Result.NO_REGIONS;
}
return result;
}
@@ -249,7 +217,7 @@ public class FlagValueCalculator {
*/
@Nullable
public <V> V queryValue(@Nullable RegionAssociable subject, Flag<V> flag) {
Collection<V> values = queryAllValues(subject, flag);
Collection<V> values = queryAllValues(subject, flag, true);
return flag.chooseValue(values);
}
@@ -270,85 +238,80 @@ public class FlagValueCalculator {
* @param flag the flag
* @return a collection of values
*/
@SuppressWarnings("unchecked")
public <V> Collection<V> queryAllValues(@Nullable RegionAssociable subject, Flag<V> flag) {
return queryAllValues(subject, flag, false);
}
/**
* Get the effective values for a flag, returning a collection of all
* values. It is up to the caller to determine which value, if any,
* from the collection will be used.
*
* <p>A subject can be provided that is used to determine whether the value
* of a flag on a particular region should be used. For example, if a
* flag's region group is set to {@link RegionGroup#MEMBERS} and the given
* subject is not a member, then the region would be skipped when
* querying that flag. If {@code null} is provided for the subject, then
* only flags that use {@link RegionGroup#ALL},
* {@link RegionGroup#NON_MEMBERS}, etc. will apply.</p>
*
* @param subject an optional subject, which would be used to determine the region group to apply
* @param flag the flag
* @param acceptOne if possible, return only one value if it doesn't matter
* @return a collection of values
*/
@SuppressWarnings("unchecked")
private <V> Collection<V> queryAllValues(@Nullable RegionAssociable subject, Flag<V> flag, boolean acceptOne) {
checkNotNull(flag);
// Can't use this optimization with flags that have a conflict resolution strategy
if (acceptOne && flag.hasConflictStrategy()) {
acceptOne = false;
}
// Check to see whether we have a subject if this is BUILD
if (flag == DefaultFlag.BUILD && subject == null) {
throw new NullPointerException("The BUILD flag is handled in a special fashion and requires a non-null subject parameter");
if (flag.requiresSubject() && subject == null) {
throw new NullPointerException("The " + flag.getName() + " flag is handled in a special fashion and requires a non-null subject parameter");
}
int minimumPriority = Integer.MIN_VALUE;
// Say there are two regions in one location: CHILD and PARENT (CHILD
// is a child of PARENT). If the two are overlapping regions in WG,
// both with values set, then we have a problem. Due to inheritance,
// only the CHILD's value for the flag should be used because it
// overrides its parent's value, but default behavior is to collect
// all the values into a list.
//
// To rectify this, we keep a map of consideredValues (region -> value)
// and an ignoredRegions set. When we iterate over the list of
// regions, there are two scenarios that we may encounter:
//
// 1) PARENT first, CHILD later:
// a) When the loop reaches PARENT, PARENT's value is added to
// consideredValues
// b) When the loop reaches CHILD, parents of CHILD (which includes
// PARENT) are removed from consideredValues (so we no longer
// consider those values). The CHILD's value is then added to
// consideredValues.
// c) In the end, only CHILD's value exists in consideredValues.
//
// 2) CHILD first, PARENT later:
// a) When the loop reaches CHILD, CHILD's value is added to
// consideredValues. In addition, the CHILD's parents (which
// includes PARENT) are added to ignoredRegions.
// b) When the loop reaches PARENT, since PARENT is in
// ignoredRegions, the parent is skipped over.
// c) In the end, only CHILD's value exists in consideredValues.
Map<ProtectedRegion, V> consideredValues = new HashMap<ProtectedRegion, V>();
Set<ProtectedRegion> ignoredRegions = new HashSet<ProtectedRegion>();
Set<ProtectedRegion> ignoredParents = new HashSet<ProtectedRegion>();
for (ProtectedRegion region : getApplicable()) {
// Don't consider lower priorities below minimumPriority
// (which starts at Integer.MIN_VALUE). A region that "counts"
// (has the flag set) will raise minimumPriority to its own
// priority.
if (getPriority(region) < minimumPriority) {
break;
}
if (ignoredParents.contains(region)) {
continue;
}
V value = getEffectiveFlag(region, flag, subject);
int priority = getPriority(region);
if (value != null) {
if (!ignoredRegions.contains(region)) {
minimumPriority = priority;
minimumPriority = priority;
ignoreValuesOfParents(consideredValues, ignoredRegions, region);
if (acceptOne) {
return Arrays.asList(value);
} else {
consideredValues.put(region, value);
if (value == State.DENY) {
// Since DENY overrides all other values, there
// is no need to consider any further regions
break;
}
}
}
// The BUILD flag (of lower priorities) can be overridden if
// this region has members... this check is here due to legacy
// reasons
if (priority != minimumPriority && flag == DefaultFlag.BUILD
addParents(ignoredParents, region);
// The BUILD flag is implicitly set on every region where
// PASSTHROUGH is not set to ALLOW
if (priority != minimumPriority && flag.implicitlySetWithMembership()
&& getEffectiveFlag(region, DefaultFlag.PASSTHROUGH, subject) != State.ALLOW) {
minimumPriority = getPriority(region);
}
}
if (flag == DefaultFlag.BUILD && consideredValues.isEmpty()) {
if (flag.usesMembershipAsDefault() && consideredValues.isEmpty()) {
switch (getMembership(subject)) {
case FAIL:
return ImmutableList.of();
@@ -401,17 +364,21 @@ public class FlagValueCalculator {
return (V) State.ALLOW;
}
} else if (flag == DefaultFlag.BUILD) {
} else if (flag instanceof StateFlag && ((StateFlag) flag).preventsAllowOnGlobal()) {
// Legacy behavior -> we can't let people change BUILD on
// the global region
State value = region.getFlag(DefaultFlag.BUILD);
State value = region.getFlag((StateFlag) flag);
return value != State.ALLOW ? (V) value : null;
}
}
ProtectedRegion current = region;
List<ProtectedRegion> seen = new ArrayList<ProtectedRegion>();
while (current != null) {
seen.add(current);
V value = current.getFlag(flag);
if (value != null) {
@@ -427,7 +394,7 @@ public class FlagValueCalculator {
use = false;
} else if (subject == null) {
use = group.contains(Association.NON_MEMBER);
} else if (!group.contains(subject.getAssociation(region))) {
} else if (!group.contains(subject.getAssociation(seen))) {
use = false;
}
}
@@ -443,40 +410,17 @@ public class FlagValueCalculator {
return null;
}
/**
* Clear a region's parents for isFlagAllowed().
*
* @param needsClear the regions that should be cleared
* @param hasCleared the regions already cleared
* @param region the region to start from
*/
private void removeParents(Set<ProtectedRegion> needsClear, Set<ProtectedRegion> hasCleared, ProtectedRegion region) {
ProtectedRegion parent = region.getParent();
while (parent != null) {
if (!needsClear.remove(parent)) {
hasCleared.add(parent);
}
parent = parent.getParent();
}
}
/**
* Clear a region's parents for getFlag().
*
* @param needsClear The regions that should be cleared
* @param hasCleared The regions already cleared
* @param ignored The regions to ignore
* @param region The region to start from
*/
private void ignoreValuesOfParents(Map<ProtectedRegion, ?> needsClear, Set<ProtectedRegion> hasCleared, ProtectedRegion region) {
private void addParents(Set<ProtectedRegion> ignored, ProtectedRegion region) {
ProtectedRegion parent = region.getParent();
while (parent != null) {
if (needsClear.remove(parent) == null) {
hasCleared.add(parent);
}
ignored.add(parent);
parent = parent.getParent();
}
}
@@ -25,14 +25,10 @@ import com.sk89q.worldguard.protection.flags.Flag;
import com.sk89q.worldguard.protection.flags.StateFlag;
import com.sk89q.worldguard.protection.flags.StateFlag.State;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import com.sk89q.worldguard.protection.util.NormativeOrders;
import javax.annotation.Nullable;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.*;
import static com.google.common.base.Preconditions.checkNotNull;
@@ -47,9 +43,10 @@ public class RegionResultSet extends AbstractRegionSet {
private Set<ProtectedRegion> regionSet;
/**
* Construct the object.
* Create a new region result set.
*
* <p>A sorted set will be created to include the collection of regions.</p>
* <p>The given list must not contain duplicates or the behavior of
* this instance will be undefined.</p>
*
* @param applicable the regions contained in this set
* @param globalRegion the global region, set aside for special handling.
@@ -59,16 +56,31 @@ public class RegionResultSet extends AbstractRegionSet {
}
/**
* Construct the object.
* Create a new region result set.
*
* @param applicable the regions contained in this set
* @param globalRegion the global region, set aside for special handling.
*/
public RegionResultSet(Set<ProtectedRegion> applicable, @Nullable ProtectedRegion globalRegion) {
this(NormativeOrders.fromSet(applicable), globalRegion, true);
this.regionSet = applicable;
}
/**
* Create a new region result set.
*
* <p>The list of regions may be first sorted with
* {@link NormativeOrders}. If that is the case, {@code sorted} should be
* {@code true}. Otherwise, the list will be sorted in-place.</p>
*
* @param applicable the regions contained in this set
* @param globalRegion the global region, set aside for special handling.
* @param sorted true if the list is already sorted
* @param sorted true if the list is already sorted with {@link NormativeOrders}
*/
private RegionResultSet(List<ProtectedRegion> applicable, @Nullable ProtectedRegion globalRegion, boolean sorted) {
public RegionResultSet(List<ProtectedRegion> applicable, @Nullable ProtectedRegion globalRegion, boolean sorted) {
checkNotNull(applicable);
if (!sorted) {
Collections.sort(applicable);
NormativeOrders.sort(applicable);
}
this.applicable = applicable;
this.flagValueCalculator = new FlagValueCalculator(applicable, globalRegion);
@@ -22,6 +22,8 @@ package com.sk89q.worldguard.protection.association;
import com.sk89q.worldguard.domains.Association;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import java.util.List;
class ConstantAssociation implements RegionAssociable {
private final Association association;
@@ -31,7 +33,7 @@ class ConstantAssociation implements RegionAssociable {
}
@Override
public Association getAssociation(ProtectedRegion region) {
public Association getAssociation(List<ProtectedRegion> regions) {
return association;
}
@@ -22,17 +22,19 @@ package com.sk89q.worldguard.protection.association;
import com.sk89q.worldguard.domains.Association;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import java.util.List;
/**
* An object that can have membership in a region.
*/
public interface RegionAssociable {
/**
* Get the most specific association level for the input region.
* Get the highest association level for the input regions.
*
* @param region the input region
* @return the most specific membership level
* @param regions a list of regions
* @return the highest membership level
*/
Association getAssociation(ProtectedRegion region);
Association getAssociation(List<ProtectedRegion> regions);
}
@@ -22,6 +22,7 @@ package com.sk89q.worldguard.protection.association;
import com.sk89q.worldguard.domains.Association;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import java.util.List;
import java.util.Set;
import static com.google.common.base.Preconditions.checkNotNull;
@@ -45,12 +46,14 @@ public class RegionOverlapAssociation implements RegionAssociable {
}
@Override
public Association getAssociation(ProtectedRegion region) {
if (source.contains(region)) {
return Association.OWNER;
} else {
return Association.NON_MEMBER;
public Association getAssociation(List<ProtectedRegion> regions) {
for (ProtectedRegion region : regions) {
if ((region.getId().equals(ProtectedRegion.GLOBAL_REGION) && source.isEmpty()) || source.contains(region)) {
return Association.OWNER;
}
}
return Association.NON_MEMBER;
}
}
@@ -24,8 +24,7 @@ import org.bukkit.command.CommandSender;
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
/**
*
* @author sk89q
* A boolean flag.
*/
public class BooleanFlag extends Flag<Boolean> {
@@ -38,8 +37,7 @@ public class BooleanFlag extends Flag<Boolean> {
}
@Override
public Boolean parseInput(WorldGuardPlugin plugin, CommandSender sender,
String input) throws InvalidFlagFormat {
public Boolean parseInput(WorldGuardPlugin plugin, CommandSender sender, String input) throws InvalidFlagFormat {
input = input.trim();
if (input.equalsIgnoreCase("true") || input.equalsIgnoreCase("yes")
@@ -0,0 +1,52 @@
/*
* 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;
/**
* A special implementation of the {@link StateFlag} for
* {@link DefaultFlag#BUILD}.
*/
class BuildFlag extends StateFlag {
public BuildFlag(String name, boolean def) {
super(name, def);
}
@Override
public boolean implicitlySetWithMembership() {
return true;
}
@Override
public boolean usesMembershipAsDefault() {
return true;
}
@Override
public boolean preventsAllowOnGlobal() {
return true;
}
@Override
public boolean requiresSubject() {
return true;
}
}
@@ -24,8 +24,7 @@ import org.bukkit.command.CommandSender;
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
/**
*
* @author sk89q
* Stores a command/
*/
public class CommandStringFlag extends Flag<String> {
@@ -38,8 +37,7 @@ public class CommandStringFlag extends Flag<String> {
}
@Override
public String parseInput(WorldGuardPlugin plugin, CommandSender sender,
String input) throws InvalidFlagFormat {
public String parseInput(WorldGuardPlugin plugin, CommandSender sender, String input) throws InvalidFlagFormat {
input = input.trim();
if (!input.startsWith("/")) {
input = "/" + input;
@@ -21,6 +21,7 @@ package com.sk89q.worldguard.protection.flags;
import org.bukkit.ChatColor;
import org.bukkit.GameMode;
import org.bukkit.WeatherType;
import org.bukkit.entity.EntityType;
/**
@@ -39,7 +40,7 @@ public final class DefaultFlag {
public static final RegionGroupFlag CONSTRUCT = new RegionGroupFlag("construct", RegionGroup.MEMBERS);
// This flag is unlike the others. It forces the checking of region membership
public static final StateFlag BUILD = new StateFlag("build", true);
public static final StateFlag BUILD = new BuildFlag("build", true);
// These flags are used in tandem with the BUILD flag - if the player can
// build, then the following flags do not need to be checked (although they
@@ -48,6 +49,7 @@ public final class DefaultFlag {
public static final StateFlag BLOCK_PLACE = new StateFlag("block-place", false);
public static final StateFlag USE = new StateFlag("use", false);
public static final StateFlag INTERACT = new StateFlag("interact", false);
public static final StateFlag DAMAGE_ANIMALS = new StateFlag("damage-animals", false);
public static final StateFlag PVP = new StateFlag("pvp", false);
public static final StateFlag SLEEP = new StateFlag("sleep", false);
public static final StateFlag TNT = new StateFlag("tnt", false);
@@ -100,16 +102,25 @@ public final class DefaultFlag {
public static final StateFlag ENDERPEARL = new StateFlag("enderpearl", true);
public static final StateFlag ENTITY_PAINTING_DESTROY = new StateFlag("entity-painting-destroy", true);
public static final StateFlag ENTITY_ITEM_FRAME_DESTROY = new StateFlag("entity-item-frame-destroy", true);
public static final StateFlag FALL_DAMAGE = new StateFlag("fall-damage", true);
// Flags that adjust behaviors that aren't state flags
public static final StringFlag DENY_MESSAGE = new StringFlag("deny-message",
"" + ChatColor.RED + ChatColor.BOLD + "Hey!" + ChatColor.GRAY + " Sorry, but you can't %what% here.");
public static final StringFlag ENTRY_DENY_MESSAGE = new StringFlag("entry-deny-message",
"" + ChatColor.RED + ChatColor.BOLD + "Hey!" + ChatColor.GRAY + " You are not permitted to enter this area.");
public static final StringFlag EXIT_DENY_MESSAGE = new StringFlag("exit-deny-message",
"" + ChatColor.RED + ChatColor.BOLD + "Hey!" + ChatColor.GRAY + " You are not permitted to leave this area.");
public static final BooleanFlag EXIT_OVERRIDE = new BooleanFlag("exit-override");
public static final StateFlag EXIT_VIA_TELEPORT = new StateFlag("exit-via-teleport", true);
public static final StringFlag GREET_MESSAGE = new StringFlag("greeting");
public static final StringFlag FAREWELL_MESSAGE = new StringFlag("farewell");
public static final BooleanFlag NOTIFY_ENTER = new BooleanFlag("notify-enter");
public static final BooleanFlag NOTIFY_LEAVE = new BooleanFlag("notify-leave");
public static final SetFlag<EntityType> DENY_SPAWN = new SetFlag<EntityType>("deny-spawn", new EntityTypeFlag(null));
public static final EnumFlag<GameMode> GAME_MODE = new EnumFlag<GameMode>("game-mode", GameMode.class);
public static final StringFlag TIME_LOCK = new StringFlag("time-lock");
public static final EnumFlag<WeatherType> WEATHER_LOCK = new EnumFlag<WeatherType>("weather-lock", WeatherType.class);
public static final IntegerFlag HEAL_DELAY = new IntegerFlag("heal-delay");
public static final IntegerFlag HEAL_AMOUNT = new IntegerFlag("heal-amount");
public static final DoubleFlag MIN_HEAL = new DoubleFlag("heal-min-health");
@@ -130,18 +141,19 @@ public final class DefaultFlag {
public static final Flag<?>[] flagsList = new Flag<?>[] {
PASSTHROUGH, BUILD, CONSTRUCT, BLOCK_BREAK, BLOCK_PLACE, PVP, CHEST_ACCESS, PISTONS,
TNT, LIGHTER, RIDE, USE, INTERACT, PLACE_VEHICLE, DESTROY_VEHICLE, SLEEP,
TNT, LIGHTER, RIDE, USE, INTERACT, PLACE_VEHICLE, DESTROY_VEHICLE, DAMAGE_ANIMALS, SLEEP,
MOB_DAMAGE, MOB_SPAWNING, DENY_SPAWN, INVINCIBILITY, EXP_DROPS,
CREEPER_EXPLOSION, OTHER_EXPLOSION, ENDERDRAGON_BLOCK_DAMAGE, GHAST_FIREBALL, ENDER_BUILD,
DENY_MESSAGE, GREET_MESSAGE, FAREWELL_MESSAGE, NOTIFY_ENTER, NOTIFY_LEAVE,
DENY_MESSAGE, ENTRY_DENY_MESSAGE, EXIT_DENY_MESSAGE, EXIT_OVERRIDE, EXIT_VIA_TELEPORT,
GREET_MESSAGE, FAREWELL_MESSAGE, NOTIFY_ENTER, NOTIFY_LEAVE,
EXIT, ENTRY, LIGHTNING, ENTITY_PAINTING_DESTROY, ENDERPEARL,
ENTITY_ITEM_FRAME_DESTROY, ITEM_PICKUP, ITEM_DROP, /*MAX_PLAYERS, MAX_PLAYERS_MESSAGE,*/
ENTITY_ITEM_FRAME_DESTROY, FALL_DAMAGE, ITEM_PICKUP, ITEM_DROP, /*MAX_PLAYERS, MAX_PLAYERS_MESSAGE,*/
HEAL_AMOUNT, HEAL_DELAY, MIN_HEAL, MAX_HEAL,
FEED_DELAY, FEED_AMOUNT, MIN_FOOD, MAX_FOOD,
SNOW_FALL, SNOW_MELT, ICE_FORM, ICE_MELT, SOIL_DRY, GAME_MODE,
MUSHROOMS, LEAF_DECAY, GRASS_SPREAD, MYCELIUM_SPREAD, VINE_GROWTH,
SEND_CHAT, RECEIVE_CHAT, FIRE_SPREAD, LAVA_FIRE, LAVA_FLOW, WATER_FLOW,
TELE_LOC, SPAWN_LOC, POTION_SPLASH,
TELE_LOC, SPAWN_LOC, POTION_SPLASH, TIME_LOCK, WEATHER_LOCK,
BLOCKED_CMDS, ALLOWED_CMDS, PRICE, BUYABLE, ENABLE_SHOP
};
@@ -24,8 +24,7 @@ import org.bukkit.command.CommandSender;
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
/**
*
* @author sk89q
* Stores doubles.
*/
public class DoubleFlag extends Flag<Double> {
@@ -38,8 +37,7 @@ public class DoubleFlag extends Flag<Double> {
}
@Override
public Double parseInput(WorldGuardPlugin plugin, CommandSender sender,
String input) throws InvalidFlagFormat {
public Double parseInput(WorldGuardPlugin plugin, CommandSender sender, String input) throws InvalidFlagFormat {
input = input.trim();
try {
@@ -22,9 +22,7 @@ package com.sk89q.worldguard.protection.flags;
import org.bukkit.entity.EntityType;
/**
* Represents an entity type.
*
* @author sk89q
* Stores an entity type.
*/
public class EntityTypeFlag extends EnumFlag<EntityType> {
@@ -24,8 +24,7 @@ import org.bukkit.command.CommandSender;
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
/**
*
* @author sk89q
* Stores an enum value.
*/
public class EnumFlag<T extends Enum<T>> extends Flag<T> {
@@ -79,8 +78,7 @@ public class EnumFlag<T extends Enum<T>> extends Flag<T> {
}
@Override
public T parseInput(WorldGuardPlugin plugin, CommandSender sender,
String input) throws InvalidFlagFormat {
public T parseInput(WorldGuardPlugin plugin, CommandSender sender, String input) throws InvalidFlagFormat {
try {
return findValue(input);
} catch (IllegalArgumentException e) {
@@ -20,33 +20,45 @@
package com.sk89q.worldguard.protection.flags;
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
import com.sk89q.worldguard.protection.FlagValueCalculator;
import org.bukkit.command.CommandSender;
import javax.annotation.Nullable;
import java.util.Collection;
/**
*
* @author sk89q
* @param <T>
* A flag carries extra data on a region.
*/
public abstract class Flag<T> {
private String name;
private RegionGroupFlag regionGroup;
public Flag(String name, RegionGroup defaultGroup) {
this.name = name;
private final String name;
private final RegionGroupFlag regionGroup;
if (defaultGroup != null) {
this.regionGroup = new RegionGroupFlag(name + "-group", defaultGroup);
}
/**
* Create a new flag.
*
* @param name The name of the flag
* @param defaultGroup The default group
*/
public Flag(String name, @Nullable RegionGroup defaultGroup) {
this.name = name;
this.regionGroup = defaultGroup != null ? new RegionGroupFlag(name + "-group", defaultGroup) : null;
}
/**
* Create a new flag with {@link RegionGroup#ALL} as the default group.
*
* @param name The name of the flag
*/
public Flag(String name) {
this(name, RegionGroup.ALL);
}
/**
* Get the name of the flag.
*
* @return The name of the flag
*/
public String getName() {
return name;
}
@@ -54,7 +66,7 @@ public abstract class Flag<T> {
/**
* Get the default value.
*
* @return the default value, if one exists, otherwise {@code null} may be returned
* @return The default value, if one exists, otherwise {@code null} may be returned
*/
@Nullable
public T getDefault() {
@@ -69,15 +81,101 @@ public abstract class Flag<T> {
return null;
}
}
/**
* Whether the flag can take a list of values and choose a "best one."
*
* <p>This is the case with the {@link StateFlag} where {@code DENY}
* overrides {@code ALLOW}, but most flags just return the
* first result from a list.</p>
*
* <p>This flag is primarily used to optimize flag lookup in
* {@link FlagValueCalculator}.</p>
*
* @return Whether a best value can be chosen
*/
public boolean hasConflictStrategy() {
return false;
}
/**
* Whether the flag implicitly has a value set as long as
* {@link DefaultFlag#PASSTHROUGH} is not set.
*
* <p>This value is only changed, at least in WorldGuard, for the
* {@link DefaultFlag#BUILD} flag.</p>
*
* @return Whether the flag is ignored
*/
public boolean implicitlySetWithMembership() {
return false;
}
/**
* Whether, if the flag is not set at all, the value should be derived
* from membership.
*
* <p>This value is only changed, at least in WorldGuard, for the
* {@link DefaultFlag#BUILD} flag.</p>
*
* @return Whether membership is used
*/
public boolean usesMembershipAsDefault() {
return false;
}
/**
* Whether the flag requires that a subject is specified in
* {@link FlagValueCalculator}.
*
* <p>This value is only changed, at least in WorldGuard, for the
* {@link DefaultFlag#BUILD} flag.</p>
*
* @return Whether a subject is required
*/
public boolean requiresSubject() {
return false;
}
/**
* Get the region group flag.
*
* <p>Every group has a region group flag except for region group flags
* themselves.</p>
*
* @return The region group flag
*/
public RegionGroupFlag getRegionGroupFlag() {
return regionGroup;
}
/**
* Parse a given input to coerce it to a type compatible with the flag.
*
* @param plugin The plugin
* @param sender The sender
* @param input THe input
* @return The coerced type
* @throws InvalidFlagFormat Raised if the input is invalid
*/
public abstract T parseInput(WorldGuardPlugin plugin, CommandSender sender, String input) throws InvalidFlagFormat;
/**
* Convert a raw type that was loaded (from a YAML file, for example)
* into the type that this flag uses.
*
* @param o The object
* @return The unmarshalled type
*/
public abstract T unmarshal(@Nullable Object o);
/**
* Convert the value stored for this flag into a type that can be
* serialized into YAML.
*
* @param o The object
* @return The marshalled type
*/
public abstract Object marshal(T o);
@Override
@@ -24,8 +24,7 @@ import org.bukkit.command.CommandSender;
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
/**
*
* @author sk89q
* Stores an integer.
*/
public class IntegerFlag extends Flag<Integer> {
@@ -38,8 +37,7 @@ public class IntegerFlag extends Flag<Integer> {
}
@Override
public Integer parseInput(WorldGuardPlugin plugin, CommandSender sender,
String input) throws InvalidFlagFormat {
public Integer parseInput(WorldGuardPlugin plugin, CommandSender sender,String input) throws InvalidFlagFormat {
input = input.trim();
try {
@@ -27,6 +27,9 @@ import org.bukkit.Bukkit;
import javax.annotation.Nullable;
/**
* A location that stores the name of the world in case the world is unloaded.
*/
class LazyLocation extends Location {
private final String worldName;
@@ -66,6 +69,4 @@ class LazyLocation extends Location {
return this.setPosition(getPosition().add(x, y, z));
}
}
@@ -26,8 +26,7 @@ import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import javax.annotation.Nullable;
/**
*
* @author sk89q
* Stores a region group.
*/
public class RegionGroupFlag extends EnumFlag<RegionGroup> {
@@ -19,6 +19,7 @@
package com.sk89q.worldguard.protection.flags;
import com.google.common.collect.Sets;
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
import org.bukkit.command.CommandSender;
@@ -29,9 +30,7 @@ import java.util.List;
import java.util.Set;
/**
* Represents a flag that consists of a set.
*
* @author sk89q
* Stores a set of types.
*/
public class SetFlag<T> extends Flag<Set<T>> {
@@ -57,15 +56,18 @@ public class SetFlag<T> extends Flag<Set<T>> {
}
@Override
public Set<T> parseInput(WorldGuardPlugin plugin, CommandSender sender,
String input) throws InvalidFlagFormat {
Set<T> items = new HashSet<T>();
public Set<T> parseInput(WorldGuardPlugin plugin, CommandSender sender, String input) throws InvalidFlagFormat {
if (input.isEmpty()) {
return Sets.newHashSet();
} else {
Set<T> items = Sets.newHashSet();
for (String str : input.split(",")) {
items.add(subFlag.parseInput(plugin, sender, str.trim()));
for (String str : input.split(",")) {
items.add(subFlag.parseInput(plugin, sender, str.trim()));
}
return items;
}
return new HashSet<T>(items);
}
@Override
@@ -26,8 +26,7 @@ import javax.annotation.Nullable;
import java.util.Collection;
/**
*
* @author sk89q
* Stores a bi-state value.
*/
public class StateFlag extends Flag<StateFlag.State> {
@@ -53,6 +52,11 @@ public class StateFlag extends Flag<StateFlag.State> {
return def ? State.ALLOW : null;
}
@Override
public boolean hasConflictStrategy() {
return true;
}
@Override
@Nullable
public State chooseValue(Collection<State> values) {
@@ -63,9 +67,21 @@ public class StateFlag extends Flag<StateFlag.State> {
}
}
/**
* Whether setting this flag to {@link State#ALLOW} is prevented on
* the global region.
*
* <p>This value is only changed, at least in WorldGuard, for the
* {@link DefaultFlag#BUILD} flag.</p>
*
* @return Whether {@code ALLOW} is prevented
*/
public boolean preventsAllowOnGlobal() {
return false;
}
@Override
public State parseInput(WorldGuardPlugin plugin, CommandSender sender,
String input) throws InvalidFlagFormat {
public State parseInput(WorldGuardPlugin plugin, CommandSender sender, String input) throws InvalidFlagFormat {
input = input.trim();
if (input.equalsIgnoreCase("allow")) {
@@ -26,8 +26,7 @@ import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
import javax.annotation.Nullable;
/**
*
* @author sk89q
* Stores a string.
*/
public class StringFlag extends Flag<String> {
@@ -60,8 +59,7 @@ public class StringFlag extends Flag<String> {
}
@Override
public String parseInput(WorldGuardPlugin plugin, CommandSender sender,
String input) throws InvalidFlagFormat {
public String parseInput(WorldGuardPlugin plugin, CommandSender sender, String input) throws InvalidFlagFormat {
return input.replaceAll("(?!\\\\)\\\\n", "\n").replaceAll("\\\\\\\\n", "\\n");
}
@@ -19,19 +19,17 @@
package com.sk89q.worldguard.protection.flags;
import java.util.HashMap;
import java.util.Map;
import org.bukkit.command.CommandSender;
import com.sk89q.minecraft.util.commands.CommandException;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldguard.bukkit.BukkitUtil;
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
import org.bukkit.command.CommandSender;
import java.util.HashMap;
import java.util.Map;
/**
*
* @author sk89q
* Stores a vector.
*/
public class VectorFlag extends Flag<Vector> {
@@ -21,6 +21,7 @@ package com.sk89q.worldguard.protection.managers;
import com.google.common.base.Predicate;
import com.google.common.base.Supplier;
import com.google.common.collect.Sets;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.Vector2D;
import com.sk89q.worldguard.LocalPlayer;
@@ -317,7 +318,7 @@ public final class RegionManager {
public ApplicableRegionSet getApplicableRegions(Vector position) {
checkNotNull(position);
List<ProtectedRegion> regions = new ArrayList<ProtectedRegion>();
Set<ProtectedRegion> regions = Sets.newHashSet();
index.applyContaining(position, new RegionCollectionConsumer(regions, true));
return new RegionResultSet(regions, index.get("__global__"));
}
@@ -332,7 +333,7 @@ public final class RegionManager {
public ApplicableRegionSet getApplicableRegions(ProtectedRegion region) {
checkNotNull(region);
List<ProtectedRegion> regions = new ArrayList<ProtectedRegion>();
Set<ProtectedRegion> regions = Sets.newHashSet();
index.applyIntersecting(region, new RegionCollectionConsumer(regions, true));
return new RegionResultSet(regions, index.get("__global__"));
}
@@ -441,7 +442,7 @@ public final class RegionManager {
* @return an {@code ApplicableRegionSet}
*/
public ApplicableRegionSet getApplicableRegions(org.bukkit.Location loc) {
return getApplicableRegions(com.sk89q.worldedit.bukkit.BukkitUtil.toVector(loc));
return getApplicableRegions(com.sk89q.worldedit.bukkit.BukkitUtil.toVector(loc).floor());
}
}
@@ -23,8 +23,10 @@ import com.sk89q.worldedit.BlockVector;
import com.sk89q.worldedit.BlockVector2D;
import com.sk89q.worldedit.Vector;
import java.awt.geom.Area;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
/**
@@ -47,6 +49,11 @@ public class GlobalProtectedRegion extends ProtectedRegion {
max = new BlockVector(0, 0, 0);
}
@Override
public boolean isPhysicalArea() {
return false;
}
@Override
public List<BlockVector2D> getPoints() {
// This doesn't make sense
@@ -74,7 +81,12 @@ public class GlobalProtectedRegion extends ProtectedRegion {
@Override
public List<ProtectedRegion> getIntersectingRegions(Collection<ProtectedRegion> regions) {
// Global regions are handled separately so it must not contain any positions
return new ArrayList<ProtectedRegion>();
return Collections.emptyList();
}
@Override
Area toArea() {
return null;
}
}
@@ -24,8 +24,9 @@ import com.sk89q.worldedit.BlockVector2D;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldguard.util.MathUtils;
import java.awt.*;
import java.awt.geom.Area;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import static com.google.common.base.Preconditions.checkNotNull;
@@ -83,6 +84,11 @@ public class ProtectedCuboidRegion extends ProtectedRegion {
setMinMaxPoints(min, position);
}
@Override
public boolean isPhysicalArea() {
return true;
}
@Override
public List<BlockVector2D> getPoints() {
List<BlockVector2D> pts = new ArrayList<BlockVector2D>();
@@ -115,30 +121,21 @@ public class ProtectedCuboidRegion extends ProtectedRegion {
}
@Override
public List<ProtectedRegion> getIntersectingRegions(Collection<ProtectedRegion> regions) {
checkNotNull(regions);
Area toArea() {
int x = getMinimumPoint().getBlockX();
int z = getMinimumPoint().getBlockZ();
int width = getMaximumPoint().getBlockX() - x;
int height = getMaximumPoint().getBlockZ() - z;
return new Area(new Rectangle(x, z, width, height));
}
List<ProtectedRegion> intersectingRegions = new ArrayList<ProtectedRegion>();
for (ProtectedRegion region : regions) {
if (!intersectsBoundingBox(region)) continue;
// If both regions are Cuboids and their bounding boxes intersect, they intersect
if (region instanceof ProtectedCuboidRegion) {
intersectingRegions.add(region);
} else if (region instanceof ProtectedPolygonalRegion) {
// If either region contains the points of the other,
// or if any edges intersect, the regions intersect
if (containsAny(region.getPoints()) || region.containsAny(getPoints()) || intersectsEdges(region)) {
intersectingRegions.add(region);
}
} else if (region instanceof GlobalProtectedRegion) {
// Never intersects
} else {
throw new IllegalArgumentException("Not supported yet.");
}
@Override
protected boolean intersects(ProtectedRegion region, Area thisArea) {
if (region instanceof ProtectedCuboidRegion) {
return intersectsBoundingBox(region);
} else {
return super.intersects(region, thisArea);
}
return intersectingRegions;
}
@Override
@@ -19,25 +19,28 @@
package com.sk89q.worldguard.protection.regions;
import com.google.common.collect.ImmutableList;
import com.sk89q.worldedit.BlockVector2D;
import com.sk89q.worldedit.Vector;
import java.awt.*;
import java.awt.geom.Area;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import static com.google.common.base.Preconditions.checkNotNull;
public class ProtectedPolygonalRegion extends ProtectedRegion {
private List<BlockVector2D> points;
private int minY;
private int maxY;
private final ImmutableList<BlockVector2D> points;
private final int minY;
private final int maxY;
public ProtectedPolygonalRegion(String id, List<BlockVector2D> points, int minY, int maxY) {
super(id);
setMinMaxPoints(points, minY, maxY);
this.points = points;
ImmutableList<BlockVector2D> immutablePoints = ImmutableList.copyOf(points);
setMinMaxPoints(immutablePoints, minY, maxY);
this.points = immutablePoints;
this.minY = min.getBlockY();
this.maxY = max.getBlockY();
}
@@ -61,6 +64,11 @@ public class ProtectedPolygonalRegion extends ProtectedRegion {
setMinMaxPoints(points);
}
@Override
public boolean isPhysicalArea() {
return true;
}
@Override
public List<BlockVector2D> getPoints() {
return points;
@@ -133,27 +141,21 @@ public class ProtectedPolygonalRegion extends ProtectedRegion {
}
@Override
public List<ProtectedRegion> getIntersectingRegions(Collection<ProtectedRegion> regions) {
checkNotNull(regions);
Area toArea() {
List<BlockVector2D> points = getPoints();
int numPoints = points.size();
int[] xCoords = new int[numPoints];
int[] yCoords = new int[numPoints];
List<ProtectedRegion> intersectingRegions = new ArrayList<ProtectedRegion>();
for (ProtectedRegion region : regions) {
if (!intersectsBoundingBox(region)) continue;
if (region instanceof ProtectedPolygonalRegion || region instanceof ProtectedCuboidRegion) {
// If either region contains the points of the other,
// or if any edges intersect, the regions intersect
if (containsAny(region.getPoints()) || region.containsAny(getPoints()) || intersectsEdges(region)) {
intersectingRegions.add(region);
}
} else if (region instanceof GlobalProtectedRegion) {
// Never intersects
} else {
throw new IllegalArgumentException("Not supported yet.");
}
int i = 0;
for (BlockVector2D point : points) {
xCoords[i] = point.getBlockX();
yCoords[i] = point.getBlockZ();
i++;
}
return intersectingRegions;
Polygon polygon = new Polygon(xCoords, yCoords, numPoints);
return new Area(polygon);
}
@Override
@@ -19,6 +19,7 @@
package com.sk89q.worldguard.protection.regions;
import com.google.common.collect.Lists;
import com.sk89q.worldedit.BlockVector;
import com.sk89q.worldedit.BlockVector2D;
import com.sk89q.worldedit.Vector;
@@ -29,6 +30,7 @@ import com.sk89q.worldguard.util.ChangeTracked;
import com.sk89q.worldguard.util.Normal;
import javax.annotation.Nullable;
import java.awt.geom.Area;
import java.awt.geom.Line2D;
import java.util.Collection;
import java.util.List;
@@ -118,6 +120,13 @@ public abstract class ProtectedRegion implements ChangeTracked, Comparable<Prote
return id;
}
/**
* Return whether this type of region encompasses physical area.
*
* @return Whether physical area is encompassed
*/
public abstract boolean isPhysicalArea();
/**
* Get a vector containing the smallest X, Y, and Z components for the
* corner of the axis-aligned bounding box that contains this region.
@@ -224,7 +233,7 @@ public abstract class ProtectedRegion implements ChangeTracked, Comparable<Prote
public void setOwners(DefaultDomain owners) {
checkNotNull(owners);
setDirty(true);
this.owners = owners;
this.owners = new DefaultDomain(owners);
}
/**
@@ -245,7 +254,7 @@ public abstract class ProtectedRegion implements ChangeTracked, Comparable<Prote
public void setMembers(DefaultDomain members) {
checkNotNull(members);
setDirty(true);
this.members = members;
this.members = new DefaultDomain(members);
}
/**
@@ -570,7 +579,39 @@ public abstract class ProtectedRegion implements ChangeTracked, Comparable<Prote
* @param regions a list of regions to source from
* @return the elements of {@code regions} that intersect with this region
*/
public abstract List<ProtectedRegion> getIntersectingRegions(Collection<ProtectedRegion> regions);
public List<ProtectedRegion> getIntersectingRegions(Collection<ProtectedRegion> regions) {
checkNotNull(regions, "regions");
List<ProtectedRegion> intersecting = Lists.newArrayList();
Area thisArea = toArea();
for (ProtectedRegion region : regions) {
if (!region.isPhysicalArea()) continue;
if (intersects(region, thisArea)) {
intersecting.add(region);
}
}
return intersecting;
}
/**
* Test whether the given region intersects with this area.
*
* @param region the region to test
* @param thisArea an area object for this region
* @return true if the two regions intersect
*/
protected boolean intersects(ProtectedRegion region, Area thisArea) {
if (intersectsBoundingBox(region)) {
Area testArea = region.toArea();
testArea.intersect(thisArea);
return !testArea.isEmpty();
} else {
return false;
}
}
/**
* Checks if the bounding box of a region intersects with with the bounding
@@ -631,6 +672,14 @@ public abstract class ProtectedRegion implements ChangeTracked, Comparable<Prote
return false;
}
/**
* Return the AWT area, otherwise null if
* {@link #isPhysicalArea()} if false.
*
* @return The shape version
*/
abstract Area toArea();
@Override
public boolean isDirty() {
return dirty || owners.isDirty() || members.isDirty();
@@ -0,0 +1,144 @@
/*
* 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.util;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.sk89q.worldguard.protection.ApplicableRegionSet;
import com.sk89q.worldguard.protection.FlagValueCalculator;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import javax.annotation.Nullable;
import java.util.*;
/**
* Sorts a list of regions so that higher priority regions always take
* precedence over lower priority ones, and after sorting by priority, so
* child regions always take priority over their parent regions.
*
* <p>For example, if the regions are a, aa, aaa, aab, aac, b, ba, bc, where
* aa implies that the second 'a' is a child of the first 'a', the sorted
* order must reflect the following properties (where regions on the
* left of &lt; appear before in the sorted list):</p>
*
* <ul>
* <li>[aaa, aab, aac] < aa < a</li>
* <li>[ba, bc] < b</li>
* </ul>
*
* <p>In the case of "[aaa, aab, aac]," the relative order between these
* regions is unimportant as they all share the same parent (aaa). The
* following choices would be valid sorts:</p>
*
* <ul>
* <li>aaa, aab, aac, aa, a, ba, bc, b</li>
* <li>aab, aaa, aac, aa, a, bc, ba, b</li>
* <li>bc, ba, b, aab, aaa, aac, aa, a</li>
* <li>aab, aaa, bc, aac, aa, ba, a, b</li>
* </ul>
*
* <p>These sorted lists are required for {@link FlagValueCalculator} and
* some implementations of {@link ApplicableRegionSet}.</p>
*/
public final class NormativeOrders {
private static final PriorityComparator PRIORITY_COMPARATOR = new PriorityComparator();
private NormativeOrders() {
}
public static void sort(List<ProtectedRegion> regions) {
sortInto(Sets.newHashSet(regions), regions);
}
public static List<ProtectedRegion> fromSet(Set<ProtectedRegion> regions) {
List<ProtectedRegion> sorted = Arrays.asList(new ProtectedRegion[regions.size()]);
sortInto(regions, sorted);
return sorted;
}
private static void sortInto(Set<ProtectedRegion> regions, List<ProtectedRegion> sorted) {
List<RegionNode> root = Lists.newArrayList();
Map<ProtectedRegion, RegionNode> nodes = Maps.newHashMap();
for (ProtectedRegion region : regions) {
addNode(nodes, root, region);
}
int index = regions.size() - 1;
for (RegionNode node : root) {
while (node != null) {
if (regions.contains(node.region)) {
sorted.set(index, node.region);
index--;
}
node = node.next;
}
}
Collections.sort(sorted, PRIORITY_COMPARATOR);
}
private static RegionNode addNode(Map<ProtectedRegion, RegionNode> nodes, List<RegionNode> root, ProtectedRegion region) {
RegionNode node = nodes.get(region);
if (node == null) {
node = new RegionNode(region);
nodes.put(region, node);
if (region.getParent() != null) {
addNode(nodes, root, region.getParent()).insertAfter(node);
} else {
root.add(node);
}
}
return node;
}
private static class RegionNode {
@Nullable private RegionNode next;
private final ProtectedRegion region;
private RegionNode(ProtectedRegion region) {
this.region = region;
}
private void insertAfter(RegionNode node) {
if (this.next == null) {
this.next = node;
} else {
node.next = this.next;
this.next = node;
}
}
}
private static class PriorityComparator implements Comparator<ProtectedRegion> {
@Override
public int compare(ProtectedRegion o1, ProtectedRegion o2) {
if (o1.getPriority() > o2.getPriority()) {
return -1;
} else if (o1.getPriority() < o2.getPriority()) {
return 1;
} else {
return 0;
}
}
}
}
@@ -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.session;
import org.bukkit.Location;
/**
* Types of movements.
*
* <p>Used with {@link Session#testMoveTo(Location, MoveType)}.</p>
*/
public enum MoveType {
RESPAWN(false, true),
EMBARK(true, false),
MOVE(true, false),
TELEPORT(true, true),
RIDE(true, false),
OTHER_NON_CANCELLABLE(false, false),
OTHER_CANCELLABLE(true, false);
private final boolean cancellable;
private final boolean teleport;
MoveType(boolean cancellable, boolean teleport) {
this.cancellable = cancellable;
this.teleport = teleport;
}
public boolean isCancellable() {
return cancellable;
}
public boolean isTeleport() {
return teleport;
}
}
@@ -0,0 +1,229 @@
/*
* 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.session;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.sk89q.worldguard.bukkit.RegionQuery;
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
import com.sk89q.worldguard.bukkit.util.Locations;
import com.sk89q.worldguard.protection.ApplicableRegionSet;
import com.sk89q.worldguard.protection.flags.StateFlag.State;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import com.sk89q.worldguard.session.handler.Handler;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import javax.annotation.Nullable;
import java.util.HashMap;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Keeps session information on a player.
*/
public class Session {
private final SessionManager manager;
private final HashMap<Class<?>, Handler> handlers = Maps.newLinkedHashMap();
private Location lastValid;
private Set<ProtectedRegion> lastRegionSet;
private final AtomicBoolean needRefresh = new AtomicBoolean(false);
/**
* Create a new session.
*
* @param manager The session manager
*/
public Session(SessionManager manager) {
checkNotNull(manager, "manager");
this.manager = manager;
}
/**
* Register a new handler.
*
* @param handler A new handler
*/
void register(Handler handler) {
handlers.put(handler.getClass(), handler);
}
/**
* Get the plugin.
*
* @return The plugin
*/
public WorldGuardPlugin getPlugin() {
return getManager().getPlugin();
}
/**
* Get the session manager.
*
* @return The session manager
*/
public SessionManager getManager() {
return manager;
}
/**
* Get a handler by class, if has been registered.
*
* @param type The type of handler
* @param <T> The type of handler
* @return A handler instance, otherwise null
*/
@Nullable
@SuppressWarnings("unchecked")
public <T extends Handler> T getHandler(Class<T> type) {
return (T) handlers.get(type);
}
/**
* Initialize the session.
*
* @param player The player
*/
void initialize(Player player) {
RegionQuery query = getManager().getPlugin().getRegionContainer().createQuery();
Location location = player.getLocation();
ApplicableRegionSet set = query.getApplicableRegions(location);
lastValid = location;
lastRegionSet = set.getRegions();
for (Handler handler : handlers.values()) {
handler.initialize(player, location, set);
}
}
/**
* Tick the session.
*
* @param player The player
*/
void tick(Player player) {
RegionQuery query = getManager().getPlugin().getRegionContainer().createQuery();
Location location = player.getLocation();
ApplicableRegionSet set = query.getApplicableRegions(location);
for (Handler handler : handlers.values()) {
handler.tick(player, set);
}
}
/**
* Re-initialize the session.
*
* @param player The player
*/
void resetState(Player player) {
initialize(player);
needRefresh.set(true);
}
/**
* Test whether the session has invincibility enabled.
*
* @return Whether invincibility is enabled
*/
public boolean isInvincible(Player player) {
boolean invincible = false;
for (Handler handler : handlers.values()) {
State state = handler.getInvincibility(player);
if (state != null) {
switch (state) {
case DENY: return false;
case ALLOW: invincible = true;
}
}
}
return invincible;
}
/**
* Test movement to the given location.
*
* @param player The player
* @param to The new location
* @param moveType The type of move
* @return The overridden location, if the location is being overridden
* @see #testMoveTo(Player, Location, MoveType, boolean) For an explanation
*/
@Nullable
public Location testMoveTo(Player player, Location to, MoveType moveType) {
return testMoveTo(player, to, moveType, false);
}
/**
* Test movement to the given location.
*
* <p>If a non-null {@link Location} is returned, the player should be
* at that location instead of where the player has tried to move to.</p>
*
* <p>If the {@code moveType} is cancellable
* ({@link MoveType#isCancellable()}, then the last valid location will
* be set to the given one.</p>
*
* @param player The player
* @param to The new location
* @param moveType The type of move
* @param forced Whether to force a check
* @return The overridden location, if the location is being overridden
*/
@Nullable
public Location testMoveTo(Player player, Location to, MoveType moveType, boolean forced) {
RegionQuery query = getManager().getPlugin().getRegionContainer().createQuery();
if (!forced && needRefresh.getAndSet(false)) {
forced = true;
}
if (forced || Locations.isDifferentBlock(lastValid, to)) {
ApplicableRegionSet toSet = query.getApplicableRegions(to);
for (Handler handler : handlers.values()) {
if (!handler.testMoveTo(player, lastValid, to, toSet, moveType) && moveType.isCancellable()) {
return lastValid;
}
}
Set<ProtectedRegion> entered = Sets.difference(toSet.getRegions(), lastRegionSet);
Set<ProtectedRegion> exited = Sets.difference(lastRegionSet, toSet.getRegions());
for (Handler handler : handlers.values()) {
if (!handler.onCrossBoundary(player, lastValid, to, toSet, entered, exited, moveType) && moveType.isCancellable()) {
return lastValid;
}
}
lastValid = to;
lastRegionSet = toSet.getRegions();
}
return null;
}
}
@@ -0,0 +1,221 @@
/*
* 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.session;
import com.sk89q.guavabackport.cache.CacheBuilder;
import com.sk89q.guavabackport.cache.CacheLoader;
import com.sk89q.guavabackport.cache.LoadingCache;
import com.sk89q.worldguard.bukkit.BukkitUtil;
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
import com.sk89q.worldguard.session.handler.*;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import javax.annotation.Nullable;
import java.lang.ref.WeakReference;
import java.util.Collection;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Keeps tracks of sessions and also does session-related handling
* (flags, etc.).
*/
public class SessionManager implements Runnable, Listener {
public static final int RUN_DELAY = 20;
public static final long SESSION_LIFETIME = 10;
private final WorldGuardPlugin plugin;
private final LoadingCache<WorldPlayerTuple, Boolean> bypassCache = CacheBuilder.newBuilder()
.maximumSize(1000)
.expireAfterAccess(2, TimeUnit.SECONDS)
.build(new CacheLoader<WorldPlayerTuple, Boolean>() {
@Override
public Boolean load(WorldPlayerTuple tuple) throws Exception {
return plugin.getGlobalRegionManager().hasBypass(tuple.player, tuple.world);
}
});
private final LoadingCache<CacheKey, Session> sessions = CacheBuilder.newBuilder()
.expireAfterAccess(SESSION_LIFETIME, TimeUnit.MINUTES)
.build(new CacheLoader<CacheKey, Session>() {
@Override
public Session load(CacheKey key) throws Exception {
return createSession(key.playerRef.get());
}
});
/**
* Create a new instance.
*
* @param plugin The plugin
*/
public SessionManager(WorldGuardPlugin plugin) {
checkNotNull(plugin, "plugin");
this.plugin = plugin;
}
/**
* Get the plugin.
*
* @return The plugin
*/
public WorldGuardPlugin getPlugin() {
return plugin;
}
/**
* Check whether a player has the region bypass permission.
*
* <p>The return value may be cached for a few seconds.</p>
*
* @param player The player
* @param world The world
* @return A value
*/
public boolean hasBypass(Player player, World world) {
return bypassCache.getUnchecked(new WorldPlayerTuple(world, player));
}
/**
* Re-initialize handlers and clear "last position," "last state," etc.
* information for all players.
*/
public void resetAllStates() {
Collection<? extends Player> players = BukkitUtil.getOnlinePlayers();
for (Player player : players) {
Session session = sessions.getIfPresent(new CacheKey(player));
if (session != null) {
session.resetState(player);
}
}
}
/**
* Re-initialize handlers and clear "last position," "last state," etc.
* information.
*
* @param player The player
*/
public void resetState(Player player) {
checkNotNull(player, "player");
@Nullable Session session = sessions.getIfPresent(new CacheKey(player));
if (session != null) {
session.resetState(player);
}
}
/**
* Create a session for a player.
*
* @param player The player
* @return The new session
*/
private Session createSession(Player player) {
Session session = new Session(this);
session.register(new HealFlag(session));
session.register(new FeedFlag(session));
session.register(new NotifyEntryFlag(session));
session.register(new NotifyExitFlag(session));
session.register(new EntryFlag(session));
session.register(new ExitFlag(session));
session.register(new GreetingFlag(session));
session.register(new FarewellFlag(session));
session.register(new GameModeFlag(session));
session.register(new InvincibilityFlag(session));
session.register(new TimeLockFlag(session));
session.register(new WeatherLockFlag(session));
session.register(new GodMode(session));
session.register(new WaterBreathing(session));
session.initialize(player);
return session;
}
/**
* Get a player's session, if one exists.
*
* @param player The player
* @return The session
*/
@Nullable
public Session getIfPresent(Player player) {
return sessions.getIfPresent(player);
}
/**
* Get a player's session. A session will be created if there is no
* existing session for the player.
*
* <p>This method can only be called from the main thread. While the
* session manager itself is thread-safe, some of the handlers may
* require initialization that requires the server main thread.</p>
*
* @param player The player to get a session for
* @return The {@code player}'s session
*/
public Session get(Player player) {
return sessions.getUnchecked(new CacheKey(player));
}
@EventHandler
public void onPlayerJoin(PlayerJoinEvent event) {
// Pre-load a session
get(event.getPlayer());
}
@Override
public void run() {
for (Player player : BukkitUtil.getOnlinePlayers()) {
get(player).tick(player);
}
}
private static final class CacheKey {
private final WeakReference<Player> playerRef;
private final UUID uuid;
private CacheKey(Player player) {
playerRef = new WeakReference<Player>(player);
uuid = player.getUniqueId();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
CacheKey cacheKey = (CacheKey) o;
return uuid.equals(cacheKey.uuid);
}
@Override
public int hashCode() {
return uuid.hashCode();
}
}
}
@@ -0,0 +1,55 @@
/*
* 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.session;
import org.bukkit.World;
import org.bukkit.entity.Player;
class WorldPlayerTuple {
final World world;
final Player player;
WorldPlayerTuple(World world, Player player) {
this.world = world;
this.player = player;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
WorldPlayerTuple that = (WorldPlayerTuple) o;
if (!player.equals(that.player)) return false;
if (!world.equals(that.world)) return false;
return true;
}
@Override
public int hashCode() {
int result = world.hashCode();
result = 31 * result + player.hashCode();
return result;
}
}
@@ -0,0 +1,64 @@
/*
* 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.session.handler;
import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.bukkit.commands.CommandUtils;
import com.sk89q.worldguard.protection.ApplicableRegionSet;
import com.sk89q.worldguard.protection.flags.DefaultFlag;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import com.sk89q.worldguard.session.MoveType;
import com.sk89q.worldguard.session.Session;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import java.util.Set;
public class EntryFlag extends Handler {
private static final long MESSAGE_THRESHOLD = 1000 * 2;
private long lastMessage;
public EntryFlag(Session session) {
super(session);
}
@Override
public boolean onCrossBoundary(Player player, Location from, Location to, ApplicableRegionSet toSet, Set<ProtectedRegion> entered, Set<ProtectedRegion> exited, MoveType moveType) {
LocalPlayer localPlayer = getPlugin().wrapPlayer(player);
boolean allowed = toSet.testState(localPlayer, DefaultFlag.ENTRY);
if (!getSession().getManager().hasBypass(player, to.getWorld()) && !allowed && moveType.isCancellable()) {
String message = toSet.queryValue(localPlayer, DefaultFlag.ENTRY_DENY_MESSAGE);
long now = System.currentTimeMillis();
if ((now - lastMessage) > MESSAGE_THRESHOLD && message != null && !message.isEmpty()) {
player.sendMessage(CommandUtils.replaceColorMacros(message));
lastMessage = now;
}
return false;
} else {
return true;
}
}
}
@@ -0,0 +1,107 @@
/*
* 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.session.handler;
import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.bukkit.commands.CommandUtils;
import com.sk89q.worldguard.protection.ApplicableRegionSet;
import com.sk89q.worldguard.protection.flags.DefaultFlag;
import com.sk89q.worldguard.protection.flags.StateFlag;
import com.sk89q.worldguard.protection.flags.StateFlag.State;
import com.sk89q.worldguard.session.MoveType;
import com.sk89q.worldguard.session.Session;
import org.bukkit.Location;
import org.bukkit.entity.Player;
public class ExitFlag extends FlagValueChangeHandler<State> {
private static final long MESSAGE_THRESHOLD = 1000 * 2;
private String storedMessage;
private boolean exitViaTeleport = false;
private long lastMessage;
public ExitFlag(Session session) {
super(session, DefaultFlag.EXIT);
}
private void update(LocalPlayer localPlayer, ApplicableRegionSet set, boolean allowed) {
if (!allowed) {
storedMessage = set.queryValue(localPlayer, DefaultFlag.EXIT_DENY_MESSAGE);
exitViaTeleport = set.testState(localPlayer, DefaultFlag.EXIT_VIA_TELEPORT);
}
}
private void sendMessage(Player player) {
long now = System.currentTimeMillis();
if ((now - lastMessage) > MESSAGE_THRESHOLD && storedMessage != null && !storedMessage.isEmpty()) {
player.sendMessage(CommandUtils.replaceColorMacros(storedMessage));
lastMessage = now;
}
}
@Override
protected void onInitialValue(Player player, ApplicableRegionSet set, State value) {
update(getPlugin().wrapPlayer(player), set, StateFlag.test(value));
}
@Override
protected boolean onSetValue(Player player, Location from, Location to, ApplicableRegionSet toSet, State currentValue, State lastValue, MoveType moveType) {
if (getSession().getManager().hasBypass(player, from.getWorld())) {
return true;
}
boolean lastAllowed = StateFlag.test(lastValue);
boolean allowed = StateFlag.test(currentValue);
LocalPlayer localPlayer = getPlugin().wrapPlayer(player);
if (allowed && !lastAllowed && !(moveType.isTeleport() && exitViaTeleport) && moveType.isCancellable()) {
Boolean override = toSet.queryValue(localPlayer, DefaultFlag.EXIT_OVERRIDE);
if (override == null || !override) {
sendMessage(player);
return false;
}
}
update(localPlayer, toSet, allowed);
return true;
}
@Override
protected boolean onAbsentValue(Player player, Location from, Location to, ApplicableRegionSet toSet, State lastValue, MoveType moveType) {
if (getSession().getManager().hasBypass(player, from.getWorld())) {
return true;
}
boolean lastAllowed = StateFlag.test(lastValue);
if (!lastAllowed && moveType.isCancellable()) {
Boolean override = toSet.queryValue(getPlugin().wrapPlayer(player), DefaultFlag.EXIT_OVERRIDE);
if (override == null || !override) {
sendMessage(player);
return false;
}
}
return true;
}
}
@@ -0,0 +1,81 @@
/*
* 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.session.handler;
import com.google.common.collect.Sets;
import com.sk89q.worldguard.bukkit.commands.CommandUtils;
import com.sk89q.worldguard.protection.ApplicableRegionSet;
import com.sk89q.worldguard.protection.flags.DefaultFlag;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import com.sk89q.worldguard.session.MoveType;
import com.sk89q.worldguard.session.Session;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import java.util.Collections;
import java.util.Set;
public class FarewellFlag extends Handler {
private Set<String> lastMessageStack = Collections.emptySet();
public FarewellFlag(Session session) {
super(session);
}
private Set<String> getMessages(Player player, ApplicableRegionSet set) {
return Sets.newLinkedHashSet(set.queryAllValues(getPlugin().wrapPlayer(player), DefaultFlag.FAREWELL_MESSAGE));
}
@Override
public void initialize(Player player, Location current, ApplicableRegionSet set) {
lastMessageStack = getMessages(player, set);
}
@Override
public boolean onCrossBoundary(Player player, Location from, Location to, ApplicableRegionSet toSet, Set<ProtectedRegion> entered, Set<ProtectedRegion> exited, MoveType moveType) {
Set<String> messages = getMessages(player, toSet);
if (!messages.isEmpty()) {
// Due to flag priorities, we have to collect the lower
// priority flag values separately
for (ProtectedRegion region : toSet) {
String message = region.getFlag(DefaultFlag.FAREWELL_MESSAGE);
if (message != null) {
messages.add(message);
}
}
}
for (String message : lastMessageStack) {
if (!messages.contains(message)) {
String effective = CommandUtils.replaceColorMacros(message);
effective = getPlugin().replaceMacros(player, effective);
player.sendMessage(effective.replaceAll("\\\\n", "\n").split("\\n"));
break;
}
}
lastMessageStack = messages;
return true;
}
}
@@ -0,0 +1,83 @@
/*
* 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.session.handler;
import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.protection.ApplicableRegionSet;
import com.sk89q.worldguard.protection.flags.DefaultFlag;
import com.sk89q.worldguard.session.Session;
import org.bukkit.GameMode;
import org.bukkit.entity.Player;
public class FeedFlag extends Handler {
private long lastFeed = 0;
public FeedFlag(Session session) {
super(session);
}
@Override
public void tick(Player player, ApplicableRegionSet set) {
long now = System.currentTimeMillis();
LocalPlayer localPlayer = getSession().getPlugin().wrapPlayer(player);
Integer feedAmount = set.queryValue(localPlayer, DefaultFlag.FEED_AMOUNT);
Integer feedDelay = set.queryValue(localPlayer, DefaultFlag.FEED_DELAY);
Integer minHunger = set.queryValue(localPlayer, DefaultFlag.MIN_FOOD);
Integer maxHunger = set.queryValue(localPlayer, DefaultFlag.MAX_FOOD);
if (feedAmount == null || feedDelay == null || feedAmount == 0 || feedDelay < 0) {
return;
}
if (feedAmount < 0
&& (getSession().isInvincible(player)
|| (player.getGameMode() != GameMode.SURVIVAL && player.getGameMode() != GameMode.ADVENTURE))) {
// don't starve invincible players
return;
}
if (minHunger == null) {
minHunger = 0;
}
if (maxHunger == null) {
maxHunger = 20;
}
// Apply a cap to prevent possible exceptions
minHunger = Math.min(20, minHunger);
maxHunger = Math.min(20, maxHunger);
if (player.getFoodLevel() >= maxHunger && feedAmount > 0) {
return;
}
if (feedDelay <= 0) {
player.setFoodLevel(feedAmount > 0 ? maxHunger : minHunger);
player.setSaturation(player.getFoodLevel());
lastFeed = now;
} else if (now - lastFeed > feedDelay * 1000) {
// clamp health between minimum and maximum
player.setFoodLevel(Math.min(maxHunger, Math.max(minHunger, player.getFoodLevel() + feedAmount)));
player.setSaturation(player.getFoodLevel());
lastFeed = now;
}
}
}
@@ -0,0 +1,72 @@
/*
* 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.session.handler;
import com.sk89q.worldguard.protection.ApplicableRegionSet;
import com.sk89q.worldguard.protection.flags.Flag;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import com.sk89q.worldguard.session.MoveType;
import com.sk89q.worldguard.session.Session;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import java.util.Set;
public abstract class FlagValueChangeHandler<T> extends Handler {
private final Flag<T> flag;
private T lastValue;
protected FlagValueChangeHandler(Session session, Flag<T> flag) {
super(session);
this.flag = flag;
}
@Override
public final void initialize(Player player, Location current, ApplicableRegionSet set) {
lastValue = set.queryValue(getPlugin().wrapPlayer(player), flag);
onInitialValue(player, set, lastValue);
}
@Override
public boolean onCrossBoundary(Player player, Location from, Location to, ApplicableRegionSet toSet, Set<ProtectedRegion> entered, Set<ProtectedRegion> exited, MoveType moveType) {
T currentValue = toSet.queryValue(getPlugin().wrapPlayer(player), flag);
boolean allowed = true;
if (currentValue == null && lastValue != null) {
allowed = onAbsentValue(player, from, to, toSet, lastValue, moveType);
} else if (currentValue != null && currentValue != lastValue) {
allowed = onSetValue(player, from, to, toSet, currentValue, lastValue, moveType);
}
if (allowed) {
lastValue = currentValue;
}
return allowed;
}
protected abstract void onInitialValue(Player player, ApplicableRegionSet set, T value);
protected abstract boolean onSetValue(Player player, Location from, Location to, ApplicableRegionSet toSet, T currentValue, T lastValue, MoveType moveType);
protected abstract boolean onAbsentValue(Player player, Location from, Location to, ApplicableRegionSet toSet, T lastValue, MoveType moveType);
}
@@ -0,0 +1,84 @@
/*
* 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.session.handler;
import com.sk89q.worldguard.protection.ApplicableRegionSet;
import com.sk89q.worldguard.protection.flags.DefaultFlag;
import com.sk89q.worldguard.session.MoveType;
import com.sk89q.worldguard.session.Session;
import org.bukkit.GameMode;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.entity.Player;
import javax.annotation.Nullable;
public class GameModeFlag extends FlagValueChangeHandler<GameMode> {
private GameMode originalGameMode;
private GameMode setGameMode;
public GameModeFlag(Session session) {
super(session, DefaultFlag.GAME_MODE);
}
public GameMode getOriginalGameMode() {
return originalGameMode;
}
public GameMode getSetGameMode() {
return setGameMode;
}
private void updateGameMode(Player player, @Nullable GameMode newValue, World world) {
if (!getSession().getManager().hasBypass(player, world) && newValue != null) {
if (player.getGameMode() != newValue) {
originalGameMode = player.getGameMode();
player.setGameMode(newValue);
} else if (originalGameMode == null) {
originalGameMode = player.getServer().getDefaultGameMode();
}
} else {
if (originalGameMode != null) {
GameMode mode = originalGameMode;
originalGameMode = null;
player.setGameMode(mode);
}
}
}
@Override
protected void onInitialValue(Player player, ApplicableRegionSet set, GameMode value) {
updateGameMode(player, value, player.getWorld());
}
@Override
protected boolean onSetValue(Player player, Location from, Location to, ApplicableRegionSet toSet, GameMode currentValue, GameMode lastValue, MoveType moveType) {
updateGameMode(player, currentValue, to.getWorld());
return true;
}
@Override
protected boolean onAbsentValue(Player player, Location from, Location to, ApplicableRegionSet toSet, GameMode lastValue, MoveType moveType) {
updateGameMode(player, null, player.getWorld());
return true;
}
}
@@ -0,0 +1,76 @@
/*
* 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.session.handler;
import com.sk89q.commandbook.CommandBook;
import com.sk89q.commandbook.GodComponent;
import com.sk89q.worldguard.protection.flags.StateFlag.State;
import com.sk89q.worldguard.session.Session;
import org.bukkit.entity.Player;
import javax.annotation.Nullable;
public class GodMode extends Handler {
private boolean godMode;
public GodMode(Session session) {
super(session);
}
public boolean hasGodMode(Player player) {
if (getPlugin().getGlobalStateManager().hasCommandBookGodMode()) {
GodComponent god = CommandBook.inst().getComponentManager().getComponent(GodComponent.class);
if (god != null) {
return god.hasGodMode(player);
}
}
return godMode;
}
public void setGodMode(Player player, boolean godMode) {
if (getPlugin().getGlobalStateManager().hasCommandBookGodMode()) {
GodComponent god = CommandBook.inst().getComponentManager().getComponent(GodComponent.class);
if (god != null) {
god.enableGodMode(player);
}
}
this.godMode = godMode;
}
@Nullable
@Override
public State getInvincibility(Player player) {
return hasGodMode(player) ? State.ALLOW : null;
}
public static boolean set(Player player, Session session, boolean value) {
GodMode godMode = session.getHandler(GodMode.class);
if (godMode != null) {
godMode.setGodMode(player, value);
return true;
} else{
return false;
}
}
}
@@ -0,0 +1,72 @@
/*
* 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.session.handler;
import com.google.common.collect.Sets;
import com.sk89q.worldguard.bukkit.commands.CommandUtils;
import com.sk89q.worldguard.protection.ApplicableRegionSet;
import com.sk89q.worldguard.protection.flags.DefaultFlag;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import com.sk89q.worldguard.session.MoveType;
import com.sk89q.worldguard.session.Session;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import java.util.Collection;
import java.util.Collections;
import java.util.Set;
public class GreetingFlag extends Handler {
private Set<String> lastMessageStack = Collections.emptySet();
public GreetingFlag(Session session) {
super(session);
}
@Override
public boolean onCrossBoundary(Player player, Location from, Location to, ApplicableRegionSet toSet, Set<ProtectedRegion> entered, Set<ProtectedRegion> exited, MoveType moveType) {
Collection<String> messages = toSet.queryAllValues(getPlugin().wrapPlayer(player), DefaultFlag.GREET_MESSAGE);
for (String message : messages) {
if (!lastMessageStack.contains(message)) {
String effective = CommandUtils.replaceColorMacros(message);
effective = getPlugin().replaceMacros(player, effective);
player.sendMessage(effective.replaceAll("\\\\n", "\n").split("\\n"));
break;
}
}
lastMessageStack = Sets.newHashSet(messages);
if (!lastMessageStack.isEmpty()) {
// Due to flag priorities, we have to collect the lower
// priority flag values separately
for (ProtectedRegion region : toSet) {
String message = region.getFlag(DefaultFlag.GREET_MESSAGE);
if (message != null) {
lastMessageStack.add(message);
}
}
}
return true;
}
}
@@ -0,0 +1,148 @@
/*
* 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.session.handler;
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
import com.sk89q.worldguard.protection.ApplicableRegionSet;
import com.sk89q.worldguard.protection.flags.StateFlag.State;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import com.sk89q.worldguard.session.MoveType;
import com.sk89q.worldguard.session.Session;
import com.sk89q.worldguard.session.SessionManager;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import javax.annotation.Nullable;
import java.util.Set;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Stores session data and possibly acts on it.
*/
public abstract class Handler {
private final Session session;
/**
* Create a new handler.
*
* @param session The session
*/
protected Handler(Session session) {
checkNotNull(session, "session");
this.session = session;
}
/**
* Get the plugin.
*
* @return The plugin
*/
public WorldGuardPlugin getPlugin() {
return getSession().getManager().getPlugin();
}
/**
* Get the session.
*
* @return The session
*/
public Session getSession() {
return session;
}
/**
* Called when the session is first being created or
* {@code /wg flushstates} is used.
*
* @param player The player
* @param current The player's current location
* @param set The regions for the current location
*/
public void initialize(Player player, Location current, ApplicableRegionSet set) {
}
/**
* Called when {@link Session#testMoveTo(Player, Location, MoveType)} is called.
*
* <p>If this method returns {@code false}, then no other handlers
* will be run (for this move attempt).</p>
*
* @param player The player
* @param from The previous, valid, location
* @param to The new location to test
* @param toSet The regions for the new location
* @param moveType The type of movement
* @return Whether the movement should be allowed
*/
public boolean testMoveTo(Player player, Location from, Location to, ApplicableRegionSet toSet, MoveType moveType) {
return true;
}
/**
* Called when a player has moved into a new location where either
* there are fewer regions or more regions.
*
* <p>This is called only if the move test
* ({@link Session#testMoveTo(Player, Location, MoveType)}) was successful.</p>
*
* <p>If this method returns {@code false}, then no other handlers
* will be run (for this move attempt).</p>
*
* @param player The player
* @param from The previous, valid, location
* @param to The new location to test
* @param toSet The regions for the new location
* @param entered The list of regions that have been entered
* @param exited The list of regions that have been left
* @param moveType The type of move
* @return Whether the movement should be allowed
*/
public boolean onCrossBoundary(Player player, Location from, Location to, ApplicableRegionSet toSet,
Set<ProtectedRegion> entered, Set<ProtectedRegion> exited, MoveType moveType) {
return true;
}
/**
* Called periodically (at least once every second) by
* {@link SessionManager} in the server's main thread.
*
* @param player The player
* @param set The regions for the player's current location
*/
public void tick(Player player, ApplicableRegionSet set) {
}
/**
* Return whether the player should be invincible.
*
* <p>{@link State#DENY} can be returned to prevent invincibility
* even if another handler permits it.</p>
*
* @param player The player
* @return Invincibility state
*/
@Nullable
public State getInvincibility(Player player) {
return null;
}
}
@@ -0,0 +1,86 @@
/*
* 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.session.handler;
import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.protection.ApplicableRegionSet;
import com.sk89q.worldguard.protection.flags.DefaultFlag;
import com.sk89q.worldguard.session.Session;
import org.bukkit.GameMode;
import org.bukkit.entity.Player;
public class HealFlag extends Handler {
private long lastHeal = 0;
public HealFlag(Session session) {
super(session);
}
@Override
public void tick(Player player, ApplicableRegionSet set) {
LocalPlayer localPlayer = getPlugin().wrapPlayer(player);
if (player.getHealth() <= 0) {
return;
}
long now = System.currentTimeMillis();
Integer healAmount = set.queryValue(localPlayer, DefaultFlag.HEAL_AMOUNT);
Integer healDelay = set.queryValue(localPlayer, DefaultFlag.HEAL_DELAY);
Double minHealth = set.queryValue(localPlayer, DefaultFlag.MIN_HEAL);
Double maxHealth = set.queryValue(localPlayer, DefaultFlag.MAX_HEAL);
if (healAmount == null || healDelay == null || healAmount == 0 || healDelay < 0) {
return;
}
if (healAmount < 0
&& (getSession().isInvincible(player)
|| (player.getGameMode() != GameMode.SURVIVAL && player.getGameMode() != GameMode.ADVENTURE))) {
// don't damage invincible players
return;
}
if (minHealth == null) {
minHealth = 0.0;
}
if (maxHealth == null) {
maxHealth = player.getMaxHealth();
}
// Apply a cap to prevent possible exceptions
minHealth = Math.min(player.getMaxHealth(), minHealth);
maxHealth = Math.min(player.getMaxHealth(), maxHealth);
if (player.getHealth() >= maxHealth && healAmount > 0) {
return;
}
if (healDelay <= 0) {
player.setHealth(healAmount > 0 ? maxHealth : minHealth); // this will insta-kill if the flag is unset
lastHeal = now;
} else if (now - lastHeal > healDelay * 1000) {
// clamp health between minimum and maximum
player.setHealth(Math.min(maxHealth, Math.max(minHealth, player.getHealth() + healAmount)));
lastHeal = now;
}
}
}
@@ -0,0 +1,68 @@
/*
* 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.session.handler;
import com.sk89q.worldguard.protection.ApplicableRegionSet;
import com.sk89q.worldguard.protection.flags.DefaultFlag;
import com.sk89q.worldguard.protection.flags.StateFlag.State;
import com.sk89q.worldguard.session.MoveType;
import com.sk89q.worldguard.session.Session;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import javax.annotation.Nullable;
public class InvincibilityFlag extends FlagValueChangeHandler<State> {
@Nullable
private State invincibility;
public InvincibilityFlag(Session session) {
super(session, DefaultFlag.INVINCIBILITY);
}
@Override
protected void onInitialValue(Player player, ApplicableRegionSet set, State value) {
invincibility = value;
}
@Override
protected boolean onSetValue(Player player, Location from, Location to, ApplicableRegionSet toSet, State currentValue, State lastValue, MoveType moveType) {
invincibility = currentValue;
return true;
}
@Override
protected boolean onAbsentValue(Player player, Location from, Location to, ApplicableRegionSet toSet, State lastValue, MoveType moveType) {
invincibility = null;
return true;
}
@Override
@Nullable
public State getInvincibility(Player player) {
if (invincibility == State.DENY && getPlugin().hasPermission(player, "worldguard.god.override-regions")) {
return null;
}
return invincibility;
}
}
@@ -0,0 +1,68 @@
/*
* 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.session.handler;
import com.sk89q.worldguard.protection.ApplicableRegionSet;
import com.sk89q.worldguard.protection.flags.DefaultFlag;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import com.sk89q.worldguard.session.MoveType;
import com.sk89q.worldguard.session.Session;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.entity.Player;
public class NotifyEntryFlag extends FlagValueChangeHandler<Boolean> {
public NotifyEntryFlag(Session session) {
super(session, DefaultFlag.NOTIFY_ENTER);
}
@Override
protected void onInitialValue(Player player, ApplicableRegionSet set, Boolean value) {
}
@Override
protected boolean onSetValue(Player player, Location from, Location to, ApplicableRegionSet toSet, Boolean currentValue, Boolean lastValue, MoveType moveType) {
StringBuilder regionList = new StringBuilder();
for (ProtectedRegion region : toSet) {
if (regionList.length() != 0) {
regionList.append(", ");
}
regionList.append(region.getId());
}
getPlugin().broadcastNotification(ChatColor.GRAY + "WG: "
+ ChatColor.LIGHT_PURPLE + player.getName()
+ ChatColor.GOLD + " entered NOTIFY region: "
+ ChatColor.WHITE
+ regionList);
return true;
}
@Override
protected boolean onAbsentValue(Player player, Location from, Location to, ApplicableRegionSet toSet, Boolean lastValue, MoveType moveType) {
return true;
}
}
@@ -0,0 +1,55 @@
/*
* 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.session.handler;
import com.sk89q.worldguard.protection.ApplicableRegionSet;
import com.sk89q.worldguard.protection.flags.DefaultFlag;
import com.sk89q.worldguard.session.MoveType;
import com.sk89q.worldguard.session.Session;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.entity.Player;
public class NotifyExitFlag extends FlagValueChangeHandler<Boolean> {
private Boolean notifiedForLeave = false;
public NotifyExitFlag(Session session) {
super(session, DefaultFlag.NOTIFY_LEAVE);
}
@Override
protected void onInitialValue(Player player, ApplicableRegionSet set, Boolean value) {
}
@Override
protected boolean onSetValue(Player player, Location from, Location to, ApplicableRegionSet toSet, Boolean currentValue, Boolean lastValue, MoveType moveType) {
return true;
}
@Override
protected boolean onAbsentValue(Player player, Location from, Location to, ApplicableRegionSet toSet, Boolean lastValue, MoveType moveType) {
getPlugin().broadcastNotification(ChatColor.GRAY + "WG: "
+ ChatColor.LIGHT_PURPLE + player.getName()
+ ChatColor.GOLD + " left NOTIFY region");
return true;
}
}
@@ -0,0 +1,86 @@
/*
* 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.session.handler;
import com.sk89q.worldguard.protection.ApplicableRegionSet;
import com.sk89q.worldguard.protection.flags.DefaultFlag;
import com.sk89q.worldguard.session.MoveType;
import com.sk89q.worldguard.session.Session;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import javax.annotation.Nullable;
import java.util.regex.Pattern;
public class TimeLockFlag extends FlagValueChangeHandler<String> {
private Long time;
private boolean relative;
private Long initialTime;
private boolean initialRelative;
Pattern timePattern = Pattern.compile("(\\+|-)?\\d+");
public TimeLockFlag(Session session) {
super(session, DefaultFlag.TIME_LOCK);
}
private void updatePlayerTime(Player player, @Nullable String value) {
// store settings, regardless of if we change anything
initialRelative = player.isPlayerTimeRelative();
initialTime = player.getPlayerTime();
if (value == null || !timePattern.matcher(value).matches()) {
// invalid input
return;
}
if (value.startsWith("+") || value.startsWith("-")) {
relative = true;
} else {
relative = false;
}
time = Long.valueOf(value);
if (!relative && (time < 0L || time > 24000L)) { // invalid time, reset to 0
time = 0L;
}
player.setPlayerTime(time, relative);
}
@Override
protected void onInitialValue(Player player, ApplicableRegionSet set, String value) {
initialTime = player.getPlayerTime();
initialRelative = player.isPlayerTimeRelative();
updatePlayerTime(player, value);
}
@Override
protected boolean onSetValue(Player player, Location from, Location to, ApplicableRegionSet toSet, String currentValue, String lastValue, MoveType moveType) {
updatePlayerTime(player, currentValue);
return true;
}
@Override
protected boolean onAbsentValue(Player player, Location from, Location to, ApplicableRegionSet toSet, String lastValue, MoveType moveType) {
player.setPlayerTime(initialTime, initialRelative);
initialRelative = true;
initialTime = 0L;
return true;
}
}
@@ -0,0 +1,51 @@
/*
* 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.session.handler;
import com.sk89q.worldguard.session.Session;
import org.bukkit.entity.Player;
public class WaterBreathing extends Handler {
public boolean waterBreathing;
public WaterBreathing(Session session) {
super(session);
}
public boolean hasWaterBreathing() {
return waterBreathing;
}
public void setWaterBreathing(boolean waterBreathing) {
this.waterBreathing = waterBreathing;
}
public static boolean set(Player player, Session session, boolean value) {
WaterBreathing waterBreathing = session.getHandler(WaterBreathing.class);
if (waterBreathing != null) {
waterBreathing.setWaterBreathing(value);
return true;
} else{
return false;
}
}
}
@@ -0,0 +1,71 @@
/*
* 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.session.handler;
import com.sk89q.worldguard.protection.ApplicableRegionSet;
import com.sk89q.worldguard.protection.flags.DefaultFlag;
import com.sk89q.worldguard.session.MoveType;
import com.sk89q.worldguard.session.Session;
import org.bukkit.Location;
import org.bukkit.WeatherType;
import org.bukkit.entity.Player;
import javax.annotation.Nullable;
public class WeatherLockFlag extends FlagValueChangeHandler<WeatherType> {
private WeatherType initialWeather;
public WeatherLockFlag(Session session) {
super(session, DefaultFlag.WEATHER_LOCK);
}
private void updatePlayerWeather(Player player, @Nullable WeatherType value) {
initialWeather = player.getPlayerWeather();
player.setPlayerWeather(value);
}
@Override
protected void onInitialValue(Player player, ApplicableRegionSet set, WeatherType value) {
if (value == null) {
initialWeather = null;
return;
}
updatePlayerWeather(player, value);
}
@Override
protected boolean onSetValue(Player player, Location from, Location to, ApplicableRegionSet toSet, WeatherType currentValue, WeatherType lastValue, MoveType moveType) {
updatePlayerWeather(player, currentValue);
return true;
}
@Override
protected boolean onAbsentValue(Player player, Location from, Location to, ApplicableRegionSet toSet, WeatherType lastValue, MoveType moveType) {
if (initialWeather != null) {
player.setPlayerWeather(initialWeather);
} else {
player.resetPlayerWeather();
}
initialWeather = null;
return true;
}
}
@@ -64,7 +64,7 @@ public class CommandFilter implements Predicate<String> {
@SuppressWarnings("StatementWithEmptyBody")
@Override
public boolean apply(String command) {
command = command.toLowerCase().replaceAll("^/([^:]*:)?", "/");
command = command.toLowerCase().replaceAll("^/([^ :]*:)?", "/");
/*
* denied used allow?
@@ -0,0 +1,124 @@
/*
* 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.logging;
import com.google.common.base.Strings;
import com.google.common.collect.Maps;
import org.bukkit.plugin.Plugin;
import javax.annotation.Nullable;
import java.security.CodeSource;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Validates that certain specified classes came from the same source as
* a plugin.
*/
public class ClassSourceValidator {
private static final Logger log = Logger.getLogger(ClassSourceValidator.class.getCanonicalName());
private static final String separatorLine = Strings.repeat("*", 46);
private final Plugin plugin;
@Nullable
private final CodeSource expectedCodeSource;
/**
* Create a new instance.
*
* @param plugin The plugin
*/
public ClassSourceValidator(Plugin plugin) {
checkNotNull(plugin, "plugin");
this.plugin = plugin;
this.expectedCodeSource = plugin.getClass().getProtectionDomain().getCodeSource();
}
/**
* Return a map of classes that been loaded from a different source.
*
* @param classes A list of classes to check
* @return The results
*/
public Map<Class<?>, CodeSource> findMismatches(List<Class<?>> classes) {
checkNotNull(classes, "classes");
Map<Class<?>, CodeSource> mismatches = Maps.newHashMap();
if (expectedCodeSource != null) {
for (Class<?> testClass : classes) {
CodeSource testSource = testClass.getProtectionDomain().getCodeSource();
if (!expectedCodeSource.equals(testSource)) {
mismatches.put(testClass, testSource);
}
}
}
return mismatches;
}
/**
* Reports classes that have come from a different source.
*
* <p>The warning is emitted to the log.</p>
*
* @param classes The list of classes to check
*/
public void reportMismatches(List<Class<?>> classes) {
Map<Class<?>, CodeSource> mismatches = findMismatches(classes);
if (!mismatches.isEmpty()) {
StringBuilder builder = new StringBuilder("\n");
builder.append(separatorLine).append("\n");
builder.append("** /!\\ SEVERE WARNING /!\\\n");
builder.append("** \n");
builder.append("** A plugin developer has copied and pasted a portion of \n");
builder.append("** ").append(plugin.getName()).append(" into their own plugin, so rather than using\n");
builder.append("** the version of ").append(plugin.getName()).append(" that you downloaded, you\n");
builder.append("** will be using a broken mix of old ").append(plugin.getName()).append(" (that came\n");
builder.append("** with the plugin) and your downloaded version. THIS MAY\n");
builder.append("** SEVERELY BREAK ").append(plugin.getName().toUpperCase()).append(" AND ALL OF ITS FEATURES.\n");
builder.append("**\n");
builder.append("** This may have happened because the developer is using\n");
builder.append("** the ").append(plugin.getName()).append(" API and thinks that including\n");
builder.append("** ").append(plugin.getName()).append(" is necessary. However, it is not!\n");
builder.append("**\n");
builder.append("** Here are some files that have been overridden:\n");
builder.append("** \n");
for (Map.Entry<Class<?>, CodeSource> entry : mismatches.entrySet()) {
CodeSource codeSource = entry.getValue();
String url = codeSource != null ? codeSource.getLocation().toExternalForm() : "(unknown)";
builder.append("** '").append(entry.getKey().getSimpleName()).append("' came from '").append(url).append("'\n");
}
builder.append("**\n");
builder.append("** Please report this to the plugins' developers.\n");
builder.append(separatorLine).append("\n");
log.log(Level.SEVERE, builder.toString());
}
}
}
@@ -0,0 +1,79 @@
/*
* 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.paste;
import com.google.common.util.concurrent.ListenableFuture;
import com.sk89q.worldguard.util.net.HttpRequest;
import com.sk89q.worldguard.util.net.HttpRequest.Form;
import org.json.simple.JSONValue;
import java.io.IOException;
import java.net.URL;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class EngineHubPaste implements Paster {
private static final Pattern URL_PATTERN = Pattern.compile("https?://.+$");
@Override
public ListenableFuture<URL> paste(String content) {
return Pasters.getExecutor().submit(new PasteTask(content));
}
private final class PasteTask implements Callable<URL> {
private final String content;
private PasteTask(String content) {
this.content = content;
}
@Override
public URL call() throws IOException, InterruptedException {
Form form = Form.create();
form.add("content", content);
form.add("from", "worldguard");
URL url = HttpRequest.url("http://paste.enginehub.org/paste");
String result = HttpRequest.post(url)
.bodyForm(form)
.execute()
.expectResponseCode(200)
.returnContent()
.asString("UTF-8").trim();
Object object = JSONValue.parse(result);
if (object instanceof Map) {
@SuppressWarnings("unchecked")
String urlString = String.valueOf(((Map<Object, Object>) object).get("url"));
Matcher m = URL_PATTERN.matcher(urlString);
if (m.matches()) {
return new URL(urlString);
}
}
throw new IOException("Failed to save paste; instead, got: " + result);
}
}
}
@@ -92,19 +92,5 @@ public class Pastebin implements Paster {
}
}
}
public static void main(String[] args) {
Futures.addCallback(new Pastebin().paste("hi there"), new FutureCallback<URL>() {
@Override
public void onSuccess(URL url) {
System.out.println("got: " + url);
}
@Override
public void onFailure(Throwable throwable) {
throwable.printStackTrace();
}
});
}
}
Loaded 100 of 111 files, more files were not shown because too many files have changed in this diff. Show more