Push limit flaot alignment (Paper 1.21.5)

Description

If a tnt (or entity of the same size) is aligned against a block and gets moved with the piston entity push limit twice it gets aligned to the block 2 in front.

Reason

The piston/entity push cap is 0.51 per axis window, and piston movement logic naturally generates 0.51 pushes (0.5 + 0.01). Two full pushes produce 1.02 total displacement, which is enough to move a 0.98-wide TNT from one aligned state into clipping on the opposite side.

Code evidence for the 0.51 cap

Path: net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java (35-36)

private static final double PUSH_OFFSET = 0.01;
public static final double TICK_MOVEMENT = 0.51;

Path: net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java (116, 175)

double d = partialTick - piston.progress;
...
d4 = Math.min(d4, d) + 0.01;

With piston tick progression (+0.5 each tick), this yields up to 0.51 movement in a single piston movement step.

Path: net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java (328-331)

float f = blockEntity.progress + 0.5F;
moveCollidedEntities(level, pos, f, blockEntity);
moveStuckEntities(level, pos, f, blockEntity);
blockEntity.progress = f;

Code evidence for the entity-side limiter

Path: net/minecraft/world/entity/Entity.java (941-948, 966-971)

if (gameTime != this.pistonDeltasGameTime) {
    Arrays.fill(this.pistonDeltas, 0.0);
    this.pistonDeltasGameTime = gameTime;
}
...
double d = Mth.clamp(distance + this.pistonDeltas[ordinal], -0.51, 0.51);
distance = d - this.pistonDeltas[ordinal];
this.pistonDeltas[ordinal] = d;

This is the actual per-axis clamp gate. It resets when game time advances.

TNT size used in the alignment math

Path: net/minecraft/world/entity/EntityType.java (901-907)

public static final EntityType<PrimedTnt> TNT = register(
    "tnt",
    EntityType.Builder.<PrimedTnt>of(PrimedTnt::new, MobCategory.MISC)
        ...
        .sized(0.98F, 0.98F)

Numeric walkthrough for (Block Air Air Block)

  1. TNT width is 0.98, so in one 1-block air cell it has 0.02 total clearance (0.01 per side when centered).
  2. One full piston push window can move it 0.51.
  3. Two full push windows move it 1.02.
  4. 1.02 is 0.02 more than one full block, so after starting perfectly aligned on one side, the entity ends up clipping into the opposite side.

Root cause statement

Push-limit float alignment is a deterministic consequence of 0.51 capped piston displacement windows combined with entity width (0.98). Two full pushes (1.02) overshoot a clean one-block transfer and force opposite-side clipping.