#pragma once #include #include #include #include extern "C" { #include #include #include } using LuaValue = std::variant; class LuaConfig { public: LuaConfig(const std::string &filePath, const std::string &tableName) { L = luaL_newstate(); luaL_openlibs(L); if (luaL_dofile(L, filePath.c_str()) != LUA_OK) { std::string err = lua_tostring(L, -1); lua_close(L); throw std::runtime_error("Error loading Lua file: " + err); } lua_getglobal(L, tableName.c_str()); if (!lua_istable(L, -1)) { lua_close(L); throw std::runtime_error("'" + tableName + "' is not a table (or missing)"); } } ~LuaConfig() { if (L) lua_close(L); } LuaConfig(const LuaConfig &) = delete; LuaConfig &operator=(const LuaConfig &) = delete; template T get(const std::string &key) const { lua_getfield(L, -1, key.c_str()); if (lua_isnil(L, -1)) { lua_pop(L, 1); throw std::runtime_error("Missing key: " + key); } T value = extract(key); lua_pop(L, 1); std::cout << "[LuaConfig] " << key << " = " << value << "\n"; return value; } private: lua_State *L = nullptr; template T extract(const std::string &key) const { if constexpr (std::is_same_v) { if (!lua_isinteger(L, -1) && !lua_isnumber(L, -1)) throw std::runtime_error("Key '" + key + "' is not a number"); return static_cast(lua_tointeger(L, -1)); } else if constexpr (std::is_same_v) { if (!lua_isnumber(L, -1)) throw std::runtime_error("Key '" + key + "' is not a number"); return static_cast(lua_tonumber(L, -1)); } else if constexpr (std::is_same_v) { if (!lua_isnumber(L, -1)) throw std::runtime_error("Key '" + key + "' is not a number"); return static_cast(lua_tonumber(L, -1)); } else if constexpr (std::is_same_v) { if (!lua_isboolean(L, -1)) throw std::runtime_error("Key '" + key + "' is not a boolean"); return lua_toboolean(L, -1) != 0; } else if constexpr (std::is_same_v) { if (!lua_isstring(L, -1)) throw std::runtime_error("Key '" + key + "' is not a string"); return std::string(lua_tostring(L, -1)); } else { static_assert(!sizeof(T *), "Unsupported type for LuaConfig::get()"); } } };