a simple implementation of virtual machine which can run il parsed by mono cecil.
click Hello
button, you will see a log Hello World
in the console:
which is run by vm, not directly call.
see HelloBtn.cs
:
load assembly by Mono.Cecil first (we default load assembly currently in use, you can replace it also):
// default parse from: "Library/ScriptAssemblies/Assembly-CSharp.dll"
using (var assemblyHandle = new AssemblyHandle())
{
// ...
}
get MethodDefinition
of method which you want to invoke:
// get MethodDefinition of HelloBtn.SayHello
var assemblyDef = assemblyHandle.GetAssembly();
var classTypeDef = assemblyDef.MainModule.GetType("HelloBtn");
var methodTypeDef = classTypeDef.Methods.First(m => m.Name == "SayHello");
invoke it by vm:
var vm = new ILVirtualMachine();
var parameters = new object[] { this };
vm.Execute(methodTypeDef, parameters);
you can treat this as a enhanced version of Unity-CSharpHotfix.
it can also replace c# method logic at runtime without stop unity play (and with less bugs).
to do this, you need do:
- compile: generate .dll with new method code, then rollback, we will hotfix old .dll by new one
- inject: add marks on method you want to modify later
- hotfix: run hotfix, then the method logic is replaced by new logic
for example, modify HelloBtn.cs
as:
// use ILVM.Hotfix to mark the method need be replaced
[ILVM.Hotfix]
public void OnClick()
{
// these are new logic
Debug.Log("Hello World after hotfix");
// these are old logic
// // default parse from: "Library/ScriptAssemblies/Assembly-CSharp.dll"
// using (var assemblyHandle = new AssemblyHandle())
// {
// // get MethodDefinition of HelloBtn.SayHello
// var assemblyDef = assemblyHandle.GetAssembly();
// var classTypeDef = assemblyDef.MainModule.GetType("HelloBtn");
// var methodTypeDef = classTypeDef.Methods.First(m => m.Name == "SayHello");
// // invoke method by Virual Machine
// var vm = new ILVirtualMachine();
// var parameters = new object[] { this };
// vm.Execute(methodTypeDef, parameters);
// }
}
compile code, we will get a new Assembly-CSharp.dll.
move it to {project}/Library/ILVM
folder,
then rollback code modifications.
you need add HelloBtn
to ILVmInjectConfig.json
:
{
"injectClass": [
"HelloBtn"
],
"nameSpaceFilter": [
"ILVM",
"System",
"UnityEngine",
"UnityEditor"
],
"classNameFilter": [
"ConsoleProDebug"
],
"methodNameFilter": [
]
}
- injectClass: the class type you may hotfix later
- **Filter: blacklist, filter the namespace & class & method you dont want to hotfix. cause if there're too many, inject will run slowly.
then click Unity Toolbar->ILVM->Inject
:
play game, click hello btn, sill get Hello World
in console:
then click Unity Toolbar->ILVM->Hotfix
:
also you can use Clear Hotfix
to rollback to old logic.