From 7d894228d0c665d336a36bd547825f4a3a6092e4 Mon Sep 17 00:00:00 2001 From: dordsor21 Date: Thu, 23 Sep 2021 01:19:24 +0100 Subject: [PATCH] Implement region blacklisting --- .../bukkit/filter/GriefDefenderFilter.java | 42 ----- .../bukkit/filter/GriefPreventionFilter.java | 41 ----- .../bukkit/filter/WorldGuardFilter.java | 73 -------- .../bukkit/regions/GriefDefenderFeature.java | 8 - .../regions/GriefPreventionFeature.java | 8 - .../bukkit/regions/WorldGuardFeature.java | 151 +++++++++------- .../regions/plotsquared/PlotRegionFilter.java | 32 ---- .../plotsquared/PlotSquaredFeature.java | 9 - .../plotsquaredv4/PlotRegionFilter.java | 32 ---- .../plotsquaredv4/PlotSquaredFeature.java | 9 - .../com/fastasyncworldedit/core/FaweAPI.java | 14 +- .../core/configuration/Settings.java | 16 ++ .../platform/binding/ProvideBindings.java | 2 +- .../core/extent/HeightBoundExtent.java | 2 +- .../core/extent/MultiRegionExtent.java | 161 ++++++++++++++---- .../core/queue/IBatchProcessor.java | 130 +++++++++----- .../core/regions/FaweMaskManager.java | 25 ++- .../core/util/EditSessionBuilder.java | 4 +- .../core/util/WEManager.java | 30 ++-- .../sk89q/worldedit/EditSessionBuilder.java | 49 +++++- .../com/sk89q/worldedit/entity/Player.java | 40 ++++- .../platform/AbstractPlayerActor.java | 33 ++-- .../sk89q/worldedit/regions/CuboidRegion.java | 151 ++++++++++++---- .../com/sk89q/worldedit/regions/Region.java | 60 ++++++- .../worldedit/regions/RegionIntersection.java | 26 ++- 25 files changed, 657 insertions(+), 491 deletions(-) delete mode 100644 worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/filter/GriefDefenderFilter.java delete mode 100644 worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/filter/GriefPreventionFilter.java delete mode 100644 worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/filter/WorldGuardFilter.java delete mode 100644 worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquared/PlotRegionFilter.java delete mode 100644 worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquaredv4/PlotRegionFilter.java diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/filter/GriefDefenderFilter.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/filter/GriefDefenderFilter.java deleted file mode 100644 index 45f0a4991..000000000 --- a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/filter/GriefDefenderFilter.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.fastasyncworldedit.bukkit.filter; - -import com.fastasyncworldedit.core.regions.filter.CuboidRegionFilter; -import com.fastasyncworldedit.core.util.TaskManager; -import com.flowpowered.math.vector.Vector3i; -import com.griefdefender.api.GriefDefender; -import com.griefdefender.api.claim.Claim; -import com.sk89q.worldedit.math.BlockVector2; -import org.bukkit.World; - -import java.util.ArrayDeque; -import java.util.Collection; -import java.util.function.Supplier; - -import static com.google.common.base.Preconditions.checkNotNull; - -public class GriefDefenderFilter extends CuboidRegionFilter { - - private final Collection claims; - private final World world; - - public GriefDefenderFilter(World world) { - checkNotNull(world); - this.claims = TaskManager.IMP.sync( - (Supplier>) () -> new ArrayDeque<>(GriefDefender.getCore().getAllClaims())); - this.world = world; - } - - @Override - public void calculateRegions() { - for (Claim claim : claims) { - Vector3i bot = claim.getGreaterBoundaryCorner(); - if (world.getUID().equals(claim.getWorldUniqueId())) { - Vector3i top = claim.getGreaterBoundaryCorner(); - BlockVector2 pos1 = BlockVector2.at(bot.getX(), bot.getZ()); - BlockVector2 pos2 = BlockVector2.at(top.getX(), top.getZ()); - add(pos1, pos2); - } - } - } - -} diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/filter/GriefPreventionFilter.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/filter/GriefPreventionFilter.java deleted file mode 100644 index c462ab897..000000000 --- a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/filter/GriefPreventionFilter.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.fastasyncworldedit.bukkit.filter; - -import com.fastasyncworldedit.core.regions.filter.CuboidRegionFilter; -import com.fastasyncworldedit.core.util.TaskManager; -import com.sk89q.worldedit.math.BlockVector2; -import me.ryanhamshire.GriefPrevention.Claim; -import me.ryanhamshire.GriefPrevention.GriefPrevention; -import org.bukkit.World; - -import java.util.ArrayDeque; -import java.util.Collection; -import java.util.function.Supplier; - -import static com.google.common.base.Preconditions.checkNotNull; - -public class GriefPreventionFilter extends CuboidRegionFilter { - - private final Collection claims; - private final World world; - - public GriefPreventionFilter(World world) { - checkNotNull(world); - this.claims = TaskManager.IMP.sync( - (Supplier>) () -> new ArrayDeque<>(GriefPrevention.instance.dataStore.getClaims())); - this.world = world; - } - - @Override - public void calculateRegions() { - for (Claim claim : claims) { - org.bukkit.Location bot = claim.getGreaterBoundaryCorner(); - if (world.equals(bot.getWorld())) { - org.bukkit.Location top = claim.getGreaterBoundaryCorner(); - BlockVector2 pos1 = BlockVector2.at(bot.getBlockX(), bot.getBlockZ()); - BlockVector2 pos2 = BlockVector2.at(top.getBlockX(), top.getBlockZ()); - add(pos1, pos2); - } - } - } - -} diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/filter/WorldGuardFilter.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/filter/WorldGuardFilter.java deleted file mode 100644 index 88128a19c..000000000 --- a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/filter/WorldGuardFilter.java +++ /dev/null @@ -1,73 +0,0 @@ -package com.fastasyncworldedit.bukkit.filter; - -import com.fastasyncworldedit.core.Fawe; -import com.fastasyncworldedit.core.regions.filter.CuboidRegionFilter; -import com.sk89q.worldedit.bukkit.BukkitAdapter; -import com.sk89q.worldedit.internal.util.LogManagerCompat; -import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldguard.WorldGuard; -import com.sk89q.worldguard.protection.ApplicableRegionSet; -import com.sk89q.worldguard.protection.managers.RegionManager; -import com.sk89q.worldguard.protection.regions.ProtectedCuboidRegion; -import com.sk89q.worldguard.protection.regions.ProtectedRegion; -import org.apache.logging.log4j.Logger; -import org.bukkit.World; - -import static com.google.common.base.Preconditions.checkNotNull; - -public class WorldGuardFilter extends CuboidRegionFilter { - - private static final Logger LOGGER = LogManagerCompat.getLogger(); - - private final World world; - private boolean large; - private RegionManager manager; - - public WorldGuardFilter(World world) { - checkNotNull(world); - this.world = world; - } - - @Override - public void calculateRegions() { - Fawe.get().getQueueHandler().sync(() -> { - WorldGuardFilter.this.manager = WorldGuard.getInstance().getPlatform().getRegionContainer().get( - BukkitAdapter.adapt(world)); - for (ProtectedRegion region : manager.getRegions().values()) { - BlockVector3 min = region.getMinimumPoint(); - BlockVector3 max = region.getMaximumPoint(); - if (max.getBlockX() - min.getBlockX() > 1024 || max.getBlockZ() - min.getBlockZ() > 1024) { - LOGGER.info("Large or complex region shapes cannot be optimized. Filtering will be slower"); - large = true; - break; - } - add(min.toBlockVector2(), max.toBlockVector2()); - } - }); - } - - @Override - public boolean containsChunk(int chunkX, int chunkZ) { - if (!large) { - return super.containsChunk(chunkX, chunkZ); - } - BlockVector3 pos1 = BlockVector3.at(chunkX << 4, 0, chunkZ << 4); - BlockVector3 pos2 = BlockVector3.at(pos1.getBlockX() + 15, 255, pos1.getBlockZ() + 15); - ProtectedCuboidRegion chunkRegion = new ProtectedCuboidRegion("unimportant", pos1, pos2); - ApplicableRegionSet set = manager.getApplicableRegions(chunkRegion); - return set.size() > 0 && !set.getRegions().iterator().next().getId().equals("__global__"); - } - - @Override - public boolean containsRegion(int mcaX, int mcaZ) { - if (!large) { - return super.containsRegion(mcaX, mcaZ); - } - BlockVector3 pos1 = BlockVector3.at(mcaX << 9, 0, mcaZ << 9); - BlockVector3 pos2 = BlockVector3.at(pos1.getBlockX() + 511, 255, pos1.getBlockZ() + 511); - ProtectedCuboidRegion regionRegion = new ProtectedCuboidRegion("unimportant", pos1, pos2); - ApplicableRegionSet set = manager.getApplicableRegions(regionRegion); - return set.size() > 0 && !set.getRegions().iterator().next().getId().equals("__global__"); - } - -} diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/GriefDefenderFeature.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/GriefDefenderFeature.java index c242afeeb..3a09a9aa8 100644 --- a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/GriefDefenderFeature.java +++ b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/GriefDefenderFeature.java @@ -1,8 +1,6 @@ package com.fastasyncworldedit.bukkit.regions; -import com.fastasyncworldedit.bukkit.filter.GriefDefenderFilter; import com.fastasyncworldedit.core.regions.FaweMask; -import com.fastasyncworldedit.core.regions.filter.RegionFilter; import com.flowpowered.math.vector.Vector3i; import com.griefdefender.api.GriefDefender; import com.griefdefender.api.claim.Claim; @@ -12,7 +10,6 @@ import com.sk89q.worldedit.internal.util.LogManagerCompat; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.CuboidRegion; import org.apache.logging.log4j.Logger; -import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.entity.Player; import org.bukkit.event.Listener; @@ -65,9 +62,4 @@ public class GriefDefenderFeature extends BukkitMaskManager implements Listener return null; } - @Override - public RegionFilter getFilter(String world) { - return new GriefDefenderFilter(Bukkit.getWorld(world)); - } - } diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/GriefPreventionFeature.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/GriefPreventionFeature.java index 00e6f3f23..a54f3a0af 100644 --- a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/GriefPreventionFeature.java +++ b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/GriefPreventionFeature.java @@ -1,8 +1,6 @@ package com.fastasyncworldedit.bukkit.regions; -import com.fastasyncworldedit.bukkit.filter.GriefPreventionFilter; import com.fastasyncworldedit.core.regions.FaweMask; -import com.fastasyncworldedit.core.regions.filter.RegionFilter; import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.internal.util.LogManagerCompat; import com.sk89q.worldedit.math.BlockVector3; @@ -10,7 +8,6 @@ import com.sk89q.worldedit.regions.CuboidRegion; import me.ryanhamshire.GriefPrevention.Claim; import me.ryanhamshire.GriefPrevention.GriefPrevention; import org.apache.logging.log4j.Logger; -import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.entity.Player; import org.bukkit.event.Listener; @@ -61,9 +58,4 @@ public class GriefPreventionFeature extends BukkitMaskManager implements Listene return null; } - @Override - public RegionFilter getFilter(String world) { - return new GriefPreventionFilter(Bukkit.getWorld(world)); - } - } diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/WorldGuardFeature.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/WorldGuardFeature.java index 1a2745dc2..4e3174b89 100644 --- a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/WorldGuardFeature.java +++ b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/WorldGuardFeature.java @@ -1,9 +1,8 @@ package com.fastasyncworldedit.bukkit.regions; -import com.fastasyncworldedit.bukkit.filter.WorldGuardFilter; import com.fastasyncworldedit.core.regions.FaweMask; import com.fastasyncworldedit.core.regions.RegionWrapper; -import com.fastasyncworldedit.core.regions.filter.RegionFilter; +import com.google.common.collect.ImmutableSet; import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.internal.util.LogManagerCompat; import com.sk89q.worldedit.math.BlockVector3; @@ -11,6 +10,7 @@ import com.sk89q.worldedit.regions.AbstractRegion; import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.Polygonal2DRegion; import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.regions.RegionIntersection; import com.sk89q.worldguard.LocalPlayer; import com.sk89q.worldguard.WorldGuard; import com.sk89q.worldguard.bukkit.WorldGuardPlugin; @@ -29,12 +29,38 @@ import org.bukkit.entity.Player; import org.bukkit.event.Listener; import org.bukkit.plugin.Plugin; +import java.util.Collections; +import java.util.HashSet; import java.util.Locale; +import java.util.Set; public class WorldGuardFeature extends BukkitMaskManager implements Listener { - private final WorldGuardPlugin worldguard; private static final Logger LOGGER = LogManagerCompat.getLogger(); + private final WorldGuardPlugin worldguard; + + public WorldGuardFeature(Plugin plugin) { + super(plugin.getName()); + this.worldguard = this.getWorldGuard(); + LOGGER.info("Plugin 'WorldGuard' found. Using it now."); + + } + + private static Region adapt(ProtectedRegion region) { + if (region instanceof ProtectedCuboidRegion) { + return new CuboidRegion(region.getMinimumPoint(), region.getMaximumPoint()); + } + if (region instanceof GlobalProtectedRegion) { + return RegionWrapper.GLOBAL(); + } + if (region instanceof ProtectedPolygonalRegion) { + ProtectedPolygonalRegion casted = (ProtectedPolygonalRegion) region; + BlockVector3 max = region.getMaximumPoint(); + BlockVector3 min = region.getMinimumPoint(); + return new Polygonal2DRegion(null, casted.getPoints(), min.getBlockY(), max.getBlockY()); + } + return new AdaptedRegion(region); + } private WorldGuardPlugin getWorldGuard() { final Plugin plugin = Bukkit.getPluginManager().getPlugin("WorldGuard"); @@ -47,27 +73,21 @@ public class WorldGuardFeature extends BukkitMaskManager implements Listener { return (WorldGuardPlugin) plugin; } - public WorldGuardFeature(Plugin plugin) { - super(plugin.getName()); - this.worldguard = this.getWorldGuard(); - LOGGER.info("Plugin 'WorldGuard' found. Using it now."); - - } - - public ProtectedRegion getRegion(LocalPlayer player, Location location) { + public Set getRegions(LocalPlayer player, Location location, boolean isWhitelist) { RegionContainer container = WorldGuard.getInstance().getPlatform().getRegionContainer(); if (container == null) { LOGGER.info("Region capability is not enabled for WorldGuard."); - return null; + return Collections.emptySet(); } RegionManager manager = container.get(BukkitAdapter.adapt(location.getWorld())); if (manager == null) { LOGGER.info("Region capability is not enabled for that world."); - return null; + return Collections.emptySet(); } final ProtectedRegion global = manager.getRegion("__global__"); - if (global != null && isAllowed(player, global)) { - return global; + // If they're allowed and it's a whitelist return, else if they're not allowed and it's a blacklist, return + if (global != null && isAllowed(player, global) == isWhitelist) { + return Collections.singleton(global); } final ApplicableRegionSet regions = manager.getApplicableRegions(BlockVector3.at( location.getX(), @@ -75,20 +95,39 @@ public class WorldGuardFeature extends BukkitMaskManager implements Listener { location.getZ() )); //Merge WorldGuardFlag - if (player.hasPermission("fawe.worldguardflag") && !regions.testState( - player, - Flags.BUILD, - Flags.BLOCK_PLACE, - Flags.BLOCK_BREAK - )) { - return null; - } - for (ProtectedRegion region : regions) { - if (isAllowed(player, region)) { - return region; + if (isWhitelist) { + if (player.hasPermission("fawe.worldguardflag") && !regions.testState( + player, + Flags.BUILD, + Flags.BLOCK_PLACE, + Flags.BLOCK_BREAK + )) { + return Collections.emptySet(); } + Set protectedRegions = new HashSet<>(); + for (ProtectedRegion region : regions) { + if (isAllowed(player, region)) { + protectedRegions.add(region); + } + } + return Collections.unmodifiableSet(protectedRegions); + } else { + if (player.hasPermission("fawe.worldguardflag") && !regions.testState( + player, + Flags.BUILD, + Flags.BLOCK_PLACE, + Flags.BLOCK_BREAK + )) { + return ImmutableSet.copyOf(regions.getRegions()); + } + Set protectedRegions = new HashSet<>(); + for (ProtectedRegion region : regions) { + if (!isAllowed(player, region)) { + protectedRegions.add(region); + } + } + return Collections.unmodifiableSet(protectedRegions); } - return null; } public boolean isAllowed(LocalPlayer localplayer, ProtectedRegion region) { @@ -115,45 +154,45 @@ public class WorldGuardFeature extends BukkitMaskManager implements Listener { } @Override - public FaweMask getMask(com.sk89q.worldedit.entity.Player wePlayer, MaskType type) { + public FaweMask getMask(com.sk89q.worldedit.entity.Player wePlayer, MaskType type, boolean isWhitelist) { final Player player = BukkitAdapter.adapt(wePlayer); final LocalPlayer localplayer = this.worldguard.wrapPlayer(player); final Location location = player.getLocation(); - final ProtectedRegion myregion = this.getRegion(localplayer, location); - if (myregion != null) { - final BlockVector3 pos1; - final BlockVector3 pos2; - if (myregion.getId().equals("__global__")) { - pos1 = BlockVector3.at(Integer.MIN_VALUE, wePlayer.getWorld().getMinY(), Integer.MIN_VALUE); - pos2 = BlockVector3.at(Integer.MAX_VALUE, wePlayer.getWorld().getMaxY(), Integer.MAX_VALUE); - } else { - if (myregion instanceof ProtectedCuboidRegion) { - pos1 = myregion.getMinimumPoint(); - pos2 = myregion.getMaximumPoint(); - } else { - return new FaweMask(adapt(myregion)) { + final Set regions = this.getRegions(localplayer, location, isWhitelist); + if (!regions.isEmpty()) { + Set result = new HashSet<>(); + for (ProtectedRegion myregion : regions) { + if (myregion.getId().equals("__global__")) { + return new FaweMask(RegionWrapper.GLOBAL()) { @Override public boolean isValid(com.sk89q.worldedit.entity.Player player, MaskType type) { return isAllowed(worldguard.wrapPlayer(BukkitAdapter.adapt(player)), myregion); } }; + } else { + if (myregion instanceof ProtectedCuboidRegion) { + result.add(new CuboidRegion(myregion.getMaximumPoint(), myregion.getMaximumPoint())); + } else { + result.add(adapt(myregion)); + } } } - return new FaweMask(new CuboidRegion(pos1, pos2)) { + return new FaweMask(new RegionIntersection(wePlayer.getWorld(), result)) { @Override public boolean isValid(com.sk89q.worldedit.entity.Player player, MaskType type) { - return isAllowed(worldguard.wrapPlayer(BukkitAdapter.adapt(player)), myregion); + final LocalPlayer localplayer = worldguard.wrapPlayer(BukkitAdapter.adapt(player)); + for (ProtectedRegion myregion : regions) { + if (!isAllowed(localplayer, myregion)) { + return false; + } + } + return true; } }; } return null; } - @Override - public RegionFilter getFilter(String world) { - return new WorldGuardFilter(Bukkit.getWorld(world)); - } - private static class AdaptedRegion extends AbstractRegion { private final ProtectedRegion region; @@ -190,20 +229,4 @@ public class WorldGuardFeature extends BukkitMaskManager implements Listener { } - private static Region adapt(ProtectedRegion region) { - if (region instanceof ProtectedCuboidRegion) { - return new CuboidRegion(region.getMinimumPoint(), region.getMaximumPoint()); - } - if (region instanceof GlobalProtectedRegion) { - return RegionWrapper.GLOBAL(); - } - if (region instanceof ProtectedPolygonalRegion) { - ProtectedPolygonalRegion casted = (ProtectedPolygonalRegion) region; - BlockVector3 max = region.getMaximumPoint(); - BlockVector3 min = region.getMinimumPoint(); - return new Polygonal2DRegion(null, casted.getPoints(), min.getBlockY(), max.getBlockY()); - } - return new AdaptedRegion(region); - } - } diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquared/PlotRegionFilter.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquared/PlotRegionFilter.java deleted file mode 100644 index 4e9e1c098..000000000 --- a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquared/PlotRegionFilter.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.fastasyncworldedit.bukkit.regions.plotsquared; - -import com.fastasyncworldedit.core.regions.filter.CuboidRegionFilter; -import com.plotsquared.core.location.Location; -import com.plotsquared.core.plot.Plot; -import com.plotsquared.core.plot.PlotArea; -import com.sk89q.worldedit.math.BlockVector2; - -import java.util.ArrayList; - -import static com.google.common.base.Preconditions.checkNotNull; - -public class PlotRegionFilter extends CuboidRegionFilter { - - private final PlotArea area; - - public PlotRegionFilter(PlotArea area) { - checkNotNull(area); - this.area = area; - } - - @Override - public void calculateRegions() { - ArrayList plots = new ArrayList<>(area.getPlots()); - for (Plot plot : plots) { - Location bottom = plot.getCorners()[0]; - Location top = plot.getCorners()[1]; - add(BlockVector2.at(bottom.getX(), bottom.getZ()), BlockVector2.at(top.getX(), top.getZ())); - } - } - -} diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquared/PlotSquaredFeature.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquared/PlotSquaredFeature.java index e45b7ed3e..2db805405 100644 --- a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquared/PlotSquaredFeature.java +++ b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquared/PlotSquaredFeature.java @@ -184,13 +184,4 @@ public class PlotSquaredFeature extends FaweMaskManager { }; } - @Override - public RegionFilter getFilter(String world) { - PlotArea area = PlotSquared.get().getPlotAreaManager().getPlotArea(world, null); - if (area != null) { - return new PlotRegionFilter(area); - } - return null; - } - } diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquaredv4/PlotRegionFilter.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquaredv4/PlotRegionFilter.java deleted file mode 100644 index 703a8bf8d..000000000 --- a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquaredv4/PlotRegionFilter.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.fastasyncworldedit.bukkit.regions.plotsquaredv4; - -import com.fastasyncworldedit.core.regions.filter.CuboidRegionFilter; -import com.github.intellectualsites.plotsquared.plot.object.Location; -import com.github.intellectualsites.plotsquared.plot.object.Plot; -import com.github.intellectualsites.plotsquared.plot.object.PlotArea; -import com.sk89q.worldedit.math.BlockVector2; - -import java.util.ArrayList; - -import static com.google.common.base.Preconditions.checkNotNull; - -public class PlotRegionFilter extends CuboidRegionFilter { - - private final PlotArea area; - - public PlotRegionFilter(PlotArea area) { - checkNotNull(area); - this.area = area; - } - - @Override - public void calculateRegions() { - ArrayList plots = new ArrayList<>(area.getPlots()); - for (Plot plot : plots) { - Location bottom = plot.getCorners()[0]; - Location top = plot.getCorners()[1]; - add(BlockVector2.at(bottom.getX(), bottom.getZ()), BlockVector2.at(top.getX(), top.getZ())); - } - } - -} diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquaredv4/PlotSquaredFeature.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquaredv4/PlotSquaredFeature.java index 0d5fa5b7c..117768670 100644 --- a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquaredv4/PlotSquaredFeature.java +++ b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquaredv4/PlotSquaredFeature.java @@ -224,13 +224,4 @@ public class PlotSquaredFeature extends FaweMaskManager { }; } - @Override - public RegionFilter getFilter(String world) { - PlotArea area = PlotSquared.get().getPlotArea(world, null); - if (area != null) { - return new PlotRegionFilter(area); - } - return null; - } - } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweAPI.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweAPI.java index 56cc5c6e2..3c94233ee 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweAPI.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweAPI.java @@ -152,12 +152,24 @@ public class FaweAPI { } /** - * Get a player's allowed WorldEdit region. + * Get a player's allowed WorldEdit region(s). */ public static Region[] getRegions(Player player) { return WEManager.IMP.getMask(player); } + /** + * Get a player's allowed WorldEdit region(s). + * + * @param player Player to get mask of + * @param type Mask type; whether to check if the player is an owner of a member of the regions + * @param isWhiteList If searching for whitelist or blacklist regions. True if whitelist + * @return array of allowed regions if whitelist, else of disallowed regions. + */ + public static Region[] getRegions(Player player, FaweMaskManager.MaskType type, boolean isWhiteList) { + return WEManager.IMP.getMask(player, type, isWhiteList); + } + /** * Cancel the edit with the following extent. * diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java index eca812058..86bd99118 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java @@ -125,6 +125,12 @@ public class Settings extends Config { " - OWNER = Players who own the region" }) public String MODE = "MEMBER"; + @Comment({ + "Allow region blacklists.", + " - Currently only implemented for WorldGuard ", + " - see region-restrictions-options.worldguard-region-blacklist" + }) + public boolean ALLOW_BLACKLISTS = false; @Comment({ "List of plugin mask managers that should be exclusive. Exclusive managers are not ", "checked for edit restrictions if another manager already allowed an edit, and further ", @@ -133,6 +139,16 @@ public class Settings extends Config { " - Some custom-implementations in other plugins may override this setting" }) public List EXCLUSIVE_MANAGERS = new ArrayList<>(Collections.singleton(("ExamplePlugin"))); + @Comment({ + "If a worldguard-protected world should be considered as a region blacklist.", + " - This will create a blacklist of regions where an edit cannot operate.", + " - Useful for a \"freebuild\" worlds with few protected areas.", + " - May cause performance loss with large numbers of protected areas.", + " - Requires region-restrictions-options.allow-blacklists be true.", + " - Will still search for current allowed regions to limit the edit to.", + " - Any blacklist regions are likely to override any internal allowed regions." + }) + public boolean WORLDGUARD_REGION_BLACKLIST = false; } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/platform/binding/ProvideBindings.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/platform/binding/ProvideBindings.java index 336b66ce6..45067dae2 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/platform/binding/ProvideBindings.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/platform/binding/ProvideBindings.java @@ -84,7 +84,7 @@ public class ProvideBindings extends Bindings { } public Region[] regions(Player player, FaweMaskManager.MaskType type) { - Region[] regions = player.getCurrentRegions(type); + Region[] regions = player.getAllowedRegions(type); if (regions == null) { throw new IllegalArgumentException(Caption.toString(Caption.of("fawe.error.no.region"))); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/HeightBoundExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/HeightBoundExtent.java index db5a03c6d..5e60af81b 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/HeightBoundExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/HeightBoundExtent.java @@ -50,7 +50,7 @@ public class HeightBoundExtent extends FaweRegionExtent { @Override public IChunkSet processSet(IChunk chunk, IChunkGet get, IChunkSet set) { - if (trimY(set, min, max) | trimNBT(set, this::contains)) { + if (trimY(set, min, max, true) | trimNBT(set, this::contains)) { return set; } return null; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/MultiRegionExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/MultiRegionExtent.java index 91ce69645..f55581f8a 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/MultiRegionExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/MultiRegionExtent.java @@ -4,88 +4,177 @@ import com.fastasyncworldedit.core.limit.FaweLimit; import com.fastasyncworldedit.core.queue.IChunk; import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.IChunkSet; +import com.fastasyncworldedit.core.regions.RegionWrapper; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.RegionIntersection; +import javax.annotation.Nullable; import java.util.Arrays; import java.util.Collection; +import java.util.List; import java.util.concurrent.Future; public class MultiRegionExtent extends FaweRegionExtent { + @Nullable private final RegionIntersection intersection; - private final Region[] regions; + @Nullable + private final RegionIntersection disallowedIntersection; + @Nullable + private final Region[] allowed; + @Nullable + private final Region[] disallowed; + @Nullable private Region region; private int index; /** - * Create a new instance. + * Create a new instance. Has both allowed and disallowed regions. Assumes that disallowed regions are encompassed by + * allowed regions. * - * @param extent the extent + * @param extent the extent + * @param limit the limit to be used + * @param allowed the allowed regions or null for global editing + * @param disallowed the disallowed regions or null for no disallowed regions */ - public MultiRegionExtent(Extent extent, FaweLimit limit, Region[] regions) { + public MultiRegionExtent(Extent extent, FaweLimit limit, @Nullable Region[] allowed, @Nullable Region[] disallowed) { super(extent, limit); this.index = 0; - this.region = regions[0]; - this.regions = regions; - this.intersection = new RegionIntersection(Arrays.asList(regions)); + if (allowed != null && !allowed[0].isGlobal()) { + this.region = allowed[0]; + this.allowed = allowed; + this.intersection = new RegionIntersection(Arrays.asList(allowed)); + } else { + this.region = null; + this.allowed = null; + this.intersection = null; + } + if (disallowed != null && disallowed.length > 0) { + this.disallowed = disallowed; + this.disallowedIntersection = new RegionIntersection(Arrays.asList(disallowed)); + } else { + this.disallowed = null; + this.disallowedIntersection = null; + } } @Override public boolean contains(int x, int y, int z) { - if (region.contains(x, y, z)) { + if (region != null && region.contains(x, y, z)) { + if (disallowed != null) { + for (final Region disallow : disallowed) { + if (disallow.contains(x, y, z)) { + return false; + } + } + } return true; } - for (int i = 0; i < regions.length; i++) { - if (i != index) { - Region current = regions[i]; - if (current.contains(x, y, z)) { - region = current; - index = i; - return true; + boolean result = allowed == null; + if (!result) { + for (int i = 0; i < allowed.length; i++) { + if (i != index) { + Region current = allowed[i]; + if (current.contains(x, y, z)) { + region = current; + index = i; + result = true; + break; + } } } } - return false; - } - - @Override - public boolean processGet(int chunkX, int chunkZ) { - for (Region region : regions) { - if (region.containsChunk(chunkX, chunkZ)) { - return true; + if (!result || disallowed == null) { + return result; + } + for (final Region disallow : disallowed) { + if (disallow.contains(x, y, z)) { + return false; } } - return false; + return true; } @Override public boolean contains(int x, int z) { - if (region.contains(x, z)) { + if (region != null && region.contains(x, z)) { + if (disallowed != null) { + for (final Region disallow : disallowed) { + if (disallow.contains(x, z)) { + return false; + } + } + } return true; } - for (int i = 0; i < regions.length; i++) { - if (i != index) { - Region current = regions[i]; - if (current.contains(x, z)) { - region = current; - index = i; - return true; + boolean result = allowed == null; + if (!result) { + for (int i = 0; i < allowed.length; i++) { + if (i != index) { + Region current = allowed[i]; + if (current.contains(x, z)) { + region = current; + index = i; + result = true; + break; + } } } } - return false; + if (!result || disallowed == null) { + return result; + } + for (final Region disallow : disallowed) { + if (disallow.contains(x, z)) { + return false; + } + } + return true; + } + + /** + * Get all allowed regions + */ + @Override + public Collection getRegions() { + if (allowed == null) { + return List.of(RegionWrapper.GLOBAL()); + } + return Arrays.asList(allowed); } @Override - public Collection getRegions() { - return Arrays.asList(regions); + public boolean processGet(int chunkX, int chunkZ) { + boolean result = allowed == null; + if (!result) { + for (Region region : allowed) { + if (region.containsChunk(chunkX, chunkZ)) { + result = true; + break; + } + } + } + if (!result || disallowed == null) { + return result; + } + for (Region region : disallowed) { + if (region.containsChunk(chunkX, chunkZ)) { + return false; + } + } + return true; } @Override public IChunkSet processSet(IChunk chunk, IChunkGet get, IChunkSet set) { - return intersection.processSet(chunk, get, set); + if (intersection != null) { + set = intersection.processSet(chunk, get, set); + } + if (disallowedIntersection != null) { + intersection.processSet(chunk, get, set); + } + return set; } @Override diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBatchProcessor.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBatchProcessor.java index fdd4eddf9..f3240d0c2 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBatchProcessor.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBatchProcessor.java @@ -34,61 +34,99 @@ public interface IBatchProcessor { Extent construct(Extent child); /** - * Utility method to trim a chunk based on min and max Y. + * Utility method to trim a chunk based on min and max Y (inclusive). * + * @param keepInsideRange if all blocks inside the range (inclusive) should be kept (default) * @return false if chunk is empty of blocks */ - default boolean trimY(IChunkSet set, int minY, int maxY) { + default boolean trimY(IChunkSet set, int minY, int maxY, final boolean keepInsideRange) { int minLayer = (minY - 1) >> 4; - for (int layer = set.getMinSectionPosition(); layer <= minLayer; layer++) { - if (set.hasSection(layer)) { - if (layer == minLayer) { - char[] arr = set.loadIfPresent(layer); - if (arr != null) { - int index = (minY & 15) << 8; - for (int i = 0; i < index; i++) { - arr[i] = 0; - } - } else { - arr = new char[4096]; - } - set.setBlocks(layer, arr); - } else { - set.setBlocks(layer, null); - } - } - } int maxLayer = (maxY + 1) >> 4; - for (int layer = maxLayer; layer < set.getMaxSectionPosition(); layer++) { - if (set.hasSection(layer)) { - if (layer == minLayer) { - char[] arr = set.loadIfPresent(layer); - if (arr != null) { - int index = ((maxY + 1) & 15) << 8; - for (int i = index; i < arr.length; i++) { - arr[i] = 0; - } - } else { - arr = new char[4096]; - } - set.setBlocks(layer, arr); - } else { - set.setBlocks(layer, null); - } - } - } - try { - int layer = (minY - 15) >> 4; - while (layer < (maxY + 15) >> 4) { + if (keepInsideRange) { + for (int layer = set.getMinSectionPosition(); layer <= minLayer; layer++) { if (set.hasSection(layer)) { - return true; + if (layer == minLayer) { + char[] arr = set.loadIfPresent(layer); + if (arr != null) { + int index = (minY & 15) << 8; + for (int i = 0; i < index; i++) { + arr[i] = 0; + } + } else { + arr = new char[4096]; + } + set.setBlocks(layer, arr); + } else { + set.setBlocks(layer, null); + } } - layer++; } - } catch (ArrayIndexOutOfBoundsException exception) { - WorldEdit.logger.error("minY = {} , layer = {}", minY, ((minY - 15) >> 4), exception); + for (int layer = maxLayer; layer < set.getMaxSectionPosition(); layer++) { + if (set.hasSection(layer)) { + if (layer == minLayer) { + char[] arr = set.loadIfPresent(layer); + if (arr != null) { + int index = ((maxY + 1) & 15) << 8; + for (int i = index; i < arr.length; i++) { + arr[i] = 0; + } + } else { + arr = new char[4096]; + } + set.setBlocks(layer, arr); + } else { + set.setBlocks(layer, null); + } + } + } + try { + int layer = (minY - 15) >> 4; + while (layer < (maxY + 15) >> 4) { + if (set.hasSection(layer)) { + return true; + } + layer++; + } + } catch (ArrayIndexOutOfBoundsException exception) { + WorldEdit.logger.error("IBatchProcessor: minY = {} , layer = {}", minY, ((minY - 15) >> 4), exception); + } + return false; } - return false; + int chunkMaxY = (set.getMaxSectionPosition() << 4) + 15; + int chunkMinY = set.getMinSectionPosition() << 4; + if (maxY >= chunkMaxY && minY <= chunkMinY) { + set.reset(); + return false; + } + boolean hasBlocks = false; + for (int layer = set.getMinSectionPosition(); layer <= set.getMaxSectionPosition(); layer++) { + if (layer < minLayer || layer > maxLayer) { + hasBlocks |= set.hasSection(layer); + continue; + } + if (layer == minLayer) { + char[] arr = set.loadIfPresent(layer); + if (arr != null) { + int index = (minY & 15) << 8; + for (int i = index; i < 4096; i++) { + arr[i] = 0; + } + } + set.setBlocks(layer, arr); + } else if (layer == maxLayer) { + char[] arr = set.loadIfPresent(layer); + if (arr != null) { + int index = ((maxY + 1) & 15) << 8; + for (int i = 0; i < index; i++) { + arr[i] = 0; + } + } + set.setBlocks(layer, arr); + } else { + set.setBlocks(layer, null); + } + } + return hasBlocks; } /** diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/regions/FaweMaskManager.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/regions/FaweMaskManager.java index fae3aa7ea..a36a44c29 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/regions/FaweMaskManager.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/regions/FaweMaskManager.java @@ -23,22 +23,39 @@ public abstract class FaweMaskManager { return this.key; } + /** + * Get a {@link FaweMask} for the given player and {@link MaskType} + * + * @deprecated Use {@link #getMask(Player, MaskType, boolean)} + */ + @Deprecated(forRemoval = true) public FaweMask getMask(final Player player, MaskType type) { return null; } + /** + * Get a {@link FaweMask} for the given player and {@link MaskType}. If isWhitelist is false, will return a "blacklist" mask. + */ + public FaweMask getMask(final Player player, MaskType type, boolean isWhitelist) { + return null; + } + + /** + * @deprecated Not used internally + */ + @Deprecated(forRemoval = true) public boolean isValid(FaweMask mask) { return true; } + /** + * @deprecated Not used internally + */ + @Deprecated(forRemoval = true) public RegionFilter getFilter(String world) { return null; } - private boolean hasMemberPermission(Player player) { - return player.hasPermission("fawe." + getKey() + ".member"); - } - public boolean isExclusive() { return Settings.IMP.REGION_RESTRICTIONS_OPTIONS.EXCLUSIVE_MANAGERS.contains(this.key); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/EditSessionBuilder.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/EditSessionBuilder.java index 8958ac2e2..e99c3a162 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/EditSessionBuilder.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/EditSessionBuilder.java @@ -391,7 +391,7 @@ public class EditSessionBuilder { } if (allowedRegions == null) { if (player != null && !player.hasPermission("fawe.bypass") && !player.hasPermission("fawe.bypass.regions")) { - allowedRegions = player.getCurrentRegions(); + allowedRegions = player.getAllowedRegions(); } } FaweRegionExtent regionExtent = null; @@ -402,7 +402,7 @@ public class EditSessionBuilder { if (allowedRegions.length == 1) { regionExtent = new SingleRegionExtent(this.extent, this.limit, allowedRegions[0]); } else { - regionExtent = new MultiRegionExtent(this.extent, this.limit, allowedRegions); + regionExtent = new MultiRegionExtent(this.extent, this.limit, allowedRegions, null); } } } else { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/WEManager.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/WEManager.java index aaaa1adff..cdef52b04 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/WEManager.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/WEManager.java @@ -61,19 +61,26 @@ public class WEManager { cancelEditSafe(parent, reason); } - @Deprecated - public Region[] getMask(Player player) { - return getMask(player, FaweMaskManager.MaskType.getDefaultMaskType()); - } - public boolean isIn(int x, int y, int z, Region region) { return region.contains(x, y, z); } /** - * Get a player's mask. + * Get a player's allowed WorldEdit region(s). */ - public Region[] getMask(Player player, FaweMaskManager.MaskType type) { + public Region[] getMask(Player player) { + return getMask(player, FaweMaskManager.MaskType.getDefaultMaskType(), true); + } + + /** + * Get a player's mask. + * + * @param player Player to get mask of + * @param type Mask type; whether to check if the player is an owner of a member of the regions + * @param isWhitelist If searching for whitelist or blacklist regions. True if whitelist + * @return array of allowed regions if whitelist, else of disallowed regions. + */ + public Region[] getMask(Player player, FaweMaskManager.MaskType type, final boolean isWhitelist) { if (!Settings.IMP.REGION_RESTRICTIONS || player.hasPermission("fawe.bypass") || player.hasPermission("fawe.bypass.regions")) { return new Region[]{RegionWrapper.GLOBAL()}; } @@ -89,7 +96,7 @@ public class WEManager { Set regions = new HashSet<>(); - if (masks == null) { + if (masks == null || !isWhitelist) { masks = new HashSet<>(); } else { synchronized (masks) { @@ -125,7 +132,7 @@ public class WEManager { if (manager.isExclusive() && !masks.isEmpty()) { continue; } - final FaweMask mask = manager.getMask(player, FaweMaskManager.MaskType.getDefaultMaskType()); + final FaweMask mask = manager.getMask(player, FaweMaskManager.MaskType.getDefaultMaskType(), isWhitelist); if (mask != null) { regions.add(mask.getRegion()); masks.add(mask); @@ -140,9 +147,10 @@ public class WEManager { player.printError(TextComponent.of("Missing permission " + "fawe." + manager.getKey())); } } - if (!masks.isEmpty()) { + regions.addAll(backupRegions); + if (!masks.isEmpty() && isWhitelist) { player.setMeta("lastMask", masks); - } else { + } else if (isWhitelist) { player.deleteMeta("lastMask"); } return regions.toArray(new Region[0]); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSessionBuilder.java b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSessionBuilder.java index 66881f44c..ff12eaf06 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSessionBuilder.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSessionBuilder.java @@ -86,6 +86,7 @@ public final class EditSessionBuilder { private FaweLimit limit; private AbstractChangeSet changeSet; private Region[] allowedRegions; + private Region[] disallowedRegions; private Boolean fastMode; private Boolean checkMemory; private Boolean combineStages; @@ -341,6 +342,34 @@ public final class EditSessionBuilder { return setDirty(); } + /** + * Set the regions the edit is allowed to operate in. Set to null for the regions to be calculated based on the actor if + * present + */ + public EditSessionBuilder disallowedRegions(@Nullable Region[] disallowedRegions) { + this.disallowedRegions = disallowedRegions; + return setDirty(); + } + + /** + * Set the regions the edit is allowed to operate in. Set to null for the regions to be calculated based on the actor if + * present + */ + @Deprecated + public EditSessionBuilder disallowedRegions(@Nullable RegionWrapper[] disallowedRegions) { + this.disallowedRegions = disallowedRegions; + return setDirty(); + } + + /** + * Set the region the edit is allowed to operate in. Set to null for the regions to be calculated based on the actor if + * present + */ + public EditSessionBuilder disallowedRegions(@Nullable RegionWrapper disallowedRegion) { + this.disallowedRegions = disallowedRegion == null ? null : disallowedRegion.toArray(); + return setDirty(); + } + /** * Set the edit to be allowed to edit everywhere */ @@ -511,23 +540,33 @@ public final class EditSessionBuilder { if (actor != null && !actor.hasPermission("fawe.bypass") && !actor.hasPermission("fawe.bypass.regions")) { if (actor instanceof Player) { Player player = (Player) actor; - allowedRegions = player.getCurrentRegions(); + allowedRegions = player.getAllowedRegions(); + } + } + } + if (disallowedRegions == null && Settings.IMP.REGION_RESTRICTIONS && Settings.IMP.REGION_RESTRICTIONS_OPTIONS.ALLOW_BLACKLISTS) { + if (actor != null && !actor.hasPermission("fawe.bypass") && !actor.hasPermission("fawe.bypass.regions")) { + if (actor instanceof Player) { + Player player = (Player) actor; + disallowedRegions = player.getDisallowedRegions(); } } } FaweRegionExtent regionExtent = null; - if (allowedRegions != null) { + if (disallowedRegions != null) { // Always use MultiRegionExtent if we have blacklist regions + regionExtent = new MultiRegionExtent(this.extent, this.limit, allowedRegions, disallowedRegions); + } else if (allowedRegions == null) { + allowedRegions = new Region[]{RegionWrapper.GLOBAL()}; + } else { if (allowedRegions.length == 0) { regionExtent = new NullExtent(this.extent, FaweCache.NO_REGION); } else { if (allowedRegions.length == 1) { regionExtent = new SingleRegionExtent(this.extent, this.limit, allowedRegions[0]); } else { - regionExtent = new MultiRegionExtent(this.extent, this.limit, allowedRegions); + regionExtent = new MultiRegionExtent(this.extent, this.limit, allowedRegions, disallowedRegions); } } - } else { - allowedRegions = new Region[]{RegionWrapper.GLOBAL()}; } // There's no need to do lighting (and it'll also just be a pain to implement) if we're not placing chunks if (placeChunks) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/entity/Player.java b/worldedit-core/src/main/java/com/sk89q/worldedit/entity/Player.java index 0ce65f2ed..5d4206c71 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/entity/Player.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/entity/Player.java @@ -348,12 +348,46 @@ public interface Player extends Entity, Actor { > void sendFakeBlock(BlockVector3 pos, @Nullable B block); //FAWE start - Region[] getCurrentRegions(); + /** + * Get the player's current allowed WorldEdit regions. + * + * @return an array of allowed regions + */ + Region[] getAllowedRegions(); - Region[] getCurrentRegions(FaweMaskManager.MaskType type); + /** + * Get the player's current allowed WorldEdit regions. + * + * @param type Mask type; whether to check if the player is an owner of a member of the regions + * @return an array of allowed regions + */ + Region[] getAllowedRegions(FaweMaskManager.MaskType type); + /** + * Get the player's current disallowed WorldEdit regions. Effectively a blacklist. + * + * @return an array of disallowed regions + */ + Region[] getDisallowedRegions(); + + /** + * Get the player's current disallowed WorldEdit regions. Effectively a blacklist. + * + * @param type Mask type; whether to check if the player is an owner of a member of the regions + * @return an array of disallowed regions + */ + Region[] getDisallowedRegions(FaweMaskManager.MaskType type); + + /** + * Get the largest region in the player's allowed WorldEdit region. + */ Region getLargestRegion(); + /** + * Set a players selection and selector type to the given region + */ + void setSelection(Region region); + /** * Get the player's selection region. If the selection is defined in * a different world, the {@code IncompleteRegionException} @@ -366,8 +400,6 @@ public interface Player extends Entity, Actor { return getSession().getSelection(getWorld()); } - void setSelection(Region region); - /** * Set the player's WorldEdit selection. * diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/AbstractPlayerActor.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/AbstractPlayerActor.java index 122fdd41b..e768f2682 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/AbstractPlayerActor.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/AbstractPlayerActor.java @@ -483,27 +483,31 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable { } //FAWE start - - /** - * Get the player's current allowed WorldEdit regions. - * - * @return an array of allowed regions - */ - public Region[] getCurrentRegions() { - return getCurrentRegions(FaweMaskManager.MaskType.MEMBER); + @Override + public Region[] getAllowedRegions() { + return getAllowedRegions(FaweMaskManager.MaskType.getDefaultMaskType()); } - public Region[] getCurrentRegions(FaweMaskManager.MaskType type) { - return WEManager.IMP.getMask(this, type); + @Override + public Region[] getAllowedRegions(FaweMaskManager.MaskType type) { + return WEManager.IMP.getMask(this, type, true); } - /** - * Get the largest region in the player's allowed WorldEdit region. - */ + @Override + public Region[] getDisallowedRegions() { + return getDisallowedRegions(FaweMaskManager.MaskType.getDefaultMaskType()); + } + + @Override + public Region[] getDisallowedRegions(FaweMaskManager.MaskType type) { + return WEManager.IMP.getMask(this, type, false); + } + + @Override public Region getLargestRegion() { long area = 0; Region max = null; - for (Region region : this.getCurrentRegions()) { + for (Region region : this.getAllowedRegions()) { final long tmp = region.getVolume(); if (tmp > area) { area = tmp; @@ -513,6 +517,7 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable { return max; } + @Override public void setSelection(Region region) { RegionSelector selector; if (region instanceof ConvexPolyhedralRegion) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java index fb4c816cf..4cf937ac4 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java @@ -748,13 +748,13 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion { if (minY <= set.getMinSectionPosition() << 4 && maxY >= (set.getMaxSectionPosition() << 4) + 15) { return set; } - trimY(set, minY, maxY); + trimY(set, minY, maxY, true); trimNBT(set, this::contains); return set; } if (tx >= minX && bx <= maxX && tz >= minZ && bz <= maxZ) { if (minY > set.getMinSectionPosition() << 4 || maxY < (set.getMaxSectionPosition() << 4) + 15) { - trimY(set, minY, maxY); + trimY(set, minY, maxY, true); } final int lowerX = Math.max(0, minX - bx); final int upperX = Math.min(15, 15 + maxX - tx); @@ -769,51 +769,128 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion { boolean trimZ = lowerZ != 0 || upperZ != 15; for (int layer = get.getMinSectionPosition(); layer < get.getMaxSectionPosition(); layer++) { - if (set.hasSection(layer)) { - char[] arr = Objects.requireNonNull(set.loadIfPresent(layer)); // This shouldn't be null if above is true - if (trimX || trimZ) { - int indexY = 0; - for (int y = 0; y < 16; y++, indexY += 256) { // For each y layer within a chunk section - int index; - if (trimZ) { - index = indexY; - for (int z = 0; z < lowerZ; z++) { - // null the z values - for (int x = 0; x < 16; x++, index++) { - arr[index] = 0; - } - } - index = indexY + upperZi; - for (int z = upperZ + 1; z < 16; z++) { - // null the z values - for (int x = 0; x < 16; x++, index++) { - arr[index] = 0; - } - } - } - if (trimX) { - index = indexY + lowerZi; - for (int z = lowerZ; z <= upperZ; z++, index += 16) { - for (int x = 0; x < lowerX; x++) { - // null the x values - arr[index + x] = 0; - } - for (int x = upperX + 1; x < 16; x++) { - // null the x values - arr[index + x] = 0; - } - } + if (!set.hasSection(layer)) { + continue; + } + char[] arr = Objects.requireNonNull(set.loadIfPresent(layer)); // This shouldn't be null if above is true + if (!(trimX || trimZ)) { + continue; + } + int indexY = 0; + for (int y = 0; y < 16; y++, indexY += 256) { // For each y layer within a chunk section + int index; + if (trimZ) { + index = indexY; + for (int z = 0; z < lowerZ; z++) { + // null the z values + for (int x = 0; x < 16; x++, index++) { + arr[index] = 0; + } + } + index = indexY + upperZi; + for (int z = upperZ + 1; z < 16; z++) { + // null the z values + for (int x = 0; x < 16; x++, index++) { + arr[index] = 0; + } + } + } + if (trimX) { + index = indexY + lowerZi; // Skip blocks already removed by trimZ + for (int z = lowerZ; z <= upperZ; z++, index += 16) { + for (int x = 0; x < lowerX; x++) { + // null the x values + arr[index + x] = 0; + } + for (int x = upperX + 1; x < 16; x++) { + // null the x values + arr[index + x] = 0; } } - set.setBlocks(layer, arr); } } + set.setBlocks(layer, arr); } + trimNBT(set, this::contains); return set; } return null; } + + @Override + public IChunkSet processSet(IChunk chunk, IChunkGet get, IChunkSet set, boolean asBlacklist) { + if (!asBlacklist) { + return processSet(chunk, get, set); + } + int bx = chunk.getX() << 4; + int bz = chunk.getZ() << 4; + int tx = bx + 15; + int tz = bz + 15; + + if (bx >= minX && tx <= maxX && bz >= minZ && tz <= maxZ) { + // contains all X/Z + int sMaxY = (set.getMaxSectionPosition() << 4) + 15; + int sMinY = set.getMinSectionPosition() << 4; + if (minY <= sMinY && maxY >= sMaxY) { + return null; + } + trimY(set, minY, maxY, false); + trimNBT(set, this::contains); + return set; + } + if (tx >= minX && bx <= maxX && tz >= minZ && bz <= maxZ) { + if (minY > set.getMinSectionPosition() << 4 || maxY < (set.getMaxSectionPosition() << 4) + 15) { + trimY(set, minY, maxY, false); + } + final int lowerX = Math.max(0, minX - bx); + final int upperX = Math.min(15, 15 + maxX - tx); + + final int lowerZ = Math.max(0, minZ - bz); + final int upperZ = Math.min(15, 15 + maxZ - tz); + + final int lowerZi = (lowerZ << 4); + + boolean trimX = lowerX != 0 || upperX != 15; + boolean trimZ = lowerZ != 0 || upperZ != 15; + + for (int layer = get.getMinSectionPosition(); layer < get.getMaxSectionPosition(); layer++) { + if (!set.hasSection(layer)) { + continue; + } + char[] arr = Objects.requireNonNull(set.loadIfPresent(layer)); // This shouldn't be null if above is true + if (!(trimX || trimZ)) { + continue; + } + int indexY = 0; + for (int y = 0; y < 16; y++, indexY += 256) { // For each y layer within a chunk section + int index; + if (trimZ) { + index = indexY; + for (int z = lowerZ; z <= upperZ; z++) { + // null the z values + for (int x = 0; x < 16; x++, index++) { + arr[index] = 0; + } + } + } + if (trimX) { + index = indexY + lowerZi; // Skip blocks already removed by trimZ + for (int z = lowerZ; z <= upperZ; z++, index += 16) { + for (int x = lowerX; x <= upperX; x++) { + // null the x values + arr[index + x] = 0; + } + } + } + } + set.setBlocks(layer, arr); + } + trimNBT(set, bv3 -> !this.contains(bv3)); + return set; + } + return set; + } //FAWE end } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/Region.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/Region.java index 5bfe8336f..10e2f45f5 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/Region.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/Region.java @@ -19,6 +19,7 @@ package com.sk89q.worldedit.regions; +import com.fastasyncworldedit.core.FaweCache; import com.fastasyncworldedit.core.extent.SingleRegionExtent; import com.fastasyncworldedit.core.extent.filter.block.ChunkFilterBlock; import com.fastasyncworldedit.core.extent.processor.ProcessorScope; @@ -366,6 +367,7 @@ public interface Region extends Iterable, Cloneable, IBatchProcess return tx >= min.getX() && bx <= max.getX() && tz >= min.getZ() && bz <= max.getZ(); } + @Override default IChunkSet processSet(IChunk chunk, IChunkGet get, IChunkSet set) { int bx = chunk.getX() << 4; int bz = chunk.getZ() << 4; @@ -377,12 +379,10 @@ public interface Region extends Iterable, Cloneable, IBatchProcess if (tx >= min.getX() && bx <= max.getX() && tz >= min.getZ() && bz <= max.getZ()) { // contains some boolean processExtra = false; - for (int layer = 0; layer < 16; layer++) { + for (int layer = getMinimumY() >> 4; layer <= getMaximumY() >> 4; layer++) { int by = layer << 4; int ty = by + 15; - if (containsEntireCuboid(bx, tx, by, ty, bz, tz)) { - continue; - } else { + if (!containsEntireCuboid(bx, tx, by, ty, bz, tz)) { processExtra = true; char[] arr = set.load(layer); for (int y = 0, index = 0; y < 16; y++) { @@ -406,6 +406,58 @@ public interface Region extends Iterable, Cloneable, IBatchProcess } } + /** + * Process the chunk, with the option to process as if the region is a blacklisted region, and thus any contained blocks + * should be removed, rather than uncontained blocks being removed. + * + * @param asBlacklist If any blocks contained by the region should be removed + */ + default IChunkSet processSet(IChunk chunk, IChunkGet get, IChunkSet set, boolean asBlacklist) { + if (!asBlacklist) { + return processSet(chunk, get, set); + } + int bx = chunk.getX() << 4; + int bz = chunk.getZ() << 4; + int tx = bx + 15; + int tz = bz + 15; + + BlockVector3 min = getMinimumPoint(); + BlockVector3 max = getMaximumPoint(); + if (tx >= min.getX() && bx <= max.getX() && tz >= min.getZ() && bz <= max.getZ()) { + // contains some + boolean processExtra = false; + for (int layer = getMinimumY() >> 4; layer <= getMaximumY() >> 4; layer++) { + int by = layer << 4; + int ty = by + 15; + if (containsEntireCuboid(bx, tx, by, ty, bz, tz)) { + set.setBlocks(layer, FaweCache.IMP.EMPTY_CHAR_4096); + processExtra = true; + continue; + } + char[] arr = set.load(layer); + for (int y = 0, index = 0; y < 16; y++) { + for (int z = 0; z < 16; z++) { + for (int x = 0; x < 16; x++, index++) { + if (arr[index] != 0 && contains(x, y, z)) { + arr[index] = 0; + processExtra = true; + } + } + } + } + if (processExtra) { + set.setBlocks(layer, arr); + } + } + if (processExtra) { + trimNBT(set, bv3 -> !this.contains(bv3)); + } + return set; + } else { + return null; + } + } + @Override default Future postProcessSet(IChunk chunk, IChunkGet get, IChunkSet set) { // Doesn't need to do anything diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/RegionIntersection.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/RegionIntersection.java index cc489d298..5e46b0d60 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/RegionIntersection.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/RegionIntersection.java @@ -30,12 +30,11 @@ import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.World; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Set; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Future; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; @@ -58,7 +57,7 @@ public class RegionIntersection extends AbstractRegion { * * @param regions a list of regions, which is copied */ - public RegionIntersection(List regions) { + public RegionIntersection(Collection regions) { this(null, regions); } @@ -77,7 +76,7 @@ public class RegionIntersection extends AbstractRegion { * @param world the world * @param regions a list of regions, which is copied */ - public RegionIntersection(World world, List regions) { + public RegionIntersection(World world, Collection regions) { super(world); checkNotNull(regions); checkArgument(!regions.isEmpty(), "empty region list is not supported"); @@ -174,9 +173,22 @@ public class RegionIntersection extends AbstractRegion { } @Override - public Future postProcessSet(IChunk chunk, IChunkGet get, IChunkSet set) { - // Doesn't need to do anything - return CompletableFuture.completedFuture(set); + public IChunkSet processSet(IChunk chunk, IChunkGet get, IChunkSet set, boolean asBlacklist) { + if (!asBlacklist) { + return processSet(chunk, get, set); + } + int bx = chunk.getX() << 4; + int bz = chunk.getZ() << 4; + int tx = bx + 15; + int tz = bz + 15; + for (Region region : regions) { + BlockVector3 regMin = region.getMinimumPoint(); + BlockVector3 regMax = region.getMaximumPoint(); + if (tx >= regMin.getX() && bx <= regMax.getX() && tz >= regMin.getZ() && bz <= regMax.getZ()) { + return region.processSet(chunk, get, set, true); + } + } + return set; // default return set as no "blacklist" regions contained the chunk } public List getRegions() {