如何使用 MoonSharp 加载 lua table?
How can I use MoonSharp to load a lua table?
在浏览了各种 Lua C# 解释器之后,似乎只有一个是真正纯 C# - MoonSharp。 LuaInterpreter(自 2009 年起失效)后来成为 NLua 取决于另外两个 c# 库管理器 KeraLua 之一或另一个库,并且需要自定义的 lua52.dll(您可以不要使用 lua.org 中的那个)。他们有一个已关闭的错误报告,上面写着查看自述文件以获取他们定制的 lua52.dll 的下载位置,但它不存在。您被迫从各种来源下载这些库,并祈祷它们一起工作,此外还有一个多文件分发,由于最终用户计算机上的几个 lua52.dll 变体,这可能 have/cause 与其他程序的兼容性问题(假设他们会使用的不仅仅是你的程序)。
NLua 上的一盏灯塔显然很受欢迎,但是该项目几年来没有收到任何重大更新。另一方面,MoonSharp 似乎是完全独立的,但缺少常见任务的文档,例如加载使用 lua 构建的 table 并使用它。
我根据他们在 Git 上提供的单个示例提出了以下代码,然后在他们的网站 moonsharp.org 上复制了代码(我不确定,以先到者为准,但是1 个示例是不够的):
using System;
using System.IO;
using MoonSharp.Interpreter;
class Foo {
function Bar( string accountName, string warcraftPath ) {
string datastore = Path.Combine(warcraftPath, "WTF", "Account", accountName, "SavedVariables", "DataStore_Containers.lua";
DynValue table = Script.RunString( File.ReadAllText( datastore ) );
Console.WriteLine( table.Table.Keys.Count().ToString() );
}
}
结果如下(图片中的代码略有不同,因为我在这里调整了粘贴的代码以保持整洁,并使您更容易使用 pastebin 中的 table 数据重现问题 link 下面。)
我正在尝试阅读的 table 如下所示(由于大小超过 30,000 个字符,简化后不得不粘贴到 pastebin 上):
World of Warcraft - Datastore_Containers Lua table sample data
我有点工作,有点老套,但似乎并没有离开循环遍历值或显式获取子tables /值或值的键.
Script s = new Script(CoreModules.Preset_Complete);
// hacked by appending ' return DataStore_ContainersDB ' to return the table as DoString seems to only work to run a function expecting a result to be returned.
DynValue dv = s.DoString(luaTable + "\nreturn DataStore_ContainersDB;");
Table t = dv.Table;
foreach(var v in t.Keys)
{
Console.WriteLine( v.ToPrintString() );
}
问题是我似乎没有任何方法可以输入子 table 结果集或显式访问像 t["global"]
或 t.global
这样的结果集。
设法破解并削减我的方式并提出一个可行的解决方案,尽管它相当初级(可能有人可以采用这个概念并使子数据的访问更合理:
Script s = new Script(CoreModules.Preset_Complete);
DynValue dv = s.DoString(luaTable + "\nreturn DataStore_ContainersDB;");
Table t = dv.Table;
Table global;
global = t.Get("global").ToObject<Table>().Get("Characters").ToObject<Table>();
foreach (var key in global.Keys)
{
Console.WriteLine( key.ToString() );
}
MoonSharp 库似乎需要并严重依赖 Script
class,这是所有其他方法运行的前提。 DoString
方法需要 return 结果,否则 DynValue
将始终是 void/null 。 DynValue
似乎是整个 Lua 进程的基本全局处理程序,它可以处理方法(也就是 lua 字符串可以包含 DynValue 将公开并允许在其中调用的几个方法C# return 将响应作为其他 DynValue 的)
因此,如果您希望加载 lua 文件,该文件仅包含 Lua 的 table 格式的日期,您必须附加 return 和 table 名字作为最后一行。这就是您看到的原因:
"\nreturn DataStore_ContainersDB;"
... 因为 table 名称被称为 "DataStore_ContainersDB"
接下来,必须将结果加载到一个新的 Table
对象中,因为 DynValue 不是一个实际的 table 而是一个 class 结构来保存所有可用的格式(方法, tables, 等).
在它成为 Table 格式后,您现在可以通过键名、数字或 DynValue 调用 key/value 对来使用它。在我的例子中,因为我知道原始键名,所以我直接调用 Table 那里存在我不知道但想使用的键名。
Table.Get( Key )
因为这个 return 是一个 DynValue,所以我们必须 convert/load 对象作为 table 再次使用 .ToObject<>
方法很方便。
我提供的 foreach
循环然后循环遍历位于以下位置的子 table 中可用的键:global > Characters > *
... 然后我使用 key.ToString()
将密钥名称写到控制台
如果还有其他子tables,在这个例子中(因为有),你可以在foreach
循环中使用相同的概念通过扩展它来遍历未知的这 :
foreach (var key in global.Keys)
{
if(IsTable(global.Get(key.String)))
{
Console.WriteLine("-------" + key.ToPrintString() + "-------");
Table characterData = global.Get(key.String).ToObject<Table>();
foreach (var characterDataField in characterData.Keys)
{
if( !IsTable(characterData.Get(characterDataField.String)))
{
Console.WriteLine(string.Format("{0} = {1}", characterDataField.ToPrintString(), characterData.Get(characterDataField.String).ToPrintString()));
}
else
{
Console.WriteLine(string.Format("{0} = {1}", characterDataField.ToPrintString(), "Table[]"));
}
}
Console.WriteLine("");
}
}
... 这是我编写的用于快速检查数据是否为 table 的方法。这是上面foreach
例子中使用的IsTable()
方法。
private static bool IsTable(DynValue table)
{
switch (table.Type)
{
case DataType.Table:
return true;
case DataType.Boolean:
case DataType.ClrFunction:
case DataType.Function:
case DataType.Nil:
case DataType.Number:
case DataType.String:
case DataType.TailCallRequest:
case DataType.Thread:
case DataType.Tuple:
case DataType.UserData:
case DataType.Void:
case DataType.YieldRequest:
break;
}
return false;
}
我已尽我所能使它可行,但是,如前所述,我确实看到了改进此递归的空间。检查每个子对象的数据类型,然后加载它感觉非常多余,似乎可以简化。
我对这个问题的其他解决方案持开放态度,理想情况下是以某种增强的形式使它使用起来不那么笨拙。
用于处理表中表,这是我首选的处理方式。我想到了这个。
Script s = new Script();
s.DoString(luaCode);
Table tableData = s.Globals[rootTableIndex] as Table;
for (int i = 1; i < tableData.Length + 1; i++) {
Table subTable = tableData.Get(i).Table;
//Do cool stuff here with the data
}
当然这需要您知道全局 rootTable 的索引。
为了我的使用,我做了以下事情(仍在测试)
string luaCode = File.ReadAllText(Path.Combine(weaponDataPath, "rifles.Lua"));
Script script = new Script();
script.DoString(luaCode);
Gun rifle = new Gun();
Table rifleData = script.Globals["rifles"] as Table;
for (int i = 1; i < rifleData.Length + 1; i++) {
Table rifleTable = rifleData.Get(i).Table;
rifle.Name = rifleTable.Get("Name").String;
rifle.BaseDamage = (int)rifleTable.Get("BaseDamage").Number;
rifle.RoundsPerMinute = (int)rifleTable.Get("RoundsPerMinute").Number;
rifle.MaxAmmoCapacity = (int)rifleTable.Get("MaxAmmoCapacity").Number;
rifle.Caliber = rifleTable.Get("Caliber").String;
rifle.WeaponType = "RIFLE";
RiflePrototypes.Add(rifle.Name, rifle);
}
这需要对表和值的命名方式做出一些假设,但如果您将其用于对象成员分配,我不明白您为什么会关心 table 中不存在的元素您使用赋值定义的对象的一部分 type.Member = table.Get(member equivalent index).member type
在浏览了各种 Lua C# 解释器之后,似乎只有一个是真正纯 C# - MoonSharp。 LuaInterpreter(自 2009 年起失效)后来成为 NLua 取决于另外两个 c# 库管理器 KeraLua 之一或另一个库,并且需要自定义的 lua52.dll(您可以不要使用 lua.org 中的那个)。他们有一个已关闭的错误报告,上面写着查看自述文件以获取他们定制的 lua52.dll 的下载位置,但它不存在。您被迫从各种来源下载这些库,并祈祷它们一起工作,此外还有一个多文件分发,由于最终用户计算机上的几个 lua52.dll 变体,这可能 have/cause 与其他程序的兼容性问题(假设他们会使用的不仅仅是你的程序)。
NLua 上的一盏灯塔显然很受欢迎,但是该项目几年来没有收到任何重大更新。另一方面,MoonSharp 似乎是完全独立的,但缺少常见任务的文档,例如加载使用 lua 构建的 table 并使用它。
我根据他们在 Git 上提供的单个示例提出了以下代码,然后在他们的网站 moonsharp.org 上复制了代码(我不确定,以先到者为准,但是1 个示例是不够的):
using System;
using System.IO;
using MoonSharp.Interpreter;
class Foo {
function Bar( string accountName, string warcraftPath ) {
string datastore = Path.Combine(warcraftPath, "WTF", "Account", accountName, "SavedVariables", "DataStore_Containers.lua";
DynValue table = Script.RunString( File.ReadAllText( datastore ) );
Console.WriteLine( table.Table.Keys.Count().ToString() );
}
}
结果如下(图片中的代码略有不同,因为我在这里调整了粘贴的代码以保持整洁,并使您更容易使用 pastebin 中的 table 数据重现问题 link 下面。)
我正在尝试阅读的 table 如下所示(由于大小超过 30,000 个字符,简化后不得不粘贴到 pastebin 上):
World of Warcraft - Datastore_Containers Lua table sample data
我有点工作,有点老套,但似乎并没有离开循环遍历值或显式获取子tables /值或值的键.
Script s = new Script(CoreModules.Preset_Complete);
// hacked by appending ' return DataStore_ContainersDB ' to return the table as DoString seems to only work to run a function expecting a result to be returned.
DynValue dv = s.DoString(luaTable + "\nreturn DataStore_ContainersDB;");
Table t = dv.Table;
foreach(var v in t.Keys)
{
Console.WriteLine( v.ToPrintString() );
}
问题是我似乎没有任何方法可以输入子 table 结果集或显式访问像 t["global"]
或 t.global
这样的结果集。
设法破解并削减我的方式并提出一个可行的解决方案,尽管它相当初级(可能有人可以采用这个概念并使子数据的访问更合理:
Script s = new Script(CoreModules.Preset_Complete);
DynValue dv = s.DoString(luaTable + "\nreturn DataStore_ContainersDB;");
Table t = dv.Table;
Table global;
global = t.Get("global").ToObject<Table>().Get("Characters").ToObject<Table>();
foreach (var key in global.Keys)
{
Console.WriteLine( key.ToString() );
}
MoonSharp 库似乎需要并严重依赖 Script
class,这是所有其他方法运行的前提。 DoString
方法需要 return 结果,否则 DynValue
将始终是 void/null 。 DynValue
似乎是整个 Lua 进程的基本全局处理程序,它可以处理方法(也就是 lua 字符串可以包含 DynValue 将公开并允许在其中调用的几个方法C# return 将响应作为其他 DynValue 的)
因此,如果您希望加载 lua 文件,该文件仅包含 Lua 的 table 格式的日期,您必须附加 return 和 table 名字作为最后一行。这就是您看到的原因:
"\nreturn DataStore_ContainersDB;"
... 因为 table 名称被称为 "DataStore_ContainersDB"
接下来,必须将结果加载到一个新的 Table
对象中,因为 DynValue 不是一个实际的 table 而是一个 class 结构来保存所有可用的格式(方法, tables, 等).
在它成为 Table 格式后,您现在可以通过键名、数字或 DynValue 调用 key/value 对来使用它。在我的例子中,因为我知道原始键名,所以我直接调用 Table 那里存在我不知道但想使用的键名。
Table.Get( Key )
因为这个 return 是一个 DynValue,所以我们必须 convert/load 对象作为 table 再次使用 .ToObject<>
方法很方便。
我提供的 foreach
循环然后循环遍历位于以下位置的子 table 中可用的键:global > Characters > *
... 然后我使用 key.ToString()
如果还有其他子tables,在这个例子中(因为有),你可以在foreach
循环中使用相同的概念通过扩展它来遍历未知的这 :
foreach (var key in global.Keys)
{
if(IsTable(global.Get(key.String)))
{
Console.WriteLine("-------" + key.ToPrintString() + "-------");
Table characterData = global.Get(key.String).ToObject<Table>();
foreach (var characterDataField in characterData.Keys)
{
if( !IsTable(characterData.Get(characterDataField.String)))
{
Console.WriteLine(string.Format("{0} = {1}", characterDataField.ToPrintString(), characterData.Get(characterDataField.String).ToPrintString()));
}
else
{
Console.WriteLine(string.Format("{0} = {1}", characterDataField.ToPrintString(), "Table[]"));
}
}
Console.WriteLine("");
}
}
... 这是我编写的用于快速检查数据是否为 table 的方法。这是上面foreach
例子中使用的IsTable()
方法。
private static bool IsTable(DynValue table)
{
switch (table.Type)
{
case DataType.Table:
return true;
case DataType.Boolean:
case DataType.ClrFunction:
case DataType.Function:
case DataType.Nil:
case DataType.Number:
case DataType.String:
case DataType.TailCallRequest:
case DataType.Thread:
case DataType.Tuple:
case DataType.UserData:
case DataType.Void:
case DataType.YieldRequest:
break;
}
return false;
}
我已尽我所能使它可行,但是,如前所述,我确实看到了改进此递归的空间。检查每个子对象的数据类型,然后加载它感觉非常多余,似乎可以简化。
我对这个问题的其他解决方案持开放态度,理想情况下是以某种增强的形式使它使用起来不那么笨拙。
用于处理表中表,这是我首选的处理方式。我想到了这个。
Script s = new Script();
s.DoString(luaCode);
Table tableData = s.Globals[rootTableIndex] as Table;
for (int i = 1; i < tableData.Length + 1; i++) {
Table subTable = tableData.Get(i).Table;
//Do cool stuff here with the data
}
当然这需要您知道全局 rootTable 的索引。
为了我的使用,我做了以下事情(仍在测试)
string luaCode = File.ReadAllText(Path.Combine(weaponDataPath, "rifles.Lua"));
Script script = new Script();
script.DoString(luaCode);
Gun rifle = new Gun();
Table rifleData = script.Globals["rifles"] as Table;
for (int i = 1; i < rifleData.Length + 1; i++) {
Table rifleTable = rifleData.Get(i).Table;
rifle.Name = rifleTable.Get("Name").String;
rifle.BaseDamage = (int)rifleTable.Get("BaseDamage").Number;
rifle.RoundsPerMinute = (int)rifleTable.Get("RoundsPerMinute").Number;
rifle.MaxAmmoCapacity = (int)rifleTable.Get("MaxAmmoCapacity").Number;
rifle.Caliber = rifleTable.Get("Caliber").String;
rifle.WeaponType = "RIFLE";
RiflePrototypes.Add(rifle.Name, rifle);
}
这需要对表和值的命名方式做出一些假设,但如果您将其用于对象成员分配,我不明白您为什么会关心 table 中不存在的元素您使用赋值定义的对象的一部分 type.Member = table.Get(member equivalent index).member type