From 04a9c2045efb6a53c53be48b1152abfa51c1cffe Mon Sep 17 00:00:00 2001 From: MihailRis Date: Thu, 25 Jan 2024 16:04:02 +0300 Subject: [PATCH] lua: file library --- res/scripts/stdlib.lua | 3 +- src/engine.cpp | 2 + src/files/engine_paths.cpp | 74 +++++++++++++++++++++++---------- src/files/engine_paths.h | 36 +++++++++------- src/logic/scripting/api_lua.cpp | 71 +++++++++++++++++++++++++++++++ 5 files changed, 147 insertions(+), 39 deletions(-) diff --git a/res/scripts/stdlib.lua b/res/scripts/stdlib.lua index c6e7814c..fb20d468 100644 --- a/res/scripts/stdlib.lua +++ b/res/scripts/stdlib.lua @@ -31,8 +31,7 @@ end -- nocache - ignore cached script, load anyway function load_script(path, nocache) local packname, filename = parse_path(path) - local packpath = pack.get_folder(packname) - local fullpath = packpath..filename + local fullpath = file.resolve(path); -- __cached_scripts used in condition because cached result may be nil if not nocache and __cached_scripts[fullpath] ~= nil then diff --git a/src/engine.cpp b/src/engine.cpp index 2204945e..7ac81c6c 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -162,6 +162,8 @@ void Engine::loadContent() { } } assets->extend(*new_assets.get()); + + paths->setContentPacks(&contentPacks); } void Engine::loadWorldContent(const fs::path& folder) { diff --git a/src/files/engine_paths.cpp b/src/files/engine_paths.cpp index 354fd920..bab9059c 100644 --- a/src/files/engine_paths.cpp +++ b/src/files/engine_paths.cpp @@ -6,37 +6,35 @@ #define SCREENSHOTS_FOLDER "screenshots" -namespace fs = std::filesystem; - fs::path EnginePaths::getUserfiles() const { - return userfiles; + return userfiles; } fs::path EnginePaths::getResources() const { - return resources; + return resources; } fs::path EnginePaths::getScreenshotFile(std::string ext) { - fs::path folder = userfiles/fs::path(SCREENSHOTS_FOLDER); - if (!fs::is_directory(folder)) { - fs::create_directory(folder); - } + fs::path folder = userfiles/fs::path(SCREENSHOTS_FOLDER); + if (!fs::is_directory(folder)) { + fs::create_directory(folder); + } - auto t = std::time(nullptr); + auto t = std::time(nullptr); auto tm = *std::localtime(&t); - const char* format = "%Y-%m-%d_%H-%M-%S"; - std::stringstream ss; - ss << std::put_time(&tm, format); - std::string datetimestr = ss.str(); + const char* format = "%Y-%m-%d_%H-%M-%S"; + std::stringstream ss; + ss << std::put_time(&tm, format); + std::string datetimestr = ss.str(); - fs::path filename = folder/fs::path("screenshot-"+datetimestr+"."+ext); - uint index = 0; - while (fs::exists(filename)) { - filename = folder/fs::path("screenshot-"+datetimestr+"-"+std::to_string(index)+"."+ext); - index++; - } - return filename; + fs::path filename = folder/fs::path("screenshot-"+datetimestr+"."+ext); + uint index = 0; + while (fs::exists(filename)) { + filename = folder/fs::path("screenshot-"+datetimestr+"-"+std::to_string(index)+"."+ext); + index++; + } + return filename; } fs::path EnginePaths::getWorldsFolder() { @@ -44,15 +42,45 @@ fs::path EnginePaths::getWorldsFolder() { } bool EnginePaths::isWorldNameUsed(std::string name) { - return fs::exists(EnginePaths::getWorldsFolder()/fs::u8path(name)); + return fs::exists(EnginePaths::getWorldsFolder()/fs::u8path(name)); } void EnginePaths::setUserfiles(fs::path folder) { - this->userfiles = folder; + this->userfiles = folder; } void EnginePaths::setResources(fs::path folder) { - this->resources = folder; + this->resources = folder; +} + +void EnginePaths::setContentPacks(std::vector* contentPacks) { + this->contentPacks = contentPacks; +} + +fs::path EnginePaths::resolve(std::string path) { + size_t separator = path.find(':'); + if (separator == std::string::npos) { + return fs::path(path); + } + std::string prefix = path.substr(0, separator); + std::string filename = path.substr(separator+1); + + if (prefix == "res" || prefix == "core") { + return resources/fs::path(filename); + } + + if (prefix == "user") { + return userfiles/fs::path(filename); + } + + if (contentPacks) { + for (auto& pack : *contentPacks) { + if (pack.id == prefix) { + return pack.folder/fs::path(filename); + } + } + } + return fs::path("./"+filename); } ResPaths::ResPaths(fs::path mainRoot, std::vector roots) diff --git a/src/files/engine_paths.h b/src/files/engine_paths.h index 62f02b38..4a25161f 100644 --- a/src/files/engine_paths.h +++ b/src/files/engine_paths.h @@ -5,30 +5,38 @@ #include #include +#include "../content/ContentPack.h" + +namespace fs = std::filesystem; + class EnginePaths { - std::filesystem::path userfiles {"."}; - std::filesystem::path resources {"res"}; + fs::path userfiles {"."}; + fs::path resources {"res"}; + std::vector* contentPacks = nullptr; public: - std::filesystem::path getUserfiles() const; - std::filesystem::path getResources() const; + fs::path getUserfiles() const; + fs::path getResources() const; - std::filesystem::path getScreenshotFile(std::string ext); - std::filesystem::path getWorldsFolder(); + fs::path getScreenshotFile(std::string ext); + fs::path getWorldsFolder(); bool isWorldNameUsed(std::string name); - void setUserfiles(std::filesystem::path folder); - void setResources(std::filesystem::path folder); + void setUserfiles(fs::path folder); + void setResources(fs::path folder); + void setContentPacks(std::vector* contentPacks); + + fs::path resolve(std::string path); }; class ResPaths { - std::filesystem::path mainRoot; - std::vector roots; + fs::path mainRoot; + std::vector roots; public: - ResPaths(std::filesystem::path mainRoot, - std::vector roots); + ResPaths(fs::path mainRoot, + std::vector roots); - std::filesystem::path find(const std::string& filename) const; - std::vector listdir(const std::string& folder) const; + fs::path find(const std::string& filename) const; + std::vector listdir(const std::string& folder) const; }; #endif // FILES_ENGINE_PATHS_H_ \ No newline at end of file diff --git a/src/logic/scripting/api_lua.cpp b/src/logic/scripting/api_lua.cpp index 45375af8..2f09c970 100644 --- a/src/logic/scripting/api_lua.cpp +++ b/src/logic/scripting/api_lua.cpp @@ -3,6 +3,7 @@ #include +#include "../../files/files.h" #include "../../physics/Hitbox.h" #include "../../objects/Player.h" #include "../../world/Level.h" @@ -29,6 +30,75 @@ inline void luaL_openlib(lua_State* L, const char* name, const luaL_Reg* libfunc lua_setglobal(L, name); } +/* == file library == */ +static int l_file_resolve(lua_State* L) { + std::string path = lua_tostring(L, 1); + fs::path resolved = scripting::engine->getPaths()->resolve(path); + lua_pushstring(L, resolved.u8string().c_str()); + return 1; +} + +static int l_file_read(lua_State* L) { + auto paths = scripting::engine->getPaths(); + fs::path path = paths->resolve(lua_tostring(L, 1)); + if (fs::is_regular_file(path)) { + lua_pushstring(L, files::read_string(path).c_str()); + return 1; + } + return luaL_error(L, "file does not exists '%s'", path.u8string().c_str()); +} + +static int l_file_write(lua_State* L) { + auto paths = scripting::engine->getPaths(); + fs::path path = paths->resolve(lua_tostring(L, 1)); + const char* text = lua_tostring(L, 2); + files::write_string(path, text); + return 1; +} + +static int l_file_exists(lua_State* L) { + auto paths = scripting::engine->getPaths(); + fs::path path = paths->resolve(lua_tostring(L, 1)); + lua_pushboolean(L, fs::exists(path)); + return 1; +} + +static int l_file_isfile(lua_State* L) { + auto paths = scripting::engine->getPaths(); + fs::path path = paths->resolve(lua_tostring(L, 1)); + lua_pushboolean(L, fs::is_regular_file(path)); + return 1; +} + +static int l_file_isdir(lua_State* L) { + auto paths = scripting::engine->getPaths(); + fs::path path = paths->resolve(lua_tostring(L, 1)); + lua_pushboolean(L, fs::is_directory(path)); + return 1; +} + +static int l_file_length(lua_State* L) { + auto paths = scripting::engine->getPaths(); + fs::path path = paths->resolve(lua_tostring(L, 1)); + if (fs::exists(path)){ + lua_pushinteger(L, fs::file_size(path)); + } else { + lua_pushinteger(L, -1); + } + return 1; +} + +static const luaL_Reg filelib [] = { + {"resolve", l_file_resolve}, + {"read", l_file_read}, + {"file", l_file_write}, + {"exists", l_file_exists}, + {"isfile", l_file_isfile}, + {"isdir", l_file_isdir}, + {"length", l_file_length}, + {NULL, NULL} +}; + /* == time library == */ static int l_time_uptime(lua_State* L) { lua_pushnumber(L, Window::time()); @@ -313,6 +383,7 @@ void apilua::create_funcs(lua_State* L) { luaL_openlib(L, "world", worldlib, 0); luaL_openlib(L, "player", playerlib, 0); luaL_openlib(L, "time", timelib, 0); + luaL_openlib(L, "file", filelib, 0); lua_addfunc(L, l_block_index, "block_index"); lua_addfunc(L, l_block_name, "block_name");