Assembly injection
This PR allows users classes to be injected into assembly with the same name as their mod assembly, instead of InjectedMonoTypes.
There are two benefits from this:
- Users can declare their assemblies in Unity Editor using asmdefs or use custom precompiled assemblies
- Because types exist in the correct assembly according to il2cpp runtime, any code which checks assembly will work correctly. For example Burst runtime checks assembly name, so with this change adding custom Bursted code becomes possible.
The changes are backwards compatible. Despite the classes now being defined in the mod assembly, they will still correctly deserialize because we inject classes into every assembly that exists.
To implement this I had to determine a list of possible assemblies very early, so plugins folder scanning is performed.
Also I needed to modify contents of ScriptingAssemblies.json file in the game Data folder, because Unity seems to get a list of assemblies from there. A backup of original is created.
I have implemented IAT hooking, so no files are modified now. Assembly scanning now should be performed by mod loader by adding AssemblyInjectorComponent.
I have tested these changes on Core Keeper Unity 2021.3.14.
@limoka can you rebase?
@ds5678 rebased as you asked. Sorry it took a while, I was busy with IRL things.
As far as I remember this one is blocked by lack of Linux support. Unfortunately I don't actually use Linux, and don't have enough knowledge about it to make these changes work there.
I also included a commit I made, but never pushed. It should make this code work on Unity 2019.
I'm hesitant to dedicate time towards reviewing this if it does not support all platforms.
Why can't this be fixed by patching one or more of these?
DO_API(Il2CppDomain*, il2cpp_domain_get, ());
DO_API(const Il2CppAssembly*, il2cpp_domain_assembly_open, (Il2CppDomain * domain, const char* name));
DO_API(const Il2CppAssembly**, il2cpp_domain_get_assemblies, (const Il2CppDomain * domain, size_t * size));
@ds5678 I don't remember full details, but the reason is: they aren't connected to the root cause of the issue. They merely mirror what native Unity side knows.
And Native Unity code makes an assembly list some time really early, by reading one of the files I edit. Then whenever someone asks for assembly by name, it uses that list.
Because the aim of this is to allow scripts in other assemblies for serialization purposes, the code that asks also lives on native side. As such patching methods you mentioned won't do anything.
So then what are these exposed api used for?
In fact this is an issue that plagues all kinds of Unity modding: Assemblies added by mods never properly work for serialization purposes
Related project: https://github.com/xiaoxiao921/FixPluginTypesSerialization
So then what are these exposed api used for?
Unfortunately I don't remember, and can't answer right now. All I remember is that patching them does nothing to fix this