From e5d558d357e6d75ac9301af4e0e0cd91ce9fa77d Mon Sep 17 00:00:00 2001 From: MihailRis Date: Thu, 30 Jan 2025 15:02:28 +0300 Subject: [PATCH 01/16] move world-related sources from files/ to world/files --- src/content/ContentReport.cpp | 2 +- src/content/ContentReport.hpp | 2 +- src/files/engine_paths.cpp | 2 +- src/logic/ChunksController.cpp | 2 +- src/logic/EngineController.cpp | 4 ++-- src/logic/LevelController.cpp | 2 +- src/logic/scripting/lua/libs/libpack.cpp | 2 +- src/logic/scripting/lua/libs/libworld.cpp | 2 +- src/voxels/Chunks.cpp | 2 +- src/voxels/GlobalChunks.cpp | 2 +- src/voxels/compressed_chunks.cpp | 2 +- src/world/World.cpp | 2 +- src/{ => world}/files/RegionsLayer.cpp | 0 src/{ => world}/files/WorldConverter.cpp | 2 +- src/{ => world}/files/WorldConverter.hpp | 2 +- src/{ => world}/files/WorldFiles.cpp | 0 src/{ => world}/files/WorldFiles.hpp | 2 +- src/{ => world}/files/WorldRegions.cpp | 0 src/{ => world}/files/WorldRegions.hpp | 2 +- src/{ => world}/files/compatibility.cpp | 0 src/{ => world}/files/compatibility.hpp | 2 +- src/{ => world}/files/world_regions_fwd.hpp | 0 22 files changed, 18 insertions(+), 18 deletions(-) rename src/{ => world}/files/RegionsLayer.cpp (100%) rename src/{ => world}/files/WorldConverter.cpp (99%) rename src/{ => world}/files/WorldConverter.hpp (98%) rename src/{ => world}/files/WorldFiles.cpp (100%) rename src/{ => world}/files/WorldFiles.hpp (98%) rename src/{ => world}/files/WorldRegions.cpp (100%) rename src/{ => world}/files/WorldRegions.hpp (99%) rename src/{ => world}/files/compatibility.cpp (100%) rename src/{ => world}/files/compatibility.hpp (89%) rename src/{ => world}/files/world_regions_fwd.hpp (100%) diff --git a/src/content/ContentReport.cpp b/src/content/ContentReport.cpp index 7de04be5..c25a903a 100644 --- a/src/content/ContentReport.cpp +++ b/src/content/ContentReport.cpp @@ -8,7 +8,7 @@ #include "items/ItemDef.hpp" #include "voxels/Block.hpp" #include "world/World.hpp" -#include "files/WorldFiles.hpp" +#include "world/files/WorldFiles.hpp" #include "Content.hpp" ContentReport::ContentReport( diff --git a/src/content/ContentReport.hpp b/src/content/ContentReport.hpp index 3476b872..62893527 100644 --- a/src/content/ContentReport.hpp +++ b/src/content/ContentReport.hpp @@ -11,7 +11,7 @@ #include "typedefs.hpp" #include "Content.hpp" #include "data/StructLayout.hpp" -#include "files/world_regions_fwd.hpp" +#include "world/files/world_regions_fwd.hpp" namespace fs = std::filesystem; diff --git a/src/files/engine_paths.cpp b/src/files/engine_paths.cpp index 2c8cd02c..0cb90de8 100644 --- a/src/files/engine_paths.cpp +++ b/src/files/engine_paths.cpp @@ -9,7 +9,7 @@ #include "util/stringutil.hpp" #include -#include "WorldFiles.hpp" +#include "world/files/WorldFiles.hpp" #include "debug/Logger.hpp" static debug::Logger logger("engine-paths"); diff --git a/src/logic/ChunksController.cpp b/src/logic/ChunksController.cpp index 0f341322..ccdd59b1 100644 --- a/src/logic/ChunksController.cpp +++ b/src/logic/ChunksController.cpp @@ -4,7 +4,7 @@ #include #include "content/Content.hpp" -#include "files/WorldFiles.hpp" +#include "world/files/WorldFiles.hpp" #include "graphics/core/Mesh.hpp" #include "lighting/Lighting.hpp" #include "maths/voxmaths.hpp" diff --git a/src/logic/EngineController.cpp b/src/logic/EngineController.cpp index 90106ec9..9eeea3a6 100644 --- a/src/logic/EngineController.cpp +++ b/src/logic/EngineController.cpp @@ -9,8 +9,8 @@ #include "debug/Logger.hpp" #include "coders/json.hpp" #include "content/ContentReport.hpp" -#include "files/WorldConverter.hpp" -#include "files/WorldFiles.hpp" +#include "world/files/WorldConverter.hpp" +#include "world/files/WorldFiles.hpp" #include "frontend/locale.hpp" #include "frontend/menu.hpp" #include "frontend/screens/LevelScreen.hpp" diff --git a/src/logic/LevelController.cpp b/src/logic/LevelController.cpp index f99d7fd6..4404fb3a 100644 --- a/src/logic/LevelController.cpp +++ b/src/logic/LevelController.cpp @@ -4,7 +4,7 @@ #include "debug/Logger.hpp" #include "engine/Engine.hpp" -#include "files/WorldFiles.hpp" +#include "world/files/WorldFiles.hpp" #include "maths/voxmaths.hpp" #include "objects/Entities.hpp" #include "objects/Players.hpp" diff --git a/src/logic/scripting/lua/libs/libpack.cpp b/src/logic/scripting/lua/libs/libpack.cpp index 5b3977a4..3629679e 100644 --- a/src/logic/scripting/lua/libs/libpack.cpp +++ b/src/logic/scripting/lua/libs/libpack.cpp @@ -7,7 +7,7 @@ #include "assets/AssetsLoader.hpp" #include "content/Content.hpp" #include "engine/Engine.hpp" -#include "files/WorldFiles.hpp" +#include "world/files/WorldFiles.hpp" #include "files/engine_paths.hpp" #include "world/Level.hpp" #include "world/World.hpp" diff --git a/src/logic/scripting/lua/libs/libworld.cpp b/src/logic/scripting/lua/libs/libworld.cpp index f858f963..24cfd733 100644 --- a/src/logic/scripting/lua/libs/libworld.cpp +++ b/src/logic/scripting/lua/libs/libworld.cpp @@ -6,7 +6,7 @@ #include "assets/AssetsLoader.hpp" #include "coders/json.hpp" #include "engine/Engine.hpp" -#include "files/WorldFiles.hpp" +#include "world/files/WorldFiles.hpp" #include "files/engine_paths.hpp" #include "files/files.hpp" #include "lighting/Lighting.hpp" diff --git a/src/voxels/Chunks.cpp b/src/voxels/Chunks.cpp index bf9b2990..5b5a2cd9 100644 --- a/src/voxels/Chunks.cpp +++ b/src/voxels/Chunks.cpp @@ -9,7 +9,7 @@ #include "data/StructLayout.hpp" #include "coders/byte_utils.hpp" #include "content/Content.hpp" -#include "files/WorldFiles.hpp" +#include "world/files/WorldFiles.hpp" #include "graphics/core/Mesh.hpp" #include "lighting/Lightmap.hpp" #include "maths/aabb.hpp" diff --git a/src/voxels/GlobalChunks.cpp b/src/voxels/GlobalChunks.cpp index 1e67a374..a4c11151 100644 --- a/src/voxels/GlobalChunks.cpp +++ b/src/voxels/GlobalChunks.cpp @@ -5,7 +5,7 @@ #include "content/Content.hpp" #include "coders/json.hpp" #include "debug/Logger.hpp" -#include "files/WorldFiles.hpp" +#include "world/files/WorldFiles.hpp" #include "items/Inventories.hpp" #include "lighting/Lightmap.hpp" #include "maths/voxmaths.hpp" diff --git a/src/voxels/compressed_chunks.cpp b/src/voxels/compressed_chunks.cpp index 24cc02dd..9bc5bf7e 100644 --- a/src/voxels/compressed_chunks.cpp +++ b/src/voxels/compressed_chunks.cpp @@ -3,7 +3,7 @@ #include "coders/rle.hpp" #include "coders/gzip.hpp" -#include "files/WorldFiles.hpp" +#include "world/files/WorldFiles.hpp" inline constexpr int HAS_VOXELS = 0x1; inline constexpr int HAS_METADATA = 0x2; diff --git a/src/world/World.cpp b/src/world/World.cpp index 54785862..2319fe2c 100644 --- a/src/world/World.cpp +++ b/src/world/World.cpp @@ -7,7 +7,7 @@ #include "content/Content.hpp" #include "content/ContentReport.hpp" #include "debug/Logger.hpp" -#include "files/WorldFiles.hpp" +#include "world/files/WorldFiles.hpp" #include "items/Inventories.hpp" #include "objects/Entities.hpp" #include "objects/Player.hpp" diff --git a/src/files/RegionsLayer.cpp b/src/world/files/RegionsLayer.cpp similarity index 100% rename from src/files/RegionsLayer.cpp rename to src/world/files/RegionsLayer.cpp diff --git a/src/files/WorldConverter.cpp b/src/world/files/WorldConverter.cpp similarity index 99% rename from src/files/WorldConverter.cpp rename to src/world/files/WorldConverter.cpp index f9484142..25a0ca9d 100644 --- a/src/files/WorldConverter.cpp +++ b/src/world/files/WorldConverter.cpp @@ -6,7 +6,7 @@ #include #include "content/ContentReport.hpp" -#include "files/compatibility.hpp" +#include "compatibility.hpp" #include "debug/Logger.hpp" #include "files/files.hpp" #include "objects/Player.hpp" diff --git a/src/files/WorldConverter.hpp b/src/world/files/WorldConverter.hpp similarity index 98% rename from src/files/WorldConverter.hpp rename to src/world/files/WorldConverter.hpp index b7852c97..499fba3c 100644 --- a/src/files/WorldConverter.hpp +++ b/src/world/files/WorldConverter.hpp @@ -6,7 +6,7 @@ #include "delegates.hpp" #include "interfaces/Task.hpp" -#include "files/world_regions_fwd.hpp" +#include "world/files/world_regions_fwd.hpp" #include "typedefs.hpp" namespace fs = std::filesystem; diff --git a/src/files/WorldFiles.cpp b/src/world/files/WorldFiles.cpp similarity index 100% rename from src/files/WorldFiles.cpp rename to src/world/files/WorldFiles.cpp diff --git a/src/files/WorldFiles.hpp b/src/world/files/WorldFiles.hpp similarity index 98% rename from src/files/WorldFiles.hpp rename to src/world/files/WorldFiles.hpp index 2d8ff0f0..d8e1f62d 100644 --- a/src/files/WorldFiles.hpp +++ b/src/world/files/WorldFiles.hpp @@ -11,7 +11,7 @@ #include "typedefs.hpp" #include "voxels/Chunk.hpp" #include "WorldRegions.hpp" -#include "files.hpp" +#include "files/files.hpp" #define GLM_ENABLE_EXPERIMENTAL #include diff --git a/src/files/WorldRegions.cpp b/src/world/files/WorldRegions.cpp similarity index 100% rename from src/files/WorldRegions.cpp rename to src/world/files/WorldRegions.cpp diff --git a/src/files/WorldRegions.hpp b/src/world/files/WorldRegions.hpp similarity index 99% rename from src/files/WorldRegions.hpp rename to src/world/files/WorldRegions.hpp index ad0bc584..75be22ac 100644 --- a/src/files/WorldRegions.hpp +++ b/src/world/files/WorldRegions.hpp @@ -13,7 +13,7 @@ #include "voxels/Chunk.hpp" #include "maths/voxmaths.hpp" #include "coders/compression.hpp" -#include "files.hpp" +#include "files/files.hpp" #include "world_regions_fwd.hpp" #define GLM_ENABLE_EXPERIMENTAL diff --git a/src/files/compatibility.cpp b/src/world/files/compatibility.cpp similarity index 100% rename from src/files/compatibility.cpp rename to src/world/files/compatibility.cpp diff --git a/src/files/compatibility.hpp b/src/world/files/compatibility.hpp similarity index 89% rename from src/files/compatibility.hpp rename to src/world/files/compatibility.hpp index cf78b5bc..736c68a9 100644 --- a/src/files/compatibility.hpp +++ b/src/world/files/compatibility.hpp @@ -2,7 +2,7 @@ #include "typedefs.hpp" #include "util/Buffer.hpp" -#include "files/world_regions_fwd.hpp" +#include "world/files/world_regions_fwd.hpp" namespace compatibility { /// @brief Convert region file from version 2 to 3 diff --git a/src/files/world_regions_fwd.hpp b/src/world/files/world_regions_fwd.hpp similarity index 100% rename from src/files/world_regions_fwd.hpp rename to src/world/files/world_regions_fwd.hpp From 1e22882284e1f7889d8216acb48f4bd06d20dc7f Mon Sep 17 00:00:00 2001 From: MihailRis Date: Thu, 30 Jan 2025 16:53:52 +0300 Subject: [PATCH 02/16] rename 'files' to 'io' --- src/assets/AssetsLoader.cpp | 6 +- src/assets/assetload_funcs.cpp | 14 ++--- src/coders/GLSLExtension.cpp | 6 +- src/coders/imageio.cpp | 4 +- src/coders/png.cpp | 4 +- src/coders/toml.cpp | 2 +- src/content/ContentLoader.cpp | 32 +++++------ src/content/ContentPack.cpp | 8 +-- src/content/ContentReport.cpp | 4 +- src/content/loading/GeneratorLoader.cpp | 8 +-- src/core_defs.cpp | 6 +- src/engine/Engine.cpp | 14 ++--- src/engine/Engine.hpp | 4 +- src/frontend/UiDocument.cpp | 4 +- src/frontend/locale.cpp | 8 +-- src/frontend/menu.cpp | 2 +- src/frontend/screens/LevelScreen.cpp | 2 +- src/graphics/render/Decorator.cpp | 2 +- src/{files => io}/engine_paths.cpp | 4 +- src/{files => io}/engine_paths.hpp | 0 src/{files/files.cpp => io/io.cpp} | 56 +++++++++---------- src/{files/files.hpp => io/io.hpp} | 2 +- src/{files => io}/settings_io.cpp | 0 src/{files => io}/settings_io.hpp | 0 src/{files => io}/util.hpp | 2 +- src/logic/EngineController.cpp | 3 - src/logic/scripting/lua/libs/libcore.cpp | 6 +- src/logic/scripting/lua/libs/libfile.cpp | 14 ++--- .../scripting/lua/libs/libgeneration.cpp | 8 +-- src/logic/scripting/lua/libs/libinput.cpp | 4 +- src/logic/scripting/lua/libs/libpack.cpp | 2 +- src/logic/scripting/lua/libs/libworld.cpp | 6 +- src/logic/scripting/lua/lua_engine.cpp | 6 +- .../lua/usertypes/lua_type_heightmap.cpp | 2 +- src/logic/scripting/scripting.cpp | 12 ++-- src/logic/scripting/scripting_hud.cpp | 6 +- .../scripting/scripting_world_generation.cpp | 4 +- src/util/command_line.cpp | 2 +- src/world/World.cpp | 6 +- src/world/files/WorldConverter.cpp | 10 ++-- src/world/files/WorldFiles.cpp | 18 +++--- src/world/files/WorldFiles.hpp | 2 +- src/world/files/WorldRegions.hpp | 4 +- test/coders/lua_parsing.cpp | 4 +- test/coders/vec3.cpp | 4 +- 45 files changed, 157 insertions(+), 160 deletions(-) rename src/{files => io}/engine_paths.cpp (96%) rename src/{files => io}/engine_paths.hpp (100%) rename src/{files/files.cpp => io/io.cpp} (72%) rename src/{files/files.hpp => io/io.hpp} (99%) rename src/{files => io}/settings_io.cpp (100%) rename src/{files => io}/settings_io.hpp (100%) rename src/{files => io}/util.hpp (95%) diff --git a/src/assets/AssetsLoader.cpp b/src/assets/AssetsLoader.cpp index 3f050055..8c7fc2dc 100644 --- a/src/assets/AssetsLoader.cpp +++ b/src/assets/AssetsLoader.cpp @@ -9,8 +9,8 @@ #include "content/Content.hpp" #include "content/ContentPack.hpp" #include "debug/Logger.hpp" -#include "files/engine_paths.hpp" -#include "files/files.hpp" +#include "io/engine_paths.hpp" +#include "io/io.hpp" #include "graphics/core/Texture.hpp" #include "logic/scripting/scripting.hpp" #include "objects/rigging.hpp" @@ -187,7 +187,7 @@ void AssetsLoader::processPreloadList(AssetType tag, const dv::value& list) { } void AssetsLoader::processPreloadConfig(const fs::path& file) { - auto root = files::read_json(file); + auto root = io::read_json(file); processPreloadList(AssetType::ATLAS, root["atlases"]); processPreloadList(AssetType::FONT, root["fonts"]); processPreloadList(AssetType::SHADER, root["shaders"]); diff --git a/src/assets/assetload_funcs.cpp b/src/assets/assetload_funcs.cpp index 399e7959..929d5e62 100644 --- a/src/assets/assetload_funcs.cpp +++ b/src/assets/assetload_funcs.cpp @@ -13,8 +13,8 @@ #include "coders/vec3.hpp" #include "constants.hpp" #include "debug/Logger.hpp" -#include "files/engine_paths.hpp" -#include "files/files.hpp" +#include "io/engine_paths.hpp" +#include "io/io.hpp" #include "frontend/UiDocument.hpp" #include "graphics/core/Atlas.hpp" #include "graphics/core/Font.hpp" @@ -72,8 +72,8 @@ assetload::postfunc assetload::shader( fs::path vertexFile = paths->find(filename + ".glslv"); fs::path fragmentFile = paths->find(filename + ".glslf"); - std::string vertexSource = files::read_string(vertexFile); - std::string fragmentSource = files::read_string(fragmentFile); + std::string vertexSource = io::read_string(vertexFile); + std::string fragmentSource = io::read_string(fragmentFile); vertexSource = Shader::preprocessor->process(vertexFile, vertexSource); fragmentSource = @@ -273,7 +273,7 @@ assetload::postfunc assetload::model( ) { auto path = paths->find(file + ".vec3"); if (fs::exists(path)) { - auto bytes = files::read_bytes_buffer(path); + auto bytes = io::read_bytes_buffer(path); auto modelVEC3 = std::make_shared(vec3::load(path.u8string(), bytes)); return [loader, name, modelVEC3=std::move(modelVEC3)](Assets* assets) { for (auto& [modelName, model] : modelVEC3->models) { @@ -292,7 +292,7 @@ assetload::postfunc assetload::model( }; } path = paths->find(file + ".obj"); - auto text = files::read_string(path); + auto text = io::read_string(path); try { auto model = obj::parse(path.u8string(), text).release(); return [=](Assets* assets) { @@ -309,7 +309,7 @@ static void read_anim_file( const std::string& animFile, std::vector>& frameList ) { - auto root = files::read_json(animFile); + auto root = io::read_json(animFile); float frameDuration = DEFAULT_FRAME_DURATION; std::string frameName; diff --git a/src/coders/GLSLExtension.cpp b/src/coders/GLSLExtension.cpp index 186522a5..c7f45cd7 100644 --- a/src/coders/GLSLExtension.cpp +++ b/src/coders/GLSLExtension.cpp @@ -5,8 +5,8 @@ #include #include -#include "files/engine_paths.hpp" -#include "files/files.hpp" +#include "io/engine_paths.hpp" +#include "io/io.hpp" #include "typedefs.hpp" #include "util/stringutil.hpp" @@ -22,7 +22,7 @@ void GLSLExtension::setPaths(const ResPaths* paths) { void GLSLExtension::loadHeader(const std::string& name) { fs::path file = paths->find("shaders/lib/" + name + ".glsl"); - std::string source = files::read_string(file); + std::string source = io::read_string(file); addHeader(name, ""); addHeader(name, process(file, source, true)); } diff --git a/src/coders/imageio.cpp b/src/coders/imageio.cpp index a80f422c..5f082abc 100644 --- a/src/coders/imageio.cpp +++ b/src/coders/imageio.cpp @@ -5,7 +5,7 @@ #include #include "graphics/core/ImageData.hpp" -#include "files/files.hpp" +#include "io/io.hpp" #include "png.hpp" namespace fs = std::filesystem; @@ -41,7 +41,7 @@ std::unique_ptr imageio::read(const fs::path& filename) { "file format is not supported (read): " + filename.u8string() ); } - auto bytes = files::read_bytes_buffer(filename); + auto bytes = io::read_bytes_buffer(filename); try { return std::unique_ptr(found->second(bytes.data(), bytes.size())); } catch (const std::runtime_error& err) { diff --git a/src/coders/png.cpp b/src/coders/png.cpp index b29afd34..6671922c 100644 --- a/src/coders/png.cpp +++ b/src/coders/png.cpp @@ -6,7 +6,7 @@ #include #include "debug/Logger.hpp" -#include "files/files.hpp" +#include "io/io.hpp" #include "graphics/core/GLTexture.hpp" #include "graphics/core/ImageData.hpp" @@ -212,7 +212,7 @@ std::unique_ptr png::load_texture(const ubyte* bytes, size_t size) { } std::unique_ptr png::load_texture(const std::string& filename) { - auto bytes = files::read_bytes_buffer(fs::u8path(filename)); + auto bytes = io::read_bytes_buffer(fs::u8path(filename)); try { return load_texture(bytes.data(), bytes.size()); } catch (const std::runtime_error& err) { diff --git a/src/coders/toml.cpp b/src/coders/toml.cpp index 080df90e..3896bcec 100644 --- a/src/coders/toml.cpp +++ b/src/coders/toml.cpp @@ -7,7 +7,7 @@ #include #include "data/setting.hpp" -#include "files/settings_io.hpp" +#include "io/settings_io.hpp" #include "util/stringutil.hpp" #include "commons.hpp" diff --git a/src/content/ContentLoader.cpp b/src/content/ContentLoader.cpp index ce3f5060..1603334d 100644 --- a/src/content/ContentLoader.cpp +++ b/src/content/ContentLoader.cpp @@ -12,7 +12,7 @@ #include "coders/json.hpp" #include "core_defs.hpp" #include "debug/Logger.hpp" -#include "files/files.hpp" +#include "io/io.hpp" #include "items/ItemDef.hpp" #include "logic/scripting/scripting.hpp" #include "objects/rigging.hpp" @@ -54,8 +54,8 @@ static void detect_defs( if (name[0] == '_') { continue; } - if (fs::is_regular_file(file) && files::is_data_file(file)) { - auto map = files::read_object(file); + if (fs::is_regular_file(file) && io::is_data_file(file)) { + auto map = io::read_object(file); std::string id = prefix.empty() ? name : prefix + ":" + name; detected.emplace_back(id); } else if (fs::is_directory(file) && @@ -78,9 +78,9 @@ static void detect_defs_pairs( if (name[0] == '_') { continue; } - if (fs::is_regular_file(file) && files::is_data_file(file)) { + if (fs::is_regular_file(file) && io::is_data_file(file)) { try { - auto map = files::read_object(file); + auto map = io::read_object(file); auto id = prefix.empty() ? name : prefix + ":" + name; auto caption = util::id_to_caption(id); map.at("caption").get(caption); @@ -147,7 +147,7 @@ void ContentLoader::fixPackIndices() { dv::value root; if (fs::is_regular_file(contentFile)) { - root = files::read_json(contentFile); + root = io::read_json(contentFile); } else { root = dv::object(); } @@ -159,7 +159,7 @@ void ContentLoader::fixPackIndices() { if (modified) { // rewrite modified json - files::write_json(contentFile, root); + io::write_json(contentFile, root); } } @@ -215,7 +215,7 @@ static void process_method( void ContentLoader::loadBlock( Block& def, const std::string& name, const fs::path& file ) { - auto root = files::read_json(file); + auto root = io::read_json(file); if (def.properties == nullptr) { def.properties = dv::object(); def.properties["name"] = name; @@ -404,7 +404,7 @@ void ContentLoader::loadBlock( void ContentLoader::loadItem( ItemDef& def, const std::string& name, const fs::path& file ) { - auto root = files::read_json(file); + auto root = io::read_json(file); def.properties = root; if (root.has("parent")) { @@ -448,7 +448,7 @@ void ContentLoader::loadItem( void ContentLoader::loadEntity( EntityDef& def, const std::string& name, const fs::path& file ) { - auto root = files::read_json(file); + auto root = io::read_json(file); if (root.has("parent")) { const auto& parentName = root["parent"].asString(); @@ -568,7 +568,7 @@ static std::tuple create_unit_id( void ContentLoader::loadBlockMaterial( BlockMaterial& def, const fs::path& file ) { - auto root = files::read_json(file); + auto root = io::read_json(file); root.at("steps-sound").get(def.stepsSound); root.at("place-sound").get(def.placeSound); root.at("break-sound").get(def.breakSound); @@ -580,7 +580,7 @@ void ContentLoader::loadContent(const dv::value& root) { auto configFile = pack->folder / fs::path(prefix + "/" + name + ".json"); std::string parent; if (fs::exists(configFile)) { - auto root = files::read_json(configFile); + auto root = io::read_json(configFile); root.at("parent").get(parent); } return parent; @@ -778,7 +778,7 @@ void ContentLoader::load() { // Load pack resources.json fs::path resourcesFile = folder / fs::u8path("resources.json"); if (fs::exists(resourcesFile)) { - auto resRoot = files::read_json(resourcesFile); + auto resRoot = io::read_json(resourcesFile); for (const auto& [key, arr] : resRoot.asObject()) { if (auto resType = ResourceType_from(key)) { loadResources(*resType, arr); @@ -792,7 +792,7 @@ void ContentLoader::load() { // Load pack resources aliases fs::path aliasesFile = folder / fs::u8path("resource-aliases.json"); if (fs::exists(aliasesFile)) { - auto resRoot = files::read_json(aliasesFile); + auto resRoot = io::read_json(aliasesFile); for (const auto& [key, arr] : resRoot.asObject()) { if (auto resType = ResourceType_from(key)) { loadResourceAliases(*resType, arr); @@ -821,7 +821,7 @@ void ContentLoader::load() { fs::path skeletonsDir = folder / fs::u8path("skeletons"); foreach_file(skeletonsDir, [this](const fs::path& file) { std::string name = pack->id + ":" + file.stem().u8string(); - std::string text = files::read_string(file); + std::string text = io::read_string(file); builder.add( rigging::SkeletonConfig::parse(text, file.u8string(), name) ); @@ -830,7 +830,7 @@ void ContentLoader::load() { // Process content.json and load defined content units auto contentFile = pack->getContentFile(); if (fs::exists(contentFile)) { - loadContent(files::read_json(contentFile)); + loadContent(io::read_json(contentFile)); } } diff --git a/src/content/ContentPack.cpp b/src/content/ContentPack.cpp index 7135f231..9bcec23c 100644 --- a/src/content/ContentPack.cpp +++ b/src/content/ContentPack.cpp @@ -7,8 +7,8 @@ #include "coders/json.hpp" #include "constants.hpp" #include "data/dv.hpp" -#include "files/engine_paths.hpp" -#include "files/files.hpp" +#include "io/engine_paths.hpp" +#include "io/io.hpp" namespace fs = std::filesystem; @@ -71,7 +71,7 @@ static void checkContentPackId(const std::string& id, const fs::path& folder) { } ContentPack ContentPack::read(const std::string& path, const fs::path& folder) { - auto root = files::read_json(folder / fs::path(PACKAGE_FILENAME)); + auto root = io::read_json(folder / fs::path(PACKAGE_FILENAME)); ContentPack pack; root.at("id").get(pack.id); root.at("title").get(pack.title); @@ -151,7 +151,7 @@ std::vector ContentPack::worldPacksList(const fs::path& folder) { if (!fs::is_regular_file(listfile)) { throw std::runtime_error("missing file 'packs.list'"); } - return files::read_list(listfile); + return io::read_list(listfile); } fs::path ContentPack::findPack( diff --git a/src/content/ContentReport.cpp b/src/content/ContentReport.cpp index c25a903a..c9043507 100644 --- a/src/content/ContentReport.cpp +++ b/src/content/ContentReport.cpp @@ -4,7 +4,7 @@ #include "coders/json.hpp" #include "constants.hpp" -#include "files/files.hpp" +#include "io/io.hpp" #include "items/ItemDef.hpp" #include "voxels/Block.hpp" #include "world/World.hpp" @@ -75,7 +75,7 @@ std::shared_ptr ContentReport::create( return nullptr; } - auto root = files::read_json(filename); + auto root = io::read_json(filename); uint regionsVersion = 2U; // old worlds compatibility (pre 0.23) root.at("region-version").get(regionsVersion); auto& blocklist = root["blocks"]; diff --git a/src/content/loading/GeneratorLoader.cpp b/src/content/loading/GeneratorLoader.cpp index f9f06d80..2e903426 100644 --- a/src/content/loading/GeneratorLoader.cpp +++ b/src/content/loading/GeneratorLoader.cpp @@ -4,8 +4,8 @@ #include "../ContentPack.hpp" -#include "files/files.hpp" -#include "files/engine_paths.hpp" +#include "io/io.hpp" +#include "io/engine_paths.hpp" #include "logic/scripting/scripting.hpp" #include "world/generator/GeneratorDef.hpp" #include "world/generator/VoxelFragment.hpp" @@ -146,7 +146,7 @@ static std::vector> load_structures( structFile.u8string()); } auto fragment = std::make_unique(); - fragment->deserialize(files::read_binary_json(structFile)); + fragment->deserialize(io::read_binary_json(structFile)); logger.info() << "fragment " << name << " has size [" << fragment->getSize().x << ", " << fragment->getSize().y << ", " << fragment->getSize().z << "]"; @@ -202,7 +202,7 @@ void ContentLoader::loadGenerator( if (!fs::exists(generatorFile)) { return; } - auto map = files::read_toml(generatorsDir / fs::u8path(name + ".toml")); + auto map = io::read_toml(generatorsDir / fs::u8path(name + ".toml")); map.at("caption").get(def.caption); map.at("biome-parameters").get(def.biomeParameters); map.at("biome-bpd").get(def.biomesBPD); diff --git a/src/core_defs.cpp b/src/core_defs.cpp index fb8540ba..04ef4101 100644 --- a/src/core_defs.cpp +++ b/src/core_defs.cpp @@ -3,8 +3,8 @@ #include "items/ItemDef.hpp" #include "content/Content.hpp" #include "content/ContentBuilder.hpp" -#include "files/files.hpp" -#include "files/engine_paths.hpp" +#include "io/io.hpp" +#include "io/engine_paths.hpp" #include "window/Window.hpp" #include "window/Events.hpp" #include "window/input.hpp" @@ -31,7 +31,7 @@ void corecontent::setup(const EnginePaths& paths, ContentBuilder& builder) { auto bindsFile = paths.getResourcesFolder()/fs::path("bindings.toml"); if (fs::is_regular_file(bindsFile)) { Events::loadBindings( - bindsFile.u8string(), files::read_string(bindsFile), BindType::BIND + bindsFile.u8string(), io::read_string(bindsFile), BindType::BIND ); } diff --git a/src/engine/Engine.cpp b/src/engine/Engine.cpp index 73704468..a9aa2b98 100644 --- a/src/engine/Engine.cpp +++ b/src/engine/Engine.cpp @@ -16,7 +16,7 @@ #include "content/ContentBuilder.hpp" #include "content/ContentLoader.hpp" #include "core_defs.hpp" -#include "files/files.hpp" +#include "io/io.hpp" #include "frontend/locale.hpp" #include "frontend/menu.hpp" #include "frontend/screens/Screen.hpp" @@ -128,14 +128,14 @@ void Engine::initialize(CoreParameters coreParameters) { keepAlive(settings.ui.language.observe([this](auto lang) { setLanguage(lang); }, true)); - basePacks = files::read_list(resdir/fs::path("config/builtins.list")); + basePacks = io::read_list(resdir/fs::path("config/builtins.list")); } void Engine::loadSettings() { fs::path settings_file = paths.getSettingsFile(); if (fs::is_regular_file(settings_file)) { logger.info() << "loading settings"; - std::string text = files::read_string(settings_file); + std::string text = io::read_string(settings_file); try { toml::parse(*settingsHandler, settings_file.string(), text); } catch (const parsing_error& err) { @@ -149,7 +149,7 @@ void Engine::loadControls() { fs::path controls_file = paths.getControlsFile(); if (fs::is_regular_file(controls_file)) { logger.info() << "loading controls"; - std::string text = files::read_string(controls_file); + std::string text = io::read_string(controls_file); Events::loadBindings(controls_file.u8string(), text, BindType::BIND); } } @@ -219,10 +219,10 @@ void Engine::renderFrame() { void Engine::saveSettings() { logger.info() << "saving settings"; - files::write_string(paths.getSettingsFile(), toml::stringify(*settingsHandler)); + io::write_string(paths.getSettingsFile(), toml::stringify(*settingsHandler)); if (!params.headless) { logger.info() << "saving bindings"; - files::write_string(paths.getControlsFile(), Events::writeBindings()); + io::write_string(paths.getControlsFile(), Events::writeBindings()); } } @@ -330,7 +330,7 @@ static void load_configs(const fs::path& root) { auto bindsFile = configFolder/fs::path("bindings.toml"); if (fs::is_regular_file(bindsFile)) { Events::loadBindings( - bindsFile.u8string(), files::read_string(bindsFile), BindType::BIND + bindsFile.u8string(), io::read_string(bindsFile), BindType::BIND ); } } diff --git a/src/engine/Engine.hpp b/src/engine/Engine.hpp index d4cbf40a..fd6cb1c3 100644 --- a/src/engine/Engine.hpp +++ b/src/engine/Engine.hpp @@ -8,8 +8,8 @@ #include "content/content_fwd.hpp" #include "content/ContentPack.hpp" #include "content/PacksManager.hpp" -#include "files/engine_paths.hpp" -#include "files/settings_io.hpp" +#include "io/engine_paths.hpp" +#include "io/settings_io.hpp" #include "util/ObjectsKeeper.hpp" #include "PostRunnables.hpp" #include "Time.hpp" diff --git a/src/frontend/UiDocument.cpp b/src/frontend/UiDocument.cpp index 2108b46e..91c1e0a0 100644 --- a/src/frontend/UiDocument.cpp +++ b/src/frontend/UiDocument.cpp @@ -2,7 +2,7 @@ #include -#include "files/files.hpp" +#include "io/io.hpp" #include "graphics/ui/elements/UINode.hpp" #include "graphics/ui/elements/InventoryView.hpp" #include "graphics/ui/gui_xml.hpp" @@ -59,7 +59,7 @@ std::unique_ptr UiDocument::read( const fs::path& file, const std::string& fileName ) { - const std::string text = files::read_string(file); + const std::string text = io::read_string(file); auto xmldoc = xml::parse(file.u8string(), text); auto env = penv == nullptr diff --git a/src/frontend/locale.cpp b/src/frontend/locale.cpp index 2af78076..bc60cc38 100644 --- a/src/frontend/locale.cpp +++ b/src/frontend/locale.cpp @@ -5,7 +5,7 @@ #include "coders/json.hpp" #include "coders/commons.hpp" #include "content/ContentPack.hpp" -#include "files/files.hpp" +#include "io/io.hpp" #include "util/stringutil.hpp" #include "data/dv.hpp" #include "debug/Logger.hpp" @@ -71,7 +71,7 @@ namespace { void langs::loadLocalesInfo(const fs::path& resdir, std::string& fallback) { auto file = resdir/fs::u8path(langs::TEXTS_FOLDER)/fs::u8path("langs.json"); - auto root = files::read_json(file); + auto root = io::read_json(file); langs::locales_info.clear(); root.at("fallback").get(fallback); @@ -123,14 +123,14 @@ void langs::load(const fs::path& resdir, fs::path core_file = resdir/filename; if (fs::is_regular_file(core_file)) { - std::string text = files::read_string(core_file); + std::string text = io::read_string(core_file); Reader reader(core_file.string(), text); reader.read(lang, ""); } for (auto pack : packs) { fs::path file = pack.folder/filename; if (fs::is_regular_file(file)) { - std::string text = files::read_string(file); + std::string text = io::read_string(file); Reader reader(file.string(), text); reader.read(lang, ""); } diff --git a/src/frontend/menu.cpp b/src/frontend/menu.cpp index 4a36410c..da2e6ba2 100644 --- a/src/frontend/menu.cpp +++ b/src/frontend/menu.cpp @@ -8,7 +8,7 @@ #include "engine/Engine.hpp" #include "data/dv.hpp" #include "interfaces/Task.hpp" -#include "files/engine_paths.hpp" +#include "io/engine_paths.hpp" #include "graphics/ui/elements/Menu.hpp" #include "graphics/ui/gui_util.hpp" #include "graphics/ui/GUI.hpp" diff --git a/src/frontend/screens/LevelScreen.cpp b/src/frontend/screens/LevelScreen.cpp index 0e9eb609..fe9156cc 100644 --- a/src/frontend/screens/LevelScreen.cpp +++ b/src/frontend/screens/LevelScreen.cpp @@ -6,7 +6,7 @@ #include "core_defs.hpp" #include "debug/Logger.hpp" #include "engine/Engine.hpp" -#include "files/files.hpp" +#include "io/io.hpp" #include "frontend/LevelFrontend.hpp" #include "frontend/hud.hpp" #include "graphics/core/DrawContext.hpp" diff --git a/src/graphics/render/Decorator.cpp b/src/graphics/render/Decorator.cpp index e6331820..605e9ec6 100644 --- a/src/graphics/render/Decorator.cpp +++ b/src/graphics/render/Decorator.cpp @@ -16,7 +16,7 @@ #include "logic/LevelController.hpp" #include "util/stringutil.hpp" #include "engine/Engine.hpp" -#include "files/files.hpp" +#include "io/io.hpp" namespace fs = std::filesystem; diff --git a/src/files/engine_paths.cpp b/src/io/engine_paths.cpp similarity index 96% rename from src/files/engine_paths.cpp rename to src/io/engine_paths.cpp index 0cb90de8..df5b8347 100644 --- a/src/files/engine_paths.cpp +++ b/src/io/engine_paths.cpp @@ -293,7 +293,7 @@ dv::value ResPaths::readCombinedList(const std::string& filename) const { continue; } try { - auto value = files::read_object(path); + auto value = io::read_object(path); if (!value.isList()) { logger.warning() << "reading combined list " << root.name << ":" << filename << " is not a list (skipped)"; @@ -318,7 +318,7 @@ dv::value ResPaths::readCombinedObject(const std::string& filename) const { continue; } try { - auto value = files::read_object(path); + auto value = io::read_object(path); if (!value.isObject()) { logger.warning() << "reading combined object " << root.name << ": " diff --git a/src/files/engine_paths.hpp b/src/io/engine_paths.hpp similarity index 100% rename from src/files/engine_paths.hpp rename to src/io/engine_paths.hpp diff --git a/src/files/files.cpp b/src/io/io.cpp similarity index 72% rename from src/files/files.cpp rename to src/io/io.cpp index f7d3f460..9979b950 100644 --- a/src/files/files.cpp +++ b/src/io/io.cpp @@ -1,4 +1,4 @@ -#include "files.hpp" +#include "io.hpp" #include @@ -15,7 +15,7 @@ namespace fs = std::filesystem; -files::rafile::rafile(const fs::path& filename) +io::rafile::rafile(const fs::path& filename) : file(filename, std::ios::binary | std::ios::ate) { if (!file) { throw std::runtime_error("could not to open file " + filename.string()); @@ -24,19 +24,19 @@ files::rafile::rafile(const fs::path& filename) file.seekg(0); } -size_t files::rafile::length() const { +size_t io::rafile::length() const { return filelength; } -void files::rafile::seekg(std::streampos pos) { +void io::rafile::seekg(std::streampos pos) { file.seekg(pos); } -void files::rafile::read(char* buffer, std::streamsize size) { +void io::rafile::read(char* buffer, std::streamsize size) { file.read(buffer, size); } -bool files::write_bytes( +bool io::write_bytes( const fs::path& filename, const ubyte* data, size_t size ) { std::ofstream output(filename, std::ios::binary); @@ -46,7 +46,7 @@ bool files::write_bytes( return true; } -uint files::append_bytes( +uint io::append_bytes( const fs::path& filename, const ubyte* data, size_t size ) { std::ofstream output(filename, std::ios::binary | std::ios::app); @@ -57,7 +57,7 @@ uint files::append_bytes( return position; } -bool files::read(const fs::path& filename, char* data, size_t size) { +bool io::read(const fs::path& filename, char* data, size_t size) { std::ifstream output(filename, std::ios::binary); if (!output.is_open()) return false; output.read(data, size); @@ -65,13 +65,13 @@ bool files::read(const fs::path& filename, char* data, size_t size) { return true; } -util::Buffer files::read_bytes_buffer(const fs::path& path) { +util::Buffer io::read_bytes_buffer(const fs::path& path) { size_t size; - auto bytes = files::read_bytes(path, size); + auto bytes = io::read_bytes(path, size); return util::Buffer(std::move(bytes), size); } -std::unique_ptr files::read_bytes( +std::unique_ptr io::read_bytes( const fs::path& filename, size_t& length ) { std::ifstream input(filename, std::ios::binary); @@ -90,7 +90,7 @@ std::unique_ptr files::read_bytes( return data; } -std::vector files::read_bytes(const fs::path& filename) { +std::vector io::read_bytes(const fs::path& filename) { std::ifstream input(filename, std::ios::binary); if (!input.is_open()) return {}; input.seekg(0, std::ios_base::end); @@ -104,13 +104,13 @@ std::vector files::read_bytes(const fs::path& filename) { return data; } -std::string files::read_string(const fs::path& filename) { +std::string io::read_string(const fs::path& filename) { size_t size; auto bytes = read_bytes(filename, size); return std::string((const char*)bytes.get(), size); } -bool files::write_string(const fs::path& filename, std::string_view content) { +bool io::write_string(const fs::path& filename, std::string_view content) { std::ofstream file(filename); if (!file) { return false; @@ -119,35 +119,35 @@ bool files::write_string(const fs::path& filename, std::string_view content) { return true; } -bool files::write_json( +bool io::write_json( const fs::path& filename, const dv::value& obj, bool nice ) { - return files::write_string(filename, json::stringify(obj, nice, " ")); + return io::write_string(filename, json::stringify(obj, nice, " ")); } -bool files::write_binary_json( +bool io::write_binary_json( const fs::path& filename, const dv::value& obj, bool compression ) { auto bytes = json::to_binary(obj, compression); - return files::write_bytes(filename, bytes.data(), bytes.size()); + return io::write_bytes(filename, bytes.data(), bytes.size()); } -dv::value files::read_json(const fs::path& filename) { - std::string text = files::read_string(filename); +dv::value io::read_json(const fs::path& filename) { + std::string text = io::read_string(filename); return json::parse(filename.string(), text); } -dv::value files::read_binary_json(const fs::path& file) { +dv::value io::read_binary_json(const fs::path& file) { size_t size; - auto bytes = files::read_bytes(file, size); + auto bytes = io::read_bytes(file, size); return json::from_binary(bytes.get(), size); } -dv::value files::read_toml(const fs::path& file) { - return toml::parse(file.u8string(), files::read_string(file)); +dv::value io::read_toml(const fs::path& file) { + return toml::parse(file.u8string(), io::read_string(file)); } -std::vector files::read_list(const fs::path& filename) { +std::vector io::read_list(const fs::path& filename) { std::ifstream file(filename); if (!file) { throw std::runtime_error( @@ -177,15 +177,15 @@ static std::map data_decoders { {fs::u8path(".toml"), toml::parse}, }; -bool files::is_data_file(const fs::path& file) { +bool io::is_data_file(const fs::path& file) { return is_data_interchange_format(file.extension()); } -bool files::is_data_interchange_format(const fs::path& ext) { +bool io::is_data_interchange_format(const fs::path& ext) { return data_decoders.find(ext) != data_decoders.end(); } -dv::value files::read_object(const fs::path& file) { +dv::value io::read_object(const fs::path& file) { const auto& found = data_decoders.find(file.extension()); if (found == data_decoders.end()) { throw std::runtime_error("unknown file format"); diff --git a/src/files/files.hpp b/src/io/io.hpp similarity index 99% rename from src/files/files.hpp rename to src/io/io.hpp index 4cf509d4..5ea4c93e 100644 --- a/src/files/files.hpp +++ b/src/io/io.hpp @@ -12,7 +12,7 @@ namespace fs = std::filesystem; -namespace files { +namespace io { /// @brief Read-only random access file class rafile { std::ifstream file; diff --git a/src/files/settings_io.cpp b/src/io/settings_io.cpp similarity index 100% rename from src/files/settings_io.cpp rename to src/io/settings_io.cpp diff --git a/src/files/settings_io.hpp b/src/io/settings_io.hpp similarity index 100% rename from src/files/settings_io.hpp rename to src/io/settings_io.hpp diff --git a/src/files/util.hpp b/src/io/util.hpp similarity index 95% rename from src/files/util.hpp rename to src/io/util.hpp index 5967299e..df7682b9 100644 --- a/src/files/util.hpp +++ b/src/io/util.hpp @@ -3,7 +3,7 @@ #include #include -namespace files { +namespace io { inline bool is_valid_name(std::string_view name) { static std::string illegalChars = "\\/%?!<>:; "; for (char c : illegalChars) { diff --git a/src/logic/EngineController.cpp b/src/logic/EngineController.cpp index 9eeea3a6..fc0b1cb0 100644 --- a/src/logic/EngineController.cpp +++ b/src/logic/EngineController.cpp @@ -74,9 +74,6 @@ std::shared_ptr create_converter( content, report, [&engine, postRunnable]() { - //auto menu = engine.getGUI()->getMenu(); - //menu->reset(); - //menu->setPage("main", false); engine.postRunnable([=]() { postRunnable(); }); }, mode, diff --git a/src/logic/scripting/lua/libs/libcore.cpp b/src/logic/scripting/lua/libs/libcore.cpp index 80128971..3566e990 100644 --- a/src/logic/scripting/lua/libs/libcore.cpp +++ b/src/logic/scripting/lua/libs/libcore.cpp @@ -7,9 +7,9 @@ #include "content/Content.hpp" #include "debug/Logger.hpp" #include "engine/Engine.hpp" -#include "files/engine_paths.hpp" -#include "files/files.hpp" -#include "files/settings_io.hpp" +#include "io/engine_paths.hpp" +#include "io/io.hpp" +#include "io/settings_io.hpp" #include "frontend/menu.hpp" #include "frontend/screens/MenuScreen.hpp" #include "graphics/core/Texture.hpp" diff --git a/src/logic/scripting/lua/libs/libfile.cpp b/src/logic/scripting/lua/libs/libfile.cpp index 7fc70f46..cedef89b 100644 --- a/src/logic/scripting/lua/libs/libfile.cpp +++ b/src/logic/scripting/lua/libs/libfile.cpp @@ -4,8 +4,8 @@ #include "coders/gzip.hpp" #include "engine/Engine.hpp" -#include "files/engine_paths.hpp" -#include "files/files.hpp" +#include "io/engine_paths.hpp" +#include "io/io.hpp" #include "util/stringutil.hpp" #include "api_lua.hpp" #include "../lua_engine.hpp" @@ -41,7 +41,7 @@ static int l_resolve(lua::State* L) { static int l_read(lua::State* L) { fs::path path = resolve_path(lua::require_string(L, 1)); if (fs::is_regular_file(path)) { - return lua::pushstring(L, files::read_string(path)); + return lua::pushstring(L, io::read_string(path)); } throw std::runtime_error( "file does not exists " + util::quote(path.u8string()) @@ -65,7 +65,7 @@ static fs::path get_writeable_path(lua::State* L) { static int l_write(lua::State* L) { fs::path path = get_writeable_path(L); std::string text = lua::require_string(L, 2); - files::write_string(path, text); + io::write_string(path, text); return 1; } @@ -128,7 +128,7 @@ static int l_read_bytes(lua::State* L) { if (fs::is_regular_file(path)) { size_t length = static_cast(fs::file_size(path)); - auto bytes = files::read_bytes(path, length); + auto bytes = io::read_bytes(path, length); lua::createtable(L, length, 0); int newTable = lua::gettop(L); @@ -150,14 +150,14 @@ static int l_write_bytes(lua::State* L) { if (auto bytearray = lua::touserdata(L, 2)) { auto& bytes = bytearray->data(); return lua::pushboolean( - L, files::write_bytes(path, bytes.data(), bytes.size()) + L, io::write_bytes(path, bytes.data(), bytes.size()) ); } std::vector bytes; lua::read_bytes_from_table(L, 2, bytes); return lua::pushboolean( - L, files::write_bytes(path, bytes.data(), bytes.size()) + L, io::write_bytes(path, bytes.data(), bytes.size()) ); } diff --git a/src/logic/scripting/lua/libs/libgeneration.cpp b/src/logic/scripting/lua/libs/libgeneration.cpp index 90b681c3..3f4bc570 100644 --- a/src/logic/scripting/lua/libs/libgeneration.cpp +++ b/src/logic/scripting/lua/libs/libgeneration.cpp @@ -1,7 +1,7 @@ #include "api_lua.hpp" -#include "files/files.hpp" -#include "files/util.hpp" +#include "io/io.hpp" +#include "io/util.hpp" #include "coders/binary_json.hpp" #include "world/Level.hpp" #include "world/generator/VoxelFragment.hpp" @@ -17,7 +17,7 @@ static int l_save_fragment(lua::State* L) { auto file = paths.resolve(lua::require_string(L, 2), true); auto map = fragment->getFragment()->serialize(); auto bytes = json::to_binary(map, true); - files::write_bytes(file, bytes.data(), bytes.size()); + io::write_bytes(file, bytes.data(), bytes.size()); return 0; } @@ -41,7 +41,7 @@ static int l_load_fragment(lua::State* L) { if (!std::filesystem::exists(path)) { throw std::runtime_error("file "+path.u8string()+" does not exist"); } - auto map = files::read_binary_json(path); + auto map = io::read_binary_json(path); auto fragment = std::make_shared(); fragment->deserialize(map); diff --git a/src/logic/scripting/lua/libs/libinput.cpp b/src/logic/scripting/lua/libs/libinput.cpp index 4121a384..6796ade2 100644 --- a/src/logic/scripting/lua/libs/libinput.cpp +++ b/src/logic/scripting/lua/libs/libinput.cpp @@ -1,7 +1,7 @@ #include #include "engine/Engine.hpp" -#include "files/files.hpp" +#include "io/io.hpp" #include "frontend/hud.hpp" #include "frontend/screens/Screen.hpp" #include "graphics/ui/GUI.hpp" @@ -141,7 +141,7 @@ static void resetPackBindings(fs::path& packFolder) { if (fs::is_regular_file(bindsFile)) { Events::loadBindings( bindsFile.u8string(), - files::read_string(bindsFile), + io::read_string(bindsFile), BindType::REBIND ); } diff --git a/src/logic/scripting/lua/libs/libpack.cpp b/src/logic/scripting/lua/libs/libpack.cpp index 3629679e..99561538 100644 --- a/src/logic/scripting/lua/libs/libpack.cpp +++ b/src/logic/scripting/lua/libs/libpack.cpp @@ -8,7 +8,7 @@ #include "content/Content.hpp" #include "engine/Engine.hpp" #include "world/files/WorldFiles.hpp" -#include "files/engine_paths.hpp" +#include "io/engine_paths.hpp" #include "world/Level.hpp" #include "world/World.hpp" #include "api_lua.hpp" diff --git a/src/logic/scripting/lua/libs/libworld.cpp b/src/logic/scripting/lua/libs/libworld.cpp index 24cfd733..07c64feb 100644 --- a/src/logic/scripting/lua/libs/libworld.cpp +++ b/src/logic/scripting/lua/libs/libworld.cpp @@ -7,8 +7,8 @@ #include "coders/json.hpp" #include "engine/Engine.hpp" #include "world/files/WorldFiles.hpp" -#include "files/engine_paths.hpp" -#include "files/files.hpp" +#include "io/engine_paths.hpp" +#include "io/io.hpp" #include "lighting/Lighting.hpp" #include "voxels/Chunk.hpp" #include "voxels/Chunks.hpp" @@ -44,7 +44,7 @@ static int l_get_list(lua::State* L) { const auto& folder = worlds[i]; auto root = - json::parse(files::read_string(folder / fs::u8path("world.json"))); + json::parse(io::read_string(folder / fs::u8path("world.json"))); const auto& versionMap = root["version"]; int versionMajor = versionMap["major"].asInteger(); int versionMinor = versionMap["minor"].asInteger(); diff --git a/src/logic/scripting/lua/lua_engine.cpp b/src/logic/scripting/lua/lua_engine.cpp index 1f4bde7d..6a494aa2 100644 --- a/src/logic/scripting/lua/lua_engine.cpp +++ b/src/logic/scripting/lua/lua_engine.cpp @@ -3,8 +3,8 @@ #include #include -#include "files/files.hpp" -#include "files/engine_paths.hpp" +#include "io/io.hpp" +#include "io/engine_paths.hpp" #include "debug/Logger.hpp" #include "util/stringutil.hpp" #include "libs/api_lua.hpp" @@ -161,7 +161,7 @@ State* lua::create_state(const EnginePaths& paths, StateType stateType) { auto resDir = paths.getResourcesFolder(); auto file = resDir / fs::u8path("scripts/stdmin.lua"); - auto src = files::read_string(file); + auto src = io::read_string(file); lua::pop(L, lua::execute(L, 0, src, "core:scripts/stdmin.lua")); return L; } diff --git a/src/logic/scripting/lua/usertypes/lua_type_heightmap.cpp b/src/logic/scripting/lua/usertypes/lua_type_heightmap.cpp index 0db89634..84aadbc0 100644 --- a/src/logic/scripting/lua/usertypes/lua_type_heightmap.cpp +++ b/src/logic/scripting/lua/usertypes/lua_type_heightmap.cpp @@ -9,7 +9,7 @@ #define FNL_IMPL #include "maths/FastNoiseLite.h" #include "coders/imageio.hpp" -#include "files/util.hpp" +#include "io/util.hpp" #include "graphics/core/ImageData.hpp" #include "maths/Heightmap.hpp" #include "engine/Engine.hpp" diff --git a/src/logic/scripting/scripting.cpp b/src/logic/scripting/scripting.cpp index 52eab4cd..ba39e334 100644 --- a/src/logic/scripting/scripting.cpp +++ b/src/logic/scripting/scripting.cpp @@ -8,8 +8,8 @@ #include "content/ContentPack.hpp" #include "debug/Logger.hpp" #include "engine/Engine.hpp" -#include "files/engine_paths.hpp" -#include "files/files.hpp" +#include "io/engine_paths.hpp" +#include "io/io.hpp" #include "frontend/UiDocument.hpp" #include "items/Inventory.hpp" #include "items/ItemDef.hpp" @@ -44,7 +44,7 @@ LevelController* scripting::controller = nullptr; void scripting::load_script(const fs::path& name, bool throwable) { const auto& paths = scripting::engine->getPaths(); fs::path file = paths.getResourcesFolder() / fs::path("scripts") / name; - std::string src = files::read_string(file); + std::string src = io::read_string(file); auto L = lua::get_main_state(); lua::loadbuffer(L, 0, src, "core:scripts/"+name.u8string()); if (throwable) { @@ -60,7 +60,7 @@ int scripting::load_script( const fs::path& file, const std::string& fileName ) { - std::string src = files::read_string(file); + std::string src = io::read_string(file); logger.info() << "script (" << type << ") " << file.u8string(); return lua::execute(lua::get_main_state(), env, src, fileName); } @@ -117,7 +117,7 @@ std::unique_ptr scripting::start_coroutine( ) { auto L = lua::get_main_state(); if (lua::getglobal(L, "__vc_start_coroutine")) { - auto source = files::read_string(script); + auto source = io::read_string(script); lua::loadbuffer(L, 0, source, script.filename().u8string()); if (lua::call(L, 1)) { int id = lua::tointeger(L, -1); @@ -872,7 +872,7 @@ void scripting::load_entity_component( const std::string& name, const fs::path& file, const std::string& fileName ) { auto L = lua::get_main_state(); - std::string src = files::read_string(file); + std::string src = io::read_string(file); logger.info() << "script (component) " << file.u8string(); lua::loadbuffer(L, 0, src, fileName); lua::store_in(L, lua::CHUNKS_TABLE, name); diff --git a/src/logic/scripting/scripting_hud.cpp b/src/logic/scripting/scripting_hud.cpp index c13a0010..66b14387 100644 --- a/src/logic/scripting/scripting_hud.cpp +++ b/src/logic/scripting/scripting_hud.cpp @@ -2,7 +2,7 @@ #include "debug/Logger.hpp" #include "engine/Engine.hpp" -#include "files/files.hpp" +#include "io/io.hpp" #include "frontend/hud.hpp" #include "frontend/UiDocument.hpp" #include "graphics/render/WorldRenderer.hpp" @@ -20,7 +20,7 @@ WorldRenderer* scripting::renderer = nullptr; static void load_script(const std::string& name) { auto file = engine->getPaths().getResourcesFolder() / "scripts" / name; - std::string src = files::read_string(file); + std::string src = io::read_string(file); logger.info() << "loading script " << file.u8string(); lua::execute(lua::get_main_state(), 0, src, file.u8string()); @@ -84,7 +84,7 @@ void scripting::load_hud_script( const std::string& fileName ) { int env = *senv; - std::string src = files::read_string(file); + std::string src = io::read_string(file); logger.info() << "loading script " << file.u8string(); lua::execute(lua::get_main_state(), env, src, fileName); diff --git a/src/logic/scripting/scripting_world_generation.cpp b/src/logic/scripting/scripting_world_generation.cpp index 1169b64f..8a19e1b0 100644 --- a/src/logic/scripting/scripting_world_generation.cpp +++ b/src/logic/scripting/scripting_world_generation.cpp @@ -13,7 +13,7 @@ #include "data/dv.hpp" #include "world/generator/GeneratorDef.hpp" #include "util/timeutil.hpp" -#include "files/files.hpp" +#include "io/io.hpp" #include "engine/Engine.hpp" #include "debug/Logger.hpp" @@ -55,7 +55,7 @@ public: pop(L); if (fs::exists(file)) { - std::string src = files::read_string(file); + std::string src = io::read_string(file); logger.info() << "script (generator) " << file.u8string(); pop(L, execute(L, *env, src, file.u8string())); } else { diff --git a/src/util/command_line.cpp b/src/util/command_line.cpp index 483b0f8b..6b579c01 100644 --- a/src/util/command_line.cpp +++ b/src/util/command_line.cpp @@ -3,7 +3,7 @@ #include #include -#include "files/engine_paths.hpp" +#include "io/engine_paths.hpp" #include "util/ArgsReader.hpp" #include "engine/Engine.hpp" diff --git a/src/world/World.cpp b/src/world/World.cpp index 2319fe2c..a04e5e9b 100644 --- a/src/world/World.cpp +++ b/src/world/World.cpp @@ -61,7 +61,7 @@ void World::writeResources(const Content& content) { } } } - files::write_json(wfile->getResourcesFile(), root); + io::write_json(wfile->getResourcesFile(), root); } void World::write(Level* level) { @@ -70,7 +70,7 @@ void World::write(Level* level) { wfile->write(this, &content); auto playerFile = level->players->serialize(); - files::write_json(wfile->getPlayerFile(), playerFile); + io::write_json(wfile->getPlayerFile(), playerFile); writeResources(content); } @@ -134,7 +134,7 @@ std::unique_ptr World::load( logger.warning() << "player.json does not exists"; level->players->create(); } else { - auto playerRoot = files::read_json(file); + auto playerRoot = io::read_json(file); level->players->deserialize(playerRoot); if (!playerRoot["players"].empty()) { diff --git a/src/world/files/WorldConverter.cpp b/src/world/files/WorldConverter.cpp index 25a0ca9d..287999de 100644 --- a/src/world/files/WorldConverter.cpp +++ b/src/world/files/WorldConverter.cpp @@ -8,7 +8,7 @@ #include "content/ContentReport.hpp" #include "compatibility.hpp" #include "debug/Logger.hpp" -#include "files/files.hpp" +#include "io/io.hpp" #include "objects/Player.hpp" #include "util/ThreadPool.hpp" #include "voxels/Chunk.hpp" @@ -185,9 +185,9 @@ void WorldConverter::upgradeRegion( const fs::path& file, int x, int z, RegionLayerIndex layer ) const { auto path = wfile->getRegions().getRegionFilePath(layer, x, z); - auto bytes = files::read_bytes_buffer(path); + auto bytes = io::read_bytes_buffer(path); auto buffer = compatibility::convert_region_2to3(bytes, layer); - files::write_bytes(path, buffer.data(), buffer.size()); + io::write_bytes(path, buffer.data(), buffer.size()); } void WorldConverter::convertVoxels(const fs::path& file, int x, int z) const { @@ -208,9 +208,9 @@ void WorldConverter::convertInventories(const fs::path& file, int x, int z) cons void WorldConverter::convertPlayer(const fs::path& file) const { logger.info() << "converting player " << file.u8string(); - auto map = files::read_json(file); + auto map = io::read_json(file); Player::convert(map, report.get()); - files::write_json(file, map); + io::write_json(file, map); } void WorldConverter::convertBlocksData(int x, int z, const ContentReport& report) const { diff --git a/src/world/files/WorldFiles.cpp b/src/world/files/WorldFiles.cpp index 3759c96b..73132f33 100644 --- a/src/world/files/WorldFiles.cpp +++ b/src/world/files/WorldFiles.cpp @@ -100,7 +100,7 @@ void WorldFiles::writePacks(const std::vector& packs) { for (const auto& pack : packs) { ss << pack.id << "\n"; } - files::write_string(packsFile, ss.str()); + io::write_string(packsFile, ss.str()); } template @@ -139,11 +139,11 @@ void WorldFiles::writeIndices(const ContentIndices* indices) { createContentIndicesCache(indices, root); createBlockFieldsIndices(indices, root); - files::write_json(getIndicesFile(), root); + io::write_json(getIndicesFile(), root); } void WorldFiles::writeWorldInfo(const WorldInfo& info) { - files::write_json(getWorldFile(), info.serialize()); + io::write_json(getWorldFile(), info.serialize()); } std::optional WorldFiles::readWorldInfo() { @@ -152,7 +152,7 @@ std::optional WorldFiles::readWorldInfo() { logger.warning() << "world.json does not exists"; return std::nullopt; } - auto root = files::read_json(file); + auto root = io::read_json(file); WorldInfo info {}; info.deserialize(root); return info; @@ -180,7 +180,7 @@ bool WorldFiles::readResourcesData(const Content& content) { logger.warning() << "resources.json does not exists"; return false; } - auto root = files::read_json(file); + auto root = io::read_json(file); for (const auto& [key, arr] : root.asObject()) { if (auto resType = ResourceType_from(key)) { read_resources_data(content, arr, *resType); @@ -197,12 +197,12 @@ void WorldFiles::patchIndicesFile(const dv::value& map) { logger.error() << file.filename().u8string() << " does not exists"; return; } - auto root = files::read_json(file); + auto root = io::read_json(file); for (const auto& [key, value] : map.asObject()) { logger.info() << "patching indices.json: update " << util::quote(key); root[key] = value; } - files::write_json(file, root, true); + io::write_json(file, root, true); } static void erase_pack_indices(dv::value& root, const std::string& id) { @@ -223,11 +223,11 @@ static void erase_pack_indices(dv::value& root, const std::string& id) { } void WorldFiles::removeIndices(const std::vector& packs) { - auto root = files::read_json(getIndicesFile()); + auto root = io::read_json(getIndicesFile()); for (const auto& id : packs) { erase_pack_indices(root, id); } - files::write_json(getIndicesFile(), root); + io::write_json(getIndicesFile(), root); } fs::path WorldFiles::getFolder() const { diff --git a/src/world/files/WorldFiles.hpp b/src/world/files/WorldFiles.hpp index d8e1f62d..7c4fb2cd 100644 --- a/src/world/files/WorldFiles.hpp +++ b/src/world/files/WorldFiles.hpp @@ -11,7 +11,7 @@ #include "typedefs.hpp" #include "voxels/Chunk.hpp" #include "WorldRegions.hpp" -#include "files/files.hpp" +#include "io/io.hpp" #define GLM_ENABLE_EXPERIMENTAL #include diff --git a/src/world/files/WorldRegions.hpp b/src/world/files/WorldRegions.hpp index 75be22ac..3f2805b1 100644 --- a/src/world/files/WorldRegions.hpp +++ b/src/world/files/WorldRegions.hpp @@ -13,7 +13,7 @@ #include "voxels/Chunk.hpp" #include "maths/voxmaths.hpp" #include "coders/compression.hpp" -#include "files/files.hpp" +#include "io/io.hpp" #include "world_regions_fwd.hpp" #define GLM_ENABLE_EXPERIMENTAL @@ -54,7 +54,7 @@ public: }; struct regfile { - files::rafile file; + io::rafile file; int version; bool inUse = false; diff --git a/test/coders/lua_parsing.cpp b/test/coders/lua_parsing.cpp index 9788d1d7..bf35965e 100644 --- a/test/coders/lua_parsing.cpp +++ b/test/coders/lua_parsing.cpp @@ -2,12 +2,12 @@ #include "coders/commons.hpp" #include "coders/lua_parsing.hpp" -#include "files/files.hpp" +#include "io/io.hpp" #include "util/stringutil.hpp" TEST(lua_parsing, Tokenizer) { auto filename = "../../res/scripts/stdlib.lua"; - auto source = files::read_string(std::filesystem::u8path(filename)); + auto source = io::read_string(std::filesystem::u8path(filename)); try { auto tokens = lua::tokenize(filename, source); for (const auto& token : tokens) { diff --git a/test/coders/vec3.cpp b/test/coders/vec3.cpp index d404e92b..6dc5e724 100644 --- a/test/coders/vec3.cpp +++ b/test/coders/vec3.cpp @@ -1,12 +1,12 @@ #include #include "coders/vec3.hpp" -#include "files/files.hpp" +#include "io/io.hpp" TEST(VEC3, Decode) { auto file = std::filesystem::u8path( "res/models/block.vec3" ); - auto bytes = files::read_bytes_buffer(file); + auto bytes = io::read_bytes_buffer(file); auto model = vec3::load(file.u8string(), bytes); } From e0314803c0613a949b94b7d7306c8ea91c3deb33 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Thu, 30 Jan 2025 22:23:13 +0300 Subject: [PATCH 03/16] migrate from std::filesystem::path to io::path (WIP) --- src/assets/AssetsLoader.cpp | 38 ++-- src/assets/AssetsLoader.hpp | 6 +- src/assets/assetload_funcs.cpp | 54 +++-- src/audio/audio.cpp | 19 +- src/audio/audio.hpp | 14 +- src/coders/GLSLExtension.cpp | 11 +- src/coders/GLSLExtension.hpp | 5 +- src/coders/imageio.cpp | 25 +- src/coders/imageio.hpp | 7 +- src/coders/ogg.cpp | 9 +- src/coders/ogg.hpp | 8 +- src/coders/png.cpp | 2 +- src/coders/wav.cpp | 9 +- src/coders/wav.hpp | 8 +- src/content/ContentLoader.cpp | 176 +++++++------- src/content/ContentLoader.hpp | 14 +- src/content/ContentPack.cpp | 54 ++--- src/content/ContentPack.hpp | 38 ++-- src/content/ContentReport.cpp | 2 +- src/content/ContentReport.hpp | 5 +- src/content/PacksManager.cpp | 8 +- src/content/PacksManager.hpp | 8 +- src/content/loading/GeneratorLoader.cpp | 42 ++-- src/core_defs.cpp | 8 +- src/core_defs.hpp | 3 +- src/engine/Engine.cpp | 70 +++--- src/engine/Engine.hpp | 9 +- src/engine/ServerMainloop.cpp | 8 +- src/frontend/UiDocument.cpp | 14 +- src/frontend/UiDocument.hpp | 7 +- src/frontend/locale.cpp | 22 +- src/frontend/locale.hpp | 13 +- src/frontend/screens/LevelScreen.cpp | 8 +- src/io/devices/Device.hpp | 76 +++++++ src/io/devices/StdfsDevice.cpp | 63 ++++++ src/io/devices/StdfsDevice.hpp | 21 ++ src/io/engine_paths.cpp | 181 ++++++++------- src/io/engine_paths.hpp | 41 ++-- src/io/fwd.hpp | 5 + src/io/io.cpp | 214 ++++++++++++------ src/io/io.hpp | 63 ++++-- src/io/path.cpp | 11 + src/io/path.hpp | 138 +++++++++++ src/logic/EngineController.cpp | 24 +- src/logic/scripting/lua/libs/libcore.cpp | 2 +- src/logic/scripting/lua/libs/libfile.cpp | 76 +++---- .../scripting/lua/libs/libgeneration.cpp | 4 +- src/logic/scripting/lua/libs/libinput.cpp | 15 +- src/logic/scripting/lua/libs/libpack.cpp | 12 +- src/logic/scripting/lua/libs/libworld.cpp | 4 +- src/logic/scripting/lua/lua_engine.cpp | 5 +- src/logic/scripting/lua/lua_extensions.cpp | 1 + .../lua/usertypes/lua_type_heightmap.cpp | 2 +- src/logic/scripting/scripting.cpp | 35 ++- src/logic/scripting/scripting.hpp | 16 +- src/logic/scripting/scripting_commons.hpp | 7 +- src/logic/scripting/scripting_hud.cpp | 10 +- src/logic/scripting/scripting_hud.hpp | 6 +- .../scripting/scripting_world_generation.cpp | 17 +- src/util/command_line.cpp | 9 +- src/world/World.cpp | 14 +- src/world/World.hpp | 6 +- src/world/files/RegionsLayer.cpp | 16 +- src/world/files/WorldConverter.cpp | 18 +- src/world/files/WorldConverter.hpp | 14 +- src/world/files/WorldFiles.cpp | 46 ++-- src/world/files/WorldFiles.hpp | 21 +- src/world/files/WorldRegions.cpp | 24 +- src/world/files/WorldRegions.hpp | 17 +- test/coders/lua_parsing.cpp | 2 +- test/coders/vec3.cpp | 6 +- test/io/path.cpp | 14 ++ 72 files changed, 1189 insertions(+), 791 deletions(-) create mode 100644 src/io/devices/Device.hpp create mode 100644 src/io/devices/StdfsDevice.cpp create mode 100644 src/io/devices/StdfsDevice.hpp create mode 100644 src/io/fwd.hpp create mode 100644 src/io/path.cpp create mode 100644 src/io/path.hpp create mode 100644 test/io/path.cpp diff --git a/src/assets/AssetsLoader.cpp b/src/assets/AssetsLoader.cpp index 8c7fc2dc..dfb2c7df 100644 --- a/src/assets/AssetsLoader.cpp +++ b/src/assets/AssetsLoader.cpp @@ -20,6 +20,8 @@ #include "Assets.hpp" #include "assetload_funcs.hpp" +namespace fs = std::filesystem; + static debug::Logger logger("assets-loader"); AssetsLoader::AssetsLoader(Assets* assets, const ResPaths* paths) @@ -83,22 +85,22 @@ void AssetsLoader::loadNext() { } } -void addLayouts( +static void add_layouts( const scriptenv& env, const std::string& prefix, - const fs::path& folder, + const io::path& folder, AssetsLoader& loader ) { - if (!fs::is_directory(folder)) { + if (!io::is_directory(folder)) { return; } - for (auto& entry : fs::directory_iterator(folder)) { - const fs::path& file = entry.path(); - if (file.extension().u8string() != ".xml") continue; - std::string name = prefix + ":" + file.stem().u8string(); + for (auto& entry : fs::directory_iterator(io::resolve(folder))) { + io::path file = folder / entry.path().filename().u8string(); + if (file.extension() != ".xml") continue; + std::string name = prefix + ":" + file.stem(); loader.add( AssetType::LAYOUT, - file.u8string(), + file.string(), name, std::make_shared(env) ); @@ -186,7 +188,7 @@ void AssetsLoader::processPreloadList(AssetType tag, const dv::value& list) { } } -void AssetsLoader::processPreloadConfig(const fs::path& file) { +void AssetsLoader::processPreloadConfig(const io::path& file) { auto root = io::read_json(file); processPreloadList(AssetType::ATLAS, root["atlases"]); processPreloadList(AssetType::FONT, root["fonts"]); @@ -198,8 +200,8 @@ void AssetsLoader::processPreloadConfig(const fs::path& file) { } void AssetsLoader::processPreloadConfigs(const Content* content) { - auto preloadFile = paths->getMainRoot() / fs::path("preload.json"); - if (fs::exists(preloadFile)) { + auto preloadFile = paths->getMainRoot() / "preload.json"; + if (io::exists(preloadFile)) { processPreloadConfig(preloadFile); } if (content == nullptr) { @@ -210,8 +212,8 @@ void AssetsLoader::processPreloadConfigs(const Content* content) { continue; } const auto& pack = entry.second; - auto preloadFile = pack->getInfo().folder / fs::path("preload.json"); - if (fs::exists(preloadFile)) { + auto preloadFile = pack->getInfo().folder / "preload.json"; + if (io::exists(preloadFile)) { processPreloadConfig(preloadFile); } } @@ -230,8 +232,8 @@ void AssetsLoader::addDefaults(AssetsLoader& loader, const Content* content) { for (auto& entry : content->getPacks()) { auto pack = entry.second.get(); auto& info = pack->getInfo(); - fs::path folder = info.folder / fs::path("layouts"); - addLayouts(pack->getEnvironment(), info.id, folder, loader); + io::path folder = info.folder / "layouts"; + add_layouts(pack->getEnvironment(), info.id, folder, loader); } for (auto& entry : content->getSkeletons()) { @@ -274,20 +276,20 @@ void AssetsLoader::addDefaults(AssetsLoader& loader, const Content* content) { bool AssetsLoader::loadExternalTexture( Assets* assets, const std::string& name, - const std::vector& alternatives + const std::vector& alternatives ) { if (assets->get(name) != nullptr) { return true; } for (auto& path : alternatives) { - if (fs::exists(path)) { + if (io::exists(path)) { try { auto image = imageio::read(path); assets->store(Texture::from(image.get()), name); return true; } catch (const std::exception& err) { logger.error() << "error while loading external " - << path.u8string() << ": " << err.what(); + << path.string() << ": " << err.what(); } } } diff --git a/src/assets/AssetsLoader.hpp b/src/assets/AssetsLoader.hpp index cd6db950..bf117a3d 100644 --- a/src/assets/AssetsLoader.hpp +++ b/src/assets/AssetsLoader.hpp @@ -1,6 +1,5 @@ #pragma once -#include #include #include #include @@ -14,6 +13,7 @@ #include "typedefs.hpp" #include "Assets.hpp" #include "data/dv.hpp" +#include "io/fwd.hpp" class ResPaths; class AssetsLoader; @@ -73,7 +73,7 @@ class AssetsLoader { AssetType tag, const std::string& name, const dv::value& map ); void processPreloadList(AssetType tag, const dv::value& list); - void processPreloadConfig(const std::filesystem::path& file); + void processPreloadConfig(const io::path& file); void processPreloadConfigs(const Content* content); public: AssetsLoader(Assets* assets, const ResPaths* paths); @@ -109,6 +109,6 @@ public: static bool loadExternalTexture( Assets* assets, const std::string& name, - const std::vector& alternatives + const std::vector& alternatives ); }; diff --git a/src/assets/assetload_funcs.cpp b/src/assets/assetload_funcs.cpp index 929d5e62..f8bcd84d 100644 --- a/src/assets/assetload_funcs.cpp +++ b/src/assets/assetload_funcs.cpp @@ -48,16 +48,14 @@ assetload::postfunc assetload::texture( const std::string& name, const std::shared_ptr& ) { - auto actualFile = paths->find(filename + ".png").u8string(); + auto actualFile = paths->find(filename + ".png"); try { - std::shared_ptr image( - imageio::read(fs::u8path(actualFile)).release() - ); + std::shared_ptr image(imageio::read(actualFile).release()); return [name, image, actualFile](auto assets) { assets->store(Texture::from(image.get()), name); }; } catch (const std::runtime_error& err) { - logger.error() << actualFile << ": " << err.what(); + logger.error() << actualFile.string() << ": " << err.what(); return [](auto) {}; } } @@ -69,8 +67,8 @@ assetload::postfunc assetload::shader( const std::string& name, const std::shared_ptr& ) { - fs::path vertexFile = paths->find(filename + ".glslv"); - fs::path fragmentFile = paths->find(filename + ".glslf"); + io::path vertexFile = paths->find(filename + ".glslv"); + io::path fragmentFile = paths->find(filename + ".glslf"); std::string vertexSource = io::read_string(vertexFile); std::string fragmentSource = io::read_string(fragmentFile); @@ -82,8 +80,8 @@ assetload::postfunc assetload::shader( return [=](auto assets) { assets->store( Shader::create( - vertexFile.u8string(), - fragmentFile.u8string(), + vertexFile.string(), + fragmentFile.string(), vertexSource, fragmentSource ), @@ -92,8 +90,8 @@ assetload::postfunc assetload::shader( }; } -static bool append_atlas(AtlasBuilder& atlas, const fs::path& file) { - std::string name = file.stem().string(); +static bool append_atlas(AtlasBuilder& atlas, const io::path& file) { + std::string name = file.stem(); // skip duplicates if (atlas.has(name)) { return false; @@ -114,19 +112,19 @@ assetload::postfunc assetload::atlas( auto atlasConfig = std::dynamic_pointer_cast(config); if (atlasConfig && atlasConfig->type == AtlasType::SEPARATE) { for (const auto& file : paths->listdir(directory)) { - if (!imageio::is_read_supported(file.extension().u8string())) + if (!imageio::is_read_supported(file.extension())) continue; loader->add( AssetType::TEXTURE, - directory + "/" + file.stem().u8string(), - name + "/" + file.stem().u8string() + directory + "/" + file.stem(), + name + "/" + file.stem() ); } return [](auto){}; } AtlasBuilder builder; for (const auto& file : paths->listdir(directory)) { - if (!imageio::is_read_supported(file.extension().u8string())) continue; + if (!imageio::is_read_supported(file.extension())) continue; if (!append_atlas(builder, file)) continue; } std::set names = builder.getNames(); @@ -151,7 +149,7 @@ assetload::postfunc assetload::font( for (size_t i = 0; i <= 1024; i++) { std::string pagefile = filename + "_" + std::to_string(i) + ".png"; auto file = paths->find(pagefile); - if (fs::exists(file)) { + if (io::exists(file)) { pages->push_back(imageio::read(file)); } else if (i == 0) { throw std::runtime_error("font must have page 0"); @@ -222,13 +220,13 @@ assetload::postfunc assetload::sound( extension = extensions[i]; // looking for 'sound_name' as base sound auto soundFile = paths->find(file + extension); - if (fs::exists(soundFile)) { + if (io::exists(soundFile)) { baseSound = audio::load_sound(soundFile, keepPCM); break; } // looking for 'sound_name_0' as base sound auto variantFile = paths->find(file + "_0" + extension); - if (fs::exists(variantFile)) { + if (io::exists(variantFile)) { baseSound = audio::load_sound(variantFile, keepPCM); break; } @@ -241,7 +239,7 @@ assetload::postfunc assetload::sound( for (uint i = 1;; i++) { auto variantFile = paths->find(file + "_" + std::to_string(i) + extension); - if (!fs::exists(variantFile)) { + if (!io::exists(variantFile)) { break; } baseSound->variants.emplace_back(audio::load_sound(variantFile, keepPCM)); @@ -272,9 +270,9 @@ assetload::postfunc assetload::model( const std::shared_ptr& ) { auto path = paths->find(file + ".vec3"); - if (fs::exists(path)) { + if (io::exists(path)) { auto bytes = io::read_bytes_buffer(path); - auto modelVEC3 = std::make_shared(vec3::load(path.u8string(), bytes)); + auto modelVEC3 = std::make_shared(vec3::load(path.string(), bytes)); return [loader, name, modelVEC3=std::move(modelVEC3)](Assets* assets) { for (auto& [modelName, model] : modelVEC3->models) { request_textures(loader, model.model); @@ -294,7 +292,7 @@ assetload::postfunc assetload::model( path = paths->find(file + ".obj"); auto text = io::read_string(path); try { - auto model = obj::parse(path.u8string(), text).release(); + auto model = obj::parse(path.string(), text).release(); return [=](Assets* assets) { request_textures(loader, *model); assets->store(std::unique_ptr(model), name); @@ -394,21 +392,21 @@ static bool load_animation( std::string animsDir = directory + "/animation"; for (const auto& folder : paths->listdir(animsDir)) { - if (!fs::is_directory(folder)) continue; - if (folder.filename().u8string() != name) continue; - if (fs::is_empty(folder)) continue; + if (!io::is_directory(folder)) continue; + if (folder.name() != name) continue; + //FIXME: if (fs::is_empty(folder)) continue; AtlasBuilder builder; append_atlas(builder, paths->find(directory + "/" + name + ".png")); std::vector> frameList; - std::string animFile = folder.u8string() + "/animation.json"; - if (fs::exists(animFile)) { + std::string animFile = folder.string() + "/animation.json"; + if (io::exists(animFile)) { read_anim_file(animFile, frameList); } for (const auto& file : paths->listdir(animsDir + "/" + name)) { if (!frameList.empty() && - !contains(frameList, file.stem().u8string())) { + !contains(frameList, file.stem())) { continue; } if (!append_atlas(builder, file)) continue; diff --git a/src/audio/audio.cpp b/src/audio/audio.cpp index 8ac8b713..761557af 100644 --- a/src/audio/audio.cpp +++ b/src/audio/audio.cpp @@ -4,6 +4,7 @@ #include #include +#include "io/io.hpp" #include "coders/ogg.hpp" #include "coders/wav.hpp" #include "AL/ALAudio.hpp" @@ -181,11 +182,11 @@ void audio::initialize(bool enabled, AudioSettings& settings) { } } -std::unique_ptr audio::load_PCM(const fs::path& file, bool headerOnly) { - if (!fs::exists(file)) { - throw std::runtime_error("file not found '" + file.u8string() + "'"); +std::unique_ptr audio::load_PCM(const io::path& file, bool headerOnly) { + if (!io::exists(file)) { + throw std::runtime_error("file not found '" + file.string() + "'"); } - std::string ext = file.extension().u8string(); + std::string ext = file.extension(); if (ext == ".wav" || ext == ".WAV") { return wav::load_pcm(file, headerOnly); } else if (ext == ".ogg" || ext == ".OGG") { @@ -194,7 +195,7 @@ std::unique_ptr audio::load_PCM(const fs::path& file, bool headerOnly) { throw std::runtime_error("unsupported audio format"); } -std::unique_ptr audio::load_sound(const fs::path& file, bool keepPCM) { +std::unique_ptr audio::load_sound(const io::path& file, bool keepPCM) { std::shared_ptr pcm( load_PCM(file, !keepPCM && backend->isDummy()).release() ); @@ -207,8 +208,8 @@ std::unique_ptr audio::create_sound( return backend->createSound(std::move(pcm), keepPCM); } -std::unique_ptr audio::open_PCM_stream(const fs::path& file) { - std::string ext = file.extension().u8string(); +std::unique_ptr audio::open_PCM_stream(const io::path& file) { + std::string ext = file.extension(); if (ext == ".wav" || ext == ".WAV") { return wav::create_stream(file); } else if (ext == ".ogg" || ext == ".OGG") { @@ -218,7 +219,7 @@ std::unique_ptr audio::open_PCM_stream(const fs::path& file) { } std::unique_ptr audio::open_stream( - const fs::path& file, bool keepSource + const io::path& file, bool keepSource ) { if (!keepSource && backend->isDummy()) { auto header = load_PCM(file, true); @@ -338,7 +339,7 @@ speakerid_t audio::play( } speakerid_t audio::play_stream( - const fs::path& file, + const io::path& file, glm::vec3 position, bool relative, float volume, diff --git a/src/audio/audio.hpp b/src/audio/audio.hpp index 37ae8e00..5893c334 100644 --- a/src/audio/audio.hpp +++ b/src/audio/audio.hpp @@ -1,14 +1,12 @@ #pragma once -#include #include #include #include #include "typedefs.hpp" #include "settings.hpp" - -namespace fs = std::filesystem; +#include "io/fwd.hpp" namespace audio { /// @brief playing speaker uid @@ -365,7 +363,7 @@ namespace audio { /// @param headerOnly read header only /// @throws std::runtime_error if I/O error ocurred or format is unknown /// @return PCM audio data - std::unique_ptr load_PCM(const fs::path& file, bool headerOnly); + std::unique_ptr load_PCM(const io::path& file, bool headerOnly); /// @brief Load sound from file /// @param file audio file path @@ -373,7 +371,7 @@ namespace audio { /// Sound::getPCM /// @throws std::runtime_error if I/O error ocurred or format is unknown /// @return new Sound instance - std::unique_ptr load_sound(const fs::path& file, bool keepPCM); + std::unique_ptr load_sound(const io::path& file, bool keepPCM); /// @brief Create new sound from PCM data /// @param pcm PCM data @@ -386,14 +384,14 @@ namespace audio { /// @param file audio file path /// @throws std::runtime_error if I/O error ocurred or format is unknown /// @return new PCMStream instance - std::unique_ptr open_PCM_stream(const fs::path& file); + std::unique_ptr open_PCM_stream(const io::path& file); /// @brief Open new audio stream from file /// @param file audio file path /// @param keepSource store PCMStream in stream to make it accessible with /// Stream::getSource /// @return new Stream instance - std::unique_ptr open_stream(const fs::path& file, bool keepSource); + std::unique_ptr open_stream(const io::path& file, bool keepSource); /// @brief Open new audio stream from source /// @param stream PCM data source @@ -464,7 +462,7 @@ namespace audio { /// @param channel channel index /// @return speaker id or 0 speakerid_t play_stream( - const fs::path& file, + const io::path& file, glm::vec3 position, bool relative, float volume, diff --git a/src/coders/GLSLExtension.cpp b/src/coders/GLSLExtension.cpp index c7f45cd7..b36e7a07 100644 --- a/src/coders/GLSLExtension.cpp +++ b/src/coders/GLSLExtension.cpp @@ -6,12 +6,9 @@ #include #include "io/engine_paths.hpp" -#include "io/io.hpp" #include "typedefs.hpp" #include "util/stringutil.hpp" -namespace fs = std::filesystem; - void GLSLExtension::setVersion(std::string version) { this->version = std::move(version); } @@ -21,7 +18,7 @@ void GLSLExtension::setPaths(const ResPaths* paths) { } void GLSLExtension::loadHeader(const std::string& name) { - fs::path file = paths->find("shaders/lib/" + name + ".glsl"); + io::path file = paths->find("shaders/lib/" + name + ".glsl"); std::string source = io::read_string(file); addHeader(name, ""); addHeader(name, process(file, source, true)); @@ -66,7 +63,7 @@ void GLSLExtension::undefine(const std::string& name) { } inline std::runtime_error parsing_error( - const fs::path& file, uint linenum, const std::string& message + const io::path& file, uint linenum, const std::string& message ) { return std::runtime_error( "file " + file.string() + ": " + message + " at line " + @@ -75,7 +72,7 @@ inline std::runtime_error parsing_error( } inline void parsing_warning( - const fs::path& file, uint linenum, const std::string& message + const io::path& file, uint linenum, const std::string& message ) { std::cerr << "file " + file.string() + ": warning: " + message + " at line " + std::to_string(linenum) @@ -87,7 +84,7 @@ inline void source_line(std::stringstream& ss, uint linenum) { } std::string GLSLExtension::process( - const fs::path& file, const std::string& source, bool header + const io::path& file, const std::string& source, bool header ) { std::stringstream ss; size_t pos = 0; diff --git a/src/coders/GLSLExtension.hpp b/src/coders/GLSLExtension.hpp index 6187d7d4..c619c9d0 100644 --- a/src/coders/GLSLExtension.hpp +++ b/src/coders/GLSLExtension.hpp @@ -1,10 +1,11 @@ #pragma once -#include #include #include #include +#include "io/io.hpp" + class ResPaths; class GLSLExtension { @@ -29,7 +30,7 @@ public: bool hasDefine(const std::string& name) const; std::string process( - const std::filesystem::path& file, + const io::path& file, const std::string& source, bool header = false ); diff --git a/src/coders/imageio.cpp b/src/coders/imageio.cpp index 5f082abc..36e1f76d 100644 --- a/src/coders/imageio.cpp +++ b/src/coders/imageio.cpp @@ -1,6 +1,5 @@ #include "imageio.hpp" -#include #include #include @@ -8,8 +7,6 @@ #include "io/io.hpp" #include "png.hpp" -namespace fs = std::filesystem; - using image_reader = std::function(const ubyte*, size_t)>; using image_writer = std::function; @@ -30,33 +27,29 @@ bool imageio::is_write_supported(const std::string& extension) { return writers.find(extension) != writers.end(); } -inline std::string extensionOf(const std::string& filename) { - return fs::u8path(filename).extension().u8string(); -} - -std::unique_ptr imageio::read(const fs::path& filename) { - auto found = readers.find(extensionOf(filename.u8string())); +std::unique_ptr imageio::read(const io::path& file) { + auto found = readers.find(file.extension()); if (found == readers.end()) { throw std::runtime_error( - "file format is not supported (read): " + filename.u8string() + "file format is not supported (read): " + file.string() ); } - auto bytes = io::read_bytes_buffer(filename); + auto bytes = io::read_bytes_buffer(file); try { return std::unique_ptr(found->second(bytes.data(), bytes.size())); } catch (const std::runtime_error& err) { throw std::runtime_error( - "could not to load image " + filename.u8string() + ": " + err.what() + "could not to load image " + file.string() + ": " + err.what() ); } } -void imageio::write(const std::string& filename, const ImageData* image) { - auto found = writers.find(extensionOf(filename)); +void imageio::write(const io::path& file, const ImageData* image) { + auto found = writers.find(file.extension()); if (found == writers.end()) { throw std::runtime_error( - "file format is not supported (write): " + filename + "file format is not supported (write): " + file.string() ); } - return found->second(filename, image); + return found->second(io::resolve(file).u8string(), image); } diff --git a/src/coders/imageio.hpp b/src/coders/imageio.hpp index beab88ad..0e59ae37 100644 --- a/src/coders/imageio.hpp +++ b/src/coders/imageio.hpp @@ -2,7 +2,8 @@ #include #include -#include + +#include "io/fwd.hpp" class ImageData; @@ -12,6 +13,6 @@ namespace imageio { bool is_read_supported(const std::string& extension); bool is_write_supported(const std::string& extension); - std::unique_ptr read(const std::filesystem::path& file); - void write(const std::string& filename, const ImageData* image); + std::unique_ptr read(const io::path& file); + void write(const io::path& file, const ImageData* image); } diff --git a/src/coders/ogg.cpp b/src/coders/ogg.cpp index df5f9826..c5c27f49 100644 --- a/src/coders/ogg.cpp +++ b/src/coders/ogg.cpp @@ -5,6 +5,7 @@ #include +#include "io/io.hpp" #include "audio/audio.hpp" #include "debug/Logger.hpp" #include "typedefs.hpp" @@ -43,11 +44,11 @@ static inline std::string vorbis_error_message(int code) { } std::unique_ptr ogg::load_pcm( - const fs::path& file, bool headerOnly + const io::path& file, bool headerOnly ) { OggVorbis_File vf; int code; - if ((code = ov_fopen(file.u8string().c_str(), &vf))) { + if ((code = ov_fopen(io::resolve(file).u8string().c_str(), &vf))) { throw std::runtime_error("vorbis: " + vorbis_error_message(code)); } std::vector data; @@ -166,10 +167,10 @@ public: } }; -std::unique_ptr ogg::create_stream(const fs::path& file) { +std::unique_ptr ogg::create_stream(const io::path& file) { OggVorbis_File vf; int code; - if ((code = ov_fopen(file.u8string().c_str(), &vf))) { + if ((code = ov_fopen(io::resolve(file).u8string().c_str(), &vf))) { throw std::runtime_error("vorbis: " + vorbis_error_message(code)); } return std::make_unique(vf); diff --git a/src/coders/ogg.hpp b/src/coders/ogg.hpp index 67ea2458..86a807e7 100644 --- a/src/coders/ogg.hpp +++ b/src/coders/ogg.hpp @@ -1,6 +1,8 @@ #pragma once -#include +#include + +#include "io/fwd.hpp" namespace audio { struct PCM; @@ -9,9 +11,9 @@ namespace audio { namespace ogg { std::unique_ptr load_pcm( - const std::filesystem::path& file, bool headerOnly + const io::path& file, bool headerOnly ); std::unique_ptr create_stream( - const std::filesystem::path& file + const io::path& file ); } diff --git a/src/coders/png.cpp b/src/coders/png.cpp index 6671922c..ddf5fea8 100644 --- a/src/coders/png.cpp +++ b/src/coders/png.cpp @@ -212,7 +212,7 @@ std::unique_ptr png::load_texture(const ubyte* bytes, size_t size) { } std::unique_ptr png::load_texture(const std::string& filename) { - auto bytes = io::read_bytes_buffer(fs::u8path(filename)); + auto bytes = io::read_bytes_buffer(filename); try { return load_texture(bytes.data(), bytes.size()); } catch (const std::runtime_error& err) { diff --git a/src/coders/wav.cpp b/src/coders/wav.cpp index 6ba337fd..1e260a0c 100644 --- a/src/coders/wav.cpp +++ b/src/coders/wav.cpp @@ -6,6 +6,7 @@ #include #include +#include "io/io.hpp" #include "audio/audio.hpp" #include "debug/Logger.hpp" @@ -118,11 +119,11 @@ public: } }; -std::unique_ptr wav::create_stream(const fs::path& file) { - std::ifstream in(file, std::ios::binary); +std::unique_ptr wav::create_stream(const io::path& file) { + std::ifstream in(io::resolve(file), std::ios::binary); if (!in.is_open()) { throw std::runtime_error( - "could not to open file '" + file.u8string() + "'" + "could not to open file '" + file.string() + "'" ); } @@ -234,7 +235,7 @@ std::unique_ptr wav::create_stream(const fs::path& file) { } std::unique_ptr wav::load_pcm( - const fs::path& file, bool headerOnly + const io::path& file, bool headerOnly ) { auto stream = wav::create_stream(file); diff --git a/src/coders/wav.hpp b/src/coders/wav.hpp index 5f5270c2..218b2447 100644 --- a/src/coders/wav.hpp +++ b/src/coders/wav.hpp @@ -1,6 +1,8 @@ #pragma once -#include +#include + +#include "io/fwd.hpp" namespace audio { struct PCM; @@ -9,9 +11,9 @@ namespace audio { namespace wav { std::unique_ptr load_pcm( - const std::filesystem::path& file, bool headerOnly + const io::path& file, bool headerOnly ); std::unique_ptr create_stream( - const std::filesystem::path& file + const io::path& file ); } diff --git a/src/content/ContentLoader.cpp b/src/content/ContentLoader.cpp index 1603334d..3c993786 100644 --- a/src/content/ContentLoader.cpp +++ b/src/content/ContentLoader.cpp @@ -43,55 +43,57 @@ ContentLoader::ContentLoader( } static void detect_defs( - const fs::path& folder, + const io::path& folder, const std::string& prefix, std::vector& detected ) { - if (fs::is_directory(folder)) { - for (const auto& entry : fs::directory_iterator(folder)) { - const fs::path& file = entry.path(); - std::string name = file.stem().string(); - if (name[0] == '_') { - continue; - } - if (fs::is_regular_file(file) && io::is_data_file(file)) { - auto map = io::read_object(file); - std::string id = prefix.empty() ? name : prefix + ":" + name; - detected.emplace_back(id); - } else if (fs::is_directory(file) && - file.extension() != fs::u8path(".files")) { - detect_defs(file, name, detected); - } + if (!io::is_directory(folder)) { + return; + } + for (const auto& entry : std::filesystem::directory_iterator(io::resolve(folder))) { + io::path file = folder / entry.path().filename().u8string(); + std::string name = file.stem(); + if (name[0] == '_') { + continue; + } + if (io::is_regular_file(file) && io::is_data_file(file)) { + auto map = io::read_object(file); + std::string id = prefix.empty() ? name : prefix + ":" + name; + detected.emplace_back(id); + } else if (io::is_directory(file) && + file.extension() != fs::u8path(".files")) { + detect_defs(file, name, detected); } } } static void detect_defs_pairs( - const fs::path& folder, + const io::path& folder, const std::string& prefix, std::vector>& detected ) { - if (fs::is_directory(folder)) { - for (const auto& entry : fs::directory_iterator(folder)) { - const fs::path& file = entry.path(); - std::string name = file.stem().string(); - if (name[0] == '_') { - continue; - } - if (fs::is_regular_file(file) && io::is_data_file(file)) { - try { - auto map = io::read_object(file); - auto id = prefix.empty() ? name : prefix + ":" + name; - auto caption = util::id_to_caption(id); - map.at("caption").get(caption); - detected.emplace_back(id, name); - } catch (const std::runtime_error& err) { - logger.error() << err.what(); - } - } else if (fs::is_directory(file) && - file.extension() != fs::u8path(".files")) { - detect_defs_pairs(file, name, detected); + if (!io::is_directory(folder)) { + return; + } + for (const auto& entry : fs::directory_iterator(io::resolve(folder))) { + io::path file = folder / entry.path().filename().u8string(); + std::string name = file.stem(); + if (name[0] == '_') { + continue; + } + if (io::is_regular_file(file) && io::is_data_file(file)) { + try { + auto map = io::read_object(file); + auto id = prefix.empty() ? name : prefix + ":" + name; + auto caption = util::id_to_caption(id); + map.at("caption").get(caption); + detected.emplace_back(id, name); + } catch (const std::runtime_error& err) { + logger.error() << err.what(); } + } else if (io::is_directory(file) && + file.extension() != fs::u8path(".files")) { + detect_defs_pairs(file, name, detected); } } } @@ -106,7 +108,7 @@ std::vector> ContentLoader::scanContent( } bool ContentLoader::fixPackIndices( - const fs::path& folder, + const io::path& folder, dv::value& indicesRoot, const std::string& contentSection ) { @@ -146,7 +148,7 @@ void ContentLoader::fixPackIndices() { auto entitiesFolder = folder / ContentPack::ENTITIES_FOLDER; dv::value root; - if (fs::is_regular_file(contentFile)) { + if (io::is_regular_file(contentFile)) { root = io::read_json(contentFile); } else { root = dv::object(); @@ -213,7 +215,7 @@ static void process_method( } void ContentLoader::loadBlock( - Block& def, const std::string& name, const fs::path& file + Block& def, const std::string& name, const io::path& file ) { auto root = io::read_json(file); if (def.properties == nullptr) { @@ -402,7 +404,7 @@ void ContentLoader::loadBlock( } void ContentLoader::loadItem( - ItemDef& def, const std::string& name, const fs::path& file + ItemDef& def, const std::string& name, const io::path& file ) { auto root = io::read_json(file); def.properties = root; @@ -446,7 +448,7 @@ void ContentLoader::loadItem( } void ContentLoader::loadEntity( - EntityDef& def, const std::string& name, const fs::path& file + EntityDef& def, const std::string& name, const io::path& file ) { auto root = io::read_json(file); @@ -518,16 +520,16 @@ void ContentLoader::loadEntity( EntityDef& def, const std::string& full, const std::string& name ) { auto folder = pack->folder; - auto configFile = folder / fs::path("entities/" + name + ".json"); - if (fs::exists(configFile)) loadEntity(def, full, configFile); + auto configFile = folder / ("entities/" + name + ".json"); + if (io::exists(configFile)) loadEntity(def, full, configFile); } void ContentLoader::loadBlock( Block& def, const std::string& full, const std::string& name ) { auto folder = pack->folder; - auto configFile = folder / fs::path("blocks/" + name + ".json"); - if (fs::exists(configFile)) loadBlock(def, full, configFile); + auto configFile = folder / ("blocks/" + name + ".json"); + if (io::exists(configFile)) loadBlock(def, full, configFile); if (!def.hidden) { bool created; @@ -549,8 +551,8 @@ void ContentLoader::loadItem( ItemDef& def, const std::string& full, const std::string& name ) { auto folder = pack->folder; - auto configFile = folder / fs::path("items/" + name + ".json"); - if (fs::exists(configFile)) loadItem(def, full, configFile); + auto configFile = folder / ("items/" + name + ".json"); + if (io::exists(configFile)) loadItem(def, full, configFile); } static std::tuple create_unit_id( @@ -566,7 +568,7 @@ static std::tuple create_unit_id( } void ContentLoader::loadBlockMaterial( - BlockMaterial& def, const fs::path& file + BlockMaterial& def, const io::path& file ) { auto root = io::read_json(file); root.at("steps-sound").get(def.stepsSound); @@ -577,9 +579,9 @@ void ContentLoader::loadBlockMaterial( void ContentLoader::loadContent(const dv::value& root) { std::vector> pendingDefs; auto getJsonParent = [this](const std::string& prefix, const std::string& name) { - auto configFile = pack->folder / fs::path(prefix + "/" + name + ".json"); + auto configFile = pack->folder / (prefix + "/" + name + ".json"); std::string parent; - if (fs::exists(configFile)) { + if (io::exists(configFile)) { auto root = io::read_json(configFile); root.at("parent").get(parent); } @@ -740,16 +742,17 @@ void ContentLoader::loadContent(const dv::value& root) { } static inline void foreach_file( - const fs::path& dir, std::function handler + const io::path& dir, std::function handler ) { - if (fs::is_directory(dir)) { - for (const auto& entry : fs::directory_iterator(dir)) { - const auto& path = entry.path(); - if (fs::is_directory(path)) { - continue; - } - handler(path); + if (!io::is_directory(dir)) { + return; + } + for (const auto& entry : fs::directory_iterator(io::resolve(dir))) { + io::path path = dir / entry.path().filename().u8string(); + if (io::is_directory(path)) { + continue; } + handler(path); } } @@ -761,11 +764,10 @@ void ContentLoader::load() { auto folder = pack->folder; // Load world generators - fs::path generatorsDir = folder / fs::u8path("generators"); - foreach_file(generatorsDir, [this](const fs::path& file) { - std::string name = file.stem().u8string(); - auto [packid, full, filename] = - create_unit_id(pack->id, file.stem().u8string()); + io::path generatorsDir = folder / fs::u8path("generators"); + foreach_file(generatorsDir, [this](const io::path& file) { + std::string name = file.stem(); + auto [packid, full, filename] = create_unit_id(pack->id, name); auto& def = builder.generators.create(full); try { @@ -776,8 +778,8 @@ void ContentLoader::load() { }); // Load pack resources.json - fs::path resourcesFile = folder / fs::u8path("resources.json"); - if (fs::exists(resourcesFile)) { + io::path resourcesFile = folder / "resources.json"; + if (io::exists(resourcesFile)) { auto resRoot = io::read_json(resourcesFile); for (const auto& [key, arr] : resRoot.asObject()) { if (auto resType = ResourceType_from(key)) { @@ -790,8 +792,8 @@ void ContentLoader::load() { } // Load pack resources aliases - fs::path aliasesFile = folder / fs::u8path("resource-aliases.json"); - if (fs::exists(aliasesFile)) { + io::path aliasesFile = folder / "resource-aliases.json"; + if (io::exists(aliasesFile)) { auto resRoot = io::read_json(aliasesFile); for (const auto& [key, arr] : resRoot.asObject()) { if (auto resType = ResourceType_from(key)) { @@ -804,32 +806,32 @@ void ContentLoader::load() { } // Load block materials - fs::path materialsDir = folder / fs::u8path("block_materials"); - if (fs::is_directory(materialsDir)) { - for (const auto& entry : fs::directory_iterator(materialsDir)) { - const auto& file = entry.path(); + io::path materialsDir = folder / "block_materials"; + if (io::is_directory(materialsDir)) { + for (const auto& entry : fs::directory_iterator(io::resolve(materialsDir))) { + io::path file = materialsDir / entry.path().filename().u8string(); auto [packid, full, filename] = - create_unit_id(pack->id, file.stem().u8string()); + create_unit_id(pack->id, file.stem()); loadBlockMaterial( builder.createBlockMaterial(full), - materialsDir / fs::u8path(filename + ".json") + materialsDir / (filename + ".json") ); } } // Load skeletons - fs::path skeletonsDir = folder / fs::u8path("skeletons"); - foreach_file(skeletonsDir, [this](const fs::path& file) { - std::string name = pack->id + ":" + file.stem().u8string(); + io::path skeletonsDir = folder / fs::u8path("skeletons"); + foreach_file(skeletonsDir, [this](const io::path& file) { + std::string name = pack->id + ":" + file.stem(); std::string text = io::read_string(file); builder.add( - rigging::SkeletonConfig::parse(text, file.u8string(), name) + rigging::SkeletonConfig::parse(text, file.string(), name) ); }); // Process content.json and load defined content units auto contentFile = pack->getContentFile(); - if (fs::exists(contentFile)) { + if (io::exists(contentFile)) { loadContent(io::read_json(contentFile)); } } @@ -844,8 +846,8 @@ static void load_scripts(Content& content, ContentUnitDefs& units) { const auto runtime = content.getPackRuntime(name.substr(0, pos)); const auto& pack = runtime->getInfo(); const auto& folder = pack.folder; - auto scriptfile = folder / fs::path("scripts/" + def->scriptName + ".lua"); - if (fs::is_regular_file(scriptfile)) { + auto scriptfile = folder / ("scripts/" + def->scriptName + ".lua"); + if (io::is_regular_file(scriptfile)) { scripting::load_content_script( runtime->getEnvironment(), name, @@ -866,8 +868,8 @@ void ContentLoader::loadScripts(Content& content) { const auto& folder = pack.folder; // Load main world script - fs::path scriptFile = folder / fs::path("scripts/world.lua"); - if (fs::is_regular_file(scriptFile)) { + io::path scriptFile = folder / "scripts/world.lua"; + if (io::is_regular_file(scriptFile)) { scripting::load_world_script( runtime->getEnvironment(), pack.id, @@ -877,13 +879,13 @@ void ContentLoader::loadScripts(Content& content) { ); } // Load entity components - fs::path componentsDir = folder / fs::u8path("scripts/components"); - foreach_file(componentsDir, [&pack](const fs::path& file) { - auto name = pack.id + ":" + file.stem().u8string(); + io::path componentsDir = folder / fs::u8path("scripts/components"); + foreach_file(componentsDir, [&pack](const io::path& file) { + auto name = pack.id + ":" + file.stem(); scripting::load_entity_component( name, file, - pack.id + ":scripts/components/" + file.filename().u8string() + pack.id + ":scripts/components/" + file.name() ); }); } diff --git a/src/content/ContentLoader.hpp b/src/content/ContentLoader.hpp index d99aa622..f1135ee3 100644 --- a/src/content/ContentLoader.hpp +++ b/src/content/ContentLoader.hpp @@ -1,14 +1,12 @@ #pragma once -#include #include #include +#include "io/io.hpp" #include "content_fwd.hpp" #include "data/dv.hpp" -namespace fs = std::filesystem; - class Block; struct BlockMaterial; struct ItemDef; @@ -43,15 +41,15 @@ class ContentLoader { GeneratorDef& def, const std::string& full, const std::string& name ); - static void loadBlockMaterial(BlockMaterial& def, const fs::path& file); + static void loadBlockMaterial(BlockMaterial& def, const io::path& file); void loadBlock( - Block& def, const std::string& name, const fs::path& file + Block& def, const std::string& name, const io::path& file ); void loadItem( - ItemDef& def, const std::string& name, const fs::path& file + ItemDef& def, const std::string& name, const io::path& file ); void loadEntity( - EntityDef& def, const std::string& name, const fs::path& file + EntityDef& def, const std::string& name, const io::path& file ); void loadResources(ResourceType type, const dv::value& list); void loadResourceAliases(ResourceType type, const dv::value& aliases); @@ -66,7 +64,7 @@ public: // Refresh pack content.json static bool fixPackIndices( - const fs::path& folder, + const io::path& folder, dv::value& indicesRoot, const std::string& contentSection ); diff --git a/src/content/ContentPack.cpp b/src/content/ContentPack.cpp index 9bcec23c..51960609 100644 --- a/src/content/ContentPack.cpp +++ b/src/content/ContentPack.cpp @@ -15,7 +15,7 @@ namespace fs = std::filesystem; ContentPack ContentPack::createCore(const EnginePaths& paths) { return ContentPack { - "core", "Core", ENGINE_VERSION_STRING, "", "", paths.getResourcesFolder(), "res:", {} + "core", "Core", ENGINE_VERSION_STRING, "", "", "res:", "res:", {} }; } @@ -23,7 +23,7 @@ const std::vector ContentPack::RESERVED_NAMES = { "res", "abs", "local", "core", "user", "world", "none", "null"}; contentpack_error::contentpack_error( - std::string packId, fs::path folder, const std::string& message + std::string packId, io::path folder, const std::string& message ) : std::runtime_error(message), packId(std::move(packId)), @@ -33,19 +33,19 @@ contentpack_error::contentpack_error( std::string contentpack_error::getPackId() const { return packId; } -fs::path contentpack_error::getFolder() const { +io::path contentpack_error::getFolder() const { return folder; } -fs::path ContentPack::getContentFile() const { - return folder / fs::path(CONTENT_FILENAME); +io::path ContentPack::getContentFile() const { + return folder / CONTENT_FILENAME; } -bool ContentPack::is_pack(const fs::path& folder) { - return fs::is_regular_file(folder / fs::path(PACKAGE_FILENAME)); +bool ContentPack::is_pack(const io::path& folder) { + return io::is_regular_file(folder / PACKAGE_FILENAME); } -static void checkContentPackId(const std::string& id, const fs::path& folder) { +static void checkContentPackId(const std::string& id, const io::path& folder) { if (id.length() < 2 || id.length() > 24) throw contentpack_error( id, folder, "content-pack id length is out of range [2, 24]" @@ -70,8 +70,8 @@ static void checkContentPackId(const std::string& id, const fs::path& folder) { } } -ContentPack ContentPack::read(const std::string& path, const fs::path& folder) { - auto root = io::read_json(folder / fs::path(PACKAGE_FILENAME)); +ContentPack ContentPack::read(const std::string& path, const io::path& folder) { + auto root = io::read_json(folder / PACKAGE_FILENAME); ContentPack pack; root.at("id").get(pack.id); root.at("title").get(pack.title); @@ -124,21 +124,21 @@ ContentPack ContentPack::read(const std::string& path, const fs::path& folder) { } void ContentPack::scanFolder( - const std::string& path, const fs::path& folder, std::vector& packs + const std::string& path, const io::path& folder, std::vector& packs ) { - if (!fs::is_directory(folder)) { + if (!io::is_directory(folder)) { return; } - for (const auto& entry : fs::directory_iterator(folder)) { - const fs::path& packFolder = entry.path(); - if (!fs::is_directory(packFolder)) continue; + for (const auto& entry : fs::directory_iterator(io::resolve(folder))) { + io::path packFolder = folder / entry.path().filename().u8string(); + if (!io::is_directory(packFolder)) continue; if (!is_pack(packFolder)) continue; try { packs.push_back( - read(path + "/" + packFolder.filename().string(), packFolder) + read(path + "/" + packFolder.name(), packFolder) ); } catch (const contentpack_error& err) { - std::cerr << "package.json error at " << err.getFolder().u8string(); + std::cerr << "package.json error at " << err.getFolder().string(); std::cerr << ": " << err.what() << std::endl; } catch (const std::runtime_error& err) { std::cerr << err.what() << std::endl; @@ -146,26 +146,26 @@ void ContentPack::scanFolder( } } -std::vector ContentPack::worldPacksList(const fs::path& folder) { - fs::path listfile = folder / fs::path("packs.list"); - if (!fs::is_regular_file(listfile)) { +std::vector ContentPack::worldPacksList(const io::path& folder) { + io::path listfile = folder / "packs.list"; + if (!io::is_regular_file(listfile)) { throw std::runtime_error("missing file 'packs.list'"); } return io::read_list(listfile); } -fs::path ContentPack::findPack( - const EnginePaths* paths, const fs::path& worldDir, const std::string& name +io::path ContentPack::findPack( + const EnginePaths* paths, const io::path& worldDir, const std::string& name ) { - fs::path folder = worldDir / fs::path("content") / fs::path(name); - if (fs::is_directory(folder)) { + io::path folder = worldDir / "content" / name; + if (io::is_directory(folder)) { return folder; } - folder = paths->getUserFilesFolder() / fs::path("content") / fs::path(name); - if (fs::is_directory(folder)) { + folder = io::path("user:content") / name; + if (io::is_directory(folder)) { return folder; } - return paths->getResourcesFolder() / fs::path("content") / fs::path(name); + return io::path("res:content") / name; } ContentPackRuntime::ContentPackRuntime(ContentPack info, scriptenv env) diff --git a/src/content/ContentPack.hpp b/src/content/ContentPack.hpp index e4360bdc..ed7c3eb8 100644 --- a/src/content/ContentPack.hpp +++ b/src/content/ContentPack.hpp @@ -1,27 +1,27 @@ #pragma once -#include #include #include #include #include "typedefs.hpp" #include "content_fwd.hpp" +#include "io/io.hpp" class EnginePaths; class contentpack_error : public std::runtime_error { std::string packId; - std::filesystem::path folder; + io::path folder; public: contentpack_error( std::string packId, - std::filesystem::path folder, + io::path folder, const std::string& message ); std::string getPackId() const; - std::filesystem::path getFolder() const; + io::path getFolder() const; }; enum class DependencyLevel { @@ -42,52 +42,52 @@ struct ContentPack { std::string version = "0.0"; std::string creator = ""; std::string description = "no description"; - std::filesystem::path folder; + io::path folder; std::string path; std::vector dependencies; std::string source = ""; - std::filesystem::path getContentFile() const; + io::path getContentFile() const; static inline const std::string PACKAGE_FILENAME = "package.json"; static inline const std::string CONTENT_FILENAME = "content.json"; - static inline const std::filesystem::path BLOCKS_FOLDER = "blocks"; - static inline const std::filesystem::path ITEMS_FOLDER = "items"; - static inline const std::filesystem::path ENTITIES_FOLDER = "entities"; - static inline const std::filesystem::path GENERATORS_FOLDER = "generators"; + static inline const io::path BLOCKS_FOLDER = "blocks"; + static inline const io::path ITEMS_FOLDER = "items"; + static inline const io::path ENTITIES_FOLDER = "entities"; + static inline const io::path GENERATORS_FOLDER = "generators"; static const std::vector RESERVED_NAMES; - static bool is_pack(const std::filesystem::path& folder); + static bool is_pack(const io::path& folder); static ContentPack read( - const std::string& path, const std::filesystem::path& folder + const std::string& path, const io::path& folder ); static void scanFolder( const std::string& path, - const std::filesystem::path& folder, + const io::path& folder, std::vector& packs ); static std::vector worldPacksList( - const std::filesystem::path& folder + const io::path& folder ); - static std::filesystem::path findPack( + static io::path findPack( const EnginePaths* paths, - const std::filesystem::path& worldDir, + const io::path& worldDir, const std::string& name ); static ContentPack createCore(const EnginePaths&); - static inline std::filesystem::path getFolderFor(ContentType type) { + static inline io::path getFolderFor(ContentType type) { switch (type) { case ContentType::BLOCK: return ContentPack::BLOCKS_FOLDER; case ContentType::ITEM: return ContentPack::ITEMS_FOLDER; case ContentType::ENTITY: return ContentPack::ENTITIES_FOLDER; case ContentType::GENERATOR: return ContentPack::GENERATORS_FOLDER; - case ContentType::NONE: return std::filesystem::u8path(""); - default: return std::filesystem::u8path(""); + case ContentType::NONE: return ""; + default: return ""; } } }; diff --git a/src/content/ContentReport.cpp b/src/content/ContentReport.cpp index c9043507..0d8a20e2 100644 --- a/src/content/ContentReport.cpp +++ b/src/content/ContentReport.cpp @@ -67,7 +67,7 @@ static void process_blocks_data( std::shared_ptr ContentReport::create( const std::shared_ptr& worldFiles, - const fs::path& filename, + const io::path& filename, const Content* content ) { auto worldInfo = worldFiles->readWorldInfo(); diff --git a/src/content/ContentReport.hpp b/src/content/ContentReport.hpp index 62893527..325e5f29 100644 --- a/src/content/ContentReport.hpp +++ b/src/content/ContentReport.hpp @@ -1,6 +1,5 @@ #pragma once -#include #include #include #include @@ -10,10 +9,10 @@ #include "data/dv.hpp" #include "typedefs.hpp" #include "Content.hpp" +#include "io/io.hpp" #include "data/StructLayout.hpp" #include "world/files/world_regions_fwd.hpp" -namespace fs = std::filesystem; enum class ContentIssueType { REORDER, @@ -139,7 +138,7 @@ public: static std::shared_ptr create( const std::shared_ptr& worldFiles, - const fs::path& filename, + const io::path& filename, const Content* content ); diff --git a/src/content/PacksManager.cpp b/src/content/PacksManager.cpp index fdf39bb3..49c3014c 100644 --- a/src/content/PacksManager.cpp +++ b/src/content/PacksManager.cpp @@ -7,7 +7,7 @@ PacksManager::PacksManager() = default; -void PacksManager::setSources(std::vector> sources) { +void PacksManager::setSources(std::vector> sources) { this->sources = std::move(sources); } @@ -42,7 +42,7 @@ std::vector PacksManager::getAll( for (auto& name : names) { auto found = packs.find(name); if (found == packs.end()) { - throw contentpack_error(name, fs::path(""), "pack not found"); + throw contentpack_error(name, io::path(), "pack not found"); } packsList.push_back(found->second); } @@ -92,7 +92,7 @@ static bool resolve_dependencies( bool exists = found != packs.end(); if (!exists && dep.level == DependencyLevel::required) { throw contentpack_error( - dep.id, fs::path(), "dependency of '" + pack->id + "'" + dep.id, io::path(), "dependency of '" + pack->id + "'" ); } if (!exists) { @@ -127,7 +127,7 @@ std::vector PacksManager::assemble( for (auto& name : names) { auto found = packs.find(name); if (found == packs.end()) { - throw contentpack_error(name, fs::path(""), "pack not found"); + throw contentpack_error(name, io::path(), "pack not found"); } queue.push(&found->second); } diff --git a/src/content/PacksManager.hpp b/src/content/PacksManager.hpp index b60b06ce..32ac43d6 100644 --- a/src/content/PacksManager.hpp +++ b/src/content/PacksManager.hpp @@ -1,21 +1,19 @@ #pragma once -#include #include #include +#include "io/io.hpp" #include "ContentPack.hpp" -namespace fs = std::filesystem; - class PacksManager { std::unordered_map packs; - std::vector> sources; + std::vector> sources; public: PacksManager(); /// @brief Set content packs sources (search folders) - void setSources(std::vector> sources); + void setSources(std::vector> sources); /// @brief Scan sources and collect all found packs excluding duplication. /// Scanning order depends on sources order diff --git a/src/content/loading/GeneratorLoader.cpp b/src/content/loading/GeneratorLoader.cpp index 2e903426..b14b0b2f 100644 --- a/src/content/loading/GeneratorLoader.cpp +++ b/src/content/loading/GeneratorLoader.cpp @@ -132,18 +132,18 @@ static VoxelStructureMeta load_structure_meta( } static std::vector> load_structures( - const dv::value& map, const fs::path& filesFolder, const ResPaths& paths + const dv::value& map, const io::path& filesFolder, const ResPaths& paths ) { - auto structuresDir = filesFolder / fs::path("fragments"); + auto structuresDir = filesFolder / "fragments"; std::vector> structures; for (auto& [name, config] : map.asObject()) { - auto structFile = structuresDir / fs::u8path(name + ".vox"); - structFile = paths.find(structFile.u8string()); - logger.debug() << "loading voxel fragment " << structFile.u8string(); - if (!fs::exists(structFile)) { + auto structFile = structuresDir / (name + ".vox"); + structFile = paths.find(structFile.string()); + logger.debug() << "loading voxel fragment " << structFile.string(); + if (!io::exists(structFile)) { throw std::runtime_error("structure file does not exist (" + - structFile.u8string()); + structFile.string()); } auto fragment = std::make_unique(); fragment->deserialize(io::read_binary_json(structFile)); @@ -162,7 +162,7 @@ static std::vector> load_structures( static void load_structures( GeneratorDef& def, const dv::value& map, - const fs::path& filesFolder, + const io::path& filesFolder, const ResPaths& paths ) { auto rawStructures = load_structures(map, filesFolder, paths); @@ -178,9 +178,9 @@ static void load_structures( } } -static inline const auto STRUCTURES_FILE = fs::u8path("structures.toml"); -static inline const auto BIOMES_FILE = fs::u8path("biomes.toml"); -static inline const auto GENERATORS_DIR = fs::u8path("generators"); +static inline const io::path STRUCTURES_FILE = "structures.toml"; +static inline const io::path BIOMES_FILE = "biomes.toml"; +static inline const io::path GENERATORS_DIR = "generators"; static void load_biomes(GeneratorDef& def, const dv::value& root) { for (const auto& [biomeName, biomeMap] : root.asObject()) { @@ -198,11 +198,11 @@ void ContentLoader::loadGenerator( ) { auto packDir = pack->folder; auto generatorsDir = packDir / GENERATORS_DIR; - auto generatorFile = generatorsDir / fs::u8path(name + ".toml"); - if (!fs::exists(generatorFile)) { + auto generatorFile = generatorsDir / (name + ".toml"); + if (!io::exists(generatorFile)) { return; } - auto map = io::read_toml(generatorsDir / fs::u8path(name + ".toml")); + auto map = io::read_toml(generatorsDir / (name + ".toml")); map.at("caption").get(def.caption); map.at("biome-parameters").get(def.biomeParameters); map.at("biome-bpd").get(def.biomesBPD); @@ -233,15 +233,15 @@ void ContentLoader::loadGenerator( logger.warning() << "generator has heightmap-inputs but biomes-bpd " "is not equal to heights-bpd, generator will work slower!"; } - auto folder = generatorsDir / fs::u8path(name + ".files"); - auto scriptFile = folder / fs::u8path("script.lua"); + auto folder = generatorsDir / (name + ".files"); + auto scriptFile = folder / "script.lua"; - auto structuresFile = GENERATORS_DIR / fs::u8path(name + ".files") / STRUCTURES_FILE; - auto structuresMap = paths.readCombinedObject(structuresFile.u8string()); - load_structures(def, structuresMap, structuresFile.parent_path(), paths); + auto structuresFile = GENERATORS_DIR / (name + ".files") / STRUCTURES_FILE; + auto structuresMap = paths.readCombinedObject(structuresFile.string()); + load_structures(def, structuresMap, structuresFile.parent(), paths); - auto biomesFile = GENERATORS_DIR / fs::u8path(name + ".files") / BIOMES_FILE; - auto biomesMap = paths.readCombinedObject(biomesFile.u8string()); + auto biomesFile = GENERATORS_DIR / (name + ".files") / BIOMES_FILE; + auto biomesMap = paths.readCombinedObject(biomesFile.string()); if (biomesMap.empty()) { throw std::runtime_error( "generator " + util::quote(def.name) + diff --git a/src/core_defs.cpp b/src/core_defs.cpp index 04ef4101..def96d69 100644 --- a/src/core_defs.cpp +++ b/src/core_defs.cpp @@ -11,7 +11,7 @@ #include "voxels/Block.hpp" // All in-game definitions (blocks, items, etc..) -void corecontent::setup(const EnginePaths& paths, ContentBuilder& builder) { +void corecontent::setup(ContentBuilder& builder) { { Block& block = builder.blocks.create(CORE_AIR); block.replaceable = true; @@ -28,10 +28,10 @@ void corecontent::setup(const EnginePaths& paths, ContentBuilder& builder) { item.iconType = ItemIconType::NONE; } - auto bindsFile = paths.getResourcesFolder()/fs::path("bindings.toml"); - if (fs::is_regular_file(bindsFile)) { + auto bindsFile = "res:bindings.toml"; + if (io::is_regular_file(bindsFile)) { Events::loadBindings( - bindsFile.u8string(), io::read_string(bindsFile), BindType::BIND + bindsFile, io::read_string(bindsFile), BindType::BIND ); } diff --git a/src/core_defs.hpp b/src/core_defs.hpp index 8042ca36..f269af10 100644 --- a/src/core_defs.hpp +++ b/src/core_defs.hpp @@ -28,9 +28,8 @@ inline const std::string BIND_PLAYER_FAST_INTERACTOIN = "player.fast_interaction"; inline const std::string BIND_HUD_INVENTORY = "hud.inventory"; -class EnginePaths; class ContentBuilder; namespace corecontent { - void setup(const EnginePaths& paths, ContentBuilder& builder); + void setup(ContentBuilder& builder); } diff --git a/src/engine/Engine.cpp b/src/engine/Engine.cpp index a9aa2b98..7be65cd1 100644 --- a/src/engine/Engine.cpp +++ b/src/engine/Engine.cpp @@ -52,10 +52,10 @@ static debug::Logger logger("engine"); namespace fs = std::filesystem; -static std::unique_ptr load_icon(const fs::path& resdir) { +static std::unique_ptr load_icon() { try { - auto file = resdir / fs::u8path("textures/misc/icon.png"); - if (fs::exists(file)) { + auto file = "res:textures/misc/icon.png"; + if (io::exists(file)) { return imageio::read(file); } } catch (const std::exception& err) { @@ -101,7 +101,7 @@ void Engine::initialize(CoreParameters coreParameters) { throw initialize_error("could not initialize window"); } time.set(Window::time()); - if (auto icon = load_icon(resdir)) { + if (auto icon = load_icon()) { icon->flipY(); Window::setIcon(icon.get()); } @@ -118,7 +118,7 @@ void Engine::initialize(CoreParameters coreParameters) { if (langNotSet) { settings.ui.language.set(langs::locale_by_envlocale( platform::detect_locale(), - paths.getResourcesFolder() + "res:" )); } scripting::initialize(this); @@ -128,12 +128,12 @@ void Engine::initialize(CoreParameters coreParameters) { keepAlive(settings.ui.language.observe([this](auto lang) { setLanguage(lang); }, true)); - basePacks = io::read_list(resdir/fs::path("config/builtins.list")); + basePacks = io::read_list("res:config/builtins.list"); } void Engine::loadSettings() { - fs::path settings_file = paths.getSettingsFile(); - if (fs::is_regular_file(settings_file)) { + io::path settings_file = paths.getSettingsFile(); + if (io::is_regular_file(settings_file)) { logger.info() << "loading settings"; std::string text = io::read_string(settings_file); try { @@ -146,11 +146,11 @@ void Engine::loadSettings() { } void Engine::loadControls() { - fs::path controls_file = paths.getControlsFile(); - if (fs::is_regular_file(controls_file)) { + io::path controls_file = paths.getControlsFile(); + if (io::is_regular_file(controls_file)) { logger.info() << "loading controls"; std::string text = io::read_string(controls_file); - Events::loadBindings(controls_file.u8string(), text, BindType::BIND); + Events::loadBindings(controls_file.string(), text, BindType::BIND); } } @@ -171,9 +171,9 @@ void Engine::updateHotkeys() { void Engine::saveScreenshot() { auto image = Window::takeScreenshot(); image->flipY(); - fs::path filename = paths.getNewScreenshotFile("png"); + io::path filename = paths.getNewScreenshotFile("png"); imageio::write(filename.string(), image.get()); - logger.info() << "saved screenshot as " << filename.u8string(); + logger.info() << "saved screenshot as " << filename.string(); } void Engine::run() { @@ -264,12 +264,12 @@ cmd::CommandsInterpreter* Engine::getCommandsInterpreter() { return interpreter.get(); } -PacksManager Engine::createPacksManager(const fs::path& worldFolder) { +PacksManager Engine::createPacksManager(const io::path& worldFolder) { PacksManager manager; manager.setSources({ - {"world:content", worldFolder.empty() ? worldFolder : worldFolder/fs::path("content")}, - {"user:content", paths.getUserFilesFolder()/fs::path("content")}, - {"res:content", paths.getResourcesFolder()/fs::path("content")} + {"world:content", worldFolder.empty() ? worldFolder : worldFolder / "content"}, + {"user:content", "user:content"}, + {"res:content", "res:content"} }); return manager; } @@ -325,12 +325,12 @@ void Engine::loadAssets() { } } -static void load_configs(const fs::path& root) { - auto configFolder = root/fs::path("config"); - auto bindsFile = configFolder/fs::path("bindings.toml"); - if (fs::is_regular_file(bindsFile)) { +static void load_configs(const io::path& root) { + auto configFolder = root/io::path("config"); + auto bindsFile = configFolder/io::path("bindings.toml"); + if (io::is_regular_file(bindsFile)) { Events::loadBindings( - bindsFile.u8string(), io::read_string(bindsFile), BindType::BIND + bindsFile.string(), io::read_string(bindsFile), BindType::BIND ); } } @@ -338,15 +338,13 @@ static void load_configs(const fs::path& root) { void Engine::loadContent() { scripting::cleanup(); - auto resdir = paths.getResourcesFolder(); - std::vector names; for (auto& pack : contentPacks) { names.push_back(pack.id); } ContentBuilder contentBuilder; - corecontent::setup(paths, contentBuilder); + corecontent::setup(contentBuilder); paths.setContentPacks(&contentPacks); PacksManager manager = createPacksManager(paths.getCurrentWorldFolder()); @@ -363,7 +361,7 @@ void Engine::loadContent() { for (auto& pack : contentPacks) { resRoots.push_back({pack.id, pack.folder}); } - resPaths = std::make_unique(resdir, resRoots); + resPaths = std::make_unique("res:", resRoots); // Load content { @@ -380,7 +378,7 @@ void Engine::loadContent() { ContentLoader::loadScripts(*content); - langs::setup(resdir, langs::current->getId(), contentPacks); + langs::setup("res:", langs::current->getId(), contentPacks); if (!isHeadless()) { loadAssets(); onAssetsLoaded(); @@ -389,23 +387,22 @@ void Engine::loadContent() { void Engine::resetContent() { scripting::cleanup(); - auto resdir = paths.getResourcesFolder(); std::vector resRoots; { auto pack = ContentPack::createCore(paths); resRoots.push_back({"core", pack.folder}); load_configs(pack.folder); } - auto manager = createPacksManager(fs::path()); + auto manager = createPacksManager(io::path()); manager.scan(); for (const auto& pack : manager.getAll(basePacks)) { resRoots.push_back({pack.id, pack.folder}); } - resPaths = std::make_unique(resdir, resRoots); + resPaths = std::make_unique("res:", resRoots); contentPacks.clear(); content.reset(); - langs::setup(resdir, langs::current->getId(), contentPacks); + langs::setup("res:", langs::current->getId(), contentPacks); if (!isHeadless()) { loadAssets(); onAssetsLoaded(); @@ -414,15 +411,14 @@ void Engine::resetContent() { contentPacks = manager.getAll(basePacks); } -void Engine::loadWorldContent(const fs::path& folder) { +void Engine::loadWorldContent(const io::path& folder) { contentPacks.clear(); auto packNames = ContentPack::worldPacksList(folder); PacksManager manager; manager.setSources( - {{"world:content", - folder.empty() ? folder : folder / fs::path("content")}, - {"user:content", paths.getUserFilesFolder() / fs::path("content")}, - {"res:content", paths.getResourcesFolder() / fs::path("content")}} + {{"world:content", folder.empty() ? folder : folder / "content"}, + {"user:content", "user:content"}, + {"res:content", "res:content"}} ); manager.scan(); contentPacks = manager.getAll(manager.assemble(packNames)); @@ -445,7 +441,7 @@ void Engine::setScreen(std::shared_ptr screen) { } void Engine::setLanguage(std::string locale) { - langs::setup(paths.getResourcesFolder(), std::move(locale), contentPacks); + langs::setup("res:", std::move(locale), contentPacks); } void Engine::onWorldOpen(std::unique_ptr level, int64_t localPlayer) { diff --git a/src/engine/Engine.hpp b/src/engine/Engine.hpp index fd6cb1c3..b05881f6 100644 --- a/src/engine/Engine.hpp +++ b/src/engine/Engine.hpp @@ -14,7 +14,6 @@ #include "PostRunnables.hpp" #include "Time.hpp" -#include #include #include #include @@ -48,8 +47,8 @@ public: struct CoreParameters { bool headless = false; bool testMode = false; - std::filesystem::path resFolder {"res"}; - std::filesystem::path userFolder {"."}; + std::filesystem::path resFolder = "res"; + std::filesystem::path userFolder = "."; std::filesystem::path scriptFile; }; @@ -122,7 +121,7 @@ public: /// @brief Collect world content-packs and load content /// @see loadContent /// @param folder world folder - void loadWorldContent(const fs::path& folder); + void loadWorldContent(const io::path& folder); /// @brief Collect all available content-packs from res/content void loadAllPacks(); @@ -172,7 +171,7 @@ public: EngineController* getController(); cmd::CommandsInterpreter* getCommandsInterpreter(); - PacksManager createPacksManager(const fs::path& worldFolder); + PacksManager createPacksManager(const io::path& worldFolder); void setLevelConsumer(OnWorldOpen levelConsumer); diff --git a/src/engine/ServerMainloop.cpp b/src/engine/ServerMainloop.cpp index 954c2a11..504deb9e 100644 --- a/src/engine/ServerMainloop.cpp +++ b/src/engine/ServerMainloop.cpp @@ -34,8 +34,10 @@ void ServerMainloop::run() { setLevel(std::move(level)); }); - logger.info() << "starting test " << coreParams.scriptFile; - auto process = scripting::start_coroutine(coreParams.scriptFile); + logger.info() << "starting test " << coreParams.scriptFile.string(); + auto process = scripting::start_coroutine( + "script:" + coreParams.scriptFile.filename().u8string() + ); double targetDelta = 1.0 / static_cast(TPS); double delta = targetDelta; @@ -76,7 +78,7 @@ void ServerMainloop::run() { void ServerMainloop::setLevel(std::unique_ptr level) { if (level == nullptr) { controller->onWorldQuit(); - engine.getPaths().setCurrentWorldFolder(fs::path()); + engine.getPaths().setCurrentWorldFolder(""); controller = nullptr; } else { controller = std::make_unique( diff --git a/src/frontend/UiDocument.cpp b/src/frontend/UiDocument.cpp index 91c1e0a0..1dfa18aa 100644 --- a/src/frontend/UiDocument.cpp +++ b/src/frontend/UiDocument.cpp @@ -56,22 +56,22 @@ scriptenv UiDocument::getEnvironment() const { std::unique_ptr UiDocument::read( const scriptenv& penv, const std::string& name, - const fs::path& file, + const io::path& file, const std::string& fileName ) { const std::string text = io::read_string(file); - auto xmldoc = xml::parse(file.u8string(), text); + auto xmldoc = xml::parse(file.string(), text); auto env = penv == nullptr ? scripting::create_doc_environment(scripting::get_root_environment(), name) : scripting::create_doc_environment(penv, name); gui::UiXmlReader reader(env); - auto view = reader.readXML(file.u8string(), *xmldoc->getRoot()); + auto view = reader.readXML(file.string(), *xmldoc->getRoot()); view->setId("root"); uidocscript script {}; - auto scriptFile = fs::path(file.u8string()+".lua"); - if (fs::is_regular_file(scriptFile)) { + auto scriptFile = io::path(file.string()+".lua"); + if (io::is_regular_file(scriptFile)) { scripting::load_layout_script( env, name, scriptFile, fileName + ".lua", script ); @@ -80,8 +80,8 @@ std::unique_ptr UiDocument::read( } std::shared_ptr UiDocument::readElement( - const fs::path& file, const std::string& fileName + const io::path& file, const std::string& fileName ) { - auto document = read(nullptr, file.filename().u8string(), file, fileName); + auto document = read(nullptr, file.name(), file, fileName); return document->getRoot(); } diff --git a/src/frontend/UiDocument.hpp b/src/frontend/UiDocument.hpp index dbf91ef1..298e63bc 100644 --- a/src/frontend/UiDocument.hpp +++ b/src/frontend/UiDocument.hpp @@ -4,10 +4,9 @@ #include #include -#include #include -namespace fs = std::filesystem; +#include "io/fwd.hpp" namespace gui { class UINode; @@ -48,10 +47,10 @@ public: static std::unique_ptr read( const scriptenv& parent_env, const std::string& name, - const fs::path& file, + const io::path& file, const std::string& fileName ); static std::shared_ptr readElement( - const fs::path& file, const std::string& fileName + const io::path& file, const std::string& fileName ); }; diff --git a/src/frontend/locale.cpp b/src/frontend/locale.cpp index bc60cc38..d199cb49 100644 --- a/src/frontend/locale.cpp +++ b/src/frontend/locale.cpp @@ -69,8 +69,8 @@ namespace { }; } -void langs::loadLocalesInfo(const fs::path& resdir, std::string& fallback) { - auto file = resdir/fs::u8path(langs::TEXTS_FOLDER)/fs::u8path("langs.json"); +void langs::loadLocalesInfo(const io::path& resdir, std::string& fallback) { + auto file = resdir / langs::TEXTS_FOLDER / "langs.json"; auto root = io::read_json(file); langs::locales_info.clear(); @@ -94,7 +94,7 @@ void langs::loadLocalesInfo(const fs::path& resdir, std::string& fallback) { } } -std::string langs::locale_by_envlocale(const std::string& envlocale, const fs::path& resdir){ +std::string langs::locale_by_envlocale(const std::string& envlocale, const io::path& resdir){ std::string fallback = FALLBACK_DEFAULT; if (locales_info.size() == 0) { loadLocalesInfo(resdir, fallback); @@ -115,21 +115,21 @@ std::string langs::locale_by_envlocale(const std::string& envlocale, const fs::p } } -void langs::load(const fs::path& resdir, +void langs::load(const io::path& resdir, const std::string& locale, const std::vector& packs, Lang& lang) { - fs::path filename = fs::path(TEXTS_FOLDER)/fs::path(locale + LANG_FILE_EXT); - fs::path core_file = resdir/filename; + io::path filename = io::path(TEXTS_FOLDER) / (locale + LANG_FILE_EXT); + io::path core_file = resdir / filename; - if (fs::is_regular_file(core_file)) { + if (io::is_regular_file(core_file)) { std::string text = io::read_string(core_file); Reader reader(core_file.string(), text); reader.read(lang, ""); } for (auto pack : packs) { - fs::path file = pack.folder/filename; - if (fs::is_regular_file(file)) { + io::path file = pack.folder / filename; + if (io::is_regular_file(file)) { std::string text = io::read_string(file); Reader reader(file.string(), text); reader.read(lang, ""); @@ -137,7 +137,7 @@ void langs::load(const fs::path& resdir, } } -void langs::load(const fs::path& resdir, +void langs::load(const io::path& resdir, const std::string& locale, const std::string& fallback, const std::vector& packs) { @@ -149,7 +149,7 @@ void langs::load(const fs::path& resdir, current = std::move(lang); } -void langs::setup(const fs::path& resdir, +void langs::setup(const io::path& resdir, std::string locale, const std::vector& packs) { std::string fallback = langs::FALLBACK_DEFAULT; diff --git a/src/frontend/locale.hpp b/src/frontend/locale.hpp index b3e200c9..1daaca21 100644 --- a/src/frontend/locale.hpp +++ b/src/frontend/locale.hpp @@ -3,9 +3,10 @@ #include #include #include -#include #include +#include "io/fwd.hpp" + struct ContentPack; namespace langs { @@ -44,17 +45,17 @@ namespace langs { extern std::unordered_map locales_info; extern void loadLocalesInfo( - const std::filesystem::path& resdir, + const io::path& resdir, std::string& fallback); extern std::string locale_by_envlocale(const std::string& envlocale, - const std::filesystem::path& resdir); + const io::path& resdir); - extern void load(const std::filesystem::path& resdir, + extern void load(const io::path& resdir, const std::string& locale, const std::vector& packs, Lang& lang); - extern void load(const std::filesystem::path& resdir, + extern void load(const io::path& resdir, const std::string& locale, const std::string& fallback, const std::vector& packs); @@ -63,7 +64,7 @@ namespace langs { extern const std::wstring& get(const std::wstring& key, const std::wstring& context); - extern void setup(const std::filesystem::path& resdir, + extern void setup(const io::path& resdir, std::string locale, const std::vector& packs); } diff --git a/src/frontend/screens/LevelScreen.cpp b/src/frontend/screens/LevelScreen.cpp index fe9156cc..d1690747 100644 --- a/src/frontend/screens/LevelScreen.cpp +++ b/src/frontend/screens/LevelScreen.cpp @@ -105,8 +105,8 @@ void LevelScreen::initializeContent() { 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)) { + io::path scriptFile = info.folder / "scripts/hud.lua"; + if (io::is_regular_file(scriptFile)) { scripting::load_hud_script( pack->getEnvironment(), info.id, @@ -124,7 +124,7 @@ LevelScreen::~LevelScreen() { // unblock all bindings Events::enableBindings(); controller->onWorldQuit(); - engine.getPaths().setCurrentWorldFolder(fs::path()); + engine.getPaths().setCurrentWorldFolder(""); } void LevelScreen::saveWorldPreview() { @@ -147,7 +147,7 @@ void LevelScreen::saveWorldPreview() { worldRenderer->draw(ctx, camera, false, true, 0.0f, postProcessing.get()); auto image = postProcessing->toImage(); image->flipY(); - imageio::write(paths.resolve("world:preview.png").u8string(), image.get()); + imageio::write(paths.resolve("world:preview.png").string(), image.get()); } catch (const std::exception& err) { logger.error() << err.what(); } diff --git a/src/io/devices/Device.hpp b/src/io/devices/Device.hpp new file mode 100644 index 00000000..39794d80 --- /dev/null +++ b/src/io/devices/Device.hpp @@ -0,0 +1,76 @@ +#pragma once + +#include +#include + +#include "../path.hpp" + +namespace io { + class Device { + public: + virtual ~Device() = default; + + virtual std::filesystem::path resolve(std::string_view path) = 0; + + virtual void write(std::string_view path, const void* data, size_t size) = 0; + virtual void read(std::string_view path, void* data, size_t size) = 0; + + virtual size_t size(std::string_view path) = 0; + + virtual bool exists(std::string_view path) = 0; + virtual bool isdir(std::string_view path) = 0; + virtual bool isfile(std::string_view path) = 0; + virtual void mkdirs(std::string_view path) = 0; + virtual bool remove(std::string_view path) = 0; + virtual uint64_t removeAll(std::string_view path) = 0; + }; + + class SubDevice : public Device { + public: + SubDevice(std::shared_ptr parent, const std::string& path) + : parent(std::move(parent)), root(path) {} + + std::filesystem::path resolve(std::string_view path) override { + return parent->resolve((root / path).pathPart()); + } + + void write(std::string_view path, const void* data, size_t size) override { + parent->write((root / path).pathPart(), data, size); + } + + void read(std::string_view path, void* data, size_t size) override { + parent->read((root / path).pathPart(), data, size); + } + + size_t size(std::string_view path) override { + return parent->size((root / path).pathPart()); + } + + bool exists(std::string_view path) override { + return parent->exists((root / path).pathPart()); + } + + bool isdir(std::string_view path) override { + return parent->isdir((root / path).pathPart()); + } + + bool isfile(std::string_view path) override { + return parent->isfile((root / path).pathPart()); + } + + void mkdirs(std::string_view path) override { + parent->mkdirs((root / path).pathPart()); + } + + bool remove(std::string_view path) override { + return parent->remove((root / path).pathPart()); + } + + uint64_t removeAll(std::string_view path) override { + return parent->removeAll((root / path).pathPart()); + } + private: + std::shared_ptr parent; + path root; + }; +} diff --git a/src/io/devices/StdfsDevice.cpp b/src/io/devices/StdfsDevice.cpp new file mode 100644 index 00000000..7078b394 --- /dev/null +++ b/src/io/devices/StdfsDevice.cpp @@ -0,0 +1,63 @@ +#include "StdfsDevice.hpp" + +#include +#include + +using namespace io; + +std::filesystem::path StdfsDevice::resolve(std::string_view path) { + return root / std::filesystem::u8path(path); +} + +void StdfsDevice::write(std::string_view path, const void* data, size_t size) { + auto resolved = resolve(path); + std::ofstream output(resolved, std::ios::binary); + if (!output.is_open()) { + throw std::runtime_error("could not to open file " + resolved.u8string()); + } + output.write((const char*)data, size); +} + +void StdfsDevice::read(std::string_view path, void* data, size_t size) { + auto resolved = resolve(path); + std::ifstream input(resolved, std::ios::binary); + if (!input.is_open()) { + throw std::runtime_error("could not to open file " + resolved.u8string()); + } + input.read((char*)data, size); +} + +size_t StdfsDevice::size(std::string_view path) { + auto resolved = resolve(path); + return std::filesystem::file_size(resolved); +} + +bool StdfsDevice::exists(std::string_view path) { + auto resolved = resolve(path); + return std::filesystem::exists(resolved); +} + +bool StdfsDevice::isdir(std::string_view path) { + auto resolved = resolve(path); + return std::filesystem::is_directory(resolved); +} + +bool StdfsDevice::isfile(std::string_view path) { + auto resolved = resolve(path); + return std::filesystem::is_regular_file(resolved); +} + +void StdfsDevice::mkdirs(std::string_view path) { + auto resolved = resolve(path); + std::filesystem::create_directories(resolved); +} + +bool StdfsDevice::remove(std::string_view path) { + auto resolved = resolve(path); + return std::filesystem::remove(resolved); +} + +uint64_t StdfsDevice::removeAll(std::string_view path) { + auto resolved = resolve(path); + return std::filesystem::remove_all(resolved); +} diff --git a/src/io/devices/StdfsDevice.hpp b/src/io/devices/StdfsDevice.hpp new file mode 100644 index 00000000..6c88949f --- /dev/null +++ b/src/io/devices/StdfsDevice.hpp @@ -0,0 +1,21 @@ +#include "Device.hpp" + +namespace io { + class StdfsDevice : public Device { + public: + StdfsDevice(std::filesystem::path root) : root(std::move(root)) {} + + std::filesystem::path resolve(std::string_view path) override; + void write(std::string_view path, const void* data, size_t size) override; + void read(std::string_view path, void* data, size_t size) override; + size_t size(std::string_view path) override; + bool exists(std::string_view path) override; + bool isdir(std::string_view path) override; + bool isfile(std::string_view path) override; + void mkdirs(std::string_view path) override; + bool remove(std::string_view path) override; + uint64_t removeAll(std::string_view path) override; + private: + std::filesystem::path root; + }; +} diff --git a/src/io/engine_paths.cpp b/src/io/engine_paths.cpp index df5b8347..88fb98ca 100644 --- a/src/io/engine_paths.cpp +++ b/src/io/engine_paths.cpp @@ -9,9 +9,12 @@ #include "util/stringutil.hpp" #include +#include "io/devices/StdfsDevice.hpp" #include "world/files/WorldFiles.hpp" #include "debug/Logger.hpp" +namespace fs = std::filesystem; + static debug::Logger logger("engine-paths"); static inline auto SCREENSHOTS_FOLDER = std::filesystem::u8path("screenshots"); @@ -22,15 +25,16 @@ static inline auto EXPORT_FOLDER = std::filesystem::u8path("export"); static inline auto CONTROLS_FILE = std::filesystem::u8path("controls.toml"); static inline auto SETTINGS_FILE = std::filesystem::u8path("settings.toml"); -static std::filesystem::path toCanonic(std::filesystem::path path) { +static io::path toCanonic(io::path path) { std::stack parts; - path = path.lexically_normal(); + + path = std::filesystem::u8path(path.string()).lexically_normal().string(); do { - parts.push(path.filename().u8string()); - path = path.parent_path(); + parts.push(path.name()); + path = path.parent(); } while (!path.empty()); - path = fs::u8path(""); + path = ""; while (!parts.empty()) { const std::string part = parts.top(); @@ -48,44 +52,47 @@ static std::filesystem::path toCanonic(std::filesystem::path path) { } void EnginePaths::prepare() { - if (!fs::is_directory(resourcesFolder)) { + io::set_device("res", std::make_shared(resourcesFolder)); + io::set_device("user", std::make_shared(userFilesFolder)); + + if (!io::is_directory("res:")) { throw std::runtime_error( - resourcesFolder.u8string() + " is not a directory" + resourcesFolder.string() + " is not a directory" ); } - if (!fs::is_directory(userFilesFolder)) { - fs::create_directories(userFilesFolder); + if (!io::is_directory("user:")) { + io::create_directories("user:"); } logger.info() << "resources folder: " << fs::canonical(resourcesFolder).u8string(); logger.info() << "user files folder: " << fs::canonical(userFilesFolder).u8string(); - auto contentFolder = userFilesFolder / CONTENT_FOLDER; - if (!fs::is_directory(contentFolder)) { - fs::create_directories(contentFolder); + auto contentFolder = io::path("user:") / CONTENT_FOLDER; + if (!io::is_directory(contentFolder)) { + io::create_directories(contentFolder); } - auto exportFolder = userFilesFolder / EXPORT_FOLDER; - if (!fs::is_directory(exportFolder)) { - fs::create_directories(exportFolder); + auto exportFolder = io::path("user:") / EXPORT_FOLDER; + if (!io::is_directory(exportFolder)) { + io::create_directories(exportFolder); } - auto configFolder = userFilesFolder / CONFIG_FOLDER; - if (!fs::is_directory(configFolder)) { - fs::create_directories(configFolder); + auto configFolder = io::path("user:") / CONFIG_FOLDER; + if (!io::is_directory(configFolder)) { + io::create_directories(configFolder); } } -std::filesystem::path EnginePaths::getUserFilesFolder() const { +const std::filesystem::path& EnginePaths::getUserFilesFolder() const { return userFilesFolder; } -std::filesystem::path EnginePaths::getResourcesFolder() const { +const std::filesystem::path& EnginePaths::getResourcesFolder() const { return resourcesFolder; } -std::filesystem::path EnginePaths::getNewScreenshotFile(const std::string& ext) { - auto folder = userFilesFolder / SCREENSHOTS_FOLDER; - if (!fs::is_directory(folder)) { - fs::create_directory(folder); +io::path EnginePaths::getNewScreenshotFile(const std::string& ext) { + auto folder = io::path("user:") / SCREENSHOTS_FOLDER; + if (!io::is_directory(folder)) { + io::create_directories(folder); } auto t = std::time(nullptr); @@ -96,55 +103,55 @@ std::filesystem::path EnginePaths::getNewScreenshotFile(const std::string& ext) ss << std::put_time(&tm, format); std::string datetimestr = ss.str(); - auto filename = folder / fs::u8path("screenshot-" + datetimestr + "." + ext); + auto file = folder / ("screenshot-" + datetimestr + "." + ext); uint index = 0; - while (fs::exists(filename)) { - filename = folder / fs::u8path( - "screenshot-" + datetimestr + "-" + - std::to_string(index) + "." + ext - ); + while (io::exists(file)) { + file = folder / fs::u8path( + "screenshot-" + datetimestr + "-" + + std::to_string(index) + "." + ext + ); index++; } - return filename; + return file; } -std::filesystem::path EnginePaths::getWorldsFolder() const { - return userFilesFolder / WORLDS_FOLDER; +io::path EnginePaths::getWorldsFolder() const { + return io::path("user:") / WORLDS_FOLDER; } -std::filesystem::path EnginePaths::getConfigFolder() const { - return userFilesFolder / CONFIG_FOLDER; +io::path EnginePaths::getConfigFolder() const { + return io::path("user:") / CONFIG_FOLDER; } -std::filesystem::path EnginePaths::getCurrentWorldFolder() { +io::path EnginePaths::getCurrentWorldFolder() { return currentWorldFolder; } -std::filesystem::path EnginePaths::getWorldFolderByName(const std::string& name) { +io::path EnginePaths::getWorldFolderByName(const std::string& name) { return getWorldsFolder() / std::filesystem::path(name); } -std::filesystem::path EnginePaths::getControlsFile() const { - return userFilesFolder / CONTROLS_FILE; +io::path EnginePaths::getControlsFile() const { + return io::path("user:") / CONTROLS_FILE; } -std::filesystem::path EnginePaths::getSettingsFile() const { - return userFilesFolder / SETTINGS_FILE; +io::path EnginePaths::getSettingsFile() const { + return io::path("user:") / SETTINGS_FILE; } -std::vector EnginePaths::scanForWorlds() const { - std::vector folders; +std::vector EnginePaths::scanForWorlds() const { + std::vector folders; auto folder = getWorldsFolder(); - if (!fs::is_directory(folder)) return folders; + if (!io::is_directory(folder)) return folders; - for (const auto& entry : fs::directory_iterator(folder)) { + for (const auto& entry : std::filesystem::directory_iterator(io::resolve(folder))) { if (!entry.is_directory()) { continue; } - const auto& worldFolder = entry.path(); - auto worldFile = worldFolder / fs::u8path(WorldFiles::WORLD_FILE); - if (!fs::is_regular_file(worldFile)) { + io::path worldFolder = folder / entry.path().filename().u8string(); + auto worldFile = worldFolder / WorldFiles::WORLD_FILE; + if (!io::is_regular_file(worldFile)) { continue; } folders.push_back(worldFolder); @@ -152,10 +159,11 @@ std::vector EnginePaths::scanForWorlds() const { std::sort( folders.begin(), folders.end(), - [](std::filesystem::path a, std::filesystem::path b) { - a = a / fs::u8path(WorldFiles::WORLD_FILE); - b = b / fs::u8path(WorldFiles::WORLD_FILE); - return fs::last_write_time(a) > fs::last_write_time(b); + [](io::path a, io::path b) { + a = a / WorldFiles::WORLD_FILE; + b = b / WorldFiles::WORLD_FILE; + return fs::last_write_time(io::resolve(a)) > + fs::last_write_time(io::resolve(b)); } ); return folders; @@ -170,11 +178,13 @@ void EnginePaths::setResourcesFolder(std::filesystem::path folder) { } void EnginePaths::setScriptFolder(std::filesystem::path folder) { + io::set_device("script", std::make_shared(folder)); this->scriptFolder = std::move(folder); } -void EnginePaths::setCurrentWorldFolder(std::filesystem::path folder) { +void EnginePaths::setCurrentWorldFolder(io::path folder) { this->currentWorldFolder = std::move(folder); + io::create_subdevice("world", "user", currentWorldFolder); } void EnginePaths::setContentPacks(std::vector* contentPacks) { @@ -191,65 +201,64 @@ std::tuple EnginePaths::parsePath(std::string_view pat return {prefix, filename}; } -std::filesystem::path EnginePaths::resolve( +// TODO: remove +io::path EnginePaths::resolve( const std::string& path, bool throwErr ) const { auto [prefix, filename] = EnginePaths::parsePath(path); if (prefix.empty()) { throw files_access_error("no entry point specified"); } - filename = toCanonic(fs::u8path(filename)).u8string(); + filename = toCanonic(filename).string(); - if (prefix == "res" || prefix == "core") { - return resourcesFolder / fs::u8path(filename); + if (prefix == "core") { + return io::path("res:") / filename; } - if (prefix == "user") { - return userFilesFolder / fs::u8path(filename); + + if (prefix == "res" || prefix == "user" || prefix == "script") { + return prefix + ":" + filename; } if (prefix == "config") { - return getConfigFolder() / fs::u8path(filename); + return getConfigFolder() / filename; } if (prefix == "world") { - return currentWorldFolder / fs::u8path(filename); + return currentWorldFolder / filename; } if (prefix == "export") { - return userFilesFolder / EXPORT_FOLDER / fs::u8path(filename); - } - if (prefix == "script" && scriptFolder) { - return scriptFolder.value() / fs::u8path(filename); + return io::path("user:") / EXPORT_FOLDER / filename; } if (contentPacks) { for (auto& pack : *contentPacks) { if (pack.id == prefix) { - return pack.folder / fs::u8path(filename); + return pack.folder / filename; } } } if (throwErr) { throw files_access_error("unknown entry point '" + prefix + "'"); } - return std::filesystem::path(filename); + return filename; } -ResPaths::ResPaths(std::filesystem::path mainRoot, std::vector roots) +ResPaths::ResPaths(io::path mainRoot, std::vector roots) : mainRoot(std::move(mainRoot)), roots(std::move(roots)) { } -std::filesystem::path ResPaths::find(const std::string& filename) const { +io::path ResPaths::find(const std::string& filename) const { for (int i = roots.size() - 1; i >= 0; i--) { auto& root = roots[i]; - auto file = root.path / fs::u8path(filename); - if (fs::exists(file)) { + auto file = root.path / filename; + if (io::exists(file)) { return file; } } - return mainRoot / fs::u8path(filename); + return mainRoot / filename; } 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.path / std::filesystem::path(filename))) { + if (io::exists(root.path / filename)) { return root.name + ":" + filename; } } @@ -261,8 +270,8 @@ std::vector ResPaths::listdirRaw(const std::string& folderName) con for (int i = roots.size() - 1; i >= 0; i--) { auto& root = roots[i]; auto folder = root.path / fs::u8path(folderName); - if (!fs::is_directory(folder)) continue; - for (const auto& entry : fs::directory_iterator(folder)) { + if (!io::is_directory(folder)) continue; + for (const auto& entry : fs::directory_iterator(io::resolve(folder))) { auto name = entry.path().filename().u8string(); entries.emplace_back(root.name + ":" + folderName + "/" + name); } @@ -270,16 +279,16 @@ std::vector ResPaths::listdirRaw(const std::string& folderName) con return entries; } -std::vector ResPaths::listdir( +std::vector ResPaths::listdir( const std::string& folderName ) const { - std::vector entries; + std::vector entries; for (int i = roots.size() - 1; i >= 0; i--) { auto& root = roots[i]; - std::filesystem::path folder = root.path / fs::u8path(folderName); - if (!fs::is_directory(folder)) continue; - for (const auto& entry : fs::directory_iterator(folder)) { - entries.push_back(entry.path()); + io::path folder = root.path / folderName; + if (!io::is_directory(folder)) continue; + for (const auto& entry : fs::directory_iterator(io::resolve(folder))) { + entries.push_back(folder / entry.path().filename().u8string()); } } return entries; @@ -288,8 +297,8 @@ std::vector ResPaths::listdir( dv::value ResPaths::readCombinedList(const std::string& filename) const { dv::value list = dv::list(); for (const auto& root : roots) { - auto path = root.path / fs::u8path(filename); - if (!fs::exists(path)) { + auto path = root.path / filename; + if (!io::exists(path)) { continue; } try { @@ -313,8 +322,8 @@ dv::value ResPaths::readCombinedList(const std::string& filename) const { dv::value ResPaths::readCombinedObject(const std::string& filename) const { dv::value object = dv::object(); for (const auto& root : roots) { - auto path = root.path / fs::u8path(filename); - if (!fs::exists(path)) { + auto path = root.path / filename; + if (!io::exists(path)) { continue; } try { @@ -335,6 +344,6 @@ dv::value ResPaths::readCombinedObject(const std::string& filename) const { return object; } -const std::filesystem::path& ResPaths::getMainRoot() const { +const io::path& ResPaths::getMainRoot() const { return mainRoot; } diff --git a/src/io/engine_paths.hpp b/src/io/engine_paths.hpp index 5ec34704..920b01aa 100644 --- a/src/io/engine_paths.hpp +++ b/src/io/engine_paths.hpp @@ -1,16 +1,15 @@ #pragma once -#include #include #include #include #include #include +#include "io.hpp" #include "data/dv.hpp" #include "content/ContentPack.hpp" - class files_access_error : public std::runtime_error { public: files_access_error(const std::string& msg) : std::runtime_error(msg) { @@ -22,29 +21,29 @@ public: void prepare(); void setUserFilesFolder(std::filesystem::path folder); - std::filesystem::path getUserFilesFolder() const; + const std::filesystem::path& getUserFilesFolder() const; void setResourcesFolder(std::filesystem::path folder); - std::filesystem::path getResourcesFolder() const; + const std::filesystem::path& getResourcesFolder() const; void setScriptFolder(std::filesystem::path folder); - std::filesystem::path getWorldFolderByName(const std::string& name); - std::filesystem::path getWorldsFolder() const; - std::filesystem::path getConfigFolder() const; + io::path getWorldFolderByName(const std::string& name); + io::path getWorldsFolder() const; + io::path getConfigFolder() const; - void setCurrentWorldFolder(std::filesystem::path folder); - std::filesystem::path getCurrentWorldFolder(); + void setCurrentWorldFolder(io::path folder); + io::path getCurrentWorldFolder(); - std::filesystem::path getNewScreenshotFile(const std::string& ext); - std::filesystem::path getControlsFile() const; - std::filesystem::path getSettingsFile() const; + io::path getNewScreenshotFile(const std::string& ext); + io::path getControlsFile() const; + io::path getSettingsFile() const; void setContentPacks(std::vector* contentPacks); - std::vector scanForWorlds() const; + std::vector scanForWorlds() const; - std::filesystem::path resolve(const std::string& path, bool throwErr = true) const; + io::path resolve(const std::string& path, bool throwErr = true) const; static std::tuple parsePath(std::string_view view); @@ -53,23 +52,23 @@ public: private: std::filesystem::path userFilesFolder {"."}; std::filesystem::path resourcesFolder {"res"}; - std::filesystem::path currentWorldFolder; + io::path currentWorldFolder; std::optional scriptFolder; std::vector* contentPacks = nullptr; }; struct PathsRoot { std::string name; - std::filesystem::path path; + io::path path; }; class ResPaths { public: - ResPaths(std::filesystem::path mainRoot, std::vector roots); + ResPaths(io::path mainRoot, std::vector roots); - std::filesystem::path find(const std::string& filename) const; + io::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 listdir(const std::string& folder) const; std::vector listdirRaw(const std::string& folder) const; /// @brief Read all found list versions from all packs and combine into a @@ -79,9 +78,9 @@ public: dv::value readCombinedObject(const std::string& file) const; - const std::filesystem::path& getMainRoot() const; + const io::path& getMainRoot() const; private: - std::filesystem::path mainRoot; + io::path mainRoot; std::vector roots; }; diff --git a/src/io/fwd.hpp b/src/io/fwd.hpp new file mode 100644 index 00000000..d6ce72f0 --- /dev/null +++ b/src/io/fwd.hpp @@ -0,0 +1,5 @@ +#pragma once + +namespace io { + class path; +} diff --git a/src/io/io.cpp b/src/io/io.cpp index 9979b950..356357c5 100644 --- a/src/io/io.cpp +++ b/src/io/io.cpp @@ -1,7 +1,7 @@ #include "io.hpp" +#include #include - #include #include #include @@ -13,10 +13,44 @@ #include "coders/toml.hpp" #include "util/stringutil.hpp" +#include "devices/Device.hpp" + namespace fs = std::filesystem; -io::rafile::rafile(const fs::path& filename) - : file(filename, std::ios::binary | std::ios::ate) { +static std::map> devices; + +void io::set_device(const std::string& name, std::shared_ptr device) { + devices[name] = device; +} + +std::shared_ptr io::get_device(const std::string& name) { + const auto& found = devices.find(name); + if (found == devices.end()) { + return nullptr; + } + return found->second; +} + +io::Device& io::require_device(const std::string& name) { + auto device = get_device(name); + if (!device) { + throw std::runtime_error("io-device not found: " + name); + } + return *device; +} + +void io::create_subdevice( + const std::string& name, const std::string& parent, const io::path& root +) { + auto parentDevice = get_device(parent); + if (!parentDevice) { + throw std::runtime_error("parent device not found for entry-point: " + parent); + } + set_device(name, std::make_shared(parentDevice, root.pathPart())); +} + +io::rafile::rafile(const io::path& filename) + : file(io::resolve(filename), std::ios::binary | std::ios::ate) { if (!file) { throw std::runtime_error("could not to open file " + filename.string()); } @@ -37,121 +71,92 @@ void io::rafile::read(char* buffer, std::streamsize size) { } bool io::write_bytes( - const fs::path& filename, const ubyte* data, size_t size + const io::path& filename, const ubyte* data, size_t size ) { - std::ofstream output(filename, std::ios::binary); - if (!output.is_open()) return false; - output.write((const char*)data, size); - output.close(); + auto device = io::get_device(filename.entryPoint()); + if (device == nullptr) { + return false; + } + device->write(filename.pathPart(), data, size); return true; } -uint io::append_bytes( - const fs::path& filename, const ubyte* data, size_t size -) { - std::ofstream output(filename, std::ios::binary | std::ios::app); - if (!output.is_open()) return 0; - uint position = output.tellp(); - output.write((const char*)data, size); - output.close(); - return position; -} - -bool io::read(const fs::path& filename, char* data, size_t size) { - std::ifstream output(filename, std::ios::binary); - if (!output.is_open()) return false; - output.read(data, size); - output.close(); +bool io::read(const io::path& filename, char* data, size_t size) { + auto device = io::get_device(filename.entryPoint()); + if (device == nullptr) { + return false; + } + device->read(filename.pathPart(), data, size); return true; } -util::Buffer io::read_bytes_buffer(const fs::path& path) { +util::Buffer io::read_bytes_buffer(const path& file) { size_t size; - auto bytes = io::read_bytes(path, size); + auto bytes = io::read_bytes(file, size); return util::Buffer(std::move(bytes), size); } std::unique_ptr io::read_bytes( - const fs::path& filename, size_t& length + const io::path& filename, size_t& length ) { - std::ifstream input(filename, std::ios::binary); - if (!input.is_open()) { - throw std::runtime_error( - "could not to load file '" + filename.string() + "'" - ); - } - input.seekg(0, std::ios_base::end); - length = input.tellg(); - input.seekg(0, std::ios_base::beg); - + auto& device = io::require_device(filename.entryPoint()); + length = device.size(filename.pathPart()); auto data = std::make_unique(length); - input.read((char*)data.get(), length); - input.close(); + device.read(filename.pathPart(), data.get(), length); return data; } -std::vector io::read_bytes(const fs::path& filename) { - std::ifstream input(filename, std::ios::binary); - if (!input.is_open()) return {}; - input.seekg(0, std::ios_base::end); - size_t length = input.tellg(); - input.seekg(0, std::ios_base::beg); - +std::vector io::read_bytes(const path& filename) { + auto& device = io::require_device(filename.entryPoint()); + size_t length = device.size(filename.pathPart()); std::vector data(length); - data.resize(length); - input.read((char*)data.data(), length); - input.close(); + device.read(filename.pathPart(), data.data(), length); return data; } -std::string io::read_string(const fs::path& filename) { +std::string io::read_string(const path& filename) { size_t size; auto bytes = read_bytes(filename, size); return std::string((const char*)bytes.get(), size); } -bool io::write_string(const fs::path& filename, std::string_view content) { - std::ofstream file(filename); - if (!file) { - return false; - } - file << content; - return true; +bool io::write_string(const io::path& file, std::string_view content) { + return io::write_bytes(file, (const ubyte*)content.data(), content.size()); } bool io::write_json( - const fs::path& filename, const dv::value& obj, bool nice + const io::path& file, const dv::value& obj, bool nice ) { - return io::write_string(filename, json::stringify(obj, nice, " ")); + return io::write_string(file, json::stringify(obj, nice, " ")); } bool io::write_binary_json( - const fs::path& filename, const dv::value& obj, bool compression + const io::path& file, const dv::value& obj, bool compression ) { auto bytes = json::to_binary(obj, compression); - return io::write_bytes(filename, bytes.data(), bytes.size()); + return io::write_bytes(file, bytes.data(), bytes.size()); } -dv::value io::read_json(const fs::path& filename) { +dv::value io::read_json(const path& filename) { std::string text = io::read_string(filename); return json::parse(filename.string(), text); } -dv::value io::read_binary_json(const fs::path& file) { +dv::value io::read_binary_json(const path& file) { size_t size; auto bytes = io::read_bytes(file, size); return json::from_binary(bytes.get(), size); } -dv::value io::read_toml(const fs::path& file) { - return toml::parse(file.u8string(), io::read_string(file)); +dv::value io::read_toml(const path& file) { + return toml::parse(file.string(), io::read_string(file)); } -std::vector io::read_list(const fs::path& filename) { - std::ifstream file(filename); +std::vector io::read_list(const io::path& filename) { + std::ifstream file(resolve(filename)); // FIXME if (!file) { throw std::runtime_error( - "could not to open file " + filename.u8string() + "could not to open file " + filename.string() ); } std::vector lines; @@ -165,6 +170,71 @@ std::vector io::read_list(const fs::path& filename) { return lines; } +bool io::is_regular_file(const io::path& file) { + if (file.empty()) { + return false; + } + auto device = io::get_device(file.entryPoint()); + if (device == nullptr) { + return false; + } + return device->isfile(file.pathPart()); +} + +bool io::is_directory(const io::path& file) { + if (file.empty()) { + return false; + } + auto device = io::get_device(file.entryPoint()); + if (device == nullptr) { + return false; + } + return device->isdir(file.pathPart()); +} + +bool io::exists(const io::path& file) { + if (file.empty()) { + return false; + } + auto device = io::get_device(file.entryPoint()); + if (device == nullptr) { + return false; + } + return device->exists(file.pathPart()); +} + +bool io::create_directories(const io::path& file) { + auto& device = io::require_device(file.entryPoint()); + if (device.isdir(file.pathPart())) { + return false; + } + device.mkdirs(file.pathPart()); + return true; +} + +bool io::remove(const io::path& file) { + auto& device = io::require_device(file.entryPoint()); + return device.remove(file.pathPart()); +} + +uint64_t io::remove_all(const io::path& file) { + auto& device = io::require_device(file.entryPoint()); + return device.removeAll(file.pathPart()); +} + +size_t io::file_size(const io::path& file) { + auto& device = io::require_device(file.entryPoint()); + return device.size(file.pathPart()); +} + +std::filesystem::path io::resolve(const io::path& file) { + auto device = io::get_device(file.entryPoint()); + if (device == nullptr) { + return {}; + } + return device->resolve(file.pathPart()); +} + #include #include "coders/json.hpp" @@ -177,22 +247,22 @@ static std::map data_decoders { {fs::u8path(".toml"), toml::parse}, }; -bool io::is_data_file(const fs::path& file) { +bool io::is_data_file(const io::path& file) { return is_data_interchange_format(file.extension()); } -bool io::is_data_interchange_format(const fs::path& ext) { +bool io::is_data_interchange_format(const std::string& ext) { return data_decoders.find(ext) != data_decoders.end(); } -dv::value io::read_object(const fs::path& file) { +dv::value io::read_object(const path& file) { const auto& found = data_decoders.find(file.extension()); if (found == data_decoders.end()) { throw std::runtime_error("unknown file format"); } auto text = read_string(file); try { - return found->second(file.u8string(), text); + return found->second(file.string(), text); } catch (const parsing_error& err) { throw std::runtime_error(err.errorLog()); } diff --git a/src/io/io.hpp b/src/io/io.hpp index 5ea4c93e..1cdc8198 100644 --- a/src/io/io.hpp +++ b/src/io/io.hpp @@ -9,16 +9,25 @@ #include "typedefs.hpp" #include "data/dv.hpp" #include "util/Buffer.hpp" - -namespace fs = std::filesystem; +#include "path.hpp" namespace io { + class Device; + + void set_device(const std::string& name, std::shared_ptr device); + std::shared_ptr get_device(const std::string& name); + Device& require_device(const std::string& name); + + void create_subdevice( + const std::string& name, const std::string& parent, const path& root + ); + /// @brief Read-only random access file class rafile { std::ifstream file; size_t filelength; public: - rafile(const fs::path& filename); + rafile(const path& filename); void seekg(std::streampos pos); void read(char* buffer, std::streamsize size); @@ -29,52 +38,56 @@ namespace io { /// @param file target file /// @param data data bytes array /// @param size size of data bytes array - bool write_bytes(const fs::path& file, const ubyte* data, size_t size); - - /// @brief Append bytes array to the file without any extra data - /// @param file target file - /// @param data data bytes array - /// @param size size of data bytes array - uint append_bytes(const fs::path& file, const ubyte* data, size_t size); + bool write_bytes(const io::path& file, const ubyte* data, size_t size); /// @brief Write string to the file - bool write_string(const fs::path& filename, std::string_view content); + bool write_string(const io::path& file, std::string_view content); /// @brief Write dynamic data to the JSON file /// @param nice if true, human readable format will be used, otherwise /// minimal bool write_json( - const fs::path& filename, const dv::value& obj, bool nice = true + const io::path& file, const dv::value& obj, bool nice = true ); /// @brief Write dynamic data to the binary JSON file /// (see src/coders/binary_json_spec.md) /// @param compressed use gzip compression bool write_binary_json( - const fs::path& filename, + const io::path& file, const dv::value& obj, bool compressed = false ); - bool read(const fs::path&, char* data, size_t size); - util::Buffer read_bytes_buffer(const fs::path&); - std::unique_ptr read_bytes(const fs::path&, size_t& length); - std::vector read_bytes(const fs::path&); - std::string read_string(const fs::path& filename); + bool read(const io::path& file, char* data, size_t size); + util::Buffer read_bytes_buffer(const path& file); + std::unique_ptr read_bytes(const path& file, size_t& length); + std::vector read_bytes(const path& file); + std::string read_string(const path& file); /// @brief Read JSON or BJSON file /// @param file *.json or *.bjson file - dv::value read_json(const fs::path& file); + dv::value read_json(const path& file); - dv::value read_binary_json(const fs::path& file); + dv::value read_binary_json(const path& file); /// @brief Read TOML file /// @param file *.toml file - dv::value read_toml(const fs::path& file); + dv::value read_toml(const path& file); - std::vector read_list(const fs::path& file); + std::vector read_list(const io::path& file); - bool is_data_file(const fs::path& file); - bool is_data_interchange_format(const fs::path& ext); - dv::value read_object(const fs::path& file); + bool is_regular_file(const io::path& file); + bool is_directory(const io::path& file); + bool exists(const io::path& file); + bool create_directories(const io::path& file); + bool remove(const io::path& file); + uint64_t remove_all(const io::path& file); + size_t file_size(const io::path& file); + + std::filesystem::path resolve(const io::path& file); + + bool is_data_file(const io::path& file); + bool is_data_interchange_format(const std::string& ext); + dv::value read_object(const path& file); } diff --git a/src/io/path.cpp b/src/io/path.cpp new file mode 100644 index 00000000..e1dd5a98 --- /dev/null +++ b/src/io/path.cpp @@ -0,0 +1,11 @@ +#include "path.hpp" + +#include + +using namespace io; + +void path::checkValid() const { + if (colonPos == std::string::npos) { + throw std::runtime_error("path entry point is not specified: " + str); + } +} diff --git a/src/io/path.hpp b/src/io/path.hpp new file mode 100644 index 00000000..454ff161 --- /dev/null +++ b/src/io/path.hpp @@ -0,0 +1,138 @@ +#pragma once + +#include +#include + +namespace io { + /// @brief std::filesystem::path project-specific alternative having + /// `entry_point:path` scheme and solving std::filesystem::path problems: + /// - implicit std::string conversions depending on compiler + /// - unicode path construction must be done with std::filesystem::u8path + class path { + public: + path() = default; + + path(std::string str) : str(std::move(str)) { + colonPos = this->str.find(':'); + + size_t len = this->str.length(); + for (size_t i = 0; i < len; i++) { + if (this->str[i] == '\\') { + this->str[i] = '/'; + } + } + } + + path(const char* str) : path(std::string(str)) {} + + bool operator==(const std::string& other) const { + return str == other; + } + + bool operator<(const path& other) const { + return str < other.str; + } + + bool operator==(const path& other) const { + return str == other.str; + } + + bool operator==(const char* other) const { + return str == other; + } + + path operator/(const char* child) const { + if (str.empty() || str[str.length()-1] == ':') { + return str + std::string(child); + } + return str + "/" + std::string(child); + } + + path operator/(const std::string& child) const { + if (str.empty() || str[str.length()-1] == ':') { + return str + child; + } + return str + "/" + child; + } + + path operator/(std::string_view child) const { + if (str.empty() || str[str.length()-1] == ':') { + return str + std::string(child); + } + return str + "/" + std::string(child); + } + + path operator/(const path& child) const { + if (str.empty() || str[str.length()-1] == ':') { + return str + child.pathPart(); + } + return str + "/" + child.pathPart(); + } + + std::string pathPart() const { + if (colonPos == std::string::npos) { + return str; + } + return str.substr(colonPos + 1); + } + + std::string name() const { + size_t slashpos = str.rfind('/'); + if (slashpos == std::string::npos) { + return colonPos == std::string::npos ? str + : str.substr(colonPos + 1); + } + return str.substr(slashpos + 1); + } + + std::string stem() const { + return name().substr(0, name().rfind('.')); + } + + /// @brief Get extension + std::string extension() const { + size_t slashpos = str.rfind('/'); + size_t dotpos = str.rfind('.'); + if (dotpos == std::string::npos || + (slashpos != std::string::npos && dotpos < slashpos)) { + return ""; + } + return str.substr(dotpos); + } + + /// @brief Get entry point + std::string entryPoint() const { + checkValid(); + return str.substr(0, colonPos); + } + + /// @brief Get parent path + path parent() const { + size_t slashpos = str.rfind('/'); + if (slashpos == std::string::npos) { + return colonPos == std::string::npos + ? path() + : path(str.substr(0, colonPos)); + } + return colonPos == std::string::npos + ? path(str.substr(0, slashpos)) + : path(str.substr(0, colonPos) + str.substr(slashpos)); + } + + std::string string() const { + return str; + } + + /// @brief Check if path is not initialized with 'entry_point:path' + bool empty() const { + return str.empty(); + } + private: + /// @brief UTF-8 string contains entry_point:path or empty string + std::string str; + /// @brief Precalculated position of colon character + size_t colonPos = std::string::npos; + + void checkValid() const; + }; +} diff --git a/src/logic/EngineController.cpp b/src/logic/EngineController.cpp index fc0b1cb0..72ce6e90 100644 --- a/src/logic/EngineController.cpp +++ b/src/logic/EngineController.cpp @@ -32,11 +32,11 @@ EngineController::EngineController(Engine& engine) : engine(engine) { } void EngineController::deleteWorld(const std::string& name) { - fs::path folder = engine.getPaths().getWorldFolderByName(name); + io::path folder = engine.getPaths().getWorldFolderByName(name); auto deletion = [this, folder]() { - logger.info() << "deleting " << folder; - fs::remove_all(folder); + logger.info() << "deleting " << folder.string(); + io::remove_all(folder); if (!engine.isHeadless()) { engine.getGUI()->getMenu()->back(); } @@ -49,7 +49,7 @@ void EngineController::deleteWorld(const std::string& name) { guiutil::confirm( engine, langs::get(L"delete-confirm", L"world") + L" (" + - util::str2wstr_utf8(folder.u8string()) + L")", + util::str2wstr_utf8(folder.string()) + L")", deletion ); } @@ -128,7 +128,7 @@ static void show_convert_request( ); } -static bool load_world_content(Engine& engine, const fs::path& folder) { +static bool load_world_content(Engine& engine, const io::path& folder) { if (engine.isHeadless()) { engine.loadWorldContent(folder); return true; @@ -192,10 +192,10 @@ void EngineController::onMissingContent(const std::shared_ptr& re void EngineController::openWorld(const std::string& name, bool confirmConvert) { const auto& paths = engine.getPaths(); - auto folder = paths.getWorldsFolder() / fs::u8path(name); - auto worldFile = folder / fs::u8path("world.json"); - if (!fs::exists(worldFile)) { - throw std::runtime_error(worldFile.u8string() + " does not exists"); + auto folder = paths.getWorldsFolder() / name; + auto worldFile = folder / "world.json"; + if (!io::exists(worldFile)) { + throw std::runtime_error(worldFile.string() + " does not exists"); } if (!load_world_content(engine, folder)) { @@ -257,7 +257,7 @@ void EngineController::createWorld( uint64_t seed = str2seed(seedstr); EnginePaths& paths = engine.getPaths(); - auto folder = paths.getWorldsFolder() / fs::u8path(name); + auto folder = paths.getWorldsFolder() / name; if (engine.isHeadless()) { engine.loadContent(); @@ -288,7 +288,7 @@ void EngineController::setLocalPlayer(int64_t player) { } void EngineController::reopenWorld(World* world) { - std::string name = world->wfile->getFolder().filename().u8string(); + std::string name = world->wfile->getFolder().name(); engine.onWorldClosed(); openWorld(name, true); } @@ -318,7 +318,7 @@ void EngineController::reconfigPacks( runnable removeFunc = [this, controller, packsToAdd, packsToRemove]() { if (controller == nullptr) { try { - auto manager = engine.createPacksManager(fs::path("")); + auto manager = engine.createPacksManager(""); manager.scan(); auto names = PacksManager::getNames(engine.getContentPacks()); for (const auto& id : packsToAdd) { diff --git a/src/logic/scripting/lua/libs/libcore.cpp b/src/logic/scripting/lua/libs/libcore.cpp index 3566e990..4c1e5dc6 100644 --- a/src/logic/scripting/lua/libs/libcore.cpp +++ b/src/logic/scripting/lua/libs/libcore.cpp @@ -260,7 +260,7 @@ static int l_load_texture(lua::State* L) { static int l_open_folder(lua::State* L) { auto path = engine->getPaths().resolve(lua::require_string(L, 1)); - platform::open_folder(path); + platform::open_folder(io::resolve(path)); return 0; } diff --git a/src/logic/scripting/lua/libs/libfile.cpp b/src/logic/scripting/lua/libs/libfile.cpp index cedef89b..5c7dd046 100644 --- a/src/logic/scripting/lua/libs/libfile.cpp +++ b/src/logic/scripting/lua/libs/libfile.cpp @@ -13,13 +13,13 @@ namespace fs = std::filesystem; using namespace scripting; -static fs::path resolve_path(const std::string& path) { +static io::path resolve_path(const std::string& path) { return engine->getPaths().resolve(path); } -static fs::path resolve_path_soft(const std::string& path) { +static io::path resolve_path_soft(const std::string& path) { if (path.find(':') == std::string::npos) { - return fs::u8path(""); + return ""; } return engine->getPaths().resolve(path, false); } @@ -34,17 +34,17 @@ static int l_find(lua::State* L) { } static int l_resolve(lua::State* L) { - fs::path path = resolve_path(lua::require_string(L, 1)); - return lua::pushstring(L, path.u8string()); + io::path path = resolve_path(lua::require_string(L, 1)); + return lua::pushstring(L, path.string()); } static int l_read(lua::State* L) { - fs::path path = resolve_path(lua::require_string(L, 1)); - if (fs::is_regular_file(path)) { + io::path path = resolve_path(lua::require_string(L, 1)); + if (io::is_regular_file(path)) { return lua::pushstring(L, io::read_string(path)); } throw std::runtime_error( - "file does not exists " + util::quote(path.u8string()) + "file does not exists " + util::quote(path.string()) ); } @@ -52,9 +52,9 @@ static std::set writeable_entry_points { "world", "export", "config" }; -static fs::path get_writeable_path(lua::State* L) { +static io::path get_writeable_path(lua::State* L) { std::string rawpath = lua::require_string(L, 1); - fs::path path = resolve_path(rawpath); + io::path path = resolve_path(rawpath); auto entryPoint = rawpath.substr(0, rawpath.find(':')); if (writeable_entry_points.find(entryPoint) == writeable_entry_points.end()) { throw std::runtime_error("access denied"); @@ -63,7 +63,7 @@ static fs::path get_writeable_path(lua::State* L) { } static int l_write(lua::State* L) { - fs::path path = get_writeable_path(L); + io::path path = get_writeable_path(L); std::string text = lua::require_string(L, 2); io::write_string(path, text); return 1; @@ -71,62 +71,62 @@ static int l_write(lua::State* L) { static int l_remove(lua::State* L) { std::string rawpath = lua::require_string(L, 1); - fs::path path = resolve_path(rawpath); + io::path path = resolve_path(rawpath); auto entryPoint = rawpath.substr(0, rawpath.find(':')); if (writeable_entry_points.find(entryPoint) == writeable_entry_points.end()) { throw std::runtime_error("access denied"); } - return lua::pushboolean(L, fs::remove(path)); + return lua::pushboolean(L, io::remove(path)); } static int l_remove_tree(lua::State* L) { std::string rawpath = lua::require_string(L, 1); - fs::path path = resolve_path(rawpath); + io::path path = resolve_path(rawpath); auto entryPoint = rawpath.substr(0, rawpath.find(':')); if (writeable_entry_points.find(entryPoint) == writeable_entry_points.end()) { throw std::runtime_error("access denied"); } - return lua::pushinteger(L, fs::remove_all(path)); + return lua::pushinteger(L, io::remove_all(path)); } static int l_exists(lua::State* L) { - fs::path path = resolve_path_soft(lua::require_string(L, 1)); - return lua::pushboolean(L, fs::exists(path)); + io::path path = resolve_path_soft(lua::require_string(L, 1)); + return lua::pushboolean(L, io::exists(path)); } static int l_isfile(lua::State* L) { - fs::path path = resolve_path_soft(lua::require_string(L, 1)); - return lua::pushboolean(L, fs::is_regular_file(path)); + io::path path = resolve_path_soft(lua::require_string(L, 1)); + return lua::pushboolean(L, io::is_regular_file(path)); } static int l_isdir(lua::State* L) { - fs::path path = resolve_path_soft(lua::require_string(L, 1)); - return lua::pushboolean(L, fs::is_directory(path)); + io::path path = resolve_path_soft(lua::require_string(L, 1)); + return lua::pushboolean(L, io::is_directory(path)); } static int l_length(lua::State* L) { - fs::path path = resolve_path(lua::require_string(L, 1)); - if (fs::exists(path)) { - return lua::pushinteger(L, fs::file_size(path)); + io::path path = resolve_path(lua::require_string(L, 1)); + if (io::exists(path)) { + return lua::pushinteger(L, io::file_size(path)); } else { return lua::pushinteger(L, -1); } } static int l_mkdir(lua::State* L) { - fs::path path = resolve_path(lua::require_string(L, 1)); - return lua::pushboolean(L, fs::create_directory(path)); + io::path path = resolve_path(lua::require_string(L, 1)); + return lua::pushboolean(L, io::create_directories(path)); // FIXME } static int l_mkdirs(lua::State* L) { - fs::path path = resolve_path(lua::require_string(L, 1)); - return lua::pushboolean(L, fs::create_directories(path)); + io::path path = resolve_path(lua::require_string(L, 1)); + return lua::pushboolean(L, io::create_directories(path)); } static int l_read_bytes(lua::State* L) { - fs::path path = resolve_path(lua::require_string(L, 1)); - if (fs::is_regular_file(path)) { - size_t length = static_cast(fs::file_size(path)); + io::path path = resolve_path(lua::require_string(L, 1)); + if (io::is_regular_file(path)) { + size_t length = static_cast(io::file_size(path)); auto bytes = io::read_bytes(path, length); @@ -140,12 +140,12 @@ static int l_read_bytes(lua::State* L) { return 1; } throw std::runtime_error( - "file does not exists " + util::quote(path.u8string()) + "file does not exists " + util::quote(path.string()) ); } static int l_write_bytes(lua::State* L) { - fs::path path = get_writeable_path(L); + io::path path = get_writeable_path(L); if (auto bytearray = lua::touserdata(L, 2)) { auto& bytes = bytearray->data(); @@ -176,15 +176,15 @@ static int l_list(lua::State* L) { if (dirname.find(':') == std::string::npos) { return l_list_all_res(L, dirname); } - fs::path path = resolve_path(dirname); - if (!fs::is_directory(path)) { + io::path path = resolve_path(dirname); + if (!io::is_directory(path)) { throw std::runtime_error( - util::quote(path.u8string()) + " is not a directory" + util::quote(path.string()) + " is not a directory" ); } lua::createtable(L, 0, 0); size_t index = 1; - for (auto& entry : fs::directory_iterator(path)) { + for (auto& entry : fs::directory_iterator(io::resolve(path))) { auto name = entry.path().filename().u8string(); auto file = dirname + "/" + name; lua::pushstring(L, file); @@ -240,7 +240,7 @@ static int l_read_combined_object(lua::State* L) { static int l_is_writeable(lua::State* L) { std::string rawpath = lua::require_string(L, 1); - fs::path path = resolve_path(rawpath); + io::path path = resolve_path(rawpath); auto entryPoint = rawpath.substr(0, rawpath.find(':')); if (writeable_entry_points.find(entryPoint) == writeable_entry_points.end()) { return lua::pushboolean(L, false); diff --git a/src/logic/scripting/lua/libs/libgeneration.cpp b/src/logic/scripting/lua/libs/libgeneration.cpp index 3f4bc570..196dae74 100644 --- a/src/logic/scripting/lua/libs/libgeneration.cpp +++ b/src/logic/scripting/lua/libs/libgeneration.cpp @@ -38,8 +38,8 @@ static int l_load_fragment(lua::State* L) { const auto& paths = engine->getPaths(); auto filename = lua::require_string(L, 1); auto path = paths.resolve(filename); - if (!std::filesystem::exists(path)) { - throw std::runtime_error("file "+path.u8string()+" does not exist"); + if (!io::exists(path)) { + throw std::runtime_error("file "+path.string()+" does not exist"); } auto map = io::read_binary_json(path); diff --git a/src/logic/scripting/lua/libs/libinput.cpp b/src/logic/scripting/lua/libs/libinput.cpp index 6796ade2..09f762ef 100644 --- a/src/logic/scripting/lua/libs/libinput.cpp +++ b/src/logic/scripting/lua/libs/libinput.cpp @@ -135,12 +135,12 @@ static int l_is_pressed(lua::State* L) { } } -static void resetPackBindings(fs::path& packFolder) { - auto configFolder = packFolder/fs::path("config"); - auto bindsFile = configFolder/fs::path("bindings.toml"); - if (fs::is_regular_file(bindsFile)) { +static void reset_pack_bindings(const io::path& packFolder) { + auto configFolder = packFolder / "config"; + auto bindsFile = configFolder / "bindings.toml"; + if (io::is_regular_file(bindsFile)) { Events::loadBindings( - bindsFile.u8string(), + bindsFile.string(), io::read_string(bindsFile), BindType::REBIND ); @@ -148,10 +148,9 @@ static void resetPackBindings(fs::path& packFolder) { } static int l_reset_bindings(lua::State*) { - auto resFolder = engine->getPaths().getResourcesFolder(); - resetPackBindings(resFolder); + reset_pack_bindings("res:"); for (auto& pack : engine->getContentPacks()) { - resetPackBindings(pack.folder); + reset_pack_bindings(pack.folder); } return 0; } diff --git a/src/logic/scripting/lua/libs/libpack.cpp b/src/logic/scripting/lua/libs/libpack.cpp index 99561538..dcff659a 100644 --- a/src/logic/scripting/lua/libs/libpack.cpp +++ b/src/logic/scripting/lua/libs/libpack.cpp @@ -21,7 +21,7 @@ static int l_pack_get_folder(lua::State* L) { for (auto& pack : packs) { if (pack.id == packName) { - return lua::pushstring(L, pack.folder.u8string() + "/"); + return lua::pushstring(L, pack.folder.string() + "/"); } } return lua::pushstring(L, ""); @@ -40,7 +40,7 @@ static int l_pack_get_installed(lua::State* L) { /// @brief pack.get_available() -> array static int l_pack_get_available(lua::State* L) { - fs::path worldFolder(""); + io::path worldFolder; if (level) { worldFolder = level->getWorld()->wfile->getFolder(); } @@ -88,7 +88,7 @@ static int l_pack_get_info( auto assets = engine->getAssets(); std::string icon = pack.id + ".icon"; if (!AssetsLoader::loadExternalTexture( - assets, icon, {pack.folder / fs::path("icon.png")} + assets, icon, {pack.folder / "icon.png"} )) { icon = "gui/no_icon"; } @@ -146,7 +146,7 @@ static int pack_get_infos(lua::State* L) { } } if (!ids.empty()) { - fs::path worldFolder(""); + io::path worldFolder; if (level) { worldFolder = level->getWorld()->wfile->getFolder(); } @@ -188,7 +188,7 @@ static int l_pack_get_info(lua::State* L) { return pack.id == packid; }); if (found == packs.end()) { - fs::path worldFolder(""); + io::path worldFolder; if (level) { worldFolder = level->getWorld()->wfile->getFolder(); } @@ -225,7 +225,7 @@ static int l_pack_assemble(lua::State* L) { ids.push_back(lua::require_string(L, -1)); lua::pop(L); } - fs::path worldFolder(""); + io::path worldFolder; if (level) { worldFolder = level->getWorld()->wfile->getFolder(); } diff --git a/src/logic/scripting/lua/libs/libworld.cpp b/src/logic/scripting/lua/libs/libworld.cpp index 07c64feb..9f640039 100644 --- a/src/logic/scripting/lua/libs/libworld.cpp +++ b/src/logic/scripting/lua/libs/libworld.cpp @@ -49,7 +49,7 @@ static int l_get_list(lua::State* L) { int versionMajor = versionMap["major"].asInteger(); int versionMinor = versionMap["minor"].asInteger(); - auto name = folder.filename().u8string(); + auto name = folder.name(); lua::pushstring(L, name); lua::setfield(L, "name"); @@ -105,7 +105,7 @@ static int l_get_seed(lua::State* L) { static int l_exists(lua::State* L) { auto name = lua::require_string(L, 1); auto worldsDir = engine->getPaths().getWorldFolderByName(name); - return lua::pushboolean(L, fs::is_directory(worldsDir)); + return lua::pushboolean(L, io::is_directory(worldsDir)); } static int l_is_day(lua::State* L) { diff --git a/src/logic/scripting/lua/lua_engine.cpp b/src/logic/scripting/lua/lua_engine.cpp index 6a494aa2..59b9cc39 100644 --- a/src/logic/scripting/lua/lua_engine.cpp +++ b/src/logic/scripting/lua/lua_engine.cpp @@ -125,7 +125,7 @@ void lua::initialize(const EnginePaths& paths, const CoreParameters& params) { main_thread = create_state( paths, params.headless ? StateType::SCRIPT : StateType::BASE ); - lua::pushstring(main_thread, params.scriptFile.stem().u8string()); + lua::pushstring(main_thread, params.scriptFile.stem()); lua::setglobal(main_thread, "__VC_SCRIPT_NAME"); } @@ -159,8 +159,7 @@ State* lua::create_state(const EnginePaths& paths, StateType stateType) { } init_state(L, stateType); - auto resDir = paths.getResourcesFolder(); - auto file = resDir / fs::u8path("scripts/stdmin.lua"); + auto file = "res:scripts/stdmin.lua"; auto src = io::read_string(file); lua::pop(L, lua::execute(L, 0, src, "core:scripts/stdmin.lua")); return L; diff --git a/src/logic/scripting/lua/lua_extensions.cpp b/src/logic/scripting/lua/lua_extensions.cpp index e1d7a230..37ed5d01 100644 --- a/src/logic/scripting/lua/lua_extensions.cpp +++ b/src/logic/scripting/lua/lua_extensions.cpp @@ -1,4 +1,5 @@ #include +#include #include "libs/api_lua.hpp" #include "debug/Logger.hpp" diff --git a/src/logic/scripting/lua/usertypes/lua_type_heightmap.cpp b/src/logic/scripting/lua/usertypes/lua_type_heightmap.cpp index 84aadbc0..983f9ba3 100644 --- a/src/logic/scripting/lua/usertypes/lua_type_heightmap.cpp +++ b/src/logic/scripting/lua/usertypes/lua_type_heightmap.cpp @@ -68,7 +68,7 @@ static int l_dump(lua::State* L) { raster[i*3 + 2] = val; } } - imageio::write(file.u8string(), &image); + imageio::write(file, &image); } return 0; } diff --git a/src/logic/scripting/scripting.cpp b/src/logic/scripting/scripting.cpp index ba39e334..92ed66a2 100644 --- a/src/logic/scripting/scripting.cpp +++ b/src/logic/scripting/scripting.cpp @@ -41,12 +41,11 @@ const ContentIndices* scripting::indices = nullptr; BlocksController* scripting::blocks = nullptr; LevelController* scripting::controller = nullptr; -void scripting::load_script(const fs::path& name, bool throwable) { - const auto& paths = scripting::engine->getPaths(); - fs::path file = paths.getResourcesFolder() / fs::path("scripts") / name; +void scripting::load_script(const io::path& name, bool throwable) { + io::path file = io::path("res:scripts") / name; std::string src = io::read_string(file); auto L = lua::get_main_state(); - lua::loadbuffer(L, 0, src, "core:scripts/"+name.u8string()); + lua::loadbuffer(L, 0, src, "core:scripts/"+name.string()); if (throwable) { lua::call(L, 0, 0); } else { @@ -57,11 +56,11 @@ void scripting::load_script(const fs::path& name, bool throwable) { int scripting::load_script( int env, const std::string& type, - const fs::path& file, + const io::path& file, const std::string& fileName ) { std::string src = io::read_string(file); - logger.info() << "script (" << type << ") " << file.u8string(); + logger.info() << "script (" << type << ") " << file.string(); return lua::execute(lua::get_main_state(), env, src, fileName); } @@ -69,8 +68,8 @@ void scripting::initialize(Engine* engine) { scripting::engine = engine; lua::initialize(engine->getPaths(), engine->getCoreParameters()); - load_script(fs::path("stdlib.lua"), true); - load_script(fs::path("classes.lua"), true); + load_script(io::path("stdlib.lua"), true); + load_script(io::path("classes.lua"), true); } class LuaCoroutine : public Process { @@ -113,12 +112,12 @@ public: }; std::unique_ptr scripting::start_coroutine( - const std::filesystem::path& script + const io::path& script ) { auto L = lua::get_main_state(); if (lua::getglobal(L, "__vc_start_coroutine")) { auto source = io::read_string(script); - lua::loadbuffer(L, 0, source, script.filename().u8string()); + lua::loadbuffer(L, 0, source, script.name()); if (lua::call(L, 1)) { int id = lua::tointeger(L, -1); lua::pop(L, 2); @@ -253,8 +252,8 @@ void scripting::on_content_load(Content* content) { lua::setfield(L, "properties"); lua::pop(L); } - load_script(fs::path("post_content.lua"), true); - load_script(fs::path("stdcmd.lua"), true); + load_script("post_content.lua", true); + load_script("stdcmd.lua", true); } void scripting::on_world_load(LevelController* controller) { @@ -829,7 +828,7 @@ int scripting::get_values_on_stack() { void scripting::load_content_script( const scriptenv& senv, const std::string& prefix, - const fs::path& file, + const io::path& file, const std::string& fileName, BlockFuncsSet& funcsset ) { @@ -854,7 +853,7 @@ void scripting::load_content_script( void scripting::load_content_script( const scriptenv& senv, const std::string& prefix, - const fs::path& file, + const io::path& file, const std::string& fileName, ItemFuncsSet& funcsset ) { @@ -869,11 +868,11 @@ void scripting::load_content_script( } void scripting::load_entity_component( - const std::string& name, const fs::path& file, const std::string& fileName + const std::string& name, const io::path& file, const std::string& fileName ) { auto L = lua::get_main_state(); std::string src = io::read_string(file); - logger.info() << "script (component) " << file.u8string(); + logger.info() << "script (component) " << file.string(); lua::loadbuffer(L, 0, src, fileName); lua::store_in(L, lua::CHUNKS_TABLE, name); } @@ -881,7 +880,7 @@ void scripting::load_entity_component( void scripting::load_world_script( const scriptenv& senv, const std::string& prefix, - const fs::path& file, + const io::path& file, const std::string& fileName, WorldFuncsSet& funcsset ) { @@ -917,7 +916,7 @@ void scripting::load_world_script( void scripting::load_layout_script( const scriptenv& senv, const std::string& prefix, - const fs::path& file, + const io::path& file, const std::string& fileName, uidocscript& script ) { diff --git a/src/logic/scripting/scripting.hpp b/src/logic/scripting/scripting.hpp index b447de28..bdd5d5d2 100644 --- a/src/logic/scripting/scripting.hpp +++ b/src/logic/scripting/scripting.hpp @@ -1,11 +1,11 @@ #pragma once -#include #include #include #include #include +#include "io/fwd.hpp" #include "data/dv.hpp" #include "delegates.hpp" #include "typedefs.hpp" @@ -61,7 +61,7 @@ namespace scripting { void process_post_runnables(); std::unique_ptr start_coroutine( - const std::filesystem::path& script + const io::path& script ); void on_world_load(LevelController* controller); @@ -150,7 +150,7 @@ namespace scripting { void load_content_script( const scriptenv& env, const std::string& prefix, - const std::filesystem::path& file, + const io::path& file, const std::string& fileName, BlockFuncsSet& funcsset ); @@ -164,7 +164,7 @@ namespace scripting { void load_content_script( const scriptenv& env, const std::string& prefix, - const std::filesystem::path& file, + const io::path& file, const std::string& fileName, ItemFuncsSet& funcsset ); @@ -175,13 +175,13 @@ namespace scripting { /// @param fileName script file path using the engine format void load_entity_component( const std::string& name, - const std::filesystem::path& file, + const io::path& file, const std::string& fileName ); std::unique_ptr load_generator( const GeneratorDef& def, - const std::filesystem::path& file, + const io::path& file, const std::string& dirPath ); @@ -193,7 +193,7 @@ namespace scripting { void load_world_script( const scriptenv& env, const std::string& packid, - const std::filesystem::path& file, + const io::path& file, const std::string& fileName, WorldFuncsSet& funcsset ); @@ -207,7 +207,7 @@ namespace scripting { void load_layout_script( const scriptenv& env, const std::string& prefix, - const std::filesystem::path& file, + const io::path& file, const std::string& fileName, uidocscript& script ); diff --git a/src/logic/scripting/scripting_commons.hpp b/src/logic/scripting/scripting_commons.hpp index 3bc31825..493e115c 100644 --- a/src/logic/scripting/scripting_commons.hpp +++ b/src/logic/scripting/scripting_commons.hpp @@ -1,15 +1,16 @@ #pragma once #include -#include + +#include "io/fwd.hpp" namespace scripting { - void load_script(const std::filesystem::path& name, bool throwable); + void load_script(const io::path& name, bool throwable); [[nodiscard]] int load_script( int env, const std::string& type, - const std::filesystem::path& file, + const io::path& file, const std::string& fileName ); } diff --git a/src/logic/scripting/scripting_hud.cpp b/src/logic/scripting/scripting_hud.cpp index 66b14387..d6f618cb 100644 --- a/src/logic/scripting/scripting_hud.cpp +++ b/src/logic/scripting/scripting_hud.cpp @@ -19,11 +19,11 @@ Hud* scripting::hud = nullptr; WorldRenderer* scripting::renderer = nullptr; static void load_script(const std::string& name) { - auto file = engine->getPaths().getResourcesFolder() / "scripts" / name; + auto file = io::path("res:scripts") / name; std::string src = io::read_string(file); - logger.info() << "loading script " << file.u8string(); + logger.info() << "loading script " << file.string(); - lua::execute(lua::get_main_state(), 0, src, file.u8string()); + lua::execute(lua::get_main_state(), 0, src, file.string()); } void scripting::on_frontend_init(Hud* hud, WorldRenderer* renderer) { @@ -80,12 +80,12 @@ void scripting::on_frontend_close() { void scripting::load_hud_script( const scriptenv& senv, const std::string& packid, - const fs::path& file, + const io::path& file, const std::string& fileName ) { int env = *senv; std::string src = io::read_string(file); - logger.info() << "loading script " << file.u8string(); + logger.info() << "loading script " << file.string(); lua::execute(lua::get_main_state(), env, src, fileName); diff --git a/src/logic/scripting/scripting_hud.hpp b/src/logic/scripting/scripting_hud.hpp index f6829976..1df47df2 100644 --- a/src/logic/scripting/scripting_hud.hpp +++ b/src/logic/scripting/scripting_hud.hpp @@ -1,13 +1,11 @@ #pragma once -#include #include #include #include #include "typedefs.hpp" - -namespace fs = std::filesystem; +#include "io/fwd.hpp" class Hud; class WorldRenderer; @@ -33,7 +31,7 @@ namespace scripting { void load_hud_script( const scriptenv& env, const std::string& packid, - const fs::path& file, + const io::path& file, const std::string& fileName ); diff --git a/src/logic/scripting/scripting_world_generation.cpp b/src/logic/scripting/scripting_world_generation.cpp index 8a19e1b0..1e34122b 100644 --- a/src/logic/scripting/scripting_world_generation.cpp +++ b/src/logic/scripting/scripting_world_generation.cpp @@ -26,10 +26,15 @@ class LuaGeneratorScript : public GeneratorScript { const GeneratorDef& def; scriptenv env = nullptr; - fs::path file; + io::path file; std::string dirPath; public: - LuaGeneratorScript(State* L, const GeneratorDef& def, const fs::path& file, const std::string& dirPath) + LuaGeneratorScript( + State* L, + const GeneratorDef& def, + const io::path& file, + const std::string& dirPath + ) : L(L), def(def), file(file), dirPath(dirPath) { } @@ -54,10 +59,10 @@ public: pop(L); - if (fs::exists(file)) { + if (io::exists(file)) { std::string src = io::read_string(file); - logger.info() << "script (generator) " << file.u8string(); - pop(L, execute(L, *env, src, file.u8string())); + logger.info() << "script (generator) " << file.string(); + pop(L, execute(L, *env, src, file.string())); } else { // Use default (empty) script pop(L, execute(L, *env, "", "")); @@ -252,7 +257,7 @@ public: std::unique_ptr scripting::load_generator( const GeneratorDef& def, - const fs::path& file, + const io::path& file, const std::string& dirPath ) { auto L = create_state(engine->getPaths(), StateType::GENERATOR); diff --git a/src/util/command_line.cpp b/src/util/command_line.cpp index 6b579c01..ee0ace92 100644 --- a/src/util/command_line.cpp +++ b/src/util/command_line.cpp @@ -1,6 +1,5 @@ #include "command_line.hpp" -#include #include #include "io/engine_paths.hpp" @@ -14,10 +13,10 @@ static bool perform_keyword( ) { if (keyword == "--res") { auto token = reader.next(); - params.resFolder = fs::u8path(token); + params.resFolder = token; } else if (keyword == "--dir") { auto token = reader.next(); - params.userFolder = fs::u8path(token); + params.userFolder = token; } else if (keyword == "--help" || keyword == "-h") { std::cout << "VoxelCore v" << ENGINE_VERSION_STRING << "\n\n"; std::cout << "command-line arguments:\n"; @@ -38,11 +37,11 @@ static bool perform_keyword( } else if (keyword == "--test") { auto token = reader.next(); params.testMode = true; - params.scriptFile = fs::u8path(token); + params.scriptFile = token; } else if (keyword == "--script") { auto token = reader.next(); params.testMode = false; - params.scriptFile = fs::u8path(token); + params.scriptFile = token; } else { throw std::runtime_error("unknown argument " + keyword); } diff --git a/src/world/World.cpp b/src/world/World.cpp index a04e5e9b..313f75cd 100644 --- a/src/world/World.cpp +++ b/src/world/World.cpp @@ -78,7 +78,7 @@ void World::write(Level* level) { std::unique_ptr World::create( const std::string& name, const std::string& generator, - const fs::path& directory, + const io::path& directory, uint64_t seed, EngineSettings& settings, const Content& content, @@ -98,7 +98,7 @@ std::unique_ptr World::create( logger.info() << "created nameless world"; } else { logger.info() << "created world '" << name << "' (" - << directory.u8string() << ")"; + << directory.string() << ")"; } logger.info() << "world seed: " << seed << " generator: " << generator; return std::make_unique(std::move(world), content, settings); @@ -116,7 +116,7 @@ std::unique_ptr World::load( throw world_load_error("could not to find world.json"); } logger.info() << "loading world " << info->name << " (" - << worldFilesPtr->getFolder().u8string() << ")"; + << worldFilesPtr->getFolder().string() << ")"; logger.info() << "world version: " << info->major << "." << info->minor << " seed: " << info->seed << " generator: " << info->generator; @@ -129,8 +129,8 @@ std::unique_ptr World::load( auto level = std::make_unique(std::move(world), content, settings); - fs::path file = wfile->getPlayerFile(); - if (!fs::is_regular_file(file)) { + io::path file = wfile->getPlayerFile(); + if (!io::is_regular_file(file)) { logger.warning() << "player.json does not exists"; level->players->create(); } else { @@ -149,8 +149,8 @@ std::unique_ptr World::load( std::shared_ptr World::checkIndices( const std::shared_ptr& worldFiles, const Content* content ) { - fs::path indicesFile = worldFiles->getIndicesFile(); - if (fs::is_regular_file(indicesFile)) { + io::path indicesFile = worldFiles->getIndicesFile(); + if (io::is_regular_file(indicesFile)) { return ContentReport::create(worldFiles, indicesFile, content); } return nullptr; diff --git a/src/world/World.hpp b/src/world/World.hpp index da1ebd81..531e7084 100644 --- a/src/world/World.hpp +++ b/src/world/World.hpp @@ -1,10 +1,10 @@ #pragma once -#include #include #include #include +#include "io/fwd.hpp" #include "content/ContentPack.hpp" #include "interfaces/Serializable.hpp" #include "typedefs.hpp" @@ -16,8 +16,6 @@ class Level; class ContentReport; struct EngineSettings; -namespace fs = std::filesystem; - class world_load_error : public std::runtime_error { public: world_load_error(const std::string& message); @@ -100,7 +98,7 @@ public: static std::unique_ptr create( const std::string& name, const std::string& generator, - const fs::path& directory, + const io::path& directory, uint64_t seed, EngineSettings& settings, const Content& content, diff --git a/src/world/files/RegionsLayer.cpp b/src/world/files/RegionsLayer.cpp index 027d6bf3..f5c5b696 100644 --- a/src/world/files/RegionsLayer.cpp +++ b/src/world/files/RegionsLayer.cpp @@ -6,8 +6,8 @@ #define REGION_FORMAT_MAGIC ".VOXREG" -static fs::path get_region_filename(int x, int z) { - return fs::path(std::to_string(x) + "_" + std::to_string(z) + ".bin"); +static io::path get_region_filename(int x, int z) { + return std::to_string(x) + "_" + std::to_string(z) + ".bin"; } /// @brief Read missing chunks data (null pointers) from region file @@ -25,7 +25,7 @@ static void fetch_chunks(WorldRegion* region, int x, int z, regfile* file) { } } -regfile::regfile(fs::path filename) : file(std::move(filename)) { +regfile::regfile(io::path filename) : file(std::move(filename)) { if (file.length() < REGION_HEADER_SIZE) throw std::runtime_error("incomplete region file header"); char header[REGION_HEADER_SIZE]; @@ -98,8 +98,8 @@ regfile_ptr RegionsLayer::getRegFile(glm::ivec2 coord, bool create) { } regfile_ptr RegionsLayer::createRegFile(glm::ivec2 coord) { - auto file = folder / get_region_filename(coord[0], coord[1]); - if (!fs::exists(file)) { + auto file = folder / get_region_filename(coord[0], coord[1]); + if (!io::exists(file)) { return nullptr; } if (openRegFiles.size() == MAX_OPEN_REGION_FILES) { @@ -138,7 +138,7 @@ WorldRegion* RegionsLayer::getRegion(int x, int z) { return found->second.get(); } -fs::path RegionsLayer::getRegionFilePath(int x, int z) const { +io::path RegionsLayer::getRegionFilePath(int x, int z) const { return folder / get_region_filename(x, z); } @@ -179,7 +179,7 @@ ubyte* RegionsLayer::getData(int x, int z, uint32_t& size, uint32_t& srcSize) { } void RegionsLayer::writeRegion(int x, int z, WorldRegion* entry) { - fs::path filename = folder / get_region_filename(x, z); + io::path filename = folder / get_region_filename(x, z); glm::ivec2 regcoord(x, z); if (auto regfile = getRegFile(regcoord, false)) { @@ -193,7 +193,7 @@ void RegionsLayer::writeRegion(int x, int z, WorldRegion* entry) { char header[REGION_HEADER_SIZE] = REGION_FORMAT_MAGIC; header[8] = REGION_FORMAT_VERSION; header[9] = static_cast(compression); // FIXME - std::ofstream file(filename, std::ios::out | std::ios::binary); + std::ofstream file(io::resolve(filename), std::ios::out | std::ios::binary); file.write(header, REGION_HEADER_SIZE); size_t offset = REGION_HEADER_SIZE; diff --git a/src/world/files/WorldConverter.cpp b/src/world/files/WorldConverter.cpp index 287999de..3361334e 100644 --- a/src/world/files/WorldConverter.cpp +++ b/src/world/files/WorldConverter.cpp @@ -39,17 +39,17 @@ void WorldConverter::addRegionsTasks( ) { const auto& regions = wfile->getRegions(); auto regionsFolder = regions.getRegionsFolder(layerid); - if (!fs::is_directory(regionsFolder)) { + if (!io::is_directory(regionsFolder)) { return; } - for (const auto& file : fs::directory_iterator(regionsFolder)) { + for (const auto& file : fs::directory_iterator(io::resolve(regionsFolder))) { int x, z; std::string name = file.path().stem().string(); if (!WorldRegions::parseRegionFilename(name, x, z)) { logger.error() << "could not parse region name " << name; continue; } - tasks.push(ConvertTask {taskType, file.path(), x, z, layerid}); + tasks.push(ConvertTask {taskType, file.path().u8string(), x, z, layerid}); } } @@ -182,7 +182,7 @@ std::shared_ptr WorldConverter::startTask( } void WorldConverter::upgradeRegion( - const fs::path& file, int x, int z, RegionLayerIndex layer + const io::path& file, int x, int z, RegionLayerIndex layer ) const { auto path = wfile->getRegions().getRegionFilePath(layer, x, z); auto bytes = io::read_bytes_buffer(path); @@ -190,7 +190,7 @@ void WorldConverter::upgradeRegion( io::write_bytes(path, buffer.data(), buffer.size()); } -void WorldConverter::convertVoxels(const fs::path& file, int x, int z) const { +void WorldConverter::convertVoxels(const io::path& file, int x, int z) const { logger.info() << "converting voxels region " << x << "_" << z; wfile->getRegions().processRegion(x, z, REGION_LAYER_VOXELS, [=](std::unique_ptr data, uint32_t*) { @@ -199,15 +199,15 @@ void WorldConverter::convertVoxels(const fs::path& file, int x, int z) const { }); } -void WorldConverter::convertInventories(const fs::path& file, int x, int z) const { +void WorldConverter::convertInventories(const io::path& file, int x, int z) const { logger.info() << "converting inventories region " << x << "_" << z; wfile->getRegions().processInventories(x, z, [=](Inventory* inventory) { inventory->convert(report.get()); }); } -void WorldConverter::convertPlayer(const fs::path& file) const { - logger.info() << "converting player " << file.u8string(); +void WorldConverter::convertPlayer(const io::path& file) const { + logger.info() << "converting player " << file.string(); auto map = io::read_json(file); Player::convert(map, report.get()); io::write_json(file, map); @@ -242,7 +242,7 @@ void WorldConverter::convertBlocksData(int x, int z, const ContentReport& report } void WorldConverter::convert(const ConvertTask& task) const { - if (!fs::is_regular_file(task.file)) return; + if (!io::is_regular_file(task.file)) return; switch (task.type) { case ConvertTaskType::UPGRADE_REGION: diff --git a/src/world/files/WorldConverter.hpp b/src/world/files/WorldConverter.hpp index 499fba3c..8c065c47 100644 --- a/src/world/files/WorldConverter.hpp +++ b/src/world/files/WorldConverter.hpp @@ -1,16 +1,14 @@ #pragma once -#include #include #include #include "delegates.hpp" #include "interfaces/Task.hpp" +#include "io/io.hpp" #include "world/files/world_regions_fwd.hpp" #include "typedefs.hpp" -namespace fs = std::filesystem; - class Content; class ContentReport; class WorldFiles; @@ -30,7 +28,7 @@ enum class ConvertTaskType { struct ConvertTask { ConvertTaskType type; - fs::path file; + io::path file; /// @brief region coords int x, z; @@ -53,10 +51,10 @@ class WorldConverter : public Task { ConvertMode mode; void upgradeRegion( - const fs::path& file, int x, int z, RegionLayerIndex layer) const; - void convertPlayer(const fs::path& file) const; - void convertVoxels(const fs::path& file, int x, int z) const; - void convertInventories(const fs::path& file, int x, int z) const; + const io::path& file, int x, int z, RegionLayerIndex layer) const; + void convertPlayer(const io::path& file) const; + void convertVoxels(const io::path& file, int x, int z) const; + void convertInventories(const io::path& file, int x, int z) const; void convertBlocksData(int x, int z, const ContentReport& report) const; void addRegionsTasks( diff --git a/src/world/files/WorldFiles.cpp b/src/world/files/WorldFiles.cpp index 73132f33..3617ad7c 100644 --- a/src/world/files/WorldFiles.cpp +++ b/src/world/files/WorldFiles.cpp @@ -36,11 +36,11 @@ static debug::Logger logger("world-files"); -WorldFiles::WorldFiles(const fs::path& directory) +WorldFiles::WorldFiles(const io::path& directory) : directory(directory), regions(directory) { } -WorldFiles::WorldFiles(const fs::path& directory, const DebugSettings& settings) +WorldFiles::WorldFiles(const io::path& directory, const DebugSettings& settings) : WorldFiles(directory) { generatorTestMode = settings.generatorTestMode.get(); doWriteLights = settings.doWriteLights.get(); @@ -51,28 +51,28 @@ WorldFiles::WorldFiles(const fs::path& directory, const DebugSettings& settings) WorldFiles::~WorldFiles() = default; void WorldFiles::createDirectories() { - fs::create_directories(directory / fs::path("data")); - fs::create_directories(directory / fs::path("content")); + io::create_directories(directory / "data"); + io::create_directories(directory / "content"); } -fs::path WorldFiles::getPlayerFile() const { - return directory / fs::path("player.json"); +io::path WorldFiles::getPlayerFile() const { + return directory / "player.json"; } -fs::path WorldFiles::getResourcesFile() const { - return directory / fs::path("resources.json"); +io::path WorldFiles::getResourcesFile() const { + return directory / "resources.json"; } -fs::path WorldFiles::getWorldFile() const { - return directory / fs::path(WORLD_FILE); +io::path WorldFiles::getWorldFile() const { + return directory / WORLD_FILE; } -fs::path WorldFiles::getIndicesFile() const { - return directory / fs::path("indices.json"); +io::path WorldFiles::getIndicesFile() const { + return directory / "indices.json"; } -fs::path WorldFiles::getPacksFile() const { - return directory / fs::path("packs.list"); +io::path WorldFiles::getPacksFile() const { + return directory / "packs.list"; } void WorldFiles::write( @@ -80,7 +80,7 @@ void WorldFiles::write( ) { if (world) { writeWorldInfo(world->getInfo()); - if (!fs::exists(getPacksFile())) { + if (!io::exists(getPacksFile())) { writePacks(world->getPacks()); } } @@ -147,8 +147,8 @@ void WorldFiles::writeWorldInfo(const WorldInfo& info) { } std::optional WorldFiles::readWorldInfo() { - fs::path file = getWorldFile(); - if (!fs::is_regular_file(file)) { + io::path file = getWorldFile(); + if (!io::is_regular_file(file)) { logger.warning() << "world.json does not exists"; return std::nullopt; } @@ -175,8 +175,8 @@ static void read_resources_data( } bool WorldFiles::readResourcesData(const Content& content) { - fs::path file = getResourcesFile(); - if (!fs::is_regular_file(file)) { + io::path file = getResourcesFile(); + if (!io::is_regular_file(file)) { logger.warning() << "resources.json does not exists"; return false; } @@ -192,9 +192,9 @@ bool WorldFiles::readResourcesData(const Content& content) { } void WorldFiles::patchIndicesFile(const dv::value& map) { - fs::path file = getIndicesFile(); - if (!fs::is_regular_file(file)) { - logger.error() << file.filename().u8string() << " does not exists"; + io::path file = getIndicesFile(); + if (!io::is_regular_file(file)) { + logger.error() << file.name() << " does not exists"; return; } auto root = io::read_json(file); @@ -230,6 +230,6 @@ void WorldFiles::removeIndices(const std::vector& packs) { io::write_json(getIndicesFile(), root); } -fs::path WorldFiles::getFolder() const { +io::path WorldFiles::getFolder() const { return directory; } diff --git a/src/world/files/WorldFiles.hpp b/src/world/files/WorldFiles.hpp index 7c4fb2cd..f14c3c33 100644 --- a/src/world/files/WorldFiles.hpp +++ b/src/world/files/WorldFiles.hpp @@ -1,6 +1,5 @@ #pragma once -#include #include #include #include @@ -24,28 +23,26 @@ class World; struct WorldInfo; struct DebugSettings; -namespace fs = std::filesystem; - class WorldFiles { - fs::path directory; + io::path directory; WorldRegions regions; bool generatorTestMode = false; bool doWriteLights = true; - fs::path getWorldFile() const; - fs::path getPacksFile() const; + io::path getWorldFile() const; + io::path getPacksFile() const; void writeWorldInfo(const WorldInfo& info); void writeIndices(const ContentIndices* indices); public: - WorldFiles(const fs::path& directory); - WorldFiles(const fs::path& directory, const DebugSettings& settings); + WorldFiles(const io::path& directory); + WorldFiles(const io::path& directory, const DebugSettings& settings); ~WorldFiles(); - fs::path getPlayerFile() const; - fs::path getIndicesFile() const; - fs::path getResourcesFile() const; + io::path getPlayerFile() const; + io::path getIndicesFile() const; + io::path getResourcesFile() const; void createDirectories(); std::optional readWorldInfo(); @@ -70,7 +67,7 @@ public: void removeIndices(const std::vector& packs); /// @return world folder - fs::path getFolder() const; + io::path getFolder() const; WorldRegions& getRegions() { return regions; diff --git a/src/world/files/WorldRegions.cpp b/src/world/files/WorldRegions.cpp index 54a25ee9..7c1ab08c 100644 --- a/src/world/files/WorldRegions.cpp +++ b/src/world/files/WorldRegions.cpp @@ -57,24 +57,24 @@ glm::u32vec2 WorldRegion::getChunkDataSize(uint x, uint z) { return sizes[z * REGION_SIZE + x]; } -WorldRegions::WorldRegions(const fs::path& directory) : directory(directory) { +WorldRegions::WorldRegions(const io::path& directory) : directory(directory) { for (size_t i = 0; i < REGION_LAYERS_COUNT; i++) { layers[i].layer = static_cast(i); } auto& voxels = layers[REGION_LAYER_VOXELS]; - voxels.folder = directory / fs::path("regions"); + voxels.folder = directory / "regions"; voxels.compression = compression::Method::EXTRLE16; auto& lights = layers[REGION_LAYER_LIGHTS]; - lights.folder = directory / fs::path("lights"); + lights.folder = directory / "lights"; lights.compression = compression::Method::EXTRLE8; layers[REGION_LAYER_INVENTORIES].folder = - directory / fs::path("inventories"); - layers[REGION_LAYER_ENTITIES].folder = directory / fs::path("entities"); + directory / "inventories"; + layers[REGION_LAYER_ENTITIES].folder = directory / "entities"; auto& blocksData = layers[REGION_LAYER_BLOCKS_DATA]; - blocksData.folder = directory / fs::path("blocksdata"); + blocksData.folder = directory / "blocksdata"; } WorldRegions::~WorldRegions() = default; @@ -388,17 +388,17 @@ void WorldRegions::processRegion( } } -const fs::path& WorldRegions::getRegionsFolder(RegionLayerIndex layerid) const { +const io::path& WorldRegions::getRegionsFolder(RegionLayerIndex layerid) const { return layers[layerid].folder; } -fs::path WorldRegions::getRegionFilePath(RegionLayerIndex layerid, int x, int z) const { +io::path WorldRegions::getRegionFilePath(RegionLayerIndex layerid, int x, int z) const { return layers[layerid].getRegionFilePath(x, z); } void WorldRegions::writeAll() { for (auto& layer : layers) { - fs::create_directories(layer.folder); + io::create_directories(layer.folder); layer.writeAll(); } } @@ -409,9 +409,9 @@ void WorldRegions::deleteRegion(RegionLayerIndex layerid, int x, int z) { throw std::runtime_error("region file is currently in use"); } auto file = layer.getRegionFilePath(x, z); - if (fs::exists(file)) { - logger.info() << "remove region file " << file.u8string(); - fs::remove(file); + if (io::exists(file)) { + logger.info() << "remove region file " << file.string(); + io::remove(file); } } diff --git a/src/world/files/WorldRegions.hpp b/src/world/files/WorldRegions.hpp index 3f2805b1..a50fc819 100644 --- a/src/world/files/WorldRegions.hpp +++ b/src/world/files/WorldRegions.hpp @@ -1,7 +1,6 @@ #pragma once #include -#include #include #include #include @@ -19,8 +18,6 @@ #define GLM_ENABLE_EXPERIMENTAL #include -namespace fs = std::filesystem; - inline constexpr uint REGION_HEADER_SIZE = 10; inline constexpr uint REGION_SIZE_BIT = 5; @@ -58,7 +55,7 @@ struct regfile { int version; bool inUse = false; - regfile(fs::path filename); + regfile(io::path filename); regfile(const regfile&) = delete; std::unique_ptr read(int index, uint32_t& size, uint32_t& srcSize); @@ -121,7 +118,7 @@ struct RegionsLayer { RegionLayerIndex layer; /// @brief Regions layer folder - fs::path folder; + io::path folder; compression::Method compression = compression::Method::NONE; @@ -146,7 +143,7 @@ struct RegionsLayer { WorldRegion* getRegion(int x, int z); WorldRegion* getOrCreateRegion(int x, int z); - fs::path getRegionFilePath(int x, int z) const; + io::path getRegionFilePath(int x, int z) const; /// @brief Get chunk data. Read from file if not loaded yet. /// @param x chunk x coord @@ -178,14 +175,14 @@ struct RegionsLayer { class WorldRegions { /// @brief World directory - fs::path directory; + io::path directory; RegionsLayer layers[REGION_LAYERS_COUNT] {}; public: bool generatorTestMode = false; bool doWriteLights = true; - WorldRegions(const fs::path& directory); + WorldRegions(const io::path& directory); WorldRegions(const WorldRegions&) = delete; ~WorldRegions(); @@ -241,9 +238,9 @@ public: /// @brief Get regions directory by layer index /// @param layerid layer index /// @return directory path - const fs::path& getRegionsFolder(RegionLayerIndex layerid) const; + const io::path& getRegionsFolder(RegionLayerIndex layerid) const; - fs::path getRegionFilePath(RegionLayerIndex layerid, int x, int z) const; + io::path getRegionFilePath(RegionLayerIndex layerid, int x, int z) const; /// @brief Write all region layers void writeAll(); diff --git a/test/coders/lua_parsing.cpp b/test/coders/lua_parsing.cpp index bf35965e..64b15d44 100644 --- a/test/coders/lua_parsing.cpp +++ b/test/coders/lua_parsing.cpp @@ -7,7 +7,7 @@ TEST(lua_parsing, Tokenizer) { auto filename = "../../res/scripts/stdlib.lua"; - auto source = io::read_string(std::filesystem::u8path(filename)); + auto source = io::read_string(filename); try { auto tokens = lua::tokenize(filename, source); for (const auto& token : tokens) { diff --git a/test/coders/vec3.cpp b/test/coders/vec3.cpp index 6dc5e724..b7c8e37e 100644 --- a/test/coders/vec3.cpp +++ b/test/coders/vec3.cpp @@ -4,9 +4,7 @@ #include "io/io.hpp" TEST(VEC3, Decode) { - auto file = std::filesystem::u8path( - "res/models/block.vec3" - ); + io::path file = "res/models/block.vec3"; auto bytes = io::read_bytes_buffer(file); - auto model = vec3::load(file.u8string(), bytes); + auto model = vec3::load(file.string(), bytes); } diff --git a/test/io/path.cpp b/test/io/path.cpp new file mode 100644 index 00000000..86d5efe3 --- /dev/null +++ b/test/io/path.cpp @@ -0,0 +1,14 @@ +#include + +#include "io/path.hpp" + +TEST(Path, Path) { + io::path p("entry_point:path/file.ext"); + EXPECT_EQ(p, "entry_point:path/file.ext"); + EXPECT_EQ(p.pathPart(), "path/file.ext"); + EXPECT_EQ(p.name(), "file.ext"); + EXPECT_EQ(p.extension(), ".ext"); + EXPECT_EQ(p.entryPoint(), "entry_point"); + EXPECT_EQ(p / "child", "entry_point:path/file.ext/child"); + EXPECT_EQ(p.parent(), "entry_point:path"); +} From 347d76870a4cb931ac8d9b2c9dcd520c3e5c6b19 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Fri, 31 Jan 2025 10:07:05 +0300 Subject: [PATCH 04/16] add io::directory_iterator --- src/assets/AssetsLoader.cpp | 3 +- src/content/ContentLoader.cpp | 12 ++-- src/content/ContentPack.cpp | 3 +- src/io/devices/Device.hpp | 5 ++ src/io/devices/StdfsDevice.cpp | 42 +++++++++++--- src/io/devices/StdfsDevice.hpp | 1 + src/io/engine_paths.cpp | 14 ++--- src/io/io.cpp | 12 +++- src/io/io.hpp | 74 ++++++++++++++++++++++++ src/io/path.hpp | 10 ++++ src/logic/scripting/lua/libs/libfile.cpp | 9 ++- src/logic/scripting/lua/lua_util.hpp | 55 ++++++++++-------- src/world/files/WorldConverter.cpp | 6 +- 13 files changed, 182 insertions(+), 64 deletions(-) diff --git a/src/assets/AssetsLoader.cpp b/src/assets/AssetsLoader.cpp index dfb2c7df..14d1298f 100644 --- a/src/assets/AssetsLoader.cpp +++ b/src/assets/AssetsLoader.cpp @@ -94,8 +94,7 @@ static void add_layouts( if (!io::is_directory(folder)) { return; } - for (auto& entry : fs::directory_iterator(io::resolve(folder))) { - io::path file = folder / entry.path().filename().u8string(); + for (const auto& file : io::directory_iterator(folder)) { if (file.extension() != ".xml") continue; std::string name = prefix + ":" + file.stem(); loader.add( diff --git a/src/content/ContentLoader.cpp b/src/content/ContentLoader.cpp index 3c993786..c1b3f10a 100644 --- a/src/content/ContentLoader.cpp +++ b/src/content/ContentLoader.cpp @@ -50,8 +50,7 @@ static void detect_defs( if (!io::is_directory(folder)) { return; } - for (const auto& entry : std::filesystem::directory_iterator(io::resolve(folder))) { - io::path file = folder / entry.path().filename().u8string(); + for (const auto& file : io::directory_iterator(folder)) { std::string name = file.stem(); if (name[0] == '_') { continue; @@ -75,8 +74,7 @@ static void detect_defs_pairs( if (!io::is_directory(folder)) { return; } - for (const auto& entry : fs::directory_iterator(io::resolve(folder))) { - io::path file = folder / entry.path().filename().u8string(); + for (const auto& file : io::directory_iterator(folder)) { std::string name = file.stem(); if (name[0] == '_') { continue; @@ -747,8 +745,7 @@ static inline void foreach_file( if (!io::is_directory(dir)) { return; } - for (const auto& entry : fs::directory_iterator(io::resolve(dir))) { - io::path path = dir / entry.path().filename().u8string(); + for (const auto& path : io::directory_iterator(dir)) { if (io::is_directory(path)) { continue; } @@ -808,8 +805,7 @@ void ContentLoader::load() { // Load block materials io::path materialsDir = folder / "block_materials"; if (io::is_directory(materialsDir)) { - for (const auto& entry : fs::directory_iterator(io::resolve(materialsDir))) { - io::path file = materialsDir / entry.path().filename().u8string(); + for (const auto& file : io::directory_iterator(materialsDir)) { auto [packid, full, filename] = create_unit_id(pack->id, file.stem()); loadBlockMaterial( diff --git a/src/content/ContentPack.cpp b/src/content/ContentPack.cpp index 51960609..73a9503e 100644 --- a/src/content/ContentPack.cpp +++ b/src/content/ContentPack.cpp @@ -129,8 +129,7 @@ void ContentPack::scanFolder( if (!io::is_directory(folder)) { return; } - for (const auto& entry : fs::directory_iterator(io::resolve(folder))) { - io::path packFolder = folder / entry.path().filename().u8string(); + for (const auto& packFolder : io::directory_iterator(folder)) { if (!io::is_directory(packFolder)) continue; if (!is_pack(packFolder)) continue; try { diff --git a/src/io/devices/Device.hpp b/src/io/devices/Device.hpp index 39794d80..30d885fa 100644 --- a/src/io/devices/Device.hpp +++ b/src/io/devices/Device.hpp @@ -23,6 +23,7 @@ namespace io { virtual void mkdirs(std::string_view path) = 0; virtual bool remove(std::string_view path) = 0; virtual uint64_t removeAll(std::string_view path) = 0; + virtual std::unique_ptr list(std::string_view path) = 0; }; class SubDevice : public Device { @@ -69,6 +70,10 @@ namespace io { uint64_t removeAll(std::string_view path) override { return parent->removeAll((root / path).pathPart()); } + + std::unique_ptr list(std::string_view path) override { + return parent->list((root / path).pathPart()); + } private: std::shared_ptr parent; path root; diff --git a/src/io/devices/StdfsDevice.cpp b/src/io/devices/StdfsDevice.cpp index 7078b394..89c585ca 100644 --- a/src/io/devices/StdfsDevice.cpp +++ b/src/io/devices/StdfsDevice.cpp @@ -4,9 +4,10 @@ #include using namespace io; +namespace fs = std::filesystem; -std::filesystem::path StdfsDevice::resolve(std::string_view path) { - return root / std::filesystem::u8path(path); +fs::path StdfsDevice::resolve(std::string_view path) { + return root / fs::u8path(path); } void StdfsDevice::write(std::string_view path, const void* data, size_t size) { @@ -29,35 +30,58 @@ void StdfsDevice::read(std::string_view path, void* data, size_t size) { size_t StdfsDevice::size(std::string_view path) { auto resolved = resolve(path); - return std::filesystem::file_size(resolved); + return fs::file_size(resolved); } bool StdfsDevice::exists(std::string_view path) { auto resolved = resolve(path); - return std::filesystem::exists(resolved); + return fs::exists(resolved); } bool StdfsDevice::isdir(std::string_view path) { auto resolved = resolve(path); - return std::filesystem::is_directory(resolved); + return fs::is_directory(resolved); } bool StdfsDevice::isfile(std::string_view path) { auto resolved = resolve(path); - return std::filesystem::is_regular_file(resolved); + return fs::is_regular_file(resolved); } void StdfsDevice::mkdirs(std::string_view path) { auto resolved = resolve(path); - std::filesystem::create_directories(resolved); + fs::create_directories(resolved); } bool StdfsDevice::remove(std::string_view path) { auto resolved = resolve(path); - return std::filesystem::remove(resolved); + return fs::remove(resolved); } uint64_t StdfsDevice::removeAll(std::string_view path) { auto resolved = resolve(path); - return std::filesystem::remove_all(resolved); + return fs::remove_all(resolved); +} + +class StdfsPathsGenerator : public PathsGenerator { +public: + StdfsPathsGenerator(fs::path root) : root(std::move(root)) { + it = fs::directory_iterator(this->root); + } + + bool next(io::path& path) override { + if (it == fs::directory_iterator()) { + return false; + } + path = it->path().filename().u8string(); + it++; + return true; + } +private: + fs::path root; + fs::directory_iterator it; +}; + +std::unique_ptr StdfsDevice::list(std::string_view path) { + return std::make_unique(root / fs::u8path(path)); } diff --git a/src/io/devices/StdfsDevice.hpp b/src/io/devices/StdfsDevice.hpp index 6c88949f..bf284ccb 100644 --- a/src/io/devices/StdfsDevice.hpp +++ b/src/io/devices/StdfsDevice.hpp @@ -15,6 +15,7 @@ namespace io { void mkdirs(std::string_view path) override; bool remove(std::string_view path) override; uint64_t removeAll(std::string_view path) override; + std::unique_ptr list(std::string_view path) override; private: std::filesystem::path root; }; diff --git a/src/io/engine_paths.cpp b/src/io/engine_paths.cpp index 88fb98ca..5dc3ddfd 100644 --- a/src/io/engine_paths.cpp +++ b/src/io/engine_paths.cpp @@ -145,11 +145,10 @@ std::vector EnginePaths::scanForWorlds() const { auto folder = getWorldsFolder(); if (!io::is_directory(folder)) return folders; - for (const auto& entry : std::filesystem::directory_iterator(io::resolve(folder))) { - if (!entry.is_directory()) { + for (const auto& worldFolder : io::directory_iterator(folder)) { + if (!io::is_directory(worldFolder)) { continue; } - io::path worldFolder = folder / entry.path().filename().u8string(); auto worldFile = worldFolder / WorldFiles::WORLD_FILE; if (!io::is_regular_file(worldFile)) { continue; @@ -271,9 +270,8 @@ std::vector ResPaths::listdirRaw(const std::string& folderName) con auto& root = roots[i]; auto folder = root.path / fs::u8path(folderName); if (!io::is_directory(folder)) continue; - for (const auto& entry : fs::directory_iterator(io::resolve(folder))) { - auto name = entry.path().filename().u8string(); - entries.emplace_back(root.name + ":" + folderName + "/" + name); + for (const auto& file : io::directory_iterator(folder)) { + entries.emplace_back(root.name + ":" + folderName + "/" + file.name()); } } return entries; @@ -287,8 +285,8 @@ std::vector ResPaths::listdir( auto& root = roots[i]; io::path folder = root.path / folderName; if (!io::is_directory(folder)) continue; - for (const auto& entry : fs::directory_iterator(io::resolve(folder))) { - entries.push_back(folder / entry.path().filename().u8string()); + for (const auto& entry : io::directory_iterator(folder)) { + entries.push_back(folder / entry); } } return entries; diff --git a/src/io/io.cpp b/src/io/io.cpp index 356357c5..b8d8d7d9 100644 --- a/src/io/io.cpp +++ b/src/io/io.cpp @@ -49,6 +49,12 @@ void io::create_subdevice( set_device(name, std::make_shared(parentDevice, root.pathPart())); } +io::directory_iterator::directory_iterator(const io::path& folder) + : folder(folder) { + auto& device = io::require_device(folder.entryPoint()); + generator = device.list(folder.pathPart()); +} + io::rafile::rafile(const io::path& filename) : file(io::resolve(filename), std::ios::binary | std::ios::ate) { if (!file) { @@ -171,7 +177,7 @@ std::vector io::read_list(const io::path& filename) { } bool io::is_regular_file(const io::path& file) { - if (file.empty()) { + if (file.emptyOrInvalid()) { return false; } auto device = io::get_device(file.entryPoint()); @@ -182,7 +188,7 @@ bool io::is_regular_file(const io::path& file) { } bool io::is_directory(const io::path& file) { - if (file.empty()) { + if (file.emptyOrInvalid()) { return false; } auto device = io::get_device(file.entryPoint()); @@ -193,7 +199,7 @@ bool io::is_directory(const io::path& file) { } bool io::exists(const io::path& file) { - if (file.empty()) { + if (file.emptyOrInvalid()) { return false; } auto device = io::get_device(file.entryPoint()); diff --git a/src/io/io.hpp b/src/io/io.hpp index 1cdc8198..435753f9 100644 --- a/src/io/io.hpp +++ b/src/io/io.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include #include @@ -34,6 +35,75 @@ namespace io { size_t length() const; }; + class directory_iterator_impl { + public: + using iterator_category = std::input_iterator_tag; + using value_type = path; + using difference_type = std::ptrdiff_t; + using pointer = path*; + using reference = path&; + + directory_iterator_impl( + PathsGenerator& generator, const path& folder, bool end = false + ) + : generator(generator), folder(folder), isend(end) { + if (!isend && this->generator.next(current)) { + isend = false; + current = folder / current; + } else { + isend = true; + } + } + + reference operator*() { + return current; + } + + pointer operator->() { + return ¤t; + } + + directory_iterator_impl& operator++() { + if (isend) { + return *this; + } + if (generator.next(current)) { + current = folder / current; + } else { + isend = true; + } + return *this; + } + + bool operator==(const directory_iterator_impl& other) const { + return isend == other.isend; + } + + bool operator!=(const directory_iterator_impl& other) const { + return !(*this == other); + } + private: + PathsGenerator& generator; + path folder; + path current; + bool isend = false; + }; + + class directory_iterator { + std::unique_ptr generator; + path folder; + public: + directory_iterator(const path& folder); + + directory_iterator_impl begin() { + return directory_iterator_impl(*generator, folder); + } + + directory_iterator_impl end() { + return directory_iterator_impl(*generator, "", true); + } + }; + /// @brief Write bytes array to the file without any extra data /// @param file target file /// @param data data bytes array @@ -87,7 +157,11 @@ namespace io { std::filesystem::path resolve(const io::path& file); + /// @brief Check if file is one of the supported data interchange formats bool is_data_file(const io::path& file); + + /// @brief Check if file extension is one of the supported data interchange formats bool is_data_interchange_format(const std::string& ext); + dv::value read_object(const path& file); } diff --git a/src/io/path.hpp b/src/io/path.hpp index 454ff161..f106b226 100644 --- a/src/io/path.hpp +++ b/src/io/path.hpp @@ -127,6 +127,10 @@ namespace io { bool empty() const { return str.empty(); } + + bool emptyOrInvalid() const { + return str.empty() || colonPos == std::string::npos; + } private: /// @brief UTF-8 string contains entry_point:path or empty string std::string str; @@ -135,4 +139,10 @@ namespace io { void checkValid() const; }; + + class PathsGenerator { + public: + virtual ~PathsGenerator() = default; + virtual bool next(path& dst) = 0; + }; } diff --git a/src/logic/scripting/lua/libs/libfile.cpp b/src/logic/scripting/lua/libs/libfile.cpp index 5c7dd046..c1843e2f 100644 --- a/src/logic/scripting/lua/libs/libfile.cpp +++ b/src/logic/scripting/lua/libs/libfile.cpp @@ -95,7 +95,8 @@ static int l_exists(lua::State* L) { } static int l_isfile(lua::State* L) { - io::path path = resolve_path_soft(lua::require_string(L, 1)); + const char* string =lua::require_string(L, 1); + io::path path = resolve_path_soft(string); return lua::pushboolean(L, io::is_regular_file(path)); } @@ -184,10 +185,8 @@ static int l_list(lua::State* L) { } lua::createtable(L, 0, 0); size_t index = 1; - for (auto& entry : fs::directory_iterator(io::resolve(path))) { - auto name = entry.path().filename().u8string(); - auto file = dirname + "/" + name; - lua::pushstring(L, file); + for (const auto& file : io::directory_iterator(path)) { + lua::pushstring(L, file.string()); lua::rawseti(L, index); index++; } diff --git a/src/logic/scripting/lua/lua_util.hpp b/src/logic/scripting/lua/lua_util.hpp index 9539fbbf..656bd504 100644 --- a/src/logic/scripting/lua/lua_util.hpp +++ b/src/logic/scripting/lua/lua_util.hpp @@ -1,13 +1,13 @@ #pragma once +#include #include #include -#include #include #include "data/dv.hpp" -#include "lua_wrapper.hpp" #include "lua_custom_types.hpp" +#include "lua_wrapper.hpp" #define GLM_ENABLE_EXPERIMENTAL #include @@ -68,7 +68,7 @@ namespace lua { return 1; } - template + template inline int pushvec_stack(lua::State* L, const glm::vec& vec) { for (int i = 0; i < n; i++) { pushnumber(L, vec[i]); @@ -76,7 +76,7 @@ namespace lua { return n; } - template + template inline int pushivec_stack(lua::State* L, const glm::vec& vec) { for (int i = 0; i < n; i++) { pushinteger(L, vec[i]); @@ -108,10 +108,10 @@ namespace lua { inline int pushquat(lua::State* L, glm::quat quat) { createtable(L, 4, 0); - + pushnumber(L, quat.w); rawseti(L, 1); - + pushnumber(L, quat.x); rawseti(L, 2); @@ -127,7 +127,7 @@ namespace lua { pushnumber(L, quat.w); rawseti(L, 1); - + pushnumber(L, quat.x); rawseti(L, 2); @@ -287,8 +287,9 @@ namespace lua { } template - inline std::enable_if_t> - newusertype(lua::State* L) { + inline std::enable_if_t> newusertype( + lua::State* L + ) { const std::string& name = T::TYPENAME; usertypeNames[typeid(T)] = name; T::createMetatable(L); @@ -386,7 +387,7 @@ namespace lua { rawgeti(L, 4); auto z = tonumber(L, -1); pop(L); - + pop(L); return glm::quat(x, y, z, w); } @@ -445,8 +446,7 @@ namespace lua { int pushvalue(lua::State*, const dv::value& value); - [[nodiscard]] - dv::value tovalue(lua::State*, int idx); + [[nodiscard]] dv::value tovalue(lua::State*, int idx); inline bool getfield(lua::State* L, const std::string& name, int idx = -1) { lua_getfield(L, idx, name.c_str()); @@ -457,11 +457,13 @@ namespace lua { return true; } - inline int requirefield(lua::State* L, const std::string& name, int idx = -1) { + inline int requirefield( + lua::State* L, const std::string& name, int idx = -1 + ) { if (getfield(L, name, idx)) { return 1; } - throw std::runtime_error("object has no member '"+name+"'"); + throw std::runtime_error("object has no member '" + name + "'"); } inline bool hasfield(lua::State* L, const std::string& name, int idx = -1) { @@ -637,7 +639,7 @@ namespace lua { } inline const char* require_string_field( - lua::State* L, const std::string& name, int idx=-1 + lua::State* L, const std::string& name, int idx = -1 ) { requirefield(L, name, idx); auto value = require_string(L, -1); @@ -646,7 +648,7 @@ namespace lua { } inline Integer require_integer_field( - lua::State* L, const std::string& name, int idx=-1 + lua::State* L, const std::string& name, int idx = -1 ) { requirefield(L, name, idx); auto value = tointeger(L, -1); @@ -655,7 +657,7 @@ namespace lua { } inline Number require_number_field( - lua::State* L, const std::string& name, int idx=-1 + lua::State* L, const std::string& name, int idx = -1 ) { requirefield(L, name, idx); auto value = tonumber(L, -1); @@ -664,7 +666,7 @@ namespace lua { } inline bool get_boolean_field( - lua::State* L, const std::string& name, bool def, int idx=-1 + lua::State* L, const std::string& name, bool def, int idx = -1 ) { if (getfield(L, name, idx)) { bool value = toboolean(L, -1); @@ -675,7 +677,7 @@ namespace lua { } inline Integer get_integer_field( - lua::State* L, const std::string& name, Integer def, int idx=-1 + lua::State* L, const std::string& name, Integer def, int idx = -1 ) { if (getfield(L, name, idx)) { auto value = tointeger(L, -1); @@ -686,7 +688,7 @@ namespace lua { } inline Number get_number_field( - lua::State* L, const std::string& name, Number def, int idx=-1 + lua::State* L, const std::string& name, Number def, int idx = -1 ) { if (getfield(L, name, idx)) { auto value = tonumber(L, -1); @@ -697,15 +699,20 @@ namespace lua { } inline Integer get_integer_field( - lua::State* L, const std::string& name, - Integer def, Integer min, Integer max, int idx=-1 + lua::State* L, + const std::string& name, + Integer def, + Integer min, + Integer max, + int idx = -1 ) { if (getfield(L, name, idx)) { auto value = tointeger(L, -1); if (value < min || value > max) { throw std::runtime_error( - "value is out of range [" - +std::to_string(min)+", "+std::to_string(max)+"]"); + "value is out of range [" + std::to_string(min) + ", " + + std::to_string(max) + "]" + ); } pop(L); return value; diff --git a/src/world/files/WorldConverter.cpp b/src/world/files/WorldConverter.cpp index 3361334e..007ad08c 100644 --- a/src/world/files/WorldConverter.cpp +++ b/src/world/files/WorldConverter.cpp @@ -42,14 +42,14 @@ void WorldConverter::addRegionsTasks( if (!io::is_directory(regionsFolder)) { return; } - for (const auto& file : fs::directory_iterator(io::resolve(regionsFolder))) { + for (const auto& file :io::directory_iterator(regionsFolder)) { int x, z; - std::string name = file.path().stem().string(); + std::string name = file.stem(); if (!WorldRegions::parseRegionFilename(name, x, z)) { logger.error() << "could not parse region name " << name; continue; } - tasks.push(ConvertTask {taskType, file.path().u8string(), x, z, layerid}); + tasks.push(ConvertTask {taskType, file, x, z, layerid}); } } From ef170247cc3028e7213db7d1a7695814c9e06327 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Mon, 3 Feb 2025 21:56:44 +0300 Subject: [PATCH 05/16] fix ResPaths::listdir --- src/io/engine_paths.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/io/engine_paths.cpp b/src/io/engine_paths.cpp index 5dc3ddfd..f9a2701d 100644 --- a/src/io/engine_paths.cpp +++ b/src/io/engine_paths.cpp @@ -286,7 +286,7 @@ std::vector ResPaths::listdir( io::path folder = root.path / folderName; if (!io::is_directory(folder)) continue; for (const auto& entry : io::directory_iterator(folder)) { - entries.push_back(folder / entry); + entries.push_back(entry); } } return entries; From b955ae59c11014a54ee93c91b75c5eb86a1e4f8b Mon Sep 17 00:00:00 2001 From: MihailRis Date: Tue, 4 Feb 2025 11:59:05 +0300 Subject: [PATCH 06/16] update StdfsDevice::removeAll --- src/io/devices/StdfsDevice.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/io/devices/StdfsDevice.cpp b/src/io/devices/StdfsDevice.cpp index 89c585ca..98ef1568 100644 --- a/src/io/devices/StdfsDevice.cpp +++ b/src/io/devices/StdfsDevice.cpp @@ -3,9 +3,13 @@ #include #include +#include "debug/Logger.hpp" + using namespace io; namespace fs = std::filesystem; +static debug::Logger logger("io-stdfs"); + fs::path StdfsDevice::resolve(std::string_view path) { return root / fs::u8path(path); } @@ -60,7 +64,12 @@ bool StdfsDevice::remove(std::string_view path) { uint64_t StdfsDevice::removeAll(std::string_view path) { auto resolved = resolve(path); - return fs::remove_all(resolved); + if (fs::exists(resolved)) { + logger.info() << "removeAll " << resolved; + return fs::remove_all(resolved); + } else { + return 0; + } } class StdfsPathsGenerator : public PathsGenerator { From a653b063e6a0c98eec125fa5a0822bc9d3e3ab17 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Tue, 4 Feb 2025 12:35:19 +0300 Subject: [PATCH 07/16] completely remove EnginePaths::resolve --- src/frontend/screens/LevelScreen.cpp | 2 +- src/io/devices/StdfsDevice.cpp | 20 +++++- src/io/devices/StdfsDevice.hpp | 2 +- src/io/engine_paths.cpp | 70 +++++-------------- src/io/engine_paths.hpp | 2 - src/io/io.cpp | 4 ++ src/io/io.hpp | 1 + src/logic/scripting/lua/libs/libcore.cpp | 3 +- src/logic/scripting/lua/libs/libfile.cpp | 55 +++++---------- .../scripting/lua/libs/libgeneration.cpp | 6 +- src/logic/scripting/lua/libs/libgui.cpp | 6 +- .../lua/usertypes/lua_type_heightmap.cpp | 2 +- 12 files changed, 67 insertions(+), 106 deletions(-) diff --git a/src/frontend/screens/LevelScreen.cpp b/src/frontend/screens/LevelScreen.cpp index d1690747..08e1b41e 100644 --- a/src/frontend/screens/LevelScreen.cpp +++ b/src/frontend/screens/LevelScreen.cpp @@ -147,7 +147,7 @@ void LevelScreen::saveWorldPreview() { worldRenderer->draw(ctx, camera, false, true, 0.0f, postProcessing.get()); auto image = postProcessing->toImage(); image->flipY(); - imageio::write(paths.resolve("world:preview.png").string(), image.get()); + imageio::write("world:preview.png", image.get()); } catch (const std::exception& err) { logger.error() << err.what(); } diff --git a/src/io/devices/StdfsDevice.cpp b/src/io/devices/StdfsDevice.cpp index 98ef1568..3951dc32 100644 --- a/src/io/devices/StdfsDevice.cpp +++ b/src/io/devices/StdfsDevice.cpp @@ -10,6 +10,18 @@ namespace fs = std::filesystem; static debug::Logger logger("io-stdfs"); +StdfsDevice::StdfsDevice(fs::path root, bool createDirectory) + : root(std::move(root)) { + if (createDirectory && !fs::is_directory(this->root)) { + std::error_code ec; + fs::create_directories(this->root, ec); + if (ec) { + logger.error() << "error creating root directory " << this->root + << ": " << ec.message(); + } + } +} + fs::path StdfsDevice::resolve(std::string_view path) { return root / fs::u8path(path); } @@ -54,7 +66,13 @@ bool StdfsDevice::isfile(std::string_view path) { void StdfsDevice::mkdirs(std::string_view path) { auto resolved = resolve(path); - fs::create_directories(resolved); + + std::error_code ec; + fs::create_directories(resolved, ec); + if (ec) { + logger.error() << "error creating directory " << resolved << ": " + << ec.message(); + } } bool StdfsDevice::remove(std::string_view path) { diff --git a/src/io/devices/StdfsDevice.hpp b/src/io/devices/StdfsDevice.hpp index bf284ccb..f518af93 100644 --- a/src/io/devices/StdfsDevice.hpp +++ b/src/io/devices/StdfsDevice.hpp @@ -3,7 +3,7 @@ namespace io { class StdfsDevice : public Device { public: - StdfsDevice(std::filesystem::path root) : root(std::move(root)) {} + StdfsDevice(std::filesystem::path root, bool createDirectory = true); std::filesystem::path resolve(std::string_view path) override; void write(std::string_view path, const void* data, size_t size) override; diff --git a/src/io/engine_paths.cpp b/src/io/engine_paths.cpp index f9a2701d..ca20b265 100644 --- a/src/io/engine_paths.cpp +++ b/src/io/engine_paths.cpp @@ -20,8 +20,8 @@ static debug::Logger logger("engine-paths"); static inline auto SCREENSHOTS_FOLDER = std::filesystem::u8path("screenshots"); static inline auto CONTENT_FOLDER = std::filesystem::u8path("content"); static inline auto WORLDS_FOLDER = std::filesystem::u8path("worlds"); -static inline auto CONFIG_FOLDER = std::filesystem::u8path("config"); -static inline auto EXPORT_FOLDER = std::filesystem::u8path("export"); +static inline auto CONFIG_FOLDER = io::path("config"); +static inline auto EXPORT_FOLDER = io::path("export"); static inline auto CONTROLS_FILE = std::filesystem::u8path("controls.toml"); static inline auto SETTINGS_FILE = std::filesystem::u8path("settings.toml"); @@ -52,7 +52,7 @@ static io::path toCanonic(io::path path) { } void EnginePaths::prepare() { - io::set_device("res", std::make_shared(resourcesFolder)); + io::set_device("res", std::make_shared(resourcesFolder, false)); io::set_device("user", std::make_shared(userFilesFolder)); if (!io::is_directory("res:")) { @@ -60,10 +60,6 @@ void EnginePaths::prepare() { resourcesFolder.string() + " is not a directory" ); } - if (!io::is_directory("user:")) { - io::create_directories("user:"); - } - logger.info() << "resources folder: " << fs::canonical(resourcesFolder).u8string(); logger.info() << "user files folder: " << fs::canonical(userFilesFolder).u8string(); @@ -71,14 +67,10 @@ void EnginePaths::prepare() { if (!io::is_directory(contentFolder)) { io::create_directories(contentFolder); } - auto exportFolder = io::path("user:") / EXPORT_FOLDER; - if (!io::is_directory(exportFolder)) { - io::create_directories(exportFolder); - } - auto configFolder = io::path("user:") / CONFIG_FOLDER; - if (!io::is_directory(configFolder)) { - io::create_directories(configFolder); - } + + io::create_subdevice("core", "res", ""); + io::create_subdevice("export", "user", EXPORT_FOLDER); + io::create_subdevice("config", "user", CONFIG_FOLDER); } const std::filesystem::path& EnginePaths::getUserFilesFolder() const { @@ -187,7 +179,16 @@ void EnginePaths::setCurrentWorldFolder(io::path folder) { } void EnginePaths::setContentPacks(std::vector* contentPacks) { + // Remove previous content entry-points + for (const auto& pack : *this->contentPacks) { + io::remove_device(pack.id); + } this->contentPacks = contentPacks; + // Create content devices + for (const auto& pack : *contentPacks) { + auto parent = pack.folder.entryPoint(); + io::create_subdevice(pack.id, parent, pack.folder); + } } std::tuple EnginePaths::parsePath(std::string_view path) { @@ -200,45 +201,6 @@ std::tuple EnginePaths::parsePath(std::string_view pat return {prefix, filename}; } -// TODO: remove -io::path EnginePaths::resolve( - const std::string& path, bool throwErr -) const { - auto [prefix, filename] = EnginePaths::parsePath(path); - if (prefix.empty()) { - throw files_access_error("no entry point specified"); - } - filename = toCanonic(filename).string(); - - if (prefix == "core") { - return io::path("res:") / filename; - } - - if (prefix == "res" || prefix == "user" || prefix == "script") { - return prefix + ":" + filename; - } - if (prefix == "config") { - return getConfigFolder() / filename; - } - if (prefix == "world") { - return currentWorldFolder / filename; - } - if (prefix == "export") { - return io::path("user:") / EXPORT_FOLDER / filename; - } - if (contentPacks) { - for (auto& pack : *contentPacks) { - if (pack.id == prefix) { - return pack.folder / filename; - } - } - } - if (throwErr) { - throw files_access_error("unknown entry point '" + prefix + "'"); - } - return filename; -} - ResPaths::ResPaths(io::path mainRoot, std::vector roots) : mainRoot(std::move(mainRoot)), roots(std::move(roots)) { } diff --git a/src/io/engine_paths.hpp b/src/io/engine_paths.hpp index 920b01aa..fda77087 100644 --- a/src/io/engine_paths.hpp +++ b/src/io/engine_paths.hpp @@ -43,8 +43,6 @@ public: std::vector scanForWorlds() const; - io::path resolve(const std::string& path, bool throwErr = true) const; - static std::tuple parsePath(std::string_view view); static inline auto CONFIG_DEFAULTS = diff --git a/src/io/io.cpp b/src/io/io.cpp index b8d8d7d9..2cfa75d9 100644 --- a/src/io/io.cpp +++ b/src/io/io.cpp @@ -23,6 +23,10 @@ void io::set_device(const std::string& name, std::shared_ptr device) devices[name] = device; } +void io::remove_device(const std::string& name) { + devices.erase(name); +} + std::shared_ptr io::get_device(const std::string& name) { const auto& found = devices.find(name); if (found == devices.end()) { diff --git a/src/io/io.hpp b/src/io/io.hpp index 435753f9..fdccc6ac 100644 --- a/src/io/io.hpp +++ b/src/io/io.hpp @@ -16,6 +16,7 @@ namespace io { class Device; void set_device(const std::string& name, std::shared_ptr device); + void remove_device(const std::string& name); std::shared_ptr get_device(const std::string& name); Device& require_device(const std::string& name); diff --git a/src/logic/scripting/lua/libs/libcore.cpp b/src/logic/scripting/lua/libs/libcore.cpp index 4c1e5dc6..7b8c152c 100644 --- a/src/logic/scripting/lua/libs/libcore.cpp +++ b/src/logic/scripting/lua/libs/libcore.cpp @@ -259,8 +259,7 @@ static int l_load_texture(lua::State* L) { } static int l_open_folder(lua::State* L) { - auto path = engine->getPaths().resolve(lua::require_string(L, 1)); - platform::open_folder(io::resolve(path)); + platform::open_folder(io::resolve(lua::require_string(L, 1))); return 0; } diff --git a/src/logic/scripting/lua/libs/libfile.cpp b/src/logic/scripting/lua/libs/libfile.cpp index c1843e2f..175d3171 100644 --- a/src/logic/scripting/lua/libs/libfile.cpp +++ b/src/logic/scripting/lua/libs/libfile.cpp @@ -13,17 +13,6 @@ namespace fs = std::filesystem; using namespace scripting; -static io::path resolve_path(const std::string& path) { - return engine->getPaths().resolve(path); -} - -static io::path resolve_path_soft(const std::string& path) { - if (path.find(':') == std::string::npos) { - return ""; - } - return engine->getPaths().resolve(path, false); -} - static int l_find(lua::State* L) { auto path = lua::require_string(L, 1); try { @@ -34,12 +23,12 @@ static int l_find(lua::State* L) { } static int l_resolve(lua::State* L) { - io::path path = resolve_path(lua::require_string(L, 1)); + io::path path = lua::require_string(L, 1); return lua::pushstring(L, path.string()); } static int l_read(lua::State* L) { - io::path path = resolve_path(lua::require_string(L, 1)); + io::path path = lua::require_string(L, 1); if (io::is_regular_file(path)) { return lua::pushstring(L, io::read_string(path)); } @@ -53,9 +42,8 @@ static std::set writeable_entry_points { }; static io::path get_writeable_path(lua::State* L) { - std::string rawpath = lua::require_string(L, 1); - io::path path = resolve_path(rawpath); - auto entryPoint = rawpath.substr(0, rawpath.find(':')); + io::path path = lua::require_string(L, 1); + auto entryPoint = path.entryPoint(); if (writeable_entry_points.find(entryPoint) == writeable_entry_points.end()) { throw std::runtime_error("access denied"); } @@ -70,9 +58,8 @@ static int l_write(lua::State* L) { } static int l_remove(lua::State* L) { - std::string rawpath = lua::require_string(L, 1); - io::path path = resolve_path(rawpath); - auto entryPoint = rawpath.substr(0, rawpath.find(':')); + io::path path = lua::require_string(L, 1); + auto entryPoint = path.entryPoint(); if (writeable_entry_points.find(entryPoint) == writeable_entry_points.end()) { throw std::runtime_error("access denied"); } @@ -80,9 +67,8 @@ static int l_remove(lua::State* L) { } static int l_remove_tree(lua::State* L) { - std::string rawpath = lua::require_string(L, 1); - io::path path = resolve_path(rawpath); - auto entryPoint = rawpath.substr(0, rawpath.find(':')); + io::path path = lua::require_string(L, 1); + auto entryPoint = path.entryPoint(); if (writeable_entry_points.find(entryPoint) == writeable_entry_points.end()) { throw std::runtime_error("access denied"); } @@ -90,23 +76,19 @@ static int l_remove_tree(lua::State* L) { } static int l_exists(lua::State* L) { - io::path path = resolve_path_soft(lua::require_string(L, 1)); - return lua::pushboolean(L, io::exists(path)); + return lua::pushboolean(L, io::exists(lua::require_string(L, 1))); } static int l_isfile(lua::State* L) { - const char* string =lua::require_string(L, 1); - io::path path = resolve_path_soft(string); - return lua::pushboolean(L, io::is_regular_file(path)); + return lua::pushboolean(L, io::is_regular_file(lua::require_string(L, 1))); } static int l_isdir(lua::State* L) { - io::path path = resolve_path_soft(lua::require_string(L, 1)); - return lua::pushboolean(L, io::is_directory(path)); + return lua::pushboolean(L, io::is_directory(lua::require_string(L, 1))); } static int l_length(lua::State* L) { - io::path path = resolve_path(lua::require_string(L, 1)); + io::path path = lua::require_string(L, 1); if (io::exists(path)) { return lua::pushinteger(L, io::file_size(path)); } else { @@ -115,17 +97,17 @@ static int l_length(lua::State* L) { } static int l_mkdir(lua::State* L) { - io::path path = resolve_path(lua::require_string(L, 1)); + io::path path = lua::require_string(L, 1); return lua::pushboolean(L, io::create_directories(path)); // FIXME } static int l_mkdirs(lua::State* L) { - io::path path = resolve_path(lua::require_string(L, 1)); + io::path path = lua::require_string(L, 1); return lua::pushboolean(L, io::create_directories(path)); } static int l_read_bytes(lua::State* L) { - io::path path = resolve_path(lua::require_string(L, 1)); + io::path path = lua::require_string(L, 1); if (io::is_regular_file(path)) { size_t length = static_cast(io::file_size(path)); @@ -177,7 +159,7 @@ static int l_list(lua::State* L) { if (dirname.find(':') == std::string::npos) { return l_list_all_res(L, dirname); } - io::path path = resolve_path(dirname); + io::path path = dirname; if (!io::is_directory(path)) { throw std::runtime_error( util::quote(path.string()) + " is not a directory" @@ -238,9 +220,8 @@ static int l_read_combined_object(lua::State* L) { } static int l_is_writeable(lua::State* L) { - std::string rawpath = lua::require_string(L, 1); - io::path path = resolve_path(rawpath); - auto entryPoint = rawpath.substr(0, rawpath.find(':')); + io::path path = lua::require_string(L, 1); + auto entryPoint = path.entryPoint(); if (writeable_entry_points.find(entryPoint) == writeable_entry_points.end()) { return lua::pushboolean(L, false); } diff --git a/src/logic/scripting/lua/libs/libgeneration.cpp b/src/logic/scripting/lua/libs/libgeneration.cpp index 196dae74..855700a9 100644 --- a/src/logic/scripting/lua/libs/libgeneration.cpp +++ b/src/logic/scripting/lua/libs/libgeneration.cpp @@ -14,7 +14,7 @@ using namespace scripting; static int l_save_fragment(lua::State* L) { const auto& paths = engine->getPaths(); auto fragment = lua::touserdata(L, 1); - auto file = paths.resolve(lua::require_string(L, 2), true); + auto file = lua::require_string(L, 2); auto map = fragment->getFragment()->serialize(); auto bytes = json::to_binary(map, true); io::write_bytes(file, bytes.data(), bytes.size()); @@ -35,9 +35,7 @@ static int l_create_fragment(lua::State* L) { } static int l_load_fragment(lua::State* L) { - const auto& paths = engine->getPaths(); - auto filename = lua::require_string(L, 1); - auto path = paths.resolve(filename); + io::path path = lua::require_string(L, 1); if (!io::exists(path)) { throw std::runtime_error("file "+path.string()+" does not exist"); } diff --git a/src/logic/scripting/lua/libs/libgui.cpp b/src/logic/scripting/lua/libs/libgui.cpp index 995cb625..d3b9c93a 100644 --- a/src/logic/scripting/lua/libs/libgui.cpp +++ b/src/logic/scripting/lua/libs/libgui.cpp @@ -808,15 +808,15 @@ static int l_gui_alert(lua::State* L) { } static int l_gui_load_document(lua::State* L) { - auto filename = lua::require_string(L, 1); + io::path filename = lua::require_string(L, 1); auto alias = lua::require_string(L, 2); auto args = lua::tovalue(L, 3); auto documentPtr = UiDocument::read( scripting::get_root_environment(), alias, - engine->getPaths().resolve(filename), - filename + filename, + filename.string() ); auto document = documentPtr.get(); engine->getAssets()->store(std::move(documentPtr), alias); diff --git a/src/logic/scripting/lua/usertypes/lua_type_heightmap.cpp b/src/logic/scripting/lua/usertypes/lua_type_heightmap.cpp index 983f9ba3..9e7cabc8 100644 --- a/src/logic/scripting/lua/usertypes/lua_type_heightmap.cpp +++ b/src/logic/scripting/lua/usertypes/lua_type_heightmap.cpp @@ -52,7 +52,7 @@ const float* LuaHeightmap::getValues() const { static int l_dump(lua::State* L) { const auto& paths = scripting::engine->getPaths(); if (auto heightmap = touserdata(L, 1)) { - auto file = paths.resolve(require_string(L, 2)); + io::path file = require_string(L, 2); uint w = heightmap->getWidth(); uint h = heightmap->getHeight(); ImageData image(ImageFormat::rgb888, w, h); From e4c33e539eabd2126d88e148d891fd9d5a6c288b Mon Sep 17 00:00:00 2001 From: MihailRis Date: Tue, 4 Feb 2025 12:53:05 +0300 Subject: [PATCH 08/16] fix io::path.parent() & update tests --- src/io/path.hpp | 8 ++------ test/coders/lua_parsing.cpp | 6 +++++- test/coders/vec3.cpp | 6 +++++- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/io/path.hpp b/src/io/path.hpp index f106b226..6c6dea14 100644 --- a/src/io/path.hpp +++ b/src/io/path.hpp @@ -110,13 +110,9 @@ namespace io { path parent() const { size_t slashpos = str.rfind('/'); if (slashpos == std::string::npos) { - return colonPos == std::string::npos - ? path() - : path(str.substr(0, colonPos)); + return colonPos == std::string::npos ? "" : str; } - return colonPos == std::string::npos - ? path(str.substr(0, slashpos)) - : path(str.substr(0, colonPos) + str.substr(slashpos)); + return str.substr(0, slashpos); } std::string string() const { diff --git a/test/coders/lua_parsing.cpp b/test/coders/lua_parsing.cpp index 64b15d44..17492d7a 100644 --- a/test/coders/lua_parsing.cpp +++ b/test/coders/lua_parsing.cpp @@ -3,10 +3,14 @@ #include "coders/commons.hpp" #include "coders/lua_parsing.hpp" #include "io/io.hpp" +#include "io/devices/StdfsDevice.hpp" #include "util/stringutil.hpp" +namespace fs = std::filesystem; + TEST(lua_parsing, Tokenizer) { - auto filename = "../../res/scripts/stdlib.lua"; + io::set_device("res", std::make_shared(fs::u8path("../../res"))); + auto filename = "res:scripts/stdlib.lua"; auto source = io::read_string(filename); try { auto tokens = lua::tokenize(filename, source); diff --git a/test/coders/vec3.cpp b/test/coders/vec3.cpp index b7c8e37e..a1dd330b 100644 --- a/test/coders/vec3.cpp +++ b/test/coders/vec3.cpp @@ -2,9 +2,13 @@ #include "coders/vec3.hpp" #include "io/io.hpp" +#include "io/devices/StdfsDevice.hpp" + +namespace fs = std::filesystem; TEST(VEC3, Decode) { - io::path file = "res/models/block.vec3"; + io::set_device("res", std::make_shared(fs::u8path("../../res"))); + io::path file = "res:models/block.vec3"; auto bytes = io::read_bytes_buffer(file); auto model = vec3::load(file.string(), bytes); } From bced20be1f028d656e992994c1f26aae534657b4 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Tue, 4 Feb 2025 13:08:42 +0300 Subject: [PATCH 09/16] update io::SubDevice constructor --- src/io/devices/Device.cpp | 16 ++++++++++++++++ src/io/devices/Device.hpp | 7 +++++-- 2 files changed, 21 insertions(+), 2 deletions(-) create mode 100644 src/io/devices/Device.cpp diff --git a/src/io/devices/Device.cpp b/src/io/devices/Device.cpp new file mode 100644 index 00000000..600f9c26 --- /dev/null +++ b/src/io/devices/Device.cpp @@ -0,0 +1,16 @@ +#include "Device.hpp" + +#include "../io.hpp" + +using namespace io; + +SubDevice::SubDevice( + std::shared_ptr parent, + const std::string& path, + bool createDirectory +) + : parent(std::move(parent)), root(path) { + if (createDirectory && !this->parent->exists(path)) { + this->parent->mkdirs(path); + } +} diff --git a/src/io/devices/Device.hpp b/src/io/devices/Device.hpp index 30d885fa..ee40d2f9 100644 --- a/src/io/devices/Device.hpp +++ b/src/io/devices/Device.hpp @@ -28,8 +28,11 @@ namespace io { class SubDevice : public Device { public: - SubDevice(std::shared_ptr parent, const std::string& path) - : parent(std::move(parent)), root(path) {} + SubDevice( + std::shared_ptr parent, + const std::string& path, + bool createDirectory = true + ); std::filesystem::path resolve(std::string_view path) override { return parent->resolve((root / path).pathPart()); From 8a12ff5879c70afba465ff0d3d1e99ed2f746b86 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Tue, 4 Feb 2025 13:17:35 +0300 Subject: [PATCH 10/16] fix EnginePaths::setContentPacks --- src/io/engine_paths.cpp | 6 ++++-- src/io/engine_paths.hpp | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/io/engine_paths.cpp b/src/io/engine_paths.cpp index ca20b265..d07a919b 100644 --- a/src/io/engine_paths.cpp +++ b/src/io/engine_paths.cpp @@ -180,14 +180,16 @@ void EnginePaths::setCurrentWorldFolder(io::path folder) { void EnginePaths::setContentPacks(std::vector* contentPacks) { // Remove previous content entry-points - for (const auto& pack : *this->contentPacks) { - io::remove_device(pack.id); + for (const auto& id : contentEntryPoints) { + io::remove_device(id); } + contentEntryPoints.clear(); this->contentPacks = contentPacks; // Create content devices for (const auto& pack : *contentPacks) { auto parent = pack.folder.entryPoint(); io::create_subdevice(pack.id, parent, pack.folder); + contentEntryPoints.push_back(pack.id); } } diff --git a/src/io/engine_paths.hpp b/src/io/engine_paths.hpp index fda77087..4858a215 100644 --- a/src/io/engine_paths.hpp +++ b/src/io/engine_paths.hpp @@ -53,6 +53,7 @@ private: io::path currentWorldFolder; std::optional scriptFolder; std::vector* contentPacks = nullptr; + std::vector contentEntryPoints; }; struct PathsRoot { From 94bae83de635bfe67310b7bf2c07b83658310e41 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Tue, 4 Feb 2025 13:32:50 +0300 Subject: [PATCH 11/16] fix windows build --- src/content/ContentLoader.cpp | 6 +++--- src/engine/Engine.cpp | 4 ++-- src/io/engine_paths.cpp | 6 ++---- src/logic/scripting/lua/libs/libworld.cpp | 6 +++--- 4 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/content/ContentLoader.cpp b/src/content/ContentLoader.cpp index c1b3f10a..d3df18f1 100644 --- a/src/content/ContentLoader.cpp +++ b/src/content/ContentLoader.cpp @@ -761,7 +761,7 @@ void ContentLoader::load() { auto folder = pack->folder; // Load world generators - io::path generatorsDir = folder / fs::u8path("generators"); + io::path generatorsDir = folder / "generators"; foreach_file(generatorsDir, [this](const io::path& file) { std::string name = file.stem(); auto [packid, full, filename] = create_unit_id(pack->id, name); @@ -816,7 +816,7 @@ void ContentLoader::load() { } // Load skeletons - io::path skeletonsDir = folder / fs::u8path("skeletons"); + io::path skeletonsDir = folder / "skeletons"; foreach_file(skeletonsDir, [this](const io::path& file) { std::string name = pack->id + ":" + file.stem(); std::string text = io::read_string(file); @@ -875,7 +875,7 @@ void ContentLoader::loadScripts(Content& content) { ); } // Load entity components - io::path componentsDir = folder / fs::u8path("scripts/components"); + io::path componentsDir = folder / "scripts/components"; foreach_file(componentsDir, [&pack](const io::path& file) { auto name = pack.id + ":" + file.stem(); scripting::load_entity_component( diff --git a/src/engine/Engine.cpp b/src/engine/Engine.cpp index 7be65cd1..80d774be 100644 --- a/src/engine/Engine.cpp +++ b/src/engine/Engine.cpp @@ -326,8 +326,8 @@ void Engine::loadAssets() { } static void load_configs(const io::path& root) { - auto configFolder = root/io::path("config"); - auto bindsFile = configFolder/io::path("bindings.toml"); + auto configFolder = root / "config"; + auto bindsFile = configFolder / "bindings.toml"; if (io::is_regular_file(bindsFile)) { Events::loadBindings( bindsFile.string(), io::read_string(bindsFile), BindType::BIND diff --git a/src/io/engine_paths.cpp b/src/io/engine_paths.cpp index d07a919b..39cc8882 100644 --- a/src/io/engine_paths.cpp +++ b/src/io/engine_paths.cpp @@ -98,10 +98,8 @@ io::path EnginePaths::getNewScreenshotFile(const std::string& ext) { auto file = folder / ("screenshot-" + datetimestr + "." + ext); uint index = 0; while (io::exists(file)) { - file = folder / fs::u8path( - "screenshot-" + datetimestr + "-" + - std::to_string(index) + "." + ext - ); + file = folder / ("screenshot-" + datetimestr + "-" + + std::to_string(index) + "." + ext); index++; } return file; diff --git a/src/logic/scripting/lua/libs/libworld.cpp b/src/logic/scripting/lua/libs/libworld.cpp index d18f964a..f54ce4e3 100644 --- a/src/logic/scripting/lua/libs/libworld.cpp +++ b/src/logic/scripting/lua/libs/libworld.cpp @@ -45,7 +45,7 @@ static int l_get_list(lua::State* L) { const auto& folder = worlds[i]; auto root = - json::parse(io::read_string(folder / fs::u8path("world.json"))); + json::parse(io::read_string(folder / "world.json")); const auto& versionMap = root["version"]; int versionMajor = versionMap["major"].asInteger(); int versionMinor = versionMap["minor"].asInteger(); @@ -59,8 +59,8 @@ static int l_get_list(lua::State* L) { if (!engine->isHeadless() && !AssetsLoader::loadExternalTexture( assets, icon, - {worlds[i] / fs::path("icon.png"), - worlds[i] / fs::path("preview.png")} + {worlds[i] / "icon.png", + worlds[i] / "preview.png"} )) { icon = "gui/no_world_icon"; } From f8d0ded70ef0e9ac37d61f7ce2a705131c1bf4e0 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Tue, 4 Feb 2025 13:52:33 +0300 Subject: [PATCH 12/16] fix windows build --- src/io/engine_paths.cpp | 20 ++++++++++---------- src/logic/scripting/lua/lua_engine.cpp | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/io/engine_paths.cpp b/src/io/engine_paths.cpp index 39cc8882..5a0f0cb6 100644 --- a/src/io/engine_paths.cpp +++ b/src/io/engine_paths.cpp @@ -17,13 +17,13 @@ namespace fs = std::filesystem; static debug::Logger logger("engine-paths"); -static inline auto SCREENSHOTS_FOLDER = std::filesystem::u8path("screenshots"); -static inline auto CONTENT_FOLDER = std::filesystem::u8path("content"); -static inline auto WORLDS_FOLDER = std::filesystem::u8path("worlds"); -static inline auto CONFIG_FOLDER = io::path("config"); -static inline auto EXPORT_FOLDER = io::path("export"); -static inline auto CONTROLS_FILE = std::filesystem::u8path("controls.toml"); -static inline auto SETTINGS_FILE = std::filesystem::u8path("settings.toml"); +static inline io::path SCREENSHOTS_FOLDER = "screenshots"; +static inline io::path CONTENT_FOLDER = "content"; +static inline io::path WORLDS_FOLDER = "worlds"; +static inline io::path CONFIG_FOLDER = "config"; +static inline io::path EXPORT_FOLDER = "export"; +static inline io::path CONTROLS_FILE = "controls.toml"; +static inline io::path SETTINGS_FILE = "settings.toml"; static io::path toCanonic(io::path path) { std::stack parts; @@ -46,7 +46,7 @@ static io::path toCanonic(io::path path) { throw files_access_error("entry point reached"); } - path = path / std::filesystem::path(part); + path = path / part; } return path; } @@ -118,7 +118,7 @@ io::path EnginePaths::getCurrentWorldFolder() { } io::path EnginePaths::getWorldFolderByName(const std::string& name) { - return getWorldsFolder() / std::filesystem::path(name); + return getWorldsFolder() / name; } io::path EnginePaths::getControlsFile() const { @@ -230,7 +230,7 @@ std::vector ResPaths::listdirRaw(const std::string& folderName) con std::vector entries; for (int i = roots.size() - 1; i >= 0; i--) { auto& root = roots[i]; - auto folder = root.path / fs::u8path(folderName); + auto folder = root.path / folderName; if (!io::is_directory(folder)) continue; for (const auto& file : io::directory_iterator(folder)) { entries.emplace_back(root.name + ":" + folderName + "/" + file.name()); diff --git a/src/logic/scripting/lua/lua_engine.cpp b/src/logic/scripting/lua/lua_engine.cpp index 59b9cc39..251f789b 100644 --- a/src/logic/scripting/lua/lua_engine.cpp +++ b/src/logic/scripting/lua/lua_engine.cpp @@ -125,7 +125,7 @@ void lua::initialize(const EnginePaths& paths, const CoreParameters& params) { main_thread = create_state( paths, params.headless ? StateType::SCRIPT : StateType::BASE ); - lua::pushstring(main_thread, params.scriptFile.stem()); + lua::pushstring(main_thread, params.scriptFile.stem().u8string()); lua::setglobal(main_thread, "__VC_SCRIPT_NAME"); } From 1ec8f89599b40f9364461b1c3a089595e12cadf2 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Tue, 4 Feb 2025 14:10:23 +0300 Subject: [PATCH 13/16] add io::Device::mkdir --- src/io/devices/Device.hpp | 11 ++++++++--- src/io/devices/StdfsDevice.cpp | 17 +++++++++++++++-- src/io/devices/StdfsDevice.hpp | 3 ++- src/io/io.cpp | 12 ++++++++++-- src/io/io.hpp | 1 + src/logic/scripting/lua/libs/libfile.cpp | 2 +- 6 files changed, 37 insertions(+), 9 deletions(-) diff --git a/src/io/devices/Device.hpp b/src/io/devices/Device.hpp index ee40d2f9..bb000602 100644 --- a/src/io/devices/Device.hpp +++ b/src/io/devices/Device.hpp @@ -20,7 +20,8 @@ namespace io { virtual bool exists(std::string_view path) = 0; virtual bool isdir(std::string_view path) = 0; virtual bool isfile(std::string_view path) = 0; - virtual void mkdirs(std::string_view path) = 0; + virtual bool mkdir(std::string_view path) = 0; + virtual bool mkdirs(std::string_view path) = 0; virtual bool remove(std::string_view path) = 0; virtual uint64_t removeAll(std::string_view path) = 0; virtual std::unique_ptr list(std::string_view path) = 0; @@ -62,8 +63,12 @@ namespace io { return parent->isfile((root / path).pathPart()); } - void mkdirs(std::string_view path) override { - parent->mkdirs((root / path).pathPart()); + bool mkdir(std::string_view path) override { + return parent->mkdir((root / path).pathPart()); + } + + bool mkdirs(std::string_view path) override { + return parent->mkdirs((root / path).pathPart()); } bool remove(std::string_view path) override { diff --git a/src/io/devices/StdfsDevice.cpp b/src/io/devices/StdfsDevice.cpp index 3951dc32..f9598e6f 100644 --- a/src/io/devices/StdfsDevice.cpp +++ b/src/io/devices/StdfsDevice.cpp @@ -64,15 +64,28 @@ bool StdfsDevice::isfile(std::string_view path) { return fs::is_regular_file(resolved); } -void StdfsDevice::mkdirs(std::string_view path) { +bool StdfsDevice::mkdir(std::string_view path) { auto resolved = resolve(path); std::error_code ec; - fs::create_directories(resolved, ec); + bool created = fs::create_directory(resolved, ec); if (ec) { logger.error() << "error creating directory " << resolved << ": " << ec.message(); } + return created; +} + +bool StdfsDevice::mkdirs(std::string_view path) { + auto resolved = resolve(path); + + std::error_code ec; + bool created = fs::create_directories(resolved, ec); + if (ec) { + logger.error() << "error creating directories " << resolved << ": " + << ec.message(); + } + return created; } bool StdfsDevice::remove(std::string_view path) { diff --git a/src/io/devices/StdfsDevice.hpp b/src/io/devices/StdfsDevice.hpp index f518af93..819dfe4f 100644 --- a/src/io/devices/StdfsDevice.hpp +++ b/src/io/devices/StdfsDevice.hpp @@ -12,7 +12,8 @@ namespace io { bool exists(std::string_view path) override; bool isdir(std::string_view path) override; bool isfile(std::string_view path) override; - void mkdirs(std::string_view path) override; + bool mkdir(std::string_view path) override; + bool mkdirs(std::string_view path) override; bool remove(std::string_view path) override; uint64_t removeAll(std::string_view path) override; std::unique_ptr list(std::string_view path) override; diff --git a/src/io/io.cpp b/src/io/io.cpp index 2cfa75d9..a9ee86de 100644 --- a/src/io/io.cpp +++ b/src/io/io.cpp @@ -213,13 +213,21 @@ bool io::exists(const io::path& file) { return device->exists(file.pathPart()); } +bool io::create_directory(const io::path& file) { + auto& device = io::require_device(file.entryPoint()); + if (device.isdir(file.pathPart())) { + return false; + } + return device.mkdirs(file.pathPart()); +} + + bool io::create_directories(const io::path& file) { auto& device = io::require_device(file.entryPoint()); if (device.isdir(file.pathPart())) { return false; } - device.mkdirs(file.pathPart()); - return true; + return device.mkdirs(file.pathPart()); } bool io::remove(const io::path& file) { diff --git a/src/io/io.hpp b/src/io/io.hpp index fdccc6ac..14541eea 100644 --- a/src/io/io.hpp +++ b/src/io/io.hpp @@ -151,6 +151,7 @@ namespace io { bool is_regular_file(const io::path& file); bool is_directory(const io::path& file); bool exists(const io::path& file); + bool create_directory(const io::path& file); bool create_directories(const io::path& file); bool remove(const io::path& file); uint64_t remove_all(const io::path& file); diff --git a/src/logic/scripting/lua/libs/libfile.cpp b/src/logic/scripting/lua/libs/libfile.cpp index 175d3171..f95c0679 100644 --- a/src/logic/scripting/lua/libs/libfile.cpp +++ b/src/logic/scripting/lua/libs/libfile.cpp @@ -98,7 +98,7 @@ static int l_length(lua::State* L) { static int l_mkdir(lua::State* L) { io::path path = lua::require_string(L, 1); - return lua::pushboolean(L, io::create_directories(path)); // FIXME + return lua::pushboolean(L, io::create_directory(path)); } static int l_mkdirs(lua::State* L) { From 59f46ad530e95751860e530e1b40048b7556ae99 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Tue, 4 Feb 2025 14:58:41 +0300 Subject: [PATCH 14/16] add io::path.normalized() --- src/io/devices/StdfsDevice.cpp | 4 ++-- src/io/engine_paths.cpp | 26 -------------------------- src/io/engine_paths.hpp | 6 ------ src/io/path.cpp | 29 ++++++++++++++++++++++++++++- src/io/path.hpp | 9 +++++++++ 5 files changed, 39 insertions(+), 35 deletions(-) diff --git a/src/io/devices/StdfsDevice.cpp b/src/io/devices/StdfsDevice.cpp index f9598e6f..ad33547d 100644 --- a/src/io/devices/StdfsDevice.cpp +++ b/src/io/devices/StdfsDevice.cpp @@ -23,7 +23,7 @@ StdfsDevice::StdfsDevice(fs::path root, bool createDirectory) } fs::path StdfsDevice::resolve(std::string_view path) { - return root / fs::u8path(path); + return root / fs::u8path(io::path(std::string(path)).normalized().string()); } void StdfsDevice::write(std::string_view path, const void* data, size_t size) { @@ -123,5 +123,5 @@ private: }; std::unique_ptr StdfsDevice::list(std::string_view path) { - return std::make_unique(root / fs::u8path(path)); + return std::make_unique(resolve(path)); } diff --git a/src/io/engine_paths.cpp b/src/io/engine_paths.cpp index 5a0f0cb6..76485031 100644 --- a/src/io/engine_paths.cpp +++ b/src/io/engine_paths.cpp @@ -25,32 +25,6 @@ static inline io::path EXPORT_FOLDER = "export"; static inline io::path CONTROLS_FILE = "controls.toml"; static inline io::path SETTINGS_FILE = "settings.toml"; -static io::path toCanonic(io::path path) { - std::stack parts; - - path = std::filesystem::u8path(path.string()).lexically_normal().string(); - do { - parts.push(path.name()); - path = path.parent(); - } while (!path.empty()); - - path = ""; - - while (!parts.empty()) { - const std::string part = parts.top(); - parts.pop(); - if (part == ".") { - continue; - } - if (part == "..") { - throw files_access_error("entry point reached"); - } - - path = path / part; - } - return path; -} - void EnginePaths::prepare() { io::set_device("res", std::make_shared(resourcesFolder, false)); io::set_device("user", std::make_shared(userFilesFolder)); diff --git a/src/io/engine_paths.hpp b/src/io/engine_paths.hpp index 4858a215..65e5e067 100644 --- a/src/io/engine_paths.hpp +++ b/src/io/engine_paths.hpp @@ -10,12 +10,6 @@ #include "data/dv.hpp" #include "content/ContentPack.hpp" -class files_access_error : public std::runtime_error { -public: - files_access_error(const std::string& msg) : std::runtime_error(msg) { - } -}; - class EnginePaths { public: void prepare(); diff --git a/src/io/path.cpp b/src/io/path.cpp index e1dd5a98..08333c34 100644 --- a/src/io/path.cpp +++ b/src/io/path.cpp @@ -1,6 +1,6 @@ #include "path.hpp" -#include +#include using namespace io; @@ -9,3 +9,30 @@ void path::checkValid() const { throw std::runtime_error("path entry point is not specified: " + str); } } + +path path::normalized() const { + io::path path = pathPart(); + + std::stack parts; + do { + parts.push(path.name()); + path.str = path.parent().string(); + } while (!path.empty()); + + while (!parts.empty()) { + const std::string part = parts.top(); + parts.pop(); + if (part == ".") { + continue; + } + if (part == "..") { + throw access_error("entry point reached"); + } + + path = path / part; + } + if (path.colonPos != std::string::npos) { + path = path.entryPoint() + ":" + path.string(); + } + return path; +} diff --git a/src/io/path.hpp b/src/io/path.hpp index 6c6dea14..3911b1ef 100644 --- a/src/io/path.hpp +++ b/src/io/path.hpp @@ -1,9 +1,16 @@ #pragma once #include +#include #include namespace io { + class access_error : public std::runtime_error { + public: + access_error(const std::string& msg) : std::runtime_error(msg) { + } + }; + /// @brief std::filesystem::path project-specific alternative having /// `entry_point:path` scheme and solving std::filesystem::path problems: /// - implicit std::string conversions depending on compiler @@ -115,6 +122,8 @@ namespace io { return str.substr(0, slashpos); } + path normalized() const; + std::string string() const { return str; } From 3e67d887f4444078cdabc16cc2ceb5cb7ee5e068 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Tue, 4 Feb 2025 16:55:43 +0300 Subject: [PATCH 15/16] update io::Device::read --- src/io/devices/Device.hpp | 8 +++--- src/io/devices/StdfsDevice.cpp | 8 +++--- src/io/devices/StdfsDevice.hpp | 2 +- src/io/io.cpp | 47 +++++++++++++++++++++------------- src/io/io.hpp | 36 +++++++++++++++++++++++--- 5 files changed, 72 insertions(+), 29 deletions(-) diff --git a/src/io/devices/Device.hpp b/src/io/devices/Device.hpp index bb000602..98666415 100644 --- a/src/io/devices/Device.hpp +++ b/src/io/devices/Device.hpp @@ -1,6 +1,8 @@ #pragma once #include +#include +#include #include #include "../path.hpp" @@ -13,7 +15,7 @@ namespace io { virtual std::filesystem::path resolve(std::string_view path) = 0; virtual void write(std::string_view path, const void* data, size_t size) = 0; - virtual void read(std::string_view path, void* data, size_t size) = 0; + virtual std::unique_ptr read(std::string_view path) = 0; virtual size_t size(std::string_view path) = 0; @@ -43,8 +45,8 @@ namespace io { parent->write((root / path).pathPart(), data, size); } - void read(std::string_view path, void* data, size_t size) override { - parent->read((root / path).pathPart(), data, size); + std::unique_ptr read(std::string_view path) override { + return parent->read((root / path).pathPart()); } size_t size(std::string_view path) override { diff --git a/src/io/devices/StdfsDevice.cpp b/src/io/devices/StdfsDevice.cpp index ad33547d..e5009e00 100644 --- a/src/io/devices/StdfsDevice.cpp +++ b/src/io/devices/StdfsDevice.cpp @@ -35,13 +35,13 @@ void StdfsDevice::write(std::string_view path, const void* data, size_t size) { output.write((const char*)data, size); } -void StdfsDevice::read(std::string_view path, void* data, size_t size) { +std::unique_ptr StdfsDevice::read(std::string_view path) { auto resolved = resolve(path); - std::ifstream input(resolved, std::ios::binary); - if (!input.is_open()) { + auto input = std::make_unique(resolved, std::ios::binary); + if (!*input) { throw std::runtime_error("could not to open file " + resolved.u8string()); } - input.read((char*)data, size); + return input; } size_t StdfsDevice::size(std::string_view path) { diff --git a/src/io/devices/StdfsDevice.hpp b/src/io/devices/StdfsDevice.hpp index 819dfe4f..9112f2f9 100644 --- a/src/io/devices/StdfsDevice.hpp +++ b/src/io/devices/StdfsDevice.hpp @@ -7,7 +7,7 @@ namespace io { std::filesystem::path resolve(std::string_view path) override; void write(std::string_view path, const void* data, size_t size) override; - void read(std::string_view path, void* data, size_t size) override; + std::unique_ptr read(std::string_view path) override; size_t size(std::string_view path) override; bool exists(std::string_view path) override; bool isdir(std::string_view path) override; diff --git a/src/io/io.cpp b/src/io/io.cpp index a9ee86de..efb241d4 100644 --- a/src/io/io.cpp +++ b/src/io/io.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include "coders/commons.hpp" @@ -60,12 +61,16 @@ io::directory_iterator::directory_iterator(const io::path& folder) } io::rafile::rafile(const io::path& filename) - : file(io::resolve(filename), std::ios::binary | std::ios::ate) { - if (!file) { + : file(std::make_unique(io::resolve(filename), std::ios::binary | std::ios::ate)) { + if (!*file) { throw std::runtime_error("could not to open file " + filename.string()); } - filelength = file.tellg(); - file.seekg(0); + filelength = file->tellg(); + file->seekg(0); +} + +io::rafile::rafile(std::unique_ptr file, size_t length) + : file(std::move(file)), filelength(length) { } size_t io::rafile::length() const { @@ -73,11 +78,11 @@ size_t io::rafile::length() const { } void io::rafile::seekg(std::streampos pos) { - file.seekg(pos); + file->seekg(pos); } void io::rafile::read(char* buffer, std::streamsize size) { - file.read(buffer, size); + file->read(buffer, size); } bool io::write_bytes( @@ -96,8 +101,17 @@ bool io::read(const io::path& filename, char* data, size_t size) { if (device == nullptr) { return false; } - device->read(filename.pathPart(), data, size); - return true; + auto stream = io::read(filename); + stream->read(data, size); + return stream->good(); +} + +std::unique_ptr io::read(const io::path& filename) { + auto device = io::get_device(filename.entryPoint()); + if (device == nullptr) { + throw std::runtime_error("io-device not found: " + filename.entryPoint()); + } + return device->read(filename.pathPart()); } util::Buffer io::read_bytes_buffer(const path& file) { @@ -112,15 +126,17 @@ std::unique_ptr io::read_bytes( auto& device = io::require_device(filename.entryPoint()); length = device.size(filename.pathPart()); auto data = std::make_unique(length); - device.read(filename.pathPart(), data.get(), length); - return data; + auto stream = io::read(filename); + stream->read(reinterpret_cast(data.get()), length); + return stream->good() ? std::move(data) : nullptr; } std::vector io::read_bytes(const path& filename) { auto& device = io::require_device(filename.entryPoint()); size_t length = device.size(filename.pathPart()); std::vector data(length); - device.read(filename.pathPart(), data.data(), length); + auto stream = io::read(filename); + stream->read(reinterpret_cast(data.data()), length); return data; } @@ -163,15 +179,10 @@ dv::value io::read_toml(const path& file) { } std::vector io::read_list(const io::path& filename) { - std::ifstream file(resolve(filename)); // FIXME - if (!file) { - throw std::runtime_error( - "could not to open file " + filename.string() - ); - } + auto stream = io::read(filename); std::vector lines; std::string line; - while (std::getline(file, line)) { + while (std::getline(*stream, line)) { util::trim(line); if (line.length() == 0) continue; if (line[0] == '#') continue; diff --git a/src/io/io.hpp b/src/io/io.hpp index 14541eea..ba63688e 100644 --- a/src/io/io.hpp +++ b/src/io/io.hpp @@ -15,21 +15,33 @@ namespace io { class Device; + /// @brief Set device for the entry-point void set_device(const std::string& name, std::shared_ptr device); + + /// @brief Remove device by entry-point void remove_device(const std::string& name); + + /// @brief Get device by entry-point std::shared_ptr get_device(const std::string& name); + + /// @brief Get device by entry-point or throw exception Device& require_device(const std::string& name); + /// @brief Create subdevice for the entry-point + /// @param name subdevice entry-point + /// @param parent parent device entry-point + /// @param root root path for the subdevice void create_subdevice( const std::string& name, const std::string& parent, const path& root ); /// @brief Read-only random access file class rafile { - std::ifstream file; + std::unique_ptr file; size_t filelength; public: rafile(const path& filename); + rafile(std::unique_ptr file, size_t length); void seekg(std::streampos pos); void read(char* buffer, std::streamsize size); @@ -131,6 +143,7 @@ namespace io { ); bool read(const io::path& file, char* data, size_t size); + std::unique_ptr read(const io::path& file); util::Buffer read_bytes_buffer(const path& file); std::unique_ptr read_bytes(const path& file, size_t& length); std::vector read_bytes(const path& file); @@ -140,21 +153,38 @@ namespace io { /// @param file *.json or *.bjson file dv::value read_json(const path& file); + /// @brief Read BJSON file dv::value read_binary_json(const path& file); /// @brief Read TOML file /// @param file *.toml file dv::value read_toml(const path& file); + /// @brief Read list of strings from the file std::vector read_list(const io::path& file); + /// @brief Check if path is a regular file bool is_regular_file(const io::path& file); - bool is_directory(const io::path& file); - bool exists(const io::path& file); + + /// @brief Check if path is a directory + bool is_directory(const io::path& path); + + /// @brief Check if file or directory exists + bool exists(const io::path& path); + + /// @brief Create directory bool create_directory(const io::path& file); + + /// @brief Create directories recursively bool create_directories(const io::path& file); + + /// @brief Remove file or empty directory bool remove(const io::path& file); + + /// @brief Remove all files and directories in the folder recursively uint64_t remove_all(const io::path& file); + + /// @brief Get file size in bytes size_t file_size(const io::path& file); std::filesystem::path resolve(const io::path& file); From 1c98d6cb372ceb443c29fdcacf7e0f3f5d694e4c Mon Sep 17 00:00:00 2001 From: MihailRis Date: Tue, 4 Feb 2025 17:38:43 +0300 Subject: [PATCH 16/16] update io::Device::write --- src/io/devices/Device.hpp | 35 +++++++++++++++++++++++++++++++--- src/io/devices/StdfsDevice.cpp | 8 ++++---- src/io/devices/StdfsDevice.hpp | 3 ++- src/io/io.cpp | 7 ++++--- src/io/io.hpp | 8 +++++++- src/io/path.hpp | 1 + 6 files changed, 50 insertions(+), 12 deletions(-) diff --git a/src/io/devices/Device.hpp b/src/io/devices/Device.hpp index 98666415..a3addaf5 100644 --- a/src/io/devices/Device.hpp +++ b/src/io/devices/Device.hpp @@ -8,27 +8,56 @@ #include "../path.hpp" namespace io { + + /// @brief Device interface for file system operations class Device { public: virtual ~Device() = default; + /// @brief Resolve path to the filesystem path virtual std::filesystem::path resolve(std::string_view path) = 0; - virtual void write(std::string_view path, const void* data, size_t size) = 0; + /// @brief Open file for writing + /// @throw std::runtime_error if file cannot be opened + virtual std::unique_ptr write(std::string_view path) = 0; + + /// @brief Open file for reading + /// @throw std::runtime_error if file cannot be opened virtual std::unique_ptr read(std::string_view path) = 0; + /// @brief Get file size in bytes virtual size_t size(std::string_view path) = 0; + /// @brief Check if file or directory exists virtual bool exists(std::string_view path) = 0; + + /// @brief Check if path is a directory virtual bool isdir(std::string_view path) = 0; + + /// @brief Check if path is a regular file virtual bool isfile(std::string_view path) = 0; + + /// @brief Create directory + /// @return true if directory was created virtual bool mkdir(std::string_view path) = 0; + + /// @brief Create directories recursively + /// @return true if directory was created virtual bool mkdirs(std::string_view path) = 0; + + /// @brief Remove file or empty directory + /// @return true if file or directory was removed virtual bool remove(std::string_view path) = 0; + + /// @brief Remove all files and directories in the folder recursively + /// @return number of removed files and directories virtual uint64_t removeAll(std::string_view path) = 0; + + /// @brief List directory contents virtual std::unique_ptr list(std::string_view path) = 0; }; + /// @brief Subdevice is a wrapper around another device limited to a directory class SubDevice : public Device { public: SubDevice( @@ -41,8 +70,8 @@ namespace io { return parent->resolve((root / path).pathPart()); } - void write(std::string_view path, const void* data, size_t size) override { - parent->write((root / path).pathPart(), data, size); + std::unique_ptr write(std::string_view path) override { + return parent->write((root / path).pathPart()); } std::unique_ptr read(std::string_view path) override { diff --git a/src/io/devices/StdfsDevice.cpp b/src/io/devices/StdfsDevice.cpp index e5009e00..cb47c2e6 100644 --- a/src/io/devices/StdfsDevice.cpp +++ b/src/io/devices/StdfsDevice.cpp @@ -26,13 +26,13 @@ fs::path StdfsDevice::resolve(std::string_view path) { return root / fs::u8path(io::path(std::string(path)).normalized().string()); } -void StdfsDevice::write(std::string_view path, const void* data, size_t size) { +std::unique_ptr StdfsDevice::write(std::string_view path) { auto resolved = resolve(path); - std::ofstream output(resolved, std::ios::binary); - if (!output.is_open()) { + auto output = std::make_unique(resolved, std::ios::binary); + if (!output->is_open()) { throw std::runtime_error("could not to open file " + resolved.u8string()); } - output.write((const char*)data, size); + return output; } std::unique_ptr StdfsDevice::read(std::string_view path) { diff --git a/src/io/devices/StdfsDevice.hpp b/src/io/devices/StdfsDevice.hpp index 9112f2f9..ec1a9526 100644 --- a/src/io/devices/StdfsDevice.hpp +++ b/src/io/devices/StdfsDevice.hpp @@ -1,12 +1,13 @@ #include "Device.hpp" namespace io { + /// @brief Device based on the standard filesystem class StdfsDevice : public Device { public: StdfsDevice(std::filesystem::path root, bool createDirectory = true); std::filesystem::path resolve(std::string_view path) override; - void write(std::string_view path, const void* data, size_t size) override; + std::unique_ptr write(std::string_view path) override; std::unique_ptr read(std::string_view path) override; size_t size(std::string_view path) override; bool exists(std::string_view path) override; diff --git a/src/io/io.cpp b/src/io/io.cpp index efb241d4..bef794b4 100644 --- a/src/io/io.cpp +++ b/src/io/io.cpp @@ -90,10 +90,11 @@ bool io::write_bytes( ) { auto device = io::get_device(filename.entryPoint()); if (device == nullptr) { - return false; + throw std::runtime_error("io-device not found: " + filename.entryPoint()); } - device->write(filename.pathPart(), data, size); - return true; + auto stream = device->write(filename.pathPart()); + stream->write(reinterpret_cast(data), size); + return stream->good(); } bool io::read(const io::path& filename, char* data, size_t size) { diff --git a/src/io/io.hpp b/src/io/io.hpp index ba63688e..46582400 100644 --- a/src/io/io.hpp +++ b/src/io/io.hpp @@ -142,11 +142,17 @@ namespace io { bool compressed = false ); - bool read(const io::path& file, char* data, size_t size); + /// @brief Open file for reading + /// @throw std::runtime_error if file cannot be opened std::unique_ptr read(const io::path& file); + + /// @brief Read bytes array from the file + bool read(const io::path& file, char* data, size_t size); util::Buffer read_bytes_buffer(const path& file); std::unique_ptr read_bytes(const path& file, size_t& length); std::vector read_bytes(const path& file); + + /// @brief Read string from the file std::string read_string(const path& file); /// @brief Read JSON or BJSON file diff --git a/src/io/path.hpp b/src/io/path.hpp index 3911b1ef..4c35d824 100644 --- a/src/io/path.hpp +++ b/src/io/path.hpp @@ -5,6 +5,7 @@ #include namespace io { + /// @brief Access violation error class access_error : public std::runtime_error { public: access_error(const std::string& msg) : std::runtime_error(msg) {