3
0
Mirror von https://github.com/Moulberry/AxiomPaperPlugin.git synchronisiert 2024-11-09 01:50:05 +01:00

Implement basic WorldGuard support

Dieser Commit ist enthalten in:
Moulberry 2024-04-13 22:06:03 +08:00
Ursprung b534b9348c
Commit 0b01a8ba8b
12 geänderte Dateien mit 412 neuen und 30 gelöschten Zeilen

Datei anzeigen

@ -3,6 +3,8 @@ package com.moulberry.axiom.integration;
import net.minecraft.core.BlockPos;
import org.jetbrains.annotations.Nullable;
import java.util.List;
public record Box(int minX, int minY, int minZ, int maxX, int maxY, int maxZ) {
@Nullable
@ -44,6 +46,27 @@ public record Box(int minX, int minY, int minZ, int maxX, int maxY, int maxZ) {
return null; // Not able to combine
}
public static void combineAll(List<Box> boxes) {
main:
while (boxes.size() >= 2) {
for (int i = 0; i < boxes.size() - 1; i++) {
Box first = boxes.get(i);
for (int j = i + 1; j < boxes.size(); j++) {
Box second = boxes.get(j);
Box combined = first.tryCombine(second);
if (combined != null) {
boxes.remove(j);
boxes.remove(i);
boxes.add(combined);
continue main;
}
}
}
break;
}
}
public boolean completelyOverlaps(Box other) {
return this.minX() <= other.minX() && this.minY() <= other.minY() && this.minZ() <= other.minZ() &&
this.maxX() >= other.maxX() && this.maxY() >= other.maxY() && this.maxZ() >= other.maxZ();
@ -54,6 +77,24 @@ public record Box(int minX, int minY, int minZ, int maxX, int maxY, int maxZ) {
this.maxX() >= x && this.maxY() >= y && this.maxZ() >= z;
}
@Nullable
public static Box intersection(Box first, Box second) {
if (first.minX > second.maxX || second.minX > first.maxX ||
first.minY > second.maxY || second.minY > first.maxY ||
first.minZ > second.maxZ || second.minZ > first.maxZ) {
return null;
}
return new Box(
Math.max(first.minX, second.minX),
Math.max(first.minY, second.minY),
Math.max(first.minZ, second.minZ),
Math.min(first.maxX, second.maxX),
Math.min(first.maxY, second.maxY),
Math.min(first.maxZ, second.maxZ)
);
}
private static boolean areLineSegmentsContinuous(int min1, int max1, int min2, int max2) {
int size1 = max1 - min1 + 1;
int size2 = max2 - min2 + 1;

Datei anzeigen

@ -0,0 +1,4 @@
package com.moulberry.axiom.integration;
public record BoxWithBoolean(Box box, boolean value) {
}

Datei anzeigen

@ -0,0 +1,28 @@
package com.moulberry.axiom.integration;
import com.moulberry.axiom.integration.plotsquared.PlotSquaredIntegration;
import com.moulberry.axiom.integration.worldguard.WorldGuardIntegration;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
public class Integration {
// todo: test if all this is working for both plotsqured, worldguard, plotsquared+worldguard
public static boolean canBreakBlock(Player player, Block block) {
return PlotSquaredIntegration.canBreakBlock(player, block) && WorldGuardIntegration.canBreakBlock(player, block.getLocation());
}
public static boolean canPlaceBlock(Player player, org.bukkit.Location loc) {
return PlotSquaredIntegration.canPlaceBlock(player, loc) && WorldGuardIntegration.canPlaceBlock(player, loc);
}
public static SectionPermissionChecker checkSection(Player player, World world, int cx, int cy, int cz) {
SectionPermissionChecker plotSquared = PlotSquaredIntegration.checkSection(player, world, cz, cy, cz);
SectionPermissionChecker worldGuard = WorldGuardIntegration.checkSection(player, world, cz, cy, cz);
return SectionPermissionChecker.combine(plotSquared, worldGuard);
}
}

Datei anzeigen

@ -9,6 +9,45 @@ public interface SectionPermissionChecker {
boolean allowed(int x, int y, int z);
Box bounds();
static SectionPermissionChecker combine(SectionPermissionChecker first, SectionPermissionChecker second) {
if (first.noneAllowed() || second.noneAllowed()) {
return NONE_ALLOWED;
}
if (first.allAllowed()) {
return second;
}
if (second.allAllowed()) {
return first;
}
Box intersect = Box.intersection(first.bounds(), second.bounds());
if (intersect == null) {
return NONE_ALLOWED;
}
return new SectionPermissionChecker() {
@Override
public boolean allAllowed() {
return false;
}
@Override
public boolean noneAllowed() {
return false;
}
@Override
public boolean allowed(int x, int y, int z) {
return first.allowed(x, y, z) && second.allowed(x, y, z);
}
@Override
public Box bounds() {
return intersect;
}
};
}
static SectionPermissionChecker fromAllowedBoxes(List<Box> allowed) {
if (allowed.isEmpty()) return NONE_ALLOWED;
@ -40,6 +79,51 @@ public interface SectionPermissionChecker {
return new AllAllowedBoxes(new Box(minBoundsX, minBoundsY, minBoundsZ, maxBoundsX, maxBoundsY, maxBoundsZ), allowed);
}
static SectionPermissionChecker fromBoxWithBooleans(List<BoxWithBoolean> boxes, boolean defaultValue) {
if (boxes.isEmpty()) return defaultValue ? ALL_ALLOWED : NONE_ALLOWED;
if (boxes.size() == 1) {
BoxWithBoolean boxWithBoolean = boxes.get(0);
if (boxWithBoolean.value()) {
if (defaultValue) {
return ALL_ALLOWED;
} else if (boxWithBoolean.box().completelyOverlaps(FULL_BOUNDS)) {
return ALL_ALLOWED;
} else {
return new AllAllowedInBox(boxWithBoolean.box());
}
} else {
if (!defaultValue) {
return NONE_ALLOWED;
} else if (boxWithBoolean.box().completelyOverlaps(FULL_BOUNDS)) {
return NONE_ALLOWED;
}
}
}
int minBoundsX = 15;
int minBoundsY = 15;
int minBoundsZ = 15;
int maxBoundsX = 0;
int maxBoundsY = 0;
int maxBoundsZ = 0;
for (BoxWithBoolean boxWithBoolean : boxes) {
if (boxWithBoolean.value()) {
Box box = boxWithBoolean.box();
minBoundsX = Math.min(box.minX(), minBoundsX);
minBoundsY = Math.min(box.minY(), minBoundsY);
minBoundsZ = Math.min(box.minZ(), minBoundsZ);
maxBoundsX = Math.max(box.maxX(), maxBoundsX);
maxBoundsY = Math.max(box.maxY(), maxBoundsY);
maxBoundsZ = Math.max(box.maxZ(), maxBoundsZ);
}
}
Box bounds = new Box(minBoundsX, minBoundsY, minBoundsZ, maxBoundsX, maxBoundsY, maxBoundsZ);
return new BooleanBoxes(bounds, boxes, defaultValue);
}
record AllAllowedInBox(Box box) implements SectionPermissionChecker {
@Override
public boolean allAllowed() {
@ -87,6 +171,33 @@ public interface SectionPermissionChecker {
}
}
record BooleanBoxes(Box bounds, List<BoxWithBoolean> boxes, boolean defaultValue) implements SectionPermissionChecker {
@Override
public boolean allAllowed() {
return false;
}
@Override
public boolean noneAllowed() {
return false;
}
@Override
public boolean allowed(int x, int y, int z) {
for (BoxWithBoolean boxWithBoolean : this.boxes) {
if (boxWithBoolean.box().contains(x, y, z)) {
return boxWithBoolean.value();
}
}
return this.defaultValue;
}
@Override
public Box bounds() {
return this.bounds;
}
}
Box FULL_BOUNDS = new Box(0, 0, 0, 15, 15, 15);
SectionPermissionChecker ALL_ALLOWED = new SectionPermissionChecker() {
@Override

Datei anzeigen

@ -245,24 +245,7 @@ public class PlotSquaredIntegrationImpl {
}
// Combine
main:
while (allowed.size() >= 2) {
for (int i = 0; i < allowed.size() - 1; i++) {
Box first = allowed.get(i);
for (int j = i + 1; j < allowed.size(); j++) {
Box second = allowed.get(j);
Box combined = first.tryCombine(second);
if (combined != null) {
allowed.remove(j);
allowed.remove(i);
allowed.add(combined);
continue main;
}
}
}
break;
}
Box.combineAll(allowed);
return SectionPermissionChecker.fromAllowedBoxes(allowed);
}

Datei anzeigen

@ -0,0 +1,31 @@
package com.moulberry.axiom.integration.worldguard;
import com.moulberry.axiom.integration.SectionPermissionChecker;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.entity.Player;
public class WorldGuardIntegration {
public static boolean canBreakBlock(Player player, org.bukkit.Location loc) {
if (!Bukkit.getPluginManager().isPluginEnabled("WorldGuard")) {
return true;
}
return WorldGuardIntegrationImpl.canBreakBlock(player, loc);
}
public static boolean canPlaceBlock(Player player, org.bukkit.Location loc) {
if (!Bukkit.getPluginManager().isPluginEnabled("WorldGuard")) {
return true;
}
return WorldGuardIntegrationImpl.canPlaceBlock(player, loc);
}
public static SectionPermissionChecker checkSection(Player player, World world, int cx, int cy, int cz) {
if (!Bukkit.getPluginManager().isPluginEnabled("WorldGuard")) {
return SectionPermissionChecker.ALL_ALLOWED;
}
return WorldGuardIntegrationImpl.checkSection(player, world, cx, cy, cz);
}
}

Datei anzeigen

@ -0,0 +1,179 @@
package com.moulberry.axiom.integration.worldguard;
import com.moulberry.axiom.integration.Box;
import com.moulberry.axiom.integration.BoxWithBoolean;
import com.moulberry.axiom.integration.SectionPermissionChecker;
import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldguard.LocalPlayer;
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.flags.Flags;
import com.sk89q.worldguard.protection.flags.StateFlag;
import com.sk89q.worldguard.protection.managers.RegionManager;
import com.sk89q.worldguard.protection.regions.*;
import org.bukkit.World;
import org.bukkit.entity.Player;
import java.util.*;
public class WorldGuardIntegrationImpl {
static boolean canBreakBlock(Player player, org.bukkit.Location loc) {
return testBuild(player, loc, Flags.BLOCK_BREAK);
}
static boolean canPlaceBlock(Player player, org.bukkit.Location loc) {
return testBuild(player, loc, Flags.BLOCK_PLACE);
}
private static boolean testBuild(Player player, org.bukkit.Location loc, StateFlag flag) {
WorldGuardPlatform platform = WorldGuard.getInstance().getPlatform();
RegionContainer regionContainer = platform.getRegionContainer();
if (regionContainer == null) {
return true;
}
RegionQuery query = regionContainer.createQuery();
LocalPlayer worldGuardPlayer = WorldGuardPlugin.inst().wrapPlayer(player);
return query.testBuild(BukkitAdapter.adapt(loc), worldGuardPlayer, flag);
}
static SectionPermissionChecker checkSection(Player player, World world, int cx, int cy, int cz) {
int minX = cx * 16;
int minY = cy * 16;
int minZ = cz * 16;
int maxX = cx * 16 + 15;
int maxY = cy * 16 + 15;
int maxZ = cz * 16 + 15;
WorldGuardPlatform platform = WorldGuard.getInstance().getPlatform();
RegionContainer regionContainer = platform.getRegionContainer();
if (regionContainer == null) {
return SectionPermissionChecker.ALL_ALLOWED;
}
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 SectionPermissionChecker.ALL_ALLOWED;
}
RegionManager regionManager = regionContainer.get(worldEditWorld);
if (regionManager == null) {
return SectionPermissionChecker.ALL_ALLOWED;
}
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 = regionManager.getApplicableRegions(test, RegionQuery.QueryOption.COMPUTE_PARENTS);
Box sectionBox = new Box(0, 0, 0, 15, 15, 15);
int lastPriority = Integer.MIN_VALUE;
List<Box> denyRegions = new ArrayList<>();
List<Box> allowRegions = new ArrayList<>();
List<BoxWithBoolean> finalRegions = new ArrayList<>();
region_loop:
for (ProtectedRegion region : regions) {
int priority = FlagValueCalculator.getPriorityOf(region);
if (priority != lastPriority) {
lastPriority = priority;
if (!denyRegions.isEmpty()) {
Box.combineAll(denyRegions);
boolean finalRegionsWasEmpty = finalRegions.isEmpty();
for (Box denyRegion : denyRegions) {
finalRegions.add(new BoxWithBoolean(denyRegion, false));
if (denyRegion.completelyOverlaps(sectionBox)) {
if (finalRegionsWasEmpty) {
return SectionPermissionChecker.NONE_ALLOWED;
} else {
break region_loop;
}
}
}
}
if (!allowRegions.isEmpty()) {
Box.combineAll(allowRegions);
for (Box allowRegion : allowRegions) {
finalRegions.add(new BoxWithBoolean(allowRegion, true));
if (allowRegion.completelyOverlaps(sectionBox)) {
if (finalRegions.size() == 1) {
return SectionPermissionChecker.ALL_ALLOWED;
} else {
break region_loop;
}
}
}
}
}
StateFlag.State value = FlagValueCalculator.getEffectiveFlagOf(region, Flags.BUILD, worldGuardPlayer);
if (value != null) {
if (region instanceof GlobalProtectedRegion) {
if (value == StateFlag.State.DENY) {
if (finalRegions.isEmpty()) {
return SectionPermissionChecker.NONE_ALLOWED;
} else {
denyRegions.add(sectionBox);
}
} else if (value == StateFlag.State.ALLOW) {
allowRegions.add(sectionBox);
}
} else if (region instanceof ProtectedCuboidRegion || value == StateFlag.State.DENY) {
// Note: we do this for DENY, even if the
// type isn't a cuboid region simply to
// be cautious
BlockVector3 regionMin = region.getMinimumPoint();
BlockVector3 regionMax = region.getMaximumPoint();
int regionMinX = Math.max(regionMin.getBlockX(), cx*16) - minX;
int regionMinY = Math.max(regionMin.getBlockY(), cy*16) - minY;
int regionMinZ = Math.max(regionMin.getBlockZ(), cz*16) - minZ;
int regionMaxX = Math.min(regionMax.getBlockX(), cx*16+15) - minX;
int regionMaxY = Math.min(regionMax.getBlockY(), cy*16+15) - minY;
int regionMaxZ = Math.min(regionMax.getBlockZ(), cz*16+15) - minZ;
Box box = new Box(regionMinX, regionMinY, regionMinZ, regionMaxX, regionMaxY, regionMaxZ);
if (value == StateFlag.State.DENY) {
denyRegions.add(box);
} else {
allowRegions.add(box);
}
}
continue;
}
// The BUILD flag is implicitly set on every region where
// PASSTHROUGH is not set to ALLOW
// todo: handle passthrough
// if (FlagValueCalculator.getEffectiveFlagOf(region, Flags.PASSTHROUGH, worldGuardPlayer) != StateFlag.State.ALLOW) {
// }
}
// todo: handle membership
return SectionPermissionChecker.fromBoxWithBooleans(finalRegions, Flags.BUILD.getDefault() == StateFlag.State.ALLOW);
}
}

Datei anzeigen

@ -1,6 +1,7 @@
package com.moulberry.axiom.packet;
import com.moulberry.axiom.AxiomPaper;
import com.moulberry.axiom.integration.Integration;
import com.moulberry.axiom.integration.plotsquared.PlotSquaredIntegration;
import io.netty.buffer.Unpooled;
import net.minecraft.network.FriendlyByteBuf;
@ -55,7 +56,7 @@ public class DeleteEntityPacketListener implements PluginMessageListener {
if (!whitelistedEntities.isEmpty() && !whitelistedEntities.contains(type)) continue;
if (blacklistedEntities.contains(type)) continue;
if (!PlotSquaredIntegration.canBreakBlock(player,
if (!Integration.canBreakBlock(player,
player.getWorld().getBlockAt(entity.getBlockX(), entity.getBlockY(), entity.getBlockZ()))) {
continue;
}

Datei anzeigen

@ -2,6 +2,7 @@ package com.moulberry.axiom.packet;
import com.moulberry.axiom.AxiomPaper;
import com.moulberry.axiom.NbtSanitization;
import com.moulberry.axiom.integration.Integration;
import com.moulberry.axiom.integration.plotsquared.PlotSquaredIntegration;
import io.netty.buffer.Unpooled;
import net.minecraft.core.BlockPos;
@ -111,7 +112,7 @@ public class ManipulateEntityPacketListener implements PluginMessageListener {
Vec3 position = entity.position();
BlockPos containing = BlockPos.containing(position.x, position.y, position.z);
if (!PlotSquaredIntegration.canPlaceBlock(player, new Location(player.getWorld(),
if (!Integration.canPlaceBlock(player, new Location(player.getWorld(),
containing.getX(), containing.getY(), containing.getZ()))) {
continue;
}
@ -146,7 +147,7 @@ public class ManipulateEntityPacketListener implements PluginMessageListener {
containing = BlockPos.containing(newX, newY, newZ);
if (PlotSquaredIntegration.canPlaceBlock(player, new Location(player.getWorld(),
if (Integration.canPlaceBlock(player, new Location(player.getWorld(),
containing.getX(), containing.getY(), containing.getZ()))) {
entity.teleportTo(serverLevel, newX, newY, newZ, Set.of(), newYaw, newPitch);
}
@ -177,7 +178,7 @@ public class ManipulateEntityPacketListener implements PluginMessageListener {
position = passenger.position();
containing = BlockPos.containing(position.x, position.y, position.z);
if (!PlotSquaredIntegration.canPlaceBlock(player, new Location(player.getWorld(),
if (!Integration.canPlaceBlock(player, new Location(player.getWorld(),
containing.getX(), containing.getY(), containing.getZ()))) {
continue;
}

Datei anzeigen

@ -6,6 +6,7 @@ import com.moulberry.axiom.WorldExtension;
import com.moulberry.axiom.buffer.BiomeBuffer;
import com.moulberry.axiom.buffer.BlockBuffer;
import com.moulberry.axiom.buffer.CompressedBlockEntity;
import com.moulberry.axiom.integration.Integration;
import com.moulberry.axiom.integration.SectionPermissionChecker;
import com.moulberry.axiom.integration.plotsquared.PlotSquaredIntegration;
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
@ -147,7 +148,7 @@ public class SetBlockBufferPacketListener {
continue;
}
SectionPermissionChecker checker = PlotSquaredIntegration.checkSection(player.getBukkitEntity(), world.getWorld(), cx, cy, cz);
SectionPermissionChecker checker = Integration.checkSection(player.getBukkitEntity(), world.getWorld(), cx, cy, cz);
if (checker != null && checker.noneAllowed()) {
continue;
}
@ -347,7 +348,7 @@ public class SetBlockBufferPacketListener {
var holder = registry.getHolder(biome);
if (holder.isPresent()) {
if (!PlotSquaredIntegration.canPlaceBlock(player.getBukkitEntity(),
if (!Integration.canPlaceBlock(player.getBukkitEntity(),
new Location(player.getBukkitEntity().getWorld(), x+1, y+1, z+1))) return;
container.set(x & 3, y & 3, z & 3, holder.get());

Datei anzeigen

@ -2,6 +2,7 @@ package com.moulberry.axiom.packet;
import com.google.common.collect.Maps;
import com.moulberry.axiom.AxiomPaper;
import com.moulberry.axiom.integration.Integration;
import com.moulberry.axiom.integration.plotsquared.PlotSquaredIntegration;
import io.netty.buffer.Unpooled;
import net.minecraft.core.BlockPos;
@ -135,10 +136,10 @@ public class SetBlockPacketListener implements PluginMessageListener {
// Check PlotSquared
if (blockState.isAir()) {
if (!PlotSquaredIntegration.canBreakBlock(bukkitPlayer, world.getBlockAt(blockPos.getX(), blockPos.getY(), blockPos.getZ()))) {
if (!Integration.canBreakBlock(bukkitPlayer, world.getBlockAt(blockPos.getX(), blockPos.getY(), blockPos.getZ()))) {
continue;
}
} else if (!PlotSquaredIntegration.canPlaceBlock(bukkitPlayer, new Location(world, blockPos.getX(), blockPos.getY(), blockPos.getZ()))) {
} else if (!Integration.canPlaceBlock(bukkitPlayer, new Location(world, blockPos.getX(), blockPos.getY(), blockPos.getZ()))) {
continue;
}
@ -160,10 +161,10 @@ public class SetBlockPacketListener implements PluginMessageListener {
// Check PlotSquared
if (blockState.isAir()) {
if (!PlotSquaredIntegration.canBreakBlock(bukkitPlayer, world.getBlockAt(blockPos.getX(), blockPos.getY(), blockPos.getZ()))) {
if (!Integration.canBreakBlock(bukkitPlayer, world.getBlockAt(blockPos.getX(), blockPos.getY(), blockPos.getZ()))) {
continue;
}
} else if (!PlotSquaredIntegration.canPlaceBlock(bukkitPlayer, new Location(world, blockPos.getX(), blockPos.getY(), blockPos.getZ()))) {
} else if (!Integration.canPlaceBlock(bukkitPlayer, new Location(world, blockPos.getX(), blockPos.getY(), blockPos.getZ()))) {
continue;
}
@ -283,7 +284,7 @@ public class SetBlockPacketListener implements PluginMessageListener {
if (desiredBlockState.getBlock() != actualBlock) return;
// Check plot squared
if (!PlotSquaredIntegration.canPlaceBlock(bukkitPlayer, new Location(world, clickedPos.getX(), clickedPos.getY(), clickedPos.getZ()))) {
if (!Integration.canPlaceBlock(bukkitPlayer, new Location(world, clickedPos.getX(), clickedPos.getY(), clickedPos.getZ()))) {
return;
}

Datei anzeigen

@ -2,6 +2,7 @@ package com.moulberry.axiom.packet;
import com.moulberry.axiom.AxiomPaper;
import com.moulberry.axiom.NbtSanitization;
import com.moulberry.axiom.integration.Integration;
import com.moulberry.axiom.integration.plotsquared.PlotSquaredIntegration;
import io.netty.buffer.Unpooled;
import net.minecraft.core.BlockPos;
@ -76,7 +77,7 @@ public class SpawnEntityPacketListener implements PluginMessageListener {
continue;
}
if (!PlotSquaredIntegration.canPlaceBlock(player, new Location(player.getWorld(),
if (!Integration.canPlaceBlock(player, new Location(player.getWorld(),
blockPos.getX(), blockPos.getY(), blockPos.getZ()))) {
continue;
}