-
Notifications
You must be signed in to change notification settings - Fork 67
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
base: master
Are you sure you want to change the base?
Speed up preloads using unity-scene-repacker
#157
Conversation
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. |
b947780
to
cfa8860
Compare
Test build: MAPI-windows.zip |
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:
|
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. |
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.
Since we know what mods request scene hooks, we could also do that automatically. Use |
Assembly-CSharp/Preloader.cs
Outdated
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); |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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
<!-- generated using https://github.com/jakobhellermann/unity-scene-repacker/blob/main/examples/export_monobehaviour_typetrees.rs --> | ||
<EmbeddedResource Include="monobehaviour-typetree-dump.lz4" /> |
There was a problem hiding this comment.
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:
- include a dump for each game version
- generate the dumps at runtime:
- either inside
unityscenerepacker.dll
using TypeTreeGeneratorAPI, but that would be an extra18MiB
dll we have to distribute - or generate the type trees here in the modding API using https://github.com/nesrak1/AssetsTools.NET, but that would have more complexity in this project
- either inside
There was a problem hiding this comment.
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)
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 behaviourrepack-scene
: repacks the scenes into anAssetBundle
containing the exact referenced scenes, but filtered to only relevant objects. The preloading code stays pretty much the samerepack-assets
: repacks the scenes into anAssetBundle
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-scene9s
repack-scene5s
repack-assetsHowever, only full-scene and repack-scene modes support
sceneHooks
.In this PR:
unityscenerepacker.dll
(orlibunityscenerepacker.{so,dylib}
on linux/macOS)$(SolutionDir)
from csproj f9f50d0 this enableddotnet build Assembly-CSharp --runtime win-x64
which is required to copy the native dependencies.<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)