Unity热更新Lua 插件Emmylua 补上CS代码属性方法呼出小工具
使用Emmylua的时候尽管可以给本身Lua文件编辑属性函数注解,但是缺少Unity端CS代码的属性方法呼出, 平时也需要经常使用到。写了个小工具,按照Emmylua的规格导出一份CS代码类属性方法等的注解文件,以方便使用CS代码。编译CS代码为Lua注解, 自己写的代码也一并导出
小工具位置和导出位置
导出的GameObject的示例
使用方法一
使用方法二
//Author : Bell
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using UnityEditor;
using UnityEngine;
namespace Assets.Editor
{
public class GeneratorCSToLuaComment
{
public static string OutPutPath = Application.dataPath + "/LuaScripts/src/Gen/Comment/";
public static List<string> FilterFileNameList = new List<string>() { &#34;CS_UnityEditor&#34;, &#34;_Editor_&#34; , &#34;CS_Microsoft_&#34; ,&#34;CS_System_&#34;};
public static void GenAllComment()
{
List<Type> typeList = GetCSTypes();
int removed = typeList.RemoveAll(type => type.BaseType != null && type.BaseType == typeof(UnityEditor.Editor));
GenLuaCommentReference(typeList, OutPutPath);
}
public static List<Type> GetAllTypes(bool exclude_generic_definition = true)
{
List<Type> allTypes = new List<Type>();
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
for (int i = 0; i < assemblies.Length; i++)
{
try
{
allTypes.AddRange(assemblies.GetTypes().Where(type => exclude_generic_definition ? !type.IsGenericTypeDefinition : true));
}
catch (Exception)
{
}
}
return allTypes;
}
public static List<Type> GetCSTypes()
{
List<Type> list = GetAllTypes();
//extra class
list.Add(typeof(UnityEngine.AI.NavMesh));
list.Add(typeof(UnityEngine.AI.NavMeshAgent));
return list;
}
/// <summary>
/// 编译出Lua注释引用追踪
/// </summary>
/// <param name=&#34;types&#34;></param>
/// <param name=&#34;save_path&#34;></param>
static void GenLuaCommentReference(IEnumerable<Type> types, string save_path)
{
if (!Directory.Exists(save_path)) Directory.CreateDirectory(save_path);
int exportCount = 0;
Dictionary<string, bool> existPropertyMethodDic = new Dictionary<string, bool>();
Dictionary<string, bool> existClassDic = new Dictionary<string, bool>();
types = types.Where(type => !type.IsEnum);
foreach (var wrap_type in types)
{
existPropertyMethodDic.Clear();
var fullName = null != wrap_type.DeclaringType ? wrap_type.DeclaringType.FullName : wrap_type.FullName;
if (fullName.Contains(&#34;+&#34;)) continue;
string classFileName = &#34;CS_&#34; + NormalizeName(fullName);
if (existClassDic.ContainsKey(classFileName))
{
Debug.Log(&#34;Duplicate Class :&#34; + classFileName);
continue;
}
existClassDic = true;
if (IsFilterFileName(classFileName))
{
Debug.Log(&#34;Skip Editor Class :&#34; + classFileName);
continue;
}
if (!IsFileNameValid(classFileName))
{
Debug.Log(&#34;Skip InValid File Name :&#34; + classFileName);
continue;
}
string filePath = save_path + classFileName + &#34;.lua&#34;;
try
{
using (StreamWriter textWriter = new StreamWriter(filePath, false, Encoding.UTF8))
{
textWriter.WriteLine(&#34;---AUTO GENERATE! DON&#39;T CHANGE!!!---&#34;);
textWriter.WriteLine(&#34;---Do not require this in another lua file! ---&#34;);
textWriter.WriteLine();
//string fullName = wrap_type.FullName;
//int plusIndex = fullName.IndexOf(&#34;+&#34;);
//if (0 < plusIndex) fullName = fullName.Substring(0, plusIndex);
textWriter.WriteLine(&#34;---@class CS.&#34; + fullName);
//属性
FieldInfo[] fields = wrap_type.GetFields();
foreach (FieldInfo field in fields)
{
if (!existPropertyMethodDic.ContainsKey(field.Name) && !field.Name.Contains(&#34;<>&#34;))
{
textWriter.WriteLine(&#34;---@field &#34; + ConverInValidName(field.Name) + &#34; &#34; + ConvertTypeToLuaType(field.FieldType.FullName));
existPropertyMethodDic = true;
}
}
PropertyInfo[] pInfos = wrap_type.GetProperties();
foreach (PropertyInfo property in pInfos)
{
if (!existPropertyMethodDic.ContainsKey(property.Name) && !property.Name.Contains(&#34;<>&#34;))
{
textWriter.WriteLine(&#34;---@field &#34; + ConverInValidName(property.Name) + &#34; &#34; + ConvertTypeToLuaType(property.PropertyType.FullName));
existPropertyMethodDic = true;
}
}
var methods = wrap_type.GetRuntimeMethods();
textWriter.WriteLine(&#34;local proto = {}&#34;);
foreach (var method in methods)
{
if (!existPropertyMethodDic.ContainsKey(method.Name)
&& method.Name.IndexOf(&#34;set_&#34;) != 0
&& method.Name.IndexOf(&#34;get_&#34;) != 0
&& !method.Name.Contains(&#34;.&#34;)
&& !method.Name.Contains(&#34;<&#34;))
{
ParameterInfo[] prms = method.GetParameters();
string paramChars = &#34;&#34;;
int index = 0;
foreach (ParameterInfo parameter in prms)
{
string prmType = parameter.ParameterType.ToString().Replace(&#34;&&#34;, &#34;&#34;);
prmType = ConvertTypeToLuaType(prmType);
textWriter.WriteLine(&#34;---@param &#34; + ConverInValidName(parameter.Name) + &#34; &#34; + prmType);
if (index < prms.Length - 1) paramChars += ConverInValidName(parameter.Name) + &#34;,&#34;;
else paramChars += ConverInValidName(parameter.Name);
index++;
}
string returnType = method.ReturnType.ToString().Replace(&#34;&&#34;, &#34;&#34;);
if (returnType != &#34;System.Void&#34;)
{
textWriter.WriteLine(&#34;---@return &#34; + ConvertTypeToLuaType(returnType));
}
if (method.IsStatic)
{
textWriter.WriteLine(&#34;function proto.&#34; + method.Name + &#34;(&#34; + paramChars + &#34;)end&#34;);
}
else
{
textWriter.WriteLine(&#34;function proto:&#34; + method.Name + &#34;(&#34; + paramChars + &#34;)end&#34;);
}
existPropertyMethodDic = true;
}
}
//| BindingFlags.Public | BindingFlags.Static
}
exportCount ++;
Debug.Log(&#34;Generated Class :&#34; + filePath);
}
catch
{
Debug.Log(&#34;Can&#39;t export &#34; + filePath);
}
}
Debug.Log(&#34;Exported Lua files : &#34; + exportCount);
}
static string ConvertTypeToLuaType(string typeName)
{
switch (typeName)
{
case &#34;System.Boolean&#34;: return &#34;boolean&#34;;
case &#34;System.Object&#34;: return &#34;object&#34;;
case &#34;System.Int32&#34;: return &#34;number&#34;;
case &#34;System.Single&#34;: return &#34;number&#34;; //float
case &#34;System.String&#34;: return &#34;string&#34;;
case &#34;System.UInt64&#34;: return &#34;number&#34;;
case &#34;System.Double&#34;: return &#34;number&#34;;
case &#34;System.Boolean[]&#34;: return &#34;boolean[]&#34;;
case &#34;System.Object[]&#34;: return &#34;object[]&#34;;
case &#34;System.Int32[]&#34;: return &#34;number[]&#34;;
case &#34;System.Single[]&#34;: return &#34;number[]&#34;;
case &#34;System.String[]&#34;: return &#34;string[]&#34;;
case &#34;System.UInt64[]&#34;: return &#34;number[]&#34;;
case &#34;System.Double[]&#34;: return &#34;number[]&#34;;
default: return &#34;CS.&#34; + typeName;
}
}
static string ConverInValidName(string paramName)
{
switch (paramName)
{
case &#34;end&#34;: return &#34;_end_&#34;;
case &#34;local&#34;: return &#34;_local_&#34;;
case &#34;function&#34;: return &#34;_function_&#34;;
default: return paramName;
}
}
static bool IsFilterFileName(string fileName)
{
foreach (string filter in FilterFileNameList)
{
if (fileName.Contains(filter))
{
return true;
}
}
return false;
}
static string NormalizeName(string name)
{
return name.Replace(&#34;+&#34;, &#34;_&#34;).Replace(&#34;.&#34;, &#34;_&#34;).Replace(&#34;`&#34;, &#34;_&#34;).Replace(&#34;&&#34;, &#34;_&#34;).Replace(&#34;[&#34;, &#34;_&#34;).Replace(&#34;]&#34;, &#34;_&#34;).Replace(&#34;,&#34;, &#34;_&#34;);
}
private static bool IsFileNameValid(string name)
{
bool isFilename = true;
string[] errorStr = new string[] { &#34;/&#34;, &#34;\\&#34;, &#34;:&#34;, &#34;,&#34;, &#34;*&#34;, &#34;?&#34;, &#34;\&#34;&#34;, &#34;<&#34;, &#34;>&#34;, &#34;|&#34; };
if (string.IsNullOrEmpty(name))
{
isFilename = false;
}
else
{
for (int i = 0; i < errorStr.Length; i++)
{
if (name.Contains(errorStr))
{
isFilename = false;
break;
}
}
}
return isFilename;
}
}
}
小工具还有很多不足,比如泛型问题。
编译导出的文件只是注解文件,不需要和其他热更新文件一起打包。
如有需要可以在工具中修改导出位置, 添加一些想排除的类型等 (请随意)。
EmmyLuaUnity插件 好像也有这个功能。求推荐更好的插件。
页:
[1]