diff --git a/src/main/java/com/moulberry/axiom/integration/plotsquared/PlotSquaredIntegration.java b/src/main/java/com/moulberry/axiom/integration/plotsquared/PlotSquaredIntegration.java new file mode 100644 index 0000000..22ff051 --- /dev/null +++ b/src/main/java/com/moulberry/axiom/integration/plotsquared/PlotSquaredIntegration.java @@ -0,0 +1,25 @@ +package com.moulberry.axiom.integration.plotsquared; + + +import org.bukkit.Bukkit; +import org.bukkit.block.Block; +import org.bukkit.entity.Player; + + +public class PlotSquaredIntegration { + + public static boolean canBreakBlock(Player player, Block block) { + if (!Bukkit.getPluginManager().isPluginEnabled("PlotSquared")) { + return true; + } + return PlotSquaredIntegrationImpl.canBreakBlock(player, block); + } + + public static boolean canPlaceBlock(Player player, org.bukkit.Location loc) { + if (!Bukkit.getPluginManager().isPluginEnabled("PlotSquared")) { + return true; + } + return PlotSquaredIntegrationImpl.canPlaceBlock(player, loc); + } + +} diff --git a/src/main/java/com/moulberry/axiom/integration/plotsquared/PlotSquaredIntegrationImpl.java b/src/main/java/com/moulberry/axiom/integration/plotsquared/PlotSquaredIntegrationImpl.java new file mode 100644 index 0000000..19249c6 --- /dev/null +++ b/src/main/java/com/moulberry/axiom/integration/plotsquared/PlotSquaredIntegrationImpl.java @@ -0,0 +1,117 @@ +package com.moulberry.axiom.integration.plotsquared; + +import com.plotsquared.bukkit.player.BukkitPlayer; +import com.plotsquared.bukkit.util.BukkitUtil; +import com.plotsquared.core.configuration.Settings; +import com.plotsquared.core.location.Location; +import com.plotsquared.core.permissions.Permission; +import com.plotsquared.core.plot.Plot; +import com.plotsquared.core.plot.PlotArea; +import com.plotsquared.core.plot.flag.implementations.BreakFlag; +import com.plotsquared.core.plot.flag.implementations.DoneFlag; +import com.plotsquared.core.plot.flag.types.BlockTypeWrapper; +import com.sk89q.worldedit.bukkit.BukkitAdapter; +import com.sk89q.worldedit.world.block.BlockType; +import org.bukkit.Bukkit; +import org.bukkit.block.Block; +import org.bukkit.entity.Player; + +import java.util.List; + +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +public class PlotSquaredIntegrationImpl { + + static boolean canBreakBlock(Player player, Block block) { + Location location = BukkitUtil.adapt(block.getLocation()); + PlotArea area = location.getPlotArea(); + if (area == null) { + return true; + } + + Plot plot = area.getPlot(location); + if (plot != null) { + BukkitPlayer plotPlayer = BukkitUtil.adapt(player); + // == rather than <= as we only care about the "ground level" not being destroyed + if (block.getY() == area.getMinGenHeight()) { + if (!plotPlayer.hasPermission(Permission.PERMISSION_ADMIN_DESTROY_GROUNDLEVEL)) { + return false; + } + } + if (area.notifyIfOutsideBuildArea(plotPlayer, location.getY())) { + return false; + } + // check unowned plots + if (!plot.hasOwner()) { + return plotPlayer.hasPermission(Permission.PERMISSION_ADMIN_DESTROY_UNOWNED, true); + } + // player is breaking another player's plot + if (!plot.isAdded(plotPlayer.getUUID())) { + List destroy = plot.getFlag(BreakFlag.class); + final BlockType blockType = BukkitAdapter.asBlockType(block.getType()); + for (final BlockTypeWrapper blockTypeWrapper : destroy) { + if (blockTypeWrapper.accepts(blockType)) { + return true; + } + } + return plotPlayer.hasPermission(Permission.PERMISSION_ADMIN_DESTROY_OTHER); + } + // plot is 'done' + if (Settings.Done.RESTRICT_BUILDING && DoneFlag.isDone(plot)) { + return plotPlayer.hasPermission(Permission.PERMISSION_ADMIN_BUILD_OTHER); + } + return true; + } + + BukkitPlayer pp = BukkitUtil.adapt(player); + return pp.hasPermission(Permission.PERMISSION_ADMIN_DESTROY_ROAD); + } + + static boolean canPlaceBlock(Player player, org.bukkit.Location loc) { + Location location = BukkitUtil.adapt(loc); + PlotArea area = location.getPlotArea(); + if (area == null) { + return true; + } + + BukkitPlayer pp = BukkitUtil.adapt(player); + Plot plot = area.getPlot(location); + if (plot != null) { + if (area.notifyIfOutsideBuildArea(pp, location.getY())) { + return false; + } + // check unowned plots + if (!plot.hasOwner()) { + return pp.hasPermission(Permission.PERMISSION_ADMIN_BUILD_UNOWNED); + } + // player is breaking another player's plot + if (!plot.isAdded(pp.getUUID())) { + return pp.hasPermission(Permission.PERMISSION_ADMIN_BUILD_OTHER); + } + // plot is 'done' + if (Settings.Done.RESTRICT_BUILDING && DoneFlag.isDone(plot)) { + return pp.hasPermission(Permission.PERMISSION_ADMIN_BUILD_OTHER); + } + return true; + } + + return pp.hasPermission(Permission.PERMISSION_ADMIN_BUILD_ROAD); + } + +} diff --git a/src/main/java/com/moulberry/axiom/packet/SetBlockPacketListener.java b/src/main/java/com/moulberry/axiom/packet/SetBlockPacketListener.java index c674d29..ed1ae7d 100644 --- a/src/main/java/com/moulberry/axiom/packet/SetBlockPacketListener.java +++ b/src/main/java/com/moulberry/axiom/packet/SetBlockPacketListener.java @@ -1,8 +1,12 @@ package com.moulberry.axiom.packet; +import com.google.common.collect.Maps; import com.moulberry.axiom.AxiomPaper; import com.moulberry.axiom.event.AxiomModifyWorldEvent; +import com.moulberry.axiom.integration.plotsquared.PlotSquaredIntegration; import io.netty.buffer.Unpooled; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import net.kyori.adventure.text.Component; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.core.SectionPos; @@ -23,7 +27,9 @@ import net.minecraft.world.level.levelgen.Heightmap; import net.minecraft.world.level.lighting.LightEngine; import net.minecraft.world.phys.BlockHitResult; import org.bukkit.Bukkit; +import org.bukkit.Location; import org.bukkit.block.BlockFace; +import org.bukkit.craftbukkit.v1_20_R2.CraftWorld; import org.bukkit.craftbukkit.v1_20_R2.block.CraftBlock; import org.bukkit.craftbukkit.v1_20_R2.entity.CraftPlayer; import org.bukkit.entity.Player; @@ -38,6 +44,7 @@ import java.lang.reflect.Method; import java.util.Map; import java.util.Objects; import java.util.Optional; +import java.util.function.IntFunction; public class SetBlockPacketListener implements PluginMessageListener { @@ -71,7 +78,9 @@ public class SetBlockPacketListener implements PluginMessageListener { // Read packet FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(message)); - Map blocks = friendlyByteBuf.readMap(FriendlyByteBuf::readBlockPos, buf -> buf.readById(Block.BLOCK_STATE_REGISTRY)); + IntFunction> mapFunction = FriendlyByteBuf.limitValue(Maps::newLinkedHashMapWithExpectedSize, 512); + Map blocks = friendlyByteBuf.readMap(mapFunction, + FriendlyByteBuf::readBlockPos, buf -> buf.readById(Block.BLOCK_STATE_REGISTRY)); boolean updateNeighbors = friendlyByteBuf.readBoolean(); int reason = friendlyByteBuf.readVarInt(); @@ -104,16 +113,47 @@ public class SetBlockPacketListener implements PluginMessageListener { return; } + CraftWorld world = player.level().getWorld(); + // Update blocks if (updateNeighbors) { + int count = 0; for (Map.Entry entry : blocks.entrySet()) { - player.level().setBlock(entry.getKey(), entry.getValue(), 3); - } - } else { - for (Map.Entry entry : blocks.entrySet()) { + if (count++ > 64) break; + BlockPos blockPos = entry.getKey(); BlockState blockState = entry.getValue(); + // Check PlotSquared + if (blockState.isAir()) { + if (!PlotSquaredIntegration.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()))) { + continue; + } + + // Place block + player.level().setBlock(blockPos, blockState, 3); + } + } else { + int count = 0; + for (Map.Entry entry : blocks.entrySet()) { + if (count++ > 64) break; + + BlockPos blockPos = entry.getKey(); + BlockState blockState = entry.getValue(); + + // Check PlotSquared + if (blockState.isAir()) { + if (!PlotSquaredIntegration.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()))) { + continue; + } + + // Place block int bx = blockPos.getX(); int by = blockPos.getY(); int bz = blockPos.getZ();