diff --git a/patches/api/0004-Add-PlayerMoveControllableVehicleEvent.patch b/patches/api/0004-Add-PlayerMoveControllableVehicleEvent.patch new file mode 100644 index 0000000..1539381 --- /dev/null +++ b/patches/api/0004-Add-PlayerMoveControllableVehicleEvent.patch @@ -0,0 +1,141 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: MrPowerGamerBR +Date: Sat, 4 Jan 2025 23:58:34 -0300 +Subject: [PATCH] Add PlayerMoveControllableVehicleEvent + + +diff --git a/src/main/java/net/sparklypower/sparklypaper/event/player/PlayerMoveControllableVehicleEvent.java b/src/main/java/net/sparklypower/sparklypaper/event/player/PlayerMoveControllableVehicleEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..a646251feb6b8bf7ff07e6b4b84bb5751ee4b90b +--- /dev/null ++++ b/src/main/java/net/sparklypower/sparklypaper/event/player/PlayerMoveControllableVehicleEvent.java +@@ -0,0 +1,129 @@ ++package net.sparklypower.sparklypaper.event.player; ++ ++import com.google.common.base.Preconditions; ++import org.bukkit.Location; ++import org.bukkit.entity.Entity; ++import org.bukkit.entity.Player; ++import org.bukkit.entity.Vehicle; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.player.PlayerEvent; ++import org.jetbrains.annotations.NotNull; ++ ++/** ++ * Raised when a player moves a controllable vehicle. Controllable vehicles are vehicles that the client can control, such as boats, horses, striders, pigs, etc. ++ *

++ * Minecarts are NOT affected by this event! ++ */ ++public class PlayerMoveControllableVehicleEvent extends PlayerEvent implements Cancellable { ++ private static final HandlerList handlers = new HandlerList(); ++ private boolean cancel = false; ++ private final Vehicle vehicle; ++ private Location from; ++ private Location to; ++ ++ public PlayerMoveControllableVehicleEvent(@NotNull final Player player, @NotNull final Vehicle vehicle, @NotNull final Location from, @NotNull final Location to) { ++ super(player); ++ ++ this.vehicle = vehicle; ++ this.from = from; ++ this.to = to; ++ } ++ ++ /** ++ * Get the previous position. ++ * ++ * @return Old position. ++ */ ++ @NotNull ++ public Location getFrom() { ++ return from.clone(); // Paper - clone to avoid changes ++ } ++ ++ /** ++ * Sets the location to mark as where the player moved from ++ * ++ * @param from New location to mark as the players previous location ++ */ ++ public void setFrom(@NotNull Location from) { ++ validateLocation(from, this.from); ++ this.from = from; ++ } ++ ++ /** ++ * Get the next position. ++ * ++ * @return New position. ++ */ ++ @NotNull ++ public Location getTo() { ++ return to.clone(); // Paper - clone to avoid changes ++ } ++ ++ /** ++ * Sets the location that this player will move to ++ * ++ * @param to New Location this player will move to ++ */ ++ public void setTo(@NotNull Location to) { ++ validateLocation(to, this.to); ++ this.to = to; ++ } ++ ++ /** ++ * Get the vehicle. ++ * ++ * @return the vehicle ++ */ ++ @NotNull ++ public final Entity getVehicle() { ++ return vehicle; ++ } ++ ++ /** ++ * Gets the cancellation state of this event. A cancelled event will not ++ * be executed in the server, but will still pass to other plugins ++ *

++ * If a move or teleport event is cancelled, the vehicle and player will be moved or ++ * teleported back to the Location as defined by getFrom(). This will not ++ * fire an event ++ * ++ * @return true if this event is cancelled ++ */ ++ @Override ++ public boolean isCancelled() { ++ return cancel; ++ } ++ ++ /** ++ * Sets the cancellation state of this event. A cancelled event will not ++ * be executed in the server, but will still pass to other plugins ++ *

++ * If a move or teleport event is cancelled, the vehicle and player will be moved or ++ * teleported back to the Location as defined by getFrom(). This will not ++ * fire an event ++ * ++ * @param cancel true if you wish to cancel this event ++ */ ++ @Override ++ public void setCancelled(boolean cancel) { ++ this.cancel = cancel; ++ } ++ ++ @NotNull ++ @Override ++ public HandlerList getHandlers() { ++ return handlers; ++ } ++ ++ @NotNull ++ public static HandlerList getHandlerList() { ++ return handlers; ++ } ++ ++ private void validateLocation(@NotNull Location loc, @NotNull Location originalLoc) { ++ Preconditions.checkArgument(loc != null, "Cannot use null location!"); ++ Preconditions.checkArgument(loc.getWorld() != null, "Cannot use null location with null world!"); ++ Preconditions.checkArgument(loc.getWorld() != originalLoc, "New location should be in the original world!"); ++ } ++} diff --git a/patches/api/0004-SPARKLYPOWER-Add-custom-blocks.patch b/patches/api/0005-SPARKLYPOWER-Add-custom-blocks.patch similarity index 100% rename from patches/api/0004-SPARKLYPOWER-Add-custom-blocks.patch rename to patches/api/0005-SPARKLYPOWER-Add-custom-blocks.patch diff --git a/patches/removed/api/0005-Extend-AsyncPlayerPreLoginEvent-to-allow-plugins-to-.patch b/patches/removed/api/0005-Extend-AsyncPlayerPreLoginEvent-to-allow-plugins-to-.patch new file mode 100644 index 0000000..a73df53 --- /dev/null +++ b/patches/removed/api/0005-Extend-AsyncPlayerPreLoginEvent-to-allow-plugins-to-.patch @@ -0,0 +1,109 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: MrPowerGamerBR +Date: Fri, 13 Dec 2024 16:35:03 -0300 +Subject: [PATCH] Extend AsyncPlayerPreLoginEvent to allow plugins to send + Login Plugin Requests to the client + + +diff --git a/src/main/java/net/sparklypower/sparklypaper/PendingConnection.java b/src/main/java/net/sparklypower/sparklypaper/PendingConnection.java +new file mode 100644 +index 0000000000000000000000000000000000000000..11d64d825c15c122192359b86561808d0d7f5fbb +--- /dev/null ++++ b/src/main/java/net/sparklypower/sparklypaper/PendingConnection.java +@@ -0,0 +1,41 @@ ++package net.sparklypower.sparklypaper; ++ ++import org.bukkit.NamespacedKey; ++import org.jetbrains.annotations.NotNull; ++ ++import java.util.concurrent.CompletableFuture; ++ ++public interface PendingConnection { ++ /** ++ * Sends a login plugin request to the client, the client must reply with a login plugin response. ++ *
++ * The vanilla client always replies with "not acknowledged", however mods, and proxies, can change ++ * the response. ++ * ++ * @param transactionId the ID of the transaction, must be unique for each connection ++ * @param channel the chanenl where the data will be sent ++ * @param data the data that will be sent ++ * @return a {@link CompletableFuture} that will be completed when the ++ * login plugin response is received or otherwise available. ++ */ ++ @NotNull ++ CompletableFuture sendLoginPluginRequest(int transactionId, @NotNull NamespacedKey channel, byte @NotNull [] data); ++ ++ class LoginPluginResponse { ++ final boolean acknowledged; ++ final byte[] response; ++ ++ public LoginPluginResponse(boolean acknowledged, byte[] response) { ++ this.acknowledged = acknowledged; ++ this.response = response; ++ } ++ ++ public boolean isAcknowledged() { ++ return acknowledged; ++ } ++ ++ public byte[] getResponse() { ++ return response; ++ } ++ } ++} +diff --git a/src/main/java/org/bukkit/event/player/AsyncPlayerPreLoginEvent.java b/src/main/java/org/bukkit/event/player/AsyncPlayerPreLoginEvent.java +index ff5cca4a7e75274b4b278a48ae1544ff42a9836a..2ace8261a836dbdf44b35cdedb53c4b5b2986f0f 100644 +--- a/src/main/java/org/bukkit/event/player/AsyncPlayerPreLoginEvent.java ++++ b/src/main/java/org/bukkit/event/player/AsyncPlayerPreLoginEvent.java +@@ -27,6 +27,7 @@ public class AsyncPlayerPreLoginEvent extends Event { + private final InetAddress rawAddress; // Paper + private final String hostname; // Paper + private final boolean transferred; ++ private net.sparklypower.sparklypaper.PendingConnection pendingConnection; // SparklyPaper - Add support for login plugin requests + + @Deprecated(since = "1.7.5") + public AsyncPlayerPreLoginEvent(@NotNull final String name, @NotNull final InetAddress ipAddress) { +@@ -53,8 +54,15 @@ public class AsyncPlayerPreLoginEvent extends Event { + this(name, ipAddress, rawAddress, uniqueId, transferred, profile, ""); + } + ++ // SparklyPaper start - Add support for login plugin requests + @org.jetbrains.annotations.ApiStatus.Internal + public AsyncPlayerPreLoginEvent(@NotNull final String name, @NotNull final InetAddress ipAddress, @NotNull final InetAddress rawAddress, @NotNull final UUID uniqueId, boolean transferred, @NotNull com.destroystokyo.paper.profile.PlayerProfile profile, @NotNull String hostname) { ++ this(name, ipAddress, rawAddress, uniqueId, transferred, profile, hostname, null); ++ } ++ ++ @org.jetbrains.annotations.ApiStatus.Internal ++ public AsyncPlayerPreLoginEvent(@NotNull final String name, @NotNull final InetAddress ipAddress, @NotNull final InetAddress rawAddress, @NotNull final UUID uniqueId, boolean transferred, @NotNull com.destroystokyo.paper.profile.PlayerProfile profile, @NotNull String hostname, @NotNull net.sparklypower.sparklypaper.PendingConnection pendingConnection) { ++ // SparklyPaper end + // Paper end + super(true); + this.result = Result.ALLOWED; +@@ -64,6 +72,7 @@ public class AsyncPlayerPreLoginEvent extends Event { + this.rawAddress = rawAddress; // Paper + this.hostname = hostname; // Paper + this.transferred = transferred; ++ this.pendingConnection = pendingConnection; // SparklyPaper - Add support for login plugin requests + } + + /** +@@ -297,6 +306,18 @@ public class AsyncPlayerPreLoginEvent extends Event { + return transferred; + } + ++ // SparklyPaper start - Add support for login plugin requests ++ ++ /** ++ * Gets the pending connection associated with this event. ++ * ++ * @return The pending connection ++ */ ++ public net.sparklypower.sparklypaper.PendingConnection getPendingConnection() { ++ return this.pendingConnection; ++ } ++ // SparklyPaper end ++ + @NotNull + @Override + public HandlerList getHandlers() { diff --git a/patches/removed/server/0026-Extend-AsyncPlayerPreLoginEvent-to-allow-plugins-to-.patch b/patches/removed/server/0026-Extend-AsyncPlayerPreLoginEvent-to-allow-plugins-to-.patch new file mode 100644 index 0000000..55152af --- /dev/null +++ b/patches/removed/server/0026-Extend-AsyncPlayerPreLoginEvent-to-allow-plugins-to-.patch @@ -0,0 +1,115 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: MrPowerGamerBR +Date: Fri, 13 Dec 2024 16:35:12 -0300 +Subject: [PATCH] Extend AsyncPlayerPreLoginEvent to allow plugins to send + Login Plugin Requests to the client + + +diff --git a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java +index 033755682c61c889723c3669b5cff4de147f637e..8809a4ee30d0701dab85556c54e29a5c315790bc 100644 +--- a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java +@@ -92,6 +92,7 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, + private ServerPlayer player; // CraftBukkit + public boolean iKnowThisMayNotBeTheBestIdeaButPleaseDisableUsernameValidation = false; // Paper - username validation overriding + private int velocityLoginMessageId = -1; // Paper - Add Velocity IP Forwarding Support ++ private net.sparklypower.sparklypaper.CraftPendingConnection pendingConnection = new net.sparklypower.sparklypaper.CraftPendingConnection(this); + + public ServerLoginPacketListenerImpl(MinecraftServer server, Connection connection, boolean transferred) { + this.state = ServerLoginPacketListenerImpl.State.HELLO; +@@ -368,7 +369,7 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, + // Paper start - Add more fields to AsyncPlayerPreLoginEvent + final InetAddress rawAddress = ((InetSocketAddress) this.connection.channel.remoteAddress()).getAddress(); + com.destroystokyo.paper.profile.PlayerProfile profile = com.destroystokyo.paper.profile.CraftPlayerProfile.asBukkitMirror(gameprofile); // Paper - setPlayerProfileAPI +- AsyncPlayerPreLoginEvent asyncEvent = new AsyncPlayerPreLoginEvent(playerName, address, rawAddress, uniqueId, this.transferred, profile, this.connection.hostname); ++ AsyncPlayerPreLoginEvent asyncEvent = new AsyncPlayerPreLoginEvent(playerName, address, rawAddress, uniqueId, this.transferred, profile, this.connection.hostname, this.pendingConnection); // SparklyPaper - Add support for login plugin requests + server.getPluginManager().callEvent(asyncEvent); + profile = asyncEvent.getPlayerProfile(); + profile.complete(true); // Paper - setPlayerProfileAPI +@@ -450,6 +451,11 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, + return; + } + // Paper end - Add Velocity IP Forwarding Support ++ // SparklyPaper - Add support for login plugin requests ++ if (pendingConnection.handleLoginPluginResponse(packet)) { ++ return; ++ } ++ // SparklyPaper end + this.disconnect(ServerCommonPacketListenerImpl.DISCONNECT_UNEXPECTED_QUERY); + } + +diff --git a/src/main/kotlin/net/sparklypower/sparklypaper/CraftPendingConnection.kt b/src/main/kotlin/net/sparklypower/sparklypaper/CraftPendingConnection.kt +new file mode 100644 +index 0000000000000000000000000000000000000000..59570030537f5ffedd199e2c74c11f9510bc4147 +--- /dev/null ++++ b/src/main/kotlin/net/sparklypower/sparklypaper/CraftPendingConnection.kt +@@ -0,0 +1,68 @@ ++package net.sparklypower.sparklypaper ++ ++import com.google.common.base.Preconditions ++import io.netty.buffer.Unpooled ++import net.minecraft.network.FriendlyByteBuf ++import net.minecraft.network.protocol.login.ClientboundCustomQueryPacket ++import net.minecraft.network.protocol.login.ServerboundCustomQueryAnswerPacket ++import net.minecraft.server.network.ServerLoginPacketListenerImpl ++import org.bukkit.NamespacedKey ++import org.bukkit.craftbukkit.util.CraftNamespacedKey ++import java.util.* ++import java.util.concurrent.CompletableFuture ++ ++class CraftPendingConnection(val manager: ServerLoginPacketListenerImpl) : PendingConnection { ++ private val requestedLoginData: Queue = LinkedList() ++ ++ override fun sendLoginPluginRequest( ++ transactionId: Int, ++ channel: NamespacedKey, ++ data: ByteArray ++ ): CompletableFuture { ++ val future = CompletableFuture() ++ ++ this.requestedLoginData.add(LoginDataFuture(transactionId, future)) ++ manager.sendPacket( ++ ClientboundCustomQueryPacket( ++ transactionId, ++ ClientboundCustomQueryPacket.PlayerInfoChannelPayload( ++ CraftNamespacedKey.toMinecraft(channel), ++ FriendlyByteBuf(Unpooled.wrappedBuffer(data)) ++ ) ++ ) ++ ) ++ ++ return future ++ } ++ ++ fun handleLoginPluginResponse(response: ServerboundCustomQueryAnswerPacket): Boolean { ++ val future = this.requestedLoginData.peek() ++ if (future != null) { ++ if (future.transactionId == response.transactionId) { ++ Preconditions.checkState(future === this.requestedLoginData.poll(), "requestedLoginData queue mismatch") ++ if (response.payload == null) { ++ future.future.complete(PendingConnection.LoginPluginResponse(false, null)) ++ return true ++ } ++ ++ val payload = response.payload as ServerboundCustomQueryAnswerPacket.QueryAnswerPayload ++ ++ // Ensure the reader index and writer index are not modified ++ val readableBytes: Int = payload.buffer.readableBytes() ++ val byteArray = ByteArray(readableBytes) ++ ++ // Copy the readable bytes into the byte array ++ payload.buffer.getBytes(payload.buffer.readerIndex(), byteArray) ++ ++ future.future.complete(PendingConnection.LoginPluginResponse(true, byteArray)) ++ ++ return true ++ } ++ } ++ ++ return false ++ } ++ ++ @JvmRecord ++ data class LoginDataFuture(val transactionId: Int, val future: CompletableFuture) ++} +\ No newline at end of file diff --git a/patches/server/0023-Add-PlayerMoveControllableVehicleEvent.patch b/patches/server/0023-Add-PlayerMoveControllableVehicleEvent.patch new file mode 100644 index 0000000..eed3fdb --- /dev/null +++ b/patches/server/0023-Add-PlayerMoveControllableVehicleEvent.patch @@ -0,0 +1,42 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: MrPowerGamerBR +Date: Sat, 4 Jan 2025 23:58:55 -0300 +Subject: [PATCH] Add PlayerMoveControllableVehicleEvent + + +diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +index af4bcc57a9ad361de5da8c62ef7928b728c033de..ac0af5da6646df1cfe66aead3f945a9f77efa5de 100644 +--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +@@ -611,6 +611,31 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + ServerGamePacketListenerImpl.LOGGER.warn("{} (vehicle of {}) moved wrongly! {}", new Object[]{entity.getName().getString(), this.player.getName().getString(), Math.sqrt(d10)}); + } + ++ // SparklyPaper start - Add PlayerMoveControllableVehicleEvent ++ Player craftPlayer = this.getCraftPlayer(); ++ org.bukkit.entity.Entity bukkitVehicle = entity.getBukkitEntity(); ++ if (bukkitVehicle instanceof org.bukkit.entity.Vehicle) { ++ net.sparklypower.sparklypaper.event.player.PlayerMoveControllableVehicleEvent playerMoveControllableVehicleEvent = new net.sparklypower.sparklypaper.event.player.PlayerMoveControllableVehicleEvent( ++ craftPlayer, ++ (org.bukkit.entity.Vehicle) bukkitVehicle, ++ new org.bukkit.Location(craftPlayer.getWorld(), d0, d1, d2, f, f1), ++ new org.bukkit.Location(craftPlayer.getWorld(), d3, d4, d5, f, f1) ++ ); ++ if (!playerMoveControllableVehicleEvent.callEvent()) { ++ // Cancelled, move back! ++ entity.absMoveTo(d0, d1, d2, f, f1); ++ this.player.absMoveTo(d0, d1, d2, this.player.getYRot(), this.player.getXRot()); // CraftBukkit ++ this.send(new ClientboundMoveVehiclePacket(entity)); ++ return; ++ } ++ d3 = playerMoveControllableVehicleEvent.getTo().x(); ++ d4 = playerMoveControllableVehicleEvent.getTo().y(); ++ d5 = playerMoveControllableVehicleEvent.getTo().z(); ++ f = playerMoveControllableVehicleEvent.getTo().getYaw(); ++ f1 = playerMoveControllableVehicleEvent.getTo().getPitch(); ++ } ++ // SparklyPaper end ++ + entity.absMoveTo(d3, d4, d5, f, f1); + this.player.absMoveTo(d3, d4, d5, this.player.getYRot(), this.player.getXRot()); // CraftBukkit + diff --git a/patches/server/0023-Parallel-world-ticking.patch b/patches/server/0024-Parallel-world-ticking.patch similarity index 100% rename from patches/server/0023-Parallel-world-ticking.patch rename to patches/server/0024-Parallel-world-ticking.patch diff --git a/patches/server/0024-SPARKLYPOWER-Remap-SparklyPower-hacky-legacy-NBT-tag.patch b/patches/server/0025-SPARKLYPOWER-Remap-SparklyPower-hacky-legacy-NBT-tag.patch similarity index 100% rename from patches/server/0024-SPARKLYPOWER-Remap-SparklyPower-hacky-legacy-NBT-tag.patch rename to patches/server/0025-SPARKLYPOWER-Remap-SparklyPower-hacky-legacy-NBT-tag.patch diff --git a/patches/server/0025-SPARKLYPOWER-Add-custom-blocks.patch b/patches/server/0026-SPARKLYPOWER-Add-custom-blocks.patch similarity index 100% rename from patches/server/0025-SPARKLYPOWER-Add-custom-blocks.patch rename to patches/server/0026-SPARKLYPOWER-Add-custom-blocks.patch