mirror of
https://github.com/EngineHub/WorldGuard.git
synced 2024-09-28 22:57:29 +02:00
Sort applicable regions by inheritance too.
This commit is contained in:
parent
e7273aaf6f
commit
3bd1c869f1
@ -21,6 +21,7 @@
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.sk89q.worldguard.domains.Association;
|
||||
import com.sk89q.worldguard.protection.association.RegionAssociable;
|
||||
import com.sk89q.worldguard.protection.flags.DefaultFlag;
|
||||
@ -29,6 +30,7 @@
|
||||
import com.sk89q.worldguard.protection.flags.StateFlag;
|
||||
import com.sk89q.worldguard.protection.flags.StateFlag.State;
|
||||
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
|
||||
import com.sk89q.worldguard.protection.util.NormativeOrders;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.*;
|
||||
@ -55,7 +57,7 @@ public class FlagValueCalculator {
|
||||
/**
|
||||
* Create a new instance.
|
||||
*
|
||||
* @param regions a list of applicable regions that <strong>must be sorted by priority descending</strong>
|
||||
* @param regions a list of applicable regions that must be sorted according to {@link NormativeOrders}
|
||||
* @param globalRegion an optional global region (null to not use one)
|
||||
*/
|
||||
public FlagValueCalculator(List<ProtectedRegion> regions, @Nullable ProtectedRegion globalRegion) {
|
||||
@ -102,36 +104,9 @@ public Result getMembership(RegionAssociable subject) {
|
||||
checkNotNull(subject);
|
||||
|
||||
int minimumPriority = Integer.MIN_VALUE;
|
||||
boolean foundApplicableRegion = false;
|
||||
Result result = Result.NO_REGIONS;
|
||||
|
||||
// Say there are two regions in one location: CHILD and PARENT (CHILD
|
||||
// is a child of PARENT). If there are two overlapping regions in WG, a
|
||||
// subject has to be a member of /both/ (or flags permit) in order to
|
||||
// build in that location. However, inheritance is supposed
|
||||
// to allow building if the subject is a member of just CHILD. That
|
||||
// presents a problem.
|
||||
//
|
||||
// To rectify this, we keep two sets. When we iterate over the list of
|
||||
// regions, there are two scenarios that we may encounter:
|
||||
//
|
||||
// 1) PARENT first, CHILD later:
|
||||
// a) When the loop reaches PARENT, PARENT is added to needsClear.
|
||||
// b) When the loop reaches CHILD, parents of CHILD (which includes
|
||||
// PARENT) are removed from needsClear.
|
||||
// c) needsClear is empty again.
|
||||
//
|
||||
// 2) CHILD first, PARENT later:
|
||||
// a) When the loop reaches CHILD, CHILD's parents (i.e. PARENT) are
|
||||
// added to hasCleared.
|
||||
// b) When the loop reaches PARENT, since PARENT is already in
|
||||
// hasCleared, it does not add PARENT to needsClear.
|
||||
// c) needsClear stays empty.
|
||||
//
|
||||
// As long as the process ends with needsClear being empty, then
|
||||
// we have satisfied all membership requirements.
|
||||
|
||||
Set<ProtectedRegion> needsClear = new HashSet<ProtectedRegion>();
|
||||
Set<ProtectedRegion> hasCleared = new HashSet<ProtectedRegion>();
|
||||
Set<ProtectedRegion> ignoredRegions = Sets.newHashSet();
|
||||
|
||||
for (ProtectedRegion region : getApplicable()) {
|
||||
// Don't consider lower priorities below minimumPriority
|
||||
@ -147,24 +122,23 @@ public Result getMembership(RegionAssociable subject) {
|
||||
continue;
|
||||
}
|
||||
|
||||
minimumPriority = getPriority(region);
|
||||
foundApplicableRegion = true;
|
||||
if (ignoredRegions.contains(region)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!hasCleared.contains(region)) {
|
||||
if (!RegionGroup.MEMBERS.contains(subject.getAssociation(Arrays.asList(region)))) {
|
||||
needsClear.add(region);
|
||||
} else {
|
||||
// Need to clear all parents
|
||||
removeParents(needsClear, hasCleared, region);
|
||||
}
|
||||
minimumPriority = getPriority(region);
|
||||
|
||||
boolean member = RegionGroup.MEMBERS.contains(subject.getAssociation(Arrays.asList(region)));
|
||||
|
||||
if (member) {
|
||||
result = Result.SUCCESS;
|
||||
addParents(ignoredRegions, region);
|
||||
} else {
|
||||
return Result.FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
if (foundApplicableRegion) {
|
||||
return needsClear.isEmpty() ? Result.SUCCESS : Result.FAIL;
|
||||
} else {
|
||||
return Result.NO_REGIONS;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@ -243,7 +217,7 @@ public State queryState(@Nullable RegionAssociable subject, StateFlag flag) {
|
||||
*/
|
||||
@Nullable
|
||||
public <V> V queryValue(@Nullable RegionAssociable subject, Flag<V> flag) {
|
||||
Collection<V> values = queryAllValues(subject, flag);
|
||||
Collection<V> values = queryAllValues(subject, flag, true);
|
||||
return flag.chooseValue(values);
|
||||
}
|
||||
|
||||
@ -264,10 +238,37 @@ public <V> V queryValue(@Nullable RegionAssociable subject, Flag<V> flag) {
|
||||
* @param flag the flag
|
||||
* @return a collection of values
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <V> Collection<V> queryAllValues(@Nullable RegionAssociable subject, Flag<V> flag) {
|
||||
return queryAllValues(subject, flag, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the effective values for a flag, returning a collection of all
|
||||
* values. It is up to the caller to determine which value, if any,
|
||||
* from the collection will be used.
|
||||
*
|
||||
* <p>A subject can be provided that is used to determine whether the value
|
||||
* of a flag on a particular region should be used. For example, if a
|
||||
* flag's region group is set to {@link RegionGroup#MEMBERS} and the given
|
||||
* subject is not a member, then the region would be skipped when
|
||||
* querying that flag. If {@code null} is provided for the subject, then
|
||||
* only flags that use {@link RegionGroup#ALL},
|
||||
* {@link RegionGroup#NON_MEMBERS}, etc. will apply.</p>
|
||||
*
|
||||
* @param subject an optional subject, which would be used to determine the region group to apply
|
||||
* @param flag the flag
|
||||
* @param acceptOne if possible, return only one value if it doesn't matter
|
||||
* @return a collection of values
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private <V> Collection<V> queryAllValues(@Nullable RegionAssociable subject, Flag<V> flag, boolean acceptOne) {
|
||||
checkNotNull(flag);
|
||||
|
||||
// Can't use this optimization with flags that have a conflict resolution strategy
|
||||
if (acceptOne && flag.hasConflictStrategy()) {
|
||||
acceptOne = false;
|
||||
}
|
||||
|
||||
// Check to see whether we have a subject if this is BUILD
|
||||
if (flag == DefaultFlag.BUILD && subject == null) {
|
||||
throw new NullPointerException("The BUILD flag is handled in a special fashion and requires a non-null subject parameter");
|
||||
@ -275,58 +276,33 @@ public <V> Collection<V> queryAllValues(@Nullable RegionAssociable subject, Flag
|
||||
|
||||
int minimumPriority = Integer.MIN_VALUE;
|
||||
|
||||
// Say there are two regions in one location: CHILD and PARENT (CHILD
|
||||
// is a child of PARENT). If the two are overlapping regions in WG,
|
||||
// both with values set, then we have a problem. Due to inheritance,
|
||||
// only the CHILD's value for the flag should be used because it
|
||||
// overrides its parent's value, but default behavior is to collect
|
||||
// all the values into a list.
|
||||
//
|
||||
// To rectify this, we keep a map of consideredValues (region -> value)
|
||||
// and an ignoredRegions set. When we iterate over the list of
|
||||
// regions, there are two scenarios that we may encounter:
|
||||
//
|
||||
// 1) PARENT first, CHILD later:
|
||||
// a) When the loop reaches PARENT, PARENT's value is added to
|
||||
// consideredValues
|
||||
// b) When the loop reaches CHILD, parents of CHILD (which includes
|
||||
// PARENT) are removed from consideredValues (so we no longer
|
||||
// consider those values). The CHILD's value is then added to
|
||||
// consideredValues.
|
||||
// c) In the end, only CHILD's value exists in consideredValues.
|
||||
//
|
||||
// 2) CHILD first, PARENT later:
|
||||
// a) When the loop reaches CHILD, CHILD's value is added to
|
||||
// consideredValues. In addition, the CHILD's parents (which
|
||||
// includes PARENT) are added to ignoredRegions.
|
||||
// b) When the loop reaches PARENT, since PARENT is in
|
||||
// ignoredRegions, the parent is skipped over.
|
||||
// c) In the end, only CHILD's value exists in consideredValues.
|
||||
|
||||
Map<ProtectedRegion, V> consideredValues = new HashMap<ProtectedRegion, V>();
|
||||
Set<ProtectedRegion> ignoredRegions = new HashSet<ProtectedRegion>();
|
||||
Set<ProtectedRegion> ignoredParents = new HashSet<ProtectedRegion>();
|
||||
|
||||
for (ProtectedRegion region : getApplicable()) {
|
||||
// Don't consider lower priorities below minimumPriority
|
||||
// (which starts at Integer.MIN_VALUE). A region that "counts"
|
||||
// (has the flag set) will raise minimumPriority to its own
|
||||
// priority.
|
||||
if (getPriority(region) < minimumPriority) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (ignoredParents.contains(region)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
V value = getEffectiveFlag(region, flag, subject);
|
||||
int priority = getPriority(region);
|
||||
|
||||
if (value != null) {
|
||||
if (!ignoredRegions.contains(region)) {
|
||||
minimumPriority = priority;
|
||||
minimumPriority = priority;
|
||||
|
||||
ignoreValuesOfParents(consideredValues, ignoredRegions, region);
|
||||
if (acceptOne) {
|
||||
return Arrays.asList(value);
|
||||
} else {
|
||||
consideredValues.put(region, value);
|
||||
}
|
||||
}
|
||||
|
||||
addParents(ignoredParents, region);
|
||||
|
||||
// The BUILD flag (of lower priorities) can be overridden if
|
||||
// this region has members... this check is here due to legacy
|
||||
// reasons
|
||||
@ -435,40 +411,17 @@ public <V> V getEffectiveFlag(final ProtectedRegion region, Flag<V> flag, @Nulla
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear a region's parents for isFlagAllowed().
|
||||
*
|
||||
* @param needsClear the regions that should be cleared
|
||||
* @param hasCleared the regions already cleared
|
||||
* @param region the region to start from
|
||||
*/
|
||||
private void removeParents(Set<ProtectedRegion> needsClear, Set<ProtectedRegion> hasCleared, ProtectedRegion region) {
|
||||
ProtectedRegion parent = region.getParent();
|
||||
|
||||
while (parent != null) {
|
||||
if (!needsClear.remove(parent)) {
|
||||
hasCleared.add(parent);
|
||||
}
|
||||
|
||||
parent = parent.getParent();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear a region's parents for getFlag().
|
||||
*
|
||||
* @param needsClear The regions that should be cleared
|
||||
* @param hasCleared The regions already cleared
|
||||
* @param ignored The regions to ignore
|
||||
* @param region The region to start from
|
||||
*/
|
||||
private void ignoreValuesOfParents(Map<ProtectedRegion, ?> needsClear, Set<ProtectedRegion> hasCleared, ProtectedRegion region) {
|
||||
private void addParents(Set<ProtectedRegion> ignored, ProtectedRegion region) {
|
||||
ProtectedRegion parent = region.getParent();
|
||||
|
||||
while (parent != null) {
|
||||
if (needsClear.remove(parent) == null) {
|
||||
hasCleared.add(parent);
|
||||
}
|
||||
|
||||
ignored.add(parent);
|
||||
parent = parent.getParent();
|
||||
}
|
||||
}
|
||||
|
@ -25,14 +25,10 @@
|
||||
import com.sk89q.worldguard.protection.flags.StateFlag;
|
||||
import com.sk89q.worldguard.protection.flags.StateFlag.State;
|
||||
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
|
||||
import com.sk89q.worldguard.protection.util.NormativeOrders;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
@ -47,9 +43,10 @@ public class RegionResultSet extends AbstractRegionSet {
|
||||
private Set<ProtectedRegion> regionSet;
|
||||
|
||||
/**
|
||||
* Construct the object.
|
||||
* Create a new region result set.
|
||||
*
|
||||
* <p>A sorted set will be created to include the collection of regions.</p>
|
||||
* <p>The given list must not contain duplicates or the behavior of
|
||||
* this instance will be undefined.</p>
|
||||
*
|
||||
* @param applicable the regions contained in this set
|
||||
* @param globalRegion the global region, set aside for special handling.
|
||||
@ -59,16 +56,30 @@ public RegionResultSet(List<ProtectedRegion> applicable, @Nullable ProtectedRegi
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct the object.
|
||||
* Create a new region result set.
|
||||
*
|
||||
* @param applicable the regions contained in this set
|
||||
* @param globalRegion the global region, set aside for special handling.
|
||||
*/
|
||||
public RegionResultSet(Set<ProtectedRegion> applicable, @Nullable ProtectedRegion globalRegion) {
|
||||
this(NormativeOrders.fromSet(applicable), globalRegion, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new region result set.
|
||||
*
|
||||
* <p>The list of regions may be first sorted with
|
||||
* {@link NormativeOrders}. If that is the case, {@code sorted} should be
|
||||
* {@code true}. Otherwise, the list will be sorted in-place.</p>
|
||||
*
|
||||
* @param applicable the regions contained in this set
|
||||
* @param globalRegion the global region, set aside for special handling.
|
||||
* @param sorted true if the list is already sorted
|
||||
* @param sorted true if the list is already sorted with {@link NormativeOrders}
|
||||
*/
|
||||
private RegionResultSet(List<ProtectedRegion> applicable, @Nullable ProtectedRegion globalRegion, boolean sorted) {
|
||||
public RegionResultSet(List<ProtectedRegion> applicable, @Nullable ProtectedRegion globalRegion, boolean sorted) {
|
||||
checkNotNull(applicable);
|
||||
if (!sorted) {
|
||||
Collections.sort(applicable);
|
||||
NormativeOrders.sort(applicable);
|
||||
}
|
||||
this.applicable = applicable;
|
||||
this.flagValueCalculator = new FlagValueCalculator(applicable, globalRegion);
|
||||
|
@ -61,6 +61,19 @@ public T getDefault() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the flag can take a list of values and choose a "best one."
|
||||
*
|
||||
* <p>This is the case with the {@link StateFlag} where {@code DENY}
|
||||
* overrides {@code ALLOW}, but most flags just return the
|
||||
* first result from a list.</p>
|
||||
*
|
||||
* @return whether a best value can be chosen
|
||||
*/
|
||||
public boolean hasConflictStrategy() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public T chooseValue(Collection<T> values) {
|
||||
if (!values.isEmpty()) {
|
||||
|
@ -53,6 +53,11 @@ public State getDefault() {
|
||||
return def ? State.ALLOW : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasConflictStrategy() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public State chooseValue(Collection<State> values) {
|
||||
|
@ -21,6 +21,7 @@
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.Vector2D;
|
||||
import com.sk89q.worldguard.LocalPlayer;
|
||||
@ -317,7 +318,7 @@ public Set<ProtectedRegion> removeRegion(String id, RemovalStrategy strategy) {
|
||||
public ApplicableRegionSet getApplicableRegions(Vector position) {
|
||||
checkNotNull(position);
|
||||
|
||||
List<ProtectedRegion> regions = new ArrayList<ProtectedRegion>();
|
||||
Set<ProtectedRegion> regions = Sets.newHashSet();
|
||||
index.applyContaining(position, new RegionCollectionConsumer(regions, true));
|
||||
return new RegionResultSet(regions, index.get("__global__"));
|
||||
}
|
||||
@ -332,7 +333,7 @@ public ApplicableRegionSet getApplicableRegions(Vector position) {
|
||||
public ApplicableRegionSet getApplicableRegions(ProtectedRegion region) {
|
||||
checkNotNull(region);
|
||||
|
||||
List<ProtectedRegion> regions = new ArrayList<ProtectedRegion>();
|
||||
Set<ProtectedRegion> regions = Sets.newHashSet();
|
||||
index.applyIntersecting(region, new RegionCollectionConsumer(regions, true));
|
||||
return new RegionResultSet(regions, index.get("__global__"));
|
||||
}
|
||||
|
@ -0,0 +1,141 @@
|
||||
/*
|
||||
* WorldGuard, a suite of tools for Minecraft
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldGuard team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldguard.protection.util;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.sk89q.worldguard.protection.ApplicableRegionSet;
|
||||
import com.sk89q.worldguard.protection.FlagValueCalculator;
|
||||
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Sorts a list of regions so that higher priority regions always take
|
||||
* precedence over lower priority ones, and after sorting by priority, so
|
||||
* child regions always take priority over their parent regions.
|
||||
*
|
||||
* <p>For example, if the regions are a, aa, aaa, aab, aac, b, ba, bc, where
|
||||
* aa implies that the second 'a' is a child of the first 'a', the sorted
|
||||
* order must reflect the following properties (where regions on the
|
||||
* left of < appear before in the sorted list):</p>
|
||||
*
|
||||
* <ul>
|
||||
* <li>[aaa, aab, aac] < aa < a</li>
|
||||
* <li>[ba, bc] < b</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>In the case of "[aaa, aab, aac]," the relative order between these
|
||||
* regions is unimportant as they all share the same parent (aaa). The
|
||||
* following choices would be valid sorts:</p>
|
||||
*
|
||||
* <ul>
|
||||
* <li>aaa, aab, aac, aa, a, ba, bc, b</li>
|
||||
* <li>aab, aaa, aac, aa, a, bc, ba, b</li>
|
||||
* <li>bc, ba, b, aab, aaa, aac, aa, a</li>
|
||||
* <li>aab, aaa, bc, aac, aa, ba, a, b</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>These sorted lists are required for {@link FlagValueCalculator} and
|
||||
* some implementations of {@link ApplicableRegionSet}.</p>
|
||||
*/
|
||||
public class NormativeOrders {
|
||||
|
||||
private static final PriorityComparator PRIORITY_COMPARATOR = new PriorityComparator();
|
||||
|
||||
public static void sort(List<ProtectedRegion> regions) {
|
||||
sortInto(Sets.newHashSet(regions), regions);
|
||||
}
|
||||
|
||||
public static List<ProtectedRegion> fromSet(Set<ProtectedRegion> regions) {
|
||||
List<ProtectedRegion> sorted = Arrays.asList(new ProtectedRegion[regions.size()]);
|
||||
sortInto(regions, sorted);
|
||||
return sorted;
|
||||
}
|
||||
|
||||
private static void sortInto(Set<ProtectedRegion> regions, List<ProtectedRegion> sorted) {
|
||||
List<RegionNode> root = Lists.newArrayList();
|
||||
Map<ProtectedRegion, RegionNode> nodes = Maps.newHashMap();
|
||||
for (ProtectedRegion region : regions) {
|
||||
addNode(nodes, root, region);
|
||||
}
|
||||
|
||||
int index = regions.size() - 1;
|
||||
for (RegionNode node : root) {
|
||||
while (node != null) {
|
||||
if (regions.contains(node.region)) {
|
||||
sorted.set(index, node.region);
|
||||
index--;
|
||||
}
|
||||
node = node.next;
|
||||
}
|
||||
}
|
||||
|
||||
Collections.sort(sorted, PRIORITY_COMPARATOR);
|
||||
}
|
||||
|
||||
private static RegionNode addNode(Map<ProtectedRegion, RegionNode> nodes, List<RegionNode> root, ProtectedRegion region) {
|
||||
RegionNode node = nodes.get(region);
|
||||
if (node == null) {
|
||||
node = new RegionNode(region);
|
||||
nodes.put(region, node);
|
||||
if (region.getParent() != null) {
|
||||
addNode(nodes, root, region.getParent()).insertAfter(node);
|
||||
} else {
|
||||
root.add(node);
|
||||
}
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
private static class RegionNode {
|
||||
@Nullable private RegionNode next;
|
||||
private final ProtectedRegion region;
|
||||
|
||||
private RegionNode(ProtectedRegion region) {
|
||||
this.region = region;
|
||||
}
|
||||
|
||||
private void insertAfter(RegionNode node) {
|
||||
if (this.next == null) {
|
||||
this.next = node;
|
||||
} else {
|
||||
node.next = this.next;
|
||||
this.next = node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class PriorityComparator implements Comparator<ProtectedRegion> {
|
||||
@Override
|
||||
public int compare(ProtectedRegion o1, ProtectedRegion o2) {
|
||||
if (o1.getPriority() > o2.getPriority()) {
|
||||
return -1;
|
||||
} else if (o1.getPriority() < o2.getPriority()) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -363,6 +363,97 @@ public void testQueryValueMultipleFlags() throws Exception {
|
||||
assertThat(result.queryValue(null, flag3), is((State) null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryValueFlagsWithRegionGroupsAndInheritance() throws Exception {
|
||||
MockApplicableRegionSet mock = new MockApplicableRegionSet();
|
||||
|
||||
StateFlag flag1 = new StateFlag("test1", false);
|
||||
|
||||
LocalPlayer nonMember = mock.createPlayer();
|
||||
LocalPlayer member = mock.createPlayer();
|
||||
|
||||
ProtectedRegion parent = mock.add(0);
|
||||
parent.setFlag(flag1, State.DENY);
|
||||
parent.setFlag(flag1.getRegionGroupFlag(), RegionGroup.NON_MEMBERS);
|
||||
|
||||
ProtectedRegion region = mock.add(0);
|
||||
region.getMembers().addPlayer(member);
|
||||
region.setParent(parent);
|
||||
|
||||
FlagValueCalculator result = mock.getFlagCalculator();
|
||||
assertThat(result.queryValue(nonMember, flag1), is(State.DENY));
|
||||
assertThat(result.queryValue(member, flag1), is((State) null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryValueFlagsWithRegionGroupsAndInheritanceAndParentMember() throws Exception {
|
||||
MockApplicableRegionSet mock = new MockApplicableRegionSet();
|
||||
|
||||
StateFlag flag1 = new StateFlag("test1", false);
|
||||
|
||||
LocalPlayer nonMember = mock.createPlayer();
|
||||
LocalPlayer memberOne = mock.createPlayer();
|
||||
LocalPlayer memberTwo = mock.createPlayer();
|
||||
|
||||
ProtectedRegion parent = mock.add(0);
|
||||
parent.getMembers().addPlayer(memberOne);
|
||||
parent.setFlag(flag1, State.DENY);
|
||||
parent.setFlag(flag1.getRegionGroupFlag(), RegionGroup.NON_MEMBERS);
|
||||
|
||||
ProtectedRegion region = mock.add(0);
|
||||
region.getMembers().addPlayer(memberOne);
|
||||
region.setParent(parent);
|
||||
|
||||
FlagValueCalculator result = mock.getFlagCalculator();
|
||||
assertThat(result.queryValue(nonMember, flag1), is(State.DENY));
|
||||
assertThat(result.queryValue(memberOne, flag1), is((State) null));
|
||||
assertThat(result.queryValue(memberTwo, flag1), is(State.DENY));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryValueFlagsWithRegionGroupsAndPriority() throws Exception {
|
||||
MockApplicableRegionSet mock = new MockApplicableRegionSet();
|
||||
|
||||
StateFlag flag1 = new StateFlag("test1", false);
|
||||
|
||||
LocalPlayer nonMember = mock.createPlayer();
|
||||
LocalPlayer member = mock.createPlayer();
|
||||
|
||||
ProtectedRegion lower = mock.add(-1);
|
||||
lower.setFlag(flag1, State.DENY);
|
||||
lower.setFlag(flag1.getRegionGroupFlag(), RegionGroup.NON_MEMBERS);
|
||||
|
||||
ProtectedRegion region = mock.add(0);
|
||||
region.getMembers().addPlayer(member);
|
||||
|
||||
FlagValueCalculator result = mock.getFlagCalculator();
|
||||
assertThat(result.queryValue(nonMember, flag1), is(State.DENY));
|
||||
assertThat(result.queryValue(member, flag1), is(State.DENY));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryValueFlagsWithRegionGroupsAndPriorityAndOveride() throws Exception {
|
||||
MockApplicableRegionSet mock = new MockApplicableRegionSet();
|
||||
|
||||
StateFlag flag1 = new StateFlag("test1", false);
|
||||
|
||||
LocalPlayer nonMember = mock.createPlayer();
|
||||
LocalPlayer member = mock.createPlayer();
|
||||
|
||||
ProtectedRegion lower = mock.add(-1);
|
||||
lower.setFlag(flag1, State.DENY);
|
||||
lower.setFlag(flag1.getRegionGroupFlag(), RegionGroup.NON_MEMBERS);
|
||||
|
||||
ProtectedRegion region = mock.add(0);
|
||||
region.setFlag(flag1, State.ALLOW);
|
||||
region.setFlag(flag1.getRegionGroupFlag(), RegionGroup.MEMBERS);
|
||||
region.getMembers().addPlayer(member);
|
||||
|
||||
FlagValueCalculator result = mock.getFlagCalculator();
|
||||
assertThat(result.queryValue(nonMember, flag1), is(State.DENY));
|
||||
assertThat(result.queryValue(member, flag1), is(State.ALLOW));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryValueStringFlag() throws Exception {
|
||||
MockApplicableRegionSet mock = new MockApplicableRegionSet();
|
||||
|
@ -25,6 +25,7 @@
|
||||
import com.sk89q.worldguard.protection.regions.GlobalProtectedRegion;
|
||||
import com.sk89q.worldguard.protection.regions.ProtectedCuboidRegion;
|
||||
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
|
||||
import com.sk89q.worldguard.protection.util.NormativeOrders;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
@ -86,7 +87,7 @@ public ApplicableRegionSet getApplicableSet() {
|
||||
}
|
||||
|
||||
public FlagValueCalculator getFlagCalculator() {
|
||||
Collections.sort(regions);
|
||||
NormativeOrders.sort(regions);
|
||||
return new FlagValueCalculator(regions, global);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user