End portal corrupting entity velocity by passing non-zero delta with Relative.DELTA

XMLWordPrintable

    • Type: Bug
    • Resolution: Fixed
    • Priority: Minor
    • None
    • Affects Version/s: None
    • This server is running Spigot version 4621-Spigot-566f972-3347052 (MC: 26.1.2) (Implementing API version 26.1.2-R0.1-SNAPSHOT)
    • Yes

      See https://github.com/PaperMC/Paper/issues/12234

      Already fixed by PaperMC but it is a verified Spigot bug, seemed to be existed even before 1.21.11 in my case (since the mentioned issue was reported on Paper 1.21.4), and this bug not happening in vanilla game.

      Although I found this bug initially in Spigot 1.21.11, I tested Spigot 26.1.2, which is the latest version at this moment, and the bug remains there – CraftBukkit source code shows that as well.

       

      Expected Behavior: When a falling block entity enters an end portal with velocity only on the X axis, it should appear in the End dimension with the same velocity vector preserved. The entity should continue moving along the X axis only.

      Actual Behavior: A falling block entity entering the end portal with X-axis-only velocity arrives in the End dimension with velocity on both the X and Z axes, causing it to move diagonally instead of straight.

      Why It Happens: In EndPortalBlock.getPortalDestination(), the vanilla code constructs a
      TeleportTransition with Vec3.ZERO as the delta movement parameter:

          new TeleportTransition(level, pos, Vec3.ZERO, yaw, pitch, relatives, ...)

      The relatives set includes Relative.DELTA, which means the delta value in
      the transition is treated as a RELATIVE offset added to the entity's
      current velocity. Vec3.ZERO added to anything is a no-op, so the entity's
      velocity is preserved unchanged.

      Spigot's CraftBukkit patch replaced Vec3.ZERO with entity.getDeltaMovement()
      to pass the entity's current velocity through the CraftPortalEvent:

          new TeleportTransition(level, pos, entity.getDeltaMovement(), yaw, pitch, relatives, ...)

      Since Relative.DELTA is still in the relatives set, the entity's current
      velocity is now added to itself (current + current = doubled velocity).

      On top of that, the end portal forces the entity's yaw to Direction.WEST.toYRot() as an absolute value (yaw is not in the relatives set).

      PositionMoveRotation.calculateAbsolute() rotates the transition's delta vector according to the yaw change.

      In vanilla this rotation is applied to Vec3.ZERO, which stays zero.

      In Spigot, the rotation is applied to the entity's actual velocity vector, producing a rotated copy that gets added to the original velocity.

      This introduces an unexpected Z-axis component, resulting in diagonal movement.

      How Vanilla Handles It: Vanilla passes Vec3.ZERO as the transition delta and relies on Relative.DELTA to preserve the entity's existing velocity untouched.
      The teleport pipeline calls PositionMoveRotation.calculateAbsolute(), which computes: final_velocity = current_velocity + transition_delta.
      With transition_delta = Vec3.ZERO, the result equals current_velocity exactly, regardless of any yaw rotation applied to the zero vector.

      My suggested fix: Change call of entity.getDeltaMovement() back to Vec3.ZERO when returning the result from method getPortalDestination(), matching vanilla behavior.

       

      PR #1555 is ready.

            Assignee:
            Unassigned
            Reporter:
            SNWCreations
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

              Created:
              Updated:
              Resolved: