Add testBuild API to ARS and clean up flag querying

This commit is contained in:
stonar96 2023-04-07 19:32:57 +02:00
parent b67fd01ebd
commit e7870d4997
9 changed files with 449 additions and 700 deletions

View File

@ -19,34 +19,6 @@
package com.sk89q.worldguard.protection;
import static com.sk89q.worldguard.protection.flags.StateFlag.test;
import com.sk89q.worldguard.protection.association.RegionAssociable;
import com.sk89q.worldguard.protection.flags.StateFlag;
import com.sk89q.worldguard.protection.flags.StateFlag.State;
import javax.annotation.Nullable;
public abstract class AbstractRegionSet implements ApplicableRegionSet {
@Override
public boolean testState(@Nullable RegionAssociable subject, StateFlag... flags) {
return test(queryState(subject, flags));
}
@Nullable
@Override
public State queryState(@Nullable RegionAssociable subject, StateFlag... flags) {
State value = null;
for (StateFlag flag : flags) {
value = StateFlag.combine(value, queryValue(subject, flag));
if (value == State.DENY) {
break;
}
}
return value;
}
}

View File

@ -20,18 +20,9 @@
package com.sk89q.worldguard.protection;
import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.protection.association.RegionAssociable;
import com.sk89q.worldguard.protection.flags.Flags;
import com.sk89q.worldguard.protection.flags.Flag;
import com.sk89q.worldguard.protection.flags.MapFlag;
import com.sk89q.worldguard.protection.flags.RegionGroup;
import com.sk89q.worldguard.protection.flags.StateFlag;
import com.sk89q.worldguard.protection.flags.StateFlag.State;
import com.sk89q.worldguard.protection.managers.RegionManager;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import javax.annotation.Nullable;
import java.util.Collection;
import java.util.Set;
/**
@ -41,7 +32,7 @@ import java.util.Set;
* <p>An instance of this can be created using the spatial query methods
* available on {@link RegionManager}.</p>
*/
public interface ApplicableRegionSet extends Iterable<ProtectedRegion> {
public interface ApplicableRegionSet extends FlagQuery, Iterable<ProtectedRegion> {
/**
* Return whether this region set is a virtual set. A virtual set
@ -61,127 +52,6 @@ public interface ApplicableRegionSet extends Iterable<ProtectedRegion> {
*/
boolean isVirtual();
/**
* Test whether the (effective) value for a list of state flags equals
* {@code ALLOW}.
*
* <p>{@code subject} can be non-null to satisfy region group requirements,
* otherwise it will be assumed that the caller that is not a member of any
* regions. (Flags on a region can be changed so that they only apply
* to certain users.) The subject argument is required if the
* {@link Flags#BUILD} flag is in the list of flags.</p>
*
* @param subject an optional subject, 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}
* @see #queryState(RegionAssociable, StateFlag...)
*/
boolean testState(@Nullable RegionAssociable subject, StateFlag... 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}. One flag may override another.
*
* <p>{@code subject} can be non-null to satisfy region group requirements,
* otherwise it will be assumed that the caller that is not a member of any
* regions. (Flags on a region can be changed so that they only apply
* to certain users.) The subject argument is required if the
* {@link Flags#BUILD} flag is in the list of flags.</p>
*
* @param subject an optional subject, which would be used to determine the region groups that apply
* @param flags a list of flags to check
* @return a state
*/
@Nullable
State queryState(@Nullable RegionAssociable subject, StateFlag... flags);
/**
* Get the effective value for a flag. If there are multiple values
* (for example, multiple overlapping regions with
* the same priority may have the same flag set), then the selected
* (or "winning") value will depend on the flag type.
*
* <p>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 actually has a strategy for picking a value is the
* {@link StateFlag}.</p>
*
* <p>{@code subject} can be non-null to satisfy region group requirements,
* otherwise it will be assumed that the caller that is not a member of any
* regions. (Flags on a region can be changed so that they only apply
* to certain users.) The subject argument is required if the
* {@link Flags#BUILD} flag is the flag being queried.</p>
*
* @param subject an optional subject, which would be used to determine the region group to apply
* @param flag the flag
* @return a value, which could be {@code null}
*/
@Nullable
<V> V queryValue(@Nullable RegionAssociable subject, Flag<V> flag);
/**
* Get the effective value for a key in a {@link MapFlag}. 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 be undefined.
*
* <p>A subject can be provided that is used to determine whether the value
* of a flag on a particular region should be used. For example, if a
* flag's region group is set to {@link RegionGroup#MEMBERS} and the given
* subject is not a member, then the region would be skipped when
* querying that flag. If {@code null} is provided for the subject, then
* only flags that use {@link RegionGroup#ALL},
* {@link RegionGroup#NON_MEMBERS}, etc. will apply.</p>
*
* @param subject an optional subject, which would be used to determine the region group to apply
* @param flag the flag of type {@link MapFlag}
* @param key the key for the map flag
* @return a value, which could be {@code null}
*/
@Nullable
<V, K> V queryMapValue(@Nullable RegionAssociable subject, MapFlag<K, V> flag, K key);
/**
* Get the effective value for a key in a {@link MapFlag}. 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 be undefined.
*
* <p>A subject can be provided that is used to determine whether the value
* of a flag on a particular region should be used. For example, if a
* flag's region group is set to {@link RegionGroup#MEMBERS} and the given
* subject is not a member, then the region would be skipped when
* querying that flag. If {@code null} is provided for the subject, then
* only flags that use {@link RegionGroup#ALL},
* {@link RegionGroup#NON_MEMBERS}, etc. will apply.</p>
*
* @param subject an optional subject, which would be used to determine the region group to apply
* @param flag the flag of type {@link MapFlag}
* @param key the key for the map flag
* @return a value, which could be {@code null}
*/
@Nullable
<V, K> V queryMapValue(@Nullable RegionAssociable subject, MapFlag<K, V> flag, K key, @Nullable Flag<V> fallback);
/**
* Get the effective values for a flag, returning a collection of all
* values. It is up to the caller to determine which value, if any,
* from the collection will be used.
*
* <p>{@code subject} can be non-null to satisfy region group requirements,
* otherwise it will be assumed that the caller that is not a member of any
* regions. (Flags on a region can be changed so that they only apply
* to certain users.) The subject argument is required if the
* {@link Flags#BUILD} flag is the flag being queried.</p>
*
* @param subject an optional subject, which would be used to determine the region group to apply
* @param flag the flag
* @return a collection of values
*/
<V> Collection<V> queryAllValues(@Nullable RegionAssociable subject, Flag<V> flag);
/**
* Test whether a player is an owner of all regions in this set.
*

View File

@ -0,0 +1,50 @@
/*
* WorldGuard, a suite of tools for Minecraft
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldGuard team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldguard.protection;
import com.google.common.collect.ImmutableList;
import com.sk89q.worldguard.protection.association.RegionAssociable;
import com.sk89q.worldguard.protection.flags.Flag;
import com.sk89q.worldguard.protection.flags.MapFlag;
import javax.annotation.Nullable;
import java.util.Collection;
import java.util.Map;
/**
* Default implementation of {@link FlagQuery}, returning flag default values.
*/
public interface DefaultFlagQuery extends FlagQuery {
@Override
@Nullable
default <V, K> V queryMapValue(@Nullable RegionAssociable subject, MapFlag<K, V> flag, K key, @Nullable Flag<V> fallback) {
Map<K, V> defaultVal = flag.getDefault();
return defaultVal != null ? defaultVal.get(key) : fallback != null ? fallback.getDefault() : null;
}
@SuppressWarnings("unchecked")
@Override
default <V> Collection<V> queryAllValues(@Nullable RegionAssociable subject, Flag<V> flag, boolean acceptOne) {
V fallback = flag.getDefault();
return fallback != null ? ImmutableList.of(fallback) : (Collection<V>) ImmutableList.of();
}
}

View File

@ -24,7 +24,6 @@ import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.protection.association.RegionAssociable;
import com.sk89q.worldguard.protection.flags.Flags;
import com.sk89q.worldguard.protection.flags.Flag;
import com.sk89q.worldguard.protection.flags.MapFlag;
import com.sk89q.worldguard.protection.flags.StateFlag.State;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
@ -32,14 +31,13 @@ import javax.annotation.Nullable;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
/**
* A region set that is to be used when region data has failed. Operations
* are blocked.
*/
public class FailedLoadRegionSet extends AbstractRegionSet {
public class FailedLoadRegionSet extends AbstractRegionSet implements DefaultFlagQuery {
private static final FailedLoadRegionSet INSTANCE = new FailedLoadRegionSet();
@ -56,40 +54,14 @@ public class FailedLoadRegionSet extends AbstractRegionSet {
}
@SuppressWarnings("unchecked")
@Nullable
@Override
public <V> V queryValue(@Nullable RegionAssociable subject, Flag<V> flag) {
if (flag == Flags.BUILD) {
return (V) State.DENY;
} else if (flag == Flags.DENY_MESSAGE) {
return (V) denyMessage;
}
return flag.getDefault();
}
@Nullable
@Override
public <V, K> V queryMapValue(@Nullable RegionAssociable subject, MapFlag<K, V> flag, K key) {
return queryMapValue(subject, flag, key, null);
}
@Nullable
@Override
public <V, K> V queryMapValue(@Nullable RegionAssociable subject, MapFlag<K, V> flag, K key, @Nullable Flag<V> fallback) {
Map<K, V> defaultVal = flag.getDefault();
return defaultVal != null ? defaultVal.get(key) : fallback != null ? fallback.getDefault() : null;
}
@SuppressWarnings("unchecked")
@Override
public <V> Collection<V> queryAllValues(@Nullable RegionAssociable subject, Flag<V> flag) {
public <V> Collection<V> queryAllValues(@Nullable RegionAssociable subject, Flag<V> flag, boolean acceptOne) {
if (flag == Flags.BUILD) {
return (Collection<V>) ImmutableList.of(State.DENY);
} else if (flag == Flags.DENY_MESSAGE) {
return (Collection<V>) denyMessageCollection;
}
V fallback = flag.getDefault();
return fallback != null ? ImmutableList.of(fallback) : (Collection<V>) ImmutableList.of();
return DefaultFlagQuery.super.queryAllValues(subject, flag, acceptOne);
}
@Override

View File

@ -0,0 +1,282 @@
/*
* WorldGuard, a suite of tools for Minecraft
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldGuard team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldguard.protection;
import static com.sk89q.worldguard.protection.flags.StateFlag.combine;
import static com.sk89q.worldguard.protection.flags.StateFlag.denyToNone;
import static com.sk89q.worldguard.protection.flags.StateFlag.test;
import com.sk89q.worldguard.protection.association.RegionAssociable;
import com.sk89q.worldguard.protection.flags.Flag;
import com.sk89q.worldguard.protection.flags.Flags;
import com.sk89q.worldguard.protection.flags.MapFlag;
import com.sk89q.worldguard.protection.flags.RegionGroup;
import com.sk89q.worldguard.protection.flags.StateFlag;
import com.sk89q.worldguard.protection.flags.StateFlag.State;
import javax.annotation.Nullable;
import java.util.Collection;
/**
* Common methods for querying flags.
*/
public interface FlagQuery {
/**
* Returns true if the BUILD flag allows the action, but it
* can be overridden by a list of other flags. The BUILD flag will not
* override the other flags, but the other flags can override BUILD. If
* neither BUILD or any of the flags permit the action, then false will
* be returned.
*
* <p>Use this method when checking flags that are related to build
* protection. For example, lighting fire in a region should not be
* permitted unless the player is a member of the region or the
* LIGHTER flag allows it. However, the LIGHTER flag should be able
* to allow lighting fires even if BUILD is set to DENY.</p>
*
* <p>How this method works (BUILD can be overridden by other flags but
* not the other way around) is inconsistent, but it's required for
* legacy reasons.</p>
*
* <p>This method does not check the region bypass permission. That must
* be done by the calling code.</p>
*
* @param subject the subject
* @param flags the flags
* @return true if the result was {@code ALLOW}
*/
default boolean testBuild(RegionAssociable subject, StateFlag... flags) {
if (flags.length == 0) {
return testState(subject, Flags.BUILD);
}
return test(
denyToNone(queryState(subject, Flags.BUILD)),
queryState(subject, flags));
}
/**
* Returns true if the BUILD flag allows the action, but it
* can be overridden by a list of other flags. The BUILD flag will not
* override the other flags, but the other flags can override BUILD. If
* neither BUILD or any of the flags permit the action, then false will
* be returned.
*
* <p>Use this method when checking flags that are related to build
* protection. For example, lighting fire in a region should not be
* permitted unless the player is a member of the region or the
* LIGHTER flag allows it. However, the LIGHTER flag should be able
* to allow lighting fires even if BUILD is set to DENY.</p>
*
* <p>This method does include parameters for a {@link MapFlag}.</p>
*
* <p>How this method works (BUILD can be overridden by other flags but
* not the other way around) is inconsistent, but it's required for
* legacy reasons.</p>
*
* <p>This method does not check the region bypass permission. That must
* be done by the calling code.</p>
*
* @param subject the subject
* @param flag the MapFlag
* @param key the key for the MapFlag
* @param fallback the fallback flag for MapFlag
* @param flags the flags
* @return true if the result was {@code ALLOW}
*/
default <K> boolean testBuild(RegionAssociable subject, MapFlag<K, State> flag, K key,
@Nullable StateFlag fallback, StateFlag... flags) {
if (flag == null)
return testBuild(subject, flags);
if (flags.length == 0) {
return test(
denyToNone(queryState(subject, Flags.BUILD)),
queryMapValue(subject, flag, key, fallback)
);
}
return test(
denyToNone(queryState(subject, Flags.BUILD)),
queryMapValue(subject, flag, key, fallback),
queryState(subject, flags)
);
}
/**
* Test whether the (effective) value for a list of state flags equals
* {@code ALLOW}.
*
* <p>{@code subject} can be non-null to satisfy region group requirements,
* otherwise it will be assumed that the caller that is not a member of any
* regions. (Flags on a region can be changed so that they only apply
* to certain users.) The subject argument is required if the
* {@link Flags#BUILD} flag is in the list of flags.</p>
*
* @param subject an optional subject, 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}
*/
default boolean testState(@Nullable RegionAssociable subject, StateFlag... flags) {
return test(queryState(subject, 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}. One flag may override another.
*
* <p>{@code subject} can be non-null to satisfy region group requirements,
* otherwise it will be assumed that the caller that is not a member of any
* regions. (Flags on a region can be changed so that they only apply
* to certain users.) The subject argument is required if the
* {@link Flags#BUILD} flag is in the list of flags.</p>
*
* @param subject an optional subject, which would be used to determine the region groups that apply
* @param flags a list of flags to check
* @return a state
*/
@Nullable
default State queryState(@Nullable RegionAssociable subject, StateFlag... flags) {
State value = null;
for (StateFlag flag : flags) {
value = combine(value, queryValue(subject, flag));
if (value == State.DENY) {
break;
}
}
return value;
}
/**
* Get the effective value for a flag. If there are multiple values
* (for example, multiple overlapping regions with
* the same priority may have the same flag set), then the selected
* (or "winning") value will depend on the flag type.
*
* <p>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 actually has a strategy for picking a value is the
* {@link StateFlag}.</p>
*
* <p>{@code subject} can be non-null to satisfy region group requirements,
* otherwise it will be assumed that the caller that is not a member of any
* regions. (Flags on a region can be changed so that they only apply
* to certain users.) The subject argument is required if the
* {@link Flags#BUILD} flag is the flag being queried.</p>
*
* @param subject an optional subject, which would be used to determine the region group to apply
* @param flag the flag
* @return a value, which could be {@code null}
*/
@Nullable
default <V> V queryValue(@Nullable RegionAssociable subject, Flag<V> flag) {
Collection<V> values = queryAllValues(subject, flag, true);
return flag.chooseValue(values);
}
/**
* Get the effective value for a key in a {@link MapFlag}. 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 be undefined.
*
* <p>A subject can be provided that is used to determine whether the value
* of a flag on a particular region should be used. For example, if a
* flag's region group is set to {@link RegionGroup#MEMBERS} and the given
* subject is not a member, then the region would be skipped when
* querying that flag. If {@code null} is provided for the subject, then
* only flags that use {@link RegionGroup#ALL},
* {@link RegionGroup#NON_MEMBERS}, etc. will apply.</p>
*
* @param subject an optional subject, which would be used to determine the region group to apply
* @param flag the flag of type {@link MapFlag}
* @param key the key for the map flag
* @return a value, which could be {@code null}
*/
@Nullable
default <V, K> V queryMapValue(@Nullable RegionAssociable subject, MapFlag<K, V> flag, K key) {
return queryMapValue(subject, flag, key, null);
}
/**
* Get the effective value for a key in a {@link MapFlag}. 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 be undefined.
*
* <p>A subject can be provided that is used to determine whether the value
* of a flag on a particular region should be used. For example, if a
* flag's region group is set to {@link RegionGroup#MEMBERS} and the given
* subject is not a member, then the region would be skipped when
* querying that flag. If {@code null} is provided for the subject, then
* only flags that use {@link RegionGroup#ALL},
* {@link RegionGroup#NON_MEMBERS}, etc. will apply.</p>
*
* @param subject an optional subject, which would be used to determine the region group to apply
* @param flag the flag of type {@link MapFlag}
* @param key the key for the map flag
* @return a value, which could be {@code null}
*/
@Nullable
<V, K> V queryMapValue(@Nullable RegionAssociable subject, MapFlag<K, V> flag, K key, @Nullable Flag<V> fallback);
/**
* Get the effective values for a flag, returning a collection of all
* values. It is up to the caller to determine which value, if any,
* from the collection will be used.
*
* <p>{@code subject} can be non-null to satisfy region group requirements,
* otherwise it will be assumed that the caller that is not a member of any
* regions. (Flags on a region can be changed so that they only apply
* to certain users.) The subject argument is required if the
* {@link Flags#BUILD} flag is the flag being queried.</p>
*
* @param subject an optional subject, which would be used to determine the region group to apply
* @param flag the flag
* @return a collection of values
*/
default <V> Collection<V> queryAllValues(@Nullable RegionAssociable subject, Flag<V> flag) {
return queryAllValues(subject, flag, false);
}
/**
* Get the effective values for a flag, returning a collection of all
* values. It is up to the caller to determine which value, if any,
* from the collection will be used.
*
* <p>{@code subject} can be non-null to satisfy region group requirements,
* otherwise it will be assumed that the caller that is not a member of any
* regions. (Flags on a region can be changed so that they only apply
* to certain users.) The subject argument is required if the
* {@link Flags#BUILD} flag is the flag being queried.</p>
*
* @param subject an optional subject, which would be used to determine the region group to apply
* @param flag the flag
* @param acceptOne if possible, return only one value if it doesn't matter
* @return a collection of values
*/
<V> Collection<V> queryAllValues(@Nullable RegionAssociable subject, Flag<V> flag, boolean acceptOne);
}

View File

@ -24,8 +24,8 @@ import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
import com.sk89q.worldguard.domains.Association;
import com.sk89q.worldguard.protection.association.RegionAssociable;
import com.sk89q.worldguard.protection.flags.Flags;
import com.sk89q.worldguard.protection.flags.Flag;
import com.sk89q.worldguard.protection.flags.Flags;
import com.sk89q.worldguard.protection.flags.MapFlag;
import com.sk89q.worldguard.protection.flags.RegionGroup;
import com.sk89q.worldguard.protection.flags.StateFlag;
@ -56,7 +56,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
* value of a flag is far from trivial. This class abstracts away the
* difficult with a number of methods for performing these calculations.</p>
*/
public class FlagValueCalculator {
public class FlagValueCalculator implements FlagQuery {
@Nullable
private final ProtectedRegion globalRegion;
@ -148,107 +148,28 @@ public class FlagValueCalculator {
return result;
}
/**
* 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}.
*
* <p>A subject can be provided that is used to determine whether the value
* of a flag on a particular region should be used. For example, if a
* flag's region group is set to {@link RegionGroup#MEMBERS} and the given
* subject is not a member, then the region would be skipped when
* querying that flag. If {@code null} is provided for the subject, then
* only flags that use {@link RegionGroup#ALL},
* {@link RegionGroup#NON_MEMBERS}, etc. will apply.</p>
*
* @param subject an optional subject, which would be used to determine the region group to apply
* @param flags a list of flags to check
* @return a state
*/
@Nullable
public State queryState(@Nullable RegionAssociable subject, StateFlag... flags) {
State value = null;
for (StateFlag flag : flags) {
value = StateFlag.combine(value, queryValue(subject, flag));
if (value == State.DENY) {
break;
}
}
return value;
}
/**
* Get the effective value for a list of state flags. The rules of
* Get the (effective) value for a state flag. The rules of
* states is observed here; that is, {@code DENY} overrides {@code ALLOW},
* and {@code ALLOW} overrides {@code NONE}.
*
* <p>This method is the same as
* {@link #queryState(RegionAssociable, StateFlag...)}.</p>
*
* @param subject an optional subject, which would be used to determine the region group to apply
* @param subject an optional subject, which would be used to determine the region groups that apply
* @param flag a flag to check
* @return a state
* @deprecated use {@link #queryState(RegionAssociable, StateFlag...)} instead, will be removed in WorldGuard 8
*/
@Deprecated(forRemoval = true)
@Nullable
public State queryState(@Nullable RegionAssociable subject, StateFlag flag) {
return queryValue(subject, flag);
}
/**
* 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.
*
* <p>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}.</p>
*
* <p>A subject can be provided that is used to determine whether the value
* of a flag on a particular region should be used. For example, if a
* flag's region group is set to {@link RegionGroup#MEMBERS} and the given
* subject is not a member, then the region would be skipped when
* querying that flag. If {@code null} is provided for the subject, then
* only flags that use {@link RegionGroup#ALL},
* {@link RegionGroup#NON_MEMBERS}, etc. will apply.</p>
*
* @param subject an optional subject, which would be used to determine the region group to apply
* @param flag the flag
* @return a value, which could be {@code null}
*/
@Override
@Nullable
public <V> V queryValue(@Nullable RegionAssociable subject, Flag<V> flag) {
Collection<V> values = queryAllValues(subject, flag, true);
return flag.chooseValue(values);
}
/**
* Get the effective value for a key in a {@link MapFlag}. 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 be undefined.
*
* <p>A subject can be provided that is used to determine whether the value
* of a flag on a particular region should be used. For example, if a
* flag's region group is set to {@link RegionGroup#MEMBERS} and the given
* subject is not a member, then the region would be skipped when
* querying that flag. If {@code null} is provided for the subject, then
* only flags that use {@link RegionGroup#ALL},
* {@link RegionGroup#NON_MEMBERS}, etc. will apply.</p>
*
* @param subject an optional subject, which would be used to determine the region group to apply
* @param flag the flag of type {@link MapFlag}
* @param key the key for the map flag
* @return a value, which could be {@code null}
*/
@Nullable
public <V, K> V queryMapValue(@Nullable RegionAssociable subject, MapFlag<K, V> flag, K key, Flag<V> fallback) {
public <V, K> V queryMapValue(@Nullable RegionAssociable subject, MapFlag<K, V> flag, K key, @Nullable Flag<V> fallback) {
checkNotNull(flag);
checkNotNull(key);
@ -297,27 +218,27 @@ public class FlagValueCalculator {
}
@Nullable
public <V, K> V getEffectiveMapValue(ProtectedRegion region, MapFlag<K, V> mapFlag, K key, RegionAssociable subject) {
return getEffectiveMapValueOf(region, mapFlag, key, subject);
public <V, K> V getEffectiveMapValue(ProtectedRegion region, MapFlag<K, V> flag, K key, RegionAssociable subject) {
return getEffectiveMapValueOf(region, flag, key, subject);
}
@Nullable
public static <V, K> V getEffectiveMapValueOf(ProtectedRegion region, MapFlag<K, V> mapFlag, K key, RegionAssociable subject) {
public static <V, K> V getEffectiveMapValueOf(ProtectedRegion region, MapFlag<K, V> flag, K key, RegionAssociable subject) {
List<ProtectedRegion> seen = new ArrayList<>();
ProtectedRegion current = region;
while (current != null) {
seen.add(current);
Map<K, V> mapValue = current.getFlag(mapFlag);
Map<K, V> mapValue = current.getFlag(flag);
if (mapValue != null && mapValue.containsKey(key)) {
boolean use = true;
if (mapFlag.getRegionGroupFlag() != null) {
RegionGroup group = current.getFlag(mapFlag.getRegionGroupFlag());
if (flag.getRegionGroupFlag() != null) {
RegionGroup group = current.getFlag(flag.getRegionGroupFlag());
if (group == null) {
group = mapFlag.getRegionGroupFlag().getDefault();
group = flag.getRegionGroupFlag().getDefault();
}
if (group == null) {
@ -339,47 +260,9 @@ public class FlagValueCalculator {
return null;
}
/**
* Get the effective values for a flag, returning a collection of all
* values. It is up to the caller to determine which value, if any,
* from the collection will be used.
*
* <p>A subject can be provided that is used to determine whether the value
* of a flag on a particular region should be used. For example, if a
* flag's region group is set to {@link RegionGroup#MEMBERS} and the given
* subject is not a member, then the region would be skipped when
* querying that flag. If {@code null} is provided for the subject, then
* only flags that use {@link RegionGroup#ALL},
* {@link RegionGroup#NON_MEMBERS}, etc. will apply.</p>
*
* @param subject an optional subject, which would be used to determine the region group to apply
* @param flag the flag
* @return a collection of values
*/
public <V> Collection<V> queryAllValues(@Nullable RegionAssociable subject, Flag<V> flag) {
return queryAllValues(subject, flag, false);
}
/**
* Get the effective values for a flag, returning a collection of all
* values. It is up to the caller to determine which value, if any,
* from the collection will be used.
*
* <p>A subject can be provided that is used to determine whether the value
* of a flag on a particular region should be used. For example, if a
* flag's region group is set to {@link RegionGroup#MEMBERS} and the given
* subject is not a member, then the region would be skipped when
* querying that flag. If {@code null} is provided for the subject, then
* only flags that use {@link RegionGroup#ALL},
* {@link RegionGroup#NON_MEMBERS}, etc. will apply.</p>
*
* @param subject an optional subject, which would be used to determine the region group to apply
* @param flag the flag
* @param acceptOne if possible, return only one value if it doesn't matter
* @return a collection of values
*/
@SuppressWarnings("unchecked")
private <V> Collection<V> queryAllValues(@Nullable RegionAssociable subject, Flag<V> flag, boolean acceptOne) {
@Override
public <V> Collection<V> queryAllValues(@Nullable RegionAssociable subject, Flag<V> flag, boolean acceptOne) {
checkNotNull(flag);
// Can't use this optimization with flags that have a conflict resolution strategy

View File

@ -19,27 +19,18 @@
package com.sk89q.worldguard.protection;
import com.google.common.collect.ImmutableList;
import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.protection.association.RegionAssociable;
import com.sk89q.worldguard.protection.flags.Flags;
import com.sk89q.worldguard.protection.flags.Flag;
import com.sk89q.worldguard.protection.flags.MapFlag;
import com.sk89q.worldguard.protection.flags.StateFlag.State;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import javax.annotation.Nullable;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
/**
* A virtual region result set that is highly permissive, considering everyone
* a member. Returned flag values are default values (when available).
*/
public class PermissiveRegionSet extends AbstractRegionSet {
public class PermissiveRegionSet extends AbstractRegionSet implements DefaultFlagQuery {
private static final PermissiveRegionSet INSTANCE = new PermissiveRegionSet();
@ -51,39 +42,6 @@ public class PermissiveRegionSet extends AbstractRegionSet {
return true;
}
@SuppressWarnings("unchecked")
@Nullable
@Override
public <V> V queryValue(@Nullable RegionAssociable subject, Flag<V> flag) {
if (flag == Flags.BUILD) {
return (V) State.DENY;
}
return flag.getDefault();
}
@Nullable
@Override
public <V, K> V queryMapValue(@Nullable RegionAssociable subject, MapFlag<K, V> flag, K key) {
return queryMapValue(subject, flag, key, null);
}
@Nullable
@Override
public <V, K> V queryMapValue(@Nullable RegionAssociable subject, MapFlag<K, V> flag, K key, @Nullable Flag<V> fallback) {
Map<K, V> defaultVal = flag.getDefault();
return defaultVal != null ? defaultVal.get(key) : fallback != null ? fallback.getDefault() : null;
}
@SuppressWarnings("unchecked")
@Override
public <V> Collection<V> queryAllValues(@Nullable RegionAssociable subject, Flag<V> flag) {
if (flag == Flags.BUILD) {
return (Collection<V>) ImmutableList.of(State.DENY);
}
V fallback = flag.getDefault();
return fallback != null ? ImmutableList.of(fallback) : (Collection<V>) ImmutableList.of();
}
@Override
public boolean isOwnerOfAll(LocalPlayer player) {
return true;

View File

@ -24,8 +24,6 @@ import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.protection.association.RegionAssociable;
import com.sk89q.worldguard.protection.flags.Flag;
import com.sk89q.worldguard.protection.flags.MapFlag;
import com.sk89q.worldguard.protection.flags.StateFlag;
import com.sk89q.worldguard.protection.flags.StateFlag.State;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import com.sk89q.worldguard.protection.util.NormativeOrders;
@ -98,31 +96,13 @@ public class RegionResultSet extends AbstractRegionSet {
}
@Override
@Nullable
public State queryState(@Nullable RegionAssociable subject, StateFlag... flags) {
return flagValueCalculator.queryState(subject, flags);
public <V> Collection<V> queryAllValues(@Nullable RegionAssociable subject, Flag<V> flag, boolean acceptOne) {
return flagValueCalculator.queryAllValues(subject, flag, acceptOne);
}
@Override
@Nullable
public <V> V queryValue(@Nullable RegionAssociable subject, Flag<V> flag) {
return flagValueCalculator.queryValue(subject, flag);
}
@Override
public <V> Collection<V> queryAllValues(@Nullable RegionAssociable subject, Flag<V> flag) {
return flagValueCalculator.queryAllValues(subject, flag);
}
@Override
@Nullable
public <V, K> V queryMapValue(@Nullable RegionAssociable subject, MapFlag<K, V> flag, K key) {
return flagValueCalculator.queryMapValue(subject, flag, key, null);
}
@Override
@Nullable
public <V, K> V queryMapValue(@Nullable RegionAssociable subject, MapFlag<K, V> flag, K key, Flag<V> fallback) {
public <V, K> V queryMapValue(@Nullable RegionAssociable subject, MapFlag<K, V> flag, K key, @Nullable Flag<V> fallback) {
return flagValueCalculator.queryMapValue(subject, flag, key, fallback);
}

View File

@ -34,9 +34,7 @@ import com.sk89q.worldguard.protection.PermissiveRegionSet;
import com.sk89q.worldguard.protection.RegionResultSet;
import com.sk89q.worldguard.protection.association.RegionAssociable;
import com.sk89q.worldguard.protection.flags.Flag;
import com.sk89q.worldguard.protection.flags.Flags;
import com.sk89q.worldguard.protection.flags.MapFlag;
import com.sk89q.worldguard.protection.flags.RegionGroup;
import com.sk89q.worldguard.protection.flags.StateFlag;
import com.sk89q.worldguard.protection.flags.StateFlag.State;
import com.sk89q.worldguard.protection.managers.RegionManager;
@ -131,293 +129,107 @@ public class RegionQuery {
}
/**
* Returns true if the BUILD flag allows the action in the location, but it
* can be overridden by a list of other flags. The BUILD flag will not
* override the other flags, but the other flags can override BUILD. If
* neither BUILD or any of the flags permit the action, then false will
* be returned.
* Convenience method for
* {@link #getApplicableRegions(Location)}{@link ApplicableRegionSet#testBuild(RegionAssociable, StateFlag...)
* .testBuild(RegionAssociable, StateFlag...)}
*
* <p>Use this method when checking flags that are related to build
* protection. For example, lighting fire in a region should not be
* permitted unless the player is a member of the region or the
* LIGHTER flag allows it. However, the LIGHTER flag should be able
* to allow lighting fires even if BUILD is set to DENY.</p>
*
* <p>How this method works (BUILD can be overridden by other flags but
* not the other way around) is inconsistent, but it's required for
* legacy reasons.</p>
*
* <p>This method does not check the region bypass permission. That must
* be done by the calling code.</p>
*
* @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 true if the result was {@code ALLOW}
* @see RegionResultSet#queryValue(RegionAssociable, Flag)
* @deprecated use {@link #testBuild(Location, RegionAssociable, StateFlag...)} instead, will be removed in WorldGuard 8
*/
public boolean testBuild(Location location, LocalPlayer player, StateFlag... flag) {
if (flag.length == 0) {
return testState(location, player, Flags.BUILD);
}
return StateFlag.test(StateFlag.combine(
StateFlag.denyToNone(queryState(location, player, Flags.BUILD)),
queryState(location, player, flag)));
@Deprecated(forRemoval = true)
public boolean testBuild(Location location, LocalPlayer subject, StateFlag... flags) {
return getApplicableRegions(location).testBuild(subject, flags);
}
/**
* Returns true if the BUILD flag allows the action in the location, but it
* can be overridden by a list of other flags. The BUILD flag will not
* override the other flags, but the other flags can override BUILD. If
* neither BUILD or any of the flags permit the action, then false will
* be returned.
*
* <p>Use this method when checking flags that are related to build
* protection. For example, lighting fire in a region should not be
* permitted unless the player is a member of the region or the
* LIGHTER flag allows it. However, the LIGHTER flag should be able
* to allow lighting fires even if BUILD is set to DENY.</p>
*
* <p>How this method works (BUILD can be overridden by other flags but
* not the other way around) is inconsistent, but it's required for
* legacy reasons.</p>
*
* <p>This method does not check the region bypass permission. That must
* be done by the calling code.</p>
*
* @param location the location
* @param associable an optional associable
* @param flag the flag
* @return true if the result was {@code ALLOW}
* @see RegionResultSet#queryValue(RegionAssociable, Flag)
* Convenience method for
* {@link #getApplicableRegions(Location)}{@link ApplicableRegionSet#testBuild(RegionAssociable, StateFlag...)
* .testBuild(RegionAssociable, StateFlag...)}
*/
public boolean testBuild(Location location, RegionAssociable associable, StateFlag... flag) {
if (flag.length == 0) {
return testState(location, associable, Flags.BUILD);
}
return StateFlag.test(StateFlag.combine(
StateFlag.denyToNone(queryState(location, associable, Flags.BUILD)),
queryState(location, associable, flag)));
public boolean testBuild(Location location, RegionAssociable subject, StateFlag... flags) {
return getApplicableRegions(location).testBuild(subject, flags);
}
/**
* Returns true if the BUILD flag allows the action in the location, but it
* can be overridden by a list of other flags. The BUILD flag will not
* override the other flags, but the other flags can override BUILD. If
* neither BUILD or any of the flags permit the action, then false will
* be returned.
*
* <p>Use this method when checking flags that are related to build
* protection. For example, lighting fire in a region should not be
* permitted unless the player is a member of the region or the
* LIGHTER flag allows it. However, the LIGHTER flag should be able
* to allow lighting fires even if BUILD is set to DENY.</p>
*
* <p>This method does include parameters for a {@link MapFlag}.</p>
*
* <p>How this method works (BUILD can be overridden by other flags but
* not the other way around) is inconsistent, but it's required for
* legacy reasons.</p>
*
* <p>This method does not check the region bypass permission. That must
* be done by the calling code.</p>
*
* @param location the location
* @param associable an optional associable
* @param mapFlag the MapFlag
* @param key the key for the MapFlag
* @param fallback the fallback flag for MapFlag
* @param flag the flags
* @return true if the result was {@code ALLOW}
* @see RegionResultSet#queryValue(RegionAssociable, Flag)
* Convenience method for
* {@link #getApplicableRegions(Location)}{@link ApplicableRegionSet#testBuild(RegionAssociable, MapFlag, Object, StateFlag, StateFlag...)
* .testBuild(RegionAssociable, MapFlag, Object, StateFlag, StateFlag...)}
*/
public <K> boolean testBuild(Location location, RegionAssociable associable, MapFlag<K, State> mapFlag, K key,
@Nullable StateFlag fallback, StateFlag... flag) {
if (mapFlag == null)
return testBuild(location, associable, flag);
if (flag.length == 0) {
return StateFlag.test(StateFlag.combine(
StateFlag.denyToNone(queryState(location, associable, Flags.BUILD)),
queryMapValue(location, associable, mapFlag, key, fallback)
));
}
return StateFlag.test(StateFlag.combine(
StateFlag.denyToNone(queryState(location, associable, Flags.BUILD)),
queryMapValue(location, associable, mapFlag, key, fallback),
queryState(location, associable, flag)
));
public <K> boolean testBuild(Location location, RegionAssociable subject, MapFlag<K, State> flag, K key,
@Nullable StateFlag fallback, StateFlag... flags) {
return getApplicableRegions(location).testBuild(subject, flag, key, fallback, flags);
}
/**
* Test whether the (effective) value for a list of state flags equals
* {@code ALLOW}.
* Convenience method for
* {@link #getApplicableRegions(Location)}{@link ApplicableRegionSet#testState(RegionAssociable, StateFlag...)
* .testState(RegionAssociable, StateFlag...)}
*
* <p>{@code player} can be non-null to satisfy region group requirements,
* otherwise it will be assumed that the caller that is not a member of any
* regions. (Flags on a region can be changed so that they only apply
* to certain users.) The player argument is required if the
* {@link Flags#BUILD} flag is in the list of flags.</p>
*
* <p>This method does not check the region bypass permission. That must
* be done by the calling code.</p>
*
* @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 true if the result was {@code ALLOW}
* @see RegionResultSet#queryValue(RegionAssociable, Flag)
* @deprecated use {@link #testState(Location, RegionAssociable, StateFlag...)} instead, will be removed in WorldGuard 8
*/
public boolean testState(Location location, @Nullable LocalPlayer player, StateFlag... flag) {
return StateFlag.test(queryState(location, player, flag));
@Deprecated(forRemoval = true)
public boolean testState(Location location, @Nullable LocalPlayer subject, StateFlag... flags) {
return getApplicableRegions(location).testState(subject, flags);
}
/**
* Test whether the (effective) value for a list of state flags equals
* {@code ALLOW}.
*
* <p>{@code player} can be non-null to satisfy region group requirements,
* otherwise it will be assumed that the caller that is not a member of any
* regions. (Flags on a region can be changed so that they only apply
* to certain users.) The player argument is required if the
* {@link Flags#BUILD} flag is in the list of flags.</p>
*
* <p>This method does not check the region bypass permission. That must
* be done by the calling code.</p>
*
* @param location the location
* @param associable an optional associable
* @param flag the flag
* @return true if the result was {@code ALLOW}
* @see RegionResultSet#queryValue(RegionAssociable, Flag)
* Convenience method for
* {@link #getApplicableRegions(Location)}{@link ApplicableRegionSet#testState(RegionAssociable, StateFlag...)
* .testState(RegionAssociable, StateFlag...)}
*/
public boolean testState(Location location, @Nullable RegionAssociable associable, StateFlag... flag) {
return StateFlag.test(queryState(location, associable, flag));
public boolean testState(Location location, @Nullable RegionAssociable subject, StateFlag... flags) {
return getApplicableRegions(location).testState(subject, 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}. One flag may override another.
* Convenience method for
* {@link #getApplicableRegions(Location)}{@link ApplicableRegionSet#queryState(RegionAssociable, StateFlag...)
* .queryState(RegionAssociable, StateFlag...)}
*
* <p>{@code player} can be non-null to satisfy region group requirements,
* otherwise it will be assumed that the caller that is not a member of any
* regions. (Flags on a region can be changed so that they only apply
* to certain users.) The player argument is required if the
* {@link Flags#BUILD} flag is in the list of flags.</p>
*
* @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 RegionResultSet#queryState(RegionAssociable, StateFlag...)
* @deprecated use {@link #queryState(Location, RegionAssociable, StateFlag...)} instead, will be removed in WorldGuard 8
*/
@Deprecated(forRemoval = true)
@Nullable
public State queryState(Location location, @Nullable LocalPlayer subject, StateFlag... flags) {
return getApplicableRegions(location).queryState(subject, flags);
}
/**
* Convenience method for
* {@link #getApplicableRegions(Location)}{@link ApplicableRegionSet#queryState(RegionAssociable, StateFlag...)
* .queryState(RegionAssociable, StateFlag...)}
*/
@Nullable
public State queryState(Location location, @Nullable LocalPlayer player, StateFlag... flags) {
return getApplicableRegions(location).queryState(player, flags);
public State queryState(Location location, @Nullable RegionAssociable subject, StateFlag... flags) {
return getApplicableRegions(location).queryState(subject, 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}. One flag may override another.
* Convenience method for
* {@link #getApplicableRegions(Location)}{@link ApplicableRegionSet#queryValue(RegionAssociable, Flag)
* .queryValue(RegionAssociable, Flag)}
*
* <p>{@code player} can be non-null to satisfy region group requirements,
* otherwise it will be assumed that the caller that is not a member of any
* regions. (Flags on a region can be changed so that they only apply
* to certain users.) The player argument is required if the
* {@link Flags#BUILD} flag is in the list of flags.</p>
*
* @param location the location
* @param associable an optional associable
* @param flags a list of flags to check
* @return a state
* @see RegionResultSet#queryState(RegionAssociable, StateFlag...)
* @deprecated use {@link #queryValue(Location, RegionAssociable, Flag)} instead, will be removed in WorldGuard 8
*/
@Deprecated(forRemoval = true)
@Nullable
public <V> V queryValue(Location location, @Nullable LocalPlayer subject, Flag<V> flag) {
return getApplicableRegions(location).queryValue(subject, flag);
}
/**
* Convenience method for
* {@link #getApplicableRegions(Location)}{@link ApplicableRegionSet#queryValue(RegionAssociable, Flag)
* .queryValue(RegionAssociable, Flag)}
*/
@Nullable
public State queryState(Location location, @Nullable RegionAssociable associable, StateFlag... flags) {
return getApplicableRegions(location).queryState(associable, flags);
public <V> V queryValue(Location location, @Nullable RegionAssociable subject, Flag<V> flag) {
return getApplicableRegions(location).queryValue(subject, flag);
}
/**
* Get the effective value for a flag. If there are multiple values
* (for example, multiple overlapping regions with
* the same priority may have the same flag set), then the selected
* (or "winning") value will depend on the flag type.
*
* <p>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 actually has a strategy for picking a value is the
* {@link StateFlag}.</p>
*
* <p>{@code player} can be non-null to satisfy region group requirements,
* otherwise it will be assumed that the caller that is not a member of any
* regions. (Flags on a region can be changed so that they only apply
* to certain users.) The player argument is required if the
* {@link Flags#BUILD} flag is the flag being queried.</p>
*
* @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 RegionResultSet#queryValue(RegionAssociable, Flag)
*/
@Nullable
public <V> V queryValue(Location location, @Nullable LocalPlayer player, Flag<V> flag) {
return getApplicableRegions(location).queryValue(player, flag);
}
/**
* Get the effective value for a flag. If there are multiple values
* (for example, multiple overlapping regions with
* the same priority may have the same flag set), then the selected
* (or "winning") value will depend on the flag type.
*
* <p>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 actually has a strategy for picking a value is the
* {@link StateFlag}.</p>
*
* <p>{@code player} can be non-null to satisfy region group requirements,
* otherwise it will be assumed that the caller that is not a member of any
* regions. (Flags on a region can be changed so that they only apply
* to certain users.) The player argument is required if the
* {@link Flags#BUILD} flag is the flag being queried.</p>
*
* @param location the location
* @param associable an optional associable
* @param flag the flag
* @return a value, which could be {@code null}
* @see RegionResultSet#queryValue(RegionAssociable, Flag)
*/
@Nullable
public <V> V queryValue(Location location, @Nullable RegionAssociable associable, Flag<V> flag) {
return getApplicableRegions(location).queryValue(associable, flag);
}
/**
* Get the effective value for a key in a {@link MapFlag}. 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 be undefined.
*
* <p>A subject can be provided that is used to determine whether the value
* of a flag on a particular region should be used. For example, if a
* flag's region group is set to {@link RegionGroup#MEMBERS} and the given
* subject is not a member, then the region would be skipped when
* querying that flag. If {@code null} is provided for the subject, then
* only flags that use {@link RegionGroup#ALL},
* {@link RegionGroup#NON_MEMBERS}, etc. will apply.</p>
*
* @param subject an optional subject, which would be used to determine the region group to apply
* @param flag the flag of type {@link MapFlag}
* @param key the key for the map flag
* @return a value, which could be {@code null}
* Convenience method for
* {@link #getApplicableRegions(Location)}{@link ApplicableRegionSet#queryMapValue(RegionAssociable, MapFlag, Object)
* .queryMapValue(RegionAssociable, MapFlag, Object)}
*/
@Nullable
public <V, K> V queryMapValue(Location location, @Nullable RegionAssociable subject, MapFlag<K, V> flag, K key) {
@ -425,73 +237,43 @@ public class RegionQuery {
}
/**
* Get the effective value for a key in a {@link MapFlag}. 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 be undefined.
*
* <p>A subject can be provided that is used to determine whether the value
* of a flag on a particular region should be used. For example, if a
* flag's region group is set to {@link RegionGroup#MEMBERS} and the given
* subject is not a member, then the region would be skipped when
* querying that flag. If {@code null} is provided for the subject, then
* only flags that use {@link RegionGroup#ALL},
* {@link RegionGroup#NON_MEMBERS}, etc. will apply.</p>
*
* <p>It's possible to provide a fallback flag for the case when the key doesn't
* exist in the {@link MapFlag}.</p>
*
* @param subject an optional subject, which would be used to determine the region group to apply
* @param flag the flag of type {@link MapFlag}
* @param key the key for the map flag
* @param fallback the fallback flag
* @return a value, which could be {@code null}
* Convenience method for
* {@link #getApplicableRegions(Location)}{@link ApplicableRegionSet#queryMapValue(RegionAssociable, MapFlag, Object, Flag)
* .queryMapValue(RegionAssociable, MapFlag, Object, Flag)}
*/
@Nullable
public <V, K> V queryMapValue(Location location, @Nullable RegionAssociable subject, MapFlag<K, V> flag, K key, Flag<V> fallback) {
public <V, K> V queryMapValue(Location location, @Nullable RegionAssociable subject, MapFlag<K, V> flag, K key, @Nullable Flag<V> fallback) {
return getApplicableRegions(location).queryMapValue(subject, flag, key, fallback);
}
/**
* Get the effective values for a flag, returning a collection of all
* values. It is up to the caller to determine which value, if any,
* from the collection will be used.
* Convenience method for
* {@link #getApplicableRegions(Location)}{@link ApplicableRegionSet#queryAllValues(RegionAssociable, Flag)
* .queryAllValues(RegionAssociable, Flag)}
*
* <p>{@code player} can be non-null to satisfy region group requirements,
* otherwise it will be assumed that the caller that is not a member of any
* regions. (Flags on a region can be changed so that they only apply
* to certain users.) The player argument is required if the
* {@link Flags#BUILD} flag is the flag being queried.</p>
*
* @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 RegionResultSet#queryAllValues(RegionAssociable, Flag)
* @deprecated use {@link #queryAllValues(Location, RegionAssociable, Flag)} instead, will be removed in WorldGuard 8
*/
public <V> Collection<V> queryAllValues(Location location, @Nullable LocalPlayer player, Flag<V> flag) {
return getApplicableRegions(location).queryAllValues(player, flag);
@Deprecated(forRemoval = true)
public <V> Collection<V> queryAllValues(Location location, @Nullable LocalPlayer subject, Flag<V> flag) {
return getApplicableRegions(location).queryAllValues(subject, flag);
}
/**
* Get the effective values for a flag, returning a collection of all
* values. It is up to the caller to determine which value, if any,
* from the collection will be used.
*
* <p>{@code player} can be non-null to satisfy region group requirements,
* otherwise it will be assumed that the caller that is not a member of any
* regions. (Flags on a region can be changed so that they only apply
* to certain users.) The player argument is required if the
* {@link Flags#BUILD} flag is the flag being queried.</p>
*
* @param location the location
* @param associable an optional associable
* @param flag the flag
* @return a collection of values
* @see RegionResultSet#queryAllValues(RegionAssociable, Flag)
* Convenience method for
* {@link #getApplicableRegions(Location)}{@link ApplicableRegionSet#queryAllValues(RegionAssociable, Flag)
* .queryAllValues(RegionAssociable, Flag)}
*/
public <V> Collection<V> queryAllValues(Location location, @Nullable RegionAssociable associable, Flag<V> flag) {
return getApplicableRegions(location).queryAllValues(associable, flag);
public <V> Collection<V> queryAllValues(Location location, @Nullable RegionAssociable subject, Flag<V> flag) {
return getApplicableRegions(location).queryAllValues(subject, flag);
}
/**
* Convenience method for
* {@link #getApplicableRegions(Location)}{@link ApplicableRegionSet#queryAllValues(RegionAssociable, Flag, boolean)
* .queryAllValues(RegionAssociable, Flag, boolean)}
*/
public <V> Collection<V> queryAllValues(Location location, @Nullable RegionAssociable subject, Flag<V> flag, boolean acceptOne) {
return getApplicableRegions(location).queryAllValues(subject, flag, acceptOne);
}
/**