Skip to content

6 March 2025 - Godot 4.4, Mods, and Data Galore

<<< Previous Post Next Post >>>


  In the last post, I gave a status update for most of what I was doing and why I had been dark for so long. Among the things mentioned was my anticipation for Godot 4.4 which, rather ironically, released within a few hours of after I made that post. So that's nice.

Godot 4.4

  Most of Godot 4.4's improvements don't affect you as a player, but some do:

  1. The replacement filesystem I wrote (talked about it last post) can now use GD's native temporary file management solution. There is a method to create a new temporary file from an asset in a mod archive so that methods that require access to a file can do so.
    1. This behavior is atypical as most stuff should stream directly. But it's there if anyone needs it.
  2. Mods can now load .wav files dynamically as this capability was added (I would have likely added this manually anyway, since WAV isn't exactly a complicated file format).
  3. Godot natively has jiggle bones. I don't know if I will use these, it depends on their performance cost, but they look pretty good already. The main concern (and benefit, honestly) is that like Dynamic Bone, or Physbone if you are a VRChat player, they require explicitly registered colliders and don't use real physics simulation. I, at the very least, want box colliders. The thing is, I want world collision too, including with physical interactions (if you have a tail, it should be able to smack stuff, for example).

Progress on the new File System (JSON Handling)

  In the last blog post, I mentioned my creation of a custom file system called StarFileSystem which is an abstraction layer above Godot's ResourceManager with the key ability to reference assets created by specific mods, even if those assets have been overridden by another mod. This system is extremely important because some mods may have privately implemented assets that shouldn't be overridden.1

  Just recently, I finished the final part of this system, which handles the merging of JSON files. See, loading JSON has problems:

  • Allowing mods to override each others' JSON files like any other asset is destructive and incompatible. What if the replacement doesn't have data I need (destructive)? What if two mods want to change the file (incompatible)?
  • Merging JSON fixes this mostly, but it's not granular enough. Things like editing specific array items is very hard to do reasonably without tricks and hacks.

  I actually came up with a couple solutions to this, and accompanying specifications for each. Originally I had an idea to work with something like Starbound's .patch files but honestly this solution is kind of bad when multiple mods intermingle with the same file, because it gets messy and unreadable very quickly. That, and some mods may want advanced or custom logic for their own asset files.

Solution 1: IJsonAssetMerger

  IJsonAssetMerger is an interface which receives an IEnumerable<(StarFileSystem, JContainer)> - the merger implementation can see which mod owns what data (via the filesystem), and the JSON container representing its contents. It is then up to this interface to output a completely merged JContainer or throw an exception where appropriate. The order of these systems is the same as the asset load order, with the original/base file being first and the top level override being last.

  Notably, the merger runs at asset query time, not at startup. As with other asset files, it's perfectly valid to query one mod's specific version of the file and bypass the merger entirely. This is an important detail because it means the code querying the JSON file chooses how multiple sources of the same file get merged together. This is very useful for modders which define their own data format, because then they can also choose how to load it when they need to use it.

Solution 2: IJsonAssetMutator

  This exists in contrast to the IJsonAssetMerger interface. Unlike its sibling, this interface is controlled by the overriding mod. It's my solution to the mess that is .patch files, and provides a code solution that must be registered by the implementor during startup. Like the merger, it executes on asset query. It's just that these can't be created on the fly like mergers can.2

  Unlike mergers, mutators only get to see the final result of a merge operation. In essence, they perform post-processing on a merged JSON document. This should allow them to be as functional as possible. Similarly to mergers, these will execute by order of registration, which itself depends partly on asset load order.

  I'm hoping these two solutions allow mods to reliably and predictably load JSON files and support data merging.


  1. In general, having private assets that ignore the override system is considered poor design and is strongly discouraged. A well-made mod should account for modifications to its own data where reasonably expected. If you look at Minecraft modding, every asset is a resource pack or data pack, and thus everything can be overridden. The ability to have private assets is a privelege! 

  2. This is mostly because of an optimization pertaining to how files get recognized. The mutator needs to spit out an array of files or paths (among other options) that it can modify, and to ensure that asset loading remains fast, these results are cached and baked into code designed to work with specific files. Modifying this on the fly would have a negative performance hit, as would simply not having it in favor of dynamically querying mods to ask "anyone want to modify this before I send it out?"