【Unity3D】默认编辑器逻辑修改
2023-06-05 本文已影响0人
crossous
有时候我们不清楚Unity编辑器的逻辑是如何执行的,可以通过查看UnityCsReference查看相关逻辑。有些实用的方法Unity没有开放出来,而做自定义工具会用到,因此可以利用反射来获取这些隐藏的方法。
有时我们需要给修改一些默认逻辑,例如在烘焙光照前后执行某些逻辑,例如执行其他自定义烘焙逻辑、弹出窗口提醒美术操作等,方便和规范美术的流程。
修改源码当然是一种操作,但这样不方便迭代,也不方便升级、切换引擎版本,对项目用到的引擎还要严格规范,这样不是一个好的方法。
然后想到了Hook,既然能用UnityCsReference获取到函数的MethodInfo,那么用Hook就可以在关键函数的执行前后插入自己的逻辑、修改原有逻辑。
例如Unity生成光照按钮的方法(从UnityCsReference找的):
namespace UnityEditor
{
internal class LightingWindowLightingTab
{
public void OnGUI()
{
//something
Buttons();
}
void Buttons()
{
//something
DoBake();
}
}
}
里面的DoBake就是我们关注的方法,如果我们想要在Bake前执行操作,就需要对DoBake函数进行Hook。
本来想查Unity C#如何Hook,发现Misaka佬已经有现成的库可用:MonoHook。
因此写了如下的Hook方法:
using System;
using System.Reflection;
using System.Runtime.CompilerServices;
using MonoHook;
using UnityEditor;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor.Callbacks;
/// <summary>
/// 修改烘焙逻辑
/// </summary>
[InitializeOnLoad]
public static class GenerateLightingCallback
{
private static MethodHook _hook;
static GenerateLightingCallback()
{
if (_hook == null)
{
Type type = Type.GetType("UnityEditor.LightingWindowLightingTab,UnityEditor.dll");
MethodInfo DoBakeTarget = type.GetMethod("DoBake", BindingFlags.Instance | BindingFlags.NonPublic);
MethodInfo Replacement = new Action(NewBakeMethod).Method;
MethodInfo Proxy = new Action(ProxyBakeFunction).Method;
_hook = new MethodHook(DoBakeTarget, Replacement, Proxy);
_hook.Install();
}
}
//Bake 前要做的逻辑
private static void OnBake()
{
//这里可以注册一些方法来执行
Debug.Log("generate lighting!");
}
#region private
[MethodImpl(MethodImplOptions.NoInlining)]
private static void NewBakeMethod()
{
OnBake();//自定义逻辑
ProxyBakeFunction();//调用原来的逻辑
}
//原方法占用,逻辑不重要,不会执行
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
private static void ProxyBakeFunction()
{
// 随便乱写点东西以占据空间
for (int i = 0; i < 100; i++)
{
UnityEngine.Debug.Log("something");
}
UnityEngine.Debug.Log(Application.targetFrameRate);
}
#endregion
}
#endif