Search code examples
c#jsonlualua-table

How can I parse a LuaTable in C#?


I am at a complete loss with the syntax to parse a LuaTable. I have a table that follows the following structure:

mission = 
{
    ["coalition"] = 
    {
        ["blue"] = 
        {
            ["bullseye"] = 
            {
                ["y"] = -378451.53125,
                ["x"] = -178644.117188,
            }, -- end of ["bullseye"]
            ["country"] = 
            {
                [1] = 
                {
                    ["plane"] = 
                    {
                        ["group"] = 
                        {
                            [1] = 
                            {
                                ["hiddenOnPlanner"] = false,
                                ["tasks"] = {},
                                ["radioSet"] = false,
                                ["task"] = "AFAC",
                                ["uncontrolled"] = false,
                                ["hiddenOnMFD"] = false,
                                ["taskSelected"] = true,
                                ["route"] = 
                                {..............

and I am doing the following in my Winforms C# application (just a button triggering this code to test):

private void button29_Click_1(object sender, EventArgs e)
{
    Lua lua = new Lua();
    string s = File.ReadAllText("C:\\Users\\username\\Desktop\\mission");
    lua.DoString(s);
    var res = lua["mission.coalition.blue.country"];
    var bluePlanes = lua["mission.coalition.blue.country.1"];

    LuaTable tb = (LuaTable)res;
    Dictionary<object, object> dict = lua.GetTableDict(tb);
    Console.WriteLine("First chunk of code:");
    foreach (KeyValuePair<object, object> de in dict)
    {
        Console.WriteLine("{0} {1}", de.Key.ToString(), de.Value.ToString());
    }

    tb = (LuaTable)bluePlanes ;
    dict = lua.GetTableDict(tb);
    Console.WriteLine("Second chunk of code:");
    foreach (KeyValuePair<object, object> de in dict)
    {
        Console.WriteLine("{0} {1}", de.Key.ToString(), de.Value.ToString());
    }
}

The first chunk works but as soon as I stumble upon one of the elements in square brackets without quotes (e.g. [1]) null is returned. I have checked that manually adding the quotes solves this, but In the Watch view, I can see there are keys and values, just that I cannot index those. Any suggestion?

This is the console output:

First chunk of code:
1 table
Exception thrown: 'System.ArgumentNullException' in NLua.dll
Value cannot be null.

However, the information is shown in the Watch window: [![Watch window screenshot][1]][1]

Additionally, I thought of converting the table to JSON and using a C# class, but I cannot manage to do that from C# (tried using NLua to run a script in Lua that converts the table to JSON, but unsuccessfully, as I did not manage to reference the required Lua libraries)

Edit: adding a minimal structure to show the issue as requested in comments

    ["coalition"] = 
    {
        ["blue"] = 
        {
            ["country"] = 
            {
                [1] = 
                {
                }
            }
        }
    }


With this minimal structure, I am able to address up to coalition.blue.country, but would not be able to access the contenta under [1] which is the only element without double quotes [1]: https://i.sstatic.net/263XtjsM.png


Solution

  • Unlike Lua, C# is a strongly typed language. So 1 is a number, and "1" is a string containing the character 1 and they can't be used interchangeably. Your line lua["mission.coalition.blue.country.1"]; is looking for the element with key "1" - a string key - on "country" and it can't find it, so you get a null returned.

    You will need to split into two steps, one for the string key, the other for the number key. The NLua library transforms integers into the C# long type.

    public void LuaTest()
    {
        const string luaData = @"coalition = 
        {
            [""blue""] = 
            {
                [""country""] = 
                {
                    [1] = 
                    {
                        [""hiddenOnPlanner""] = false,
                        [""tasks""] = {},
                        [""radioSet""] = false
                    }
                }
            }
        }";
        Lua lua = new Lua();
        lua.DoString(luaData);
    
        var country = lua["coalition.blue.country"] as LuaTable;
        if (country is null)
            throw new InvalidOperationException("Didn't find coalition.blue.country");
        var bluePlanes = country[1L] as LuaTable;
        if (bluePlanes is null)
            throw new InvalidOperationException("Didn't find item 1 on country");
        var dict = lua.GetTableDict(bluePlanes);
    
        Console.WriteLine("Second chunk of code:");
        foreach (KeyValuePair<object, object> de in dict)
        {
            Console.WriteLine($"{de.Key} {de.Value}");
        }
    }
    

    You'll notice that I've also added some checks for null. This is good practice: instead of a NullReferenceException at some point later in the code, you know exactly when something returned null that you were not expecting.

    Output:

    Second chunk of code:
    radioSet False
    hiddenOnPlanner False
    tasks table