diff --git a/src/main/java/com/sk89q/worldguard/bukkit/RegionQuery.java b/src/main/java/com/sk89q/worldguard/bukkit/RegionQuery.java index 7b6a7fb4..9a4ef736 100644 --- a/src/main/java/com/sk89q/worldguard/bukkit/RegionQuery.java +++ b/src/main/java/com/sk89q/worldguard/bukkit/RegionQuery.java @@ -22,14 +22,16 @@ import com.sk89q.worldguard.LocalPlayer; import com.sk89q.worldguard.protection.ApplicableRegionSet; import com.sk89q.worldguard.protection.GlobalRegionManager; -import com.sk89q.worldguard.protection.flags.DefaultFlag; +import com.sk89q.worldguard.protection.flags.Flag; import com.sk89q.worldguard.protection.flags.StateFlag; +import com.sk89q.worldguard.protection.flags.StateFlag.State; import com.sk89q.worldguard.protection.managers.RegionManager; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.entity.Player; import javax.annotation.Nullable; +import java.util.Collection; import static com.google.common.base.Preconditions.checkNotNull; @@ -42,6 +44,7 @@ public class RegionQuery { private final WorldGuardPlugin plugin; private final ConfigurationManager config; + @SuppressWarnings("deprecation") private final GlobalRegionManager globalManager; private final QueryCache cache; @@ -66,15 +69,15 @@ public class RegionQuery { * Query for regions containing the given location. * *
An instance of {@link ApplicableRegionSet} will always be returned, - * even if regions are disabled or region data failed to load. The most - * appropriate implementation will be returned in such a case - * (for example, if regions are disable, the returned implementation + * even if regions are disabled or region data failed to load. An + * appropriate "virtual" set will be returned in such a case + * (for example, if regions are disabled, the returned set * would permit all activities).
* * @param location the location * @return a region set */ - public ApplicableRegionSet queryContains(Location location) { + public ApplicableRegionSet getApplicableRegions(Location location) { checkNotNull(location); World world = location.getWorld(); @@ -93,52 +96,22 @@ public ApplicableRegionSet queryContains(Location location) { } /** - * Test a the player can build at the given location, checking membership - * information and the state of the {@link DefaultFlag#BUILD} flag. - * - *This method is used to check blocks and entities for which there - * are no other related flags for (i.e. beds have the - * {@link DefaultFlag#SLEEP} flag).
- * - *If region data is not available (it failed to load or region support - * is disabled), then either {@code true} or {@code false} may be returned - * depending on the configuration.
+ * Test whether the given player is permitted to modify or interact with + * blocks at the given location. Additional flags to be considered can be + * provided. The {@code BUILD} flag is already included in the list of + * flags considered. * * @param location the location * @param player the player - * @return true if building is permitted - * @throws NullPointerException if there is no player for this query + * @param flags zero or more flags + * @return true if permission is granted + * @see ApplicableRegionSet#testBuild(LocalPlayer, StateFlag...) */ - public boolean testPermission(Location location, Player player) { - return testPermission(location, player, new StateFlag[0]); - } - - /** - * Test a the player can build at the given location, checking membership - * information, state of the {@link DefaultFlag#BUILD} flag, and the state - * of any passed flags. - * - *This method is used to check blocks and entities for which there - * are other related flags for (i.e. beds have the - * {@link DefaultFlag#SLEEP} flag). The criteria under which this method - * returns true is subject to change (i.e. all flags must be true or - * one cannot be DENY, etc.).
- * - *If region data is not available (it failed to load or region support - * is disabled), then either {@code true} or {@code false} may be returned - * depending on the configuration.
- * - * @param location the location to test - * @param player the player - * @param flags an array of flags - * @return true if the flag tests true - */ - public boolean testPermission(Location location, Player player, StateFlag... flags) { + public boolean testBuild(Location location, Player player, StateFlag... flags) { checkNotNull(location); checkNotNull(player); checkNotNull(flags); - LocalPlayer localPlayer = plugin.wrapPlayer(player); World world = location.getWorld(); WorldConfiguration worldConfig = config.get(world); @@ -150,61 +123,106 @@ public boolean testPermission(Location location, Player player, StateFlag... fla return true; } - RegionManager manager = globalManager.get(location.getWorld()); - - if (manager != null) { - ApplicableRegionSet result = cache.queryContains(manager, location); - - if (result.canBuild(localPlayer)) { - return true; - } - - for (StateFlag flag : flags) { - if (result.allows(flag, localPlayer)) { - return true; - } - } - - return false; - } else{ - return true; // null manager -> return true for now - } + LocalPlayer localPlayer = plugin.wrapPlayer(player); + return getApplicableRegions(location).testBuild(localPlayer, flags); } /** - * Test whether a {@link StateFlag} is evaluates to {@code ALLOW}. + * Get the effective value for a flag. If there are multiple values + * (for example, if there are multiple regions with the same priority + * but with different farewell messages set, there would be multiple + * completing values), then the selected (or "winning") value will depend + * on the flag type. * - *This method is to check whether certain functionality - * is enabled (i.e. water flow). The player, if provided, may be used - * in evaluation of the flag.
+ *This method does not properly process build + * permissions. Instead, use {@link #testBuild(Location, Player, StateFlag...)} + * for that purpose.
* - *If region data is not available (it failed to load or region support - * is disabled), then either {@code true} or {@code false} may be returned - * depending on the configuration.
+ *This method does the same as + * {@link #queryState(Location, Player, StateFlag...)} except that it + * returns a boolean when the result is {@code ALLOW}.
* * @param location the location - * @param player the player (or null) + * @param player an optional player, which would be used to determine the region group to apply * @param flag the flag - * @return true if the flag evaluates to {@code ALLOW} + * @return true if the result was {@code ALLOW} + * @see ApplicableRegionSet#queryValue(LocalPlayer, Flag) */ public boolean testState(Location location, @Nullable Player player, StateFlag flag) { - checkNotNull(location); - checkNotNull(flag); + return StateFlag.test(queryState(location, player, flag)); + } + /** + * Get the effective value for a list of state flags. The rules of + * states is observed here; that is, {@code DENY} overrides {@code ALLOW}, + * and {@code ALLOW} overrides {@code NONE}. + * + *This method does not properly process build + * permissions. Instead, use {@link #testBuild(Location, Player, StateFlag...)} + * for that purpose.
+ * + * See {@link ApplicableRegionSet#queryState(LocalPlayer, StateFlag...)} + * for more information. + * + * @param location the location + * @param player an optional player, which would be used to determine the region groups that apply + * @param flags a list of flags to check + * @return a state + * @see ApplicableRegionSet#queryState(LocalPlayer, StateFlag...) + */ + @Nullable + public State queryState(Location location, @Nullable Player player, StateFlag... flags) { LocalPlayer localPlayer = player != null ? plugin.wrapPlayer(player) : null; - World world = location.getWorld(); - WorldConfiguration worldConfig = config.get(world); + return getApplicableRegions(location).queryState(localPlayer, flags); + } - if (!worldConfig.useRegions) { - return true; - } + /** + * Get the effective value for a flag. If there are multiple values + * (for example, if there are multiple regions with the same priority + * but with different farewell messages set, there would be multiple + * completing values), then the selected (or "winning") value will depend + * on the flag type. + * + *This method does not properly process build + * permissions. Instead, use {@link #testBuild(Location, Player, StateFlag...)} + * for that purpose.
+ * + *See {@link ApplicableRegionSet#queryValue(LocalPlayer, Flag)} for + * more information.
+ * + * @param location the location + * @param player an optional player, which would be used to determine the region group to apply + * @param flag the flag + * @return a value, which could be {@code null} + * @see ApplicableRegionSet#queryValue(LocalPlayer, Flag) + */ + @Nullable + publicThis method does not properly process build + * permissions. Instead, use {@link #testBuild(Location, Player, StateFlag...)} + * for that purpose.
+ * + *See {@link ApplicableRegionSet#queryAllValues(LocalPlayer, Flag)} + * for more information.
+ * + * @param location the location + * @param player an optional player, which would be used to determine the region group to apply + * @param flag the flag + * @return a collection of values + * @see ApplicableRegionSet#queryAllValues(LocalPlayer, Flag) + */ + publicIf there are several relevant flags (i.e. in addition to + * {@code BUILD}, such as {@link DefaultFlag#SLEEP} when the target + * object is a bed), then + * {@link #testBuild(LocalPlayer, StateFlag...)} should be used.
+ * + * @param player the player to check + * @return true if permitted + * @deprecated use {@link #testBuild(LocalPlayer, StateFlag...)} */ + @Deprecated public boolean canBuild(LocalPlayer player) { checkNotNull(player); - return test(flagValueCalculator.testPermission(player, DefaultFlag.BUILD)); + return test(flagValueCalculator.queryPermission(player, DefaultFlag.BUILD)); + } + + /** + * Test whether the given player is permitted to modify or interact with + * blocks. Additional flags to be considered can be provided. The + * {@code BUILD} flag is already included in the list of flags considered. + * + * @param player the player + * @param flags zero or more flags + * @return true if permission is granted + */ + public boolean testBuild(LocalPlayer player, StateFlag... flags) { + return test(flagValueCalculator.queryPermission(player, ObjectArrays.concat(flags, DefaultFlag.BUILD))); + } + + /** + * Get the effective value for a list of state flags. The rules of + * states is observed here; that is, {@code DENY} overrides {@code ALLOW}, + * and {@code ALLOW} overrides {@code NONE}. + * + *This method does not properly process build + * permissions. Instead, use {@link #testBuild(LocalPlayer, StateFlag...)} + * for that purpose. This method is ideal for testing non-build related + * state flags (although a rarity), an example of which would be whether + * to play a song to players that enter an area.
+ * + *A player can be provided that is used to determine whether the value + * of a flag on a particular region should be used. For example, if a + * flag's region group is set to {@link RegionGroup#MEMBERS} and the given + * player is not a member, then the region would be skipped when + * querying that flag. If {@code null} is provided for the player, then + * only flags that use {@link RegionGroup#ALL}, + * {@link RegionGroup#NON_MEMBERS}, etc. will apply.
+ * + *This method does not use a {@link StateFlag}'s + * default value ({@link StateFlag#getDefault()}).
+ * + * @param player an optional player, which would be used to determine the region groups that apply + * @param flags a list of flags to check + * @return a state + */ + @Nullable + public State queryState(@Nullable LocalPlayer player, StateFlag... flags) { + return flagValueCalculator.queryState(player, flags); + } + + /** + * Get the effective value for a list of state flags. The rules of + * states is observed here; that is, {@code DENY} overrides {@code ALLOW}, + * and {@code ALLOW} overrides {@code NONE}. + * + *This method is the same as + * {@link #queryState(LocalPlayer, StateFlag...)} except that it returns + * a boolean when the return value is {@code ALLOW}.
+ * + * @param player an optional player, which would be used to determine the region groups that apply + * @param flags a list of flags to check + * @return true if the result was {@code ALLOW} + */ + public boolean testState(@Nullable LocalPlayer player, StateFlag... flags) { + return test(flagValueCalculator.queryState(player, flags)); + } + + /** + * Get the effective value for a flag. If there are multiple values + * (for example, if there are multiple regions with the same priority + * but with different farewell messages set, there would be multiple + * completing values), then the selected (or "winning") value will depend + * on the flag type. + * + *Only some flag types actually have a strategy for picking the + * "best value." For most types, the actual value that is chosen to be + * returned is undefined (it could be any value). As of writing, the only + * type of flag that can consistently return the same 'best' value is + * {@link StateFlag}.
+ * + *This method does not properly process build + * permissions. Instead, use {@link #testBuild(LocalPlayer, StateFlag...)} + * for that purpose.
+ * + *A player can be provided that is used to determine whether the value + * of a flag on a particular region should be used. For example, if a + * flag's region group is set to {@link RegionGroup#MEMBERS} and the given + * player is not a member, then the region would be skipped when + * querying that flag. If {@code null} is provided for the player, then + * only flags that use {@link RegionGroup#ALL}, + * {@link RegionGroup#NON_MEMBERS}, etc. will apply.
+ * + *This method does not use a {@link StateFlag}'s + * default value ({@link StateFlag#getDefault()}) if the provided flag is + * a {@code StateFlag}.
+ * + * @param player an optional player, which would be used to determine the region group to apply + * @param flag the flag + * @return a value, which could be {@code null} + */ + @Nullable + publicThis method does not properly process build + * permissions. Instead, use {@link #testBuild(LocalPlayer, StateFlag...)} + * for that purpose.
+ * + *A player can be provided that is used to determine whether the value + * of a flag on a particular region should be used. For example, if a + * flag's region group is set to {@link RegionGroup#MEMBERS} and the given + * player is not a member, then the region would be skipped when + * querying that flag. If {@code null} is provided for the player, then + * only flags that use {@link RegionGroup#ALL}, + * {@link RegionGroup#NON_MEMBERS}, etc. will apply.
+ * + *This method does not include a {@link StateFlag}'s + * default value ({@link StateFlag#getDefault()}) if the provided flag is + * a {@code StateFlag}.
+ * + * @param player an optional player, which would be used to determine the region group to apply + * @param flag the flag + * @return a collection of values + */ + publicThis method handles that example perfectly. To use the method for * the example, the call would look like this:
* - *testPermission(player, DefaultFlag.BUILD, DefaultFlag.CHEST_ACCESS)+ *
queryPermission(player, DefaultFlag.BUILD, DefaultFlag.CHEST_ACCESS)* * @param player the player * @param flags zero or more flags * @return true if permission is granted */ - public State testPermission(LocalPlayer player, StateFlag... flags) { + public State queryPermission(LocalPlayer player, StateFlag... flags) { checkNotNull(player); checkNotNull(flags); @@ -233,7 +233,7 @@ public State testPermission(LocalPlayer player, StateFlag... flags) { * and {@code ALLOW} overrides {@code NONE}. * *
This method does not properly process build - * permissions. Instead, use {@link #testPermission(LocalPlayer, StateFlag...)} + * permissions. Instead, use {@link #queryPermission(LocalPlayer, StateFlag...)} * for that purpose. This method is ideal for testing non-build related * state flags (although a rarity), an example of which would be whether * to play a song to players that enter an area.
@@ -278,7 +278,7 @@ public State queryState(@Nullable LocalPlayer player, StateFlag... flags) { * {@link StateFlag}. * *This method does not properly process build - * permissions. Instead, use {@link #testPermission(LocalPlayer, StateFlag...)} + * permissions. Instead, use {@link #queryPermission(LocalPlayer, StateFlag...)} * for that purpose.
* *A player can be provided that is used to determine whether the value
@@ -305,7 +305,7 @@ public This method does not properly process build
- * permissions. Instead, use {@link #testPermission(LocalPlayer, StateFlag...)}
+ * permissions. Instead, use {@link #queryPermission(LocalPlayer, StateFlag...)}
* for that purpose. A player can be provided that is used to determine whether the value
@@ -315,6 +315,10 @@ public