From 068a1ccda18e24b5dad189739950925401cacc7a Mon Sep 17 00:00:00 2001 From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> Date: Mon, 23 Jun 2025 22:36:49 -0400 Subject: [PATCH] Improve AbstractHurtingProjectile syncing I am sure this has been reported before but I cannot search for any bugs due to Mojang's new bug tracker. Projectiles at high velocities very obviously go off track from their original course when sent to the client. This is due to the aggressive downsizing of velocity when sent over the client, and these entities typically have large velocity and still work just fine. We workaround this by sending the velocity for these entities exactly by using a teleport packet with relative flags and zero positional data. This prevents any possible position syncing, but sends an accurate velocity. Then, we properly send the ClientboundProjectilePowerPacket on the first tick the entity is created, as vanilla only updates this when the delta is updated typically. --- .../main/java/org/bukkit/entity/Fireball.java | 4 -- .../server/level/ServerEntity.java.patch | 48 ++++++++++++++++++- .../craftbukkit/entity/CraftFireball.java | 7 +-- 3 files changed, 51 insertions(+), 8 deletions(-) diff --git a/paper-api/src/main/java/org/bukkit/entity/Fireball.java b/paper-api/src/main/java/org/bukkit/entity/Fireball.java index 252e3d35c0..e2974c49db 100644 --- a/paper-api/src/main/java/org/bukkit/entity/Fireball.java +++ b/paper-api/src/main/java/org/bukkit/entity/Fireball.java @@ -46,10 +46,6 @@ public interface Fireball extends Projectile, Explosive { * The acceleration gets applied to the velocity every tick, depending on * the specific type of the fireball a damping / drag factor is applied so * that the velocity does not grow into infinity. - *
- * Note: that the client may not respect non-default acceleration - * power and will therefore mispredict the location of the fireball, causing - * visual stutter. * * @param acceleration the acceleration */ diff --git a/paper-server/patches/sources/net/minecraft/server/level/ServerEntity.java.patch b/paper-server/patches/sources/net/minecraft/server/level/ServerEntity.java.patch index d28acac7d5..b651b9bc77 100644 --- a/paper-server/patches/sources/net/minecraft/server/level/ServerEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/level/ServerEntity.java.patch @@ -28,7 +28,30 @@ this.level = level; this.broadcast = broadcast; this.entity = entity; -@@ -103,16 +_,22 @@ +@@ -98,21 +_,45 @@ + this.trackedDataValues = entity.getEntityData().getNonDefaultValues(); + } + ++ // Paper start - fix desync when a player is added to the tracker ++ public void onPlayerAdd() { ++ // TODO - IMPLEMENT STUBBED METHOD FROM MOONRISE ++ } ++ // Paper end - fix desync when a player is added to the tracker ++ // Paper start - Improve AbstractHurtingProjectile syncing ++ // This can be removed when velocity is no longer downsized when sending it over the protocol. ++ // We create a packet that only updates the velocity on the client. ++ private static final Set RELATIVES = net.minecraft.world.entity.Relative.union(Set.of(net.minecraft.world.entity.Relative.X, net.minecraft.world.entity.Relative.Y, net.minecraft.world.entity.Relative.Z), net.minecraft.world.entity.Relative.ROTATION); ++ public Packet getAccurateVelocityPacket() { ++ return new net.minecraft.network.protocol.game.ClientboundTeleportEntityPacket(this.entity.getId(), ++ new net.minecraft.world.entity.PositionMoveRotation(net.minecraft.world.phys.Vec3.ZERO, this.lastSentMovement, 0, 0), ++ RELATIVES, ++ this.wasOnGround ++ ); ++ } ++ // Paper end - Improve AbstractHurtingProjectile syncing ++ + public void sendChanges() { + List passengers = this.entity.getPassengers(); if (!passengers.equals(this.lastPassengers)) { List list = this.mountedOrDismounted(passengers).map(Entity::getUUID).toList(); this.broadcastWithIgnore.accept(new ClientboundSetPassengersPacket(this.entity), list); @@ -70,6 +93,15 @@ Packet packet = null; boolean flag2 = flag1 || this.tickCount % 60 == 0; boolean flag3 = false; +@@ -188,7 +_,7 @@ + .accept( + new ClientboundBundlePacket( + List.of( +- new ClientboundSetEntityMotionPacket(this.entity.getId(), this.lastSentMovement), ++ this.getAccurateVelocityPacket(), // Paper - Improve AbstractHurtingProjectile syncing + new ClientboundProjectilePowerPacket(abstractHurtingProjectile.getId(), abstractHurtingProjectile.accelerationPower) + ) + ) @@ -227,6 +_,25 @@ this.tickCount++; @@ -131,6 +163,20 @@ } if (!this.entity.getPassengers().isEmpty()) { +@@ -326,6 +_,13 @@ + if (this.entity instanceof Leashable leashable && leashable.isLeashed()) { + consumer.accept(new ClientboundSetEntityLinkPacket(this.entity, leashable.getLeashHolder())); + } ++ // Paper start - Improve AbstractHurtingProjectile syncing ++ // We need to send our more accurate velocity and our acceleration power ++ if (this.entity instanceof AbstractHurtingProjectile abstractHurtingProjectile) { ++ consumer.accept(new ClientboundProjectilePowerPacket(abstractHurtingProjectile.getId(), abstractHurtingProjectile.accelerationPower)); ++ consumer.accept(this.getAccurateVelocityPacket()); ++ } ++ // Paper end - Improve AbstractHurtingProjectile syncing + } + + public Vec3 getPositionBase() { @@ -359,6 +_,11 @@ if (this.entity instanceof LivingEntity) { Set attributesToSync = ((LivingEntity)this.entity).getAttributes().getAttributesToSync(); diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftFireball.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftFireball.java index 7e53e12c8e..5d7976f0ad 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftFireball.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftFireball.java @@ -62,9 +62,10 @@ public class CraftFireball extends AbstractProjectile implements Fireball { public void setAcceleration(@NotNull Vector acceleration) { Preconditions.checkArgument(acceleration != null, "Vector acceleration cannot be null"); // SPIGOT-6993: AbstractHurtingProjectile#assignDirectionalMovement will normalize the given values - // Note: Because of MC-80142 the fireball will stutter on the client when setting the power to something other than 0 or the normalized vector * 0.1 - this.getHandle().assignDirectionalMovement(CraftVector.toVec3(acceleration), acceleration.length()); - this.update(); // SPIGOT-6579 + // Set the acceleration power in order to properly sync the movement to the client + double length = acceleration.length(); + this.getHandle().accelerationPower = length; + this.getHandle().assignDirectionalMovement(CraftVector.toVec3(acceleration), length); } @NotNull