From aff54bcd3426e7b11fe12bc6e422c4ef5a962354 Mon Sep 17 00:00:00 2001 From: Moulberry Date: Mon, 11 Sep 2023 20:38:49 +0800 Subject: [PATCH] Region protection WIP --- .../axiom/integration/RegionProtection.java | 16 +- .../RegionProtectionWorldGuard.java | 140 +++++++++++++++++- .../axiom/integration/SectionProtection.java | 38 +++++ .../packet/SetBlockBufferPacketListener.java | 23 ++- 4 files changed, 205 insertions(+), 12 deletions(-) create mode 100644 src/main/java/com/moulberry/axiom/integration/SectionProtection.java diff --git a/src/main/java/com/moulberry/axiom/integration/RegionProtection.java b/src/main/java/com/moulberry/axiom/integration/RegionProtection.java index 9b95e46..cef48d9 100644 --- a/src/main/java/com/moulberry/axiom/integration/RegionProtection.java +++ b/src/main/java/com/moulberry/axiom/integration/RegionProtection.java @@ -4,6 +4,9 @@ import org.bukkit.Bukkit; import org.bukkit.World; import org.bukkit.entity.Player; +import java.util.ArrayList; +import java.util.List; + public class RegionProtection { private final RegionProtectionWorldGuard worldGuard; @@ -16,8 +19,17 @@ public class RegionProtection { } } - public boolean canBuildInSection(int cx, int cy, int cz) { - if (this.worldGuard != null && !this.worldGuard.canBuildInSection(cx, cy, cz)) return false; + public SectionProtection getSection(int cx, int cy, int cz) { + List protections = new ArrayList<>(); + if (this.worldGuard != null) { + return this.worldGuard.getSection(cx, cy, cz); + } + // todo: PlotSquared + return SectionProtection.ALLOW; + } + + public boolean canBuild(int x, int y, int z) { + if (this.worldGuard != null && !this.worldGuard.canBuild(x, y, z)) return false; // todo: PlotSquared return true; } diff --git a/src/main/java/com/moulberry/axiom/integration/RegionProtectionWorldGuard.java b/src/main/java/com/moulberry/axiom/integration/RegionProtectionWorldGuard.java index 784fb3e..8f22020 100644 --- a/src/main/java/com/moulberry/axiom/integration/RegionProtectionWorldGuard.java +++ b/src/main/java/com/moulberry/axiom/integration/RegionProtectionWorldGuard.java @@ -1,5 +1,7 @@ package com.moulberry.axiom.integration; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Sets; import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldguard.LocalPlayer; @@ -7,16 +9,21 @@ import com.sk89q.worldguard.WorldGuard; import com.sk89q.worldguard.bukkit.WorldGuardPlugin; import com.sk89q.worldguard.internal.platform.WorldGuardPlatform; import com.sk89q.worldguard.protection.ApplicableRegionSet; +import com.sk89q.worldguard.protection.FlagValueCalculator; +import com.sk89q.worldguard.protection.association.RegionAssociable; import com.sk89q.worldguard.protection.flags.Flags; +import com.sk89q.worldguard.protection.flags.RegionGroup; +import com.sk89q.worldguard.protection.flags.StateFlag; import com.sk89q.worldguard.protection.managers.RegionManager; -import com.sk89q.worldguard.protection.regions.ProtectedCuboidRegion; -import com.sk89q.worldguard.protection.regions.ProtectedRegion; -import com.sk89q.worldguard.protection.regions.RegionContainer; -import com.sk89q.worldguard.protection.regions.RegionQuery; +import com.sk89q.worldguard.protection.regions.*; import org.bukkit.World; import org.bukkit.entity.Player; import org.jetbrains.annotations.Nullable; +import java.util.*; + +import static com.google.common.base.Preconditions.checkNotNull; + public class RegionProtectionWorldGuard { private final LocalPlayer player; @@ -32,12 +39,15 @@ public class RegionProtectionWorldGuard { WorldGuardPlatform platform = WorldGuard.getInstance().getPlatform(); RegionContainer regionContainer = platform.getRegionContainer(); + if (regionContainer == null) return null; + com.sk89q.worldedit.world.World worldEditWorld = BukkitAdapter.adapt(world); LocalPlayer worldGuardPlayer = WorldGuardPlugin.inst().wrapPlayer(player); // Don't do any protection if player has bypass if (platform.getSessionManager().hasBypass(worldGuardPlayer, worldEditWorld)) { - return null; + // todo: enable bypass +// return null; } RegionManager regionManager = regionContainer.get(worldEditWorld); @@ -46,12 +56,128 @@ public class RegionProtectionWorldGuard { return new RegionProtectionWorldGuard(worldGuardPlayer, regionManager); } - public boolean canBuildInSection(int cx, int cy, int cz) { + public SectionProtection getSection(int cx, int cy, int cz) { BlockVector3 min = BlockVector3.at(cx*16, cy*16, cz*16); BlockVector3 max = BlockVector3.at(cx*16+15, cy*16+15, cz*16+15); ProtectedRegion test = new ProtectedCuboidRegion("dummy", min, max); ApplicableRegionSet regions = this.regionManager.getApplicableRegions(test, RegionQuery.QueryOption.COMPUTE_PARENTS); - return regions.testState(this.player, Flags.BUILD); + + int minimumPriority = Integer.MIN_VALUE; + + Map consideredValues = new HashMap<>(); + Set ignoredParents = new HashSet<>(); + + for (ProtectedRegion region : regions) { + int priority = FlagValueCalculator.getPriorityOf(region); + + // todo: this logic doesn't work for us in determining ALLOW, DENY, CHECK + if (priority < minimumPriority) { + break; + } + + // todo: have to keep track of 2 booleans: partialAllow & partialDeny + + if (ignoredParents.contains(region)) { + continue; + } + + StateFlag.State value = FlagValueCalculator.getEffectiveFlagOf(region, Flags.BUILD, this.player); + if (value != null) { + minimumPriority = priority; + consideredValues.put(region, value); + } + + addParents(ignoredParents, region); + + // The BUILD flag is implicitly set on every region where + // PASSTHROUGH is not set to ALLOW + if (minimumPriority != priority && Flags.BUILD.implicitlySetWithMembership() && + FlagValueCalculator.getEffectiveFlagOf(region, Flags.PASSTHROUGH, this.player) != StateFlag.State.ALLOW) { + minimumPriority = priority; + } + } + + if (consideredValues.isEmpty()) { + if (Flags.BUILD.usesMembershipAsDefault()) { + // todo +// switch (getMembership(subject)) { +// case FAIL: +// return ImmutableList.of(); +// case SUCCESS: +// return (Collection) ImmutableList.of(StateFlag.State.ALLOW); +// } + } + + System.out.println("returning default"); + StateFlag.State fallback = Flags.BUILD.getDefault(); + return fallback == StateFlag.State.DENY ? SectionProtection.DENY : SectionProtection.ALLOW; + } + + boolean hasPartialDeny = false; + for (Map.Entry entry : consideredValues.entrySet()) { + ProtectedRegion region = entry.getKey(); + if (entry.getValue() == StateFlag.State.DENY) { + System.out.println("found region with deny!"); + if (region instanceof GlobalProtectedRegion) { + return SectionProtection.DENY; + } else if (region instanceof ProtectedCuboidRegion && doesRegionCompletelyContainSection(region, cx, cy, cz)) { + return SectionProtection.DENY; + } + hasPartialDeny = true; + } + } + + if (hasPartialDeny) { + System.out.println("returning check!"); + return new SectionProtection() { + @Override + public SectionState getSectionState() { + return SectionState.CHECK; + } + + @Override + public boolean check(int wx, int wy, int wz) { + return true; + } + }; + // return complex thing + } + + System.out.println("returning allow!"); + return SectionProtection.ALLOW; + } + + private boolean doesRegionCompletelyContainSection(ProtectedRegion region, int cx, int cy, int cz) { + BlockVector3 regionMin = region.getMinimumPoint(); + + if (regionMin.getBlockX() > cx*16) return false; + if (regionMin.getBlockY() > cy*16) return false; + if (regionMin.getBlockZ() > cz*16) return false; + + BlockVector3 regionMax = region.getMaximumPoint(); + + if (regionMax.getBlockX() < cx*16+15) return false; + if (regionMax.getBlockY() < cy*16+15) return false; + if (regionMax.getBlockZ() < cz*16+15) return false; + + return true; + } + + private void addParents(Set ignored, ProtectedRegion region) { + ProtectedRegion parent = region.getParent(); + + while (parent != null) { + ignored.add(parent); + parent = parent.getParent(); + } + } + + public boolean canBuild(int x, int y, int z) { + return this.regionManager.getApplicableRegions(BlockVector3.at(x, y, z)).testState(this.player, Flags.BUILD); + } + + public boolean isAllowed(LocalPlayer player, ProtectedRegion protectedRegion) { + return protectedRegion.isOwner(player) || protectedRegion.isMember(player); } } diff --git a/src/main/java/com/moulberry/axiom/integration/SectionProtection.java b/src/main/java/com/moulberry/axiom/integration/SectionProtection.java new file mode 100644 index 0000000..07b8d60 --- /dev/null +++ b/src/main/java/com/moulberry/axiom/integration/SectionProtection.java @@ -0,0 +1,38 @@ +package com.moulberry.axiom.integration; + +public interface SectionProtection { + + SectionProtection ALLOW = new SectionProtection() { + @Override + public SectionState getSectionState() { + return SectionState.ALLOW; + } + + @Override + public boolean check(int wx, int wy, int wz) { + return true; + } + }; + + SectionProtection DENY = new SectionProtection() { + @Override + public SectionState getSectionState() { + return SectionState.DENY; + } + + @Override + public boolean check(int wx, int wy, int wz) { + return false; + } + }; + + enum SectionState { + ALLOW, + DENY, + CHECK + } + + SectionState getSectionState(); + boolean check(int wx, int wy, int wz); + +} diff --git a/src/main/java/com/moulberry/axiom/packet/SetBlockBufferPacketListener.java b/src/main/java/com/moulberry/axiom/packet/SetBlockBufferPacketListener.java index 44b7479..d433834 100644 --- a/src/main/java/com/moulberry/axiom/packet/SetBlockBufferPacketListener.java +++ b/src/main/java/com/moulberry/axiom/packet/SetBlockBufferPacketListener.java @@ -6,6 +6,7 @@ import com.moulberry.axiom.buffer.BlockBuffer; import com.moulberry.axiom.buffer.CompressedBlockEntity; import com.moulberry.axiom.event.AxiomModifyWorldEvent; import com.moulberry.axiom.integration.RegionProtection; +import com.moulberry.axiom.integration.SectionProtection; import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.World; @@ -38,6 +39,7 @@ import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.Level; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.EntityBlock; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; @@ -135,9 +137,14 @@ public class SetBlockBufferPacketListener { continue; } - if (!regionProtection.canBuildInSection(cx, cy, cz)) { - continue; - } + SectionProtection sectionProtection = regionProtection.getSection(cx, cy, cz); +// switch (sectionProtection.getSectionState()) { +// case ALLOW -> sectionProtection = null; +// case DENY -> { +// continue; +// } +// case CHECK -> {} +// } LevelChunk chunk = world.getChunk(cx, cz); chunk.setUnsaved(true); @@ -170,10 +177,20 @@ public class SetBlockBufferPacketListener { BlockState blockState = container.get(x, y, z); if (blockState == emptyState) continue; + switch (sectionProtection.getSectionState()) { + case ALLOW -> {} + case DENY -> blockState = Blocks.REDSTONE_BLOCK.defaultBlockState(); + case CHECK -> blockState = Blocks.DIAMOND_BLOCK.defaultBlockState(); + } + int bx = cx*16 + x; int by = cy*16 + y; int bz = cz*16 + z; +// if (!regionProtection.canBuild(bx, by, bz)) { +// continue; +// } + blockPos.set(bx, by, bz); if (hasOnlyAir && blockState.isAir()) {