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

Merge branch 'master' into entity-manip-event

Dieser Commit ist enthalten in:
Moulberry 2024-06-10 12:06:38 +08:00 committet von GitHub
Commit 2673221f38
Es konnte kein GPG-Schlüssel zu dieser Signatur gefunden werden
GPG-Schlüssel-ID: B5690EEEBB952194
47 geänderte Dateien mit 1220 neuen und 331 gelöschten Zeilen

3
.gitignore vendored
Datei anzeigen

@ -15,6 +15,9 @@ out/
plugin/bin/
api/bin/
# VSCode
.vscode/
# Compiled class file
*.class

Datei anzeigen

@ -6,3 +6,13 @@ Serverside component for Axiom
## Download
https://modrinth.com/plugin/axiom-paper-plugin/
## FAQ
**Axiom works in singleplayer but not when I connect to a multiplayer server running the Axiom Paper Plugin. What gives?**
First, the player must be an op on the server. If the player does not have op permissions, run `/op <playername>`. This player must then disconnect from the server and reconnect.
If you're using an alternative solution for permission management, you must give players the `axiom.*` permission.
If players continue to have issues, they can run the `/whynoaxiom` command for more information.

Datei anzeigen

@ -1,43 +1,52 @@
plugins {
`java-library`
id("io.papermc.paperweight.userdev") version "1.5.11"
id("xyz.jpenilla.run-paper") version "2.2.2" // Adds runServer and runMojangMappedServer tasks for testing
alias(libs.plugins.paperweight.userdev)
alias(libs.plugins.run.paper) // Adds runServer and runMojangMappedServer tasks for testing
// Shades and relocates dependencies into our plugin jar. See https://imperceptiblethoughts.com/shadow/introduction/
id("com.github.johnrengelman.shadow") version "8.1.1"
alias(libs.plugins.shadow)
}
group = "com.moulberry.axiom"
version = "1.5.9"
version = "1.5.11"
description = "Serverside component for Axiom on Paper"
java {
// Configure the java toolchain. This allows gradle to auto-provision JDK 17 on systems that only have JDK 8 installed for example.
toolchain.languageVersion.set(JavaLanguageVersion.of(17))
// Configure the java toolchain. This allows gradle to auto-provision JDK 21 on systems that only have JDK 11 installed for example.
toolchain.languageVersion.set(JavaLanguageVersion.of(21))
}
repositories {
mavenCentral()
maven("https://repo.viaversion.com")
maven("https://s01.oss.sonatype.org/content/repositories/snapshots/")
maven("https://jitpack.io")
maven("https://repo.papermc.io/repository/maven-public/")
maven("https://maven.enginehub.org/repo/")
maven("https://maven.playpro.com")
}
dependencies {
paperweight.paperDevBundle("1.20.4-R0.1-SNAPSHOT")
implementation("xyz.jpenilla:reflection-remapper:0.1.0-SNAPSHOT")
paperweight.paperDevBundle(libs.versions.paper)
implementation(libs.reflection.remapper)
implementation(libs.cloud.paper)
// Zstd Compression Library
implementation("com.github.luben:zstd-jni:1.5.5-4")
implementation(libs.zstd.jni)
// ViaVersion support
compileOnly(libs.viaversion.api)
// WorldGuard support
compileOnly("com.sk89q.worldguard:worldguard-bukkit:7.1.0-SNAPSHOT")
compileOnly(libs.worldguard.bukkit)
// PlotSquared support
implementation(platform("com.intellectualsites.bom:bom-newest:1.37"))
compileOnly("com.intellectualsites.plotsquared:plotsquared-core")
compileOnly("com.intellectualsites.plotsquared:plotsquared-bukkit") { isTransitive = false }
implementation(platform(libs.bom.newest))
compileOnly(libs.plotsquared.core)
compileOnly(libs.plotsquared.bukkit) { isTransitive = false }
// CoreProtect support
compileOnly(libs.coreprotect)
}
tasks {
@ -51,7 +60,7 @@ tasks {
// Set the release flag. This configures what version bytecode the compiler will emit, as well as what JDK APIs are usable.
// See https://openjdk.java.net/jeps/247 for more information.
options.release.set(17)
options.release.set(21)
}
javadoc {
options.encoding = Charsets.UTF_8.name() // We want UTF-8 for everything

32
gradle/libs.versions.toml Normale Datei
Datei anzeigen

@ -0,0 +1,32 @@
[versions]
# Dependencies
bom-newest = "1.37"
cloud-paper = "2.0.0-20240516.054251-69"
coreprotect = "22.4"
paper = "1.20.6-R0.1-SNAPSHOT"
plotsquared = "7.3.9-20240513.192211-13"
reflection-remapper = "0.1.2-20240315.033304-2"
viaversion-api = "4.10.1-20240505.124211-22"
worldguard-bukkit = "7.1.0-20240503.180049-12"
zstd-jni = "1.5.5-4"
# Plugins
paperweight-userdev = "1.7.1"
run-paper = "2.2.4"
shadow = "8.1.7"
[libraries]
bom-newest = { group = "com.intellectualsites.bom", name = "bom-newest", version.ref = "bom-newest" }
cloud-paper = { group = "org.incendo", name = "cloud-paper", version.ref = "cloud-paper" }
coreprotect = { group = "net.coreprotect", name = "coreprotect", version.ref = "coreprotect" }
plotsquared-bukkit = { group = "com.intellectualsites.plotsquared", name = "plotsquared-bukkit", version.ref = "plotsquared" }
plotsquared-core = { group = "com.intellectualsites.plotsquared", name = "plotsquared-core", version.ref = "plotsquared" }
reflection-remapper = { group = "xyz.jpenilla", name = "reflection-remapper", version.ref = "reflection-remapper" }
viaversion-api = { group = "com.viaversion", name = "viaversion-api", version.ref = "viaversion-api" }
worldguard-bukkit = { group = "com.sk89q.worldguard", name = "worldguard-bukkit", version.ref = "worldguard-bukkit" }
zstd-jni = { group = "com.github.luben", name = "zstd-jni", version = "1.5.5-4" }
[plugins]
paperweight-userdev = { id = "io.papermc.paperweight.userdev", version.ref = "paperweight-userdev" }
run-paper = { id = "xyz.jpenilla.run-paper", version.ref = "run-paper" }
shadow = { id = "io.github.goooler.shadow", version.ref = "shadow" }

Datei anzeigen

@ -3,8 +3,10 @@ package com.moulberry.axiom;
import com.google.common.util.concurrent.RateLimiter;
import com.moulberry.axiom.blueprint.ServerBlueprintManager;
import com.moulberry.axiom.buffer.CompressedBlockEntity;
import com.moulberry.axiom.commands.AxiomDebugCommand;
import com.moulberry.axiom.event.AxiomCreateWorldPropertiesEvent;
import com.moulberry.axiom.event.AxiomModifyWorldEvent;
import com.moulberry.axiom.integration.coreprotect.CoreProtectIntegration;
import com.moulberry.axiom.integration.plotsquared.PlotSquaredIntegration;
import com.moulberry.axiom.packet.*;
import com.moulberry.axiom.world_properties.server.ServerWorldPropertiesRegistry;
@ -15,17 +17,19 @@ 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.SharedConstants;
import net.minecraft.core.BlockPos;
import net.minecraft.core.IdMapper;
import net.minecraft.network.Connection;
import net.minecraft.network.ConnectionProtocol;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.protocol.Packet;
import net.minecraft.network.protocol.PacketFlow;
import net.minecraft.network.*;
import net.minecraft.network.protocol.common.ServerboundCustomPayloadPacket;
import net.minecraft.network.protocol.common.custom.DiscardedPayload;
import net.minecraft.network.protocol.game.GameProtocols;
import net.minecraft.network.protocol.game.ServerGamePacketListener;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.level.block.state.BlockState;
import org.bukkit.*;
import org.bukkit.command.CommandSender;
import org.bukkit.configuration.Configuration;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
@ -34,9 +38,13 @@ import org.bukkit.event.player.PlayerChangedWorldEvent;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.plugin.messaging.Messenger;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.incendo.cloud.bukkit.CloudBukkitCapabilities;
import org.incendo.cloud.execution.ExecutionCoordinator;
import org.incendo.cloud.paper.LegacyPaperCommandManager;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
@ -49,6 +57,8 @@ 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 final Map<UUID, IdMapper<BlockState>> playerBlockRegistry = new ConcurrentHashMap<>();
public final Map<UUID, Integer> playerProtocolVersion = new ConcurrentHashMap<>();
public Configuration configuration;
public IdMapper<BlockState> allowedBlockRegistry = null;
@ -151,21 +161,16 @@ public class AxiomPaper extends JavaPlugin implements Listener {
RequestChunkDataPacketListener requestChunkDataPacketListener = allowLargeChunkDataRequest ?
new RequestChunkDataPacketListener(this) : null;
// Hack to figure out the id of the CustomPayload packet
ProtocolInfo<ServerGamePacketListener> protocol = GameProtocols.SERVERBOUND.bind(k -> new RegistryFriendlyByteBuf(k,
MinecraftServer.getServer().registryAccess()));
RegistryFriendlyByteBuf friendlyByteBuf = new RegistryFriendlyByteBuf(Unpooled.buffer(), MinecraftServer.getServer().registryAccess());
protocol.codec().encode(friendlyByteBuf, new ServerboundCustomPayloadPacket(new DiscardedPayload(new ResourceLocation("dummy"), Unpooled.buffer())));
int payloadId = friendlyByteBuf.readVarInt();
ChannelInitializeListenerHolder.addListener(Key.key("axiom:handle_big_payload"), new ChannelInitializeListener() {
@Override
public void afterInitChannel(@NonNull Channel channel) {
var packets = ConnectionProtocol.PLAY.getPacketsByIds(PacketFlow.SERVERBOUND);
int payloadId = -1;
for (Map.Entry<Integer, Class<? extends Packet<?>>> entry : packets.entrySet()) {
if (entry.getValue() == ServerboundCustomPayloadPacket.class) {
payloadId = entry.getKey();
break;
}
}
if (payloadId < 0) {
throw new RuntimeException("Failed to find ServerboundCustomPayloadPacket id");
}
Connection connection = (Connection) channel.pipeline().get("packet_handler");
channel.pipeline().addBefore("decoder", "axiom-big-payload-handler",
new AxiomBigPayloadHandler(payloadId, connection, setBlockBufferPacketListener,
@ -213,32 +218,31 @@ public class AxiomPaper extends JavaPlugin implements Listener {
send = true;
}
BlockPos boundsMin = null;
BlockPos boundsMax = null;
Set<PlotSquaredIntegration.PlotBox> bounds = Set.of();
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();
bounds = editable.boxes();
} else if (restrictions.lastPlotBounds != null && restrictions.lastPlotBounds.worldName().equals(player.getWorld().getName())) {
boundsMin = restrictions.lastPlotBounds.min();
boundsMax = restrictions.lastPlotBounds.max();
bounds = restrictions.lastPlotBounds.boxes();
} else {
boundsMin = BlockPos.ZERO;
boundsMax = BlockPos.ZERO;
bounds = Set.of(new PlotSquaredIntegration.PlotBox(BlockPos.ZERO, BlockPos.ZERO));
}
}
if (bounds.size() == 1) {
PlotSquaredIntegration.PlotBox plotBounds = bounds.iterator().next();
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;
if (plotBounds.min().getX() == min && plotBounds.min().getY() == min && plotBounds.min().getZ() == min &&
plotBounds.max().getX() == max && plotBounds.max().getY() == max && plotBounds.max().getZ() == max) {
bounds = Set.of();
}
}
}
@ -246,12 +250,10 @@ public class AxiomPaper extends JavaPlugin implements Listener {
if (restrictions.maxSectionsPerSecond != rateLimit ||
restrictions.canImportBlocks != allowImportingBlocks ||
!Objects.equals(restrictions.boundsMin, boundsMin) ||
!Objects.equals(restrictions.boundsMax, boundsMax)) {
!Objects.equals(restrictions.bounds, bounds)) {
restrictions.maxSectionsPerSecond = rateLimit;
restrictions.canImportBlocks = allowImportingBlocks;
restrictions.boundsMin = boundsMin;
restrictions.boundsMax = boundsMax;
restrictions.bounds = bounds;
send = true;
}
@ -265,6 +267,8 @@ public class AxiomPaper extends JavaPlugin implements Listener {
activeAxiomPlayers.retainAll(stillActiveAxiomPlayers);
playerBlockBufferRateLimiters.keySet().retainAll(stillActiveAxiomPlayers);
playerRestrictions.keySet().retainAll(stillActiveAxiomPlayers);
playerBlockRegistry.keySet().retainAll(stillActiveAxiomPlayers);
playerProtocolVersion.keySet().retainAll(stillActiveAxiomPlayers);
}, 20, 20);
boolean sendMarkers = configuration.getBoolean("send-markers");
@ -274,6 +278,25 @@ public class AxiomPaper extends JavaPlugin implements Listener {
Bukkit.getScheduler().scheduleSyncRepeatingTask(this, () -> {
WorldExtension.tick(MinecraftServer.getServer(), sendMarkers, maxChunkRelightsPerTick, maxChunkSendsPerTick);
}, 1, 1);
try {
LegacyPaperCommandManager<CommandSender> manager = LegacyPaperCommandManager.createNative(
this,
ExecutionCoordinator.simpleCoordinator()
);
if (manager.hasCapability(CloudBukkitCapabilities.NATIVE_BRIGADIER)) {
manager.registerBrigadier();
}
AxiomDebugCommand.register(this, manager);
} catch (Exception e) {
e.printStackTrace();
}
if (CoreProtectIntegration.isEnabled()) {
this.getLogger().info("CoreProtect integration enabled");
}
}
public boolean logLargeBlockBufferChanges() {
@ -281,17 +304,46 @@ public class AxiomPaper extends JavaPlugin implements Listener {
}
public boolean hasAxiomPermission(Player player) {
return player.hasPermission("axiom.*") || player.isOp();
return hasAxiomPermission(player, null, false);
}
public boolean hasAxiomPermission(Player player, String permission, boolean strict) {
if (player.hasPermission("axiom.*") || player.isOp()) {
return !strict || permission == null || player.hasPermission("axiom.all") || player.hasPermission(permission);
} else if (permission != null && !player.hasPermission(permission)) {
return false;
}
return player.hasPermission("axiom.use");
}
public boolean canUseAxiom(Player player) {
return hasAxiomPermission(player) && activeAxiomPlayers.contains(player.getUniqueId());
return canUseAxiom(player, null, false);
}
public boolean canUseAxiom(Player player, String permission) {
return canUseAxiom(player, permission, false);
}
public boolean canUseAxiom(Player player, String permission, boolean strict) {
return activeAxiomPlayers.contains(player.getUniqueId()) && hasAxiomPermission(player, permission, strict);
}
public @Nullable RateLimiter getBlockBufferRateLimiter(UUID uuid) {
return this.playerBlockBufferRateLimiters.get(uuid);
}
public boolean isMismatchedDataVersion(UUID uuid) {
return this.playerProtocolVersion.containsKey(uuid);
}
public int getProtocolVersionFor(UUID uuid) {
return this.playerProtocolVersion.getOrDefault(uuid, SharedConstants.getProtocolVersion());
}
public IdMapper<BlockState> getBlockRegistry(UUID uuid) {
return this.playerBlockRegistry.getOrDefault(uuid, this.allowedBlockRegistry);
}
private final WeakHashMap<World, ServerWorldPropertiesRegistry> worldProperties = new WeakHashMap<>();
public @Nullable ServerWorldPropertiesRegistry getWorldPropertiesIfPresent(World world) {
@ -363,7 +415,7 @@ public class AxiomPaper extends JavaPlugin implements Listener {
}
private ServerWorldPropertiesRegistry createWorldProperties(World world) {
ServerWorldPropertiesRegistry registry = new ServerWorldPropertiesRegistry(world);
ServerWorldPropertiesRegistry registry = new ServerWorldPropertiesRegistry(new WeakReference<>(world));
AxiomCreateWorldPropertiesEvent createEvent = new AxiomCreateWorldPropertiesEvent(world, registry);
Bukkit.getPluginManager().callEvent(createEvent);

Datei anzeigen

@ -3,6 +3,7 @@ package com.moulberry.axiom;
import com.mojang.brigadier.StringReader;
import com.mojang.datafixers.util.Either;
import com.moulberry.axiom.buffer.BlockBuffer;
import com.viaversion.viaversion.api.data.Mappings;
import net.minecraft.commands.arguments.blocks.BlockPredicateArgument;
import net.minecraft.commands.arguments.blocks.BlockStateParser;
import net.minecraft.core.IdMapper;

Datei anzeigen

@ -6,14 +6,15 @@ import net.minecraft.core.BlockPos;
import net.minecraft.network.FriendlyByteBuf;
import org.bukkit.entity.Player;
import java.util.Set;
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 Set<PlotSquaredIntegration.PlotBox> bounds = Set.of();
public PlotSquaredIntegration.PlotBounds lastPlotBounds = null;
@ -26,16 +27,21 @@ public class Restrictions {
buf.writeVarInt(this.maxSectionsPerSecond);
if (this.boundsMin == null || this.boundsMax == null) {
buf.writeBoolean(false);
int count = Math.min(64, bounds.size());
buf.writeVarInt(count);
for (PlotSquaredIntegration.PlotBox bound : this.bounds) {
if (count > 0) {
count -= 1;
} 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();
break;
}
int minX = bound.min().getX();
int minY = bound.min().getY();
int minZ = bound.min().getZ();
int maxX = bound.max().getX();
int maxY = bound.max().getY();
int maxZ = bound.max().getZ();
if (minX < -33554431) minX = -33554431;
if (minX > 33554431) minX = 33554431;
@ -61,4 +67,15 @@ public class Restrictions {
}
}
@Override
public String toString() {
return "Restrictions{" +
"canImportBlocks=" + canImportBlocks +
", canUseEditor=" + canUseEditor +
", canEditDisplayEntities=" + canEditDisplayEntities +
", maxSectionsPerSecond=" + maxSectionsPerSecond +
", bounds=" + bounds +
", lastPlotBounds=" + lastPlotBounds +
'}';
}
}

Datei anzeigen

@ -1,14 +1,15 @@
package com.moulberry.axiom;
import com.moulberry.axiom.packet.CustomByteArrayPayload;
import io.netty.buffer.Unpooled;
import net.minecraft.network.protocol.common.ClientboundCustomPayloadPacket;
import net.minecraft.network.protocol.common.custom.DiscardedPayload;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerPlayer;
public class VersionHelper {
public static void sendCustomPayload(ServerPlayer serverPlayer, ResourceLocation id, byte[] data) {
serverPlayer.connection.send(new ClientboundCustomPayloadPacket(new CustomByteArrayPayload(id, data)));
serverPlayer.connection.send(new ClientboundCustomPayloadPacket(new DiscardedPayload(id, Unpooled.wrappedBuffer(data))));
}
}

Datei anzeigen

@ -16,8 +16,8 @@ import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.chunk.LevelChunk;
import org.bukkit.World;
import org.bukkit.craftbukkit.v1_20_R3.CraftWorld;
import org.bukkit.craftbukkit.v1_20_R3.entity.CraftPlayer;
import org.bukkit.craftbukkit.CraftWorld;
import org.bukkit.craftbukkit.entity.CraftPlayer;
import org.bukkit.entity.Player;
import java.util.*;
@ -65,7 +65,7 @@ public class WorldExtension {
FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer());
buf.writeCollection(markerData, MarkerData::write);
buf.writeCollection(Set.of(), FriendlyByteBuf::writeUUID);
buf.writeCollection(Set.<UUID>of(), (buffer, uuid) -> buffer.writeUUID(uuid));
byte[] bytes = new byte[buf.writerIndex()];
buf.getBytes(0, bytes);
@ -106,7 +106,7 @@ public class WorldExtension {
if (!changedData.isEmpty() || !oldUuids.isEmpty()) {
FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer());
buf.writeCollection(changedData, MarkerData::write);
buf.writeCollection(oldUuids, FriendlyByteBuf::writeUUID);
buf.writeCollection(oldUuids, (buffer, uuid) -> buffer.writeUUID(uuid));
byte[] bytes = new byte[buf.writerIndex()];
buf.getBytes(0, bytes);

Datei anzeigen

@ -128,7 +128,7 @@ public class BlueprintIo {
CompoundTag blockStates = compoundTag.getCompound("BlockStates");
blockStates = DFUHelper.updatePalettedContainer(blockStates, dataVersion);
PalettedContainer<BlockState> container = BLOCK_STATE_CODEC.parse(NbtOps.INSTANCE, blockStates)
.getOrThrow(false, err -> {});
.getOrThrow();
map.put(BlockPos.asLong(cx, cy, cz), container);
}
}
@ -205,8 +205,7 @@ public class BlueprintIo {
tag.putInt("X", cx);
tag.putInt("Y", cy);
tag.putInt("Z", cz);
Tag encoded = BlueprintIo.BLOCK_STATE_CODEC.encodeStart(NbtOps.INSTANCE, container)
.getOrThrow(false, err -> {});
Tag encoded = BlueprintIo.BLOCK_STATE_CODEC.encodeStart(NbtOps.INSTANCE, container).getOrThrow();
tag.put("BlockStates", encoded);
savedBlockRegions.add(tag);
}

Datei anzeigen

@ -6,7 +6,7 @@ import io.netty.buffer.Unpooled;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerPlayer;
import org.bukkit.craftbukkit.v1_20_R3.entity.CraftPlayer;
import org.bukkit.craftbukkit.entity.CraftPlayer;
import java.io.BufferedInputStream;
import java.io.IOException;

Datei anzeigen

@ -9,6 +9,7 @@ import it.unimi.dsi.fastutil.objects.ObjectSet;
import it.unimi.dsi.fastutil.shorts.Short2ObjectMap;
import it.unimi.dsi.fastutil.shorts.Short2ObjectOpenHashMap;
import net.minecraft.core.BlockPos;
import net.minecraft.core.IdMapper;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState;
@ -23,18 +24,16 @@ public class BlockBuffer {
private final Long2ObjectMap<PalettedContainer<BlockState>> values;
private IdMapper<BlockState> registry;
private PalettedContainer<BlockState> last = null;
private long lastId = AxiomConstants.MIN_POSITION_LONG;
private final Long2ObjectMap<Short2ObjectMap<CompressedBlockEntity>> blockEntities = new Long2ObjectOpenHashMap<>();
private long totalBlockEntities = 0;
private long totalBlockEntityBytes = 0;
public BlockBuffer() {
public BlockBuffer(IdMapper<BlockState> registry) {
this.values = new Long2ObjectOpenHashMap<>();
}
public BlockBuffer(Long2ObjectMap<PalettedContainer<BlockState>> values) {
this.values = values;
this.registry = registry;
}
public void save(FriendlyByteBuf friendlyByteBuf) {
@ -57,8 +56,9 @@ public class BlockBuffer {
friendlyByteBuf.writeLong(AxiomConstants.MIN_POSITION_LONG);
}
public static BlockBuffer load(FriendlyByteBuf friendlyByteBuf, @Nullable RateLimiter rateLimiter, AtomicBoolean reachedRateLimit) {
BlockBuffer buffer = new BlockBuffer();
public static BlockBuffer load(FriendlyByteBuf friendlyByteBuf, @Nullable RateLimiter rateLimiter, AtomicBoolean reachedRateLimit,
IdMapper<BlockState> registry) {
BlockBuffer buffer = new BlockBuffer(registry);
long totalBlockEntities = 0;
long totalBlockEntityBytes = 0;
@ -177,7 +177,7 @@ public class BlockBuffer {
public PalettedContainer<BlockState> getOrCreateSection(long id) {
if (this.last == null || id != this.lastId) {
this.lastId = id;
this.last = this.values.computeIfAbsent(id, k -> new PalettedContainer<>(AxiomPaper.PLUGIN.allowedBlockRegistry,
this.last = this.values.computeIfAbsent(id, k -> new PalettedContainer<>(this.registry,
EMPTY_STATE, PalettedContainer.Strategy.SECTION_STATES));
}

Datei anzeigen

@ -0,0 +1,155 @@
package com.moulberry.axiom.commands;
import com.moulberry.axiom.AxiomPaper;
import com.moulberry.axiom.Restrictions;
import com.moulberry.axiom.integration.Integration;
import com.moulberry.axiom.integration.plotsquared.PlotSquaredIntegration;
import com.moulberry.axiom.integration.worldguard.WorldGuardIntegration;
import net.kyori.adventure.text.Component;
import org.bukkit.block.Block;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.incendo.cloud.Command;
import org.incendo.cloud.bukkit.BukkitCommandManager;
import org.incendo.cloud.parser.standard.EnumParser;
import org.incendo.cloud.parser.standard.StringParser;
import org.incendo.cloud.permission.PredicatePermission;
import java.util.UUID;
public class AxiomDebugCommand {
/**
* Command requires either the axiom.debug permission or for you to have the UUID d0e05de7-6067-454d-beae-c6d19d886191
* The command isn't capable of modifying the world, only checking various properties for debugging purposes
* It should be 100% safe to give to any player, but is locked behind some restrictions due to the potential
* for lagging the server by spamming certain commands
*/
private static final UUID MOULBERRY_UUID = UUID.fromString("d0e05de7-6067-454d-beae-c6d19d886191");
public static void register(AxiomPaper axiomPaper, BukkitCommandManager<CommandSender> manager) {
manager.command(
base(manager, "hasAxiomPermission").handler(context -> {
if (!(context.sender() instanceof Player player)) return;
boolean hasAxiomPermission = axiomPaper.hasAxiomPermission(player);
context.sender().sendMessage(Component.text("hasAxiomPermission: " + hasAxiomPermission));
})
);
manager.command(
base(manager, "canUseAxiom").handler(context -> {
if (!(context.sender() instanceof Player player)) return;
boolean canUseAxiom = axiomPaper.canUseAxiom(player);
context.sender().sendMessage(Component.text("canUseAxiom: " + canUseAxiom));
})
);
manager.command(
base(manager, "isMismatchedDataVersion").handler(context -> {
if (!(context.sender() instanceof Player player)) return;
boolean isMismatchedDataVersion = axiomPaper.isMismatchedDataVersion(player.getUniqueId());
context.sender().sendMessage(Component.text("isMismatchedDataVersion: " + isMismatchedDataVersion));
})
);
manager.command(
base(manager, "canModifyWorld").handler(context -> {
if (!(context.sender() instanceof Player player)) return;
boolean canModifyWorld = axiomPaper.canModifyWorld(player, player.getWorld());
context.sender().sendMessage(Component.text("canModifyWorld: " + canModifyWorld));
})
);
manager.command(
base(manager, "isClientListening").required("channel", StringParser.greedyStringParser()).handler(context -> {
if (!(context.sender() instanceof Player player)) return;
String channel = context.get("channel");
boolean isClientListening = player.getListeningPluginChannels().contains(channel);
context.sender().sendMessage(Component.text("listening to " + channel +": " + isClientListening));
})
);
manager.command(
base(manager, "hasPermission").required("permission", StringParser.greedyStringParser()).handler(context -> {
String permission = context.get("permission");
boolean hasPermission = context.sender().hasPermission(permission);
context.sender().sendMessage(Component.text("has permission " + permission +": " + hasPermission));
})
);
manager.command(
base(manager, "getRestrictions").handler(context -> {
if (!(context.sender() instanceof Player player)) return;
Restrictions restrictions = axiomPaper.playerRestrictions.get(player.getUniqueId());
if (restrictions == null) {
context.sender().sendMessage(Component.text("no restrictions"));
} else {
context.sender().sendMessage(Component.text("restrictions: " + restrictions));
}
})
);
enum IntegrationType {
PLOT_SQUARED,
WORLD_GUARD
}
manager.command(
base(manager, "canBreakBlockAtCurrentPosition").optional("type", EnumParser.enumParser(IntegrationType.class)).handler(context -> {
if (!(context.sender() instanceof Player player)) return;
IntegrationType integrationType = (IntegrationType) context.optional("type").orElse(null);
Block block = player.getWorld().getBlockAt(player.getLocation());
boolean canBreakBlock;
if (integrationType == IntegrationType.PLOT_SQUARED) {
canBreakBlock = PlotSquaredIntegration.canBreakBlock(player, block);
} else if (integrationType == IntegrationType.WORLD_GUARD) {
canBreakBlock = WorldGuardIntegration.canBreakBlock(player, block.getLocation());
} else {
canBreakBlock = Integration.canBreakBlock(player, block);
}
context.sender().sendMessage(Component.text("canBreakBlock: " + canBreakBlock));
})
);
manager.command(
base(manager, "canPlaceBlockAtCurrentPosition").optional("type", EnumParser.enumParser(IntegrationType.class)).handler(context -> {
if (!(context.sender() instanceof Player player)) return;
IntegrationType integrationType = (IntegrationType) context.optional("type").orElse(null);
boolean canPlaceBlock;
if (integrationType == IntegrationType.PLOT_SQUARED) {
canPlaceBlock = PlotSquaredIntegration.canPlaceBlock(player, player.getLocation());
} else if (integrationType == IntegrationType.WORLD_GUARD) {
canPlaceBlock = WorldGuardIntegration.canPlaceBlock(player, player.getLocation());
} else {
canPlaceBlock = Integration.canPlaceBlock(player, player.getLocation());
}
context.sender().sendMessage(Component.text("canPlaceBlock: " + canPlaceBlock));
})
);
manager.command(
base(manager, "isPlotWorld").handler(context -> {
if (!(context.sender() instanceof Player player)) return;
boolean isPlotWorld = PlotSquaredIntegration.isPlotWorld(player.getWorld());
context.sender().sendMessage(Component.text("isPlotWorld: " + isPlotWorld));
})
);
manager.command(
base(manager, "getCurrentEditablePlot").handler(context -> {
if (!(context.sender() instanceof Player player)) return;
PlotSquaredIntegration.PlotBounds plotBounds = PlotSquaredIntegration.getCurrentEditablePlot(player);
context.sender().sendMessage(Component.text("plotBounds: " + plotBounds));
})
);
}
private static Command.Builder<CommandSender> base(BukkitCommandManager<CommandSender> manager, String subcommand) {
return manager.commandBuilder("axiompaperdebug")
.literal(subcommand)
.senderType(CommandSender.class)
.permission(PredicatePermission.of(sender -> {
if (sender instanceof Player player) {
return player.hasPermission("axiom.debug") || player.getUniqueId().equals(MOULBERRY_UUID);
} else {
return false;
}
}));
}
}

Datei anzeigen

@ -13,10 +13,10 @@ public interface SectionPermissionChecker {
if (first.noneAllowed() || second.noneAllowed()) {
return NONE_ALLOWED;
}
if (first.allAllowed()) {
if (first == ALL_ALLOWED) {
return second;
}
if (second.allAllowed()) {
if (second == ALL_ALLOWED) {
return first;
}
@ -25,6 +25,10 @@ public interface SectionPermissionChecker {
return NONE_ALLOWED;
}
if (first.allAllowed() && second.allAllowed()) {
return new AllAllowedInBox(intersect);
}
return new SectionPermissionChecker() {
@Override
public boolean allAllowed() {

Datei anzeigen

@ -0,0 +1,29 @@
package com.moulberry.axiom.integration.coreprotect;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.state.BlockState;
import org.bukkit.craftbukkit.CraftWorld;
public class CoreProtectIntegration {
public static boolean isEnabled() {
return CoreProtectIntegrationImpl.isEnabled();
}
public static void logPlacement(String name, BlockState blockState, CraftWorld world, BlockPos pos) {
if (!CoreProtectIntegrationImpl.isEnabled()) {
return;
}
CoreProtectIntegrationImpl.logPlacement(name, blockState, world, pos);
}
public static void logRemoval(String name, BlockState blockState, CraftWorld world, BlockPos pos) {
if (!CoreProtectIntegrationImpl.isEnabled()) {
return;
}
CoreProtectIntegrationImpl.logRemoval(name, blockState, world, pos);
}
}

Datei anzeigen

@ -0,0 +1,83 @@
package com.moulberry.axiom.integration.coreprotect;
import com.moulberry.axiom.AxiomPaper;
import net.coreprotect.CoreProtect;
import net.coreprotect.CoreProtectAPI;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.block.state.BlockState;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.craftbukkit.CraftWorld;
import org.bukkit.craftbukkit.block.CraftBlockState;
import org.bukkit.plugin.Plugin;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class CoreProtectIntegrationImpl {
private static final CoreProtectAPI COREPROTECT_API;
private static final boolean COREPROTECT_ENABLED;
private static final Constructor<CraftBlockState> CRAFT_BLOCK_STATE_CONSTRUCTOR;
static {
COREPROTECT_API = getCoreProtect();
Constructor<CraftBlockState> constructor = null;
if (COREPROTECT_API != null) {
try {
constructor = CraftBlockState.class.getDeclaredConstructor(World.class, BlockPos.class, BlockState.class);
constructor.setAccessible(true);
} catch (NoSuchMethodException | SecurityException e) {
AxiomPaper.PLUGIN.getLogger().warning("Failed to get CraftBlockState constructor for CoreProtect: " + e);
}
}
CRAFT_BLOCK_STATE_CONSTRUCTOR = constructor;
COREPROTECT_ENABLED = COREPROTECT_API != null && CRAFT_BLOCK_STATE_CONSTRUCTOR != null;
}
private static CoreProtectAPI getCoreProtect() {
Plugin plugin = Bukkit.getPluginManager().getPlugin("CoreProtect");
if (!(plugin instanceof CoreProtect)) {
return null;
}
CoreProtectAPI coreProtect = ((CoreProtect) plugin).getAPI();
if (!coreProtect.isEnabled()) {
return null;
}
if (coreProtect.APIVersion() < 10) {
return null;
}
return coreProtect;
}
private static CraftBlockState createCraftBlockState(World world, BlockPos pos, BlockState blockState) {
try {
return CRAFT_BLOCK_STATE_CONSTRUCTOR.newInstance(world, pos, blockState);
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
AxiomPaper.PLUGIN.getLogger().warning("Failed to create CraftBlockState for CoreProtect: " + e);
return null;
}
}
static boolean isEnabled() {
return COREPROTECT_ENABLED;
}
static void logPlacement(String name, BlockState blockState, CraftWorld world, BlockPos pos) {
if (blockState.isAir()) {
return;
}
COREPROTECT_API.logPlacement(name, createCraftBlockState(world, pos, blockState));
}
static void logRemoval(String name, BlockState blockState, CraftWorld world, BlockPos pos) {
COREPROTECT_API.logRemoval(name, createCraftBlockState(world, pos, blockState));
}
}

Datei anzeigen

@ -10,26 +10,13 @@ import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import java.util.Set;
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 record PlotBox(BlockPos min, BlockPos max) {}
public record PlotBounds(Set<PlotBox> boxes, String worldName) {}
public static boolean canBreakBlock(Player player, Block block) {
if (!Bukkit.getPluginManager().isPluginEnabled("PlotSquared")) {

Datei anzeigen

@ -18,6 +18,7 @@ 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 net.minecraft.core.BlockPos;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
@ -147,16 +148,12 @@ public class PlotSquaredIntegrationImpl {
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());
return createBounds(plot, player.getWorld().getName());
}
}
// player is breaking another player's plot
@ -164,7 +161,7 @@ public class PlotSquaredIntegrationImpl {
if (!pp.hasPermission(Permission.PERMISSION_ADMIN_BUILD_OTHER, false)) {
return null;
} else {
return new PlotSquaredIntegration.PlotBounds(cuboidRegion, player.getWorld().getName());
return createBounds(plot, player.getWorld().getName());
}
}
// plot is 'done'
@ -172,15 +169,35 @@ public class PlotSquaredIntegrationImpl {
if (!pp.hasPermission(Permission.PERMISSION_ADMIN_BUILD_OTHER, false)) {
return null;
} else {
return new PlotSquaredIntegration.PlotBounds(cuboidRegion, player.getWorld().getName());
return createBounds(plot, player.getWorld().getName());
}
}
return new PlotSquaredIntegration.PlotBounds(cuboidRegion, player.getWorld().getName());
return createBounds(plot, player.getWorld().getName());
}
return null;
}
private static PlotSquaredIntegration.PlotBounds createBounds(Plot plot, String worldName) {
Set<PlotSquaredIntegration.PlotBox> boxes = new HashSet<>();
for (CuboidRegion region : plot.getRegions()) {
BlockPos min = new BlockPos(
region.getMinimumPoint().getBlockX(),
region.getMinimumPoint().getBlockY(),
region.getMinimumPoint().getBlockZ()
);
BlockPos max = new BlockPos(
region.getMaximumPoint().getBlockX(),
region.getMaximumPoint().getBlockY(),
region.getMaximumPoint().getBlockZ()
);
boxes.add(new PlotSquaredIntegration.PlotBox(min, max));
}
return new PlotSquaredIntegration.PlotBounds(boxes, worldName);
}
static SectionPermissionChecker checkSection(Player player, World world, int sectionX, int sectionY, int sectionZ) {
int minX = sectionX * 16;
int minY = sectionY * 16;
@ -220,12 +237,12 @@ public class PlotSquaredIntegrationImpl {
BlockVector3 minPoint = region.getMinimumPoint();
BlockVector3 maxPoint = region.getMaximumPoint();
int minPlotX = Math.max(minPoint.getX(), minX);
int minPlotY = Math.max(minPoint.getY(), minY);
int minPlotZ = Math.max(minPoint.getZ(), minZ);
int maxPlotX = Math.min(maxPoint.getX(), maxX);
int maxPlotY = Math.min(maxPoint.getY(), maxY);
int maxPlotZ = Math.min(maxPoint.getZ(), maxZ);
int minPlotX = Math.max(minPoint.x(), minX);
int minPlotY = Math.max(minPoint.y(), minY);
int minPlotZ = Math.max(minPoint.z(), minZ);
int maxPlotX = Math.min(maxPoint.x(), maxX);
int maxPlotY = Math.min(maxPoint.y(), maxY);
int maxPlotZ = Math.min(maxPoint.z(), maxZ);
if (minPlotX > maxPlotX) continue;
if (minPlotY > maxPlotY) continue;

Datei anzeigen

@ -34,15 +34,19 @@ public class WorldGuardIntegrationImpl {
private static boolean testBuild(Player player, org.bukkit.Location loc, StateFlag flag) {
WorldGuardPlatform platform = WorldGuard.getInstance().getPlatform();
com.sk89q.worldedit.world.World worldEditWorld = BukkitAdapter.adapt(loc.getWorld());
LocalPlayer worldGuardPlayer = WorldGuardPlugin.inst().wrapPlayer(player);
if (platform.getSessionManager().hasBypass(worldGuardPlayer, worldEditWorld)) {
return true;
}
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);
}
@ -118,12 +122,12 @@ public class WorldGuardIntegrationImpl {
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;
int regionMinX = Math.max(regionMin.x(), cx*16) - minX;
int regionMinY = Math.max(regionMin.y(), cy*16) - minY;
int regionMinZ = Math.max(regionMin.z(), cz*16) - minZ;
int regionMaxX = Math.min(regionMax.x(), cx*16+15) - minX;
int regionMaxY = Math.min(regionMax.y(), cy*16+15) - minY;
int regionMaxZ = Math.min(regionMax.z(), cz*16+15) - minZ;
Box box = new Box(regionMinX, regionMinY, regionMinZ, regionMaxX, regionMaxY, regionMaxZ);
if (value == StateFlag.State.DENY) {

Datei anzeigen

@ -11,6 +11,7 @@ import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerPlayer;
import java.io.IOException;
import java.util.List;
public class AxiomBigPayloadHandler extends ByteToMessageDecoder {
@ -35,14 +36,31 @@ public class AxiomBigPayloadHandler extends ByteToMessageDecoder {
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
// Don't process if channel isn't active
if (!ctx.channel().isActive()) {
in.skipBytes(in.readableBytes());
// No bytes to read?! Go away
if (in.readableBytes() == 0) {
return;
}
// Don't handle if player doesn't have permission to use Axiom
ServerPlayer player = connection.getPlayer();
if (player == null || !AxiomPaper.PLUGIN.canUseAxiom(player.getBukkitEntity())) {
ctx.fireChannelRead(in.retain());
// Skip remaining bytes
if (in.readableBytes() > 0) {
in.skipBytes(in.readableBytes());
}
return;
}
// Don't process if channel isn't active
if (!ctx.channel().isActive()) {
if (in.readableBytes() > 0) {
in.skipBytes(in.readableBytes());
}
return;
}
int i = in.readableBytes();
if (i != 0) {
int readerIndex = in.readerIndex();
boolean success = false;
try {
@ -52,44 +70,58 @@ public class AxiomBigPayloadHandler extends ByteToMessageDecoder {
if (packetId == payloadId) {
ResourceLocation identifier = buf.readResourceLocation();
if (identifier.equals(SET_BUFFER)) {
ServerPlayer player = connection.getPlayer();
if (AxiomPaper.PLUGIN.canUseAxiom(player.getBukkitEntity())) {
setBlockBuffer.onReceive(player, buf);
success = true;
in.skipBytes(in.readableBytes());
return;
if (in.readableBytes() > 0) {
throw new IOException("Axiom packet " + identifier + " was larger than I expected, found " + in.readableBytes() +
" bytes extra whilst reading packet");
}
return;
} else if (identifier.equals(UPLOAD_BLUEPRINT)) {
ServerPlayer player = connection.getPlayer();
if (AxiomPaper.PLUGIN.canUseAxiom(player.getBukkitEntity())) {
player.getServer().execute(() -> uploadBlueprint.onReceive(player, buf));
uploadBlueprint.onReceive(player, buf);
success = true;
in.skipBytes(in.readableBytes());
return;
if (in.readableBytes() > 0) {
throw new IOException("Axiom packet " + identifier + " was larger than I expected, found " + in.readableBytes() +
" bytes extra whilst reading packet");
}
return;
} else if (requestChunkDataPacketListener != null && identifier.equals(REQUEST_CHUNK_DATA)) {
ServerPlayer player = connection.getPlayer();
if (AxiomPaper.PLUGIN.canUseAxiom(player.getBukkitEntity())) {
byte[] bytes = new byte[buf.writerIndex() - buf.readerIndex()];
buf.getBytes(buf.readerIndex(), bytes);
player.getServer().execute(() -> requestChunkDataPacketListener.onPluginMessageReceived(
identifier.toString(), player.getBukkitEntity(), bytes));
player.getServer().execute(() -> {
try {
requestChunkDataPacketListener.onPluginMessageReceived(
identifier.toString(), player.getBukkitEntity(), bytes);
} catch (Throwable t) {
player.getBukkitEntity().kick(net.kyori.adventure.text.Component.text(
"An error occured while requesting chunk data: " + t.getMessage()));
}
});
success = true;
if (in.readableBytes() > 0) {
in.skipBytes(in.readableBytes());
}
return;
}
}
} catch (Throwable t) {
if (!(t instanceof IndexOutOfBoundsException)) {
// Skip remaining bytes
success = true;
if (in.readableBytes() > 0) {
in.skipBytes(in.readableBytes());
}
// Throw error, will disconnect client
throw t;
}
} catch (Throwable ignored) {
} finally {
if (!success) {
in.readerIndex(readerIndex);
}
}
}
ctx.fireChannelRead(in.retain());

Datei anzeigen

@ -6,9 +6,11 @@ import com.moulberry.axiom.blueprint.RawBlueprint;
import com.moulberry.axiom.blueprint.ServerBlueprintManager;
import com.moulberry.axiom.blueprint.ServerBlueprintRegistry;
import io.netty.buffer.Unpooled;
import net.kyori.adventure.text.Component;
import net.minecraft.SharedConstants;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation;
import org.bukkit.craftbukkit.v1_20_R3.entity.CraftPlayer;
import org.bukkit.craftbukkit.entity.CraftPlayer;
import org.bukkit.entity.Player;
import org.bukkit.plugin.messaging.PluginMessageListener;
import org.jetbrains.annotations.NotNull;
@ -26,7 +28,20 @@ public class BlueprintRequestPacketListener implements PluginMessageListener {
@Override
public void onPluginMessageReceived(@NotNull String channel, @NotNull Player player, @NotNull byte[] message) {
if (!this.plugin.canUseAxiom(player)) {
try {
this.process(player, message);
} catch (Throwable t) {
player.kick(Component.text("Error while processing packet " + channel + ": " + t.getMessage()));
}
}
private void process(Player player, byte[] message) {
if (!this.plugin.canUseAxiom(player, "axiom.blueprint.request")) {
return;
}
if (this.plugin.isMismatchedDataVersion(player.getUniqueId())) {
player.sendMessage(Component.text("Axiom+ViaVersion: This feature isn't supported. Switch your client version to " + SharedConstants.VERSION_STRING + " to use this"));
return;
}

Datei anzeigen

@ -1,12 +0,0 @@
package com.moulberry.axiom.packet;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
import net.minecraft.resources.ResourceLocation;
public record CustomByteArrayPayload(ResourceLocation id, byte[] bytes) implements CustomPacketPayload {
@Override
public void write(FriendlyByteBuf buf) {
buf.writeBytes(bytes);
}
}

Datei anzeigen

@ -4,11 +4,12 @@ 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.kyori.adventure.text.Component;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import org.bukkit.craftbukkit.v1_20_R3.CraftWorld;
import org.bukkit.craftbukkit.CraftWorld;
import org.bukkit.entity.Player;
import org.bukkit.plugin.messaging.PluginMessageListener;
import org.jetbrains.annotations.NotNull;
@ -26,11 +27,15 @@ public class DeleteEntityPacketListener implements PluginMessageListener {
@Override
public void onPluginMessageReceived(@NotNull String channel, @NotNull Player player, @NotNull byte[] message) {
if (!this.plugin.canUseAxiom(player)) {
return;
try {
this.process(player, message);
} catch (Throwable t) {
player.kick(Component.text("Error while processing packet " + channel + ": " + t.getMessage()));
}
}
if (!player.hasPermission("axiom.entity.*") && !player.hasPermission("axiom.entity.delete")) {
private void process(Player player, byte[] message) {
if (!this.plugin.canUseAxiom(player, "axiom.entity.delete", true)) {
return;
}
@ -40,7 +45,7 @@ public class DeleteEntityPacketListener implements PluginMessageListener {
FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(message));
List<UUID> delete = friendlyByteBuf.readCollection(FriendlyByteBuf.limitValue(ArrayList::new, 1000),
FriendlyByteBuf::readUUID);
buf -> buf.readUUID());
ServerLevel serverLevel = ((CraftWorld)player.getWorld()).getHandle();

Datei anzeigen

@ -1,25 +1,29 @@
package com.moulberry.axiom.packet;
import com.google.common.util.concurrent.RateLimiter;
import com.moulberry.axiom.AxiomConstants;
import com.moulberry.axiom.AxiomPaper;
import com.moulberry.axiom.View;
import com.moulberry.axiom.WorldExtension;
import com.moulberry.axiom.*;
import com.moulberry.axiom.blueprint.ServerBlueprintManager;
import com.moulberry.axiom.event.AxiomHandshakeEvent;
import com.moulberry.axiom.persistence.ItemStackDataType;
import com.moulberry.axiom.persistence.UUIDDataType;
import com.moulberry.axiom.viaversion.ViaVersionHelper;
import com.moulberry.axiom.world_properties.server.ServerWorldPropertiesRegistry;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
import io.netty.buffer.Unpooled;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.minecraft.SharedConstants;
import net.minecraft.core.IdMapper;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.RegistryFriendlyByteBuf;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.level.block.state.BlockState;
import org.bukkit.Bukkit;
import org.bukkit.NamespacedKey;
import org.bukkit.World;
import org.bukkit.craftbukkit.v1_20_R3.entity.CraftPlayer;
import org.bukkit.craftbukkit.v1_20_R3.inventory.CraftItemStack;
import org.bukkit.craftbukkit.entity.CraftPlayer;
import org.bukkit.craftbukkit.inventory.CraftItemStack;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.persistence.PersistentDataContainer;
@ -28,7 +32,6 @@ import org.bukkit.plugin.messaging.PluginMessageListener;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.Set;
import java.util.UUID;
public class HelloPacketListener implements PluginMessageListener {
@ -41,6 +44,14 @@ public class HelloPacketListener implements PluginMessageListener {
@Override
public void onPluginMessageReceived(@NotNull String channel, @NotNull Player player, @NotNull byte[] message) {
try {
this.process(player, message);
} catch (Throwable t) {
player.kick(Component.text("Error while processing packet " + channel + ": " + t.getMessage()));
}
}
private void process(Player player, byte[] message) {
if (!this.plugin.hasAxiomPermission(player)) {
return;
}
@ -48,22 +59,71 @@ public class HelloPacketListener implements PluginMessageListener {
FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(message));
int apiVersion = friendlyByteBuf.readVarInt();
int dataVersion = friendlyByteBuf.readVarInt();
friendlyByteBuf.readNbt(); // Discard
// note - skipping NBT here. friendlyByteBuf.readNBT();
int serverDataVersion = SharedConstants.getCurrentVersion().getDataVersion().getVersion();
if (dataVersion != serverDataVersion) {
Component text = Component.text("Axiom: Incompatible data version detected (client " + dataVersion +
", server " + serverDataVersion + "), are you using ViaVersion?");
String incompatibleDataVersion = plugin.configuration.getString("incompatible-data-version");
if (incompatibleDataVersion == null) incompatibleDataVersion = "kick";
if (incompatibleDataVersion == null) incompatibleDataVersion = "warn";
Component incompatibleWarning = Component.text("Axiom: Incompatible data version detected (client " + dataVersion +
", server " + serverDataVersion + ")");
if (!Bukkit.getPluginManager().isPluginEnabled("ViaVersion")) {
if (incompatibleDataVersion.equals("warn")) {
player.sendMessage(text.color(NamedTextColor.RED));
player.sendMessage(incompatibleWarning.color(NamedTextColor.RED));
return;
} else if (!incompatibleDataVersion.equals("ignore")) {
player.kick(text);
player.kick(incompatibleWarning);
return;
}
} else {
int playerVersion = Via.getAPI().getPlayerVersion(player.getUniqueId());
if (playerVersion == SharedConstants.getProtocolVersion()) {
// Likely using via on the proxy, try to get protocol version from data version
if (dataVersion < 3337) {
player.sendMessage(incompatibleWarning.color(NamedTextColor.RED));
return;
} else if (dataVersion == 3337) {
playerVersion = 762; // 1.19.4
} else if (dataVersion <= 3465) {
playerVersion = 763; // 1.20.1
} else if (dataVersion <= 3578) {
playerVersion = 764; // 1.20.2
} else if (dataVersion <= 3700) {
playerVersion = 765; // 1.20.3 / 1.20.4
} else if (dataVersion <= 3837) {
playerVersion = 766; // 1.20.3 / 1.20.4
} else {
player.sendMessage(incompatibleWarning.color(NamedTextColor.RED));
return;
}
}
IdMapper<BlockState> mapper;
try {
mapper = ViaVersionHelper.getBlockRegistryForVersion(this.plugin.allowedBlockRegistry, playerVersion);
} catch (Exception e) {
String clientDescription = "client: " + ProtocolVersion.getProtocol(playerVersion);
String serverDescription = "server: " + ProtocolVersion.getProtocol(SharedConstants.getProtocolVersion());
String description = clientDescription + " <-> " + serverDescription;
Component text = Component.text("Axiom+ViaVersion: " + e.getMessage() + " (" + description + ")");
if (incompatibleDataVersion.equals("warn")) {
player.sendMessage(text.color(NamedTextColor.RED));
} else {
player.kick(text);
}
return;
}
this.plugin.playerBlockRegistry.put(player.getUniqueId(), mapper);
this.plugin.playerProtocolVersion.put(player.getUniqueId(), playerVersion);
Component text = Component.text("Axiom: Warning, client and server versions don't match. " +
"Axiom will try to use ViaVersion conversions, but this process may cause problems");
player.sendMessage(text.color(NamedTextColor.RED));
}
}
if (apiVersion != AxiomConstants.API_VERSION) {
@ -85,7 +145,7 @@ public class HelloPacketListener implements PluginMessageListener {
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 == null) unsupportedRestrictions = "warn";
if (unsupportedRestrictions.equals("warn")) {
player.sendMessage(text.color(NamedTextColor.RED));
return;
@ -110,7 +170,7 @@ public class HelloPacketListener implements PluginMessageListener {
}
// Enable
FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer());
RegistryFriendlyByteBuf buf = new RegistryFriendlyByteBuf(Unpooled.buffer(), MinecraftServer.getServer().registryAccess());
buf.writeBoolean(true);
buf.writeInt(handshakeEvent.getMaxBufferSize()); // Max Buffer Size
buf.writeBoolean(false); // No source info
@ -125,18 +185,19 @@ public class HelloPacketListener implements PluginMessageListener {
// Initialize Hotbars
PersistentDataContainer container = player.getPersistentDataContainer();
if (!this.plugin.isMismatchedDataVersion(player.getUniqueId())) {
int activeHotbarIndex = container.getOrDefault(AxiomConstants.ACTIVE_HOTBAR_INDEX, PersistentDataType.BYTE, (byte) 0);
PersistentDataContainer hotbarItems = container.get(AxiomConstants.HOTBAR_DATA, PersistentDataType.TAG_CONTAINER);
if (hotbarItems != null) {
buf = new FriendlyByteBuf(Unpooled.buffer());
buf = new RegistryFriendlyByteBuf(Unpooled.buffer(), MinecraftServer.getServer().registryAccess());
buf.writeByte((byte) activeHotbarIndex);
for (int i=0; i<9*9; i++) {
// Ignore selected hotbar
if (i / 9 == activeHotbarIndex) {
buf.writeItem(net.minecraft.world.item.ItemStack.EMPTY);
net.minecraft.world.item.ItemStack.OPTIONAL_STREAM_CODEC.encode(buf, net.minecraft.world.item.ItemStack.EMPTY);
} else {
ItemStack stack = hotbarItems.get(new NamespacedKey("axiom", "slot_"+i), ItemStackDataType.INSTANCE);
buf.writeItem(CraftItemStack.asNMSCopy(stack));
net.minecraft.world.item.ItemStack.OPTIONAL_STREAM_CODEC.encode(buf, CraftItemStack.asNMSCopy(stack));
}
}
@ -144,11 +205,12 @@ public class HelloPacketListener implements PluginMessageListener {
buf.getBytes(0, bytes);
player.sendPluginMessage(this.plugin, "axiom:initialize_hotbars", bytes);
}
}
// Initialize Views
UUID activeView = container.get(AxiomConstants.ACTIVE_VIEW, UUIDDataType.INSTANCE);
if (activeView != null) {
buf = new FriendlyByteBuf(Unpooled.buffer());
buf = new RegistryFriendlyByteBuf(Unpooled.buffer(), MinecraftServer.getServer().registryAccess());
buf.writeUUID(activeView);
PersistentDataContainer[] views = container.get(AxiomConstants.VIEWS, PersistentDataType.TAG_CONTAINER_ARRAY);

Datei anzeigen

@ -4,7 +4,11 @@ import com.moulberry.axiom.AxiomPaper;
import com.moulberry.axiom.NbtSanitization;
import com.moulberry.axiom.event.AxiomManipulateEntityEvent;
import com.moulberry.axiom.integration.Integration;
import com.moulberry.axiom.integration.plotsquared.PlotSquaredIntegration;
import com.moulberry.axiom.viaversion.UnknownVersionHelper;
import com.moulberry.axiom.viaversion.ViaVersionHelper;
import io.netty.buffer.Unpooled;
import net.kyori.adventure.text.Component;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
@ -19,7 +23,7 @@ import net.minecraft.world.entity.decoration.ItemFrame;
import net.minecraft.world.level.block.Rotation;
import net.minecraft.world.phys.Vec3;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_20_R3.CraftWorld;
import org.bukkit.craftbukkit.CraftWorld;
import org.bukkit.entity.Player;
import org.bukkit.plugin.messaging.PluginMessageListener;
import org.jetbrains.annotations.NotNull;
@ -46,7 +50,7 @@ public class ManipulateEntityPacketListener implements PluginMessageListener {
public record ManipulateEntry(UUID uuid, @Nullable Set<RelativeMovement> relativeMovementSet, @Nullable Vec3 position,
float yaw, float pitch, CompoundTag merge, PassengerManipulation passengerManipulation, List<UUID> passengers) {
public static ManipulateEntry read(FriendlyByteBuf friendlyByteBuf) {
public static ManipulateEntry read(FriendlyByteBuf friendlyByteBuf, Player player) {
UUID uuid = friendlyByteBuf.readUUID();
int flags = friendlyByteBuf.readByte();
@ -61,13 +65,13 @@ public class ManipulateEntityPacketListener implements PluginMessageListener {
pitch = friendlyByteBuf.readFloat();
}
CompoundTag nbt = friendlyByteBuf.readNbt();
CompoundTag nbt = UnknownVersionHelper.readTagUnknown(friendlyByteBuf, player);
PassengerManipulation passengerManipulation = friendlyByteBuf.readEnum(PassengerManipulation.class);
List<UUID> passengers = List.of();
if (passengerManipulation == PassengerManipulation.ADD_LIST || passengerManipulation == PassengerManipulation.REMOVE_LIST) {
passengers = friendlyByteBuf.readCollection(FriendlyByteBuf.limitValue(ArrayList::new, 1000),
FriendlyByteBuf::readUUID);
buffer -> buffer.readUUID());
}
return new ManipulateEntry(uuid, relativeMovementSet, position, yaw, pitch, nbt,
@ -79,11 +83,15 @@ public class ManipulateEntityPacketListener implements PluginMessageListener {
@Override
public void onPluginMessageReceived(@NotNull String channel, @NotNull Player player, @NotNull byte[] message) {
if (!this.plugin.canUseAxiom(player)) {
return;
try {
this.process(player, message);
} catch (Throwable t) {
player.kick(Component.text("Error while processing packet " + channel + ": " + t.getMessage()));
}
}
if (!player.hasPermission("axiom.entity.*") && !player.hasPermission("axiom.entity.manipulate")) {
private void process(Player player, byte[] message) {
if (!this.plugin.canUseAxiom(player, "axiom.entity.manipulate", true)) {
return;
}
@ -93,7 +101,7 @@ public class ManipulateEntityPacketListener implements PluginMessageListener {
FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(message));
List<ManipulateEntry> entries = friendlyByteBuf.readCollection(FriendlyByteBuf.limitValue(ArrayList::new, 1000),
ManipulateEntry::read);
buf -> ManipulateEntry.read(buf, player));
ServerLevel serverLevel = ((CraftWorld)player.getWorld()).getHandle();

Datei anzeigen

@ -3,12 +3,13 @@ package com.moulberry.axiom.packet;
import com.moulberry.axiom.AxiomPaper;
import com.moulberry.axiom.marker.MarkerData;
import io.netty.buffer.Unpooled;
import net.kyori.adventure.text.Component;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.Marker;
import org.bukkit.craftbukkit.v1_20_R3.CraftWorld;
import org.bukkit.craftbukkit.CraftWorld;
import org.bukkit.entity.Player;
import org.bukkit.plugin.messaging.PluginMessageListener;
import org.jetbrains.annotations.NotNull;
@ -24,11 +25,15 @@ public class MarkerNbtRequestPacketListener implements PluginMessageListener {
@Override
public void onPluginMessageReceived(@NotNull String channel, @NotNull Player player, @NotNull byte[] message) {
if (!this.plugin.canUseAxiom(player)) {
return;
try {
this.process(player, message);
} catch (Throwable t) {
player.kick(Component.text("Error while processing packet " + channel + ": " + t.getMessage()));
}
}
if (!player.hasPermission("axiom.entity.*") && !player.hasPermission("axiom.entity.manipulate")) {
private void process(Player player, byte[] message) {
if (!this.plugin.canUseAxiom(player, "axiom.entity.manipulate", true)) {
return;
}

Datei anzeigen

@ -5,8 +5,10 @@ import com.moulberry.axiom.AxiomPaper;
import com.moulberry.axiom.VersionHelper;
import com.moulberry.axiom.buffer.CompressedBlockEntity;
import com.moulberry.axiom.integration.plotsquared.PlotSquaredIntegration;
import com.viaversion.viaversion.api.Via;
import io.netty.buffer.Unpooled;
import it.unimi.dsi.fastutil.longs.*;
import net.kyori.adventure.text.Component;
import net.minecraft.core.BlockPos;
import net.minecraft.core.registries.Registries;
import net.minecraft.nbt.CompoundTag;
@ -20,11 +22,11 @@ import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.chunk.ChunkStatus;
import net.minecraft.world.level.chunk.status.ChunkStatus;
import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.chunk.LevelChunkSection;
import net.minecraft.world.level.chunk.PalettedContainer;
import org.bukkit.craftbukkit.v1_20_R3.entity.CraftPlayer;
import org.bukkit.craftbukkit.entity.CraftPlayer;
import org.bukkit.entity.Player;
import org.bukkit.plugin.messaging.PluginMessageListener;
import org.jetbrains.annotations.NotNull;
@ -41,12 +43,20 @@ public class RequestChunkDataPacketListener implements PluginMessageListener {
}
@Override
public void onPluginMessageReceived(@NotNull String channel, @NotNull Player bukkitPlayer, @NotNull byte[] message) {
public void onPluginMessageReceived(@NotNull String channel, @NotNull Player player, @NotNull byte[] message) {
try {
this.process(player, message);
} catch (Throwable t) {
player.kick(Component.text("Error while processing packet " + channel + ": " + t.getMessage()));
}
}
private void process(Player bukkitPlayer, byte[] message) {
ServerPlayer player = ((CraftPlayer)bukkitPlayer).getHandle();
FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(message));
long id = friendlyByteBuf.readLong();
if (!this.plugin.canUseAxiom(bukkitPlayer)) {
if (!this.plugin.canUseAxiom(bukkitPlayer, "axiom.chunk.request") || this.plugin.isMismatchedDataVersion(bukkitPlayer.getUniqueId())) {
// We always send an 'empty' response in order to make the client happy
sendEmptyResponse(player, id);
return;
@ -105,7 +115,7 @@ public class RequestChunkDataPacketListener implements PluginMessageListener {
BlockEntity blockEntity = chunk.getBlockEntity(mutableBlockPos, LevelChunk.EntityCreationType.IMMEDIATE);
if (blockEntity != null) {
CompoundTag tag = blockEntity.saveWithoutMetadata();
CompoundTag tag = blockEntity.saveWithoutMetadata(player.registryAccess());
blockEntityMap.put(pos, CompressedBlockEntity.compress(tag, baos));
}
}
@ -144,7 +154,7 @@ public class RequestChunkDataPacketListener implements PluginMessageListener {
mutableBlockPos.set(sx*16 + x, sy*16 + y, sz*16 + z);
BlockEntity blockEntity = chunk.getBlockEntity(mutableBlockPos, LevelChunk.EntityCreationType.CHECK);
if (blockEntity != null) {
CompoundTag tag = blockEntity.saveWithoutMetadata();
CompoundTag tag = blockEntity.saveWithoutMetadata(player.registryAccess());
blockEntityMap.put(mutableBlockPos.asLong(), CompressedBlockEntity.compress(tag, baos));
}
}

Datei anzeigen

@ -8,7 +8,8 @@ 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 com.moulberry.axiom.integration.coreprotect.CoreProtectIntegration;
import com.moulberry.axiom.viaversion.UnknownVersionHelper;
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
import it.unimi.dsi.fastutil.shorts.Short2ObjectMap;
import net.minecraft.ChatFormatting;
@ -33,7 +34,7 @@ import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.EntityBlock;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.chunk.ChunkStatus;
import net.minecraft.world.level.chunk.status.ChunkStatus;
import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.chunk.LevelChunkSection;
import net.minecraft.world.level.chunk.PalettedContainer;
@ -77,7 +78,7 @@ public class SetBlockBufferPacketListener {
boolean continuation = friendlyByteBuf.readBoolean();
if (!continuation) {
friendlyByteBuf.readNbt(); // Discard sourceInfo
UnknownVersionHelper.skipTagUnknown(friendlyByteBuf, player.getBukkitEntity());
}
RateLimiter rateLimiter = this.plugin.getBlockBufferRateLimiter(player.getUUID());
@ -85,7 +86,7 @@ public class SetBlockBufferPacketListener {
byte type = friendlyByteBuf.readByte();
if (type == 0) {
AtomicBoolean reachedRateLimit = new AtomicBoolean(false);
BlockBuffer buffer = BlockBuffer.load(friendlyByteBuf, rateLimiter, reachedRateLimit);
BlockBuffer buffer = BlockBuffer.load(friendlyByteBuf, rateLimiter, reachedRateLimit, this.plugin.getBlockRegistry(player.getUUID()));
if (reachedRateLimit.get()) {
player.sendSystemMessage(Component.literal("[Axiom] Exceeded server rate-limit of " + (int)rateLimiter.getRate() + " sections per second")
.withStyle(ChatFormatting.RED));
@ -124,7 +125,7 @@ public class SetBlockBufferPacketListener {
ServerLevel world = player.serverLevel();
if (!world.dimension().equals(worldKey)) return;
if (!this.plugin.canUseAxiom(player.getBukkitEntity())) {
if (!this.plugin.canUseAxiom(player.getBukkitEntity(), "axiom.build.section")) {
return;
}
@ -281,12 +282,20 @@ public class SetBlockBufferPacketListener {
int key = x | (y << 4) | (z << 8);
CompressedBlockEntity savedBlockEntity = blockEntityChunkMap.get((short) key);
if (savedBlockEntity != null) {
blockEntity.load(savedBlockEntity.decompress());
blockEntity.loadWithComponents(savedBlockEntity.decompress(), player.registryAccess());
}
}
} else if (old.hasBlockEntity()) {
chunk.removeBlockEntity(blockPos);
}
if (CoreProtectIntegration.isEnabled() && old != blockState) {
String changedBy = player.getBukkitEntity().getName();
BlockPos changedPos = new BlockPos(bx, by, bz);
CoreProtectIntegration.logRemoval(changedBy, old, world.getWorld(), changedPos);
CoreProtectIntegration.logPlacement(changedBy, blockState, world.getWorld(), changedPos);
}
}
}
}
@ -316,7 +325,7 @@ public class SetBlockBufferPacketListener {
ServerLevel world = player.serverLevel();
if (!world.dimension().equals(worldKey)) return;
if (!this.plugin.canUseAxiom(player.getBukkitEntity())) {
if (!this.plugin.canUseAxiom(player.getBukkitEntity(), "axiom.build.section")) {
return;
}
@ -340,16 +349,16 @@ public class SetBlockBufferPacketListener {
return;
}
var holder = registry.getHolder(biome);
if (holder.isPresent()) {
var chunk = (LevelChunk) world.getChunk(x >> 2, z >> 2, ChunkStatus.FULL, false);
if (chunk == null) return;
var section = chunk.getSection(cy - minSection);
PalettedContainer<Holder<Biome>> container = (PalettedContainer<Holder<Biome>>) section.getBiomes();
var holder = registry.getHolder(biome);
if (holder.isPresent()) {
if (!Integration.canPlaceBlock(player.getBukkitEntity(),
new Location(player.getBukkitEntity().getWorld(), x+1, y+1, z+1))) return;
new Location(player.getBukkitEntity().getWorld(), (x<<2)+1, (y<<2)+1, (z<<2)+1))) return;
container.set(x & 3, y & 3, z & 3, holder.get());
changedChunks.add(chunk);

Datei anzeigen

@ -3,10 +3,13 @@ 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.coreprotect.CoreProtectIntegration;
import com.moulberry.axiom.integration.plotsquared.PlotSquaredIntegration;
import io.netty.buffer.Unpooled;
import net.kyori.adventure.text.Component;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Holder;
import net.minecraft.core.IdMapper;
import net.minecraft.core.SectionPos;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.server.level.ServerLevel;
@ -29,9 +32,9 @@ import net.minecraft.world.phys.HitResult;
import net.minecraft.world.phys.Vec3;
import org.bukkit.Location;
import org.bukkit.block.BlockFace;
import org.bukkit.craftbukkit.v1_20_R3.CraftWorld;
import org.bukkit.craftbukkit.v1_20_R3.block.CraftBlock;
import org.bukkit.craftbukkit.v1_20_R3.entity.CraftPlayer;
import org.bukkit.craftbukkit.CraftWorld;
import org.bukkit.craftbukkit.block.CraftBlock;
import org.bukkit.craftbukkit.entity.CraftPlayer;
import org.bukkit.entity.Player;
import org.bukkit.event.block.Action;
import org.bukkit.event.player.PlayerInteractEvent;
@ -67,8 +70,16 @@ public class SetBlockPacketListener implements PluginMessageListener {
}
@Override
public void onPluginMessageReceived(@NotNull String channel, @NotNull Player bukkitPlayer, @NotNull byte[] message) {
if (!this.plugin.canUseAxiom(bukkitPlayer)) {
public void onPluginMessageReceived(@NotNull String channel, @NotNull Player player, @NotNull byte[] message) {
try {
this.process(player, message);
} catch (Throwable t) {
player.kick(Component.text("Error while processing packet " + channel + ": " + t.getMessage()));
}
}
private void process(Player bukkitPlayer, byte[] message) {
if (!this.plugin.canUseAxiom(bukkitPlayer, "axiom.build.place")) {
return;
}
@ -79,8 +90,9 @@ public class SetBlockPacketListener implements PluginMessageListener {
// Read packet
FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(message));
IntFunction<Map<BlockPos, BlockState>> mapFunction = FriendlyByteBuf.limitValue(Maps::newLinkedHashMapWithExpectedSize, 512);
IdMapper<BlockState> registry = this.plugin.getBlockRegistry(bukkitPlayer.getUniqueId());
Map<BlockPos, BlockState> blocks = friendlyByteBuf.readMap(mapFunction,
FriendlyByteBuf::readBlockPos, buf -> buf.readById(this.plugin.allowedBlockRegistry));
buf -> buf.readBlockPos(), buf -> buf.readById(registry::byIdOrThrow));
boolean updateNeighbors = friendlyByteBuf.readBoolean();
int reason = friendlyByteBuf.readVarInt();
@ -129,6 +141,10 @@ public class SetBlockPacketListener implements PluginMessageListener {
BlockPos blockPos = entry.getKey();
BlockState blockState = entry.getValue();
if (blockState == null) {
continue;
}
// Disallow in unloaded chunks
if (!player.level().isLoaded(blockPos)) {
continue;
@ -143,8 +159,14 @@ public class SetBlockPacketListener implements PluginMessageListener {
continue;
}
if (CoreProtectIntegration.isEnabled()) {
BlockState old = player.level().getBlockState(blockPos);
CoreProtectIntegration.logRemoval(bukkitPlayer.getName(), old, world, blockPos);
}
// Place block
player.level().setBlock(blockPos, blockState, 3);
CoreProtectIntegration.logPlacement(bukkitPlayer.getName(), blockState, world, blockPos);
}
} else {
int count = 0;
@ -154,6 +176,10 @@ public class SetBlockPacketListener implements PluginMessageListener {
BlockPos blockPos = entry.getKey();
BlockState blockState = entry.getValue();
if (blockState == null) {
continue;
}
// Disallow in unloaded chunks
if (!player.level().isLoaded(blockPos)) {
continue;
@ -258,6 +284,14 @@ public class SetBlockPacketListener implements PluginMessageListener {
if (oldPoi.isPresent()) level.getPoiManager().remove(blockPos);
if (newPoi.isPresent()) level.getPoiManager().add(blockPos, newPoi.get());
}
if (CoreProtectIntegration.isEnabled()) {
String changedBy = player.getBukkitEntity().getName();
BlockPos changedPos = new BlockPos(bx, by, bz);
CoreProtectIntegration.logRemoval(changedBy, old, world, changedPos);
CoreProtectIntegration.logPlacement(changedBy, blockState, world, changedPos);
}
}
boolean nowHasOnlyAir = section.hasOnlyAir();

Datei anzeigen

@ -6,6 +6,7 @@ import com.moulberry.axiom.AxiomPaper;
import com.moulberry.axiom.View;
import com.moulberry.axiom.persistence.UUIDDataType;
import io.netty.buffer.Unpooled;
import net.kyori.adventure.text.Component;
import net.minecraft.network.FriendlyByteBuf;
import org.bukkit.entity.Player;
import org.bukkit.persistence.PersistentDataContainer;
@ -26,7 +27,15 @@ public class SetEditorViewsPacketListener implements PluginMessageListener {
@Override
public void onPluginMessageReceived(@NotNull String channel, @NotNull Player player, @NotNull byte[] message) {
if (!this.plugin.canUseAxiom(player)) {
try {
this.process(player, message);
} catch (Throwable t) {
player.kick(Component.text("Error while processing packet " + channel + ": " + t.getMessage()));
}
}
private void process(Player player, byte[] message) {
if (!this.plugin.canUseAxiom(player, "axiom.editor.views")) {
return;
}

Datei anzeigen

@ -3,9 +3,10 @@ package com.moulberry.axiom.packet;
import com.moulberry.axiom.AxiomPaper;
import com.moulberry.axiom.event.AxiomFlySpeedChangeEvent;
import io.netty.buffer.Unpooled;
import net.kyori.adventure.text.Component;
import net.minecraft.network.FriendlyByteBuf;
import org.bukkit.Bukkit;
import org.bukkit.craftbukkit.v1_20_R3.entity.CraftPlayer;
import org.bukkit.craftbukkit.entity.CraftPlayer;
import org.bukkit.entity.Player;
import org.bukkit.plugin.messaging.PluginMessageListener;
import org.jetbrains.annotations.NotNull;
@ -19,7 +20,15 @@ public class SetFlySpeedPacketListener implements PluginMessageListener {
@Override
public void onPluginMessageReceived(@NotNull String channel, @NotNull Player player, @NotNull byte[] message) {
if (!this.plugin.canUseAxiom(player)) {
try {
this.process(player, message);
} catch (Throwable t) {
player.kick(Component.text("Error while processing packet " + channel + ": " + t.getMessage()));
}
}
private void process(Player player, byte[] message) {
if (!this.plugin.canUseAxiom(player, "axiom.player.speed")) {
return;
}

Datei anzeigen

@ -3,11 +3,12 @@ package com.moulberry.axiom.packet;
import com.moulberry.axiom.AxiomPaper;
import com.moulberry.axiom.event.AxiomGameModeChangeEvent;
import io.netty.buffer.Unpooled;
import net.kyori.adventure.text.Component;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.world.level.GameType;
import org.bukkit.Bukkit;
import org.bukkit.GameMode;
import org.bukkit.craftbukkit.v1_20_R3.entity.CraftPlayer;
import org.bukkit.craftbukkit.entity.CraftPlayer;
import org.bukkit.entity.Player;
import org.bukkit.plugin.messaging.PluginMessageListener;
import org.jetbrains.annotations.NotNull;
@ -21,7 +22,15 @@ public class SetGamemodePacketListener implements PluginMessageListener {
@Override
public void onPluginMessageReceived(@NotNull String channel, @NotNull Player player, @NotNull byte[] message) {
if (!this.plugin.canUseAxiom(player)) {
try {
this.process(player, message);
} catch (Throwable t) {
player.kick(Component.text("Error while processing packet " + channel + ": " + t.getMessage()));
}
}
private void process(Player player, byte[] message) {
if (!this.plugin.canUseAxiom(player, "axiom.player.gamemode")) {
return;
}

Datei anzeigen

@ -3,10 +3,15 @@ package com.moulberry.axiom.packet;
import com.moulberry.axiom.AxiomConstants;
import com.moulberry.axiom.AxiomPaper;
import com.moulberry.axiom.persistence.ItemStackDataType;
import com.viaversion.viaversion.api.Via;
import io.netty.buffer.Unpooled;
import net.kyori.adventure.text.Component;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.RegistryFriendlyByteBuf;
import net.minecraft.world.item.ItemStack;
import org.bukkit.NamespacedKey;
import org.bukkit.craftbukkit.v1_20_R3.inventory.CraftItemStack;
import org.bukkit.craftbukkit.entity.CraftPlayer;
import org.bukkit.craftbukkit.inventory.CraftItemStack;
import org.bukkit.entity.Player;
import org.bukkit.persistence.PersistentDataContainer;
import org.bukkit.persistence.PersistentDataType;
@ -22,14 +27,22 @@ public class SetHotbarSlotPacketListener implements PluginMessageListener {
@Override
public void onPluginMessageReceived(@NotNull String channel, @NotNull Player player, @NotNull byte[] message) {
if (!this.plugin.canUseAxiom(player)) {
try {
this.process(player, message);
} catch (Throwable t) {
player.kick(Component.text("Error while processing packet " + channel + ": " + t.getMessage()));
}
}
private void process(Player player, byte[] message) {
if (!this.plugin.canUseAxiom(player, "axiom.player.hotbar") || this.plugin.isMismatchedDataVersion(player.getUniqueId())) {
return;
}
FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(message));
RegistryFriendlyByteBuf friendlyByteBuf = new RegistryFriendlyByteBuf(Unpooled.wrappedBuffer(message), ((CraftPlayer)player).getHandle().registryAccess());
int index = friendlyByteBuf.readByte();
if (index < 0 || index >= 9*9) return;
net.minecraft.world.item.ItemStack nmsStack = friendlyByteBuf.readItem();
net.minecraft.world.item.ItemStack nmsStack = ItemStack.OPTIONAL_STREAM_CODEC.decode(friendlyByteBuf);
PersistentDataContainer container = player.getPersistentDataContainer();
PersistentDataContainer hotbarItems = container.get(AxiomConstants.HOTBAR_DATA, PersistentDataType.TAG_CONTAINER);

Datei anzeigen

@ -4,6 +4,7 @@ import com.moulberry.axiom.AxiomPaper;
import com.moulberry.axiom.event.AxiomTimeChangeEvent;
import com.moulberry.axiom.integration.plotsquared.PlotSquaredIntegration;
import io.netty.buffer.Unpooled;
import net.kyori.adventure.text.Component;
import net.minecraft.core.registries.Registries;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceKey;
@ -11,7 +12,7 @@ import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.GameRules;
import net.minecraft.world.level.Level;
import org.bukkit.Bukkit;
import org.bukkit.craftbukkit.v1_20_R3.CraftWorld;
import org.bukkit.craftbukkit.CraftWorld;
import org.bukkit.entity.Player;
import org.bukkit.plugin.messaging.PluginMessageListener;
import org.jetbrains.annotations.NotNull;
@ -25,7 +26,15 @@ public class SetTimePacketListener implements PluginMessageListener {
@Override
public void onPluginMessageReceived(@NotNull String channel, @NotNull Player player, @NotNull byte[] message) {
if (!this.plugin.canUseAxiom(player)) {
try {
this.process(player, message);
} catch (Throwable t) {
player.kick(Component.text("Error while processing packet " + channel + ": " + t.getMessage()));
}
}
private void process(Player player, byte[] message) {
if (!this.plugin.canUseAxiom(player, "axiom.world.time")) {
return;
}

Datei anzeigen

@ -5,6 +5,7 @@ import com.moulberry.axiom.integration.plotsquared.PlotSquaredIntegration;
import com.moulberry.axiom.world_properties.server.ServerWorldPropertiesRegistry;
import com.moulberry.axiom.world_properties.server.ServerWorldPropertyHolder;
import io.netty.buffer.Unpooled;
import net.kyori.adventure.text.Component;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation;
import org.bukkit.entity.Player;
@ -20,7 +21,15 @@ public class SetWorldPropertyListener implements PluginMessageListener {
@Override
public void onPluginMessageReceived(@NotNull String channel, @NotNull Player player, @NotNull byte[] message) {
if (!this.plugin.canUseAxiom(player)) {
try {
this.process(player, message);
} catch (Throwable t) {
player.kick(Component.text("Error while processing packet " + channel + ": " + t.getMessage()));
}
}
private void process(Player player, byte[] message) {
if (!this.plugin.canUseAxiom(player, "axiom.world.property")) {
return;
}

Datei anzeigen

@ -4,7 +4,10 @@ import com.moulberry.axiom.AxiomPaper;
import com.moulberry.axiom.NbtSanitization;
import com.moulberry.axiom.integration.Integration;
import com.moulberry.axiom.integration.plotsquared.PlotSquaredIntegration;
import com.moulberry.axiom.viaversion.UnknownVersionHelper;
import com.moulberry.axiom.viaversion.ViaVersionHelper;
import io.netty.buffer.Unpooled;
import net.kyori.adventure.text.Component;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
@ -18,7 +21,7 @@ import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Rotation;
import net.minecraft.world.phys.Vec3;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_20_R3.CraftWorld;
import org.bukkit.craftbukkit.CraftWorld;
import org.bukkit.entity.Player;
import org.bukkit.plugin.messaging.PluginMessageListener;
import org.jetbrains.annotations.NotNull;
@ -38,22 +41,21 @@ public class SpawnEntityPacketListener implements PluginMessageListener {
private record SpawnEntry(UUID newUuid, double x, double y, double z, float yaw, float pitch,
@Nullable UUID copyFrom, CompoundTag tag) {
public SpawnEntry(FriendlyByteBuf friendlyByteBuf) {
this(friendlyByteBuf.readUUID(), friendlyByteBuf.readDouble(), friendlyByteBuf.readDouble(),
friendlyByteBuf.readDouble(), friendlyByteBuf.readFloat(), friendlyByteBuf.readFloat(),
friendlyByteBuf.readNullable(FriendlyByteBuf::readUUID), friendlyByteBuf.readNbt());
}
}
private static final Rotation[] ROTATION_VALUES = Rotation.values();
@Override
public void onPluginMessageReceived(@NotNull String channel, @NotNull Player player, @NotNull byte[] message) {
if (!this.plugin.canUseAxiom(player)) {
return;
try {
this.process(player, message);
} catch (Throwable t) {
player.kick(Component.text("Error while processing packet " + channel + ": " + t.getMessage()));
}
}
if (!player.hasPermission("axiom.entity.*") && !player.hasPermission("axiom.entity.spawn")) {
private void process(Player player, byte[] message) {
if (!this.plugin.canUseAxiom(player, "axiom.entity.spawn", true)) {
return;
}
@ -62,7 +64,10 @@ public class SpawnEntityPacketListener implements PluginMessageListener {
}
FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(message));
List<SpawnEntry> entries = friendlyByteBuf.readCollection(FriendlyByteBuf.limitValue(ArrayList::new, 1000), SpawnEntry::new);
List<SpawnEntry> entries = friendlyByteBuf.readCollection(FriendlyByteBuf.limitValue(ArrayList::new, 1000),
buf -> new SpawnEntry(buf.readUUID(), buf.readDouble(), buf.readDouble(),
buf.readDouble(), buf.readFloat(), buf.readFloat(),
buf.readNullable(buffer -> buffer.readUUID()), UnknownVersionHelper.readTagUnknown(buf, player)));
ServerLevel serverLevel = ((CraftWorld)player.getWorld()).getHandle();

Datei anzeigen

@ -4,11 +4,14 @@ import com.moulberry.axiom.AxiomConstants;
import com.moulberry.axiom.AxiomPaper;
import com.moulberry.axiom.persistence.ItemStackDataType;
import io.netty.buffer.Unpooled;
import net.kyori.adventure.text.Component;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.RegistryFriendlyByteBuf;
import org.bukkit.GameMode;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.craftbukkit.v1_20_R3.inventory.CraftItemStack;
import org.bukkit.craftbukkit.entity.CraftPlayer;
import org.bukkit.craftbukkit.inventory.CraftItemStack;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.persistence.PersistentDataContainer;
@ -25,17 +28,25 @@ public class SwitchActiveHotbarPacketListener implements PluginMessageListener {
@Override
public void onPluginMessageReceived(@NotNull String channel, @NotNull Player player, @NotNull byte[] message) {
if (!this.plugin.canUseAxiom(player)) {
try {
this.process(player, message);
} catch (Throwable t) {
player.kick(Component.text("Error while processing packet " + channel + ": " + t.getMessage()));
}
}
private void process(Player player, byte[] message) {
if (!this.plugin.canUseAxiom(player, "axiom.player.hotbar") || this.plugin.isMismatchedDataVersion(player.getUniqueId())) {
return;
}
FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(message));
RegistryFriendlyByteBuf friendlyByteBuf = new RegistryFriendlyByteBuf(Unpooled.wrappedBuffer(message), ((CraftPlayer)player).getHandle().registryAccess());
int oldHotbarIndex = friendlyByteBuf.readByte();
int activeHotbarIndex = friendlyByteBuf.readByte();
ItemStack[] hotbarItems = new ItemStack[9];
for (int i=0; i<9; i++) {
hotbarItems[i] = CraftItemStack.asCraftMirror(friendlyByteBuf.readItem());
hotbarItems[i] = CraftItemStack.asCraftMirror(net.minecraft.world.item.ItemStack.OPTIONAL_STREAM_CODEC.decode(friendlyByteBuf));
}
PersistentDataContainer container = player.getPersistentDataContainer();

Datei anzeigen

@ -4,13 +4,14 @@ import com.moulberry.axiom.AxiomPaper;
import com.moulberry.axiom.event.AxiomUnknownTeleportEvent;
import com.moulberry.axiom.event.AxiomTeleportEvent;
import io.netty.buffer.Unpooled;
import net.kyori.adventure.text.Component;
import net.minecraft.core.registries.Registries;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceKey;
import net.minecraft.world.level.Level;
import org.bukkit.*;
import org.bukkit.craftbukkit.v1_20_R3.entity.CraftPlayer;
import org.bukkit.craftbukkit.v1_20_R3.util.CraftNamespacedKey;
import org.bukkit.craftbukkit.entity.CraftPlayer;
import org.bukkit.craftbukkit.util.CraftNamespacedKey;
import org.bukkit.entity.Player;
import org.bukkit.plugin.messaging.PluginMessageListener;
import org.jetbrains.annotations.NotNull;
@ -24,7 +25,15 @@ public class TeleportPacketListener implements PluginMessageListener {
@Override
public void onPluginMessageReceived(@NotNull String channel, @NotNull Player player, @NotNull byte[] message) {
if (!this.plugin.canUseAxiom(player)) {
try {
this.process(player, message);
} catch (Throwable t) {
player.kick(Component.text("Error while processing packet " + channel + ": " + t.getMessage()));
}
}
private void process(Player player, byte[] message) {
if (!this.plugin.canUseAxiom(player, "axiom.world.teleport")) {
return;
}

Datei anzeigen

@ -5,7 +5,9 @@ import com.moulberry.axiom.blueprint.BlueprintIo;
import com.moulberry.axiom.blueprint.RawBlueprint;
import com.moulberry.axiom.blueprint.ServerBlueprintManager;
import com.moulberry.axiom.blueprint.ServerBlueprintRegistry;
import net.minecraft.SharedConstants;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerPlayer;
import java.io.BufferedOutputStream;
@ -22,7 +24,12 @@ public class UploadBlueprintPacketListener {
}
public void onReceive(ServerPlayer serverPlayer, FriendlyByteBuf friendlyByteBuf) {
if (!this.plugin.canUseAxiom(serverPlayer.getBukkitEntity())) {
if (!this.plugin.canUseAxiom(serverPlayer.getBukkitEntity(), "axiom.blueprint.upload")) {
return;
}
if (this.plugin.isMismatchedDataVersion(serverPlayer.getUUID())) {
serverPlayer.sendSystemMessage(Component.literal("Axiom+ViaVersion: This feature isn't supported. Switch your client version to " + SharedConstants.VERSION_STRING + " to use this"));
return;
}
@ -47,6 +54,10 @@ public class UploadBlueprintPacketListener {
return;
}
String pathName = pathStr.substring(0, pathStr.length()-3);
serverPlayer.getServer().execute(() -> {
try {
Path path = this.plugin.blueprintFolder.resolve(relative);
// Write file
@ -62,10 +73,15 @@ public class UploadBlueprintPacketListener {
}
// Update registry
registry.blueprints().put("/" + pathStr.substring(0, pathStr.length()-3), rawBlueprint);
registry.blueprints().put("/" + pathName, rawBlueprint);
// Resend manifest
ServerBlueprintManager.sendManifest(serverPlayer.getServer().getPlayerList().getPlayers());
} catch (Throwable t) {
serverPlayer.getBukkitEntity().kick(net.kyori.adventure.text.Component.text(
"An error occured while uploading blueprint: " + t.getMessage()));
}
});
}
}

Datei anzeigen

@ -1,8 +1,9 @@
package com.moulberry.axiom.persistence;
import net.minecraft.nbt.CompoundTag;
import org.bukkit.craftbukkit.v1_20_R3.inventory.CraftItemStack;
import org.bukkit.craftbukkit.v1_20_R3.persistence.CraftPersistentDataContainer;
import net.minecraft.server.MinecraftServer;
import org.bukkit.craftbukkit.inventory.CraftItemStack;
import org.bukkit.craftbukkit.persistence.CraftPersistentDataContainer;
import org.bukkit.inventory.ItemStack;
import org.bukkit.persistence.PersistentDataAdapterContext;
import org.bukkit.persistence.PersistentDataContainer;
@ -28,8 +29,7 @@ public class ItemStackDataType implements PersistentDataType<PersistentDataConta
public @NotNull PersistentDataContainer toPrimitive(@NotNull ItemStack complex, @NotNull PersistentDataAdapterContext context) {
net.minecraft.world.item.ItemStack nmsStack = CraftItemStack.asNMSCopy(complex);
if (nmsStack == null) nmsStack = net.minecraft.world.item.ItemStack.EMPTY;
CompoundTag tag = new CompoundTag();
nmsStack.save(tag);
CompoundTag tag = (CompoundTag) nmsStack.save(MinecraftServer.getServer().registryAccess());
PersistentDataContainer container = context.newPersistentDataContainer();
((CraftPersistentDataContainer)container).putAll(tag);
@ -39,7 +39,7 @@ public class ItemStackDataType implements PersistentDataType<PersistentDataConta
@Override
public @NotNull ItemStack fromPrimitive(@NotNull PersistentDataContainer primitive, @NotNull PersistentDataAdapterContext context) {
CompoundTag tag = ((CraftPersistentDataContainer)primitive).toTagCompound();
net.minecraft.world.item.ItemStack nmsStack = net.minecraft.world.item.ItemStack.of(tag);
net.minecraft.world.item.ItemStack nmsStack = net.minecraft.world.item.ItemStack.parseOptional(MinecraftServer.getServer().registryAccess(), tag);
return CraftItemStack.asCraftMirror(nmsStack);
}

Datei anzeigen

@ -0,0 +1,34 @@
package com.moulberry.axiom.viaversion;
import com.moulberry.axiom.AxiomPaper;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.FriendlyByteBuf;
import org.bukkit.entity.Player;
public class UnknownVersionHelper {
public static void skipTagUnknown(FriendlyByteBuf friendlyByteBuf, Player player) {
if (AxiomPaper.PLUGIN.isMismatchedDataVersion(player.getUniqueId())) {
try {
ViaVersionHelper.skipTagViaVersion(friendlyByteBuf, player);
} catch (Exception e) {
throw new RuntimeException(e);
}
} else {
friendlyByteBuf.readNbt(); // Discard
}
}
public static CompoundTag readTagUnknown(FriendlyByteBuf friendlyByteBuf, Player player) {
if (AxiomPaper.PLUGIN.isMismatchedDataVersion(player.getUniqueId())) {
try {
return ViaVersionHelper.readTagViaVersion(friendlyByteBuf, player);
} catch (Exception e) {
throw new RuntimeException(e);
}
} else {
return friendlyByteBuf.readNbt();
}
}
}

Datei anzeigen

@ -1,2 +1,138 @@
package com.moulberry.axiom.viaversion;public class ViaVersionHelper {
package com.moulberry.axiom.viaversion;
import com.moulberry.axiom.AxiomPaper;
import com.moulberry.axiom.buffer.BlockBuffer;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.data.MappingData;
import com.viaversion.viaversion.api.data.Mappings;
import com.viaversion.viaversion.api.protocol.ProtocolPathEntry;
import com.viaversion.viaversion.api.type.Type;
import io.netty.buffer.Unpooled;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import net.minecraft.SharedConstants;
import net.minecraft.core.IdMapper;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.world.level.block.state.BlockState;
import org.bukkit.entity.Player;
import java.util.List;
public class ViaVersionHelper {
private static final Int2ObjectOpenHashMap<IdMapper<BlockState>> blockRegistryCache = new Int2ObjectOpenHashMap<>();
private static final Int2ObjectOpenHashMap<String> blockRegistryErrorCache = new Int2ObjectOpenHashMap<>();
public static IdMapper<BlockState> getBlockRegistryForVersion(IdMapper<BlockState> mapper, int playerVersion) {
if (blockRegistryErrorCache.containsKey(playerVersion)) {
throw new RuntimeException(blockRegistryErrorCache.get(playerVersion));
}
if (blockRegistryCache.containsKey(playerVersion)) {
return blockRegistryCache.get(playerVersion);
}
List<ProtocolPathEntry> path = Via.getManager().getProtocolManager().getProtocolPath(playerVersion,
SharedConstants.getProtocolVersion());
if (path == null) {
blockRegistryErrorCache.put(playerVersion, "Failed to find protocol path");
throw new RuntimeException("Failed to find protocol path");
}
for (int i = path.size()-1; i >= 0; i--) {
ProtocolPathEntry protocolPathEntry = path.get(i);
MappingData mappingData = protocolPathEntry.protocol().getMappingData();
if (mappingData == null) {
blockRegistryErrorCache.put(playerVersion, "Failed to load mapping data (" + protocolPathEntry + ")");
throw new RuntimeException("Failed to load mapping data (" + protocolPathEntry + ")");
}
Mappings blockStateMappings = mappingData.getBlockStateMappings();
if (blockStateMappings == null) {
blockRegistryErrorCache.put(playerVersion, "Failed to load BlockState mappings (" + protocolPathEntry + ")");
throw new RuntimeException("Failed to load BlockState mappings (" + protocolPathEntry + ")");
}
mapper = ViaVersionHelper.applyMappings(mapper, blockStateMappings);
}
blockRegistryCache.put(playerVersion, mapper);
return mapper;
}
private static IdMapper<BlockState> applyMappings(IdMapper<BlockState> registry, Mappings mappings) {
IdMapper<BlockState> newBlockRegistry = new IdMapper<>();
// Add empty mappings for non-existent blocks
int size = mappings.mappedSize();
for (int i = 0; i < size; i++) {
newBlockRegistry.addMapping(BlockBuffer.EMPTY_STATE, i);
}
// Map blocks
for (int i = 0; i < registry.size(); i++) {
BlockState blockState = registry.byId(i);
if (blockState != null) {
int newId = mappings.getNewId(i);
if (newId >= 0) {
newBlockRegistry.addMapping(blockState, newId);
}
}
}
// Ensure block -> id is correct for the empty state
int newEmptyStateId = mappings.getNewId(registry.getId(BlockBuffer.EMPTY_STATE));
if (newEmptyStateId >= 0) {
newBlockRegistry.addMapping(BlockBuffer.EMPTY_STATE, newEmptyStateId);
}
return newBlockRegistry;
}
private static final int UNNAMED_COMPOUND_TAG_CHANGE_VERSION = 764; // 1.20.2
public static void skipTagViaVersion(FriendlyByteBuf friendlyByteBuf, Player player) throws Exception {
skipTagViaVersion(friendlyByteBuf, AxiomPaper.PLUGIN.getProtocolVersionFor(player.getUniqueId()));
}
public static void skipTagViaVersion(FriendlyByteBuf friendlyByteBuf, int playerVersion) throws Exception {
getTagType(playerVersion).read(friendlyByteBuf);
}
public static CompoundTag readTagViaVersion(FriendlyByteBuf friendlyByteBuf, Player player) throws Exception {
return readTagViaVersion(friendlyByteBuf, AxiomPaper.PLUGIN.getProtocolVersionFor(player.getUniqueId()));
}
public static CompoundTag readTagViaVersion(FriendlyByteBuf friendlyByteBuf, int playerVersion) throws Exception {
Type<com.viaversion.viaversion.libs.opennbt.tag.builtin.CompoundTag> from = getTagType(playerVersion);
Type<com.viaversion.viaversion.libs.opennbt.tag.builtin.CompoundTag> to = getTagType(SharedConstants.getProtocolVersion());
return readTagViaVersion(friendlyByteBuf, from, to);
}
private static Type<com.viaversion.viaversion.libs.opennbt.tag.builtin.CompoundTag> getTagType(int version) {
if (version < UNNAMED_COMPOUND_TAG_CHANGE_VERSION) {
return Type.NAMED_COMPOUND_TAG;
} else {
return Type.COMPOUND_TAG;
}
}
private static CompoundTag readTagViaVersion(FriendlyByteBuf friendlyByteBuf,
Type<com.viaversion.viaversion.libs.opennbt.tag.builtin.CompoundTag> from,
Type<com.viaversion.viaversion.libs.opennbt.tag.builtin.CompoundTag> to) throws Exception {
if (from == to) {
return friendlyByteBuf.readNbt();
}
com.viaversion.viaversion.libs.opennbt.tag.builtin.CompoundTag tag = from.read(friendlyByteBuf);
FriendlyByteBuf buffer = new FriendlyByteBuf(Unpooled.buffer());
to.write(buffer, tag);
return buffer.readNbt();
}
}

Datei anzeigen

@ -87,7 +87,7 @@ public abstract class WorldPropertyDataType<T> {
if (value == null) value = Items.AIR;
FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer(8));
buf.writeId(BuiltInRegistries.ITEM, value);
buf.writeById(BuiltInRegistries.ITEM::getIdOrThrow, value);
byte[] bytes = new byte[buf.writerIndex()];
buf.getBytes(0, bytes);
@ -97,7 +97,7 @@ public abstract class WorldPropertyDataType<T> {
@Override
public Item deserialize(byte[] bytes) {
FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.wrappedBuffer(bytes));
return buf.readById(BuiltInRegistries.ITEM);
return buf.readById(BuiltInRegistries.ITEM::byIdOrThrow);
}
};
@ -112,7 +112,7 @@ public abstract class WorldPropertyDataType<T> {
if (value == null) value = Blocks.AIR;
FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer(8));
buf.writeId(BuiltInRegistries.BLOCK, value);
buf.writeById(BuiltInRegistries.BLOCK::getIdOrThrow, value);
byte[] bytes = new byte[buf.writerIndex()];
buf.getBytes(0, bytes);
@ -122,7 +122,7 @@ public abstract class WorldPropertyDataType<T> {
@Override
public Block deserialize(byte[] bytes) {
FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.wrappedBuffer(bytes));
return buf.readById(BuiltInRegistries.BLOCK);
return buf.readById(BuiltInRegistries.BLOCK::byIdOrThrow);
}
};

Datei anzeigen

@ -9,19 +9,20 @@ import net.minecraft.server.level.ServerLevel;
import org.bukkit.GameRule;
import org.bukkit.NamespacedKey;
import org.bukkit.World;
import org.bukkit.craftbukkit.v1_20_R3.CraftWorld;
import org.bukkit.craftbukkit.CraftWorld;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import java.lang.ref.Reference;
import java.util.*;
public class ServerWorldPropertiesRegistry {
private final LinkedHashMap<WorldPropertyCategory, List<ServerWorldPropertyHolder<?>>> propertyList = new LinkedHashMap<>();
private final Map<ResourceLocation, ServerWorldPropertyHolder<?>> propertyMap = new HashMap<>();
private final World world;
private final Reference<World> world;
public ServerWorldPropertiesRegistry(World world) {
public ServerWorldPropertiesRegistry(Reference<World> world) {
this.world = world;
this.registerDefault();
}
@ -32,9 +33,14 @@ public class ServerWorldPropertiesRegistry {
@SuppressWarnings("unchecked")
public void addCategory(WorldPropertyCategory category, List<ServerWorldPropertyBase<?>> properties) {
World world = this.world.get();
if (world == null) {
return;
}
List<ServerWorldPropertyHolder<?>> holders = new ArrayList<>();
for (ServerWorldPropertyBase<?> property : properties) {
Object defaultValue = property.getDefaultValue(this.world);
Object defaultValue = property.getDefaultValue(world);
holders.add(new ServerWorldPropertyHolder<>(defaultValue, (ServerWorldPropertyBase<Object>) property));
}

Datei anzeigen

@ -6,7 +6,7 @@ import com.moulberry.axiom.world_properties.WorldPropertyWidgetType;
import net.minecraft.resources.ResourceLocation;
import org.bukkit.NamespacedKey;
import org.bukkit.World;
import org.bukkit.craftbukkit.v1_20_R3.util.CraftNamespacedKey;
import org.bukkit.craftbukkit.util.CraftNamespacedKey;
import org.bukkit.entity.Player;
public abstract class ServerWorldPropertyBase<T> {

Datei anzeigen

@ -9,7 +9,7 @@ import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation;
import org.bukkit.NamespacedKey;
import org.bukkit.World;
import org.bukkit.craftbukkit.v1_20_R3.util.CraftNamespacedKey;
import org.bukkit.craftbukkit.util.CraftNamespacedKey;
import org.bukkit.entity.Player;
import java.util.Objects;

Datei anzeigen

@ -5,20 +5,63 @@ description: $description
authors:
- Moulberry
api-version: "$apiVersion"
softdepend: ["CoreProtect", "ViaVersion", "WorldGuard", "PlotSquared"]
permissions:
axiom.*:
axiom.all:
description: Allows use of all default Axiom features
default: op
children:
axiom.*: true
axiom.use:
description: Allows basic use of axiom
default: op
axiom.debug:
description: Allows use of the /axiompaperdebug command
default: op
axiom.entity.*:
description: Allows use of all entity-related features (spawning, manipulating, deleting)
default: op
axiom.entity.spawn:
description: Allows entity spawning
axiom.entity.manipulate:
description: Allows entity manipulation
axiom.entity.delete:
description: Allows entity deletion
children:
axiom.entity.spawn: true
axiom.entity.manipulate: true
axiom.entity.delete: true
axiom.blueprint.*:
description: Allows use of all blueprint-related features
default: op
children:
axiom.blueprint.upload: true
axiom.blueprint.request: true
axiom.blueprint.manifest: true
axiom.chunk.*:
description: Allows use of all chunk-related features
default: op
children:
axiom.chunk.request: true
axiom.build.*:
description: Allows use of all build-related features
default: op
children:
axiom.build.place: true
axiom.build.section: true
axiom.editor.*:
description: Allows use of all editor-related features
default: op
children:
axiom.editor.views: true
axiom.player.*:
description: Allows use of all player-related features
default: op
children:
axiom.player.speed: true
axiom.player.gamemode: true
axiom.player.hotbar: true
axiom.world.*:
description: Allows use of all world-related features
default: op
children:
axiom.world.time: true
axiom.world.property: true
axiom.world.teleport: true
axiom.allow_copying_other_plots:
description: This permission allows users to copy other user's plots