提交 515e31d8 编写于 作者: J johnche(车雄生)

支持C#复杂值类型改为lua实现

上级 fcc205e6
fileFormatVersion: 2
guid: 58695f06576335e46bf1769637db2255
folderAsset: yes
timeCreated: 1501577332
licenseType: Pro
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:
using UnityEngine;
using System.Collections;
using XLua;
[GCOptimize(OptimizeFlag.PackAsTable)]
public struct PushAsTableStruct
{
public int x;
public int y;
}
public class ReImplementInLua : MonoBehaviour {
// Use this for initialization
void Start () {
LuaEnv luaenv = new LuaEnv();
//例子1:改造Vector3
//沿用Vector3原来的映射方案Vector3 -> userdata,但是把Vector3的方法实现改为lua实现,通过xlua.genaccessor实现不经过C#直接操作内存
//改为不经过C#的好处是性能更高,而且你可以省掉相应的生成代码以达成省text段的效果
//映射仍然沿用的好处是userdata比table更省内存,但操作字段比table性能稍低,当然,你也可以结合例子2的思路,把Vector3也改为映射到table
luaenv.DoString(@"
function test_vector3(title, v1, v2)
print(title)
print(v1.x, v1.y, v1.z)
print(v1, v2)
print(v1 + v2)
v1:Set(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z)
print(v1)
print(CS.UnityEngine.Vector3.Normalize(v1))
end
test_vector3('----before change metatable----', CS.UnityEngine.Vector3(1, 2, 3), CS.UnityEngine.Vector3(7, 8, 9))
local get_x, set_x = xlua.genaccessor(0, 8)
local get_y, set_y = xlua.genaccessor(4, 8)
local get_z, set_z = xlua.genaccessor(8, 8)
local fields_getters = {
x = get_x, y = get_y, z = get_z
}
local fields_setters = {
x = set_x, y = set_y, z = set_z
}
local ins_methods = {
Set = function(o, x, y, z)
set_x(o, x)
set_y(o, y)
set_z(o, z)
end
}
local mt = {
__index = function(o, k)
--print('__index', k)
if ins_methods[k] then return ins_methods[k] end
return fields_getters[k] and fields_getters[k](o)
end,
__newindex = function(o, k, v)
return fields_setters[k] and fields_setters[k](o, v) or error('no such field ' .. k)
end,
__tostring = function(o)
return string.format('vector3 { %f, %f, %f}', o.x, o.y, o.z)
end,
__add = function(a, b)
return CS.UnityEngine.Vector3(a.x + b.x, a.y + b.y, a.z + b.z)
end
}
xlua.setmetatable(CS.UnityEngine.Vector3, mt)
test_vector3('----after change metatable----', CS.UnityEngine.Vector3(1, 2, 3), CS.UnityEngine.Vector3(7, 8, 9))
");
Debug.Log("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
//例子2:struct映射到table改造
//PushAsTableStruct传送到lua侧将会是table,例子里头还为这个table添加了一个成员方法SwapXY,静态方法Print,打印格式化,以及构造函数
luaenv.DoString(@"
local mt = {
__index = {
SwapXY = function(o) --成员函数
o.x, o.y = o.y, o.x
end
},
__tostring = function(o) --打印格式化函数
return string.format('struct { %d, %d}', o.x, o.y)
end,
}
xlua.setmetatable(CS.PushAsTableStruct, mt)
local PushAsTableStruct = {
Print = function(o) --静态函数
print(o.x, o.y)
end
}
setmetatable(PushAsTableStruct, {
__call = function(_, x, y) --构造函数
return setmetatable({x = x, y = y}, mt)
end
})
xlua.setclass(CS, 'PushAsTableStruct', PushAsTableStruct)
");
PushAsTableStruct test;
test.x = 100;
test.y = 200;
luaenv.Global.Set("from_cs", test);
luaenv.DoString(@"
print('--------------from csharp---------------------')
assert(type(from_cs) == 'table')
print(from_cs)
CS.PushAsTableStruct.Print(from_cs)
from_cs:SwapXY()
print(from_cs)
print('--------------from lua---------------------')
local from_lua = CS.PushAsTableStruct(4, 5)
assert(type(from_lua) == 'table')
print(from_lua)
CS.PushAsTableStruct.Print(from_lua)
from_lua:SwapXY()
print(from_lua)
");
luaenv.Dispose();
}
// Update is called once per frame
void Update () {
}
}
fileFormatVersion: 2
guid: cffb50bfe4f87494c8a4851450dfb340
timeCreated: 1501577402
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
......@@ -845,11 +845,17 @@ namespace CSObjectWrapEditor
{
string filePath = save_path + "WrapPusher.cs";
StreamWriter textWriter = new StreamWriter(filePath, false, Encoding.UTF8);
var emptyMap = new Dictionary<Type, Type>();
GenOne(typeof(ObjectTranslator), (type, type_info) =>
{
type_info.Set("purevaluetypes", types
.Where(t => t.IsEnum || (!t.IsPrimitive && SizeOf(t) != -1))
.Select(t => new { Type = t, Size = SizeOf(t) }).ToList());
.Select(t => new {
Type = t,
Size = SizeOf(t),
Flag = t.IsEnum ? OptimizeFlag.Default : OptimizeCfg[t],
FieldInfos = (t.IsEnum || OptimizeCfg[t] == OptimizeFlag.Default) ? null : getXluaTypeInfo(t, emptyMap).FieldInfos
}).ToList());
type_info.Set("tableoptimzetypes", types.Where(t => !t.IsEnum && SizeOf(t) == -1)
.Select(t => new { Type = t, Fields = t.GetFields(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly) })
.ToList());
......@@ -1037,6 +1043,58 @@ namespace CSObjectWrapEditor
public int Size;
}
class XluaTypeInfo
{
public Type Type;
public List<XluaFieldInfo> FieldInfos;
public List<List<XluaFieldInfo>> FieldGroup;
public bool IsRoot;
}
static XluaTypeInfo getXluaTypeInfo(Type t, Dictionary<Type, Type> set)
{
var fs = t.GetFields(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly)
.Select(fi => new XluaFieldInfo { Name = fi.Name, Type = fi.FieldType, IsField = true, Size = SizeOf(fi.FieldType) })
.Concat(t.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly)
.Where(prop => {
return (AdditionalProperties.ContainsKey(t) && AdditionalProperties[t].Contains(prop.Name))
|| prop.IsDefined(typeof(AdditionalPropertiesAttribute), false);
})
.Select(prop => new XluaFieldInfo { Name = prop.Name, Type = prop.PropertyType, IsField = false, Size = SizeOf(prop.PropertyType) }));
int float_field_count = 0;
bool only_float = true;
foreach (var f in fs)
{
if (f.Type == typeof(float))
{
float_field_count++;
}
else
{
only_float = false;
break;
}
}
List<List<XluaFieldInfo>> grouped_field = null;
if (only_float && float_field_count > 1)
{
grouped_field = new List<List<XluaFieldInfo>>();
List<XluaFieldInfo> group = null;
foreach (var f in fs)
{
if (group == null) group = new List<XluaFieldInfo>();
group.Add(f);
if (group.Count >= 6)
{
grouped_field.Add(group);
group = null;
}
}
if (group != null) grouped_field.Add(group);
}
return new XluaTypeInfo { Type = t, FieldInfos = fs.ToList(), FieldGroup = grouped_field, IsRoot = set.ContainsKey(t) };
}
public static void GenPackUnpack(IEnumerable<Type> types, string save_path)
{
var set = types.ToDictionary(type => type);
......@@ -1054,49 +1112,7 @@ namespace CSObjectWrapEditor
StreamWriter textWriter = new StreamWriter(filePath, false, Encoding.UTF8);
GenOne(typeof(CopyByValue), (type, type_info) =>
{
type_info.Set("type_infos", all_types.Distinct().Select(t =>
{
var fs = t.GetFields(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly)
.Select(fi => new XluaFieldInfo { Name = fi.Name, Type = fi.FieldType, IsField = true, Size = SizeOf(fi.FieldType) })
.Concat(t.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly)
.Where(prop => {
return (AdditionalProperties.ContainsKey(t) && AdditionalProperties[t].Contains(prop.Name))
|| prop.IsDefined(typeof(AdditionalPropertiesAttribute), false);
})
.Select(prop=> new XluaFieldInfo { Name = prop.Name, Type = prop.PropertyType, IsField = false, Size = SizeOf(prop.PropertyType) }));
int float_field_count = 0;
bool only_float = true;
foreach (var f in fs)
{
if (f.Type == typeof(float))
{
float_field_count++;
}
else
{
only_float = false;
break;
}
}
List<List<XluaFieldInfo>> grouped_field = null;
if (only_float && float_field_count > 1)
{
grouped_field = new List<List<XluaFieldInfo>>();
List<XluaFieldInfo> group = null;
foreach (var f in fs)
{
if (group == null) group = new List<XluaFieldInfo>();
group.Add(f);
if (group.Count >= 6)
{
grouped_field.Add(group);
group = null;
}
}
if (group != null) grouped_field.Add(group);
}
return new { Type = t, FieldInfos = fs.ToList(), FieldGroup = grouped_field, IsRoot = set.ContainsKey(t) };
}).ToList());
type_info.Set("type_infos", all_types.Distinct().Select(t => getXluaTypeInfo(t, set)).ToList());
}, templateRef.PackUnpack, textWriter);
textWriter.Close();
}
......@@ -1118,7 +1134,9 @@ namespace CSObjectWrapEditor
public static Dictionary<Type, HotfixFlag> HotfixCfg = null;
static void AddToList(List<Type> list, Func<object> get, Type attr)
public static Dictionary<Type, OptimizeFlag> OptimizeCfg = null;
static void AddToList(List<Type> list, Func<object> get, object attr)
{
object obj = get();
if (obj is Type)
......@@ -1131,7 +1149,22 @@ namespace CSObjectWrapEditor
}
else
{
throw new InvalidOperationException("Only field/property with the type IEnumerable<Type> can be marked " + attr.Name);
throw new InvalidOperationException("Only field/property with the type IEnumerable<Type> can be marked " + attr.GetType().Name);
}
if (attr is GCOptimizeAttribute)
{
var flag = (attr as GCOptimizeAttribute).Flag;
if (obj is Type)
{
OptimizeCfg.Add(obj as Type, flag);
}
else if (obj is IEnumerable<Type>)
{
foreach(var type in (obj as IEnumerable<Type>))
{
OptimizeCfg.Add(type, flag);
}
}
}
}
......@@ -1139,24 +1172,24 @@ namespace CSObjectWrapEditor
{
if (test.IsDefined(typeof(LuaCallCSharpAttribute), false))
{
AddToList(LuaCallCSharp, get_cfg, typeof(LuaCallCSharpAttribute));
object[] ccla = test.GetCustomAttributes(typeof(LuaCallCSharpAttribute), false);
AddToList(LuaCallCSharp, get_cfg, ccla[0]);
if (ccla.Length == 1 && (((ccla[0] as LuaCallCSharpAttribute).Flag & GenFlag.GCOptimize) != 0))
{
AddToList(GCOptimizeList, get_cfg, typeof(LuaCallCSharpAttribute));
AddToList(GCOptimizeList, get_cfg, ccla[0]);
}
}
if (test.IsDefined(typeof(CSharpCallLuaAttribute), false))
{
AddToList(CSharpCallLua, get_cfg, typeof(CSharpCallLuaAttribute));
AddToList(CSharpCallLua, get_cfg, test.GetCustomAttributes(typeof(CSharpCallLuaAttribute), false)[0]);
}
if (test.IsDefined(typeof(GCOptimizeAttribute), false))
{
AddToList(GCOptimizeList, get_cfg, typeof(GCOptimizeAttribute));
AddToList(GCOptimizeList, get_cfg, test.GetCustomAttributes(typeof(GCOptimizeAttribute), false)[0]);
}
if (test.IsDefined(typeof(ReflectionUseAttribute), false))
{
AddToList(ReflectionUse, get_cfg, typeof(ReflectionUseAttribute));
AddToList(ReflectionUse, get_cfg, test.GetCustomAttributes(typeof(ReflectionUseAttribute), false)[0]);
}
if (test.IsDefined(typeof(HotfixAttribute), false))
{
......@@ -1215,6 +1248,8 @@ namespace CSObjectWrapEditor
HotfixCfg = new Dictionary<Type, HotfixFlag>();
OptimizeCfg = new Dictionary<Type, OptimizeFlag>();
foreach (var t in check_types)
{
MergeCfg(t, null, () => t);
......
......@@ -72,13 +72,27 @@ namespace XLua
{
return;
}
<%end%>
<%
end
if type_info.Flag == CS.XLua.OptimizeFlag.PackAsTable then
%>
var translator = this;
LuaAPI.xlua_pushcstable(L, <%=type_info.FieldInfos.Count%>, <%=type_id_var_name%>);
<%ForEachCsList(type_info.FieldInfos, function(fieldInfo)%>
LuaAPI.xlua_pushasciistring(L, "<%=fieldInfo.Name%>");
<%=GetPushStatement(fieldInfo.Type, "val."..fieldInfo.Name)%>;
LuaAPI.lua_rawset(L, -3);
<%end)%>
<%else%>
IntPtr buff = LuaAPI.xlua_pushstruct(L, <%=is_enum and 4 or type_info.Size%>, <%=type_id_var_name%>);
if (!CopyByValue.Pack(buff, 0, <%=is_enum and "(int)" or ""%>val))
{
throw new Exception("pack fail fail for <%=full_type_name%> ,value="+val);
}
<%if is_enum then%>
<%
end
if is_enum then
%>
LuaAPI.lua_getref(L, <%=enum_ref_var_name%>);
LuaAPI.lua_pushvalue(L, -2);
LuaAPI.xlua_rawseti(L, -2, (int)val);
......@@ -117,6 +131,12 @@ namespace XLua
public void Update<%=CSVariableName(type_info.Type)%>(RealStatePtr L, int index, <%=full_type_name%> val)
{
<%if type_info.Flag == CS.XLua.OptimizeFlag.PackAsTable then%>
if (LuaAPI.lua_type(L, index) == LuaTypes.LUA_TTABLE)
{
return;
}
<%else%>
if (LuaAPI.lua_type(L, index) == LuaTypes.LUA_TUSERDATA)
{
if (LuaAPI.xlua_gettypeid(L, index) != <%=type_id_var_name%>)
......@@ -130,6 +150,7 @@ namespace XLua
throw new Exception("pack fail for <%=full_type_name%> ,value="+val);
}
}
<%end%>
else
{
throw new Exception("try to update a data with lua type:" + LuaAPI.lua_type(L, index));
......
......@@ -47,10 +47,29 @@ namespace XLua
}
[Flags]
public enum OptimizeFlag
{
Default = 0,
PackAsTable = 1
}
//如果想对struct生成免GC代码,加这个标签
public class GCOptimizeAttribute : Attribute
{
OptimizeFlag flag;
public OptimizeFlag Flag
{
get
{
return flag;
}
}
public GCOptimizeAttribute(OptimizeFlag flag = OptimizeFlag.Default)
{
this.flag = flag;
}
}
//如果想在反射下使用,加这个标签
......
......@@ -497,6 +497,9 @@ namespace XLua.LuaDLL
[DllImport(LUADLL, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr xlua_pushstruct(IntPtr L, uint size, int meta_ref);
[DllImport(LUADLL, CallingConvention = CallingConvention.Cdecl)]
public static extern void xlua_pushcstable(IntPtr L, uint field_count, int meta_ref);
[DllImport(LUADLL, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr lua_touserdata(IntPtr L, int idx);
......
......@@ -541,6 +541,10 @@ namespace XLua
xlua.setmetatable = function(cs, mt)
return xlua.metatable_operation(cs, mt)
end
xlua.setclass = function(parent, name, impl)
impl.UnderlyingSystemType = parent[name].UnderlyingSystemType
rawset(parent, name, impl)
end
";
public delegate byte[] CustomLoader(ref string filepath);
......
......@@ -95,6 +95,7 @@ Debug.Log("max:" + max(32, 12));
* [09_GenericMethod](Assets/XLua/Examples/09_GenericMethod/): 泛化函数支持的演示。
* [10_SignatureLoader](Assets/XLua/Examples/10_SignatureLoader/): 展示如何读取经数字签名的lua脚本,参见[数字签名](Assets/XLua/Doc/signature.md)的文档介绍。
* [11_RawObject](Assets/XLua/Examples/11_RawObject/): 当C#参数是object时,如何把一个lua number指定以boxing后的int传递过去。
* [12_ReImplementInLua](Assets/XLua/Examples/12_ReImplementInLua/): 展示如何将复杂值类型改为lua实现。
## 文档
......
......@@ -824,6 +824,12 @@ LUA_API void *xlua_pushstruct(lua_State *L, unsigned int size, int meta_ref) {
return css;
}
LUA_API void xlua_pushcstable(lua_State *L, unsigned int size, int meta_ref) {
lua_createtable(L, 0, size);
lua_rawgeti(L, LUA_REGISTRYINDEX, meta_ref);
lua_setmetatable(L, -2);
}
LUA_API int xlua_gettypeid(lua_State *L, int idx) {
int type_id = -1;
if (lua_type(L, idx) == LUA_TUSERDATA) {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册