国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

xlua源碼分析(二)lua Call C#的無(wú)wrap實(shí)現(xiàn)

這篇具有很好參考價(jià)值的文章主要介紹了xlua源碼分析(二)lua Call C#的無(wú)wrap實(shí)現(xiàn)。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

上一節(jié)我們主要分析了xlua中C# Call lua的實(shí)現(xiàn)思路,本節(jié)我們將根據(jù)Examples 03_UIEvent,分析lua Call C#的底層實(shí)現(xiàn)。例子場(chǎng)景里有一個(gè)簡(jiǎn)單的UI面板,面板中包含一個(gè)input field,一個(gè)button:

xlua源碼分析(二)lua Call C#的無(wú)wrap實(shí)現(xiàn),xlua源碼分析,lua,c#,xlua

輸入任意文本,點(diǎn)擊button,就會(huì)打印出輸入的內(nèi)容:

xlua源碼分析(二)lua Call C#的無(wú)wrap實(shí)現(xiàn),xlua源碼分析,lua,c#,xlua

響應(yīng)點(diǎn)擊事件的代碼是在lua層,位于ButtonInteraction.lua.txt這個(gè)文件中,lua代碼很簡(jiǎn)單,就是一個(gè)簡(jiǎn)單的函數(shù):

function start()
	print("lua start...")

	self:GetComponent("Button").onClick:AddListener(function()
		print("clicked, you input is '" ..input:GetComponent("InputField").text .."'")
	end)
end

那么C#層從哪里讀取到這個(gè)文件的呢?可以看到,Button這個(gè)GameObject上綁了上一節(jié)我們提到過的LuaBehaviour組件,而組件里設(shè)置的Lua Script就是這個(gè)文件了:

xlua源碼分析(二)lua Call C#的無(wú)wrap實(shí)現(xiàn),xlua源碼分析,lua,c#,xlua

上一節(jié)我們說(shuō)過,LuaBehaviour組件會(huì)在Awake的時(shí)候會(huì)執(zhí)行l(wèi)ua代碼,獲取lua層寫的start函數(shù),然后在MonoBehaviour的Start中執(zhí)行它。在lua層的start函數(shù)中,首先可以發(fā)現(xiàn)一個(gè)self,這個(gè)self也是在C#層Awake的時(shí)候設(shè)置的,對(duì)應(yīng)的就是C#的LuaBehaviour對(duì)象。和tolua一樣,xlua也會(huì)把C#對(duì)象當(dāng)作userdata來(lái)處理,每個(gè)要push到lua層的C#類型都有唯一的type_id,對(duì)應(yīng)到不同的metatable,用來(lái)定義userdata的行為。并且,除了值類型和枚舉類型之外,所有push到lua層的C#對(duì)象,都會(huì)在C#層緩存,這一點(diǎn)也是和tolua一樣的,甚至緩存的數(shù)據(jù)結(jié)構(gòu)也大差不差。

public void Push(RealStatePtr L, object o)
{
    if (needcache && (is_enum ? enumMap.TryGetValue(o, out index) : reverseMap.TryGetValue(o, out index)))
    {
        if (LuaAPI.xlua_tryget_cachedud(L, index, cacheRef) == 1)
        {
            return;
        }
    }

    bool is_first;
    int type_id = getTypeId(L, type, out is_first);

    index = addObject(o, is_valuetype, is_enum);
    LuaAPI.xlua_pushcsobj(L, index, type_id, needcache, cacheRef);
}

xlua_tryget_cachedud函數(shù)就是通過C#緩存拿到的index,去lua層的緩存去拿userdata,lua層的緩存與C#不同,它只負(fù)責(zé)查詢,不負(fù)責(zé)存儲(chǔ),因此是一個(gè)value為弱引用的弱表,這一點(diǎn)和tolua也是一樣的,xlua在初始化時(shí)就會(huì)將這個(gè)弱表準(zhǔn)備好:

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);

由于這個(gè)緩存是弱表,意味著userdata在被真正gc之前,弱表里對(duì)應(yīng)的值有可能已經(jīng)不存在了。那么xlua_tryget_cachedud這個(gè)函數(shù)有可能是取不到userdata的:

LUA_API int xlua_tryget_cachedud(lua_State *L, int key, int cache_ref) {
	lua_rawgeti(L, LUA_REGISTRYINDEX, cache_ref);
	lua_rawgeti(L, -1, key);
	if (!lua_isnil(L, -1))
	{
		lua_remove(L, -2);
		return 1;
	}
	lua_pop(L, 2);
	return 0;
}

取不到的話就通過xlua_pushcsobj這個(gè)函數(shù)新增一個(gè)userdata:

static void cacheud(lua_State *L, int key, int cache_ref) {
	lua_rawgeti(L, LUA_REGISTRYINDEX, cache_ref);
	lua_pushvalue(L, -2);
	lua_rawseti(L, -2, key);
	lua_pop(L, 1);
}


LUA_API void xlua_pushcsobj(lua_State *L, int key, int meta_ref, int need_cache, int cache_ref) {
	int* pointer = (int*)lua_newuserdata(L, sizeof(int));
	*pointer = key;
	
	if (need_cache) cacheud(L, key, cache_ref);

    lua_rawgeti(L, LUA_REGISTRYINDEX, meta_ref);

	lua_setmetatable(L, -2);
}

但是,xlua設(shè)置userdata metatable的做法和tolua完全不同。xlua使用delay wrap的策略,即只有某個(gè)C#類型的對(duì)象push到了lua層,才會(huì)將這個(gè)C#類型的信息,真正地加載到lua層,在此之前,這個(gè)metatable并不存在;而tolua默認(rèn)是在一開始就wrap的,這樣的話類型一多,初始化的時(shí)間就大大增加,而且根據(jù)二八定律,可能絕大部分的類型在一開始?jí)焊貌坏健?/p>

那么,這個(gè)delay wrap具體是怎么實(shí)現(xiàn)的呢?既然它是在C#對(duì)象push到lua層觸發(fā)的,那么顯而易見,在獲取這個(gè)類的type_id時(shí),就要把C#類的信息加載進(jìn)來(lái)了:

internal int getTypeId(RealStatePtr L, Type type, out bool is_first, LOGLEVEL log_level = LOGLEVEL.WARN)
{
    int type_id;
    if (!typeIdMap.TryGetValue(type, out type_id)) // no reference
    {
        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);
            }
        }

        typeIdMap.Add(type, type_id);
    }
    return type_id;
}

負(fù)責(zé)這件事情的函數(shù)就是TryDelayWrapLoader。在例子中,由于我們沒有生成過類的wrap,默認(rèn)就會(huì)使用反射的方式來(lái)注冊(cè)各種C#方法與成員。具體實(shí)現(xiàn)的邏輯比較復(fù)雜,主要在ReflectionWrap這個(gè)函數(shù)中:

public static void ReflectionWrap(RealStatePtr L, Type type, bool privateAccessible)
{
    LuaAPI.lua_checkstack(L, 20);

    int top_enter = LuaAPI.lua_gettop(L);
    ObjectTranslator translator = ObjectTranslatorPool.Instance.Find(L);
    //create obj meta table
    LuaAPI.luaL_getmetatable(L, type.FullName);
    if (LuaAPI.lua_isnil(L, -1))
    {
        LuaAPI.lua_pop(L, 1);
        LuaAPI.luaL_newmetatable(L, type.FullName);
    }
    LuaAPI.lua_pushlightuserdata(L, LuaAPI.xlua_tag());
    LuaAPI.lua_pushnumber(L, 1);
    LuaAPI.lua_rawset(L, -3);
    int obj_meta = LuaAPI.lua_gettop(L);

    LuaAPI.lua_newtable(L);
    int cls_meta = LuaAPI.lua_gettop(L);

    LuaAPI.lua_newtable(L);
    int obj_field = LuaAPI.lua_gettop(L);
    LuaAPI.lua_newtable(L);
    int obj_getter = LuaAPI.lua_gettop(L);
    LuaAPI.lua_newtable(L);
    int obj_setter = LuaAPI.lua_gettop(L);
    LuaAPI.lua_newtable(L);
    int cls_field = LuaAPI.lua_gettop(L);
    //set cls_field to namespace
    SetCSTable(L, type, cls_field);
    //finish set cls_field to namespace
    LuaAPI.lua_newtable(L);
    int cls_getter = LuaAPI.lua_gettop(L);
    LuaAPI.lua_newtable(L);
    int cls_setter = LuaAPI.lua_gettop(L);

    LuaCSFunction item_getter;
    LuaCSFunction item_setter;
    makeReflectionWrap(L, type, cls_field, cls_getter, cls_setter, obj_field, obj_getter, obj_setter, obj_meta,
        out item_getter, out item_setter, privateAccessible ? (BindingFlags.Public | BindingFlags.NonPublic) : BindingFlags.Public);

    // init obj metatable
    LuaAPI.xlua_pushasciistring(L, "__gc");
    LuaAPI.lua_pushstdcallcfunction(L, translator.metaFunctions.GcMeta);
    LuaAPI.lua_rawset(L, obj_meta);

    LuaAPI.xlua_pushasciistring(L, "__tostring");
    LuaAPI.lua_pushstdcallcfunction(L, translator.metaFunctions.ToStringMeta);
    LuaAPI.lua_rawset(L, obj_meta);

    LuaAPI.xlua_pushasciistring(L, "__index");
    LuaAPI.lua_pushvalue(L, obj_field);
    LuaAPI.lua_pushvalue(L, obj_getter);
    translator.PushFixCSFunction(L, item_getter);
    translator.PushAny(L, type.BaseType());
    LuaAPI.xlua_pushasciistring(L, LuaIndexsFieldName);
    LuaAPI.lua_rawget(L, LuaIndexes.LUA_REGISTRYINDEX);
    LuaAPI.lua_pushnil(L);
    LuaAPI.gen_obj_indexer(L);
    //store in lua indexs function tables
    LuaAPI.xlua_pushasciistring(L, LuaIndexsFieldName);
    LuaAPI.lua_rawget(L, LuaIndexes.LUA_REGISTRYINDEX);
    translator.Push(L, type);
    LuaAPI.lua_pushvalue(L, -3);
    LuaAPI.lua_rawset(L, -3);
    LuaAPI.lua_pop(L, 1);
    LuaAPI.lua_rawset(L, obj_meta); // set __index

    LuaAPI.xlua_pushasciistring(L, "__newindex");
    LuaAPI.lua_pushvalue(L, obj_setter);
    translator.PushFixCSFunction(L, item_setter);
    translator.Push(L, type.BaseType());
    LuaAPI.xlua_pushasciistring(L, LuaNewIndexsFieldName);
    LuaAPI.lua_rawget(L, LuaIndexes.LUA_REGISTRYINDEX);
    LuaAPI.lua_pushnil(L);
    LuaAPI.gen_obj_newindexer(L);
    //store in lua newindexs function tables
    LuaAPI.xlua_pushasciistring(L, LuaNewIndexsFieldName);
    LuaAPI.lua_rawget(L, LuaIndexes.LUA_REGISTRYINDEX);
    translator.Push(L, type);
    LuaAPI.lua_pushvalue(L, -3);
    LuaAPI.lua_rawset(L, -3);
    LuaAPI.lua_pop(L, 1);
    LuaAPI.lua_rawset(L, obj_meta); // set __newindex
                                    //finish init obj metatable

    LuaAPI.xlua_pushasciistring(L, "UnderlyingSystemType");
    translator.PushAny(L, type);
    LuaAPI.lua_rawset(L, cls_field);

    if (type != null && type.IsEnum())
    {
        LuaAPI.xlua_pushasciistring(L, "__CastFrom");
        translator.PushFixCSFunction(L, genEnumCastFrom(type));
        LuaAPI.lua_rawset(L, cls_field);
    }

    //init class meta
    LuaAPI.xlua_pushasciistring(L, "__index");
    LuaAPI.lua_pushvalue(L, cls_getter);
    LuaAPI.lua_pushvalue(L, cls_field);
    translator.Push(L, type.BaseType());
    LuaAPI.xlua_pushasciistring(L, LuaClassIndexsFieldName);
    LuaAPI.lua_rawget(L, LuaIndexes.LUA_REGISTRYINDEX);
    LuaAPI.gen_cls_indexer(L);
    //store in lua indexs function tables
    LuaAPI.xlua_pushasciistring(L, LuaClassIndexsFieldName);
    LuaAPI.lua_rawget(L, LuaIndexes.LUA_REGISTRYINDEX);
    translator.Push(L, type);
    LuaAPI.lua_pushvalue(L, -3);
    LuaAPI.lua_rawset(L, -3);
    LuaAPI.lua_pop(L, 1);
    LuaAPI.lua_rawset(L, cls_meta); // set __index 

    LuaAPI.xlua_pushasciistring(L, "__newindex");
    LuaAPI.lua_pushvalue(L, cls_setter);
    translator.Push(L, type.BaseType());
    LuaAPI.xlua_pushasciistring(L, LuaClassNewIndexsFieldName);
    LuaAPI.lua_rawget(L, LuaIndexes.LUA_REGISTRYINDEX);
    LuaAPI.gen_cls_newindexer(L);
    //store in lua newindexs function tables
    LuaAPI.xlua_pushasciistring(L, LuaClassNewIndexsFieldName);
    LuaAPI.lua_rawget(L, LuaIndexes.LUA_REGISTRYINDEX);
    translator.Push(L, type);
    LuaAPI.lua_pushvalue(L, -3);
    LuaAPI.lua_rawset(L, -3);
    LuaAPI.lua_pop(L, 1);
    LuaAPI.lua_rawset(L, cls_meta); // set __newindex

    LuaCSFunction constructor = typeof(Delegate).IsAssignableFrom(type) ? translator.metaFunctions.DelegateCtor : translator.methodWrapsCache.GetConstructorWrap(type);
    if (constructor == null)
    {
        constructor = (RealStatePtr LL) =>
        {
            return LuaAPI.luaL_error(LL, "No constructor for " + type);
        };
    }

    LuaAPI.xlua_pushasciistring(L, "__call");
    translator.PushFixCSFunction(L, constructor);
    LuaAPI.lua_rawset(L, cls_meta);

    LuaAPI.lua_pushvalue(L, cls_meta);
    LuaAPI.lua_setmetatable(L, cls_field);

    LuaAPI.lua_pop(L, 8);

    System.Diagnostics.Debug.Assert(top_enter == LuaAPI.lua_gettop(L));
}

相比于tolua只使用兩個(gè)table,xlua使用了若干的table來(lái)輔助索引查找C#的方法和成員。從代碼中可以看出,cls_meta,cls_field,cls_getter和cls_setter是用直接給類訪問用的,比如一些靜態(tài)的方法與成員,lua層可以通過namespace和類名直接訪問。而相應(yīng)地,obj_meta,obj_field,obj_getter和obj_setter是給userdata訪問用的,對(duì)應(yīng)C#層實(shí)例方法與成員。從命名中也可看出,field對(duì)應(yīng)的是C#的字段和方法,getter對(duì)應(yīng)的是C#的get屬性,setter對(duì)應(yīng)的是set屬性,meta就是對(duì)外設(shè)置的metatable了。cls_meta中包含__index,__newindex,__call這三個(gè)元方法,這樣lua層就可以通過類名創(chuàng)建一個(gè)C#對(duì)象;obj_meta中包含__index,__newindex__gc,__tostring這四個(gè)元方法,并且它就是userdata的type_id。__index__newindex這兩個(gè)元方法,還會(huì)通過registry表,記錄對(duì)應(yīng)的type,來(lái)進(jìn)行額外的緩存,這么做的目的主要是為了基類查找,xlua不像tolua一樣,嵌套使用多個(gè)metatable來(lái)實(shí)現(xiàn)繼承機(jī)制。

那么field,getter,setter這三種table是如何跟meta進(jìn)行關(guān)聯(lián)的呢?xlua使用了一種非常巧妙的機(jī)制,以u(píng)serdata的__index為例,它其實(shí)對(duì)應(yīng)著一個(gè)函數(shù),這個(gè)函數(shù)使用包含field,getter,setter這三種table在內(nèi),以及其他的一些參數(shù),作為upvalue來(lái)引用。

LUA_API int gen_obj_indexer(lua_State *L) {
	lua_pushnil(L);
	lua_pushcclosure(L, obj_indexer, 7);
	return 0;
}

obj_indexer這個(gè)函數(shù)持有了7個(gè)upvalue,是有點(diǎn)多,注釋里也標(biāo)明了每個(gè)upvalue的用途:

//upvalue --- [1]: methods, [2]:getters, [3]:csindexer, [4]:base, [5]:indexfuncs, [6]:arrayindexer, [7]:baseindex
//param   --- [1]: obj, [2]: key
LUA_API int obj_indexer(lua_State *L) {	
	if (!lua_isnil(L, lua_upvalueindex(1))) {
		lua_pushvalue(L, 2);
		lua_gettable(L, lua_upvalueindex(1));
		if (!lua_isnil(L, -1)) {//has method
			return 1;
		}
		lua_pop(L, 1);
	}
	
	if (!lua_isnil(L, lua_upvalueindex(2))) {
		lua_pushvalue(L, 2);
		lua_gettable(L, lua_upvalueindex(2));
		if (!lua_isnil(L, -1)) {//has getter
			lua_pushvalue(L, 1);
			lua_call(L, 1, 1);
			return 1;
		}
		lua_pop(L, 1);
	}
	
	
	if (!lua_isnil(L, lua_upvalueindex(6)) && lua_type(L, 2) == LUA_TNUMBER) {
		lua_pushvalue(L, lua_upvalueindex(6));
		lua_pushvalue(L, 1);
		lua_pushvalue(L, 2);
		lua_call(L, 2, 1);
		return 1;
	}
	
	if (!lua_isnil(L, lua_upvalueindex(3))) {
		lua_pushvalue(L, lua_upvalueindex(3));
		lua_pushvalue(L, 1);
		lua_pushvalue(L, 2);
		lua_call(L, 2, 2);
		if (lua_toboolean(L, -2)) {
			return 1;
		}
		lua_pop(L, 2);
	}
	
	if (!lua_isnil(L, lua_upvalueindex(4))) {
		lua_pushvalue(L, lua_upvalueindex(4));
		while(!lua_isnil(L, -1)) {
			lua_pushvalue(L, -1);
			lua_gettable(L, lua_upvalueindex(5));
			if (!lua_isnil(L, -1)) // found
			{
				lua_replace(L, lua_upvalueindex(7)); //baseindex = indexfuncs[base]
				lua_pop(L, 1);
				break;
			}
			lua_pop(L, 1);
			lua_getfield(L, -1, "BaseType");
			lua_remove(L, -2);
		}
		lua_pushnil(L);
		lua_replace(L, lua_upvalueindex(4));//base = nil
	}
	
	if (!lua_isnil(L, lua_upvalueindex(7))) {
		lua_settop(L, 2);
		lua_pushvalue(L, lua_upvalueindex(7));
		lua_insert(L, 1);
		lua_call(L, 2, 1);
		return 1;
	} else {
		return 0;
	}
}

我們著重看一下第4個(gè)upvalue的情況,走到這里說(shuō)明在當(dāng)前類中沒有查找到,例子中的GetComponent方法是在Component類里,在LuaBehaviour類里自然是查找不到的,那么就需要不斷地往父類查找。第4個(gè)upvalue是當(dāng)前類的基類類型base type,第5個(gè)upvalue就是緩存了當(dāng)前所有type的__index元方法函數(shù),那么自然而然就要去這個(gè)緩存中查找base type的__index元方法,然后把事情直接交給它做就好了,這其實(shí)就是一個(gè)遞歸的做法。為了避免下次還要從緩存中查找基類,這里直接把第4個(gè)upvalue置為空,然后把基類的__index元方法緩存到第7個(gè)upvalue上。

那問題來(lái)了,我們之前提到xlua是delay wrap的,在訪問C#對(duì)象的時(shí)候,它的基類信息很可能還沒wrap到lua層。所以這里也需要獲取一下基類的type_id。在從緩存中獲取__index元方法時(shí),代碼中使用的是:

lua_gettable(L, lua_upvalueindex(5));

lua_gettable是會(huì)觸發(fā)metatable的,這個(gè)緩存table在xlua初始化時(shí)就設(shè)置了一個(gè)metatable:

LuaAPI.lua_newtable(rawL); //metatable of indexs and newindexs functions
LuaAPI.xlua_pushasciistring(rawL, "__index");
LuaAPI.lua_pushstdcallcfunction(rawL, StaticLuaCallbacks.MetaFuncIndex);
LuaAPI.lua_rawset(rawL, -3);

LuaAPI.xlua_pushasciistring(rawL, Utils.LuaIndexsFieldName);
LuaAPI.lua_newtable(rawL);
LuaAPI.lua_pushvalue(rawL, -3);
LuaAPI.lua_setmetatable(rawL, -2);
LuaAPI.lua_rawset(rawL, LuaIndexes.LUA_REGISTRYINDEX);

因此如果基類信息還沒wrap,就會(huì)觸發(fā)到C#層的MetaFuncIndex方法:

public static int MetaFuncIndex(RealStatePtr L)
{
    try
    {
        ObjectTranslator translator = ObjectTranslatorPool.Instance.Find(L);
        Type type = translator.FastGetCSObj(L, 2) as Type;
        if (type == null)
        {
            return LuaAPI.luaL_error(L, "#2 param need a System.Type!");
        }
        translator.GetTypeId(L, type);
        LuaAPI.lua_pushvalue(L, 2);
        LuaAPI.lua_rawget(L, 1);
        return 1;
    }
    catch (System.Exception e)
    {
        return LuaAPI.luaL_error(L, "c# exception in MetaFuncIndex:" + e);
    }
}

這個(gè)函數(shù)首先會(huì)從lua層獲取當(dāng)前要wrap的type,生成唯一的type_id,并把類型信息wrap到lua層,然后再使用一次rawget把__index方法放回lua層,這樣lua層就可以繼續(xù)遞歸查找了。在例子中,想要調(diào)用到GetComponent得沿著LuaBehaviour=>MonoBehaviour=>Behaviour=>Component這條鏈一直查找3次才能找到。

最后,push到lua層的這些C#函數(shù),都是使用PushFixCSFunction這個(gè)方法完成的,這個(gè)方法把push到lua層的函數(shù)統(tǒng)一放到一個(gè)list中管理,實(shí)際調(diào)用時(shí)根據(jù)list中的索引,觸發(fā)具體的某個(gè)函數(shù):

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);
    }
}

static int FixCSFunction(RealStatePtr L)
{
    try
    {
        ObjectTranslator translator = ObjectTranslatorPool.Instance.Find(L);
        int idx = LuaAPI.xlua_tointeger(L, LuaAPI.xlua_upvalueindex(1));
        LuaCSFunction func = (LuaCSFunction)translator.GetFixCSFunction(idx);
        return func(L);
    }
    catch (Exception e)
    {
        return LuaAPI.luaL_error(L, "c# exception in FixCSFunction:" + e);
    }
}

推測(cè)這么做的原因可能是為了少一些MonoPInvokeCallback吧:)文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-742592.html

到了這里,關(guān)于xlua源碼分析(二)lua Call C#的無(wú)wrap實(shí)現(xiàn)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • XLua中l(wèi)ua讀寫cs對(duì)象的原理

    XLua在C#維護(hù)了兩個(gè)數(shù)據(jù)結(jié)構(gòu),ObjectPool和ReverseMap。 首次傳遞一個(gè)C#對(duì)象obj到Lua時(shí),對(duì)象被加入到ObjectPool中,并為它創(chuàng)建一個(gè)唯一標(biāo)識(shí)objId,建立obj和objId的雙向映射。 如果該對(duì)象的類型是第一次傳到Lua,還會(huì)為類型創(chuàng)建一個(gè)元表typeMetatable。 把typeMetatable注冊(cè)到Lua的全局表中,這

    2024年02月08日
    瀏覽(15)
  • 使用XLua在Unity中獲取lua全局變量和函數(shù)

    使用XLua在Unity中獲取lua全局變量和函數(shù)

    1、Lua腳本? 入口腳本 測(cè)試腳本 2、C#腳本 (1)獲取全局變量 執(zhí)行結(jié)果 (2)獲取全局函數(shù)

    2024年02月07日
    瀏覽(22)
  • Unity Xlua熱更新框架(五):Lua和UI管理

    Unity Xlua熱更新框架(五):Lua和UI管理

    :::info Lua存在兩種加載器,一種默認(rèn)加載器(env.DoString(\\\"require(‘test’)\\\"直接用了默認(rèn)加載其),直接調(diào)用StreamingAssets中的腳本);一種是自定義加載器(env.AddLoader(Envpath)),優(yōu)先于默認(rèn)加載器(下文DoString就是從自定義加載器的路徑讀取的),并且當(dāng)Lua代碼執(zhí)行require函數(shù)時(shí),

    2024年02月06日
    瀏覽(39)
  • 關(guān)于Unity在Xlua調(diào)用Lua腳本函數(shù)時(shí)報(bào)錯(cuò)This type must add to CSharpCallLua 解決辦法

    使用委托來(lái)獲取xlua中的function是不行的 報(bào)錯(cuò)腳本示范 即使全部接口打好標(biāo)簽并且在編輯器中把兼容等級(jí)改為4.X 打包出去還是會(huì)出問題 建議在lua腳本中建立一個(gè)空的table 再把方法塞進(jìn)去 比如 然后在c#端 就可以正常運(yùn)作這個(gè)方法了

    2024年02月12日
    瀏覽(26)
  • [游戲開發(fā)][Unity] Xlua與C#互相調(diào)用規(guī)則

    [游戲開發(fā)][Unity] Xlua與C#互相調(diào)用規(guī)則

    靜態(tài)方法無(wú)需獲取類對(duì)象,獲取到類直接執(zhí)行 例1: 例2 調(diào)用非靜態(tài)方法一定要獲取到具體的C#類對(duì)象?。。?例1:獲取單例對(duì)象并調(diào)用非靜態(tài)方法,Singleton是單例的一種寫法,網(wǎng)上源碼很多 下面是Lua調(diào)用C#的代碼,我這是模擬Xlua的工程,以類的方式實(shí)現(xiàn)交互 看Log日志發(fā)現(xiàn):

    2024年02月07日
    瀏覽(33)
  • lua中執(zhí)行l(wèi)uci.sys.call、luci.sys.exec、os.execute的區(qū)別

    相同點(diǎn):都是調(diào)用Linux底層腳本及程序 不同點(diǎn): (1)luci.sys.call(command) 脾氣捉摸不透,實(shí)際使用有些時(shí)候沒有得到任何狀態(tài)或數(shù)據(jù)返回,純粹被用了一下。 (2)luci.sys.exec(command) 比較可靠,可以返回標(biāo)準(zhǔn)輸出,比如 value = luci.sys.exec(command) 獲取執(zhí)行結(jié)果用作參量。 message =

    2024年02月13日
    瀏覽(38)
  • 基于C#的無(wú)邊框窗體動(dòng)畫效果的完美解決方案 - 開源研究系列文章

    基于C#的無(wú)邊框窗體動(dòng)畫效果的完美解決方案 - 開源研究系列文章

    ?????? 最近在整理和編寫基于C#的WinForm應(yīng)用程序,然后碰到一個(gè)其他讀者也可能碰到的問題,就是C#的Borderless無(wú)邊框窗體的動(dòng)畫效果問題。 ?????? 在Visual Studio 2022里,C#的WinForm程序提供了Borderless無(wú)邊框窗體的樣式效果,但是它沒提供在無(wú)邊框窗體下,窗體的載入、最小

    2024年02月15日
    瀏覽(22)
  • 【面試 分布式鎖詳細(xì)解析】續(xù)命 自旋鎖 看門狗 重入鎖,加鎖 續(xù)命 解鎖 核心源碼,lua腳本解析,具體代碼和lua腳本如何實(shí)現(xiàn)

    自己實(shí)現(xiàn)鎖續(xù)命 在 controller 里開一個(gè) 線程 (可以為 守護(hù)線程) 每10秒,判斷一個(gè) 這個(gè) UUID是否存在,如果 存在,重置為 30秒。 如果不存在,守護(hù)線程 也結(jié)束。 基本的key value 基本的使用 setIfAbsent存在不設(shè)置 16384 Redis 集群沒有使用一致性hash, 而是引入了哈希槽的概念。 R

    2023年04月09日
    瀏覽(27)
  • C#考勤系統(tǒng)數(shù)據(jù)分析源碼

    C#考勤系統(tǒng)數(shù)據(jù)分析源碼

    C#考勤系統(tǒng)數(shù)據(jù)分析源碼 源碼描述: 針對(duì)大部分考勤機(jī)采用E語(yǔ)言和ACCESS數(shù)據(jù)庫(kù)做系統(tǒng)的缺陷。 做出如下建議: 1.打卡機(jī)設(shè)置成直接續(xù)傳數(shù)據(jù)到SQL Server,不需要開著考勤系統(tǒng)和考勤安裝的電腦去維持打卡記錄 2.打卡機(jī)數(shù)據(jù)共享,把內(nèi)部ACCESS表?yè)Q成名稱一樣的Server連接表,連接

    2024年02月02日
    瀏覽(16)
  • C# Linq源碼分析之Take (一)

    C# Linq源碼分析之Take (一)

    在.Net 6 中引入的Take的另一個(gè)重載方法,一個(gè)基于Range的重載方法。因?yàn)樵摲椒ㄖ猩婕傲撕芏嘈碌母拍?,所以在分析源碼之前,先將這些概念搞清楚。 后續(xù)代碼分析,請(qǐng)參考 C# Linq源碼分析之Take (二) public static System.Collections.Generic.IEnumerable Take (this System.Collections.Generic.IEnu

    2024年02月12日
    瀏覽(15)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包