From e9d3bf49da92386274a45c71bc80b9021453ef20 Mon Sep 17 00:00:00 2001 From: MysterD Date: Sun, 30 Jan 2022 23:11:33 -0800 Subject: [PATCH] Initial foundation for lua networking --- autogen/lua_constants/constants.lua | 22 +- build-windows-visual-studio/sm64ex.vcxproj | 2 + .../sm64ex.vcxproj.filters | 6 + developer/network.sh | 4 +- docs/lua/constants.md | 6 + src/pc/lua/smlua.c | 8 +- src/pc/lua/smlua.h | 9 + src/pc/lua/smlua_cobject.c | 4 + src/pc/lua/smlua_constants_autogen.c | 20 +- src/pc/lua/smlua_sync_table.c | 258 ++++++++++++++++++ src/pc/lua/smlua_sync_table.h | 16 ++ src/pc/lua/smlua_utils.c | 2 +- src/pc/mod_list.c | 7 +- src/pc/network/packets/packet.c | 2 + src/pc/network/packets/packet.h | 16 ++ .../network/packets/packet_lua_sync_table.c | 79 ++++++ 16 files changed, 450 insertions(+), 11 deletions(-) create mode 100644 src/pc/lua/smlua_sync_table.c create mode 100644 src/pc/lua/smlua_sync_table.h create mode 100644 src/pc/network/packets/packet_lua_sync_table.c diff --git a/autogen/lua_constants/constants.lua b/autogen/lua_constants/constants.lua index b682bd58..6a1b867a 100644 --- a/autogen/lua_constants/constants.lua +++ b/autogen/lua_constants/constants.lua @@ -9,18 +9,36 @@ 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); + return _get_field(t['_lot'], t['_pointer'], k) end, __newindex = function (t,k,v) - _set_field(t['_lot'], t['_pointer'], k, v); + _set_field(t['_lot'], t['_pointer'], k, v) end, __eq = function (a, b) return a['_pointer'] == b['_pointer'] and a['_lot'] == b['_lot'] and a['_pointer'] ~= nil and a['_lot'] ~= nil end } +_SyncTable = { + __index = function (t,k) + local _table = rawget(t, '_table') + return _table[k] + end, + __newindex = function (t,k,v) + local _table = rawget(t, '_table') + if _table[k] == v then return end + if _set_sync_table_field(t, k, v) ~= 0 then + _table[k] = v + end + end +} + function vec3f_copy(dest, src) dest.x = src.x dest.y = src.y diff --git a/build-windows-visual-studio/sm64ex.vcxproj b/build-windows-visual-studio/sm64ex.vcxproj index e78458a3..7c121a20 100644 --- a/build-windows-visual-studio/sm64ex.vcxproj +++ b/build-windows-visual-studio/sm64ex.vcxproj @@ -519,6 +519,7 @@ + @@ -975,6 +976,7 @@ + diff --git a/build-windows-visual-studio/sm64ex.vcxproj.filters b/build-windows-visual-studio/sm64ex.vcxproj.filters index 8cd9c3c9..c16d0da1 100644 --- a/build-windows-visual-studio/sm64ex.vcxproj.filters +++ b/build-windows-visual-studio/sm64ex.vcxproj.filters @@ -4866,6 +4866,9 @@ Source Files\src\pc\lua + + Source Files\src\pc\lua + @@ -6013,5 +6016,8 @@ Source Files\src\pc\lua + + Source Files\src\pc\lua + \ No newline at end of file diff --git a/developer/network.sh b/developer/network.sh index b274aefe..259bb615 100644 --- a/developer/network.sh +++ b/developer/network.sh @@ -19,12 +19,12 @@ fi # no debug, direct $FILE --server 27015 --configfile sm64config_server.txt & -sleep 7 +sleep 5 $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 & +#$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 diff --git a/docs/lua/constants.md b/docs/lua/constants.md index e91312b9..394b8e6b 100644 --- a/docs/lua/constants.md +++ b/docs/lua/constants.md @@ -619,6 +619,12 @@ - HOOK_BEFORE_PHYS_STEP - HOOK_MAX +
+ +- LST_GLOBAL +- LST_PLAYER +- LST_MAX + [:arrow_up_small:](#)
diff --git a/src/pc/lua/smlua.c b/src/pc/lua/smlua.c index c04c11ed..69bc73ed 100644 --- a/src/pc/lua/smlua.c +++ b/src/pc/lua/smlua.c @@ -21,7 +21,7 @@ static void smlua_exec_str(char* str) { lua_pop(L, lua_gettop(L)); } -static void smlua_load_script(char* path) { +static void smlua_load_script(char* path, u16 remoteIndex) { lua_State* L = gLuaState; if (luaL_loadfile(L, path) != LUA_OK) { LOG_LUA("Failed to load lua script '%s'.", path); @@ -42,6 +42,9 @@ static void smlua_load_script(char* path) { lua_getfield(L, LUA_REGISTRYINDEX, path); lua_setupvalue(L, 1, 1); // set upvalue (_ENV) + // load per-file globals + smlua_sync_table_init_globals(path, remoteIndex); + // run chunks if (lua_pcall(L, 0, LUA_MULTRET, 0) != LUA_OK) { LOG_LUA("Failed to execute lua script '%s'.", path); @@ -74,6 +77,7 @@ void smlua_init(void) { smlua_bind_cobject(); smlua_bind_functions(); smlua_bind_functions_autogen(); + smlua_bind_sync_table(); extern char gSmluaConstants[]; smlua_exec_str(gSmluaConstants); @@ -87,7 +91,7 @@ void smlua_init(void) { struct ModListEntry* entry = &table->entries[i]; if (!entry->enabled) { continue; } LOG_INFO(" %s", entry->path); - smlua_load_script(entry->path); + smlua_load_script(entry->path, entry->remoteIndex); } } diff --git a/src/pc/lua/smlua.h b/src/pc/lua/smlua.h index 41a29592..13a43ad0 100644 --- a/src/pc/lua/smlua.h +++ b/src/pc/lua/smlua.h @@ -15,11 +15,20 @@ #include "smlua_functions.h" #include "smlua_functions_autogen.h" #include "smlua_hooks.h" +#include "smlua_sync_table.h" #include "pc/debuglog.h" #define LOG_LUA(...) ( _debuglog_print_log("LUA ", __FILE__), printf(__VA_ARGS__), printf("\n") ) +#ifdef DEVELOPMENT +#define LUA_STACK_CHECK_BEGIN() int __LUA_STACK_TOP = lua_gettop(gLuaState) +#define LUA_STACK_CHECK_END() if (__LUA_STACK_TOP != lua_gettop(gLuaState)) { smlua_dump_stack(); fflush(stdout); } assert(__LUA_STACK_TOP == lua_gettop(gLuaState)) +#else +#define LUA_STACK_CHECK_BEGIN() +#define LUA_STACK_CHECK_END() +#endif + extern lua_State* gLuaState; void smlua_init(void); diff --git a/src/pc/lua/smlua_cobject.c b/src/pc/lua/smlua_cobject.c index be6588d8..8430f1f4 100644 --- a/src/pc/lua/smlua_cobject.c +++ b/src/pc/lua/smlua_cobject.c @@ -48,6 +48,8 @@ bool smlua_valid_lot(u16 lot) { } static int smlua__get_field(lua_State* L) { + if (!smlua_functions_valid_param_count(L, 3)) { return 0; } + enum LuaObjectType lot = smlua_to_integer(L, 1); if (!gSmLuaConvertSuccess) { return 0; } @@ -98,6 +100,8 @@ static int smlua__get_field(lua_State* L) { } static int smlua__set_field(lua_State* L) { + if (!smlua_functions_valid_param_count(L, 4)) { return 0; } + enum LuaObjectType lot = smlua_to_integer(L, 1); if (!gSmLuaConvertSuccess) { return 0; } diff --git a/src/pc/lua/smlua_constants_autogen.c b/src/pc/lua/smlua_constants_autogen.c index 317a6762..1de08e1a 100644 --- a/src/pc/lua/smlua_constants_autogen.c +++ b/src/pc/lua/smlua_constants_autogen.c @@ -4,17 +4,33 @@ 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" +" return _get_field(t['_lot'], t['_pointer'], k)\n" " end,\n" " __newindex = function (t,k,v)\n" -" _set_field(t['_lot'], t['_pointer'], k, v);\n" +" _set_field(t['_lot'], t['_pointer'], k, v)\n" " end,\n" " __eq = function (a, b)\n" " return a['_pointer'] == b['_pointer'] and a['_lot'] == b['_lot'] and a['_pointer'] ~= nil and a['_lot'] ~= nil\n" " end\n" "}\n" +"_SyncTable = {\n" +" __index = function (t,k)\n" +" local _table = rawget(t, '_table')\n" +" return _table[k]\n" +" end,\n" +" __newindex = function (t,k,v)\n" +" local _table = rawget(t, '_table')\n" +" if _table[k] == v then return end\n" +" if _set_sync_table_field(t, k, v) ~= 0 then\n" +" _table[k] = v\n" +" end\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 new file mode 100644 index 00000000..417b0836 --- /dev/null +++ b/src/pc/lua/smlua_sync_table.c @@ -0,0 +1,258 @@ +#include "smlua.h" +#include "pc/mod_list.h" +#include "pc/network/network.h" + +static int smlua__set_sync_table_field(UNUSED lua_State* L) { + LUA_STACK_CHECK_BEGIN(); + if (!smlua_functions_valid_param_count(L, 3)) { return 0; } + + // get remoteIndex + u16 remoteIndex = smlua_get_integer_field(1, "_remoteIndex"); + if (!gSmLuaConvertSuccess) { return 0; } + + // get lst + enum LuaSyncTableType lst = smlua_get_integer_field(1, "_type"); + if (!gSmLuaConvertSuccess) { return 0; } + if (lst >= LST_MAX) { + LOG_LUA("_set_sync_table_field on invalid LST: %u", lst); + lua_pushinteger(L, 0); + return 0; + } + + // get key + const char* key = smlua_to_string(L, 2); + if (!gSmLuaConvertSuccess) { return 0; } + if (key == NULL || strlen(key) == 0 || strlen(key) > 64) { + LOG_LUA("_set_sync_table_field on invalid key: '%s'", (key == NULL) ? "" : key); + lua_pushinteger(L, 0); + return 0; + } + + // get value + union LSTNetworkUnion lUnion = { 0 }; + enum LSTNetworkType lUnionType = LST_NETWORK_TYPE_MAX; + int valueType = lua_type(L, 3); + if (valueType == LUA_TNUMBER) { + lUnion.integer = lua_tointeger(L, 3); + lUnionType = LST_NETWORK_TYPE_INTEGER; + + if (lUnion.integer == 0) { + lUnion.number = lua_tonumber(L, 3); + lUnionType = LST_NETWORK_TYPE_NUMBER; + } + } else { + LOG_LUA("_set_sync_table_field on invalid type: '%d'", valueType); + lua_pushinteger(L, 0); + return 0; + } + + // get seq table + lua_getfield(L, 1, "_seq"); + int seqT = lua_gettop(L); + + // get seq number + lua_getfield(L, -1, key); + u64 seq = lua_tointeger(L, -1); + lua_pop(L, 1); + + // set seq number + seq += MAX_PLAYERS + (MAX_PLAYERS - gNetworkPlayers[0].globalIndex); + smlua_push_number_field(seqT, (char*)key, seq); + lua_pop(L, 1); + + // get index + u16 index = smlua_get_integer_field(1, "_index"); + // TODO: translate to global index + + network_send_lua_sync_table(seq, remoteIndex, lst, index, key, lUnionType, lUnion); + + LUA_STACK_CHECK_END(); + lua_pushinteger(L, 1); + return 1; +} + +void smlua_set_sync_table_field_from_network(u64 seq, u16 remoteIndex, u16 lst, u16 index, const char* key, u16 lUnionType, union LSTNetworkUnion lUnion) { + LUA_STACK_CHECK_BEGIN(); + lua_State* L = gLuaState; + + // figure out table + struct ModTable* table = NULL; + if (gNetworkType == NT_SERVER) { + table = &gModTableLocal; + } else if (gNetworkType == NT_CLIENT) { + table = &gModTableRemote; + } else { + LOG_ERROR("Received sync table field packet with an unknown network type: %d", gNetworkType); + return; + } + + // figure out entry + struct ModListEntry* entry = NULL; + for (int i = 0; i < table->entryCount; i++) { + if (table->entries[i].remoteIndex == remoteIndex) { + entry = &table->entries[i]; + break; + } + } + if (entry == NULL) { + LOG_ERROR("Could not find mod list entry for remoteIndex: %u", remoteIndex); + return; + } + + // sanity check lst + if (lst >= LST_MAX) { + LOG_LUA("Received sync table field packet with an invalid LST: %u", lst); + return; + } + + // sanity check lUnionType + if (lUnionType >= LST_NETWORK_TYPE_MAX) { + LOG_LUA("Received sync table field packet with an invalid lUnionType: %u", lUnionType); + return; + } + + lua_getglobal(L, "_G"); // get global table + lua_getfield(L, LUA_REGISTRYINDEX, entry->path); // get the file's "global" table + + // 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, index); + lua_gettable(L, -2); + // TODO: translate to local index + break; + default: assert(false); + } + + // get seq table + lua_getfield(L, -1, "_seq"); + int seqT = lua_gettop(L); + + // get seq number + lua_getfield(L, -1, key); + u64 readSeq = lua_tointeger(L, -1); + lua_pop(L, 1); + + // validate seq + if (seq <= readSeq) { + LOG_INFO("Received outdated sync table field packet: %llu <= %llu", seq, readSeq); + lua_pop(L, 1); // pop seq table + lua_pop(L, syncTableSize); // pop sync table + lua_pop(L, 1); // pop file's "global" table + lua_pop(L, 1); // pop global table + return; + } + + // set seq number + smlua_push_number_field(seqT, (char*)key, seq); + lua_pop(L, 1); // pop seq table + + // get internal table + lua_pushstring(L, "_table"); + lua_rawget(L, -2); + int t = lua_gettop(L); + + // set key/value + switch (lUnionType) { + case LST_NETWORK_TYPE_INTEGER: + lua_pushstring(L, key); + lua_pushinteger(L, lUnion.integer); + lua_rawset(L, t); + break; + case LST_NETWORK_TYPE_NUMBER: + lua_pushstring(L, key); + lua_pushnumber(L, lUnion.number); + lua_rawset(L, t); + break; + default: SOFT_ASSERT(false); + } + + lua_pop(L, 1); // pop internal table + lua_pop(L, syncTableSize); // pop sync table + lua_pop(L, 1); // pop file's "global" table + lua_pop(L, 1); // pop global table + LUA_STACK_CHECK_END(); +} + +static void smlua_exec_str(char* str) { + LUA_STACK_CHECK_BEGIN(); + lua_State* L = gLuaState; + if (luaL_dostring(L, str) != LUA_OK) { + LOG_LUA("Failed to load lua string."); + puts(smlua_to_string(L, lua_gettop(L))); + } + LUA_STACK_CHECK_END(); +} + +void smlua_sync_table_init_globals(char* path, u16 remoteIndex) { + LUA_STACK_CHECK_BEGIN(); + lua_State* L = gLuaState; + + lua_getfield(L, LUA_REGISTRYINDEX, path); + int base = lua_gettop(L); + { + lua_newtable(L); + int t = lua_gettop(L); + + smlua_push_integer_field(t, "_remoteIndex", remoteIndex); + smlua_push_integer_field(t, "_type", LST_GLOBAL); + smlua_push_integer_field(t, "_index", 0); + + lua_newtable(L); + lua_setfield(L, t, "_seq"); + + lua_newtable(L); + lua_setfield(L, t, "_table"); + + lua_pushglobaltable(L); + lua_getfield(L, -1, "_SyncTable"); + lua_setmetatable(L, -3); + lua_pop(L, 1); // pop global table + 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", remoteIndex); + smlua_push_integer_field(t, "_type", LST_PLAYER); + smlua_push_integer_field(t, "_index", i); + + lua_newtable(L); + lua_setfield(L, t, "_seq"); + + lua_newtable(L); + lua_setfield(L, t, "_table"); + + lua_pushglobaltable(L); + lua_getfield(L, -1, "_SyncTable"); + lua_setmetatable(L, -3); + lua_pop(L, 1); // pop global table + + lua_settable(L, playerTop); + } + lua_setfield(L, base, "gPlayerSyncTable"); + } + lua_pop(L, 1); // pop file's "global" table + + LUA_STACK_CHECK_END(); +} + +void smlua_bind_sync_table(void) { + LUA_STACK_CHECK_BEGIN(); + lua_State* L = gLuaState; + smlua_bind_function(L, "_set_sync_table_field", smlua__set_sync_table_field); + LUA_STACK_CHECK_END(); +} diff --git a/src/pc/lua/smlua_sync_table.h b/src/pc/lua/smlua_sync_table.h new file mode 100644 index 00000000..e0bb56cc --- /dev/null +++ b/src/pc/lua/smlua_sync_table.h @@ -0,0 +1,16 @@ +#ifndef SMLUA_SYNC_TABLE_H +#define SMLUA_SYNC_TABLE_H + +enum LuaSyncTableType { + LST_GLOBAL, + LST_PLAYER, + LST_MAX, +}; + +union LSTNetworkUnion; + +void smlua_set_sync_table_field_from_network(u64 seq, u16 remoteIndex, u16 lst, u16 index, const char* key, u16 lUnionType, union LSTNetworkUnion lUnion); +void smlua_sync_table_init_globals(char* path, u16 remoteIndex); +void smlua_bind_sync_table(void); + +#endif \ No newline at end of file diff --git a/src/pc/lua/smlua_utils.c b/src/pc/lua/smlua_utils.c index be346abd..bfebe2ea 100644 --- a/src/pc/lua/smlua_utils.c +++ b/src/pc/lua/smlua_utils.c @@ -236,7 +236,7 @@ void smlua_dump_table(int index) { lua_pushnil(L); // first key while (lua_next(L, index) != 0) { // uses 'key' (at index -2) and 'value' (at index -1) - if (lua_type(L, index) == LUA_TSTRING) { + if (lua_type(L, -2) == LUA_TSTRING) { printf("%s - %s\n", lua_tostring(L, -2), lua_typename(L, lua_type(L, -1))); diff --git a/src/pc/mod_list.c b/src/pc/mod_list.c index 353db803..43139814 100644 --- a/src/pc/mod_list.c +++ b/src/pc/mod_list.c @@ -149,6 +149,7 @@ static void mod_list_add_local(u16 index, const char* path, char* name) { table->totalSize += entry->size; fseek(entry->fp, 0, SEEK_SET); + entry->remoteIndex = index; entry->complete = true; entry->enabled = false; entry->selectable = true; @@ -263,14 +264,15 @@ static void mod_list_load_local(const char* path) { count++; } + u16 totalCount = table->entryCount; u16 index = 0; if (table->entries == NULL) { if (count == 0) { closedir(d); return; } mod_list_alloc(table, count); } else { index = table->entryCount; - table->entryCount += count; - table->entries = (struct ModListEntry*)realloc(table->entries, table->entryCount * sizeof(struct ModListEntry)); + totalCount += count; + table->entries = (struct ModListEntry*)realloc(table->entries, totalCount * sizeof(struct ModListEntry)); } rewinddir(d); @@ -281,6 +283,7 @@ static void mod_list_load_local(const char* path) { if (mod_list_contains(table, dir->d_name)) { continue; } LOG_INFO(" %s", dir->d_name); mod_list_add_local(index++, path, dir->d_name); + if (index > table->entryCount) { table->entryCount = index; } } closedir(d); diff --git a/src/pc/network/packets/packet.c b/src/pc/network/packets/packet.c index b409177f..b897307e 100644 --- a/src/pc/network/packets/packet.c +++ b/src/pc/network/packets/packet.c @@ -83,6 +83,8 @@ void packet_process(struct Packet* p) { case PACKET_DOWNLOAD_REQUEST: network_receive_download_request(p); break; case PACKET_DOWNLOAD: network_receive_download(p); break; + case PACKET_LUA_SYNC_TABLE: network_receive_lua_sync_table(p); break; + // custom case PACKET_CUSTOM: network_receive_custom(p); break; default: LOG_ERROR("received unknown packet: %d", p->buffer[0]); diff --git a/src/pc/network/packets/packet.h b/src/pc/network/packets/packet.h index 84724c41..4d778051 100644 --- a/src/pc/network/packets/packet.h +++ b/src/pc/network/packets/packet.h @@ -59,6 +59,8 @@ enum PacketType { PACKET_DOWNLOAD_REQUEST, PACKET_DOWNLOAD, + PACKET_LUA_SYNC_TABLE, + /// PACKET_CUSTOM = 255, }; @@ -99,6 +101,17 @@ enum KickReasonType { EKT_FULL_PARTY, }; +union LSTNetworkUnion { + long long integer; + double number; +}; + +enum LSTNetworkType { + LST_NETWORK_TYPE_INTEGER, + LST_NETWORK_TYPE_NUMBER, + LST_NETWORK_TYPE_MAX +}; + // packet.c void packet_process(struct Packet* p); void packet_receive(struct Packet* packet); @@ -301,5 +314,8 @@ void network_receive_download_request(struct Packet* p); void network_send_download(u16 clientIndex, u16 serverIndex, u64 offset); void network_receive_download(struct Packet* p); +// packet_lua_sync_table.c +void network_send_lua_sync_table(u64 seq, u16 remoteIndex, u16 lst, u16 index, const char* key, enum LSTNetworkType lUnionType, union LSTNetworkUnion lUnion); +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 new file mode 100644 index 00000000..c1c13340 --- /dev/null +++ b/src/pc/network/packets/packet_lua_sync_table.c @@ -0,0 +1,79 @@ +#include +#include "../network.h" +#include "pc/lua/smlua.h" +#include "pc/debuglog.h" + +void network_send_lua_sync_table(u64 seq, u16 remoteIndex, u16 lst, u16 index, const char* key, enum LSTNetworkType lUnionType, union LSTNetworkUnion lUnion) { + u16 keyLength = strlen(key); + + struct Packet p = { 0 }; + packet_init(&p, PACKET_LUA_SYNC_TABLE, true, PLMT_NONE); + packet_write(&p, &seq, sizeof(u64)); + packet_write(&p, &remoteIndex, sizeof(u16)); + packet_write(&p, &lst, sizeof(u16)); + packet_write(&p, &index, sizeof(u16)); + + packet_write(&p, &keyLength, sizeof(u16)); + packet_write(&p, (char*)key, keyLength * sizeof(u8)); + + packet_write(&p, &lUnionType, sizeof(u16)); + switch (lUnionType) { + case LST_NETWORK_TYPE_NUMBER: { + f64 number = lUnion.number; + packet_write(&p, &number, sizeof(f64)); + //LOG_INFO("sent lua_sync_table: %llu, %u, %u, %s, %u, %f", seq, remoteIndex, lst, key, lUnionType, number); + break; + } + case LST_NETWORK_TYPE_INTEGER: { + s64 integer = lUnion.integer; + packet_write(&p, &integer, sizeof(s64)); + //LOG_INFO("sent lua_sync_table: %llu, %u, %u, %s, %u, %llu", seq, remoteIndex, lst, key, lUnionType, integer); + break; + } + default: + LOG_ERROR("attempted to send lua sync table with invalid type: %d", lUnionType); + return; + } + + network_send(&p); +} + +void network_receive_lua_sync_table(struct Packet* p) { + u64 seq = 0; + u16 remoteIndex = 0; + u16 lst = 0; + u16 index = 0; + u16 keyLength = 0; + char key[65] = { 0 }; + u16 lUnionType = 0; + union LSTNetworkUnion lUnion; + + packet_read(p, &seq, sizeof(u64)); + packet_read(p, &remoteIndex, sizeof(u16)); + packet_read(p, &lst, sizeof(u16)); + packet_read(p, &index, sizeof(u16)); + + packet_read(p, &keyLength, sizeof(u16)); + if (keyLength > 64) { + LOG_ERROR("received lua sync table with invalid key length: %d", keyLength); + return; + } + packet_read(p, &key, keyLength * sizeof(u8)); + + packet_read(p, &lUnionType, sizeof(u16)); + switch (lUnionType) { + case LST_NETWORK_TYPE_NUMBER: + packet_read(p, &lUnion.number, sizeof(f64)); + //LOG_INFO("rx lua_sync_table: %llu, %u, %u, %s, %u, %f", seq, remoteIndex, lst, key, lUnionType, lUnion.number); + break; + case LST_NETWORK_TYPE_INTEGER: + packet_read(p, &lUnion.integer, sizeof(s64)); + //LOG_INFO("rx lua_sync_table: %llu, %u, %u, %s, %u, %llu", seq, remoteIndex, lst, key, lUnionType, lUnion.integer); + break; + default: + LOG_ERROR("received lua sync table with invalid type: %d", lUnionType); + return; + } + + smlua_set_sync_table_field_from_network(seq, remoteIndex, lst, index, key, lUnionType, lUnion); +}