AI提示词:一个游戏服务端跨LUA状态机(线程)访问对象(TABLE)的方法
今天较深入学习了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;
}

浙公网安备 33010602011771号