Bug Closed · Resolved

A saved `render_radius` of -1 makes a mob invisible to every player

#10147 opened by chikage_ 1 day ago

chikage_reported this bug
  • Type: Bug
  • Version: ModelEngine R4.2.0, Leaf 1.21.4-525
  • Evidence: our plugin repaired this 25,821 times between Oct 13 and Nov 4, 2026, on 25,817 occasions on one server
  • Location: TempTrackedEntity, BaseEntity.save, BaseEntity.load, BukkitEntity.setRenderRadius

Checked against ModelEngine-R4.2.0.jar.

Logs

[00:01:50] [Server thread/INFO]: [MythicUtils] [ModelGuard] node_crop_wheat 43719f5c-2d2a-485b-b107-44c683a0a160 @ rulid 71,65,88: tracking range -1 -> 96 (original)
[00:03:31] [Server thread/INFO]: [MythicUtils] [ModelGuard] node_iron b46a9cc0-172c-4d7d-939a-aea8b65b7469 @ ice_cave -103,39,-21: tracking range -1 -> 96 (original)
[00:03:48] [Server thread/INFO]: [MythicUtils] [ModelGuard] node_coal a6f3a721-3c5c-4f7b-a8c9-0609dda7c36c @ ice_cave -151,43,-126: tracking range -1 -> 96 (original)

The same entity can need this repair many times: one UUID was repaired 79 times.

What we had to work around

After each chunk load or spawn, our plugin reads the render radius of the modeled entity. If it is negative, it writes back the tracker's original range and marks the viewers dirty.

Problem

-1 is a placeholder that gets saved. When a model is created before the server has a tracker for the entity, wrapTrackedEntity returns a TempTrackedEntity, whose baseRange is -1. BaseEntity.save stores render_radius with no check, so that placeholder can reach the save.

Loading writes it into the real tracker. BaseEntity.load calls setRenderRadius with the saved value. If the real tracker exists by then, BukkitEntity.setRenderRadius writes -1 into it.

The swap path handles this, but the load path does not. BukkitEntityData.getTracked already skips a base range of -1 when it moves from the temporary tracker to the real one.

The mob then disappears for everyone. With a negative range, the server sends the entity to no player, so neither the model nor the base entity appears.

The value keeps coming back. The next save reads -1 from the real tracker and stores it again, which explains why the same entity can need many repairs.

Solution

  1. Do not save render_radius when it is negative.
  2. Ignore negative values in BaseEntity.load, so existing saves heal themselves.
  3. Consider restoring getInitialBaseRange() when a negative range is found on a real tracker.
Sign in to join the discussion.