先说说Unity热跟新方案
1.LuaInterface CS2Lua simpleFramWork ulua (不再维护)
2.tolua 基于tolua 开发了 luaFramwork
3 Slua 代码质量好,性能比tolua 低
4C#light (c#like) Lsharp 很少用于商业
5 腾讯的xlua
说说 LuaInterface
LuaForWindows下载地址:http://luaforge.net/projects/luaforwindows/
LuaInterface下载地址:http://luaforge.net/projects/luainterface/ (下载luainterface-1.5.3,这里面的资源比较多,还有比较完整的示例代码。)
LuaInterface.Lua类是CLR访问Lua解释器的主要接口,一个LuaInterface.Lua类对象就代表了一个Lua解释器(或Lua执行环境),Lua解释器可以同时存在多个,并且它们之间是完全相互独立的。
xlua传送门
https://github.com/Tencent/xLua
FAQ 常见问题
https://github.com/Tencent/xLua/blob/master/Assets/XLua/Doc/faq.md
对于lua 不熟悉的
http://www.runoob.com/lua/lua-tutorial.html
xlua 运行过程
c#源代码 —— 编译 ——中间语言 IL——安装包
lua——安装包
xlua热跟新
开启 热跟新宏
C#代码写好了之后, 点击 Xlua-Generate Code 就会 在XLua下 Gen文件 下 生成C#的文件。 没出问题就 输出Finish
最后 再点下Hotfix Inject In Editor 就可以 开始 开始热跟新了。
对某个类打补丁
类名加[Hotfix]特性(标签)
源码
加了这个标签 后,就会注入 生成到xlua里面
提前要 在 一些 可能以后会出Bug 不确定的,会跟新的,变动的类,前面 加上[Hotfix]特性, 在可能需要改写,跟新的方法前 加上 [LuaCallCSharp] 特性, 这样 就可以在Lua里面 调用 HotFix方法。 不需要更新的,确定不用修改的可以加上黑名单[XLua.BlackList] 特性。
var extensionMethods = Utils.GetExtensionMethodsOf(toBeWrap);
源代码 ,下面这个方法 会检查标签类型。
进行 迭代,遍历一个类 里所有 是成员方法,是否有加那些特性, 所有打包的
IEnumerable<MethodInfo> extend_methods = GetExtensionMethodsOf(type);
internal static IEnumerable<MethodInfo> GetExtensionMethodsOf(Type type_to_be_extend)
{
if (InternalGlobals.extensionMethodMap == null)
{
List<Type> type_def_extention_method = new List<Type>();
IEnumerator<Type> enumerator = GetAllTypes().GetEnumerator();
while(enumerator.MoveNext())
{
Type type = enumerator.Current;
if (type.IsDefined(typeof(ExtensionAttribute), false) && (
type.IsDefined(typeof(ReflectionUseAttribute), false)
#if UNITY_EDITOR || XLUA_GENERAL
|| type.IsDefined(typeof(LuaCallCSharpAttribute), false)
#endif
))
{
type_def_extention_method.Add(type);
}
if (!type.IsAbstract() || !type.IsSealed()) continue;
var fields = type.GetFields(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly);
for (int i = 0; i < fields.Length; i++)
{
var field = fields[i];
if ((field.IsDefined(typeof(ReflectionUseAttribute), false)
#if UNITY_EDITOR || XLUA_GENERAL
|| field.IsDefined(typeof(LuaCallCSharpAttribute), false)
#endif
) && (typeof(IEnumerable<Type>)).IsAssignableFrom(field.FieldType))
{
type_def_extention_method.AddRange((field.GetValue(null) as IEnumerable<Type>)
.Where(t => t.IsDefined(typeof(ExtensionAttribute), false)));
}
}
var props = type.GetProperties(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly);
for (int i = 0; i < props.Length; i++)
{
var prop = props[i];
if ((prop.IsDefined(typeof(ReflectionUseAttribute), false)
#if UNITY_EDITOR || XLUA_GENERAL
|| prop.IsDefined(typeof(LuaCallCSharpAttribute), false)
#endif
) && (typeof(IEnumerable<Type>)).IsAssignableFrom(prop.PropertyType))
{
type_def_extention_method.AddRange((prop.GetValue(null, null) as IEnumerable<Type>)
.Where(t => t.IsDefined(typeof(ExtensionAttribute), false)));
}
}
}
enumerator.Dispose();
InternalGlobals.extensionMethodMap = (from type in type_def_extention_method
from method in type.GetMethods(BindingFlags.Static | BindingFlags.Public)
where method.IsDefined(typeof(ExtensionAttribute), false) && IsSupportedMethod(method)
group method by getExtendedType(method)).ToDictionary(g => g.Key, g => g as IEnumerable<MethodInfo>);
}
IEnumerable<MethodInfo> ret = null;
InternalGlobals.extensionMethodMap.TryGetValue(type_to_be_extend, out ret);
return ret;
}
下面是 生成反射包装的方法
static void makeReflectionWrap(RealStatePtr L, Type type, int cls_field, int cls_getter, int cls_setter,
int obj_field, int obj_getter, int obj_setter, int obj_meta, out LuaCSFunction item_getter, out LuaCSFunction item_setter, bool private_access = false)
{
ObjectTranslator translator = ObjectTranslatorPool.Instance.Find(L);
BindingFlags flag = BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | (private_access ? BindingFlags.NonPublic : BindingFlags.Public);
FieldInfo[] fields = type.GetFields(flag);
EventInfo[] all_events = type.GetEvents(flag | BindingFlags.Public | BindingFlags.NonPublic);
for (int i = 0; i < fields.Length; ++i)
{
FieldInfo field = fields[i];
string fieldName = field.Name;
if (private_access)
{
// skip hotfix inject field
if (field.IsStatic && (field.Name.StartsWith("__Hotfix") || field.Name.StartsWith("_c__Hotfix")) && typeof(Delegate).IsAssignableFrom(field.FieldType))
{
continue;
}
if (all_events.Any(e => e.Name == fieldName))
{
fieldName = "&" + fieldName;
}
}
if (field.IsStatic && (field.IsInitOnly || field.IsLiteral))
{
LuaAPI.xlua_pushasciistring(L, fieldName);
translator.PushAny(L, field.GetValue(null));
LuaAPI.lua_rawset(L, cls_field);
}
else
{
LuaAPI.xlua_pushasciistring(L, fieldName);
translator.PushFixCSFunction(L, genFieldGetter(type, field));
LuaAPI.lua_rawset(L, field.IsStatic ? cls_getter : obj_getter);
LuaAPI.xlua_pushasciistring(L, fieldName);
translator.PushFixCSFunction(L, genFieldSetter(type, field));
LuaAPI.lua_rawset(L, field.IsStatic ? cls_setter : obj_setter);
}
}
EventInfo[] events = type.GetEvents(flag);
for (int i = 0; i < events.Length; ++i)
{
EventInfo eventInfo = events[i];
LuaAPI.xlua_pushasciistring(L, eventInfo.Name);
translator.PushFixCSFunction(L, translator.methodWrapsCache.GetEventWrap(type, eventInfo.Name));
bool is_static = (eventInfo.GetAddMethod() != null) ? eventInfo.GetAddMethod().IsStatic : eventInfo.GetRemoveMethod().IsStatic;
LuaAPI.lua_rawset(L, is_static ? cls_field : obj_field);
}
Dictionary<string, PropertyInfo> prop_map = new Dictionary<string, PropertyInfo>();
List<PropertyInfo> items = new List<PropertyInfo>();
PropertyInfo[] props = type.GetProperties(flag);
for (int i = 0; i < props.Length; ++i)
{
PropertyInfo prop = props[i];
if (prop.Name == "Item" && prop.GetIndexParameters().Length > 0)
{
items.Add(prop);
}
else
{
prop_map.Add(prop.Name, prop);
}
}
var item_array = items.ToArray();
item_getter = item_array.Length > 0 ? genItemGetter(type, item_array) : null;
item_setter = item_array.Length > 0 ? genItemSetter(type, item_array) : null; ;
MethodInfo[] methods = type.GetMethods(flag);
Dictionary<MethodKey, List<MemberInfo>> pending_methods = new Dictionary<MethodKey, List<MemberInfo>>();
for (int i = 0; i < methods.Length; ++i)
{
MethodInfo method = methods[i];
string method_name = method.Name;
MethodKey method_key = new MethodKey { Name = method_name, IsStatic = method.IsStatic };
List<MemberInfo> overloads;
if (pending_methods.TryGetValue(method_key, out overloads))
{
overloads.Add(method);
continue;
}
PropertyInfo prop = null;
if (method_name.StartsWith("add_") || method_name.StartsWith("remove_")
|| method_name == "get_Item" || method_name == "set_Item")
{
continue;
}
if (method_name.StartsWith("op_")) // 操作符
{
if (InternalGlobals.supportOp.ContainsKey(method_name))
{
if (overloads == null)
{
overloads = new List<MemberInfo>();
pending_methods.Add(method_key, overloads);
}
overloads.Add(method);
}
continue;
}
else if (method_name.StartsWith("get_") && method.IsSpecialName) // getter of property
{
string prop_name = method.Name.Substring(4);
if (!prop_map.TryGetValue(prop_name, out prop))
{
prop = type.GetProperty(prop_name);
}
LuaAPI.xlua_pushasciistring(L, prop.Name);
translator.PushFixCSFunction(L, translator.methodWrapsCache._GenMethodWrap(method.DeclaringType, prop.Name, new MethodBase[] { method }).Call);
LuaAPI.lua_rawset(L, method.IsStatic ? cls_getter : obj_getter);
}
else if (method_name.StartsWith("set_") && method.IsSpecialName) // setter of property
{
string prop_name = method.Name.Substring(4);
if (!prop_map.TryGetValue(prop_name, out prop))
{
prop = type.GetProperty(prop_name);
}
LuaAPI.xlua_pushasciistring(L, prop.Name);
translator.PushFixCSFunction(L, translator.methodWrapsCache._GenMethodWrap(method.DeclaringType, prop.Name, new MethodBase[] { method }).Call);
LuaAPI.lua_rawset(L, method.IsStatic ? cls_setter : obj_setter);
}
else if (method_name == ".ctor" && method.IsConstructor)
{
continue;
}
else
{
if (overloads == null)
{
overloads = new List<MemberInfo>();
pending_methods.Add(method_key, overloads);
}
overloads.Add(method);
}
}
IEnumerable<MethodInfo> extend_methods = GetExtensionMethodsOf(type);
if (extend_methods != null)
{
foreach (var extend_method in extend_methods)
{
MethodKey method_key = new MethodKey { Name = extend_method.Name, IsStatic = false };
List<MemberInfo> overloads;
if (pending_methods.TryGetValue(method_key, out overloads))
{
overloads.Add(extend_method);
continue;
}
else
{
overloads = new List<MemberInfo>() { extend_method };
pending_methods.Add(method_key, overloads);
}
}
}
foreach (var kv in pending_methods)
{
if (kv.Key.Name.StartsWith("op_")) // 操作符
{
LuaAPI.xlua_pushasciistring(L, InternalGlobals.supportOp[kv.Key.Name]);
translator.PushFixCSFunction(L,
new LuaCSFunction(translator.methodWrapsCache._GenMethodWrap(type, kv.Key.Name, kv.Value.ToArray()).Call));
LuaAPI.lua_rawset(L, obj_meta);
}
else
{
LuaAPI.xlua_pushasciistring(L, kv.Key.Name);
translator.PushFixCSFunction(L,
new LuaCSFunction(translator.methodWrapsCache._GenMethodWrap(type, kv.Key.Name, kv.Value.ToArray()).Call));
LuaAPI.lua_rawset(L, kv.Key.IsStatic ? cls_field : obj_field);
}
}
}
发出类型打包,通过 ILGenerator 接口,调用 IL(中间语言)里 的方法,传送门 : https://blog.csdn.net/dodream/article/details/4726421
Emit类 的是CodeEmit类里的
public Type EmitTypeWrap(Type toBeWrap)
{
TypeBuilder wrapTypeBuilder = CodeEmitModule.DefineType(toBeWrap.Name + "Wrap" + (genID++), TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.Abstract | TypeAttributes.Sealed);
var methodBuilder = wrapTypeBuilder.DefineMethod("__Register", MethodAttributes.Static | MethodAttributes.Public, null, parameterTypeOfWrap);
methodBuilder.DefineParameter(1, ParameterAttributes.None, "L");
ILGenerator il = methodBuilder.GetILGenerator();
LocalBuilder translator = il.DeclareLocal(typeof(ObjectTranslator));
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Call, ObjectTranslatorPool_FindTranslator);
il.Emit(OpCodes.Stloc, translator);
var instanceFlag = BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly;
var staticFlag = BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly;
var instanceFields = toBeWrap.GetFields(instanceFlag);
var instanceProperties = toBeWrap.GetProperties(instanceFlag);
var extensionMethods = Utils.GetExtensionMethodsOf(toBeWrap);
var instanceMethods = toBeWrap.GetMethods(instanceFlag)
.Concat(extensionMethods == null ? Enumerable.Empty<MethodInfo>() : Utils.GetExtensionMethodsOf(toBeWrap))
.Where(m => Utils.IsSupportedMethod(m))
.Where(m => !m.IsSpecialName).GroupBy(m => m.Name).ToList();
var supportOperators = toBeWrap.GetMethods(staticFlag)
.Where(m => m.IsSpecialName && InternalGlobals.supportOp.ContainsKey(m.Name))
.GroupBy(m => m.Name);
//begin obj
il.Emit(OpCodes.Ldtoken, toBeWrap);
il.Emit(OpCodes.Call, Type_GetTypeFromHandle); // typeof(type)
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldloc, translator);
il.Emit(OpCodes.Ldc_I4_1);
il.Emit(OpCodes.Ldc_I4_1);
il.Emit(OpCodes.Ldc_I4_1);
il.Emit(OpCodes.Ldc_I4_1);
il.Emit(OpCodes.Ldc_I4_M1);
il.Emit(OpCodes.Call, Utils_BeginObjectRegister);
foreach(var field in instanceFields)
{
emitRegisterFunc(il, emitFieldWrap(wrapTypeBuilder, field, true), Utils.GETTER_IDX, field.Name);
emitRegisterFunc(il, emitFieldWrap(wrapTypeBuilder, field, false), Utils.SETTER_IDX, field.Name);
}
List<MethodBase> itemGetter = new List<MethodBase>();
List<MethodBase> itemSetter = new List<MethodBase>();
foreach(var prop in instanceProperties)
{
var getter = prop.GetGetMethod();
if (getter != null && getter.IsPublic)
{
if (prop.Name == "Item" && prop.GetIndexParameters().Length > 0)
{
if (!prop.GetIndexParameters()[0].ParameterType.IsAssignableFrom(typeof(string)))
{
itemGetter.Add(getter);
}
}
else
{
emitRegisterFunc(il, emitPropertyWrap(wrapTypeBuilder, prop, getter, true), Utils.GETTER_IDX, prop.Name);
}
}
var setter = prop.GetSetMethod();
if (setter != null && setter.IsPublic)
{
if (prop.Name == "Item" && prop.GetIndexParameters().Length > 0)
{
if (!prop.GetIndexParameters()[0].ParameterType.IsAssignableFrom(typeof(string)))
{
itemSetter.Add(setter);
}
}
else
{
emitRegisterFunc(il, emitPropertyWrap(wrapTypeBuilder, prop, setter, false), Utils.SETTER_IDX, prop.Name);
}
}
}
foreach (var group in instanceMethods)
{
emitRegisterFunc(il, emitMethodWrap(wrapTypeBuilder, group.Cast<MethodBase>().ToList(), false, toBeWrap), Utils.METHOD_IDX, group.Key);
}
foreach (var group in supportOperators)
{
emitRegisterFunc(il, emitMethodWrap(wrapTypeBuilder, group.Cast<MethodBase>().ToList(), false, toBeWrap), Utils.OBJ_META_IDX, InternalGlobals.supportOp[group.Key]);
}
foreach (var ev in toBeWrap.GetEvents(instanceFlag))
{
emitRegisterFunc(il, emitEventWrap(wrapTypeBuilder, ev), Utils.METHOD_IDX, ev.Name);
}
//end obj
il.Emit(OpCodes.Ldtoken, toBeWrap);
il.Emit(OpCodes.Call, Type_GetTypeFromHandle); // typeof(type)
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldloc, translator);
il.Emit(OpCodes.Ldnull);
if (itemGetter.Count > 0)
{
il.Emit(OpCodes.Ldftn, emitMethodWrap(wrapTypeBuilder, itemGetter, true, toBeWrap));
il.Emit(OpCodes.Newobj, LuaCSFunction_Constructor);
}
il.Emit(OpCodes.Ldnull);
if (itemSetter.Count > 0)
{
il.Emit(OpCodes.Ldftn, emitMethodWrap(wrapTypeBuilder, itemSetter, true, toBeWrap));
il.Emit(OpCodes.Newobj, LuaCSFunction_Constructor);
}
il.Emit(OpCodes.Ldnull);
il.Emit(OpCodes.Ldnull);
il.Emit(OpCodes.Ldnull);
il.Emit(OpCodes.Call, Utils_EndObjectRegister);
// begin class
il.Emit(OpCodes.Ldtoken, toBeWrap);
il.Emit(OpCodes.Call, Type_GetTypeFromHandle); // typeof(type)
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldnull);
il.Emit(OpCodes.Ldftn, emitMethodWrap(wrapTypeBuilder,
toBeWrap.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase)
.Cast<MethodBase>().ToList(), false, toBeWrap, toBeWrap.ToString() + " constructor"));
il.Emit(OpCodes.Newobj, LuaCSFunction_Constructor);
il.Emit(OpCodes.Ldc_I4_1);
il.Emit(OpCodes.Ldc_I4_1);
il.Emit(OpCodes.Ldc_I4_1);
il.Emit(OpCodes.Call, Utils_BeginClassRegister);
var staticMethods = toBeWrap.GetMethods(staticFlag)
.Where(m => Utils.IsSupportedMethod(m))
.Where(m => !m.IsSpecialName).GroupBy(m => m.Name);
var staticFields = toBeWrap.GetFields(staticFlag);
var staticProperties = toBeWrap.GetProperties(staticFlag);
foreach (var group in staticMethods)
{
emitRegisterFunc(il, emitMethodWrap(wrapTypeBuilder, group.Cast<MethodBase>().ToList(), false, toBeWrap), Utils.CLS_IDX, group.Key);
}
foreach (var ev in toBeWrap.GetEvents(staticFlag))
{
emitRegisterFunc(il, emitEventWrap(wrapTypeBuilder, ev), Utils.CLS_IDX, ev.Name);
}
foreach (var prop in staticProperties)
{
var getter = prop.GetGetMethod();
if (getter != null && getter.IsPublic)
{
emitRegisterFunc(il, emitPropertyWrap(wrapTypeBuilder, prop, getter, true), Utils.GETTER_IDX, prop.Name);
}
var setter = prop.GetSetMethod();
if (setter != null && setter.IsPublic)
{
emitRegisterFunc(il, emitPropertyWrap(wrapTypeBuilder, prop, setter, false), Utils.SETTER_IDX, prop.Name);
}
}
foreach (var field in staticFields)
{
if (field.IsInitOnly || field.IsLiteral)
{
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldloc, translator);
il.Emit(OpCodes.Ldc_I4, Utils.CLS_IDX);
il.Emit(OpCodes.Ldstr, field.Name);
if (field.IsLiteral)
{
LocalBuilder literalStore = il.DeclareLocal(field.FieldType);
emitLiteralLoad(il, field.FieldType, field.GetValue(null), literalStore.LocalIndex);
il.Emit(OpCodes.Stloc, literalStore);
il.Emit(OpCodes.Ldloc, literalStore);
}
else
{
il.Emit(OpCodes.Ldsfld, field);
}
if (field.FieldType.IsValueType)
{
il.Emit(OpCodes.Box, field.FieldType);
}
il.Emit(OpCodes.Call, Utils_RegisterObject);
}
else
{
emitRegisterFunc(il, emitFieldWrap(wrapTypeBuilder, field, true), Utils.CLS_GETTER_IDX, field.Name);
emitRegisterFunc(il, emitFieldWrap(wrapTypeBuilder, field, false), Utils.CLS_SETTER_IDX, field.Name);
}
}
//end class
il.Emit(OpCodes.Ldtoken, toBeWrap);
il.Emit(OpCodes.Call, Type_GetTypeFromHandle); // typeof(type)
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldloc, translator);
il.Emit(OpCodes.Call, Utils_EndClassRegister);
il.Emit(OpCodes.Ret);
return wrapTypeBuilder.CreateType();
}
上面基本上就 点下Generate Code 和 Hotfix Inject In Editor 做的事情,还有一些没贴出来,他们的源码实在是太多了
xlua在 Unity中的使用:
在代码发布之前要做的
[Hotfix]
public class FishHotFix : MonoBehaviour {
LuaEnv lua = new LuaEnv();
// Use this for initialization
public static Dictionary<string, GameObject> prefabsDic = new Dictionary<string, GameObject>();
private void Awake()
{
lua.AddLoader(MyLoader);
lua.DoString("require 'FishLua'");
}
private byte[] MyLoader(ref string filePath)
{
string luaPath = Application.streamingAssetsPath + @"\" + filePath + ".lua.txt";
return System.Text.Encoding.UTF8.GetBytes(System.IO.File.ReadAllText(luaPath));
}
// Update is called once per frame
void Update ()
{
}
[LuaCallCSharp]
public void LoadResource(string resName,string filePath)
{
StartCoroutine(LoadResourceCorotine(resName, filePath));
}
IEnumerator LoadResourceCorotine(string resName,string filePath )
{
UnityWebRequest request = UnityWebRequestAssetBundle.GetAssetBundle(@"http://localhost/AssetBundles/"+filePath);
yield return request.SendWebRequest();
AssetBundle bundle= DownloadHandlerAssetBundle.GetContent(request);
//AssetBundle assetBundle = AssetBundle.LoadFromFile(@"" + Application.streamingAssetsPath + @"/" + filePath);
GameObject gameObject = bundle.LoadAsset<GameObject>(resName);
if (!prefabsDic.ContainsKey(resName))
{
prefabsDic.Add(resName, gameObject);
}
bundle.LoadAsset<GameObject>(resName);
}
[LuaCallCSharp]
public static GameObject GetPrefabs(string name)
{
if (prefabsDic.ContainsKey(name))
{
return prefabsDic[name];
}
return null;
}
private void OnDisable()
{
lua.DoString("require 'FishDispose'");
}
private void OnDestroy()
{
lua.Dispose();
}
}
lua.AddLoader(MyLoader);
这个方法 在 执行 lua.DoString("require 'xxx"); 时 就会运行 MyLoader这个函数。
源码
public void AddLoader(CustomLoader loader)
CustomLoader 是一个委托,我们调用 AddLoader的时候, 只需要把自己定义的Loader函数传进入就好了,
//loader : CustomLoader, filepath参数:(ref类型)输入是require的参数,如果需要支持调试,需要输出真实路径。
// 返回值:如果返回null,代表加载该源下无合适的文件,否则返回UTF8编码的byte[]
public delegate byte[] CustomLoader(ref string filepath);
public void AddLoader(CustomLoader loader)
{
customLoaders.Add(loader);
}
DoString方法, 一般我们调用的是第二个,方法,它会先把string 转成Byt[]再去调用第一个方法
public object[] DoString(byte[] chunk, string chunkName = "chunk", LuaTable env = null)
{
#if THREAD_SAFE || HOTFIX_ENABLE
lock (luaEnvLock)
{
#endif
var _L = L;
int oldTop = LuaAPI.lua_gettop(_L);
int errFunc = LuaAPI.load_error_func(_L, errorFuncRef);
if (LuaAPI.xluaL_loadbuffer(_L, chunk, chunk.Length, chunkName) == 0)
{
if (env != null)
{
env.push(_L);
LuaAPI.lua_setfenv(_L, -2);
}
if (LuaAPI.lua_pcall(_L, 0, -1, errFunc) == 0)
{
LuaAPI.lua_remove(_L, errFunc);
return translator.popValues(_L, oldTop);
}
else
ThrowExceptionFromError(oldTop);
}
else
ThrowExceptionFromError(oldTop);
return null;
#if THREAD_SAFE || HOTFIX_ENABLE
}
#endif
}
public object[] DoString(string chunk, string chunkName = "chunk", LuaTable env = null)
{
byte[] bytes = System.Text.Encoding.UTF8.GetBytes(chunk);
return DoString(bytes, chunkName, env);
}
说下 lua.DoString("require 'LuaFileName'" ); 如果 你没有用 lua.AddLoader(MyLoader),去自定义 路径的话,
那么lua会自动从 当前文件下Resources文件夹下去查找LuaFileName的 文件, 再说下这个坑, 后缀为Lua的时候,Unity是没办法读取的,这这个时候怎么办呢,再后缀加上.txt就好了, 例如: mylua.lua.txt 这样。
Dispose 会释放下GC
public void Dispose()
{
FullGc();
System.GC.Collect();
System.GC.WaitForPendingFinalizers();
Dispose(true);
System.GC.Collect();
System.GC.WaitForPendingFinalizers();
}
在 Dispose之前 要清空下委托里面的函数,不然会报错。
一般 不需要运行的时候 清空 ,上面的例子是加在OnDisable里
private void OnDisable()
{
lua.DoString("require 'FishDispose'");
}
用法如下
xlua.hotfix( ClassName,'MethodName',nil)
在lua中调用,打补丁
xlua.hotfix(ClassName,'MethodName',function (self)
end
对于 我们写的 类 通过 CS.ClassName来访问,如果有命名空间 直接通过CS+命名空间名+.className 来访问 例如访问 GameObject类里的Instantiate() 方法, CS.UnityEngine.GameObject.Instantiate() 这个方法是静态的 所以可以直接通过.来访问。
Q1 在 C#中 不需要重新写某个方法,只需要修改几个值 。
可以引入util 库,util.hotfix_ex(ClassName,'MethodName',function (self) end
local util =require('util')
util.hotfix_ex(ClassName,'MethodName',function (self)
self:MethodName()
end
官方说这个方法 要少用, 减少 性能消耗。
源码
--和xlua.hotfix的区别是:这个可以调用原来的函数
local function hotfix_ex(cs, field, func)
assert(type(field) == 'string' and type(func) == 'function', 'invalid argument: #2 string needed, #3 function needed!')
local function func_after(...)
xlua.hotfix(cs, field, nil)
local ret = {func(...)}
xlua.hotfix(cs, field, func_after)
return unpack(ret)
end
xlua.hotfix(cs, field, func_after)
end
xlua.hotfix的
xlua.hotfix = function(cs, field, func)
if func == nil then func = false end
local tbl = (type(field) == 'table') and field or {[field] = func}
for k, v in pairs(tbl) do
local cflag = ''
if k == '.ctor' then
cflag = '_c'
k = 'ctor'
end
local f = type(v) == 'function' and v or nil
xlua.access(cs, cflag .. '__Hotfix0_'..k, f) -- at least one
pcall(function()
for i = 1, 99 do
xlua.access(cs, cflag .. '__Hotfix'..i..'_'..k, f)
end
end)
end
end
Q2 访问 私用属性
xlua.private_accessible(ClassName),
另外 访问 普通方法 通过 “:” 来访问,静态方法就可以用 ”.“ 来访问 function(self) 这里self表示 是 自身,相对于C# 里是无参数的方法, 所以在传递参数的时候,只需要在self 后面加上就可以了
说下可能遇到的坑
坑1 可能 build之后会报错, 这个时候检查下Xlua 下的Example有没有被删除,把Exapmle删除掉即可。
坑2 在 运行lua 环境 时,一定 要在所有初始化完成(生命周期函数执行)之前 才有效,例如,想要修改一个方法,这个方法在Awake调用,而 lua环境 在Start里面执行, 这样就是无效的了。
坑3 在Unity 里 Random.Range 有int 和float 两个方法,而在Lua中是没有int float的,怎么办呢, 可以调用Unity里的Math方法进行取整,一般在Lua中调用Ran'dom.Range方法都是识别为float的,或者调用 C#里的强制转换类型。 也就是说,在lua中无法做到的,一般都交给Unity/C#里做。
最后在CS脚本中 打上热跟新的标签的,都需要在Disable中 释放它,减少性能上的开销,不这么做会包错的。
关于 另一个 版本 luainterface :