DbManager.refuseStaticWrite logs the handler method and its caller and
stops the write (W3). It guards every write whose row belongs to a
Building, Zone, City, Guild, Mob or NPC: 69 handler methods, including
friends/condemned/patrol lists, guard minions, NPC profits and guild
banish/alliance lists. ID-only methods look the object up in the cache.
Writes that only reference a static object (character guild history,
another guild's alliance row) are not guarded.
Value changes: none; nothing is flagged static yet.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
AbstractWorldObject.rot (a Vector3f holding one quaternion part) becomes a
Quaternion. Building drops its separate w field; Mob and NPC serialize
through AbstractCharacter.getClientYaw. DB columns are unchanged and are
converted at load and save: building (w, rotY) map to the quaternion's w and
y, npc_rotation (cos of half the yaw) becomes fromYaw(2 acos(value)).
Wire values are meant to be unchanged; a parity run follows. Behaviour kept
on purpose:
- mob_rotation is still not loaded, so every mob defaults to yaw pi as before
- the slot rotation still reads the product's sin as a cos
- /rotate on NPCs and mobs still treats its input as cos of half the yaw
Value changes: building serializer writes the quaternion's x and z instead
of literal zeros (both are 0 for every building); /info "Rot" for NPCs and
mobs prints the quaternion y (sin of half the yaw) instead of the stored cos.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Building.runAfterLoad ran GET_UID_ENUM for every building (~47k queries).
One query now reads the NPC owner IDs before the building load; runtime
loads also check the NPC cache. City load reads ownerIsNPC before NPCs
are cached, so a pass after the NPC load would not work.
Value changes: none. ownerIsNPC is still true exactly when the owner's
object.type is 'npc' (dev DB: 388 buildings, 24 owners).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Building gets a no-arg constructor, a createBuilding factory (in the style
of Mob.createMob) and persistBuilding, which inserts the row through
building_CREATE, sets the returned UID, caches the object and runs
runAfterLoad. The GET_BUILDINGBYUUID re-select after the insert is gone.
PlaceAssetMsgHandler (createStructure, createBarracks, createWarehouse),
Bane and AddBuildingCmd move onto it.
Value changes:
- floor/level start at -1 and the other unset fields at the obj_building
column defaults, same as the reloaded row.
- upgradeDateTime keeps milliseconds instead of the DATETIME-rounded value
(sub-second difference in the upgrade job time).
- Warehouse placement no longer runs runAfterLoad twice, which submitted
the warehouse upgrade job twice.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>