How TEngine Loads Hot Update Assemblies at Runtime: A HybridCLR Deep Dive
TEngine uses a HybridCLR-based workflow to load hot-update assemblies at runtime by downloading compiled DLLs as binary TextAssets, loading them via Assembly.Load, and injecting them into the game entry point.
TEngine, an open-source Unity game framework maintained by alex-rachel, implements a sophisticated hot-update mechanism using HybridCLR to patch game logic without rebuilding the entire player. This system leverages runtime assembly loading to streamline the update pipeline, enabling developers to distribute code fixes as lightweight binary assets.
The Hot Update Assembly Loading Pipeline
Configuration and Assembly Manifest
The process begins in UnityProject/Assets/TEngine/Runtime/Core/UpdateSetting.cs, where the HotUpdateAssemblies array defines which DLLs require hot updating. According to the source code at lines 71-74, this list typically includes assemblies like GameProto.dll and GameLogic.dll. The framework also uses LogicMainDllName to identify the primary game logic assembly that serves as the entry point.
Async Asset Retrieval
Inside UnityProject/Assets/GameScripts/Procedure/ProcedureLoadAssembly.cs, the LoadAssembly coroutine (lines 78-93) iterates through the hot-update list. For each assembly name, it constructs the asset path following the pattern Assets/AssetRaw/DLL/{name}.dll.bytes and calls ResourceModule.LoadAssetAsync<TextAsset> to retrieve the binary data asynchronously.
Runtime Assembly Instantiation
Once the asset loads, the LoadAssetSuccess callback (lines 97-104) receives the TextAsset and invokes Assembly.Load(textAsset.bytes) to create an in-memory assembly. The code tracks these assemblies in two ways:
- If the DLL matches
UpdateSetting.LogicMainDllName, it stores the reference in_mainLogicAssembly. - All hot-update assemblies append to
_hotfixAssemblyListfor later use.
Entry Point Resolution and Invocation
After all assets finish loading (tracked via _loadAssemblyComplete when _loadAssetCount reaches zero at lines 122-129), the GetMainLogicAssembly method (lines 152-169) iterates through AppDomain.CurrentDomain.GetAssemblies() to locate the main logic assembly. TEngine then reflects the GameApp type, finds its Entrance method, and invokes it while passing the complete list of hot-update assemblies (lines 134-148).
AOT Metadata Handling
When UpdateSetting.Enable is true, the framework calls LoadMetadataForAOTAssembly (lines 221-238) to load original metadata for ahead-of-time compiled assemblies. This enables the interpreter to handle missing generic methods that were stripped during the AOT compilation process.
Critical Source Files in the Loading Chain
UnityProject/Assets/GameScripts/Procedure/ProcedureLoadAssembly.cs: Contains the coreProcedureLoadAssemblyclass that orchestrates the async loading, assembly instantiation, and entry point invocation.UnityProject/Assets/TEngine/Runtime/Core/UpdateSetting.cs: Defines theHotUpdateAssembliesarray and configuration flags that control the hot-update behavior at lines 71-74.UnityProject/Assets/TEngine/Editor/HybridCLR/BuildDLLCommand.cs: Build-time utility that copies generated hot-update DLLs into theAssetRaw/DLLfolder used at runtime.UnityProject/Assets/TEngine/Runtime/Core/Utility/Assembly/Utility.Assembly.cs: Provides helper methods likeGetAssembliesfor runtime assembly discovery.
Runtime Loading Code Example
The following simplified example demonstrates the essential loading logic found in ProcedureLoadAssembly.cs:
// Inside ProcedureLoadAssembly.LoadAssembly()
foreach (var hotUpdateDllName in Settings.UpdateSetting.HotUpdateAssemblies)
{
var assetPath = $"Assets/{Settings.UpdateSetting.AssemblyTextAssetPath}/{hotUpdateDllName}{Settings.UpdateSetting.AssemblyTextAssetExtension}";
var textAsset = await ResourceModule.LoadAssetAsync<TextAsset>(assetPath);
var assembly = Assembly.Load(textAsset.bytes);
_hotfixAssemblyList.Add(assembly);
}
After loading completes, the framework invokes the game entry point:
// From lines 134-148 in ProcedureLoadAssembly.cs
var gameAppType = _mainLogicAssembly.GetType("GameApp");
var entranceMethod = gameAppType.GetMethod("Entrance", BindingFlags.Static | BindingFlags.Public);
entranceMethod?.Invoke(null, new object[] { _hotfixAssemblyList });
Summary
- TEngine implements hot updates through HybridCLR integration, allowing runtime loading of compiled DLLs in IL2CPP builds.
- The UpdateSetting configuration file defines which assemblies participate in the hot-update cycle via the
HotUpdateAssembliesarray. - Assembly.Load transforms binary TextAssets into executable code at runtime without requiring application restart.
- The ProcedureLoadAssembly procedure manages async asset loading, assembly tracking via
_hotfixAssemblyList, and entry point invocation through reflection. - Optional AOT metadata loading ensures compatibility with ahead-of-time compiled assemblies by providing fallback interpreter support for stripped generic methods.
Frequently Asked Questions
What is the role of HybridCLR in TEngine's hot update system?
HybridCLR provides the underlying technology that enables loading .NET assemblies at runtime in Unity IL2CPP builds. TEngine leverages this to load updated game logic DLLs without requiring a full application rebuild, allowing patches to be distributed as small binary assets that the engine loads via Assembly.Load.
How does TEngine know which assemblies to load for hot updating?
The framework checks the HotUpdateAssemblies array defined in UnityProject/Assets/TEngine/Runtime/Core/UpdateSetting.cs (lines 71-74). This configurable list specifies the DLL names that the ProcedureLoadAssembly procedure will attempt to load from the Assets/AssetRaw/DLL/ directory at runtime.
Where does TEngine store the hot update DLL files before loading them?
At build time, BuildDLLCommand.cs copies the compiled hot-update DLLs to UnityProject/Assets/AssetRaw/DLL/ with a .dll.bytes extension. At runtime, ProcedureLoadAssembly.cs loads these as Unity TextAssets using ResourceModule.LoadAssetAsync<TextAsset> before converting them to assemblies via Assembly.Load.
What happens after TEngine loads the hot update assemblies?
Once loading completes, TEngine locates the GameApp type within the main logic assembly and invokes its static Entrance method, passing the list of loaded hot-update assemblies. This transfers control to the updated game logic while maintaining references to all patched assemblies in _hotfixAssemblyList.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →