unity

[Unity 3d] unity_cecil_example(元

2019-07-12  本文已影响3人  雨落随风

教你如何使用 Mono.Cecil 进行元数据编程。

GitHub 上的工程多如繁星,有些好的仓库,但凡不经意间错过了就很难找回,故稍作采撷,希望能帮助到有心人。

简介:

笔者今天推荐的仓库叫 unity_cecil_example
Proof of concept to show how Mono.Cecil can be used with Unity for metaprogramming
验证使用Mono.Cecil在Unity进行元数据编程的可行性。

功能:

For the purposes of this blog post, I'll just create a simple post processor that adds logging in and out of functions which are marked with a special attribute. A tool like this could be used just for debug builds, but stripped out of release. In his talk, JB Evain showed some interesting examples like inserting sanity checks on function parameters, amongst other things.

这个仓库作者借助 Mono.Cecil 在Unity 中通过不修改 C#源代码而直接将逻辑插入 Dll 中!需要插入逻辑的方法只需要冠上一个特定的属性即可:[Log] .

使用:

using UnityEngine;
using System.Collections;

public class Test : MonoBehaviour 
{
    private void Start()
    {
        this.LogTest();
    }

    [Log] //写一个自定义的特定属性标记这个方法会被插入逻辑
    private void LogTest()
    {
        Debug.Log( "Here's some logic" );
    }
}
[InitializeOnLoad]
public static class AssemblyPostProcessor
{
    static AssemblyPostProcessor()
    {
        try
        {
            // 锁定程序集避免被其它地方意外加载
            EditorApplication.LockReloadAssemblies();

            foreach( System.Reflection.Assembly assembly in AppDomain.CurrentDomain.GetAssemblies() )
            {
                // 仅仅处理工程引用或者编译好的 dll (这是DLL编译后存放的路径)
                if( assembly.Location.Replace( '\\', '/' ).StartsWith( Application.dataPath.Substring( 0, Application.dataPath.Length - 7 ) ) )
                {
                    AssemblyDefinition assemblyDefinition = AssemblyDefinition.ReadAssembly( assembly.Location );
                    AssemblyPostProcessor.PostProcessAssembly( assemblyDefinition ); //此处调用后期处理逻辑
                }
            }
            // 当上述处理搞定了就解锁程序集
            EditorApplication.UnlockReloadAssemblies();
        }
        catch( Exception e )
        {
            Debug.LogWarning( e );
        }
    }
}
MethodReference logMethodReference = moduleDefinition.Import( typeof( Debug ).GetMethod( "Log", new Type[] { typeof( object ) } ) );

ILProcessor ilProcessor = methodDefinition.Body.GetILProcessor();

Instruction first = methodDefinition.Body.Instructions[0];
ilProcessor.InsertBefore( first, Instruction.Create( OpCodes.Ldstr, 
"Enter " + typeDefinition.FullName + "." + methodDefinition.Name ) );
ilProcessor.InsertBefore( first, Instruction.Create( OpCodes.Call, logMethodReference ) );

Instruction last = methodDefinition.Body.Instructions[
methodDefinition.Body.Instructions.Count - 1];
ilProcessor.InsertBefore( last, Instruction.Create( OpCodes.Ldstr, 
"Exit " + typeDefinition.FullName + "." + methodDefinition.Name ) );
ilProcessor.InsertBefore( last, Instruction.Create( OpCodes.Call, logMethodReference ) );

Tips : 所有代码仅为片段截取,所以有兴趣的请务必Down下来跑跑。

演示:

链接:

Proof of concept to show how Mono.Cecil can be used with Unity for metaprogramming

结语:

目前该作者只是简单的在原逻辑前后各插入了一段Debug.log,但是在实际生产中还可以开开脑洞高搞事情,譬如雨凇Mo就用它做性能检查,就问酷不酷!

扩展阅读:

Integrating Mono.Cecil with Unity — Coder's Block - Game Development, Netcode, C++, Tea
Unity3D研究院自动注入代码统计每个函数的执行效率以及内存分配(九十八) | 雨松MOMO程序研究院

本文集持续更新ing,喜欢记得点赞关注哦!

上一篇下一篇

猜你喜欢

热点阅读