Uploaded image for project: 'Minecraft: Java Edition'
  1. Minecraft: Java Edition
  2. MC-273758

Ominous item spawner's animation breaks if the level.dat "Time" value is over a certain number

XMLWordPrintable

    • Confirmed
    • Survival
    • Rendering
    • Important
    • 1258491
    • Expansion B

      The Bug

      Ominous item spawners can have a slow/choppy animation if the Time value in the level.dat file is over 16,777,216 ticks (~9.71 days in real-time).

      The ominous item spawner becomes more jittery the higher the level time is, to the point where it stops animating completely. However, this takes much longer to achieve.

      See this video for a demonstration of the bug.

      How to Reproduce

      1. Generate a new world, or use an existing one, and play in it for approximately 9.71 days in real-time, or run /tick sprint 16777216 to speed up the process. Alternatively, use this world: MC-273758.zip
      2. Start an Ominous Trial by placing a Trial Spawner spawning any mob such as pigs, and drinking an Ominous Bottle near it in Survival mode.
      3. When you hear/see an ominous item spawner appearing, look closely at it.
      4. Note how the ominous item spawner's animation is broken due to the high-level time value.

      Code Analysis / Possible Fix

      Thanks to haykam for the explanation!

      The bug starts occurring when the level time reaches 16,777,216 ticks (also 2^24), which is notably where floating-point numbers lose precision, due to the 32-bit single-precision floating-point as defined by the IEEE 754 standard. You cannot count by 1 in floats at that point, so the lerping of the angle fails.

      The possibly relevant code for this issue is located in the OminousItemSpawnerEntityRenderer#render method. Source code of Minecraft 1.21 using Yarn mappings:

      float j = MathHelper.wrapDegrees((float)(world.getTime() - 1L)) * 40.0F;
      float k = MathHelper.wrapDegrees((float)world.getTime()) * 40.0F;

      A possible fix would be to get rid of the inner float cast and make wrap degrees for longs. That should get rid of precision issues because -180 to 180 is precise enough for this case, and a modulo of a long probably does not have overflow issues.

      A fix could be something along the lines of:

      // Assuming a MathHelper.wrapDegrees(long) now exists:
      float j = MathHelper.wrapDegrees(world.getTime() - 1L) * 40.0F;
      float k = MathHelper.wrapDegrees(world.getTime()) * 40.0F;

            Unassigned Unassigned
            Viradex Viradex
            Votes:
            10 Vote for this issue
            Watchers:
            6 Start watching this issue

              Created:
              Updated:
              Resolved:
              CHK: