diff --git a/res/scripts/stdlib.lua b/res/scripts/stdlib.lua index 6e075768..fe3c0be7 100644 --- a/res/scripts/stdlib.lua +++ b/res/scripts/stdlib.lua @@ -276,6 +276,15 @@ function table.tostring(t) return s..']' end +function file.readlines(path) + local str = file.read(path) + local lines = {} + for s in str:gmatch("[^\r\n]+") do + table.insert(lines, s) + end + return lines +end + console.add_command( "tp obj:sel=$obj.id x:num~pos.x y:num~pos.y z:num~pos.z", function (args, kwargs) diff --git a/src/engine.cpp b/src/engine.cpp index 2b64341c..a903453e 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -266,7 +266,7 @@ void Engine::loadContent() { names = manager.assembly(names); contentPacks = manager.getAll(names); - std::vector> resRoots; + std::vector resRoots; for (auto& pack : contentPacks) { resRoots.push_back({pack.id, pack.folder}); diff --git a/src/files/engine_paths.cpp b/src/files/engine_paths.cpp index f14828b3..509c4055 100644 --- a/src/files/engine_paths.cpp +++ b/src/files/engine_paths.cpp @@ -164,14 +164,14 @@ fs::path EnginePaths::resolve(std::string path) { throw files_access_error("unknown entry point '"+prefix+"'"); } -ResPaths::ResPaths(fs::path mainRoot, std::vector> roots) +ResPaths::ResPaths(fs::path mainRoot, std::vector roots) : mainRoot(mainRoot), roots(roots) { } fs::path ResPaths::find(const std::string& filename) const { for (int i = roots.size()-1; i >= 0; i--) { auto& root = roots[i]; - fs::path file = root.second / fs::u8path(filename); + fs::path file = root.path / fs::u8path(filename); if (fs::exists(file)) { return file; } @@ -182,8 +182,8 @@ fs::path ResPaths::find(const std::string& filename) const { std::string ResPaths::findRaw(const std::string& filename) const { for (int i = roots.size()-1; i >= 0; i--) { auto& root = roots[i]; - if (fs::exists(root.second / fs::path(filename))) { - return root.first+":"+filename; + if (fs::exists(root.path / fs::path(filename))) { + return root.name + ":" + filename; } } auto resDir = mainRoot; @@ -193,11 +193,35 @@ std::string ResPaths::findRaw(const std::string& filename) const { throw std::runtime_error("could not to find file "+util::quote(filename)); } +std::vector ResPaths::listdirRaw(const std::string& folderName) const { + std::vector entries; + for (int i = roots.size()-1; i >= 0; i--) { + auto& root = roots[i]; + fs::path folder = root.path / fs::u8path(folderName); + if (!fs::is_directory(folder)) + continue; + for (const auto& entry : fs::directory_iterator(folder)) { + auto name = entry.path().filename().u8string(); + entries.push_back(root.name+":"+folderName+"/"+name); + } + } + { + fs::path folder = mainRoot / fs::u8path(folderName); + if (!fs::is_directory(folder)) + return entries; + for (const auto& entry : fs::directory_iterator(folder)) { + auto name = entry.path().filename().u8string(); + entries.push_back("core:"+folderName+"/"+name); + } + } + return entries; +} + std::vector ResPaths::listdir(const std::string& folderName) const { std::vector entries; for (int i = roots.size()-1; i >= 0; i--) { auto& root = roots[i]; - fs::path folder = root.second / fs::u8path(folderName); + fs::path folder = root.path / fs::u8path(folderName); if (!fs::is_directory(folder)) continue; for (const auto& entry : fs::directory_iterator(folder)) { diff --git a/src/files/engine_paths.hpp b/src/files/engine_paths.hpp index 41c57e6e..ac1ed5a8 100644 --- a/src/files/engine_paths.hpp +++ b/src/files/engine_paths.hpp @@ -42,18 +42,24 @@ public: fs::path resolve(std::string path); }; +struct PathsRoot { + std::string name; + fs::path path; +}; + class ResPaths { fs::path mainRoot; - std::vector> roots; + std::vector roots; public: ResPaths( fs::path mainRoot, - std::vector> roots + std::vector roots ); fs::path find(const std::string& filename) const; std::string findRaw(const std::string& filename) const; std::vector listdir(const std::string& folder) const; + std::vector listdirRaw(const std::string& folder) const; const fs::path& getMainRoot() const; }; diff --git a/src/frontend/screens/LevelScreen.cpp b/src/frontend/screens/LevelScreen.cpp index 94dc2239..7882d033 100644 --- a/src/frontend/screens/LevelScreen.cpp +++ b/src/frontend/screens/LevelScreen.cpp @@ -24,9 +24,9 @@ static debug::Logger logger("level-screen"); -LevelScreen::LevelScreen(Engine* engine, Level* level) : Screen(engine) { - postProcessing = std::make_unique(); - +LevelScreen::LevelScreen(Engine* engine, Level* level) + : Screen(engine), postProcessing(std::make_unique()) +{ auto& settings = engine->getSettings(); auto assets = engine->getAssets(); auto menu = engine->getGUI()->getMenu(); @@ -48,7 +48,11 @@ LevelScreen::LevelScreen(Engine* engine, Level* level) : Screen(engine) { animator = std::make_unique(); animator->addAnimations(assets->getAnimations()); - auto content = level->content; + initializeContent(); +} + +void LevelScreen::initializeContent() { + auto content = controller->getLevel()->content; for (auto& entry : content->getPacks()) { auto pack = entry.second.get(); const ContentPack& info = pack->getInfo(); diff --git a/src/frontend/screens/LevelScreen.hpp b/src/frontend/screens/LevelScreen.hpp index ff41dd60..8f70cf12 100644 --- a/src/frontend/screens/LevelScreen.hpp +++ b/src/frontend/screens/LevelScreen.hpp @@ -26,6 +26,7 @@ class LevelScreen : public Screen { bool hudVisible = true; void updateHotkeys(); + void initializeContent(); public: LevelScreen(Engine* engine, Level* level); ~LevelScreen(); diff --git a/src/graphics/ui/elements/TextBox.cpp b/src/graphics/ui/elements/TextBox.cpp index 022a0732..e8f4cf48 100644 --- a/src/graphics/ui/elements/TextBox.cpp +++ b/src/graphics/ui/elements/TextBox.cpp @@ -130,7 +130,6 @@ void TextBox::drawBackground(const DrawContext* pctx, Assets*) { /// @brief Insert text at the caret. Also selected text will be erased /// @param text Inserting text void TextBox::paste(const std::wstring& text) { - eraseSelected(); if (caret >= input.length()) { input += text; @@ -203,7 +202,9 @@ void TextBox::setTextOffset(uint x) { } void TextBox::typed(unsigned int codepoint) { - paste(std::wstring({(wchar_t)codepoint})); + if (editable) { + paste(std::wstring({(wchar_t)codepoint})); + } } bool TextBox::validate() { diff --git a/src/logic/scripting/lua/libfile.cpp b/src/logic/scripting/lua/libfile.cpp index 9c6ebe97..7db2d5ab 100644 --- a/src/logic/scripting/lua/libfile.cpp +++ b/src/logic/scripting/lua/libfile.cpp @@ -140,6 +140,37 @@ static int l_file_write_bytes(lua_State* L) { } } +static int l_file_list_all_res(lua_State* L, const std::string& path) { + auto files = scripting::engine->getResPaths()->listdirRaw(path); + lua_createtable(L, files.size(), 0); + for (size_t i = 0; i < files.size(); i++) { + lua_pushstring(L, files[i].c_str()); + lua_rawseti(L, -2, i+1); + } + return 1; +} + +static int l_file_list(lua_State* L) { + std::string dirname = lua_tostring(L, 1); + if (dirname.find(':') == std::string::npos) { + return l_file_list_all_res(L, dirname); + } + fs::path path = resolve_path(L, dirname); + if (!fs::is_directory(path)) { + throw std::runtime_error(util::quote(path.u8string())+" is not a directory"); + } + lua_createtable(L, 0, 0); + size_t index = 1; + for (auto& entry : fs::directory_iterator(path)) { + auto name = entry.path().filename().u8string(); + auto file = dirname + "/" + name; + lua_pushstring(L, file.c_str()); + lua_rawseti(L, -2, index); + index++; + } + return 1; +} + const luaL_Reg filelib [] = { {"resolve", lua_wrap_errors}, {"find", lua_wrap_errors}, @@ -153,5 +184,6 @@ const luaL_Reg filelib [] = { {"mkdirs", lua_wrap_errors}, {"read_bytes", lua_wrap_errors}, {"write_bytes", lua_wrap_errors}, + {"list", lua_wrap_errors}, {NULL, NULL} }; diff --git a/src/logic/scripting/lua/libgui.cpp b/src/logic/scripting/lua/libgui.cpp index 84973805..b8c30b6b 100644 --- a/src/logic/scripting/lua/libgui.cpp +++ b/src/logic/scripting/lua/libgui.cpp @@ -204,6 +204,13 @@ static int p_get_text(UINode* node) { return 0; } +static int p_get_editable(UINode* node) { + if (auto box = dynamic_cast(node)) { + return state->pushboolean(box->isEditable()); + } + return 0; +} + static int p_get_add(UINode* node) { if (dynamic_cast(node)) { return state->pushcfunction(l_container_add); @@ -268,6 +275,7 @@ static int l_gui_getattr(lua_State* L) { {"placeholder", p_get_placeholder}, {"valid", p_is_valid}, {"text", p_get_text}, + {"editable", p_get_editable}, {"value", p_get_value}, {"min", p_get_min}, {"max", p_get_max}, @@ -325,6 +333,11 @@ static void p_set_text(UINode* node, int idx) { box->setText(util::str2wstr_utf8(state->tostring(idx))); } } +static void p_set_editable(UINode* node, int idx) { + if (auto box = dynamic_cast(node)) { + box->setEditable(state->toboolean(idx)); + } +} static void p_set_value(UINode* node, int idx) { if (auto bar = dynamic_cast(node)) { bar->setValue(state->tonumber(idx)); @@ -397,6 +410,7 @@ static int l_gui_setattr(lua_State* L) { {"enabled", p_set_enabled}, {"placeholder", p_set_placeholder}, {"text", p_set_text}, + {"editable", p_set_editable}, {"value", p_set_value}, {"min", p_set_min}, {"max", p_set_max}, @@ -459,8 +473,7 @@ static int l_gui_get_locales_info(lua_State* L) { } static int l_gui_getviewport(lua_State* L) { - lua::pushvec2_arr(L, scripting::engine->getGUI()->getContainer()->getSize()); - return 1; + return lua::pushvec2_arr(L, scripting::engine->getGUI()->getContainer()->getSize()); } const luaL_Reg guilib [] = { diff --git a/src/logic/scripting/lua/libinput.cpp b/src/logic/scripting/lua/libinput.cpp index f654dc47..1c021093 100644 --- a/src/logic/scripting/lua/libinput.cpp +++ b/src/logic/scripting/lua/libinput.cpp @@ -1,4 +1,5 @@ #include "api_lua.hpp" +#include "lua_util.hpp" #include "lua_commons.hpp" #include "LuaState.hpp" #include "../scripting.hpp" @@ -39,9 +40,14 @@ static int l_add_callback(lua_State* L) { return 0; } +static int l_get_mouse_pos(lua_State* L) { + return lua::pushvec2_arr(L, Events::cursor); +} + const luaL_Reg inputlib [] = { {"keycode", lua_wrap_errors}, {"add_callback", lua_wrap_errors}, + {"get_mouse_pos", lua_wrap_errors}, {NULL, NULL} }; diff --git a/src/window/Events.cpp b/src/window/Events.cpp index 1232559e..8ac783fd 100644 --- a/src/window/Events.cpp +++ b/src/window/Events.cpp @@ -88,8 +88,7 @@ void Events::pollEvents() { binding.justChange = true; binding.onactived.notify(); } - } - else { + } else { if (binding.state) { binding.state = false; binding.justChange = true; @@ -107,7 +106,7 @@ void Events::bind(const std::string& name, inputtype type, mousecode code) { } void Events::bind(const std::string& name, inputtype type, int code) { - bindings[name] = Binding(type, code); + bindings.emplace(name, Binding(type, code)); } bool Events::active(const std::string& name) {