diff --git a/res/modules/toml.lua b/res/modules/toml.lua index fb082e75..33c8faf1 100644 --- a/res/modules/toml.lua +++ b/res/modules/toml.lua @@ -1,65 +1,2 @@ --- TOML serialization module -local toml = {} - --- Convert table to TOML -function toml.serialize(tb, isinner) - local text = "" - for k, v in pairs(tb) do - local tp = type(v) - if tp ~= "table" then - text = text..k.." = " - if tp == "string" then - text = text..string.format("%q", v) - else - text = text..tostring(v) - end - text = text.."\n" - end - end - for k, v in pairs(tb) do - local tp = type(v) - if tp == "table" then - if isinner then - error("only one level of subtables supported") - end - text = text.."["..k.."]\n"..toml.serialize(v).."\n" - end - end - return text -end - --- Parse TOML to new table -function toml.deserialize(s) - local output = {} - local current = output - local lines = {} - for line in string.gmatch(s, "[^\r\n]+") do - line = string.gsub(line, "%s+", "") - table.insert(lines, line) - end - for i = 1,#lines do - local s = lines[i] - if string.sub(s, 1, 1) == "[" then - local section = s.sub(s, 2, #s-1) - current = {} - output[section] = current - else - for k, v in string.gmatch(s, "(%w+)=(.+)" ) do - v = string.gsub(v, "%s+", "") - if v.sub(v, 1, 1) == "\"" then - current[k] = v.sub(v, 2, #v-1) - elseif v == "true" or v == "false" then - current[k] = v == "true" - end - - local num = tonumber(v) - if num ~= nil then - current[k] = num - end - end - end - end - return output -end - +print("WARNING: toml is replaced with built-in library, just remove 'require \"core:toml\"'") return toml diff --git a/src/coders/toml.cpp b/src/coders/toml.cpp index dfa0e467..740c2733 100644 --- a/src/coders/toml.cpp +++ b/src/coders/toml.cpp @@ -7,15 +7,14 @@ #include "../files/settings_io.hpp" #include -#include #include #include #include using namespace toml; -class Reader : BasicParser { - SettingsHandler& handler; +class TomlReader : BasicParser { + dynamic::Map_sptr root; void skipWhitespace() override { BasicParser::skipWhitespace(); @@ -26,7 +25,34 @@ class Reader : BasicParser { } } } - void readSection(const std::string& section) { + + dynamic::Map& getSection(const std::string& section) { + if (section.empty()) { + return *root; + } + size_t offset = 0; + auto& rootMap = *root; + do { + size_t index = section.find('.', offset); + if (index == std::string::npos) { + auto map = rootMap.map(section); + if (map == nullptr) { + return rootMap.putMap(section); + } + return *map; + } + auto subsection = section.substr(offset, index); + auto map = rootMap.map(subsection); + if (map == nullptr) { + rootMap = rootMap.putMap(subsection); + } else { + rootMap = *map; + } + offset = index+1; + } while (true); + } + + void readSection(const std::string& section, dynamic::Map& map) { while (hasNext()) { skipWhitespace(); if (!hasNext()) { @@ -36,43 +62,31 @@ class Reader : BasicParser { if (c == '[') { std::string name = parseName(); pos++; - readSection(name); + readSection(name, getSection(name)); return; } pos--; - std::string name = section+"."+parseName(); + std::string name = parseName(); expect('='); c = peek(); if (is_digit(c)) { - auto num = parseNumber(1); - if (handler.has(name)) { - handler.setValue(name, num); - } + map.put(name, parseNumber(1)); } else if (c == '-' || c == '+') { int sign = c == '-' ? -1 : 1; pos++; - auto num = parseNumber(sign); - if (handler.has(name)) { - handler.setValue(name, num); - } + map.put(name, parseNumber(sign)); } else if (is_identifier_start(c)) { std::string identifier = parseName(); - if (handler.has(name)) { - if (identifier == "true" || identifier == "false") { - bool flag = identifier == "true"; - handler.setValue(name, flag); - } else if (identifier == "inf") { - handler.setValue(name, INFINITY); - } else if (identifier == "nan") { - handler.setValue(name, NAN); - } + if (identifier == "true" || identifier == "false") { + map.put(name, identifier == "true"); + } else if (identifier == "inf") { + map.put(name, INFINITY); + } else if (identifier == "nan") { + map.put(name, NAN); } } else if (c == '"' || c == '\'') { pos++; - std::string str = parseString(c); - if (handler.has(name)) { - handler.setValue(name, str); - } + map.put(name, parseString(c)); } else { throw error("feature is not supported"); } @@ -81,29 +95,60 @@ class Reader : BasicParser { } public: - Reader( - SettingsHandler& handler, + TomlReader( std::string_view file, std::string_view source) - : BasicParser(file, source), handler(handler) { + : BasicParser(file, source) { + root = dynamic::create_map(); } - void read() { + dynamic::Map_sptr read() { skipWhitespace(); if (!hasNext()) { - return; + return root; } - readSection(""); + readSection("", *root); + return root; } }; +dynamic::Map_sptr toml::parse(std::string_view file, std::string_view source) { + return TomlReader(file, source).read(); +} + void toml::parse( - SettingsHandler& handler, - const std::string& file, - const std::string& source + SettingsHandler& handler, std::string_view file, std::string_view source ) { - Reader reader(handler, file, source); - reader.read(); + auto map = parse(file, source); + for (auto& entry : map->values) { + const auto& sectionName = entry.first; + auto sectionMap = std::get_if(&entry.second); + if (sectionMap == nullptr) { + continue; + } + for (auto& sectionEntry : (*sectionMap)->values) { + const auto& name = sectionEntry.first; + auto& value = sectionEntry.second; + auto fullname = sectionName+"."+name; + if (handler.has(fullname)) { + handler.setValue(fullname, value); + } + } + } +} + +std::string toml::stringify(dynamic::Map& root) { + std::stringstream ss; + for (auto& sectionEntry : root.values) { + ss << "[" << sectionEntry.first << "]\n"; + auto sectionMap = std::get_if(§ionEntry.second); + for (auto& entry : (*sectionMap)->values) { + ss << entry.first << " = "; + ss << entry.second << "\n"; + } + ss << "\n"; + } + return ss.str(); } std::string toml::stringify(SettingsHandler& handler) { diff --git a/src/coders/toml.hpp b/src/coders/toml.hpp index 4574e468..b4b5d356 100644 --- a/src/coders/toml.hpp +++ b/src/coders/toml.hpp @@ -1,6 +1,7 @@ #ifndef CODERS_TOML_HPP_ #define CODERS_TOML_HPP_ +#include "../data/dynamic.hpp" #include "commons.hpp" #include @@ -9,11 +10,13 @@ class SettingsHandler; namespace toml { std::string stringify(SettingsHandler& handler); + std::string stringify(dynamic::Map& root); + dynamic::Map_sptr parse(std::string_view file, std::string_view source); void parse( SettingsHandler& handler, - const std::string& file, - const std::string& source + std::string_view file, + std::string_view source ); } diff --git a/src/data/dynamic.hpp b/src/data/dynamic.hpp index 93e87b4b..4c5b602c 100644 --- a/src/data/dynamic.hpp +++ b/src/data/dynamic.hpp @@ -152,6 +152,9 @@ namespace dynamic { Map& put(std::string key, bool value) { return put(key, Value(static_cast(value))); } + Map& put(std::string key, const char* value) { + return put(key, Value(value)); + } Map& put(std::string key, const Value& value); void remove(const std::string& key); diff --git a/src/frontend/screens/LevelScreen.cpp b/src/frontend/screens/LevelScreen.cpp index bed9de27..fea96193 100644 --- a/src/frontend/screens/LevelScreen.cpp +++ b/src/frontend/screens/LevelScreen.cpp @@ -2,26 +2,26 @@ #include "../hud.hpp" #include "../LevelFrontend.hpp" -#include "../../debug/Logger.hpp" #include "../../audio/audio.hpp" #include "../../coders/imageio.hpp" -#include "../../graphics/core/PostProcessing.hpp" +#include "../../debug/Logger.hpp" +#include "../../engine.hpp" #include "../../graphics/core/DrawContext.hpp" -#include "../../graphics/core/Viewport.hpp" #include "../../graphics/core/ImageData.hpp" -#include "../../graphics/ui/GUI.hpp" -#include "../../graphics/ui/elements/Menu.hpp" +#include "../../graphics/core/PostProcessing.hpp" +#include "../../graphics/core/Viewport.hpp" #include "../../graphics/render/WorldRenderer.hpp" +#include "../../graphics/ui/elements/Menu.hpp" +#include "../../graphics/ui/GUI.hpp" #include "../../logic/LevelController.hpp" #include "../../logic/scripting/scripting_hud.hpp" #include "../../physics/Hitbox.hpp" #include "../../voxels/Chunks.hpp" -#include "../../world/Level.hpp" -#include "../../world/World.hpp" #include "../../window/Camera.hpp" #include "../../window/Events.hpp" #include "../../window/Window.hpp" -#include "../../engine.hpp" +#include "../../world/Level.hpp" +#include "../../world/World.hpp" static debug::Logger logger("level-screen"); @@ -55,16 +55,20 @@ LevelScreen::LevelScreen(Engine* engine, std::unique_ptr level) void LevelScreen::initializeContent() { auto content = controller->getLevel()->content; for (auto& entry : content->getPacks()) { - auto pack = entry.second.get(); - const ContentPack& info = pack->getInfo(); - fs::path scriptFile = info.folder/fs::path("scripts/hud.lua"); - if (fs::is_regular_file(scriptFile)) { - scripting::load_hud_script(pack->getEnvironment(), info.id, scriptFile); - } + initializePack(entry.second.get()); } scripting::on_frontend_init(hud.get()); } +void LevelScreen::initializePack(ContentPackRuntime* pack) { + const ContentPack& info = pack->getInfo(); + fs::path scriptFile = info.folder/fs::path("scripts/hud.lua"); + if (fs::is_regular_file(scriptFile)) { + scripting::load_hud_script(pack->getEnvironment(), info.id, scriptFile); + } + auto configFolder = info.folder/fs::path("config"); +} + LevelScreen::~LevelScreen() { saveWorldPreview(); scripting::on_frontend_close(); diff --git a/src/frontend/screens/LevelScreen.hpp b/src/frontend/screens/LevelScreen.hpp index 8548c06c..2b5f3527 100644 --- a/src/frontend/screens/LevelScreen.hpp +++ b/src/frontend/screens/LevelScreen.hpp @@ -12,6 +12,7 @@ class LevelController; class WorldRenderer; class TextureAnimator; class PostProcessing; +class ContentPackRuntime; class Level; class LevelScreen : public Screen { @@ -27,6 +28,7 @@ class LevelScreen : public Screen { bool hudVisible = true; void updateHotkeys(); void initializeContent(); + void initializePack(ContentPackRuntime* pack); public: LevelScreen(Engine* engine, std::unique_ptr level); ~LevelScreen(); diff --git a/src/logic/scripting/lua/LuaState.cpp b/src/logic/scripting/lua/LuaState.cpp index 902e9bf3..1a860670 100644 --- a/src/logic/scripting/lua/LuaState.cpp +++ b/src/logic/scripting/lua/LuaState.cpp @@ -12,14 +12,16 @@ inline std::string LAMBDAS_TABLE = "$L"; static debug::Logger logger("lua-state"); +using namespace lua; + namespace scripting { - extern lua::LuaState* state; + extern LuaState* state; } -lua::luaerror::luaerror(const std::string& message) : std::runtime_error(message) { +luaerror::luaerror(const std::string& message) : std::runtime_error(message) { } -void lua::LuaState::removeLibFuncs(const char* libname, const char* funcs[]) { +void LuaState::removeLibFuncs(const char* libname, const char* funcs[]) { if (getglobal(libname)) { for (uint i = 0; funcs[i]; i++) { pushnil(); @@ -28,13 +30,13 @@ void lua::LuaState::removeLibFuncs(const char* libname, const char* funcs[]) { } } -lua::LuaState::LuaState() { +LuaState::LuaState() { logger.info() << LUA_VERSION; logger.info() << LUAJIT_VERSION; L = luaL_newstate(); if (L == nullptr) { - throw lua::luaerror("could not to initialize Lua"); + throw luaerror("could not to initialize Lua"); } // Allowed standard libraries luaopen_base(L); @@ -66,24 +68,24 @@ lua::LuaState::LuaState() { setglobal(LAMBDAS_TABLE); } -const std::string lua::LuaState::envName(int env) { +const std::string LuaState::envName(int env) { return "_ENV"+util::mangleid(env); } -lua::LuaState::~LuaState() { +LuaState::~LuaState() { lua_close(L); } -void lua::LuaState::logError(const std::string& text) { +void LuaState::logError(const std::string& text) { logger.error() << text; } -void lua::LuaState::addfunc(const std::string& name, lua_CFunction func) { +void LuaState::addfunc(const std::string& name, lua_CFunction func) { lua_pushcfunction(L, func); lua_setglobal(L, name.c_str()); } -bool lua::LuaState::getglobal(const std::string& name) { +bool LuaState::getglobal(const std::string& name) { lua_getglobal(L, name.c_str()); if (lua_isnil(L, lua_gettop(L))) { lua_pop(L, lua_gettop(L)); @@ -92,7 +94,7 @@ bool lua::LuaState::getglobal(const std::string& name) { return true; } -bool lua::LuaState::hasglobal(const std::string& name) { +bool LuaState::hasglobal(const std::string& name) { lua_getglobal(L, name.c_str()); if (lua_isnil(L, lua_gettop(L))) { lua_pop(L, lua_gettop(L)); @@ -102,11 +104,11 @@ bool lua::LuaState::hasglobal(const std::string& name) { return true; } -void lua::LuaState::setglobal(const std::string& name) { +void LuaState::setglobal(const std::string& name) { lua_setglobal(L, name.c_str()); } -bool lua::LuaState::rename(const std::string& from, const std::string& to) { +bool LuaState::rename(const std::string& from, const std::string& to) { const char* src = from.c_str(); lua_getglobal(L, src); if (lua_isnil(L, lua_gettop(L))) { @@ -121,12 +123,12 @@ bool lua::LuaState::rename(const std::string& from, const std::string& to) { return true; } -void lua::LuaState::remove(const std::string& name) { +void LuaState::remove(const std::string& name) { lua_pushnil(L); lua_setglobal(L, name.c_str()); } -void lua::LuaState::createLibs() { +void LuaState::createLibs() { openlib("audio", audiolib); openlib("block", blocklib); openlib("console", consolelib); @@ -140,28 +142,29 @@ void lua::LuaState::createLibs() { openlib("pack", packlib); openlib("player", playerlib); openlib("time", timelib); + openlib("toml", tomllib); openlib("world", worldlib); addfunc("print", lua_wrap_errors); } -void lua::LuaState::loadbuffer(int env, const std::string& src, const std::string& file) { +void LuaState::loadbuffer(int env, const std::string& src, const std::string& file) { if (luaL_loadbuffer(L, src.c_str(), src.length(), file.c_str())) { - throw lua::luaerror(lua_tostring(L, -1)); + throw luaerror(lua_tostring(L, -1)); } if (env && getglobal(envName(env))) { lua_setfenv(L, -2); } } -int lua::LuaState::call(int argc, int nresults) { +int LuaState::call(int argc, int nresults) { if (lua_pcall(L, argc, nresults, 0)) { - throw lua::luaerror(lua_tostring(L, -1)); + throw luaerror(lua_tostring(L, -1)); } return 1; } -int lua::LuaState::callNoThrow(int argc) { +int LuaState::callNoThrow(int argc) { if (lua_pcall(L, argc, LUA_MULTRET, 0)) { logError(lua_tostring(L, -1)); return 0; @@ -169,59 +172,59 @@ int lua::LuaState::callNoThrow(int argc) { return 1; } -int lua::LuaState::eval(int env, const std::string& src, const std::string& file) { +int LuaState::eval(int env, const std::string& src, const std::string& file) { auto srcText = "return "+src; loadbuffer(env, srcText, file); return call(0); } -int lua::LuaState::execute(int env, const std::string& src, const std::string& file) { +int LuaState::execute(int env, const std::string& src, const std::string& file) { loadbuffer(env, src, file); return callNoThrow(0); } -int lua::LuaState::gettop() const { +int LuaState::gettop() const { return lua_gettop(L); } -int lua::LuaState::pushinteger(luaint x) { +int LuaState::pushinteger(luaint x) { lua_pushinteger(L, x); return 1; } -int lua::LuaState::pushnumber(luanumber x) { +int LuaState::pushnumber(luanumber x) { lua_pushnumber(L, x); return 1; } -int lua::LuaState::pushboolean(bool x) { +int LuaState::pushboolean(bool x) { lua_pushboolean(L, x); return 1; } -int lua::LuaState::pushivec3(luaint x, luaint y, luaint z) { +int LuaState::pushivec3(luaint x, luaint y, luaint z) { lua::pushivec3(L, x, y, z); return 3; } -int lua::LuaState::pushstring(const std::string& str) { +int LuaState::pushstring(const std::string& str) { lua_pushstring(L, str.c_str()); return 1; } -int lua::LuaState::pushenv(int env) { +int LuaState::pushenv(int env) { if (getglobal(envName(env))) { return 1; } return 0; } -int lua::LuaState::pushvalue(int idx) { +int LuaState::pushvalue(int idx) { lua_pushvalue(L, idx); return 1; } -int lua::LuaState::pushvalue(const dynamic::Value& value) { +int LuaState::pushvalue(const dynamic::Value& value) { using namespace dynamic; if (auto* flag = std::get_if(&value)) { @@ -252,26 +255,26 @@ int lua::LuaState::pushvalue(const dynamic::Value& value) { return 1; } -int lua::LuaState::pushglobals() { +int LuaState::pushglobals() { lua_pushvalue(L, LUA_GLOBALSINDEX); return 1; } -int lua::LuaState::pushcfunction(lua_CFunction function) { +int LuaState::pushcfunction(lua_CFunction function) { lua_pushcfunction(L, function); return 1; } -void lua::LuaState::pop(int n) { +void LuaState::pop(int n) { lua_pop(L, n); } -int lua::LuaState::pushnil() { +int LuaState::pushnil() { lua_pushnil(L); return 1; } -bool lua::LuaState::getfield(const std::string& name, int idx) { +bool LuaState::getfield(const std::string& name, int idx) { lua_getfield(L, idx, name.c_str()); if (lua_isnil(L, -1)) { lua_pop(L, -1); @@ -280,35 +283,35 @@ bool lua::LuaState::getfield(const std::string& name, int idx) { return true; } -void lua::LuaState::setfield(const std::string& name, int idx) { +void LuaState::setfield(const std::string& name, int idx) { lua_setfield(L, idx, name.c_str()); } -bool lua::LuaState::toboolean(int idx) { +bool LuaState::toboolean(int idx) { return lua_toboolean(L, idx); } -lua::luaint lua::LuaState::tointeger(int idx) { +luaint LuaState::tointeger(int idx) { return lua_tointeger(L, idx); } -lua::luanumber lua::LuaState::tonumber(int idx) { +luanumber LuaState::tonumber(int idx) { return lua_tonumber(L, idx); } -glm::vec2 lua::LuaState::tovec2(int idx) { +glm::vec2 LuaState::tovec2(int idx) { return lua::tovec2(L, idx); } -glm::vec4 lua::LuaState::tocolor(int idx) { +glm::vec4 LuaState::tocolor(int idx) { return lua::tocolor(L, idx); } -const char* lua::LuaState::tostring(int idx) { +const char* LuaState::tostring(int idx) { return lua_tostring(L, idx); } -dynamic::Value lua::LuaState::tovalue(int idx) { +dynamic::Value LuaState::tovalue(int idx) { using namespace dynamic; auto type = lua_type(L, idx); switch (type) { @@ -361,21 +364,21 @@ dynamic::Value lua::LuaState::tovalue(int idx) { } } -bool lua::LuaState::isstring(int idx) { +bool LuaState::isstring(int idx) { return lua_isstring(L, idx); } -bool lua::LuaState::isfunction(int idx) { +bool LuaState::isfunction(int idx) { return lua_isfunction(L, idx); } -void lua::LuaState::openlib(const std::string& name, const luaL_Reg* libfuncs) { +void LuaState::openlib(const std::string& name, const luaL_Reg* libfuncs) { lua_newtable(L); luaL_setfuncs(L, libfuncs, 0); lua_setglobal(L, name.c_str()); } -std::shared_ptr lua::LuaState::createLambdaHandler() { +std::shared_ptr LuaState::createLambdaHandler() { auto ptr = reinterpret_cast(lua_topointer(L, -1)); auto name = util::mangleid(ptr); lua_getglobal(L, LAMBDAS_TABLE.c_str()); @@ -392,7 +395,7 @@ std::shared_ptr lua::LuaState::createLambdaHandler() { }); } -runnable lua::LuaState::createRunnable() { +runnable LuaState::createRunnable() { auto funcptr = createLambdaHandler(); return [=]() { lua_getglobal(L, LAMBDAS_TABLE.c_str()); @@ -401,7 +404,7 @@ runnable lua::LuaState::createRunnable() { }; } -scripting::common_func lua::LuaState::createLambda() { +scripting::common_func LuaState::createLambda() { auto funcptr = createLambdaHandler(); return [=](const std::vector& args) { lua_getglobal(L, LAMBDAS_TABLE.c_str()); @@ -418,7 +421,14 @@ scripting::common_func lua::LuaState::createLambda() { }; } -int lua::LuaState::createEnvironment(int parent) { +const char* LuaState::requireString(int idx) { + if (!lua_isstring(L, idx)) { + throw luaerror("string expected at "+std::to_string(idx)); + } + return lua_tostring(L, idx); +} + +int LuaState::createEnvironment(int parent) { int id = nextEnvironment++; // local env = {} @@ -442,7 +452,7 @@ int lua::LuaState::createEnvironment(int parent) { } -void lua::LuaState::removeEnvironment(int id) { +void LuaState::removeEnvironment(int id) { if (id == 0) { return; } @@ -450,7 +460,7 @@ void lua::LuaState::removeEnvironment(int id) { setglobal(envName(id)); } -bool lua::LuaState::emit_event(const std::string &name, std::function args) { +bool LuaState::emit_event(const std::string &name, std::function args) { getglobal("events"); getfield("emit"); pushstring(name); @@ -461,7 +471,7 @@ bool lua::LuaState::emit_event(const std::string &name, std::function args=[](auto*){return 0;}); diff --git a/src/logic/scripting/lua/api_lua.hpp b/src/logic/scripting/lua/api_lua.hpp index 4d798d82..69526057 100644 --- a/src/logic/scripting/lua/api_lua.hpp +++ b/src/logic/scripting/lua/api_lua.hpp @@ -8,19 +8,20 @@ // Libraries extern const luaL_Reg audiolib []; extern const luaL_Reg blocklib []; +extern const luaL_Reg consolelib []; extern const luaL_Reg corelib []; extern const luaL_Reg filelib []; extern const luaL_Reg guilib []; extern const luaL_Reg hudlib []; +extern const luaL_Reg inputlib []; extern const luaL_Reg inventorylib []; extern const luaL_Reg itemlib []; +extern const luaL_Reg jsonlib []; extern const luaL_Reg packlib []; extern const luaL_Reg playerlib []; extern const luaL_Reg timelib []; +extern const luaL_Reg tomllib []; extern const luaL_Reg worldlib []; -extern const luaL_Reg jsonlib []; -extern const luaL_Reg inputlib []; -extern const luaL_Reg consolelib []; // Lua Overrides extern int l_print(lua_State* L); diff --git a/src/logic/scripting/lua/libinput.cpp b/src/logic/scripting/lua/libinput.cpp index 7f3fbc20..beb2c5de 100644 --- a/src/logic/scripting/lua/libinput.cpp +++ b/src/logic/scripting/lua/libinput.cpp @@ -20,13 +20,13 @@ namespace scripting { using namespace scripting; static int l_keycode(lua_State* L) { - const char* name = lua_tostring(L, 1); + const char* name = state->requireString(1); lua_pushinteger(L, static_cast(input_util::keycode_from(name))); return 1; } static int l_add_callback(lua_State* L) { - auto bindname = lua_tostring(L, 1); + auto bindname = state->requireString(1); const auto& bind = Events::bindings.find(bindname); if (bind == Events::bindings.end()) { throw std::runtime_error("unknown binding "+util::quote(bindname)); diff --git a/src/logic/scripting/lua/libtoml.cpp b/src/logic/scripting/lua/libtoml.cpp new file mode 100644 index 00000000..4bb4a123 --- /dev/null +++ b/src/logic/scripting/lua/libtoml.cpp @@ -0,0 +1,37 @@ +#include "api_lua.hpp" +#include "lua_commons.hpp" +#include "LuaState.hpp" + +#include "../../../coders/toml.hpp" +#include "../../../data/dynamic.hpp" + +namespace scripting { + extern lua::LuaState* state; +} +using namespace scripting; + +static int l_toml_stringify(lua_State* L) { + auto value = state->tovalue(1); + + if (auto mapptr = std::get_if(&value)) { + auto string = toml::stringify(**mapptr); + lua_pushstring(L, string.c_str()); + return 1; + } else { + throw std::runtime_error("table expected"); + } +} + +static int l_toml_parse(lua_State*) { + auto string = state->requireString(1); + auto element = toml::parse("", string); + auto value = std::make_unique(element); + state->pushvalue(*value); + return 1; +} + +const luaL_Reg tomllib [] = { + {"serialize", lua_wrap_errors}, + {"deserialize", lua_wrap_errors}, + {NULL, NULL} +}; diff --git a/src/util/stringutil.cpp b/src/util/stringutil.cpp index 9480af4c..804d9a99 100644 --- a/src/util/stringutil.cpp +++ b/src/util/stringutil.cpp @@ -443,3 +443,14 @@ std::string util::format_data_size(size_t size) { std::to_string(static_cast(round(remainder/1024.0f)))+ postfixes[group]; } + +std::pair util::split_at(std::string_view view, char c) { + size_t idx = view.find(c); + if (idx == std::string::npos) { + throw std::runtime_error(util::quote(std::string({c}))+" not found"); + } + return std::make_pair( + std::string(view.substr(0, idx)), + std::string(view.substr(idx+1)) + ); +} diff --git a/src/util/stringutil.hpp b/src/util/stringutil.hpp index 3270c92e..ffac1eab 100644 --- a/src/util/stringutil.hpp +++ b/src/util/stringutil.hpp @@ -57,6 +57,8 @@ namespace util { std::vector split(const std::wstring& str, char delimiter); std::string format_data_size(size_t size); + + std::pair split_at(std::string_view view, char c); } #endif // UTIL_STRINGUTIL_HPP_ diff --git a/src/window/input.cpp b/src/window/input.cpp index 2d1d7c65..bdb8bbcd 100644 --- a/src/window/input.cpp +++ b/src/window/input.cpp @@ -32,6 +32,12 @@ static std::unordered_map keycodes { {"up", GLFW_KEY_UP}, }; +static std::unordered_map mousecodes { + {"left", GLFW_MOUSE_BUTTON_1}, + {"right", GLFW_MOUSE_BUTTON_2}, + {"middle", GLFW_MOUSE_BUTTON_3}, +}; + void Binding::reset(inputtype type, int code) { this->type = type; this->code = code; @@ -65,6 +71,14 @@ keycode input_util::keycode_from(const std::string& name) { return static_cast(found->second); } +mousecode input_util::mousecode_from(const std::string& name) { + const auto& found = mousecodes.find(name); + if (found == mousecodes.end()) { + return mousecode::UNKNOWN; + } + return static_cast(found->second); +} + std::string input_util::to_string(keycode code) { int icode_repr = static_cast(code); #ifdef _WIN32 diff --git a/src/window/input.hpp b/src/window/input.hpp index 72aedb95..21ca63c1 100644 --- a/src/window/input.hpp +++ b/src/window/input.hpp @@ -103,6 +103,7 @@ enum class mousecode : int { BUTTON_1 = 0, // Left mouse button BUTTON_2 = 1, // Right mouse button BUTTON_3 = 2, // Middle mouse button + UNKNOWN = -1, }; inline mousecode MOUSECODES_ALL[] { @@ -115,6 +116,8 @@ namespace input_util { void initialize(); keycode keycode_from(const std::string& name); + mousecode mousecode_from(const std::string& name); + /// @return Key label by keycode std::string to_string(keycode code); /// @return Mouse button label by keycode