Two coupled changes that close the data-loss windows around saves.
Logout / disconnect now does a full state save instead of just a partial one. Your inventory, mail, houses, auction listings, mounts, guild state — all committed to the database before the disconnect finishes, even on a hard crash or network drop.
Periodic autosave tightened from every 5 minutes down to every 1 minute. So even if the server itself crashes randomly (mid-fight, server admin push-restarts a build, the box loses power), at most ~60 seconds of in-flight state across every online player can be lost — not 5 minutes.
The old behavior (the bug)
The server had a periodic "save tick" that ran every minute. That tick is what actually wrote inventory items, mail, houses, and auction state to the database. When you logged out, the server only saved your character row (position, HP, money, skills, quests) — not the items in your bag, not the mail in your inbox, not your house tax timer.
So if the sequence was: 1. You pick up a rare drop 2. You hearth out and log off two seconds later 3. The server crashes 30 seconds after that 4. The next-save-tick that would have written your item to disk never ran
The item is gone. Your character is fine (saved at logout), but the item is missing. This is the classic "I swear I had it before the server crashed" scenario.
The fix
SaveAndRemoveFromWorld (the function that runs on every disconnect, graceful or hard) now triggers a full SaveManager.DoSave() after the per-character save. That DoSave() is the same routine the periodic tick uses — it flushes:
- Inventory items
- Houses (and tax timers)
- Auction listings
- Slaves / mounts
- Expeditions
- Residents
So as long as the disconnect itself completes (which is essentially always, even on hard kills), your full state is on disk before the connection drops.
Edge case handled
If the periodic tick is already running when you disconnect (it takes roughly 1 second normally), our force-save attempt returns immediately without starting a second one — the in-flight tick will pick up your still-dirty items as part of its sweep. Either path saves; you don't lose anything either way.
Performance note
This makes every disconnect slightly more expensive on the server side — the global save is heavier than just-your-character. With Rookery's player counts this is invisible. If the server ever gets crowded enough that simultaneous logouts pile up, the path to optimize is a per-player item filter inside the save routine (right now it iterates all containers every time). Not a worry today.
Behind the scenes
Two files changed:
GameConnection.cs(+33 lines): newSaveManager.Instance.DoSave()call insideSaveAndRemoveFromWorld, with try/catch and Debug-level logging if the in-flight-tick race hits. Both disconnect paths (LeaveWorldTaskfor graceful,GameProtocolHandler.OnDisconnectfor hard) route through the same patched function.Z_RookeryLocal.json: newWorld.AutoSaveInterval: 1.0override. UpstreamConfigurations/World.jsonstays at 5.0 (so the canonical config we get fromgit pullis untouched); Rookery'sZ_*override file forces the tighter cadence locally.
Together: leaving players are covered by the disconnect-time DoSave, and the rest of the playerbase is covered by the 1-minute global tick. Worst-case loss from a kernel-panic crash mid-tick: under 60 seconds of state across the entire server.
No client patch — same .pak, no download.