mojira.dev
MC-111339

Certain animated entities stutter inside of spawners

The bug

Certain entities render weirdly in when inside spawners, stuttering backwards. This happens both while the spawner is active and while the spawner is not active, but is generally much easier to see when it's not active (since the stutter happens quite quickly).

Affected entities

Here's a table of the various situations where this can be found.

The WF column indicates whether or not my suggested fix would solve the issue for this entity. If ✔ , then it's solved completely; in most cases when it's ❌ it's solved for when the spawner is not spinning and partialTicks is unused but not solved when partialTicks is used.

The L column refers to the location where the offending code is. R means the renderer: a direct reference to partialTicks. M means the model: A reference to ageInTicks, which is generated via RenderLivingBase.handleRotationFloat.

Entity

WF

L

Depends on

Spawner NBT

Notes

Charged creeper

R

ticksExisted

{SpawnData:{id:"minecraft:creeper",powered:1}}

Charge "armor" translates sideways as a function of time

jeb_ sheep

R

ticksExisted

{SpawnData:{id:"minecraft:sheep",CustomName:"jeb_"}}

jeb_ sheep easter egg: wool cycles through all colors. Almost impossible to notice due to the partialTicks portion being very small, but detectable by comparing RGB values between screenshots.

Wither aura

R

ticksExisted

{SpawnData:{id:"minecraft:wither",Health:1}}

Low health "armor" translates sideways as a function of time

Arrow shaking

R

arrowShake

{SpawnData:{id:"minecraft:arrow",shake:7}}

While it does normally shake, the shake is supposed to be sinusoidal, not rapidly alternating like that.

Dying entities

R

deathTime

{SpawnData:{id:"minecraft:pig",Health:0,DeathTime:1}}

Logic present both for regular entities and dragons specifically

Shulker bullet

R

ticksExisted

{SpawnData:{id:"minecraft:shulker_bullet"}}

Spins around

Lit TNT Minecart

R

fuseTicks

{SpawnData:{id:"minecraft:tnt_minecart",TNTFuse:0}}

Most notable with fuse of 1, but present for all values under 10. Fuse must be specified, though, or else it defaults to -1.

Primed TNT

R

fuse

{SpawnData:{id:"minecraft:tnt"}}

TNT expands

Ender crystal

R

innerRotation

{SpawnData:{id:"minecraft:ender_crystal"}}

Crystal rotation; stutter isn't significant

Bat

M

ticksExisted

{SpawnData:{id:"minecraft:bat"}}

Bat flapping wings

Blaze

M

ticksExisted

{SpawnData:{id:"minecraft:blaze"}}

Blaze rods

Ender crystal (2)

M

ticksExisted

{SpawnData:{id:"minecraft:ender_crystal"}}

Crystal height; stutter is significant

Endermite

M

ticksExisted

{SpawnData:{id:"minecraft:endermite"}}

Model swaggering

Ghast tentacles

M

ticksExisted

{SpawnData:{id:"minecraft:ghast"}}

Ghast tentacles

Guardian spikes

M

ticksExisted

{SpawnData:{id:"minecraft:guardian"}}

Only noticeable if inside the guardian model itself (spectator mode), though slightly visible from outside

Silverfish

M

ticksExisted

{SpawnData:{id:"minecraft:silverfish"}}

Model swaggering

Vex wings

M

ticksExisted

{SpawnData:{id:"minecraft:vex"}}

Phantom wings/tail

M

ticksExisted

{SpawnData:{id:"minecraft:phantom"}}

To reproduce

You need to have over 20 frames per second to see this effect in-game. If your FPS is locked at or below 20 it will be more or less impossible to notice.

The non-spinning-spawner variant of this issue is much easier to reproduce.

  1. Switch to spectator mode (/gamemode 3), so that the spawner doesn't spin even if you're close

  2. Use /setblock ~ ~ ~ minecraft:mob_spawner replace with the given data to create the appropriate spawner.

  3. Observe the spawner. In some cases, you'll need to fly really close (or even inside) the spawner to see the effect

To reproduce with a spinning version, add Delay:10000 to the spawner NBT such that the spawner spins extremely slowly. (Previously, I recommended using cheat engine to slow the game, but @unknown suggested this better way).

  1. Switch to creative mode (/gamemode 1).

  2. Use /setblock ~ ~ ~ minecraft:mob_spawner replace with the given data to create the appropriate spawner.

  3. Watch the spawner, trying to see the stutter while it's spinning.

Cause

These entities all have an animation that occurs as a function of both a variable on the entity (usually the time it has existed for) and the distance into the current tick (partialTicks). The reliance on partialTicks is what causes it to stutter, while the reliance on the time it has existed for is what causes it to not advance to the next part of the animation.

Suggested fix

There is no real good fix for this, but the best fix I can come up with is tweaking the way spawners render so that when the spawner is spinning, ticksExisted is updated, and when it is not spinning, partialTicks is always set to 0. That way, the animations play normally when the spawner is spinning, and when it isn't spinning, it doesn't attempt to animate a nonexistent animation.

This could be done by adding this code into MobSpawnerBaseLogic.updateSpawner (ajg.c, line 62):

if (cachedEntity != null) {
    // This null check may be unneeded.
    // Update the entity's existence ticks, for rendering purposes
    cachedEntity.ticksExisted++;
}

And then also adding this code into TileEntityMobSpawnerRenderer.renderMob (bsn.a, line 17):

if (!mobSpawnerLogic.isActivated()) {
    // Don't interpolate the position if the spawner isn't rotating
    partialTicks = 0;
}

This doesn't help with all entities, but it does solve it for the common of them.

An alternative fix would be to always use partialTicks set to 0, even if the spawner is spinning. This will prevent any kind of issue, but in my opinion is a slightly less interesting graphical effect.

Comments

pokechu22

Relates to:

migrated

the suggested fix works for most things. The other things could be fixed by simply changing the animation to based on ticks rather then changing it on entity.update() would be my guess.

you ignored the fact that entities in spawners can and will have passengers aka jockey spawners. You need to get and cache the recursive passengers and the entity into a list. from there then you can do entity.ticksExisted++; 

[Mod]Les3awe

Also affected the bees.

Avoma

Can confirm in 21w03a.

Avoma

Can confirm in 21w05b.

Avoma

Can confirm in 21w06a.

pokechu22

(Unassigned)

Confirmed

Block states, Rendering

animation, rendering, spawner, stutter

Minecraft 1.11, Minecraft 16w50a, Minecraft 1.11.1, Minecraft 1.11.2, Minecraft 17w06a, ..., 20w46a, 21w03a, 1.16.5, 21w05b, 21w06a

Retrieved