From c8f7c55138fbe36d6b3afc268fabe478c48a08c3 Mon Sep 17 00:00:00 2001 From: Moulberry Date: Tue, 10 Oct 2023 13:56:08 +0800 Subject: [PATCH 01/53] Add support for noclip --- src/main/java/com/moulberry/axiom/AxiomPaper.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/moulberry/axiom/AxiomPaper.java b/src/main/java/com/moulberry/axiom/AxiomPaper.java index 27b1049..c2de0a0 100644 --- a/src/main/java/com/moulberry/axiom/AxiomPaper.java +++ b/src/main/java/com/moulberry/axiom/AxiomPaper.java @@ -127,9 +127,12 @@ public class AxiomPaper extends JavaPlugin implements Listener { @EventHandler public void onFailMove(PlayerFailMoveEvent event) { - if (event.getPlayer().hasPermission("axiom.*") && - event.getFailReason() == PlayerFailMoveEvent.FailReason.MOVED_TOO_QUICKLY) { - event.setAllowed(true); + if (event.getPlayer().hasPermission("axiom.*")) { + if (event.getFailReason() == PlayerFailMoveEvent.FailReason.MOVED_TOO_QUICKLY) { + event.setAllowed(true); // Support for arcball camera + } else if (event.getPlayer().isFlying()) { + event.setAllowed(true); // Support for noclip + } } } From 6de6ff0d282bc9df1166f03814cd8553ab130267 Mon Sep 17 00:00:00 2001 From: Moulberry Date: Tue, 10 Oct 2023 13:59:55 +0800 Subject: [PATCH 02/53] Bump version --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index a9c78ac..1e9c65e 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -8,7 +8,7 @@ plugins { } group = "com.moulberry.axiom" -version = "1.5.0" +version = "1.5.1" description = "Serverside component for Axiom on Paper" java { From d7523cba6a0dd1b01a52d63d708a666ce495c57f Mon Sep 17 00:00:00 2001 From: Moulberry Date: Tue, 10 Oct 2023 14:33:32 +0800 Subject: [PATCH 03/53] Log data versions when incompatible --- .../com/moulberry/axiom/packet/HelloPacketListener.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/moulberry/axiom/packet/HelloPacketListener.java b/src/main/java/com/moulberry/axiom/packet/HelloPacketListener.java index d372c3c..6b6101e 100644 --- a/src/main/java/com/moulberry/axiom/packet/HelloPacketListener.java +++ b/src/main/java/com/moulberry/axiom/packet/HelloPacketListener.java @@ -46,8 +46,10 @@ public class HelloPacketListener implements PluginMessageListener { int dataVersion = friendlyByteBuf.readVarInt(); friendlyByteBuf.readNbt(); // Discard - if (dataVersion != SharedConstants.getCurrentVersion().getDataVersion().getVersion()) { - player.kick(Component.text("Axiom: Incompatible data version detected, are you using ViaVersion?")); + int serverDataVersion = SharedConstants.getCurrentVersion().getDataVersion().getVersion(); + if (dataVersion != serverDataVersion) { + player.kick(Component.text("Axiom: Incompatible data version detected (client " + dataVersion + + ", server " + serverDataVersion + "), are you using ViaVersion?")); return; } From fa3f904f22d385685f928f7d4ccbccf648c79b18 Mon Sep 17 00:00:00 2001 From: Moulberry Date: Sat, 14 Oct 2023 11:59:05 +0800 Subject: [PATCH 04/53] Add configuration options, major performance improvements --- .../java/com/moulberry/axiom/AxiomPaper.java | 110 ++++++++--- .../com/moulberry/axiom/WorldExtension.java | 105 ++++++++++ .../axiom/event/AxiomHandshakeEvent.java | 5 +- .../axiom/integration/RegionProtection.java | 39 ---- .../RegionProtectionWorldGuard.java | 183 ------------------ .../axiom/integration/SectionProtection.java | 38 ---- .../axiom/packet/HelloPacketListener.java | 34 +++- .../RequestChunkDataPacketListener.java | 13 +- .../packet/SetBlockBufferPacketListener.java | 92 ++++----- .../axiom/packet/SetBlockPacketListener.java | 2 +- .../packet/SetEditorViewsPacketListener.java | 8 +- .../packet/SetFlySpeedPacketListener.java | 8 +- .../packet/SetGamemodePacketListener.java | 8 +- .../packet/SetHotbarSlotPacketListener.java | 8 +- .../axiom/packet/SetTimePacketListener.java | 16 +- .../packet/SetWorldPropertyListener.java | 7 +- .../SwitchActiveHotbarPacketListener.java | 8 +- .../axiom/packet/TeleportPacketListener.java | 8 +- src/main/resources/config.yml | 29 +++ 19 files changed, 355 insertions(+), 366 deletions(-) create mode 100644 src/main/java/com/moulberry/axiom/WorldExtension.java delete mode 100644 src/main/java/com/moulberry/axiom/integration/RegionProtection.java delete mode 100644 src/main/java/com/moulberry/axiom/integration/RegionProtectionWorldGuard.java delete mode 100644 src/main/java/com/moulberry/axiom/integration/SectionProtection.java create mode 100644 src/main/resources/config.yml diff --git a/src/main/java/com/moulberry/axiom/AxiomPaper.java b/src/main/java/com/moulberry/axiom/AxiomPaper.java index c2de0a0..880199f 100644 --- a/src/main/java/com/moulberry/axiom/AxiomPaper.java +++ b/src/main/java/com/moulberry/axiom/AxiomPaper.java @@ -19,7 +19,10 @@ import net.minecraft.network.protocol.Packet; import net.minecraft.network.protocol.PacketFlow; import net.minecraft.network.protocol.common.ServerboundCustomPayloadPacket; import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.MinecraftServer; import org.bukkit.*; +import org.bukkit.configuration.Configuration; +import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; @@ -37,11 +40,23 @@ public class AxiomPaper extends JavaPlugin implements Listener { public static AxiomPaper PLUGIN; // tsk tsk tsk public final Set activeAxiomPlayers = Collections.newSetFromMap(new ConcurrentHashMap<>()); + public Configuration configuration; @Override public void onEnable() { PLUGIN = this; + this.saveDefaultConfig(); + configuration = this.getConfig(); + + Set validResolutions = Set.of("kick", "warn", "ignore"); + if (!validResolutions.contains(configuration.getString("incompatible-data-version"))) { + this.getLogger().warning("Invalid value for incompatible-data-version, expected 'kick', 'warn' or 'ignore'"); + } + if (!validResolutions.contains(configuration.getString("unsupported-axiom-version"))) { + this.getLogger().warning("Invalid value for unsupported-axiom-version, expected 'kick', 'warn' or 'ignore'"); + } + Bukkit.getPluginManager().registerEvents(this, this); // Bukkit.getPluginManager().registerEvents(new WorldPropertiesExample(), this); CompressedBlockEntity.initialize(this); @@ -56,40 +71,64 @@ public class AxiomPaper extends JavaPlugin implements Listener { msg.registerOutgoingPluginChannel(this, "axiom:set_world_property"); msg.registerOutgoingPluginChannel(this, "axiom:ack_world_properties"); - msg.registerIncomingPluginChannel(this, "axiom:hello", new HelloPacketListener(this, activeAxiomPlayers)); - msg.registerIncomingPluginChannel(this, "axiom:set_gamemode", new SetGamemodePacketListener()); - msg.registerIncomingPluginChannel(this, "axiom:set_fly_speed", new SetFlySpeedPacketListener()); - msg.registerIncomingPluginChannel(this, "axiom:set_world_time", new SetTimePacketListener()); - msg.registerIncomingPluginChannel(this, "axiom:set_world_property", new SetWorldPropertyListener()); - msg.registerIncomingPluginChannel(this, "axiom:set_block", new SetBlockPacketListener(this)); - msg.registerIncomingPluginChannel(this, "axiom:set_hotbar_slot", new SetHotbarSlotPacketListener()); - msg.registerIncomingPluginChannel(this, "axiom:switch_active_hotbar", new SwitchActiveHotbarPacketListener()); - msg.registerIncomingPluginChannel(this, "axiom:teleport", new TeleportPacketListener()); - msg.registerIncomingPluginChannel(this, "axiom:set_editor_views", new SetEditorViewsPacketListener()); - msg.registerIncomingPluginChannel(this, "axiom:request_chunk_data", new RequestChunkDataPacketListener(this)); + if (configuration.getBoolean("packet-handlers.hello")) { + msg.registerIncomingPluginChannel(this, "axiom:hello", new HelloPacketListener(this, activeAxiomPlayers)); + } + if (configuration.getBoolean("packet-handlers.set-gamemode")) { + msg.registerIncomingPluginChannel(this, "axiom:set_gamemode", new SetGamemodePacketListener(this)); + } + if (configuration.getBoolean("packet-handlers.set-fly-speed")) { + msg.registerIncomingPluginChannel(this, "axiom:set_fly_speed", new SetFlySpeedPacketListener(this)); + } + if (configuration.getBoolean("packet-handlers.set-world-time")) { + msg.registerIncomingPluginChannel(this, "axiom:set_world_time", new SetTimePacketListener(this)); + } + if (configuration.getBoolean("packet-handlers.set-world-property")) { + msg.registerIncomingPluginChannel(this, "axiom:set_world_property", new SetWorldPropertyListener(this)); + } + if (configuration.getBoolean("packet-handlers.set-single-block")) { + msg.registerIncomingPluginChannel(this, "axiom:set_block", new SetBlockPacketListener(this)); + } + if (configuration.getBoolean("packet-handlers.set-hotbar-slot")) { + msg.registerIncomingPluginChannel(this, "axiom:set_hotbar_slot", new SetHotbarSlotPacketListener(this)); + } + if (configuration.getBoolean("packet-handlers.switch-active-hotbar")) { + msg.registerIncomingPluginChannel(this, "axiom:switch_active_hotbar", new SwitchActiveHotbarPacketListener(this)); + } + if (configuration.getBoolean("packet-handlers.teleport")) { + msg.registerIncomingPluginChannel(this, "axiom:teleport", new TeleportPacketListener(this)); + } + if (configuration.getBoolean("packet-handlers.set-editor-views")) { + msg.registerIncomingPluginChannel(this, "axiom:set_editor_views", new SetEditorViewsPacketListener(this)); + } + if (configuration.getBoolean("packet-handlers.request-chunk-data")) { + msg.registerIncomingPluginChannel(this, "axiom:request_chunk_data", new RequestChunkDataPacketListener(this)); + } - SetBlockBufferPacketListener setBlockBufferPacketListener = new SetBlockBufferPacketListener(this); + if (configuration.getBoolean("packet-handlers.set-buffer")) { + SetBlockBufferPacketListener setBlockBufferPacketListener = new SetBlockBufferPacketListener(this); - 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>> entry : packets.entrySet()) { - if (entry.getValue() == ServerboundCustomPayloadPacket.class) { - payloadId = entry.getKey(); - break; + 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>> entry : packets.entrySet()) { + if (entry.getValue() == ServerboundCustomPayloadPacket.class) { + payloadId = entry.getKey(); + break; + } + } + if (payloadId < 0) { + throw new RuntimeException("Failed to find ServerboundCustomPayloadPacket id"); } - } - 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)); - } - }); + Connection connection = (Connection) channel.pipeline().get("packet_handler"); + channel.pipeline().addBefore("decoder", "axiom-big-payload-handler", + new AxiomBigPayloadHandler(payloadId, connection, setBlockBufferPacketListener)); + } + }); + } Bukkit.getScheduler().scheduleSyncRepeatingTask(this, () -> { HashSet newActiveAxiomPlayers = new HashSet<>(); @@ -111,6 +150,17 @@ public class AxiomPaper extends JavaPlugin implements Listener { activeAxiomPlayers.clear(); activeAxiomPlayers.addAll(newActiveAxiomPlayers); }, 20, 20); + + int maxChunkRelightsPerTick = configuration.getInt("max-chunk-relights-per-tick"); + int maxChunkSendsPerTick = configuration.getInt("max-chunk-sends-per-tick"); + + Bukkit.getScheduler().scheduleSyncRepeatingTask(this, () -> { + WorldExtension.tick(MinecraftServer.getServer(), maxChunkRelightsPerTick, maxChunkSendsPerTick); + }, 1, 1); + } + + public boolean canUseAxiom(Player player) { + return player.hasPermission("axiom.*") && activeAxiomPlayers.contains(player.getUniqueId()); } private final WeakHashMap worldProperties = new WeakHashMap<>(); diff --git a/src/main/java/com/moulberry/axiom/WorldExtension.java b/src/main/java/com/moulberry/axiom/WorldExtension.java new file mode 100644 index 0000000..e18c2b8 --- /dev/null +++ b/src/main/java/com/moulberry/axiom/WorldExtension.java @@ -0,0 +1,105 @@ +package com.moulberry.axiom; + +import it.unimi.dsi.fastutil.longs.*; +import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; +import net.minecraft.resources.ResourceKey; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ChunkMap; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.chunk.LevelChunk; + +import java.util.*; + +public class WorldExtension { + + private static final Map, WorldExtension> extensions = new HashMap<>(); + + public static WorldExtension get(ServerLevel serverLevel) { + WorldExtension extension = extensions.computeIfAbsent(serverLevel.dimension(), k -> new WorldExtension()); + extension.level = serverLevel; + return extension; + } + + public static void tick(MinecraftServer server, int maxChunkRelightsPerTick, int maxChunkSendsPerTick) { + extensions.keySet().retainAll(server.levelKeys()); + + for (ServerLevel level : server.getAllLevels()) { + WorldExtension extension = extensions.get(level.dimension()); + if (extension != null) { + extension.level = level; + extension.tick(maxChunkRelightsPerTick, maxChunkSendsPerTick); + } + } + } + + private ServerLevel level; + + private final LongSet pendingChunksToSend = new LongOpenHashSet(); + private final LongSet pendingChunksToLight = new LongOpenHashSet(); + + public void sendChunk(int cx, int cz) { + this.pendingChunksToSend.add(ChunkPos.asLong(cx, cz)); + } + + public void lightChunk(int cx, int cz) { + this.pendingChunksToLight.add(ChunkPos.asLong(cx, cz)); + } + + public void tick(int maxChunkRelightsPerTick, int maxChunkSendsPerTick) { + ChunkMap chunkMap = this.level.getChunkSource().chunkMap; + + boolean sendAll = maxChunkSendsPerTick <= 0; + + // Send chunks + LongIterator longIterator = this.pendingChunksToSend.longIterator(); + while (longIterator.hasNext()) { + ChunkPos chunkPos = new ChunkPos(longIterator.nextLong()); + List players = chunkMap.getPlayers(chunkPos, false); + if (players.isEmpty()) continue; + + LevelChunk chunk = this.level.getChunk(chunkPos.x, chunkPos.z); + var packet = new ClientboundLevelChunkWithLightPacket(chunk, this.level.getLightEngine(), null, null, false); + for (ServerPlayer player : players) { + player.connection.send(packet); + } + + if (!sendAll) { + longIterator.remove(); + + maxChunkSendsPerTick -= 1; + if (maxChunkSendsPerTick <= 0) { + break; + } + } + } + if (sendAll) { + this.pendingChunksToSend.clear(); + } + + // Relight chunks + Set chunkSet = new HashSet<>(); + longIterator = this.pendingChunksToLight.longIterator(); + if (maxChunkRelightsPerTick <= 0) { + while (longIterator.hasNext()) { + chunkSet.add(new ChunkPos(longIterator.nextLong())); + } + this.pendingChunksToLight.clear(); + } else { + while (longIterator.hasNext()) { + chunkSet.add(new ChunkPos(longIterator.nextLong())); + longIterator.remove(); + + maxChunkRelightsPerTick -= 1; + if (maxChunkRelightsPerTick <= 0) { + break; + } + } + } + + this.level.getChunkSource().getLightEngine().relight(chunkSet, pos -> {}, count -> {}); + } + +} diff --git a/src/main/java/com/moulberry/axiom/event/AxiomHandshakeEvent.java b/src/main/java/com/moulberry/axiom/event/AxiomHandshakeEvent.java index 735c762..749ec91 100644 --- a/src/main/java/com/moulberry/axiom/event/AxiomHandshakeEvent.java +++ b/src/main/java/com/moulberry/axiom/event/AxiomHandshakeEvent.java @@ -12,10 +12,11 @@ public class AxiomHandshakeEvent extends Event implements Cancellable { private final Player player; private boolean cancelled = false; - private int maxBufferSize = 0x100000; + private int maxBufferSize; - public AxiomHandshakeEvent(Player player) { + public AxiomHandshakeEvent(Player player, int maxBufferSize) { this.player = player; + this.maxBufferSize = maxBufferSize; } public Player getPlayer() { diff --git a/src/main/java/com/moulberry/axiom/integration/RegionProtection.java b/src/main/java/com/moulberry/axiom/integration/RegionProtection.java deleted file mode 100644 index cef48d9..0000000 --- a/src/main/java/com/moulberry/axiom/integration/RegionProtection.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.moulberry.axiom.integration; - -import org.bukkit.Bukkit; -import org.bukkit.World; -import org.bukkit.entity.Player; - -import java.util.ArrayList; -import java.util.List; - -public class RegionProtection { - - private final RegionProtectionWorldGuard worldGuard; - - public RegionProtection(Player player, World world) { - if (Bukkit.getPluginManager().isPluginEnabled("WorldGuard")) { - this.worldGuard = RegionProtectionWorldGuard.tryCreate(player, world); - } else { - this.worldGuard = null; - } - } - - public SectionProtection getSection(int cx, int cy, int cz) { - List protections = new ArrayList<>(); - if (this.worldGuard != null) { - return this.worldGuard.getSection(cx, cy, cz); - } - // todo: PlotSquared - return SectionProtection.ALLOW; - } - - public boolean canBuild(int x, int y, int z) { - if (this.worldGuard != null && !this.worldGuard.canBuild(x, y, z)) return false; - // todo: PlotSquared - return true; - } - - - -} diff --git a/src/main/java/com/moulberry/axiom/integration/RegionProtectionWorldGuard.java b/src/main/java/com/moulberry/axiom/integration/RegionProtectionWorldGuard.java deleted file mode 100644 index 5158140..0000000 --- a/src/main/java/com/moulberry/axiom/integration/RegionProtectionWorldGuard.java +++ /dev/null @@ -1,183 +0,0 @@ -package com.moulberry.axiom.integration; - -import com.google.common.collect.ImmutableList; -import com.google.common.collect.Sets; -import com.sk89q.worldedit.bukkit.BukkitAdapter; -import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldguard.LocalPlayer; -import com.sk89q.worldguard.WorldGuard; -import com.sk89q.worldguard.bukkit.WorldGuardPlugin; -import com.sk89q.worldguard.internal.platform.WorldGuardPlatform; -import com.sk89q.worldguard.protection.ApplicableRegionSet; -import com.sk89q.worldguard.protection.FlagValueCalculator; -import com.sk89q.worldguard.protection.association.RegionAssociable; -import com.sk89q.worldguard.protection.flags.Flags; -import com.sk89q.worldguard.protection.flags.RegionGroup; -import com.sk89q.worldguard.protection.flags.StateFlag; -import com.sk89q.worldguard.protection.managers.RegionManager; -import com.sk89q.worldguard.protection.regions.*; -import org.bukkit.World; -import org.bukkit.entity.Player; -import org.jetbrains.annotations.Nullable; - -import java.util.*; - -import static com.google.common.base.Preconditions.checkNotNull; - -public class RegionProtectionWorldGuard { - - private final LocalPlayer player; - private final RegionManager regionManager; - - public RegionProtectionWorldGuard(LocalPlayer player, RegionManager regionManager) { - this.player = player; - this.regionManager = regionManager; - } - - @Nullable - public static RegionProtectionWorldGuard tryCreate(Player player, World world) { - WorldGuardPlatform platform = WorldGuard.getInstance().getPlatform(); - - RegionContainer regionContainer = platform.getRegionContainer(); - if (regionContainer == null) return null; - - com.sk89q.worldedit.world.World worldEditWorld = BukkitAdapter.adapt(world); - LocalPlayer worldGuardPlayer = WorldGuardPlugin.inst().wrapPlayer(player); - - // Don't do any protection if player has bypass - if (platform.getSessionManager().hasBypass(worldGuardPlayer, worldEditWorld)) { - // todo: enable bypass - return null; - } - - RegionManager regionManager = regionContainer.get(worldEditWorld); - if (regionManager == null) return null; - - return new RegionProtectionWorldGuard(worldGuardPlayer, regionManager); - } - - public SectionProtection getSection(int cx, int cy, int cz) { - BlockVector3 min = BlockVector3.at(cx*16, cy*16, cz*16); - BlockVector3 max = BlockVector3.at(cx*16+15, cy*16+15, cz*16+15); - ProtectedRegion test = new ProtectedCuboidRegion("dummy", min, max); - ApplicableRegionSet regions = this.regionManager.getApplicableRegions(test, RegionQuery.QueryOption.COMPUTE_PARENTS); - - int minimumPriority = Integer.MIN_VALUE; - - Map consideredValues = new HashMap<>(); - Set ignoredParents = new HashSet<>(); - - for (ProtectedRegion region : regions) { - int priority = FlagValueCalculator.getPriorityOf(region); - - // todo: this logic doesn't work for us in determining ALLOW, DENY, CHECK - if (priority < minimumPriority) { - break; - } - - // todo: have to keep track of 2 booleans: partialAllow & partialDeny - - if (ignoredParents.contains(region)) { - continue; - } - - StateFlag.State value = FlagValueCalculator.getEffectiveFlagOf(region, Flags.BUILD, this.player); - if (value != null) { - minimumPriority = priority; - consideredValues.put(region, value); - } - - addParents(ignoredParents, region); - - // The BUILD flag is implicitly set on every region where - // PASSTHROUGH is not set to ALLOW - if (minimumPriority != priority && Flags.BUILD.implicitlySetWithMembership() && - FlagValueCalculator.getEffectiveFlagOf(region, Flags.PASSTHROUGH, this.player) != StateFlag.State.ALLOW) { - minimumPriority = priority; - } - } - - if (consideredValues.isEmpty()) { - if (Flags.BUILD.usesMembershipAsDefault()) { - // todo -// switch (getMembership(subject)) { -// case FAIL: -// return ImmutableList.of(); -// case SUCCESS: -// return (Collection) ImmutableList.of(StateFlag.State.ALLOW); -// } - } - - // System.out.println("returning default"); - StateFlag.State fallback = Flags.BUILD.getDefault(); - return fallback == StateFlag.State.DENY ? SectionProtection.DENY : SectionProtection.ALLOW; - } - - boolean hasPartialDeny = false; - for (Map.Entry entry : consideredValues.entrySet()) { - ProtectedRegion region = entry.getKey(); - if (entry.getValue() == StateFlag.State.DENY) { - // System.out.println("found region with deny!"); - if (region instanceof GlobalProtectedRegion) { - return SectionProtection.DENY; - } else if (region instanceof ProtectedCuboidRegion && doesRegionCompletelyContainSection(region, cx, cy, cz)) { - return SectionProtection.DENY; - } - hasPartialDeny = true; - } - } - - if (hasPartialDeny) { - // System.out.println("returning check!"); - return new SectionProtection() { - @Override - public SectionState getSectionState() { - return SectionState.CHECK; - } - - @Override - public boolean check(int wx, int wy, int wz) { - return true; - } - }; - // return complex thing - } - - // System.out.println("returning allow!"); - return SectionProtection.ALLOW; - } - - private boolean doesRegionCompletelyContainSection(ProtectedRegion region, int cx, int cy, int cz) { - BlockVector3 regionMin = region.getMinimumPoint(); - - if (regionMin.getBlockX() > cx*16) return false; - if (regionMin.getBlockY() > cy*16) return false; - if (regionMin.getBlockZ() > cz*16) return false; - - BlockVector3 regionMax = region.getMaximumPoint(); - - if (regionMax.getBlockX() < cx*16+15) return false; - if (regionMax.getBlockY() < cy*16+15) return false; - if (regionMax.getBlockZ() < cz*16+15) return false; - - return true; - } - - private void addParents(Set ignored, ProtectedRegion region) { - ProtectedRegion parent = region.getParent(); - - while (parent != null) { - ignored.add(parent); - parent = parent.getParent(); - } - } - - public boolean canBuild(int x, int y, int z) { - return this.regionManager.getApplicableRegions(BlockVector3.at(x, y, z)).testState(this.player, Flags.BUILD); - } - - public boolean isAllowed(LocalPlayer player, ProtectedRegion protectedRegion) { - return protectedRegion.isOwner(player) || protectedRegion.isMember(player); - } - -} diff --git a/src/main/java/com/moulberry/axiom/integration/SectionProtection.java b/src/main/java/com/moulberry/axiom/integration/SectionProtection.java deleted file mode 100644 index 07b8d60..0000000 --- a/src/main/java/com/moulberry/axiom/integration/SectionProtection.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.moulberry.axiom.integration; - -public interface SectionProtection { - - SectionProtection ALLOW = new SectionProtection() { - @Override - public SectionState getSectionState() { - return SectionState.ALLOW; - } - - @Override - public boolean check(int wx, int wy, int wz) { - return true; - } - }; - - SectionProtection DENY = new SectionProtection() { - @Override - public SectionState getSectionState() { - return SectionState.DENY; - } - - @Override - public boolean check(int wx, int wy, int wz) { - return false; - } - }; - - enum SectionState { - ALLOW, - DENY, - CHECK - } - - SectionState getSectionState(); - boolean check(int wx, int wy, int wz); - -} diff --git a/src/main/java/com/moulberry/axiom/packet/HelloPacketListener.java b/src/main/java/com/moulberry/axiom/packet/HelloPacketListener.java index 6b6101e..9a7a261 100644 --- a/src/main/java/com/moulberry/axiom/packet/HelloPacketListener.java +++ b/src/main/java/com/moulberry/axiom/packet/HelloPacketListener.java @@ -9,6 +9,7 @@ import com.moulberry.axiom.persistence.UUIDDataType; import com.moulberry.axiom.world_properties.server.ServerWorldPropertiesRegistry; 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.network.FriendlyByteBuf; import org.bukkit.Bukkit; @@ -48,19 +49,38 @@ public class HelloPacketListener implements PluginMessageListener { int serverDataVersion = SharedConstants.getCurrentVersion().getDataVersion().getVersion(); if (dataVersion != serverDataVersion) { - player.kick(Component.text("Axiom: Incompatible data version detected (client " + dataVersion + - ", server " + serverDataVersion + "), are you using ViaVersion?")); - return; + 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.equals("warn")) { + player.sendMessage(text.color(NamedTextColor.RED)); + return; + } else if (!incompatibleDataVersion.equals("ignore")) { + player.kick(text); + return; + } } if (apiVersion != AxiomConstants.API_VERSION) { - player.kick(Component.text("Unsupported Axiom API Version. Server supports " + AxiomConstants.API_VERSION + - ", while client is " + apiVersion)); - return; + Component text = Component.text("Unsupported Axiom API Version. Server supports " + AxiomConstants.API_VERSION + + ", while client is " + apiVersion); + + String unsupportedAxiomVersion = plugin.configuration.getString("unsupported-axiom-version"); + if (unsupportedAxiomVersion == null) unsupportedAxiomVersion = "kick"; + if (unsupportedAxiomVersion.equals("warn")) { + player.sendMessage(text.color(NamedTextColor.RED)); + return; + } else if (!unsupportedAxiomVersion.equals("ignore")) { + player.kick(text); + return; + } } // Call handshake event - AxiomHandshakeEvent handshakeEvent = new AxiomHandshakeEvent(player); + int maxBufferSize = plugin.configuration.getInt("max-block-buffer-packet-size"); + AxiomHandshakeEvent handshakeEvent = new AxiomHandshakeEvent(player, maxBufferSize); Bukkit.getPluginManager().callEvent(handshakeEvent); if (handshakeEvent.isCancelled()) { return; diff --git a/src/main/java/com/moulberry/axiom/packet/RequestChunkDataPacketListener.java b/src/main/java/com/moulberry/axiom/packet/RequestChunkDataPacketListener.java index 4f83a2a..db92663 100644 --- a/src/main/java/com/moulberry/axiom/packet/RequestChunkDataPacketListener.java +++ b/src/main/java/com/moulberry/axiom/packet/RequestChunkDataPacketListener.java @@ -3,6 +3,7 @@ package com.moulberry.axiom.packet; import com.moulberry.axiom.AxiomConstants; import com.moulberry.axiom.AxiomPaper; import com.moulberry.axiom.buffer.CompressedBlockEntity; +import com.moulberry.axiom.event.AxiomModifyWorldEvent; import io.netty.buffer.Unpooled; import it.unimi.dsi.fastutil.longs.*; import net.minecraft.core.BlockPos; @@ -21,6 +22,7 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunkSection; import net.minecraft.world.level.chunk.PalettedContainer; +import org.bukkit.Bukkit; import org.bukkit.craftbukkit.v1_20_R2.entity.CraftPlayer; import org.bukkit.entity.Player; import org.bukkit.plugin.messaging.PluginMessageListener; @@ -33,7 +35,6 @@ public class RequestChunkDataPacketListener implements PluginMessageListener { private static final ResourceLocation RESPONSE_ID = new ResourceLocation("axiom:response_chunk_data"); private final AxiomPaper plugin; - public RequestChunkDataPacketListener(AxiomPaper plugin) { this.plugin = plugin; } @@ -44,12 +45,20 @@ public class RequestChunkDataPacketListener implements PluginMessageListener { FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(message)); long id = friendlyByteBuf.readLong(); - if (!bukkitPlayer.hasPermission("axiom.*")) { + if (!this.plugin.canUseAxiom(bukkitPlayer)) { // We always send an 'empty' response in order to make the client happy sendEmptyResponse(player, id); return; } + // Call AxiomModifyWorldEvent event + AxiomModifyWorldEvent modifyWorldEvent = new AxiomModifyWorldEvent(bukkitPlayer, bukkitPlayer.getWorld()); + Bukkit.getPluginManager().callEvent(modifyWorldEvent); + if (modifyWorldEvent.isCancelled()) { + sendEmptyResponse(player, id); + return; + } + MinecraftServer server = player.getServer(); if (server == null) { sendEmptyResponse(player, id); diff --git a/src/main/java/com/moulberry/axiom/packet/SetBlockBufferPacketListener.java b/src/main/java/com/moulberry/axiom/packet/SetBlockBufferPacketListener.java index c7883ac..9733e53 100644 --- a/src/main/java/com/moulberry/axiom/packet/SetBlockBufferPacketListener.java +++ b/src/main/java/com/moulberry/axiom/packet/SetBlockBufferPacketListener.java @@ -1,27 +1,11 @@ package com.moulberry.axiom.packet; import com.moulberry.axiom.AxiomPaper; +import com.moulberry.axiom.WorldExtension; import com.moulberry.axiom.buffer.BiomeBuffer; import com.moulberry.axiom.buffer.BlockBuffer; import com.moulberry.axiom.buffer.CompressedBlockEntity; import com.moulberry.axiom.event.AxiomModifyWorldEvent; -import com.moulberry.axiom.integration.RegionProtection; -import com.moulberry.axiom.integration.SectionProtection; -import com.sk89q.worldedit.bukkit.BukkitAdapter; -import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.world.World; -import com.sk89q.worldguard.LocalPlayer; -import com.sk89q.worldguard.WorldGuard; -import com.sk89q.worldguard.bukkit.WorldGuardPlugin; -import com.sk89q.worldguard.protection.ApplicableRegionSet; -import com.sk89q.worldguard.protection.flags.Flags; -import com.sk89q.worldguard.protection.flags.StateFlag; -import com.sk89q.worldguard.protection.managers.RegionManager; -import com.sk89q.worldguard.protection.regions.ProtectedCuboidRegion; -import com.sk89q.worldguard.protection.regions.ProtectedRegion; -import com.sk89q.worldguard.protection.regions.RegionContainer; -import com.sk89q.worldguard.protection.regions.RegionQuery; -import io.netty.buffer.Unpooled; import it.unimi.dsi.fastutil.longs.Long2ObjectMap; import it.unimi.dsi.fastutil.shorts.Short2ObjectMap; import net.minecraft.core.BlockPos; @@ -41,7 +25,6 @@ import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.Level; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.EntityBlock; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; @@ -96,7 +79,7 @@ public class SetBlockBufferPacketListener { applyBlockBuffer(player, server, buffer, worldKey); } else if (type == 1) { BiomeBuffer buffer = BiomeBuffer.load(friendlyByteBuf); - applyBiomeBuffer(server, buffer, worldKey); + applyBiomeBuffer(player, server, buffer, worldKey); } else { throw new RuntimeException("Unknown buffer type: " + type); } @@ -109,17 +92,18 @@ public class SetBlockBufferPacketListener { ServerLevel world = server.getLevel(worldKey); if (world == null) return; + if (!this.plugin.canUseAxiom(player.getBukkitEntity())) { + return; + } + // Call AxiomModifyWorldEvent event AxiomModifyWorldEvent modifyWorldEvent = new AxiomModifyWorldEvent(player.getBukkitEntity(), world.getWorld()); Bukkit.getPluginManager().callEvent(modifyWorldEvent); if (modifyWorldEvent.isCancelled()) return; - // RegionProtection regionProtection = new RegionProtection(player.getBukkitEntity(), world.getWorld()); - // Allowed, apply buffer BlockPos.MutableBlockPos blockPos = new BlockPos.MutableBlockPos(); - - var lightEngine = world.getChunkSource().getLightEngine(); + WorldExtension extension = WorldExtension.get(world); BlockState emptyState = BlockBuffer.EMPTY_STATE; @@ -133,17 +117,7 @@ public class SetBlockBufferPacketListener { continue; } -// SectionProtection sectionProtection = regionProtection.getSection(cx, cy, cz); -// switch (sectionProtection.getSectionState()) { -// case ALLOW -> sectionProtection = null; -// case DENY -> { -// continue; -// } -// case CHECK -> {} -// } - LevelChunk chunk = world.getChunk(cx, cz); - chunk.setUnsaved(true); LevelChunkSection section = chunk.getSection(world.getSectionIndexFromSectionY(cy)); PalettedContainer sectionStates = section.getStates(); @@ -163,6 +137,12 @@ public class SetBlockBufferPacketListener { } } + boolean sectionChanged = false; + boolean sectionLightChanged = false; + + boolean containerMaybeHasPoi = container.maybeHas(PoiTypes::hasPoi); + boolean sectionMaybeHasPoi = section.maybeHas(PoiTypes::hasPoi); + Short2ObjectMap blockEntityChunkMap = buffer.getBlockEntityChunkMap(entry.getLongKey()); for (int x = 0; x < 16; x++) { @@ -171,28 +151,19 @@ public class SetBlockBufferPacketListener { BlockState blockState = container.get(x, y, z); if (blockState == emptyState) continue; -// switch (sectionProtection.getSectionState()) { -// case ALLOW -> {} -// case DENY -> blockState = Blocks.REDSTONE_BLOCK.defaultBlockState(); -// case CHECK -> blockState = Blocks.DIAMOND_BLOCK.defaultBlockState(); -// } - int bx = cx*16 + x; int by = cy*16 + y; int bz = cz*16 + z; -// if (!regionProtection.canBuild(bx, by, bz)) { -// continue; -// } - - blockPos.set(bx, by, bz); - if (hasOnlyAir && blockState.isAir()) { continue; } BlockState old = section.setBlockState(x, y, z, blockState, true); if (blockState != old) { + sectionChanged = true; + blockPos.set(bx, by, bz); + Block block = blockState.getBlock(); motionBlocking.update(x, by, z, blockState); motionBlockingNoLeaves.update(x, by, z, blockState); @@ -245,18 +216,12 @@ public class SetBlockBufferPacketListener { chunk.removeBlockEntity(blockPos); } - // Mark block changed - world.getChunkSource().blockChanged(blockPos); // todo: maybe simply resend chunk instead of this? - // Update Light - if (LightEngine.hasDifferentLightProperties(chunk, blockPos, old, blockState)) { - chunk.getSkyLightSources().update(chunk, x, by, z); - lightEngine.checkBlock(blockPos); - } + sectionLightChanged |= LightEngine.hasDifferentLightProperties(chunk, blockPos, old, blockState); // Update Poi - Optional> newPoi = PoiTypes.forState(blockState); - Optional> oldPoi = PoiTypes.forState(old); + Optional> newPoi = containerMaybeHasPoi ? PoiTypes.forState(blockState) : Optional.empty(); + Optional> oldPoi = sectionMaybeHasPoi ? PoiTypes.forState(old) : Optional.empty(); if (!Objects.equals(oldPoi, newPoi)) { if (oldPoi.isPresent()) world.getPoiManager().remove(blockPos); if (newPoi.isPresent()) world.getPoiManager().add(blockPos, newPoi.get()); @@ -270,16 +235,33 @@ public class SetBlockBufferPacketListener { if (hasOnlyAir != nowHasOnlyAir) { world.getChunkSource().getLightEngine().updateSectionStatus(SectionPos.of(cx, cy, cz), nowHasOnlyAir); } + + if (sectionChanged) { + extension.sendChunk(cx, cz); + chunk.setUnsaved(true); + } + if (sectionLightChanged) { + extension.lightChunk(cx, cz); + } } }); } - private void applyBiomeBuffer(MinecraftServer server, BiomeBuffer biomeBuffer, ResourceKey worldKey) { + private void applyBiomeBuffer(ServerPlayer player, MinecraftServer server, BiomeBuffer biomeBuffer, ResourceKey worldKey) { server.execute(() -> { ServerLevel world = server.getLevel(worldKey); if (world == null) return; + if (!this.plugin.canUseAxiom(player.getBukkitEntity())) { + return; + } + + // Call AxiomModifyWorldEvent event + AxiomModifyWorldEvent modifyWorldEvent = new AxiomModifyWorldEvent(player.getBukkitEntity(), world.getWorld()); + Bukkit.getPluginManager().callEvent(modifyWorldEvent); + if (modifyWorldEvent.isCancelled()) return; + Set changedChunks = new HashSet<>(); int minSection = world.getMinSection(); diff --git a/src/main/java/com/moulberry/axiom/packet/SetBlockPacketListener.java b/src/main/java/com/moulberry/axiom/packet/SetBlockPacketListener.java index 7db3fb8..247af05 100644 --- a/src/main/java/com/moulberry/axiom/packet/SetBlockPacketListener.java +++ b/src/main/java/com/moulberry/axiom/packet/SetBlockPacketListener.java @@ -62,7 +62,7 @@ public class SetBlockPacketListener implements PluginMessageListener { @Override public void onPluginMessageReceived(@NotNull String channel, @NotNull Player bukkitPlayer, @NotNull byte[] message) { - if (!bukkitPlayer.hasPermission("axiom.*")) { + if (!this.plugin.canUseAxiom(bukkitPlayer)) { return; } diff --git a/src/main/java/com/moulberry/axiom/packet/SetEditorViewsPacketListener.java b/src/main/java/com/moulberry/axiom/packet/SetEditorViewsPacketListener.java index 1fd9bda..96c257a 100644 --- a/src/main/java/com/moulberry/axiom/packet/SetEditorViewsPacketListener.java +++ b/src/main/java/com/moulberry/axiom/packet/SetEditorViewsPacketListener.java @@ -1,6 +1,7 @@ package com.moulberry.axiom.packet; import com.moulberry.axiom.AxiomConstants; +import com.moulberry.axiom.AxiomPaper; import com.moulberry.axiom.View; import com.moulberry.axiom.persistence.UUIDDataType; import io.netty.buffer.Unpooled; @@ -16,9 +17,14 @@ import java.util.UUID; public class SetEditorViewsPacketListener implements PluginMessageListener { + private final AxiomPaper plugin; + public SetEditorViewsPacketListener(AxiomPaper plugin) { + this.plugin = plugin; + } + @Override public void onPluginMessageReceived(@NotNull String channel, @NotNull Player player, @NotNull byte[] message) { - if (!player.hasPermission("axiom.*")) { + if (!this.plugin.canUseAxiom(player)) { return; } diff --git a/src/main/java/com/moulberry/axiom/packet/SetFlySpeedPacketListener.java b/src/main/java/com/moulberry/axiom/packet/SetFlySpeedPacketListener.java index bc516fb..2e246a5 100644 --- a/src/main/java/com/moulberry/axiom/packet/SetFlySpeedPacketListener.java +++ b/src/main/java/com/moulberry/axiom/packet/SetFlySpeedPacketListener.java @@ -1,5 +1,6 @@ package com.moulberry.axiom.packet; +import com.moulberry.axiom.AxiomPaper; import com.moulberry.axiom.event.AxiomFlySpeedChangeEvent; import io.netty.buffer.Unpooled; import net.minecraft.network.FriendlyByteBuf; @@ -11,9 +12,14 @@ import org.jetbrains.annotations.NotNull; public class SetFlySpeedPacketListener implements PluginMessageListener { + private final AxiomPaper plugin; + public SetFlySpeedPacketListener(AxiomPaper plugin) { + this.plugin = plugin; + } + @Override public void onPluginMessageReceived(@NotNull String channel, @NotNull Player player, @NotNull byte[] message) { - if (!player.hasPermission("axiom.*")) { + if (!this.plugin.canUseAxiom(player)) { return; } diff --git a/src/main/java/com/moulberry/axiom/packet/SetGamemodePacketListener.java b/src/main/java/com/moulberry/axiom/packet/SetGamemodePacketListener.java index 17f321a..dd66081 100644 --- a/src/main/java/com/moulberry/axiom/packet/SetGamemodePacketListener.java +++ b/src/main/java/com/moulberry/axiom/packet/SetGamemodePacketListener.java @@ -1,5 +1,6 @@ package com.moulberry.axiom.packet; +import com.moulberry.axiom.AxiomPaper; import com.moulberry.axiom.event.AxiomGameModeChangeEvent; import io.netty.buffer.Unpooled; import net.minecraft.network.FriendlyByteBuf; @@ -13,9 +14,14 @@ import org.jetbrains.annotations.NotNull; public class SetGamemodePacketListener implements PluginMessageListener { + private final AxiomPaper plugin; + public SetGamemodePacketListener(AxiomPaper plugin) { + this.plugin = plugin; + } + @Override public void onPluginMessageReceived(@NotNull String channel, @NotNull Player player, @NotNull byte[] message) { - if (!player.hasPermission("axiom.*")) { + if (!this.plugin.canUseAxiom(player)) { return; } diff --git a/src/main/java/com/moulberry/axiom/packet/SetHotbarSlotPacketListener.java b/src/main/java/com/moulberry/axiom/packet/SetHotbarSlotPacketListener.java index 7d18a7d..5c299b0 100644 --- a/src/main/java/com/moulberry/axiom/packet/SetHotbarSlotPacketListener.java +++ b/src/main/java/com/moulberry/axiom/packet/SetHotbarSlotPacketListener.java @@ -1,6 +1,7 @@ package com.moulberry.axiom.packet; import com.moulberry.axiom.AxiomConstants; +import com.moulberry.axiom.AxiomPaper; import com.moulberry.axiom.persistence.ItemStackDataType; import io.netty.buffer.Unpooled; import net.minecraft.network.FriendlyByteBuf; @@ -15,9 +16,14 @@ import org.jetbrains.annotations.NotNull; public class SetHotbarSlotPacketListener implements PluginMessageListener { + private final AxiomPaper plugin; + public SetHotbarSlotPacketListener(AxiomPaper plugin) { + this.plugin = plugin; + } + @Override public void onPluginMessageReceived(@NotNull String channel, @NotNull Player player, @NotNull byte[] message) { - if (!player.hasPermission("axiom.*")) { + if (!this.plugin.canUseAxiom(player)) { return; } diff --git a/src/main/java/com/moulberry/axiom/packet/SetTimePacketListener.java b/src/main/java/com/moulberry/axiom/packet/SetTimePacketListener.java index f650fd6..6b858fc 100644 --- a/src/main/java/com/moulberry/axiom/packet/SetTimePacketListener.java +++ b/src/main/java/com/moulberry/axiom/packet/SetTimePacketListener.java @@ -1,5 +1,7 @@ package com.moulberry.axiom.packet; +import com.moulberry.axiom.AxiomPaper; +import com.moulberry.axiom.event.AxiomModifyWorldEvent; import com.moulberry.axiom.event.AxiomTimeChangeEvent; import io.netty.buffer.Unpooled; import net.minecraft.core.registries.Registries; @@ -16,9 +18,14 @@ import org.jetbrains.annotations.NotNull; public class SetTimePacketListener implements PluginMessageListener { + private final AxiomPaper plugin; + public SetTimePacketListener(AxiomPaper plugin) { + this.plugin = plugin; + } + @Override public void onPluginMessageReceived(@NotNull String channel, @NotNull Player player, @NotNull byte[] message) { - if (!player.hasPermission("axiom.*")) { + if (!this.plugin.canUseAxiom(player)) { return; } @@ -32,7 +39,12 @@ public class SetTimePacketListener implements PluginMessageListener { ServerLevel level = ((CraftWorld)player.getWorld()).getHandle(); if (!level.dimension().equals(key)) return; - // Call event + // Call modify world + AxiomModifyWorldEvent modifyWorldEvent = new AxiomModifyWorldEvent(player, player.getWorld()); + Bukkit.getPluginManager().callEvent(modifyWorldEvent); + if (modifyWorldEvent.isCancelled()) return; + + // Call time change event AxiomTimeChangeEvent timeChangeEvent = new AxiomTimeChangeEvent(player, time, freezeTime); Bukkit.getPluginManager().callEvent(timeChangeEvent); if (timeChangeEvent.isCancelled()) return; diff --git a/src/main/java/com/moulberry/axiom/packet/SetWorldPropertyListener.java b/src/main/java/com/moulberry/axiom/packet/SetWorldPropertyListener.java index c18a72f..d9a4ce8 100644 --- a/src/main/java/com/moulberry/axiom/packet/SetWorldPropertyListener.java +++ b/src/main/java/com/moulberry/axiom/packet/SetWorldPropertyListener.java @@ -12,9 +12,14 @@ import org.jetbrains.annotations.NotNull; public class SetWorldPropertyListener implements PluginMessageListener { + private final AxiomPaper plugin; + public SetWorldPropertyListener(AxiomPaper plugin) { + this.plugin = plugin; + } + @Override public void onPluginMessageReceived(@NotNull String channel, @NotNull Player player, @NotNull byte[] message) { - if (!player.hasPermission("axiom.*")) { + if (!this.plugin.canUseAxiom(player)) { return; } diff --git a/src/main/java/com/moulberry/axiom/packet/SwitchActiveHotbarPacketListener.java b/src/main/java/com/moulberry/axiom/packet/SwitchActiveHotbarPacketListener.java index 2c98b73..edd0d45 100644 --- a/src/main/java/com/moulberry/axiom/packet/SwitchActiveHotbarPacketListener.java +++ b/src/main/java/com/moulberry/axiom/packet/SwitchActiveHotbarPacketListener.java @@ -1,6 +1,7 @@ package com.moulberry.axiom.packet; import com.moulberry.axiom.AxiomConstants; +import com.moulberry.axiom.AxiomPaper; import com.moulberry.axiom.persistence.ItemStackDataType; import io.netty.buffer.Unpooled; import net.minecraft.network.FriendlyByteBuf; @@ -17,9 +18,14 @@ import org.jetbrains.annotations.NotNull; public class SwitchActiveHotbarPacketListener implements PluginMessageListener { + private final AxiomPaper plugin; + public SwitchActiveHotbarPacketListener(AxiomPaper plugin) { + this.plugin = plugin; + } + @Override public void onPluginMessageReceived(@NotNull String channel, @NotNull Player player, @NotNull byte[] message) { - if (!player.hasPermission("axiom.*")) { + if (!this.plugin.canUseAxiom(player)) { return; } diff --git a/src/main/java/com/moulberry/axiom/packet/TeleportPacketListener.java b/src/main/java/com/moulberry/axiom/packet/TeleportPacketListener.java index 871cc2a..7fff066 100644 --- a/src/main/java/com/moulberry/axiom/packet/TeleportPacketListener.java +++ b/src/main/java/com/moulberry/axiom/packet/TeleportPacketListener.java @@ -1,5 +1,6 @@ package com.moulberry.axiom.packet; +import com.moulberry.axiom.AxiomPaper; import com.moulberry.axiom.event.AxiomGameModeChangeEvent; import com.moulberry.axiom.event.AxiomTeleportEvent; import io.netty.buffer.Unpooled; @@ -14,9 +15,14 @@ import org.jetbrains.annotations.NotNull; public class TeleportPacketListener implements PluginMessageListener { + private final AxiomPaper plugin; + public TeleportPacketListener(AxiomPaper plugin) { + this.plugin = plugin; + } + @Override public void onPluginMessageReceived(@NotNull String channel, @NotNull Player player, @NotNull byte[] message) { - if (!player.hasPermission("axiom.*")) { + if (!this.plugin.canUseAxiom(player)) { return; } diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml new file mode 100644 index 0000000..065daf9 --- /dev/null +++ b/src/main/resources/config.yml @@ -0,0 +1,29 @@ +# Max chunk sends per tick (per-world), 0 = no limit +max-chunk-sends-per-tick: 0 + +# Max chunk relights per tick (per-world), 0 = no limit +max-chunk-relights-per-tick: 0 + +# Action to take when a user with an incompatible Minecraft version or Axiom version joins +# Valid actions are 'kick', 'warn' and 'ignore' +# Using 'ignore' may result in corruption and is only provided for debugging purposes +incompatible-data-version: "kick" +unsupported-axiom-version: "kick" + +# Maximum packet size. Must not be less than 32767 +max-block-buffer-packet-size: 0x100000 + +# Toggles for individual packet handlers. May break certain features +packet-handlers: + hello: true + set-gamemode: true + set-fly-speed: true + set-world-time: true + set-world-property: true + set-single-block: true + set-hotbar-slot: true + switch-active-hotbar: true + teleport: true + set-editor-views: true + request-chunk-data: true + set-buffer: true From 5c8e845b620241dbb3cee1385c017ac1ba5a44a2 Mon Sep 17 00:00:00 2001 From: Moulberry Date: Sat, 14 Oct 2023 12:15:30 +0800 Subject: [PATCH 05/53] Add two more config options --- build.gradle.kts | 2 +- .../RequestChunkDataPacketListener.java | 61 ++++++++++--------- .../axiom/packet/SetBlockPacketListener.java | 1 - .../axiom/packet/TeleportPacketListener.java | 6 ++ 4 files changed, 39 insertions(+), 31 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 1e9c65e..caa783c 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -8,7 +8,7 @@ plugins { } group = "com.moulberry.axiom" -version = "1.5.1" +version = "1.5.2" description = "Serverside component for Axiom on Paper" java { diff --git a/src/main/java/com/moulberry/axiom/packet/RequestChunkDataPacketListener.java b/src/main/java/com/moulberry/axiom/packet/RequestChunkDataPacketListener.java index db92663..5a891e9 100644 --- a/src/main/java/com/moulberry/axiom/packet/RequestChunkDataPacketListener.java +++ b/src/main/java/com/moulberry/axiom/packet/RequestChunkDataPacketListener.java @@ -93,39 +93,43 @@ public class RequestChunkDataPacketListener implements PluginMessageListener { int playerSectionZ = player.getBlockZ() >> 4; Long2ObjectMap> sections = new Long2ObjectOpenHashMap<>(); - count = friendlyByteBuf.readVarInt(); - for (int i = 0; i < count; i++) { - long pos = friendlyByteBuf.readLong(); - int sx = BlockPos.getX(pos); - int sy = BlockPos.getY(pos); - int sz = BlockPos.getZ(pos); + int maxChunkLoadDistance = this.plugin.configuration.getInt("max-chunk-load-distance"); + if (maxChunkLoadDistance > 0) { + count = friendlyByteBuf.readVarInt(); + for (int i = 0; i < count; i++) { + long pos = friendlyByteBuf.readLong(); - int distance = Math.abs(playerSectionX - sx) + Math.abs(playerSectionZ - sz); - if (distance > 128) continue; + int sx = BlockPos.getX(pos); + int sy = BlockPos.getY(pos); + int sz = BlockPos.getZ(pos); - LevelChunk chunk = level.getChunk(sx, sz); - int sectionIndex = chunk.getSectionIndexFromSectionY(sy); - if (sectionIndex < 0 || sectionIndex >= chunk.getSectionsCount()) continue; - LevelChunkSection section = chunk.getSection(sectionIndex); + int distance = Math.abs(playerSectionX - sx) + Math.abs(playerSectionZ - sz); + if (distance > maxChunkLoadDistance) continue; - if (section.hasOnlyAir()) { - sections.put(pos, null); - } else { - PalettedContainer container = section.getStates(); - sections.put(pos, container); + LevelChunk chunk = level.getChunk(sx, sz); + int sectionIndex = chunk.getSectionIndexFromSectionY(sy); + if (sectionIndex < 0 || sectionIndex >= chunk.getSectionsCount()) continue; + LevelChunkSection section = chunk.getSection(sectionIndex); - if (sendBlockEntitiesInChunks && section.maybeHas(BlockState::hasBlockEntity)) { - for (int x = 0; x < 16; x++) { - for (int y = 0; y < 16; y++) { - for (int z = 0; z < 16; z++) { - BlockState blockState = container.get(x, y, z); - if (blockState.hasBlockEntity()) { - 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(); - blockEntityMap.put(mutableBlockPos.asLong(), CompressedBlockEntity.compress(tag, baos)); + if (section.hasOnlyAir()) { + sections.put(pos, null); + } else { + PalettedContainer container = section.getStates(); + sections.put(pos, container); + + if (sendBlockEntitiesInChunks && section.maybeHas(BlockState::hasBlockEntity)) { + for (int x = 0; x < 16; x++) { + for (int y = 0; y < 16; y++) { + for (int z = 0; z < 16; z++) { + BlockState blockState = container.get(x, y, z); + if (blockState.hasBlockEntity()) { + 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(); + blockEntityMap.put(mutableBlockPos.asLong(), CompressedBlockEntity.compress(tag, baos)); + } } } } @@ -135,7 +139,6 @@ public class RequestChunkDataPacketListener implements PluginMessageListener { } } - // Send response packet boolean firstPart = true; diff --git a/src/main/java/com/moulberry/axiom/packet/SetBlockPacketListener.java b/src/main/java/com/moulberry/axiom/packet/SetBlockPacketListener.java index 247af05..41b28a9 100644 --- a/src/main/java/com/moulberry/axiom/packet/SetBlockPacketListener.java +++ b/src/main/java/com/moulberry/axiom/packet/SetBlockPacketListener.java @@ -38,7 +38,6 @@ import java.lang.reflect.Method; import java.util.Map; import java.util.Objects; import java.util.Optional; -import java.util.logging.Level; public class SetBlockPacketListener implements PluginMessageListener { diff --git a/src/main/java/com/moulberry/axiom/packet/TeleportPacketListener.java b/src/main/java/com/moulberry/axiom/packet/TeleportPacketListener.java index 7fff066..b8b6ec7 100644 --- a/src/main/java/com/moulberry/axiom/packet/TeleportPacketListener.java +++ b/src/main/java/com/moulberry/axiom/packet/TeleportPacketListener.java @@ -38,6 +38,12 @@ public class TeleportPacketListener implements PluginMessageListener { World world = Bukkit.getWorld(namespacedKey); if (world == null) return; + // Prevent teleport based on config value + boolean allowTeleportBetweenWorlds = this.plugin.configuration.getBoolean("allow-teleport-between-worlds"); + if (!allowTeleportBetweenWorlds && world != player.getWorld()) { + return; + } + // Call event AxiomTeleportEvent teleportEvent = new AxiomTeleportEvent(player, new Location(world, x, y, z, yRot, xRot)); Bukkit.getPluginManager().callEvent(teleportEvent); From 55e85a3d0ea10626c6d061b405062e2fb20e4af6 Mon Sep 17 00:00:00 2001 From: Moulberry Date: Sat, 14 Oct 2023 12:17:35 +0800 Subject: [PATCH 06/53] Add new options to default config --- src/main/resources/config.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 065daf9..b79da88 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -4,6 +4,13 @@ max-chunk-sends-per-tick: 0 # Max chunk relights per tick (per-world), 0 = no limit max-chunk-relights-per-tick: 0 +# Maximum distance from which players can load chunks +# Set to 0 to only allow editing within render distance +max-chunk-load-distance: 128 + +# Whether players are allowed to teleport between worlds using views +allow-teleport-between-worlds: true + # Action to take when a user with an incompatible Minecraft version or Axiom version joins # Valid actions are 'kick', 'warn' and 'ignore' # Using 'ignore' may result in corruption and is only provided for debugging purposes From a76aaba3d0a80353d187b94e166d98d5544c5740 Mon Sep 17 00:00:00 2001 From: Moulberry Date: Tue, 17 Oct 2023 08:54:18 +0800 Subject: [PATCH 07/53] Don't update skylight sources on Paper --- .../axiom/packet/RequestChunkDataPacketListener.java | 2 +- .../com/moulberry/axiom/packet/SetBlockPacketListener.java | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/moulberry/axiom/packet/RequestChunkDataPacketListener.java b/src/main/java/com/moulberry/axiom/packet/RequestChunkDataPacketListener.java index 5a891e9..1692bb5 100644 --- a/src/main/java/com/moulberry/axiom/packet/RequestChunkDataPacketListener.java +++ b/src/main/java/com/moulberry/axiom/packet/RequestChunkDataPacketListener.java @@ -72,7 +72,7 @@ public class RequestChunkDataPacketListener implements PluginMessageListener { return; } - boolean sendBlockEntitiesInChunks= friendlyByteBuf.readBoolean(); + boolean sendBlockEntitiesInChunks = friendlyByteBuf.readBoolean(); Long2ObjectMap blockEntityMap = new Long2ObjectOpenHashMap<>(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); diff --git a/src/main/java/com/moulberry/axiom/packet/SetBlockPacketListener.java b/src/main/java/com/moulberry/axiom/packet/SetBlockPacketListener.java index 41b28a9..cb9ee48 100644 --- a/src/main/java/com/moulberry/axiom/packet/SetBlockPacketListener.java +++ b/src/main/java/com/moulberry/axiom/packet/SetBlockPacketListener.java @@ -191,7 +191,9 @@ public class SetBlockPacketListener implements PluginMessageListener { // Update Light if (LightEngine.hasDifferentLightProperties(chunk, blockPos, old, blockState)) { - chunk.getSkyLightSources().update(chunk, x, by, z); + // Note: Skylight Sources not currently needed on Paper due to Starlight + // This might change in the future, so be careful! + // chunk.getSkyLightSources().update(chunk, x, by, z); level.getChunkSource().getLightEngine().checkBlock(blockPos); } From eb1a1cd9cdbe4fd95f96548a51bb6df86eee5a7b Mon Sep 17 00:00:00 2001 From: Moulberry Date: Tue, 7 Nov 2023 13:23:17 +0800 Subject: [PATCH 08/53] Implement whitelist-world-regex and blacklist-world-regex config options --- .../java/com/moulberry/axiom/AxiomPaper.java | 17 +++++++++++++++++ .../axiom/event/AxiomModifyWorldEvent.java | 1 + .../packet/RequestChunkDataPacketListener.java | 5 +---- .../packet/SetBlockBufferPacketListener.java | 14 ++++++-------- .../axiom/packet/SetBlockPacketListener.java | 7 +++---- .../axiom/packet/SetTimePacketListener.java | 6 +++--- src/main/resources/config.yml | 8 ++++++++ 7 files changed, 39 insertions(+), 19 deletions(-) diff --git a/src/main/java/com/moulberry/axiom/AxiomPaper.java b/src/main/java/com/moulberry/axiom/AxiomPaper.java index 880199f..ee38eb0 100644 --- a/src/main/java/com/moulberry/axiom/AxiomPaper.java +++ b/src/main/java/com/moulberry/axiom/AxiomPaper.java @@ -2,6 +2,7 @@ package com.moulberry.axiom; import com.moulberry.axiom.buffer.CompressedBlockEntity; import com.moulberry.axiom.event.AxiomCreateWorldPropertiesEvent; +import com.moulberry.axiom.event.AxiomModifyWorldEvent; import com.moulberry.axiom.packet.*; import com.moulberry.axiom.world_properties.server.ServerWorldPropertiesRegistry; import com.moulberry.axiom.world_properties.server.ServerWorldProperty; @@ -175,6 +176,22 @@ public class AxiomPaper extends JavaPlugin implements Listener { } } + public boolean canModifyWorld(Player player, World world) { + String whitelist = this.configuration.getString("whitelist-world-regex"); + if (whitelist != null && !world.getName().matches(whitelist)) { + return false; + } + + String blacklist = this.configuration.getString("blacklist-world-regex"); + if (blacklist != null && world.getName().matches(blacklist)) { + return false; + } + + AxiomModifyWorldEvent modifyWorldEvent = new AxiomModifyWorldEvent(player, world); + Bukkit.getPluginManager().callEvent(modifyWorldEvent); + return !modifyWorldEvent.isCancelled(); + } + @EventHandler public void onFailMove(PlayerFailMoveEvent event) { if (event.getPlayer().hasPermission("axiom.*")) { diff --git a/src/main/java/com/moulberry/axiom/event/AxiomModifyWorldEvent.java b/src/main/java/com/moulberry/axiom/event/AxiomModifyWorldEvent.java index 405948f..01f4a42 100644 --- a/src/main/java/com/moulberry/axiom/event/AxiomModifyWorldEvent.java +++ b/src/main/java/com/moulberry/axiom/event/AxiomModifyWorldEvent.java @@ -1,5 +1,6 @@ package com.moulberry.axiom.event; +import com.moulberry.axiom.AxiomPaper; import org.bukkit.World; import org.bukkit.entity.Player; import org.bukkit.event.Cancellable; diff --git a/src/main/java/com/moulberry/axiom/packet/RequestChunkDataPacketListener.java b/src/main/java/com/moulberry/axiom/packet/RequestChunkDataPacketListener.java index 1692bb5..3b10061 100644 --- a/src/main/java/com/moulberry/axiom/packet/RequestChunkDataPacketListener.java +++ b/src/main/java/com/moulberry/axiom/packet/RequestChunkDataPacketListener.java @@ -51,10 +51,7 @@ public class RequestChunkDataPacketListener implements PluginMessageListener { return; } - // Call AxiomModifyWorldEvent event - AxiomModifyWorldEvent modifyWorldEvent = new AxiomModifyWorldEvent(bukkitPlayer, bukkitPlayer.getWorld()); - Bukkit.getPluginManager().callEvent(modifyWorldEvent); - if (modifyWorldEvent.isCancelled()) { + if (!this.plugin.canModifyWorld(bukkitPlayer, bukkitPlayer.getWorld())) { sendEmptyResponse(player, id); return; } diff --git a/src/main/java/com/moulberry/axiom/packet/SetBlockBufferPacketListener.java b/src/main/java/com/moulberry/axiom/packet/SetBlockBufferPacketListener.java index 9733e53..64f1911 100644 --- a/src/main/java/com/moulberry/axiom/packet/SetBlockBufferPacketListener.java +++ b/src/main/java/com/moulberry/axiom/packet/SetBlockBufferPacketListener.java @@ -96,10 +96,9 @@ public class SetBlockBufferPacketListener { return; } - // Call AxiomModifyWorldEvent event - AxiomModifyWorldEvent modifyWorldEvent = new AxiomModifyWorldEvent(player.getBukkitEntity(), world.getWorld()); - Bukkit.getPluginManager().callEvent(modifyWorldEvent); - if (modifyWorldEvent.isCancelled()) return; + if (!this.plugin.canModifyWorld(player.getBukkitEntity(), world.getWorld())) { + return; + } // Allowed, apply buffer BlockPos.MutableBlockPos blockPos = new BlockPos.MutableBlockPos(); @@ -257,10 +256,9 @@ public class SetBlockBufferPacketListener { return; } - // Call AxiomModifyWorldEvent event - AxiomModifyWorldEvent modifyWorldEvent = new AxiomModifyWorldEvent(player.getBukkitEntity(), world.getWorld()); - Bukkit.getPluginManager().callEvent(modifyWorldEvent); - if (modifyWorldEvent.isCancelled()) return; + if (!this.plugin.canModifyWorld(player.getBukkitEntity(), world.getWorld())) { + return; + } Set changedChunks = new HashSet<>(); diff --git a/src/main/java/com/moulberry/axiom/packet/SetBlockPacketListener.java b/src/main/java/com/moulberry/axiom/packet/SetBlockPacketListener.java index cb9ee48..c674d29 100644 --- a/src/main/java/com/moulberry/axiom/packet/SetBlockPacketListener.java +++ b/src/main/java/com/moulberry/axiom/packet/SetBlockPacketListener.java @@ -65,10 +65,9 @@ public class SetBlockPacketListener implements PluginMessageListener { return; } - // Check if player is allowed to modify this world - AxiomModifyWorldEvent modifyWorldEvent = new AxiomModifyWorldEvent(bukkitPlayer, bukkitPlayer.getWorld()); - Bukkit.getPluginManager().callEvent(modifyWorldEvent); - if (modifyWorldEvent.isCancelled()) return; + if (!this.plugin.canModifyWorld(bukkitPlayer, bukkitPlayer.getWorld())) { + return; + } // Read packet FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(message)); diff --git a/src/main/java/com/moulberry/axiom/packet/SetTimePacketListener.java b/src/main/java/com/moulberry/axiom/packet/SetTimePacketListener.java index 6b858fc..9ec6def 100644 --- a/src/main/java/com/moulberry/axiom/packet/SetTimePacketListener.java +++ b/src/main/java/com/moulberry/axiom/packet/SetTimePacketListener.java @@ -40,9 +40,9 @@ public class SetTimePacketListener implements PluginMessageListener { if (!level.dimension().equals(key)) return; // Call modify world - AxiomModifyWorldEvent modifyWorldEvent = new AxiomModifyWorldEvent(player, player.getWorld()); - Bukkit.getPluginManager().callEvent(modifyWorldEvent); - if (modifyWorldEvent.isCancelled()) return; + if (!this.plugin.canModifyWorld(player, player.getWorld())) { + return; + } // Call time change event AxiomTimeChangeEvent timeChangeEvent = new AxiomTimeChangeEvent(player, time, freezeTime); diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index b79da88..094b641 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -20,6 +20,14 @@ unsupported-axiom-version: "kick" # Maximum packet size. Must not be less than 32767 max-block-buffer-packet-size: 0x100000 +# Regex for whitelisting worlds +# The world can only be modified if the regex matches the world's name +whitelist-world-regex: null + +# Regex for blacklisting worlds +# If the regex matches the world's name, the world can't be modified +blacklist-world-regex: null + # Toggles for individual packet handlers. May break certain features packet-handlers: hello: true From 93c618a150fa06578d6e4cce96522d12d16ca659 Mon Sep 17 00:00:00 2001 From: Moulberry Date: Tue, 7 Nov 2023 19:29:12 +0800 Subject: [PATCH 09/53] Don't log exceptions in Big Payload Handler --- .../axiom/packet/AxiomBigPayloadHandler.java | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/moulberry/axiom/packet/AxiomBigPayloadHandler.java b/src/main/java/com/moulberry/axiom/packet/AxiomBigPayloadHandler.java index eb64174..57c1748 100644 --- a/src/main/java/com/moulberry/axiom/packet/AxiomBigPayloadHandler.java +++ b/src/main/java/com/moulberry/axiom/packet/AxiomBigPayloadHandler.java @@ -26,10 +26,11 @@ public class AxiomBigPayloadHandler extends ByteToMessageDecoder { @Override protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { - try { + int i = in.readableBytes(); + if (i != 0) { int readerIndex = in.readerIndex(); - int i = in.readableBytes(); - if (i != 0) { + boolean success = false; + try { FriendlyByteBuf buf = new FriendlyByteBuf(in); int packetId = buf.readVarInt(); @@ -39,15 +40,18 @@ public class AxiomBigPayloadHandler extends ByteToMessageDecoder { ServerPlayer player = connection.getPlayer(); if (player != null && player.getBukkitEntity().hasPermission("axiom.*")) { if (listener.onReceive(player, buf)) { + success = true; return; } } } } + } catch (Throwable ignored) { + } finally { + if (!success) { + in.readerIndex(readerIndex); + } } - in.readerIndex(readerIndex); - } catch (Exception e) { - e.printStackTrace(); } ctx.fireChannelRead(in.retain()); From 11402041574c17cda37fba7ce9d50e8779d05279 Mon Sep 17 00:00:00 2001 From: Moulberry Date: Thu, 9 Nov 2023 02:07:59 +0800 Subject: [PATCH 10/53] Don't process inactive channel + skip remaining bytes --- build.gradle.kts | 2 +- .../axiom/packet/AxiomBigPayloadHandler.java | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index caa783c..ebacafe 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -25,7 +25,7 @@ repositories { } dependencies { - paperweight.paperDevBundle("1.20.2-R0.1-20231010.011415-29") + paperweight.paperDevBundle("1.20.2-R0.1-SNAPSHOT") implementation("xyz.jpenilla:reflection-remapper:0.1.0-SNAPSHOT") // Zstd Compression Library diff --git a/src/main/java/com/moulberry/axiom/packet/AxiomBigPayloadHandler.java b/src/main/java/com/moulberry/axiom/packet/AxiomBigPayloadHandler.java index 57c1748..60fa216 100644 --- a/src/main/java/com/moulberry/axiom/packet/AxiomBigPayloadHandler.java +++ b/src/main/java/com/moulberry/axiom/packet/AxiomBigPayloadHandler.java @@ -26,6 +26,12 @@ public class AxiomBigPayloadHandler extends ByteToMessageDecoder { @Override protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { + // Don't process if channel isn't active + if (!ctx.channel().isActive()) { + in.skipBytes(in.readableBytes()); + return; + } + int i = in.readableBytes(); if (i != 0) { int readerIndex = in.readerIndex(); @@ -55,6 +61,11 @@ public class AxiomBigPayloadHandler extends ByteToMessageDecoder { } ctx.fireChannelRead(in.retain()); + + // Skip remaining bytes + if (in.readableBytes() > 0) { + in.skipBytes(in.readableBytes()); + } } @Override From 342aa8036c315845dac6913002b0b3391d149901 Mon Sep 17 00:00:00 2001 From: Moulberry Date: Thu, 9 Nov 2023 17:00:16 +0800 Subject: [PATCH 11/53] Implement preliminary PlotSquared support for SetBlock packet --- .../plotsquared/PlotSquaredIntegration.java | 25 ++++ .../PlotSquaredIntegrationImpl.java | 117 ++++++++++++++++++ .../axiom/packet/SetBlockPacketListener.java | 50 +++++++- 3 files changed, 187 insertions(+), 5 deletions(-) create mode 100644 src/main/java/com/moulberry/axiom/integration/plotsquared/PlotSquaredIntegration.java create mode 100644 src/main/java/com/moulberry/axiom/integration/plotsquared/PlotSquaredIntegrationImpl.java diff --git a/src/main/java/com/moulberry/axiom/integration/plotsquared/PlotSquaredIntegration.java b/src/main/java/com/moulberry/axiom/integration/plotsquared/PlotSquaredIntegration.java new file mode 100644 index 0000000..22ff051 --- /dev/null +++ b/src/main/java/com/moulberry/axiom/integration/plotsquared/PlotSquaredIntegration.java @@ -0,0 +1,25 @@ +package com.moulberry.axiom.integration.plotsquared; + + +import org.bukkit.Bukkit; +import org.bukkit.block.Block; +import org.bukkit.entity.Player; + + +public class PlotSquaredIntegration { + + public static boolean canBreakBlock(Player player, Block block) { + if (!Bukkit.getPluginManager().isPluginEnabled("PlotSquared")) { + return true; + } + return PlotSquaredIntegrationImpl.canBreakBlock(player, block); + } + + public static boolean canPlaceBlock(Player player, org.bukkit.Location loc) { + if (!Bukkit.getPluginManager().isPluginEnabled("PlotSquared")) { + return true; + } + return PlotSquaredIntegrationImpl.canPlaceBlock(player, loc); + } + +} diff --git a/src/main/java/com/moulberry/axiom/integration/plotsquared/PlotSquaredIntegrationImpl.java b/src/main/java/com/moulberry/axiom/integration/plotsquared/PlotSquaredIntegrationImpl.java new file mode 100644 index 0000000..19249c6 --- /dev/null +++ b/src/main/java/com/moulberry/axiom/integration/plotsquared/PlotSquaredIntegrationImpl.java @@ -0,0 +1,117 @@ +package com.moulberry.axiom.integration.plotsquared; + +import com.plotsquared.bukkit.player.BukkitPlayer; +import com.plotsquared.bukkit.util.BukkitUtil; +import com.plotsquared.core.configuration.Settings; +import com.plotsquared.core.location.Location; +import com.plotsquared.core.permissions.Permission; +import com.plotsquared.core.plot.Plot; +import com.plotsquared.core.plot.PlotArea; +import com.plotsquared.core.plot.flag.implementations.BreakFlag; +import com.plotsquared.core.plot.flag.implementations.DoneFlag; +import com.plotsquared.core.plot.flag.types.BlockTypeWrapper; +import com.sk89q.worldedit.bukkit.BukkitAdapter; +import com.sk89q.worldedit.world.block.BlockType; +import org.bukkit.Bukkit; +import org.bukkit.block.Block; +import org.bukkit.entity.Player; + +import java.util.List; + +/* + * PlotSquared, a land and world management plugin for Minecraft. + * Copyright (C) IntellectualSites + * Copyright (C) IntellectualSites team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +public class PlotSquaredIntegrationImpl { + + static boolean canBreakBlock(Player player, Block block) { + Location location = BukkitUtil.adapt(block.getLocation()); + PlotArea area = location.getPlotArea(); + if (area == null) { + return true; + } + + Plot plot = area.getPlot(location); + if (plot != null) { + BukkitPlayer plotPlayer = BukkitUtil.adapt(player); + // == rather than <= as we only care about the "ground level" not being destroyed + if (block.getY() == area.getMinGenHeight()) { + if (!plotPlayer.hasPermission(Permission.PERMISSION_ADMIN_DESTROY_GROUNDLEVEL)) { + return false; + } + } + if (area.notifyIfOutsideBuildArea(plotPlayer, location.getY())) { + return false; + } + // check unowned plots + if (!plot.hasOwner()) { + return plotPlayer.hasPermission(Permission.PERMISSION_ADMIN_DESTROY_UNOWNED, true); + } + // player is breaking another player's plot + if (!plot.isAdded(plotPlayer.getUUID())) { + List destroy = plot.getFlag(BreakFlag.class); + final BlockType blockType = BukkitAdapter.asBlockType(block.getType()); + for (final BlockTypeWrapper blockTypeWrapper : destroy) { + if (blockTypeWrapper.accepts(blockType)) { + return true; + } + } + return plotPlayer.hasPermission(Permission.PERMISSION_ADMIN_DESTROY_OTHER); + } + // plot is 'done' + if (Settings.Done.RESTRICT_BUILDING && DoneFlag.isDone(plot)) { + return plotPlayer.hasPermission(Permission.PERMISSION_ADMIN_BUILD_OTHER); + } + return true; + } + + BukkitPlayer pp = BukkitUtil.adapt(player); + return pp.hasPermission(Permission.PERMISSION_ADMIN_DESTROY_ROAD); + } + + static boolean canPlaceBlock(Player player, org.bukkit.Location loc) { + Location location = BukkitUtil.adapt(loc); + PlotArea area = location.getPlotArea(); + if (area == null) { + return true; + } + + BukkitPlayer pp = BukkitUtil.adapt(player); + Plot plot = area.getPlot(location); + if (plot != null) { + if (area.notifyIfOutsideBuildArea(pp, location.getY())) { + return false; + } + // check unowned plots + if (!plot.hasOwner()) { + return pp.hasPermission(Permission.PERMISSION_ADMIN_BUILD_UNOWNED); + } + // player is breaking another player's plot + if (!plot.isAdded(pp.getUUID())) { + return pp.hasPermission(Permission.PERMISSION_ADMIN_BUILD_OTHER); + } + // plot is 'done' + if (Settings.Done.RESTRICT_BUILDING && DoneFlag.isDone(plot)) { + return pp.hasPermission(Permission.PERMISSION_ADMIN_BUILD_OTHER); + } + return true; + } + + return pp.hasPermission(Permission.PERMISSION_ADMIN_BUILD_ROAD); + } + +} diff --git a/src/main/java/com/moulberry/axiom/packet/SetBlockPacketListener.java b/src/main/java/com/moulberry/axiom/packet/SetBlockPacketListener.java index c674d29..ed1ae7d 100644 --- a/src/main/java/com/moulberry/axiom/packet/SetBlockPacketListener.java +++ b/src/main/java/com/moulberry/axiom/packet/SetBlockPacketListener.java @@ -1,8 +1,12 @@ package com.moulberry.axiom.packet; +import com.google.common.collect.Maps; import com.moulberry.axiom.AxiomPaper; import com.moulberry.axiom.event.AxiomModifyWorldEvent; +import com.moulberry.axiom.integration.plotsquared.PlotSquaredIntegration; import io.netty.buffer.Unpooled; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import net.kyori.adventure.text.Component; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.core.SectionPos; @@ -23,7 +27,9 @@ import net.minecraft.world.level.levelgen.Heightmap; import net.minecraft.world.level.lighting.LightEngine; import net.minecraft.world.phys.BlockHitResult; import org.bukkit.Bukkit; +import org.bukkit.Location; import org.bukkit.block.BlockFace; +import org.bukkit.craftbukkit.v1_20_R2.CraftWorld; import org.bukkit.craftbukkit.v1_20_R2.block.CraftBlock; import org.bukkit.craftbukkit.v1_20_R2.entity.CraftPlayer; import org.bukkit.entity.Player; @@ -38,6 +44,7 @@ import java.lang.reflect.Method; import java.util.Map; import java.util.Objects; import java.util.Optional; +import java.util.function.IntFunction; public class SetBlockPacketListener implements PluginMessageListener { @@ -71,7 +78,9 @@ public class SetBlockPacketListener implements PluginMessageListener { // Read packet FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(message)); - Map blocks = friendlyByteBuf.readMap(FriendlyByteBuf::readBlockPos, buf -> buf.readById(Block.BLOCK_STATE_REGISTRY)); + IntFunction> mapFunction = FriendlyByteBuf.limitValue(Maps::newLinkedHashMapWithExpectedSize, 512); + Map blocks = friendlyByteBuf.readMap(mapFunction, + FriendlyByteBuf::readBlockPos, buf -> buf.readById(Block.BLOCK_STATE_REGISTRY)); boolean updateNeighbors = friendlyByteBuf.readBoolean(); int reason = friendlyByteBuf.readVarInt(); @@ -104,16 +113,47 @@ public class SetBlockPacketListener implements PluginMessageListener { return; } + CraftWorld world = player.level().getWorld(); + // Update blocks if (updateNeighbors) { + int count = 0; for (Map.Entry entry : blocks.entrySet()) { - player.level().setBlock(entry.getKey(), entry.getValue(), 3); - } - } else { - for (Map.Entry entry : blocks.entrySet()) { + if (count++ > 64) break; + BlockPos blockPos = entry.getKey(); BlockState blockState = entry.getValue(); + // Check PlotSquared + if (blockState.isAir()) { + if (!PlotSquaredIntegration.canBreakBlock(bukkitPlayer, world.getBlockAt(blockPos.getX(), blockPos.getY(), blockPos.getZ()))) { + continue; + } + } else if (!PlotSquaredIntegration.canPlaceBlock(bukkitPlayer, new Location(world, blockPos.getX(), blockPos.getY(), blockPos.getZ()))) { + continue; + } + + // Place block + player.level().setBlock(blockPos, blockState, 3); + } + } else { + int count = 0; + for (Map.Entry entry : blocks.entrySet()) { + if (count++ > 64) break; + + BlockPos blockPos = entry.getKey(); + BlockState blockState = entry.getValue(); + + // Check PlotSquared + if (blockState.isAir()) { + if (!PlotSquaredIntegration.canBreakBlock(bukkitPlayer, world.getBlockAt(blockPos.getX(), blockPos.getY(), blockPos.getZ()))) { + continue; + } + } else if (!PlotSquaredIntegration.canPlaceBlock(bukkitPlayer, new Location(world, blockPos.getX(), blockPos.getY(), blockPos.getZ()))) { + continue; + } + + // Place block int bx = blockPos.getX(); int by = blockPos.getY(); int bz = blockPos.getZ(); From dcf70936e26603a2b95249d003b577a4a640e181 Mon Sep 17 00:00:00 2001 From: Moulberry Date: Thu, 9 Nov 2023 17:22:11 +0800 Subject: [PATCH 12/53] Link to modrinth download page in README --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 707ea93..6806e14 100644 --- a/README.md +++ b/README.md @@ -3,3 +3,6 @@ Serverside component for Axiom (todo: better readme) + +## Download +https://modrinth.com/plugin/axiom-paper-plugin/ From 9382958959c3c900a0e160079a4d499e4c0659e8 Mon Sep 17 00:00:00 2001 From: Moulberry Date: Thu, 9 Nov 2023 17:22:27 +0800 Subject: [PATCH 13/53] PlotSquared: Notify when permissions missing --- .../plotsquared/PlotSquaredIntegrationImpl.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/moulberry/axiom/integration/plotsquared/PlotSquaredIntegrationImpl.java b/src/main/java/com/moulberry/axiom/integration/plotsquared/PlotSquaredIntegrationImpl.java index 19249c6..70057f6 100644 --- a/src/main/java/com/moulberry/axiom/integration/plotsquared/PlotSquaredIntegrationImpl.java +++ b/src/main/java/com/moulberry/axiom/integration/plotsquared/PlotSquaredIntegrationImpl.java @@ -50,7 +50,7 @@ public class PlotSquaredIntegrationImpl { BukkitPlayer plotPlayer = BukkitUtil.adapt(player); // == rather than <= as we only care about the "ground level" not being destroyed if (block.getY() == area.getMinGenHeight()) { - if (!plotPlayer.hasPermission(Permission.PERMISSION_ADMIN_DESTROY_GROUNDLEVEL)) { + if (!plotPlayer.hasPermission(Permission.PERMISSION_ADMIN_DESTROY_GROUNDLEVEL, true)) { return false; } } @@ -70,17 +70,17 @@ public class PlotSquaredIntegrationImpl { return true; } } - return plotPlayer.hasPermission(Permission.PERMISSION_ADMIN_DESTROY_OTHER); + return plotPlayer.hasPermission(Permission.PERMISSION_ADMIN_DESTROY_OTHER, true); } // plot is 'done' if (Settings.Done.RESTRICT_BUILDING && DoneFlag.isDone(plot)) { - return plotPlayer.hasPermission(Permission.PERMISSION_ADMIN_BUILD_OTHER); + return plotPlayer.hasPermission(Permission.PERMISSION_ADMIN_BUILD_OTHER, true); } return true; } BukkitPlayer pp = BukkitUtil.adapt(player); - return pp.hasPermission(Permission.PERMISSION_ADMIN_DESTROY_ROAD); + return pp.hasPermission(Permission.PERMISSION_ADMIN_DESTROY_ROAD, true); } static boolean canPlaceBlock(Player player, org.bukkit.Location loc) { @@ -98,20 +98,20 @@ public class PlotSquaredIntegrationImpl { } // check unowned plots if (!plot.hasOwner()) { - return pp.hasPermission(Permission.PERMISSION_ADMIN_BUILD_UNOWNED); + return pp.hasPermission(Permission.PERMISSION_ADMIN_BUILD_UNOWNED, true); } // player is breaking another player's plot if (!plot.isAdded(pp.getUUID())) { - return pp.hasPermission(Permission.PERMISSION_ADMIN_BUILD_OTHER); + return pp.hasPermission(Permission.PERMISSION_ADMIN_BUILD_OTHER, true); } // plot is 'done' if (Settings.Done.RESTRICT_BUILDING && DoneFlag.isDone(plot)) { - return pp.hasPermission(Permission.PERMISSION_ADMIN_BUILD_OTHER); + return pp.hasPermission(Permission.PERMISSION_ADMIN_BUILD_OTHER, true); } return true; } - return pp.hasPermission(Permission.PERMISSION_ADMIN_BUILD_ROAD); + return pp.hasPermission(Permission.PERMISSION_ADMIN_BUILD_ROAD, true); } } From ca7ef8266d08615201823da1d2b97b5e19569ba6 Mon Sep 17 00:00:00 2001 From: Moulberry Date: Thu, 9 Nov 2023 17:42:35 +0800 Subject: [PATCH 14/53] PlotSquared: Don't allow changing time of Plot Worlds --- .../plotsquared/PlotSquaredIntegration.java | 8 ++++++ .../PlotSquaredIntegrationImpl.java | 25 ++++++++++++++++++- .../axiom/packet/SetTimePacketListener.java | 6 +++++ 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/moulberry/axiom/integration/plotsquared/PlotSquaredIntegration.java b/src/main/java/com/moulberry/axiom/integration/plotsquared/PlotSquaredIntegration.java index 22ff051..2ebc218 100644 --- a/src/main/java/com/moulberry/axiom/integration/plotsquared/PlotSquaredIntegration.java +++ b/src/main/java/com/moulberry/axiom/integration/plotsquared/PlotSquaredIntegration.java @@ -2,6 +2,7 @@ package com.moulberry.axiom.integration.plotsquared; import org.bukkit.Bukkit; +import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.entity.Player; @@ -22,4 +23,11 @@ public class PlotSquaredIntegration { return PlotSquaredIntegrationImpl.canPlaceBlock(player, loc); } + public static boolean isPlotWorld(World world) { + if (!Bukkit.getPluginManager().isPluginEnabled("PlotSquared")) { + return true; + } + return PlotSquaredIntegrationImpl.isPlotWorld(world); + } + } diff --git a/src/main/java/com/moulberry/axiom/integration/plotsquared/PlotSquaredIntegrationImpl.java b/src/main/java/com/moulberry/axiom/integration/plotsquared/PlotSquaredIntegrationImpl.java index 70057f6..7f2cfd7 100644 --- a/src/main/java/com/moulberry/axiom/integration/plotsquared/PlotSquaredIntegrationImpl.java +++ b/src/main/java/com/moulberry/axiom/integration/plotsquared/PlotSquaredIntegrationImpl.java @@ -2,6 +2,7 @@ package com.moulberry.axiom.integration.plotsquared; import com.plotsquared.bukkit.player.BukkitPlayer; import com.plotsquared.bukkit.util.BukkitUtil; +import com.plotsquared.core.PlotSquared; import com.plotsquared.core.configuration.Settings; import com.plotsquared.core.location.Location; import com.plotsquared.core.permissions.Permission; @@ -12,11 +13,12 @@ import com.plotsquared.core.plot.flag.implementations.DoneFlag; import com.plotsquared.core.plot.flag.types.BlockTypeWrapper; import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.world.block.BlockType; -import org.bukkit.Bukkit; +import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.entity.Player; import java.util.List; +import java.util.WeakHashMap; /* * PlotSquared, a land and world management plugin for Minecraft. @@ -114,4 +116,25 @@ public class PlotSquaredIntegrationImpl { return pp.hasPermission(Permission.PERMISSION_ADMIN_BUILD_ROAD, true); } + private static final WeakHashMap plotWorldCache = new WeakHashMap<>(); + static boolean isPlotWorld(World world) { + if (plotWorldCache.containsKey(world)) { + return plotWorldCache.get(world); + } + + boolean isPlotWorld = false; + + String worldName = world.getName(); + for (String plotWorld : PlotSquared.get().getPlotAreaManager().getAllWorlds()) { + if (plotWorld.equals(worldName)) { + isPlotWorld = true; + break; + } + } + + plotWorldCache.put(world, isPlotWorld); + return isPlotWorld; + + } + } diff --git a/src/main/java/com/moulberry/axiom/packet/SetTimePacketListener.java b/src/main/java/com/moulberry/axiom/packet/SetTimePacketListener.java index 9ec6def..38a3a25 100644 --- a/src/main/java/com/moulberry/axiom/packet/SetTimePacketListener.java +++ b/src/main/java/com/moulberry/axiom/packet/SetTimePacketListener.java @@ -3,6 +3,7 @@ package com.moulberry.axiom.packet; import com.moulberry.axiom.AxiomPaper; import com.moulberry.axiom.event.AxiomModifyWorldEvent; import com.moulberry.axiom.event.AxiomTimeChangeEvent; +import com.moulberry.axiom.integration.plotsquared.PlotSquaredIntegration; import io.netty.buffer.Unpooled; import net.minecraft.core.registries.Registries; import net.minecraft.network.FriendlyByteBuf; @@ -44,6 +45,11 @@ public class SetTimePacketListener implements PluginMessageListener { return; } + // Don't allow on plot worlds + if (PlotSquaredIntegration.isPlotWorld(player.getWorld())) { + return; + } + // Call time change event AxiomTimeChangeEvent timeChangeEvent = new AxiomTimeChangeEvent(player, time, freezeTime); Bukkit.getPluginManager().callEvent(timeChangeEvent); From e5c8acff02308095cf69406ff420344c6343f0bc Mon Sep 17 00:00:00 2001 From: Moulberry Date: Fri, 10 Nov 2023 16:27:25 +0800 Subject: [PATCH 15/53] Preliminary PlotSquared support for SetBlockBuffer packet --- .../com/moulberry/axiom/integration/Box.java | 68 +++++++++ .../integration/SectionPermissionChecker.java | 137 ++++++++++++++++++ .../plotsquared/PlotSquaredIntegration.java | 8 + .../PlotSquaredIntegrationImpl.java | 92 +++++++++++- .../packet/SetBlockBufferPacketListener.java | 38 ++++- 5 files changed, 336 insertions(+), 7 deletions(-) create mode 100644 src/main/java/com/moulberry/axiom/integration/Box.java create mode 100644 src/main/java/com/moulberry/axiom/integration/SectionPermissionChecker.java diff --git a/src/main/java/com/moulberry/axiom/integration/Box.java b/src/main/java/com/moulberry/axiom/integration/Box.java new file mode 100644 index 0000000..3bf51b4 --- /dev/null +++ b/src/main/java/com/moulberry/axiom/integration/Box.java @@ -0,0 +1,68 @@ +package com.moulberry.axiom.integration; + +import net.minecraft.core.BlockPos; +import org.jetbrains.annotations.Nullable; + +public record Box(int minX, int minY, int minZ, int maxX, int maxY, int maxZ) { + + @Nullable + public Box tryCombine(Box other) { + if (this.completelyOverlaps(other)) { + return this; + } + + if (other.completelyOverlaps(this)) { + return other; + } + + if (other.minX == this.minX && other.maxX == this.maxX) { + if (other.minY == this.minY && other.maxY == this.maxY) { + if (areLineSegmentsContinuous(other.minZ, other.maxZ, this.minZ, this.maxZ)) { + return new Box( + other.minX, other.minY, Math.min(other.minZ, this.minZ), + other.maxX, other.maxY, Math.max(other.maxZ, this.maxZ) + ); + } + } else if (other.minZ == this.minZ && other.maxZ == this.maxZ) { + if (areLineSegmentsContinuous(other.minY, other.maxY, this.minY, this.maxY)) { + return new Box( + other.minX, Math.min(other.minY, this.minY), other.minZ, + other.maxX, Math.max(other.maxY, this.maxY), other.maxZ + ); + } + } + } else if (other.minY == this.minY && other.maxY == this.maxY && + other.minZ == this.minZ && other.maxZ == this.maxZ) { + if (areLineSegmentsContinuous(other.minX, other.maxX, this.minX, this.maxX)) { + return new Box( + Math.min(other.minX, this.minX), other.minY, other.minZ, + Math.max(other.maxX, this.maxX), other.maxY, other.maxZ + ); + } + } + + return null; // Not able to combine + } + + public boolean completelyOverlaps(Box other) { + return this.minX() <= other.minX() && this.minY() <= other.minY() && this.minZ() <= other.minZ() && + this.maxX() >= other.maxX() && this.maxY() >= other.maxY() && this.maxZ() >= other.maxZ(); + } + + public boolean contains(int x, int y, int z) { + return this.minX() <= x && this.minY() <= y && this.minZ() <= z && + this.maxX() >= x && this.maxY() >= y && this.maxZ() >= z; + } + + private static boolean areLineSegmentsContinuous(int min1, int max1, int min2, int max2) { + int size1 = max1 - min1 + 1; + int size2 = max2 - min2 + 1; + + float mid1 = (min1 + max1); + float mid2 = (min2 + max2); + + float midDiff = Math.abs(mid1 - mid2); + return midDiff <= size1 + size2; + } + +} diff --git a/src/main/java/com/moulberry/axiom/integration/SectionPermissionChecker.java b/src/main/java/com/moulberry/axiom/integration/SectionPermissionChecker.java new file mode 100644 index 0000000..cf7d685 --- /dev/null +++ b/src/main/java/com/moulberry/axiom/integration/SectionPermissionChecker.java @@ -0,0 +1,137 @@ +package com.moulberry.axiom.integration; + +import java.util.List; + +public interface SectionPermissionChecker { + + boolean allAllowed(); + boolean noneAllowed(); + boolean allowed(int x, int y, int z); + Box bounds(); + + static SectionPermissionChecker fromAllowedBoxes(List allowed) { + if (allowed.isEmpty()) return NONE_ALLOWED; + + if (allowed.size() == 1) { + Box allowedBox = allowed.get(0); + if (allowedBox.completelyOverlaps(FULL_BOUNDS)) { + return ALL_ALLOWED; + } else { + return new AllAllowedInBox(allowedBox); + } + } + + int minBoundsX = 15; + int minBoundsY = 15; + int minBoundsZ = 15; + int maxBoundsX = 0; + int maxBoundsY = 0; + int maxBoundsZ = 0; + + for (Box box : allowed) { + minBoundsX = Math.min(box.minX(), minBoundsX); + minBoundsY = Math.min(box.minY(), minBoundsY); + minBoundsZ = Math.min(box.minZ(), minBoundsZ); + maxBoundsX = Math.max(box.maxX(), maxBoundsX); + maxBoundsY = Math.max(box.maxY(), maxBoundsY); + maxBoundsZ = Math.max(box.maxZ(), maxBoundsZ); + } + + return new AllAllowedBoxes(new Box(minBoundsX, minBoundsY, minBoundsZ, maxBoundsX, maxBoundsY, maxBoundsZ), allowed); + } + + record AllAllowedInBox(Box box) implements SectionPermissionChecker { + @Override + public boolean allAllowed() { + return true; + } + + @Override + public boolean noneAllowed() { + return false; + } + + @Override + public boolean allowed(int x, int y, int z) { + return true; + } + + @Override + public Box bounds() { + return box; + } + } + + record AllAllowedBoxes(Box bounds, List allowed) implements SectionPermissionChecker { + @Override + public boolean allAllowed() { + return false; + } + + @Override + public boolean noneAllowed() { + return false; + } + + @Override + public boolean allowed(int x, int y, int z) { + for (Box box : this.allowed) { + if (box.contains(x, y, z)) return true; + } + return false; + } + + @Override + public Box bounds() { + return this.bounds; + } + } + + Box FULL_BOUNDS = new Box(0, 0, 0, 15, 15, 15); + SectionPermissionChecker ALL_ALLOWED = new SectionPermissionChecker() { + @Override + public boolean allAllowed() { + return true; + } + + @Override + public boolean noneAllowed() { + return false; + } + + @Override + public boolean allowed(int x, int y, int z) { + return true; + } + + @Override + public Box bounds() { + return FULL_BOUNDS; + } + }; + + + Box EMPTY_BOUNDS = new Box(0, 0, 0, 0, 0, 0); + SectionPermissionChecker NONE_ALLOWED = new SectionPermissionChecker() { + @Override + public boolean allAllowed() { + return false; + } + + @Override + public boolean noneAllowed() { + return true; + } + + @Override + public boolean allowed(int x, int y, int z) { + return false; + } + + @Override + public Box bounds() { + return EMPTY_BOUNDS; + } + }; + +} diff --git a/src/main/java/com/moulberry/axiom/integration/plotsquared/PlotSquaredIntegration.java b/src/main/java/com/moulberry/axiom/integration/plotsquared/PlotSquaredIntegration.java index 2ebc218..e2d51e7 100644 --- a/src/main/java/com/moulberry/axiom/integration/plotsquared/PlotSquaredIntegration.java +++ b/src/main/java/com/moulberry/axiom/integration/plotsquared/PlotSquaredIntegration.java @@ -1,6 +1,7 @@ package com.moulberry.axiom.integration.plotsquared; +import com.moulberry.axiom.integration.SectionPermissionChecker; import org.bukkit.Bukkit; import org.bukkit.World; import org.bukkit.block.Block; @@ -30,4 +31,11 @@ public class PlotSquaredIntegration { return PlotSquaredIntegrationImpl.isPlotWorld(world); } + public static SectionPermissionChecker checkSection(Player player, World world, int sectionX, int sectionY, int sectionZ) { + if (!Bukkit.getPluginManager().isPluginEnabled("PlotSquared")) { + return SectionPermissionChecker.ALL_ALLOWED; + } + return PlotSquaredIntegrationImpl.checkSection(player, world, sectionX, sectionY, sectionZ); + } + } diff --git a/src/main/java/com/moulberry/axiom/integration/plotsquared/PlotSquaredIntegrationImpl.java b/src/main/java/com/moulberry/axiom/integration/plotsquared/PlotSquaredIntegrationImpl.java index 7f2cfd7..c74f3b3 100644 --- a/src/main/java/com/moulberry/axiom/integration/plotsquared/PlotSquaredIntegrationImpl.java +++ b/src/main/java/com/moulberry/axiom/integration/plotsquared/PlotSquaredIntegrationImpl.java @@ -1,5 +1,7 @@ package com.moulberry.axiom.integration.plotsquared; +import com.moulberry.axiom.integration.Box; +import com.moulberry.axiom.integration.SectionPermissionChecker; import com.plotsquared.bukkit.player.BukkitPlayer; import com.plotsquared.bukkit.util.BukkitUtil; import com.plotsquared.core.PlotSquared; @@ -8,17 +10,20 @@ import com.plotsquared.core.location.Location; import com.plotsquared.core.permissions.Permission; import com.plotsquared.core.plot.Plot; import com.plotsquared.core.plot.PlotArea; +import com.plotsquared.core.plot.PlotId; import com.plotsquared.core.plot.flag.implementations.BreakFlag; import com.plotsquared.core.plot.flag.implementations.DoneFlag; import com.plotsquared.core.plot.flag.types.BlockTypeWrapper; 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 org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.entity.Player; +import org.checkerframework.checker.nullness.qual.NonNull; -import java.util.List; -import java.util.WeakHashMap; +import java.util.*; /* * PlotSquared, a land and world management plugin for Minecraft. @@ -117,6 +122,7 @@ public class PlotSquaredIntegrationImpl { } private static final WeakHashMap plotWorldCache = new WeakHashMap<>(); + static boolean isPlotWorld(World world) { if (plotWorldCache.containsKey(world)) { return plotWorldCache.get(world); @@ -134,7 +140,85 @@ public class PlotSquaredIntegrationImpl { plotWorldCache.put(world, isPlotWorld); return isPlotWorld; - } -} + static SectionPermissionChecker checkSection(Player player, World world, int sectionX, int sectionY, int sectionZ) { + int minX = sectionX * 16; + int minY = sectionY * 16; + int minZ = sectionZ * 16; + int maxX = sectionX * 16 + 15; + int maxY = sectionY * 16 + 15; + int maxZ = sectionZ * 16 + 15; + + PlotArea[] plotAreas = PlotSquared.get().getPlotAreaManager().getPlotAreas(world.getName(), new CuboidRegion( + BlockVector3.at(minX, minY, minZ), + BlockVector3.at(maxX, maxY, maxZ) + )); + + if (plotAreas.length == 0) { + return SectionPermissionChecker.ALL_ALLOWED; + } + + Set checkedPlots = new HashSet<>(); + List allowed = new ArrayList<>(); + + for (PlotArea plotArea : plotAreas) { + for (int px = minX; px <= maxX; px += 15) { + for (int py = minY; py <= maxY; py += 15) { + for (int pz = minZ; pz <= maxZ; pz += 15) { + PlotId pid = plotArea.getPlotManager().getPlotId(px, py, pz); + if (pid == null) continue; + Plot plot = plotArea.getOwnedPlotAbs(pid); + if (plot == null) continue; + + if (!checkedPlots.add(plot)) continue; + + if (!plot.hasOwner()) continue; + if (!plot.isAdded(player.getUniqueId())) continue; + if (Settings.Done.RESTRICT_BUILDING && DoneFlag.isDone(plot)) continue; + + Location bottom = plot.getBottomAbs(); + Location top = plot.getTopAbs(); + + int minPlotX = Math.max(Math.min(bottom.getX(), top.getX()), minX); + int minPlotY = Math.max(Math.min(bottom.getY(), top.getY()), minY); + int minPlotZ = Math.max(Math.min(bottom.getZ(), top.getZ()), minZ); + int maxPlotX = Math.min(Math.max(bottom.getX(), top.getX()), maxX); + int maxPlotY = Math.min(Math.max(bottom.getY(), top.getY()), maxY); + int maxPlotZ = Math.min(Math.max(bottom.getZ(), top.getZ()), maxZ); + + if (minPlotX <= minX && minPlotY <= minY && minPlotZ <= minZ && + maxPlotX >= maxX && maxPlotY >= maxY && maxPlotZ >= maxZ) { + return SectionPermissionChecker.ALL_ALLOWED; + } + + allowed.add(new Box(minPlotX - minX, minPlotY - minY, minPlotZ - minZ, + maxPlotX - minX, maxPlotY - minY, maxPlotZ - minZ)); + } + } + } + } + + // Combine + main: + while (allowed.size() >= 2) { + for (int i = 0; i < allowed.size() - 1; i++) { + Box first = allowed.get(i); + for (int j = i + 1; j < allowed.size(); j++) { + Box second = allowed.get(j); + + Box combined = first.tryCombine(second); + if (combined != null) { + allowed.remove(j); + allowed.remove(i); + allowed.add(combined); + continue main; + } + } + } + break; + } + + return SectionPermissionChecker.fromAllowedBoxes(allowed); + } +} \ No newline at end of file diff --git a/src/main/java/com/moulberry/axiom/packet/SetBlockBufferPacketListener.java b/src/main/java/com/moulberry/axiom/packet/SetBlockBufferPacketListener.java index 64f1911..2c2cacb 100644 --- a/src/main/java/com/moulberry/axiom/packet/SetBlockBufferPacketListener.java +++ b/src/main/java/com/moulberry/axiom/packet/SetBlockBufferPacketListener.java @@ -6,6 +6,8 @@ import com.moulberry.axiom.buffer.BiomeBuffer; import com.moulberry.axiom.buffer.BlockBuffer; import com.moulberry.axiom.buffer.CompressedBlockEntity; import com.moulberry.axiom.event.AxiomModifyWorldEvent; +import com.moulberry.axiom.integration.SectionPermissionChecker; +import com.moulberry.axiom.integration.plotsquared.PlotSquaredIntegration; import it.unimi.dsi.fastutil.longs.Long2ObjectMap; import it.unimi.dsi.fastutil.shorts.Short2ObjectMap; import net.minecraft.core.BlockPos; @@ -35,6 +37,7 @@ import net.minecraft.world.level.chunk.PalettedContainer; import net.minecraft.world.level.levelgen.Heightmap; import net.minecraft.world.level.lighting.LightEngine; import org.bukkit.Bukkit; +import org.bukkit.Location; import xyz.jpenilla.reflectionremapper.ReflectionRemapper; import java.lang.reflect.InvocationTargetException; @@ -116,6 +119,11 @@ public class SetBlockBufferPacketListener { continue; } + SectionPermissionChecker checker = PlotSquaredIntegration.checkSection(player.getBukkitEntity(), world.getWorld(), cx, cy, cz); + if (checker != null && checker.noneAllowed()) { + continue; + } + LevelChunk chunk = world.getChunk(cx, cz); LevelChunkSection section = chunk.getSection(world.getSectionIndexFromSectionY(cy)); @@ -144,9 +152,28 @@ public class SetBlockBufferPacketListener { Short2ObjectMap blockEntityChunkMap = buffer.getBlockEntityChunkMap(entry.getLongKey()); - for (int x = 0; x < 16; x++) { - for (int y = 0; y < 16; y++) { - for (int z = 0; z < 16; z++) { + int minX = 0; + int minY = 0; + int minZ = 0; + int maxX = 15; + int maxY = 15; + int maxZ = 15; + + if (checker != null) { + minX = checker.bounds().minX(); + minY = checker.bounds().minY(); + minZ = checker.bounds().minZ(); + maxX = checker.bounds().maxX(); + maxY = checker.bounds().maxY(); + maxZ = checker.bounds().maxZ(); + if (checker.allAllowed()) { + checker = null; + } + } + + for (int x = minX; x <= maxX; x++) { + for (int y = minY; y <= maxY; y++) { + for (int z = minZ; z <= maxZ; z++) { BlockState blockState = container.get(x, y, z); if (blockState == emptyState) continue; @@ -158,6 +185,8 @@ public class SetBlockBufferPacketListener { continue; } + if (checker != null && !checker.allowed(x, y, z)) continue; + BlockState old = section.setBlockState(x, y, z, blockState, true); if (blockState != old) { sectionChanged = true; @@ -284,6 +313,9 @@ public class SetBlockBufferPacketListener { var holder = registry.getHolder(biome); if (holder.isPresent()) { + if (!PlotSquaredIntegration.canPlaceBlock(player.getBukkitEntity(), + new Location(player.getBukkitEntity().getWorld(), x+1, y+1, z+1))) return; + container.set(x & 3, y & 3, z & 3, holder.get()); changedChunks.add(chunk); } From 63d04d3656f4cbb1d57ee6d6f149ecce2577a87d Mon Sep 17 00:00:00 2001 From: Moulberry Date: Sat, 11 Nov 2023 15:40:40 +0800 Subject: [PATCH 16/53] PlotSquared: Support for merged plots --- .../PlotSquaredIntegrationImpl.java | 36 +++++++++++-------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/moulberry/axiom/integration/plotsquared/PlotSquaredIntegrationImpl.java b/src/main/java/com/moulberry/axiom/integration/plotsquared/PlotSquaredIntegrationImpl.java index c74f3b3..44ab1bd 100644 --- a/src/main/java/com/moulberry/axiom/integration/plotsquared/PlotSquaredIntegrationImpl.java +++ b/src/main/java/com/moulberry/axiom/integration/plotsquared/PlotSquaredIntegrationImpl.java @@ -168,7 +168,7 @@ public class PlotSquaredIntegrationImpl { for (int pz = minZ; pz <= maxZ; pz += 15) { PlotId pid = plotArea.getPlotManager().getPlotId(px, py, pz); if (pid == null) continue; - Plot plot = plotArea.getOwnedPlotAbs(pid); + Plot plot = plotArea.getOwnedPlot(pid); if (plot == null) continue; if (!checkedPlots.add(plot)) continue; @@ -177,23 +177,29 @@ public class PlotSquaredIntegrationImpl { if (!plot.isAdded(player.getUniqueId())) continue; if (Settings.Done.RESTRICT_BUILDING && DoneFlag.isDone(plot)) continue; - Location bottom = plot.getBottomAbs(); - Location top = plot.getTopAbs(); + for (CuboidRegion region : plot.getRegions()) { + BlockVector3 minPoint = region.getMinimumPoint(); + BlockVector3 maxPoint = region.getMaximumPoint(); - int minPlotX = Math.max(Math.min(bottom.getX(), top.getX()), minX); - int minPlotY = Math.max(Math.min(bottom.getY(), top.getY()), minY); - int minPlotZ = Math.max(Math.min(bottom.getZ(), top.getZ()), minZ); - int maxPlotX = Math.min(Math.max(bottom.getX(), top.getX()), maxX); - int maxPlotY = Math.min(Math.max(bottom.getY(), top.getY()), maxY); - int maxPlotZ = Math.min(Math.max(bottom.getZ(), top.getZ()), maxZ); + 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); - if (minPlotX <= minX && minPlotY <= minY && minPlotZ <= minZ && - maxPlotX >= maxX && maxPlotY >= maxY && maxPlotZ >= maxZ) { - return SectionPermissionChecker.ALL_ALLOWED; + if (minPlotX > maxPlotX) continue; + if (minPlotY > maxPlotY) continue; + if (minPlotZ > maxPlotZ) continue; + + if (minPlotX <= minX && minPlotY <= minY && minPlotZ <= minZ && + maxPlotX >= maxX && maxPlotY >= maxY && maxPlotZ >= maxZ) { + return SectionPermissionChecker.ALL_ALLOWED; + } + + allowed.add(new Box(minPlotX - minX, minPlotY - minY, minPlotZ - minZ, + maxPlotX - minX, maxPlotY - minY, maxPlotZ - minZ)); } - - allowed.add(new Box(minPlotX - minX, minPlotY - minY, minPlotZ - minZ, - maxPlotX - minX, maxPlotY - minY, maxPlotZ - minZ)); } } } From 83b60d3c6f552137528208bc4830323621561121 Mon Sep 17 00:00:00 2001 From: Moulberry Date: Sat, 11 Nov 2023 15:49:49 +0800 Subject: [PATCH 17/53] PlotSquared: Don't allow loading chunks outside render distance for plot worlds --- .../axiom/packet/RequestChunkDataPacketListener.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/java/com/moulberry/axiom/packet/RequestChunkDataPacketListener.java b/src/main/java/com/moulberry/axiom/packet/RequestChunkDataPacketListener.java index 3b10061..893fa59 100644 --- a/src/main/java/com/moulberry/axiom/packet/RequestChunkDataPacketListener.java +++ b/src/main/java/com/moulberry/axiom/packet/RequestChunkDataPacketListener.java @@ -4,6 +4,7 @@ import com.moulberry.axiom.AxiomConstants; import com.moulberry.axiom.AxiomPaper; import com.moulberry.axiom.buffer.CompressedBlockEntity; import com.moulberry.axiom.event.AxiomModifyWorldEvent; +import com.moulberry.axiom.integration.plotsquared.PlotSquaredIntegration; import io.netty.buffer.Unpooled; import it.unimi.dsi.fastutil.longs.*; import net.minecraft.core.BlockPos; @@ -92,6 +93,12 @@ public class RequestChunkDataPacketListener implements PluginMessageListener { Long2ObjectMap> sections = new Long2ObjectOpenHashMap<>(); int maxChunkLoadDistance = this.plugin.configuration.getInt("max-chunk-load-distance"); + + // Don't allow loading chunks outside render distance for plot worlds + if (PlotSquaredIntegration.isPlotWorld(level.getWorld())) { + maxChunkLoadDistance = 0; + } + if (maxChunkLoadDistance > 0) { count = friendlyByteBuf.readVarInt(); for (int i = 0; i < count; i++) { From 54564c188ba7b86dca3de523b2da38b320c3fda4 Mon Sep 17 00:00:00 2001 From: Moulberry Date: Sat, 11 Nov 2023 18:30:28 +0800 Subject: [PATCH 18/53] Protocol: Limit Views ArrayList to 64 --- .../axiom/packet/SetEditorViewsPacketListener.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/moulberry/axiom/packet/SetEditorViewsPacketListener.java b/src/main/java/com/moulberry/axiom/packet/SetEditorViewsPacketListener.java index 96c257a..5a96d06 100644 --- a/src/main/java/com/moulberry/axiom/packet/SetEditorViewsPacketListener.java +++ b/src/main/java/com/moulberry/axiom/packet/SetEditorViewsPacketListener.java @@ -1,11 +1,15 @@ package com.moulberry.axiom.packet; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; import com.moulberry.axiom.AxiomConstants; import com.moulberry.axiom.AxiomPaper; import com.moulberry.axiom.View; import com.moulberry.axiom.persistence.UUIDDataType; import io.netty.buffer.Unpooled; +import net.minecraft.core.BlockPos; import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.world.level.block.state.BlockState; import org.bukkit.entity.Player; import org.bukkit.persistence.PersistentDataContainer; import org.bukkit.persistence.PersistentDataType; @@ -13,7 +17,9 @@ import org.bukkit.plugin.messaging.PluginMessageListener; import org.jetbrains.annotations.NotNull; import java.util.List; +import java.util.Map; import java.util.UUID; +import java.util.function.IntFunction; public class SetEditorViewsPacketListener implements PluginMessageListener { @@ -30,7 +36,8 @@ public class SetEditorViewsPacketListener implements PluginMessageListener { FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(message)); UUID uuid = friendlyByteBuf.readUUID(); - List views = friendlyByteBuf.readList(View::read); + IntFunction> listFunction = FriendlyByteBuf.limitValue(Lists::newArrayListWithCapacity, 64); + List views = friendlyByteBuf.readCollection(listFunction, View::read); PersistentDataContainer container = player.getPersistentDataContainer(); container.set(AxiomConstants.ACTIVE_VIEW, UUIDDataType.INSTANCE, uuid); From 5b61aebd32b87d2f2297c47170d80248e420ad25 Mon Sep 17 00:00:00 2001 From: Moulberry Date: Thu, 16 Nov 2023 17:33:24 +0800 Subject: [PATCH 19/53] Avoid Bukkit#getWorld, add AxiomUnknownTeleportEvent --- .../axiom/event/AxiomTeleportEvent.java | 1 - .../event/AxiomUnknownTeleportEvent.java | 80 +++++++++++++++++++ .../packet/SetBlockBufferPacketListener.java | 8 +- .../axiom/packet/TeleportPacketListener.java | 18 ++++- 4 files changed, 100 insertions(+), 7 deletions(-) create mode 100644 src/main/java/com/moulberry/axiom/event/AxiomUnknownTeleportEvent.java diff --git a/src/main/java/com/moulberry/axiom/event/AxiomTeleportEvent.java b/src/main/java/com/moulberry/axiom/event/AxiomTeleportEvent.java index 2b7f800..bed8a60 100644 --- a/src/main/java/com/moulberry/axiom/event/AxiomTeleportEvent.java +++ b/src/main/java/com/moulberry/axiom/event/AxiomTeleportEvent.java @@ -1,7 +1,6 @@ package com.moulberry.axiom.event; import org.bukkit.Location; -import org.bukkit.World; import org.bukkit.entity.Player; import org.bukkit.event.Cancellable; import org.bukkit.event.Event; diff --git a/src/main/java/com/moulberry/axiom/event/AxiomUnknownTeleportEvent.java b/src/main/java/com/moulberry/axiom/event/AxiomUnknownTeleportEvent.java new file mode 100644 index 0000000..21dc403 --- /dev/null +++ b/src/main/java/com/moulberry/axiom/event/AxiomUnknownTeleportEvent.java @@ -0,0 +1,80 @@ +package com.moulberry.axiom.event; + +import org.bukkit.NamespacedKey; +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; +import org.jetbrains.annotations.NotNull; + +public class AxiomUnknownTeleportEvent extends Event implements Cancellable { + + private static final HandlerList HANDLERS = new HandlerList(); + + private final Player player; + private final NamespacedKey world; + private final double x; + private final double y; + private final double z; + private final float yaw; + private final float pitch; + private boolean cancelled = false; + + public AxiomUnknownTeleportEvent(Player player, NamespacedKey world, double x, double y, double z, float yaw, float pitch) { + this.player = player; + this.world = world; + this.x = x; + this.y = y; + this.z = z; + this.yaw = yaw; + this.pitch = pitch; + } + + public Player getPlayer() { + return this.player; + } + + public NamespacedKey getWorld() { + return this.world; + } + + public double getX() { + return this.x; + } + + public double getY() { + return this.y; + } + + public double getZ() { + return this.z; + } + + public float getYaw() { + return this.yaw; + } + + public float getPitch() { + return this.pitch; + } + + @Override + public boolean isCancelled() { + return this.cancelled; + } + + @Override + public void setCancelled(boolean cancel) { + this.cancelled = cancel; + } + + public static HandlerList getHandlerList() { + return HANDLERS; + } + + @Override + public @NotNull HandlerList getHandlers() { + return HANDLERS; + } + +} diff --git a/src/main/java/com/moulberry/axiom/packet/SetBlockBufferPacketListener.java b/src/main/java/com/moulberry/axiom/packet/SetBlockBufferPacketListener.java index 2c2cacb..a13eb1b 100644 --- a/src/main/java/com/moulberry/axiom/packet/SetBlockBufferPacketListener.java +++ b/src/main/java/com/moulberry/axiom/packet/SetBlockBufferPacketListener.java @@ -92,8 +92,8 @@ public class SetBlockBufferPacketListener { private void applyBlockBuffer(ServerPlayer player, MinecraftServer server, BlockBuffer buffer, ResourceKey worldKey) { server.execute(() -> { - ServerLevel world = server.getLevel(worldKey); - if (world == null) return; + ServerLevel world = player.serverLevel(); + if (!world.dimension().equals(worldKey)) return; if (!this.plugin.canUseAxiom(player.getBukkitEntity())) { return; @@ -278,8 +278,8 @@ public class SetBlockBufferPacketListener { private void applyBiomeBuffer(ServerPlayer player, MinecraftServer server, BiomeBuffer biomeBuffer, ResourceKey worldKey) { server.execute(() -> { - ServerLevel world = server.getLevel(worldKey); - if (world == null) return; + ServerLevel world = player.serverLevel(); + if (!world.dimension().equals(worldKey)) return; if (!this.plugin.canUseAxiom(player.getBukkitEntity())) { return; diff --git a/src/main/java/com/moulberry/axiom/packet/TeleportPacketListener.java b/src/main/java/com/moulberry/axiom/packet/TeleportPacketListener.java index b8b6ec7..dfabcfa 100644 --- a/src/main/java/com/moulberry/axiom/packet/TeleportPacketListener.java +++ b/src/main/java/com/moulberry/axiom/packet/TeleportPacketListener.java @@ -1,7 +1,7 @@ package com.moulberry.axiom.packet; import com.moulberry.axiom.AxiomPaper; -import com.moulberry.axiom.event.AxiomGameModeChangeEvent; +import com.moulberry.axiom.event.AxiomUnknownTeleportEvent; import com.moulberry.axiom.event.AxiomTeleportEvent; import io.netty.buffer.Unpooled; import net.minecraft.core.registries.Registries; @@ -9,6 +9,8 @@ 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_R2.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_20_R2.util.CraftNamespacedKey; import org.bukkit.entity.Player; import org.bukkit.plugin.messaging.PluginMessageListener; import org.jetbrains.annotations.NotNull; @@ -34,12 +36,24 @@ public class TeleportPacketListener implements PluginMessageListener { float yRot = friendlyByteBuf.readFloat(); float xRot = friendlyByteBuf.readFloat(); + // Prevent teleport based on config value + boolean allowTeleportBetweenWorlds = this.plugin.configuration.getBoolean("allow-teleport-between-worlds"); + if (!allowTeleportBetweenWorlds && !((CraftPlayer)player).getHandle().serverLevel().dimension().equals(resourceKey)) { + return; + } + + // Call unknown teleport event + AxiomUnknownTeleportEvent preTeleportEvent = new AxiomUnknownTeleportEvent(player, + CraftNamespacedKey.fromMinecraft(resourceKey.location()), x, y, z, yRot, xRot); + Bukkit.getPluginManager().callEvent(preTeleportEvent); + if (preTeleportEvent.isCancelled()) return; + + // Get bukkit world NamespacedKey namespacedKey = new NamespacedKey(resourceKey.location().getNamespace(), resourceKey.location().getPath()); World world = Bukkit.getWorld(namespacedKey); if (world == null) return; // Prevent teleport based on config value - boolean allowTeleportBetweenWorlds = this.plugin.configuration.getBoolean("allow-teleport-between-worlds"); if (!allowTeleportBetweenWorlds && world != player.getWorld()) { return; } From 8c6fd853aba54277ff6f7422f88d6c1a1c94a42b Mon Sep 17 00:00:00 2001 From: Moulberry Date: Thu, 16 Nov 2023 17:36:13 +0800 Subject: [PATCH 20/53] WorldProperties: Use NamespacedKey instead of ResourceLocation --- .../java/com/moulberry/axiom/WorldPropertiesExample.java | 9 +++++---- .../server/ServerWorldPropertiesRegistry.java | 7 ++++--- .../world_properties/server/ServerWorldProperty.java | 8 +++++--- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/moulberry/axiom/WorldPropertiesExample.java b/src/main/java/com/moulberry/axiom/WorldPropertiesExample.java index a9f5444..e1a8b72 100644 --- a/src/main/java/com/moulberry/axiom/WorldPropertiesExample.java +++ b/src/main/java/com/moulberry/axiom/WorldPropertiesExample.java @@ -7,6 +7,7 @@ import com.moulberry.axiom.world_properties.server.ServerWorldProperty; import net.kyori.adventure.text.Component; import net.minecraft.resources.ResourceLocation; import net.minecraft.util.Unit; +import org.bukkit.NamespacedKey; import org.bukkit.World; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; @@ -21,28 +22,28 @@ public class WorldPropertiesExample implements Listener { World world = event.getWorld(); - ServerWorldProperty checkbox = new ServerWorldProperty<>(new ResourceLocation("axiom:checkbox"), + ServerWorldProperty checkbox = new ServerWorldProperty<>(new NamespacedKey("axiom", "checkbox"), "Checkbox", false, WorldPropertyWidgetType.CHECKBOX, false, bool -> { world.sendMessage(Component.text("Checkbox: " + bool)); // Do something with input return true; // true to sync with client }); - ServerWorldProperty slider = new ServerWorldProperty<>(new ResourceLocation("axiom:slider"), + ServerWorldProperty slider = new ServerWorldProperty<>(new NamespacedKey("axiom", "slider"), "Slider", false, new WorldPropertyWidgetType.Slider(0, 8), 4, integer -> { world.sendMessage(Component.text("Slider: " + integer)); // Do something with input return true; // true to sync with client }); - ServerWorldProperty textbox = new ServerWorldProperty<>(new ResourceLocation("axiom:textbox"), + ServerWorldProperty textbox = new ServerWorldProperty<>(new NamespacedKey("axiom", "textbox"), "Textbox", false, WorldPropertyWidgetType.TEXTBOX, "Hello", string -> { world.sendMessage(Component.text("Textbox: " + string)); // Do something with input return true; // true to sync with client }); - ServerWorldProperty button = new ServerWorldProperty<>(new ResourceLocation("axiom:button"), + ServerWorldProperty button = new ServerWorldProperty<>(new NamespacedKey("axiom", "button"), "Button", false, WorldPropertyWidgetType.BUTTON, Unit.INSTANCE, unit -> { world.sendMessage(Component.text("Button pressed")); // Do something with input diff --git a/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertiesRegistry.java b/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertiesRegistry.java index 774b549..cb15a52 100644 --- a/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertiesRegistry.java +++ b/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertiesRegistry.java @@ -8,6 +8,7 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.GameRules; import org.bukkit.GameRule; +import org.bukkit.NamespacedKey; import org.bukkit.World; import org.bukkit.craftbukkit.v1_20_R2.CraftWorld; import org.bukkit.entity.Player; @@ -64,7 +65,7 @@ public class ServerWorldPropertiesRegistry { // Time WorldPropertyCategory timeCategory = new WorldPropertyCategory("axiom.editorui.window.world_properties.time", true); - ServerWorldProperty time = new ServerWorldProperty<>(new ResourceLocation("axiom:time"), + ServerWorldProperty time = new ServerWorldProperty<>(new NamespacedKey("axiom", "time"), "axiom.editorui.window.world_properties.time", true, WorldPropertyWidgetType.TIME, 0, integer -> false ); @@ -75,14 +76,14 @@ public class ServerWorldPropertiesRegistry { WorldPropertyCategory weatherCategory = new WorldPropertyCategory("axiom.editorui.window.world_properties.weather", true); - ServerWorldProperty pauseWeather = new ServerWorldProperty<>(new ResourceLocation("axiom:pause_weather"), + ServerWorldProperty pauseWeather = new ServerWorldProperty<>(new NamespacedKey("axiom", "pause_weather"), "axiom.editorui.window.world_properties.pause_weather", true, WorldPropertyWidgetType.CHECKBOX, !world.getGameRuleValue(GameRule.DO_WEATHER_CYCLE), bool -> { world.setGameRule(GameRule.DO_WEATHER_CYCLE, !bool); return false; }); - ServerWorldProperty weatherType = new ServerWorldProperty<>(new ResourceLocation("axiom:weather_type"), + ServerWorldProperty weatherType = new ServerWorldProperty<>(new NamespacedKey("axiom", "weather_type"), "axiom.editorui.window.world_properties.clear_weather", true, new WorldPropertyWidgetType.ButtonArray( List.of("axiom.editorui.window.world_properties.rain_weather", "axiom.editorui.window.world_properties.thunder_weather") diff --git a/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldProperty.java b/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldProperty.java index e5c8d5b..0d44f90 100644 --- a/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldProperty.java +++ b/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldProperty.java @@ -6,7 +6,9 @@ import com.moulberry.axiom.world_properties.WorldPropertyWidgetType; import io.netty.buffer.Unpooled; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.resources.ResourceLocation; +import org.bukkit.NamespacedKey; import org.bukkit.World; +import org.bukkit.craftbukkit.v1_20_R2.util.CraftNamespacedKey; import org.bukkit.entity.Player; import java.util.function.Predicate; @@ -20,9 +22,9 @@ public class ServerWorldProperty { private T value; private Predicate handler; - public ServerWorldProperty(ResourceLocation id, String name, boolean localizeName, WorldPropertyWidgetType widget, - T value, Predicate handler) { - this.id = id; + public ServerWorldProperty(NamespacedKey id, String name, boolean localizeName, WorldPropertyWidgetType widget, + T value, Predicate handler) { + this.id = CraftNamespacedKey.toMinecraft(id); this.name = name; this.localizeName = localizeName; this.widget = widget; From 1ce77ea5e01ba2684e09abd4df272e1fe93567d5 Mon Sep 17 00:00:00 2001 From: Moulberry Date: Thu, 16 Nov 2023 17:48:04 +0800 Subject: [PATCH 21/53] WorldProperties: Use PropertyUpdateHandler functional interface with Player and World --- .../moulberry/axiom/WorldPropertiesExample.java | 11 ++++------- .../axiom/packet/SetWorldPropertyListener.java | 2 +- .../world_properties/PropertyUpdateHandler.java | 17 +++++++++++++++++ .../server/ServerWorldPropertiesRegistry.java | 6 +++--- .../server/ServerWorldProperty.java | 9 +++++---- 5 files changed, 30 insertions(+), 15 deletions(-) create mode 100644 src/main/java/com/moulberry/axiom/world_properties/PropertyUpdateHandler.java diff --git a/src/main/java/com/moulberry/axiom/WorldPropertiesExample.java b/src/main/java/com/moulberry/axiom/WorldPropertiesExample.java index e1a8b72..080fa9e 100644 --- a/src/main/java/com/moulberry/axiom/WorldPropertiesExample.java +++ b/src/main/java/com/moulberry/axiom/WorldPropertiesExample.java @@ -5,7 +5,6 @@ import com.moulberry.axiom.world_properties.WorldPropertyCategory; import com.moulberry.axiom.world_properties.WorldPropertyWidgetType; import com.moulberry.axiom.world_properties.server.ServerWorldProperty; import net.kyori.adventure.text.Component; -import net.minecraft.resources.ResourceLocation; import net.minecraft.util.Unit; import org.bukkit.NamespacedKey; import org.bukkit.World; @@ -20,32 +19,30 @@ public class WorldPropertiesExample implements Listener { public void onCreateWorldProperties(AxiomCreateWorldPropertiesEvent event) { WorldPropertyCategory category = new WorldPropertyCategory("Examples", false); - World world = event.getWorld(); - ServerWorldProperty checkbox = new ServerWorldProperty<>(new NamespacedKey("axiom", "checkbox"), "Checkbox", - false, WorldPropertyWidgetType.CHECKBOX, false, bool -> { + false, WorldPropertyWidgetType.CHECKBOX, false, (player, world, bool) -> { world.sendMessage(Component.text("Checkbox: " + bool)); // Do something with input return true; // true to sync with client }); ServerWorldProperty slider = new ServerWorldProperty<>(new NamespacedKey("axiom", "slider"), "Slider", - false, new WorldPropertyWidgetType.Slider(0, 8), 4, integer -> { + false, new WorldPropertyWidgetType.Slider(0, 8), 4, (player, world, integer) -> { world.sendMessage(Component.text("Slider: " + integer)); // Do something with input return true; // true to sync with client }); ServerWorldProperty textbox = new ServerWorldProperty<>(new NamespacedKey("axiom", "textbox"), "Textbox", - false, WorldPropertyWidgetType.TEXTBOX, "Hello", string -> { + false, WorldPropertyWidgetType.TEXTBOX, "Hello", (player, world, string) -> { world.sendMessage(Component.text("Textbox: " + string)); // Do something with input return true; // true to sync with client }); ServerWorldProperty button = new ServerWorldProperty<>(new NamespacedKey("axiom", "button"), "Button", - false, WorldPropertyWidgetType.BUTTON, Unit.INSTANCE, unit -> { + false, WorldPropertyWidgetType.BUTTON, Unit.INSTANCE, (player, world, unit) -> { world.sendMessage(Component.text("Button pressed")); // Do something with input return true; // true to sync with client }); diff --git a/src/main/java/com/moulberry/axiom/packet/SetWorldPropertyListener.java b/src/main/java/com/moulberry/axiom/packet/SetWorldPropertyListener.java index d9a4ce8..f1166ec 100644 --- a/src/main/java/com/moulberry/axiom/packet/SetWorldPropertyListener.java +++ b/src/main/java/com/moulberry/axiom/packet/SetWorldPropertyListener.java @@ -34,7 +34,7 @@ public class SetWorldPropertyListener implements PluginMessageListener { ServerWorldProperty property = registry.getById(id); if (property != null && property.getType().getTypeId() == type) { - property.update(player.getWorld(), data); + property.update(player, player.getWorld(), data); } FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer()); diff --git a/src/main/java/com/moulberry/axiom/world_properties/PropertyUpdateHandler.java b/src/main/java/com/moulberry/axiom/world_properties/PropertyUpdateHandler.java new file mode 100644 index 0000000..de754f7 --- /dev/null +++ b/src/main/java/com/moulberry/axiom/world_properties/PropertyUpdateHandler.java @@ -0,0 +1,17 @@ +package com.moulberry.axiom.world_properties; + +import org.bukkit.World; +import org.bukkit.entity.Player; + +@FunctionalInterface +public interface PropertyUpdateHandler { + + /** + * @param player the player that updated the property + * @param world the world for which the property has been updated + * @param value the new value of the property + * @return whether to sync the value back to the client + */ + boolean update(Player player, World world, T value); + +} diff --git a/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertiesRegistry.java b/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertiesRegistry.java index cb15a52..b19b703 100644 --- a/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertiesRegistry.java +++ b/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertiesRegistry.java @@ -67,7 +67,7 @@ public class ServerWorldPropertiesRegistry { ServerWorldProperty time = new ServerWorldProperty<>(new NamespacedKey("axiom", "time"), "axiom.editorui.window.world_properties.time", - true, WorldPropertyWidgetType.TIME, 0, integer -> false + true, WorldPropertyWidgetType.TIME, 0, (player, w, integer) -> false ); this.addCategory(timeCategory, List.of(time)); @@ -78,7 +78,7 @@ public class ServerWorldPropertiesRegistry { ServerWorldProperty pauseWeather = new ServerWorldProperty<>(new NamespacedKey("axiom", "pause_weather"), "axiom.editorui.window.world_properties.pause_weather", - true, WorldPropertyWidgetType.CHECKBOX, !world.getGameRuleValue(GameRule.DO_WEATHER_CYCLE), bool -> { + true, WorldPropertyWidgetType.CHECKBOX, !world.getGameRuleValue(GameRule.DO_WEATHER_CYCLE), (player, w, bool) -> { world.setGameRule(GameRule.DO_WEATHER_CYCLE, !bool); return false; }); @@ -87,7 +87,7 @@ public class ServerWorldPropertiesRegistry { "axiom.editorui.window.world_properties.clear_weather", true, new WorldPropertyWidgetType.ButtonArray( List.of("axiom.editorui.window.world_properties.rain_weather", "axiom.editorui.window.world_properties.thunder_weather") - ), 0, index -> { + ), 0, (player, w, index) -> { if (index == 0) { serverLevel.setWeatherParameters(ServerLevel.RAIN_DELAY.sample(serverLevel.random), 0, false, false); } else if (index == 1) { diff --git a/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldProperty.java b/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldProperty.java index 0d44f90..0a2cbda 100644 --- a/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldProperty.java +++ b/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldProperty.java @@ -1,6 +1,7 @@ package com.moulberry.axiom.world_properties.server; import com.moulberry.axiom.AxiomPaper; +import com.moulberry.axiom.world_properties.PropertyUpdateHandler; import com.moulberry.axiom.world_properties.WorldPropertyDataType; import com.moulberry.axiom.world_properties.WorldPropertyWidgetType; import io.netty.buffer.Unpooled; @@ -20,10 +21,10 @@ public class ServerWorldProperty { private final boolean localizeName; private WorldPropertyWidgetType widget; private T value; - private Predicate handler; + private PropertyUpdateHandler handler; public ServerWorldProperty(NamespacedKey id, String name, boolean localizeName, WorldPropertyWidgetType widget, - T value, Predicate handler) { + T value, PropertyUpdateHandler handler) { this.id = CraftNamespacedKey.toMinecraft(id); this.name = name; this.localizeName = localizeName; @@ -40,9 +41,9 @@ public class ServerWorldProperty { return this.widget.dataType(); } - public void update(World world, byte[] data) { + public void update(Player player, World world, byte[] data) { this.value = this.widget.dataType().deserialize(data); - if (this.handler.test(this.value)) { + if (this.handler.update(player, world, this.value)) { this.sync(world); } } From 89e04ffb395d690cc521fba9e0305dcfcf8e502b Mon Sep 17 00:00:00 2001 From: Moulberry Date: Thu, 16 Nov 2023 19:20:28 +0800 Subject: [PATCH 22/53] WorldProperties: Rewrite API --- build.gradle.kts | 2 +- .../java/com/moulberry/axiom/AxiomPaper.java | 19 ++-- .../axiom/WorldPropertiesExample.java | 76 +++++++++------ .../AxiomCreateWorldPropertiesEvent.java | 3 +- .../axiom/packet/HelloPacketListener.java | 2 +- .../packet/SetWorldPropertyListener.java | 6 +- .../WorldPropertyDataType.java | 9 +- .../WorldPropertyWidgetType.java | 5 +- .../server/ServerWorldPropertiesRegistry.java | 97 ++++++++++--------- .../server/ServerWorldProperty.java | 73 ++++++-------- .../server/ServerWorldPropertyHolder.java | 77 +++++++++++++++ 11 files changed, 220 insertions(+), 149 deletions(-) create mode 100644 src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertyHolder.java diff --git a/build.gradle.kts b/build.gradle.kts index ebacafe..eea7a94 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -8,7 +8,7 @@ plugins { } group = "com.moulberry.axiom" -version = "1.5.2" +version = "1.5.4" description = "Serverside component for Axiom on Paper" java { diff --git a/src/main/java/com/moulberry/axiom/AxiomPaper.java b/src/main/java/com/moulberry/axiom/AxiomPaper.java index ee38eb0..138bb95 100644 --- a/src/main/java/com/moulberry/axiom/AxiomPaper.java +++ b/src/main/java/com/moulberry/axiom/AxiomPaper.java @@ -5,7 +5,6 @@ import com.moulberry.axiom.event.AxiomCreateWorldPropertiesEvent; import com.moulberry.axiom.event.AxiomModifyWorldEvent; import com.moulberry.axiom.packet.*; import com.moulberry.axiom.world_properties.server.ServerWorldPropertiesRegistry; -import com.moulberry.axiom.world_properties.server.ServerWorldProperty; import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import io.papermc.paper.event.player.PlayerFailMoveEvent; @@ -19,11 +18,9 @@ import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.protocol.Packet; import net.minecraft.network.protocol.PacketFlow; import net.minecraft.network.protocol.common.ServerboundCustomPayloadPacket; -import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; import org.bukkit.*; import org.bukkit.configuration.Configuration; -import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; @@ -166,7 +163,11 @@ public class AxiomPaper extends JavaPlugin implements Listener { private final WeakHashMap worldProperties = new WeakHashMap<>(); - public @Nullable ServerWorldPropertiesRegistry getWorldProperties(World world) { + public @Nullable ServerWorldPropertiesRegistry getWorldPropertiesIfPresent(World world) { + return worldProperties.get(world); + } + + public @Nullable ServerWorldPropertiesRegistry getOrCreateWorldProperties(World world) { if (worldProperties.containsKey(world)) { return worldProperties.get(world); } else { @@ -207,7 +208,7 @@ public class AxiomPaper extends JavaPlugin implements Listener { public void onChangedWorld(PlayerChangedWorldEvent event) { World world = event.getPlayer().getWorld(); - ServerWorldPropertiesRegistry properties = getWorldProperties(world); + ServerWorldPropertiesRegistry properties = getOrCreateWorldProperties(world); if (properties == null) { event.getPlayer().sendPluginMessage(this, "axiom:register_world_properties", new byte[]{0}); @@ -219,13 +220,7 @@ public class AxiomPaper extends JavaPlugin implements Listener { @EventHandler public void onGameRuleChanged(WorldGameRuleChangeEvent event) { if (event.getGameRule() == GameRule.DO_WEATHER_CYCLE) { - ServerWorldPropertiesRegistry properties = getWorldProperties(event.getWorld()); - if (properties != null) { - ServerWorldProperty property = properties.getById(new ResourceLocation("axiom:pause_weather")); - if (property != null) { - ((ServerWorldProperty)property).setValue(event.getWorld(), !Boolean.parseBoolean(event.getValue())); - } - } + ServerWorldPropertiesRegistry.PAUSE_WEATHER.setValue(event.getWorld(), !Boolean.parseBoolean(event.getValue())); } } diff --git a/src/main/java/com/moulberry/axiom/WorldPropertiesExample.java b/src/main/java/com/moulberry/axiom/WorldPropertiesExample.java index 080fa9e..2decb48 100644 --- a/src/main/java/com/moulberry/axiom/WorldPropertiesExample.java +++ b/src/main/java/com/moulberry/axiom/WorldPropertiesExample.java @@ -5,9 +5,7 @@ import com.moulberry.axiom.world_properties.WorldPropertyCategory; import com.moulberry.axiom.world_properties.WorldPropertyWidgetType; import com.moulberry.axiom.world_properties.server.ServerWorldProperty; import net.kyori.adventure.text.Component; -import net.minecraft.util.Unit; import org.bukkit.NamespacedKey; -import org.bukkit.World; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; @@ -15,39 +13,53 @@ import java.util.List; public class WorldPropertiesExample implements Listener { + private static final ServerWorldProperty CHECKBOX = new ServerWorldProperty<>( + new NamespacedKey("axiom", "checkbox"), + "Checkbox", + false, WorldPropertyWidgetType.CHECKBOX, world -> false, + (player, world, bool) -> { + world.sendMessage(Component.text("Checkbox: " + bool)); // Do something with input + return true; // true to sync with client + } + ); + + private static final ServerWorldProperty SLIDER = new ServerWorldProperty<>( + new NamespacedKey("axiom", "slider"), + "Slider", + false, new WorldPropertyWidgetType.Slider(0, 8), + world -> 4, + (player, world, integer) -> { + world.sendMessage(Component.text("Slider: " + integer)); // Do something with input + return true; // true to sync with client + } + ); + + private static final ServerWorldProperty TEXTBOX = new ServerWorldProperty<>( + new NamespacedKey("axiom", "textbox"), + "Textbox", + false, WorldPropertyWidgetType.TEXTBOX, + world -> "Hello", + (player, world, string) -> { + world.sendMessage(Component.text("Textbox: " + string)); // Do something with input + return true; // true to sync with client + } + ); + + private static final ServerWorldProperty BUTTON = new ServerWorldProperty<>( + new NamespacedKey("axiom", "button"), + "Button", + false, WorldPropertyWidgetType.BUTTON, + world -> null, + (player, world, unit) -> { + world.sendMessage(Component.text("Button pressed")); // Do something with input + return true; // true to sync with client + } + ); + @EventHandler public void onCreateWorldProperties(AxiomCreateWorldPropertiesEvent event) { WorldPropertyCategory category = new WorldPropertyCategory("Examples", false); - - ServerWorldProperty checkbox = new ServerWorldProperty<>(new NamespacedKey("axiom", "checkbox"), - "Checkbox", - false, WorldPropertyWidgetType.CHECKBOX, false, (player, world, bool) -> { - world.sendMessage(Component.text("Checkbox: " + bool)); // Do something with input - return true; // true to sync with client - }); - - ServerWorldProperty slider = new ServerWorldProperty<>(new NamespacedKey("axiom", "slider"), - "Slider", - false, new WorldPropertyWidgetType.Slider(0, 8), 4, (player, world, integer) -> { - world.sendMessage(Component.text("Slider: " + integer)); // Do something with input - return true; // true to sync with client - }); - - ServerWorldProperty textbox = new ServerWorldProperty<>(new NamespacedKey("axiom", "textbox"), - "Textbox", - false, WorldPropertyWidgetType.TEXTBOX, "Hello", (player, world, string) -> { - world.sendMessage(Component.text("Textbox: " + string)); // Do something with input - return true; // true to sync with client - }); - - ServerWorldProperty button = new ServerWorldProperty<>(new NamespacedKey("axiom", "button"), - "Button", - false, WorldPropertyWidgetType.BUTTON, Unit.INSTANCE, (player, world, unit) -> { - world.sendMessage(Component.text("Button pressed")); // Do something with input - return true; // true to sync with client - }); - - event.addCategory(category, List.of(checkbox, slider, textbox, button)); + event.addCategory(category, List.of(CHECKBOX, SLIDER, TEXTBOX, BUTTON)); } } diff --git a/src/main/java/com/moulberry/axiom/event/AxiomCreateWorldPropertiesEvent.java b/src/main/java/com/moulberry/axiom/event/AxiomCreateWorldPropertiesEvent.java index 36cf2d9..087355c 100644 --- a/src/main/java/com/moulberry/axiom/event/AxiomCreateWorldPropertiesEvent.java +++ b/src/main/java/com/moulberry/axiom/event/AxiomCreateWorldPropertiesEvent.java @@ -3,13 +3,12 @@ package com.moulberry.axiom.event; import com.moulberry.axiom.world_properties.WorldPropertyCategory; import com.moulberry.axiom.world_properties.server.ServerWorldPropertiesRegistry; import com.moulberry.axiom.world_properties.server.ServerWorldProperty; +import com.moulberry.axiom.world_properties.server.ServerWorldPropertyHolder; import org.bukkit.World; -import org.bukkit.entity.Player; import org.bukkit.event.Cancellable; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.util.List; diff --git a/src/main/java/com/moulberry/axiom/packet/HelloPacketListener.java b/src/main/java/com/moulberry/axiom/packet/HelloPacketListener.java index 9a7a261..62a2322 100644 --- a/src/main/java/com/moulberry/axiom/packet/HelloPacketListener.java +++ b/src/main/java/com/moulberry/axiom/packet/HelloPacketListener.java @@ -143,7 +143,7 @@ public class HelloPacketListener implements PluginMessageListener { // Register world properties World world = player.getWorld(); - ServerWorldPropertiesRegistry properties = plugin.getWorldProperties(world); + ServerWorldPropertiesRegistry properties = plugin.getOrCreateWorldProperties(world); if (properties == null) { player.sendPluginMessage(plugin, "axiom:register_world_properties", new byte[]{0}); diff --git a/src/main/java/com/moulberry/axiom/packet/SetWorldPropertyListener.java b/src/main/java/com/moulberry/axiom/packet/SetWorldPropertyListener.java index f1166ec..52d043e 100644 --- a/src/main/java/com/moulberry/axiom/packet/SetWorldPropertyListener.java +++ b/src/main/java/com/moulberry/axiom/packet/SetWorldPropertyListener.java @@ -2,7 +2,7 @@ package com.moulberry.axiom.packet; import com.moulberry.axiom.AxiomPaper; import com.moulberry.axiom.world_properties.server.ServerWorldPropertiesRegistry; -import com.moulberry.axiom.world_properties.server.ServerWorldProperty; +import com.moulberry.axiom.world_properties.server.ServerWorldPropertyHolder; import io.netty.buffer.Unpooled; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.resources.ResourceLocation; @@ -29,10 +29,10 @@ public class SetWorldPropertyListener implements PluginMessageListener { byte[] data = friendlyByteBuf.readByteArray(); int updateId = friendlyByteBuf.readVarInt(); - ServerWorldPropertiesRegistry registry = AxiomPaper.PLUGIN.getWorldProperties(player.getWorld()); + ServerWorldPropertiesRegistry registry = AxiomPaper.PLUGIN.getOrCreateWorldProperties(player.getWorld()); if (registry == null) return; - ServerWorldProperty property = registry.getById(id); + ServerWorldPropertyHolder property = registry.getById(id); if (property != null && property.getType().getTypeId() == type) { property.update(player, player.getWorld(), data); } diff --git a/src/main/java/com/moulberry/axiom/world_properties/WorldPropertyDataType.java b/src/main/java/com/moulberry/axiom/world_properties/WorldPropertyDataType.java index 21f8d85..e3d163d 100644 --- a/src/main/java/com/moulberry/axiom/world_properties/WorldPropertyDataType.java +++ b/src/main/java/com/moulberry/axiom/world_properties/WorldPropertyDataType.java @@ -3,7 +3,6 @@ package com.moulberry.axiom.world_properties; import io.netty.buffer.Unpooled; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.util.Unit; import net.minecraft.world.item.Item; import net.minecraft.world.level.block.Block; @@ -118,20 +117,20 @@ public abstract class WorldPropertyDataType { } }; - public static WorldPropertyDataType EMPTY = new WorldPropertyDataType<>() { + public static WorldPropertyDataType EMPTY = new WorldPropertyDataType<>() { @Override public int getTypeId() { return 5; } @Override - public byte[] serialize(Unit value) { + public byte[] serialize(Void value) { return new byte[0]; } @Override - public Unit deserialize(byte[] bytes) { - return Unit.INSTANCE; + public Void deserialize(byte[] bytes) { + return null; } }; diff --git a/src/main/java/com/moulberry/axiom/world_properties/WorldPropertyWidgetType.java b/src/main/java/com/moulberry/axiom/world_properties/WorldPropertyWidgetType.java index 547aefb..7166324 100644 --- a/src/main/java/com/moulberry/axiom/world_properties/WorldPropertyWidgetType.java +++ b/src/main/java/com/moulberry/axiom/world_properties/WorldPropertyWidgetType.java @@ -1,7 +1,6 @@ package com.moulberry.axiom.world_properties; import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.resources.ResourceLocation; import net.minecraft.util.Unit; import java.util.List; @@ -62,9 +61,9 @@ public interface WorldPropertyWidgetType { }; - WorldPropertyWidgetType BUTTON = new WorldPropertyWidgetType<>() { + WorldPropertyWidgetType BUTTON = new WorldPropertyWidgetType<>() { @Override - public WorldPropertyDataType dataType() { + public WorldPropertyDataType dataType() { return WorldPropertyDataType.EMPTY; } diff --git a/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertiesRegistry.java b/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertiesRegistry.java index b19b703..63a8bd9 100644 --- a/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertiesRegistry.java +++ b/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertiesRegistry.java @@ -6,7 +6,6 @@ import io.netty.buffer.Unpooled; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.level.GameRules; import org.bukkit.GameRule; import org.bukkit.NamespacedKey; import org.bukkit.World; @@ -14,33 +13,39 @@ import org.bukkit.craftbukkit.v1_20_R2.CraftWorld; import org.bukkit.entity.Player; import org.bukkit.plugin.Plugin; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; +import java.util.*; public class ServerWorldPropertiesRegistry { - private final LinkedHashMap>> propertyList = new LinkedHashMap<>(); - private final Map> propertyMap = new HashMap<>(); + private final LinkedHashMap>> propertyList = new LinkedHashMap<>(); + private final Map> propertyMap = new HashMap<>(); + private final World world; public ServerWorldPropertiesRegistry(World world) { - this.registerDefault(world); + this.world = world; + this.registerDefault(); } - public ServerWorldProperty getById(ResourceLocation resourceLocation) { + public ServerWorldPropertyHolder getById(ResourceLocation resourceLocation) { return propertyMap.get(resourceLocation); } + @SuppressWarnings("unchecked") public void addCategory(WorldPropertyCategory category, List> properties) { - this.propertyList.put(category, properties); - + List> holders = new ArrayList<>(); for (ServerWorldProperty property : properties) { - ResourceLocation id = property.getId(); + Object defaultValue = property.defaultValueFunction.apply(this.world); + holders.add(new ServerWorldPropertyHolder<>(defaultValue, (ServerWorldProperty) property)); + } + + this.propertyList.put(category, holders); + + for (ServerWorldPropertyHolder holder : holders) { + ResourceLocation id = holder.getId(); if (this.propertyMap.containsKey(id)) { throw new RuntimeException("Duplicate property: " + id); } - this.propertyMap.put(id, property); + this.propertyMap.put(id, holder); } } @@ -49,7 +54,7 @@ public class ServerWorldPropertiesRegistry { buf.writeVarInt(this.propertyList.size()); - for (Map.Entry>> entry : this.propertyList.entrySet()) { + for (Map.Entry>> entry : this.propertyList.entrySet()) { entry.getKey().write(buf); buf.writeCollection(entry.getValue(), (buffer, p) -> p.write(buffer)); } @@ -59,46 +64,48 @@ public class ServerWorldPropertiesRegistry { bukkitPlayer.sendPluginMessage(plugin, "axiom:register_world_properties", bytes); } - public void registerDefault(World world) { - ServerLevel serverLevel = ((CraftWorld)world).getHandle(); + private static final ServerWorldProperty TIME = new ServerWorldProperty<>( + new NamespacedKey("axiom", "time"), + "axiom.editorui.window.world_properties.time", + true, WorldPropertyWidgetType.TIME, world -> 0, (player, w, integer) -> false + ); + public static final ServerWorldProperty PAUSE_WEATHER = new ServerWorldProperty<>( + new NamespacedKey("axiom", "pause_weather"), + "axiom.editorui.window.world_properties.pause_weather", + true, WorldPropertyWidgetType.CHECKBOX, world -> !world.getGameRuleValue(GameRule.DO_WEATHER_CYCLE), (player, world, bool) -> { + world.setGameRule(GameRule.DO_WEATHER_CYCLE, !bool); + return false; + }); + + private static final ServerWorldProperty WEATHER_TYPE = new ServerWorldProperty<>( + new NamespacedKey("axiom", "weather_type"), + "axiom.editorui.window.world_properties.clear_weather", + true, new WorldPropertyWidgetType.ButtonArray( + List.of("axiom.editorui.window.world_properties.rain_weather", "axiom.editorui.window.world_properties.thunder_weather") + ), world -> 0, (player, world, index) -> { + ServerLevel serverLevel = ((CraftWorld)world).getHandle(); + if (index == 0) { + serverLevel.setWeatherParameters(ServerLevel.RAIN_DELAY.sample(serverLevel.random), 0, false, false); + } else if (index == 1) { + serverLevel.setWeatherParameters(0, ServerLevel.RAIN_DURATION.sample(serverLevel.random), true, false); + } else if (index == 2) { + serverLevel.setWeatherParameters(0, ServerLevel.THUNDER_DURATION.sample(serverLevel.random), true, true); + } + return false; + }); + + public void registerDefault() { // Time WorldPropertyCategory timeCategory = new WorldPropertyCategory("axiom.editorui.window.world_properties.time", true); - ServerWorldProperty time = new ServerWorldProperty<>(new NamespacedKey("axiom", "time"), - "axiom.editorui.window.world_properties.time", - true, WorldPropertyWidgetType.TIME, 0, (player, w, integer) -> false - ); - - this.addCategory(timeCategory, List.of(time)); + this.addCategory(timeCategory, List.of(TIME)); // Weather WorldPropertyCategory weatherCategory = new WorldPropertyCategory("axiom.editorui.window.world_properties.weather", true); - ServerWorldProperty pauseWeather = new ServerWorldProperty<>(new NamespacedKey("axiom", "pause_weather"), - "axiom.editorui.window.world_properties.pause_weather", - true, WorldPropertyWidgetType.CHECKBOX, !world.getGameRuleValue(GameRule.DO_WEATHER_CYCLE), (player, w, bool) -> { - world.setGameRule(GameRule.DO_WEATHER_CYCLE, !bool); - return false; - }); - - ServerWorldProperty weatherType = new ServerWorldProperty<>(new NamespacedKey("axiom", "weather_type"), - "axiom.editorui.window.world_properties.clear_weather", - true, new WorldPropertyWidgetType.ButtonArray( - List.of("axiom.editorui.window.world_properties.rain_weather", "axiom.editorui.window.world_properties.thunder_weather") - ), 0, (player, w, index) -> { - if (index == 0) { - serverLevel.setWeatherParameters(ServerLevel.RAIN_DELAY.sample(serverLevel.random), 0, false, false); - } else if (index == 1) { - serverLevel.setWeatherParameters(0, ServerLevel.RAIN_DURATION.sample(serverLevel.random), true, false); - } else if (index == 2) { - serverLevel.setWeatherParameters(0, ServerLevel.THUNDER_DURATION.sample(serverLevel.random), true, true); - } - return false; - }); - - this.addCategory(weatherCategory, List.of(pauseWeather, weatherType)); + this.addCategory(weatherCategory, List.of(PAUSE_WEATHER, WEATHER_TYPE)); } } diff --git a/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldProperty.java b/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldProperty.java index 0a2cbda..8749368 100644 --- a/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldProperty.java +++ b/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldProperty.java @@ -4,32 +4,29 @@ import com.moulberry.axiom.AxiomPaper; import com.moulberry.axiom.world_properties.PropertyUpdateHandler; import com.moulberry.axiom.world_properties.WorldPropertyDataType; import com.moulberry.axiom.world_properties.WorldPropertyWidgetType; -import io.netty.buffer.Unpooled; -import net.minecraft.network.FriendlyByteBuf; import net.minecraft.resources.ResourceLocation; import org.bukkit.NamespacedKey; import org.bukkit.World; import org.bukkit.craftbukkit.v1_20_R2.util.CraftNamespacedKey; -import org.bukkit.entity.Player; -import java.util.function.Predicate; +import java.util.function.Function; public class ServerWorldProperty { private final ResourceLocation id; - private final String name; - private final boolean localizeName; - private WorldPropertyWidgetType widget; - private T value; - private PropertyUpdateHandler handler; + /*package-private*/ final String name; + /*package-private*/ final boolean localizeName; + /*package-private*/ WorldPropertyWidgetType widget; + /*package-private*/ Function defaultValueFunction; + /*package-private*/ PropertyUpdateHandler handler; public ServerWorldProperty(NamespacedKey id, String name, boolean localizeName, WorldPropertyWidgetType widget, - T value, PropertyUpdateHandler handler) { + Function defaultValueFunction, PropertyUpdateHandler handler) { this.id = CraftNamespacedKey.toMinecraft(id); this.name = name; this.localizeName = localizeName; this.widget = widget; - this.value = value; + this.defaultValueFunction = defaultValueFunction; this.handler = handler; } @@ -41,44 +38,30 @@ public class ServerWorldProperty { return this.widget.dataType(); } - public void update(Player player, World world, byte[] data) { - this.value = this.widget.dataType().deserialize(data); - if (this.handler.update(player, world, this.value)) { - this.sync(world); - } - } - - public void setValueWithoutSyncing(T value) { - this.value = value; - } - - public void setValue(World world, T value) { - this.value = value; - this.sync(world); - } - - public void sync(World world) { - FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer()); - - buf.writeResourceLocation(this.id); - buf.writeVarInt(this.widget.dataType().getTypeId()); - buf.writeByteArray(this.widget.dataType().serialize(this.value)); - - byte[] message = new byte[buf.writerIndex()]; - buf.getBytes(0, message); - for (Player player : world.getPlayers()) { - if (AxiomPaper.PLUGIN.activeAxiomPlayers.contains(player.getUniqueId())) { - player.sendPluginMessage(AxiomPaper.PLUGIN, "axiom:set_world_property", message); + @SuppressWarnings("unchecked") + public boolean setValueWithoutSyncing(World world, T value) { + ServerWorldPropertiesRegistry properties = AxiomPaper.PLUGIN.getWorldPropertiesIfPresent(world); + if (properties != null) { + ServerWorldPropertyHolder property = properties.getById(this.id); + if (property != null && property.getProperty() == this) { + ((ServerWorldPropertyHolder)property).setValueWithoutSyncing(value); + return true; } } + return false; } - public void write(FriendlyByteBuf friendlyByteBuf) { - friendlyByteBuf.writeResourceLocation(this.id); - friendlyByteBuf.writeUtf(this.name); - friendlyByteBuf.writeBoolean(this.localizeName); - this.widget.write(friendlyByteBuf); - friendlyByteBuf.writeByteArray(this.widget.dataType().serialize(this.value)); + @SuppressWarnings("unchecked") + public boolean setValue(World world, T value) { + ServerWorldPropertiesRegistry properties = AxiomPaper.PLUGIN.getWorldPropertiesIfPresent(world); + if (properties != null) { + ServerWorldPropertyHolder property = properties.getById(this.id); + if (property != null && property.getProperty() == this) { + ((ServerWorldPropertyHolder)property).setValue(world, value); + return true; + } + } + return false; } } diff --git a/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertyHolder.java b/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertyHolder.java new file mode 100644 index 0000000..72e1cb9 --- /dev/null +++ b/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertyHolder.java @@ -0,0 +1,77 @@ +package com.moulberry.axiom.world_properties.server; + +import com.moulberry.axiom.AxiomPaper; +import com.moulberry.axiom.world_properties.PropertyUpdateHandler; +import com.moulberry.axiom.world_properties.WorldPropertyDataType; +import com.moulberry.axiom.world_properties.WorldPropertyWidgetType; +import io.netty.buffer.Unpooled; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.resources.ResourceLocation; +import org.bukkit.NamespacedKey; +import org.bukkit.World; +import org.bukkit.craftbukkit.v1_20_R2.util.CraftNamespacedKey; +import org.bukkit.entity.Player; + +public class ServerWorldPropertyHolder { + + private T value; + private ServerWorldProperty property; + + public ServerWorldPropertyHolder(T value, ServerWorldProperty property) { + this.value = value; + this.property = property; + } + + public ResourceLocation getId() { + return this.property.getId(); + } + + public WorldPropertyDataType getType() { + return this.property.widget.dataType(); + } + + public ServerWorldProperty getProperty() { + return property; + } + + public void update(Player player, World world, byte[] data) { + this.value = this.property.widget.dataType().deserialize(data); + if (this.property.handler.update(player, world, this.value)) { + this.sync(world); + } + } + + public void setValueWithoutSyncing(T value) { + this.value = value; + } + + public void setValue(World world, T value) { + this.value = value; + this.sync(world); + } + + public void sync(World world) { + FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer()); + + buf.writeResourceLocation(this.getId()); + buf.writeVarInt(this.property.widget.dataType().getTypeId()); + buf.writeByteArray(this.property.widget.dataType().serialize(this.value)); + + byte[] message = new byte[buf.writerIndex()]; + buf.getBytes(0, message); + for (Player player : world.getPlayers()) { + if (AxiomPaper.PLUGIN.activeAxiomPlayers.contains(player.getUniqueId())) { + player.sendPluginMessage(AxiomPaper.PLUGIN, "axiom:set_world_property", message); + } + } + } + + public void write(FriendlyByteBuf friendlyByteBuf) { + friendlyByteBuf.writeResourceLocation(this.getId()); + friendlyByteBuf.writeUtf(this.property.name); + friendlyByteBuf.writeBoolean(this.property.localizeName); + this.property.widget.write(friendlyByteBuf); + friendlyByteBuf.writeByteArray(this.property.widget.dataType().serialize(this.value)); + } + +} From 8a17605969481673715893a27469b7a1a9d0d044 Mon Sep 17 00:00:00 2001 From: Moulberry Date: Thu, 16 Nov 2023 19:26:13 +0800 Subject: [PATCH 23/53] WorldProperties: Create more easily extendable ServerWorldPropertyBase class --- .../AxiomCreateWorldPropertiesEvent.java | 3 +- .../server/ServerWorldPropertiesRegistry.java | 8 +-- .../server/ServerWorldProperty.java | 56 ++++------------ .../server/ServerWorldPropertyBase.java | 64 +++++++++++++++++++ .../server/ServerWorldPropertyHolder.java | 8 +-- 5 files changed, 85 insertions(+), 54 deletions(-) create mode 100644 src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertyBase.java diff --git a/src/main/java/com/moulberry/axiom/event/AxiomCreateWorldPropertiesEvent.java b/src/main/java/com/moulberry/axiom/event/AxiomCreateWorldPropertiesEvent.java index 087355c..7ae6581 100644 --- a/src/main/java/com/moulberry/axiom/event/AxiomCreateWorldPropertiesEvent.java +++ b/src/main/java/com/moulberry/axiom/event/AxiomCreateWorldPropertiesEvent.java @@ -3,6 +3,7 @@ package com.moulberry.axiom.event; import com.moulberry.axiom.world_properties.WorldPropertyCategory; import com.moulberry.axiom.world_properties.server.ServerWorldPropertiesRegistry; import com.moulberry.axiom.world_properties.server.ServerWorldProperty; +import com.moulberry.axiom.world_properties.server.ServerWorldPropertyBase; import com.moulberry.axiom.world_properties.server.ServerWorldPropertyHolder; import org.bukkit.World; import org.bukkit.event.Cancellable; @@ -29,7 +30,7 @@ public class AxiomCreateWorldPropertiesEvent extends Event implements Cancellabl return world; } - public void addCategory(WorldPropertyCategory category, List> properties) { + public void addCategory(WorldPropertyCategory category, List> properties) { this.registry.addCategory(category, properties); } diff --git a/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertiesRegistry.java b/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertiesRegistry.java index 63a8bd9..3f3b5b5 100644 --- a/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertiesRegistry.java +++ b/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertiesRegistry.java @@ -31,11 +31,11 @@ public class ServerWorldPropertiesRegistry { } @SuppressWarnings("unchecked") - public void addCategory(WorldPropertyCategory category, List> properties) { + public void addCategory(WorldPropertyCategory category, List> properties) { List> holders = new ArrayList<>(); - for (ServerWorldProperty property : properties) { - Object defaultValue = property.defaultValueFunction.apply(this.world); - holders.add(new ServerWorldPropertyHolder<>(defaultValue, (ServerWorldProperty) property)); + for (ServerWorldPropertyBase property : properties) { + Object defaultValue = property.getDefaultValue(this.world); + holders.add(new ServerWorldPropertyHolder<>(defaultValue, (ServerWorldPropertyBase) property)); } this.propertyList.put(category, holders); diff --git a/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldProperty.java b/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldProperty.java index 8749368..ea69352 100644 --- a/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldProperty.java +++ b/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldProperty.java @@ -1,67 +1,33 @@ package com.moulberry.axiom.world_properties.server; -import com.moulberry.axiom.AxiomPaper; import com.moulberry.axiom.world_properties.PropertyUpdateHandler; -import com.moulberry.axiom.world_properties.WorldPropertyDataType; 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_R2.util.CraftNamespacedKey; +import org.bukkit.entity.Player; import java.util.function.Function; -public class ServerWorldProperty { +public class ServerWorldProperty extends ServerWorldPropertyBase { - private final ResourceLocation id; - /*package-private*/ final String name; - /*package-private*/ final boolean localizeName; - /*package-private*/ WorldPropertyWidgetType widget; - /*package-private*/ Function defaultValueFunction; - /*package-private*/ PropertyUpdateHandler handler; + private final Function defaultValueFunction; + private final PropertyUpdateHandler handler; public ServerWorldProperty(NamespacedKey id, String name, boolean localizeName, WorldPropertyWidgetType widget, Function defaultValueFunction, PropertyUpdateHandler handler) { - this.id = CraftNamespacedKey.toMinecraft(id); - this.name = name; - this.localizeName = localizeName; - this.widget = widget; + super(id, name, localizeName, widget); this.defaultValueFunction = defaultValueFunction; this.handler = handler; } - public ResourceLocation getId() { - return this.id; + @Override + public T getDefaultValue(World world) { + return this.defaultValueFunction.apply(world); } - public WorldPropertyDataType getType() { - return this.widget.dataType(); - } - - @SuppressWarnings("unchecked") - public boolean setValueWithoutSyncing(World world, T value) { - ServerWorldPropertiesRegistry properties = AxiomPaper.PLUGIN.getWorldPropertiesIfPresent(world); - if (properties != null) { - ServerWorldPropertyHolder property = properties.getById(this.id); - if (property != null && property.getProperty() == this) { - ((ServerWorldPropertyHolder)property).setValueWithoutSyncing(value); - return true; - } - } - return false; - } - - @SuppressWarnings("unchecked") - public boolean setValue(World world, T value) { - ServerWorldPropertiesRegistry properties = AxiomPaper.PLUGIN.getWorldPropertiesIfPresent(world); - if (properties != null) { - ServerWorldPropertyHolder property = properties.getById(this.id); - if (property != null && property.getProperty() == this) { - ((ServerWorldPropertyHolder)property).setValue(world, value); - return true; - } - } - return false; + @Override + public boolean handleUpdateProperty(Player player, World world, T value) { + return this.handler.update(player, world, value); } } diff --git a/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertyBase.java b/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertyBase.java new file mode 100644 index 0000000..ee3690a --- /dev/null +++ b/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertyBase.java @@ -0,0 +1,64 @@ +package com.moulberry.axiom.world_properties.server; + +import com.moulberry.axiom.AxiomPaper; +import com.moulberry.axiom.world_properties.WorldPropertyDataType; +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_R2.util.CraftNamespacedKey; +import org.bukkit.entity.Player; + +public abstract class ServerWorldPropertyBase { + + private final ResourceLocation id; + /*package-private*/ final String name; + /*package-private*/ final boolean localizeName; + /*package-private*/ WorldPropertyWidgetType widget; + + public ServerWorldPropertyBase(NamespacedKey id, String name, boolean localizeName, WorldPropertyWidgetType widget) { + this.id = CraftNamespacedKey.toMinecraft(id); + this.name = name; + this.localizeName = localizeName; + this.widget = widget; + } + + public abstract T getDefaultValue(World world); + + public abstract boolean handleUpdateProperty(Player player, World world, T value); + + public ResourceLocation getId() { + return this.id; + } + + public WorldPropertyDataType getType() { + return this.widget.dataType(); + } + + @SuppressWarnings("unchecked") + public boolean setValueWithoutSyncing(World world, T value) { + ServerWorldPropertiesRegistry properties = AxiomPaper.PLUGIN.getWorldPropertiesIfPresent(world); + if (properties != null) { + ServerWorldPropertyHolder property = properties.getById(this.id); + if (property != null && property.getProperty() == this) { + ((ServerWorldPropertyHolder)property).setValueWithoutSyncing(value); + return true; + } + } + return false; + } + + @SuppressWarnings("unchecked") + public boolean setValue(World world, T value) { + ServerWorldPropertiesRegistry properties = AxiomPaper.PLUGIN.getWorldPropertiesIfPresent(world); + if (properties != null) { + ServerWorldPropertyHolder property = properties.getById(this.id); + if (property != null && property.getProperty() == this) { + ((ServerWorldPropertyHolder)property).setValue(world, value); + return true; + } + } + return false; + } + +} diff --git a/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertyHolder.java b/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertyHolder.java index 72e1cb9..d092512 100644 --- a/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertyHolder.java +++ b/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertyHolder.java @@ -15,9 +15,9 @@ import org.bukkit.entity.Player; public class ServerWorldPropertyHolder { private T value; - private ServerWorldProperty property; + private ServerWorldPropertyBase property; - public ServerWorldPropertyHolder(T value, ServerWorldProperty property) { + public ServerWorldPropertyHolder(T value, ServerWorldPropertyBase property) { this.value = value; this.property = property; } @@ -30,13 +30,13 @@ public class ServerWorldPropertyHolder { return this.property.widget.dataType(); } - public ServerWorldProperty getProperty() { + public ServerWorldPropertyBase getProperty() { return property; } public void update(Player player, World world, byte[] data) { this.value = this.property.widget.dataType().deserialize(data); - if (this.property.handler.update(player, world, this.value)) { + if (this.property.handleUpdateProperty(player, world, this.value)) { this.sync(world); } } From 970678f8b14a0beb9bc8be3b1105f9ce07728c59 Mon Sep 17 00:00:00 2001 From: Moulberry Date: Thu, 16 Nov 2023 19:59:04 +0800 Subject: [PATCH 24/53] Don't allow World Properties to change on worlds you don't have permission to build --- .../axiom/packet/SetWorldPropertyListener.java | 11 +++++++++++ .../world_properties/WorldPropertyWidgetType.java | 1 - 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/moulberry/axiom/packet/SetWorldPropertyListener.java b/src/main/java/com/moulberry/axiom/packet/SetWorldPropertyListener.java index 52d043e..35c70c1 100644 --- a/src/main/java/com/moulberry/axiom/packet/SetWorldPropertyListener.java +++ b/src/main/java/com/moulberry/axiom/packet/SetWorldPropertyListener.java @@ -1,6 +1,7 @@ package com.moulberry.axiom.packet; import com.moulberry.axiom.AxiomPaper; +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; @@ -23,6 +24,16 @@ public class SetWorldPropertyListener implements PluginMessageListener { return; } + // Call modify world + if (!this.plugin.canModifyWorld(player, player.getWorld())) { + return; + } + + // Don't allow on plot worlds + if (PlotSquaredIntegration.isPlotWorld(player.getWorld())) { + return; + } + FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(message)); ResourceLocation id = friendlyByteBuf.readResourceLocation(); int type = friendlyByteBuf.readVarInt(); diff --git a/src/main/java/com/moulberry/axiom/world_properties/WorldPropertyWidgetType.java b/src/main/java/com/moulberry/axiom/world_properties/WorldPropertyWidgetType.java index 7166324..e274cbb 100644 --- a/src/main/java/com/moulberry/axiom/world_properties/WorldPropertyWidgetType.java +++ b/src/main/java/com/moulberry/axiom/world_properties/WorldPropertyWidgetType.java @@ -60,7 +60,6 @@ public interface WorldPropertyWidgetType { } }; - WorldPropertyWidgetType BUTTON = new WorldPropertyWidgetType<>() { @Override public WorldPropertyDataType dataType() { From d4e950f9965b8426bcff40e13f39604aaceb39ab Mon Sep 17 00:00:00 2001 From: Moulberry Date: Thu, 16 Nov 2023 20:10:55 +0800 Subject: [PATCH 25/53] Add PropertyUpdateResult enum, adding possible 'cancel' action to prevent value write --- .../axiom/WorldPropertiesExample.java | 9 +++--- .../packet/SetWorldPropertyListener.java | 31 ++++++++++++------- .../PropertyUpdateHandler.java | 5 +-- .../server/PropertyUpdateResult.java | 25 +++++++++++++++ .../server/ServerWorldPropertiesRegistry.java | 19 +++++++----- .../server/ServerWorldProperty.java | 2 +- .../server/ServerWorldPropertyBase.java | 2 +- .../server/ServerWorldPropertyHolder.java | 8 +++-- 8 files changed, 72 insertions(+), 29 deletions(-) create mode 100644 src/main/java/com/moulberry/axiom/world_properties/server/PropertyUpdateResult.java diff --git a/src/main/java/com/moulberry/axiom/WorldPropertiesExample.java b/src/main/java/com/moulberry/axiom/WorldPropertiesExample.java index 2decb48..314d253 100644 --- a/src/main/java/com/moulberry/axiom/WorldPropertiesExample.java +++ b/src/main/java/com/moulberry/axiom/WorldPropertiesExample.java @@ -3,6 +3,7 @@ package com.moulberry.axiom; import com.moulberry.axiom.event.AxiomCreateWorldPropertiesEvent; import com.moulberry.axiom.world_properties.WorldPropertyCategory; import com.moulberry.axiom.world_properties.WorldPropertyWidgetType; +import com.moulberry.axiom.world_properties.server.PropertyUpdateResult; import com.moulberry.axiom.world_properties.server.ServerWorldProperty; import net.kyori.adventure.text.Component; import org.bukkit.NamespacedKey; @@ -19,7 +20,7 @@ public class WorldPropertiesExample implements Listener { false, WorldPropertyWidgetType.CHECKBOX, world -> false, (player, world, bool) -> { world.sendMessage(Component.text("Checkbox: " + bool)); // Do something with input - return true; // true to sync with client + return PropertyUpdateResult.UPDATE_AND_SYNC; // sync with client } ); @@ -30,7 +31,7 @@ public class WorldPropertiesExample implements Listener { world -> 4, (player, world, integer) -> { world.sendMessage(Component.text("Slider: " + integer)); // Do something with input - return true; // true to sync with client + return PropertyUpdateResult.UPDATE_AND_SYNC; // sync with client } ); @@ -41,7 +42,7 @@ public class WorldPropertiesExample implements Listener { world -> "Hello", (player, world, string) -> { world.sendMessage(Component.text("Textbox: " + string)); // Do something with input - return true; // true to sync with client + return PropertyUpdateResult.UPDATE_AND_SYNC; // sync with client } ); @@ -52,7 +53,7 @@ public class WorldPropertiesExample implements Listener { world -> null, (player, world, unit) -> { world.sendMessage(Component.text("Button pressed")); // Do something with input - return true; // true to sync with client + return PropertyUpdateResult.UPDATE_AND_SYNC; // sync with client } ); diff --git a/src/main/java/com/moulberry/axiom/packet/SetWorldPropertyListener.java b/src/main/java/com/moulberry/axiom/packet/SetWorldPropertyListener.java index 35c70c1..a6b4691 100644 --- a/src/main/java/com/moulberry/axiom/packet/SetWorldPropertyListener.java +++ b/src/main/java/com/moulberry/axiom/packet/SetWorldPropertyListener.java @@ -24,30 +24,39 @@ public class SetWorldPropertyListener implements PluginMessageListener { return; } - // Call modify world - if (!this.plugin.canModifyWorld(player, player.getWorld())) { - return; - } - - // Don't allow on plot worlds - if (PlotSquaredIntegration.isPlotWorld(player.getWorld())) { - return; - } - FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(message)); ResourceLocation id = friendlyByteBuf.readResourceLocation(); int type = friendlyByteBuf.readVarInt(); byte[] data = friendlyByteBuf.readByteArray(); int updateId = friendlyByteBuf.readVarInt(); + // Call modify world + if (!this.plugin.canModifyWorld(player, player.getWorld())) { + sendAck(player, updateId); + return; + } + + // Don't allow on plot worlds + if (PlotSquaredIntegration.isPlotWorld(player.getWorld())) { + sendAck(player, updateId); + return; + } + ServerWorldPropertiesRegistry registry = AxiomPaper.PLUGIN.getOrCreateWorldProperties(player.getWorld()); - if (registry == null) return; + if (registry == null) { + sendAck(player, updateId); + return; + } ServerWorldPropertyHolder property = registry.getById(id); if (property != null && property.getType().getTypeId() == type) { property.update(player, player.getWorld(), data); } + sendAck(player, updateId); + } + + private void sendAck(Player player, int updateId) { FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer()); buf.writeVarInt(updateId); diff --git a/src/main/java/com/moulberry/axiom/world_properties/PropertyUpdateHandler.java b/src/main/java/com/moulberry/axiom/world_properties/PropertyUpdateHandler.java index de754f7..de081f3 100644 --- a/src/main/java/com/moulberry/axiom/world_properties/PropertyUpdateHandler.java +++ b/src/main/java/com/moulberry/axiom/world_properties/PropertyUpdateHandler.java @@ -1,5 +1,6 @@ package com.moulberry.axiom.world_properties; +import com.moulberry.axiom.world_properties.server.PropertyUpdateResult; import org.bukkit.World; import org.bukkit.entity.Player; @@ -10,8 +11,8 @@ public interface PropertyUpdateHandler { * @param player the player that updated the property * @param world the world for which the property has been updated * @param value the new value of the property - * @return whether to sync the value back to the client + * @return {@link PropertyUpdateResult} */ - boolean update(Player player, World world, T value); + PropertyUpdateResult update(Player player, World world, T value); } diff --git a/src/main/java/com/moulberry/axiom/world_properties/server/PropertyUpdateResult.java b/src/main/java/com/moulberry/axiom/world_properties/server/PropertyUpdateResult.java new file mode 100644 index 0000000..01072ec --- /dev/null +++ b/src/main/java/com/moulberry/axiom/world_properties/server/PropertyUpdateResult.java @@ -0,0 +1,25 @@ +package com.moulberry.axiom.world_properties.server; + +public enum PropertyUpdateResult { + + UPDATE_AND_SYNC(true, true), + UPDATE_WITHOUT_SYNC(true, false), + CANCEL(false, false); + + private final boolean update; + private final boolean sync; + + PropertyUpdateResult(boolean update, boolean sync) { + this.update = update; + this.sync = sync; + } + + public boolean isUpdate() { + return this.update; + } + + public boolean isSync() { + return this.sync; + } + +} diff --git a/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertiesRegistry.java b/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertiesRegistry.java index 3f3b5b5..78fef4f 100644 --- a/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertiesRegistry.java +++ b/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertiesRegistry.java @@ -67,16 +67,19 @@ public class ServerWorldPropertiesRegistry { private static final ServerWorldProperty TIME = new ServerWorldProperty<>( new NamespacedKey("axiom", "time"), "axiom.editorui.window.world_properties.time", - true, WorldPropertyWidgetType.TIME, world -> 0, (player, w, integer) -> false + true, WorldPropertyWidgetType.TIME, world -> 0, + (player, w, integer) -> PropertyUpdateResult.UPDATE_WITHOUT_SYNC ); public static final ServerWorldProperty PAUSE_WEATHER = new ServerWorldProperty<>( - new NamespacedKey("axiom", "pause_weather"), - "axiom.editorui.window.world_properties.pause_weather", - true, WorldPropertyWidgetType.CHECKBOX, world -> !world.getGameRuleValue(GameRule.DO_WEATHER_CYCLE), (player, world, bool) -> { - world.setGameRule(GameRule.DO_WEATHER_CYCLE, !bool); - return false; - }); + new NamespacedKey("axiom", "pause_weather"), + "axiom.editorui.window.world_properties.pause_weather", + true, WorldPropertyWidgetType.CHECKBOX, world -> !world.getGameRuleValue(GameRule.DO_WEATHER_CYCLE), + (player, world, bool) -> { + world.setGameRule(GameRule.DO_WEATHER_CYCLE, !bool); + return PropertyUpdateResult.UPDATE_WITHOUT_SYNC; + } + ); private static final ServerWorldProperty WEATHER_TYPE = new ServerWorldProperty<>( new NamespacedKey("axiom", "weather_type"), @@ -92,7 +95,7 @@ public class ServerWorldPropertiesRegistry { } else if (index == 2) { serverLevel.setWeatherParameters(0, ServerLevel.THUNDER_DURATION.sample(serverLevel.random), true, true); } - return false; + return PropertyUpdateResult.UPDATE_WITHOUT_SYNC; }); public void registerDefault() { diff --git a/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldProperty.java b/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldProperty.java index ea69352..b38b2e6 100644 --- a/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldProperty.java +++ b/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldProperty.java @@ -26,7 +26,7 @@ public class ServerWorldProperty extends ServerWorldPropertyBase { } @Override - public boolean handleUpdateProperty(Player player, World world, T value) { + public PropertyUpdateResult handleUpdateProperty(Player player, World world, T value) { return this.handler.update(player, world, value); } diff --git a/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertyBase.java b/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertyBase.java index ee3690a..802d9c8 100644 --- a/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertyBase.java +++ b/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertyBase.java @@ -25,7 +25,7 @@ public abstract class ServerWorldPropertyBase { public abstract T getDefaultValue(World world); - public abstract boolean handleUpdateProperty(Player player, World world, T value); + public abstract PropertyUpdateResult handleUpdateProperty(Player player, World world, T value); public ResourceLocation getId() { return this.id; diff --git a/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertyHolder.java b/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertyHolder.java index d092512..69cf77d 100644 --- a/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertyHolder.java +++ b/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertyHolder.java @@ -35,8 +35,12 @@ public class ServerWorldPropertyHolder { } public void update(Player player, World world, byte[] data) { - this.value = this.property.widget.dataType().deserialize(data); - if (this.property.handleUpdateProperty(player, world, this.value)) { + PropertyUpdateResult result = this.property.handleUpdateProperty(player, world, this.value); + + if (result.isUpdate()) { + this.value = this.property.widget.dataType().deserialize(data); + } + if (result.isSync()) { this.sync(world); } } From a8b4ee2a1df0c4b3d066e1d25b416fed36b14c33 Mon Sep 17 00:00:00 2001 From: Moulberry Date: Thu, 16 Nov 2023 22:30:37 +0800 Subject: [PATCH 26/53] WorldProperties: Pass correct value to handleUpdateProperty, prevent excessive syncing with repeated call to setValue --- .../server/ServerWorldPropertyHolder.java | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertyHolder.java b/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertyHolder.java index 69cf77d..210f23a 100644 --- a/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertyHolder.java +++ b/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertyHolder.java @@ -16,6 +16,7 @@ public class ServerWorldPropertyHolder { private T value; private ServerWorldPropertyBase property; + private boolean unsyncedValue = false; public ServerWorldPropertyHolder(T value, ServerWorldPropertyBase property) { this.value = value; @@ -35,10 +36,15 @@ public class ServerWorldPropertyHolder { } public void update(Player player, World world, byte[] data) { - PropertyUpdateResult result = this.property.handleUpdateProperty(player, world, this.value); + T newValue = this.property.widget.dataType().deserialize(data); + + PropertyUpdateResult result = this.property.handleUpdateProperty(player, world, newValue); if (result.isUpdate()) { - this.value = this.property.widget.dataType().deserialize(data); + this.value = newValue; + if (!result.isSync()) { + this.unsyncedValue = true; + } } if (result.isSync()) { this.sync(world); @@ -50,8 +56,11 @@ public class ServerWorldPropertyHolder { } public void setValue(World world, T value) { + boolean sync = this.unsyncedValue || !value.equals(this.value); this.value = value; - this.sync(world); + if (sync) { + this.sync(world); + } } public void sync(World world) { From bf43e7c0b92b190414bb413367dcf100af716aa0 Mon Sep 17 00:00:00 2001 From: Moulberry Date: Thu, 16 Nov 2023 22:33:11 +0800 Subject: [PATCH 27/53] WorldProperties: Set unsyncedValue back to false after syncing --- .../world_properties/server/ServerWorldPropertyHolder.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertyHolder.java b/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertyHolder.java index 210f23a..b2f90f7 100644 --- a/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertyHolder.java +++ b/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertyHolder.java @@ -77,6 +77,8 @@ public class ServerWorldPropertyHolder { player.sendPluginMessage(AxiomPaper.PLUGIN, "axiom:set_world_property", message); } } + + this.unsyncedValue = false; } public void write(FriendlyByteBuf friendlyByteBuf) { From b6afa50b0421ef39411ac8a9d9f956d7ddb59d8a Mon Sep 17 00:00:00 2001 From: Moulberry Date: Thu, 16 Nov 2023 22:36:12 +0800 Subject: [PATCH 28/53] WorldProperties: Small cleanup --- .../server/ServerWorldPropertyHolder.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertyHolder.java b/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertyHolder.java index b2f90f7..58a9276 100644 --- a/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertyHolder.java +++ b/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertyHolder.java @@ -42,13 +42,13 @@ public class ServerWorldPropertyHolder { if (result.isUpdate()) { this.value = newValue; - if (!result.isSync()) { + + if (result.isSync()) { + this.sync(world); + } else { this.unsyncedValue = true; } } - if (result.isSync()) { - this.sync(world); - } } public void setValueWithoutSyncing(T value) { From f38226c9fbb8ba333fe1667c2abf11242e7287f8 Mon Sep 17 00:00:00 2001 From: Moulberry Date: Thu, 16 Nov 2023 22:39:20 +0800 Subject: [PATCH 29/53] WorldProperties: Prevent NPE if setValue is called with null --- .../world_properties/server/ServerWorldPropertyHolder.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertyHolder.java b/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertyHolder.java index 58a9276..676f2c6 100644 --- a/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertyHolder.java +++ b/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertyHolder.java @@ -12,6 +12,8 @@ import org.bukkit.World; import org.bukkit.craftbukkit.v1_20_R2.util.CraftNamespacedKey; import org.bukkit.entity.Player; +import java.util.Objects; + public class ServerWorldPropertyHolder { private T value; @@ -56,7 +58,7 @@ public class ServerWorldPropertyHolder { } public void setValue(World world, T value) { - boolean sync = this.unsyncedValue || !value.equals(this.value); + boolean sync = this.unsyncedValue || !Objects.equals(value, this.value); this.value = value; if (sync) { this.sync(world); From 0c05b3a46f65c9a3eecab20ae4381c387b1cb341 Mon Sep 17 00:00:00 2001 From: Moulberry Date: Thu, 16 Nov 2023 23:54:49 +0800 Subject: [PATCH 30/53] WorldProperties: Add default serialization for null values --- .../axiom/world_properties/WorldPropertyDataType.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/moulberry/axiom/world_properties/WorldPropertyDataType.java b/src/main/java/com/moulberry/axiom/world_properties/WorldPropertyDataType.java index e3d163d..23790f6 100644 --- a/src/main/java/com/moulberry/axiom/world_properties/WorldPropertyDataType.java +++ b/src/main/java/com/moulberry/axiom/world_properties/WorldPropertyDataType.java @@ -4,7 +4,9 @@ import io.netty.buffer.Unpooled; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.world.item.Item; +import net.minecraft.world.item.Items; import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; import java.nio.charset.StandardCharsets; @@ -22,7 +24,7 @@ public abstract class WorldPropertyDataType { @Override public byte[] serialize(Boolean value) { - return new byte[] { value ? (byte)1 : (byte)0 }; + return new byte[] { value != null && value ? (byte)1 : (byte)0 }; } @Override @@ -39,6 +41,8 @@ public abstract class WorldPropertyDataType { @Override public byte[] serialize(Integer value) { + if (value == null) value = 0; + FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer(8)); buf.writeVarInt(value); @@ -62,6 +66,7 @@ public abstract class WorldPropertyDataType { @Override public byte[] serialize(String value) { + if (value == null) value = ""; return value.getBytes(StandardCharsets.UTF_8); } @@ -79,6 +84,8 @@ public abstract class WorldPropertyDataType { @Override public byte[] serialize(Item value) { + if (value == null) value = Items.AIR; + FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer(8)); buf.writeId(BuiltInRegistries.ITEM, value); @@ -102,6 +109,8 @@ public abstract class WorldPropertyDataType { @Override public byte[] serialize(Block value) { + if (value == null) value = Blocks.AIR; + FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer(8)); buf.writeId(BuiltInRegistries.BLOCK, value); From c027e56fc4f166f662bdab19baf80db3b59b4c0d Mon Sep 17 00:00:00 2001 From: Moulberry Date: Fri, 17 Nov 2023 00:18:28 +0800 Subject: [PATCH 31/53] PlotSquared: Change isPlotWorld logic to check for non-zero PlotArea count --- .../plotsquared/PlotSquaredIntegrationImpl.java | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/moulberry/axiom/integration/plotsquared/PlotSquaredIntegrationImpl.java b/src/main/java/com/moulberry/axiom/integration/plotsquared/PlotSquaredIntegrationImpl.java index 44ab1bd..e530e0d 100644 --- a/src/main/java/com/moulberry/axiom/integration/plotsquared/PlotSquaredIntegrationImpl.java +++ b/src/main/java/com/moulberry/axiom/integration/plotsquared/PlotSquaredIntegrationImpl.java @@ -128,16 +128,9 @@ public class PlotSquaredIntegrationImpl { return plotWorldCache.get(world); } - boolean isPlotWorld = false; - String worldName = world.getName(); - for (String plotWorld : PlotSquared.get().getPlotAreaManager().getAllWorlds()) { - if (plotWorld.equals(worldName)) { - isPlotWorld = true; - break; - } - } - + PlotArea[] plotAreas = PlotSquared.get().getPlotAreaManager().getPlotAreas(worldName, null); + boolean isPlotWorld = plotAreas.length > 0; plotWorldCache.put(world, isPlotWorld); return isPlotWorld; } From b2d67e4f91b3ca589bc3b775b5e39cbbe047d409 Mon Sep 17 00:00:00 2001 From: Moulberry Date: Fri, 17 Nov 2023 00:36:33 +0800 Subject: [PATCH 32/53] PlotSquared: Return correct value when PlotSquared isn't installed --- .../axiom/integration/plotsquared/PlotSquaredIntegration.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/moulberry/axiom/integration/plotsquared/PlotSquaredIntegration.java b/src/main/java/com/moulberry/axiom/integration/plotsquared/PlotSquaredIntegration.java index e2d51e7..e307a29 100644 --- a/src/main/java/com/moulberry/axiom/integration/plotsquared/PlotSquaredIntegration.java +++ b/src/main/java/com/moulberry/axiom/integration/plotsquared/PlotSquaredIntegration.java @@ -26,7 +26,7 @@ public class PlotSquaredIntegration { public static boolean isPlotWorld(World world) { if (!Bukkit.getPluginManager().isPluginEnabled("PlotSquared")) { - return true; + return false; } return PlotSquaredIntegrationImpl.isPlotWorld(world); } From 313dd873d99b75be565dfc160364e3fdae624878 Mon Sep 17 00:00:00 2001 From: Moulberry Date: Fri, 17 Nov 2023 00:39:35 +0800 Subject: [PATCH 33/53] Bump version to 1.5.5 --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index eea7a94..c361e1d 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -8,7 +8,7 @@ plugins { } group = "com.moulberry.axiom" -version = "1.5.4" +version = "1.5.5" description = "Serverside component for Axiom on Paper" java { From 13df370a42673cd260bacc4bfd96222bcb817740 Mon Sep 17 00:00:00 2001 From: Moulberry Date: Tue, 26 Dec 2023 17:41:17 +0800 Subject: [PATCH 34/53] Add disallowed-blocks, log-large-block-buffer-changes and block-buffer-rate-limit config options --- build.gradle.kts | 6 +- .../java/com/moulberry/axiom/AxiomPaper.java | 40 +- .../com/moulberry/axiom/DisallowedBlocks.java | 92 ++++ .../moulberry/axiom/buffer/BiomeBuffer.java | 12 +- .../moulberry/axiom/buffer/BlockBuffer.java | 54 ++- .../axiom/buffer/CompressedBlockEntity.java | 3 +- .../axiom/buffer/Position2ByteMap.java | 16 +- .../axiom/packet/AxiomBigPayloadHandler.java | 1 + .../axiom/packet/HelloPacketListener.java | 11 +- .../packet/SetBlockBufferPacketListener.java | 421 ++++++++++-------- .../axiom/packet/SetBlockPacketListener.java | 2 +- src/main/resources/config.yml | 11 + 12 files changed, 437 insertions(+), 232 deletions(-) create mode 100644 src/main/java/com/moulberry/axiom/DisallowedBlocks.java diff --git a/build.gradle.kts b/build.gradle.kts index c361e1d..e771b98 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,7 +1,7 @@ plugins { `java-library` - id("io.papermc.paperweight.userdev") version "1.5.8" - id("xyz.jpenilla.run-paper") version "2.2.0" // Adds runServer and runMojangMappedServer tasks for testing + 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 // Shades and relocates dependencies into our plugin jar. See https://imperceptiblethoughts.com/shadow/introduction/ id("com.github.johnrengelman.shadow") version "8.1.1" @@ -20,8 +20,8 @@ repositories { mavenCentral() maven("https://s01.oss.sonatype.org/content/repositories/snapshots/") maven("https://jitpack.io") - maven("https://maven.enginehub.org/repo/") maven("https://repo.papermc.io/repository/maven-public/") + maven("https://maven.enginehub.org/repo/") } dependencies { diff --git a/src/main/java/com/moulberry/axiom/AxiomPaper.java b/src/main/java/com/moulberry/axiom/AxiomPaper.java index 138bb95..7e18301 100644 --- a/src/main/java/com/moulberry/axiom/AxiomPaper.java +++ b/src/main/java/com/moulberry/axiom/AxiomPaper.java @@ -1,5 +1,8 @@ package com.moulberry.axiom; +import com.google.common.util.concurrent.RateLimiter; +import com.mojang.brigadier.StringReader; +import com.moulberry.axiom.buffer.BlockBuffer; import com.moulberry.axiom.buffer.CompressedBlockEntity; import com.moulberry.axiom.event.AxiomCreateWorldPropertiesEvent; import com.moulberry.axiom.event.AxiomModifyWorldEvent; @@ -12,6 +15,11 @@ import io.papermc.paper.event.world.WorldGameRuleChangeEvent; import io.papermc.paper.network.ChannelInitializeListener; import io.papermc.paper.network.ChannelInitializeListenerHolder; import net.kyori.adventure.key.Key; +import net.minecraft.commands.arguments.blocks.BlockPredicateArgument; +import net.minecraft.commands.arguments.blocks.BlockStateArgument; +import net.minecraft.commands.arguments.blocks.BlockStateParser; +import net.minecraft.core.IdMapper; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.network.Connection; import net.minecraft.network.ConnectionProtocol; import net.minecraft.network.FriendlyByteBuf; @@ -19,6 +27,9 @@ import net.minecraft.network.protocol.Packet; import net.minecraft.network.protocol.PacketFlow; import net.minecraft.network.protocol.common.ServerboundCustomPayloadPacket; import net.minecraft.server.MinecraftServer; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.state.BlockState; import org.bukkit.*; import org.bukkit.configuration.Configuration; import org.bukkit.entity.Player; @@ -32,14 +43,20 @@ import org.jetbrains.annotations.Nullable; import java.util.*; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; public class AxiomPaper extends JavaPlugin implements Listener { public static AxiomPaper PLUGIN; // tsk tsk tsk public final Set activeAxiomPlayers = Collections.newSetFromMap(new ConcurrentHashMap<>()); + public final Map playerBlockBufferRateLimiters = new ConcurrentHashMap<>(); public Configuration configuration; + public IdMapper allowedBlockRegistry = null; + private boolean logLargeBlockBufferChanges = false; + @Override public void onEnable() { PLUGIN = this; @@ -55,6 +72,11 @@ public class AxiomPaper extends JavaPlugin implements Listener { this.getLogger().warning("Invalid value for unsupported-axiom-version, expected 'kick', 'warn' or 'ignore'"); } + this.logLargeBlockBufferChanges = this.configuration.getBoolean("log-large-block-buffer-changes"); + + List disallowedBlocks = this.configuration.getStringList("disallowed-blocks"); + this.allowedBlockRegistry = DisallowedBlocks.createAllowedBlockRegistry(disallowedBlocks); + Bukkit.getPluginManager().registerEvents(this, this); // Bukkit.getPluginManager().registerEvents(new WorldPropertiesExample(), this); CompressedBlockEntity.initialize(this); @@ -70,7 +92,7 @@ public class AxiomPaper extends JavaPlugin implements Listener { msg.registerOutgoingPluginChannel(this, "axiom:ack_world_properties"); if (configuration.getBoolean("packet-handlers.hello")) { - msg.registerIncomingPluginChannel(this, "axiom:hello", new HelloPacketListener(this, activeAxiomPlayers)); + msg.registerIncomingPluginChannel(this, "axiom:hello", new HelloPacketListener(this)); } if (configuration.getBoolean("packet-handlers.set-gamemode")) { msg.registerIncomingPluginChannel(this, "axiom:set_gamemode", new SetGamemodePacketListener(this)); @@ -129,7 +151,7 @@ public class AxiomPaper extends JavaPlugin implements Listener { } Bukkit.getScheduler().scheduleSyncRepeatingTask(this, () -> { - HashSet newActiveAxiomPlayers = new HashSet<>(); + HashSet stillActiveAxiomPlayers = new HashSet<>(); for (Player player : Bukkit.getServer().getOnlinePlayers()) { if (activeAxiomPlayers.contains(player.getUniqueId())) { @@ -140,13 +162,13 @@ public class AxiomPaper extends JavaPlugin implements Listener { buf.getBytes(0, bytes); player.sendPluginMessage(this, "axiom:enable", bytes); } else { - newActiveAxiomPlayers.add(player.getUniqueId()); + stillActiveAxiomPlayers.add(player.getUniqueId()); } } } - activeAxiomPlayers.clear(); - activeAxiomPlayers.addAll(newActiveAxiomPlayers); + activeAxiomPlayers.retainAll(stillActiveAxiomPlayers); + playerBlockBufferRateLimiters.keySet().retainAll(stillActiveAxiomPlayers); }, 20, 20); int maxChunkRelightsPerTick = configuration.getInt("max-chunk-relights-per-tick"); @@ -157,10 +179,18 @@ public class AxiomPaper extends JavaPlugin implements Listener { }, 1, 1); } + public boolean logLargeBlockBufferChanges() { + return this.logLargeBlockBufferChanges; + } + public boolean canUseAxiom(Player player) { return player.hasPermission("axiom.*") && activeAxiomPlayers.contains(player.getUniqueId()); } + public @Nullable RateLimiter getBlockBufferRateLimiter(UUID uuid) { + return this.playerBlockBufferRateLimiters.get(uuid); + } + private final WeakHashMap worldProperties = new WeakHashMap<>(); public @Nullable ServerWorldPropertiesRegistry getWorldPropertiesIfPresent(World world) { diff --git a/src/main/java/com/moulberry/axiom/DisallowedBlocks.java b/src/main/java/com/moulberry/axiom/DisallowedBlocks.java new file mode 100644 index 0000000..f80d2b8 --- /dev/null +++ b/src/main/java/com/moulberry/axiom/DisallowedBlocks.java @@ -0,0 +1,92 @@ +package com.moulberry.axiom; + +import com.mojang.brigadier.StringReader; +import com.mojang.datafixers.util.Either; +import com.moulberry.axiom.buffer.BlockBuffer; +import net.minecraft.commands.arguments.blocks.BlockPredicateArgument; +import net.minecraft.commands.arguments.blocks.BlockStateParser; +import net.minecraft.core.IdMapper; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.nbt.NbtUtils; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.Property; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.function.Predicate; + +public class DisallowedBlocks { + + public static IdMapper createAllowedBlockRegistry(List disallowedBlocks) { + List> disallowedPredicates = new ArrayList<>(); + + for (String disallowedBlock : disallowedBlocks) { + try { + var parsed = BlockStateParser.parseForTesting(BuiltInRegistries.BLOCK.asLookup(), new StringReader(disallowedBlock), false); + + parsed.left().ifPresent(result -> { + disallowedPredicates.add(blockState -> { + if (!blockState.is(result.blockState().getBlock())) { + return false; + } else { + for (Property property : result.properties().keySet()) { + if (blockState.getValue(property) != result.blockState().getValue(property)) { + return false; + } + } + return true; + } + }); + }); + + parsed.right().ifPresent(result -> { + disallowedPredicates.add(blockState -> { + if (!blockState.is(result.tag())) { + return false; + } else { + for(Map.Entry entry : result.vagueProperties().entrySet()) { + Property property = blockState.getBlock().getStateDefinition().getProperty(entry.getKey()); + if (property == null) { + return false; + } + + Comparable comparable = property.getValue(entry.getValue()).orElse(null); + if (comparable == null) { + return false; + } + + if (blockState.getValue(property) != comparable) { + return false; + } + } + + return true; + } + }); + }); + } catch (Exception ignored) {} + } + + IdMapper allowedBlockRegistry = new IdMapper<>(); + + // Create allowedBlockRegistry + blocks: + for (BlockState blockState : Block.BLOCK_STATE_REGISTRY) { + for (Predicate disallowedPredicate : disallowedPredicates) { + if (disallowedPredicate.test(blockState)) { + allowedBlockRegistry.add(BlockBuffer.EMPTY_STATE); + continue blocks; + } + } + + allowedBlockRegistry.add(blockState); + } + allowedBlockRegistry.addMapping(BlockBuffer.EMPTY_STATE, Block.BLOCK_STATE_REGISTRY.getId(BlockBuffer.EMPTY_STATE)); + return allowedBlockRegistry; + } + +} diff --git a/src/main/java/com/moulberry/axiom/buffer/BiomeBuffer.java b/src/main/java/com/moulberry/axiom/buffer/BiomeBuffer.java index bf14541..9f756d9 100644 --- a/src/main/java/com/moulberry/axiom/buffer/BiomeBuffer.java +++ b/src/main/java/com/moulberry/axiom/buffer/BiomeBuffer.java @@ -1,11 +1,15 @@ package com.moulberry.axiom.buffer; +import com.google.common.util.concurrent.RateLimiter; import it.unimi.dsi.fastutil.objects.Object2ByteMap; import it.unimi.dsi.fastutil.objects.Object2ByteOpenHashMap; import net.minecraft.core.registries.Registries; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.resources.ResourceKey; import net.minecraft.world.level.biome.Biome; +import org.jetbrains.annotations.Nullable; + +import java.util.concurrent.atomic.AtomicBoolean; public class BiomeBuffer { @@ -27,6 +31,10 @@ public class BiomeBuffer { this.paletteSize = this.paletteReverse.size(); } + public int size() { + return this.map.size(); + } + public void save(FriendlyByteBuf friendlyByteBuf) { friendlyByteBuf.writeByte(this.paletteSize); for (int i = 0; i < this.paletteSize; i++) { @@ -35,7 +43,7 @@ public class BiomeBuffer { this.map.save(friendlyByteBuf); } - public static BiomeBuffer load(FriendlyByteBuf friendlyByteBuf) { + public static BiomeBuffer load(FriendlyByteBuf friendlyByteBuf, @Nullable RateLimiter rateLimiter, AtomicBoolean reachedRateLimit) { int paletteSize = friendlyByteBuf.readByte(); ResourceKey[] palette = new ResourceKey[255]; Object2ByteMap> paletteReverse = new Object2ByteOpenHashMap<>(); @@ -44,7 +52,7 @@ public class BiomeBuffer { palette[i] = key; paletteReverse.put(key, (byte)(i+1)); } - Position2ByteMap map = Position2ByteMap.load(friendlyByteBuf); + Position2ByteMap map = Position2ByteMap.load(friendlyByteBuf, rateLimiter, reachedRateLimit); return new BiomeBuffer(map, palette, paletteReverse); } diff --git a/src/main/java/com/moulberry/axiom/buffer/BlockBuffer.java b/src/main/java/com/moulberry/axiom/buffer/BlockBuffer.java index 6cc39bb..8094081 100644 --- a/src/main/java/com/moulberry/axiom/buffer/BlockBuffer.java +++ b/src/main/java/com/moulberry/axiom/buffer/BlockBuffer.java @@ -1,5 +1,6 @@ package com.moulberry.axiom.buffer; +import com.google.common.util.concurrent.RateLimiter; import com.moulberry.axiom.AxiomConstants; import com.moulberry.axiom.AxiomPaper; import it.unimi.dsi.fastutil.longs.Long2ObjectMap; @@ -15,6 +16,8 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.PalettedContainer; import org.jetbrains.annotations.Nullable; +import java.util.concurrent.atomic.AtomicBoolean; + public class BlockBuffer { public static final BlockState EMPTY_STATE = Blocks.STRUCTURE_VOID.defaultBlockState(); @@ -24,6 +27,8 @@ public class BlockBuffer { private PalettedContainer last = null; private long lastId = AxiomConstants.MIN_POSITION_LONG; private final Long2ObjectMap> blockEntities = new Long2ObjectOpenHashMap<>(); + private long totalBlockEntities = 0; + private long totalBlockEntityBytes = 0; public BlockBuffer() { this.values = new Long2ObjectOpenHashMap<>(); @@ -53,54 +58,57 @@ public class BlockBuffer { friendlyByteBuf.writeLong(AxiomConstants.MIN_POSITION_LONG); } - public static BlockBuffer load(FriendlyByteBuf friendlyByteBuf) { + public static BlockBuffer load(FriendlyByteBuf friendlyByteBuf, @Nullable RateLimiter rateLimiter, AtomicBoolean reachedRateLimit) { BlockBuffer buffer = new BlockBuffer(); + long totalBlockEntities = 0; + long totalBlockEntityBytes = 0; + while (true) { long index = friendlyByteBuf.readLong(); if (index == AxiomConstants.MIN_POSITION_LONG) break; + if (rateLimiter != null) { + if (!rateLimiter.tryAcquire()) { + reachedRateLimit.set(true); + buffer.totalBlockEntities = totalBlockEntities; + buffer.totalBlockEntityBytes = totalBlockEntityBytes; + return buffer; + } + } + PalettedContainer palettedContainer = buffer.getOrCreateSection(index); palettedContainer.read(friendlyByteBuf); int blockEntitySize = Math.min(4096, friendlyByteBuf.readVarInt()); if (blockEntitySize > 0) { Short2ObjectMap map = new Short2ObjectOpenHashMap<>(blockEntitySize); + + int startIndex = friendlyByteBuf.readerIndex(); + for (int i = 0; i < blockEntitySize; i++) { short offset = friendlyByteBuf.readShort(); CompressedBlockEntity blockEntity = CompressedBlockEntity.read(friendlyByteBuf); map.put(offset, blockEntity); } + buffer.blockEntities.put(index, map); + totalBlockEntities += blockEntitySize; + totalBlockEntityBytes += friendlyByteBuf.readerIndex() - startIndex; } } + buffer.totalBlockEntities = totalBlockEntities; + buffer.totalBlockEntityBytes = totalBlockEntityBytes; return buffer; } - public void clear() { - this.last = null; - this.lastId = AxiomConstants.MIN_POSITION_LONG; - this.values.clear(); + public long getTotalBlockEntities() { + return this.totalBlockEntities; } - public void putBlockEntity(int x, int y, int z, CompressedBlockEntity blockEntity) { - long cpos = BlockPos.asLong(x >> 4, y >> 4, z >> 4); - Short2ObjectMap chunkMap = this.blockEntities.computeIfAbsent(cpos, k -> new Short2ObjectOpenHashMap<>()); - - int key = (x & 0xF) | ((y & 0xF) << 4) | ((z & 0xF) << 8); - chunkMap.put((short)key, blockEntity); - } - - @Nullable - public CompressedBlockEntity getBlockEntity(int x, int y, int z) { - long cpos = BlockPos.asLong(x >> 4, y >> 4, z >> 4); - Short2ObjectMap chunkMap = this.blockEntities.get(cpos); - - if (chunkMap == null) return null; - - int key = (x & 0xF) | ((y & 0xF) << 4) | ((z & 0xF) << 8); - return chunkMap.get((short)key); + public long getTotalBlockEntityBytes() { + return this.totalBlockEntityBytes; } @Nullable @@ -170,7 +178,7 @@ public class BlockBuffer { public PalettedContainer getOrCreateSection(long id) { if (this.last == null || id != this.lastId) { this.lastId = id; - this.last = this.values.computeIfAbsent(id, k -> new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, + this.last = this.values.computeIfAbsent(id, k -> new PalettedContainer<>(AxiomPaper.PLUGIN.allowedBlockRegistry, EMPTY_STATE, PalettedContainer.Strategy.SECTION_STATES)); } diff --git a/src/main/java/com/moulberry/axiom/buffer/CompressedBlockEntity.java b/src/main/java/com/moulberry/axiom/buffer/CompressedBlockEntity.java index 76f9bba..c1d09b0 100644 --- a/src/main/java/com/moulberry/axiom/buffer/CompressedBlockEntity.java +++ b/src/main/java/com/moulberry/axiom/buffer/CompressedBlockEntity.java @@ -5,6 +5,7 @@ import com.github.luben.zstd.ZstdDictCompress; import com.github.luben.zstd.ZstdDictDecompress; import com.moulberry.axiom.AxiomPaper; import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtAccounter; import net.minecraft.nbt.NbtIo; import net.minecraft.network.FriendlyByteBuf; @@ -44,7 +45,7 @@ public record CompressedBlockEntity(int originalSize, byte compressionDict, byte try { byte[] nbt = Zstd.decompress(this.compressed, zstdDictDecompress, this.originalSize); - return NbtIo.read(new DataInputStream(new ByteArrayInputStream(nbt))); + return NbtIo.read(new DataInputStream(new ByteArrayInputStream(nbt)), NbtAccounter.create(131072)); } catch (IOException e) { throw new RuntimeException(e); } diff --git a/src/main/java/com/moulberry/axiom/buffer/Position2ByteMap.java b/src/main/java/com/moulberry/axiom/buffer/Position2ByteMap.java index 438872e..3080891 100644 --- a/src/main/java/com/moulberry/axiom/buffer/Position2ByteMap.java +++ b/src/main/java/com/moulberry/axiom/buffer/Position2ByteMap.java @@ -1,13 +1,16 @@ package com.moulberry.axiom.buffer; +import com.google.common.util.concurrent.RateLimiter; import com.moulberry.axiom.AxiomConstants; import com.moulberry.axiom.AxiomPaper; import it.unimi.dsi.fastutil.longs.Long2ObjectMap; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; import net.minecraft.core.BlockPos; import net.minecraft.network.FriendlyByteBuf; +import org.jetbrains.annotations.Nullable; import java.util.Arrays; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.LongFunction; public class Position2ByteMap { @@ -42,6 +45,10 @@ public class Position2ByteMap { } } + public int size() { + return this.map.size(); + } + public void save(FriendlyByteBuf friendlyByteBuf) { friendlyByteBuf.writeByte(this.defaultValue); for (Long2ObjectMap.Entry entry : this.map.long2ObjectEntrySet()) { @@ -51,13 +58,20 @@ public class Position2ByteMap { friendlyByteBuf.writeLong(AxiomConstants.MIN_POSITION_LONG); } - public static Position2ByteMap load(FriendlyByteBuf friendlyByteBuf) { + public static Position2ByteMap load(FriendlyByteBuf friendlyByteBuf, @Nullable RateLimiter rateLimiter, AtomicBoolean reachedRateLimit) { Position2ByteMap map = new Position2ByteMap(friendlyByteBuf.readByte()); while (true) { long pos = friendlyByteBuf.readLong(); if (pos == AxiomConstants.MIN_POSITION_LONG) break; + if (rateLimiter != null) { + if (!rateLimiter.tryAcquire()) { + reachedRateLimit.set(true); + return map; + } + } + byte[] bytes = new byte[16*16*16]; friendlyByteBuf.readBytes(bytes); map.map.put(pos, bytes); diff --git a/src/main/java/com/moulberry/axiom/packet/AxiomBigPayloadHandler.java b/src/main/java/com/moulberry/axiom/packet/AxiomBigPayloadHandler.java index 60fa216..0b8761f 100644 --- a/src/main/java/com/moulberry/axiom/packet/AxiomBigPayloadHandler.java +++ b/src/main/java/com/moulberry/axiom/packet/AxiomBigPayloadHandler.java @@ -47,6 +47,7 @@ public class AxiomBigPayloadHandler extends ByteToMessageDecoder { if (player != null && player.getBukkitEntity().hasPermission("axiom.*")) { if (listener.onReceive(player, buf)) { success = true; + in.skipBytes(in.readableBytes()); return; } } diff --git a/src/main/java/com/moulberry/axiom/packet/HelloPacketListener.java b/src/main/java/com/moulberry/axiom/packet/HelloPacketListener.java index 62a2322..35084af 100644 --- a/src/main/java/com/moulberry/axiom/packet/HelloPacketListener.java +++ b/src/main/java/com/moulberry/axiom/packet/HelloPacketListener.java @@ -1,5 +1,6 @@ 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; @@ -29,11 +30,9 @@ import java.util.UUID; public class HelloPacketListener implements PluginMessageListener { private final AxiomPaper plugin; - private final Set activeAxiomPlayers; - public HelloPacketListener(AxiomPaper plugin, Set activeAxiomPlayers) { + public HelloPacketListener(AxiomPaper plugin) { this.plugin = plugin; - this.activeAxiomPlayers = activeAxiomPlayers; } @Override @@ -86,7 +85,11 @@ public class HelloPacketListener implements PluginMessageListener { return; } - activeAxiomPlayers.add(player.getUniqueId()); + this.plugin.activeAxiomPlayers.add(player.getUniqueId()); + int rateLimit = this.plugin.configuration.getInt("block-buffer-rate-limit"); + if (rateLimit > 0) { + this.plugin.playerBlockBufferRateLimiters.putIfAbsent(player.getUniqueId(), RateLimiter.create(rateLimit)); + } // Enable FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer()); diff --git a/src/main/java/com/moulberry/axiom/packet/SetBlockBufferPacketListener.java b/src/main/java/com/moulberry/axiom/packet/SetBlockBufferPacketListener.java index a13eb1b..21d29aa 100644 --- a/src/main/java/com/moulberry/axiom/packet/SetBlockBufferPacketListener.java +++ b/src/main/java/com/moulberry/axiom/packet/SetBlockBufferPacketListener.java @@ -1,5 +1,6 @@ package com.moulberry.axiom.packet; +import com.google.common.util.concurrent.RateLimiter; import com.moulberry.axiom.AxiomPaper; import com.moulberry.axiom.WorldExtension; import com.moulberry.axiom.buffer.BiomeBuffer; @@ -10,12 +11,14 @@ import com.moulberry.axiom.integration.SectionPermissionChecker; import com.moulberry.axiom.integration.plotsquared.PlotSquaredIntegration; import it.unimi.dsi.fastutil.longs.Long2ObjectMap; import it.unimi.dsi.fastutil.shorts.Short2ObjectMap; +import net.minecraft.ChatFormatting; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.core.Registry; import net.minecraft.core.SectionPos; import net.minecraft.core.registries.Registries; import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.chat.Component; import net.minecraft.network.protocol.game.ClientboundChunksBiomesPacket; import net.minecraft.resources.ResourceKey; import net.minecraft.server.MinecraftServer; @@ -36,18 +39,19 @@ import net.minecraft.world.level.chunk.LevelChunkSection; import net.minecraft.world.level.chunk.PalettedContainer; import net.minecraft.world.level.levelgen.Heightmap; import net.minecraft.world.level.lighting.LightEngine; -import org.bukkit.Bukkit; import org.bukkit.Location; import xyz.jpenilla.reflectionremapper.ReflectionRemapper; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.*; +import java.util.concurrent.atomic.AtomicBoolean; public class SetBlockBufferPacketListener { private final AxiomPaper plugin; private final Method updateBlockEntityTicker; + private final WeakHashMap packetRateLimiter = new WeakHashMap<>(); public SetBlockBufferPacketListener(AxiomPaper plugin) { this.plugin = plugin; @@ -76,12 +80,38 @@ public class SetBlockBufferPacketListener { friendlyByteBuf.readNbt(); // Discard sourceInfo } + RateLimiter rateLimiter = this.plugin.getBlockBufferRateLimiter(player.getUUID()); + byte type = friendlyByteBuf.readByte(); if (type == 0) { - BlockBuffer buffer = BlockBuffer.load(friendlyByteBuf); + AtomicBoolean reachedRateLimit = new AtomicBoolean(false); + BlockBuffer buffer = BlockBuffer.load(friendlyByteBuf, rateLimiter, reachedRateLimit); + if (reachedRateLimit.get()) { + player.sendSystemMessage(Component.literal("[Axiom] Exceeded server rate-limit of " + (int)rateLimiter.getRate() + " sections per second") + .withStyle(ChatFormatting.RED)); + } + + if (this.plugin.logLargeBlockBufferChanges()) { + this.plugin.getLogger().info("Player " + player.getUUID() + " modified " + buffer.entrySet().size() + " chunk sections (blocks)"); + if (buffer.getTotalBlockEntities() > 0) { + this.plugin.getLogger().info("Player " + player.getUUID() + " modified " + buffer.getTotalBlockEntities() + " block entities, compressed bytes = " + + buffer.getTotalBlockEntityBytes()); + } + } + applyBlockBuffer(player, server, buffer, worldKey); } else if (type == 1) { - BiomeBuffer buffer = BiomeBuffer.load(friendlyByteBuf); + AtomicBoolean reachedRateLimit = new AtomicBoolean(false); + BiomeBuffer buffer = BiomeBuffer.load(friendlyByteBuf, rateLimiter, reachedRateLimit); + if (reachedRateLimit.get()) { + player.sendSystemMessage(Component.literal("[Axiom] Exceeded server rate-limit of " + (int)rateLimiter.getRate() + " sections per second") + .withStyle(ChatFormatting.RED)); + } + + if (this.plugin.logLargeBlockBufferChanges()) { + this.plugin.getLogger().info("Player " + player.getUUID() + " modified " + buffer.size() + " chunk sections (biomes)"); + } + applyBiomeBuffer(player, server, buffer, worldKey); } else { throw new RuntimeException("Unknown buffer type: " + type); @@ -92,245 +122,252 @@ public class SetBlockBufferPacketListener { private void applyBlockBuffer(ServerPlayer player, MinecraftServer server, BlockBuffer buffer, ResourceKey worldKey) { server.execute(() -> { - ServerLevel world = player.serverLevel(); - if (!world.dimension().equals(worldKey)) return; + try { + ServerLevel world = player.serverLevel(); + if (!world.dimension().equals(worldKey)) return; - if (!this.plugin.canUseAxiom(player.getBukkitEntity())) { - return; - } - - if (!this.plugin.canModifyWorld(player.getBukkitEntity(), world.getWorld())) { - return; - } - - // Allowed, apply buffer - BlockPos.MutableBlockPos blockPos = new BlockPos.MutableBlockPos(); - WorldExtension extension = WorldExtension.get(world); - - BlockState emptyState = BlockBuffer.EMPTY_STATE; - - for (Long2ObjectMap.Entry> entry : buffer.entrySet()) { - int cx = BlockPos.getX(entry.getLongKey()); - int cy = BlockPos.getY(entry.getLongKey()); - int cz = BlockPos.getZ(entry.getLongKey()); - PalettedContainer container = entry.getValue(); - - if (cy < world.getMinSection() || cy >= world.getMaxSection()) { - continue; + if (!this.plugin.canUseAxiom(player.getBukkitEntity())) { + return; } - SectionPermissionChecker checker = PlotSquaredIntegration.checkSection(player.getBukkitEntity(), world.getWorld(), cx, cy, cz); - if (checker != null && checker.noneAllowed()) { - continue; + if (!this.plugin.canModifyWorld(player.getBukkitEntity(), world.getWorld())) { + return; } - LevelChunk chunk = world.getChunk(cx, cz); + // Allowed, apply buffer + BlockPos.MutableBlockPos blockPos = new BlockPos.MutableBlockPos(); + WorldExtension extension = WorldExtension.get(world); - LevelChunkSection section = chunk.getSection(world.getSectionIndexFromSectionY(cy)); - PalettedContainer sectionStates = section.getStates(); - boolean hasOnlyAir = section.hasOnlyAir(); + BlockState emptyState = BlockBuffer.EMPTY_STATE; - Heightmap worldSurface = null; - Heightmap oceanFloor = null; - Heightmap motionBlocking = null; - Heightmap motionBlockingNoLeaves = null; - for (Map.Entry heightmap : chunk.getHeightmaps()) { - switch (heightmap.getKey()) { - case WORLD_SURFACE -> worldSurface = heightmap.getValue(); - case OCEAN_FLOOR -> oceanFloor = heightmap.getValue(); - case MOTION_BLOCKING -> motionBlocking = heightmap.getValue(); - case MOTION_BLOCKING_NO_LEAVES -> motionBlockingNoLeaves = heightmap.getValue(); - default -> {} + for (Long2ObjectMap.Entry> entry : buffer.entrySet()) { + int cx = BlockPos.getX(entry.getLongKey()); + int cy = BlockPos.getY(entry.getLongKey()); + int cz = BlockPos.getZ(entry.getLongKey()); + PalettedContainer container = entry.getValue(); + + if (cy < world.getMinSection() || cy >= world.getMaxSection()) { + continue; } - } - boolean sectionChanged = false; - boolean sectionLightChanged = false; - - boolean containerMaybeHasPoi = container.maybeHas(PoiTypes::hasPoi); - boolean sectionMaybeHasPoi = section.maybeHas(PoiTypes::hasPoi); - - Short2ObjectMap blockEntityChunkMap = buffer.getBlockEntityChunkMap(entry.getLongKey()); - - int minX = 0; - int minY = 0; - int minZ = 0; - int maxX = 15; - int maxY = 15; - int maxZ = 15; - - if (checker != null) { - minX = checker.bounds().minX(); - minY = checker.bounds().minY(); - minZ = checker.bounds().minZ(); - maxX = checker.bounds().maxX(); - maxY = checker.bounds().maxY(); - maxZ = checker.bounds().maxZ(); - if (checker.allAllowed()) { - checker = null; + SectionPermissionChecker checker = PlotSquaredIntegration.checkSection(player.getBukkitEntity(), world.getWorld(), cx, cy, cz); + if (checker != null && checker.noneAllowed()) { + continue; } - } - for (int x = minX; x <= maxX; x++) { - for (int y = minY; y <= maxY; y++) { - for (int z = minZ; z <= maxZ; z++) { - BlockState blockState = container.get(x, y, z); - if (blockState == emptyState) continue; + LevelChunk chunk = world.getChunk(cx, cz); - int bx = cx*16 + x; - int by = cy*16 + y; - int bz = cz*16 + z; + LevelChunkSection section = chunk.getSection(world.getSectionIndexFromSectionY(cy)); + PalettedContainer sectionStates = section.getStates(); + boolean hasOnlyAir = section.hasOnlyAir(); - if (hasOnlyAir && blockState.isAir()) { - continue; - } + Heightmap worldSurface = null; + Heightmap oceanFloor = null; + Heightmap motionBlocking = null; + Heightmap motionBlockingNoLeaves = null; + for (Map.Entry heightmap : chunk.getHeightmaps()) { + switch (heightmap.getKey()) { + case WORLD_SURFACE -> worldSurface = heightmap.getValue(); + case OCEAN_FLOOR -> oceanFloor = heightmap.getValue(); + case MOTION_BLOCKING -> motionBlocking = heightmap.getValue(); + case MOTION_BLOCKING_NO_LEAVES -> motionBlockingNoLeaves = heightmap.getValue(); + default -> {} + } + } - if (checker != null && !checker.allowed(x, y, z)) continue; + boolean sectionChanged = false; + boolean sectionLightChanged = false; - BlockState old = section.setBlockState(x, y, z, blockState, true); - if (blockState != old) { - sectionChanged = true; - blockPos.set(bx, by, bz); + boolean containerMaybeHasPoi = container.maybeHas(PoiTypes::hasPoi); + boolean sectionMaybeHasPoi = section.maybeHas(PoiTypes::hasPoi); - Block block = blockState.getBlock(); - motionBlocking.update(x, by, z, blockState); - motionBlockingNoLeaves.update(x, by, z, blockState); - oceanFloor.update(x, by, z, blockState); - worldSurface.update(x, by, z, blockState); + Short2ObjectMap blockEntityChunkMap = buffer.getBlockEntityChunkMap(entry.getLongKey()); - if (false) { // Full update - old.onRemove(world, blockPos, blockState, false); + int minX = 0; + int minY = 0; + int minZ = 0; + int maxX = 15; + int maxY = 15; + int maxZ = 15; - if (sectionStates.get(x, y, z).is(block)) { - blockState.onPlace(world, blockPos, old, false); - } + if (checker != null) { + minX = checker.bounds().minX(); + minY = checker.bounds().minY(); + minZ = checker.bounds().minZ(); + maxX = checker.bounds().maxX(); + maxY = checker.bounds().maxY(); + maxZ = checker.bounds().maxZ(); + if (checker.allAllowed()) { + checker = null; + } + } + + for (int x = minX; x <= maxX; x++) { + for (int y = minY; y <= maxY; y++) { + for (int z = minZ; z <= maxZ; z++) { + BlockState blockState = container.get(x, y, z); + if (blockState == emptyState) continue; + + int bx = cx*16 + x; + int by = cy*16 + y; + int bz = cz*16 + z; + + if (hasOnlyAir && blockState.isAir()) { + continue; } - if (blockState.hasBlockEntity()) { - BlockEntity blockEntity = chunk.getBlockEntity(blockPos, LevelChunk.EntityCreationType.CHECK); + if (checker != null && !checker.allowed(x, y, z)) continue; - if (blockEntity == null) { - // There isn't a block entity here, create it! - blockEntity = ((EntityBlock)block).newBlockEntity(blockPos, blockState); - if (blockEntity != null) { - chunk.addAndRegisterBlockEntity(blockEntity); - } - } else if (blockEntity.getType().isValid(blockState)) { - // Block entity is here and the type is correct - blockEntity.setBlockState(blockState); + BlockState old = section.setBlockState(x, y, z, blockState, true); + if (blockState != old) { + sectionChanged = true; + blockPos.set(bx, by, bz); - try { - this.updateBlockEntityTicker.invoke(chunk, blockEntity); - } catch (IllegalAccessException | InvocationTargetException e) { - throw new RuntimeException(e); + Block block = blockState.getBlock(); + motionBlocking.update(x, by, z, blockState); + motionBlockingNoLeaves.update(x, by, z, blockState); + oceanFloor.update(x, by, z, blockState); + worldSurface.update(x, by, z, blockState); + + if (false) { // Full update + old.onRemove(world, blockPos, blockState, false); + + if (sectionStates.get(x, y, z).is(block)) { + blockState.onPlace(world, blockPos, old, false); } - } else { - // Block entity type isn't correct, we need to recreate it + } + + if (blockState.hasBlockEntity()) { + BlockEntity blockEntity = chunk.getBlockEntity(blockPos, LevelChunk.EntityCreationType.CHECK); + + if (blockEntity == null) { + // There isn't a block entity here, create it! + blockEntity = ((EntityBlock)block).newBlockEntity(blockPos, blockState); + if (blockEntity != null) { + chunk.addAndRegisterBlockEntity(blockEntity); + } + } else if (blockEntity.getType().isValid(blockState)) { + // Block entity is here and the type is correct + blockEntity.setBlockState(blockState); + + try { + this.updateBlockEntityTicker.invoke(chunk, blockEntity); + } catch (IllegalAccessException | InvocationTargetException e) { + throw new RuntimeException(e); + } + } else { + // Block entity type isn't correct, we need to recreate it + chunk.removeBlockEntity(blockPos); + + blockEntity = ((EntityBlock)block).newBlockEntity(blockPos, blockState); + if (blockEntity != null) { + chunk.addAndRegisterBlockEntity(blockEntity); + } + } + if (blockEntity != null && blockEntityChunkMap != null) { + int key = x | (y << 4) | (z << 8); + CompressedBlockEntity savedBlockEntity = blockEntityChunkMap.get((short) key); + if (savedBlockEntity != null) { + blockEntity.load(savedBlockEntity.decompress()); + } + } + } else if (old.hasBlockEntity()) { chunk.removeBlockEntity(blockPos); - - blockEntity = ((EntityBlock)block).newBlockEntity(blockPos, blockState); - if (blockEntity != null) { - chunk.addAndRegisterBlockEntity(blockEntity); - } } - if (blockEntity != null && blockEntityChunkMap != null) { - int key = x | (y << 4) | (z << 8); - CompressedBlockEntity savedBlockEntity = blockEntityChunkMap.get((short) key); - if (savedBlockEntity != null) { - blockEntity.load(savedBlockEntity.decompress()); - } + + // Update Light + sectionLightChanged |= LightEngine.hasDifferentLightProperties(chunk, blockPos, old, blockState); + + // Update Poi + Optional> newPoi = containerMaybeHasPoi ? PoiTypes.forState(blockState) : Optional.empty(); + Optional> oldPoi = sectionMaybeHasPoi ? PoiTypes.forState(old) : Optional.empty(); + if (!Objects.equals(oldPoi, newPoi)) { + if (oldPoi.isPresent()) world.getPoiManager().remove(blockPos); + if (newPoi.isPresent()) world.getPoiManager().add(blockPos, newPoi.get()); } - } else if (old.hasBlockEntity()) { - chunk.removeBlockEntity(blockPos); - } - - // Update Light - sectionLightChanged |= LightEngine.hasDifferentLightProperties(chunk, blockPos, old, blockState); - - // Update Poi - Optional> newPoi = containerMaybeHasPoi ? PoiTypes.forState(blockState) : Optional.empty(); - Optional> oldPoi = sectionMaybeHasPoi ? PoiTypes.forState(old) : Optional.empty(); - if (!Objects.equals(oldPoi, newPoi)) { - if (oldPoi.isPresent()) world.getPoiManager().remove(blockPos); - if (newPoi.isPresent()) world.getPoiManager().add(blockPos, newPoi.get()); } } } } - } - boolean nowHasOnlyAir = section.hasOnlyAir(); - if (hasOnlyAir != nowHasOnlyAir) { - world.getChunkSource().getLightEngine().updateSectionStatus(SectionPos.of(cx, cy, cz), nowHasOnlyAir); - } + boolean nowHasOnlyAir = section.hasOnlyAir(); + if (hasOnlyAir != nowHasOnlyAir) { + world.getChunkSource().getLightEngine().updateSectionStatus(SectionPos.of(cx, cy, cz), nowHasOnlyAir); + } - if (sectionChanged) { - extension.sendChunk(cx, cz); - chunk.setUnsaved(true); - } - if (sectionLightChanged) { - extension.lightChunk(cx, cz); + if (sectionChanged) { + extension.sendChunk(cx, cz); + chunk.setUnsaved(true); + } + if (sectionLightChanged) { + extension.lightChunk(cx, cz); + } } + } catch (Throwable t) { + player.getBukkitEntity().kick(net.kyori.adventure.text.Component.text("An error occured while processing block change: " + t.getMessage())); } }); } - private void applyBiomeBuffer(ServerPlayer player, MinecraftServer server, BiomeBuffer biomeBuffer, ResourceKey worldKey) { server.execute(() -> { - ServerLevel world = player.serverLevel(); - if (!world.dimension().equals(worldKey)) return; + try { + ServerLevel world = player.serverLevel(); + if (!world.dimension().equals(worldKey)) return; - if (!this.plugin.canUseAxiom(player.getBukkitEntity())) { - return; - } - - if (!this.plugin.canModifyWorld(player.getBukkitEntity(), world.getWorld())) { - return; - } - - Set changedChunks = new HashSet<>(); - - int minSection = world.getMinSection(); - int maxSection = world.getMaxSection(); - - Optional> registryOptional = world.registryAccess().registry(Registries.BIOME); - if (registryOptional.isEmpty()) return; - - Registry registry = registryOptional.get(); - - biomeBuffer.forEachEntry((x, y, z, biome) -> { - int cy = y >> 2; - if (cy < minSection || cy >= maxSection) { + if (!this.plugin.canUseAxiom(player.getBukkitEntity())) { return; } - var chunk = (LevelChunk) world.getChunk(x >> 2, z >> 2, ChunkStatus.FULL, false); - if (chunk == null) return; + if (!this.plugin.canModifyWorld(player.getBukkitEntity(), world.getWorld())) { + return; + } - var section = chunk.getSection(cy - minSection); - PalettedContainer> container = (PalettedContainer>) section.getBiomes(); + Set changedChunks = new HashSet<>(); - var holder = registry.getHolder(biome); - if (holder.isPresent()) { - if (!PlotSquaredIntegration.canPlaceBlock(player.getBukkitEntity(), + int minSection = world.getMinSection(); + int maxSection = world.getMaxSection(); + + Optional> registryOptional = world.registryAccess().registry(Registries.BIOME); + if (registryOptional.isEmpty()) return; + + Registry registry = registryOptional.get(); + + biomeBuffer.forEachEntry((x, y, z, biome) -> { + int cy = y >> 2; + if (cy < minSection || cy >= maxSection) { + return; + } + + var chunk = (LevelChunk) world.getChunk(x >> 2, z >> 2, ChunkStatus.FULL, false); + if (chunk == null) return; + + var section = chunk.getSection(cy - minSection); + PalettedContainer> container = (PalettedContainer>) section.getBiomes(); + + var holder = registry.getHolder(biome); + if (holder.isPresent()) { + if (!PlotSquaredIntegration.canPlaceBlock(player.getBukkitEntity(), new Location(player.getBukkitEntity().getWorld(), x+1, y+1, z+1))) return; - container.set(x & 3, y & 3, z & 3, holder.get()); - changedChunks.add(chunk); - } - }); + container.set(x & 3, y & 3, z & 3, holder.get()); + changedChunks.add(chunk); + } + }); - var chunkMap = world.getChunkSource().chunkMap; - HashMap> map = new HashMap<>(); - for (LevelChunk chunk : changedChunks) { - chunk.setUnsaved(true); - ChunkPos chunkPos = chunk.getPos(); - for (ServerPlayer serverPlayer2 : chunkMap.getPlayers(chunkPos, false)) { - map.computeIfAbsent(serverPlayer2, serverPlayer -> new ArrayList<>()).add(chunk); + var chunkMap = world.getChunkSource().chunkMap; + HashMap> map = new HashMap<>(); + for (LevelChunk chunk : changedChunks) { + chunk.setUnsaved(true); + ChunkPos chunkPos = chunk.getPos(); + for (ServerPlayer serverPlayer2 : chunkMap.getPlayers(chunkPos, false)) { + map.computeIfAbsent(serverPlayer2, serverPlayer -> new ArrayList<>()).add(chunk); + } } + map.forEach((serverPlayer, list) -> serverPlayer.connection.send(ClientboundChunksBiomesPacket.forChunks(list))); + } catch (Throwable t) { + player.getBukkitEntity().kick(net.kyori.adventure.text.Component.text("An error occured while processing biome change: " + t.getMessage())); } - map.forEach((serverPlayer, list) -> serverPlayer.connection.send(ClientboundChunksBiomesPacket.forChunks(list))); }); } diff --git a/src/main/java/com/moulberry/axiom/packet/SetBlockPacketListener.java b/src/main/java/com/moulberry/axiom/packet/SetBlockPacketListener.java index ed1ae7d..a4ec05c 100644 --- a/src/main/java/com/moulberry/axiom/packet/SetBlockPacketListener.java +++ b/src/main/java/com/moulberry/axiom/packet/SetBlockPacketListener.java @@ -80,7 +80,7 @@ public class SetBlockPacketListener implements PluginMessageListener { FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(message)); IntFunction> mapFunction = FriendlyByteBuf.limitValue(Maps::newLinkedHashMapWithExpectedSize, 512); Map blocks = friendlyByteBuf.readMap(mapFunction, - FriendlyByteBuf::readBlockPos, buf -> buf.readById(Block.BLOCK_STATE_REGISTRY)); + FriendlyByteBuf::readBlockPos, buf -> buf.readById(this.plugin.allowedBlockRegistry)); boolean updateNeighbors = friendlyByteBuf.readBoolean(); int reason = friendlyByteBuf.readVarInt(); diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 094b641..edf4bc7 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -28,6 +28,17 @@ whitelist-world-regex: null # If the regex matches the world's name, the world can't be modified blacklist-world-regex: null +# Block buffer rate-limit (in chunk sections per second), 0 = no limit +block-buffer-rate-limit: 0 + +# Log large block buffer changes +log-large-block-buffer-changes: false + +# Disallowed blocks +disallowed-blocks: +# - "minecraft:wheat" +# - "minecraft:oak_stairs[waterlogged=true]" + # Toggles for individual packet handlers. May break certain features packet-handlers: hello: true From bb57b073237f0d37b6b0383a18069edbe3f63ef7 Mon Sep 17 00:00:00 2001 From: Moulberry Date: Tue, 26 Dec 2023 17:41:45 +0800 Subject: [PATCH 35/53] Bump version to 1.5.6 --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index e771b98..44ec1a7 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -8,7 +8,7 @@ plugins { } group = "com.moulberry.axiom" -version = "1.5.5" +version = "1.5.6" description = "Serverside component for Axiom on Paper" java { From 8106e24d74df778753ebbaa43e5e73e1514b2bbb Mon Sep 17 00:00:00 2001 From: Moulberry Date: Tue, 26 Dec 2023 17:54:04 +0800 Subject: [PATCH 36/53] Update to 1.20.4 --- build.gradle.kts | 2 +- .../com/moulberry/axiom/packet/HelloPacketListener.java | 2 +- .../axiom/packet/RequestChunkDataPacketListener.java | 2 +- .../com/moulberry/axiom/packet/SetBlockPacketListener.java | 6 +++--- .../moulberry/axiom/packet/SetFlySpeedPacketListener.java | 2 +- .../moulberry/axiom/packet/SetGamemodePacketListener.java | 2 +- .../moulberry/axiom/packet/SetHotbarSlotPacketListener.java | 4 ++-- .../com/moulberry/axiom/packet/SetTimePacketListener.java | 2 +- .../axiom/packet/SwitchActiveHotbarPacketListener.java | 2 +- .../com/moulberry/axiom/packet/TeleportPacketListener.java | 4 ++-- .../com/moulberry/axiom/persistence/ItemStackDataType.java | 4 ++-- .../server/ServerWorldPropertiesRegistry.java | 2 +- .../world_properties/server/ServerWorldPropertyBase.java | 2 +- .../world_properties/server/ServerWorldPropertyHolder.java | 2 +- 14 files changed, 19 insertions(+), 19 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 44ec1a7..a765015 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -25,7 +25,7 @@ repositories { } dependencies { - paperweight.paperDevBundle("1.20.2-R0.1-SNAPSHOT") + paperweight.paperDevBundle("1.20.4-R0.1-SNAPSHOT") implementation("xyz.jpenilla:reflection-remapper:0.1.0-SNAPSHOT") // Zstd Compression Library diff --git a/src/main/java/com/moulberry/axiom/packet/HelloPacketListener.java b/src/main/java/com/moulberry/axiom/packet/HelloPacketListener.java index 35084af..5f60988 100644 --- a/src/main/java/com/moulberry/axiom/packet/HelloPacketListener.java +++ b/src/main/java/com/moulberry/axiom/packet/HelloPacketListener.java @@ -16,7 +16,7 @@ import net.minecraft.network.FriendlyByteBuf; import org.bukkit.Bukkit; import org.bukkit.NamespacedKey; import org.bukkit.World; -import org.bukkit.craftbukkit.v1_20_R2.inventory.CraftItemStack; +import org.bukkit.craftbukkit.v1_20_R3.inventory.CraftItemStack; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.bukkit.persistence.PersistentDataContainer; diff --git a/src/main/java/com/moulberry/axiom/packet/RequestChunkDataPacketListener.java b/src/main/java/com/moulberry/axiom/packet/RequestChunkDataPacketListener.java index 893fa59..de6a6b3 100644 --- a/src/main/java/com/moulberry/axiom/packet/RequestChunkDataPacketListener.java +++ b/src/main/java/com/moulberry/axiom/packet/RequestChunkDataPacketListener.java @@ -24,7 +24,7 @@ import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunkSection; import net.minecraft.world.level.chunk.PalettedContainer; import org.bukkit.Bukkit; -import org.bukkit.craftbukkit.v1_20_R2.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_20_R3.entity.CraftPlayer; import org.bukkit.entity.Player; import org.bukkit.plugin.messaging.PluginMessageListener; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/com/moulberry/axiom/packet/SetBlockPacketListener.java b/src/main/java/com/moulberry/axiom/packet/SetBlockPacketListener.java index a4ec05c..f7eedf3 100644 --- a/src/main/java/com/moulberry/axiom/packet/SetBlockPacketListener.java +++ b/src/main/java/com/moulberry/axiom/packet/SetBlockPacketListener.java @@ -29,9 +29,9 @@ import net.minecraft.world.phys.BlockHitResult; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.block.BlockFace; -import org.bukkit.craftbukkit.v1_20_R2.CraftWorld; -import org.bukkit.craftbukkit.v1_20_R2.block.CraftBlock; -import org.bukkit.craftbukkit.v1_20_R2.entity.CraftPlayer; +import org.bukkit.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.entity.Player; import org.bukkit.event.block.Action; import org.bukkit.event.player.PlayerInteractEvent; diff --git a/src/main/java/com/moulberry/axiom/packet/SetFlySpeedPacketListener.java b/src/main/java/com/moulberry/axiom/packet/SetFlySpeedPacketListener.java index 2e246a5..8feb59a 100644 --- a/src/main/java/com/moulberry/axiom/packet/SetFlySpeedPacketListener.java +++ b/src/main/java/com/moulberry/axiom/packet/SetFlySpeedPacketListener.java @@ -5,7 +5,7 @@ import com.moulberry.axiom.event.AxiomFlySpeedChangeEvent; import io.netty.buffer.Unpooled; import net.minecraft.network.FriendlyByteBuf; import org.bukkit.Bukkit; -import org.bukkit.craftbukkit.v1_20_R2.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_20_R3.entity.CraftPlayer; import org.bukkit.entity.Player; import org.bukkit.plugin.messaging.PluginMessageListener; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/com/moulberry/axiom/packet/SetGamemodePacketListener.java b/src/main/java/com/moulberry/axiom/packet/SetGamemodePacketListener.java index dd66081..0251410 100644 --- a/src/main/java/com/moulberry/axiom/packet/SetGamemodePacketListener.java +++ b/src/main/java/com/moulberry/axiom/packet/SetGamemodePacketListener.java @@ -7,7 +7,7 @@ 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_R2.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_20_R3.entity.CraftPlayer; import org.bukkit.entity.Player; import org.bukkit.plugin.messaging.PluginMessageListener; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/com/moulberry/axiom/packet/SetHotbarSlotPacketListener.java b/src/main/java/com/moulberry/axiom/packet/SetHotbarSlotPacketListener.java index 5c299b0..4fb427e 100644 --- a/src/main/java/com/moulberry/axiom/packet/SetHotbarSlotPacketListener.java +++ b/src/main/java/com/moulberry/axiom/packet/SetHotbarSlotPacketListener.java @@ -6,8 +6,8 @@ import com.moulberry.axiom.persistence.ItemStackDataType; import io.netty.buffer.Unpooled; import net.minecraft.network.FriendlyByteBuf; import org.bukkit.NamespacedKey; -import org.bukkit.craftbukkit.v1_20_R2.entity.CraftPlayer; -import org.bukkit.craftbukkit.v1_20_R2.inventory.CraftItemStack; +import org.bukkit.craftbukkit.v1_20_R3.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_20_R3.inventory.CraftItemStack; import org.bukkit.entity.Player; import org.bukkit.persistence.PersistentDataContainer; import org.bukkit.persistence.PersistentDataType; diff --git a/src/main/java/com/moulberry/axiom/packet/SetTimePacketListener.java b/src/main/java/com/moulberry/axiom/packet/SetTimePacketListener.java index 38a3a25..9888af5 100644 --- a/src/main/java/com/moulberry/axiom/packet/SetTimePacketListener.java +++ b/src/main/java/com/moulberry/axiom/packet/SetTimePacketListener.java @@ -12,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_R2.CraftWorld; +import org.bukkit.craftbukkit.v1_20_R3.CraftWorld; import org.bukkit.entity.Player; import org.bukkit.plugin.messaging.PluginMessageListener; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/com/moulberry/axiom/packet/SwitchActiveHotbarPacketListener.java b/src/main/java/com/moulberry/axiom/packet/SwitchActiveHotbarPacketListener.java index edd0d45..5307ec3 100644 --- a/src/main/java/com/moulberry/axiom/packet/SwitchActiveHotbarPacketListener.java +++ b/src/main/java/com/moulberry/axiom/packet/SwitchActiveHotbarPacketListener.java @@ -8,7 +8,7 @@ import net.minecraft.network.FriendlyByteBuf; import org.bukkit.GameMode; import org.bukkit.Material; import org.bukkit.NamespacedKey; -import org.bukkit.craftbukkit.v1_20_R2.inventory.CraftItemStack; +import org.bukkit.craftbukkit.v1_20_R3.inventory.CraftItemStack; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.bukkit.persistence.PersistentDataContainer; diff --git a/src/main/java/com/moulberry/axiom/packet/TeleportPacketListener.java b/src/main/java/com/moulberry/axiom/packet/TeleportPacketListener.java index dfabcfa..a36a277 100644 --- a/src/main/java/com/moulberry/axiom/packet/TeleportPacketListener.java +++ b/src/main/java/com/moulberry/axiom/packet/TeleportPacketListener.java @@ -9,8 +9,8 @@ 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_R2.entity.CraftPlayer; -import org.bukkit.craftbukkit.v1_20_R2.util.CraftNamespacedKey; +import org.bukkit.craftbukkit.v1_20_R3.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_20_R3.util.CraftNamespacedKey; import org.bukkit.entity.Player; import org.bukkit.plugin.messaging.PluginMessageListener; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/com/moulberry/axiom/persistence/ItemStackDataType.java b/src/main/java/com/moulberry/axiom/persistence/ItemStackDataType.java index babb077..14a2fe6 100644 --- a/src/main/java/com/moulberry/axiom/persistence/ItemStackDataType.java +++ b/src/main/java/com/moulberry/axiom/persistence/ItemStackDataType.java @@ -1,8 +1,8 @@ package com.moulberry.axiom.persistence; import net.minecraft.nbt.CompoundTag; -import org.bukkit.craftbukkit.v1_20_R2.inventory.CraftItemStack; -import org.bukkit.craftbukkit.v1_20_R2.persistence.CraftPersistentDataContainer; +import org.bukkit.craftbukkit.v1_20_R3.inventory.CraftItemStack; +import org.bukkit.craftbukkit.v1_20_R3.persistence.CraftPersistentDataContainer; import org.bukkit.inventory.ItemStack; import org.bukkit.persistence.PersistentDataAdapterContext; import org.bukkit.persistence.PersistentDataContainer; diff --git a/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertiesRegistry.java b/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertiesRegistry.java index 78fef4f..09e0b9d 100644 --- a/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertiesRegistry.java +++ b/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertiesRegistry.java @@ -9,7 +9,7 @@ import net.minecraft.server.level.ServerLevel; import org.bukkit.GameRule; import org.bukkit.NamespacedKey; import org.bukkit.World; -import org.bukkit.craftbukkit.v1_20_R2.CraftWorld; +import org.bukkit.craftbukkit.v1_20_R3.CraftWorld; import org.bukkit.entity.Player; import org.bukkit.plugin.Plugin; diff --git a/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertyBase.java b/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertyBase.java index 802d9c8..2d7837b 100644 --- a/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertyBase.java +++ b/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertyBase.java @@ -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_R2.util.CraftNamespacedKey; +import org.bukkit.craftbukkit.v1_20_R3.util.CraftNamespacedKey; import org.bukkit.entity.Player; public abstract class ServerWorldPropertyBase { diff --git a/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertyHolder.java b/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertyHolder.java index 676f2c6..0755b69 100644 --- a/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertyHolder.java +++ b/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertyHolder.java @@ -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_R2.util.CraftNamespacedKey; +import org.bukkit.craftbukkit.v1_20_R3.util.CraftNamespacedKey; import org.bukkit.entity.Player; import java.util.Objects; From d83cc8ca0617eca7164d40f052d0c65ab3cee800 Mon Sep 17 00:00:00 2001 From: Moulberry Date: Sun, 7 Jan 2024 06:05:56 +0800 Subject: [PATCH 37/53] Copy custom block entity tag when doing custom placement --- build.gradle.kts | 2 +- .../moulberry/axiom/packet/SetBlockPacketListener.java | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index a765015..acd30d4 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -8,7 +8,7 @@ plugins { } group = "com.moulberry.axiom" -version = "1.5.6" +version = "1.5.7" description = "Serverside component for Axiom on Paper" java { diff --git a/src/main/java/com/moulberry/axiom/packet/SetBlockPacketListener.java b/src/main/java/com/moulberry/axiom/packet/SetBlockPacketListener.java index f7eedf3..78da702 100644 --- a/src/main/java/com/moulberry/axiom/packet/SetBlockPacketListener.java +++ b/src/main/java/com/moulberry/axiom/packet/SetBlockPacketListener.java @@ -16,7 +16,9 @@ import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.InteractionHand; import net.minecraft.world.entity.ai.village.poi.PoiType; import net.minecraft.world.entity.ai.village.poi.PoiTypes; +import net.minecraft.world.item.BlockItem; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.context.BlockPlaceContext; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.EntityBlock; import net.minecraft.world.level.block.entity.BlockEntity; @@ -115,6 +117,8 @@ public class SetBlockPacketListener implements PluginMessageListener { CraftWorld world = player.level().getWorld(); + BlockPlaceContext blockPlaceContext = new BlockPlaceContext(player, hand, player.getItemInHand(hand), blockHit); + // Update blocks if (updateNeighbors) { int count = 0; @@ -252,6 +256,10 @@ public class SetBlockPacketListener implements PluginMessageListener { } } + if (!breaking) { + BlockItem.updateCustomBlockEntityTag(player.level(), player, blockPlaceContext.getClickedPos(), player.getItemInHand(hand)); + } + if (sequenceId >= 0) { player.connection.ackBlockChangesUpTo(sequenceId); } From 2acc42b1255bcd5e1c61b4b3fb12a8c07c93b73b Mon Sep 17 00:00:00 2001 From: Moulberry Date: Sat, 13 Jan 2024 19:06:11 +0800 Subject: [PATCH 38/53] Also call setPlacedBy, used by some block entities (like player skull) to update properties --- .../com/moulberry/axiom/packet/SetBlockPacketListener.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/moulberry/axiom/packet/SetBlockPacketListener.java b/src/main/java/com/moulberry/axiom/packet/SetBlockPacketListener.java index 78da702..493249a 100644 --- a/src/main/java/com/moulberry/axiom/packet/SetBlockPacketListener.java +++ b/src/main/java/com/moulberry/axiom/packet/SetBlockPacketListener.java @@ -257,7 +257,12 @@ public class SetBlockPacketListener implements PluginMessageListener { } if (!breaking) { - BlockItem.updateCustomBlockEntityTag(player.level(), player, blockPlaceContext.getClickedPos(), player.getItemInHand(hand)); + BlockPos clickedPos = blockPlaceContext.getClickedPos(); + ItemStack inHand = player.getItemInHand(hand); + BlockState blockState = player.level().getBlockState(clickedPos); + + BlockItem.updateCustomBlockEntityTag(player.level(), player, clickedPos, inHand); + blockState.getBlock().setPlacedBy(player.level(), clickedPos, blockState, player, inHand); } if (sequenceId >= 0) { From 8fd71e59bad9eabe7e37b6ff6b94acd33d12ad24 Mon Sep 17 00:00:00 2001 From: Moulberry Date: Sun, 14 Jan 2024 16:24:59 +0800 Subject: [PATCH 39/53] Support spawn, manipulate and delete packets --- .../java/com/moulberry/axiom/AxiomPaper.java | 9 + .../packet/DeleteEntityPacketListener.java | 68 ++++++ .../ManipulateEntityPacketListener.java | 201 ++++++++++++++++++ .../packet/SpawnEntityPacketListener.java | 130 +++++++++++ src/main/resources/config.yml | 17 ++ src/main/resources/plugin.yml | 11 +- 6 files changed, 435 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/moulberry/axiom/packet/DeleteEntityPacketListener.java create mode 100644 src/main/java/com/moulberry/axiom/packet/ManipulateEntityPacketListener.java create mode 100644 src/main/java/com/moulberry/axiom/packet/SpawnEntityPacketListener.java diff --git a/src/main/java/com/moulberry/axiom/AxiomPaper.java b/src/main/java/com/moulberry/axiom/AxiomPaper.java index 7e18301..0e960c0 100644 --- a/src/main/java/com/moulberry/axiom/AxiomPaper.java +++ b/src/main/java/com/moulberry/axiom/AxiomPaper.java @@ -124,6 +124,15 @@ public class AxiomPaper extends JavaPlugin implements Listener { if (configuration.getBoolean("packet-handlers.request-chunk-data")) { msg.registerIncomingPluginChannel(this, "axiom:request_chunk_data", new RequestChunkDataPacketListener(this)); } + if (configuration.getBoolean("packet-handlers.spawn-entity")) { + msg.registerIncomingPluginChannel(this, "axiom:spawn_entity", new SpawnEntityPacketListener(this)); + } + if (configuration.getBoolean("packet-handlers.manipulate-entity")) { + msg.registerIncomingPluginChannel(this, "axiom:manipulate_entity", new ManipulateEntityPacketListener(this)); + } + if (configuration.getBoolean("packet-handlers.delete-entity")) { + msg.registerIncomingPluginChannel(this, "axiom:delete_entity", new DeleteEntityPacketListener(this)); + } if (configuration.getBoolean("packet-handlers.set-buffer")) { SetBlockBufferPacketListener setBlockBufferPacketListener = new SetBlockBufferPacketListener(this); diff --git a/src/main/java/com/moulberry/axiom/packet/DeleteEntityPacketListener.java b/src/main/java/com/moulberry/axiom/packet/DeleteEntityPacketListener.java new file mode 100644 index 0000000..2fe253c --- /dev/null +++ b/src/main/java/com/moulberry/axiom/packet/DeleteEntityPacketListener.java @@ -0,0 +1,68 @@ +package com.moulberry.axiom.packet; + +import com.moulberry.axiom.AxiomPaper; +import io.netty.buffer.Unpooled; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +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.EntityType; +import net.minecraft.world.entity.decoration.HangingEntity; +import net.minecraft.world.entity.decoration.ItemFrame; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Rotation; +import net.minecraft.world.phys.Vec3; +import org.bukkit.craftbukkit.v1_20_R3.CraftWorld; +import org.bukkit.entity.Player; +import org.bukkit.plugin.messaging.PluginMessageListener; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.UUID; + +public class DeleteEntityPacketListener implements PluginMessageListener { + + private final AxiomPaper plugin; + public DeleteEntityPacketListener(AxiomPaper plugin) { + this.plugin = plugin; + } + + @Override + public void onPluginMessageReceived(@NotNull String channel, @NotNull Player player, @NotNull byte[] message) { + if (!this.plugin.canUseAxiom(player)) { + return; + } + + if (!player.hasPermission("axiom.entity.*") && !player.hasPermission("axiom.entity.delete")) { + return; + } + + if (!this.plugin.canModifyWorld(player, player.getWorld())) { + return; + } + + FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(message)); + List delete = friendlyByteBuf.readList(FriendlyByteBuf::readUUID); + + ServerLevel serverLevel = ((CraftWorld)player.getWorld()).getHandle(); + + List whitelistedEntities = this.plugin.configuration.getStringList("whitelist-entities"); + List blacklistedEntities = this.plugin.configuration.getStringList("blacklist-entities"); + + for (UUID uuid : delete) { + Entity entity = serverLevel.getEntity(uuid); + if (entity == null || entity instanceof net.minecraft.world.entity.player.Player || entity.hasPassenger(e -> e instanceof net.minecraft.world.entity.player.Player)) continue; + + String type = EntityType.getKey(entity.getType()).toString(); + + if (!whitelistedEntities.isEmpty() && !whitelistedEntities.contains(type)) continue; + if (blacklistedEntities.contains(type)) continue; + + entity.remove(Entity.RemovalReason.DISCARDED); + } + } + +} diff --git a/src/main/java/com/moulberry/axiom/packet/ManipulateEntityPacketListener.java b/src/main/java/com/moulberry/axiom/packet/ManipulateEntityPacketListener.java new file mode 100644 index 0000000..89da687 --- /dev/null +++ b/src/main/java/com/moulberry/axiom/packet/ManipulateEntityPacketListener.java @@ -0,0 +1,201 @@ +package com.moulberry.axiom.packet; + +import com.moulberry.axiom.AxiomPaper; +import io.netty.buffer.Unpooled; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.Tag; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.RelativeMovement; +import net.minecraft.world.entity.decoration.HangingEntity; +import net.minecraft.world.entity.decoration.ItemFrame; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Rotation; +import net.minecraft.world.phys.Vec3; +import org.bukkit.craftbukkit.v1_20_R3.CraftWorld; +import org.bukkit.entity.Player; +import org.bukkit.plugin.messaging.PluginMessageListener; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.Set; +import java.util.UUID; + +public class ManipulateEntityPacketListener implements PluginMessageListener { + + private final AxiomPaper plugin; + public ManipulateEntityPacketListener(AxiomPaper plugin) { + this.plugin = plugin; + } + + public enum PassengerManipulation { + NONE, + REMOVE_ALL, + ADD_LIST, + REMOVE_LIST + } + + public record ManipulateEntry(UUID uuid, @Nullable Set relativeMovementSet, @Nullable Vec3 position, + float yaw, float pitch, CompoundTag merge, PassengerManipulation passengerManipulation, List passengers) { + public static ManipulateEntry read(FriendlyByteBuf friendlyByteBuf) { + UUID uuid = friendlyByteBuf.readUUID(); + + int flags = friendlyByteBuf.readByte(); + Set relativeMovementSet = null; + Vec3 position = null; + float yaw = 0; + float pitch = 0; + if (flags >= 0) { + relativeMovementSet = RelativeMovement.unpack(flags); + position = new Vec3(friendlyByteBuf.readDouble(), friendlyByteBuf.readDouble(), friendlyByteBuf.readDouble()); + yaw = friendlyByteBuf.readFloat(); + pitch = friendlyByteBuf.readFloat(); + } + + CompoundTag nbt = friendlyByteBuf.readNbt(); + + PassengerManipulation passengerManipulation = friendlyByteBuf.readEnum(PassengerManipulation.class); + List passengers = List.of(); + if (passengerManipulation == PassengerManipulation.ADD_LIST || passengerManipulation == PassengerManipulation.REMOVE_LIST) { + passengers = friendlyByteBuf.readList(FriendlyByteBuf::readUUID); + } + + return new ManipulateEntry(uuid, relativeMovementSet, position, yaw, pitch, nbt, + passengerManipulation, passengers); + } + } + + 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; + } + + if (!player.hasPermission("axiom.entity.*") && !player.hasPermission("axiom.entity.manipulate")) { + return; + } + + if (!this.plugin.canModifyWorld(player, player.getWorld())) { + return; + } + + FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(message)); + List entries = friendlyByteBuf.readList(ManipulateEntry::read); + + ServerLevel serverLevel = ((CraftWorld)player.getWorld()).getHandle(); + + List whitelistedEntities = this.plugin.configuration.getStringList("whitelist-entities"); + List blacklistedEntities = this.plugin.configuration.getStringList("blacklist-entities"); + + for (ManipulateEntry entry : entries) { + Entity entity = serverLevel.getEntity(entry.uuid); + if (entity == null || entity instanceof net.minecraft.world.entity.player.Player || entity.hasPassenger(ManipulateEntityPacketListener::isPlayer)) continue; + + String type = EntityType.getKey(entity.getType()).toString(); + + if (!whitelistedEntities.isEmpty() && !whitelistedEntities.contains(type)) continue; + if (blacklistedEntities.contains(type)) continue; + + if (entry.merge != null && !entry.merge.isEmpty()) { + CompoundTag compoundTag = entity.saveWithoutId(new CompoundTag()); + compoundTag = merge(compoundTag, entry.merge); + entity.load(compoundTag); + } + + Vec3 entryPos = entry.position(); + if (entryPos != null && entry.relativeMovementSet != null) { + double newX = entry.relativeMovementSet.contains(RelativeMovement.X) ? entity.position().x + entryPos.x : entryPos.x; + double newY = entry.relativeMovementSet.contains(RelativeMovement.Y) ? entity.position().y + entryPos.y : entryPos.y; + double newZ = entry.relativeMovementSet.contains(RelativeMovement.Z) ? entity.position().z + entryPos.z : entryPos.z; + float newYaw = entry.relativeMovementSet.contains(RelativeMovement.Y_ROT) ? entity.getYRot() + entry.yaw : entry.yaw; + float newPitch = entry.relativeMovementSet.contains(RelativeMovement.X_ROT) ? entity.getXRot() + entry.pitch : entry.pitch; + + if (entity instanceof HangingEntity hangingEntity) { + float changedYaw = newYaw - entity.getYRot(); + int rotations = Math.round(changedYaw / 90); + hangingEntity.rotate(ROTATION_VALUES[rotations & 3]); + + if (entity instanceof ItemFrame itemFrame && itemFrame.getDirection().getAxis() == Direction.Axis.Y) { + itemFrame.setRotation(itemFrame.getRotation() - Math.round(changedYaw / 45)); + } + } + + entity.teleportTo(serverLevel, newX, newY, newZ, Set.of(), newYaw, newPitch); + entity.setYHeadRot(newYaw); + } + + switch (entry.passengerManipulation) { + case NONE -> {} + case REMOVE_ALL -> entity.ejectPassengers(); + case ADD_LIST -> { + for (UUID passengerUuid : entry.passengers) { + Entity passenger = serverLevel.getEntity(passengerUuid); + + if (passenger == null || passenger.isPassenger() || + passenger instanceof net.minecraft.world.entity.player.Player || passenger.hasPassenger(ManipulateEntityPacketListener::isPlayer)) continue; + + String passengerType = EntityType.getKey(passenger.getType()).toString(); + + if (!whitelistedEntities.isEmpty() && !whitelistedEntities.contains(passengerType)) continue; + if (blacklistedEntities.contains(passengerType)) continue; + + // Prevent mounting loop + if (passenger.getSelfAndPassengers().anyMatch(entity2 -> entity2 == entity)) { + continue; + } + + passenger.startRiding(entity, true); + } + } + case REMOVE_LIST -> { + for (UUID passengerUuid : entry.passengers) { + Entity passenger = serverLevel.getEntity(passengerUuid); + if (passenger == null || passenger == entity || passenger instanceof net.minecraft.world.entity.player.Player || + passenger.hasPassenger(ManipulateEntityPacketListener::isPlayer)) continue; + + String passengerType = EntityType.getKey(passenger.getType()).toString(); + + if (!whitelistedEntities.isEmpty() && !whitelistedEntities.contains(passengerType)) continue; + if (blacklistedEntities.contains(passengerType)) continue; + + Entity vehicle = passenger.getVehicle(); + if (vehicle == entity) { + passenger.stopRiding(); + } + } + } + } + } + } + + private static CompoundTag merge(CompoundTag left, CompoundTag right) { + for (String key : right.getAllKeys()) { + Tag tag = right.get(key); + if (tag instanceof CompoundTag compound) { + if (compound.isEmpty()) { + left.remove(key); + } else if (left.contains(key, Tag.TAG_COMPOUND)) { + CompoundTag child = left.getCompound(key); + merge(child, compound); + } else { + left.put(key, tag.copy()); + } + } else { + left.put(key, tag.copy()); + } + } + return left; + } + + private static boolean isPlayer(Entity entity) { + return entity instanceof net.minecraft.world.entity.player.Player; + } + +} diff --git a/src/main/java/com/moulberry/axiom/packet/SpawnEntityPacketListener.java b/src/main/java/com/moulberry/axiom/packet/SpawnEntityPacketListener.java new file mode 100644 index 0000000..967707e --- /dev/null +++ b/src/main/java/com/moulberry/axiom/packet/SpawnEntityPacketListener.java @@ -0,0 +1,130 @@ +package com.moulberry.axiom.packet; + +import com.moulberry.axiom.AxiomPaper; +import com.moulberry.axiom.event.AxiomTeleportEvent; +import com.moulberry.axiom.event.AxiomUnknownTeleportEvent; +import io.netty.buffer.Unpooled; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.registries.Registries; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.resources.ResourceKey; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.decoration.HangingEntity; +import net.minecraft.world.entity.decoration.ItemFrame; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Rotation; +import net.minecraft.world.phys.Vec3; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.NamespacedKey; +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.v1_20_R3.util.CraftNamespacedKey; +import org.bukkit.entity.Player; +import org.bukkit.plugin.messaging.PluginMessageListener; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.UUID; + +public class SpawnEntityPacketListener implements PluginMessageListener { + + private final AxiomPaper plugin; + public SpawnEntityPacketListener(AxiomPaper plugin) { + this.plugin = plugin; + } + + 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; + } + + if (!player.hasPermission("axiom.entity.*") && !player.hasPermission("axiom.entity.spawn")) { + return; + } + + if (!this.plugin.canModifyWorld(player, player.getWorld())) { + return; + } + + FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(message)); + List entries = friendlyByteBuf.readList(SpawnEntry::new); + + ServerLevel serverLevel = ((CraftWorld)player.getWorld()).getHandle(); + + List whitelistedEntities = this.plugin.configuration.getStringList("whitelist-entities"); + List blacklistedEntities = this.plugin.configuration.getStringList("blacklist-entities"); + + for (SpawnEntry entry : entries) { + Vec3 position = new Vec3(entry.x, entry.y, entry.z); + + BlockPos blockPos = BlockPos.containing(position); + if (!Level.isInSpawnableBounds(blockPos)) { + continue; + } + + CompoundTag tag = entry.tag == null ? new CompoundTag() : entry.tag; + + if (serverLevel.getEntity(entry.newUuid) != null) continue; + + if (entry.copyFrom != null) { + Entity entityCopyFrom = serverLevel.getEntity(entry.copyFrom); + if (entityCopyFrom != null) { + CompoundTag compoundTag = new CompoundTag(); + if (entityCopyFrom.saveAsPassenger(compoundTag)) { + compoundTag.remove("Dimension"); + tag = tag.merge(compoundTag); + } + } + } + + if (!tag.contains("id")) continue; + + Entity spawned = EntityType.loadEntityRecursive(tag, serverLevel, entity -> { + String type = EntityType.getKey(entity.getType()).toString(); + if (!whitelistedEntities.isEmpty() && !whitelistedEntities.contains(type)) return null; + if (blacklistedEntities.contains(type)) return null; + + entity.setUUID(entry.newUuid); + + if (entity instanceof HangingEntity hangingEntity) { + float changedYaw = entry.yaw - entity.getYRot(); + int rotations = Math.round(changedYaw / 90); + hangingEntity.rotate(ROTATION_VALUES[rotations & 3]); + + if (entity instanceof ItemFrame itemFrame && itemFrame.getDirection().getAxis() == Direction.Axis.Y) { + itemFrame.setRotation(itemFrame.getRotation() - Math.round(changedYaw / 45)); + } + } + + entity.moveTo(position.x, position.y, position.z, entry.yaw, entry.pitch); + entity.setYHeadRot(entity.getYRot()); + + return entity; + }); + + if (spawned != null) { + serverLevel.tryAddFreshEntityWithPassengers(spawned); + } + } + } + +} diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index edf4bc7..bf42371 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -34,6 +34,20 @@ block-buffer-rate-limit: 0 # Log large block buffer changes log-large-block-buffer-changes: false +# Whitelist entities that can be spawned/manipulated/deleted by the client +whitelist-entities: + - "minecraft:item_display" + - "minecraft:block_display" + - "minecraft:text_display" + - "minecraft:painting" + - "minecraft:armor_stand" + - "minecraft:item_frame" + - "minecraft:glow_item_frame" + +# Blacklist entities that can be spawned/manipulated/deleted by the client +blacklist-entities: +# - "minecraft:ender_dragon" + # Disallowed blocks disallowed-blocks: # - "minecraft:wheat" @@ -53,3 +67,6 @@ packet-handlers: set-editor-views: true request-chunk-data: true set-buffer: true + spawn-entity: true + manipulate-entity: true + delete-entity: true diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 67339da..f9b3b63 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -7,6 +7,15 @@ authors: api-version: "$apiVersion" permissions: axiom.*: - description: Allows use of all Axiom features + description: Allows use of all default Axiom features 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 From 8631549a4aff4445d4e28734d0ffd8acd5ae5b55 Mon Sep 17 00:00:00 2001 From: Moulberry Date: Sun, 14 Jan 2024 17:50:02 +0800 Subject: [PATCH 40/53] Use axiom:restrictions packet to control client behaviour --- .../java/com/moulberry/axiom/AxiomPaper.java | 80 ++++++++++++++++--- .../com/moulberry/axiom/Restrictions.java | 64 +++++++++++++++ .../plotsquared/PlotSquaredIntegration.java | 28 +++++++ .../PlotSquaredIntegrationImpl.java | 48 ++++++++++- .../axiom/packet/HelloPacketListener.java | 14 ++++ src/main/resources/config.yml | 21 ++--- src/main/resources/plugin.yml | 7 ++ 7 files changed, 241 insertions(+), 21 deletions(-) create mode 100644 src/main/java/com/moulberry/axiom/Restrictions.java diff --git a/src/main/java/com/moulberry/axiom/AxiomPaper.java b/src/main/java/com/moulberry/axiom/AxiomPaper.java index 0e960c0..817a488 100644 --- a/src/main/java/com/moulberry/axiom/AxiomPaper.java +++ b/src/main/java/com/moulberry/axiom/AxiomPaper.java @@ -1,11 +1,10 @@ package com.moulberry.axiom; import com.google.common.util.concurrent.RateLimiter; -import com.mojang.brigadier.StringReader; -import com.moulberry.axiom.buffer.BlockBuffer; import com.moulberry.axiom.buffer.CompressedBlockEntity; import com.moulberry.axiom.event.AxiomCreateWorldPropertiesEvent; import com.moulberry.axiom.event.AxiomModifyWorldEvent; +import com.moulberry.axiom.integration.plotsquared.PlotSquaredIntegration; import com.moulberry.axiom.packet.*; import com.moulberry.axiom.world_properties.server.ServerWorldPropertiesRegistry; import io.netty.buffer.Unpooled; @@ -15,11 +14,8 @@ import io.papermc.paper.event.world.WorldGameRuleChangeEvent; import io.papermc.paper.network.ChannelInitializeListener; import io.papermc.paper.network.ChannelInitializeListenerHolder; import net.kyori.adventure.key.Key; -import net.minecraft.commands.arguments.blocks.BlockPredicateArgument; -import net.minecraft.commands.arguments.blocks.BlockStateArgument; -import net.minecraft.commands.arguments.blocks.BlockStateParser; +import net.minecraft.core.BlockPos; import net.minecraft.core.IdMapper; -import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.network.Connection; import net.minecraft.network.ConnectionProtocol; import net.minecraft.network.FriendlyByteBuf; @@ -27,8 +23,6 @@ import net.minecraft.network.protocol.Packet; import net.minecraft.network.protocol.PacketFlow; import net.minecraft.network.protocol.common.ServerboundCustomPayloadPacket; import net.minecraft.server.MinecraftServer; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.state.BlockState; import org.bukkit.*; import org.bukkit.configuration.Configuration; @@ -43,8 +37,6 @@ import org.jetbrains.annotations.Nullable; import java.util.*; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.TimeUnit; -import java.util.logging.Level; public class AxiomPaper extends JavaPlugin implements Listener { @@ -52,6 +44,7 @@ public class AxiomPaper extends JavaPlugin implements Listener { public final Set activeAxiomPlayers = Collections.newSetFromMap(new ConcurrentHashMap<>()); public final Map playerBlockBufferRateLimiters = new ConcurrentHashMap<>(); + public final Map playerRestrictions = new ConcurrentHashMap<>(); public Configuration configuration; public IdMapper allowedBlockRegistry = null; @@ -90,6 +83,7 @@ public class AxiomPaper extends JavaPlugin implements Listener { msg.registerOutgoingPluginChannel(this, "axiom:register_world_properties"); msg.registerOutgoingPluginChannel(this, "axiom:set_world_property"); msg.registerOutgoingPluginChannel(this, "axiom:ack_world_properties"); + msg.registerOutgoingPluginChannel(this, "axiom:restrictions"); if (configuration.getBoolean("packet-handlers.hello")) { msg.registerIncomingPluginChannel(this, "axiom:hello", new HelloPacketListener(this)); @@ -162,6 +156,13 @@ public class AxiomPaper extends JavaPlugin implements Listener { Bukkit.getScheduler().scheduleSyncRepeatingTask(this, () -> { HashSet stillActiveAxiomPlayers = new HashSet<>(); + int rateLimit = this.configuration.getInt("block-buffer-rate-limit"); + if (rateLimit > 0) { + // Reduce by 20% just to prevent synchronization/timing issues + rateLimit = rateLimit * 8/10; + if (rateLimit <= 0) rateLimit = 1; + } + for (Player player : Bukkit.getServer().getOnlinePlayers()) { if (activeAxiomPlayers.contains(player.getUniqueId())) { if (!player.hasPermission("axiom.*")) { @@ -171,13 +172,70 @@ public class AxiomPaper extends JavaPlugin implements Listener { buf.getBytes(0, bytes); player.sendPluginMessage(this, "axiom:enable", bytes); } else { - stillActiveAxiomPlayers.add(player.getUniqueId()); + UUID uuid = player.getUniqueId(); + stillActiveAxiomPlayers.add(uuid); + + boolean send = false; + + Restrictions restrictions = playerRestrictions.get(uuid); + if (restrictions == null) { + restrictions = new Restrictions(); + playerRestrictions.put(uuid, restrictions); + send = true; + } + + BlockPos boundsMin = null; + BlockPos boundsMax = null; + + if (!player.hasPermission("axiom.allow_copying_other_plots")) { + if (PlotSquaredIntegration.isPlotWorld(player.getWorld())) { + PlotSquaredIntegration.PlotBounds editable = PlotSquaredIntegration.getCurrentEditablePlot(player); + if (editable != null) { + restrictions.lastPlotBounds = editable; + boundsMin = editable.min(); + boundsMax = editable.max(); + } else if (restrictions.lastPlotBounds != null && restrictions.lastPlotBounds.worldName().equals(player.getWorld().getName())) { + boundsMin = restrictions.lastPlotBounds.min(); + boundsMax = restrictions.lastPlotBounds.max(); + } else { + boundsMin = BlockPos.ZERO; + boundsMax = BlockPos.ZERO; + } + } + + int min = Integer.MIN_VALUE; + int max = Integer.MAX_VALUE; + if (boundsMin != null && boundsMax != null && + boundsMin.getX() == min && boundsMin.getY() == min && boundsMin.getZ() == min && + boundsMax.getX() == max && boundsMax.getY() == max && boundsMax.getZ() == max) { + boundsMin = null; + boundsMax = null; + } + } + + boolean allowImportingBlocks = player.hasPermission("axiom.can_import_blocks"); + + if (restrictions.maxSectionsPerSecond != rateLimit || + restrictions.canImportBlocks != allowImportingBlocks || + !Objects.equals(restrictions.boundsMin, boundsMin) || + !Objects.equals(restrictions.boundsMax, boundsMax)) { + restrictions.maxSectionsPerSecond = rateLimit; + restrictions.canImportBlocks = allowImportingBlocks; + restrictions.boundsMin = boundsMin; + restrictions.boundsMax = boundsMax; + send = true; + } + + if (send) { + restrictions.send(this, player); + } } } } activeAxiomPlayers.retainAll(stillActiveAxiomPlayers); playerBlockBufferRateLimiters.keySet().retainAll(stillActiveAxiomPlayers); + playerRestrictions.keySet().retainAll(stillActiveAxiomPlayers); }, 20, 20); int maxChunkRelightsPerTick = configuration.getInt("max-chunk-relights-per-tick"); diff --git a/src/main/java/com/moulberry/axiom/Restrictions.java b/src/main/java/com/moulberry/axiom/Restrictions.java new file mode 100644 index 0000000..5dd0180 --- /dev/null +++ b/src/main/java/com/moulberry/axiom/Restrictions.java @@ -0,0 +1,64 @@ +package com.moulberry.axiom; + +import com.moulberry.axiom.integration.plotsquared.PlotSquaredIntegration; +import io.netty.buffer.Unpooled; +import net.minecraft.core.BlockPos; +import net.minecraft.network.FriendlyByteBuf; +import org.bukkit.entity.Player; + +public class Restrictions { + + public boolean canImportBlocks = true; + public boolean canUseEditor = true; + public boolean canEditDisplayEntities = true; + public int maxSectionsPerSecond = 0; + public BlockPos boundsMin = null; + public BlockPos boundsMax = null; + + public PlotSquaredIntegration.PlotBounds lastPlotBounds = null; + + public void send(AxiomPaper plugin, Player player) { + if (player.getListeningPluginChannels().contains("axiom:restrictions")) { + FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer()); + buf.writeBoolean(this.canImportBlocks); + buf.writeBoolean(this.canUseEditor); + buf.writeBoolean(this.canEditDisplayEntities); + + buf.writeVarInt(this.maxSectionsPerSecond); + + if (this.boundsMin == null || this.boundsMax == null) { + buf.writeBoolean(false); + } else { + buf.writeBoolean(true); + int minX = this.boundsMin.getX(); + int minY = this.boundsMin.getY(); + int minZ = this.boundsMin.getZ(); + int maxX = this.boundsMax.getX(); + int maxY = this.boundsMax.getY(); + int maxZ = this.boundsMax.getZ(); + + if (minX < -33554431) minX = -33554431; + if (minX > 33554431) minX = 33554431; + if (minY < -2047) minY = -2047; + if (minY > 2047) minY = 2047; + if (minZ < -33554431) minZ = -33554431; + if (minZ > 33554431) minZ = 33554431; + + if (maxX < -33554431) maxX = -33554431; + if (maxX > 33554431) maxX = 33554431; + if (maxY < -2047) maxY = -2047; + if (maxY > 2047) maxY = 2047; + if (maxZ < -33554431) maxZ = -33554431; + if (maxZ > 33554431) maxZ = 33554431; + + buf.writeBlockPos(new BlockPos(minX, minY, minZ)); + buf.writeBlockPos(new BlockPos(maxX, maxY, maxZ)); + } + + byte[] bytes = new byte[buf.writerIndex()]; + buf.getBytes(0, bytes); + player.sendPluginMessage(plugin, "axiom:restrictions", bytes); + } + } + +} diff --git a/src/main/java/com/moulberry/axiom/integration/plotsquared/PlotSquaredIntegration.java b/src/main/java/com/moulberry/axiom/integration/plotsquared/PlotSquaredIntegration.java index e307a29..deab2cf 100644 --- a/src/main/java/com/moulberry/axiom/integration/plotsquared/PlotSquaredIntegration.java +++ b/src/main/java/com/moulberry/axiom/integration/plotsquared/PlotSquaredIntegration.java @@ -2,7 +2,10 @@ package com.moulberry.axiom.integration.plotsquared; import com.moulberry.axiom.integration.SectionPermissionChecker; +import com.sk89q.worldedit.regions.CuboidRegion; +import net.minecraft.core.BlockPos; import org.bukkit.Bukkit; +import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.entity.Player; @@ -10,6 +13,24 @@ import org.bukkit.entity.Player; public class PlotSquaredIntegration { + public record PlotBounds(BlockPos min, BlockPos max, String worldName) { + public PlotBounds(CuboidRegion cuboidRegion, String worldName) { + this( + new BlockPos( + cuboidRegion.getMinimumPoint().getBlockX(), + cuboidRegion.getMinimumPoint().getBlockY(), + cuboidRegion.getMinimumPoint().getBlockZ() + ), + new BlockPos( + cuboidRegion.getMaximumPoint().getBlockX(), + cuboidRegion.getMaximumPoint().getBlockY(), + cuboidRegion.getMaximumPoint().getBlockZ() + ), + worldName + ); + } + } + public static boolean canBreakBlock(Player player, Block block) { if (!Bukkit.getPluginManager().isPluginEnabled("PlotSquared")) { return true; @@ -31,6 +52,13 @@ public class PlotSquaredIntegration { return PlotSquaredIntegrationImpl.isPlotWorld(world); } + public static PlotSquaredIntegration.PlotBounds getCurrentEditablePlot(Player player) { + if (!Bukkit.getPluginManager().isPluginEnabled("PlotSquared")) { + return null; + } + return PlotSquaredIntegrationImpl.getCurrentEditablePlot(player); + } + public static SectionPermissionChecker checkSection(Player player, World world, int sectionX, int sectionY, int sectionZ) { if (!Bukkit.getPluginManager().isPluginEnabled("PlotSquared")) { return SectionPermissionChecker.ALL_ALLOWED; diff --git a/src/main/java/com/moulberry/axiom/integration/plotsquared/PlotSquaredIntegrationImpl.java b/src/main/java/com/moulberry/axiom/integration/plotsquared/PlotSquaredIntegrationImpl.java index e530e0d..a9d6e3d 100644 --- a/src/main/java/com/moulberry/axiom/integration/plotsquared/PlotSquaredIntegrationImpl.java +++ b/src/main/java/com/moulberry/axiom/integration/plotsquared/PlotSquaredIntegrationImpl.java @@ -135,6 +135,52 @@ public class PlotSquaredIntegrationImpl { return isPlotWorld; } + static PlotSquaredIntegration.PlotBounds getCurrentEditablePlot(Player player) { + org.bukkit.Location loc = player.getLocation(); + + Location location = BukkitUtil.adapt(loc); + PlotArea area = location.getPlotArea(); + if (area == null) { + return null; + } + + BukkitPlayer pp = BukkitUtil.adapt(player); + Plot plot = area.getPlot(location); + if (plot != null) { + Location bottom = plot.getExtendedBottomAbs(); + Location top = plot.getExtendedTopAbs(); + CuboidRegion cuboidRegion = new CuboidRegion(bottom.getBlockVector3(), top.getBlockVector3()); + + // check unowned plots + if (!plot.hasOwner()) { + if (!pp.hasPermission(Permission.PERMISSION_ADMIN_BUILD_UNOWNED, false)) { + return null; + } else { + return new PlotSquaredIntegration.PlotBounds(cuboidRegion, player.getWorld().getName()); + } + } + // player is breaking another player's plot + if (!plot.isAdded(pp.getUUID())) { + if (!pp.hasPermission(Permission.PERMISSION_ADMIN_BUILD_OTHER, false)) { + return null; + } else { + return new PlotSquaredIntegration.PlotBounds(cuboidRegion, player.getWorld().getName()); + } + } + // plot is 'done' + if (Settings.Done.RESTRICT_BUILDING && DoneFlag.isDone(plot)) { + if (!pp.hasPermission(Permission.PERMISSION_ADMIN_BUILD_OTHER, false)) { + return null; + } else { + return new PlotSquaredIntegration.PlotBounds(cuboidRegion, player.getWorld().getName()); + } + } + return new PlotSquaredIntegration.PlotBounds(cuboidRegion, player.getWorld().getName()); + } + + return null; + } + static SectionPermissionChecker checkSection(Player player, World world, int sectionX, int sectionY, int sectionZ) { int minX = sectionX * 16; int minY = sectionY * 16; @@ -220,4 +266,4 @@ public class PlotSquaredIntegrationImpl { return SectionPermissionChecker.fromAllowedBoxes(allowed); } -} \ No newline at end of file +} diff --git a/src/main/java/com/moulberry/axiom/packet/HelloPacketListener.java b/src/main/java/com/moulberry/axiom/packet/HelloPacketListener.java index 5f60988..0344e6b 100644 --- a/src/main/java/com/moulberry/axiom/packet/HelloPacketListener.java +++ b/src/main/java/com/moulberry/axiom/packet/HelloPacketListener.java @@ -77,6 +77,20 @@ public class HelloPacketListener implements PluginMessageListener { } } + if (!player.getListeningPluginChannels().contains("axiom:restrictions")) { + Component text = Component.text("This server requires the use of Axiom 2.3 or later. Contact the server administrator if you believe this is unintentional"); + + String unsupportedRestrictions = plugin.configuration.getString("client-doesnt-support-restrictions"); + if (unsupportedRestrictions == null) unsupportedRestrictions = "kick"; + if (unsupportedRestrictions.equals("warn")) { + player.sendMessage(text.color(NamedTextColor.RED)); + return; + } else if (!unsupportedRestrictions.equals("ignore")) { + player.kick(text); + return; + } + } + // Call handshake event int maxBufferSize = plugin.configuration.getInt("max-block-buffer-packet-size"); AxiomHandshakeEvent handshakeEvent = new AxiomHandshakeEvent(player, maxBufferSize); diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index bf42371..7e87583 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -13,9 +13,12 @@ allow-teleport-between-worlds: true # Action to take when a user with an incompatible Minecraft version or Axiom version joins # Valid actions are 'kick', 'warn' and 'ignore' +# 'warn' will give the player a warning and disable Axiom # Using 'ignore' may result in corruption and is only provided for debugging purposes -incompatible-data-version: "kick" -unsupported-axiom-version: "kick" +incompatible-data-version: "warn" +unsupported-axiom-version: "warn" +client-doesnt-support-restrictions: "ignore" + # Maximum packet size. Must not be less than 32767 max-block-buffer-packet-size: 0x100000 @@ -36,13 +39,13 @@ log-large-block-buffer-changes: false # Whitelist entities that can be spawned/manipulated/deleted by the client whitelist-entities: - - "minecraft:item_display" - - "minecraft:block_display" - - "minecraft:text_display" - - "minecraft:painting" - - "minecraft:armor_stand" - - "minecraft:item_frame" - - "minecraft:glow_item_frame" +# - "minecraft:item_display" +# - "minecraft:block_display" +# - "minecraft:text_display" +# - "minecraft:painting" +# - "minecraft:armor_stand" +# - "minecraft:item_frame" +# - "minecraft:glow_item_frame" # Blacklist entities that can be spawned/manipulated/deleted by the client blacklist-entities: diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index f9b3b63..53267da 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -19,3 +19,10 @@ permissions: description: Allows entity manipulation axiom.entity.delete: description: Allows entity deletion + + axiom.allow_copying_other_plots: + description: This permission allows users to copy other user's plots + default: true + axiom.can_import_blocks: + description: Allows players to import schematics/blueprints into Axiom + default: true From 8cd2930fa216e3574ed5846bb53f6d1743cbed9b Mon Sep 17 00:00:00 2001 From: Moulberry Date: Sun, 14 Jan 2024 17:57:00 +0800 Subject: [PATCH 41/53] Bump version to 1.5.8 --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index acd30d4..91d0d4e 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -8,7 +8,7 @@ plugins { } group = "com.moulberry.axiom" -version = "1.5.7" +version = "1.5.8" description = "Serverside component for Axiom on Paper" java { From b694a0515bdd67dc7bdca0c7b31d06d3e94b8e75 Mon Sep 17 00:00:00 2001 From: Moulberry Date: Sun, 21 Jan 2024 13:21:36 +0800 Subject: [PATCH 42/53] Implement axiom:modify logic for tag merging --- .../packet/ManipulateEntityPacketListener.java | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/moulberry/axiom/packet/ManipulateEntityPacketListener.java b/src/main/java/com/moulberry/axiom/packet/ManipulateEntityPacketListener.java index 89da687..dc31da8 100644 --- a/src/main/java/com/moulberry/axiom/packet/ManipulateEntityPacketListener.java +++ b/src/main/java/com/moulberry/axiom/packet/ManipulateEntityPacketListener.java @@ -176,6 +176,11 @@ public class ManipulateEntityPacketListener implements PluginMessageListener { } private static CompoundTag merge(CompoundTag left, CompoundTag right) { + if (right.contains("axiom:modify")) { + right.remove("axiom:modify"); + return right; + } + for (String key : right.getAllKeys()) { Tag tag = right.get(key); if (tag instanceof CompoundTag compound) { @@ -183,9 +188,14 @@ public class ManipulateEntityPacketListener implements PluginMessageListener { left.remove(key); } else if (left.contains(key, Tag.TAG_COMPOUND)) { CompoundTag child = left.getCompound(key); - merge(child, compound); + child = merge(child, compound); + left.put(key, child); } else { - left.put(key, tag.copy()); + CompoundTag copied = compound.copy(); + if (copied.contains("axiom:modify")) { + copied.remove("axiom:modify"); + } + left.put(key, copied); } } else { left.put(key, tag.copy()); From dbcfd0bb2b16f002a53235662d4868981fc2ad73 Mon Sep 17 00:00:00 2001 From: Moulberry Date: Sun, 21 Jan 2024 19:24:51 +0800 Subject: [PATCH 43/53] Add marker manipulation & nbt sanitization --- .../java/com/moulberry/axiom/AxiomPaper.java | 27 +++-- .../com/moulberry/axiom/NbtSanitization.java | 63 +++++++++++ .../com/moulberry/axiom/WorldExtension.java | 84 ++++++++++++-- .../moulberry/axiom/marker/MarkerData.java | 105 ++++++++++++++++++ .../axiom/packet/HelloPacketListener.java | 3 + .../ManipulateEntityPacketListener.java | 3 + .../MarkerNbtRequestPacketListener.java | 66 +++++++++++ .../packet/SpawnEntityPacketListener.java | 5 +- src/main/resources/config.yml | 5 +- 9 files changed, 345 insertions(+), 16 deletions(-) create mode 100644 src/main/java/com/moulberry/axiom/NbtSanitization.java create mode 100644 src/main/java/com/moulberry/axiom/marker/MarkerData.java create mode 100644 src/main/java/com/moulberry/axiom/packet/MarkerNbtRequestPacketListener.java diff --git a/src/main/java/com/moulberry/axiom/AxiomPaper.java b/src/main/java/com/moulberry/axiom/AxiomPaper.java index 817a488..fe23a99 100644 --- a/src/main/java/com/moulberry/axiom/AxiomPaper.java +++ b/src/main/java/com/moulberry/axiom/AxiomPaper.java @@ -84,6 +84,8 @@ public class AxiomPaper extends JavaPlugin implements Listener { msg.registerOutgoingPluginChannel(this, "axiom:set_world_property"); msg.registerOutgoingPluginChannel(this, "axiom:ack_world_properties"); msg.registerOutgoingPluginChannel(this, "axiom:restrictions"); + msg.registerOutgoingPluginChannel(this, "axiom:marker_data"); + msg.registerOutgoingPluginChannel(this, "axiom:marker_nbt_response"); if (configuration.getBoolean("packet-handlers.hello")) { msg.registerIncomingPluginChannel(this, "axiom:hello", new HelloPacketListener(this)); @@ -127,6 +129,9 @@ public class AxiomPaper extends JavaPlugin implements Listener { if (configuration.getBoolean("packet-handlers.delete-entity")) { msg.registerIncomingPluginChannel(this, "axiom:delete_entity", new DeleteEntityPacketListener(this)); } + if (configuration.getBoolean("packet-handlers.marker-nbt-request")) { + msg.registerIncomingPluginChannel(this, "axiom:marker_nbt_request", new MarkerNbtRequestPacketListener(this)); + } if (configuration.getBoolean("packet-handlers.set-buffer")) { SetBlockBufferPacketListener setBlockBufferPacketListener = new SetBlockBufferPacketListener(this); @@ -238,11 +243,12 @@ public class AxiomPaper extends JavaPlugin implements Listener { playerRestrictions.keySet().retainAll(stillActiveAxiomPlayers); }, 20, 20); + boolean sendMarkers = configuration.getBoolean("send-markers"); int maxChunkRelightsPerTick = configuration.getInt("max-chunk-relights-per-tick"); int maxChunkSendsPerTick = configuration.getInt("max-chunk-sends-per-tick"); Bukkit.getScheduler().scheduleSyncRepeatingTask(this, () -> { - WorldExtension.tick(MinecraftServer.getServer(), maxChunkRelightsPerTick, maxChunkSendsPerTick); + WorldExtension.tick(MinecraftServer.getServer(), sendMarkers, maxChunkRelightsPerTick, maxChunkSendsPerTick); }, 1, 1); } @@ -292,17 +298,22 @@ public class AxiomPaper extends JavaPlugin implements Listener { @EventHandler public void onFailMove(PlayerFailMoveEvent event) { - if (event.getPlayer().hasPermission("axiom.*")) { - if (event.getFailReason() == PlayerFailMoveEvent.FailReason.MOVED_TOO_QUICKLY) { - event.setAllowed(true); // Support for arcball camera - } else if (event.getPlayer().isFlying()) { - event.setAllowed(true); // Support for noclip - } + if (!this.activeAxiomPlayers.contains(event.getPlayer().getUniqueId())) { + return; + } + if (event.getFailReason() == PlayerFailMoveEvent.FailReason.MOVED_TOO_QUICKLY) { + event.setAllowed(true); // Support for arcball camera + } else if (event.getPlayer().isFlying()) { + event.setAllowed(true); // Support for noclip } } @EventHandler public void onChangedWorld(PlayerChangedWorldEvent event) { + if (!this.activeAxiomPlayers.contains(event.getPlayer().getUniqueId())) { + return; + } + World world = event.getPlayer().getWorld(); ServerWorldPropertiesRegistry properties = getOrCreateWorldProperties(world); @@ -312,6 +323,8 @@ public class AxiomPaper extends JavaPlugin implements Listener { } else { properties.registerFor(this, event.getPlayer()); } + + WorldExtension.onPlayerJoin(world, event.getPlayer()); } @EventHandler diff --git a/src/main/java/com/moulberry/axiom/NbtSanitization.java b/src/main/java/com/moulberry/axiom/NbtSanitization.java new file mode 100644 index 0000000..c24c4df --- /dev/null +++ b/src/main/java/com/moulberry/axiom/NbtSanitization.java @@ -0,0 +1,63 @@ +package com.moulberry.axiom; + +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.Tag; + +import java.util.Set; + +public class NbtSanitization { + + private static final Set ALLOWED_KEYS = Set.of( + "id", // entity id + // generic + "Pos", + "Rotation", + "Invulnerable", + "CustomName", + "CustomNameVisible", + "Silent", + "NoGravity", + "Glowing", + "Tags", + "Passengers", + // marker + "data", + // display entity + "transformation", + "interpolation_duration", + "start_interpolation", + "teleport_duration", + "billboard", + "view_range", + "shadow_radius", + "shadow_strength", + "width", + "height", + "glow_color_override", + "brightness", + "line_width", + "text_opacity", + "background", + "shadow", + "see_through", + "default_background", + "alignment", + "text", + "block_state", + "item", + "item_display" + ); + + public static void sanitizeEntity(CompoundTag entityRoot) { + entityRoot.getAllKeys().retainAll(ALLOWED_KEYS); + + if (entityRoot.contains("Passengers", Tag.TAG_LIST)) { + ListTag listTag = entityRoot.getList("Passengers", Tag.TAG_COMPOUND); + for (Tag tag : listTag) { + sanitizeEntity((CompoundTag) tag); + } + } + } + +} diff --git a/src/main/java/com/moulberry/axiom/WorldExtension.java b/src/main/java/com/moulberry/axiom/WorldExtension.java index e18c2b8..2152bb2 100644 --- a/src/main/java/com/moulberry/axiom/WorldExtension.java +++ b/src/main/java/com/moulberry/axiom/WorldExtension.java @@ -1,15 +1,24 @@ package com.moulberry.axiom; +import com.moulberry.axiom.marker.MarkerData; +import io.netty.buffer.Unpooled; import it.unimi.dsi.fastutil.longs.*; +import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; import net.minecraft.resources.ResourceKey; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ChunkMap; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.Marker; 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.entity.Player; import java.util.*; @@ -23,15 +32,16 @@ public class WorldExtension { return extension; } - public static void tick(MinecraftServer server, int maxChunkRelightsPerTick, int maxChunkSendsPerTick) { + public static void onPlayerJoin(World world, Player player) { + ServerLevel level = ((CraftWorld)world).getHandle(); + get(level).onPlayerJoin(player); + } + + public static void tick(MinecraftServer server, boolean sendMarkers, int maxChunkRelightsPerTick, int maxChunkSendsPerTick) { extensions.keySet().retainAll(server.levelKeys()); for (ServerLevel level : server.getAllLevels()) { - WorldExtension extension = extensions.get(level.dimension()); - if (extension != null) { - extension.level = level; - extension.tick(maxChunkRelightsPerTick, maxChunkSendsPerTick); - } + get(level).tick(sendMarkers, maxChunkRelightsPerTick, maxChunkSendsPerTick); } } @@ -39,6 +49,7 @@ public class WorldExtension { private final LongSet pendingChunksToSend = new LongOpenHashSet(); private final LongSet pendingChunksToLight = new LongOpenHashSet(); + private final Map previousMarkerData = new HashMap<>(); public void sendChunk(int cx, int cz) { this.pendingChunksToSend.add(ChunkPos.asLong(cx, cz)); @@ -48,7 +59,66 @@ public class WorldExtension { this.pendingChunksToLight.add(ChunkPos.asLong(cx, cz)); } - public void tick(int maxChunkRelightsPerTick, int maxChunkSendsPerTick) { + public void onPlayerJoin(Player player) { + if (!this.previousMarkerData.isEmpty()) { + List markerData = new ArrayList<>(this.previousMarkerData.values()); + + FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer()); + buf.writeCollection(markerData, MarkerData::write); + buf.writeCollection(Set.of(), FriendlyByteBuf::writeUUID); + byte[] bytes = new byte[buf.writerIndex()]; + buf.getBytes(0, bytes); + + player.sendPluginMessage(AxiomPaper.PLUGIN, "axiom:marker_data", bytes); + } + } + + public void tick(boolean sendMarkers, int maxChunkRelightsPerTick, int maxChunkSendsPerTick) { + if (sendMarkers) { + this.tickMarkers(); + } + this.tickChunkRelight(maxChunkRelightsPerTick, maxChunkSendsPerTick); + } + + private void tickMarkers() { + List changedData = new ArrayList<>(); + + Set allMarkers = new HashSet<>(); + + for (Entity entity : this.level.getEntities().getAll()) { + if (entity instanceof Marker marker) { + MarkerData currentData = MarkerData.createFrom(marker); + + MarkerData previousData = this.previousMarkerData.get(marker.getUUID()); + if (!Objects.equals(currentData, previousData)) { + this.previousMarkerData.put(marker.getUUID(), currentData); + changedData.add(currentData); + } + + allMarkers.add(marker.getUUID()); + } + } + + Set oldUuids = new HashSet<>(this.previousMarkerData.keySet()); + oldUuids.removeAll(allMarkers); + this.previousMarkerData.keySet().removeAll(oldUuids); + + if (!changedData.isEmpty() || !oldUuids.isEmpty()) { + FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer()); + buf.writeCollection(changedData, MarkerData::write); + buf.writeCollection(oldUuids, FriendlyByteBuf::writeUUID); + byte[] bytes = new byte[buf.writerIndex()]; + buf.getBytes(0, bytes); + + for (ServerPlayer player : this.level.players()) { + if (AxiomPaper.PLUGIN.activeAxiomPlayers.contains(player.getUUID())) { + player.getBukkitEntity().sendPluginMessage(AxiomPaper.PLUGIN, "axiom:marker_data", bytes); + } + } + } + } + + private void tickChunkRelight(int maxChunkRelightsPerTick, int maxChunkSendsPerTick) { ChunkMap chunkMap = this.level.getChunkSource().chunkMap; boolean sendAll = maxChunkSendsPerTick <= 0; diff --git a/src/main/java/com/moulberry/axiom/marker/MarkerData.java b/src/main/java/com/moulberry/axiom/marker/MarkerData.java new file mode 100644 index 0000000..e86411f --- /dev/null +++ b/src/main/java/com/moulberry/axiom/marker/MarkerData.java @@ -0,0 +1,105 @@ +package com.moulberry.axiom.marker; + +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.Tag; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.world.entity.Marker; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.phys.Vec3; +import org.jetbrains.annotations.Nullable; +import xyz.jpenilla.reflectionremapper.ReflectionRemapper; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.UUID; + +public record MarkerData(UUID uuid, Vec3 position, @Nullable String name, @Nullable Vec3 minRegion, @Nullable Vec3 maxRegion) { + public static MarkerData read(FriendlyByteBuf friendlyByteBuf) { + UUID uuid = friendlyByteBuf.readUUID(); + Vec3 position = new Vec3(friendlyByteBuf.readDouble(), friendlyByteBuf.readDouble(), friendlyByteBuf.readDouble()); + String name = friendlyByteBuf.readNullable(FriendlyByteBuf::readUtf); + + Vec3 minRegion = null; + Vec3 maxRegion = null; + if (friendlyByteBuf.readBoolean()) { + minRegion = new Vec3(friendlyByteBuf.readDouble(), friendlyByteBuf.readDouble(), friendlyByteBuf.readDouble()); + maxRegion = new Vec3(friendlyByteBuf.readDouble(), friendlyByteBuf.readDouble(), friendlyByteBuf.readDouble()); + } + + return new MarkerData(uuid, position, name, minRegion, maxRegion); + } + + public static void write(FriendlyByteBuf friendlyByteBuf, MarkerData markerData) { + friendlyByteBuf.writeUUID(markerData.uuid); + friendlyByteBuf.writeDouble(markerData.position.x); + friendlyByteBuf.writeDouble(markerData.position.y); + friendlyByteBuf.writeDouble(markerData.position.z); + friendlyByteBuf.writeNullable(markerData.name, FriendlyByteBuf::writeUtf); + + if (markerData.minRegion != null && markerData.maxRegion != null) { + friendlyByteBuf.writeBoolean(true); + friendlyByteBuf.writeDouble(markerData.minRegion.x); + friendlyByteBuf.writeDouble(markerData.minRegion.y); + friendlyByteBuf.writeDouble(markerData.minRegion.z); + friendlyByteBuf.writeDouble(markerData.maxRegion.x); + friendlyByteBuf.writeDouble(markerData.maxRegion.y); + friendlyByteBuf.writeDouble(markerData.maxRegion.z); + } else { + friendlyByteBuf.writeBoolean(false); + } + } + + private static final Field dataField; + static { + ReflectionRemapper reflectionRemapper = ReflectionRemapper.forReobfMappingsInPaperJar(); + String fieldName = reflectionRemapper.remapFieldName(Marker.class, "data"); + + try { + dataField = Marker.class.getDeclaredField(fieldName); + dataField.setAccessible(true); + } catch (Exception e) { + e.printStackTrace(); + throw new RuntimeException(e); + } + } + + public static CompoundTag getData(Marker marker) { + try { + return (CompoundTag) dataField.get(marker); + } catch (Exception e) { + e.printStackTrace(); + throw new RuntimeException(e); + } + } + + public static MarkerData createFrom(Marker marker) { + Vec3 position = marker.position(); + CompoundTag data = getData(marker); + + String name = data.getString("name").trim(); + if (name.isEmpty()) name = null; + + Vec3 minRegion = null; + Vec3 maxRegion = null; + if (data.contains("min", Tag.TAG_LIST) && data.contains("max", Tag.TAG_LIST)) { + ListTag min = data.getList("min", Tag.TAG_DOUBLE); + ListTag max = data.getList("max", Tag.TAG_DOUBLE); + + if (min.size() == 3 && max.size() == 3) { + double minX = min.getDouble(0); + double minY = min.getDouble(1); + double minZ = min.getDouble(2); + double maxX = max.getDouble(0); + double maxY = max.getDouble(1); + double maxZ = max.getDouble(2); + minRegion = new Vec3(minX, minY, minZ); + maxRegion = new Vec3(maxX, maxY, maxZ); + } + + } + + return new MarkerData(marker.getUUID(), position, name, minRegion, maxRegion); + } +} diff --git a/src/main/java/com/moulberry/axiom/packet/HelloPacketListener.java b/src/main/java/com/moulberry/axiom/packet/HelloPacketListener.java index 0344e6b..6843a54 100644 --- a/src/main/java/com/moulberry/axiom/packet/HelloPacketListener.java +++ b/src/main/java/com/moulberry/axiom/packet/HelloPacketListener.java @@ -4,6 +4,7 @@ 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.event.AxiomHandshakeEvent; import com.moulberry.axiom.persistence.ItemStackDataType; import com.moulberry.axiom.persistence.UUIDDataType; @@ -167,6 +168,8 @@ public class HelloPacketListener implements PluginMessageListener { } else { properties.registerFor(plugin, player); } + + WorldExtension.onPlayerJoin(world, player); } } diff --git a/src/main/java/com/moulberry/axiom/packet/ManipulateEntityPacketListener.java b/src/main/java/com/moulberry/axiom/packet/ManipulateEntityPacketListener.java index dc31da8..0cb5769 100644 --- a/src/main/java/com/moulberry/axiom/packet/ManipulateEntityPacketListener.java +++ b/src/main/java/com/moulberry/axiom/packet/ManipulateEntityPacketListener.java @@ -1,6 +1,7 @@ package com.moulberry.axiom.packet; import com.moulberry.axiom.AxiomPaper; +import com.moulberry.axiom.NbtSanitization; import io.netty.buffer.Unpooled; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; @@ -104,6 +105,8 @@ public class ManipulateEntityPacketListener implements PluginMessageListener { if (blacklistedEntities.contains(type)) continue; if (entry.merge != null && !entry.merge.isEmpty()) { + NbtSanitization.sanitizeEntity(entry.merge); + CompoundTag compoundTag = entity.saveWithoutId(new CompoundTag()); compoundTag = merge(compoundTag, entry.merge); entity.load(compoundTag); diff --git a/src/main/java/com/moulberry/axiom/packet/MarkerNbtRequestPacketListener.java b/src/main/java/com/moulberry/axiom/packet/MarkerNbtRequestPacketListener.java new file mode 100644 index 0000000..55f9b16 --- /dev/null +++ b/src/main/java/com/moulberry/axiom/packet/MarkerNbtRequestPacketListener.java @@ -0,0 +1,66 @@ +package com.moulberry.axiom.packet; + +import com.moulberry.axiom.AxiomPaper; +import com.moulberry.axiom.event.AxiomTimeChangeEvent; +import com.moulberry.axiom.integration.plotsquared.PlotSquaredIntegration; +import com.moulberry.axiom.marker.MarkerData; +import io.netty.buffer.Unpooled; +import net.minecraft.core.registries.Registries; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.resources.ResourceKey; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.Marker; +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.entity.Player; +import org.bukkit.plugin.messaging.PluginMessageListener; +import org.jetbrains.annotations.NotNull; + +import java.util.Set; +import java.util.UUID; + +public class MarkerNbtRequestPacketListener implements PluginMessageListener { + + private final AxiomPaper plugin; + public MarkerNbtRequestPacketListener(AxiomPaper plugin) { + this.plugin = plugin; + } + + @Override + public void onPluginMessageReceived(@NotNull String channel, @NotNull Player player, @NotNull byte[] message) { + if (!this.plugin.canUseAxiom(player)) { + return; + } + + if (!player.hasPermission("axiom.entity.*") && !player.hasPermission("axiom.entity.manipulate")) { + return; + } + + if (!this.plugin.canModifyWorld(player, player.getWorld())) { + return; + } + + FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(message)); + UUID uuid = friendlyByteBuf.readUUID(); + + ServerLevel serverLevel = ((CraftWorld)player.getWorld()).getHandle(); + + Entity entity = serverLevel.getEntity(uuid); + if (entity instanceof Marker marker) { + CompoundTag data = MarkerData.getData(marker); + + FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer()); + buf.writeUUID(uuid); + buf.writeNbt(data); + byte[] bytes = new byte[buf.writerIndex()]; + buf.getBytes(0, bytes); + + player.sendPluginMessage(AxiomPaper.PLUGIN, "axiom:marker_nbt_response", bytes); + } + } + +} diff --git a/src/main/java/com/moulberry/axiom/packet/SpawnEntityPacketListener.java b/src/main/java/com/moulberry/axiom/packet/SpawnEntityPacketListener.java index 967707e..ea6f385 100644 --- a/src/main/java/com/moulberry/axiom/packet/SpawnEntityPacketListener.java +++ b/src/main/java/com/moulberry/axiom/packet/SpawnEntityPacketListener.java @@ -1,6 +1,7 @@ package com.moulberry.axiom.packet; import com.moulberry.axiom.AxiomPaper; +import com.moulberry.axiom.NbtSanitization; import com.moulberry.axiom.event.AxiomTeleportEvent; import com.moulberry.axiom.event.AxiomUnknownTeleportEvent; import io.netty.buffer.Unpooled; @@ -81,9 +82,11 @@ public class SpawnEntityPacketListener implements PluginMessageListener { continue; } + if (serverLevel.getEntity(entry.newUuid) != null) continue; + CompoundTag tag = entry.tag == null ? new CompoundTag() : entry.tag; - if (serverLevel.getEntity(entry.newUuid) != null) continue; + NbtSanitization.sanitizeEntity(tag); if (entry.copyFrom != null) { Entity entityCopyFrom = serverLevel.getEntity(entry.copyFrom); diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 7e87583..f5c0b38 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -19,7 +19,6 @@ incompatible-data-version: "warn" unsupported-axiom-version: "warn" client-doesnt-support-restrictions: "ignore" - # Maximum packet size. Must not be less than 32767 max-block-buffer-packet-size: 0x100000 @@ -51,6 +50,9 @@ whitelist-entities: blacklist-entities: # - "minecraft:ender_dragon" +# True allows players to see/manipulate marker entities +send-markers: false + # Disallowed blocks disallowed-blocks: # - "minecraft:wheat" @@ -73,3 +75,4 @@ packet-handlers: spawn-entity: true manipulate-entity: true delete-entity: true + marker-nbt-request: true From ff46b9330cc40880a1e0752109ede218896a899e Mon Sep 17 00:00:00 2001 From: yoyosource Date: Sun, 3 Sep 2023 12:22:53 +0200 Subject: [PATCH 44/53] Add steamwarci.yml --- steamwarci.yml | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 steamwarci.yml diff --git a/steamwarci.yml b/steamwarci.yml new file mode 100644 index 0000000..b950a8d --- /dev/null +++ b/steamwarci.yml @@ -0,0 +1,9 @@ +setup: + - "ln -s /home/gitea/lib" + +build: + - "./gradlew shadowJar" + - "./gradlew --stop" + +artifacts: + "/binarys/AxiomPaper.jar": "build/libs/AxiomPaper-1.0.0-SNAPSHOT-dev-all.jar" From a8fdb871d4919d8f172ae12a182b6c477176b2d6 Mon Sep 17 00:00:00 2001 From: yoyosource Date: Sun, 3 Sep 2023 12:25:46 +0200 Subject: [PATCH 45/53] Add steamwarci.yml --- steamwarci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/steamwarci.yml b/steamwarci.yml index b950a8d..8897287 100644 --- a/steamwarci.yml +++ b/steamwarci.yml @@ -2,8 +2,8 @@ setup: - "ln -s /home/gitea/lib" build: - - "./gradlew shadowJar" - - "./gradlew --stop" + - "JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64 ./gradlew shadowJar" + - "JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64 ./gradlew --stop" artifacts: "/binarys/AxiomPaper.jar": "build/libs/AxiomPaper-1.0.0-SNAPSHOT-dev-all.jar" From db9b7dce07caf352830ae6d030b3f0b86bd65134 Mon Sep 17 00:00:00 2001 From: yoyosource Date: Sun, 3 Sep 2023 13:05:13 +0200 Subject: [PATCH 46/53] Fix steamwarci.yml --- steamwarci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/steamwarci.yml b/steamwarci.yml index 8897287..79db689 100644 --- a/steamwarci.yml +++ b/steamwarci.yml @@ -2,7 +2,7 @@ setup: - "ln -s /home/gitea/lib" build: - - "JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64 ./gradlew shadowJar" + - "JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64 ./gradlew reobfJar" - "JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64 ./gradlew --stop" artifacts: From 77b58a5dcfaf3697a6d0c53c02dddf2a2dbd6391 Mon Sep 17 00:00:00 2001 From: yoyosource Date: Sun, 3 Sep 2023 13:05:47 +0200 Subject: [PATCH 47/53] Fix steamwarci.yml --- steamwarci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/steamwarci.yml b/steamwarci.yml index 79db689..cf58a75 100644 --- a/steamwarci.yml +++ b/steamwarci.yml @@ -6,4 +6,4 @@ build: - "JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64 ./gradlew --stop" artifacts: - "/binarys/AxiomPaper.jar": "build/libs/AxiomPaper-1.0.0-SNAPSHOT-dev-all.jar" + "/binarys/AxiomPaper.jar": "build/libs/AxiomPaper-1.0.0-SNAPSHOT.jar" From a3d3d16e7c69f467b0f46e9007ea4ef546e0ffa5 Mon Sep 17 00:00:00 2001 From: yoyosource Date: Wed, 6 Sep 2023 16:49:39 +0200 Subject: [PATCH 48/53] Fix steamwarci.yml --- steamwarci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/steamwarci.yml b/steamwarci.yml index cf58a75..3ddc308 100644 --- a/steamwarci.yml +++ b/steamwarci.yml @@ -6,4 +6,4 @@ build: - "JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64 ./gradlew --stop" artifacts: - "/binarys/AxiomPaper.jar": "build/libs/AxiomPaper-1.0.0-SNAPSHOT.jar" + "/binarys/AxiomPaper.jar": "build/libs/AxiomPaper-1.2.1.jar" From 9ba82ce6a7a30e8436446501bc58d3799f0f74e9 Mon Sep 17 00:00:00 2001 From: yoyosource Date: Wed, 6 Sep 2023 18:00:11 +0200 Subject: [PATCH 49/53] Add axiom to maven repo --- steamwarci.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/steamwarci.yml b/steamwarci.yml index 3ddc308..66dec17 100644 --- a/steamwarci.yml +++ b/steamwarci.yml @@ -7,3 +7,6 @@ build: artifacts: "/binarys/AxiomPaper.jar": "build/libs/AxiomPaper-1.2.1.jar" + +release: + - "mvn deploy:deploy-file -DgroupId=de.steamwar -DartifactId=axiompaper -Dversion=RELEASE -Dpackaging=jar -Dfile=build/libs/AxiomPaper-1.2.1.jar -Durl=file:///var/www/html/maven/" \ No newline at end of file From 1319a3d7c2f9e8d7d77f8a35689062c0acbca742 Mon Sep 17 00:00:00 2001 From: Moulberry Date: Tue, 10 Oct 2023 13:07:49 +0800 Subject: [PATCH 50/53] Backport to 1.20.1 --- build.gradle.kts | 2 +- .../axiom/packet/CustomByteArrayPayload.java | 12 ------------ .../packet/RequestChunkDataPacketListener.java | 14 +++++++------- .../axiom/packet/SetBlockPacketListener.java | 5 +++++ 4 files changed, 13 insertions(+), 20 deletions(-) delete mode 100644 src/main/java/com/moulberry/axiom/packet/CustomByteArrayPayload.java diff --git a/build.gradle.kts b/build.gradle.kts index 91d0d4e..24ecb7a 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -25,7 +25,7 @@ repositories { } dependencies { - paperweight.paperDevBundle("1.20.4-R0.1-SNAPSHOT") + paperweight.paperDevBundle("1.20.1-R0.1-SNAPSHOT") implementation("xyz.jpenilla:reflection-remapper:0.1.0-SNAPSHOT") // Zstd Compression Library diff --git a/src/main/java/com/moulberry/axiom/packet/CustomByteArrayPayload.java b/src/main/java/com/moulberry/axiom/packet/CustomByteArrayPayload.java deleted file mode 100644 index cb2bcd7..0000000 --- a/src/main/java/com/moulberry/axiom/packet/CustomByteArrayPayload.java +++ /dev/null @@ -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); - } -} diff --git a/src/main/java/com/moulberry/axiom/packet/RequestChunkDataPacketListener.java b/src/main/java/com/moulberry/axiom/packet/RequestChunkDataPacketListener.java index de6a6b3..f82c231 100644 --- a/src/main/java/com/moulberry/axiom/packet/RequestChunkDataPacketListener.java +++ b/src/main/java/com/moulberry/axiom/packet/RequestChunkDataPacketListener.java @@ -11,7 +11,7 @@ import net.minecraft.core.BlockPos; import net.minecraft.core.registries.Registries; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.network.protocol.common.ClientboundCustomPayloadPacket; +import net.minecraft.network.protocol.game.ClientboundCustomPayloadPacket; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; @@ -165,7 +165,7 @@ public class RequestChunkDataPacketListener implements PluginMessageListener { buf.writeBoolean(false); byte[] bytes = new byte[buf.writerIndex()]; buf.getBytes(0, bytes); - player.connection.send(new ClientboundCustomPayloadPacket(new CustomByteArrayPayload(RESPONSE_ID, bytes))); + player.connection.send(new ClientboundCustomPayloadPacket(RESPONSE_ID, buf)); // Continuation packet buf = new FriendlyByteBuf(Unpooled.buffer()); @@ -185,7 +185,7 @@ public class RequestChunkDataPacketListener implements PluginMessageListener { buf.writeBoolean(false); byte[] bytes = new byte[buf.writerIndex()]; buf.getBytes(0, bytes); - player.connection.send(new ClientboundCustomPayloadPacket(new CustomByteArrayPayload(RESPONSE_ID, bytes))); + player.connection.send(new ClientboundCustomPayloadPacket(RESPONSE_ID, buf)); // Continuation packet buf = new FriendlyByteBuf(Unpooled.buffer()); @@ -221,7 +221,7 @@ public class RequestChunkDataPacketListener implements PluginMessageListener { buf.writeBoolean(false); byte[] bytes = new byte[buf.writerIndex()]; buf.getBytes(0, bytes); - player.connection.send(new ClientboundCustomPayloadPacket(new CustomByteArrayPayload(RESPONSE_ID, bytes))); + player.connection.send(new ClientboundCustomPayloadPacket(RESPONSE_ID, buf)); // Continuation packet buf = new FriendlyByteBuf(Unpooled.buffer()); @@ -241,7 +241,7 @@ public class RequestChunkDataPacketListener implements PluginMessageListener { buf.writeBoolean(false); byte[] bytes = new byte[buf.writerIndex()]; buf.getBytes(0, bytes); - player.connection.send(new ClientboundCustomPayloadPacket(new CustomByteArrayPayload(RESPONSE_ID, bytes))); + player.connection.send(new ClientboundCustomPayloadPacket(RESPONSE_ID, buf)); // Continuation packet buf = new FriendlyByteBuf(Unpooled.buffer()); @@ -261,7 +261,7 @@ public class RequestChunkDataPacketListener implements PluginMessageListener { buf.writeBoolean(true); byte[] bytes = new byte[buf.writerIndex()]; buf.getBytes(0, bytes); - player.connection.send(new ClientboundCustomPayloadPacket(new CustomByteArrayPayload(RESPONSE_ID, bytes))); + player.connection.send(new ClientboundCustomPayloadPacket(RESPONSE_ID, buf)); } private void sendEmptyResponse(ServerPlayer player, long id) { @@ -273,7 +273,7 @@ public class RequestChunkDataPacketListener implements PluginMessageListener { byte[] bytes = new byte[buf.writerIndex()]; buf.getBytes(0, bytes); - player.connection.send(new ClientboundCustomPayloadPacket(new CustomByteArrayPayload(RESPONSE_ID, bytes))); + player.connection.send(new ClientboundCustomPayloadPacket(RESPONSE_ID, buf)); } } diff --git a/src/main/java/com/moulberry/axiom/packet/SetBlockPacketListener.java b/src/main/java/com/moulberry/axiom/packet/SetBlockPacketListener.java index 493249a..9ede7a7 100644 --- a/src/main/java/com/moulberry/axiom/packet/SetBlockPacketListener.java +++ b/src/main/java/com/moulberry/axiom/packet/SetBlockPacketListener.java @@ -31,9 +31,14 @@ import net.minecraft.world.phys.BlockHitResult; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.block.BlockFace; +<<<<<<< HEAD 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.v1_20_R1.block.CraftBlock; +import org.bukkit.craftbukkit.v1_20_R1.entity.CraftPlayer; +>>>>>>> 7c8f500 (Backport to 1.20.1) import org.bukkit.entity.Player; import org.bukkit.event.block.Action; import org.bukkit.event.player.PlayerInteractEvent; From b3a36ebda489026e413c0f13b3c7ce277f87bbea Mon Sep 17 00:00:00 2001 From: YoyoNow Date: Wed, 11 Oct 2023 12:55:36 +0200 Subject: [PATCH 51/53] steamwarci.yml aktualisiert --- steamwarci.yml | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/steamwarci.yml b/steamwarci.yml index 66dec17..a42f256 100644 --- a/steamwarci.yml +++ b/steamwarci.yml @@ -1,12 +1,12 @@ -setup: - - "ln -s /home/gitea/lib" - -build: - - "JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64 ./gradlew reobfJar" - - "JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64 ./gradlew --stop" - -artifacts: - "/binarys/AxiomPaper.jar": "build/libs/AxiomPaper-1.2.1.jar" - -release: - - "mvn deploy:deploy-file -DgroupId=de.steamwar -DartifactId=axiompaper -Dversion=RELEASE -Dpackaging=jar -Dfile=build/libs/AxiomPaper-1.2.1.jar -Durl=file:///var/www/html/maven/" \ No newline at end of file +setup: + - "ln -s /home/gitea/lib" + +build: + - "JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64 ./gradlew reobfJar" + - "JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64 ./gradlew --stop" + +artifacts: + "/binarys/AxiomPaper.jar": "build/libs/AxiomPaper-1.5.1.jar" + +release: + - "mvn deploy:deploy-file -DgroupId=de.steamwar -DartifactId=axiompaper -Dversion=RELEASE -Dpackaging=jar -Dfile=build/libs/AxiomPaper-1.5.1.jar -Durl=file:///var/www/html/maven/" \ No newline at end of file From 47505405ca8db92e84993dd46be68978590a1b42 Mon Sep 17 00:00:00 2001 From: yoyosource Date: Thu, 1 Feb 2024 19:55:42 +0100 Subject: [PATCH 52/53] Backport to 1.20.1 --- build.gradle.kts | 4 ---- src/main/java/com/moulberry/axiom/AxiomPaper.java | 15 ++++----------- .../com/moulberry/axiom/DisallowedBlocks.java | 5 ----- src/main/java/com/moulberry/axiom/View.java | 2 -- .../java/com/moulberry/axiom/WorldExtension.java | 7 ++++--- .../com/moulberry/axiom/buffer/BlockBuffer.java | 1 - .../axiom/buffer/CompressedBlockEntity.java | 2 +- .../moulberry/axiom/buffer/Position2ByteMap.java | 1 - .../event/AxiomCreateWorldPropertiesEvent.java | 2 -- .../axiom/event/AxiomFlySpeedChangeEvent.java | 1 - .../axiom/event/AxiomGameModeChangeEvent.java | 1 - .../axiom/event/AxiomModifyWorldEvent.java | 1 - .../java/com/moulberry/axiom/integration/Box.java | 1 - .../plotsquared/PlotSquaredIntegration.java | 1 - .../plotsquared/PlotSquaredIntegrationImpl.java | 1 - .../com/moulberry/axiom/marker/MarkerData.java | 3 --- .../axiom/packet/DeleteEntityPacketListener.java | 11 +---------- .../axiom/packet/HelloPacketListener.java | 1 - .../packet/ManipulateEntityPacketListener.java | 4 +--- .../packet/MarkerNbtRequestPacketListener.java | 10 +--------- .../packet/RequestChunkDataPacketListener.java | 6 +++--- .../packet/SetBlockBufferPacketListener.java | 1 - .../axiom/packet/SetBlockPacketListener.java | 5 +---- .../packet/SetEditorViewsPacketListener.java | 4 ---- .../axiom/packet/SetHotbarSlotPacketListener.java | 1 - .../axiom/packet/SetTimePacketListener.java | 1 - .../axiom/packet/SpawnEntityPacketListener.java | 12 +----------- .../axiom/packet/TeleportPacketListener.java | 11 +++++++---- .../world_properties/WorldPropertyWidgetType.java | 1 - .../server/ServerWorldPropertyBase.java | 2 +- .../server/ServerWorldPropertyHolder.java | 4 ---- 31 files changed, 25 insertions(+), 97 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 1f49669..24ecb7a 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -8,11 +8,7 @@ plugins { } group = "com.moulberry.axiom" -<<<<<<< HEAD -version = "1.5.1" -======= version = "1.5.8" ->>>>>>> Mirrors-master description = "Serverside component for Axiom on Paper" java { diff --git a/src/main/java/com/moulberry/axiom/AxiomPaper.java b/src/main/java/com/moulberry/axiom/AxiomPaper.java index eee6446..2ea9e70 100644 --- a/src/main/java/com/moulberry/axiom/AxiomPaper.java +++ b/src/main/java/com/moulberry/axiom/AxiomPaper.java @@ -21,10 +21,12 @@ 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.protocol.common.ServerboundCustomPayloadPacket; +import net.minecraft.network.protocol.game.ServerboundCustomPayloadPacket; import net.minecraft.server.MinecraftServer; import net.minecraft.world.level.block.state.BlockState; -import org.bukkit.*; +import org.bukkit.Bukkit; +import org.bukkit.GameRule; +import org.bukkit.World; import org.bukkit.configuration.Configuration; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; @@ -298,14 +300,6 @@ public class AxiomPaper extends JavaPlugin implements Listener { @EventHandler public void onFailMove(PlayerFailMoveEvent event) { -<<<<<<< HEAD - if (event.getPlayer().hasPermission("axiom.*")) { - if (event.getFailReason() == PlayerFailMoveEvent.FailReason.MOVED_TOO_QUICKLY) { - event.setAllowed(true); // Support for arcball camera - } else if (event.getPlayer().isFlying()) { - event.setAllowed(true); // Support for noclip - } -======= if (!this.activeAxiomPlayers.contains(event.getPlayer().getUniqueId())) { return; } @@ -313,7 +307,6 @@ public class AxiomPaper extends JavaPlugin implements Listener { event.setAllowed(true); // Support for arcball camera } else if (event.getPlayer().isFlying()) { event.setAllowed(true); // Support for noclip ->>>>>>> Mirrors-master } } diff --git a/src/main/java/com/moulberry/axiom/DisallowedBlocks.java b/src/main/java/com/moulberry/axiom/DisallowedBlocks.java index f80d2b8..930bbe2 100644 --- a/src/main/java/com/moulberry/axiom/DisallowedBlocks.java +++ b/src/main/java/com/moulberry/axiom/DisallowedBlocks.java @@ -1,16 +1,11 @@ package com.moulberry.axiom; import com.mojang.brigadier.StringReader; -import com.mojang.datafixers.util.Either; import com.moulberry.axiom.buffer.BlockBuffer; -import net.minecraft.commands.arguments.blocks.BlockPredicateArgument; import net.minecraft.commands.arguments.blocks.BlockStateParser; import net.minecraft.core.IdMapper; import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.nbt.NbtUtils; import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.properties.Property; diff --git a/src/main/java/com/moulberry/axiom/View.java b/src/main/java/com/moulberry/axiom/View.java index 5dd2138..7d219dd 100644 --- a/src/main/java/com/moulberry/axiom/View.java +++ b/src/main/java/com/moulberry/axiom/View.java @@ -2,8 +2,6 @@ package com.moulberry.axiom; import com.moulberry.axiom.persistence.UUIDDataType; import net.minecraft.core.registries.Registries; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.Tag; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; diff --git a/src/main/java/com/moulberry/axiom/WorldExtension.java b/src/main/java/com/moulberry/axiom/WorldExtension.java index 2152bb2..4863c9a 100644 --- a/src/main/java/com/moulberry/axiom/WorldExtension.java +++ b/src/main/java/com/moulberry/axiom/WorldExtension.java @@ -2,7 +2,9 @@ package com.moulberry.axiom; import com.moulberry.axiom.marker.MarkerData; import io.netty.buffer.Unpooled; -import it.unimi.dsi.fastutil.longs.*; +import it.unimi.dsi.fastutil.longs.LongIterator; +import it.unimi.dsi.fastutil.longs.LongOpenHashSet; +import it.unimi.dsi.fastutil.longs.LongSet; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; import net.minecraft.resources.ResourceKey; @@ -16,8 +18,7 @@ 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.v1_20_R1.CraftWorld; import org.bukkit.entity.Player; import java.util.*; diff --git a/src/main/java/com/moulberry/axiom/buffer/BlockBuffer.java b/src/main/java/com/moulberry/axiom/buffer/BlockBuffer.java index 8094081..aa24244 100644 --- a/src/main/java/com/moulberry/axiom/buffer/BlockBuffer.java +++ b/src/main/java/com/moulberry/axiom/buffer/BlockBuffer.java @@ -10,7 +10,6 @@ import it.unimi.dsi.fastutil.shorts.Short2ObjectMap; import it.unimi.dsi.fastutil.shorts.Short2ObjectOpenHashMap; import net.minecraft.core.BlockPos; import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.PalettedContainer; diff --git a/src/main/java/com/moulberry/axiom/buffer/CompressedBlockEntity.java b/src/main/java/com/moulberry/axiom/buffer/CompressedBlockEntity.java index c1d09b0..eee0923 100644 --- a/src/main/java/com/moulberry/axiom/buffer/CompressedBlockEntity.java +++ b/src/main/java/com/moulberry/axiom/buffer/CompressedBlockEntity.java @@ -45,7 +45,7 @@ public record CompressedBlockEntity(int originalSize, byte compressionDict, byte try { byte[] nbt = Zstd.decompress(this.compressed, zstdDictDecompress, this.originalSize); - return NbtIo.read(new DataInputStream(new ByteArrayInputStream(nbt)), NbtAccounter.create(131072)); + return NbtIo.read(new DataInputStream(new ByteArrayInputStream(nbt)), new NbtAccounter(131072)); } catch (IOException e) { throw new RuntimeException(e); } diff --git a/src/main/java/com/moulberry/axiom/buffer/Position2ByteMap.java b/src/main/java/com/moulberry/axiom/buffer/Position2ByteMap.java index 3080891..b4b354b 100644 --- a/src/main/java/com/moulberry/axiom/buffer/Position2ByteMap.java +++ b/src/main/java/com/moulberry/axiom/buffer/Position2ByteMap.java @@ -2,7 +2,6 @@ package com.moulberry.axiom.buffer; import com.google.common.util.concurrent.RateLimiter; import com.moulberry.axiom.AxiomConstants; -import com.moulberry.axiom.AxiomPaper; import it.unimi.dsi.fastutil.longs.Long2ObjectMap; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; import net.minecraft.core.BlockPos; diff --git a/src/main/java/com/moulberry/axiom/event/AxiomCreateWorldPropertiesEvent.java b/src/main/java/com/moulberry/axiom/event/AxiomCreateWorldPropertiesEvent.java index 7ae6581..d88c077 100644 --- a/src/main/java/com/moulberry/axiom/event/AxiomCreateWorldPropertiesEvent.java +++ b/src/main/java/com/moulberry/axiom/event/AxiomCreateWorldPropertiesEvent.java @@ -2,9 +2,7 @@ package com.moulberry.axiom.event; import com.moulberry.axiom.world_properties.WorldPropertyCategory; import com.moulberry.axiom.world_properties.server.ServerWorldPropertiesRegistry; -import com.moulberry.axiom.world_properties.server.ServerWorldProperty; import com.moulberry.axiom.world_properties.server.ServerWorldPropertyBase; -import com.moulberry.axiom.world_properties.server.ServerWorldPropertyHolder; import org.bukkit.World; import org.bukkit.event.Cancellable; import org.bukkit.event.Event; diff --git a/src/main/java/com/moulberry/axiom/event/AxiomFlySpeedChangeEvent.java b/src/main/java/com/moulberry/axiom/event/AxiomFlySpeedChangeEvent.java index a914830..361ab89 100644 --- a/src/main/java/com/moulberry/axiom/event/AxiomFlySpeedChangeEvent.java +++ b/src/main/java/com/moulberry/axiom/event/AxiomFlySpeedChangeEvent.java @@ -1,6 +1,5 @@ package com.moulberry.axiom.event; -import org.bukkit.GameMode; import org.bukkit.entity.Player; import org.bukkit.event.Cancellable; import org.bukkit.event.Event; diff --git a/src/main/java/com/moulberry/axiom/event/AxiomGameModeChangeEvent.java b/src/main/java/com/moulberry/axiom/event/AxiomGameModeChangeEvent.java index 86da786..e3f110b 100644 --- a/src/main/java/com/moulberry/axiom/event/AxiomGameModeChangeEvent.java +++ b/src/main/java/com/moulberry/axiom/event/AxiomGameModeChangeEvent.java @@ -1,7 +1,6 @@ package com.moulberry.axiom.event; import org.bukkit.GameMode; -import org.bukkit.World; import org.bukkit.entity.Player; import org.bukkit.event.Cancellable; import org.bukkit.event.Event; diff --git a/src/main/java/com/moulberry/axiom/event/AxiomModifyWorldEvent.java b/src/main/java/com/moulberry/axiom/event/AxiomModifyWorldEvent.java index 01f4a42..405948f 100644 --- a/src/main/java/com/moulberry/axiom/event/AxiomModifyWorldEvent.java +++ b/src/main/java/com/moulberry/axiom/event/AxiomModifyWorldEvent.java @@ -1,6 +1,5 @@ package com.moulberry.axiom.event; -import com.moulberry.axiom.AxiomPaper; import org.bukkit.World; import org.bukkit.entity.Player; import org.bukkit.event.Cancellable; diff --git a/src/main/java/com/moulberry/axiom/integration/Box.java b/src/main/java/com/moulberry/axiom/integration/Box.java index 3bf51b4..28635bf 100644 --- a/src/main/java/com/moulberry/axiom/integration/Box.java +++ b/src/main/java/com/moulberry/axiom/integration/Box.java @@ -1,6 +1,5 @@ package com.moulberry.axiom.integration; -import net.minecraft.core.BlockPos; import org.jetbrains.annotations.Nullable; public record Box(int minX, int minY, int minZ, int maxX, int maxY, int maxZ) { diff --git a/src/main/java/com/moulberry/axiom/integration/plotsquared/PlotSquaredIntegration.java b/src/main/java/com/moulberry/axiom/integration/plotsquared/PlotSquaredIntegration.java index deab2cf..aefad2c 100644 --- a/src/main/java/com/moulberry/axiom/integration/plotsquared/PlotSquaredIntegration.java +++ b/src/main/java/com/moulberry/axiom/integration/plotsquared/PlotSquaredIntegration.java @@ -5,7 +5,6 @@ import com.moulberry.axiom.integration.SectionPermissionChecker; import com.sk89q.worldedit.regions.CuboidRegion; import net.minecraft.core.BlockPos; import org.bukkit.Bukkit; -import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.entity.Player; diff --git a/src/main/java/com/moulberry/axiom/integration/plotsquared/PlotSquaredIntegrationImpl.java b/src/main/java/com/moulberry/axiom/integration/plotsquared/PlotSquaredIntegrationImpl.java index a9d6e3d..2dc36b6 100644 --- a/src/main/java/com/moulberry/axiom/integration/plotsquared/PlotSquaredIntegrationImpl.java +++ b/src/main/java/com/moulberry/axiom/integration/plotsquared/PlotSquaredIntegrationImpl.java @@ -21,7 +21,6 @@ import com.sk89q.worldedit.world.block.BlockType; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.entity.Player; -import org.checkerframework.checker.nullness.qual.NonNull; import java.util.*; diff --git a/src/main/java/com/moulberry/axiom/marker/MarkerData.java b/src/main/java/com/moulberry/axiom/marker/MarkerData.java index e86411f..6f331af 100644 --- a/src/main/java/com/moulberry/axiom/marker/MarkerData.java +++ b/src/main/java/com/moulberry/axiom/marker/MarkerData.java @@ -5,14 +5,11 @@ import net.minecraft.nbt.ListTag; import net.minecraft.nbt.Tag; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.world.entity.Marker; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.phys.Vec3; import org.jetbrains.annotations.Nullable; import xyz.jpenilla.reflectionremapper.ReflectionRemapper; import java.lang.reflect.Field; -import java.lang.reflect.Method; import java.util.UUID; public record MarkerData(UUID uuid, Vec3 position, @Nullable String name, @Nullable Vec3 minRegion, @Nullable Vec3 maxRegion) { diff --git a/src/main/java/com/moulberry/axiom/packet/DeleteEntityPacketListener.java b/src/main/java/com/moulberry/axiom/packet/DeleteEntityPacketListener.java index 2fe253c..0045582 100644 --- a/src/main/java/com/moulberry/axiom/packet/DeleteEntityPacketListener.java +++ b/src/main/java/com/moulberry/axiom/packet/DeleteEntityPacketListener.java @@ -2,23 +2,14 @@ package com.moulberry.axiom.packet; import com.moulberry.axiom.AxiomPaper; import io.netty.buffer.Unpooled; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -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.EntityType; -import net.minecraft.world.entity.decoration.HangingEntity; -import net.minecraft.world.entity.decoration.ItemFrame; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.Rotation; -import net.minecraft.world.phys.Vec3; -import org.bukkit.craftbukkit.v1_20_R3.CraftWorld; +import org.bukkit.craftbukkit.v1_20_R1.CraftWorld; import org.bukkit.entity.Player; import org.bukkit.plugin.messaging.PluginMessageListener; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.util.List; import java.util.UUID; diff --git a/src/main/java/com/moulberry/axiom/packet/HelloPacketListener.java b/src/main/java/com/moulberry/axiom/packet/HelloPacketListener.java index 3dfbacd..3cb287a 100644 --- a/src/main/java/com/moulberry/axiom/packet/HelloPacketListener.java +++ b/src/main/java/com/moulberry/axiom/packet/HelloPacketListener.java @@ -25,7 +25,6 @@ import org.bukkit.persistence.PersistentDataType; import org.bukkit.plugin.messaging.PluginMessageListener; import org.jetbrains.annotations.NotNull; -import java.util.Set; import java.util.UUID; public class HelloPacketListener implements PluginMessageListener { diff --git a/src/main/java/com/moulberry/axiom/packet/ManipulateEntityPacketListener.java b/src/main/java/com/moulberry/axiom/packet/ManipulateEntityPacketListener.java index 0cb5769..d802f7a 100644 --- a/src/main/java/com/moulberry/axiom/packet/ManipulateEntityPacketListener.java +++ b/src/main/java/com/moulberry/axiom/packet/ManipulateEntityPacketListener.java @@ -3,7 +3,6 @@ package com.moulberry.axiom.packet; import com.moulberry.axiom.AxiomPaper; import com.moulberry.axiom.NbtSanitization; import io.netty.buffer.Unpooled; -import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.Tag; @@ -14,10 +13,9 @@ import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.RelativeMovement; import net.minecraft.world.entity.decoration.HangingEntity; import net.minecraft.world.entity.decoration.ItemFrame; -import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Rotation; import net.minecraft.world.phys.Vec3; -import org.bukkit.craftbukkit.v1_20_R3.CraftWorld; +import org.bukkit.craftbukkit.v1_20_R1.CraftWorld; import org.bukkit.entity.Player; import org.bukkit.plugin.messaging.PluginMessageListener; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/com/moulberry/axiom/packet/MarkerNbtRequestPacketListener.java b/src/main/java/com/moulberry/axiom/packet/MarkerNbtRequestPacketListener.java index 55f9b16..91acd37 100644 --- a/src/main/java/com/moulberry/axiom/packet/MarkerNbtRequestPacketListener.java +++ b/src/main/java/com/moulberry/axiom/packet/MarkerNbtRequestPacketListener.java @@ -1,26 +1,18 @@ package com.moulberry.axiom.packet; import com.moulberry.axiom.AxiomPaper; -import com.moulberry.axiom.event.AxiomTimeChangeEvent; -import com.moulberry.axiom.integration.plotsquared.PlotSquaredIntegration; import com.moulberry.axiom.marker.MarkerData; import io.netty.buffer.Unpooled; -import net.minecraft.core.registries.Registries; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.resources.ResourceKey; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Marker; -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.v1_20_R1.CraftWorld; import org.bukkit.entity.Player; import org.bukkit.plugin.messaging.PluginMessageListener; import org.jetbrains.annotations.NotNull; -import java.util.Set; import java.util.UUID; public class MarkerNbtRequestPacketListener implements PluginMessageListener { diff --git a/src/main/java/com/moulberry/axiom/packet/RequestChunkDataPacketListener.java b/src/main/java/com/moulberry/axiom/packet/RequestChunkDataPacketListener.java index 368f300..7baf46d 100644 --- a/src/main/java/com/moulberry/axiom/packet/RequestChunkDataPacketListener.java +++ b/src/main/java/com/moulberry/axiom/packet/RequestChunkDataPacketListener.java @@ -3,10 +3,10 @@ package com.moulberry.axiom.packet; import com.moulberry.axiom.AxiomConstants; import com.moulberry.axiom.AxiomPaper; import com.moulberry.axiom.buffer.CompressedBlockEntity; -import com.moulberry.axiom.event.AxiomModifyWorldEvent; import com.moulberry.axiom.integration.plotsquared.PlotSquaredIntegration; import io.netty.buffer.Unpooled; -import it.unimi.dsi.fastutil.longs.*; +import it.unimi.dsi.fastutil.longs.Long2ObjectMap; +import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; import net.minecraft.core.BlockPos; import net.minecraft.core.registries.Registries; import net.minecraft.nbt.CompoundTag; @@ -23,7 +23,7 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunkSection; import net.minecraft.world.level.chunk.PalettedContainer; -import org.bukkit.Bukkit; +import org.bukkit.craftbukkit.v1_20_R1.entity.CraftPlayer; import org.bukkit.entity.Player; import org.bukkit.plugin.messaging.PluginMessageListener; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/com/moulberry/axiom/packet/SetBlockBufferPacketListener.java b/src/main/java/com/moulberry/axiom/packet/SetBlockBufferPacketListener.java index 21d29aa..1db0581 100644 --- a/src/main/java/com/moulberry/axiom/packet/SetBlockBufferPacketListener.java +++ b/src/main/java/com/moulberry/axiom/packet/SetBlockBufferPacketListener.java @@ -6,7 +6,6 @@ import com.moulberry.axiom.WorldExtension; import com.moulberry.axiom.buffer.BiomeBuffer; import com.moulberry.axiom.buffer.BlockBuffer; import com.moulberry.axiom.buffer.CompressedBlockEntity; -import com.moulberry.axiom.event.AxiomModifyWorldEvent; import com.moulberry.axiom.integration.SectionPermissionChecker; import com.moulberry.axiom.integration.plotsquared.PlotSquaredIntegration; import it.unimi.dsi.fastutil.longs.Long2ObjectMap; diff --git a/src/main/java/com/moulberry/axiom/packet/SetBlockPacketListener.java b/src/main/java/com/moulberry/axiom/packet/SetBlockPacketListener.java index 60f95fb..5754b4f 100644 --- a/src/main/java/com/moulberry/axiom/packet/SetBlockPacketListener.java +++ b/src/main/java/com/moulberry/axiom/packet/SetBlockPacketListener.java @@ -2,11 +2,8 @@ package com.moulberry.axiom.packet; import com.google.common.collect.Maps; import com.moulberry.axiom.AxiomPaper; -import com.moulberry.axiom.event.AxiomModifyWorldEvent; import com.moulberry.axiom.integration.plotsquared.PlotSquaredIntegration; import io.netty.buffer.Unpooled; -import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; -import net.kyori.adventure.text.Component; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.core.SectionPos; @@ -28,9 +25,9 @@ import net.minecraft.world.level.chunk.LevelChunkSection; import net.minecraft.world.level.levelgen.Heightmap; import net.minecraft.world.level.lighting.LightEngine; import net.minecraft.world.phys.BlockHitResult; -import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.block.BlockFace; +import org.bukkit.craftbukkit.v1_20_R1.CraftWorld; import org.bukkit.craftbukkit.v1_20_R1.block.CraftBlock; import org.bukkit.craftbukkit.v1_20_R1.entity.CraftPlayer; import org.bukkit.entity.Player; diff --git a/src/main/java/com/moulberry/axiom/packet/SetEditorViewsPacketListener.java b/src/main/java/com/moulberry/axiom/packet/SetEditorViewsPacketListener.java index 5a96d06..ce1465a 100644 --- a/src/main/java/com/moulberry/axiom/packet/SetEditorViewsPacketListener.java +++ b/src/main/java/com/moulberry/axiom/packet/SetEditorViewsPacketListener.java @@ -1,15 +1,12 @@ package com.moulberry.axiom.packet; import com.google.common.collect.Lists; -import com.google.common.collect.Maps; import com.moulberry.axiom.AxiomConstants; import com.moulberry.axiom.AxiomPaper; import com.moulberry.axiom.View; import com.moulberry.axiom.persistence.UUIDDataType; import io.netty.buffer.Unpooled; -import net.minecraft.core.BlockPos; import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.world.level.block.state.BlockState; import org.bukkit.entity.Player; import org.bukkit.persistence.PersistentDataContainer; import org.bukkit.persistence.PersistentDataType; @@ -17,7 +14,6 @@ import org.bukkit.plugin.messaging.PluginMessageListener; import org.jetbrains.annotations.NotNull; import java.util.List; -import java.util.Map; import java.util.UUID; import java.util.function.IntFunction; diff --git a/src/main/java/com/moulberry/axiom/packet/SetHotbarSlotPacketListener.java b/src/main/java/com/moulberry/axiom/packet/SetHotbarSlotPacketListener.java index 1636273..3ec626e 100644 --- a/src/main/java/com/moulberry/axiom/packet/SetHotbarSlotPacketListener.java +++ b/src/main/java/com/moulberry/axiom/packet/SetHotbarSlotPacketListener.java @@ -6,7 +6,6 @@ import com.moulberry.axiom.persistence.ItemStackDataType; import io.netty.buffer.Unpooled; import net.minecraft.network.FriendlyByteBuf; import org.bukkit.NamespacedKey; -import org.bukkit.craftbukkit.v1_20_R1.entity.CraftPlayer; import org.bukkit.craftbukkit.v1_20_R1.inventory.CraftItemStack; import org.bukkit.entity.Player; import org.bukkit.persistence.PersistentDataContainer; diff --git a/src/main/java/com/moulberry/axiom/packet/SetTimePacketListener.java b/src/main/java/com/moulberry/axiom/packet/SetTimePacketListener.java index ea70952..5cf48be 100644 --- a/src/main/java/com/moulberry/axiom/packet/SetTimePacketListener.java +++ b/src/main/java/com/moulberry/axiom/packet/SetTimePacketListener.java @@ -1,7 +1,6 @@ package com.moulberry.axiom.packet; import com.moulberry.axiom.AxiomPaper; -import com.moulberry.axiom.event.AxiomModifyWorldEvent; import com.moulberry.axiom.event.AxiomTimeChangeEvent; import com.moulberry.axiom.integration.plotsquared.PlotSquaredIntegration; import io.netty.buffer.Unpooled; diff --git a/src/main/java/com/moulberry/axiom/packet/SpawnEntityPacketListener.java b/src/main/java/com/moulberry/axiom/packet/SpawnEntityPacketListener.java index ea6f385..53b708c 100644 --- a/src/main/java/com/moulberry/axiom/packet/SpawnEntityPacketListener.java +++ b/src/main/java/com/moulberry/axiom/packet/SpawnEntityPacketListener.java @@ -2,15 +2,11 @@ package com.moulberry.axiom.packet; import com.moulberry.axiom.AxiomPaper; import com.moulberry.axiom.NbtSanitization; -import com.moulberry.axiom.event.AxiomTeleportEvent; -import com.moulberry.axiom.event.AxiomUnknownTeleportEvent; import io.netty.buffer.Unpooled; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; -import net.minecraft.core.registries.Registries; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.resources.ResourceKey; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityType; @@ -19,13 +15,7 @@ import net.minecraft.world.entity.decoration.ItemFrame; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Rotation; import net.minecraft.world.phys.Vec3; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.NamespacedKey; -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.v1_20_R3.util.CraftNamespacedKey; +import org.bukkit.craftbukkit.v1_20_R1.CraftWorld; import org.bukkit.entity.Player; import org.bukkit.plugin.messaging.PluginMessageListener; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/com/moulberry/axiom/packet/TeleportPacketListener.java b/src/main/java/com/moulberry/axiom/packet/TeleportPacketListener.java index a36a277..1b66209 100644 --- a/src/main/java/com/moulberry/axiom/packet/TeleportPacketListener.java +++ b/src/main/java/com/moulberry/axiom/packet/TeleportPacketListener.java @@ -1,16 +1,19 @@ package com.moulberry.axiom.packet; import com.moulberry.axiom.AxiomPaper; -import com.moulberry.axiom.event.AxiomUnknownTeleportEvent; import com.moulberry.axiom.event.AxiomTeleportEvent; +import com.moulberry.axiom.event.AxiomUnknownTeleportEvent; import io.netty.buffer.Unpooled; 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.Bukkit; +import org.bukkit.Location; +import org.bukkit.NamespacedKey; +import org.bukkit.World; +import org.bukkit.craftbukkit.v1_20_R1.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_20_R1.util.CraftNamespacedKey; import org.bukkit.entity.Player; import org.bukkit.plugin.messaging.PluginMessageListener; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/com/moulberry/axiom/world_properties/WorldPropertyWidgetType.java b/src/main/java/com/moulberry/axiom/world_properties/WorldPropertyWidgetType.java index e274cbb..3dbf612 100644 --- a/src/main/java/com/moulberry/axiom/world_properties/WorldPropertyWidgetType.java +++ b/src/main/java/com/moulberry/axiom/world_properties/WorldPropertyWidgetType.java @@ -1,7 +1,6 @@ package com.moulberry.axiom.world_properties; import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.util.Unit; import java.util.List; diff --git a/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertyBase.java b/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertyBase.java index 2d7837b..b14f373 100644 --- a/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertyBase.java +++ b/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertyBase.java @@ -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.v1_20_R1.util.CraftNamespacedKey; import org.bukkit.entity.Player; public abstract class ServerWorldPropertyBase { diff --git a/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertyHolder.java b/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertyHolder.java index 0755b69..d97dda5 100644 --- a/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertyHolder.java +++ b/src/main/java/com/moulberry/axiom/world_properties/server/ServerWorldPropertyHolder.java @@ -1,15 +1,11 @@ package com.moulberry.axiom.world_properties.server; import com.moulberry.axiom.AxiomPaper; -import com.moulberry.axiom.world_properties.PropertyUpdateHandler; import com.moulberry.axiom.world_properties.WorldPropertyDataType; -import com.moulberry.axiom.world_properties.WorldPropertyWidgetType; import io.netty.buffer.Unpooled; 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.entity.Player; import java.util.Objects; From bac3f8e5a3c33da7e7ecb4e87a313c7bb4f3072d Mon Sep 17 00:00:00 2001 From: yoyosource Date: Thu, 1 Feb 2024 19:56:36 +0100 Subject: [PATCH 53/53] Update steamwarci.yml --- steamwarci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/steamwarci.yml b/steamwarci.yml index a42f256..7119112 100644 --- a/steamwarci.yml +++ b/steamwarci.yml @@ -6,7 +6,7 @@ build: - "JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64 ./gradlew --stop" artifacts: - "/binarys/AxiomPaper.jar": "build/libs/AxiomPaper-1.5.1.jar" + "/binarys/AxiomPaper.jar": "build/libs/AxiomPaper-1.5.8.jar" release: - - "mvn deploy:deploy-file -DgroupId=de.steamwar -DartifactId=axiompaper -Dversion=RELEASE -Dpackaging=jar -Dfile=build/libs/AxiomPaper-1.5.1.jar -Durl=file:///var/www/html/maven/" \ No newline at end of file + - "mvn deploy:deploy-file -DgroupId=de.steamwar -DartifactId=axiompaper -Dversion=RELEASE -Dpackaging=jar -Dfile=build/libs/AxiomPaper-1.5.8.jar -Durl=file:///var/www/html/maven/" \ No newline at end of file