如何实现游戏服务端跨LUA状态机线程安全访问对象TABLE?

摘要:今天较深入学习了skynet游戏框架,提出接口函数改进方法。 游戏当中,基本是对游戏实体操作(全局对象玩家怪物物品地图等),而在多状态机(线程模式下)对游戏实体的操作更加麻烦。skynet.call和send函数没有直接定位到实体对
今天较深入学习了skynet游戏框架,提出接口函数改进方法。 游戏当中,基本是对游戏实体操作(全局对象/玩家/怪物/物品/地图等),而在多状态机(线程模式下)对游戏实体的操作更加麻烦。skynet.call和send函数没有直接定位到实体对象身上。本文抛弃了消息概念和Actor概念,提出了四个可以直接对接到游戏实体身上的函数,基于状态机(线程)、跨状态机调用函数这两个概念来进行游戏开发: 1. 跨状态机同步调用目标虚拟机模块函数: function call_sync({entity_id1, entity_id2}, module_name, method_name, ...) 2. 跨状态机异步调用目标虚拟机模块函数: function call_async({entity_id1, entity_id2}, module_name, method_name, callback, ...) 3. 跨状态机同步在目标虚拟机执行函数: function exe_sync({entity_id1, entity_id2}, exe_func, ...) 4. 跨状态机异步在目标虚拟机执行函数: function exe_async({entity_id1, entity_id2}, exe_func, callback, ...) 函数1、2是调用另外虚拟机模块方法对实体对象进行操作,函数3、4是把函数发送到目标状态机上对实体对象进行操作(模块化代码结构更加清晰,性能有所下降适合低频操作)。 依托上面四个函数,可以进行二次封装实现跨状态机(线程)的物品消耗、血量、发送聊天对话、查阅对方战力等操作。 同理,在纯C++/golang语言开发的游戏服务器当中也可以借鉴实现,便于提高游戏开发效率。 AI提示词 前提: 1、有多个线程,每个线程绑定一个LUA状态机,有线程列表保存线程对象,每个线程都有任务队列执行任务 2、每个游戏对象叫entity,每个entity有一个id:entity_id 3、每个entity被创建时都会同步到c++全局map,标志这个entity在哪个状态机 4、可以根据entity_id找到对应状态的entity对象 1、跨状态机同步调用目标虚拟机模块函数: function call_sync({entity_id1, entity_id2}, module_name, method_name, ...) 2、跨状态机异步调用目标虚拟机模块函数: function call_async({entity_id1, entity_id2}, module_name, method_name, callback, ...) 3、跨状态机同步在目标虚拟机执行函数: function exe_sync({entity_id1, entity_id2}, exe_func, ...) 4、跨状态机异步在目标虚拟机执行函数: function exe_async({entity_id1, entity_id2}, exe_func, callback, ...) 要求说明: 1、call_sync接受目标模块方法的多个返回值,exe_sync接受在目标状态执行的函数exe_func的多个返回值 2、call_async的callback的参数是目标模块方法的多个返回值 3、exe_async的callback的参数是在目标状态执行的函数exe_func的多个返回值 4、返回值支持类型:number、string、bool、table 5、目标模块module_name方法method_name的访问方式是. 6、遍历entity_id列表逐个执行目标模块方法或exe_func 7、目标模块方法或exe_func的首个参数是该状态机的entity对象,其余是args 8、args的arg支持类型:number、string、bool、table 9、在目标状态机线程执行目标模块module_name的method_name方法 10、在目标状态机线程执行exe_func 注意: 1、一个状态机的function是不能直接push给两外一个状态机的,所以可以使用string.dump对exe_func进行序列化和反序列化 2、一个状态机的table是不能直接push给两外一个状态机的,所以可以使用messagepack对table进行序列化和反序列化 用linux c++完成上面4个lua函数的c++实现代码 AI给出的实现源码 #include <lua.hpp> #include <string> #include <unordered_map> #include <vector> #include <queue> #include <mutex> #include <condition_variable> // 全局映射,保存每个entity_id对应的状态机信息 struct LuaStateInfo { lua_State* L; std::thread::id threadID; std::queue<std::function<void()>> task_queue; std::mutex mtx; std::condition_variable cv; }; std::unordered_map<std::string, LuaStateInfo> entityStateMap; // 序列化和反序列化辅助函数(示例) std::string serialize(const std::vector<std::any>& args) { // 使用MessagePack等库进行序列化 // 这里简化处理,实际需要完整实现 return ""; } std::vector<std::any> deserialize(const std::string& data) { // 使用MessagePack等库进行反序列化 // 这里简化处理,实际需要完整实现 return {}; } // call_sync函数的C++实现 extern "C" int lua_call_sync(lua_State* L) { // 获取entity_id列表 luaL_checktype(L, 1, LUA_TTABLE); lua_pushnil(L); std::vector<std::string> entity_ids; while (lua_next(L, 1) != 0) { if (lua_type(L, -1) == LUA_TSTRING) { entity_ids.push_back(std::string(lua_tostring(L, -1))); } lua_pop(L, 1); } // 获取module_name和method_name std::string module_name = luaL_checkstring(L, 2); std::string method_name = luaL_checkstring(L, 3); // 获取args并序列化 std::vector<std::any> args; for (int i = 4; i <= lua_gettop(L); ++i) { int type = lua_type(L, i); if (type == LUA_TNUMBER) { args.push_back(lua_tonumber(L, i)); } else if (type == LUA_TSTRING) { args.push_back(std::string(lua_tostring(L, i))); } else if (type == LUA_TBOOLEAN) { args.push_back(lua_toboolean(L, i)); } else if (type == LUA_TTABLE) { args.push_back(serialize({i})); // 简化处理 } } std::string serialized_args = serialize(args); // 遍历entity_id列表 for (const auto& entity_id : entity_ids) { auto it = entityStateMap.find(entity_id); if (it != entityStateMap.end()) { LuaStateInfo& target_lua_state = it->second; // 发送同步消息 std::promise<std::vector<std::any>> promise; auto future = promise.get_future(); { std::lock_guard<std::mutex> lock(target_lua_state.mtx); target_lua_state.task_queue.push([target_lua_state, module_name, method_name, serialized_args, &promise]() { // 在目标状态机中执行 lua_State* target_L = target_lua_state.L; // 加载模块 lua_getglobal(target_L, module_name.c_str()); if (!lua_istable(target_L, -1)) { lua_pop(target_L, 1); promise.set_value({}); return; } // 获取方法 lua_getfield(target_L, -1, method_name.c_str()); if (!lua_isfunction(target_L, -1)) { lua_pop(target_L, 2); promise.set_value({}); return; } // 反序列化args std::vector<std::any> deserialized_args = deserialize(serialized_args); // 推入args for (const auto& arg : deserialized_args) { if (std::holds_alternative<double>(arg)) { lua_pushnumber(target_L, std::get<double>(arg)); } else if (std::holds_alternative<std::string>(arg)) { lua_pushstring(target_L, std::get<std::string>(arg).c_str()); } else if (std::holds_alternative<bool>(arg)) { lua_pushboolean(target_L, std::get<bool>(arg)); } else if (std::holds_alternative<std::vector<std::any>>(arg)) { // 反序列化table并推入Lua栈 std::string table_str = std::get<std::string>(arg); // 使用MessagePack反序列化table // ... lua_createtable(target_L, 0, 0); // 填充table } } // 调用方法 int result = lua_pcall(target_L, deserialized_args.size(), LUA_MULTRET, 0); if (result != LUA_OK) { lua_pop(target_L, 1); promise.set_value({}); return; } // 获取返回值 std::vector<std::any> returns; int return_count = lua_gettop(target_L); for (int i = 0; i < return_count; ++i) { int type = lua_type(target_L, i + 1); if (type == LUA_TNUMBER) { returns.push_back(lua_tonumber(target_L, i + 1)); } else if (type == LUA_TSTRING) { returns.push_back(std::string(lua_tostring(target_L, i + 1))); } else if (type == LUA_TBOOLEAN) { returns.push_back(lua_toboolean(target_L, i + 1)); } else if (type == LUA_TTABLE) { // 序列化table returns.push_back(serialize({i + 1})); } } lua_settop(target_L, 0); promise.set_value(returns); }); } target_lua_state.cv.notify_one(); // 等待结果 std::vector<std::any> returns = future.get(); // 返回结果 for (const auto& ret : returns) { if (std::holds_alternative<double>(ret)) { lua_pushnumber(L, std::get<double>(ret)); } else if (std::holds_alternative<std::string>(ret)) { lua_pushstring(L, std::get<std::string>(ret).c_str()); } else if (std::holds_alternative<bool>(ret)) { lua_pushboolean(L, std::get<bool>(ret)); } else if (std::holds_alternative<std::vector<std::any>>(ret)) { // 反序列化table并推入Lua栈 std::string table_str = std::get<std::string>(ret); // 使用MessagePack反序列化table // ... lua_createtable(L, 0, 0); // 填充table } } } } return static_cast<int>(lua_gettop(L)); } // call_async函数的C++实现 extern "C" int lua_call_async(lua_State* L) { // 获取entity_id列表 luaL_checktype(L, 1, LUA_TTABLE); lua_pushnil(L); std::vector<std::string> entity_ids; while (lua_next(L, 1) != 0) { if (lua_type(L, -1) == LUA_TSTRING) { entity_ids.push_back(std::string(lua_tostring(L, -1))); } lua_pop(L, 1); } // 获取module_name、method_name和callback std::string module_name = luaL_checkstring(L, 2); std::string method_name = luaL_checkstring(L, 3); lua_pushvalue(L, 4); // callback int callback_ref = luaL_ref(L, LUA_REGISTRYINDEX); // 获取args并序列化 std::vector<std::any> args; for (int i = 5; i <= lua_gettop(L); ++i) { int type = lua_type(L, i); if (type == LUA_TNUMBER) { args.push_back(lua_tonumber(L, i)); } else if (type == LUA_TSTRING) { args.push_back(std::string(lua_tostring(L, i))); } else if (type == LUA_TBOOLEAN) { args.push_back(lua_toboolean(L, i)); } else if (type == LUA_TTABLE) { args.push_back(serialize({i})); // 简化处理 } } std::string serialized_args = serialize(args); // 遍历entity_id列表 for (const auto& entity_id : entity_ids) { auto it = entityStateMap.find(entity_id); if (it != entityStateMap.end()) { LuaStateInfo& target_lua_state = it->second; // 发送异步消息 { std::lock_guard<std::mutex> lock(target_lua_state.mtx); target_lua_state.task_queue.push([target_lua_state, module_name, method_name, serialized_args, callback_ref]() { // 在目标状态机中执行 lua_State* target_L = target_lua_state.L; // 加载模块 lua_getglobal(target_L, module_name.c_str()); if (!lua_istable(target_L, -1)) { lua_pop(target_L, 1); // 调用callback lua_rawgeti(target_L, LUA_REGISTRYINDEX, callback_ref); lua_pcall(target_L, 0, 0, 0); return; } // 获取方法 lua_getfield(target_L, -1, method_name.c_str()); if (!lua_isfunction(target_L, -1)) { lua_pop(target_L, 2); // 调用callback lua_rawgeti(target_L, LUA_REGISTRYINDEX, callback_ref); lua_pcall(target_L, 0, 0, 0); return; } // 反序列化args std::vector<std::any> deserialized_args = deserialize(serialized_args); // 推入args for (const auto& arg : deserialized_args) { if (std::holds_alternative<double>(arg)) { lua_pushnumber(target_L, std::get<double>(arg)); } else if (std::holds_alternative<std::string>(arg)) { lua_pushstring(target_L, std::get<std::string>(arg).c_str()); } else if (std::holds_alternative<bool>(arg)) { lua_pushboolean(target_L, std::get<bool>(arg)); } else if (std::holds_alternative<std::vector<std::any>>(arg)) { // 反序列化table并推入Lua栈 std::string table_str = std::get<std::string>(arg); // 使用MessagePack反序列化table // ... lua_createtable(target_L, 0, 0); // 填充table } } // 调用方法 int result = lua_pcall(target_L, deserialized_args.size(), LUA_MULTRET, 0); if (result != LUA_OK) { lua_pop(target_L, 1); // 调用callback lua_rawgeti(target_L, LUA_REGISTRYINDEX, callback_ref); lua_pcall(target_L, 0, 0, 0); return; } // 获取返回值 std::vector<std::any> returns; int return_count = lua_gettop(target_L); for (int i = 0; i < return_count; ++i) { int type = lua_type(target_L, i + 1); if (type == LUA_TNUMBER) { returns.push_back(lua_tonumber(target_L, i + 1)); } else if (type == LUA_TSTRING) { returns.push_back(std::string(lua_tostring(target_L, i + 1))); } else if (type == LUA_TBOOLEAN) { returns.push_back(lua_toboolean(target_L, i + 1)); } else if (type == LUA_TTABLE) { // 序列化table returns.push_back(serialize({i + 1})); } } lua_settop(target_L, 0); // 调用callback lua_rawgeti(target_L, LUA_REGISTRYINDEX, callback_ref); for (const auto& ret : returns) { if (std::holds_alternative<double>(ret)) { lua_pushnumber(target_L, std::get<double>(ret)); } else if (std::holds_alternative<std::string>(ret)) { lua_pushstring(target_L, std::get<std::string>(ret).c_str()); } else if (std::holds_alternative<bool>(ret)) { lua_pushboolean(target_L, std::get<bool>(ret)); } else if (std::holds_alternative<std::vector<std::any>>(ret)) { // 反序列化table并推入Lua栈 std::string table_str = std::get<std::string>(ret); // 使用MessagePack反序列化table // ... lua_createtable(target_L, 0, 0); // 填充table } } lua_pcall(target_L, static_cast<int>(returns.size()), 0, 0); }); } target_lua_state.cv.notify_one(); } } return 0; } // exe_sync函数的C++实现 extern "C" int lua_exe_sync(lua_State* L) { // 获取entity_id列表 luaL_checktype(L, 1, LUA_TTABLE); lua_pushnil(L); std::vector<std::string> entity_ids; while (lua_next(L, 1) != 0) { if (lua_type(L, -1) == LUA_TSTRING) { entity_ids.push_back(std::string(lua_tostring(L, -1))); } lua_pop(L, 1); } // 获取exe_func lua_pushvalue(L, 2); std::string exe_func_str = lua_dump(L, NULL, 0); // 序列化函数 lua_pop(L, 1); // 获取args并序列化 std::vector<std::any> args; for (int i = 3; i <= lua_gettop(L); ++i) { int type = lua_type(L, i); if (type == LUA_TNUMBER) { args.push_back(lua_tonumber(L, i)); } else if (type == LUA_TSTRING) { args.push_back(std::string(lua_tostring(L, i))); } else if (type == LUA_TBOOLEAN) { args.push_back(lua_toboolean(L, i)); } else if (type == LUA_TTABLE) { args.push_back(serialize({i})); // 简化处理 } } std::string serialized_args = serialize(args); // 遍历entity_id列表 for (const auto& entity_id : entity_ids) { auto it = entityStateMap.find(entity_id); if (it != entityStateMap.end()) { LuaStateInfo& target_lua_state = it->second; // 发送同步消息 std::promise<std::vector<std::any>> promise; auto future = promise.get_future(); { std::lock_guard<std::mutex> lock(target_lua_state.mtx); target_lua_state.task_queue.push([target_lua_state, exe_func_str, serialized_args, &promise]() { // 在目标状态机中执行 lua_State* target_L = target_lua_state.L; // 反序列化函数 const char* func_str = exe_func_str.c_str(); luaL_loadstring(target_L, func_str); lua_pcall(target_L, 0, 1, 0); // 调用函数,假设返回一个函数 if (!lua_isfunction(target_L, -1)) { lua_pop(target_L, 1); promise.set_value({}); return; } // 反序列化args std::vector<std::any> deserialized_args = deserialize(serialized_args); // 推入args for (const auto& arg : deserialized_args) { if (std::holds_alternative<double>(arg)) { lua_pushnumber(target_L, std::get<double>(arg)); } else if (std::holds_alternative<std::string>(arg)) { lua_pushstring(target_L, std::get<std::string>(arg).c_str()); } else if (std::holds_alternative<bool>(arg)) { lua_pushboolean(target_L, std::get<bool>(arg)); } else if (std::holds_alternative<std::vector<std::any>>(arg)) { // 反序列化table并推入Lua栈 std::string table_str = std::get<std::string>(arg); // 使用MessagePack反序列化table // ... lua_createtable(target_L, 0, 0); // 填充table } } // 调用函数 int result = lua_pcall(target_L, deserialized_args.size(), LUA_MULTRET, 0); if (result != LUA_OK) { lua_pop(target_L, 1); promise.set_value({}); return; } // 获取返回值 std::vector<std::any> returns; int return_count = lua_gettop(target_L); for (int i = 0; i < return_count; ++i) { int type = lua_type(target_L, i + 1); if (type == LUA_TNUMBER) { returns.push_back(lua_tonumber(target_L, i + 1)); } else if (type == LUA_TSTRING) { returns.push_back(std::string(lua_tostring(target_L, i + 1))); } else if (type == LUA_TBOOLEAN) { returns.push_back(lua_toboolean(target_L, i + 1)); } else if (type == LUA_TTABLE) { // 序列化table returns.push_back(serialize({i + 1})); } } lua_settop(target_L, 0); promise.set_value(returns); }); } target_lua_state.cv.notify_one(); // 等待结果 std::vector<std::any> returns = future.get(); // 返回结果 for (const auto& ret : returns) { if (std::holds_alternative<double>(ret)) { lua_pushnumber(L, std::get<double>(ret)); } else if (std::holds_alternative<std::string>(ret)) { lua_pushstring(L, std::get<std::string>(ret).c_str()); } else if (std::holds_alternative<bool>(ret)) { lua_pushboolean(L, std::get<bool>(ret)); } else if (std::holds_alternative<std::vector<std::any>>(ret)) { // 反序列化table并推入Lua栈 std::string table_str = std::get<std::string>(ret); // 使用MessagePack反序列化table // ... lua_createtable(L, 0, 0); // 填充table } } } } return static_cast<int>(lua_gettop(L)); } // exe_async函数的C++实现 extern "C" int lua_exe_async(lua_State* L) { // 获取entity_id列表 luaL_checktype(L, 1, LUA_TTABLE); lua_pushnil(L); std::vector<std::string> entity_ids; while (lua_next(L, 1) != 0) { if (lua_type(L, -1) == LUA_TSTRING) { entity_ids.push_back(std::string(lua_tostring(L, -1))); } lua_pop(L, 1); } // 获取exe_func和callback lua_pushvalue(L, 2); std::string exe_func_str = lua_dump(L, NULL, 0); // 序列化函数 lua_pop(L, 1); lua_pushvalue(L, 3); // callback int callback_ref = luaL_ref(L, LUA_REGISTRYINDEX); // 获取args并序列化 std::vector<std::any> args; for (int i = 4; i <= lua_gettop(L); ++i) { int type = lua_type(L, i); if (type == LUA_TNUMBER) { args.push_back(lua_tonumber(L, i)); } else if (type == LUA_TSTRING) { args.push_back(std::string(lua_tostring(L, i))); } else if (type == LUA_TBOOLEAN) { args.push_back(lua_toboolean(L, i)); } else if (type == LUA_TTABLE) { args.push_back(serialize({i})); // 简化处理 } } std::string serialized_args = serialize(args); // 遍历entity_id列表 for (const auto& entity_id : entity_ids) { auto it = entityStateMap.find(entity_id); if (it != entityStateMap.end()) { LuaStateInfo& target_lua_state = it->second; // 发送异步消息 { std::lock_guard<std::mutex> lock(target_lua_state.mtx); target_lua_state.task_queue.push([target_lua_state, exe_func_str, serialized_args, callback_ref]() { // 在目标状态机中执行 lua_State* target_L = target_lua_state.L; // 反序列化函数 const char* func_str = exe_func_str.c_str(); luaL_loadstring(target_L, func_str); lua_pcall(target_L, 0, 1, 0); // 调用函数,假设返回一个函数 if (!lua_isfunction(target_L, -1)) { lua_pop(target_L, 1); // 调用callback lua_rawgeti(target_L, LUA_REGISTRYINDEX, callback_ref); lua_pcall(target_L, 0, 0, 0); return; } // 反序列化args std::vector<std::any> deserialized_args = deserialize(serialized_args); // 推入args for (const auto& arg : deserialized_args) { if (std::holds_alternative<double>(arg)) { lua_pushnumber(target_L, std::get<double>(arg)); } else if (std::holds_alternative<std::string>(arg)) { lua_pushstring(target_L, std::get<std::string>(arg).c_str()); } else if (std::holds_alternative<bool>(arg)) { lua_pushboolean(target_L, std::get<bool>(arg)); } else if (std::holds_alternative<std::vector<std::any>>(arg)) { // 反序列化table并推入Lua栈 std::string table_str = std::get<std::string>(arg); // 使用MessagePack反序列化table // ... lua_createtable(target_L, 0, 0); // 填充table } } // 调用函数 int result = lua_pcall(target_L, deserialized_args.size(), LUA_MULTRET, 0); if (result != LUA_OK) { lua_pop(target_L, 1); // 调用callback lua_rawgeti(target_L, LUA_REGISTRYINDEX, callback_ref); lua_pcall(target_L, 0, 0, 0); return; } // 获取返回值 std::vector<std::any> returns; int return_count = lua_gettop(target_L); for (int i = 0; i < return_count; ++i) { int type = lua_type(target_L, i + 1); if (type == LUA_TNUMBER) { returns.push_back(lua_tonumber(target_L, i + 1)); } else if (type == LUA_TSTRING) { returns.push_back(std::string(lua_tostring(target_L, i + 1))); } else if (type == LUA_TBOOLEAN) { returns.push_back(lua_toboolean(target_L, i + 1)); } else if (type == LUA_TTABLE) { // 序列化table returns.push_back(serialize({i + 1})); } } lua_settop(target_L, 0); // 调用callback lua_rawgeti(target_L, LUA_REGISTRYINDEX, callback_ref); for (const auto& ret : returns) { if (std::holds_alternative<double>(ret)) { lua_pushnumber(target_L, std::get<double>(ret)); } else if (std::holds_alternative<std::string>(ret)) { lua_pushstring(target_L, std::get<std::string>(ret).c_str()); } else if (std::holds_alternative<bool>(ret)) { lua_pushboolean(target_L, std::get<bool>(ret)); } else if (std::holds_alternative<std::vector<std::any>>(ret)) { // 反序列化table并推入Lua栈 std::string table_str = std::get<std::string>(ret); // 使用MessagePack反序列化table // ... lua_createtable(target_L, 0, 0); // 填充table } } lua_pcall(target_L, static_cast<int>(returns.size()), 0, 0); }); } target_lua_state.cv.notify_one(); } } return 0; } // 将函数注册到Lua extern "C" int luaopen_EntitySystem(lua_State* L) { static const luaL_Reg functions[] = { {"call_sync", lua_call_sync}, {"call_async", lua_call_async}, {"exe_sync", lua_exe_sync}, {"exe_async", lua_exe_async}, {nullptr, nullptr} }; luaL_newlib(L, functions); return 1; }