MechanicaSaveFix
- 7 Devlogs
- 26 Total hours
I thought this step was going to be simple… Not at all!
It’s been a nightmare of an ordeal. The save selection menu’s code (its logic) was basically one flat, tangled plate of spaghetti.
The base game used a bunch of dictionaries to store data and look it back up. The functions tied to the buttons used the Rect object handed to the class to look up the data they needed. Why hand over an object to look up data through a dictionary when you can just pass the function what it needs directly…
I completely rewrote the menu’s behavior from scratch, cleanly, to support displaying and loading saves in their new archive form.
What’s changed:
Progress so far:
System.IO functions..msa (Mechanica Save Archive) file.It wasn’t as simple as expected… But it works now!
You can load a normal world, and on the first save it will be converted into a .msa archive. From then on, whenever you try to load a world that has an archived version, that version will be loaded instead of the other one.
What’s changed:
VirtualFS incorrectly normalizing the root save path, which caused it to no longer match the paths built by the game itself, breaking file lookups everywhere.QueryEntries not sanitizing multi-level directory paths, which caused Directory.GetFiles/GetDirectories to return nothing for nested folders (welds, anchors, etc.)./ and \ separators, which broke the game’s own string comparisons (e.g. RemoveOldFiles deleting everything instead of only orphaned files).DirectoryInfo/FileInfo instance methods (GetFiles, GetDirectories, CreateSubdirectory, Exists), which weren’t covered by the static File/Directory patches.VirtualFS‘s internal mode from three states (Idle/Capturing/Playback) down to two (Idle/Intercepting), since capture and playback behaved identically from the interception logic’s point of view.Save()/LoadSave() coroutine wrappers that trigger the capture/playback cycle and commit/load the .msa archive.Progress so far:
System.IO functions..msa (Mechanica Save Archive) file.I added the Harmony patches to intercept System.IO functions. It was long and repetitive 👍.
What’s changed:
src\Patches\io\Directory.cs for the directory-related function patches.src\Patches\io\File.cs for the file-related function patches.Progress so far:
System.IO functions..msa (Mechanica Save Archive) file.The next step should let me run the first tests, which will probably be followed by some bug fixes. Hopefully not 🤞.
I almost went CRAZY 😰 I ran into an architecture problem, and I was about two steps away from refactoring EVERYTHING to make it clean. I finally found a solution. It’s not the cleanest, but I didn’t have any other idea. So the world-swap function lives inside the VFS. In the end it’s just a matter of roles/responsibilities, nothing technically blocking really 😅.
What’s changed:
Progress so far:
System.IO functions..msa (Mechanica Save Archive) file.Mostly environment/tooling additions and improvements.
What’s changed:
build.yml GitHub CI, to verify that commits and PRs compile.release.yml GitHub CI, to build and attach the mod to releases.Progress so far (so no changes here ¯_(ツ)_/¯):
System.IO functions..msa (Mechanica Save Archive) file.I finished the Forward component, which faithfully reproduces every System.IO function (the functions used to interact with the computer’s file system).
Why? : I need functions with the exact same API, since I’m going to intercept the game’s disk read/write functions to stop it from writing thousands of small files and folders.
What’s changed:
VirtualFS.DeleteFile()
VirtualFS.DeleteFileNoThrow() (System.IO‘s Delete function doesn’t throw an error, unlike VirtualFS.DeleteFile(), so I made an alternative to properly mimic Delete’s behavior.Forward.cs
Progress so far:
System.IO functions..msa (Mechanica Save Archive) file.I have to admit I’ve been working on reverse-engineering / decompiling this game for a long time now, so getting set up was pretty quick.
I established the mod/patch structure, refactored it, refactored it again, until I landed on my current plan.
Right now I’ve only written VirtualFS.cs, which contains the virtual file system that will intercept System.IO requests to prevent them from writing to disk.
Next I’ll move on to writing the fake System.IO functions (write a file, read a file, etc.), the functions that will write and read the save in .zip format, the patches for the system functions, the triggers, and finally the interface.
Progress so far:
System.IO functions..msa (Mechanica Save Archive) file.Markdown checkboxes don’t work… so I’m using good old emojis instead. ¯_(ツ)_/¯