Skip to content

Speed up preloads using unity-scene-repacker #157

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 20 commits into
base: master
Choose a base branch
from

Conversation

jakobhellermann
Copy link
Contributor

@jakobhellermann jakobhellermann commented Jun 30, 2025

Currently preloading loads the entire scene at startup, which is usually the slowest part of startup.

unity-scene-repacker lets us repack the game's scenes into AssetBundles which can be loaded instead.

This PR introduces a PreloadMode globalsetting, with the following modes:

  • full-scene: the current behaviour
  • repack-scene: repacks the scenes into an AssetBundle containing the exact referenced scenes, but filtered to only relevant objects. The preloading code stays pretty much the same
  • repack-assets: repacks the scenes into an AssetBundle that contains the game objects separately, which can then be spawned using `bundle.LoadAsset("SceneName/path/to/object.prefab"). For compatibility with the current API, every object still gets spawned in the beginning and handed off to the mods.

Some rough benchmarking with a few mods enabled:

  • 20s full-scene
  • 9s repack-scene
  • 5s repack-assets
    However, only full-scene and repack-scene modes support sceneHooks.

In this PR:

  • new preloader strategies 7be2e86 a81730f
    • this include a new unityscenerepacker.dll (or libunityscenerepacker.{so,dylib} on linux/macOS)
  • remove $(SolutionDir) from csproj f9f50d0 this enabled dotnet build Assembly-CSharp --runtime win-x64 which is required to copy the native dependencies.
  • fix smoothing of progress bar f3f77be
    • previously, when progress was made too fast, it would never actually catch up
  • add <CopyDir> csproj variable which you can set to your game to automatically copy files on build, simplifying the build -> run -> edit cycle (I can move this to another PR or delete this if y'all don't like this)

@jakobhellermann jakobhellermann marked this pull request as draft June 30, 2025 20:03
@jakobhellermann
Copy link
Contributor Author

Draft because the version of https://github.com/jakobhellermann/unity-scene-repacker used is not yet released and currently contains some hardcoded data for Hollow Knight I want to remove first.

@jakobhellermann
Copy link
Contributor Author

Test build: MAPI-windows.zip

@BadMagic100
Copy link
Contributor

Practically speaking, I think having this as a mapi global setting is bad since the majority of users will see no benefits from the feature that way. I would propose the following approach instead:

  • Possibility of different strategies per mod
  • By default, all mods use repack-scene for a modest performance improvement
  • Mods which don't implement PreloadSceneHooks can opt themselves in to repack-assets for even better performance. Perhaps also worth considering, since this is opt-in anyway, making the API break that was discussed in discord to just be handed the assetbundle for even better performance
  • Optional: add a legacyPreloads global setting (default false) to allow players to revert to the current behavior instead of repack-scene by default. Would allow players to work around any incompatibilities

@PrashantMohta
Copy link
Contributor

I think having an opt out ( setting it to enabled by default) will be good enough for players wanting to kill switch it.

for mods wanting to use scene hooks, they should be able to indicate somehow that they care to hook into some scenes and only those should be loaded in that case.

@jakobhellermann
Copy link
Contributor Author

Practically speaking, I think having this as a mapi global setting is bad since the majority of users will see no benefits from the feature that way. I would propose the following approach instead:

Yes, it makes sense to have this enabled my default. I mostly did it this way first in case we wanted to do some testing before rolling it out, in case there are any issues that come up. E.g., I haven't tested this on macOS, and I wonder if the native dependency immediately works on apple silicon.

Mods which don't implement PreloadSceneHooks can opt themselves in to repack-assets for even better performance.

Since we know what mods request scene hooks, we could also do that automatically. Use repack-scene for those that need it, and repack-assets otherwise.

case PreloadMode.RepackAssets:
if (usesSceneHooks) {
Logger.APILogger.LogWarn($"Some mods ({string.Join(", ", sceneHooks.Keys)}) use scene hooks, falling back to \"RepackScene\" preload mode");
yield return DoPreloadClassic(toPreload, preloadedObjects, sceneHooks, true);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This name implies to me that it's using FullScene, not RepackScene

Copy link
Contributor Author

@jakobhellermann jakobhellermann Jul 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed it to

IEnumerator DoPreloadAssets(...) {
  if(uses scenehooks) return DoPreloadRepackedScenes(...);
}
IEnumerator DoPreloadRepackedScenes(...) {
  // repack bundle
  DoPreloadScenes(..., "mapi_preload_assetbundle");
}
IEnumerator DoPreloadScenes(..., sceneprefix = "")

By extracting `DoPreloadRepackedScenes` into a separate method, that
just passes the scenePrefix to `DoPreloadScenes`.
previously this was hardcoded in the unityscenerepacker dll
@jakobhellermann jakobhellermann marked this pull request as ready for review July 2, 2025 13:15
Comment on lines +139 to +140
<!-- generated using https://github.com/jakobhellermann/unity-scene-repacker/blob/main/examples/export_monobehaviour_typetrees.rs -->
<EmbeddedResource Include="monobehaviour-typetree-dump.lz4" />
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When packing the scenes into an assetbundle, we need to have information about the layout of the serialized data of the game's MonoBehaviours, so that we can patch up some layout changes.

Here I'm just bundling them into the dll (they're 200KiB big).

But the question is, does the modding API support earlier game versions as well?
In that case, this would have to be done differently:

  1. include a dump for each game version
  2. generate the dumps at runtime:

Copy link
Collaborator

@Yurihaia Yurihaia Jul 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But the question is, does the modding API support earlier game versions as well?

we only support the current version really. there are builds for some earlier patches but they don't really need these types of new features (and the API itself is wildly different)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants