2024-08-23 15:49:34 +08:00
/ *
* 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 ( ) ;
2024-09-04 02:07:48 +08:00
#if ! XLUA_GENERAL
2024-08-23 15:49:34 +08:00
if ( ( delegateMethod . ReturnType . IsValueType ( ) & & delegateMethod . ReturnType ! = typeof ( void ) ) | | parameters . Length > 4 )
{
genericDelegateCreator = ( x ) = > null ;
}
else
2024-09-04 02:07:48 +08:00
#endif
2024-08-23 15:49:34 +08:00
{
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 ;
}
}
2024-09-04 02:07:48 +08:00
public delegate bool CheckFunc < T > ( RealStatePtr L , int idx ) ;
2024-08-23 15:49:34 +08:00
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 ) ;
}
) ;
}
2024-09-04 02:07:48 +08:00
public void RegisterChecker < T > ( CheckFunc < T > check )
{
objectCheckers . AddChecker ( typeof ( T ) , ( L , idx ) = >
{
return check ( L , idx ) ;
} ) ;
}
2024-08-23 15:49:34 +08:00
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 ) ;
}
}
}
}