Preliminary PlotSquared support for SetBlockBuffer packet

Dieser Commit ist enthalten in:
Moulberry 2023-11-10 16:27:25 +08:00
Ursprung ca7ef8266d
Commit e5c8acff02
5 geänderte Dateien mit 336 neuen und 7 gelöschten Zeilen

Datei anzeigen

@ -0,0 +1,68 @@
package com.moulberry.axiom.integration;
import net.minecraft.core.BlockPos;
import org.jetbrains.annotations.Nullable;
public record Box(int minX, int minY, int minZ, int maxX, int maxY, int maxZ) {
@Nullable
public Box tryCombine(Box other) {
if (this.completelyOverlaps(other)) {
return this;
}
if (other.completelyOverlaps(this)) {
return other;
}
if (other.minX == this.minX && other.maxX == this.maxX) {
if (other.minY == this.minY && other.maxY == this.maxY) {
if (areLineSegmentsContinuous(other.minZ, other.maxZ, this.minZ, this.maxZ)) {
return new Box(
other.minX, other.minY, Math.min(other.minZ, this.minZ),
other.maxX, other.maxY, Math.max(other.maxZ, this.maxZ)
);
}
} else if (other.minZ == this.minZ && other.maxZ == this.maxZ) {
if (areLineSegmentsContinuous(other.minY, other.maxY, this.minY, this.maxY)) {
return new Box(
other.minX, Math.min(other.minY, this.minY), other.minZ,
other.maxX, Math.max(other.maxY, this.maxY), other.maxZ
);
}
}
} else if (other.minY == this.minY && other.maxY == this.maxY &&
other.minZ == this.minZ && other.maxZ == this.maxZ) {
if (areLineSegmentsContinuous(other.minX, other.maxX, this.minX, this.maxX)) {
return new Box(
Math.min(other.minX, this.minX), other.minY, other.minZ,
Math.max(other.maxX, this.maxX), other.maxY, other.maxZ
);
}
}
return null; // Not able to combine
}
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();
}
public boolean contains(int x, int y, int z) {
return this.minX() <= x && this.minY() <= y && this.minZ() <= z &&
this.maxX() >= x && this.maxY() >= y && this.maxZ() >= z;
}
private static boolean areLineSegmentsContinuous(int min1, int max1, int min2, int max2) {
int size1 = max1 - min1 + 1;
int size2 = max2 - min2 + 1;
float mid1 = (min1 + max1);
float mid2 = (min2 + max2);
float midDiff = Math.abs(mid1 - mid2);
return midDiff <= size1 + size2;
}
}

Datei anzeigen

@ -0,0 +1,137 @@
package com.moulberry.axiom.integration;
import java.util.List;
public interface SectionPermissionChecker {
boolean allAllowed();
boolean noneAllowed();
boolean allowed(int x, int y, int z);
Box bounds();
static SectionPermissionChecker fromAllowedBoxes(List<Box> allowed) {
if (allowed.isEmpty()) return NONE_ALLOWED;
if (allowed.size() == 1) {
Box allowedBox = allowed.get(0);
if (allowedBox.completelyOverlaps(FULL_BOUNDS)) {
return ALL_ALLOWED;
} else {
return new AllAllowedInBox(allowedBox);
}
}
int minBoundsX = 15;
int minBoundsY = 15;
int minBoundsZ = 15;
int maxBoundsX = 0;
int maxBoundsY = 0;
int maxBoundsZ = 0;
for (Box box : allowed) {
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);
}
return new AllAllowedBoxes(new Box(minBoundsX, minBoundsY, minBoundsZ, maxBoundsX, maxBoundsY, maxBoundsZ), allowed);
}
record AllAllowedInBox(Box box) implements SectionPermissionChecker {
@Override
public boolean allAllowed() {
return true;
}
@Override
public boolean noneAllowed() {
return false;
}
@Override
public boolean allowed(int x, int y, int z) {
return true;
}
@Override
public Box bounds() {
return box;
}
}
record AllAllowedBoxes(Box bounds, List<Box> allowed) 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 (Box box : this.allowed) {
if (box.contains(x, y, z)) return true;
}
return false;
}
@Override
public Box bounds() {
return this.bounds;
}
}
Box FULL_BOUNDS = new Box(0, 0, 0, 15, 15, 15);
SectionPermissionChecker ALL_ALLOWED = new SectionPermissionChecker() {
@Override
public boolean allAllowed() {
return true;
}
@Override
public boolean noneAllowed() {
return false;
}
@Override
public boolean allowed(int x, int y, int z) {
return true;
}
@Override
public Box bounds() {
return FULL_BOUNDS;
}
};
Box EMPTY_BOUNDS = new Box(0, 0, 0, 0, 0, 0);
SectionPermissionChecker NONE_ALLOWED = new SectionPermissionChecker() {
@Override
public boolean allAllowed() {
return false;
}
@Override
public boolean noneAllowed() {
return true;
}
@Override
public boolean allowed(int x, int y, int z) {
return false;
}
@Override
public Box bounds() {
return EMPTY_BOUNDS;
}
};
}

Datei anzeigen

@ -1,6 +1,7 @@
package com.moulberry.axiom.integration.plotsquared; package com.moulberry.axiom.integration.plotsquared;
import com.moulberry.axiom.integration.SectionPermissionChecker;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.block.Block; import org.bukkit.block.Block;
@ -30,4 +31,11 @@ public class PlotSquaredIntegration {
return PlotSquaredIntegrationImpl.isPlotWorld(world); return PlotSquaredIntegrationImpl.isPlotWorld(world);
} }
public static SectionPermissionChecker checkSection(Player player, World world, int sectionX, int sectionY, int sectionZ) {
if (!Bukkit.getPluginManager().isPluginEnabled("PlotSquared")) {
return SectionPermissionChecker.ALL_ALLOWED;
}
return PlotSquaredIntegrationImpl.checkSection(player, world, sectionX, sectionY, sectionZ);
}
} }

Datei anzeigen

@ -1,5 +1,7 @@
package com.moulberry.axiom.integration.plotsquared; package com.moulberry.axiom.integration.plotsquared;
import com.moulberry.axiom.integration.Box;
import com.moulberry.axiom.integration.SectionPermissionChecker;
import com.plotsquared.bukkit.player.BukkitPlayer; import com.plotsquared.bukkit.player.BukkitPlayer;
import com.plotsquared.bukkit.util.BukkitUtil; import com.plotsquared.bukkit.util.BukkitUtil;
import com.plotsquared.core.PlotSquared; import com.plotsquared.core.PlotSquared;
@ -8,17 +10,20 @@ import com.plotsquared.core.location.Location;
import com.plotsquared.core.permissions.Permission; import com.plotsquared.core.permissions.Permission;
import com.plotsquared.core.plot.Plot; import com.plotsquared.core.plot.Plot;
import com.plotsquared.core.plot.PlotArea; import com.plotsquared.core.plot.PlotArea;
import com.plotsquared.core.plot.PlotId;
import com.plotsquared.core.plot.flag.implementations.BreakFlag; import com.plotsquared.core.plot.flag.implementations.BreakFlag;
import com.plotsquared.core.plot.flag.implementations.DoneFlag; import com.plotsquared.core.plot.flag.implementations.DoneFlag;
import com.plotsquared.core.plot.flag.types.BlockTypeWrapper; import com.plotsquared.core.plot.flag.types.BlockTypeWrapper;
import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockType;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.checkerframework.checker.nullness.qual.NonNull;
import java.util.List; import java.util.*;
import java.util.WeakHashMap;
/* /*
* PlotSquared, a land and world management plugin for Minecraft. * PlotSquared, a land and world management plugin for Minecraft.
@ -117,6 +122,7 @@ public class PlotSquaredIntegrationImpl {
} }
private static final WeakHashMap<World, Boolean> plotWorldCache = new WeakHashMap<>(); private static final WeakHashMap<World, Boolean> plotWorldCache = new WeakHashMap<>();
static boolean isPlotWorld(World world) { static boolean isPlotWorld(World world) {
if (plotWorldCache.containsKey(world)) { if (plotWorldCache.containsKey(world)) {
return plotWorldCache.get(world); return plotWorldCache.get(world);
@ -134,7 +140,85 @@ public class PlotSquaredIntegrationImpl {
plotWorldCache.put(world, isPlotWorld); plotWorldCache.put(world, isPlotWorld);
return isPlotWorld; return isPlotWorld;
} }
static SectionPermissionChecker checkSection(Player player, World world, int sectionX, int sectionY, int sectionZ) {
int minX = sectionX * 16;
int minY = sectionY * 16;
int minZ = sectionZ * 16;
int maxX = sectionX * 16 + 15;
int maxY = sectionY * 16 + 15;
int maxZ = sectionZ * 16 + 15;
PlotArea[] plotAreas = PlotSquared.get().getPlotAreaManager().getPlotAreas(world.getName(), new CuboidRegion(
BlockVector3.at(minX, minY, minZ),
BlockVector3.at(maxX, maxY, maxZ)
));
if (plotAreas.length == 0) {
return SectionPermissionChecker.ALL_ALLOWED;
}
Set<Plot> checkedPlots = new HashSet<>();
List<Box> allowed = new ArrayList<>();
for (PlotArea plotArea : plotAreas) {
for (int px = minX; px <= maxX; px += 15) {
for (int py = minY; py <= maxY; py += 15) {
for (int pz = minZ; pz <= maxZ; pz += 15) {
PlotId pid = plotArea.getPlotManager().getPlotId(px, py, pz);
if (pid == null) continue;
Plot plot = plotArea.getOwnedPlotAbs(pid);
if (plot == null) continue;
if (!checkedPlots.add(plot)) continue;
if (!plot.hasOwner()) continue;
if (!plot.isAdded(player.getUniqueId())) continue;
if (Settings.Done.RESTRICT_BUILDING && DoneFlag.isDone(plot)) continue;
Location bottom = plot.getBottomAbs();
Location top = plot.getTopAbs();
int minPlotX = Math.max(Math.min(bottom.getX(), top.getX()), minX);
int minPlotY = Math.max(Math.min(bottom.getY(), top.getY()), minY);
int minPlotZ = Math.max(Math.min(bottom.getZ(), top.getZ()), minZ);
int maxPlotX = Math.min(Math.max(bottom.getX(), top.getX()), maxX);
int maxPlotY = Math.min(Math.max(bottom.getY(), top.getY()), maxY);
int maxPlotZ = Math.min(Math.max(bottom.getZ(), top.getZ()), maxZ);
if (minPlotX <= minX && minPlotY <= minY && minPlotZ <= minZ &&
maxPlotX >= maxX && maxPlotY >= maxY && maxPlotZ >= maxZ) {
return SectionPermissionChecker.ALL_ALLOWED;
}
allowed.add(new Box(minPlotX - minX, minPlotY - minY, minPlotZ - minZ,
maxPlotX - minX, maxPlotY - minY, maxPlotZ - minZ));
}
}
}
}
// 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;
}
return SectionPermissionChecker.fromAllowedBoxes(allowed);
}
} }

Datei anzeigen

@ -6,6 +6,8 @@ import com.moulberry.axiom.buffer.BiomeBuffer;
import com.moulberry.axiom.buffer.BlockBuffer; import com.moulberry.axiom.buffer.BlockBuffer;
import com.moulberry.axiom.buffer.CompressedBlockEntity; import com.moulberry.axiom.buffer.CompressedBlockEntity;
import com.moulberry.axiom.event.AxiomModifyWorldEvent; import com.moulberry.axiom.event.AxiomModifyWorldEvent;
import com.moulberry.axiom.integration.SectionPermissionChecker;
import com.moulberry.axiom.integration.plotsquared.PlotSquaredIntegration;
import it.unimi.dsi.fastutil.longs.Long2ObjectMap; import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
import it.unimi.dsi.fastutil.shorts.Short2ObjectMap; import it.unimi.dsi.fastutil.shorts.Short2ObjectMap;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
@ -35,6 +37,7 @@ import net.minecraft.world.level.chunk.PalettedContainer;
import net.minecraft.world.level.levelgen.Heightmap; import net.minecraft.world.level.levelgen.Heightmap;
import net.minecraft.world.level.lighting.LightEngine; import net.minecraft.world.level.lighting.LightEngine;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Location;
import xyz.jpenilla.reflectionremapper.ReflectionRemapper; import xyz.jpenilla.reflectionremapper.ReflectionRemapper;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
@ -116,6 +119,11 @@ public class SetBlockBufferPacketListener {
continue; continue;
} }
SectionPermissionChecker checker = PlotSquaredIntegration.checkSection(player.getBukkitEntity(), world.getWorld(), cx, cy, cz);
if (checker != null && checker.noneAllowed()) {
continue;
}
LevelChunk chunk = world.getChunk(cx, cz); LevelChunk chunk = world.getChunk(cx, cz);
LevelChunkSection section = chunk.getSection(world.getSectionIndexFromSectionY(cy)); LevelChunkSection section = chunk.getSection(world.getSectionIndexFromSectionY(cy));
@ -144,9 +152,28 @@ public class SetBlockBufferPacketListener {
Short2ObjectMap<CompressedBlockEntity> blockEntityChunkMap = buffer.getBlockEntityChunkMap(entry.getLongKey()); Short2ObjectMap<CompressedBlockEntity> blockEntityChunkMap = buffer.getBlockEntityChunkMap(entry.getLongKey());
for (int x = 0; x < 16; x++) { int minX = 0;
for (int y = 0; y < 16; y++) { int minY = 0;
for (int z = 0; z < 16; z++) { int minZ = 0;
int maxX = 15;
int maxY = 15;
int maxZ = 15;
if (checker != null) {
minX = checker.bounds().minX();
minY = checker.bounds().minY();
minZ = checker.bounds().minZ();
maxX = checker.bounds().maxX();
maxY = checker.bounds().maxY();
maxZ = checker.bounds().maxZ();
if (checker.allAllowed()) {
checker = null;
}
}
for (int x = minX; x <= maxX; x++) {
for (int y = minY; y <= maxY; y++) {
for (int z = minZ; z <= maxZ; z++) {
BlockState blockState = container.get(x, y, z); BlockState blockState = container.get(x, y, z);
if (blockState == emptyState) continue; if (blockState == emptyState) continue;
@ -158,6 +185,8 @@ public class SetBlockBufferPacketListener {
continue; continue;
} }
if (checker != null && !checker.allowed(x, y, z)) continue;
BlockState old = section.setBlockState(x, y, z, blockState, true); BlockState old = section.setBlockState(x, y, z, blockState, true);
if (blockState != old) { if (blockState != old) {
sectionChanged = true; sectionChanged = true;
@ -284,6 +313,9 @@ public class SetBlockBufferPacketListener {
var holder = registry.getHolder(biome); var holder = registry.getHolder(biome);
if (holder.isPresent()) { if (holder.isPresent()) {
if (!PlotSquaredIntegration.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()); container.set(x & 3, y & 3, z & 3, holder.get());
changedChunks.add(chunk); changedChunks.add(chunk);
} }