Full notes
· Patch release — three stability fixes from a live Windows prod box,
plus the timezone field on the Server Restart panel grows up into a
host-resolvable dropdown. No new features, no schema changes.
Fixed
- No more stack overflow from
LogCallbackEventre-entrancy during
shutdown.EventBroadcastersubscribed toLogCallbackEventand
broadcast each fired log message over the WebSocket. When KC was
mid-shutdown and the WebSocket manager had already stopped, the
innerBroadcastthrew ("The current state of the manager is not
Start.") and the catch block calledLog.Warning(...)— which fired
anotherLogCallbackEvent, re-entered the same subscriber, threw
again, logged again, and recursed until the stack overflowed and KC
crashed. Observed live on a Windows prod box: a botched
GracefulRestartleft the WS manager stopped while the event bus
was still alive, and KC logged "Error in event handler for
LogCallbackEvent: The requested operation caused a stack overflow."
dozens of times before the service died. Fix: a[ThreadStatic]
re-entrancy guard scoped to theLogCallbackEventpath only (other
events don't loop back into the logger), and the failure path on
that path writes toConsole.Errorinstead ofLog.Warningso the
recursion can't restart. - Restart Server no longer probes
systemctlon Windows. The
POST /api/server/restartendpoint always tried
sudo -n systemctl restart 7daystodie.servicefirst and waited up to
5 seconds before falling back to in-game shutdown. On Windows there
is nosystemctl, so every restart click wasted ~5s and logged a
misleadingsystemctl restart failed or not available...warning.
On a live Windows prod box this code path was the trigger for a
cascading crash — the fallback in-game shutdown ran concurrent with
a stuck main-thread operation and snowballed into a stack overflow.
Fix: newCore/OsRestartStrategy.cspicks the path per OS. Windows
goes straight to in-game shutdown and relies on the service
supervisor (NSSMAppExit Restart, which is its default) to bounce
7DTD on game exit; an INFO-level log line announces the chosen path
instead of the warning. Linux behavior is unchanged — systemctl
first, fall back to in-game shutdown forRestart=always. Console
commandkrestartalready uses the OS-agnostic
GracefulRestartFeature.TriggerNow(no shell-out) so it didn't need
to change. - Graceful restart timezone is now host-resolvable. The
GracefulRestart feature called
TimeZoneInfo.FindSystemTimeZoneByIdwith whatever string was in
the persisted config. On .NET Framework 4.8 / Windows, IANA IDs
likeAmerica/Los_Angelesaren't recognized, so the tick threw,
the catch block logged "bad schedule config" every 30 seconds, and
the daily restart never fired. Observed in the wild with a value
of"UTC-5"(not even an IANA ID) where nobody realized the
feature was a no-op. Two-part fix: (1)LoadPersistedSettings
now probes the configured timezone, and if it doesn't resolve,
falls back toTimeZoneInfo.Local(orUtcif Local is unset),
logs one INFO line, and persists the corrected value back to the
DB so the next boot is clean. (2) NewGET /api/server/timezones
endpoint returns the runtime-resolvable timezone list sorted by
UTC offset; the Settings → Server Restart panel now renders a
PrimeVueSelectpopulated from that endpoint instead of a
free-text input that admins would fill with strings the host
couldn't parse. Savesid(whatever the runtime accepts:
Windows registry IDs on .NET Framework, IANA on .NET Core),
showsdisplayNameto the user.