Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add query methods to get values from MapFlags #1650

Merged
merged 4 commits into from
Jan 24, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
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;
Expand Down Expand Up @@ -119,6 +121,50 @@ public interface ApplicableRegionSet extends Iterable<ProtectedRegion> {
@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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,15 @@
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;

/**
Expand Down Expand Up @@ -65,6 +67,19 @@ public <V> V queryValue(@Nullable RegionAssociable subject, Flag<V> flag) {
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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
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;
Expand Down Expand Up @@ -224,6 +225,110 @@ public <V> V queryValue(@Nullable RegionAssociable subject, Flag<V> flag) {
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) {
checkNotNull(flag);
checkNotNull(key);

Map<ProtectedRegion, V> consideredValues = new HashMap<>();
Map<ProtectedRegion, V> fallbackValues = new HashMap<>();
int minimumPriority = Integer.MIN_VALUE;
Set<ProtectedRegion> ignoredParents = new HashSet<>();

for(ProtectedRegion region : getApplicable()) {
if (getPriority(region) < minimumPriority) {
break;
}

if (ignoredParents.contains(region)) {
continue;
}

V effectiveValue = getEffectiveMapValue(region, flag, key, subject);

if (effectiveValue != null) {
minimumPriority = getPriority(region);
consideredValues.put(region, effectiveValue);
} else if (fallback != null) {
effectiveValue = getEffectiveFlag(region, fallback, subject);
if (effectiveValue != null) {
minimumPriority = getPriority(region);
fallbackValues.put(region, effectiveValue);
}
}

addParents(ignoredParents, region);
}


if (consideredValues.isEmpty()) {
if (fallback != null && !fallbackValues.isEmpty()) {
return fallback.chooseValue(fallbackValues.values());
}
V defaultValue = flag.getValueFlag().getDefault();
return defaultValue != null ? defaultValue : fallback != null ? fallback.getDefault() : null;
}

return flag.getValueFlag().chooseValue(consideredValues.values());
}

@Nullable
private <V, K> V getEffectiveMapValue(ProtectedRegion region, MapFlag<K, V> mapFlag, 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);

if (mapValue != null && mapValue.containsKey(key)) {
boolean use = true;

if (mapFlag.getRegionGroupFlag() != null) {
RegionGroup group = current.getFlag(mapFlag.getRegionGroupFlag());
if (group == null) {
group = mapFlag.getRegionGroupFlag().getDefault();
}

if (group == null) {
use = false;
} else if (subject == null) {
use = group.contains(Association.NON_MEMBER);
} else if (!group.contains(subject.getAssociation(seen))) {
use = false;
}
}

if (use) {
return mapValue.get(key);
}
}

current = current.getParent();
}
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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,15 @@
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;

/**
Expand Down Expand Up @@ -59,6 +61,19 @@ public <V> V queryValue(@Nullable RegionAssociable subject, Flag<V> flag) {
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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
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;
Expand Down Expand Up @@ -108,6 +109,18 @@ public <V> Collection<V> queryAllValues(@Nullable RegionAssociable subject, 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) {
return flagValueCalculator.queryMapValue(subject, flag, key, fallback);
}

@Override
public boolean isOwnerOfAll(LocalPlayer player) {
checkNotNull(player);
Expand Down
Loading