diff --git a/worldguard-core/src/main/java/com/sk89q/worldguard/protection/association/AbstractRegionOverlapAssociation.java b/worldguard-core/src/main/java/com/sk89q/worldguard/protection/association/AbstractRegionOverlapAssociation.java index 0cbd78fe0..3ca155581 100644 --- a/worldguard-core/src/main/java/com/sk89q/worldguard/protection/association/AbstractRegionOverlapAssociation.java +++ b/worldguard-core/src/main/java/com/sk89q/worldguard/protection/association/AbstractRegionOverlapAssociation.java @@ -24,12 +24,12 @@ import com.sk89q.worldguard.domains.Association; import com.sk89q.worldguard.protection.FlagValueCalculator; import com.sk89q.worldguard.protection.flags.Flags; +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.HashSet; import java.util.List; import java.util.Set; @@ -37,9 +37,9 @@ public abstract class AbstractRegionOverlapAssociation implements RegionAssociab @Nullable protected Set source; - private boolean useMaxPriorityAssociation; + private boolean effectivelyEmpty; + private final boolean useMaxPriorityAssociation; private int maxPriority; - private Set maxPriorityRegions; protected AbstractRegionOverlapAssociation(@Nullable Set source, boolean useMaxPriorityAssociation) { this.source = source; @@ -48,36 +48,53 @@ protected AbstractRegionOverlapAssociation(@Nullable Set source protected void calcMaxPriority() { checkNotNull(source); - int best = 0; - Set bestRegions = new HashSet<>(); + boolean effectivelyEmpty = true; + int maxPriority = Integer.MIN_VALUE; + for (ProtectedRegion region : source) { int priority = region.getPriority(); - if (priority > best) { - best = priority; - bestRegions.clear(); - bestRegions.add(region); - } else if (priority == best) { - bestRegions.add(region); + + // Potential endless recurrence? No, because there is no region group flag. + if ((effectivelyEmpty || priority > maxPriority) && FlagValueCalculator.getEffectiveFlagOf(region, Flags.PASSTHROUGH, this) != State.ALLOW) { + effectivelyEmpty = false; + + if (useMaxPriorityAssociation) { + maxPriority = priority; + } else { + break; + } } } - this.maxPriority = best; - this.maxPriorityRegions = bestRegions; + + this.effectivelyEmpty = effectivelyEmpty; + this.maxPriority = maxPriority; } - private boolean checkNonplayerProtectionDomains(Iterable source, Collection domains) { - if (source == null || domains == null || domains.isEmpty()) { + private boolean checkNonplayerProtectionDomains(ProtectedRegion region) { + if (source.isEmpty()) { return false; } - for (ProtectedRegion region : source) { + // Potential endless recurrence? No, because there is no region group flag. + Set domains = FlagValueCalculator.getEffectiveFlagOf(region, Flags.NONPLAYER_PROTECTION_DOMAINS, this); + + if (domains == null || domains.isEmpty()) { + return false; + } + + for (ProtectedRegion sourceRegion : source) { + if (sourceRegion.getPriority() < maxPriority) { + continue; + } + // Potential endless recurrence? No, because there is no region group flag. - Set regionDomains = FlagValueCalculator.getEffectiveFlagOf(region, Flags.NONPLAYER_PROTECTION_DOMAINS, this); + Set sourceDomains = FlagValueCalculator.getEffectiveFlagOf(sourceRegion, Flags.NONPLAYER_PROTECTION_DOMAINS, this); - if (regionDomains == null || regionDomains.isEmpty()) { + if (sourceDomains == null || sourceDomains.isEmpty()) { continue; } - if (!Collections.disjoint(regionDomains, domains)) { + if (!Collections.disjoint(sourceDomains, domains)) { return true; } } @@ -90,31 +107,15 @@ public Association getAssociation(List regions) { checkNotNull(source); for (ProtectedRegion region : regions) { while (region != null) { - if ((region.getId().equals(ProtectedRegion.GLOBAL_REGION) && source.isEmpty())) { + if (region.getId().equals(ProtectedRegion.GLOBAL_REGION) && effectivelyEmpty) { return Association.OWNER; } - if (source.contains(region)) { - if (useMaxPriorityAssociation) { - int priority = region.getPriority(); - if (priority == maxPriority) { - return Association.OWNER; - } - } else { - return Association.OWNER; - } - } - - Set source; - - if (useMaxPriorityAssociation) { - source = maxPriorityRegions; - } else { - source = this.source; + if (source.contains(region) && region.getPriority() >= maxPriority) { + return Association.OWNER; } - // Potential endless recurrence? No, because there is no region group flag. - if (checkNonplayerProtectionDomains(source, FlagValueCalculator.getEffectiveFlagOf(region, Flags.NONPLAYER_PROTECTION_DOMAINS, this))) { + if (checkNonplayerProtectionDomains(region)) { return Association.OWNER; } diff --git a/worldguard-core/src/main/java/com/sk89q/worldguard/protection/flags/Flags.java b/worldguard-core/src/main/java/com/sk89q/worldguard/protection/flags/Flags.java index b8ccfb3fc..467666283 100644 --- a/worldguard-core/src/main/java/com/sk89q/worldguard/protection/flags/Flags.java +++ b/worldguard-core/src/main/java/com/sk89q/worldguard/protection/flags/Flags.java @@ -45,7 +45,7 @@ public final class Flags { public static final List INBUILT_FLAGS = Collections.unmodifiableList(INBUILT_FLAGS_LIST); // Overrides membership check - public static final StateFlag PASSTHROUGH = register(new StateFlag("passthrough", false)); + public static final StateFlag PASSTHROUGH = register(new StateFlag("passthrough", false, null)); public static final SetFlag NONPLAYER_PROTECTION_DOMAINS = register(new SetFlag<>("nonplayer-protection-domains", null, new StringFlag(null))); // This flag is unlike the others. It forces the checking of region membership diff --git a/worldguard-core/src/main/java/com/sk89q/worldguard/protection/flags/registry/SimpleFlagRegistry.java b/worldguard-core/src/main/java/com/sk89q/worldguard/protection/flags/registry/SimpleFlagRegistry.java index 741d17491..6b6ed0155 100644 --- a/worldguard-core/src/main/java/com/sk89q/worldguard/protection/flags/registry/SimpleFlagRegistry.java +++ b/worldguard-core/src/main/java/com/sk89q/worldguard/protection/flags/registry/SimpleFlagRegistry.java @@ -24,6 +24,10 @@ import com.google.common.collect.Maps; import com.sk89q.worldguard.protection.flags.Flag; import com.sk89q.worldguard.protection.flags.Flags; +import com.sk89q.worldguard.protection.flags.RegionGroup; +import com.sk89q.worldguard.protection.flags.RegionGroupFlag; +import com.sk89q.worldguard.protection.flags.StateFlag; +import com.sk89q.worldguard.protection.flags.StateFlag.State; import javax.annotation.Nullable; import java.util.Collection; @@ -162,7 +166,23 @@ public Map, Object> unmarshal(Map rawValues, boolean cre values.put(unk, entry.getValue()); } } else { - values.put(parent.getRegionGroupFlag(), parent.getRegionGroupFlag().unmarshal(entry.getValue())); + RegionGroupFlag regionGroupFlag = parent.getRegionGroupFlag(); + + if (regionGroupFlag != null) { + values.put(regionGroupFlag, regionGroupFlag.unmarshal(entry.getValue())); + } else { + log.warning("Found non-existent region group flag '" + entry.getKey() + "' with value '" + entry.getValue() + "' for flag '" + parent.getName() + "'"); + log.warning("The region group flag '" + entry.getKey() + "' with value '" + entry.getValue() + "' will be removed"); + regionGroupFlag = new RegionGroupFlag("dummy", RegionGroup.ALL); + RegionGroup regionGroup = regionGroupFlag.unmarshal(entry.getValue()); + + if (regionGroup != null && regionGroup != RegionGroup.ALL) { + if (!(parent instanceof StateFlag) || values.get(parent) == State.ALLOW) { + log.warning("For safety reasons the flag '" + parent.getName() + "' with value '" + values.get(parent) + "' will also be removed"); + values.remove(parent); + } + } + } } }