Week of July 6, 2026. This is an archive page; back to the current week.
2026-07-11 · 21 items
Headlines
- Bug tracker reorganized. Reviewed all 230 tracker entries and re-filed 105 of them into seven new categories covering graphics, sound, stability, chat and mail, translations, decorations, and the in-game Oracle assistant itself. The Oracle's own reports now classify into twenty areas instead of thirteen, so crashes and disconnects no longer share a bucket with frame-rate problems.
- Fixed players showing online forever. A player reported on the forum that friends and guild lists kept showing him online with his machine powered off, and it never cleared. The cause was found and fixed: the online list was kept up to date only by login and logout signals, so one lost logout stranded a player as online until a full restart. The servers now cross-check the list against real connections once a minute and correct it both ways. Reaches testers with the next test-shard build.
- The Linux client is live on the test shard. Build 34 shipped to both Windows and Linux from a single source revision at the same build number: the server was rebuilt to match, both download channels went live, and a login test passed before the release was called done. Testers can now download a Linux launcher, and a link for it sits on the tester and developer pages beside the Windows one.
- Build releases can no longer split across platforms. The two platform builds of a release used to each pick up "the latest code" independently, so a change landing between them could put them on different revisions. The release now locks one revision up front and builds every platform from it, and the deploy refuses any mismatched pair as a backstop.
- Faster test builds. Measured where a two-hour build actually goes: about 50 minutes was spent compressing the finished 16 GB game package with settings meant for text, on data that is already compressed. The packaging step now uses a fast multi-core archiver, and a written plan covers the next target: making the 49-minute asset packaging step skip work that has not changed. That skip check now records a per-file fingerprint list each build and logs exactly which files triggered a rebuild, so the next build names the files that keep defeating it.
- Community suggestion sweep. Read the workblog discussion thread, every wishlist request active since January 2025, the live-server feedback board, and all fifteen bug-report boards, then filed 70 new tracker entries: 53 player suggestions and 17 bugs and follow-ups. Everything was checked against the suggestions already on file so nothing got logged twice.
- Ended the terrain-texture file churn. A long-running annoyance where 253 terrain texturing files could show up as locally modified after simply opening the editor was traced to a stored checksum that mixed in the editor version and build platform. The checksum now depends only on the actual texture formats, which are identical on every desktop platform, and an automated test locks the formula in place.
Bug tracker
- Added seven categories to the bug tracker: graphics, audio, stability, social, localization, decorations, and oracle (reports about the in-game Oracle assistant itself). Crashes, freezes, and disconnects moved out of performance into stability; performance now means frame rate, lag, and load times.
- Reviewed all 230 open and closed tracker entries and re-filed 105 of them. The engineering catch-all bucket dropped from 134 entries to 61, the 45 player reports filed before the Oracle learned area classification all found real homes, and a 16-entry cluster of requests about the Oracle itself now sits in its own category.
- Taught the in-game Oracle the new areas: its classification guide now routes a crash to stability, a missing texture to graphics, a silent spell to audio, and mail or party problems to social. It also counts how often it fails to classify a report, so classification slips show up in the service metrics. The reporting service picks this up with its next deploy.
Linux client
- Shipped build 34 to the test shard on Windows and Linux together. Both clients were built from the same source revision and carry the same build number, the server was rebuilt to match and swapped in with a rollback copy kept aside, both download channels flipped live, and an automated login test passed before the release finished.
- Released the Linux launcher as a small archive that stays runnable after extraction, and verified the whole path on a Linux machine end to end: the launcher fetched build 34 over the network, checked its signature, and left the game marked runnable. Added a Linux launcher download link to the tester page and the developer portal next to the Windows one.
- Closed the release race that could put two platforms on different code: a release now locks one source revision up front and builds every platform from it. The build tooling gained the revision pin, and the deploy still refuses a mismatched pair as a backstop.
Community
- Swept recent community input across four sources: the workblog discussion thread (all 50 posts), wishlist requests active since January 2025, the live-server feedback board (38 threads), and the fifteen bug-report boards.
- Filed 53 new player suggestions on the tracker, including bulk vendor listings with partial-quantity buying, town maps that show placed lots and owners, calendar-driven seasons and weather, PvP factions with territory, ambient sound for player-owned towns, and a pass on underperforming skills and incomplete tooltips.
- Filed 17 bug and follow-up entries from the same pass, among them farm actions failing on very large farms, axe-head salvage yielding nothing for a quest, players showing online to friends while logged off, and interactive objects getting stuck in a busy state.
- Bug reports already moving through the Bug Brigade's forum pipeline were left with them; only open, systemic, or stalled items were imported. Ideas players re-raised that were already on file got follow-up notes instead of duplicates.
Friends and guild presence
- Fixed the bug where a player could show as online in friends and guild lists indefinitely, even with their machine powered off, surviving relogs and server restarts (from a forum report, tracker entry filed in yesterday's community sweep). The online roster was maintained purely by login and logout signals, so a single lost logout (a dropped connection with no clean sign-off, a hiccup in cross-server delivery, or a restart replaying old state) left a stale entry with nothing to ever remove it. The servers now audit the roster against real connections once a minute and repair it in both directions: stuck online entries clear within about two minutes, and missed logins get filled in. Verified the repair logic directly with an automated harness, 31 checks passing.
- Fixed a related gap where stopping a server skipped the disconnect handling for every connected player, which could strand online entries and skip session cleanup. Player disconnects now complete before the server finishes shutting down.
Board game tables
- Fixed a tester-reported bug where the placeable chess, checkers, and backgammon tables did nothing on double-click. The placed tables were missing the piece that makes a world object clickable, so the game never recognized the mouse was over them: no highlight, no prompt, no game window. All three tables now show their play prompt and open the game window. The fix needs the next test-shard build to reach testers.
Terrain textures
- Diagnosed why 253 terrain texturing files kept showing up as locally modified: the MicroSplat plugin stamps a checksum into each of its 84 texture-array configs, and the stock formula mixed in the editor version and the active build platform, so any environment difference rebuilt and re-saved every config plus its large texture-array files. The trigger this morning was an unclean editor shutdown on a portable drive losing the saved build-target setting, which silently reset the platform on the next launch.
- Reworked the checksum to depend only on the texture formats the arrays are actually built with, which are identical across all desktop platforms. Editors on different machines, platforms, or versions now agree on the stored value, so the mass rewrite cannot recur; a genuine format change, such as a mobile build target, still rebuilds the arrays as designed.
- When only the stored checksum is stale, the plugin now restamps the config file instead of recompiling, so the multi-megabyte array files are no longer rewritten needlessly. An automated test pins the formula to a golden value, making an accidental change fail the test suite instead of dirtying 84 files on every developer machine.
Build pipeline
- Timed every phase of a full client build from the build farm's logs: roughly 7 minutes of real build work, 49 minutes packaging game assets, and 50 minutes compressing the finished 16 GB package at maximum effort even though the data inside is already compressed. Switched the packaging step to a fast multi-core archiver on both build platforms.
- Wrote up the full speed-up plan for the asset packaging step: the change tracking that should skip untouched work currently invalidates itself every build, and the plan lays out how to fix that, close a staleness gap, and cache the expensive bookkeeping, targeting routine builds in well under half an hour.
- Confirmed from build logs that half the skip system already works: the scene half of asset packaging reused its previous output in the latest build, while the game-data half rebuilt every time. That narrows the always-rebuilds problem to the folders the build itself rewrites while it runs, including nearly two thousand dialog data files it deletes and regenerates on every pass.
- Added diagnostic logging to the asset-packaging skip check, verified by 8 new automated tests. The build now stores a per-file fingerprint list alongside its rolled-up change signature, and when a rebuild triggers it logs which files changed, were added, or were removed, with the full list saved to a report file. It also times the fingerprint scan and the heaviest native packaging call, so the next build produces exact numbers instead of estimates.
- Fixed the blog publishing tool to reset file permissions on the web server after each upload. Publishing from a Mac had shipped image files the web server was not allowed to read, which briefly broke every picture on this blog; the deploy now cleans that up itself no matter which machine publishes.
2026-07-10 · 90 items
Headlines
- A Linux client is on the way. The game client now builds and runs natively on Linux: the first build came out of the build farm today on the first try and passed the new network stack's self test, 7 checks of 7, on a Linux machine. The launcher, the patch server, and the release pipeline all learned the second platform, and a public test build is being prepared.
- Random dungeon generator. A new chest for player-owned dungeons builds a random layout from whatever room pieces you drop inside: close the lid, confirm, and rooms attach themselves to your dungeon's open doorways, with a different layout on every roll. Hand-built work is never touched, pieces that do not fit stay in the chest, and every build obeys the same rules as placing rooms by hand.
- Mounts can jump. The jump animations for the horse, stag, and reindeer mounts were fully built and wired into the game years ago and shipped switched off behind a single disabled setting. That setting is now on: a mounted jump costs half the focus of one on foot and clears the same height, measured at 1.1 meters in a live test session. From the player wish list on the official forums.
- Dungeon-exit crash run down. A tester's client died twice today at the same instant: the moment the game begins tearing a player dungeon down to travel out. Server logs traced the window to scene teardown racing the engine's new background object spawning, and the tester's crash file confirmed the exact failure inside the engine's teardown walk. The game now finishes those spawns before any teardown and holds new ones until loading ends.
- The client exits properly again. Quitting the game on the new network stack left the process running forever: ending a connection never closed its underlying socket, every trip between servers leaked another one (a two-hour session held 22 at quit), and the engine's new runtime waits for socket threads where the old one killed them. Sockets now close when a connection ends, when the client hops servers, and at quit. Diagnosed from a live hung process on a dev machine.
- One build number everywhere. The launcher called today's test build 32 while the game inside called itself build 30. Both were the same build: build jobs and the patch channel counted independently, and the publisher bridged any gap by renumbering the release, so the two numbers could never re-converge. The number stamped into the game is now the number the channel publishes, a mismatched release is refused instead of shipped, and the server turns away out-of-date clients at login with the standard "restart your launcher" prompt instead of letting them play into strange errors. Build 33 shipped through the new chain the same evening with the launcher, the in-game label, and the server all reporting one number.
- The in-game Oracle got a full reporting overhaul. It now asks up to two short follow-up questions about a bug (what you expected against what actually happened, how to reproduce it, how often it happens) and stops the moment the report is usable, so reports arrive with real detail instead of one vague line. Every report is classified into one of 13 game areas such as combat, crafting, interface, or performance, severity follows a written rubric instead of a guess, and before anything is filed the report is checked by meaning against every existing report, similar wording or not, so duplicates get pointed at the original instead of piling up.
Player dungeons
- Added the Random Dungeon Generator Chest for player-owned dungeons. Place the chest inside your dungeon, fill it with dungeon room pieces, and close it: after a confirmation, the pieces assemble themselves onto the dungeon's open doorways, rolling a different layout every time. It only ever adds to what you built by hand, and pieces that do not fit stay in the chest with a chat summary of why (no matching doorway, no space, or the dungeon point limit).
- Generated layouts obey every rule manual building enforces: doorway set matching, room collision, the dungeon point budget, and every room staying reachable from the entrance. Verified end to end against a local server: two full builds each landing on an exact 100 of 100 point budget, all rooms connected, and the layout identical after leaving and re-entering the dungeon.
- Fixed two defects that live verification surfaced before they could ship: rooms built from a stacked item briefly shared one network identity, and a rapid build could outrun the server's save acknowledgments so a room could trail in on the next visit. Builds now pace themselves against the server and stop with an honest report if it falls behind.
- The manual doorway builder now shares one placement code path with the generator, so the two cannot drift apart. 15 automated tests pin the layout logic. The chest is a test-only item for now; how players will earn it gets decided after the testers have beaten on it.
Mounts
- Enabled mounted jumping (a player wish list item from the official forums). The horse, stag, and reindeer jump animations, the rider animations, the input handling, the physics, and the network replication all existed and were switched off behind one disabled setting since the mount system first shipped. A mounted jump costs half the usual focus and clears the same height as on foot, measured at 1.1 meters in a live session. The mounted body is wider than a walking avatar, so this opens no new squeeze-through routes; the tester task includes an out-of-bounds sweep anyway. Known cosmetic gap: cat mounts have no rider jump animation, so the rider holds the saddle pose while the cat jumps.
- Riders now stay mounted across scene changes. The Automatic Remount option existed but was off by default and visibly re-cast the mount seconds after arrival. It is now on by default and starts behind the loading screen. Players who had explicitly turned it off keep their choice, and dismounting on purpose before traveling still means arriving on foot. The re-cast needs about two seconds after arrival to survive the arrival state sync, so a short wait can remain visible after long loads.
- Fixed three defects in the remount logic while moving it: being knocked off a mount and then traveling on foot no longer surprise-remounts you scenes later, arriving dead no longer queues a forced remount for whenever you resurrect (it gives up quietly after 30 seconds), and the remount can no longer stall a scene load, because it runs independently of the loading sequence.
- Doors and city gates can be opened while mounted. Every door refused with "You cannot interact while mounted!"; doors and gates now open from the saddle, while chests, crafting stations, and everything else still require dismounting. A door swinging open no longer counts as a collision that knocks the rider off; riding into a genuinely low doorframe still dismounts as before.
- Verified in a live Editor session with a real login: a measured mounted jump arc, a mounted zone transition running the full remount chain, and a door query from the saddle. Six new automated tests lock the setting values and the door and collision behavior. Filed three tester verification tasks and two new wish list entries; none of this is on the test shard until the next build.
Input
- Caught and fixed a bug from yesterday's harvesting swing meter that silently unbound the jump key for every player. The meter registered its own key defaulting to Space, and key registrations are exclusive: the second owner of a key strips the first, so Space stopped jumping everywhere, on foot and mounted. The swing input now has no default key of its own and reads the jump key while the meter is live, which was the intended design. The live test build predates the meter, so testers never saw the broken state.
Client stability
- Ran down a tester's report of the client dying while leaving a player dungeon. Server logs showed two hard crashes in one afternoon, both at the exact moment the game starts tearing the dungeon scene down for the trip out, and two error entries from the same session caught the underlying state: the engine's new background object spawning was still integrating pooled objects while the game swept and tore down the scene around them.
- Fixed the window: in-progress spawn batches are now finished off before the end-of-load sweep of a fresh scene, before the dungeon cleanup pass, and before a scene is torn down for travel. The stalls land behind the loading screen. The same race had been silently aborting the pass that registers lights and effects for distance culling and the pass that returns disconnected dungeon pieces to inventory, so those now complete reliably in player dungeons. Four automated tests pin the new behavior; the fix rides the next test-shard build.
- The same log dig surfaced a separate problem: a slower scene load got another player disconnected to the title screen mid-travel because the server's client timeout keeps counting during long loads. Filed for follow-up rather than fixed today.
- The tester sent in the crash file, and it confirmed the diagnosis exactly: the engine died walking a half-built spawn batch while it tore the dungeon scene down. The symbols matched the exact engine build, so the readout is definitive.
- The crash file also exposed one residual gap: the doomed scene keeps running for a few frames after the safety flush, so a spawn batch started in that window could reopen the race. Background spawning now switches to immediate mode for the whole loading sequence and back afterward. Five automated tests cover the behavior.
Oracle
- Taught the Oracle to gather a usable bug report before filing. For bugs it may ask up to two short clarifying messages aimed at what is missing: expected against actual first, then how to make it happen, then frequency. It stops early once the report is usable, never asks anything after you confirm, and a player who answers "I don't know" or "just file it" still gets their report filed with what they gave. Feature ideas stay at a single question at most.
- Reports now carry structured Expected, Actual, and Frequency sections when the player provided them, so the team reads the failure in the player's own words instead of digging it out of a summary paragraph.
- The Oracle now files every report into one of 13 player-facing game areas (combat, crafting, gathering, economy, housing, items, interface, travel, world, quests, progression, taming, performance) instead of one catch-all engineering bucket. The choice is checked server-side and falls back safely when nothing fits.
- Severity now follows a written rubric: blocker means you cannot keep playing or lost something permanently, major means a system is broken with no workaround, minor covers cosmetic issues and inconveniences. When torn, the Oracle picks the lower level, except lost progress is never minor.
- Built duplicate detection that cannot be skipped. Every filing attempt is compared by meaning against all existing reports, open and closed, and against reports other players filed minutes earlier. Likely matches are surfaced and must be ruled out before a new report files; a match against a fixed bug files anyway with a note that it may have returned. Shipped in a watch-only mode first, with a calibration tool that picks the match thresholds from the real report corpus before enforcement turns on.
- Hardened the service around the funnel: per-player and service-wide usage limits now survive restarts, oversized requests are trimmed before they cost anything, a single abusive account can be cut off without touching anyone else, and every decision is logged for tuning.
- Filed reports now include the build number, operating system, hardware, display mode, graphics quality, frame rate, and language when the game client sends them. The service side landed today; the client side rides the next test-shard build, and either half works alone.
- Backed the whole overhaul with an offline test suite, 52 checks covering the new prompt rules, the area list, the duplicate gate paths, the usage limits, and the report rendering.
- The game client's half landed too, riding the next test-shard build: the Oracle window's input box now stops at the same length the server accepts instead of silently losing the overflow, and the "Filed report" and "Matches existing report" lines are styled apart from the knowledge-base citations so the outcome of a report is the first thing you see.
- Split the client's request-building code out of the window plumbing into a pure piece with 7 editor tests pinning it, including one that keeps decimal points correct for players running the game on German or French systems.
- Grew the Oracle's knowledge base where players asked about the interface. The Game Interface guide went from a 60-line overview to a full walkthrough of status bars, effect icons, targeting, nameplates, the compass, hotbars, and window management, and four new guides joined it: Inventory Management, Options and Settings, Chat and Social, and The Map and Compass. Every claim was pulled from the game's own code and help text and then independently re-checked, which caught and corrected 16 wrong or unverifiable statements before anything shipped.
- Deployed the whole overhaul to the live Oracle service the same day and verified it end to end: a question about splitting item stacks answered from the new Inventory Management guide with a working source link, and a test bug report came back tagged interface, severity minor, with the expected and actual behavior as separate sections and the report visible to the duplicate matcher seconds later. The tracker gained the 13 new game-area categories, and a verification task went to the testers.
- The duplicate-matching calibration proved its worth before it could do harm: measured on the real report corpus, two completely unrelated reports typically score 79 percent similar to their nearest neighbor under the matching model, so the ship-with defaults would have flagged half of all honest reports. The measured thresholds went live instead, and matching runs in a watch-only mode while a week of data confirms them.
Launcher
- The launcher now detects that the previous game session did not close properly (a crash, a hang, or a killed process) and automatically sends that session's log file, plus a short hardware summary (operating system, processor, memory, graphics cards, language, free disk space), to the team. A small line in the launcher notes when a report went out; a setting in the launcher's config file turns the feature off.
- Privacy rules are built in: the computer name and Windows username are never collected, and file paths inside the log are blanked to a placeholder before anything leaves the machine. Each distinct crash is reported once, with at most three delivery attempts, and uploads are size-capped.
- When the engine wrote a crash dump for a hard crash, the report carries the dump and its error log too, so those crashes arrive with enough detail to be read directly. An update interrupted mid-upload finishes the send on the next launcher start.
- Built the receiving service endpoint with per-machine and service-wide daily limits, verified the full loop end to end with a staged crash (detected, uploaded, stored with its hardware summary, and correctly skipped as a duplicate on the next start), and covered both halves with 44 new automated tests. Rides the next launcher update.
Linux client
- Started shipping a native Linux client. The first Linux build came out of the build farm on the first try with no game-code changes and passed the new network stack's built-in self test, 7 checks of 7, running on a Linux machine.
- Fixed the failure that killed an earlier Linux release-build attempt: the build-number stamp marks two project files read-only after writing them, and on Linux clearing that mark requires owning the file. The stamp now skips the read-only marking on non-Windows build machines.
- The launcher's transfer engine now records which files in a build must be executable and marks them after every update on Linux and Mac, where a downloaded file is not runnable by default. The launcher also starts the game directly on those platforms; the old launch path only worked reliably on Windows. The launcher test suite, 97 checks, passes on both Windows and Linux.
- The Linux launcher download will be a small archive that keeps the program runnable after extraction, built automatically by the release script alongside the plain binary the launcher uses to update itself.
- The patch server gained a Linux section beside the Windows one, the nightly cleanup of old builds understands the Linux download shapes, and the pre-deploy security checks audit the Linux channel with the same rules as the Windows one.
- The release pipeline can now ship both platforms as one release: Windows and Linux clients built from the same source revision carry the same build number, are checked against each other before anything goes live, and publish to their own patch channels in a single deploy.
Build and deploy
- Diagnosed last night's failed Windows client release build: a leftover Unity process had held the dedicated build tree open all night, so the build could not open the project, and the console blamed a licensing retry instead of the real cause. Build jobs now clear any stale Unity process off the build tree before starting and report that failure by name with the offending process listed. A fresh release build went through cleanly this morning.
- Rebuilt the chaos deploy pipeline around the new server stack. The old server phase still tried to ship the retired backend to a machine that no longer exists, which is why yesterday's deploy died in its first seconds, and it would have paired the client with a five-day-old server build even if it had worked. The deploy now compiles the new-stack server from exactly the same source revision as the client being published, refuses any client and server mismatch up front, and a server build that fails to compile leaves the running shard untouched.
- A failed server start now rolls itself back: the previous build is kept aside on the shard, restored, and restarted automatically, so a bad deploy can no longer leave the test shard down.
- The deploy pipeline targets the chaos shard only now. The options to point it at other environments were removed outright, and the deploy scripts refuse any other destination independently of the pipeline settings.
- Each server deploy can also carry a freshly generated world report, so player-owned towns created since the last snapshot set up correctly after an update.
- The reworked deploy's first live run proved the safety design and caught its own gap: the server compile references shared sources outside the source slice the pipeline had prepared, so the compile failed and the running shard was left untouched, exactly as intended. The slice now covers the full shared-source set.
- Chaos build 32 went out through the rebuilt pipeline end to end: the server was compiled from the same source revision as the client, the shard restarted with a rollback copy held aside, the world report shipped fresh so all 442 player-owned towns are current, and the automated login probe passed before the release was called done. Eleven waiting tester tasks were marked ready to test on the new build.
- Fixed the recurring "phantom-modified" file noise in the game repo. 529 large baked Unity assets (combined meshes, occlusion-culling data, terrain and project-settings assets) were stored as raw text even though the repo is configured to keep files that size in dedicated large-file storage, so every fresh checkout reported them as changed forever and each sync had to stash the noise away. Re-stored them as proper large-file pointers; the on-disk content is unchanged and the working tree is finally clean after a pull.
- Merged that large-file fix into the working copy here, which surfaced one more publisher gap: the merge rewrote this log's page with Windows line endings and the weekly rollover script only accepted Unix ones, so publishing refused to run. The script now accepts both, and the merged page with both machines' entries went out.
- Made the launcher and the game agree on the build number. The launcher called the current test build 32 while the game inside reported build 30: each build job counts its own builds, the patch channel counts published releases, and the publisher bridged any gap by renumbering the release, so the two numbers drifted apart permanently. Builds now stamp themselves with the next channel number, the publisher refuses to renumber anything, and a release whose numbers disagree is refused instead of shipped. The next build converges launcher, in-game build label, and server on one number.
- The server now turns away out-of-date game clients at login. The only version check compared a name that changes once per data wipe, not per build, so a stale client could keep playing against a newer server and run into confusing errors. The server now compares the client's build number against the build it shipped with and sends old clients the standard "restart the game using the launcher" prompt. Local development servers and Editor sessions are unaffected.
- The Chaos shard's daily message now greets testers with a real welcome instead of the "Default Message" placeholder: the shard never had a message file, so it served the built-in fallback, and each deploy now installs the real one.
- Build 33 shipped through the whole reworked chain the same evening: the build stamped itself one above the live channel, the publisher accepted it without renumbering, and the launcher, the in-game build label, and the server now all report 33. An outdated client picked up the new build through the launcher bounce exactly as designed, and a scripted login on the fresh build confirmed the new welcome message in chat.
- The first live pass caught one placement bug in the new deploy step: the server reads its runtime files from its data directory, and the deploy had written the build-number stamp and the daily-message file next to the binaries instead, leaving the login gate off. The deploy now writes both to the right place and restores the previous values if a deploy rolls back; corrected on the shard the same hour and verified with the gate reporting build 33 on startup.
- Verified remote access to the build machine ahead of travel. The web build console already works from anywhere behind two logins, and direct maintenance access rides an existing secure tunnel between two of our servers; both connections dial outward from the office and reconnect on their own after a network blip. Wrote the procedure into the operations docs and set up a one-command shortcut on the laptop.
Client performance
- Started the next client performance workstream: runtime combining of identical house decorations into single render objects, with the originals restored the moment anyone edits one. Groundwork landed first: the decoration audit tool now measures combine readiness across all 6,524 decoration items (mesh readability, level-of-detail structure, transparent materials), and an Editor survey of a 425-item sample showed 86 percent of decoration meshes already qualify. The design doc covers grouping by item and dye, spatial clustering, and the safety rules that keep decorations clickable while combined.
- Built the decoration combining core: identical items group by prefab and dye into 24 meter plot cells, a quiet-time debounce holds work until a lot stops changing, builds are budgeted per frame, and any edit to a member dissolves its combined group on the spot. 22 automated tests pin the scheduling behavior. The piece is inert until the mesh combiner and game hooks land on top.
- Landed the rest of the decoration combining runtime on top of that core: the mesh combiner that merges each group into one draw object with dye colors preserved per piece, and the game hooks that hide the originals and bring them back the instant a decoration is grabbed, moved, dyed, or picked up, with the whole lot held out of combining while a player is actively decorating it. A new Video option (on by default) lets players switch the system off; everything stays inactive behind the master setting until the benchmark and audit gates pass.
- Added the measurement tools for those gates: a play-mode audit that reports how many identical-item groups a real player town actually offers the combiner, and the synthetic benchmark scene can now stamp combine-eligible decorations for before/after captures. The full client test suite is green at 773 tests, including one scheduling test that had never been run to completion and was asserting at the wrong moment.
GM tools
- Chased a report that the Light spell cast fine but produced no light. The spell itself was healthy: the test character was in GM ghost mode, which hides all of a ghosted GM's spell effects by design, persists across logins, and switches itself on when certain GM windows open. Nothing on screen ever said so, which made a working spell look broken.
- Casting while ghosted now prints a chat notice that GM ghost mode is hiding your spell effects, with where to turn Ghost off, at most once every ten seconds. Verified in a live session: one notice on a ghosted cast, none after unghosting, and the Light spell's light back on the caster.
- Ran down a red "Server: Unknown operation code" error appearing in chat at character select. A GM window left open survives logging out, and its automatic player-roster refresh kept asking the login server a question only game servers can answer. GM requests now hold until the client is back on a game server, and the login server answers unknown requests without printing its confusion into player chat.
- Typing /gm now leaves a success line in the client log, so a "nothing happened" report can be settled from the log alone: every failure branch already logged, and total silence now always means the command never reached the game. Verified end to end in a scripted fresh client session on the test shard: window open, roster request answered, screenshot taken.
Connection errors
- Rewrote all 22 connection-error dialogs. Each kept its support code word ([WHEAT], [IRON], [CICADA], and the rest) so a screenshot still identifies the exact failure branch, but the message behind the code now explains in plain language what likely happened and what to try: servers down or restarting, a firewall or router blocking the game's ports, an internet connection that dropped, the account service unreachable. The old texts were deliberately vague one-liners.
- The generic "connection lost" dialog now names the usual real causes: an internet connection that dropped or changed mid-session, such as a router failover, a VPN reconnect, or a network switch. That exact case came up this morning: a mid-session failover to a backup internet line dropped the connection, and the old dialog offered nothing but a code word and Diagnostic="None".
- On the new network stack the dialog's Diagnostic value now carries the real transport reason (timeout, connection refused, socket error) instead of "None" for every unclassified drop, and the client logs that reason on every disconnect, so a report screenshot alone tells support what actually happened.
- All 22 messages were re-translated into the seven supported languages and the shipped language files regenerated; the Spanish and Italian files caught up with several older text changes at the same time. Verified end to end in a live play-mode session: a real disconnect rendered the new dialog text cleanly, and the client test suite passed with no failures.
Client shutdown
- Fixed the built client never exiting after quit. On the new network stack, ending a connection stopped the conversation but left the underlying socket and its listening thread running, and every hop between servers opened a fresh connection without closing the old one; a two-hour play session held 22 abandoned sockets at quit. The old engine runtime forcibly ended those threads on exit, the new one waits for them, so the window closed and the process lived on until killed by hand. Diagnosed from a live hung process: engine teardown had completed and the leaked sockets were still bound two hours later.
- The transport now closes its socket the moment a connection ends, a reconnect retires the old socket before opening the new one, and quitting closes every remaining connection before the engine shuts down. Three new automated tests pin the behavior, including the server-hop reconnect pattern, and the full transport test suite passed.
- Fixed every radio deco object throwing an error during shutdown: the engine no longer accepts a missing texture when a radio turns its screen off, and the error was also skipping the radio player's cleanup accounting. Missing textures are now skipped.
- The internet-radio tuner could park a thread for ten minutes waiting on a dead station stream: the wait constant was 100 times larger than intended. It now gives up after the intended six seconds, and the wait no longer counts against process exit.
Quest tools
- Designed the quest wizard, the authoring step for the Quest Graph tool: a designer describes a quest in plain language, an AI drafts the dialogue in each character's established voice along with the flags, journal entries, and reward wiring, and a step-by-step review screen with exact file previews is the gate before anything is written. Every generated quest must pass the same validation that already checks the 677 shipped quests, and a finished quest lands as one change that a single undo removes completely.
- The design rests on a full audit of everything creating a quest actually touches (conversation files, journal entries, reward lists on the characters themselves) and does not require the AI: the same wizard accepts hand-built quest plans, and the id bookkeeping the retired quest database used to handle moves into the tool. Build order is settled in the design document; implementation starts later.
Tavern games
- The chess, checkers, and backgammon game tables are now obtainable on the chaos shard. The tables shipped in an earlier build, but the server's item data snapshot predated them, so the server did not recognize the tables and could not create or mail one. Build 32's deploy carried a current snapshot, confirmed on the shard itself, and each community tester account received one of each table by in-game mail for the open verification task.
Harvesting
- Redrew the harvesting swing meter as a ring track after team feedback that the needle read poorly. The old design filled a half circle and swung a needle from the center, but the needle's pivot sat below the wedge's center, so where it pointed was ambiguous. The meter is now a thin ring: a red marker sweeps along the track right to left, the target is a green zone on the track with a gold center for a perfect hit, and the marker overhangs the track like a tick so the press moment reads at a glance.
- Timing, skill effects, and rewards are unchanged: gathering skill still sizes the zone, Meticulous Collection still softens how much it shrinks per hit, and the sweep still speeds up as a chain grows. How much of the ring the sweep covers is a tuning value, shipped at 270 degrees to match the team mockup.
- Verified in a live session against a local server: a real copper vein drove the new meter through a full harvest pass, and 7 new automated tests pin the ring geometry alongside the existing 12 on the harvest math.
- Fixed gathering speed bonuses not applying to Meticulous Collection's bonus swings. The extra collection passes a high Meticulous Collection skill grants ran on a flat timer, so the skills, potions, and gear that speed up gathering did nothing for them and the bonus swings dragged compared to the first. Bonus passes now get the same speed bonus as the first pass; 4 new automated tests pin the timer math.
Scene analysis
- Ran the scene analysis bake across 10 more scenes picked for variety: the mountain city of Aerie, The Rise dungeon, the Graff Gem Mines, the Grunvald Shardfall, a swamp, an underground cavern, an island, the Spindelskog forest, the Isle of Storms, and a roadside siege encounter. The scene browser now carries 13 scenes with spawner levels, chests, merchants, quest givers, entry points, and load health for each; all 10 loaded with zero errors.
- Fixed a bake tool defect along the way: analyzing a chosen list of scenes rebuilt the browser index from only that list, dropping every scene baked earlier. A partial bake now folds the existing results back in, so the index always reflects everything baked so far.
- Followed up with a second batch of 20 scenes, taking the browser to 33: the towns of Kingsport, Etceter, and Valhold with its palace interior, the Owls Head sewers, the Despair and The Fall dungeons, the Etceter Crag Mines, the Verdantis Shardfall, the Crawl to Krul passage, the Kas ruins, the Necropolis forest, Superstition Canyon, Eastreach Gap, a volcanic field, Mariah Overlook, a kobold battle camp, a desert road encounter, the Tartarus PvP scene, and the Sequana Colossus. The 20 scenes baked and published in under four minutes.
- The batch produced its first real content finding: the Necropolis forest logs 16 physics errors on every load, from a flat quad mesh being used as a solid collider shape. The failure now shows in the scene's health panel in the browser instead of scrolling past in a console.
- Fixed a browser defect the new batch exposed: detail pages for scenes with spaces in their names (The Fall, The Rise, Graff Gem Mines, the sewers) refused to load, showing "Missing or invalid scene id". The page's id check did not allow spaces. Verified fixed on the live page, where The Fall now renders its full data set including live telemetry from the test shard.
- The first full test-suite run since the bulk mail work landed caught its one pending test disagreeing with the game by a single gold at exact tenth-of-a-pound package weights. The game's postage fee was correct; the test's copy of the formula rounded slightly differently near the boundary. The test now rounds exactly like the game does.
Server logging
- The log cluster's field-typing templates now carry version numbers, and the setup script refuses to overwrite a newer live template with an older file. Earlier this week a re-run from a stale copy silently reverted fresh field typing and three days of log indices rolled unusable for the dashboards; that class of mistake is now blocked at the script.
Developer tools
- Stopping the local development server no longer scatters a stray log folder into whatever directory the stop command happened to run from.
- Updated the Editor's assistant plugin to its current release.
- Committed a batch of routine Editor re-saves: five effect materials picked up current shader property lists, and the Chinese UI font shed a megabyte of stale baked glyph data its dynamic atlas regenerates at runtime anyway.
Images
2026-07-09 · 115 items
Headlines
- Harvesting became a game. Mining an ore vein, chopping a tree, foraging a plant, or skinning a carcass no longer means standing still while a bar fills: a needle sweeps a half-circle swing meter, and stopping it inside the gold wedge collects a bonus pull and re-arms a smaller, faster swing, chain after chain until a miss or the cap of 12. Skill still matters (gathering level widens the wedge, the meticulous skills slow its shrink), and ignoring the meter behaves exactly like the old harvest, so nothing was taken away from players who prefer to wait.
- Windmills now face the wind. The wind system always had a direction field, but the authored data kept it between zero and one degree in every weather type except storms, so every windmill top in the game pointed north. Wind now gets a real heading from the shared game clock: each map has its own prevailing wind that drifts around the full compass over an hour or two, gusts swing it harder in storms, every player sees the same direction, and windmill tops, ship flags, and wind turbines track it at a believable turn rate.
- A tester hub went live: a limited page for external testers with the launcher download, verification tasks, the player wish list, the balance audit, and server health. One checkbox on the accounts page now creates a tester account that works on the hub, the tracker, and in the game, and grants nothing else. By evening the hub gained a sortable tester leaderboard: every tester ranked by hours played on the Chaos shard, bugs reported, and tests completed, each with a last-7-days column and a running total, refreshed every 15 minutes. Late in the day a tester found the gap in it: bugs reported from inside the game earned no credit. Fixed the same evening; in-game reports now credit the reporter, and testers gained read access to the main bug project so they can find their own reports.
- Tavern games reached feature-complete for version one. On top of yesterday's playable chess, checkers, and backgammon: every window string is now translated into all seven supported languages, the three games ship as game-table furniture you can place in your house or tavern, and /roll was moved to the server so a dice result can no longer be faked by a modified client. The tables themselves wait on a server data refresh before they can be handed out on the test shard; /roll is live there now.
- The chaos launcher connects again, and the shard now runs the new networking stack end to end. The morning's legacy-stack retirement exposed that the launcher's update channel still carried a client built before the cutover, so every install hung at "Connecting..." while a healthy server sat unreachable. The channel now delivers build 30, a client and server built from the same commit, and the publishing tools and security checks enforce that pairing from now on: a mismatched client is refused at publish time and flagged by the nightly checks. A follow-up caught that build 30 also went out as a clean player build, which dropped the tester tools and the developer console; the publisher now enforces the right build flavor too, and build 31 shipped the same evening with the tools restored and verified in a live client session. The cutover also left the chat window filling with blank red "Server:" lines: the new stack marked every routine server reply with an empty debug note, and test builds print any note into chat. Replies without a note are silent again, and the fix rides the next build.
- Vendors on the Chaos shard sell again. Since the network cutover every vendor in every town showed an empty list: the search index that feeds the vendor window lost its data when the legacy virtual machine was retired, and the window trusted the healthy but empty answer instead of falling back to the game server. The indexer now runs on the new stack and was refilled with 286,993 listings, and the nightly security checks now catch an empty index before players do.
- The mirror flip key for house decorations works properly now. Garden gnomes mirror upright instead of flipping into the ground, and by end of day 1,245 more decorations accept the flip (statues, trophies, portraits, columns, snowmen, road pavers, city walls), every one cleared by an automated safety audit of all 6,524 decoration items. A player wish list item from the official forums.
- Mail can now go to several friends at once. Pick friends in the send-mail window and one send delivers to all of them: each attached stack is split evenly between the recipients, the leftover stays in your bag, and gold and postage are charged per recipient, with a preview of the exact split before anything sends. Limited to your friends list. A player wish list item from the official forums.
Harvesting
- Added a swing meter to resource gathering. Harvesting an ore vein, tree, plant, or carcass now shows a half-circle meter with a sweeping needle: press Space (or click) while the needle is inside the gold wedge to collect a bonus pull and start the next swing. Every hit grants one bonus, and each hit shrinks the wedge and speeds up the next sweep, so deep chains take real timing. A chain ends on a miss or at 12 hits.
- Skills feed the meter. Gathering level widens the target wedge and shortens the sweep, and the Meticulous Collection skills now slow how fast the wedge shrinks between hits instead of rolling a hidden continuation chance, so the same skills that used to mean more random bonuses now mean longer reachable chains.
- Missing never costs what you earned. A miss or no input on the first swing falls back to the old random bonus roll, so ignoring the meter gives exactly the old harvesting experience; a miss later in the chain ends it with all collected loot kept, and the missed swing itself pays nothing.
- The swing key is rebindable (Harvest Swing under Options, Space by default). Jumping and attacking are suspended while a swing is live so the same key and mouse button serve the meter, and moving still cancels a harvest exactly as before. Fishing, watering, and breakables are unchanged.
- A settings switch on the data side can restore the old wait-timer behavior instantly if testing turns up trouble. 12 new automated tests pin the meter math. Not on the test shard yet; it rides the next build.
Dev portal & tester hub
- Launched a tester hub: a small page for external testers with the game launcher download, their verification task list, the player wish list, the combat balance audit, and the server health view. A new tester account flag gates it; a tester reaches exactly those pages and nothing else behind the portal login.
- Tester onboarding is one checkbox on the accounts page. Ticking tester creates everything the person needs: hub access, a tracker login, and a playable game account. Unticking it shuts off the hub immediately and leaves the rest to their own checkboxes.
- Added tracker cards to the dev portal: the tracker itself, the open task list, the player wish list, and the new verification board.
- Stood up a Tester Verification board on the tracker: the team files an item for each change that needs a check on the test shard, a tester picks it up, tries it in the game, and posts the result as a comment. Testers see this board and the wish list; the main project stays private.
- Fixed a bug that would have blocked every tester from the tracker: accounts created through the accounts page were missing a name in the login directory, and the tracker rejects nameless users with an error page after sign-in. New accounts get names automatically now, and the 9 existing directory users were repaired the same way.
- Extended the pre-deploy security checks to cover the new pages and re-ran the full suite: green, with anonymous visitors still locked out of every gated page.
- Made verification tasks part of the definition of done: every change a tester could exercise now gets a task filed on the verification board in the same working session, with a fixed template covering what changed in player terms, the build that carries it, numbered test steps, an expected-results checklist, and edge cases worth trying to break.
- Added a leaderboard to the tester hub, above the buttons: every tester listed with hours on the Chaos shard, bugs reported, and tests completed, each as a last-7-days column plus a running total, sortable by any column. It started the day as four aggregate tiles and grew into rankings by evening. A collector on the web box refreshes it every 15 minutes from the account directory, the game's own per-account play time counter, and the verification board.
- Made the hours column count Chaos play only. The game's play time counter is a lifetime value, and accounts imported from the live-game data snapshot arrived with thousands of live hours on it, so the collector now keeps its own sample history and shows the growth since tracking began rather than the raw counter. A data reseed that rewinds the counter resets that tester's history cleanly.
- Bug and completed-test credits come from the tracker: a bug counts for whoever filed it, and a completed test counts for the testers who posted results on it before the team closed it.
- A tester caught the leaderboard missing credit for bugs reported from inside the game. Those reports are filed by an automation account into the private bug project, so the board's whoever-filed-it rule never matched a tester. The in-game reporter now looks up the reporting account's game name and stamps it on the issue in a new Reported by field, and the leaderboard counts that field first, so a bug reported from the game credits the right tester. The tester's three existing reports were credited retroactively, verified end to end with a fresh in-game report, and the board caption now says bugs reported in the game or on the board both count.
- Tightened web access to two tiers: the dev portal is now admin only, and testers see exactly the tester hub, server health, and the balance audit. The old catch-all access group that every new account used to receive is retired and was stripped from all accounts.
- Flagging an account as Admin on the accounts page now carries web access with it: one checkbox grants the portal, the tester hub, and membership on the main tracker project, and unflagging takes them away again. Tracker membership reconciles automatically every 15 minutes.
- New accounts with tracker access get their tracker account created at creation time instead of on their first sign-in, so a new tester or admin can be handed working links immediately.
- The Tester Verification button on the hub and the dev portal now shows how many verification tasks are open, so a tester can see at a glance whether there is work waiting. The count refreshes with the leaderboard every 15 minutes.
- Added an "Open links in a new window" checkbox to the hub and the dev portal. The choice is remembered per machine in the browser and applies to every button on the page.
- A tester reported the expected-results checkboxes on verification tasks cannot be ticked; the tracker only lets a task's author edit them. All 32 open tasks now ask testers to copy the checklist into their comment with PASS or FAIL on each line, and new tasks use that format from the start. The board-games task also got corrected steps to match what the current test build can exercise.
Tracker
- Added one-click Close and In Progress buttons to every tracker issue page, next to Edit. Close asks for an optional note first and files it as a comment on the issue; In Progress also assigns the issue to whoever clicked it, when nobody owns it yet.
- The buttons follow the same permissions as a manual edit: someone without the right to make a status change does not see them, and the button for the status the issue is already in stays hidden.
- Packaged the tracker theme install as a one-command server recipe so the styling and the new buttons survive container updates.
- Opened the buttons up to testers on the verification board: taking a task marks it In Progress and assigns it to them, and closing it asks for the result note. Testers get exactly those two moves and only on that board; the wish list and the main project are unchanged.
- Testers can now read the main bug project. A new read-and-comment role, granted automatically to every tester account, lets a tester find the bug they reported from the game, check whether something is already known before re-reporting it, and answer follow-up questions from the team. It covers ordinary issues only; anything marked private stays hidden, so sensitive reports go in as private issues from now on.
Tavern games
- Made /roll server-authoritative. The command used to roll on your own machine and announce the number, which a modified client could fake; the roll now happens on the server with its own random generator and is broadcast to everyone nearby, so a wagered roll can be trusted. The chat wording and range are unchanged for players, single-player offline keeps working, and the change is additive so it deploys without breaking older clients.
- Translated the game window into German, Spanish, French, Italian, Portuguese, Russian, and Simplified Chinese, reusing each language's existing terms for the game names and actions. No more English-only board games.
- Added three placeable game tables as furniture: a wooden table with the board on top for chess, checkers, and backgammon. Place one like any decoration, interact to open the board, and the game is bound to that specific table so two tables on a lot never mix up their games. Player-placed tables are for playing each other; computer opponents arrive later with the fixed tavern tables.
- Learned, and wrote down, why the editor kept blocking a tool script mid-run: the game guards against deleting item templates because that would orphan references in saved games, and it enforces it with a popup. A brand-new template nobody owns yet is safe to remove, but the guard does not make that distinction, so the tooling now updates templates in place and never deletes.
- Tried to hand the new game tables to testers on the test shard and found they cannot exist there yet: the server's item data snapshot is two days older than the tables, so the server refuses to create them even though the code shipped. A data refresh is prepared and rides the next server update. The tester task now separates what is testable today (the server-rolled /roll command) from what waits on the refresh.
Vendors
- Fixed vendors showing no entries in every scene on the Chaos shard. The vendor window is fed by a search index, and the indexer that keeps it current (VendorSync) ran inside the retired legacy virtual machine: when that machine's game database was wiped ahead of the reseed, the indexer's reconciliation emptied the index to match, and the machine's retirement the next day killed the indexer itself. Rebuilt the pipeline on the new stack, refilled the index with 286,993 listings in 39 seconds, and verified a new listing becomes searchable within 4 seconds and a removed one disappears as fast.
- The vendor window only falls back to asking the game server when the search service errors, so a healthy but empty index looked like a world with no vendor stock while every status light stayed green. The pre-deploy security checks now fail when the index is empty while the game database holds listings, and warn when the indexer service is not running.
- Public vendor listings on the Chaos shard now last 30 days. The deployed rules still carried a 20-minute development value, and a background sweep was deleting every public vendor listing 20 minutes after it was created, including everything a data reseed restores (the items go back to their owners by mail). Player vendors were never affected by this one.
- Added multi-recipient mail from the player wish list: select several friends in the send-mail window (Ctrl or Shift click), attach item stacks and gold as usual, and one send delivers to everyone. Each stack is split evenly between the recipients and the remainder stays with the sender; enclosed gold and postage are charged per recipient. A confirmation shows the exact per-recipient split and total cost before anything sends.
- Recipients are limited to mutual friends and capped at 20 per send, and the server checks every recipient before anything moves: one full mailbox or ended friendship cancels the whole send, and the window names which recipient blocked it. A stack too small to give every recipient at least one is rejected up front, which also covers single unstackable items.
- Not on the test shard yet; it rides the next build. The stack-splitting and postage rules are pure shared logic covered by 17 automated editor tests.
Test server
- Investigated the test server showing 93% memory used and found three causes: the retired legacy stack's virtual machine still held its full 32 GB reservation, the new stack's database cache had swelled to 37 GB during Tuesday's data reseed (the dataset itself is 15 GB) and never returns memory on its own, and the host's file cache had no ceiling either.
- Shut the legacy virtual machine down and halved its allocation for any future revival. Its game data had already been wiped for the reseed and nothing had connected to it since, so the old stack going dark is intentional and reversible in about a minute.
- Put hard ceilings on the database cache and the file cache, and wrote the caps into the bring-up script and runbooks so future setups inherit them. Memory settled at 33% used, all 8.8 million database records verified intact, and a full login test against the new stack passed afterward.
Server health page
- Investigated the health page's two yellow tiles and traced both to the legacy stack's retirement. The inter-server drop counter was counting seven orphaned worker processes left behind by Tuesday's shutdown, still retrying their stopped master every two seconds, and the unreachable game port was that stopped master's login listener. Neither reflected the serving stack, which was healthy the whole time.
- Re-pointed the page at the all-Linux cluster it should have been watching. The old virtual-machine tiles are gone, a new cluster group checks that all seven server processes are running and their client listeners are bound, and the outside-in reachability probe now speaks the new stack's protocol family instead of testing retired ports.
- Discovered the new stack had never shipped a log line to the on-box search cluster: its logging config still pointed at an unreachable address from the old office network. Repointed it (a hot reload, no restart), which restored the error-rate, drop-counter, and player-count tiles and lit up the server metrics dashboard for the serving stack for the first time. The deploy script now applies the repoint automatically and refuses to start if it ever regresses.
- Broadened the dropped-connection detector so it recognizes both the legacy stack's error format and the new stack's, and updated the security posture checks for a world without the virtual machine: its checks now skip cleanly, and any leftover forwarding rule from the old setup gets flagged for review instead of silently allowed.
- Verified the result end to end: every tile green on live data, log and metric streams flowing, and a credentialed login test against the shard passing from the outside. The whole change shipped without restarting the game cluster.
Weather & windmills
- Gave the wind a real direction. Windmill houses and windmill decorations were already wired to turn their tops toward the wind, but the authored wind direction data sat between zero and one degree for every weather type except storms, so every windmill in the game pointed north. Direction is now computed from the game clock: each map gets its own prevailing heading, the heading drifts around the full compass over an hour or two, and gusts swing it harder in heavy wind and storms.
- Every player sees the same wind. The old path rolled the direction per machine; the new one derives it from the shared game clock and the map name, so two players watching the same windmill see the same heading with no network traffic added. Trees, drifting clouds, and blowing particles read the same value, so the whole scene agrees on which way the wind blows.
- Windmill tops now swing at a capped turn rate instead of snapping to the new heading every frame, and the rate no longer varies with frame rate. Ship flags on the galleon houses, air balloon teleporters, and the other wind-facing props pick the direction up through the same component.
- Stopped windmill tops turning inside the store and inventory item preview window, where the constant re-aim fought the mouse rotation. Blades still spin in the preview, and placing a windmill in the world still aims it into the wind.
- Six new automated tests pin the wind model: identical inputs give identical headings, the turn rate stays under a documented bound (including with a server clock millions of game hours past epoch), the full compass is covered over time, different maps get different prevailing winds, and gust strength scales as intended. Full suite green after the change, 575 for 575, plus a live check in the editor watching the heading drift smoothly with the wind zone tracking it exactly.
Dev tooling
- Built a reservation system so multiple AI coding sessions on one machine stop colliding in the Unity Editor. Every session drives the same editor; the first to touch it now holds a short lease, later arrivals wait up to two minutes and are then told to come back, and the lease frees itself after ten idle minutes, on session exit, or by hand.
- The guard runs as a hook in front of every editor call and fails open: if anything in the lock machinery breaks, the call goes through and the problem is logged, so a bug in the guard can never block editor access. A 23-check test suite covers acquisition races (20 simultaneous claimers, exactly one winner), stale-lease takeover, and corrupt-state recovery.
- Verified it live: a second session's editor call waited, then received the reserved message naming the holder and its idle time, and a fresh session acquired, renewed, and auto-released the lease when it exited.
- Taught the test bot to deliver items by in-game mail: a new command logs in with a staff account, looks the recipient up by character name, and has the server compose the mail, so test items can reach tester mailboxes without cutting a new build.
Work blog
- This work log now has an RSS feed at /blog/feed.xml, backfilled with the full history. Every work item is its own feed entry, titled by its area, and each day also carries a headlines digest entry and an entry per screenshot gallery.
- The feed rebuilds automatically on every publish and every blog page links it from the header, so subscribing in any feed reader keeps up with new work without visiting the page.
In-game tester tools
- Locked the in-game developer console behind the game-admin account flag. On test builds it used to open for any player who pressed the tilde key; now only admin-flagged accounts can open it, it closes itself if the flag goes away mid-session, and single-player offline mode still allows it since nothing there leaves the local machine. The /gm window already checked the same flag, so the two developer surfaces now match.
- Added a /tester chat command for tester accounts. It opens a window with the essentials for exercising a build: jump to any zone by name with type-ahead suggestions, set every skill to a chosen level or a single skill through a picker, duplicate whatever items are selected in an open inventory window, and open the verification task board in the browser.
- Tester access in the game rides the same account flag the accounts page already creates: the one tester checkbox that grants the hub and tracker now also unlocks /tester on the player's next login, and unticking it takes the window away again.
- The server checks the tester flag again on its own side before honoring the item duplication, so the window is a convenience, not the permission.
- Nine new automated tests pin the access rules (who can open the console, /gm, and /tester), the exact flag value the login system writes, and the window's wiring; the full suite stays green.
Deco placement
- Fixed the placement-mode mirror flip key for a player wish list request. The true mirror path had never been wired to a single item, so the few flippable decorations fell back to a rotation that tipped floor items upside down; garden gnomes buried head-first were the reported case. Gnomes now mirror upright, with details like the lantern swapping hands.
- Enabled the mirror flip on 120 more decorations: statues, trophies, ancient portraits, classic columns, snowmen, and housewares. Symmetric pieces show little change; the asymmetric ones players asked for can finally face the other way.
- Every enabled item passed an automated safety audit of all 6,524 decoration items: static meshes only, collision shapes outside the mirrored part, visual roots centered on the mirror plane, no animated or interactive pieces. Items that used the old rotation flip on purpose (the upside-down painting, weapons crossed on walls) keep their behavior exactly.
- The audit ships as an editor tool with a CSV report and an apply mode, and a new automated test locks every flippable item to a valid mirror setup so future items cannot ship half-configured. The roughly 3,600 uncategorized decoration items wait for a follow-up batch after this one soaks on the test shard.
- The follow-up batch landed the same day: the remaining 1,125 audit-approved decorations (the uncategorized pile plus road pavers, city walls, and building blocks) are now flippable too, bringing the total to 1,250. The reaper statue mirrors its scythe to the other side, which is the exact statue example the original forum request asked for. Fixed a tool bug along the way where the bulk pass added the mirror markers but forgot to set the flip permission itself.
- What is left is the roughly 1,750 decorations the audit flagged for per-item work before they can mirror safely: meshes on the item root, collision shapes inside the mirrored part, or visual roots sitting off the mirror plane.
Deco lights
- Fixed placed home lights (torches, lanterns, lampposts, candles) going dark even when set to stay lit. Yesterday's decoration culling pass hides distant decorations to speed up dense towns, and hiding a decoration also switched off the light it carries: a lantern went dark about 40 meters out, close enough to notice from your own yard, and the culling ignored a light's own never-fade setting. Testers reported it within a day.
- Decorations that carry a light are now left out of that culling entirely, so their lights keep the same fade distances they had before the performance pass; everything unlit is still culled for the performance win. A new automated test pins the exclusion. The fix rides the next Chaos build.
Inventory & vendors
- Moving a multi-selected batch of items into a chest that cannot hold them all now stores what fits and hands back only the overflow, with a message counting how many items came back. Before, a single item that did not fit made the game refuse the entire drop. A player wish list request from the official forums.
- Items that combine into a stack the chest already holds never needed a free slot, so a full chest now accepts a drop of resources it already stores and merges them in; only items needing their own slot come back.
- Dragging a batch onto an NPC merchant's sell window now carts the sellable items and skips the rest (locked, untradeable, or worthless pieces), with a chat note counting what was left out. One bad item no longer cancels the whole sale.
- Trades, mail attachments, and equipping from a drop keep the old all-or-nothing behavior on purpose, since those flows track the whole set after the move. New automated tests pin the container-capacity rules the change relies on, and the full editor test suite stays green.
Player wish list
- Pets can now be told to stop using stun attacks, a player wish list ask from the official forums. A pet spamming weak stuns builds up the target's crowd control resistance, which made a group member's long stun fail to land. A new right-click option on a tamed or summoned pet, Stop Using Stun Attacks, makes the pet skip attacks that stun or knock down while keeping its normal attacks; the chat commands /pet nostuns and /pet usestuns do the same.
- The pet stun choice is saved per pet and survives resummoning and relogging. The menu entry only appears on pets that actually have a stunning attack: earth elementals and golems (the earthquake slam) and charging boars qualify, while a plain wolf turns out to have no stun at all, only a slowing bite, so wolves show no entry. The menu strings and chat feedback shipped in all seven supported languages.
- Added Tier and Episode columns to the teleport scroll's Select Destination window, a player wish list ask from the official forums. Tier now shows the zone difficulty on its own ("5", "5+") in the same color coding as the summary text, and Episode shows EP-1 or EP-2 so groups can pick zones everyone can enter. The Episode entry turns orange when the account does not own Episode 2.
- Clicking the new Tier column header sorts zones by difficulty; the plain text sort would have put tier 10 ahead of tier 2. German translations for the new labels shipped with the change, and the other languages show English until the next translation pass.
- Rescanned the Wishlist Requests forum against the curated wish list. Five days on from the last sweep, so the yield was small: added two housing and placement asks (garden bowers as wall decoration surfaces, and decoy doors for player dungeons) to the tracker, and refreshed several existing entries with current reply and view counts and new developer replies.
- Fixed ESC dismounting the rider while UI windows were open, a wish list ask from the official forums. ESC now closes open windows and dialogs first; pressing it again with nothing left to close dismounts as before. Binding a dedicated dismount key still disables ESC dismounting entirely.
Compass
- Made the compass direction letters readable under markers, a player wish list ask from the official forums. The letters are part of the compass strip artwork and every point of interest icon drew on top of them, so in a town full of vendors or with several quests running the cardinal letters disappeared. A gold copy of the letters and tick marks now draws above all markers; markers stay visible around the glyphs since everything outside the letters is transparent.
- Press and hold on the compass still brings the classic white strip with its dark backing to the front; the gold letters step aside while it is held so nothing draws twice.
- Added a Show POI Markers on Compass option, on by default. Turning it off hides discovered location, vendor, and lot markers on the compass for a clean strip. Task, destination, and resurrection markers always stay visible: quest markers already have their own toggle, destinations are somewhere the player explicitly asked to go, and a dead player needs to find an ankh. The map is unaffected.
- The option label and tooltip ship translated into all seven supported languages, and nine new automated tests pin the setup: the letter overlay exists and stays wired, its color stays distinct from every marker color, press-to-front keeps hiding the overlay, and the option keeps its default and its saved-setting name.
Localization pipeline
- Found and documented a trap in the translation deploy while shipping the compass option strings: the shipped Spanish and Italian text packs contain translations that are missing from the translation database, so regenerating those two languages would silently strip live text from the game. The deploy for this change ran per language on the five languages that are in sync, and the pipeline docs now warn that Spanish and Italian need a database back-fill before their packs can be regenerated.
Build pipeline
- Client builds now pull the latest code before compiling, matching the step the server build already ran. This closes a gap where a build kicked off after new commits could compile slightly out-of-date source; a safety check that refuses stale source had already caught the case and stopped the build.
- Repaired the nightly job that regenerates the town and scene data a server deploy ships. A packaging change last week broke its final cleanup step, so it failed every night and deploys fell back to older data. The check now allows for the new layout and the job completes, keeping that data current.
Scene analysis
- Built a Scene Analysis browser for the dev portal: one page with a generated thumbnail card for each adventure and story scene (291 qualify; player towns and player dungeons are excluded), each card opening a detailed analysis page for that scene.
- An editor tool walks the scenes and bakes the data: spawner count with average, median, and highest level, chest and merchant counts, quest givers and quest steps drawn from the quest tooling, every player entry point with a screenshot rendered from that exact spot at eye height, a card thumbnail, and a lighting summary with the time of day forced to noon.
- Every scene also gets a clean-load test: errors and warnings the scene produces while loading are captured, de-duplicated with counts, listed on the detail page, and rolled up into a green, yellow, or red badge on the scene's card.
- The detail page joins in two weeks of play data from the test shard: gold earned per player hour, average frame rate by player, zone load times, and visit counts. Two new measurements feed it: the server now records each scene's player count once a minute, and the client reports its frame rate once a minute while in a scene. Panels show a collecting-data note until those accrue; gold totals and zone load times populate from data the game already recorded.
- Three pilot scenes are live now: Soltown (91 spawners, 19 quest givers), the Soltown Catacombs, and Vertas Pass (123 spawners, average level 55). The full sweep across all 291 scenes runs next; scenes appear on the page as they are baked.
- Along the way, fixed the scene tool reading zone-in points from the wrong marker type (towns use the base spawn marker, not the subclass) and matched conversations through the NPC's conversation component because prefab file names do not match conversation names.
- Reworked the screenshot capture after the first pass came out flat, shadowless, and uniformly bright. Captures now render through the game's own camera rig with its post-processing stack, and the weather system that drives the game's authored lighting curves is initialized at the forced noon hour instead of bypassed. The three pilot scenes were re-baked: daylight, cast shadows, and tone now match what a player sees in the game.
Chaos shard deploy
- Diagnosed the chaos launcher's game client hanging at "Connecting...": the update channel was still serving a client built four days before the networking cutover, dialing a connection path retired that morning, while the new server stack sat healthy the whole time. Watching the server's network traffic live confirmed the stuck client knocking on the old door with nothing answering.
- Published build 30 to the update channel: the first launcher-delivered client on the new networking stack, built from the same commit as the server cluster it talks to. It is a large download because the build also moves the client to the precompiled runtime used for shipping.
- Redeployed the server cluster from that same commit, which brings this week's gameplay changes (partial chest drops, merchant batch selling, the tavern game tables, scene telemetry) to testers. Verified with a credentialed login test from outside and clean server logs after the restart.
- The server redeploy hit a build breakage first: the new table-game files compiled in the main server build but were missing from the new stack's build list. The existing drift checker named the 12 missing files and the list is fixed; the nightly gate that watches for exactly this now covers the new feature.
- Made the one-version rule mechanical. The publisher refuses to put a pre-cutover client on the chaos channel, the security preflight fails if the live channel ever serves one, and it warns when the channel's client and the deployed server come from different commits. All three checks were verified against the bad state (they fire) and the fixed state (they pass).
- Commented the build number on the seven waiting verification tasks and filed a new task covering the launcher update and login.
- Traced a report that a developer account could not open the developer console on build 30, while the GM tools worked fine for the same account. The account and its permissions were never the problem: build 30 went out as a clean player build, a flavor that leaves out the developer console, the tester tools window, and the test-automation hook at compile time, while the GM tools ship in every build behind a runtime permission check. The shard's intended flavor keeps those tools in and relies on the runtime checks added this week to keep them locked to the right accounts.
- Closed the gap the same way as the one-version rule: the publisher now refuses a clean player build on the chaos channel (with a deliberate override for knowingly trialing one), and the security preflight warns when the live channel serves a build without the tester surface. Both were verified to fire on the bad flavor and pass on the right one.
- Published build 31 the same evening: the same game as build 30 with the tester and developer tools compiled back in, client and server from one commit. Before it shipped, the artifact passed the networking self-test (7 of 7 checks) and a scan proving the tool code is present. After the channel switched over, the full security preflight came back green (52 checks, none failed), a credentialed login test passed, and a scripted client session on the shard confirmed the GM tools and the tester window open for a developer account.
Server networking (Photon replacement)
- Fixed the chat window filling with blank red "Server:" lines on the test shard. Test builds print any server reply's debug note into chat, and the new networking stack attached an empty note to every routine reply where the old stack sent none, so most actions produced a blank line. An absent note now stays absent end to end, and the chat echo skips blank text as a second guard. Real warnings still print.
- Four new automated tests pin the reply format's debug-note round trip (absent, empty, and real text), and the networking suites stay green, including the live check against the new server runtime. The fix reaches testers with the next chaos build.
Legacy servers
- Fixed the old QA shard's admin console, which had refused to connect since July 5. Its message and MotD pages talk to a logging service on a separate machine, and that service had shut itself down: a periodic check it makes over a secure connection stopped working with the machine's outdated settings, so the service exited about a second after every start. Enabled current TLS settings on that machine and started the service; the console's QA pages load again, verified end to end.
- Set the service to restart itself automatically if it stops again, and wrote the diagnosis and the fix recipe into the server reference docs, with a warning that the remaining legacy machines need the same settings before their next restart.
- Documented a separate long-standing rule found during the diagnosis: the console's command pages reject one class of sign-in by design on every environment, which is easy to mistake for the same outage. The message pages are unaffected.
Crafting
- Fixed the Only craftable checkbox at crafting stations never showing its check mark. The filter itself worked, but the check mark graphic was saved disabled inside the window layout, and the toggle only fades that graphic in and out, so the box always looked unticked. Reported by a tester on the verification board; the fix rides the next Chaos build.
- A new automated test now checks the window layout keeps the check mark wired and enabled, so it cannot ship that way again.
Images
2026-07-08 · 34 items
Headlines
- Tavern games went from idea to playable in one day. Research across other online games settled the design in the morning: server-enforced chess, checkers, and backgammon, free to play, with computer opponents. By night the whole system was built and the first real games ran end to end in the client against the real server: a 44-move checkers game, a chess game ending in checkmate, and a backgammon gammon, every move validated server-side. Screenshots below.
- The Monty Python coconut gallop is back. Equipping a coconut half in each hand once made your avatar ride an invisible steed; the 2020 mounts feature disconnected that code path and the emote had been dead in towns ever since. Held coconuts now ride the mount system's own coconut animations, and real mounts are untouched.
- Kicked off the city performance pass. Player towns are CPU-bound on the sheer count of small placed decorations, and a code investigation pinned the causes: distant decorations never dropped from rendering, redundant per-frame work in the culling and mouse-targeting systems, and draw batching switched off entirely in the shipping client. Measurement tooling landed first, so every coming fix ships with before and after numbers.
- The first measured baseline settled the biggest question in one day: with 3,000 real decorations in a controlled benchmark scene, about 95% of the decoration frame cost is the main thread submitting thousands of individual draw calls. Script overhead is under a millisecond, and the graphics card itself sits idle waiting. The fix priorities are now proven, not guessed: stop rendering far-away decorations, and let identical items share draw calls.
- Yesterday's build of the new-networking test client shipped unable to connect, and the cause was embarrassingly simple: the build machine's source tree was one commit behind, missing the change that bakes the connection settings into the client. The build tools now check for that before starting: a build from a tree that is missing pushed commits fails outright on the build farm and asks for confirmation in the editor, instead of silently spending hours producing a dud.
- Refreshed the networking test shard from a current, sanitized snapshot of live player data and ran the outstanding data migrations against it, so the new stack now runs against realistic world, item, and economy state. Database changes also gained a standing rule: log the needed migration in the same commit, enforced by a new check.
Tavern games
- Researched how other online games do in-world parlor games before designing ours: Ultima Online's freeform boards (loved as decor, unplayable competitively), Final Fantasy XIV's Gold Saucer, Elder Scrolls Online's card game, Red Dead's poker and its country-by-country blocks, and Puzzle Pirates' server-dealt tables. The published court rulings on virtual-chip gambling shaped the biggest call: version one has no wagering of any kind.
- Wrote the implementation plan and added the epic to the roadmap: chess, checkers, and backgammon first, at game tables placeable on player lots and fixed in NPC taverns with a computer opponent, unranked and free, spectators supported. The server validates every move, turn, and outcome; the client is only a view. Card games and any stakes system are designed-for seams, deliberately deferred.
- Landed the wire contract and the first plumbing: a new table-games operation set on the game server (join, sit, ready, move, concede, draw, rematch, spectate, reset, add a computer opponent), the session state machine and complete checkers rules in the shared code both client and server compile, and the client-side manager that mirrors table state. Sessions key to the table object itself, so two players walking to the same table land in the same game.
- The rules layer sends each seat its own filtered view of the game from day one. For chess and checkers every view is identical, but the pipeline shape is what later lets poker deal hidden hole cards without changing the protocol.
- All three rules engines shipped complete with 85 automated tests: chess passes the standard move-generation reference counts through four levels deep (197,281 positions from the opening) plus castling, en passant, promotion, the fifty-move rule, and threefold repetition; checkers enforces mandatory captures and multi-jump chains; backgammon enforces the forced-play and higher-die rules with server-rolled dice. Each game also has a computer opponent with three difficulty levels, and a bad or buggy submission cannot corrupt a game: the server rejects anything that is not in its own list of legal moves.
- Played the first real games in the client tonight against a local run of the real server: joined a table in the world, summoned a computer opponent, and played checkers (44 moves), chess (checkmate in 24), and backgammon (lost by a gammon, 48 turns) to completion, with rematches swapping who moves first. The game window handles seats, ready-up, turn indicators, draw offers, concede, rematch, and spectators.
- Sessions survive the messy cases by design: disconnecting mid-game reserves your seat for three minutes before it counts as abandonment, walking away from the table does not forfeit, and closing the window mid-game just hides it. A test-harness verb can drive whole games from scripts, which is how tonight's games were played.
Images
Server networking (Photon replacement)
- Diagnosed why the freshly built test client could not connect: the build machine's tree was one commit behind the push that bakes the new-stack connection settings, so the client dialed the old stack's port with no server identity key and failed closed. The client's own log told the whole story in two lines.
- Added a staleness gate to the chaos build tools: before any build starts, the tree is checked against the pushed branch; a tree missing pushed commits fails the build on the farm (with an explicit override switch for deliberate cases) and asks first in the editor. Trees that are ahead for local experiments still build, and offline builds still work when the check cannot reach the server.
- A corrected build is running from the updated tree; it gets verified end to end (bare launch, login, world entry) before it goes anywhere near the patch channel.
Client performance
- Investigated why player-town scenes are CPU-bound. The decoration objects themselves are cheap; the cost lives around them: no system that stops rendering far-away decorations, the culling manager re-reading positions of objects that never move, the mouse-targeting ray tested against the whole decoration collider soup every frame (even with the cursor parked over a window), and the shaders and most materials ready for GPU instancing that nothing ever enables.
- Wrote the phased fix plan: measurement first, then the low-risk fixes, each gated on captured numbers. One finding reshaped it: the rule that keeps a player town's central plot always loaded is load-bearing (its items are what spawn every claimed lot), so the eventual "do not even create far-away town decorations" change is designed but deferred until the cheaper fixes show what headroom is left.
- Landed the measurement kit: timing markers through the decoration load and culling path, a capture recorder that logs frame-time and engine-subsystem percentiles for before/after comparisons, an audit tool that inventories every decoration prefab (which animation scripts it carries, which materials cannot batch), and a builder that generates a repeatable synthetic benchmark town from real decoration prefabs, no server needed.
- Audited all 6,209 unique decoration prefabs. It corrected an assumption: animated decorations are rare (158 animation scripts total, mostly moondials and windmills), so the planned per-object animation work moved down the list. The real weight is elsewhere: 46,621 colliders across the prefab set, 7,319 particle systems, and 626 prefabs carrying materials with GPU instancing switched off.
- Captured the first baseline: 3,000 decorations in the benchmark scene cost 27.9 ms per frame, and 26.6 ms of that is the main thread pushing roughly 6,500 draw batches. A one-decoration control scene isolated the number, and a graphics-wait probe confirmed the GPU is not the bottleneck. Two harness defects were fixed on the way (a stats recorder that was created but never started, and game-logic scripts on benchmark decorations throwing without the game's bootstrap).
- The benchmark scene itself: a seeded grid of three thousand real decorations, from dragon trophies to potted palms, built in one click and identical on every run.
- First fix landed: deleted twelve empty per-frame Update methods left over from script templates. The engine pays a native-to-managed call for every declared Update even when the body is empty, and these rode common objects like nameplate status panels and vendor shout triggers.
- The culling system now knows that placed decorations do not move. It re-read the position and bounds of every registered object every frame to keep its spheres current; objects flagged static (decorations, houses) are skipped, a slow five-second sweep self-heals anything mis-flagged, and dragging a decoration flips it back to dynamic until placement finishes. The sweep also stopped re-scanning the same list multiple times within one frame.
- Mouse targeting stopped paying for a full-scene ray test every frame. The ray only re-runs when the cursor or camera actually moved (or on a short tunable interval so objects moving under a parked cursor still update), and it skips entirely while the cursor sits over a window. Hover feel is unchanged: any movement re-tests the same frame.
- Nameplates that faded out at distance now re-check only a few times a second instead of every frame, spread across frames so crowds of vendor plates do not check in lockstep, with a small hysteresis so a plate at the exact fade boundary cannot flicker.
- Creating a placed decoration used to walk its object hierarchy about fifteen separate times looking for different component types; it now walks it twice (the game can modify the hierarchy midway through setup, so once is not safe). Eight new tests pin the replacement to the exact old semantics, including two obscure engine rules the rewrite had to reproduce. The full editor test suite passes, 410 for 410. This trims the per-item cost of streaming a lot’s decorations in.
- The big one landed: placed decorations now stop rendering at distance. Every placed item registers one bounding sphere with a new dedicated culling system; small furniture stops drawing past 40 m, larger pieces at 75 or 120 m, and only structures render out to 200 m, with all distances live-tunable and a kill switch. Only the rendering is culled: colliders, interactions, and server updates keep working on a hidden item, and landmarks players steer by (lot markers, buildings, vendors, teleporters, pets) never hide. Eleven new tests pin the bookkeeping; the before/after capture on the benchmark scene is next.
- Measured the culling on the benchmark scene, and the honest result is a modest win there: draw batches dropped about 7% on a wide 380 m layout and frame time about 3%. The reason is instructive: many prefabs carry the engine's own screen-size level-of-detail culling, which already stops drawing far small items in a synthetic overhead view. The real test is a live player town at eye level, where most placed items have no such setup; that capture runs once the next test-shard build carries the new recorder. The measurement session also hardened the benchmark tooling against duplicated automation calls that could half-wire a scene.
- Switched on GPU instancing for 496 decoration materials that supported it but never opted in (about 3,900 sibling materials already had it). A new editor tool found them through the decoration catalog, checked each shader actually compiles instancing support, and flipped exactly one line per material file. Measured on the dense benchmark view: 13% fewer draw batches and 12% less main-thread render time, about 3 ms a frame back. Dyed items keep their colors; the shader family stores dye per instance.
Gameplay fixes
- Restored the coconut gallop emote. Holding a coconut half in each hand is meant to play the pretend-horse gallop everywhere; the September 2020 mounts change removed the code that put coconut holders into the pretend-mount state and repurposed that state for real mounts, so the emote only survived on the overworld map. Held coconuts now enter the mount state through the mount system's coconut animation set, which shipped with mounts but was only reachable from the summonable coconut mount item.
- Tightened a mount-era animator ejection so it cannot kick a coconut holder out of the overworld gallop during scene transitions, and taught the mount state to handle a rider with no mount item: movement unlocks immediately and the horse-sized collision volume stays off.
- Added editor tests that pin the coconut animator wiring in both player animator controllers: the coconut dispatch in the mount hub, the overworld gallop entries, and the ejection guard's coconut exemption. Verified the full flow by simulating the animator in the editor: equip, idle, gallop while moving, and clean dismount back to normal locomotion.
- Wrote up a test-runner quirk found during the coconut work: the editor test tool's class and method filters can miss fixtures whose tests are all parameterized. The test docs now carry the workarounds, running by namespace or invoking the fixture directly.
Database and test data
- Refreshed the networking test shard with a current, sanitized copy of live player data, so the new stack gets exercised against realistic world, item, and economy state instead of a handful of test accounts. Payment records, credential caches, and last-login IPs are stripped before the data leaves the source and re-checked on the target.
- Brought that older snapshot up to the current build by running two data migrations against it: the gold-crown normalization that lets crown stacks from every source merge again, and the pet-bag cleanup that clears orphaned entries able to bloat a character's pet list.
- Tightened the process behind those migrations. Any change to a database record, collection, index, or data backfill now has to add an entry to the migration log in the same commit, and a new check flags a database change that ships without one. That log is what tells you which migrations an older data snapshot needs.
- Wrote up the whole test-shard reseed and migration procedure in the ops runbook, including the parts that fought back this time, so the next refresh is a recipe rather than a re-derivation.
Images
2026-07-07 · 71 items
Headlines
- The Photon replacement crossed its biggest line yet: the entire game backend ran on the new networking stack for the first time, every service up as its own process against real game data, registering with each other over the new authenticated internal links. The automated test bot then passed its full conformance suite against it, all forty-seven modes, zero failures: logins, characters, gameplay, banking, mail, vendors, crafting, chat, parties, guilds, trade, duels, and matchmaking, end to end over the new wire.
- The replacement stack then went live on the test shard's server: the whole seven-service backend running natively on Linux beside the still-serving current stack. By evening a real player was in the world on it, from a home internet connection with a normal account login. Character creation, the tutorial with quests advancing, and a zone change into Brittany, over twenty minutes of play on the new wire with zero server errors. The test build is now turnkey, so invited testers just run the game.
- An experimental Ultima mode went into the client: flip one developer toggle and the whole game renders with flattened banded lighting, ink outlines, and posterized painterly color, in the spirit of the classic Ultima games. The shader review behind it also fixed a years-old lighting bug on batched scenery and cut thousands of dead shader variants.
- Then the deeper check passed too: the new stack's traffic was recorded and compared message by message against the reference captures of the current stack. Thirteen test modes match byte for byte, and every other difference traced to message ordering or already-known multi-bot timing, none to message content. The two stacks say the same things on the wire.
- An endurance soak then earned its keep: repeated full-suite runs against one long-lived cluster surfaced a defect no single run could, a rare thread race that silently killed a server-to-server link while it still looked healthy. It was hunted down live (thread dumps, per-message logging, a twenty-run reproduction with a perfect correlation), fixed the same day, and verified with the same three-cycle endurance test that first exposed it: 144 suite modes and 18 targeted probes, zero failures on the cluster that previously sickened by cycle three.
- Then the real game client joined the backend on the new stack. A normal Windows client, built with one flag flipped, logged into the local server cluster over the new networking, created a character, loaded into a rendered scene, and ran a full scripted session (movement, chat commands, an emote, screenshots) with no errors, its entire networking path on the replacement transport. The vendor library is compiled out of that build entirely. This is the same client players run, proven end to end on the new wire for the first time.
- The combat balance program is underway. A new audit tool graded all 163 implemented combat skills on paper and confirmed the big suspects: Death magic computes to zero damage against tier-5 undead at grandmaster, Chaos and Bard rank far above every other school, and 59.5% of characters that invest in Bard take it to grandmaster. A new changeset pipeline makes every coming tuning change reviewed, capped, and revertible.
Server networking (Photon replacement)
- Ran the complete backend on the replacement stack: all seven server processes (master, social, game, scene, two group servers, and logging) on the new process host, on the same port layout the current stack uses, against the local database and real game data. The servers found and registered with each other over the new encrypted internal links, and a game server restarting its connection to the master recovered on its own.
- Wrote the one-command launcher that stands that cluster up and down. It publishes each service together with the host so their shared components agree, copies the runtime config the services expect, generates and wires the shared local development key for the internal authentication, and pins the master's identity setting (its fallback of reading a network adapter's hardware address can pick an adapter without one and crash a store subsystem).
- Ran the full automated test suite against the live cluster: 48 of 48 modes pass with only the website-credentials mode skipped, the same mode set the reference captures of the current stack were recorded from. The suite went from twelve passes on the first attempt to all of them on the third as the defects below were fixed.
- Fixed typed lists over the wire. The game's messages carry lists of numbers, names, and object ids whose exact element type must survive transit (the receiving code casts to the typed list), and the new encoding only carried untyped lists; lists of the game's custom data types were not carried at all. Both now travel with their element type and rebuild exactly, covered by new encoder test cases on both the server and the in-editor client suites.
- Fixed the disconnect reason a client sees when the server deliberately drops it. The logging server's spam cutoff test checks for the specific server-logic disconnect code, and the new client layer reported a generic one; the deliberate-close case now maps to the code the game expects, with the timeout case kept separate.
- Fixed a silent message loss that broke chat, parties, and social presence. A group server introduces itself to the social server the moment its connection object is constructed, and the new stack only armed a connection's encryption after construction finished, so that first message was dropped without a trace. The handshake keys are now staged before construction, matching how the old system behaved, and the ordering guarantees the receiving side can decrypt construction-time messages.
- Fixed the local address a server sees on its own outgoing connections. Servers derive their cluster identity from it, and the new stack reported a placeholder; registrations now carry the real address, which is also what the master hands to clients when directing them to a game server.
- Made the published test bot self-contained: its login credentials, per-test fixture data, and logging config now ride the publish, and the test harness gained a switch to point at the new-stack bot. The missing fixture files had accounted for two thirds of the first run's failures.
- Ran the message-level comparison between the stacks: recorded the new stack's full test-suite traffic and diffed it against the current stack's reference captures under the documented masking rules. Thirteen modes are byte-identical; seven contain the same messages in a different order (the new transport is faster, so paired responses sometimes land swapped); the rest differ only within the same noise the current stack shows against itself run to run. One mode logs a single extra client message that raced the server's spam cutoff. No content drift anywhere.
- The comparison surfaced four gaps in the masking rules that same-day reference runs could never expose: a store version counter, a weekday embedded in a test game name, a date-derived price field, and a timestamp hidden inside a byte-encoded blob. All four are now encoded with their reasons, and the differ gained composable rule files plus drop rules for the client status callbacks that legitimately differ between transports.
- Wrote the hosting-requirements input for next week's production hosting decision: what the chosen servers must additionally support so the new networking stack lands on them later without revisiting the decision. Short version: room to run native Linux processes beside the launch-era Windows VMs, one extra port range during transitions, and a storage dataset per environment for the parallel test copy of the database.
- Put the standing tripwire in place for mirror drift: the team ships weekly on the current server project files while the port compiles the same sources from derived file lists, and a file added to one side without the other still builds cleanly and silently loses behavior. A new checker evaluates both sides exactly as the builds do and diffs them (five project pairs, all in sync at introduction), and a nightly build-farm job now runs that check plus the full test-harness suite so drift is caught the next morning, not months later.
- Ran an endurance soak (repeated full-suite runs against one long-lived cluster) and it caught a serious defect: after enough sustained traffic, whispers, chat channels, parties, and social presence started failing while every connection still looked healthy. A twenty-run reproduction showed failures correlating perfectly with the two test clients landing on different group servers, live thread dumps showed every process idle, and restarting a single server cleared it, which narrowed the fault to in-memory link state.
- The root cause was a thread race in the new encrypted transport: taking a message's sequence number and handing the message to the transport were two separate steps, so two server fibers sending on the same internal link could put messages on the wire out of sequence order. The receiver's strict ordering check then silently discarded everything after the gap, forever, while the link stayed up. The fix makes sequencing and sending one atomic step per channel, and an ordering violation now drops the connection loudly so the existing reconnect logic recovers, instead of leaving a healthy-looking link that eats messages.
- The hunt left durable tooling behind: a host switch that turns on per-message logging across every generated server interface without a source edit, and a written triage guide covering this failure class's signature and the live thread-dump recipe.
- Settled how shipping clients will trust the new stack's server identity: the server's public key ships baked into the client per environment, as an ordered current-plus-next set, so a routine key rotation is a normal client patch instead of a flag day. This follows the same approach the current client already uses for its login key. The decision and its coupling to the client's self-integrity checks are recorded in the key-handling runbook, which also shed the certificate-authority language left over from a superseded internal-links design.
- Opened the game-client phase of the replacement with a two-track code survey before writing any code, and it changed the plan for the better: the vendor networking library turns out to compile from source inside its own assembly (there is no vendor binary in the client at all), so the client can switch stacks with a single build flag while every consumer compiles unchanged, and regular test-shard builds keep shipping the current stack untouched. The survey also flagged two candidate wire-level gaps a real client might hit that the automated test bot structurally never could, and the phase now has its own written execution plan.
- The client-side keystone compile then passed: with the new build flag set, the whole game client, its forked network framework included, compiles against the replacement networking facade instead of the vendor library, and with the flag unset the client builds exactly as before. The facade source moved into the client tree so the game and the test bot compile the identical file and cannot drift, three members the framework reads were added, and the facade's 66-check behavior proof still passes. A one-command script now builds both configurations headlessly, without the editor, for use as a standing gate.
- Chased both flagged wire gaps to ground before touching the protocol, and both dissolved against the game's actual code paths: the suspect type registrations turned out to be disabled code that never compiles, and remote-call payloads travel as opaque byte blobs the game serializes itself, so the new encoding never sees the suspect types. The strict encoding stays as designed, now with tests pinning that it refuses unknown type codes, and the client's disconnect timeout default was aligned to the current stack's value. The full 48-mode suite passed against the live local cluster with the change in.
- Wired the client-side key and identity plumbing for the new stack: a per-environment key module that refuses to compile a live or QA client until real keys exist for it (which is also the moment the tamper-check constants get redefined, so the coupling cannot be forgotten), a startup hook that provisions every connection with the pinned key and the game's version identity, environment overrides available only in flag builds so a local test client can reach a local cluster without weakening the shipping server lock, a build-farm switch that produces the flag build, and a hygiene check that fails any player artifact carrying the new networking flag however the define might leak in.
- Closed the client test harness's last login gap while preparing the first live flag-client run: an automated login on an account with no character now creates a default one through the same code path the game's functional tests already use and continues into the world (real players still get the normal creation and select screens), and the local cluster launcher gained the same offline-login option the old-stack launcher had, so a real client can log into the local replacement-stack cluster without the production account service.
- Ran the first live client session on the new stack, and it passed twelve of twelve steps. A flag-built client (with the vendor networking library verified absent from the finished build) connected to the local seven-process cluster, created its character automatically, loaded the Solace Bridge starter scene rendered over the new transport, and ran through queries, location commands, an emote, and autorun movement with screenshots at each stage, no client errors, the whole networking path on the replacement code. The one server-side note was a missing local data file unrelated to networking. That completes the client phase of the port locally; the next milestone is the same client in front of invited testers on the test shard.
- Re-planned the rest of the networking replacement end to end and adopted an accelerated schedule as the plan of record: the parallel new-stack cluster goes up on the test shard's server immediately, beside the current one, with invited testers on a side channel; the test shard's players move to the new stack in late August behind a drilled under-an-hour rollback; the stack then soaks under real players for months while the large-battle fan-out work is built and certified next to it; live moves in the winter window after a thirty-day bake; and once the rollback window formally closes, an archive branch is cut and every vendor networking dependency is deleted from the project, client and server.
- The re-plan's review pass caught three traps before they cost anything: a rollback needs the old database driver to be able to read what the new one wrote (write formats now get pinned and tested in both directions), the planned one-app pilot phase turned out to be impossible under the all-or-nothing client switch (its checks fold into the parallel-cluster gates instead), and the generated server code still depended on a single build machine (its output gets committed with a drift check so any machine can build).
- Made the new-stack server buildable from any fresh checkout, the completion plan's first item: the generated network-dispatch code that only one machine's toolchain could produce is now committed beside the sources, and the nightly server build gained a gate that fails if a regeneration ever diverges from the committed copy. The generator's per-build timestamp stubs stay untracked, so the snapshot is churn-free.
- Closed a long-open cutover question for good: no player client can use the TCP fallback, because the shipped client hard-compiles to UDP and the protocol setting never ships in the settings asset. Only the editor and a developer tunnel switch speak TCP. Conditional TCP support is now removed from the client cutover gates by construction rather than by observation.
- Fixed the local cluster's character-select error from the first live client run: the server resolves its scene-lock and name-blacklist files against a doubled path under our launcher's layout, so the launcher now provisions both files where the server actually looks.
- Stood the whole backend up natively on Linux for the first time and got it green: all seven services running as native Linux processes, encrypted internal links established, and the conformance bot connecting and authenticating over the new wire on Linux. This is the shape the servers will actually run in after the move off Windows. The full automated conformance suite then passed there too: all forty-eight modes, zero failures, the same result as on Windows, over the new wire on native Linux. Getting there fixed the real portability gaps the run surfaced: the ported server and the test bot both hard-coded Windows path separators for their credential, log, and fixture files (a Windows host accepts them, Linux reads them as literal filenames), swept across roughly ninety of them to the form both accept; and the deploy layout was missing a config the server assembles for itself, so the launcher now provisions it. Also added an editor-length keepalive soak to the client facade proof: the current editor talks to the old server over a different transport, so under the replacement the editor's minutes-long pauses ride the new keepalive for the first time; a ninety-second stall held the connection with no stray work and the session resumed cleanly (74 of 74 checks pass).
- Prepared the Linux leg of the parallel-universe bring-up: the local cluster launcher is now cross-platform (verified by rebuilding the Windows cluster with it and passing the bot probe), the production service definitions for the new stack are written (one template service per backend process, with a resource cage so load tests cannot starve the co-resident live services), and a new build-farm job stands the whole seven-service backend up natively on the Linux build machine from any fresh checkout, runs the conformance probe against it, and tears it down.
- Stood the parallel new-stack cluster up on the test shard's server for real: all seven services running natively on Linux beside the still-serving current stack, on their own port range, against a local copy of the database, with a snapshot taken first. A 22-mode conformance pass ran green on the box, and after the firewall opened, a probe from a workstation connected and authenticated over the public internet on the replacement transport.
- Test-shard client builds now default to the new stack: the build farm's client jobs, the in-editor build tools, and the command-line build path all produce new-stack clients unless told otherwise, and the build hygiene gate fails a mis-flavored artifact in either direction (a new-stack build containing the vendor library, or a vendor build carrying the new-stack flag).
- The first real game client then connected to the parallel cluster from a home internet connection: full encrypted handshake and a login round-trip on the replacement transport, in the same packaged build testers will run.
- Chased down the two faults that kept real password logins failing after that first connection, both provisioning gaps in the new deploy. It had shipped a retired signing key for the login service, so every request the servers signed was rejected and logins died before the password was ever checked (the test bots kept passing on their separate credential path and never saw it). And the services advertised internal addresses, so an outside client could log in but was then directed to unreachable addresses for world entry. With the current key provisioned and an address mapping added to the deploy, the full scripted login now passes from an external connection end to end: authentication against the real login service, character creation, and world entry redirects an outside client can actually follow.
- A real player then played on it: logged in from a home connection with a normal account password, created a character, ran the Solace Bridge tutorial with quests advancing, and zoned into Brittany, a full scene transition through the master's routing. Over twenty minutes of play on the replacement stack with zero server errors and no disconnects.
- Made the new-stack test build turnkey for testers: the client flavor now bakes the parallel universe's server identity key and its port band, so a tester runs the game executable directly with no launcher script or environment setup. Development overrides still take precedence for pointing a client at a local cluster, and the client's telemetry connection gained the override it was missing (it previously always dialed the current stack's telemetry port and logged connect errors in new-stack builds).
- Closed out the day's paperwork: the security posture table now declares the parallel cluster's shifted port range (the pre-deploy check asserts it and carries a note to retire it at the test-shard cutover), and the roadmap's networking row reflects the live status.
Telemetry
- Added a Zone Load Times dashboard to the team log site. Every zone load a client performs already reports a timing line with the total wait and a per-phase split (scene file load, activation, server join, decorations, avatar, finalize, garbage collection); the dashboard charts average and 95th-percentile load times over time and per scene, the phase breakdown, load counts, and memory after each load.
- Kept first-of-session loads out of the regular charts. The first load pays one-time warm-up costs and runs far longer, so it is charted on its own row; mixing it in would mask real regressions in the everyday numbers.
- Typed the load-time and memory fields in the log store so they can be aggregated, and re-rolled the existing daily log buckets to match, verifying entry counts before and after so nothing was lost.
- Documented the tooling pitfall found on the way: the log viewer caches a pattern's field list, so newly typed fields report as missing in every chart until that cached list is refreshed.
- Wired server metrics into the same log stack: every server process (master, game, scene, group, social, logging) now reports its load every ten seconds, covering connected sessions, process CPU and memory, garbage collections, internal queue depths, bandwidth, the load-shedding level, and on the master the online player count and login-queue occupancy against its cap.
- Added per-request response times: every request type is timed where it executes and aggregated inside the server before reporting (count, average, worst case, and a fast/medium/slow split per type each interval), so the reporting cost stays flat regardless of how busy the shard gets. Request types report by name through a generated lookup of about 1,100 entries; unknown codes fall back to the number.
- Built a Server Metrics dashboard with thirteen panels: sessions per service, requests per second, latency average and worst case, slow-request buckets, a busiest-requests table, CPU, memory, garbage collections, queue depths, network throughput, the master's login-queue view, and load-shedding state.
- Typed the new metric fields in the log store up front, extended retention to the new stream, and gave the read-only viewer account access (which also fixed the item-audit stream having been invisible to it).
- Verified the path at every layer before deploying: 23 pure-logic checks in the server test harness (including a port of the ingest parser's exact rules and a number-formatting check under a hostile locale), a live capture of the publisher's real datagrams, and a synthetic ingest test on the shard. Deployed to the test shard end to end; the full readiness gate passed and metrics from all six services are flowing.
Combat balance
- Kicked off the combat skill balance pass: wrote up the methodology (how balance is measured, what counts as balanced, and how changes ship safely) in the epic plan and roadmap, with the first targets set: bring Bard and Taming down, lift the schools crushed by undead resistances.
- Built a Balance Audit editor tool that evaluates every implemented combat skill's formulas (damage, damage over time, area radius, focus cost, cooldown, buff uptime) against standard character and target profiles and writes a ranked power table per skill and per school. All 163 implemented skills evaluate cleanly and twelve editor tests pin hand-computed values.
- First audit results: the Death school's damage against tier-5 undead computes to zero at grandmaster (stacked resistances absorb all of it), Air, Earth, and Water land near zero against undead, and Chaos and Bard sit at two to four times the median school's output on paper. Physical weapon schools are untouched by the resistance wall.
- Built a Balance Changeset tool: skill tuning changes are now reviewable JSON files applied through the game's real formula parser, with old-value locks, a cap on how far a single change can move a number, automatic before-and-after reports, and one-command revert. Verified that a no-change file leaves assets byte-identical and that a real apply-and-revert cycle restores the original bytes.
- Measured what players actually master from 120k character records: among characters that ever invested in Bard, 59.5% took it to grandmaster, rising to 68.7% among characters active in the last year. Taming holds the largest invested experience pool of any school. Both support the community's read on the outlier schools.
- Added population snapshot scripts that report per-school investment and grandmaster share on demand, with an exact replica of the game's skill experience curve so reported levels match in-game levels.
- Gave the balance audit a visual report: a one-command generator turns any audit run into a self-contained interactive page with the per-school damage ranking against the target band, a school-by-target damage matrix that makes the undead resistance wall visible at a glance, and the top skills with hover detail.
- Published the balance audit report to the team portal behind the team login, with its own portal card and a one-command publish script that verifies the deploy the same way the other dashboards do.
- Started tracking balance over time: every published audit run is recorded in a shared history, and the report gained a trend chart plotting each school's power against the cross-school median across runs, with the target band drawn in, so the effect of each tuning change shows up run over run.
Client rendering
- Cleaned up the main object shader family (the one nearly every item, player, and building renders with): removed a leftover debug flag that made every compiled variant of the batching shader ship unoptimized with debug info, deleted an unused forward-rendering code path and two dead helper functions, and stopped compiling lighting variants the family can never use. The two transparent shaders each dropped from 24,964 compiled variants to 12,484 and the color-swap shader from 308 to 178, with all eight shaders recompiling clean.
- Fixed a years-old lighting bug on draw-call-batched scenery: the batching shader read the day/night sun value under a different name than the game sets (a historical misspelling became the real contract), so on batched objects the value was stuck at zero. Vertex tinting was forced to white, emissive materials never responded to day or night, and glow was pinned to its dimmest level. Batched and unbatched copies of the same object now light identically.
- Made undyed objects stop paying for the dye system. Every pixel of every object evaluated the full color-replacement path (two texture reads plus three animated gradient computations) and then multiplied the result by zero when no dye was applied, which is most of what is on screen. The shader now skips that work outright when a material has dye off. Verified pixel-identical output before and after on dyed, undyed, and color-shift materials (0 differing pixels of 262,144 in isolated renders).
- Built an experimental Ultima mode: a toggleable retro rendering style with flattened, banded lighting, dark ink outlines, posterized painterly color, and an optional chunky-pixel pass. One shader change restyles the whole scene (the game lights every solid object through a single lighting pass), the rest composes effects the project already shipped but never used. Runs from the developer console with every layer tunable live; verified pixel-identical when off, and absent from release builds. Before/after shots below.
- Wrote up the render mode and its console commands in the docs, and added it to the roadmap as an experimental epic pending an art-direction call.
- Captured before and after evidence renders for a long-standing lighting question found in the same review: the main shader caps a grazing-angle reflection term, which removes the edge-of-light sheen on cloth, leather, and wood. Filed for an art-direction decision with the renders attached.
- Promoted Ultima Mode to a checkbox on the Video tab of the options window. The setting persists between sessions, stays in sync with the developer console toggle, and applies without a restart. Fine tuning of the individual layers stays on the console while the look is dialed in.
- While adding the new checkbox, restored the correct interface font on all 157 labels of the options window: an earlier save had baked the Chinese fallback font into every label. Chinese clients are unaffected; they swap fonts at runtime.
- Added five tuning sliders under the Ultima Mode checkbox, shown only while the mode is on: light banding, outline strength, color steps, pixel size, and saturation. Changes apply immediately and persist between sessions.
- Fixed the new option's label showing question marks around it (the marker the game puts on text missing from the translation tables), and removed the defunct GPU Occlusion setting from the video options along with its backing code.
- Localized all twelve Ultima Mode option strings (the checkbox, five sliders, and their tooltips) into German, Portuguese, Russian, and Chinese, with matching entries in the QA test language. The Chinese text uses the series name Chinese players know Ultima by.
- Moved those option strings into the translation pipeline's source database as well, with French, Spanish, and Italian translations added at the database level, so future language deploys carry them instead of overwriting them.
- Retired the old third-party translation platform for good: the AI translation pipeline that produced the German, Portuguese, French, Russian, and Chinese fills is now the standing system. Confirmed nothing on the current build infrastructure still runs the old platform's sync, and marked its legacy build steps as never-to-be-ported.
Dev portal & infra
- Made screenshots a standard part of this work log: any change with something visual to show (an editor tool, the game, a web page) now ships with a capture, and every image is reviewed for sensitive content before it is published.
- Split this work log into one page per week. The front page carries the current week, finished weeks live on their own archive pages, and every page links to the previous and next week at the bottom. The publish script rolls a finished week onto its archive page automatically on the first update of a new week.
- Extended the pre-publish checks to the new layout: image references and deployed byte sizes are verified for every page and shared asset, and the pre-deploy security scan reads every blog page instead of just the front page.
Images
2026-07-06 · 21 items
Headlines
- The Photon replacement reached its biggest server milestone: the entire game server, every service, now compiles unedited on the replacement networking library. That confirms the compatibility layer is complete for the whole backend, not just the pilot pieces, and all six of the game's custom data types serialize correctly over the new wire.
- Worked down the client-side checklist from the plan review: captured reference traffic from the current stack and built the comparison tool for it, restored the server clock the game reads from timestamps, and closed the connection-startup and keep-alive gaps flagged for the client swap. Two full reference runs of the same current-stack server now match each other message for message on the deterministic flows, which is what makes the comparison trustworthy.
- Audited the Photon replacement plan against everything built so far and re-based it. The build phases finished about a quarter ahead of the written schedule, so the plan now tracks the remaining work as a per-gate checklist, with reference traffic captures from the current stack at the top. The review also settled how backend servers will authenticate to each other and pulled the first test-shard rollout steps into this quarter.
- Built the matching client-side layer too, so the game and bot client code can move over the same way. A test drives it exactly as the automated test bot does and runs a full round of requests, replies, an event, and a clean disconnect against a real server on the new stack. Later in the day the test bot port was finished outright: all of its files compile with zero errors and its custom-type registration is proven on the wire in both directions.
- Ran the first real game service on the new stack too: the client logging server, the smallest backend application, boots unedited and answers a real client over a lossy connection through connect, news of the day, log submission, its spam cutoff, and the two-port split that separates player traffic from the internal admin tool.
- Moved the database layer to the current driver as part of that. The whole persistence layer builds against MongoDB driver 3.9 with small guarded changes, and a fidelity check against a real database confirms documents still read and write identically, including reading records written by the old driver, so live data survives the jump.
Server networking (Photon replacement)
- Stood up the client logging server, the first real backend application, on the replacement stack: the unedited application and its connection handlers boot on the new host across two ports and serve a real client over a connection dropping one packet in ten, through connect and its acknowledgement, news-of-the-day returning the loaded server messages, log acceptance, the hundred-messages-per-fifteen-seconds spam cutoff dropping the connection, and the port split that routes player connections and the internal admin tool to their separate handlers. It leans on the game's real generated message dispatch throughout.
- Ported the database layer to MongoDB driver 3.9 (from 2.7): it compiles unchanged except for a couple of calls whose signatures moved, guarded so the old build still compiles too. A new fidelity check runs the real persistence classes against a live database and confirms real documents round-trip, the custom field formats keep their exact on-disk shape, and records laid out by the old driver still read back correctly, which is what lets the upgrade touch live data safely.
- Compiled the entire game server, every service, unedited against the replacement networking library. This confirms the compatibility layer reproduces the full interface the backend was built on, not just the slice the pilot apps use. A handful of gaps surfaced and were filled in the compatibility layer, and one database call adjusted for the new driver, all without changing the game code. A runtime check then serialized all six of the game's custom data types over the new wire and read them back intact.
- Built the client-side compatibility layer, the counterpart to the server one, so the game client's networking can switch over the same way. A test constructs and drives it exactly as the automated test bot does, its own connection object and per-frame pump, and runs twenty-five requests, their replies in order, a server event, and a clean disconnect against a real server application on the new stack. The full automated test bot, all three hundred-plus files, then compiles against it except for one custom-type serialization file that couples two buffer types, which is the last piece of that port.
- Audited the whole replacement implementation against the plan, file and line, and re-based the plan around what the audit found. The build phases landed about a quarter ahead of the written estimates, so remaining work is now tracked as a per-gate checklist instead of time bands. Top of the checklist: recording reference traffic captures from the current stack while it still runs unchanged, so the new stack can be diffed against real behavior instead of assumptions.
- Two decisions came out of the review. Backend servers will authenticate to each other with their own handshake keys on the same encrypted transport the game clients use, replacing the earlier certificate-based design. And the first rollout stages on the test shard move up to this quarter, while the main cutover waits until after the new-infrastructure launch settles.
- The audit also corrected the test-bot record: the serialization file thought to block its compile actually resolves fine, and the real remaining piece is a small adapter so the game's custom data types register at runtime. It flagged a handful of client-layer gaps to close before the game client switches over, including server time synchronization and a threading fix in the keep-alive path used during scene loads.
- Finished the test-bot port the audit unblocked: the registration adapter landed (the client layer's stream-style custom-type registration now feeds the shared registry instead of silently dropping), a buffer constructor was fixed so deserializers can read the incoming bytes, and the client layer grew the traffic-statistics and network-simulation surfaces the ported code compiles against. The full bot, all of its files, builds with zero errors; its project file is committed and the spike harness now compile-checks it on every run so it cannot drift quietly. The end-to-end proof grew four cases covering the new registration path round-tripping a custom type in both directions on a live connection.
- Built the traffic trace recorder, the top item from the plan review. When enabled it records every message the test bot sends and receives, in order, with a stable rendering of each value, to a line-per-message file. The same recording code compiles into both the current-stack bot and the replacement-stack bot, so a run against the old server produces reference captures the new stack can be diffed against message by message.
- Captured the reference traffic and built the comparison tool. Three full runs of the test suite against a local current-stack server were recorded, all forty-seven modes passing, and a differ compares two captures mode by mode under a set of rules that mask the values which legitimately change between runs (timestamps, generated ids, session keys, a couple of counters). To prove the rules are honest they were derived by diffing two runs of the same server against each other: eighteen of the forty-seven modes then match byte for byte, and the rest differ only in message ordering at login and teardown or in the multi-bot modes, both written down as known exceptions rather than chased.
- Restored the server clock. The client reads a server timestamp that gameplay leans on for timed effects and message ordering, and it had been left as a local stopwatch. It now comes from a small ping exchange on the encrypted transport, built the same way the old system built it, so the value tracks the server and survives the counter wrapping around. Pinned with hand-checked cases and a live round-trip.
- Closed three client-layer gaps before the game-client swap. The connection handshake now carries the application name and patch version, bound into the handshake so it cannot be altered in transit, which also fixes how the server tells its own internal connections apart. Oversized unreliable messages are routed to the reliable channel instead of dropped, matching the old behavior, with a counter so oversized batches get noticed. And the scene-load keep-alive is now a true no-op that keeps the connection up without running game callbacks on the wrong thread, verified by stalling the main loop past the disconnect timeout and confirming the session survives.
- Built how the backend servers authenticate to each other, one of the decisions from the review. Each server now carries its own handshake key; a server dialing another proves its identity as part of the encrypted handshake, and the receiving server only accepts keys on its trusted list. A wrong or unknown key is turned away before anything else happens, and a stand-in that presents a key it does not actually hold cannot complete the connection. Proven both as isolated cases and live over the network: a trusted backend connects and an operation round-trips, an untrusted one is rejected. This is new protection the old setup never had on its internal server links.
- Finished the last client-layer item on the checklist: the in-game lag and packet-loss simulation controls used for testing now map onto the new transport's own simulator. The controls are wired and safe to leave in place; the actual effect only kicks in on a test build of the transport, exactly as the old simulator was test-build only. That clears the client-side facade checklist end to end.
- Made the server-to-server authentication deployable. The process host now takes its trusted-key list and the address of any server it dials from configuration, validating each key up front and refusing to start on a bad one. That completes the internal-server-authentication work start to finish: the handshake, the server plumbing, the live test, and now the configuration to run it. What is left is the multi-server bring-up that uses it.
- Started the deployment work for running the real backend services on the new host. Tried booting one of the actual services and traced through what it needs: each service has to be packaged together with the host so their shared components agree, and each carries its own runtime data files. Wrote the host support for loading a service's own libraries and documented the deployment recipe and the exact remaining gaps, so the multi-service bring-up starts from a known checklist instead of rediscovery.