Compare commits

...
77 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
72 changed files with 3162 additions and 1151 deletions

No files matched your search

+62
View File
@@ -1,5 +1,67 @@
# 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.
+42 -51
View File
@@ -2,7 +2,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.sk89q</groupId>
<artifactId>worldguard</artifactId>
<version>6.0.0-beta-04</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>
@@ -92,8 +92,15 @@
<dependency>
<groupId>com.sk89q.spigot</groupId>
<artifactId>bukkit</artifactId>
<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.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+ -->
@@ -461,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>
@@ -492,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>
@@ -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() + ".");
@@ -27,6 +27,8 @@ 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 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.*;
@@ -87,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.
*
@@ -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();
}
@@ -327,8 +338,8 @@ public class WorldGuardPlugin extends JavaPlugin {
*
* @return The flag state manager
*/
public FlagStateManager getFlagStateManager() {
return flagStateManager;
public SessionManager getSessionManager() {
return sessionManager;
}
/**
@@ -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.
@@ -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);
}
}
}
@@ -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.");
}
}
@@ -250,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() + "\".");
}
}
@@ -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;
}
}
}
@@ -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;
@@ -65,9 +64,8 @@ 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;
@@ -244,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));
}
}
}
@@ -304,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()) {
@@ -313,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:
@@ -328,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, event.getAction() == Action.RIGHT_CLICK_BLOCK) || (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;
}
}
@@ -377,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)
@@ -420,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
@@ -615,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;
@@ -679,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)
@@ -702,7 +725,9 @@ public class EventAbstractionListener extends AbstractListener {
if (holder instanceof BlockState) {
Events.fireToCancel(event, new UseBlockEvent(event, create(event.getPlayer()), ((BlockState) holder).getBlock()));
} else if (holder instanceof Entity) {
Events.fireToCancel(event, new UseEntityEvent(event, create(event.getPlayer()), (Entity) holder));
if (!(holder instanceof Player)) {
Events.fireToCancel(event, new UseEntityEvent(event, create(event.getPlayer()), (Entity) holder));
}
}
}
@@ -827,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();
@@ -901,6 +931,12 @@ public class EventAbstractionListener extends AbstractListener {
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,252 +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.BukkitUtil;
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 = BukkitUtil.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,7 +390,8 @@ public class RegionProtectionListener extends AbstractListener {
String what;
/* Hostile / ambient mob override */
if (Entities.isHostile(event.getEntity()) || Entities.isAmbient(event.getEntity()) || Entities.isNPC(event.getEntity())) {
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";
@@ -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
@@ -424,13 +434,14 @@ public class RegionProtectionListener extends AbstractListener {
// Block PvP like normal even if the player has an override permission
// because (1) this is a frequent source of confusion and
// (2) some users want to block PvP even with the bypass permission
boolean pvp = event.getEntity() instanceof Player && playerAttacker != null;
boolean pvp = event.getEntity() instanceof Player && playerAttacker != null && !playerAttacker.equals(event.getEntity());
if (isWhitelisted(event.getCause(), event.getWorld(), pvp)) {
return;
}
/* Hostile / ambient mob override */
if (Entities.isHostile(event.getEntity()) || Entities.isAmbient(event.getEntity())) {
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";
@@ -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()))) {
@@ -458,6 +470,11 @@ public class RegionProtectionListener extends AbstractListener {
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());
}
}
@@ -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();
}
}
@@ -46,7 +46,15 @@ public final class Materials {
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);
@@ -66,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);
@@ -197,7 +208,7 @@ 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);
@@ -241,7 +252,7 @@ public final class Materials {
try {
MATERIAL_FLAGS.put(Material.STANDING_BANNER, 0);
MATERIAL_FLAGS.put(Material.WALL_BANNER, 0);
MATERIAL_FLAGS.put(Material.DAYLIGHT_DETECTOR_INVERTED, 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);
@@ -391,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);
@@ -423,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);
@@ -644,11 +677,13 @@ public final class Materials {
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;
@@ -720,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;
}
/**
@@ -70,17 +70,19 @@ public class SchedulerReport extends DataReport {
@SuppressWarnings("unchecked")
@Nullable
private Class<?> getTaskClass(BukkitTask task) {
Class<?> clazz = task.getClass();
Set<Class<?>> classes = (Set) TypeToken.of(clazz).getTypes().rawTypes();
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()) {
return field.get().get(task).getClass();
Object res = field.get().get(task);
return res == null ? null : res.getClass();
}
}
} catch (IllegalAccessException ignored) {
} catch (NoClassDefFoundError ignored) {
}
return null;
@@ -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();
}
@@ -63,6 +63,7 @@ public class RegionResultSet extends AbstractRegionSet {
*/
public RegionResultSet(Set<ProtectedRegion> applicable, @Nullable ProtectedRegion globalRegion) {
this(NormativeOrders.fromSet(applicable), globalRegion, true);
this.regionSet = applicable;
}
/**
@@ -48,7 +48,7 @@ public class RegionOverlapAssociation implements RegionAssociable {
@Override
public Association getAssociation(List<ProtectedRegion> regions) {
for (ProtectedRegion region : regions) {
if (source.contains(region)) {
if ((region.getId().equals(ProtectedRegion.GLOBAL_REGION) && source.isEmpty()) || source.contains(region)) {
return Association.OWNER;
}
}
@@ -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;
/**
@@ -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
};
@@ -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;
@@ -56,13 +57,17 @@ 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>();
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
@@ -442,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,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());
}
}
}
@@ -40,6 +40,7 @@ public class CancelReport implements Report {
private final List<CancelAttempt> cancels;
private final HandlerTracer tracer;
private final int stackTruncateLength;
private boolean detectingPlugin = true;
public <T extends Event & Cancellable> CancelReport(T event, List<CancelAttempt> cancels, int stackTruncateLength) {
checkNotNull(event, "event");
@@ -51,6 +52,14 @@ public class CancelReport implements Report {
this.stackTruncateLength = stackTruncateLength;
}
public boolean isDetectingPlugin() {
return detectingPlugin;
}
public void setDetectingPlugin(boolean detectingPlugin) {
this.detectingPlugin = detectingPlugin;
}
private StackTraceElement[] truncateStackTrace(StackTraceElement[] elements) {
int newLength = elements.length - stackTruncateLength;
if (newLength <= 0) {
@@ -87,7 +96,7 @@ public class CancelReport implements Report {
builder.append(getCancelText(cancel.getAfter()));
builder.append(" by ");
if (cause != null) {
if (detectingPlugin && cause != null) {
builder.append(cause.getName());
} else {
builder.append(" (NOT KNOWN - use the stack trace below)");
@@ -21,8 +21,10 @@ package com.sk89q.worldguard.util.report;
import com.google.common.collect.Lists;
import java.util.*;
import java.util.function.UnaryOperator;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
public class ReportList implements Report, List<Report> {
@@ -103,16 +105,6 @@ public class ReportList implements Report, List<Report> {
return reports.retainAll(c);
}
@Override
public void replaceAll(UnaryOperator<Report> operator) {
reports.replaceAll(operator);
}
@Override
public void sort(Comparator<? super Report> c) {
reports.sort(c);
}
@Override
public void clear() {
reports.clear();