Rebuilt jar — seventeen optimisation patches.
New: boats
AbstractBoat#tick built a Bukkit Location, cast the boat to a CraftEntity, fired VehicleUpdateEvent, optionally fired VehicleMoveEvent, then allocated a second Location for lastLocation — every boat, every tick.
VehicleUpdateEvent's result is discarded outright, and VehicleMoveEvent only reports movement. With neither listened for, none of it is observable. Boats are everywhere on most servers — transport, ice roads, boat farms — so this adds up in a way the event name doesn't suggest.
lastLocation is nulled rather than left stale in the unlistened branch. The existing code already skips VehicleMoveEvent when it's null, so a plugin registering later seeds cleanly on its first tick instead of receiving one bogus move spanning however long nothing was listening.
What I found already done
EntityMoveEvent in LivingEntity#aiStep and Purpur's RidableMoveEvent are already guarded — via cached hasEntityMoveEvent / hasRidableMoveEvent fields on ServerLevel. That's a better version of this same idea, since it avoids even the handler-list lookup.
My first scan this round flagged them as unguarded because the guard sits on the enclosing if rather than the event line. Widening the search window to 25 lines eliminated that whole class of false positive, along with several other apparent candidates. Worth knowing if you ever run the same search.
Still included
The low-spec profile (AtlasSpigot-26.2-lowspec.zip) for ~3GB RAM, an older CPU near 100% thread usage, ~10GB disk and a heavy plugin count. 1600M heap, view-distance 3, simulation-distance 2, monster cap 15, and hopper.disable-move-event deliberately off so shop and sorting plugins keep working.
Verified
Boots at 1600M on the low-spec profile in 32.17s with zero errors.
Not measured
No performance figures are claimed. 26.2 was benchmarked against Paper and the result was too noisy to publish — see results-26.2.txt.