JJBB/Assets/XLua/Src/ObjectTranslator.cs

1725 lines
62 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Tencent is pleased to support the open source community by making xLua available.
* Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
* Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
* http://opensource.org/licenses/MIT
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
*/
#if USE_UNI_LUA
using LuaAPI = UniLua.Lua;
using RealStatePtr = UniLua.ILuaState;
using LuaCSFunction = UniLua.CSharpFunctionDelegate;
#else
using LuaAPI = XLua.LuaDLL.Lua;
using RealStatePtr = System.IntPtr;
using LuaCSFunction = XLua.LuaDLL.lua_CSFunction;
#endif
namespace XLua
{
using System;
using System.Collections;
using System.Reflection;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
class ReferenceEqualsComparer : IEqualityComparer<object>
{
public new bool Equals(object o1, object o2)
{
return object.ReferenceEquals(o1, o2);
}
public int GetHashCode(object obj)
{
return System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(obj);
}
}
#pragma warning disable 414
public class MonoPInvokeCallbackAttribute : System.Attribute
{
private Type type;
public MonoPInvokeCallbackAttribute(Type t) { type = t; }
}
#pragma warning restore 414
public enum LuaTypes
{
LUA_TNONE = -1,
LUA_TNIL = 0,
LUA_TNUMBER = 3,
LUA_TSTRING = 4,
LUA_TBOOLEAN = 1,
LUA_TTABLE = 5,
LUA_TFUNCTION = 6,
LUA_TUSERDATA = 7,
LUA_TTHREAD = 8,
LUA_TLIGHTUSERDATA = 2
}
public enum LuaGCOptions
{
LUA_GCSTOP = 0,
LUA_GCRESTART = 1,
LUA_GCCOLLECT = 2,
LUA_GCCOUNT = 3,
LUA_GCCOUNTB = 4,
LUA_GCSTEP = 5,
LUA_GCSETPAUSE = 6,
LUA_GCSETSTEPMUL = 7,
}
public enum LuaThreadStatus
{
LUA_RESUME_ERROR = -1,
LUA_OK = 0,
LUA_YIELD = 1,
LUA_ERRRUN = 2,
LUA_ERRSYNTAX = 3,
LUA_ERRMEM = 4,
LUA_ERRERR = 5,
}
sealed class LuaIndexes
{
public static int LUA_REGISTRYINDEX
{
get
{
return InternalGlobals.LUA_REGISTRYINDEX;
}
set
{
InternalGlobals.LUA_REGISTRYINDEX = value;
}
}
}
#if GEN_CODE_MINIMIZE
public delegate int CSharpWrapper(IntPtr L, int top);
#endif
public partial class ObjectTranslator
{
internal MethodWrapsCache methodWrapsCache;
internal ObjectCheckers objectCheckers;
internal ObjectCasters objectCasters;
internal readonly ObjectPool objects = new ObjectPool();
internal readonly Dictionary<object, int> reverseMap = new Dictionary<object, int>(new ReferenceEqualsComparer());
internal LuaEnv luaEnv;
internal StaticLuaCallbacks metaFunctions;
internal List<Assembly> assemblies;
private LuaCSFunction importTypeFunction,loadAssemblyFunction, castFunction;
//延迟加载
private readonly Dictionary<Type, Action<RealStatePtr>> delayWrap = new Dictionary<Type, Action<RealStatePtr>>();
private readonly Dictionary<Type, Func<int, LuaEnv, LuaBase>> interfaceBridgeCreators = new Dictionary<Type, Func<int, LuaEnv, LuaBase>>();
//无法访问的类比如声明成internal可以用其接口、基类的生成代码来访问
private readonly Dictionary<Type, Type> aliasCfg = new Dictionary<Type, Type>();
public void DelayWrapLoader(Type type, Action<RealStatePtr> loader)
{
delayWrap[type] = loader;
}
public void AddInterfaceBridgeCreator(Type type, Func<int, LuaEnv, LuaBase> creator)
{
interfaceBridgeCreators.Add(type, creator);
}
Dictionary<Type, bool> loaded_types = new Dictionary<Type, bool>();
public bool TryDelayWrapLoader(RealStatePtr L, Type type)
{
if (loaded_types.ContainsKey(type)) return true;
loaded_types.Add(type, true);
LuaAPI.luaL_newmetatable(L, type.FullName); //先建一个metatable因为加载过程可能会需要用到
LuaAPI.lua_pop(L, 1);
Action<RealStatePtr> loader;
int top = LuaAPI.lua_gettop(L);
if (delayWrap.TryGetValue(type, out loader))
{
delayWrap.Remove(type);
loader(L);
}
else
{
#if !GEN_CODE_MINIMIZE && !ENABLE_IL2CPP && (UNITY_EDITOR || XLUA_GENERAL) && !FORCE_REFLECTION && !NET_STANDARD_2_0
if (!DelegateBridge.Gen_Flag && !type.IsEnum() && !typeof(Delegate).IsAssignableFrom(type) && Utils.IsPublic(type))
{
Type wrap = ce.EmitTypeWrap(type);
MethodInfo method = wrap.GetMethod("__Register", BindingFlags.Static | BindingFlags.Public);
method.Invoke(null, new object[] { L });
}
else
{
Utils.ReflectionWrap(L, type, privateAccessibleFlags.Contains(type));
}
#else
Utils.ReflectionWrap(L, type, privateAccessibleFlags.Contains(type));
#endif
#if NOT_GEN_WARNING
if (!typeof(Delegate).IsAssignableFrom(type))
{
#if !XLUA_GENERAL
UnityEngine.Debug.LogWarning(string.Format("{0} not gen, using reflection instead", type));
#else
System.Console.WriteLine(string.Format("Warning: {0} not gen, using reflection instead", type));
#endif
}
#endif
}
if (top != LuaAPI.lua_gettop(L))
{
throw new Exception("top change, before:" + top + ", after:" + LuaAPI.lua_gettop(L));
}
foreach (var nested_type in type.GetNestedTypes(BindingFlags.Public))
{
if (nested_type.IsGenericTypeDefinition())
{
continue;
}
GetTypeId(L, nested_type);
}
return true;
}
public void Alias(Type type, string alias)
{
Type alias_type = FindType(alias);
if (alias_type == null)
{
throw new ArgumentException("Can not find " + alias);
}
aliasCfg[alias_type] = type;
}
public int cacheRef;
void addAssemblieByName(IEnumerable<Assembly> assemblies_usorted, string name)
{
foreach(var assemblie in assemblies_usorted)
{
if (assemblie.FullName.StartsWith(name) && !assemblies.Contains(assemblie))
{
assemblies.Add(assemblie);
break;
}
}
}
public ObjectTranslator(LuaEnv luaenv,RealStatePtr L)
{
#if XLUA_GENERAL || (UNITY_WSA && !UNITY_EDITOR)
var dumb_field = typeof(ObjectTranslator).GetField("s_gen_reg_dumb_obj", BindingFlags.Static| BindingFlags.DeclaredOnly | BindingFlags.NonPublic);
if (dumb_field != null)
{
dumb_field.GetValue(null);
}
#endif
assemblies = new List<Assembly>();
#if (UNITY_WSA && !ENABLE_IL2CPP) && !UNITY_EDITOR
var assemblies_usorted = Utils.GetAssemblies();
#else
assemblies.Add(Assembly.GetExecutingAssembly());
var assemblies_usorted = AppDomain.CurrentDomain.GetAssemblies();
#endif
addAssemblieByName(assemblies_usorted, "mscorlib,");
addAssemblieByName(assemblies_usorted, "System,");
addAssemblieByName(assemblies_usorted, "System.Core,");
foreach (Assembly assembly in assemblies_usorted)
{
if (!assemblies.Contains(assembly))
{
assemblies.Add(assembly);
}
}
this.luaEnv=luaenv;
objectCasters = new ObjectCasters(this);
objectCheckers = new ObjectCheckers(this);
methodWrapsCache = new MethodWrapsCache(this, objectCheckers, objectCasters);
metaFunctions=new StaticLuaCallbacks();
importTypeFunction = new LuaCSFunction(StaticLuaCallbacks.ImportType);
loadAssemblyFunction = new LuaCSFunction(StaticLuaCallbacks.LoadAssembly);
castFunction = new LuaCSFunction(StaticLuaCallbacks.Cast);
LuaAPI.lua_newtable(L);
LuaAPI.lua_newtable(L);
LuaAPI.xlua_pushasciistring(L, "__mode");
LuaAPI.xlua_pushasciistring(L, "v");
LuaAPI.lua_rawset(L, -3);
LuaAPI.lua_setmetatable(L, -2);
cacheRef = LuaAPI.luaL_ref(L, LuaIndexes.LUA_REGISTRYINDEX);
initCSharpCallLua();
}
internal enum LOGLEVEL{
NO,
INFO,
WARN,
ERROR
}
#if (UNITY_EDITOR || XLUA_GENERAL) && !NET_STANDARD_2_0
Type delegate_birdge_type;
class CompareByArgRet : IEqualityComparer<MethodInfo>
{
public bool Equals(MethodInfo x, MethodInfo y)
{
return Utils.IsParamsMatch(x, y);
}
public int GetHashCode(MethodInfo method)
{
int hc = 0;
hc += method.ReturnType.GetHashCode();
foreach (var pi in method.GetParameters())
{
hc += pi.ParameterType.GetHashCode();
}
return hc;
}
}
#endif
void initCSharpCallLua()
{
#if (UNITY_EDITOR || XLUA_GENERAL) && !NET_STANDARD_2_0
delegate_birdge_type = typeof(DelegateBridge);
if (!DelegateBridge.Gen_Flag)
{
List<Type> cs_call_lua = new List<Type>();
foreach (var type in Utils.GetAllTypes())
{
if(type.IsDefined(typeof(CSharpCallLuaAttribute), false))
{
cs_call_lua.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(CSharpCallLuaAttribute), false) && (typeof(IEnumerable<Type>)).IsAssignableFrom(field.FieldType))
{
cs_call_lua.AddRange(field.GetValue(null) as IEnumerable<Type>);
}
}
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(CSharpCallLuaAttribute), false) && (typeof(IEnumerable<Type>)).IsAssignableFrom(prop.PropertyType))
{
cs_call_lua.AddRange(prop.GetValue(null, null) as IEnumerable<Type>);
}
}
}
IEnumerable<IGrouping<MethodInfo, Type>> groups = (from type in cs_call_lua
where typeof(Delegate).IsAssignableFrom(type) && type != typeof(Delegate) && type != typeof(MulticastDelegate)
where !type.GetMethod("Invoke").GetParameters().Any(paramInfo => paramInfo.ParameterType.IsGenericParameter)
select type).GroupBy(t => t.GetMethod("Invoke"), new CompareByArgRet());
ce.SetGenInterfaces(cs_call_lua.Where(type=>type.IsInterface()).ToList());
delegate_birdge_type = ce.EmitDelegateImpl(groups);
}
#endif
}
#if (UNITY_EDITOR || XLUA_GENERAL) && !NET_STANDARD_2_0
CodeEmit ce = new CodeEmit();
#endif
MethodInfo[] genericAction = null;
MethodInfo[] genericFunc = null;
Dictionary<Type, Func<DelegateBridgeBase, Delegate>> delegateCreatorCache
= new Dictionary<Type, Func<DelegateBridgeBase, Delegate>>();
Func<DelegateBridgeBase, Delegate> getCreatorUsingGeneric(DelegateBridgeBase bridge, Type delegateType, MethodInfo delegateMethod)
{
Func<DelegateBridgeBase, Delegate> genericDelegateCreator = null;
if (genericAction == null)
{
var methods = typeof(DelegateBridge).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly);
genericAction = methods.Where(m => m.Name == "Action").OrderBy(m => m.GetParameters().Length).ToArray();
genericFunc = methods.Where(m => m.Name == "Func").OrderBy(m => m.GetParameters().Length).ToArray();
}
if (genericAction.Length != 5 || genericFunc.Length != 5)
{
return null;
}
var parameters = delegateMethod.GetParameters();
#if !XLUA_GENERAL
if ((delegateMethod.ReturnType.IsValueType() && delegateMethod.ReturnType != typeof(void)) || parameters.Length > 4)
{
genericDelegateCreator = (x) => null;
}
else
#endif
{
foreach (var pinfo in parameters)
{
if (pinfo.ParameterType.IsValueType() || pinfo.IsOut || pinfo.ParameterType.IsByRef)
{
genericDelegateCreator = (x) => null;
break;
}
}
if (genericDelegateCreator == null)
{
var typeArgs = parameters.Select(pinfo => pinfo.ParameterType);
MethodInfo genericMethodInfo = null;
if (delegateMethod.ReturnType == typeof(void))
{
genericMethodInfo = genericAction[parameters.Length];
}
else
{
genericMethodInfo = genericFunc[parameters.Length];
typeArgs = typeArgs.Concat(new Type[] { delegateMethod.ReturnType });
}
if (genericMethodInfo.IsGenericMethodDefinition)
{
var methodInfo = genericMethodInfo.MakeGenericMethod(typeArgs.ToArray());
genericDelegateCreator = (o) =>
#if !UNITY_WSA || UNITY_EDITOR
Delegate.CreateDelegate(delegateType, o, methodInfo);
#else
methodInfo.CreateDelegate(delegateType, bridge);
#endif
}
else
{
genericDelegateCreator = (o) =>
#if !UNITY_WSA || UNITY_EDITOR
Delegate.CreateDelegate(delegateType, o, genericMethodInfo);
#else
genericMethodInfo.CreateDelegate(delegateType, o);
#endif
}
}
}
return genericDelegateCreator;
}
Delegate getDelegate(DelegateBridgeBase bridge, Type delegateType)
{
Delegate ret = bridge.GetDelegateByType(delegateType);
if (ret != null)
{
return ret;
}
if (delegateType == typeof(Delegate) || delegateType == typeof(MulticastDelegate))
{
return null;
}
Func<DelegateBridgeBase, Delegate> delegateCreator;
if (!delegateCreatorCache.TryGetValue(delegateType, out delegateCreator))
{
// get by parameters
MethodInfo delegateMethod = delegateType.GetMethod("Invoke");
var methods = bridge.GetType().GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly).Where(m => !m.IsGenericMethodDefinition && (m.Name.StartsWith("__Gen_Delegate_Imp") || m.Name == "Action")).ToArray();
for (int i = 0; i < methods.Length; i++)
{
if (!methods[i].IsConstructor && Utils.IsParamsMatch(delegateMethod, methods[i]))
{
var foundMethod = methods[i];
delegateCreator = (o) =>
#if !UNITY_WSA || UNITY_EDITOR
Delegate.CreateDelegate(delegateType, o, foundMethod);
#else
foundMethod.CreateDelegate(delegateType, o);
#endif
break;
}
}
if (delegateCreator == null)
{
delegateCreator = getCreatorUsingGeneric(bridge, delegateType, delegateMethod);
}
delegateCreatorCache.Add(delegateType, delegateCreator);
}
ret = delegateCreator(bridge);
if (ret != null)
{
return ret;
}
throw new InvalidCastException("This type must add to CSharpCallLua: " + delegateType.GetFriendlyName());
}
Dictionary<int, WeakReference> delegate_bridges = new Dictionary<int, WeakReference>();
public object CreateDelegateBridge(RealStatePtr L, Type delegateType, int idx)
{
LuaAPI.lua_pushvalue(L, idx);
LuaAPI.lua_rawget(L, LuaIndexes.LUA_REGISTRYINDEX);
if (!LuaAPI.lua_isnil(L, -1))
{
int referenced = LuaAPI.xlua_tointeger(L, -1);
LuaAPI.lua_pop(L, 1);
if (delegate_bridges[referenced].IsAlive)
{
if (delegateType == null)
{
return delegate_bridges[referenced].Target;
}
DelegateBridgeBase exist_bridge = delegate_bridges[referenced].Target as DelegateBridgeBase;
Delegate exist_delegate;
if (exist_bridge.TryGetDelegate(delegateType, out exist_delegate))
{
return exist_delegate;
}
else
{
exist_delegate = getDelegate(exist_bridge, delegateType);
exist_bridge.AddDelegate(delegateType, exist_delegate);
return exist_delegate;
}
}
}
else
{
LuaAPI.lua_pop(L, 1);
}
LuaAPI.lua_pushvalue(L, idx);
int reference = LuaAPI.luaL_ref(L);
LuaAPI.lua_pushvalue(L, idx);
LuaAPI.lua_pushnumber(L, reference);
LuaAPI.lua_rawset(L, LuaIndexes.LUA_REGISTRYINDEX);
DelegateBridgeBase bridge;
try
{
#if (UNITY_EDITOR || XLUA_GENERAL) && !NET_STANDARD_2_0
if (!DelegateBridge.Gen_Flag)
{
bridge = Activator.CreateInstance(delegate_birdge_type, new object[] { reference, luaEnv }) as DelegateBridgeBase;
}
else
#endif
{
bridge = new DelegateBridge(reference, luaEnv);
}
}
catch(Exception e)
{
LuaAPI.lua_pushvalue(L, idx);
LuaAPI.lua_pushnil(L);
LuaAPI.lua_rawset(L, LuaIndexes.LUA_REGISTRYINDEX);
LuaAPI.lua_pushnil(L);
LuaAPI.xlua_rawseti(L, LuaIndexes.LUA_REGISTRYINDEX, reference);
throw e;
}
if (delegateType == null)
{
delegate_bridges[reference] = new WeakReference(bridge);
return bridge;
}
try {
var ret = getDelegate(bridge, delegateType);
bridge.AddDelegate(delegateType, ret);
delegate_bridges[reference] = new WeakReference(bridge);
return ret;
}
catch(Exception e)
{
bridge.Dispose();
throw e;
}
}
public bool AllDelegateBridgeReleased()
{
foreach (var kv in delegate_bridges)
{
if (kv.Value.IsAlive)
{
return false;
}
}
return true;
}
public void ReleaseLuaBase(RealStatePtr L, int reference, bool is_delegate)
{
if(is_delegate)
{
LuaAPI.xlua_rawgeti(L, LuaIndexes.LUA_REGISTRYINDEX, reference);
if (LuaAPI.lua_isnil(L, -1))
{
LuaAPI.lua_pop(L, 1);
}
else
{
LuaAPI.lua_pushvalue(L, -1);
LuaAPI.lua_rawget(L, LuaIndexes.LUA_REGISTRYINDEX);
if (LuaAPI.lua_type(L, -1) == LuaTypes.LUA_TNUMBER && LuaAPI.xlua_tointeger(L, -1) == reference) //
{
//UnityEngine.Debug.LogWarning("release delegate ref = " + luaReference);
LuaAPI.lua_pop(L, 1);// pop LUA_REGISTRYINDEX[func]
LuaAPI.lua_pushnil(L);
LuaAPI.lua_rawset(L, LuaIndexes.LUA_REGISTRYINDEX); // LUA_REGISTRYINDEX[func] = nil
}
else //another Delegate ref the function before the GC tick
{
LuaAPI.lua_pop(L, 2); // pop LUA_REGISTRYINDEX[func] & func
}
}
LuaAPI.lua_unref(L, reference);
delegate_bridges.Remove(reference);
}
else
{
LuaAPI.lua_unref(L, reference);
}
}
public object CreateInterfaceBridge(RealStatePtr L, Type interfaceType, int idx)
{
Func<int, LuaEnv, LuaBase> creator;
if (!interfaceBridgeCreators.TryGetValue(interfaceType, out creator))
{
#if (UNITY_EDITOR || XLUA_GENERAL) && !NET_STANDARD_2_0
var bridgeType = ce.EmitInterfaceImpl(interfaceType);
creator = (int reference, LuaEnv luaenv) =>
{
return Activator.CreateInstance(bridgeType, new object[] { reference, luaEnv }) as LuaBase;
};
interfaceBridgeCreators.Add(interfaceType, creator);
#else
throw new InvalidCastException("This type must add to CSharpCallLua: " + interfaceType);
#endif
}
LuaAPI.lua_pushvalue(L, idx);
return creator(LuaAPI.luaL_ref(L), luaEnv);
}
int common_array_meta = -1;
public void CreateArrayMetatable(RealStatePtr L)
{
Utils.BeginObjectRegister(null, L, this, 0, 0, 1, 0, common_array_meta);
Utils.RegisterFunc(L, Utils.GETTER_IDX, "Length", StaticLuaCallbacks.ArrayLength);
Utils.EndObjectRegister(null, L, this, null, null,
typeof(System.Array), StaticLuaCallbacks.ArrayIndexer, StaticLuaCallbacks.ArrayNewIndexer);
}
int common_delegate_meta = -1;
public void CreateDelegateMetatable(RealStatePtr L)
{
Utils.BeginObjectRegister(null, L, this, 3, 0, 0, 0, common_delegate_meta);
Utils.RegisterFunc(L, Utils.OBJ_META_IDX, "__call", StaticLuaCallbacks.DelegateCall);
Utils.RegisterFunc(L, Utils.OBJ_META_IDX, "__add", StaticLuaCallbacks.DelegateCombine);
Utils.RegisterFunc(L, Utils.OBJ_META_IDX, "__sub", StaticLuaCallbacks.DelegateRemove);
Utils.EndObjectRegister(null, L, this, null, null,
typeof(System.MulticastDelegate), null, null);
}
int enumerable_pairs_func = -1;
internal void CreateEnumerablePairs(RealStatePtr L)
{
LuaFunction func = luaEnv.DoString(@"
return function(obj)
local isKeyValuePair
local function lua_iter(cs_iter, k)
if cs_iter:MoveNext() then
local current = cs_iter.Current
if isKeyValuePair == nil then
if type(current) == 'userdata' then
local t = current:GetType()
isKeyValuePair = t.Name == 'KeyValuePair`2' and t.Namespace == 'System.Collections.Generic'
else
isKeyValuePair = false
end
--print(current, isKeyValuePair)
end
if isKeyValuePair then
return current.Key, current.Value
else
return k + 1, current
end
end
end
return lua_iter, obj:GetEnumerator(), -1
end
")[0] as LuaFunction;
func.push(L);
enumerable_pairs_func = LuaAPI.luaL_ref(L, LuaIndexes.LUA_REGISTRYINDEX);
func.Dispose();
}
public void OpenLib(RealStatePtr L)
{
if (0 != LuaAPI.xlua_getglobal(L, "xlua"))
{
throw new Exception("call xlua_getglobal fail!" + LuaAPI.lua_tostring(L, -1));
}
LuaAPI.xlua_pushasciistring(L, "import_type");
LuaAPI.lua_pushstdcallcfunction(L,importTypeFunction);
LuaAPI.lua_rawset(L, -3);
LuaAPI.xlua_pushasciistring(L, "import_generic_type");
LuaAPI.lua_pushstdcallcfunction(L, StaticLuaCallbacks.ImportGenericType);
LuaAPI.lua_rawset(L, -3);
LuaAPI.xlua_pushasciistring(L, "cast");
LuaAPI.lua_pushstdcallcfunction(L, castFunction);
LuaAPI.lua_rawset(L, -3);
LuaAPI.xlua_pushasciistring(L, "load_assembly");
LuaAPI.lua_pushstdcallcfunction(L,loadAssemblyFunction);
LuaAPI.lua_rawset(L, -3);
LuaAPI.xlua_pushasciistring(L, "access");
LuaAPI.lua_pushstdcallcfunction(L, StaticLuaCallbacks.XLuaAccess);
LuaAPI.lua_rawset(L, -3);
LuaAPI.xlua_pushasciistring(L, "private_accessible");
LuaAPI.lua_pushstdcallcfunction(L, StaticLuaCallbacks.XLuaPrivateAccessible);
LuaAPI.lua_rawset(L, -3);
LuaAPI.xlua_pushasciistring(L, "metatable_operation");
LuaAPI.lua_pushstdcallcfunction(L, StaticLuaCallbacks.XLuaMetatableOperation);
LuaAPI.lua_rawset(L, -3);
LuaAPI.xlua_pushasciistring(L, "tofunction");
LuaAPI.lua_pushstdcallcfunction(L, StaticLuaCallbacks.ToFunction);
LuaAPI.lua_rawset(L, -3);
LuaAPI.xlua_pushasciistring(L, "get_generic_method");
LuaAPI.lua_pushstdcallcfunction(L, StaticLuaCallbacks.GetGenericMethod);
LuaAPI.lua_rawset(L, -3);
LuaAPI.xlua_pushasciistring(L, "release");
LuaAPI.lua_pushstdcallcfunction(L, StaticLuaCallbacks.ReleaseCsObject);
LuaAPI.lua_rawset(L, -3);
LuaAPI.lua_pop(L, 1);
LuaAPI.lua_createtable(L, 1, 4); // 4 for __gc, __tostring, __index, __newindex
common_array_meta = LuaAPI.luaL_ref(L, LuaIndexes.LUA_REGISTRYINDEX);
LuaAPI.lua_createtable(L, 1, 4); // 4 for __gc, __tostring, __index, __newindex
common_delegate_meta = LuaAPI.luaL_ref(L, LuaIndexes.LUA_REGISTRYINDEX);
}
internal void createFunctionMetatable(RealStatePtr L)
{
LuaAPI.lua_newtable(L);
LuaAPI.xlua_pushasciistring(L,"__gc");
LuaAPI.lua_pushstdcallcfunction(L,metaFunctions.GcMeta);
LuaAPI.lua_rawset(L,-3);
LuaAPI.lua_pushlightuserdata(L, LuaAPI.xlua_tag());
LuaAPI.lua_pushnumber(L, 1);
LuaAPI.lua_rawset(L, -3);
LuaAPI.lua_pushvalue(L, -1);
int type_id = LuaAPI.luaL_ref(L, LuaIndexes.LUA_REGISTRYINDEX);
LuaAPI.lua_pushnumber(L, type_id);
LuaAPI.xlua_rawseti(L, -2, 1);
LuaAPI.lua_pop(L, 1);
typeIdMap.Add(typeof(LuaCSFunction), type_id);
}
internal Type FindType(string className, bool isQualifiedName = false)
{
foreach (Assembly assembly in assemblies)
{
Type klass = assembly.GetType(className);
if (klass!=null)
{
return klass;
}
}
int p1 = className.IndexOf('[');
if (p1 > 0 && !isQualifiedName)
{
string qualified_name = className.Substring(0, p1 + 1);
string[] generic_params = className.Substring(p1 + 1, className.Length - qualified_name.Length - 1).Split(',');
for(int i = 0; i < generic_params.Length; i++)
{
Type generic_param = FindType(generic_params[i].Trim());
if (generic_param == null)
{
return null;
}
if (i != 0 )
{
qualified_name += ", ";
}
qualified_name = qualified_name + "[" + generic_param.AssemblyQualifiedName + "]";
}
qualified_name += "]";
return FindType(qualified_name, true);
}
return null;
}
bool hasMethod(Type type, string methodName)
{
foreach (var method in type.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static))
{
if (method.Name == methodName)
{
return true;
}
}
return false;
}
internal void collectObject(int obj_index_to_collect)
{
object o;
if (objects.TryGetValue(obj_index_to_collect, out o))
{
objects.Remove(obj_index_to_collect);
if (o != null)
{
int obj_index;
//lua gc是先把weak table移除后再调用__gc这期间同一个对象可能再次push到lua关联到新的index
bool is_enum = o.GetType().IsEnum();
if ((is_enum ? enumMap.TryGetValue(o, out obj_index) : reverseMap.TryGetValue(o, out obj_index))
&& obj_index == obj_index_to_collect)
{
if (is_enum)
{
enumMap.Remove(o);
}
else
{
reverseMap.Remove(o);
}
}
}
}
}
int addObject(object obj, bool is_valuetype, bool is_enum)
{
int index = objects.Add(obj);
if (is_enum)
{
enumMap[obj] = index;
}
else if (!is_valuetype)
{
reverseMap[obj] = index;
}
return index;
}
internal object GetObject(RealStatePtr L,int index)
{
return (objectCasters.GetCaster(typeof(object))(L, index, null));
}
public Type GetTypeOf(RealStatePtr L, int idx)
{
Type type = null;
int type_id = LuaAPI.xlua_gettypeid(L, idx);
if (type_id != -1)
{
typeMap.TryGetValue(type_id, out type);
}
return type;
}
public bool Assignable<T>(RealStatePtr L, int index)
{
return Assignable(L, index, typeof(T));
}
public bool Assignable(RealStatePtr L, int index, Type type)
{
if (LuaAPI.lua_type(L, index) == LuaTypes.LUA_TUSERDATA) // 快路径
{
int udata = LuaAPI.xlua_tocsobj_safe(L, index);
object obj;
if (udata != -1 && objects.TryGetValue(udata, out obj))
{
RawObject rawObject = obj as RawObject;
if (rawObject != null)
{
obj = rawObject.Target;
}
if (obj == null)
{
return !type.IsValueType();
}
return type.IsAssignableFrom(obj.GetType());
}
int type_id = LuaAPI.xlua_gettypeid(L, index);
Type type_of_struct;
if (type_id != -1 && typeMap.TryGetValue(type_id, out type_of_struct)) // is struct
{
return type.IsAssignableFrom(type_of_struct);
}
}
return objectCheckers.GetChecker(type)(L, index);
}
public object GetObject(RealStatePtr L, int index, Type type)
{
int udata = LuaAPI.xlua_tocsobj_safe(L, index);
if (udata != -1)
{
object obj = objects.Get(udata);
RawObject rawObject = obj as RawObject;
return rawObject == null ? obj : rawObject.Target;
}
else
{
if (LuaAPI.lua_type(L, index) == LuaTypes.LUA_TUSERDATA)
{
GetCSObject get;
int type_id = LuaAPI.xlua_gettypeid(L, index);
if (type_id != -1 && type_id == decimal_type_id)
{
decimal d;
Get(L, index, out d);
return d;
}
Type type_of_struct;
if (type_id != -1 && typeMap.TryGetValue(type_id, out type_of_struct) && type.IsAssignableFrom(type_of_struct) && custom_get_funcs.TryGetValue(type, out get))
{
return get(L, index);
}
}
return (objectCasters.GetCaster(type)(L, index, null));
}
}
public void Get<T>(RealStatePtr L, int index, out T v)
{
Func<RealStatePtr, int, T> get_func;
if (tryGetGetFuncByType(typeof(T), out get_func))
{
v = get_func(L, index);
}
else
{
v = (T)GetObject(L, index, typeof(T));
}
}
public void PushByType<T>(RealStatePtr L, T v)
{
Action<RealStatePtr, T> push_func;
if (tryGetPushFuncByType(typeof(T), out push_func))
{
push_func(L, v);
}
else
{
PushAny(L, v);
}
}
#if GENERIC_SHARING
public T GetByType<T>(RealStatePtr L, int index)
{
Func<RealStatePtr, int, T> get_func;
if (tryGetGetFuncByType(typeof(T), out get_func))
{
return get_func(L, index);
}
else
{
return (T)GetObject(L, index, typeof(T));
}
}
#endif
public T[] GetParams<T>(RealStatePtr L, int index)
{
T[] ret = new T[Math.Max(LuaAPI.lua_gettop(L) - index + 1, 0)];
for(int i = 0; i < ret.Length; i++)
{
Get(L, index + i, out ret[i]);
}
return ret;
}
public Array GetParams(RealStatePtr L, int index, Type type) //反射版本
{
Array ret = Array.CreateInstance(type, Math.Max(LuaAPI.lua_gettop(L) - index + 1, 0)); //这个函数长度为0的话返回null
for (int i = 0; i < ret.Length; i++)
{
ret.SetValue(GetObject(L, index + i, type), i);
}
return ret;
}
#if UNITY_EDITOR || XLUA_GENERAL
public void PushParams(RealStatePtr L, Array ary)
{
if (ary != null)
{
for (int i = 0; i < ary.Length; i++)
{
PushAny(L, ary.GetValue(i));
}
}
}
#endif
public T GetDelegate<T>(RealStatePtr L, int index) where T :class
{
if (LuaAPI.lua_isfunction(L, index))
{
return CreateDelegateBridge(L, typeof(T), index) as T;
}
else if (LuaAPI.lua_type(L, index) == LuaTypes.LUA_TUSERDATA)
{
return (T)SafeGetCSObj(L, index);
}
else
{
return null;
}
}
Dictionary<Type, int> typeIdMap = new Dictionary<Type, int>();
//only store the type id to type map for struct
Dictionary<int, Type> typeMap = new Dictionary<int, Type>();
public int GetTypeId(RealStatePtr L, Type type)
{
bool isFirst;
return getTypeId(L, type, out isFirst);
}
HashSet<Type> privateAccessibleFlags = new HashSet<Type>();
public void PrivateAccessible(RealStatePtr L, Type type)
{
if (!privateAccessibleFlags.Contains(type)) //未处理
{
privateAccessibleFlags.Add(type);
if (typeIdMap.ContainsKey(type)) //loaded
{
Utils.MakePrivateAccessible(L, type);
}
}
}
internal int getTypeId(RealStatePtr L, Type type, out bool is_first, LOGLEVEL log_level = LOGLEVEL.WARN)
{
int type_id;
is_first = false;
if (!typeIdMap.TryGetValue(type, out type_id)) // no reference
{
if (type.IsArray)
{
if (common_array_meta == -1) throw new Exception("Fatal Exception! Array Metatable not inited!");
return common_array_meta;
}
if (typeof(MulticastDelegate).IsAssignableFrom(type))
{
if (common_delegate_meta == -1) throw new Exception("Fatal Exception! Delegate Metatable not inited!");
TryDelayWrapLoader(L, type);
return common_delegate_meta;
}
is_first = true;
Type alias_type = null;
aliasCfg.TryGetValue(type, out alias_type);
LuaAPI.luaL_getmetatable(L, alias_type == null ? type.FullName : alias_type.FullName);
if (LuaAPI.lua_isnil(L, -1)) //no meta yet, try to use reflection meta
{
LuaAPI.lua_pop(L, 1);
if (TryDelayWrapLoader(L, alias_type == null ? type : alias_type))
{
LuaAPI.luaL_getmetatable(L, alias_type == null ? type.FullName : alias_type.FullName);
}
else
{
throw new Exception("Fatal: can not load metatable of type:" + type);
}
}
//循环依赖自身依赖自己的class比如有个自身类型的静态readonly对象。
if (typeIdMap.TryGetValue(type, out type_id))
{
LuaAPI.lua_pop(L, 1);
}
else
{
if (type.IsEnum())
{
LuaAPI.xlua_pushasciistring(L, "__band");
LuaAPI.lua_pushstdcallcfunction(L, metaFunctions.EnumAndMeta);
LuaAPI.lua_rawset(L, -3);
LuaAPI.xlua_pushasciistring(L, "__bor");
LuaAPI.lua_pushstdcallcfunction(L, metaFunctions.EnumOrMeta);
LuaAPI.lua_rawset(L, -3);
}
if (typeof(IEnumerable).IsAssignableFrom(type))
{
LuaAPI.xlua_pushasciistring(L, "__pairs");
LuaAPI.lua_getref(L, enumerable_pairs_func);
LuaAPI.lua_rawset(L, -3);
}
LuaAPI.lua_pushvalue(L, -1);
type_id = LuaAPI.luaL_ref(L, LuaIndexes.LUA_REGISTRYINDEX);
LuaAPI.lua_pushnumber(L, type_id);
LuaAPI.xlua_rawseti(L, -2, 1);
LuaAPI.lua_pop(L, 1);
if (type.IsValueType())
{
typeMap.Add(type_id, type);
}
typeIdMap.Add(type, type_id);
}
}
return type_id;
}
void pushPrimitive(RealStatePtr L, object o)
{
if (o is sbyte || o is byte || o is short || o is ushort ||
o is int)
{
int i = Convert.ToInt32(o);
LuaAPI.xlua_pushinteger(L, i);
}
else if (o is uint)
{
LuaAPI.xlua_pushuint(L, (uint)o);
}
else if (o is float || o is double)
{
double d = Convert.ToDouble(o);
LuaAPI.lua_pushnumber(L, d);
}
else if (o is IntPtr)
{
LuaAPI.lua_pushlightuserdata(L, (IntPtr)o);
}
else if (o is char)
{
LuaAPI.xlua_pushinteger(L, (char)o);
}
else if (o is long)
{
LuaAPI.lua_pushint64(L, Convert.ToInt64(o));
}
else if (o is ulong)
{
LuaAPI.lua_pushuint64(L, Convert.ToUInt64(o));
}
else if (o is bool)
{
bool b = (bool)o;
LuaAPI.lua_pushboolean(L, b);
}
else
{
throw new Exception("No support type " + o.GetType());
}
}
public void PushAny(RealStatePtr L, object o)
{
if (o == null)
{
LuaAPI.lua_pushnil(L);
return;
}
Type type = o.GetType();
if (type.IsPrimitive())
{
pushPrimitive(L, o);
}
else if (o is string)
{
LuaAPI.lua_pushstring(L, o as string);
}
else if (type == typeof(byte[]))
{
LuaAPI.lua_pushstring(L, o as byte[]);
}
else if (o is decimal)
{
PushDecimal(L, (decimal)o);
}
else if (o is LuaBase)
{
((LuaBase)o).push(L);
}
else if (o is LuaCSFunction)
{
Push(L, o as LuaCSFunction);
}
else if (o is ValueType)
{
PushCSObject push;
if (custom_push_funcs.TryGetValue(o.GetType(), out push))
{
push(L, o);
}
else
{
Push(L, o);
}
}
else
{
Push(L, o);
}
}
Dictionary<object, int> enumMap = new Dictionary<object, int>();
public int TranslateToEnumToTop(RealStatePtr L, Type type, int idx)
{
object res = null;
LuaTypes lt = (LuaTypes)LuaAPI.lua_type(L, idx);
if (lt == LuaTypes.LUA_TNUMBER)
{
int ival = (int)LuaAPI.lua_tonumber(L, idx);
res = Enum.ToObject(type, ival);
}
else if (lt == LuaTypes.LUA_TSTRING)
{
string sflags = LuaAPI.lua_tostring(L, idx);
res = Enum.Parse(type, sflags);
}
else
{
return LuaAPI.luaL_error(L, "#1 argument must be a integer or a string");
}
PushAny(L, res);
return 1;
}
public void Push(RealStatePtr L, LuaCSFunction o)
{
if (Utils.IsStaticPInvokeCSFunction(o))
{
LuaAPI.lua_pushstdcallcfunction(L, o);
}
else
{
Push(L, (object)o);
LuaAPI.lua_pushstdcallcfunction(L, metaFunctions.StaticCSFunctionWraper, 1);
}
}
public void Push(RealStatePtr L, LuaBase o)
{
if (o == null)
{
LuaAPI.lua_pushnil(L);
}
else
{
o.push(L);
}
}
public void Push(RealStatePtr L, object o)
{
if (o == null)
{
LuaAPI.lua_pushnil(L);
return;
}
int index = -1;
Type type = o.GetType();
#if !UNITY_WSA || UNITY_EDITOR
bool is_enum = type.IsEnum;
bool is_valuetype = type.IsValueType;
#else
bool is_enum = type.GetTypeInfo().IsEnum;
bool is_valuetype = type.GetTypeInfo().IsValueType;
#endif
bool needcache = !is_valuetype || is_enum;
if (needcache && (is_enum ? enumMap.TryGetValue(o, out index) : reverseMap.TryGetValue(o, out index)))
{
if (LuaAPI.xlua_tryget_cachedud(L, index, cacheRef) == 1)
{
return;
}
//这里实在太经典了weaktable先删除然后GC会延迟调用当index会循环利用的时候不注释这行将会导致重复释放
//collectObject(index);
}
bool is_first;
int type_id = getTypeId(L, type, out is_first);
//如果一个type的定义含本身静态readonly实例时getTypeId会push一个实例这时候应该用这个实例
if (is_first && needcache && (is_enum ? enumMap.TryGetValue(o, out index) : reverseMap.TryGetValue(o, out index)))
{
if (LuaAPI.xlua_tryget_cachedud(L, index, cacheRef) == 1)
{
return;
}
}
index = addObject(o, is_valuetype, is_enum);
LuaAPI.xlua_pushcsobj(L, index, type_id, needcache, cacheRef);
}
public void PushObject(RealStatePtr L, object o, int type_id)
{
if (o == null)
{
LuaAPI.lua_pushnil(L);
return;
}
int index = -1;
if (reverseMap.TryGetValue(o, out index))
{
if (LuaAPI.xlua_tryget_cachedud(L, index, cacheRef) == 1)
{
return;
}
}
index = addObject(o, false, false);
LuaAPI.xlua_pushcsobj(L, index, type_id, true, cacheRef);
}
public void Update(RealStatePtr L, int index, object obj)
{
int udata = LuaAPI.xlua_tocsobj_fast(L, index);
if (udata != -1)
{
objects.Replace(udata, obj);
}
else
{
UpdateCSObject update;
if (custom_update_funcs.TryGetValue(obj.GetType(), out update))
{
update(L, index, obj);
}
else
{
throw new Exception("can not update [" + obj + "]");
}
}
}
private object getCsObj(RealStatePtr L, int index, int udata)
{
object obj;
if (udata == -1)
{
if (LuaAPI.lua_type(L, index) != LuaTypes.LUA_TUSERDATA) return null;
Type type = GetTypeOf(L, index);
if (type == typeof(decimal))
{
decimal v;
Get(L, index, out v);
return v;
}
GetCSObject get;
if (type != null && custom_get_funcs.TryGetValue(type, out get))
{
return get(L, index);
}
else
{
return null;
}
}
else if (objects.TryGetValue(udata, out obj))
{
#if !UNITY_5 && !XLUA_GENERAL && !UNITY_2017 && !UNITY_2017_1_OR_NEWER && !UNITY_2018
if (obj != null && obj is UnityEngine.Object && ((obj as UnityEngine.Object) == null))
{
//throw new UnityEngine.MissingReferenceException("The object of type '"+ obj.GetType().Name +"' has been destroyed but you are still trying to access it.");
return null;
}
#endif
return obj;
}
return null;
}
internal object SafeGetCSObj(RealStatePtr L, int index)
{
return getCsObj(L, index, LuaAPI.xlua_tocsobj_safe(L, index));
}
internal object FastGetCSObj(RealStatePtr L,int index)
{
return getCsObj(L, index, LuaAPI.xlua_tocsobj_fast(L,index));
}
internal void ReleaseCSObj(RealStatePtr L, int index)
{
int udata = LuaAPI.xlua_tocsobj_safe(L, index);
if (udata != -1)
{
object o = objects.Replace(udata, null);
if (o != null && reverseMap.ContainsKey(o))
{
reverseMap.Remove(o);
}
}
}
List<LuaCSFunction> fix_cs_functions = new List<LuaCSFunction>();
internal LuaCSFunction GetFixCSFunction(int index)
{
return fix_cs_functions[index];
}
internal void PushFixCSFunction(RealStatePtr L, LuaCSFunction func)
{
if (func == null)
{
LuaAPI.lua_pushnil(L);
}
else
{
LuaAPI.xlua_pushinteger(L, fix_cs_functions.Count);
fix_cs_functions.Add(func);
LuaAPI.lua_pushstdcallcfunction(L, metaFunctions.FixCSFunctionWraper, 1);
}
}
#if GEN_CODE_MINIMIZE
CSharpWrapper[] csharpWrapper = new CSharpWrapper[0];
int csharpWrapperSize = 0;
internal int CallCSharpWrapper(RealStatePtr L, int funcidx, int top)
{
return csharpWrapper[funcidx](L, top);
}
void ensureCSharpWrapperCapacity(int min)
{
if (csharpWrapper.Length < min)
{
int num = (csharpWrapper.Length == 0) ? 4 : (csharpWrapper.Length * 2);
if (num > 2146435071)
{
num = 2146435071;
}
if (num < min)
{
num = min;
}
var array = new CSharpWrapper[num];
Array.Copy(csharpWrapper, 0, array, 0, csharpWrapper.Length);
csharpWrapper = array;
}
}
internal void PushCSharpWrapper(RealStatePtr L, CSharpWrapper func)
{
if (func == null)
{
LuaAPI.lua_pushnil(L);
}
else
{
LuaAPI.xlua_push_csharp_wrapper(L, csharpWrapperSize);
ensureCSharpWrapperCapacity(csharpWrapperSize + 1);
csharpWrapper[csharpWrapperSize++] = func;
}
}
#endif
internal object[] popValues(RealStatePtr L,int oldTop)
{
int newTop=LuaAPI.lua_gettop(L);
if(oldTop==newTop)
{
return null;
}
else
{
ArrayList returnValues=new ArrayList();
for(int i=oldTop+1;i<=newTop;i++)
{
returnValues.Add(GetObject(L,i));
}
LuaAPI.lua_settop(L,oldTop);
return returnValues.ToArray();
}
}
internal object[] popValues(RealStatePtr L,int oldTop,Type[] popTypes)
{
int newTop=LuaAPI.lua_gettop(L);
if(oldTop==newTop)
{
return null;
}
else
{
int iTypes;
ArrayList returnValues=new ArrayList();
if(popTypes[0] == typeof(void))
iTypes=1;
else
iTypes=0;
for(int i=oldTop+1;i<=newTop;i++)
{
returnValues.Add(GetObject(L,i,popTypes[iTypes]));
iTypes++;
}
LuaAPI.lua_settop(L,oldTop);
return returnValues.ToArray();
}
}
public delegate void PushCSObject(RealStatePtr L, object obj);
public delegate object GetCSObject(RealStatePtr L, int idx);
public delegate void UpdateCSObject(RealStatePtr L, int idx, object obj);
private Dictionary<Type, PushCSObject> custom_push_funcs = new Dictionary<Type, PushCSObject>();
private Dictionary<Type, GetCSObject> custom_get_funcs = new Dictionary<Type, GetCSObject>();
private Dictionary<Type, UpdateCSObject> custom_update_funcs = new Dictionary<Type, UpdateCSObject>();
void registerCustomOp(Type type, PushCSObject push, GetCSObject get, UpdateCSObject update)
{
if (push != null) custom_push_funcs.Add(type, push);
if (get != null) custom_get_funcs.Add(type, get);
if (update != null) custom_update_funcs.Add(type, update);
}
public bool HasCustomOp(Type type)
{
return custom_push_funcs.ContainsKey(type);
}
private Dictionary<Type, Delegate> push_func_with_type = null;
bool tryGetPushFuncByType<T>(Type type, out T func) where T : class
{
if (push_func_with_type == null)
{
push_func_with_type = new Dictionary<Type, Delegate>()
{
{typeof(int), new Action<RealStatePtr, int>(LuaAPI.xlua_pushinteger) },
{typeof(double), new Action<RealStatePtr, double>(LuaAPI.lua_pushnumber) },
{typeof(string), new Action<RealStatePtr, string>(LuaAPI.lua_pushstring) },
{typeof(byte[]), new Action<RealStatePtr, byte[]>(LuaAPI.lua_pushstring) },
{typeof(bool), new Action<RealStatePtr, bool>(LuaAPI.lua_pushboolean) },
{typeof(long), new Action<RealStatePtr, long>(LuaAPI.lua_pushint64) },
{typeof(ulong), new Action<RealStatePtr, ulong>(LuaAPI.lua_pushuint64) },
{typeof(IntPtr), new Action<RealStatePtr, IntPtr>(LuaAPI.lua_pushlightuserdata) },
{typeof(decimal), new Action<RealStatePtr, decimal>(PushDecimal) },
{typeof(byte), new Action<RealStatePtr, byte>((L, v) => LuaAPI.xlua_pushinteger(L, v)) },
{typeof(sbyte), new Action<RealStatePtr, sbyte>((L, v) => LuaAPI.xlua_pushinteger(L, v)) },
{typeof(char), new Action<RealStatePtr, char>((L, v) => LuaAPI.xlua_pushinteger(L, v)) },
{typeof(short), new Action<RealStatePtr, short>((L, v) => LuaAPI.xlua_pushinteger(L, v)) },
{typeof(ushort), new Action<RealStatePtr, ushort>((L, v) => LuaAPI.xlua_pushinteger(L, v)) },
{typeof(uint), new Action<RealStatePtr, uint>(LuaAPI.xlua_pushuint) },
{typeof(float), new Action<RealStatePtr, float>((L, v) => LuaAPI.lua_pushnumber(L, v)) },
};
}
Delegate obj;
if (push_func_with_type.TryGetValue(type, out obj))
{
func = obj as T;
return true;
}
else
{
func = null;
return false;
}
}
private Dictionary<Type, Delegate> get_func_with_type = null;
bool tryGetGetFuncByType<T>(Type type, out T func) where T : class
{
if (get_func_with_type == null)
{
get_func_with_type = new Dictionary<Type, Delegate>()
{
{typeof(int), new Func<RealStatePtr, int, int>(LuaAPI.xlua_tointeger) },
{typeof(double), new Func<RealStatePtr, int, double>(LuaAPI.lua_tonumber) },
{typeof(string), new Func<RealStatePtr, int, string>(LuaAPI.lua_tostring) },
{typeof(byte[]), new Func<RealStatePtr, int, byte[]>(LuaAPI.lua_tobytes) },
{typeof(bool), new Func<RealStatePtr, int, bool>(LuaAPI.lua_toboolean) },
{typeof(long), new Func<RealStatePtr, int, long>(LuaAPI.lua_toint64) },
{typeof(ulong), new Func<RealStatePtr, int, ulong>(LuaAPI.lua_touint64) },
{typeof(IntPtr), new Func<RealStatePtr, int, IntPtr>(LuaAPI.lua_touserdata) },
{typeof(decimal), new Func<RealStatePtr, int, decimal>((L, idx) => {
decimal ret;
Get(L, idx, out ret);
return ret;
}) },
{typeof(byte), new Func<RealStatePtr, int, byte>((L, idx) => (byte)LuaAPI.xlua_tointeger(L, idx) ) },
{typeof(sbyte), new Func<RealStatePtr, int, sbyte>((L, idx) => (sbyte)LuaAPI.xlua_tointeger(L, idx) ) },
{typeof(char), new Func<RealStatePtr, int, char>((L, idx) => (char)LuaAPI.xlua_tointeger(L, idx) ) },
{typeof(short), new Func<RealStatePtr, int, short>((L, idx) => (short)LuaAPI.xlua_tointeger(L, idx) ) },
{typeof(ushort), new Func<RealStatePtr, int, ushort>((L, idx) => (ushort)LuaAPI.xlua_tointeger(L, idx) ) },
{typeof(uint), new Func<RealStatePtr, int, uint>(LuaAPI.xlua_touint) },
{typeof(float), new Func<RealStatePtr, int, float>((L, idx) => (float)LuaAPI.lua_tonumber(L, idx) ) },
};
}
Delegate obj;
if (get_func_with_type.TryGetValue(type, out obj))
{
func = obj as T;
return true;
}
else
{
func = null;
return false;
}
}
public delegate bool CheckFunc<T>(RealStatePtr L, int idx);
public delegate void GetFunc<T>(RealStatePtr L, int idx, out T val);
public void RegisterPushAndGetAndUpdate<T>(Action<RealStatePtr, T> push, GetFunc<T> get, Action<RealStatePtr, int, T> update)
{
Type type = typeof(T);
Action<RealStatePtr, T> org_push;
Func<RealStatePtr, int, T> org_get;
if (tryGetPushFuncByType(type, out org_push) || tryGetGetFuncByType(type, out org_get))
{
throw new InvalidOperationException("push or get of " + type + " has register!");
}
push_func_with_type.Add(type, push);
get_func_with_type.Add(type, new Func<RealStatePtr, int, T>((L, idx) => {
T ret;
get(L, idx, out ret);
return ret;
}));
registerCustomOp(type,
(RealStatePtr L, object obj) => {
push(L, (T)obj);
},
(RealStatePtr L, int idx) => {
T val;
get(L, idx, out val);
return val;
},
(RealStatePtr L, int idx, object obj) => {
update(L, idx, (T)obj);
}
);
}
public void RegisterChecker<T>(CheckFunc<T> check)
{
objectCheckers.AddChecker(typeof(T), (L, idx) =>
{
return check(L, idx);
});
}
public void RegisterCaster<T>(GetFunc<T> get)
{
objectCasters.AddCaster(typeof(T), (L, idx, o) =>
{
T obj;
get(L, idx, out obj);
return obj;
});
}
int decimal_type_id = -1;
public void PushDecimal(RealStatePtr L, decimal val)
{
if (decimal_type_id == -1)
{
bool is_first;
decimal_type_id = getTypeId(L, typeof(decimal), out is_first);
}
IntPtr buff = LuaAPI.xlua_pushstruct(L, 16, decimal_type_id);
if (!CopyByValue.Pack(buff, 0, val))
{
throw new Exception("pack fail for decimal ,value=" + val);
}
}
public bool IsDecimal(RealStatePtr L, int index)
{
if (decimal_type_id == -1) return false;
return LuaAPI.xlua_gettypeid(L, index) == decimal_type_id;
}
public decimal GetDecimal(RealStatePtr L, int index)
{
decimal ret;
Get(L, index, out ret);
return ret;
}
public void Get(RealStatePtr L, int index, out decimal val)
{
LuaTypes lua_type = LuaAPI.lua_type(L, index);
if (lua_type == LuaTypes.LUA_TUSERDATA)
{
if (LuaAPI.xlua_gettypeid(L, index) != decimal_type_id)
{
throw new Exception("invalid userdata for decimal!");
}
IntPtr buff = LuaAPI.lua_touserdata(L, index);
if (!CopyByValue.UnPack(buff, 0, out val))
{
throw new Exception("unpack decimal fail!");
}
}
else if(lua_type == LuaTypes.LUA_TNUMBER)
{
if (LuaAPI.lua_isint64(L, index))
{
val = (decimal)LuaAPI.lua_toint64(L, index);
}
else
{
val = (decimal)LuaAPI.lua_tonumber(L, index); // has gc
}
}
else
{
throw new Exception("invalid lua value for decimal, LuaType=" + lua_type);
}
}
}
}