• There is NO official Otland's Discord server and NO official Otland's server list. The Otland's Staff does not manage any Discord server or server list. Moderators or administrator of any Discord server or server lists have NO connection to the Otland's Staff. Do not get scammed!

TFS 1.X+ Reading 2D table from lua in sources

Snavy

Bakasta
Senator
Joined
Apr 1, 2012
Messages
1,249
Solutions
71
Reaction score
621
Location
Hell
I have been trying to read a 2D lua-table in sources and I am not sure how to debug this.
The error msg that shows up is "attemp to index a boolean value".

What is going on here?

Lua:
myLuaFunction({
    { a = 0, b = 123, c = "string", d = true, e = true, f = true },
    { a = 0, b = 123, c = "string", d = true, e = true, f = true }
})

C++:
int LuaScriptInterface::luaMyLuaFunction(lua_State* L)
{
    if(!isTable(L, -1)) {
        printf("not a table.");
        return 1;
    }

    lua_pushnil(L);
    while (lua_next(L, lua_gettop(L)) != 0) {
        auto index = lua_gettop(L);
        auto a = getField<int>(L, index, "a");
        auto b = getField<int>(L, index, "b");
        auto c = getFieldString(L, index, "c");
        bool d = getField<bool>(L, index, "d");
        bool e = getField<bool>(L, index, "e");
        bool f = getField<bool>(L, index, "f");
        lua_pop(L, 7);
    }
    lua_pop(L, 1);
    return 1;
}

error msg on startup:
Code:
Lua Script Error: [Scripts Interface]
/Users/snavy/forgottenserver/data/scripts/test.lua
attempt to index a boolean value
stack traceback:
    [C]: at 0x01093ec710
    [C]: in function 'myLuaFunction'
    ...snavy/forgottenserver/data/scripts/test.lua:1: in main chunk
> test.lua [error]
 
Solution
I'm pretty sure there is a better way to do this but getField didn't work for me either when I had to work with similar table...
C++:
lua_pushnil(L);
while (lua_next(L, -2) != 0)
{
    int32_t a;
    int32_t b;
    std::string c;
    bool d;
    bool e;
    bool f;
    lua_pushnil(L);
    while (lua_next(L, -2) != 0)
    {
        if (getString(L, -2) == "a")
            a = getNumber<int32_t>(L, -1);
        else if (getString(L, -2) == "b")
            b = getNumber<int32_t>(L, -1);
        else if (getString(L, -2) == "c")
            c = getString(L, -1);
        else if (getString(L, -2) == "d")
            d = getBoolean(L, -1);
        else if (getString(L, -2) == "e")
            e = getBoolean(L, -1);
        else if...
I'm pretty sure there is a better way to do this but getField didn't work for me either when I had to work with similar table...
C++:
lua_pushnil(L);
while (lua_next(L, -2) != 0)
{
    int32_t a;
    int32_t b;
    std::string c;
    bool d;
    bool e;
    bool f;
    lua_pushnil(L);
    while (lua_next(L, -2) != 0)
    {
        if (getString(L, -2) == "a")
            a = getNumber<int32_t>(L, -1);
        else if (getString(L, -2) == "b")
            b = getNumber<int32_t>(L, -1);
        else if (getString(L, -2) == "c")
            c = getString(L, -1);
        else if (getString(L, -2) == "d")
            d = getBoolean(L, -1);
        else if (getString(L, -2) == "e")
            e = getBoolean(L, -1);
        else if (getString(L, -2) == "f")
            f = getBoolean(L, -1);
        lua_pop(L, 1);
    }
    lua_pop(L, 1);
}
 
Solution
This is bad use this Example is better...

¡bad example!
C++:
int LuaScriptInterface::luaMyLuaFunction(lua_State* L)
{
    if (!isTable(L, -1)) {
        lua_pushnil(L);
        return 1;
    }

    lua_pushnil(L);
    while (lua_next(L, -2) != 0) {
        if (!isTable(L, -1)) {
            pushBoolean(L, false);
            return 1;
        }
        int32_t a = getField<int32_t>(L, -1, "a");
        int32_t b = getField<int32_t>(L, -1, "b");
        const std::string& c = getFieldString(L, -1, "c");
        bool d = getField<int32_t>(L, -1, "d") != 0;
        bool e = getField<int32_t>(L, -1, "e") != 0;
        bool f = getField<int32_t>(L, -1, "f") != 0;
        lua_pop(L, 1);
    }

    lua_pop(L, 1);
    pushBoolean(L, true);
    return 1;
}
 
Last edited:
C++:
int LuaScriptInterface::luaMyLuaFunction(lua_State* L)
{
    if (!isTable(L, -1)) {
        lua_pushnil(L);
        return 1;
    }

    lua_pushnil(L);
    while (lua_next(L, -2) != 0) {
        if (!isTable(L, -1)) {
            pushBoolean(L, false);
            return 1;
        }
        int32_t a = getField<int32_t>(L, -1, "a");
        int32_t b = getField<int32_t>(L, -1, "b");
        const std::string& c = getFieldString(L, -1, "c");
        bool d = getField<int32_t>(L, -1, "d") != 0;
        bool e = getField<int32_t>(L, -1, "e") != 0;
        bool f = getField<int32_t>(L, -1, "f") != 0;
        lua_pop(L, 1);
    }

    lua_pop(L, 1);
    pushBoolean(L, true);
    return 1;
}
That's the thing, getField doesn't work here. So this code is not working either.
 
I'm pretty sure there is a better way to do this but getField didn't work for me either when I had to work with similar table...
C++:
lua_pushnil(L);
while (lua_next(L, -2) != 0)
{
    int32_t a;
    int32_t b;
    std::string c;
    bool d;
    bool e;
    bool f;
    lua_pushnil(L);
    while (lua_next(L, -2) != 0)
    {
        if (getString(L, -2) == "a")
            a = getNumber<int32_t>(L, -1);
        else if (getString(L, -2) == "b")
            b = getNumber<int32_t>(L, -1);
        else if (getString(L, -2) == "c")
            c = getString(L, -1);
        else if (getString(L, -2) == "d")
            d = getBoolean(L, -1);
        else if (getString(L, -2) == "e")
            e = getBoolean(L, -1);
        else if (getString(L, -2) == "f")
            f = getBoolean(L, -1);
        lua_pop(L, 1);
    }
    lua_pop(L, 1);
}
C++:
int LuaScriptInterface::luaMyLuaFunction(lua_State* L)
{
    if (!isTable(L, -1)) {
        lua_pushnil(L);
        return 1;
    }

    lua_pushnil(L);
    while (lua_next(L, -2) != 0) {
        if (!isTable(L, -1)) {
            pushBoolean(L, false);
            return 1;
        }
        int32_t a = getField<int32_t>(L, -1, "a");
        int32_t b = getField<int32_t>(L, -1, "b");
        const std::string& c = getFieldString(L, -1, "c");
        bool d = getField<int32_t>(L, -1, "d") != 0;
        bool e = getField<int32_t>(L, -1, "e") != 0;
        bool f = getField<int32_t>(L, -1, "f") != 0;
        lua_pop(L, 1);
    }

    lua_pop(L, 1);
    pushBoolean(L, true);
    return 1;
}
Oen, your code gave the expected results and the error message is gone. 👍
However I am a bit confused because experienceStages from config.lua is also a 2D table and only 1 while loop is used 🤔

Sarah, your code did not produce the expected results and the error remains.
 
Oen, your code gave the expected results and the error message is gone. 👍
However I am a bit confused because experienceStages from config.lua is also a 2D table and only 1 while loop is used 🤔

Sarah, your code did not produce the expected results and the error remains.
Oh wow, if only this was a thing when I needed it the most... And looks like all I was missing is lua_pop having +1 number. I'm so disappointed right now...

This works (except bool, somehow not returning proper value).
Lua:
{
    {a = 123, b = "str", c = true},
    {a = 456, b = "ing", c = false},
}
C++:
    lua_pushnil(L);
    while (lua_next(L, -2) != 0) {
        const auto tableIndex = lua_gettop(L);
        auto a = getField<uint32_t>(L, tableIndex, "a");
        auto b = getFieldString(L, tableIndex, "b");
        auto c = getField<bool>(L, tableIndex, "c");
        std::cout << "a " << a << std::endl;
        std::cout << "b " << b << std::endl;
        std::cout << "c " << c << std::endl;
        lua_pop(L, 4);
    }
    lua_pop(L, 1);

Code:
a 123
b str
c 0
a 456
b ing
c 0
 
Oh wow, if only this was a thing when I needed it the most... And looks like all I was missing is lua_pop having +1 number. I'm so disappointed right now...

This works (except bool, somehow not returning proper value).
Lua:
{
    {a = 123, b = "str", c = true},
    {a = 456, b = "ing", c = false},
}
C++:
    lua_pushnil(L);
    while (lua_next(L, -2) != 0) {
        const auto tableIndex = lua_gettop(L);
        auto a = getField<uint32_t>(L, tableIndex, "a");
        auto b = getFieldString(L, tableIndex, "b");
        auto c = getField<bool>(L, tableIndex, "c");
        std::cout << "a " << a << std::endl;
        std::cout << "b " << b << std::endl;
        std::cout << "c " << c << std::endl;
        lua_pop(L, 4);
    }
    lua_pop(L, 1);

Code:
a 123
b str
c 0
a 456
b ing
c 0
This gave 0 on both bool values (true or false) and caused Seg fault 11 🤔
 
This gave 0 on both bool values (true or false) and caused Seg fault 11 🤔
Yup, thought it's because I used that code in global.lua but even after server starts it just crashes. Eh, I'm over it, sorry, you will have to use the longer version.
 
Here is an example without using the TFS interface

only lua api
C++:
int LuaScriptInterface::luaMyLuaFunction(lua_State* L)
{
    if (lua_istable(L, -1) == 0) {
        return 0;
    }

    lua_pushnil(L);
    while (lua_next(L, -2) != 0) {
        if (lua_istable(L, -1) == 0) {
            return 0;
        }
        lua_getfield(L, -1, "a");
        int32_t a = lua_tonumber(L, -1);
        lua_pop(L, 1);
        lua_getfield(L, -1, "b");
        int32_t b = lua_tonumber(L, -1);
        lua_pop(L, 1);
        lua_getfield(L, -1, "c");
        const std::string& c = lua_tostring(L, -1);
        lua_pop(L, 1);
        lua_getfield(L, -1, "d");
        bool d = lua_toboolean(L, -1) != 0;
        lua_pop(L, 1);
        lua_getfield(L, -1, "e");
        bool e = lua_toboolean(L, -1) != 0;
        lua_pop(L, 1);
        lua_getfield(L, -1, "f");
        bool f = lua_toboolean(L, -1) != 0;
        lua_pop(L, 2);
    }

    lua_pop(L, 1);
    return 0;
}
 
Eh, I'm over it, sorry, you will have to use the longer version.
Understandable xD
Thank you for saving me from the confusion I've been having for over 24h.
Post automatically merged:

Here is an example without using the TFS interface

only lua api
C++:
int LuaScriptInterface::luaMyLuaFunction(lua_State* L)
{
    if (lua_istable(L, -1) == 0) {
        return 0;
    }

    lua_pushnil(L);
    while (lua_next(L, -2) != 0) {
        if (lua_istable(L, -1) == 0) {
            return 0;
        }
        lua_getfield(L, -1, "a");
        int32_t a = lua_tonumber(L, -1);
        lua_pop(L, 1);
        lua_getfield(L, -1, "b");
        int32_t b = lua_tonumber(L, -1);
        lua_pop(L, 1);
        lua_getfield(L, -1, "c");
        const std::string& c = lua_tostring(L, -1);
        lua_pop(L, 1);
        lua_getfield(L, -1, "d");
        bool d = lua_toboolean(L, -1) != 0;
        lua_pop(L, 1);
        lua_getfield(L, -1, "e");
        bool e = lua_toboolean(L, -1) != 0;
        lua_pop(L, 1);
        lua_getfield(L, -1, "f");
        bool f = lua_toboolean(L, -1) != 0;
        lua_pop(L, 2);
    }

    lua_pop(L, 1);
    return 0;
}

Thank you sarah, I will have to stick to Oen's previous solution for now and keep digging into the next problem I have at hand xD
 
Understandable xD
Thank you for saving me from the confusion I've been having for over 24h.
Post automatically merged:



Thank you sarah, I will have to stick to Oen's previous solution for now and keep digging into the next problem I have at hand xD
The problem you have is that the TFS lua interface does not have a method to obtain booleans from a table, and you must handle this case manually with the original lua api or else create this new method, it should have the name: getFieldBoolean ;)

And if you wonder why this method does not exist, the answer is simple, so far it has no use and therefore does not exist

here an example of what the function looks like:
C++:
static bool getFieldBoolean(lua_State* L, int32_t arg, const std::string& key)
{
    lua_getfield(L, arg, key.c_str());
    return getBoolean(L, -1);
}
 
The problem you have is that the TFS lua interface does not have a method to obtain booleans from a table, and you must handle this case manually with the original lua api or else create this new method, it should have the name: getFieldBoolean ;)

I see. Once I have (hopefully) fixed the next problem I will try to do that and see how that works out.
 
Back
Top