Mirror von
https://github.com/Moulberry/AxiomPaperPlugin.git
synchronisiert 2024-11-08 17:40:04 +01:00
Use axiom:restrictions packet to control client behaviour
Dieser Commit ist enthalten in:
Ursprung
8fd71e59ba
Commit
8631549a4a
@ -1,11 +1,10 @@
|
||||
package com.moulberry.axiom;
|
||||
|
||||
import com.google.common.util.concurrent.RateLimiter;
|
||||
import com.mojang.brigadier.StringReader;
|
||||
import com.moulberry.axiom.buffer.BlockBuffer;
|
||||
import com.moulberry.axiom.buffer.CompressedBlockEntity;
|
||||
import com.moulberry.axiom.event.AxiomCreateWorldPropertiesEvent;
|
||||
import com.moulberry.axiom.event.AxiomModifyWorldEvent;
|
||||
import com.moulberry.axiom.integration.plotsquared.PlotSquaredIntegration;
|
||||
import com.moulberry.axiom.packet.*;
|
||||
import com.moulberry.axiom.world_properties.server.ServerWorldPropertiesRegistry;
|
||||
import io.netty.buffer.Unpooled;
|
||||
@ -15,11 +14,8 @@ import io.papermc.paper.event.world.WorldGameRuleChangeEvent;
|
||||
import io.papermc.paper.network.ChannelInitializeListener;
|
||||
import io.papermc.paper.network.ChannelInitializeListenerHolder;
|
||||
import net.kyori.adventure.key.Key;
|
||||
import net.minecraft.commands.arguments.blocks.BlockPredicateArgument;
|
||||
import net.minecraft.commands.arguments.blocks.BlockStateArgument;
|
||||
import net.minecraft.commands.arguments.blocks.BlockStateParser;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.IdMapper;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.network.Connection;
|
||||
import net.minecraft.network.ConnectionProtocol;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
@ -27,8 +23,6 @@ import net.minecraft.network.protocol.Packet;
|
||||
import net.minecraft.network.protocol.PacketFlow;
|
||||
import net.minecraft.network.protocol.common.ServerboundCustomPayloadPacket;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import org.bukkit.*;
|
||||
import org.bukkit.configuration.Configuration;
|
||||
@ -43,8 +37,6 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public class AxiomPaper extends JavaPlugin implements Listener {
|
||||
|
||||
@ -52,6 +44,7 @@ public class AxiomPaper extends JavaPlugin implements Listener {
|
||||
|
||||
public final Set<UUID> activeAxiomPlayers = Collections.newSetFromMap(new ConcurrentHashMap<>());
|
||||
public final Map<UUID, RateLimiter> playerBlockBufferRateLimiters = new ConcurrentHashMap<>();
|
||||
public final Map<UUID, Restrictions> playerRestrictions = new ConcurrentHashMap<>();
|
||||
public Configuration configuration;
|
||||
|
||||
public IdMapper<BlockState> allowedBlockRegistry = null;
|
||||
@ -90,6 +83,7 @@ public class AxiomPaper extends JavaPlugin implements Listener {
|
||||
msg.registerOutgoingPluginChannel(this, "axiom:register_world_properties");
|
||||
msg.registerOutgoingPluginChannel(this, "axiom:set_world_property");
|
||||
msg.registerOutgoingPluginChannel(this, "axiom:ack_world_properties");
|
||||
msg.registerOutgoingPluginChannel(this, "axiom:restrictions");
|
||||
|
||||
if (configuration.getBoolean("packet-handlers.hello")) {
|
||||
msg.registerIncomingPluginChannel(this, "axiom:hello", new HelloPacketListener(this));
|
||||
@ -162,6 +156,13 @@ public class AxiomPaper extends JavaPlugin implements Listener {
|
||||
Bukkit.getScheduler().scheduleSyncRepeatingTask(this, () -> {
|
||||
HashSet<UUID> stillActiveAxiomPlayers = new HashSet<>();
|
||||
|
||||
int rateLimit = this.configuration.getInt("block-buffer-rate-limit");
|
||||
if (rateLimit > 0) {
|
||||
// Reduce by 20% just to prevent synchronization/timing issues
|
||||
rateLimit = rateLimit * 8/10;
|
||||
if (rateLimit <= 0) rateLimit = 1;
|
||||
}
|
||||
|
||||
for (Player player : Bukkit.getServer().getOnlinePlayers()) {
|
||||
if (activeAxiomPlayers.contains(player.getUniqueId())) {
|
||||
if (!player.hasPermission("axiom.*")) {
|
||||
@ -171,13 +172,70 @@ public class AxiomPaper extends JavaPlugin implements Listener {
|
||||
buf.getBytes(0, bytes);
|
||||
player.sendPluginMessage(this, "axiom:enable", bytes);
|
||||
} else {
|
||||
stillActiveAxiomPlayers.add(player.getUniqueId());
|
||||
UUID uuid = player.getUniqueId();
|
||||
stillActiveAxiomPlayers.add(uuid);
|
||||
|
||||
boolean send = false;
|
||||
|
||||
Restrictions restrictions = playerRestrictions.get(uuid);
|
||||
if (restrictions == null) {
|
||||
restrictions = new Restrictions();
|
||||
playerRestrictions.put(uuid, restrictions);
|
||||
send = true;
|
||||
}
|
||||
|
||||
BlockPos boundsMin = null;
|
||||
BlockPos boundsMax = null;
|
||||
|
||||
if (!player.hasPermission("axiom.allow_copying_other_plots")) {
|
||||
if (PlotSquaredIntegration.isPlotWorld(player.getWorld())) {
|
||||
PlotSquaredIntegration.PlotBounds editable = PlotSquaredIntegration.getCurrentEditablePlot(player);
|
||||
if (editable != null) {
|
||||
restrictions.lastPlotBounds = editable;
|
||||
boundsMin = editable.min();
|
||||
boundsMax = editable.max();
|
||||
} else if (restrictions.lastPlotBounds != null && restrictions.lastPlotBounds.worldName().equals(player.getWorld().getName())) {
|
||||
boundsMin = restrictions.lastPlotBounds.min();
|
||||
boundsMax = restrictions.lastPlotBounds.max();
|
||||
} else {
|
||||
boundsMin = BlockPos.ZERO;
|
||||
boundsMax = BlockPos.ZERO;
|
||||
}
|
||||
}
|
||||
|
||||
int min = Integer.MIN_VALUE;
|
||||
int max = Integer.MAX_VALUE;
|
||||
if (boundsMin != null && boundsMax != null &&
|
||||
boundsMin.getX() == min && boundsMin.getY() == min && boundsMin.getZ() == min &&
|
||||
boundsMax.getX() == max && boundsMax.getY() == max && boundsMax.getZ() == max) {
|
||||
boundsMin = null;
|
||||
boundsMax = null;
|
||||
}
|
||||
}
|
||||
|
||||
boolean allowImportingBlocks = player.hasPermission("axiom.can_import_blocks");
|
||||
|
||||
if (restrictions.maxSectionsPerSecond != rateLimit ||
|
||||
restrictions.canImportBlocks != allowImportingBlocks ||
|
||||
!Objects.equals(restrictions.boundsMin, boundsMin) ||
|
||||
!Objects.equals(restrictions.boundsMax, boundsMax)) {
|
||||
restrictions.maxSectionsPerSecond = rateLimit;
|
||||
restrictions.canImportBlocks = allowImportingBlocks;
|
||||
restrictions.boundsMin = boundsMin;
|
||||
restrictions.boundsMax = boundsMax;
|
||||
send = true;
|
||||
}
|
||||
|
||||
if (send) {
|
||||
restrictions.send(this, player);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
activeAxiomPlayers.retainAll(stillActiveAxiomPlayers);
|
||||
playerBlockBufferRateLimiters.keySet().retainAll(stillActiveAxiomPlayers);
|
||||
playerRestrictions.keySet().retainAll(stillActiveAxiomPlayers);
|
||||
}, 20, 20);
|
||||
|
||||
int maxChunkRelightsPerTick = configuration.getInt("max-chunk-relights-per-tick");
|
||||
|
64
src/main/java/com/moulberry/axiom/Restrictions.java
Normale Datei
64
src/main/java/com/moulberry/axiom/Restrictions.java
Normale Datei
@ -0,0 +1,64 @@
|
||||
package com.moulberry.axiom;
|
||||
|
||||
import com.moulberry.axiom.integration.plotsquared.PlotSquaredIntegration;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class Restrictions {
|
||||
|
||||
public boolean canImportBlocks = true;
|
||||
public boolean canUseEditor = true;
|
||||
public boolean canEditDisplayEntities = true;
|
||||
public int maxSectionsPerSecond = 0;
|
||||
public BlockPos boundsMin = null;
|
||||
public BlockPos boundsMax = null;
|
||||
|
||||
public PlotSquaredIntegration.PlotBounds lastPlotBounds = null;
|
||||
|
||||
public void send(AxiomPaper plugin, Player player) {
|
||||
if (player.getListeningPluginChannels().contains("axiom:restrictions")) {
|
||||
FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer());
|
||||
buf.writeBoolean(this.canImportBlocks);
|
||||
buf.writeBoolean(this.canUseEditor);
|
||||
buf.writeBoolean(this.canEditDisplayEntities);
|
||||
|
||||
buf.writeVarInt(this.maxSectionsPerSecond);
|
||||
|
||||
if (this.boundsMin == null || this.boundsMax == null) {
|
||||
buf.writeBoolean(false);
|
||||
} else {
|
||||
buf.writeBoolean(true);
|
||||
int minX = this.boundsMin.getX();
|
||||
int minY = this.boundsMin.getY();
|
||||
int minZ = this.boundsMin.getZ();
|
||||
int maxX = this.boundsMax.getX();
|
||||
int maxY = this.boundsMax.getY();
|
||||
int maxZ = this.boundsMax.getZ();
|
||||
|
||||
if (minX < -33554431) minX = -33554431;
|
||||
if (minX > 33554431) minX = 33554431;
|
||||
if (minY < -2047) minY = -2047;
|
||||
if (minY > 2047) minY = 2047;
|
||||
if (minZ < -33554431) minZ = -33554431;
|
||||
if (minZ > 33554431) minZ = 33554431;
|
||||
|
||||
if (maxX < -33554431) maxX = -33554431;
|
||||
if (maxX > 33554431) maxX = 33554431;
|
||||
if (maxY < -2047) maxY = -2047;
|
||||
if (maxY > 2047) maxY = 2047;
|
||||
if (maxZ < -33554431) maxZ = -33554431;
|
||||
if (maxZ > 33554431) maxZ = 33554431;
|
||||
|
||||
buf.writeBlockPos(new BlockPos(minX, minY, minZ));
|
||||
buf.writeBlockPos(new BlockPos(maxX, maxY, maxZ));
|
||||
}
|
||||
|
||||
byte[] bytes = new byte[buf.writerIndex()];
|
||||
buf.getBytes(0, bytes);
|
||||
player.sendPluginMessage(plugin, "axiom:restrictions", bytes);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -2,7 +2,10 @@ package com.moulberry.axiom.integration.plotsquared;
|
||||
|
||||
|
||||
import com.moulberry.axiom.integration.SectionPermissionChecker;
|
||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.entity.Player;
|
||||
@ -10,6 +13,24 @@ import org.bukkit.entity.Player;
|
||||
|
||||
public class PlotSquaredIntegration {
|
||||
|
||||
public record PlotBounds(BlockPos min, BlockPos max, String worldName) {
|
||||
public PlotBounds(CuboidRegion cuboidRegion, String worldName) {
|
||||
this(
|
||||
new BlockPos(
|
||||
cuboidRegion.getMinimumPoint().getBlockX(),
|
||||
cuboidRegion.getMinimumPoint().getBlockY(),
|
||||
cuboidRegion.getMinimumPoint().getBlockZ()
|
||||
),
|
||||
new BlockPos(
|
||||
cuboidRegion.getMaximumPoint().getBlockX(),
|
||||
cuboidRegion.getMaximumPoint().getBlockY(),
|
||||
cuboidRegion.getMaximumPoint().getBlockZ()
|
||||
),
|
||||
worldName
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean canBreakBlock(Player player, Block block) {
|
||||
if (!Bukkit.getPluginManager().isPluginEnabled("PlotSquared")) {
|
||||
return true;
|
||||
@ -31,6 +52,13 @@ public class PlotSquaredIntegration {
|
||||
return PlotSquaredIntegrationImpl.isPlotWorld(world);
|
||||
}
|
||||
|
||||
public static PlotSquaredIntegration.PlotBounds getCurrentEditablePlot(Player player) {
|
||||
if (!Bukkit.getPluginManager().isPluginEnabled("PlotSquared")) {
|
||||
return null;
|
||||
}
|
||||
return PlotSquaredIntegrationImpl.getCurrentEditablePlot(player);
|
||||
}
|
||||
|
||||
public static SectionPermissionChecker checkSection(Player player, World world, int sectionX, int sectionY, int sectionZ) {
|
||||
if (!Bukkit.getPluginManager().isPluginEnabled("PlotSquared")) {
|
||||
return SectionPermissionChecker.ALL_ALLOWED;
|
||||
|
@ -135,6 +135,52 @@ public class PlotSquaredIntegrationImpl {
|
||||
return isPlotWorld;
|
||||
}
|
||||
|
||||
static PlotSquaredIntegration.PlotBounds getCurrentEditablePlot(Player player) {
|
||||
org.bukkit.Location loc = player.getLocation();
|
||||
|
||||
Location location = BukkitUtil.adapt(loc);
|
||||
PlotArea area = location.getPlotArea();
|
||||
if (area == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
BukkitPlayer pp = BukkitUtil.adapt(player);
|
||||
Plot plot = area.getPlot(location);
|
||||
if (plot != null) {
|
||||
Location bottom = plot.getExtendedBottomAbs();
|
||||
Location top = plot.getExtendedTopAbs();
|
||||
CuboidRegion cuboidRegion = new CuboidRegion(bottom.getBlockVector3(), top.getBlockVector3());
|
||||
|
||||
// check unowned plots
|
||||
if (!plot.hasOwner()) {
|
||||
if (!pp.hasPermission(Permission.PERMISSION_ADMIN_BUILD_UNOWNED, false)) {
|
||||
return null;
|
||||
} else {
|
||||
return new PlotSquaredIntegration.PlotBounds(cuboidRegion, player.getWorld().getName());
|
||||
}
|
||||
}
|
||||
// player is breaking another player's plot
|
||||
if (!plot.isAdded(pp.getUUID())) {
|
||||
if (!pp.hasPermission(Permission.PERMISSION_ADMIN_BUILD_OTHER, false)) {
|
||||
return null;
|
||||
} else {
|
||||
return new PlotSquaredIntegration.PlotBounds(cuboidRegion, player.getWorld().getName());
|
||||
}
|
||||
}
|
||||
// plot is 'done'
|
||||
if (Settings.Done.RESTRICT_BUILDING && DoneFlag.isDone(plot)) {
|
||||
if (!pp.hasPermission(Permission.PERMISSION_ADMIN_BUILD_OTHER, false)) {
|
||||
return null;
|
||||
} else {
|
||||
return new PlotSquaredIntegration.PlotBounds(cuboidRegion, player.getWorld().getName());
|
||||
}
|
||||
}
|
||||
return new PlotSquaredIntegration.PlotBounds(cuboidRegion, player.getWorld().getName());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
static SectionPermissionChecker checkSection(Player player, World world, int sectionX, int sectionY, int sectionZ) {
|
||||
int minX = sectionX * 16;
|
||||
int minY = sectionY * 16;
|
||||
@ -220,4 +266,4 @@ public class PlotSquaredIntegrationImpl {
|
||||
|
||||
return SectionPermissionChecker.fromAllowedBoxes(allowed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -77,6 +77,20 @@ public class HelloPacketListener implements PluginMessageListener {
|
||||
}
|
||||
}
|
||||
|
||||
if (!player.getListeningPluginChannels().contains("axiom:restrictions")) {
|
||||
Component text = Component.text("This server requires the use of Axiom 2.3 or later. Contact the server administrator if you believe this is unintentional");
|
||||
|
||||
String unsupportedRestrictions = plugin.configuration.getString("client-doesnt-support-restrictions");
|
||||
if (unsupportedRestrictions == null) unsupportedRestrictions = "kick";
|
||||
if (unsupportedRestrictions.equals("warn")) {
|
||||
player.sendMessage(text.color(NamedTextColor.RED));
|
||||
return;
|
||||
} else if (!unsupportedRestrictions.equals("ignore")) {
|
||||
player.kick(text);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Call handshake event
|
||||
int maxBufferSize = plugin.configuration.getInt("max-block-buffer-packet-size");
|
||||
AxiomHandshakeEvent handshakeEvent = new AxiomHandshakeEvent(player, maxBufferSize);
|
||||
|
@ -13,9 +13,12 @@ allow-teleport-between-worlds: true
|
||||
|
||||
# Action to take when a user with an incompatible Minecraft version or Axiom version joins
|
||||
# Valid actions are 'kick', 'warn' and 'ignore'
|
||||
# 'warn' will give the player a warning and disable Axiom
|
||||
# Using 'ignore' may result in corruption and is only provided for debugging purposes
|
||||
incompatible-data-version: "kick"
|
||||
unsupported-axiom-version: "kick"
|
||||
incompatible-data-version: "warn"
|
||||
unsupported-axiom-version: "warn"
|
||||
client-doesnt-support-restrictions: "ignore"
|
||||
|
||||
|
||||
# Maximum packet size. Must not be less than 32767
|
||||
max-block-buffer-packet-size: 0x100000
|
||||
@ -36,13 +39,13 @@ log-large-block-buffer-changes: false
|
||||
|
||||
# Whitelist entities that can be spawned/manipulated/deleted by the client
|
||||
whitelist-entities:
|
||||
- "minecraft:item_display"
|
||||
- "minecraft:block_display"
|
||||
- "minecraft:text_display"
|
||||
- "minecraft:painting"
|
||||
- "minecraft:armor_stand"
|
||||
- "minecraft:item_frame"
|
||||
- "minecraft:glow_item_frame"
|
||||
# - "minecraft:item_display"
|
||||
# - "minecraft:block_display"
|
||||
# - "minecraft:text_display"
|
||||
# - "minecraft:painting"
|
||||
# - "minecraft:armor_stand"
|
||||
# - "minecraft:item_frame"
|
||||
# - "minecraft:glow_item_frame"
|
||||
|
||||
# Blacklist entities that can be spawned/manipulated/deleted by the client
|
||||
blacklist-entities:
|
||||
|
@ -19,3 +19,10 @@ permissions:
|
||||
description: Allows entity manipulation
|
||||
axiom.entity.delete:
|
||||
description: Allows entity deletion
|
||||
|
||||
axiom.allow_copying_other_plots:
|
||||
description: This permission allows users to copy other user's plots
|
||||
default: true
|
||||
axiom.can_import_blocks:
|
||||
description: Allows players to import schematics/blueprints into Axiom
|
||||
default: true
|
||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren