xLua Cheat Sheet

xLua 协程 WaitForSeconds

Continue.lua

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
Continue = {}
local M = Continue

local mIsAlreadyAdd = false
local mGameObjectHolder = nil
local function LazyAddGameObjectHolder()
if mIsAlreadyAdd then return end
mIsAlreadyAdd = true
local gameobject = CS.UnityEngine.GameObject('Coroutine_Runner')
CS.UnityEngine.Object.DontDestroyOnLoad(gameobject)
mGameObjectHolder = gameobject:AddComponent(typeof(CS.Coroutine_Runner))
end

--[[
开始一个协程函数,并返回该协程函数句柄
后续可通过该句柄停止该协程
比如:

local a = Continue.Start(xxx)
...
Continue.Stop(a)

--]]
function M.Start(...)
LazyAddGameObjectHolder()
local holder = CS.IEnumeratorHolder(xLuaUtils.cs_generator(...))
mGameObjectHolder:StartCoroutine(holder)
return holder
end

function M.Stop(holder)
mGameObjectHolder:StopCoroutine(holder)
end

function M.Wait(_seconds)
coroutine.yield(CS.UnityEngine.WaitForSeconds(_seconds))
end

xLuaUtils.lua

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
local unpack = unpack or table.unpack

local function async_to_sync(async_func, callback_pos)
return function(...)
local _co = coroutine.running() or error ('this function must be run in coroutine')
local rets
local waiting = false
local function cb_func(...)
if waiting then
assert(coroutine.resume(_co, ...))
else
rets = {...}
end
end
local params = {...}
table.insert(params, callback_pos or (#params + 1), cb_func)
async_func(unpack(params))
if rets == nil then
waiting = true
rets = {coroutine.yield()}
end

return unpack(rets)
end
end

local function coroutine_call(func)
return function(...)
local co = coroutine.create(func)
assert(coroutine.resume(co, ...))
end
end

local move_end = {}

local generator_mt = {
__index = {
MoveNext = function(self)
self.Current = self.co()
if self.Current == move_end then
self.Current = nil
return false
else
return true
end
end;
Reset = function(self)
self.co = coroutine.wrap(self.w_func)
end
}
}

local function cs_generator(func, ...)
local params = {...}
local generator = setmetatable({
w_func = function()
func(unpack(params))
return move_end
end
}, generator_mt)
generator:Reset()
return generator
end

local function loadpackage(...)
for _, loader in ipairs(package.searchers) do
local func = loader(...)
if type(func) == 'function' then
return func
end
end
end

local function auto_id_map()
local hotfix_id_map = require 'hotfix_id_map'
local org_hotfix = xlua.hotfix
xlua.hotfix = function(cs, field, func)
local map_info_of_type = hotfix_id_map[typeof(cs):ToString()]
if map_info_of_type then
if func == nil then func = false end
local tbl = (type(field) == 'table') and field or {[field] = func}
for k, v in pairs(tbl) do
local map_info_of_methods = map_info_of_type[k]
local f = type(v) == 'function' and v or nil
for _, id in ipairs(map_info_of_methods or {}) do
CS.XLua.HotfixDelegateBridge.Set(id, f)
end
--CS.XLua.HotfixDelegateBridge.Set(
end
else
return org_hotfix(cs, field, func)
end
end
end

--和xlua.hotfix的区别是:这个可以调用原来的函数
local function hotfix_ex(cs, field, func)
assert(type(field) == 'string' and type(func) == 'function', 'invalid argument: #2 string needed, #3 function needed!')
local function func_after(...)
xlua.hotfix(cs, field, nil)
local ret = {func(...)}
xlua.hotfix(cs, field, func_after)
return unpack(ret)
end
xlua.hotfix(cs, field, func_after)
end

local function bind(func, obj)
return function(...)
return func(obj, ...)
end
end

--为了兼容luajit,lua53版本直接用|操作符即可
local enum_or_op = debug.getmetatable(CS.System.Reflection.BindingFlags.Public).__bor
local enum_or_op_ex = function(first, ...)
for _, e in ipairs({...}) do
first = enum_or_op(first, e)
end
return first
end

-- description: 直接用C#函数创建delegate
local function createdelegate(delegate_cls, obj, impl_cls, method_name, parameter_type_list)
local flag = enum_or_op_ex(CS.System.Reflection.BindingFlags.Public, CS.System.Reflection.BindingFlags.NonPublic,
CS.System.Reflection.BindingFlags.Instance, CS.System.Reflection.BindingFlags.Static)
local m = parameter_type_list and typeof(impl_cls):GetMethod(method_name, flag, nil, parameter_type_list, nil)
or typeof(impl_cls):GetMethod(method_name, flag)
return CS.System.Delegate.CreateDelegate(typeof(delegate_cls), obj, m)
end

local function state(csobj, state)
local csobj_mt = getmetatable(csobj)
for k, v in pairs(csobj_mt) do rawset(state, k, v) end
local csobj_index, csobj_newindex = state.__index, state.__newindex
state.__index = function(obj, k)
return rawget(state, k) or csobj_index(obj, k)
end
state.__newindex = function(obj, k, v)
if rawget(state, k) ~= nil then
rawset(state, k, v)
else
csobj_newindex(obj, k, v)
end
end
debug.setmetatable(csobj, state)
return state
end

xLuaUtils= {
async_to_sync = async_to_sync,
coroutine_call = coroutine_call,
cs_generator = cs_generator,
loadpackage = loadpackage,
auto_id_map = auto_id_map,
hotfix_ex = hotfix_ex,
bind = bind,
createdelegate = createdelegate,
state = state,
}

需要导入Demo中的Coroutine_Runner.cs 去除LuaLink部分LuaCallCSharp,Link部分统一加入一个文件.
需要用到

1
2
typeof(WaitForSeconds),
typeof(System.Collections.IEnumerator)

详情参见XLuaGenConfig.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
using System.Collections;
using UnityEngine;
using XLua.Cast;

public class Coroutine_Runner : MonoBehaviour
{
}

public class IEnumeratorHolder : Any<IEnumerator>
{
public IEnumeratorHolder(IEnumerator i) : base(i)
{
}
}

使用例子

1
2
3
4
5
6
7
8
9
10
11
12
13
function Fun()
Log("Star log word..")
Continue.Wait(1)
Log("a")
Continue.Wait(1)
Log("b")
Continue.Wait(1)
Log("c")
Continue.Wait(1)
Log("end")
end

Continue.Start(Fun)

This type must add to CSharpCallLua: System.Collections.IEnumerator

报错提示

LuaException: c# exception:System.InvalidCastException: This type must add to CSharpCallLua: System.Collections.IEnumerator

原本只是在给System.Collections.IEnumerator加入了[LuaCallCSharp] 标签,后来发现不行.Github的论坛里面也有人反应这个事儿.所以就直接按照帖子里面说的将ExampleGenConfig提到的类都加进去,就可以了.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
using System.Collections.Generic;
using System;
using UnityEngine;
using XLua;

public static class XLuaGenConfig
{
//lua中要使用到C#库的配置,比如C#标准库,或者Unity API,第三方库等。
[LuaCallCSharp]
public static List<Type> LuaCallCSharp = new List<Type>()
{
typeof(System.Object),
typeof(UnityEngine.Object),
typeof(Vector2),
typeof(Vector3),
typeof(Vector4),
typeof(Quaternion),
typeof(Color),
typeof(Ray),
typeof(Bounds),
typeof(Ray2D),
typeof(Time),
typeof(GameObject),
typeof(Component),
typeof(Behaviour),
typeof(Transform),
typeof(Resources),
typeof(TextAsset),
typeof(Keyframe),
typeof(AnimationCurve),
typeof(AnimationClip),
typeof(MonoBehaviour),
typeof(ParticleSystem),
typeof(SkinnedMeshRenderer),
typeof(Renderer),
typeof(WWW),
typeof(Light),
typeof(Mathf),
typeof(System.Collections.Generic.List<int>),
typeof(Action<string>),
typeof(UnityEngine.Debug),
typeof(WaitForSeconds),
typeof(System.Collections.IEnumerator)
};

//C#静态调用Lua的配置(包括事件的原型),仅可以配delegate,interface
[CSharpCallLua]
public static List<Type> CSharpCallLua = new List<Type>()
{
typeof(Action),
typeof(Func<double, double, double>),
typeof(Action<string>),
typeof(Action<double>),
typeof(UnityEngine.Events.UnityAction),
typeof(System.Collections.IEnumerator)
};

//黑名单
[BlackList]
public static List<List<string>> BlackList = new List<List<string>>()
{
new List<string>() {"System.Xml.XmlNodeList", "ItemOf"},
new List<string>() {"UnityEngine.WWW", "movie"},
#if UNITY_WEBGL
new List<string>(){"UnityEngine.WWW", "threadPriority"},
#endif
new List<string>() {"UnityEngine.Texture2D", "alphaIsTransparency"},
new List<string>() {"UnityEngine.Security", "GetChainOfTrustValue"},
new List<string>() {"UnityEngine.CanvasRenderer", "onRequestRebuild"},
new List<string>() {"UnityEngine.Light", "areaSize"},
new List<string>() {"UnityEngine.Light", "lightmapBakeType"},
new List<string>() {"UnityEngine.WWW", "MovieTexture"},
new List<string>() {"UnityEngine.WWW", "GetMovieTexture"},
new List<string>() {"UnityEngine.AnimatorOverrideController", "PerformOverrideClipListCleanup"},
#if !UNITY_WEBPLAYER
new List<string>() {"UnityEngine.Application", "ExternalEval"},
#endif
new List<string>() {"UnityEngine.GameObject", "networkView"}, //4.6.2 not support
new List<string>() {"UnityEngine.Component", "networkView"}, //4.6.2 not support
new List<string>() {"System.IO.FileInfo", "GetAccessControl", "System.Security.AccessControl.AccessControlSections"},
new List<string>() {"System.IO.FileInfo", "SetAccessControl", "System.Security.AccessControl.FileSecurity"},
new List<string>() {"System.IO.DirectoryInfo", "GetAccessControl", "System.Security.AccessControl.AccessControlSections"},
new List<string>() {"System.IO.DirectoryInfo", "SetAccessControl", "System.Security.AccessControl.DirectorySecurity"},
new List<string>() {"System.IO.DirectoryInfo", "CreateSubdirectory", "System.String", "System.Security.AccessControl.DirectorySecurity"},
new List<string>() {"System.IO.DirectoryInfo", "Create", "System.Security.AccessControl.DirectorySecurity"},
new List<string>() {"UnityEngine.MonoBehaviour", "runInEditMode"},
};
}

xLua Unity 调用 Lua 任意函数 多参 不绑定

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
using XLua;

namespace Code.Lua.Utils
{
/// <summary>
/// 对Xlua进行扩展
/// </summary>
public static class XLuaExtentions
{
/// <summary>
/// 调用LuaTable中 以点(.) 定义的某一个方法.(首参数不传入LuaTable自身)
/// 注意:调用不缓存Delegate,适用于一次性调用.
/// </summary>
public static object[] Call(this LuaTable _luaTable, string _funName, params object[] _args)
{
return _luaTable.GetInPath<LuaFunction>(_funName).Call(_args);
}

/// <summary>
/// 调用LuaTable中 以冒号(:) 定义的某一个方法.(首参数传入LuaTable自身)
/// 注意:调用不缓存Delegate,适用于一次性调用.
/// </summary>
public static object[] CallSelf(this LuaTable _luaTable, string _funName, params object[] _args)
{
if (_args != null && _args.Length > 0)
{
var newArgs = new object[_args.Length + 1];
newArgs[0] = _luaTable;
for (var i = 0; i < _args.Length; i++)
{
newArgs[i + 1] = _args[i];
}

return _luaTable.GetInPath<LuaFunction>(_funName).Call(newArgs);
}
else
{
return _luaTable.GetInPath<LuaFunction>(_funName).Call(_luaTable);
}
}

/// <summary>
/// 返回Lua函数,适用于需要多次调用的情况
/// </summary>
public static LuaFunction GetFun(this LuaTable _luaTable, string _funName)
{
return _luaTable.GetInPath<LuaFunction>(_funName);
}
}
}

直接扩展LuaTable,加入两个调用方法.使用内置的LuaFunction直接调用. 可传入任意参数和返回任意多个参数.

坚持原创技术分享,您的支持将鼓励我继续创作!