lua_bind.h
#pragma once
#include <string>
#include <string_view>
#include "asio/detail/noncopyable.hpp"
#include "io_context_pool.h"
#include "logger.h"
#include "sol/sol.hpp"
namespace flower {
class lua_bind final : public asio::detail::noncopyable {
public:
lua_bind() = default;
~lua_bind() = default;
enum lua_msg_type {
lmt_none,
lmt_main,
lmt_message,
lmt_timer,
lmt_mysql,
lmt_server_stop,
lmt_hotfix,
};
bool start(flower::io_context_pool& pool, std::string_view script_dir);
void call_code(std::string_view code);
void call_file(std::string_view file);
template <typename... Args>
void call_frame(Args&&... args) {
auto res = state_["on_frame"](std::forward<Args>(args)...);
if (!res.valid()) {
sol::error err = res;
LOG_ERROR("lua_bind::call_frame error:\n{}", err.what());
}
}
sol::state& get() {
return state_;
}
private:
void register_class();
bool register_field(std::string_view script_path);
private:
sol::state state_;
std::string script_path_{};
flower::io_context_pool* io_pool_{};
};
} // namespace flower
lua_bind.cpp
#include "lua_bind.h"
#include "packet.h"
#include "comm_func.h"
namespace flower {
bool lua_bind::start(flower::io_context_pool& pool, std::string_view script_dir) {
try {
state_.open_libraries();
if (!register_field(script_dir)) {
return false;
}
register_class();
io_pool_ = &pool;
} catch (const sol::error& e) {
LOG_ERROR("lua_bind::start error:{}", e.what());
}
return true;
}
void lua_bind::call_code(std::string_view code) {
state_.script(code, [](lua_State* L, sol::protected_function_result pfr) {
sol::error err = pfr;
LOG_ERROR("lua_bind::call_code error:{}", err.what());
return pfr;
});
}
void lua_bind::call_file(std::string_view file) {
std::string file_path = script_path_;
file_path.append(file.data()).append(".lua");
state_.script_file(file_path, [](lua_State* L, sol::protected_function_result pfr) {
sol::error err = pfr;
LOG_ERROR("lua_bind::call_file error:{}", err.what());
return pfr;
});
}
void lua_bind::register_class() {
using namespace flower;
auto packet = state_.new_usertype<flower::packet>("packet");
packet["read_int8"] = &packet::read_int8;
packet["read_uint8"] = &packet::read_uint8;
packet["read_int16"] = &packet::read_int16;
packet["read_uint16"] = &packet::read_uint16;
packet["read_int32"] = &packet::read_int32;
packet["read_uint32"] = &packet::read_uint32;
packet["read_int64"] = &packet::read_int64;
packet["read_uint64"] = &packet::read_uint64;
packet["read_float"] = &packet::read_float;
packet["read_double"] = &packet::read_double;
packet["read_string"] = &packet::read_string;
packet["can_read_more"] = &packet::can_read_more;
}
bool lua_bind::register_field(std::string_view script_path) {
using namespace flower;
std::string path = comm_func::get_current_exe_dir();
if (path.empty()) {
LOG_ERROR("lua_bind::register_lua_field exec_path is empty");
return false;
}
if (script_path.empty()) {
LOG_ERROR("lua_bind::register_lua_field script_path is empty");
return false;
}
#ifdef _WIN32
auto pos = path.find_last_of("\\");
#else
auto pos = path.find_last_of('/');
#endif
if (pos == std::string::npos) {
LOG_ERROR("lua_bind::register_lua_field path error");
return false;
}
script_path_ = path.substr(0, pos + 1) + script_path.data();
#ifdef _WIN32
script_path_.append("\\");
#else
script_path_.append("/");
#endif
state_["lExecPath"] = path;
state_["lScriptPath"] = script_path_;
state_["print"] = [](lua_State* L) {
std::string msg;
int n = lua_gettop(L);
int i;
lua_getglobal(L, "tostring");
for (i = 1; i <= n; i++) {
std::size_t l;
lua_pushvalue(L, -1);
lua_pushvalue(L, i);
lua_call(L, 1, 1);
const char* str = lua_tolstring(L, -1, &l);
if (str == nullptr) {
LOG_ERROR("[LUA] 'tostring' must return a string to 'print'");
return 0;
}
if (i > 1) {
msg.append("\t");
}
msg.append(str);
lua_pop(L, 1);
}
LOG_DEBUG("[LUA] {}", msg);
return 0;
};
state_["lShowMem"] = [this]() {
state_.step_gc(state_.memory_used());
LOG_WARN("LUA_MEM: {:.2f}M", static_cast<double>(state_.memory_used()) / 1024 / 1024);
};
state_["lShowInfo"] = [](std::string_view msg) {
LOG_INFO("[LUA] {}", msg);
};
state_["lShowError"] = [](std::string_view msg) {
LOG_ERROR("[LUA] {}", msg);
};
state_["lGetMilliTime"] = comm_func::get_milli_time;
state_["lGetMicroTime"] = comm_func::get_micro_time;
state_["lGetSecTime"] = comm_func::get_sec_time;
state_["lAddTimer"] = [this](uint32_t delay, uint32_t interval, int32_t count) {
return io_pool_->add_timer(delay, interval, count, [this](timer_event::ptr event) {
call_frame(lua_msg_type::lmt_timer, event->get_sn());
});
};
state_["lDelTimer"] = [this](int32_t sn) {
io_pool_->del_timer(sn);
};
return true;
}
} // namespace flower