环境:Unity2017.2 语言:C#
总起:
今天同事在做自动化的工具,需要在脚本编译完成之后回调一个函数。我在Google上找到UnityEditor.Callbacks.DidReloadScripts这个标签可以在编译完成后,Unity自动帮忙回调。
但是这样很麻烦,可不可以像是主动设置一个函数名称,等编译完成之后进行回调呢?
通过EditorPrefs对需要回调函数名的存储,我大体上完成了以上的想法。
代码:
将以下代码放到Editor文件夹下:
// CompilingFinishedCallback.cs
using System;
using System.Linq;
using System.Reflection;
using UnityEditor;
using UnityEngine;
public static class CompilingFinishedCallback
{
private static string TmpMethodNamesKey = "CompilingFinishedCallback_TmpMethodNames";
public static void Set<T>(string methodName, string arg = null)
{
var type = typeof(T);
string methoedName = type.FullName + "." + methodName + "(" + arg + ")";
AddTmpMethodName(methoedName);
}
static string[] GetTmpMethodNameArr()
{
return GetTmpMethodNames().Split(';').Where(value=>value != null && value.Trim() != "").ToArray();
}
static void AddTmpMethodName(string value)
{
SetTmpMethodNames(GetTmpMethodNames() + ";" + value);
}
static string GetTmpMethodNames()
{
if (EditorPrefs.HasKey(TmpMethodNamesKey))
return EditorPrefs.GetString(TmpMethodNamesKey);
return "";
}
static void SetTmpMethodNames(string value)
{
EditorPrefs.SetString(TmpMethodNamesKey, value);
}
[UnityEditor.Callbacks.DidReloadScripts]
private static void OnScriptsReloaded()
{
var methods = GetTmpMethodNameArr();
foreach (var method in methods)
{
var pointIndex = method.LastIndexOf(".");
var left = method.LastIndexOf("(");
var right = method.LastIndexOf(")");
string className = method.Substring(0, pointIndex);
string methodName = method.Substring(pointIndex + 1, left - pointIndex - 1);
string argName = method.Substring(left + 1, right - left - 1);
Type type = Type.GetType(className);
if (type == null)
{
Debug.LogError("type == null");
continue;
}
var method1 = type.GetMethod(methodName, BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public, null, new Type[] { }, null);
var method2 = type.GetMethod(methodName, BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public, null, new Type[] { typeof(string) }, null);
if (method1 == null && method2 == null)
{
Debug.LogError("method1 == null && method2 == null");
continue;
}
if (method1 != null && argName.Trim() == "")
method1.Invoke(null, null);
if (method2 != null && argName.Trim() != "")
method2.Invoke(null, new object[] {argName});
}
SetTmpMethodNames("");
}
}
思路比较简单,就是把函数名存起来,等回调的时候,通过反射进行调用。
新建一个Test来试试效果(放在Editor文件夹下):
// Test.cs
using UnityEditor;
using UnityEngine;
public class Test
{
[MenuItem("Tool/test")]
public static void Start()
{
CompilingFinishedCallback.Set<Test>("Log");
CompilingFinishedCallback.Set<Test>("Log", "arg");
}
private static void Log()
{
Debug.Log("log");
}
private static void Log(string arg)
{
Debug.Log(arg);
}
}
首先点击菜单栏的Tool/test按钮,再随便改动一下脚本触发编译,最终效果: