|
40610
|
Story of Alicia custom server change (12 player ro Story of Alicia custom server change (12 player rooms) by @CherryMG | Stardance...
|
CherryMG
|
0
|
17.71
|
0
|
[]
|
[{"post_id": 47847, "ts": "202 [{"post_id": 47847, "ts": "2026-08-16T02:18:12Z", "hours": 0.4981, "text": "I finally got new icons to work (sort of), it was absolute hell and somehow no time logged so yippee, 11 hours of work counts as 30 minutes. I need to fix some packet issues because the place numbers below 8 are sometimes not correct, for example a player can have the marker for 9th place permanently when between spots 9-12."}, {"post_id": 42599, "ts": "2026-08-07T12:47:58Z", "hours": 5.8289, "text": "Slowly turning this into an actual repo I’ve started slowly putting together a proper repository for the whole 12-player project. Up until now, a lot of the work has basically been spread across my local setup: modified server code, patched executables, launcher scripts, test-client setup, resource tools, backups, configs, and a bunch of other little things I ended up changing along the way. It works for me because I know where everything is, but obviously that’s not very useful if someone else ever wants to reproduce it. So the next goal is to gradually turn all of that into one repo that actually makes sense. I want it to eventually include the tools I used or modified, the 12-player server changes, the client patching/setup stuff, and proper instructions for getting everything running without having to recreate my increasingly cursed development folder from scratch. This is also important because I don’t really consider the project ready for approval by the Story of Alicia developers yet. Twelve players can already join the same room, start a race, synchronize with each other and actually finish it, which is honestly way further than where I started. The main annoying problem left is still making the transition from the race results back into a stable 12-player lobby completely reliable. Until that and the rest of the important pieces are finished, I’d rather keep treating this as an ongoing modding/reverse-engineering project instead of something polished and ready to merge. There will probably also be some slightly different versions of certain tools included with releases, since a few parts of my setup have been changed specifically for this project. Basically: less exciting reverse engineering this time, more slowly cleaning up the giant pile of things the reverse engineering created. Hopefully by the end of it, launching the 12-player setup won’t require being me and remembering why twelve different folders exist."}, {"post_id": 37598, "ts": "2026-07-30T13:10:56Z", "hours": 0.8156, "text": "I just wanted to quickly show a video showing how all 12 players synchronize properly between each other:) A huge feat of reverse engineering and caffeine addiction"}, {"post_id": 37561, "ts": "2026-07-30T11:44:04Z", "hours": 3.1375, "text": "#post 6 of 6 - current updates will be posted now The local automation and resource behavior are config/toggle controlled. The server is based on upstream 47fada2 while retaining the local 12-player work. The new editor is installed beside the existing tools. Launcher CLI 1.2 is installed. The July 7 full resource pack was compared, backed up, installed, and verified. Existing instances no longer get stuck on an old executable. Magic items are allocated using live race rank like the newer patch. The PostgreSQL dependency is local and clean server builds work again. Personalized eight-racer finish/result views build and run. The experimental client finish guard builds into per-instance executables. The post-result delete suppression experiment has a clean verification binary. What is still unresolved: A complete 12-player race does not yet return every client to the lobby safely. Limiting only the final score packet to eight entries did not work. Personalized finish/result visibility improved the behavior but did not eliminate the crash. The client finish-record guard got farther but exposed another failure during lobby cleanup. The post-result racer-delete suppression still needs a full 12-client runtime test. The newer July 26 E:\\soa\\res.pak has not yet been compared or installed. What I Learned The main lesson is that “support twelve players” is not one number. It is a chain of capacities and state transitions shared by the server, protocol, executable, resources, UI, and cleanup logic. Fixing room creation does not fix race creation. Fixing race creation does not fix the finish UI. Truncating a result list does not help if the client overflow happened ten seconds earlier when finish notifications arrived. The 12-instance setup has been the most useful tool in the whole project. It lets me test the exact full-room condition repeatedly, compare behavior between clients, and catch cases like only client02 surviving. It also lets me test separate changes across twelve isolated working directories without rebuilding or manually repairing every client. I also learned to keep every risky workaround reversible. That has saved a lot of time. I can switch between full and development resources, turn room automation off, disable rank weighting, remove the finish compatibility limit, disable post-result suppression, and regenerate clean per-instance executables without touching the base client. This is not finished yet, but the remaining bug is much narrower than where I started. Twelve players can get into the same room, start the same race, finish it, and reach the result sequence. The current work is focused specifically on the client’s transition from those results back into a stable twelve-player lobby."}, {"post_id": 36581, "ts": "2026-07-28T19:52:58Z", "hours": 0.5528, "text": "post 5 of 6 Broadcasting race result for room 1 with 8 packed score entries (10 total racers) That did not solve the crash. It reduced the final result rows, but every client had already received finish notifications for more racers than its UI seemed able to store. I then implemented a personalized finish view behind client_safe_finish_racer_limit: 8 . Each client receives at most eight visible racers, always including itself and the first finisher. The same visibility set is used for finish notifications and the final score list, so a client does not receive a final row for a racer it was never told had finished. The later logs proved this path was active: Broadcasting personalized race results for room 1 with at most 8 score entries (12 total racers) It still did not fully fix the client. It changed the failure and allowed the process to get farther, but clients continued resetting their connections around the result-to-lobby transition. Experimental Client Finish Guard Because the evidence continued to point at an eight-record client allocation, I added a reversible executable safety guard to the per-instance patcher. With $EnableFinishRecordOverflowGuard = $true , the launcher: Extends the executable text-section size to include a small code cave. Redirects the suspected finish-record creation function through that cave. Checks the client’s current finish-record count. Calls the original function for records zero through seven. Returns safely instead of constructing record nine or later. The base Alicia.exe remains untouched. Turning the toggle off restores the original per-instance binary on the next launch because the script always rebuilds instance executables from the clean base. This guard also did not finish the job. It got the clients farther into the post-race flow, which supports the theory that the client has an eight-record assumption, but the next test kicked or crashed most clients while returning to the lobby. The user-visible result was that the second client was the only one that did not crash in that run. The corresponding server log showed a personalized 8-of-12 result, followed later by many AcCmdUserRaceDeleteNotify packets and connection resets. That moved the suspected failure point from result-row creation to post-result cleanup. Current Post-Result Cleanup Experiment The newest server experiment is suppress_post_result_race_delete_notifications . When enabled, the server still sends racer-delete notifications for a disconnect during an active race, because remaining racers need that state update. After the race has returned to the waiting stage, however, it suppresses AcCmdUserRaceDeleteNotify and lets normal room-leave notifications perform lobby cleanup. I added this because the latest test reached the lobby transition before most clients failed, and the logs showed a burst of racer-delete packets as clients began leaving. The change is deliberately narrow and reversible through config. At the time of this devlog, this experiment has a successful clean verification build at build/post-result-delete-verify/alicia-server.exe , but it has not yet been proven by a full successful 12-client race. I am treating it as an active hypothesis, not a finished fix."}, {"post_id": 36520, "ts": "2026-07-28T18:04:08Z", "hours": 3.6636, "text": "post 4 of 6 144 bytes with SHA256 A04A2BB2D5E43D5D161023B3A82D7DC8D7735EBBA48069C1891F90BDBE37B1B2 . The backed-up previous executable has SHA256 C0D1FC4D1E4D465FE7797A8D857A79A7CDC52B1AFAEDE5D17E2913430500CD5F . This fixed the problem where I thought I was testing the new client while the twelve launch folders were silently running old binaries. July 27: Matching the New Magic-Item Allocation The next mismatch was magic-item assignment. The newer client behavior gives useful defensive or control items, such as Shield or Ice Wall, to the leader and reserves stronger catch-up items for lower positions. My local server still used one mostly global weighted pool, so first place could receive items that did not match the new patch. I added rank-weighted magic allocation to the server: The registry now loads per-rank weights from magic.yaml . Live race progress is stored on each racer. The server resolves a racer’s current rank when an item is requested. Ranks one through eight use their own configured buckets. Ranks nine through twelve intentionally reuse the rank-eight bucket. Lightning cannot roll for first place and stays a catch-up item. Shield and Ice Wall are favored at the front. Booster, Hot Rodding, buffs, attacks, and team-assistance items receive position-dependent weights. Invalid or missing critical variants are no longer selected. Debug logging records the chosen item type, racer, and calculated rank. rankWeighted: false restores the previous global pool. This work was committed as cb63e80 . It was needed because updating the client resources does not automatically update server-side item selection. The server is authoritative for what item a racer receives, so matching the new client design required a server implementation too. Fixing the Windows Build When I rebuilt after the update, libpqxx failed because it could not find libpq-fe.h . The old CMake file pointed to a PostgreSQL archive in a user Downloads directory, which was not a stable project dependency. I downloaded the PostgreSQL 18.4 Windows binaries into D:\\alicia modding\\dependencies\\postgresql\\pgsql and changed PostgreSQL_ROOT to use that workspace-relative SDK. CMake now resolves: Includes from dependencies/postgresql/pgsql/include libpq.lib from dependencies/postgresql/pgsql/lib I also made MSVC /MP optional through ALICIA_MSVC_MULTIPROCESSOR_COMPILATION . The verification build disables it, which avoids parallel compiler pressure while debugging and gives more predictable clean builds. Fresh verification builds produced: build/finish-guard-verify/alicia-server.exe build/post-result-delete-verify/alicia-server.exe This replaced the unreliable old incremental build path that had produced ZERO_CHECK access-denied problems and the missing PostgreSQL-header failure. The 12-Player Finish Crash Investigation The hardest issue has always been the transition after the first finisher’s countdown expires. The first logs showed that the race itself worked. Players joined, started, raced, finished or received DNF results, and the server handled AcCmdUserRaceFinal and AcCmdCRRaceResult . The clients crashed immediately before the result screen appeared. The server then logged connection resets because the client processes had already died. The log looked like the server was sending some packets many times, but most repeats were one broadcast being serialized once per connected client. With twelve recipients, chat notifications, finish notifications, result acknowledgements, leave notifications, and racer-delete notifications naturally appear repeatedly in the server log. The result packet was the strongest clue. A 12-player result notification was 1,016 bytes and contained only eight packed score entries while still declaring twelve total racers. The early compatibility attempt simply truncated the score list to eight:"}, {"post_id": 36338, "ts": "2026-07-28T12:05:22Z", "hours": 0.9297, "text": "post 3 of 6 The release archive did not include a replacement bridge executable, so the existing alicia-launcher-bridge.exe stayed unchanged and its backup has the same hash. July 8: Comparing and Installing the New Resource Pack The client update was not just an executable update. Alicia stores most game content in NPAK resource files, so I used the editor/libpak tooling to inspect the newer E:\\soa\\res.pak and compare it with the active pack. The comparison produced: 19,186 indexed assets in the old pack. 19,186 indexed assets in the new pack. 97 changed assets. 21 priority changes under UI, scripts, script source, and INI data. The priority list included: graphics/ui/refresh/result_timeattack_window.xml graphics/ui/refresh/rd_navigation_bar_window.xml graphics/ui/refresh/rd_navigation_desktop.xml graphics/ui/game/readyroom/icon_cancel.png script/capturescene.lua script_src/ai/body_sheep.lua other/ini/libconfig_c.dat I saved the old/new asset indexes, changed-asset reports, priority report, unpack logs, pack hashes, and client verification CSV files in res-compare-20260708-1559 . The July 7 source pack had these hashes: res.pak : 8EFA88EEF555A941792FF7739DE94E36459D3D12A258F08DD72AF32D0ADF63FA res.pak.001 : 1267921AF6AA21EAD6D0054A6FCA7D789DD8C8CA1FD8265087DDC16EDB3C18C0 I installed those files into the active game and root pack locations, then generated reports confirming all twelve instances used the intended packs and all six original executable patches had the correct bytes. I made resource switching explicit in Start-Client.ps1 with $UseFullPackedResources . When it is true , instances hard-link the full res.pak and res.pak.001 . When it is false , they use _modres.pak and remove res.pak.001 so a leftover second part cannot accidentally mix two resource layouts. This fixed an early reversible-switching bug. One important current detail is that E:\\soa\\res.pak changed again on July 26. It is now 995,659,281 bytes with SHA256 6A47C96395E16CAFB732A6516187FE807EA855CC33F5214F363E972F8725E60B . That is newer and different from the 995,600,812-byte pack currently installed. I have not claimed that newer July 26 pack is active; it still needs a fresh comparison and controlled installation. July 10 to July 12: Restoring the Known-Good Transition After the upstream update, I restored the known-good 12-player transition behavior instead of keeping newer post-result behavior that changed packet ordering. I removed finish-time room-master reassignment and the extra game-money update from RaceInstance::Stop() . Room-master reassignment remains handled when the current master actually leaves. I kept the simpler sequence of broadcasting results, setting the room back to waiting, and clearing ready states. The reason was compatibility: the older sequence had already allowed the 12-player setup to get through more of the race, while the newer extra notifications created another variable during the fragile result transition. I also moved local auto-fill to the safe point at the end of room entry and forced managed rooms to stay at twelve even when the stock UI tried to report eight. July 12: Fixing Old Executables in Existing Instances After updating the base client, I noticed the launched instances still behaved like the old version. The cause was simple but important: the original launcher copied Alicia.exe only when an instance did not already have one. Existing instances therefore kept stale executables forever. I backed up the previous executable under Story of Alicia/backups/pre-new-exe-20260712 , installed the newer base executable, and changed the launcher so every run derives the desired patched bytes from the current clean base executable. It compares the final SHA256 and replaces an instance executable whenever it is stale. The active base executable is 11,142,"}, {"post_id": 36101, "ts": "2026-07-27T23:41:55Z", "hours": 0.4106, "text": "post 2 out of 6 so normal per-address anti-abuse throttling would treat my test rig like one machine opening too many connections. The bypass applies only to loopback traffic, which keeps it appropriate for local testing. On the client side, I found and added six executable patches: Offset Patch Reason 0x00588742 75 to EB Bypass the single-instance mutex so twelve clients can run. 0x003776E3 7F 11 to EB 11 Bypass the first AddPlayerError crash path during race start. 0x00377BDE 7F 11 to EB 11 Bypass the second AddPlayerError crash path. 0x003B5022 limit 08 to 0C Raise the race creator’s player-list capacity to twelve. 0x003B507A limit 09 to 0D Raise the occupied-slot boundary to support twelve entries. 0x003B50BA limit 09 to 0D Raise the slot-assignment boundary to support twelve entries. These changes got twelve players much farther than a server-only limit increase. At this stage, twelve-player rooms could exist and the clients could enter and start races, but the complete post-race flow was not safe yet. July 7: Automating Full Test Rooms Manually clicking eleven clients into every new room was slowing down every test, so I added a reversible local room automation system to the server. The new local_test_rooms config contains: enabled - auto_fill_on_create auto_ready_on_join A tracked list of CherryMG (really it is test1 through 12) through CherryMG12 When a tracked account creates an eligible twelve-player test room, the server marks that room as managed, summons the other tracked online accounts into it, and automatically readies them as they enter. I restricted this to configured users and eligible local test rooms so it would not affect ordinary players or every room on the server. I originally triggered the auto-fill too early in the room-entry process. That could make client01 , the creator, crash while joining its own newly created room. I moved the auto-fill call until after the creator had received the complete room-entry response and existing users had received the join notification. I also protected the twelve-player count from the vanilla UI sending its normal eight-player room option, and prevented an occupied room from being shrunk below its current population. This is why all players now join as soon as one room is created: it turns one room-creation action into a repeatable full-load test. The feature can be reversed by setting local_test_rooms.enabled to false . July 8: Updating the Story of Alicia Repositories The project had moved ahead upstream, so I updated the local development environment instead of continuing to build on an increasingly old snapshot. Before changing anything, I created backups/update-20260708-152328 . That backup includes: A server branch named backup/cherry-test-before-upstream-47fada2-20260708-152328 . The previous server head. The active game directory. All twelve instance directories. multi-client . mod-launcher . The existing editor CLI assets. The launcher executables. The old res.pak and res.pak.001 files from both active locations. I moved the server work onto upstream Story-Of-Alicia/alicia-server commit 47fada238fd3cc8a0660b20867b08e68c1960652 . I preserved the local 12-player protocol, room, loopback, and automation changes on the upgrade/upstream-47fada2 branch instead of replacing them. I also cloned the new Story-Of-Alicia/alicia-editor repository into D:\\alicia modding\\alicia-editor . I kept alicia-editor-cli and alicia-web-editor intact because they serve different purposes and were already part of the workflow. For the launcher, I downloaded the stable alicia-launcher-cli 1.2 release and installed its CLI executable after backing up the previous one. The installed CLI hash matches the downloaded 1.2 binary."}, {"post_id": 36066, "ts": "2026-07-27T22:19:55Z", "hours": 1.8753, "text": "post 1 of 6 Alicia 12-Player Modding Devlog Development period covered: April 12, 2026 to July 27, 2026 Developer: CherryMakesGames Main goal: Make Alicia support real 12-player local races, keep the setup practical to test alone, update everything to the current Story of Alicia code and resources, and track down the client crash at the end of a race. Why I Started This I am 18, and this project turned into a much bigger reverse-engineering job than I expected. The original target sounded simple: raise an eight-player race to twelve players. In reality, the player limit existed in several different places at once. The server protocol had limits, the room code had limits, the race-start code had limits, the client executable had hard-coded limits, and the finish UI appeared to have its own eight-entry allocation. I also needed a way to test this by myself. Waiting for eleven other people after every small change would make debugging almost impossible, so I built a 12-client local test setup. It lets me reproduce a complete room whenever I want, test twelve separate accounts or client states at once, and see whether a change works for the host, ordinary players, finishers, DNFs, and late disconnects. It also makes repeated tests consistent instead of depending on different people joining each time. The most important rule throughout the project has been reversibility. The base game executable stays clean, experimental patches are applied only to per-instance copies, resource-pack switching is controlled by a toggle, server compatibility work is behind config options, and I made full backups before the upstream update. April 12: Building the Local Test Environment My first major step was creating a proper local client installation and committing the test setup in the Story of Alicia repository. I added: Twelve client folders, from instances/client01 through instances/client12 . One account entry per instance. Individual launchers for each client and a launcher for all twelve. A PowerShell launcher that creates and repairs each instance layout automatically. Separate writable log and _tmp directories for every client. Junctions and hard links for large shared game files so I did not need twelve complete copies of the whole installation. A 4x3 window grid so I can see all twelve clients on one monitor. An automatic Alt+Enter step to move clients out of fullscreen before tiling them. A dry-run mode for checking account paths, arguments, and instance layout without starting the game. A check that each configured local account has a matching server user record. The launcher starts development mode with -GameID 2 and supplies each account’s username and password. I documented the required 127.0.0.1 aliciadev hosts entry because the development client connects to that hostname. The reason each instance has its own Alicia.exe is that every copy needs binary patches, but I do not want to patch the clean base executable. On launch, the script reads the base executable, verifies the expected original bytes, applies the required modifications in memory, hashes the result, and writes only the instance copy. If the executable does not match the version the patch was designed for, the script stops instead of blindly corrupting it. April 12 to April 15: Raising the Race Limit The first server changes raised the protocol and room assumptions from ten or eight players to twelve.I changed AcCmdCREnterRoomOK and AcCmdCRStartRaceNotify so their racer lists accept up to twelve entries. I added validation that throws if the server tries to serialize more than twelve. I also changed room creation so Magic Team rooms resolve to twelve players instead of being clamped to eight. I added a special loopback exception to connection throttling. All twelve clients connect from 127.0.0.1 ,"}]...
|
Title: Story of Alicia custom server change (12 pl Title: Story of Alicia custom server change (12 player rooms) by @CherryMG | Stardance
Devlogs:
post 1 of 6 Alicia 12-Player Modding Devlog Development period covered: April 12, 2026 to July 27, 2026 Developer: CherryMakesGames Main goal: Make Alicia support real 12-player local races, keep the setup practical to test alone, update everything to the current Story of Alicia code and resources, and track down the client crash at the end of a race. Why I Started This I am 18, and this project turned into a much bigger reverse-engineering job than I expected. The original target sounded simple: raise an eight-player race to twelve players. In reality, the player limit existed in several different places at once. The server protocol had limits, the room code had limits, the race-start code had limits, the client executable had hard-coded limits, and the finish UI appeared to have its own eight-entry allocation. I also needed a way to test this by myself. Waiting for eleven other people after every small change would make debugging almost impossible, so I built a 12-client local test setup. It lets me reproduce a complete room whenever I want, test twelve separate accounts or client states at once, and see whether a change works for the host, ordinary players, finishers, DNFs, and late disconnects. It also makes repeated tests consistent instead of depending on different people joining each time. The most important rule throughout the project has been reversibility. The base game executable stays clean, experimental patches are applied only to per-instance copies, resource-pack switching is controlled by a toggle, server compatibility work is behind config options, and I made full backups before the upstream update. April 12: Building the Local Test Environment My first major step was creating a proper local client installation and committing the test setup in the Story of Alicia repository. I added: Twelve client folders, from instances/client01 through instances/client12 . One account entry per instance. Individual launchers for each client and a launcher for all twelve. A PowerShell launcher that creates and repairs each instance layout automatically. Separate writable log and _tmp directories for every client. Junctions and hard links for large shared game files so I did not need twelve complete copies of the whole installation. A 4x3 window grid so I can see all twelve clients on one monitor. An automatic Alt+Enter step to move clients out of fullscreen before tiling them. A dry-run mode for checking account paths, arguments, and instance layout without starting the game. A check that each configured local account has a matching server user record. The launcher starts development mode with -GameID 2 and supplies each account’s username and password. I documented the required 127.0.0.1 aliciadev hosts entry because the development client connects to that hostname. The reason each instance has its own Alicia.exe is that every copy needs binary patches, but I do not want to patch the clean base executable. On launch, the script reads the base executable, verifies the expected original bytes, applies the required modifications in memory, hashes the result, and writes only the instance copy. If the executable does not match the version the patch was designed for, the script stops instead of blindly corrupting it. April 12 to April 15: Raising the Race Limit The first server changes raised the protocol and room assumptions from ten or eight players to twelve.I changed AcCmdCREnterRoomOK and AcCmdCRStartRaceNotify so their racer lists accept up to twelve entries. I added validation that throws if the server tries to serialize more than twelve. I also changed room creation so Magic Team rooms resolve to twelve players instead of being clamped to eight. I added a special loopback exception to connection throttling. All twelve clients connect from 127.0.0.1 ,
post 2 out of 6 so normal per-address anti-abuse throttling would treat my test rig like one machine opening too many connections. The bypass applies only to loopback traffic, which keeps it appropriate for local testing. On the client side, I found and added six executable patches: Offset Patch Reason 0x00588742 75 to EB Bypass the single-instance mutex so twelve clients can run. 0x003776E3 7F 11 to EB 11 Bypass the first AddPlayerError crash path during race start. 0x00377BDE 7F 11 to EB 11 Bypass the second AddPlayerError crash path. 0x003B5022 limit 08 to 0C Raise the race creator’s player-list capacity to twelve. 0x003B507A limit 09 to 0D Raise the occupied-slot boundary to support twelve entries. 0x003B50BA limit 09 to 0D Raise the slot-assignment boundary to support twelve entries. These changes got twelve players much farther than a server-only limit increase. At this stage, twelve-player rooms could exist and the clients could enter and start races, but the complete post-race flow was not safe yet. July 7: Automating Full Test Rooms Manually clicking eleven clients into every new room was slowing down every test, so I added a reversible local room automation system to the server. The new local_test_rooms config contains: enabled - auto_fill_on_create auto_ready_on_join A tracked list of CherryMG (really it is test1 through 12) through CherryMG12 When a tracked account creates an eligible twelve-player test room, the server marks that room as managed, summons the other tracked online accounts into it, and automatically readies them as they enter. I restricted this to configured users and eligible local test rooms so it would not affect ordinary players or every room on the server. I originally triggered the auto-fill too early in the room-entry process. That could make client01 , the creator, crash while joining its own newly created room. I moved the auto-fill call until after the creator had received the complete room-entry response and existing users had received the join notification. I also protected the twelve-player count from the vanilla UI sending its normal eight-player room option, and prevented an occupied room from being shrunk below its current population. This is why all players now join as soon as one room is created: it turns one room-creation action into a repeatable full-load test. The feature can be reversed by setting local_test_rooms.enabled to false . July 8: Updating the Story of Alicia Repositories The project had moved ahead upstream, so I updated the local development environment instead of continuing to build on an increasingly old snapshot. Before changing anything, I created backups/update-20260708-152328 . That backup includes: A server branch named backup/cherry-test-before-upstream-47fada2-20260708-152328 . The previous server head. The active game directory. All twelve instance directories. multi-client . mod-launcher . The existing editor CLI assets. The launcher executables. The old res.pak and res.pak.001 files from both active locations. I moved the server work onto upstream Story-Of-Alicia/alicia-server commit 47fada238fd3cc8a0660b20867b08e68c1960652 . I preserved the local 12-player protocol, room, loopback, and automation changes on the upgrade/upstream-47fada2 branch instead of replacing them. I also cloned the new Story-Of-Alicia/alicia-editor repository into D:\alicia modding\alicia-editor . I kept alicia-editor-cli and alicia-web-editor intact because they serve different purposes and were already part of the workflow. For the launcher, I downloaded the stable alicia-launcher-cli 1.2 release and installed its CLI executable after backing up the previous one. The installed CLI hash matches the downloaded 1.2 binary.
post 3 of 6 The release archive did not include a replacement bridge executable, so the existing alicia-launcher-bridge.exe stayed unchanged and its backup has the same hash. July 8: Comparing and Installing the New Resource Pack The client update was not just an executable update. Alicia stores most game content in NPAK resource files, so I used the editor/libpak tooling to inspect the newer E:\soa\res.pak and compare it with the active pack. The comparison produced: 19,186 indexed assets in the old pack. 19,186 indexed assets in the new pack. 97 changed assets. 21 priority changes under UI, scripts, script source, and INI data. The priority list included: graphics/ui/refresh/result_timeattack_window.xml graphics/ui/refresh/rd_navigation_bar_window.xml graphics/ui/refresh/rd_navigation_desktop.xml graphics/ui/game/readyroom/icon_cancel.png script/capturescene.lua script_src/ai/body_sheep.lua other/ini/libconfig_c.dat I saved the old/new asset indexes, changed-asset reports, priority report, unpack logs, pack hashes, and client verification CSV files in res-compare-20260708-1559 . The July 7 source pack had these hashes: res.pak : 8EFA88EEF555A941792FF7739DE94E36459D3D12A258F08DD72AF32D0ADF63FA res.pak.001 : 1267921AF6AA21EAD6D0054A6FCA7D789DD8C8CA1FD8265087DDC16EDB3C18C0 I installed those files into the active game and root pack locations, then generated reports confirming all twelve instances used the intended packs and all six original executable patches had the correct bytes. I made resource switching explicit in Start-Client.ps1 with $UseFullPackedResources . When it is true , instances hard-link the full res.pak and res.pak.001 . When it is false , they use _modres.pak and remove res.pak.001 so a leftover second part cannot accidentally mix two resource layouts. This fixed an early reversible-switching bug. One important current detail is that E:\soa\res.pak changed again on July 26. It is now 995,659,281 bytes with SHA256 6A47C96395E16CAFB732A6516187FE807EA855CC33F5214F363E972F8725E60B . That is newer and different from the 995,600,812-byte pack currently installed. I have not claimed that newer July 26 pack is active; it still needs a fresh comparison and controlled installation. July 10 to July 12: Restoring the Known-Good Transition After the upstream update, I restored the known-good 12-player transition behavior instead of keeping newer post-result behavior that changed packet ordering. I removed finish-time room-master reassignment and the extra game-money update from RaceInstance::Stop() . Room-master reassignment remains handled when the current master actually leaves. I kept the simpler sequence of broadcasting results, setting the room back to waiting, and clearing ready states. The reason was compatibility: the older sequence had already allowed the 12-player setup to get through more of the race, while the newer extra notifications created another variable during the fragile result transition. I also moved local auto-fill to the safe point at the end of room entry and forced managed rooms to stay at twelve even when the stock UI tried to report eight. July 12: Fixing Old Executables in Existing Instances After updating the base client, I noticed the launched instances still behaved like the old version. The cause was simple but important: the original launcher copied Alicia.exe only when an instance did not already have one. Existing instances therefore kept stale executables forever. I backed up the previous executable under Story of Alicia/backups/pre-new-exe-20260712 , installed the newer base executable, and changed the launcher so every run derives the desired patched bytes from the current clean base executable. It compares the final SHA256 and replaces an instance executable whenever it is stale. The active base executable is 11,142,
post 4 of 6 144 bytes with SHA256 A04A2BB2D5E43D5D161023B3A82D7DC8D7735EBBA48069C1891F90BDBE37B1B2 . The backed-up previous executable has SHA256 C0D1FC4D1E4D465FE7797A8D857A79A7CDC52B1AFAEDE5D17E2913430500CD5F . This fixed the problem where I thought I was testing the new client while the twelve launch folders were silently running old binaries. July 27: Matching the New Magic-Item Allocation The next mismatch was magic-item assignment. The newer client behavior gives useful defensive or control items, such as Shield or Ice Wall, to the leader and reserves stronger catch-up items for lower positions. My local server still used one mostly global weighted pool, so first place could receive items that did not match the new patch. I added rank-weighted magic allocation to the server: The registry now loads per-rank weights from magic.yaml . Live race progress is stored on each racer. The server resolves a racer’s current rank when an item is requested. Ranks one through eight use their own configured buckets. Ranks nine through twelve intentionally reuse the rank-eight bucket. Lightning cannot roll for first place and stays a catch-up item. Shield and Ice Wall are favored at the front. Booster, Hot Rodding, buffs, attacks, and team-assistance items receive position-dependent weights. Invalid or missing critical variants are no longer selected. Debug logging records the chosen item type, racer, and calculated rank. rankWeighted: false restores the previous global pool. This work was committed as cb63e80 . It was needed because updating the client resources does not automatically update server-side item selection. The server is authoritative for what item a racer receives, so matching the new client design required a server implementation too. Fixing the Windows Build When I rebuilt after the update, libpqxx failed because it could not find libpq-fe.h . The old CMake file pointed to a PostgreSQL archive in a user Downloads directory, which was not a stable project dependency. I downloaded the PostgreSQL 18.4 Windows binaries into D:\alicia modding\dependencies\postgresql\pgsql and changed PostgreSQL_ROOT to use that workspace-relative SDK. CMake now resolves: Includes from dependencies/postgresql/pgsql/include libpq.lib from dependencies/postgresql/pgsql/lib I also made MSVC /MP optional through ALICIA_MSVC_MULTIPROCESSOR_COMPILATION . The verification build disables it, which avoids parallel compiler pressure while debugging and gives more predictable clean builds. Fresh verification builds produced: build/finish-guard-verify/alicia-server.exe build/post-result-delete-verify/alicia-server.exe This replaced the unreliable old incremental build path that had produced ZERO_CHECK access-denied problems and the missing PostgreSQL-header failure. The 12-Player Finish Crash Investigation The hardest issue has always been the transition after the first finisher’s countdown expires. The first logs showed that the race itself worked. Players joined, started, raced, finished or received DNF results, and the server handled AcCmdUserRaceFinal and AcCmdCRRaceResult . The clients crashed immediately before the result screen appeared. The server then logged connection resets because the client processes had already died. The log looked like the server was sending some packets many times, but most repeats were one broadcast being serialized once per connected client. With twelve recipients, chat notifications, finish notifications, result acknowledgements, leave notifications, and racer-delete notifications naturally appear repeatedly in the server log. The result packet was the strongest clue. A 12-player result notification was 1,016 bytes and contained only eight packed score entries while still declaring twelve total racers. The early compatibility attempt simply truncated the score list to eight:
post 5 of 6 Broadcasting race result for room 1 with 8 packed score entries (10 total racers) That did not solve the crash. It reduced the final result rows, but every client had already received finish notifications for more racers than its UI seemed able to store. I then implemented a personalized finish view behind client_safe_finish_racer_limit: 8 . Each client receives at most eight visible racers, always including itself and the first finisher. The same visibility set is used for finish notifications and the final score list, so a client does not receive a final row for a racer it was never told had finished. The later logs proved this path was active: Broadcasting personalized race results for room 1 with at most 8 score entries (12 total racers) It still did not fully fix the client. It changed the failure and allowed the process to get farther, but clients continued resetting their connections around the result-to-lobby transition. Experimental Client Finish Guard Because the evidence continued to point at an eight-record client allocation, I added a reversible executable safety guard to the per-instance patcher. With $EnableFinishRecordOverflowGuard = $true , the launcher: Extends the executable text-section size to include a small code cave. Redirects the suspected finish-record creation function through that cave. Checks the client’s current finish-record count. Calls the original function for records zero through seven. Returns safely instead of constructing record nine or later. The base Alicia.exe remains untouched. Turning the toggle off restores the original per-instance binary on the next launch because the script always rebuilds instance executables from the clean base. This guard also did not finish the job. It got the clients farther into the post-race flow, which supports the theory that the client has an eight-record assumption, but the next test kicked or crashed most clients while returning to the lobby. The user-visible result was that the second client was the only one that did not crash in that run. The corresponding server log showed a personalized 8-of-12 result, followed later by many AcCmdUserRaceDeleteNotify packets and connection resets. That moved the suspected failure point from result-row creation to post-result cleanup. Current Post-Result Cleanup Experiment The newest server experiment is suppress_post_result_race_delete_notifications . When enabled, the server still sends racer-delete notifications for a disconnect during an active race, because remaining racers need that state update. After the race has returned to the waiting stage, however, it suppresses AcCmdUserRaceDeleteNotify and lets normal room-leave notifications perform lobby cleanup. I added this because the latest test reached the lobby transition before most clients failed, and the logs showed a burst of racer-delete packets as clients began leaving. The change is deliberately narrow and reversible through config. At the time of this devlog, this experiment has a successful clean verification build at build/post-result-delete-verify/alicia-server.exe , but it has not yet been proven by a full successful 12-client race. I am treating it as an active hypothesis, not a finished fix.
#post 6 of 6 - current updates will be posted now The local automation and resource behavior are config/toggle controlled. The server is based on upstream 47fada2 while retaining the local 12-player work. The new editor is installed beside the existing tools. Launcher CLI 1.2 is installed. The July 7 full resource pack was compared, backed up, installed, and verified. Existing instances no longer get stuck on an old executable. Magic items are allocated using live race rank like the newer patch. The PostgreSQL dependency is local and clean server builds work again. Personalized eight-racer finish/result views build and run. The experimental client finish guard builds into per-instance executables. The post-result delete suppression experiment has a clean verification binary. What is still unresolved: A complete 12-player race does not yet return every client to the lobby safely. Limiting only the final score packet to eight entries did not work. Personalized finish/result visibility improved the behavior but did not eliminate the crash. The client finish-record guard got farther but exposed another failure during lobby cleanup. The post-result racer-delete suppression still needs a full 12-client runtime test. The newer July 26 E:\soa\res.pak has not yet been compared or installed. What I Learned The main lesson is that “support twelve players” is not one number. It is a chain of capacities and state transitions shared by the server, protocol, executable, resources, UI, and cleanup logic. Fixing room creation does not fix race creation. Fixing race creation does not fix the finish UI. Truncating a result list does not help if the client overflow happened ten seconds earlier when finish notifications arrived. The 12-instance setup has been the most useful tool in the whole project. It lets me test the exact full-room condition repeatedly, compare behavior between clients, and catch cases like only client02 surviving. It also lets me test separate changes across twelve isolated working directories without rebuilding or manually repairing every client. I also learned to keep every risky workaround reversible. That has saved a lot of time. I can switch between full and development resources, turn room automation off, disable rank weighting, remove the finish compatibility limit, disable post-result suppression, and regenerate clean per-instance executables without touching the base client. This is not finished yet, but the remaining bug is much narrower than where I started. Twelve players can get into the same room, start the same race, finish it, and reach the result sequence. The current work is focused specifically on the client’s transition from those results back into a stable twelve-player lobby.
I just wanted to quickly show a video showing how all 12 players synchronize properly between each other:) A huge feat of reverse engineering and caffeine addiction
Slowly turning this into an actual repo I’ve started slowly putting together a proper repository for the whole 12-player project. Up until now, a lot of the work has basically been spread across my local setup: modified server code, patched executables, launcher scripts, test-client setup, resource tools, backups, configs, and a bunch of other little things I ended up changing along the way. It works for me because I know where everything is, but obviously that’s not very useful if someone else ever wants to reproduce it. So the next goal is to gradually turn all of that into one repo that actually makes sense. I want it to eventually include the tools I used or modified, the 12-player server changes, the client patching/setup stuff, and proper instructions for getting everything running without having to recreate my increasingly cursed development folder from scratch. This is also important because I don’t really consider the project ready for approval by the Story of Alicia developers yet. Twelve players can already join the same room, start a race, synchronize with each other and actually finish it, which is honestly way further than where I started. The main annoying problem left is still making the transition from the race results back into a stable 12-player lobby completely reliable. Until that and the rest of the important pieces are finished, I’d rather keep treating this as an ongoing modding/reverse-engineering project instead of something polished and ready to merge. There will probably also be some slightly different versions of certain tools included with releases, since a few parts of my setup have been changed specifically for this project. Basically: less exciting reverse engineering this time, more slowly cleaning up the giant pile of things the reverse engineering created. Hopefully by the end of it, launching the 12-player setup won’t require being me and remembering why twelve different folders exist.
I finally got new icons to work (sort of), it was absolute hell and somehow no time logged so yippee, 11 hours of work counts as 30 minutes. I need to fix some packet issues because the place numbers below 8 are sometimes not correct, for example a player can have the marker for 9th place permanently when between spots 9-12....
|
1791823212.3372438
|
1792687212.3372438
|