From 9a3796f0b83db5d576027c8db3983a21e91edb81 Mon Sep 17 00:00:00 2001 From: MysterD Date: Tue, 1 Feb 2022 18:15:10 -0800 Subject: [PATCH] Added ability for sync tables to contain tables --- autogen/lua_constants/constants.lua | 13 +- developer/network.sh | 6 +- docs/lua/constants.md | 6 - src/pc/lua/smlua_constants_autogen.c | 11 +- src/pc/lua/smlua_sync_table.c | 379 +++++++++++------- src/pc/lua/smlua_sync_table.h | 7 +- src/pc/lua/smlua_utils.c | 146 ++++++- src/pc/lua/smlua_utils.h | 10 +- src/pc/network/packets/packet.h | 7 +- .../network/packets/packet_lua_sync_table.c | 64 +-- 10 files changed, 444 insertions(+), 205 deletions(-) diff --git a/autogen/lua_constants/constants.lua b/autogen/lua_constants/constants.lua index 0d54477e..458bb884 100644 --- a/autogen/lua_constants/constants.lua +++ b/autogen/lua_constants/constants.lua @@ -9,10 +9,6 @@ HOOK_ON_SET_MARIO_ACTION = 3 HOOK_BEFORE_PHYS_STEP = 4 HOOK_MAX = 5 -LST_GLOBAL = 0 -LST_PLAYER = 1 -LST_MAX = 2 - _CObject = { __index = function (t,k) return _get_field(t['_lot'], t['_pointer'], k) @@ -37,6 +33,15 @@ _SyncTable = { end } +_ReadOnlyTable = { + __index = function (t,k) + local _table = rawget(t, '_table') + return _table[k] + end, + __newindex = function (t,k,v) + end +} + function vec3f_copy(dest, src) dest.x = src.x dest.y = src.y diff --git a/developer/network.sh b/developer/network.sh index 126e29d4..8fd0a05e 100644 --- a/developer/network.sh +++ b/developer/network.sh @@ -24,9 +24,9 @@ $FILE --client 127.0.0.1 27015 --configfile sm64config_client.txt & exit # debug on server -#$FILE --client 127.0.0.1 27015 --configfile sm64config_client.txt & > /dev/null -#winpty cgdb $FILE -ex 'break debug_breakpoint_here' -ex 'run --server 27015 --configfile sm64config_server.txt' -ex 'quit' -#exit +$FILE --client 127.0.0.1 27015 --configfile sm64config_client.txt & > /dev/null +winpty cgdb $FILE -ex 'break debug_breakpoint_here' -ex 'run --server 27015 --configfile sm64config_server.txt' -ex 'quit' +exit ################### # debug on client # diff --git a/docs/lua/constants.md b/docs/lua/constants.md index 394b8e6b..e91312b9 100644 --- a/docs/lua/constants.md +++ b/docs/lua/constants.md @@ -619,12 +619,6 @@ - HOOK_BEFORE_PHYS_STEP - HOOK_MAX -
- -- LST_GLOBAL -- LST_PLAYER -- LST_MAX - [:arrow_up_small:](#)
diff --git a/src/pc/lua/smlua_constants_autogen.c b/src/pc/lua/smlua_constants_autogen.c index b3868b04..eaabc30d 100644 --- a/src/pc/lua/smlua_constants_autogen.c +++ b/src/pc/lua/smlua_constants_autogen.c @@ -4,9 +4,6 @@ char gSmluaConstants[] = "HOOK_UPDATE = 0\n" "HOOK_ON_SET_MARIO_ACTION = 3\n" "HOOK_BEFORE_PHYS_STEP = 4\n" "HOOK_MAX = 5\n" -"LST_GLOBAL = 0\n" -"LST_PLAYER = 1\n" -"LST_MAX = 2\n" "_CObject = {\n" " __index = function (t,k)\n" " return _get_field(t['_lot'], t['_pointer'], k)\n" @@ -29,6 +26,14 @@ char gSmluaConstants[] = "HOOK_UPDATE = 0\n" " _set_sync_table_field(t, k, v)\n" " end\n" "}\n" +"_ReadOnlyTable = {\n" +" __index = function (t,k)\n" +" local _table = rawget(t, '_table')\n" +" return _table[k]\n" +" end,\n" +" __newindex = function (t,k,v)\n" +" end\n" +"}\n" "function vec3f_copy(dest, src)\n" " dest.x = src.x\n" " dest.y = src.y\n" diff --git a/src/pc/lua/smlua_sync_table.c b/src/pc/lua/smlua_sync_table.c index cd1fa4e8..41f4f215 100644 --- a/src/pc/lua/smlua_sync_table.c +++ b/src/pc/lua/smlua_sync_table.c @@ -3,65 +3,114 @@ #include "pc/network/network.h" #include "pc/network/network_player.h" -static bool smlua_value_to_lnt(int index, struct LSTNetworkType* lnt) { +#define MAX_UNWOUND_SIZE 256 +static struct LSTNetworkType sUnwoundLnts[MAX_UNWOUND_LNT] = { 0 }; +u16 sUnwoundLntsCount = 0; + +static void smlua_sync_table_create(u16 modRemoteIndex, enum LuaSyncTableType lst, int* parentIndex, int* keyIndex) { lua_State* L = gLuaState; - int valueType = lua_type(L, index); + lua_newtable(L); + int t = lua_gettop(L); - if (valueType == LUA_TNUMBER) { - lnt->type = LST_NETWORK_TYPE_INTEGER; - lnt->value.integer = lua_tointeger(L, index); + // push fields + smlua_push_integer_field(t, "_remoteIndex", modRemoteIndex); + smlua_push_integer_field(t, "_type", lst); + smlua_push_table_field(t, "_seq"); + smlua_push_table_field(t, "_table"); - if (lnt->value.integer == 0) { - lnt->type = LST_NETWORK_TYPE_NUMBER; - lnt->value.number = lua_tonumber(L, index); - } - return true; - } + // set parent + lua_pushstring(L, "_parent"); + if (parentIndex == NULL) { lua_pushnil(L); } else { lua_pushvalue(L, *parentIndex); } + lua_settable(L, -3); - if (valueType == LUA_TBOOLEAN) { - lnt->type = LST_NETWORK_TYPE_BOOLEAN; - lnt->value.boolean = lua_toboolean(L, index); - return true; - } + // set key name + lua_pushstring(L, "_name"); + if (keyIndex == NULL) { lua_pushnil(L); } else { lua_pushvalue(L, *keyIndex); } + lua_settable(L, -3); - if (valueType == LUA_TSTRING) { - lnt->type = LST_NETWORK_TYPE_STRING; - lnt->value.string = lua_tostring(L, index); - if (lnt->value.string == NULL || strlen(lnt->value.string) > 256) { - LOG_LUA("smlua_value_to_lnt on invalid string value: '%s'", (lnt->value.string == NULL) ? "" : lnt->value.string); - return false; - } - return true; - } - - if (valueType == LUA_TNIL) { - lnt->type = LST_NETWORK_TYPE_NIL; - return true; - } - - return false; + // attach metatable + lua_pushglobaltable(L); + lua_getfield(L, -1, "_SyncTable"); + lua_setmetatable(L, -3); + lua_pop(L, 1); // pop global table } -static void smlua_push_lnt(struct LSTNetworkType* lnt) { +static bool smlua_sync_table_unwind(int syncTableIndex, int keyIndex) { + LUA_STACK_CHECK_BEGIN(); lua_State* L = gLuaState; - switch (lnt->type) { - case LST_NETWORK_TYPE_INTEGER: - lua_pushinteger(L, lnt->value.integer); - break; - case LST_NETWORK_TYPE_NUMBER: - lua_pushnumber(L, lnt->value.number); - break; - case LST_NETWORK_TYPE_BOOLEAN: - lua_pushboolean(L, lnt->value.boolean); - break; - case LST_NETWORK_TYPE_STRING: - lua_pushstring(L, lnt->value.string); - break; - case LST_NETWORK_TYPE_NIL: - lua_pushnil(L); - break; - default: SOFT_ASSERT(false); + sUnwoundLntsCount = 0; + + // get key + sUnwoundLnts[sUnwoundLntsCount++] = smlua_to_lnt(L, keyIndex); + if (!gSmLuaConvertSuccess) { + LOG_LUA("attempted to unwind sync table with invalid key type"); + return false; } + + // duplicate sync table for iteration + lua_pushvalue(L, syncTableIndex); + syncTableIndex = lua_gettop(L); + + while (true) { + // make sure we remain within limits + if (sUnwoundLntsCount >= MAX_UNWOUND_LNT) { + LOG_LUA("attempted to unwind sync table past its limit"); + return false; + } + + // get name of table + lua_pushstring(L, "_name"); + lua_gettable(L, syncTableIndex); + sUnwoundLnts[sUnwoundLntsCount++] = smlua_to_lnt(L, -1); + + // translate player index + lua_getfield(L, syncTableIndex, "_type"); + lua_Integer lst = lua_tointeger(L, -1); + lua_pop(L, 1); + if (lst == LST_PLAYER) { + struct LSTNetworkType* n = &sUnwoundLnts[sUnwoundLntsCount - 1]; + assert(n->type == LST_NETWORK_TYPE_INTEGER); + n->value.integer = network_player_global_index_from_local(n->value.integer); + } + + lua_pop(L, 1); // pop _name value + if (!gSmLuaConvertSuccess) { + LOG_LUA("attempted to unwind sync table with invalid parent"); + lua_pop(L, 1); // pop iterative _parent + return false; + } + + // get parent of table + lua_pushstring(L, "_parent"); + lua_gettable(L, syncTableIndex); + int parentType = lua_type(L, -1); + lua_replace(L, syncTableIndex); + + // validate parent type + if (parentType != LUA_TTABLE) { + if (parentType != LUA_TNIL) { + LOG_LUA("attempted to unwind sync table into an invalid parent"); + return false; + } + break; + } + } + + lua_pop(L, 1); // pop iterative _parent + + // check size + size_t unwoundSize = 0; + for (int i = 0; i < sUnwoundLntsCount; i++) { + unwoundSize += sUnwoundLnts[i].size; + } + + if (unwoundSize >= MAX_UNWOUND_SIZE) { + LOG_LUA("attempted to unwind sync table with too long of a key/parent length"); + return false; + } + + LUA_STACK_CHECK_END(); + return true; } static void smlua_sync_table_send_field(u8 toLocalIndex, int stackIndex, bool alterSeq) { @@ -75,29 +124,70 @@ static void smlua_sync_table_send_field(u8 toLocalIndex, int stackIndex, bool al // get modRemoteIndex u16 modRemoteIndex = smlua_get_integer_field(syncTableIndex, "_remoteIndex"); if (!gSmLuaConvertSuccess) { - LOG_LUA("smlua_sync_table_send_field on invalid modRemoteIndex: %u", modRemoteIndex); - return; - } - - // get lst - enum LuaSyncTableType lst = smlua_get_integer_field(syncTableIndex, "_type"); - if (!gSmLuaConvertSuccess || lst >= LST_MAX) { - LOG_LUA("smlua_sync_table_send_field on invalid LST: %u", lst); + LOG_LUA("Error: tried to alter sync table with an invalid modRemoteIndex: %u", modRemoteIndex); return; } // get key - struct LSTNetworkType lntKey = { 0 }; - if (!smlua_value_to_lnt(keyIndex, &lntKey)) { return; } + struct LSTNetworkType lntKey = smlua_to_lnt(L, keyIndex); + if (!gSmLuaConvertSuccess) { + LOG_LUA("Error: tried to alter sync table with an invalid key"); + return; + } + lntKey = lntKey; + + //////////////// + // prev value // + //////////////// + + lua_getfield(L, syncTableIndex, "_table"); + lua_pushvalue(L, keyIndex); + lua_rawget(L, -2); + int prevValueType = lua_type(L, -1); + lua_pop(L, 1); // pop prev value + lua_pop(L, 1); // pop _table + + if (prevValueType == LUA_TTABLE) { + LOG_LUA("Error: tried to assign on top of sync table"); + return; + } /////////// // value // /////////// // get value - struct LSTNetworkType lntValue = { 0 }; - if (!smlua_value_to_lnt(valueIndex, &lntValue)) { return; } + int valueType = lua_type(L, valueIndex); + if (valueType == LUA_TTABLE) { + if (prevValueType != LUA_TNIL) { + LOG_LUA("Error: tried to set a sync table field to a different sync table"); + return; + } + + if (!smlua_is_table_empty(valueIndex)) { + LOG_LUA("Error: tried to generate a sync table with a non-empty table"); + return; + } + + // create sync table + int modRemoteIndex = smlua_get_integer_field(syncTableIndex, "_remoteIndex"); + + // set table + lua_getfield(L, syncTableIndex, "_table"); + lua_pushvalue(L, keyIndex); + smlua_sync_table_create(modRemoteIndex, LST_NORMAL, &syncTableIndex, &keyIndex); + lua_settable(L, -3); + lua_pop(L, 1); // pop _table + + LUA_STACK_CHECK_END(); + return; + } + struct LSTNetworkType lntValue = smlua_to_lnt(L, valueIndex); + if (!gSmLuaConvertSuccess) { + LOG_LUA("Error: tried to alter sync table with an invalid value"); + return; + } // set value lua_getfield(L, syncTableIndex, "_table"); @@ -128,22 +218,19 @@ static void smlua_sync_table_send_field(u8 toLocalIndex, int stackIndex, bool al lua_pop(L, 1); // pop seq table - /////////// - // index // - /////////// - - // get index - u16 index = smlua_get_integer_field(syncTableIndex, "_index"); - index = network_player_global_index_from_local(index); - - ///////////// // network // ///////////// + // unwind key + parent tables + if (!smlua_sync_table_unwind(syncTableIndex, keyIndex)) { + LOG_LUA("Error: failed to unwind sync table for sending over the network"); + return; + } + // send over the network if (!gLuaInitializingScript && seq > 0) { - network_send_lua_sync_table(toLocalIndex, seq, modRemoteIndex, lst, index, &lntKey, &lntValue); + network_send_lua_sync_table(toLocalIndex, seq, modRemoteIndex, sUnwoundLntsCount, sUnwoundLnts, &lntValue); } LUA_STACK_CHECK_END(); @@ -155,11 +242,11 @@ static int smlua__set_sync_table_field(UNUSED lua_State* L) { return 1; } -void smlua_set_sync_table_field_from_network(u64 seq, u16 modRemoteIndex, u16 lst, u16 index, struct LSTNetworkType* lntKey, struct LSTNetworkType* lntValue) { +void smlua_set_sync_table_field_from_network(u64 seq, u16 modRemoteIndex, u16 lntKeyCount, struct LSTNetworkType* lntKeys, struct LSTNetworkType* lntValue) { LUA_STACK_CHECK_BEGIN(); lua_State* L = gLuaState; - // figure out table + // figure out mod table struct ModTable* table = NULL; if (gNetworkType == NT_SERVER) { table = &gModTableLocal; @@ -183,12 +270,6 @@ void smlua_set_sync_table_field_from_network(u64 seq, u16 modRemoteIndex, u16 ls return; } - // sanity check lst - if (lst >= LST_MAX) { - LOG_ERROR("Received sync table field packet with an invalid LST: %u", lst); - return; - } - // sanity check lntValue if (lntValue->type >= LST_NETWORK_TYPE_MAX) { LOG_ERROR("Received sync table field packet with an invalid lnt type: %u", lntValue->type); @@ -197,28 +278,61 @@ void smlua_set_sync_table_field_from_network(u64 seq, u16 modRemoteIndex, u16 ls lua_getglobal(L, "_G"); // get global table lua_getfield(L, LUA_REGISTRYINDEX, entry->path); // get the file's "global" table + int fileGlobalIndex = lua_gettop(L); - // get sync table - u16 syncTableSize = 0; - switch (lst) { - case LST_GLOBAL: - syncTableSize = 1; - lua_getfield(L, -1, "gGlobalSyncTable"); - break; - case LST_PLAYER: - syncTableSize = 2; - lua_getfield(L, -1, "gPlayerSyncTable"); - lua_pushinteger(L, network_player_local_index_from_global(index)); + // push global sync table + u16 syncTableSize = 1; + smlua_push_lnt(&lntKeys[lntKeyCount - 1]); + lua_gettable(L, fileGlobalIndex); + int syncTableIndex = lua_gettop(L); + if (lua_type(L, -1) != LUA_TTABLE) { + LOG_ERROR("Received sync table field packet with an invalid table"); + return; + } + + for (int i = lntKeyCount - 2; i >= 1; i--) { + // get child sync table + smlua_push_lnt(&lntKeys[i]); + lua_gettable(L, -2); + + // create missing tables + if (lua_type(L, -1) != LUA_TTABLE) { + lua_pop(L, 1); // pop non-table + + // push internal table of parent + lua_pushstring(L, "_table"); + lua_gettable(L, syncTableIndex); + + // set internal[key] = new sync table + smlua_push_lnt(&lntKeys[i]); + int keyIndex = lua_gettop(L); + smlua_sync_table_create(modRemoteIndex, LST_NORMAL, &syncTableIndex, &keyIndex); + lua_rawset(L, -3); + + // get new sync table + smlua_push_lnt(&lntKeys[i]); lua_gettable(L, -2); - break; - default: assert(false); + + lua_remove(L, -2); // remove paren'ts internal table + } else { + + // translate player index + if (smlua_get_integer_field(-1, "_type") == LST_PLAYER) { + lua_pop(L, 1); // pop wrong table + assert(lntKeys[i].type == LST_NETWORK_TYPE_INTEGER); + lua_pushinteger(L, network_player_local_index_from_global(lntKeys[i].value.integer)); + lua_gettable(L, -2); + } + } + + lua_remove(L, -2); // remove parent table } // get seq table lua_getfield(L, -1, "_seq"); // get seq number - smlua_push_lnt(lntKey); + smlua_push_lnt(&lntKeys[0]); lua_gettable(L, -2); u64 readSeq = lua_tointeger(L, -1); lua_pop(L, 1); // pop seq value @@ -234,7 +348,7 @@ void smlua_set_sync_table_field_from_network(u64 seq, u16 modRemoteIndex, u16 ls } // set seq number - smlua_push_lnt(lntKey); + smlua_push_lnt(&lntKeys[0]); lua_pushinteger(L, seq); lua_settable(L, -3); lua_pop(L, 1); // pop seq table @@ -245,7 +359,7 @@ void smlua_set_sync_table_field_from_network(u64 seq, u16 modRemoteIndex, u16 ls int t = lua_gettop(L); // set key/value - smlua_push_lnt(lntKey); + smlua_push_lnt(&lntKeys[0]); smlua_push_lnt(lntValue); lua_rawset(L, t); @@ -271,56 +385,45 @@ void smlua_sync_table_init_globals(char* path, u16 modRemoteIndex) { lua_State* L = gLuaState; lua_getfield(L, LUA_REGISTRYINDEX, path); - int base = lua_gettop(L); + int fileGlobalIndex = lua_gettop(L); { + // create and attach global sync table + lua_pushstring(L, "gGlobalSyncTable"); + int keyIndex = lua_gettop(L); + smlua_sync_table_create(modRemoteIndex, LST_NORMAL, NULL, &keyIndex); + lua_settable(L, fileGlobalIndex); + } + { + // create player sync table + lua_pushstring(L, "gPlayerSyncTable"); lua_newtable(L); - int t = lua_gettop(L); + int tableIndex = lua_gettop(L); + smlua_push_string_field(tableIndex, "_name", "gPlayerSyncTable"); - // push fields - smlua_push_integer_field(t, "_remoteIndex", modRemoteIndex); - smlua_push_integer_field(t, "_type", LST_GLOBAL); - smlua_push_integer_field(t, "_index", 0); - smlua_push_table_field(t, "_seq"); - smlua_push_table_field(t, "_table"); - smlua_push_string_field(t, "_name", "gGlobalSyncTable"); - smlua_push_nil_field(t, "_parent"); + // create internal table + lua_pushstring(L, "_table"); + lua_newtable(L); + int internalTableIndex = lua_gettop(L); + + // create player sync tables + for (int i = 0; i < MAX_PLAYERS; i++) { + lua_pushinteger(L, i); + int keyIndex = lua_gettop(L); + smlua_sync_table_create(modRemoteIndex, LST_PLAYER, &tableIndex, &keyIndex); + lua_settable(L, internalTableIndex); + } + + // attach internal table + lua_settable(L, tableIndex); // attach metatable lua_pushglobaltable(L); - lua_getfield(L, -1, "_SyncTable"); - lua_setmetatable(L, -3); + lua_getfield(L, -1, "_ReadOnlyTable"); + lua_setmetatable(L, tableIndex); lua_pop(L, 1); // pop global table - // attach sync table to file's "globals" - lua_setfield(L, base, "gGlobalSyncTable"); - } - { - lua_newtable(L); - int playerTop = lua_gettop(L); - for (int i = 0; i < MAX_PLAYERS; i++) { - lua_pushinteger(L, i); - - lua_newtable(L); - int t = lua_gettop(L); - - smlua_push_integer_field(t, "_remoteIndex", modRemoteIndex); - smlua_push_integer_field(t, "_type", LST_PLAYER); - smlua_push_integer_field(t, "_index", i); - smlua_push_table_field(t, "_seq"); - smlua_push_table_field(t, "_table"); - smlua_push_string_field(t, "_name", "gPlayerSyncTable"); // <--- incorrect - smlua_push_nil_field(t, "_parent"); // <--- incorrect - - // attach metatable - lua_pushglobaltable(L); - lua_getfield(L, -1, "_SyncTable"); - lua_setmetatable(L, -3); - lua_pop(L, 1); // pop global table - - // attach table to gPlayerSyncTable - lua_settable(L, playerTop); - } - lua_setfield(L, base, "gPlayerSyncTable"); + // attach player sync table + lua_settable(L, fileGlobalIndex); } lua_pop(L, 1); // pop file's "global" table diff --git a/src/pc/lua/smlua_sync_table.h b/src/pc/lua/smlua_sync_table.h index b6032e0e..b6fdaaa1 100644 --- a/src/pc/lua/smlua_sync_table.h +++ b/src/pc/lua/smlua_sync_table.h @@ -1,15 +1,16 @@ #ifndef SMLUA_SYNC_TABLE_H #define SMLUA_SYNC_TABLE_H +#define MAX_UNWOUND_LNT 16 + enum LuaSyncTableType { - LST_GLOBAL, + LST_NORMAL, LST_PLAYER, LST_MAX, }; struct LSTNetworkType; - -void smlua_set_sync_table_field_from_network(u64 seq, u16 remoteIndex, u16 lst, u16 index, struct LSTNetworkType* lntKey, struct LSTNetworkType* lntValue); +void smlua_set_sync_table_field_from_network(u64 seq, u16 modRemoteIndex, u16 lntKeyCount, struct LSTNetworkType* lntKeys, struct LSTNetworkType* lntValue); void smlua_sync_table_init_globals(char* path, u16 remoteIndex); void smlua_bind_sync_table(void); void smlua_sync_table_send_all(u8 toLocalIndex); diff --git a/src/pc/lua/smlua_utils.c b/src/pc/lua/smlua_utils.c index 0b8e97fa..05d7a14b 100644 --- a/src/pc/lua/smlua_utils.c +++ b/src/pc/lua/smlua_utils.c @@ -20,25 +20,24 @@ s16* smlua_get_vec3s_from_buffer(void) { return sVec3sBuffer[sVec3sBufferIndex++]; } +/////////////////////////////////////////////////////////////////////////////////////////// + void smlua_bind_function(lua_State* L, const char* name, void* func) { lua_pushcfunction(L, func); lua_setglobal(L, name); } -void smlua_logline(void) { - lua_State* L = gLuaState; - lua_Debug info; - int level = 0; - while (lua_getstack(L, level, &info)) { - lua_getinfo(L, "nSl", &info); - LOG_INFO(" [%d] %s:%d -- %s [%s]", - level, info.short_src, info.currentline, - (info.name ? info.name : ""), info.what); - ++level; + +bool smlua_is_table_empty(int index) { + lua_pushnil(gLuaState); // key + if (lua_next(gLuaState, index)) { + lua_pop(gLuaState, 2); + return false; } + return true; } -////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////// lua_Integer smlua_to_integer(lua_State* L, int index) { if (lua_type(L, index) == LUA_TBOOLEAN) { @@ -121,7 +120,63 @@ void* smlua_to_cobject(lua_State* L, int index, u16 lot) { return pointer; } -////////////////////////////////////////////// +struct LSTNetworkType smlua_to_lnt(lua_State* L, int index) { + struct LSTNetworkType lnt = { 0 }; + int valueType = lua_type(L, index); + + if (valueType == LUA_TNUMBER) { + lnt.type = LST_NETWORK_TYPE_INTEGER; + lnt.value.integer = lua_tointeger(L, index); + lnt.size = sizeof(u8) + sizeof(long long); + + if (lnt.value.integer == 0) { + lnt.type = LST_NETWORK_TYPE_NUMBER; + lnt.value.number = lua_tonumber(L, index); + lnt.size = sizeof(u8) + sizeof(double); + + if (lnt.value.number == 0) { + lnt.type = LST_NETWORK_TYPE_INTEGER; + lnt.size = sizeof(u8) + sizeof(long long); + } + } + gSmLuaConvertSuccess = true; + return lnt; + } + + if (valueType == LUA_TBOOLEAN) { + lnt.type = LST_NETWORK_TYPE_BOOLEAN; + lnt.value.boolean = lua_toboolean(L, index); + lnt.size = sizeof(u8) + sizeof(u8); + gSmLuaConvertSuccess = true; + return lnt; + } + + if (valueType == LUA_TSTRING) { + lnt.type = LST_NETWORK_TYPE_STRING; + lnt.value.string = (char*)lua_tostring(L, index); + if (lnt.value.string == NULL || strlen(lnt.value.string) > 256) { + LOG_LUA("smlua_to_lnt on invalid string value: '%s'", (lnt.value.string == NULL) ? "" : lnt.value.string); + gSmLuaConvertSuccess = false; + return lnt; + } + lnt.size = sizeof(u8) + sizeof(u16) + sizeof(u8) * strlen(lnt.value.string); + gSmLuaConvertSuccess = true; + return lnt; + } + + if (valueType == LUA_TNIL) { + lnt.type = LST_NETWORK_TYPE_NIL; + lnt.size = sizeof(u8); + gSmLuaConvertSuccess = true; + return lnt; + } + + LOG_LUA("smlua_to_lnt on invalid type: '%d'", valueType); + gSmLuaConvertSuccess = false; + return lnt; +} + +/////////////////////////////////////////////////////////////////////////////////////////// void smlua_push_object(lua_State* L, u16 lot, void* p) { if (p == NULL) { @@ -166,6 +221,32 @@ void smlua_push_table_field(int index, char* name) { lua_setfield(gLuaState, index, name); } +/////////////////////////////////////////////////////////////////////////////////////////// + +void smlua_push_lnt(struct LSTNetworkType* lnt) { + lua_State* L = gLuaState; + switch (lnt->type) { + case LST_NETWORK_TYPE_INTEGER: + lua_pushinteger(L, lnt->value.integer); + break; + case LST_NETWORK_TYPE_NUMBER: + lua_pushnumber(L, lnt->value.number); + break; + case LST_NETWORK_TYPE_BOOLEAN: + lua_pushboolean(L, lnt->value.boolean); + break; + case LST_NETWORK_TYPE_STRING: + lua_pushstring(L, lnt->value.string); + break; + case LST_NETWORK_TYPE_NIL: + lua_pushnil(L); + break; + default: SOFT_ASSERT(false); + } +} + +/////////////////////////////////////////////////////////////////////////////////////////// + lua_Integer smlua_get_integer_field(int index, char* name) { if (lua_type(gLuaState, index) != LUA_TTABLE) { LOG_LUA("smlua_get_integer_field received improper type '%d'", lua_type(gLuaState, index)); @@ -190,13 +271,29 @@ lua_Number smlua_get_number_field(int index, char* name) { return val; } -bool smlua_is_table_empty(int index) { - lua_pushnil(gLuaState); // key - if (lua_next(gLuaState, index)) { - lua_pop(gLuaState, 2); - return false; +/////////////////////////////////////////////////////////////////////////////////////////// + +char* smlua_lnt_to_str(struct LSTNetworkType* lnt) { + static char sLntStr[32] = ""; + switch (lnt->type) { + case LST_NETWORK_TYPE_INTEGER: + snprintf(sLntStr, 32, "%lld", lnt->value.integer); + break; + case LST_NETWORK_TYPE_NUMBER: + snprintf(sLntStr, 32, "%f", lnt->value.number); + break; + case LST_NETWORK_TYPE_BOOLEAN: + snprintf(sLntStr, 32, "%u", lnt->value.boolean); + break; + case LST_NETWORK_TYPE_STRING: + snprintf(sLntStr, 32, "%s", lnt->value.string); + break; + case LST_NETWORK_TYPE_NIL: + snprintf(sLntStr, 32, ""); + break; + default: SOFT_ASSERT(false); } - return true; + return sLntStr; } void smlua_dump_stack(void) { @@ -274,4 +371,17 @@ void smlua_dump_table(int index) { lua_pop(L, 1); } printf("--------------\n"); +} + +void smlua_logline(void) { + lua_State* L = gLuaState; + lua_Debug info; + int level = 0; + while (lua_getstack(L, level, &info)) { + lua_getinfo(L, "nSl", &info); + LOG_INFO(" [%d] %s:%d -- %s [%s]", + level, info.short_src, info.currentline, + (info.name ? info.name : ""), info.what); + ++level; + } } \ No newline at end of file diff --git a/src/pc/lua/smlua_utils.h b/src/pc/lua/smlua_utils.h index 79493f54..fa1098c9 100644 --- a/src/pc/lua/smlua_utils.h +++ b/src/pc/lua/smlua_utils.h @@ -7,12 +7,14 @@ f32* smlua_get_vec3f_from_buffer(void); s16* smlua_get_vec3s_from_buffer(void); void smlua_bind_function(lua_State* L, const char* name, void* func); -void smlua_logline(void); +bool smlua_is_table_empty(int index); + lua_Integer smlua_to_integer(lua_State* L, int index); lua_Number smlua_to_number(lua_State* L, int index); const char* smlua_to_string(lua_State* L, int index); void* smlua_to_cobject(lua_State* L, int index, u16 lot); +struct LSTNetworkType smlua_to_lnt(lua_State* L, int index); void smlua_push_object(lua_State* L, u16 lot, void* p); void smlua_push_integer_field(int index, char* name, lua_Integer val); @@ -21,11 +23,13 @@ void smlua_push_string_field(int index, char* name, const char* val); void smlua_push_nil_field(int index, char* name); void smlua_push_table_field(int index, char* name); +void smlua_push_lnt(struct LSTNetworkType* lnt); + lua_Integer smlua_get_integer_field(int index, char* name); lua_Number smlua_get_number_field(int index, char* name); -bool smlua_is_table_empty(int index); - +char* smlua_lnt_to_str(struct LSTNetworkType* lnt); +void smlua_logline(void); void smlua_dump_stack(void); void smlua_dump_globals(void); void smlua_dump_table(int index); diff --git a/src/pc/network/packets/packet.h b/src/pc/network/packets/packet.h index 27028e28..e6f2dff1 100644 --- a/src/pc/network/packets/packet.h +++ b/src/pc/network/packets/packet.h @@ -118,8 +118,10 @@ struct LSTNetworkType { long long integer; double number; u8 boolean; - const char* string; + char* string; } value; + + size_t size; }; // packet.c @@ -329,7 +331,8 @@ void network_receive_download(struct Packet* p); // packet_lua_sync_table.c void network_send_lua_sync_table_request(void); void network_receive_lua_sync_table_request(struct Packet* p); -void network_send_lua_sync_table(u8 toLocalIndex, u64 seq, u16 remoteIndex, u16 lst, u16 index, struct LSTNetworkType* lntKey, struct LSTNetworkType* lntValue); + +void network_send_lua_sync_table(u8 toLocalIndex, u64 seq, u16 remoteIndex, u16 lntKeyCount, struct LSTNetworkType* lntKey, struct LSTNetworkType* lntValue); void network_receive_lua_sync_table(struct Packet* p); #endif diff --git a/src/pc/network/packets/packet_lua_sync_table.c b/src/pc/network/packets/packet_lua_sync_table.c index 369c7f2c..cd591c1c 100644 --- a/src/pc/network/packets/packet_lua_sync_table.c +++ b/src/pc/network/packets/packet_lua_sync_table.c @@ -3,8 +3,6 @@ #include "pc/lua/smlua.h" #include "pc/debuglog.h" -static char sLuaStrValue[257] = { 0 }; - ///////////////////////////////////////////////////////////// void network_send_lua_sync_table_request(void) { @@ -25,8 +23,8 @@ void network_receive_lua_sync_table_request(struct Packet* p) { ///////////////////////////////////////////////////////////// static bool packet_write_lnt(struct Packet* p, struct LSTNetworkType* lnt) { - u16 lntType = lnt->type; - packet_write(p, &lntType, sizeof(u16)); + u8 lntType = lnt->type; + packet_write(p, &lntType, sizeof(u8)); switch (lnt->type) { case LST_NETWORK_TYPE_NUMBER: { @@ -47,10 +45,13 @@ static bool packet_write_lnt(struct Packet* p, struct LSTNetworkType* lnt) { } case LST_NETWORK_TYPE_STRING: { - snprintf(sLuaStrValue, 256, "%s", lnt->value.string); - u16 valueLength = strlen(sLuaStrValue); + u16 valueLength = strlen(lnt->value.string); + if (valueLength < 1 || valueLength > 256) { + LOG_ERROR("attempted to send lua sync table with invalid string length: %u", valueLength); + return false; + } packet_write(p, &valueLength, sizeof(u16)); - packet_write(p, &sLuaStrValue, valueLength * sizeof(u8)); + packet_write(p, lnt->value.string, valueLength * sizeof(u8)); return true; } @@ -68,7 +69,7 @@ static bool packet_write_lnt(struct Packet* p, struct LSTNetworkType* lnt) { } static bool packet_read_lnt(struct Packet* p, struct LSTNetworkType* lnt) { - packet_read(p, &lnt->type, sizeof(u16)); + packet_read(p, &lnt->type, sizeof(u8)); switch (lnt->type) { case LST_NETWORK_TYPE_NUMBER: @@ -86,14 +87,12 @@ static bool packet_read_lnt(struct Packet* p, struct LSTNetworkType* lnt) { case LST_NETWORK_TYPE_STRING: { u16 valueLength = 0; packet_read(p, &valueLength, sizeof(u16)); - if (valueLength > 256) { + if (valueLength < 1 || valueLength > 256) { LOG_ERROR("received lua sync table with invalid value length: %d", valueLength); return false; } - - packet_read(p, &sLuaStrValue, valueLength * sizeof(u8)); - sLuaStrValue[valueLength] = 0; - lnt->value.string = sLuaStrValue; + lnt->value.string = calloc(valueLength + 1, sizeof(u8)); + packet_read(p, lnt->value.string, valueLength * sizeof(u8)); return true; } @@ -111,16 +110,18 @@ static bool packet_read_lnt(struct Packet* p, struct LSTNetworkType* lnt) { ///////////////////////////////////////////////////////////// -void network_send_lua_sync_table(u8 toLocalIndex, u64 seq, u16 modRemoteIndex, u16 lst, u16 index, struct LSTNetworkType* lntKey, struct LSTNetworkType* lntValue) { +void network_send_lua_sync_table(u8 toLocalIndex, u64 seq, u16 modRemoteIndex, u16 lntKeyCount, struct LSTNetworkType* lntKeys, struct LSTNetworkType* lntValue) { struct Packet p = { 0 }; packet_init(&p, PACKET_LUA_SYNC_TABLE, true, PLMT_NONE); packet_write(&p, &seq, sizeof(u64)); packet_write(&p, &modRemoteIndex, sizeof(u16)); - packet_write(&p, &lst, sizeof(u16)); - packet_write(&p, &index, sizeof(u16)); - if (!packet_write_lnt(&p, lntKey)) { return; } + packet_write(&p, &lntKeyCount, sizeof(u16)); + for (int i = 0; i < lntKeyCount; i++) { + if (!packet_write_lnt(&p, &lntKeys[i])) { return; } + } + if (!packet_write_lnt(&p, lntValue)) { return; } if (toLocalIndex == 0 || toLocalIndex >= MAX_PLAYERS) { @@ -133,18 +134,31 @@ void network_send_lua_sync_table(u8 toLocalIndex, u64 seq, u16 modRemoteIndex, u void network_receive_lua_sync_table(struct Packet* p) { u64 seq = 0; u16 modRemoteIndex = 0; - u16 lst = 0; - u16 index = 0; - struct LSTNetworkType lntKey = { 0 }; + u16 lntKeyCount = 0; + struct LSTNetworkType lntKeys[MAX_UNWOUND_LNT] = { 0 }; struct LSTNetworkType lntValue = { 0 }; packet_read(p, &seq, sizeof(u64)); packet_read(p, &modRemoteIndex, sizeof(u16)); - packet_read(p, &lst, sizeof(u16)); - packet_read(p, &index, sizeof(u16)); - if (!packet_read_lnt(p, &lntKey)) { return; } - if (!packet_read_lnt(p, &lntValue)) { return; } + packet_read(p, &lntKeyCount, sizeof(u16)); + for (int i = 0; i < lntKeyCount; i++) { + if (!packet_read_lnt(p, &lntKeys[i])) { goto cleanup; } + } - smlua_set_sync_table_field_from_network(seq, modRemoteIndex, lst, index, &lntKey, &lntValue); + if (!packet_read_lnt(p, &lntValue)) { goto cleanup; } + + smlua_set_sync_table_field_from_network(seq, modRemoteIndex, lntKeyCount, lntKeys, &lntValue); + +cleanup: + for (int i = 0; i < lntKeyCount; i++) { + if (lntKeys[i].type != LST_NETWORK_TYPE_STRING) { continue; } + if (lntKeys[i].value.string == NULL) { continue; } + free(lntKeys[i].value.string); + lntKeys[i].value.string = NULL; + } + if (lntValue.type == LST_NETWORK_TYPE_STRING && lntValue.value.string != NULL) { + free(lntValue.value.string); + lntValue.value.string = NULL; + } }